:root {
  --bg: #090d18;
  --panel: #10182b;
  --panel-alt: #0c1222;
  --text: #edf3ff;
  --muted: #9eb0d1;
  --accent: #38c6a8;
  --accent-2: #59a8ff;
  --border: #1e2a45;
  --danger: #ff6b78;
  --shadow: 0 16px 36px rgba(0, 0, 0, 0.35);
  --font-sans: "IBM Plex Sans", "Segoe UI", "Trebuchet MS", sans-serif;
  --font-mono: "JetBrains Mono", "Consolas", "Liberation Mono", monospace;
  --score-prod: #38c6a8;
  --score-mvp: #59a8ff;
  --score-tool: #d8b948;
  --score-hobby: #d98a4a;
  --score-empty: #6a7794;
}

.audit-nav-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.5rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 0.88rem;
}
.audit-nav-item:hover { background: var(--panel-alt); }
.audit-nav-item.active { background: rgba(89, 168, 255, 0.15); outline: 1px solid var(--accent-2); }
.audit-score {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: var(--panel-alt);
  color: var(--muted);
  min-width: 2.4rem;
  text-align: center;
}
.audit-score.score-prod  { background: rgba(56,198,168,0.18); color: var(--score-prod); }
.audit-score.score-mvp   { background: rgba(89,168,255,0.18); color: var(--score-mvp); }
.audit-score.score-tool  { background: rgba(216,185,72,0.18); color: var(--score-tool); }
.audit-score.score-hobby { background: rgba(217,138,74,0.18); color: var(--score-hobby); }
.audit-score.score-empty { background: rgba(106,119,148,0.18); color: var(--score-empty); }

.audit-job-row {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.45rem 0.55rem;
  margin-top: 0.4rem;
  background: var(--panel-alt);
}
.audit-job-row strong { color: var(--text); }
.job-status-running { background: rgba(89,168,255,0.18); color: var(--accent-2); }
.job-status-done    { background: rgba(56,198,168,0.18); color: var(--accent); }
.job-status-failed  { background: rgba(255,107,120,0.18); color: var(--danger); }

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  background: radial-gradient(circle at 15% 15%, #1a2342 0%, #090d18 50%), linear-gradient(145deg, #060910 0%, #0b1020 100%);
  color: var(--text);
  font-family: var(--font-sans);
  overflow: hidden;
}

.bg-shape {
  position: fixed;
  border-radius: 9999px;
  filter: blur(70px);
  opacity: 0.2;
  pointer-events: none;
}

.bg-a {
  width: 340px;
  height: 340px;
  background: #2b7fff;
  top: -100px;
  left: -60px;
}

.bg-b {
  width: 300px;
  height: 300px;
  background: #33d1a7;
  bottom: -120px;
  right: -40px;
}

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
  background: rgba(9, 13, 24, 0.85);
  backdrop-filter: blur(8px);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

h1 {
  margin: 0;
  letter-spacing: 0.3px;
  font-size: 1.35rem;
}

h2,
h3,
h4 {
  margin: 0;
}

.subtitle {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.actions,
.view-switch,
.hero-actions {
  display: flex;
  gap: 10px;
}

.btn {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 9px 14px;
  font-weight: 600;
  cursor: pointer;
  color: var(--text);
  background: var(--panel-alt);
}

.btn:hover,
.tile:hover {
  transform: translateY(-1px);
}

.btn-primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #041122;
  border-color: transparent;
}

.btn-ghost {
  background: transparent;
}

.tab {
  border: 1px solid var(--border);
  background: #091226;
  color: var(--muted);
  border-radius: 999px;
  padding: 7px 12px;
  cursor: pointer;
  font-weight: 600;
}

.tab.active {
  color: #041122;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  border-color: transparent;
}

/* The Agents sub-bar: one subsystem's five views, subordinate to one top-level tab.
   Deliberately NOT `.view-switch` — ui/acp/shared.js keys its "get out of the way"
   behaviour off `.view-switch .tab`, and a second bar with that class would make these
   five buttons hide each other's panels. Smaller and rule-separated so it reads as a
   level down from the bar in the header rather than a second bar competing with it. */
.subview-switch {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 0 0 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

.subview-switch .tab {
  padding: 5px 11px;
  font-size: 0.85rem;
}

.app-main {
  height: calc(100vh - 86px);
}

.dashboard-view {
  height: 100%;
  overflow: auto;
  padding: 16px;
}

.hero-panel,
.dashboard-group,
.panel {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: linear-gradient(170deg, rgba(16, 24, 43, 0.96), rgba(12, 18, 34, 0.96));
  box-shadow: var(--shadow);
}

.hero-panel {
  display: flex;
  justify-content: space-between;
  align-items: end;
  gap: 16px;
  padding: 20px;
  margin-bottom: 16px;
}

.eyebrow {
  color: var(--accent);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-bottom: 8px;
}

.hero-panel h2 {
  font-size: 1.8rem;
  margin-bottom: 10px;
}

.hero-copy {
  max-width: 760px;
  color: var(--muted);
  line-height: 1.6;
}

.dashboard-groups {
  display: grid;
  gap: 16px;
}

.dashboard-group {
  padding: 18px;
}

.dashboard-group-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14px;
}

.dashboard-group h3 {
  font-size: 1.15rem;
}

.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}

.tile-link {
  text-decoration: none;
  color: inherit;
  display: block;
}

.tile {
  height: 100%;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px;
  background: linear-gradient(180deg, rgba(11, 18, 34, 0.95), rgba(7, 13, 27, 0.98));
  transition: transform 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
}

.tile:hover {
  border-color: rgba(89, 168, 255, 0.55);
  box-shadow: 0 18px 30px rgba(0, 0, 0, 0.28);
}

.tile-topline {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-bottom: 12px;
}

.tile-status {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  flex: none;
  background: #6b7280;
  box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.18);
}
.tile-status.up {
  background: #34d399;
  box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.22);
}
.tile-status.down {
  background: #f87171;
  box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.22);
}
.tile-status.unknown {
  background: #6b7280;
  box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.18);
}

.tile-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 4px 9px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #dce9ff;
  background: rgba(89, 168, 255, 0.14);
  border: 1px solid rgba(89, 168, 255, 0.18);
}

.tile h4 {
  margin-bottom: 8px;
  font-size: 1.02rem;
}

.tile p {
  margin: 0 0 14px;
  color: var(--muted);
  line-height: 1.5;
  font-size: 0.94rem;
}

.tile-meta {
  font-size: 0.86rem;
  color: #cfe1ff;
  font-family: var(--font-mono);
}

.tile-ops h4,
.tile-internal h4 {
  color: #7bd7c0;
}

.tile-monitoring h4 {
  color: #86b7ff;
}

.tile-data h4 {
  color: #e0c27a;
}

.tile-ai h4 {
  color: #f39ec3;
}

.layout {
  display: grid;
  grid-template-columns: 290px 1fr;
  gap: 16px;
  padding: 16px;
  height: 100%;
}

.side {
  padding: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* The Ask sidebar, and ONLY the Ask sidebar, scrolls instead of squeezing.
 *
 * .side is a flex column with overflow:hidden, so once its content is taller than the panel every
 * child is shrunk to make it fit -- and a <textarea> shrinks all the way. Measured 2026-08-31 in a
 * real browser: #askGoal, rows="5", computed to SIX PIXELS. It was there, it was focusable, and it
 * was invisible. `flex: none` makes each block keep the height it asked for, and the scroll gives
 * the overflow somewhere to go rather than being clipped away.
 *
 * Scoped to #askShell on purpose: eight other panels use .side and none of them asked for this. */
#askShell > .side { overflow-y: auto; }
#askShell > .side > * { flex: none; }

.panel-title {
  font-size: 0.95rem;
  font-weight: 700;
  margin-bottom: 10px;
}

#searchInput {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  background: #091226;
  color: var(--text);
  margin-bottom: 10px;
}

