/* Project styles layered on top of Bootstrap 5.3. */

/* Theme palette. Dark is the default; `body.theme-light` overrides the same
   variables, so every rule below is written once against var(--…). */
:root {
  --bg: #0a0a0a;
  --fg: #d4d4d4;
  --card-bg: #14141f;
  --card-border: #24243a;
  --header-bg: #1a1a2e;
  --header-fg: #8b8ba7;
  --label: #7a7a93;
  --sub: #6b6b85;
  --muted: #7a7a93;
  --num: #8b8ba7;
  --table-border: #1c1c2c;
  --row-hover: #1a1a2a;
  --chip-bg: #1a1a2e;
  --chip-hover: #24243a;
  --chip-active-bg: #1f2937;
  --tail-border: #111111;
  --ts: #5a5a72;
  --bar: #2b6cb0;
  --teal: #4fd1c5;
  --green: #68d391;
  --yellow: #ecc94b;
  --red: #fc8181;
  --crit: #f56565;
  --on-bar: #0a0a0a;
  --so-bg: #4a5568;
  --so-fg: #cbd5e0;
}

body.theme-light {
  --bg: #f4f6f9;
  --fg: #1f2430;
  --card-bg: #ffffff;
  --card-border: #e2e6ec;
  --header-bg: #eef1f5;
  --header-fg: #5a6172;
  --label: #6b7280;
  --sub: #8a90a0;
  --muted: #6b7280;
  --num: #4b5160;
  --table-border: #edeff3;
  --row-hover: #f0f3f7;
  --chip-bg: #eef1f5;
  --chip-hover: #e2e6ec;
  --chip-active-bg: #dbeafe;
  --tail-border: #eef1f5;
  --ts: #9aa0ad;
  --bar: #3b82f6;
  --teal: #0d9488;
  --green: #059669;
  --yellow: #b7791f;
  --red: #dc2626;
  --crit: #dc2626;
  --on-bar: #ffffff;
  --so-bg: #cbd5e0;
  --so-fg: #1f2430;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
}

main {
  flex: 1 0 auto;
}

/* ── Live stats dashboard ── */
.dash {
  --mono: 'SF Mono', 'Fira Code', 'Consolas', ui-monospace, monospace;
}
.dash .card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
}
.dash .card-header {
  background: var(--header-bg);
  border-bottom: 1px solid var(--card-border);
  color: var(--header-fg);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* collapsible panel headers (top paths → methods) */
.dash .card-header.acc-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  user-select: none;
}
.dash .card-header.acc-toggle.collapsed { border-bottom-color: transparent; }
.dash .card-header.acc-toggle:hover { color: var(--teal); }
.acc-caret { transition: transform 0.15s ease; opacity: 0.7; }
.card-header.acc-toggle:not(.collapsed) .acc-caret { transform: rotate(90deg); }
/* title-only toggle, for headers that also carry inline controls (chart, tail) */
.dash .card-header .acc-h { display: inline-flex; align-items: center; cursor: pointer; user-select: none; }
.dash .card-header .acc-h:hover { color: var(--teal); }
.dash .card-header .acc-h .acc-caret { margin-right: 4px; }
.acc-h:not(.collapsed) .acc-caret { transform: rotate(90deg); }
.stat-card .value {
  font-family: var(--mono);
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1.1;
}
.stat-card .label {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--label);
}
.stat-card .sub { font-size: 0.72rem; color: var(--sub); }

.teal { color: var(--teal); }
.green { color: var(--green); }
.yellow { color: var(--yellow); }
.red { color: var(--red); }
.crit { color: var(--crit); }
.muted { color: var(--muted); }

/* theme toggle */
.theme-toggle {
  font-size: 0.9rem; line-height: 1.3; cursor: pointer;
  color: var(--fg); background: var(--chip-bg);
  border: 1px solid var(--card-border); border-radius: 6px; padding: 2px 9px;
}
.theme-toggle:hover { background: var(--chip-hover); }

table.dash-table { font-family: var(--mono); font-size: 0.78rem; width: 100%; }
table.dash-table td { padding: 2px 6px; border-top: 1px solid var(--table-border); vertical-align: top; }
table.dash-table td.num { text-align: right; color: var(--num); white-space: nowrap; }
table.dash-table td.key { word-break: break-all; }
table.dash-table tr:hover td { background: var(--row-hover); }
.dash-table .flag { font-size: 0.95rem; }