#toc {
  overflow: auto;
  flex: 1;
  padding-right: 6px;
}

#auditNav {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 6px;
}

.side-tool {
  margin-top: 0.6rem;
  flex: 0 0 auto;
}

.side-tool > summary {
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  padding: 4px 0;
  list-style: none;
  user-select: none;
  color: var(--text);
}

.side-tool > summary::-webkit-details-marker { display: none; }

.side-tool > summary::before {
  content: "▸ ";
  display: inline-block;
  width: 1em;
  color: var(--muted);
  transition: transform 120ms ease;
}

.side-tool[open] > summary::before {
  content: "▾ ";
}

.side-tool[open] > summary {
  margin-bottom: 0.4rem;
}

#toc a {
  display: block;
  color: var(--muted);
  text-decoration: none;
  padding: 6px 7px;
  border-radius: 8px;
  font-size: 0.9rem;
}

#toc a:hover,
#toc a.active {
  background: rgba(89, 168, 255, 0.18);
  color: var(--text);
}

#toc a.toc-match {
  border-left: 2px solid rgba(56, 198, 168, 0.7);
  line-height: 1.35;
}

#toc a.toc-match span,
#toc a.toc-match small {
  display: block;
}

#toc a.toc-match small {
  margin-top: 3px;
  color: var(--accent);
  font-size: 0.72rem;
}

.meta {
  margin-top: 10px;
  font-size: 0.82rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
  padding-top: 10px;
  font-family: var(--font-mono);
}

.content {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.mode-switch {
  display: flex;
  gap: 8px;
  padding: 12px;
  border-bottom: 1px solid var(--border);
}

.preview,
.editor {
  height: 100%;
  overflow: auto;
  padding: 18px;
}

.preview {
  line-height: 1.55;
}

.preview h1,
.preview h2,
.preview h3 {
  margin-top: 1.3em;
  margin-bottom: 0.55em;
}

.preview a {
  color: #8fcbff;
}

.preview table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}

.preview th,
.preview td {
  border: 1px solid var(--border);
  padding: 8px;
  text-align: left;
}

.preview code,
.editor,
.tile-meta {
  font-family: var(--font-mono);
}

.preview pre {
  background: #060b16;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  overflow: auto;
}

.editor {
  width: 100%;
  border: none;
  outline: none;
  background: #070d1b;
  color: var(--text);
  resize: none;
}

.status {
  border-top: 1px solid var(--border);
  min-height: 34px;
  font-size: 0.86rem;
  color: var(--muted);
  padding: 7px 12px;
  font-family: var(--font-mono);
}

/* LAB-34. This row used to carry `style="display:flex"` INLINE alongside class="hidden",
   and an inline declaration beats a class rule, so hideRepoActions() could never hide it:
   a near-full-width bar sat on the page from first paint. The layout lives here now, and
   the :not(.hidden) guard means the flex rule does not merely lose to `.hidden` on source
   order -- it stops applying at all, so moving either rule in this file cannot revive the
   bug. Do not reintroduce an inline display on a class-toggled element. */
.repo-actions:not(.hidden) {
  display: flex;
  gap: 0.5rem;
  padding: 0.4rem 0;
  align-items: center;
  flex-wrap: wrap;
}

/* Plugins pane (ui/config/index.js). Deliberately reuses .cfg-table from the Config tab
   rather than a second table style. cfg-warn marks a module the shell does not load --
   dead weight that is otherwise invisible. */
.cfg-ok   { color: #6fd58c; }
.cfg-warn { color: #ffb066; }
.cfg-note { font-size: 0.78rem; opacity: 0.75; margin: 0 0 .7em; line-height: 1.45; }
.cfg-note code { font-size: 0.75rem; }

/* Inventory > VMs (ui/inventory/index.js). Reuses .cfg-table; only the filter bar and the
   powered-off treatment are new. Powered-off rows are dimmed rather than hidden -- the whole
   reason this pane exists is that an off VM was previously indistinguishable from a deleted
   one, so it must stay on the page. */
.vm-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 0 0 10px; }
.vm-bar input[type=search] { min-width: 210px; }
.vm-chip.active { background: var(--accent, #2b6cb0); color: #fff; }
.vm-stamp { margin-left: auto; font-size: 0.74rem; }
.vm-off { opacity: 0.65; }
.vm-row-off > td { opacity: 0.62; }
.vm-note { font-size: 0.72rem; max-width: 34ch; white-space: normal; }

.hidden {
  display: none;
}

.error {
  color: var(--danger);
}

.success {
  color: #7ce4a6;
}

@media (max-width: 900px) {
  body {
    overflow: auto;
  }

  .topbar,
  .hero-panel {
    flex-direction: column;
    align-items: stretch;
  }

  .topbar-right {
    flex-direction: column;
    align-items: stretch;
  }

  .layout {
    grid-template-columns: 1fr;
    height: auto;
  }

  .side {
    max-height: 220px;
  }

  .content {
    min-height: 70vh;
  }
}

/* ---- UPS / Power view ---- */
.ups-status-card { display: flex; flex-direction: column; gap: 0.5rem; }
.ups-status-badge {
  display: inline-block;
  padding: 0.4rem 0.7rem;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.95rem;
  text-align: center;
  background: #233; color: #ccc;
  border: 1px solid #355;
}
.ups-status-badge.ok { background: #0e3324; color: #6cffb0; border-color: #1b6a48; }
.ups-status-badge.warn { background: #3d2e0c; color: #ffd479; border-color: #7a5d18; }
.ups-status-badge.crit { background: #3d0c0c; color: #ff7979; border-color: #7a1818; }
.ups-status-badge.unk { background: #2a2a2a; color: #aaa; border-color: #444; }
.ups-status-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem;
  font-size: 0.85rem;
}
.ups-status-grid > div { display: flex; justify-content: space-between; gap: 0.5rem; }
.ups-k { color: var(--muted); }
.ups-v { font-family: var(--font-mono); font-weight: 600; }
.ups-model { font-size: 0.8rem; color: var(--muted); font-style: italic; }
.ups-cards { display: flex; flex-direction: column; gap: 0.6rem; }
.ups-card { border: 1px solid var(--border); border-radius: 8px; padding: 0.6rem 0.7rem; background: rgba(255,255,255,0.02); }
.ups-card.selected { border-color: #6ca0ff; box-shadow: 0 0 0 1px #6ca0ff inset; }
.ups-card.dimmed { opacity: 0.5; }
.login-gate { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: #0e1116; }
.login-gate.hidden { display: none; }
.login-box { background: #161b22; border: 1px solid var(--border); border-radius: 10px; padding: 1.6rem; width: 320px; max-width: 90vw; display: flex; flex-direction: column; gap: 0.6rem; }
.login-box h2 { margin: 0 0 0.2rem 0; }
.login-box input { padding: 0.5rem 0.6rem; border-radius: 6px; border: 1px solid var(--border); background: #0e1116; color: #e6e6e6; }
.ups-card-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.45rem; flex-wrap: wrap; }
.ups-card-title { font-weight: 600; font-size: 0.9rem; }
.ups-powers { font-size: 0.8rem; color: var(--muted); margin-top: 0.4rem; }
.ups-vms { font-size: 0.8rem; margin-top: 0.4rem; }
.ups-vms > summary { cursor: pointer; color: var(--muted); }
.ups-vms ul { margin: 0.3rem 0 0 1rem; padding: 0; }
.ups-vms li { margin: 0.1rem 0; }
.power-step {
  border: 1px solid var(--border); border-radius: 6px;
  padding: 0.6rem 0.8rem; margin: 0.4rem 0; background: rgba(255,255,255,0.02);
}
.power-step h4 { margin: 0 0 0.4rem 0; font-size: 0.95rem; }
.power-step .step-meta { font-size: 0.8rem; color: var(--muted); margin-bottom: 0.4rem; font-family: var(--font-mono); }
.power-step ul { margin: 0.3rem 0 0 1rem; padding: 0; font-size: 0.83rem; }
.power-warn {
  background: #3d2e0c; color: #ffd479; border: 1px solid #7a5d18;
  padding: 0.4rem 0.6rem; border-radius: 5px; font-size: 0.85rem; margin: 0.3rem 0;
}
.power-cp-pill {
  display: inline-block; padding: 0.05rem 0.4rem; border-radius: 4px;
  background: #25304a; color: #8eafff; font-size: 0.7rem;
  border: 1px solid #3b4d75; margin-left: 0.4rem;
}
.power-tbl { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.power-tbl th, .power-tbl td { border-bottom: 1px solid var(--border); padding: 0.35rem 0.5rem; text-align: left; vertical-align: top; }
.power-tbl th { color: var(--muted); font-weight: 500; }

/* ---- Power editor (Config sub-tab) ---- */
.power-fs {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.7rem 1rem;
  margin: 0.6rem 0;
  background: rgba(255,255,255,0.015);
}
.power-fs > legend {
  padding: 0 0.4rem;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
}
.power-field {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 0.5rem 0.8rem;
  align-items: center;
  margin: 0.3rem 0;
}
.power-field > label {
  color: var(--muted);
  font-size: 0.85rem;
}
.power-field input[type="text"],
.power-field input[type="number"],
.power-field textarea {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  background: rgba(0,0,0,0.25);
  color: var(--text, #e8eaf0);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.3rem 0.45rem;
}
.power-field textarea { font-family: var(--font-mono); resize: vertical; }
.power-vmgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 0.2rem 0.6rem;
  max-height: 320px;
  overflow: auto;
  padding: 0.3rem;
  border: 1px dashed var(--border);
  border-radius: 4px;
}
.power-vmrow {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 0.4rem;
  align-items: center;
  padding: 0.15rem 0.25rem;
  font-size: 0.85rem;
  border-radius: 3px;
}
.power-vmrow:hover { background: rgba(255,255,255,0.03); }
.power-vmrow input[type="checkbox"] { margin: 0; }
.power-vmname { font-weight: 500; }
.power-vmip { color: var(--muted); font-size: 0.78rem; }
.power-vmrow-orphan { opacity: 0.7; font-style: italic; }
.power-policy-row {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  margin: 0.25rem 0;
  flex-wrap: wrap;
}
.power-save-bar {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  padding: 0.6rem 0;
  margin-top: 0.5rem;
  border-top: 1px solid var(--border);
}
.status.ok { color: #6cffb0; }

/* Audit Refresh Schedules */
.sched-toolbar {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.4rem;
}
.sched-toolbar .grow { flex: 1; }
.sched-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}
.sched-table th, .sched-table td {
  text-align: left;
  padding: 0.3rem 0.4rem;
  border-bottom: 1px solid rgba(255,255,255,0.05);
  vertical-align: middle;
}
.sched-table th {
  font-weight: 600;
  color: var(--muted);
  position: sticky;
  top: 0;
  background: var(--bg, #0a1428);
  z-index: 1;
}
.sched-table tr:hover td { background: rgba(255,255,255,0.025); }
.sched-table input[type="number"] {
  width: 4.5rem;
  background: rgba(0,0,0,0.25);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.2rem 0.3rem;
  font-family: var(--font-mono);
}
.sched-table select {
  background: rgba(0,0,0,0.25);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.2rem 0.3rem;
}
.sched-table .row-actions {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
}
.sched-table .btn-tiny {
  font-size: 0.75rem;
  padding: 0.15rem 0.45rem;
}
.sched-pill {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border-radius: 8px;
  font-size: 0.72rem;
  font-weight: 600;
  border: 1px solid var(--border);
}
.sched-pill.enabled { background: rgba(108,255,176,0.12); color: #6cffb0; border-color: rgba(108,255,176,0.4); }
.sched-pill.disabled { color: #9eb0d1; }
.sched-pill.status-done { background: rgba(108,255,176,0.12); color: #6cffb0; }
.sched-pill.status-running { background: rgba(255,255,108,0.12); color: #ffec6b; }
.sched-pill.status-failed { background: rgba(255,108,108,0.12); color: #ff8a8a; }
.sched-pill.status-skipped { color: #9eb0d1; }

/* Ingress view + degraded health dot */
.tile-status.degraded {
  background: #fbbf24;
  box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.22);
}
.muted { color: var(--muted); font-size: 0.85rem; }
.ingress-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.ingress-table th, .ingress-table td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--border, #2a2a2a); }
.ingress-table th { color: var(--muted); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
.ingress-table a { color: #9cc4ff; text-decoration: none; }
.ingress-table a:hover { text-decoration: underline; }
/* The public-access switch on an app tile. The pressed side IS the current edge state,
   so it is styled straight off aria-pressed rather than a second class to keep in sync. */
.pa-ctl[aria-pressed="true"] { border-color: var(--accent-2); background: rgba(89,168,255,0.15); color: #cfe3ff; }
.pa-ctl[aria-pressed="true"][data-pa="on"] { border-color: #1b6a48; background: rgba(108,255,176,0.12); color: #6cffb0; }
.pa-ctl:disabled { opacity: 0.45; cursor: not-allowed; }
.pa-block #appPubMsg:empty { display: none; }

.pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 0.74rem; font-weight: 700; }
.pill-on { background: #0e3324; color: #6cffb0; border: 1px solid #1b6a48; }
.pill-off { background: #2a2a2a; color: #aaa; border: 1px solid #444; }
.apps-group td { background: var(--panel-alt, #1c1c1c); font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: #cfe3ff; }

/* Intruder Watch */
.nav-badge {
  display: inline-block; margin-left: 6px; min-width: 18px; padding: 0 5px;
  border-radius: 999px; font-size: 0.7rem; font-weight: 800; line-height: 18px;
  text-align: center; background: var(--danger); color: #1a0a0c; vertical-align: middle;
}
.pill-cat { background: #3d2e0c; color: #ffd479; border: 1px solid #7a5d18; }
.watch-drill td { background: var(--panel-alt); }
/* Security: severity pills + signature form */
.pill-crit { background: #3d0c0c; color: #ff7979; border: 1px solid #7a1818; }
.pill-high { background: #3d1e0c; color: #ffb066; border: 1px solid #7a4318; }
.pill-med  { background: #3d2e0c; color: #ffd479; border: 1px solid #7a5d18; }
.pill-low  { background: #16233d; color: #9ec2ff; border: 1px solid #2c4a7a; }
/* auto-renew on/off toggle switch (single control: position = state) */
.ar-toggle { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; vertical-align: middle; user-select: none; }
.ar-track { position: relative; width: 34px; height: 18px; border-radius: 999px; background: #444; border: 1px solid #555; transition: background .15s, border-color .15s; flex: none; }
.ar-knob { position: absolute; top: 1px; left: 1px; width: 14px; height: 14px; border-radius: 50%; background: #ddd; transition: left .15s; }
.ar-toggle.on .ar-track { background: #0e3324; border-color: #1b6a48; }
.ar-toggle.on .ar-knob { left: 17px; background: #6cffb0; }
.ar-toggle .ar-lbl { font-size: 0.72rem; color: var(--muted); }
.ar-toggle.on .ar-lbl { color: #6cffb0; }
.sig-form-box { border: 1px solid var(--border); border-radius: 8px; padding: 0.75rem; margin-bottom: 0.75rem; background: var(--panel-alt); }
.sig-form-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.55rem; }
.sig-form-grid label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.76rem; color: var(--muted); }
.sig-form-grid .sig-wide { grid-column: 1 / -1; }
.sig-form-grid input, .sig-form-grid select { padding: 0.4rem 0.5rem; border-radius: 6px; border: 1px solid var(--border); background: var(--bg); color: var(--text); font-size: 0.85rem; }
.sig-form-grid input:disabled { opacity: 0.6; }

/* Security: AI triage verdicts + analyst chat */
.pill-benign { background: #0e3324; color: #6cffb0; border: 1px solid #1b6a48; }
.pill-susp   { background: #33270c; color: #ffcf66; border: 1px solid #6a5018; }
.pill-mal    { background: #3d0c0c; color: #ff7979; border: 1px solid #7a1818; }
.triage-summary { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.5rem; }
.triage-rat { font-size: 0.74rem; margin-top: 0.2rem; white-space: normal; max-width: 46ch; }
.risk-cell { font-family: var(--font-mono); font-weight: 800; text-align: center; }
.chat-log { max-height: 52vh; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 0.6rem; background: var(--panel-alt); display: flex; flex-direction: column; gap: 0.5rem; }
.chat-msg { padding: 0.5rem 0.7rem; border-radius: 10px; max-width: 84%; white-space: pre-wrap; font-size: 0.9rem; line-height: 1.4; }
.chat-user { align-self: flex-end; background: #16233d; color: #cfe0ff; border: 1px solid #2c4a7a; }
.chat-ai { align-self: flex-start; background: var(--bg); color: var(--text); border: 1px solid var(--border); }
.chat-trace { margin-top: 0.35rem; font-size: 0.72rem; color: var(--muted); }
.chat-trace summary { cursor: pointer; }
.chat-trace pre { white-space: pre-wrap; max-height: 220px; overflow: auto; margin: 0.3rem 0 0; }
.chat-input { display: flex; gap: 0.5rem; margin-top: 0.6rem; align-items: flex-end; }
.chat-input textarea { flex: 1 1 auto; padding: 0.5rem 0.6rem; border-radius: 8px; border: 1px solid var(--border); background: var(--bg); color: var(--text); font-family: inherit; font-size: 0.9rem; resize: vertical; }

/* Investigation dossier */
.dossier { max-width: 900px; }
.dossier-detail { font-family: var(--font-mono); font-size: 0.85rem; background: var(--panel-alt); border: 1px solid var(--border); border-radius: 6px; padding: 0.5rem 0.7rem; margin: 0.3rem 0; word-break: break-all; }
.dossier-verline { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; margin: 0.5rem 0; }
.dossier-brief { background: #12203a; border-left: 3px solid #3a5a9a; border-radius: 6px; padding: 0.7rem 0.85rem; margin: 0.6rem 0; line-height: 1.5; font-size: 0.92rem; white-space: pre-wrap; }
.dossier-facts { width: 100%; border-collapse: collapse; margin: 0.4rem 0; }
.dossier-facts td { padding: 0.35rem 0.5rem; border-top: 1px solid var(--border); vertical-align: top; font-size: 0.86rem; }
.dossier-facts td:first-child { color: var(--muted); width: 130px; white-space: nowrap; font-weight: 600; }
.dossier-ev { font-family: var(--font-mono); font-size: 0.78rem; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 0.5rem 0.7rem; overflow-x: auto; white-space: pre-wrap; word-break: break-all; margin: 0.3rem 0; }
.dossier-actions { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.9rem; flex-wrap: wrap; }
.dossier-proc { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; padding: 0.35rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; margin: 0.25rem 0; font-size: 0.82rem; }
.dossier-proc .mono { font-family: var(--font-mono); word-break: break-all; }

/* How-To hub */
#howtoNav .howto-group { margin-bottom: 0.75rem; }
#howtoNav .howto-doc { display: block; width: 100%; text-align: left; margin: 0.15rem 0; }
#howtoPreview { overflow: auto; }
#howtoPreview .howto-toolbar { margin: 0 0 0.75rem 0; padding-bottom: 0.5rem; border-bottom: 1px solid var(--border, #2a2a2a); }

/* ---------------- MCP hub tab ---------------- */
.mcp-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 10px; }
#mcpHubLine { margin-top: 4px; line-height: 1.5; }
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 999px; background: #555; vertical-align: middle; }
.dot.ok { background: #38d27e; box-shadow: 0 0 6px #38d27e88; }
.dot.bad { background: #ff5d5d; box-shadow: 0 0 6px #ff5d5d88; }
.mcp-card { border: 1px solid #2a2f3a; border-radius: 10px; padding: 12px 14px; margin: 10px 0; background: #161a22; }
.mcp-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mcp-card-head b { font-size: 1.05rem; }
.mcp-ep { margin-left: auto; font-size: 0.82rem; color: #9ec2ff; }
.mcp-uses { font-variant-numeric: tabular-nums; }
.mcp-uses-detail { font-size: 0.74rem; }
.mcp-uses-err { color: #ffb066; }
.mcp-usage-note { margin-top: 6px; font-size: 0.74rem; }
.mcp-what { margin: 7px 0; line-height: 1.45; }
.mcp-tools { margin: 6px 0; line-height: 1.9; }
.mcp-tools code, .mcp-ep { background: #0e1117; border: 1px solid #2a2f3a; border-radius: 5px; padding: 1px 6px; font-size: 0.8rem; }
.mcp-use { margin: 4px 0; line-height: 1.45; font-size: 0.92rem; }
.mcp-use b { color: #ffd479; }
.mcp-creds { margin-top: 7px; }

/* MCP common-prompt card */
.mcp-prompt-card { border: 1px solid #2c4a7a; border-radius: 10px; padding: 12px 14px; margin: 10px 0 14px; background: #0f1830; }
.mcp-prompt-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 6px; }
.mcp-prompt-head b { font-size: 1rem; }
.mcp-prompt { background: #0a0e18; border: 1px solid #2a2f3a; border-radius: 8px; padding: 12px 14px; margin: 8px 0; white-space: pre-wrap; word-break: break-word; font-family: var(--font-mono, monospace); font-size: 0.82rem; line-height: 1.5; max-height: 320px; overflow: auto; color: #cfe3ff; }
.dot.warn { background: #ffd479; box-shadow: 0 0 6px #ffd47988; }

/* Git Mirrors toolbar */
.gitmirrors-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.gitmirrors-interval { width: 8rem; background: #0e1117; border: 1px solid #2a2f3a; border-radius: 6px; padding: 6px 9px; color: #cfe3ff; font-family: var(--font-mono, monospace); font-size: 0.82rem; }
#gitMirrorsHubLine { margin-top: 4px; line-height: 1.5; }
#gitMirrorsTable { margin-top: 10px; }

/* agentlens: session step-by-step timeline (Agents tab) */
.al-tl { margin-top: 6px; border-left: 2px solid #30363d; padding-left: 10px; }
.al-turn { margin: 8px 0; }
.al-turn > b { font-size: 12px; }
.al-step { font-size: 12px; padding: 2px 0 2px 10px; }
.al-step code { color: #6e7681; margin-right: 6px; }
.al-inbox { font-size: 12px; padding: 3px 0 3px 10px; border-left: 2px solid #d29922; margin: 3px 0; }
.al-inbox code { color: #6e7681; margin-right: 6px; }
.al-in { background: #0d1117; border: 1px solid #30363d; color: #c9d1d9; border-radius: 4px;
         padding: 3px 7px; font-size: 12px; width: 46%; }
.al-pend { font-size: 12px; padding: 4px 9px; margin: 3px 0; border-left: 2px solid #d29922;
           background: #241c10; border-radius: 4px; }
.al-reply { font-size: 12px; margin: 4px 0 4px 10px; padding: 4px 9px; border-left: 2px solid #3fb950;
            background: #12261a; color: #7ee787; border-radius: 4px; }
.ac-static { margin-top: 2px; }

/* agentlens digest — the readable summary, first thing on each card */
/* No box border. #30363d is a desaturated blue-grey and its top edge read as a stray
   line sitting above the text. Background + padding is enough to group the block, and a
   left accent gives it an edge without drawing a horizontal rule through the layout. */
.ag-digest { margin: 6px 0 8px; padding: 9px 12px; background: #11161d;
             border-left: 2px solid #30363d; border-radius: 0 6px 6px 0; }
.ag-what { font-size: 13px; color: #e6edf3; line-height: 1.45; }
.ag-next { font-size: 12px; color: #8b949e; margin-top: 5px; }
.ag-sec { margin-top: 7px; font-size: 12px; }
.ag-sec > b { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
              color: #6e7681; margin-bottom: 3px; }
.ag-sec ul { margin: 0; padding-left: 16px; }
.ag-sec li { margin: 2px 0; line-height: 1.4; }
.ag-sec li.p { color: #7ee787; }
.ag-sec li.u { color: #e3b341; }
.ag-sec li.n { color: #ff9d97; }
.ag-sec li.r { color: #c9d1d9; }
.ag-sec li.r code { color: #6e7681; margin-right: 5px; }
.ag-needs { border-left: 2px solid #f85149; padding-left: 8px; }
.ag-config { margin: 4px 0 10px; font-size: 12px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ag-by { margin-top: 8px; font-size: 10.5px; color: #6e7681; }
.ag-by a { color: #8b949e; }
.ag-raw { margin-top: 6px; padding-top: 6px; }
.ag-raw.hidden { display: none; }

/* ---------------- Agent Control Plane (phase 1) ----------------
   Prefixed .acp-* so nothing here can collide with the existing sheet. Colours are taken
   from the values already in use above rather than introducing a second palette. */
.acp-card { margin: 8px 0; padding: 10px 12px; background: #11161d;
            border-left: 2px solid #30363d; border-radius: 0 6px 6px 0; }
.acp-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
                 margin-bottom: 4px; }
.acp-spacer { flex: 1 1 auto; }
.acp-err { color: #f85149; }
.acp-ok { color: #3fb950; }
.acp-formhost { margin-top: 16px; padding-top: 12px; border-top: 1px solid #21262d; }
.acp-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
            gap: 10px 14px; margin: 8px 0; }
.acp-form-wide { display: grid; gap: 10px; margin: 8px 0; }
.acp-form label, .acp-form-wide label { display: flex; flex-direction: column; gap: 4px;
            font-size: 12px; color: #8b949e; }
.acp-form input, .acp-form select,
.acp-form-wide input, .acp-form-wide textarea {
  background: #0d1117; color: #e6edf3; border: 1px solid #30363d; border-radius: 5px;
  padding: 6px 8px; font-size: 13px; font-family: inherit;
}
.acp-form-wide textarea { resize: vertical; font-family: ui-monospace, monospace; }
.acp-form input:disabled { color: #6e7681; background: #161b22; }
.acp-check { flex-direction: row !important; align-items: center; gap: 6px !important; }
.acp-check input { width: auto; }
.acp-fieldset { border: 1px solid #21262d; border-radius: 6px; padding: 8px 10px;
                display: flex; flex-wrap: wrap; gap: 4px 14px; }
.acp-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.acp-pre { background: #0d1117; border: 1px solid #21262d; border-radius: 6px;
           padding: 8px; font-size: 12px; white-space: pre-wrap; overflow-x: auto; }
.acp-models summary { cursor: pointer; }

/* ---- Agent Control Plane phase 2: jobs, detail, needs-attention ---- */
.acp-card-attn { border-left-color: #f85149; }
.acp-goal { white-space: pre-wrap; color: #e6edf3; }
.acp-goal-sum { cursor: pointer; }
/* Bounded even when open, so expanding a 16 KB goal does not push the plan off screen.
   data-dk on the scroller means its position survives the 4s repaint. */
.acp-goal-full { max-height: 340px; overflow-y: auto; margin-top: 0.35rem; }
.acp-appr { margin: 8px 0; padding: 8px 10px; background: #0d1117;
            border: 1px solid #30363d; border-radius: 6px; }
.acp-task { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
            padding: 4px 0; border-bottom: 1px solid #161b22; }
.acp-task:last-child { border-bottom: none; }
.acp-ev-seq { display: inline-block; min-width: 2.2em; text-align: right; color: #6e7681;
              font-family: ui-monospace, monospace; font-size: 11px; }
.acp-ev { padding: 3px 0; border-bottom: 1px solid #161b22; }
.acp-ev:last-child { border-bottom: none; }
.acp-ev-type { font-family: ui-monospace, monospace; font-size: 11px; color: #8b949e; }
.acp-evlist { max-height: 380px; overflow-y: auto; }
.acp-fb { margin: 6px 0; padding: 6px 0; border-bottom: 1px solid #161b22; }
.acp-fb:last-child { border-bottom: none; }
.acp-fb-raw { color: #e6edf3; font-style: italic; }
.acp-manual { margin-top: 10px; padding-top: 8px; border-top: 1px dashed #30363d; }
.acp-manual select { background: #0d1117; color: #e6edf3; border: 1px solid #30363d;
                     border-radius: 5px; padding: 4px 6px; font-size: 12px; }
.acp-inline-note { background: #0d1117; color: #e6edf3; border: 1px solid #30363d;
                   border-radius: 5px; padding: 4px 8px; font-size: 12px; min-width: 220px; }

/* Raw executor log drawer in the Job Detail task list. Monospace, scroll-capped: the summary is
   the story, this is the evidence, and it must not push the rest of the page out of view. */
.acp-rawlog {
  margin: 6px 0 0; padding: 8px; max-height: 320px; overflow: auto;
  background: var(--bg-code, #11151c); border: 1px solid var(--border, #2a3340);
  border-radius: 4px; font-size: 11px; line-height: 1.45; white-space: pre-wrap;
  word-break: break-word;
}

/* Conversation with the Manager in Job Detail. Deliberately looks like a chat and not like the
   event log: asking a question and issuing a directive are different acts, and the UI should not
   make them look interchangeable — conflating them is what let a wrong premise get entrenched. */
.acp-chat {
  max-height: 340px; overflow-y: auto; margin: 0 0 10px;
  border: 1px solid var(--border, #2a3340); border-radius: 4px; padding: 8px;
  background: var(--bg-sunken, #0e1218);
}
.acp-turn { padding: 6px 8px; margin-bottom: 6px; border-radius: 4px; font-size: 12px; }
.acp-turn-you { background: var(--bg-accent-soft, #16202c); border-left: 2px solid #4a90d9; }
.acp-turn-agent { background: var(--bg-raised, #131922); border-left: 2px solid #5aa469; }

/* Separates the launch form from the job list now that the form sits above it. */
.acp-listhead { margin: 18px 0 8px; font-size: 13px; opacity: 0.85; }

/* Inline answer under a pending approval, so you can interrogate a proposal without leaving the
   tab that told you it needed you. */
.acp-reply {
  margin: 6px 0; padding: 8px; border-radius: 4px; font-size: 12px; line-height: 1.5;
  background: var(--bg-raised, #131922); border-left: 2px solid #5aa469; white-space: pre-wrap;
}

/* Model usage / cost visibility in Job Detail. */
.acp-usage-cards { display: flex; gap: 10px; margin: 8px 0; flex-wrap: wrap; }
.acp-usage-card {
  display: flex; flex-direction: column; min-width: 108px; padding: 8px 12px;
  background: var(--bg-raised, #131922); border: 1px solid var(--border, #2a3340);
  border-radius: 4px;
}
.acp-usage-card b { font-size: 18px; line-height: 1.1; }
table.acp-usage { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 6px; }
table.acp-usage th, table.acp-usage td {
  text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--border, #2a3340);
}
table.acp-usage th { opacity: 0.7; font-weight: normal; }

/* LLM Cost tab: reuses the usage-card and usage-table styling from Job Detail so the per-job and
   cross-job views look like one system rather than two dashboards. */
.acp-block { margin: 0 0 18px; }
.acp-block h4 { margin: 14px 0 6px; }

/* Job progress. "RUNNING" alone is indistinguishable from wedged, so the bar carries a step
   count and the name of the step actually executing, and pulses only while genuinely active. */
.acp-prog { margin: 6px 0 2px; }
.acp-prog-track {
  height: 5px; border-radius: 3px; overflow: hidden;
  background: var(--bg-sunken, #0e1218); border: 1px solid var(--border, #2a3340);
}
.acp-prog-fill { height: 100%; background: #5aa469; transition: width .4s ease; }
.acp-prog-fill.acp-prog-live { background: linear-gradient(90deg, #4a90d9, #5aa469); }
@keyframes acp-pulse { 0%,100% { opacity: 1 } 50% { opacity: .55 } }
.acp-prog-live { animation: acp-pulse 1.8s ease-in-out infinite; }
.acp-prog-label { margin-top: 3px; }

/* Smart job intake — the recommendation card and the Advanced settings disclosure. */
.acp-sugg { border-left-color: #4a90d9; }
.acp-sugg-row { display: grid; grid-template-columns: 150px 1fr; gap: 8px;
  padding: 4px 0; border-bottom: 1px solid #161b22; align-items: start; }
.acp-sugg-row:last-of-type { border-bottom: none; }
.acp-sugg-k { color: #8b949e; font-size: 12px; }
.acp-sugg-v { font-size: 12px; display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.acp-sugg-v code { color: #e6edf3; }
.acp-reuse { margin-top: 6px; font-style: italic; }
.acp-diff { color: #ffb066; }
.acp-adv { margin-top: 12px; border: 1px solid #21262d; border-radius: 6px; padding: 6px 10px;
  background: #0d1117; }
.acp-adv-sum { cursor: pointer; color: #8b949e; font-size: 12px; }
.acp-adv[open] .acp-adv-sum { color: #e6edf3; margin-bottom: 6px; }
@media (max-width: 700px) { .acp-sugg-row { grid-template-columns: 1fr; } }

/* ---- What needs you, at the top of the one job list ----
   A second "Needs Attention" tab meant the answer to "is anything waiting on me?" lived somewhere
   other than the list of jobs, and clicking through from it lost your place. The list is now ordered
   by urgency and says what is being asked on the card itself. ---- */
.acp-attn-banner { border: 1px solid var(--accent, #388bfd); border-left: 4px solid #d29922;
  border-radius: 8px; padding: 0.5rem 0.8rem; margin-bottom: 0.7rem; background: #1c1a12;
  display: flex; gap: 0.8rem; align-items: baseline; flex-wrap: wrap; }
.acp-asked { border-left: 3px solid #d29922; padding: 0.35rem 0.6rem; margin: 0.4rem 0;
  background: #17150f; border-radius: 0 6px 6px 0; }
.acp-asked-bad { border-left-color: #f85149; background: #1a1111; }
/* Deliberately slow and low-contrast: this draws the eye on arrival without turning the page into a
   fairground when three jobs are parked. Respects reduced-motion. */
@keyframes acpFlash { 0%,100% { box-shadow: 0 0 0 0 rgba(210,153,34,0); }
                      50%     { box-shadow: 0 0 0 3px rgba(210,153,34,0.35); } }
.acp-flash { animation: acpFlash 2.4s ease-in-out 3; }
@media (prefers-reduced-motion: reduce) { .acp-flash { animation: none;
  box-shadow: 0 0 0 2px rgba(210,153,34,0.45); } }

/* A RUNNING task whose process is gone. Dimmed rather than hidden: it happened, it is just no
   longer happening, and the sweep will record it as lost within the minute. */
.acp-task-ghost { opacity: 0.6; border-left: 3px solid #f85149; padding-left: 0.5rem; }

/* The decision lives on the card. Approve/Reject/Ask/instruct inline, so nothing needs opening. */
.acp-asked-q { white-space: pre-wrap; font-weight: 600; margin-bottom: 0.3rem; }
.acp-listbox { margin-top: 0.45rem; }
.acp-listbox textarea { width: 100%; }

/* Finished jobs: present and countable, but collapsed and dimmed so they cannot bury the work that
   still needs someone. data-dk means the open/closed choice survives the 4s repaint. */
.acp-done > summary { cursor: pointer; margin-top: 1rem; }
.acp-card-done { opacity: 0.72; }

/* ---------------- Config tab (ui/config/index.js) ----------------
   Two tables and one form. The only thing here that is not plumbing is .cfg-unclaimed: a repo that
   no app claims is the reason the page exists, so it is marked on the row rather than left for the
   reader to spot in a list of fifty-six. */
table.cfg-table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 6px; }
table.cfg-table th, table.cfg-table td {
  text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--border, #2a2f3a); vertical-align: top;
}
table.cfg-table th { opacity: 0.7; font-weight: normal; }
tr.cfg-unclaimed > td { background: rgba(220, 120, 60, 0.10); }
.cfg-form { margin-bottom: 0.8rem; }
.cfg-grid { display: grid; gap: 0.4rem 0.8rem; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.cfg-f { display: flex; flex-direction: column; font-size: 12px; }
.cfg-f > span { opacity: 0.7; }
.cfg-f input, .cfg-f select { width: 100%; }

/* Config tab: the page could not be scrolled at all. `body` is `overflow: hidden` and
   `.layout` is `height: 100%`, so a pane taller than the viewport simply had nowhere to go —
   and the Apps pane renders one row per apps.json entry (58 today), which is far taller than
   any screen. `.main` had no rule of its own at all.
   Every other tab solves this by giving ONE inner element the scroll (#toc, #auditNav:
   `flex: 1; min-height: 0; overflow-y: auto`). Config never got that element, so the scroll
   goes on the panes themselves. Scoped to #configShell so no other tab's layout moves. */
#configShell .side,
#configShell .main {
  min-height: 0;
  overflow-y: auto;
}

/* Config > Modules: the live On/Order controls in the Configure column. Kept compact so a
   12-row table does not grow a scrollbar just for two inputs per row. */
.cfg-tabctl { white-space: nowrap; margin-right: .5em; }
.cfg-tabord { width: 5.5em; }

/* Spark tab (ui/spark/index.js). Chart chrome per the dataviz method: hairline solid grid one step
   off the panel, 2px series lines, 10% area wash, text in text tokens (never the series color). */
.spark-msg { padding: 10px 12px; border: 1px dashed var(--border); border-radius: 10px; color: var(--muted); margin: 6px 0; font-size: 0.88rem; }
.spark-msg.err { border-style: solid; border-color: #7a1818; color: #ffb3b3; background: rgba(255, 107, 120, 0.06); }
.spark-msg.okmsg { border-style: solid; border-color: #1b6a48; color: #b9f5d4; }
.spark-lead { margin: 4px 0 10px; }
.spark-section-title { margin: 18px 0 8px; font-weight: 700; color: var(--text); font-size: 0.95rem; }
.spark-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 12px; }
.spark-tile { background: var(--panel-alt); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; min-width: 0; }
.spark-tile-label { color: var(--muted); font-size: 0.78rem; }
.spark-tile-value { font-size: 1.25rem; font-weight: 650; margin: 4px 0 2px; overflow-wrap: anywhere; }
.spark-tile-sub { color: var(--muted); font-size: 0.76rem; font-weight: 400; }
.spark-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 6px 0 4px; }
.spark-filter-label { color: var(--muted); font-size: 0.82rem; }
.spark-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 12px; }
.spark-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 12px; }
.spark-chart, .spark-card { background: var(--panel-alt); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; min-width: 0; }
.spark-card-title { font-weight: 650; margin-bottom: 6px; }
.spark-chart-head { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; margin-bottom: 4px; }
.spark-chart-title { font-weight: 600; font-size: 0.88rem; }
.spark-chart-now { display: flex; gap: 10px; color: var(--muted); font-size: 0.8rem; }
.spark-chart-now b { color: var(--text); font-weight: 600; }
.spark-key { display: inline-block; width: 10px; height: 2px; vertical-align: middle; margin-right: 3px; border-radius: 1px; }
.spark-plot { position: relative; }
.spark-plot svg { width: 100%; height: auto; display: block; overflow: visible; }
.spark-grid line, line.spark-grid { stroke: #1e2a45; stroke-width: 1; }
.spark-axis { fill: #8a97b3; font-size: 10px; font-variant-numeric: tabular-nums; font-family: var(--font-sans); }
.spark-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.spark-area { opacity: 0.1; stroke: none; }
.spark-cross { stroke: #9eb0d1; stroke-width: 1; }
.spark-tip { position: absolute; top: 4px; min-width: 120px; background: #0b1120; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; font-size: 0.78rem; pointer-events: none; box-shadow: var(--shadow); }
.spark-tip-time { color: var(--muted); margin-bottom: 2px; }
.spark-tip b { color: var(--text); margin-left: 4px; }
.spark-tip span { color: var(--muted); }
.spark-lkey { display: inline-block; width: 12px; height: 2px; vertical-align: middle; border-radius: 1px; margin-right: 4px; }
.spark-legend { display: flex; gap: 14px; color: var(--muted); font-size: 0.78rem; margin-top: 2px; }
.spark-data summary { color: var(--muted); font-size: 0.75rem; cursor: pointer; margin-top: 4px; }
.spark-stale { opacity: 0.6; transition: opacity 0.2s; }
.spark-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin: 6px 0; }
.spark-table th { text-align: left; color: var(--muted); font-weight: 600; font-size: 0.78rem; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.spark-table td { padding: 7px 8px; border-bottom: 1px solid rgba(30, 42, 69, 0.6); vertical-align: top; }
.spark-table td .meta { font-size: 0.75rem; }
.spark-kv th { width: 14em; }
.spark-pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 0.74rem; font-weight: 700; border: 1px solid #444; background: #1a2238; color: #c7d3ea; white-space: nowrap; }
.spark-pill.ok { background: #0e3324; color: #6cffb0; border-color: #1b6a48; }
.spark-pill.bad { background: #3d0c0c; color: #ff9b9b; border-color: #7a1818; }
.spark-pill.run { background: #0c2240; color: #9cc8ff; border-color: #1f4f8a; }
.spark-pill.off { background: #1c1f27; color: #8e97a8; border-color: #333a48; }
.spark-mini { padding: 4px 10px; font-size: 0.8rem; border-radius: 8px; }
.spark-mini:disabled { opacity: 0.45; cursor: not-allowed; }
.spark-blocked { color: #ffcf8a; font-size: 0.75rem; margin-top: 4px; max-width: 26em; }
.spark-confirm { font-size: 0.8rem; color: var(--text); max-width: 28em; }
.spark-action { margin-bottom: 12px; }
.spark-action.run { border-color: #1f4f8a; }
.spark-action.ok { border-color: #1b6a48; }
.spark-action.bad { border-color: #7a1818; }
.spark-steps { margin: 6px 0; padding-left: 20px; font-size: 0.82rem; max-height: 220px; overflow: auto; }
.spark-logs { max-height: 320px; overflow: auto; background: #070b15; border: 1px solid var(--border); border-radius: 8px; padding: 8px; font-size: 0.75rem; white-space: pre-wrap; }
.spark-wrap { white-space: pre-wrap; word-break: break-word; font-size: 0.75rem; }
.spark-dgx { width: 100%; height: calc(100vh - 260px); min-height: 560px; border: 1px solid var(--border); border-radius: 12px; background: #000; margin-top: 8px; }
.nowrap { white-space: nowrap; }
.spark-sub { color: var(--muted); font-size: 0.78rem; margin-top: 2px; }
.spark-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 10px; }
#sparkShell a { color: var(--accent-2); }
#sparkShell a.btn { color: var(--text); text-decoration: none; }
.spark-pill.warn { background: #3d2e0c; color: #ffd479; border-color: #7a5d18; }

/* ---- Containers tab (ui/containers/index.js). State colors always come with a text label. ---- */
#containersShell a { color: var(--accent-2); }
.ct-msg { padding: 10px 12px; border: 1px dashed var(--border); border-radius: 10px; color: var(--muted); margin: 6px 0; font-size: 0.88rem; }
.ct-msg.err { border-style: solid; border-color: #7a1818; color: #ffb3b3; background: rgba(255, 107, 120, 0.06); }
.ct-sub { color: var(--muted); font-size: 0.76rem; font-weight: 400; }
.ct-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 4px 0 12px; }
.ct-filters select, .ct-search { background: var(--panel-alt); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; font: inherit; font-size: 0.86rem; }
.ct-search { flex: 1 1 280px; min-width: 200px; }
.ct-host { margin: 14px 0 22px; }
.ct-host-head { display: flex; flex-wrap: wrap; gap: 10px; align-items: baseline; margin-bottom: 8px; }
.ct-host-name { font-weight: 700; font-size: 1.05rem; color: var(--text); }
.ct-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-bottom: 12px; }
.ct-tile { background: var(--panel-alt); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; min-width: 0; }
.ct-tile-label { color: var(--muted); font-size: 0.78rem; }
.ct-tile-value { font-size: 1.25rem; font-weight: 650; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.ct-badt { color: var(--danger); }
.ct-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 10px; }
.ct-card { all: unset; box-sizing: border-box; cursor: pointer; display: flex; flex-direction: column; gap: 5px; min-width: 0;
  background: var(--panel-alt); border: 1px solid var(--border); border-left: 4px solid #6b7a99; border-radius: 12px; padding: 10px 12px; color: var(--text); }
.ct-card:hover, .ct-card:focus-visible { border-color: #3a4d78; }
.ct-card.sel { outline: 2px solid var(--accent-2); outline-offset: 1px; }
.ct-card.ct-ok { border-left-color: #38c6a8; }
.ct-card.ct-warn { border-left-color: #e5b454; }
.ct-card.ct-bad { border-left-color: var(--danger); }
.ct-card.ct-off { opacity: 0.72; }
.ct-card-head { display: flex; justify-content: space-between; gap: 8px; align-items: center; }
.ct-name { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-image { color: var(--muted); font-size: 0.8rem; font-family: ui-monospace, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-tag { color: var(--text); }
.ct-meta { display: flex; flex-wrap: wrap; gap: 8px; color: var(--muted); font-size: 0.76rem; }
.ct-chip { background: #16213a; border: 1px solid var(--border); border-radius: 999px; padding: 0 7px; color: var(--text); }
.ct-warnt { color: #e5b454; }
.ct-badge { display: inline-flex; align-items: center; gap: 5px; font-size: 0.74rem; border-radius: 999px; padding: 1px 8px; border: 1px solid var(--border); white-space: nowrap; }
.ct-badge i { width: 7px; height: 7px; border-radius: 50%; background: #6b7a99; }
.ct-badge.ct-ok { color: #b9f5d4; } .ct-badge.ct-ok i { background: #38c6a8; }
.ct-badge.ct-warn { color: #ffd479; } .ct-badge.ct-warn i { background: #e5b454; }
.ct-badge.ct-bad { color: #ffb3b3; } .ct-badge.ct-bad i { background: var(--danger); }
.ct-badge.ct-off { color: var(--muted); }
.ct-row { display: grid; grid-template-columns: 34px auto 1fr; gap: 6px; align-items: center; font-size: 0.84rem; font-variant-numeric: tabular-nums; }
.ct-row:has(.ct-sub) { grid-template-columns: 34px auto auto 1fr; }
.ct-k { color: var(--muted); font-size: 0.76rem; }
.ct-spark { width: 100%; height: 22px; display: block; }
.ct-io { display: flex; justify-content: space-between; gap: 8px; color: var(--muted); font-size: 0.74rem; }
.ct-meter { height: 4px; background: #16213a; border-radius: 4px; overflow: hidden; margin-top: 4px; }
.ct-meter i { display: block; height: 100%; background: #3987e5; border-radius: 4px; }
.ct-meter.hot i { background: var(--danger); }
.ct-detail { background: var(--panel); border: 1px solid #3a4d78; border-radius: 14px; padding: 12px 14px; margin: 6px 0 18px; }
.ct-detail-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 8px; }
.ct-kv th { text-align: left; width: 14em; color: var(--muted); font-weight: 500; vertical-align: top; }
.ct-kv td { overflow-wrap: anywhere; }
.ct-section-title { margin: 16px 0 8px; font-weight: 700; display: flex; gap: 10px; align-items: center; }
.ct-ranges { display: inline-flex; gap: 4px; }
.ct-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 10px; }
.ct-chart { background: var(--panel-alt); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; min-width: 0; }
.ct-chart-head { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; margin-bottom: 4px; }
.ct-chart-title { font-weight: 600; font-size: 0.88rem; }
.ct-chart-now { display: flex; gap: 10px; color: var(--muted); font-size: 0.8rem; }
.ct-chart-now b { color: var(--text); font-weight: 600; }
.ct-key { display: inline-block; width: 12px; height: 2px; vertical-align: middle; border-radius: 1px; margin-right: 4px; }
.ct-legend { display: flex; gap: 12px; color: var(--muted); font-size: 0.76rem; margin-top: 2px; }
.ct-plot { position: relative; }
.ct-plot svg { width: 100%; height: auto; display: block; overflow: visible; }
.ct-grid-line { stroke: #1e2a45; stroke-width: 1; }
.ct-axis { fill: #8a97b3; font-size: 10px; font-variant-numeric: tabular-nums; font-family: var(--font-sans); }
.ct-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.ct-cross { stroke: #9eb0d1; stroke-width: 1; }
.ct-tip { position: absolute; top: 4px; min-width: 120px; background: #0b1120; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; font-size: 0.78rem; pointer-events: none; box-shadow: var(--shadow); }
.ct-tip b { color: var(--text); margin-left: 4px; }
.ct-fold { margin-top: 10px; }
.ct-fold summary { cursor: pointer; font-weight: 650; }
.ct-logs { max-height: 360px; overflow: auto; background: #070b14; border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; font-size: 0.76rem; white-space: pre-wrap; overflow-wrap: anywhere; }
/* Redis memory on a Redis host's container cards (ui/containers) and the Redis capacity page (ui/redisCapacity).
   Bar colors always travel with the % in text. */
.ct-redis { border-top: 1px dashed var(--border); padding-top: 5px; margin-top: 2px; display: flex; flex-direction: column; gap: 4px; }
.ct-rmeter { height: 8px; background: #16213a; border-radius: 4px; overflow: hidden; }
.ct-rmeter i { display: block; height: 100%; border-radius: 4px; background: #6b7a99; }
.ct-rmeter.ct-rok i { background: #38c6a8; }
.ct-rmeter.ct-rwarn i { background: #e5b454; }
.ct-rmeter.ct-rbad i { background: var(--danger); }
.ct-rnocap { color: #e5b454; font-size: 0.78rem; }
.ct-rlink { color: var(--accent-2); cursor: pointer; text-decoration: underline; font-size: 0.8rem; }
.ct-card.ct-svc { cursor: default; }
.rc-panel { margin: 0 0 14px; padding: 12px; border: 1px solid var(--border); border-radius: 8px; }
.rc-panel table { width: 100%; }
.rc-panel td, .rc-panel th { vertical-align: top; }
.rc-ok { color: #38c6a8; } .rc-warn { color: #e5b454; } .rc-bad { color: var(--danger); }
.rc-plan { margin-top: 10px; padding: 10px; border-radius: 6px; border: 1px solid var(--border); }
.rc-plan.refused { border-color: var(--danger); }
.rc-plan.allowed { border-color: #38c6a8; }
.rc-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.rc-actions input { width: 7em; }

/* Agents -> Controller */
.ctl-target { white-space: pre-wrap; word-break: break-all; font-size: 12px; }
.ctl-table td { vertical-align: top; }
.ctl-quiet { opacity: 0.6; }
.ctl-approve label { margin-right: 12px; display: inline-block; margin-top: 6px; }
/* Review tab: one row per item, Done on the right */
.rv-item { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border, #2a2f3a); }
.rv-text { flex: 1; min-width: 0; }
.rv-title { font-weight: 600; }
.rv-done .rv-title { text-decoration: line-through; opacity: 0.6; }
.spark-wide { grid-column: 1 / -1; }
.spark-heat-ramp { display: inline-block; width: 90px; height: 8px; border-radius: 4px; align-self: center; background: linear-gradient(90deg, rgba(57,135,229,0.08), #3987e5); }