/* broken routes (known-good pages returning 404/5xx) */
#broken { font-family: var(--mono); font-size: 0.74rem; }
.broken-row { padding: 2px 0; display: flex; gap: 6px; align-items: baseline; border-top: 1px solid var(--tail-border); }
.broken-row:first-child { border-top: none; }
.broken-path { flex: 1; color: var(--red); word-break: break-all; }
.broken-n { white-space: nowrap; }

/* requests/min chart — per-minute stacked bars, horizontally scrollable */
#rpm { flex: 1 1 auto; min-width: 0; display: flex; align-items: flex-end; gap: 0; height: 170px; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; overscroll-behavior-x: contain; }
/* vertical number line (y-axis) — height is set in JS to the bars' drawable area */
#rpm-yaxis { position: relative; flex: 0 0 40px; align-self: flex-start; border-right: 1px solid var(--card-border); }
.rpm-y-tick { position: absolute; right: 6px; transform: translateY(50%); font-size: 0.56rem; line-height: 1; color: var(--muted); white-space: nowrap; }
.rpm-y-tick::after { content: ''; position: absolute; right: -6px; bottom: 50%; width: 4px; border-bottom: 1px solid var(--card-border); }
#rpm .bar { flex: 0 0 var(--barw, 4px); width: var(--barw, 4px); min-height: 1px; box-sizing: border-box; border-right: 1px solid var(--card-border); display: flex; flex-direction: column-reverse; overflow: hidden; }
/* when the loaded data is narrower than the chart, push it right so the newest
   bar is flush at the right edge (auto-margin collapses to 0 once it overflows,
   so horizontal scrolling/left-loading is unaffected). */
#rpm .bar:first-child { margin-left: auto; }
#rpm .seg { width: 100%; }
#rpm .seg.s2 { background: var(--green); }
#rpm .seg.s3 { background: var(--yellow); }
#rpm .seg.s4 { background: var(--red); }
#rpm .seg.s5 { background: var(--crit); }
#rpm .seg.so { background: var(--so-bg); }
/* the bars at the chart's left/right edges, tied to the edge hit-count labels */
#rpm .bar.edge { background: var(--bar); }
#rpm .bar.edge .seg { background: var(--bar); }

/* hit-count labels pinned to the chart's left/right edges (current edge bars) */
.rpm-wrap { position: relative; display: flex; align-items: flex-start; }
.rpm-end { position: absolute; top: 3px; z-index: 2; pointer-events: none;
  display: flex; flex-direction: column; line-height: 1.25; /* stack the per-status counts */
  font-family: var(--mono); font-size: 0.62rem; color: var(--fg); opacity: 0.95;
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 3px; padding: 1px 4px; }
.rpm-end:empty { display: none; }
#rpm-end-l { left: 44px; align-items: flex-start; } /* clear the y-axis gutter (40px) */
#rpm-end-r { right: 3px; align-items: flex-end; }
.rpm-end-t { color: var(--muted); font-size: 0.56rem; margin-bottom: 1px; white-space: nowrap; } /* edge bar date+time */

/* infrastructure health (per-server rows) */
#infra { font-family: var(--mono); font-size: 0.72rem; }
.infra-row { padding: 5px 0; border-top: 1px solid var(--table-border); }
.infra-row:first-child { border-top: none; }
.infra-row.warn { background: color-mix(in srgb, var(--red) 8%, transparent); border-radius: 3px; }
.infra-h { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }
.infra-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--green); }
.infra-dot.warn { background: var(--red); } .infra-dot.off { background: var(--muted); }
.infra-host { font-size: 0.66rem; }
.infra-up { margin-left: auto; font-size: 0.66rem; white-space: nowrap; }
.infra-spark { width: 64px; height: 14px; }
.infra-spark polyline { fill: none; stroke: var(--teal); stroke-width: 1; vector-effect: non-scaling-stroke; }
.im { display: flex; align-items: center; gap: 6px; line-height: 1.6; }
.im-l { width: 28px; color: var(--muted); }
.im-bar { flex: 1; height: 7px; background: var(--chip-bg); border-radius: 3px; overflow: hidden; }
.im-fill { display: block; height: 100%; }
.im-fill.ok { background: var(--green); } .im-fill.warn { background: var(--yellow); } .im-fill.crit { background: var(--red); }
.im-v { width: 34px; text-align: right; }
.infra-meta { font-size: 0.68rem; margin-top: 2px; }
.infra-row.off { opacity: 0.7; }

/* per-server cards (row under the stat strip) */
.srv-card { font-family: var(--mono); font-size: 0.72rem; }
.srv-card.warn { border-color: var(--red); }
.srv-h { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.srv-name { font-weight: 700; font-size: 0.82rem; }
.srv-host { font-size: 0.66rem; }
.srv-up { margin-left: auto; font-size: 0.66rem; white-space: nowrap; }
.srv-card .infra-spark { margin-left: auto; }
.srv-card .srv-up { margin-left: 6px; }
.srv-off { margin-top: 2px; word-break: break-word; }

/* manage-servers list in the sidebar card */
.srv-cfg { display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 0.72rem;
  padding: 3px 0; border-top: 1px solid var(--table-border); }
.srv-cfg:first-child { border-top: none; }
.srv-cfg-l { font-weight: 700; }
.srv-cfg-s { flex: 1; font-size: 0.66rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srv-rm { cursor: pointer; color: var(--muted); padding: 0 3px; }
.srv-rm:hover { color: var(--red); }
/* on-demand top-processes: header button + modal table */
.srv-procs-btn { margin-left: 6px; cursor: pointer; color: var(--muted); font-size: 0.9rem; line-height: 1; flex: 0 0 auto; }
.srv-procs-btn:hover { color: var(--teal); }
.procs-tbl { font-family: var(--mono); font-size: 0.74rem; }
.procs-r { display: grid; grid-template-columns: 1fr auto 3.4em 3.4em; gap: 10px; padding: 2px 0; border-top: 1px solid var(--table-border); }
.procs-r.procs-head { border-top: none; color: var(--muted); }
.procs-r > span:nth-child(3), .procs-r > span:nth-child(4) { text-align: right; }
.procs-c { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.procs-tbl .ok { color: var(--green); } .procs-tbl .warn { color: var(--yellow); } .procs-tbl .crit { color: var(--red); }

/* req/min rolling time axis (scrolls in sync with the bars) */
.rpm-axis-wrap { position: relative; height: 26px; overflow: hidden; margin-left: 40px; } /* align the time axis with the bars (past the y-axis gutter) */
.rpm-axis { position: relative; height: 26px; will-change: transform; }
/* labels are right-anchored to their tick (text extends LEFT) so the live-edge
   label isn't clipped off the right edge when the newest bar sits flush there. */
.rpm-tick { position: absolute; top: 5px; font-family: var(--mono); font-size: 0.58rem; color: var(--yellow); white-space: nowrap; transform-origin: top right; transform: translateX(-100%) rotate(40deg); }
.rpm-tick.day { color: var(--yellow); font-weight: 700; transform: translateX(-100%) rotate(0deg); }
.rpm-tick::before { content: ''; position: absolute; top: -5px; right: 0; left: auto; width: 1px; height: 4px; background: var(--card-border); }

/* req/min chart IP filter tag */
.rpm-ip-tag { font-family: var(--mono); font-size: 0.7rem; color: var(--teal); cursor: pointer; margin-left: 6px; text-transform: none; letter-spacing: 0; }
.rpm-ip-tag .clear { color: var(--red); }

/* req/min chart controls */
.rpm-date { font-family: var(--mono); font-size: 0.66rem; color: var(--fg); background: var(--chip-bg);
  border: 1px solid var(--card-border); border-radius: 4px; padding: 1px 4px; color-scheme: dark; }
body.theme-light .rpm-date { color-scheme: light; }
.rpm-now { font-family: var(--mono); font-size: 0.68rem; color: var(--header-fg); cursor: pointer;
  background: var(--chip-bg); border: 1px solid var(--card-border); border-radius: 4px; padding: 1px 8px; line-height: 1.4; }
.rpm-now:hover { color: var(--teal); border-color: var(--teal); background: var(--chip-hover); }
.rpm-tip { position: fixed; z-index: 50; pointer-events: none; font-family: var(--mono); font-size: 0.7rem;
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 5px; padding: 5px 8px;
  color: var(--fg); box-shadow: 0 4px 14px rgba(0,0,0,0.45); white-space: nowrap; line-height: 1.5; }
.rpm-tip-h { color: var(--header-fg); margin-bottom: 2px; }
.rpm-tip-t { color: var(--muted); border-top: 1px solid var(--card-border); margin-top: 3px; padding-top: 2px; }

/* AI analysis panel (rendered markdown) */
.ai-analysis { font-size: 0.78rem; line-height: 1.5; color: var(--fg); word-break: break-word; }
.ai-analysis h3, .ai-analysis h4, .ai-analysis h5, .ai-analysis h6 { font-size: 0.82rem; font-weight: 700; margin: 10px 0 4px; color: var(--header-fg); text-transform: none; letter-spacing: 0; }
.ai-analysis p { margin: 0 0 7px; }
.ai-analysis ul, .ai-analysis ol { margin: 0 0 7px; padding-left: 18px; }
.ai-analysis li { margin: 1px 0; }
.ai-analysis code { font-family: var(--mono); font-size: 0.92em; background: var(--chip-bg); border-radius: 3px; padding: 0 3px; }
.ai-analysis strong { color: var(--fg); font-weight: 700; }
.ai-meta { font-size: 0.66rem; color: var(--muted); margin-bottom: 6px; }
#ai-run:disabled, #ai-refresh:disabled, #ai-pdf:disabled { opacity: 0.5; cursor: default; }

/* IP search */
.ipq-row { display: flex; gap: 6px; margin-bottom: 6px; }
.ipq-input { flex: 1; font-family: var(--mono); font-size: 0.74rem; color: var(--fg); background: var(--chip-bg);
  border: 1px solid var(--card-border); border-radius: 4px; padding: 3px 7px; }
.ipq-list { max-height: 180px; overflow-y: auto; }
.ipq-item { display: flex; justify-content: space-between; gap: 8px; font-family: var(--mono); font-size: 0.72rem;
  padding: 3px 6px; cursor: pointer; border-radius: 3px; }
.ipq-item:hover { background: var(--chip-hover); }
.ipq-item .ip { color: var(--fg); }
.ipq-c { color: var(--muted); white-space: nowrap; }
.ipq-empty { color: var(--muted); font-size: 0.72rem; padding: 4px 6px; }
.ipq-result { margin-top: 8px; }
.ipq-result:empty { display: none; }
.ipq-head { font-family: var(--mono); font-size: 0.78rem; margin-bottom: 2px; }
.ipq-span { margin-bottom: 5px; }
.ipq-status { display: flex; gap: 8px; flex-wrap: wrap; font-family: var(--mono); font-size: 0.72rem; margin-bottom: 6px; }
.ipq-path { display: flex; justify-content: space-between; gap: 8px; font-family: var(--mono); font-size: 0.72rem;
  padding: 1px 0; border-top: 1px solid var(--table-border); }
.ipq-path .key { word-break: break-all; }
.ipq-path .num { color: var(--num); white-space: nowrap; }

/* status split bar */
.status-bar { display: flex; height: 22px; border-radius: 4px; overflow: hidden; font-size: 0.62rem; }
.status-bar > span { display: flex; align-items: center; justify-content: center; color: var(--on-bar); font-weight: 700; min-width: 0; }
.status-bar .s2 { background: var(--green); }
.status-bar .s3 { background: var(--yellow); }
.status-bar .s4 { background: var(--red); }
.status-bar .s5 { background: var(--crit); }
.status-bar .so { background: var(--so-bg); color: var(--so-fg); }

/* source chips */
.chip { display: inline-flex; gap: 4px; align-items: center; font-family: var(--mono); font-size: 0.72rem;
        padding: 1px 7px; margin: 2px; border-radius: 10px; background: var(--chip-bg); }
.chip .c { color: var(--sub); }
.chip.src-chip { cursor: pointer; user-select: none; }
.chip.src-chip:hover { background: var(--chip-hover); }
.chip.src-chip.active { outline: 1px solid var(--teal); background: var(--chip-active-bg); }

/* sources donut */
#sources .pie-wrap { display: flex; justify-content: center; padding: 2px 0 8px; }
.pie { width: 244px; height: 244px; max-width: 100%; }
.pie .slice { cursor: pointer; transition: opacity .15s, stroke-width .12s, filter .12s; }
.pie .slice.dim { opacity: 0.3; }
.src-chip { transition: opacity .15s; }
/* hover highlight — brighten the hovered source, dim the others (console-style) */
#sources.hovering .slice:not(.hot) { opacity: 0.22; }
#sources.hovering .slice.hot { stroke-width: 6.5; filter: brightness(1.25); }
#sources.hovering .src-chip:not(.hot) { opacity: 0.4; }
.src-legend { display: flex; flex-wrap: wrap; }
.src-chip .dot, .rpm-tip-h .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }
#tail-filter { cursor: pointer; }
#tail-filter .clear { color: var(--red); }
.tail-clear { font-family: var(--mono); font-size: 0.68rem; color: var(--header-fg); cursor: pointer;
  background: var(--chip-bg); border: 1px solid var(--card-border); border-radius: 4px; padding: 1px 7px; line-height: 1.4; }
.tail-clear:hover { color: var(--red); border-color: var(--red); background: var(--chip-hover); }
.tail-ip { font-family: var(--mono); font-size: 0.66rem; color: var(--fg); background: var(--chip-bg);
  border: 1px solid var(--card-border); border-radius: 4px; padding: 1px 6px; width: 108px; }
.tail-max { font-family: var(--mono); font-size: 0.66rem; color: var(--fg); background: var(--chip-bg);
  border: 1px solid var(--card-border); border-radius: 4px; padding: 1px 4px; color-scheme: dark; }
body.theme-light .tail-max { color-scheme: light; }
#tail .ln[hidden] { display: none; }
#tail .ln.s404 { outline: 1px solid var(--red); outline-offset: -2px; border-radius: 2px; } /* flag 404 probes */
/* "click a bar" pinned-bucket banner */
#rpm .bar { cursor: pointer; }
.tail-pin { font-family: var(--mono); font-size: 0.68rem; color: var(--teal); white-space: nowrap; }
.tail-pin:empty { display: none; }
.tail-pin .pin-dot { color: var(--yellow); margin-right: 2px; }
.tail-pin .pin-x { cursor: pointer; color: var(--header-fg); border: 1px solid var(--card-border);
  border-radius: 4px; padding: 0 5px; margin-left: 4px; }
.tail-pin .pin-x:hover { color: var(--red); border-color: var(--red); }

/* live tail */
#tail { font-family: var(--mono); font-size: 0.72rem; max-height: 360px; overflow-y: auto; }
#tail .ln { padding: 1px 0; white-space: pre-wrap; word-break: break-all; border-bottom: 1px solid var(--tail-border); }
#tail .ln .ts { color: var(--ts); }
#tail .ln.atk { background: rgba(245,101,101,0.08); }
#tail .ln.alert { background: rgba(236,201,75,0.12); }
#tail .src { font-weight: 600; }

/* alerts */
#alerts .a { font-family: var(--mono); font-size: 0.72rem; padding: 4px 6px; border-left: 3px solid var(--crit);
             background: rgba(245,101,101,0.06); margin-bottom: 4px; word-break: break-all; }

/* auto-reports */
#reports .rep { font-family: var(--mono); font-size: 0.72rem; padding: 2px 0; border-bottom: 1px solid var(--tail-border); word-break: break-all; }
#reports .rep:last-child { border-bottom: 0; }
#reports .rep-t { color: var(--ts); margin-right: 4px; }

#attackers .atk-ip { color: var(--red); }
#attackers .svc-row { white-space: nowrap; }
#attackers .svc { margin-left: 5px; opacity: 0.65; }
#attackers .svc:hover { opacity: 1; }
#attackers .svc img { vertical-align: -2px; border-radius: 2px; }

.pulse-ok { color: var(--green); }
.pulse-bad { color: var(--red); }
