/* manage.css -- the whole visual vocabulary for the management UI.
 *
 * Two halves:
 *   1. `.shell-*` / `#panel-root`  -- owned by the shell (manage.html). Panels
 *      must not use these.
 *   2. `.rmm-*`                    -- the FIXED vocabulary from the contract.
 *      Panels use ONLY these and carry no <style> of their own.
 *
 * Dark, dense, calm. Depth comes from spacing and the muted colour, not borders.
 */

:root {
  /* Palette from index.html -- re-declared here verbatim. */
  --bg: #0e1116;
  --panel: #161b22;
  --border: #2a323d;
  --text: #e6edf3;
  --muted: #8b949e;
  --accent: #2f81f7;
  --ok: #3fb950;
  --off: #6e7681;

  /* Additions beyond the contract palette: severity needs a red and an amber,
     and the raised surface matches index.html's agent-row background. */
  --err: #f85149;
  --warn: #d29922;
  --raised: #1b222b;

  /* CHROME vs CONTENT, ported from Fork A (H:/AutotaskRepo/docs/UI_THEMING.md).
     Chrome is the frame -- the header bar AND the side nav -- and it is ONE
     continuous surface. Content is everything the panels render into.

     The distinction is what stops a divider being drawn between the header and
     the sidebar: they are the same material, so a line between them cuts a
     surface in half rather than separating two things. The hairline belongs on
     the chrome's CONTENT edge, and nowhere else. */
  --chrome: var(--panel);
  --chrome-border: #2a323d;
  /* Interactive fill ON chrome. Never rgba(255,255,255,a): a white overlay only
     reads as "lighter" on a dark surface, and silently disappears the moment
     this palette gains a light profile. Fork A was bitten by exactly this. */
  --chrome-hover: #212a35;

  /* Elevation. A single token so depth stays consistent, and so a light profile
     can make it soft-and-visible rather than deep-and-invisible. */
  --shadow: rgba(0, 0, 0, 0.35);

  /* Content-side interaction, the counterparts to --chrome-hover. Named
     rather than inlined as white overlays for the same reason: a white tint
     only reads as "lighter" on a dark surface and inverts meaning on a light
     one. Zebra striping is deliberately far subtler than hover -- it separates
     rows without becoming a pattern you have to look past. */
  --stripe: #12171e;
  --hover: #1b222b;

  /* Must always equal --err as r,g,b, for the same reason as --accent-rgb. */
  --err-rgb: 248, 81, 73;
  /* Body text inside a danger panel: light enough to read on the tinted fill
     without being the saturated red of the ring itself. */
  --err-text: #ffd7d3;

  /* Must always equal --accent as r,g,b -- used for rgba() tints so accent
     washes track the accent colour instead of drifting from it. */
  --accent-rgb: 47, 129, 247;

  /* SHELL GEOMETRY -- single source of truth, ported from Fork A.
     The sidebar/topbar sizes and the notch curve ALL derive from these. Fork A
     learned this the hard way: a literal offset left behind after the navbar
     height changed clipped the notch. Change a dimension here, never inline. */
  --topbar-h: 52px;
  --sidebar-w: 208px;
  /* --notch MUST equal .shell-content's padding, or the curve is not tangent to
     the content edge and a straight band clips the corner. */
  --notch: 1.5rem;

  --ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, "Liberation Mono", monospace;
}

* { box-sizing: border-box; }

html, body { margin: 0; height: 100%; }

body {
  background: var(--bg);
  color: var(--text);
  font: 14px/1.4 var(--ui);
  display: flex;
  flex-direction: column;
  height: 100vh;
  /* The page itself never scrolls -- .rmm-scroll does. */
  overflow: hidden;
}

/* ---------------------------------------------------------------- shell ---- */

.shell-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  height: var(--topbar-h);
  padding: 0 16px;
  background: var(--chrome);
  /* No border-bottom. The sidebar directly below is the same chrome surface,
     and a line here would cut it in half. The chrome/content boundary is drawn
     once, by .shell-content. */
  min-width: 0;
}


.shell-title { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.shell-title h1 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline;
}
.rename-btn {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 16px;
  padding: 0 6px;
  vertical-align: middle;
  opacity: 0.7;
  transition: opacity 0.15s, color 0.15s;
}
.rename-btn:hover { opacity: 1; color: var(--accent, #4af); }
.shell-sub {
  font-size: 12px;
  color: var(--muted);
  font-family: var(--mono);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.quarantine-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  padding: 8px 12px;
  margin: 0 0 10px;
  font-size: 12px;
  color: var(--warn);
  background: rgba(210, 153, 34, 0.10);
  border: 1px solid rgba(210, 153, 34, 0.35);
  border-radius: 4px;
}
.quarantine-bar-title { font-weight: 600; font-size: 12px; }
.quarantine-bar-sub { font-size: 11px; color: var(--muted); flex-basis: 100%; }
.quarantine-bar-field {
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
}
.quarantine-bar .rmm-field {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
}
.quarantine-bar .approve-btn {
  padding: 2px 10px;
  font-size: 11px;
  background: var(--warn);
  color: var(--bg);
  border: none;
  border-radius: 3px;
  font-weight: 600;
  cursor: pointer;
}
.quarantine-bar .approve-btn:hover { filter: brightness(1.15); }

.shell-spacer { flex: 1 1 auto; min-width: 8px; }

.shell-state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}
.shell-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--off);
  flex: 0 0 auto;
}
.shell-state.up { color: var(--ok); }
.shell-state.up .shell-dot { background: var(--ok); }
.shell-state.bad { color: var(--err); }
.shell-state.bad .shell-dot { background: var(--err); }
.shell-state.warn { color: var(--warn); }
.shell-state.warn .shell-dot { background: var(--warn); }

/* Who is logged in (OIDC authenticated). Muted and small like a .shell-state,
   with the mono treatment the rest of the identity chrome uses for the UPN. */
.shell-who {
  font-size: 12px;
  color: var(--muted);
  font-family: var(--mono);
  white-space: nowrap;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.shell-who[hidden] { display: none; }

/* OIDC "Log in" affordance in the header (anonymous public-tier viewers). */
.shell-login {
  font-size: 12px;
  font-weight: 600;
  color: var(--accent, #4a9eff);
  text-decoration: none;
  padding: 4px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  white-space: nowrap;
}
.shell-login:hover { background: var(--panel); }
.shell-login[hidden] { display: none; }

.shell-admin-btn {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 10px;
  cursor: pointer;
  white-space: nowrap;
}
.shell-admin-btn:hover { color: var(--text); border-color: var(--accent); }
.shell-admin-btn[hidden] { display: none; }

.token-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
}
.token-overlay[hidden] { display: none; }
.token-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  width: min(90vw, 800px);
  max-height: 80vh;
  overflow-y: auto;
  padding: 16px 20px;
  box-shadow: 0 8px 32px var(--shadow);
}
.token-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.token-panel-head h2 {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}
.token-inactive { opacity: 0.45; }

/* Approvals panel */
.approvals-panel { max-width: 720px; }
.approvals-actions { display: flex; gap: 8px; align-items: center; }
.approvals-actions .approve-btn {
  padding: 4px 12px;
  font-size: 12px;
  background: var(--ok);
  color: var(--bg);
  border: none;
  border-radius: 3px;
  font-weight: 600;
  cursor: pointer;
}
.approvals-actions .approve-btn:disabled { opacity: 0.4; cursor: default; }
.approvals-actions .approve-btn:not(:disabled):hover { filter: brightness(1.15); }
.approvals-sort { display: flex; gap: 6px; align-items: center; padding: 6px 0; font-size: 12px; color: var(--muted); }
.approvals-sort select {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: 3px; font-size: 11px; padding: 2px 6px;
}
.approvals-row { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: 3px; }
.approvals-row:nth-child(even) { background: var(--stripe); }
.approvals-row:hover { background: var(--hover); }
.approvals-row input[type="checkbox"] { flex-shrink: 0; cursor: pointer; }
.approvals-name { font-size: 13px; font-weight: 500; min-width: 160px; }
.approvals-id { font-size: 11px; color: var(--muted); font-family: var(--mono); min-width: 120px; }
.approvals-company { font-size: 11px; color: var(--muted); flex: 1; }
.approvals-time { font-size: 11px; color: var(--muted); white-space: nowrap; }
.approvals-online { font-size: 11px; }
.approvals-online.up { color: var(--ok); }
.approvals-online.off { color: var(--off); }
.approvals-selectall { display: flex; align-items: center; gap: 6px; padding: 4px 8px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.approvals-selectall input[type="checkbox"] { cursor: pointer; }
.approvals-count { font-size: 12px; color: var(--muted); padding: 4px 0; }

/* ---- endpoint management panel ---- */
.endpoints-panel { max-width: 800px; }
.endpoints-actions { display: flex; gap: 8px; align-items: center; }
.endpoints-actions .retire-btn {
  background: var(--warn, #e0a030); color: #000; border: none; font-weight: 600;
}
.endpoints-actions .retire-btn:disabled { opacity: 0.4; cursor: default; }
.endpoints-actions .retire-btn:not(:disabled):hover { filter: brightness(1.15); }
.endpoints-actions .delete-btn {
  background: var(--danger, #c03030); color: #fff; border: none; font-weight: 600;
}
.endpoints-actions .delete-btn:disabled { opacity: 0.4; cursor: default; }
.endpoints-actions .delete-btn:not(:disabled):hover { filter: brightness(1.15); }
.endpoints-filter { display: flex; gap: 6px; align-items: center; padding: 6px 0; font-size: 12px; color: var(--muted); flex-wrap: wrap; }
.endpoints-filter select {
  background: var(--surface); color: inherit; border: 1px solid var(--border); border-radius: 3px; padding: 2px 4px; font-size: 12px;
}
.endpoints-row { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: 3px; }
.endpoints-row:nth-child(even) { background: var(--stripe); }
.endpoints-row:hover { background: var(--hover); }
.endpoints-row input[type="checkbox"] { flex-shrink: 0; cursor: pointer; }
.endpoints-row .ep-status { font-size: 10px; text-transform: uppercase; padding: 1px 6px; border-radius: 3px; font-weight: 600; }
.endpoints-row .ep-status.active { background: var(--ok, #30a060); color: #fff; }
.endpoints-row .ep-status.quarantined { background: var(--warn, #e0a030); color: #000; }
.endpoints-row .ep-status.retired { background: var(--muted, #666); color: #fff; }
.ep-reinstall-btn {
  margin-left: auto;
  flex-shrink: 0;
  background: none;
  border: 1px solid var(--muted, #666);
  color: var(--fg);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 3px;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s, border-color 0.15s;
}
.ep-reinstall-btn:hover { opacity: 1; border-color: var(--accent, #4af); color: var(--accent, #4af); }
.endpoints-selectall { display: flex; align-items: center; gap: 6px; padding: 4px 8px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.endpoints-selectall input[type="checkbox"] { cursor: pointer; }
.endpoints-count { font-size: 12px; color: var(--muted); padding: 4px 0; }

/* Installer dialog */
.installer-dialog {
  position: fixed; inset: 0; z-index: 1100;
  background: rgba(0,0,0,0.6);
  display: flex; align-items: center; justify-content: center;
}
.installer-dialog-inner {
  background: var(--bg, #1a1a2e);
  border: 1px solid var(--border, #333);
  border-radius: 8px;
  padding: 20px 24px;
  max-width: 640px;
  width: 90%;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
}
.installer-dialog h3 { margin: 0 0 4px; font-size: 15px; }
.installer-expires { font-size: 11px; color: var(--muted); margin: 0 0 16px; }
.installer-section { margin-bottom: 14px; }
.installer-section label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.installer-cmd {
  width: 100%; box-sizing: border-box;
  font-family: var(--mono); font-size: 11px;
  background: var(--stripe, #111); color: var(--fg);
  border: 1px solid var(--border, #333); border-radius: 4px;
  padding: 8px 10px; margin-bottom: 6px;
  cursor: text;
}
.installer-copy-btn, .installer-dl-btn {
  background: var(--accent, #4af); color: #000;
  border: none; border-radius: 4px;
  padding: 6px 14px; font-size: 12px; font-weight: 600;
  cursor: pointer;
}
.installer-copy-btn:hover, .installer-dl-btn:hover { opacity: 0.85; }
.installer-dl-btn { background: none; border: 1px solid var(--muted, #666); color: var(--fg); }
.installer-dl-btn:hover { border-color: var(--accent, #4af); color: var(--accent, #4af); }
.installer-close-btn {
  display: block; margin-top: 12px; margin-left: auto;
  background: none; border: 1px solid var(--border, #333); color: var(--muted);
  border-radius: 4px; padding: 4px 12px; font-size: 12px; cursor: pointer;
}
.installer-close-btn:hover { color: var(--fg); border-color: var(--fg); }

.shell-body {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
  min-width: 0;
}

.shell-nav {
  flex: 0 0 var(--sidebar-w);
  background: var(--chrome);
  /* No border-right either -- .shell-content casts the single chrome/content
     edge for both, as a shadow that can follow the notch curve. */
  padding: 10px 8px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
}

/* ---- topbar: panel tabs ---------------------------------------------------
   Tabs sit ON chrome, so the active one is marked by an underline meeting the
   content edge rather than a filled pill: it reads as the tab opening onto the
   panel below it, which is what a tab is. */
.shell-tabs {
  display: flex;
  align-items: stretch;
  gap: 2px;
  height: 100%;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.shell-tabs::-webkit-scrollbar { display: none; }

.shell-tab {
  display: flex;
  align-items: center;
  padding: 0 14px;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font: 13px/1 var(--ui);
  white-space: nowrap;
  cursor: pointer;
}
.shell-tab:hover { color: var(--text); background: var(--chrome-hover); }
/* Active tab: no underline -- emphasise with the accent colour, bolder + a touch
   larger, so the current panel reads at a glance. */
.shell-tab.active { color: var(--accent); font-weight: 700; font-size: 14px; }
/* Unavailable panels stay visible and keep their tooltip -- a real `disabled`
   attribute would swallow the hover and hide the reason WHY. */
.shell-tab[aria-disabled="true"] { color: var(--off); cursor: not-allowed; }
.shell-tab[aria-disabled="true"]:hover { background: none; color: var(--off); }

/* ---- sidebar: machines --------------------------------------------------- */

.shell-navgroup {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  padding: 10px 10px 4px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--off);
}
.shell-navgroup-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.shell-navgroup-count {
  flex-shrink: 0;
  font-size: 10px;
  text-transform: none;
  letter-spacing: normal;
  color: var(--muted);
  font-family: var(--mono);
}

.shell-navempty { padding: 12px 10px; color: var(--muted); font-size: 13px; }

.shell-machine {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 7px;
  padding: 7px 10px;
  color: var(--text);
  font: 13px/1.3 var(--ui);
  cursor: pointer;
}
.shell-machine:hover { background: var(--chrome-hover); }
.shell-machine.active {
  background: rgba(var(--accent-rgb), 0.14);
  box-shadow: inset 2px 0 0 var(--accent);
}
/* Offline machines stay listed and selectable: their details are still worth
   reading, and hiding them makes a fleet look smaller than it is. */
.shell-machine.off .shell-machinename { color: var(--muted); }
.shell-machine .shell-dot { background: var(--off); }
.shell-machine .shell-dot.up { background: var(--ok); }
.shell-machine .shell-dot.q { background: var(--warn); }
.shell-machine.quarantined .shell-machinename { color: var(--warn); }
.shell-machine.retired .shell-machinename { color: var(--err); opacity: 0.6; }

.shell-badge-q, .shell-badge-r {
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  padding: 1px 4px;
  border-radius: 3px;
  flex-shrink: 0;
}
.shell-badge-q { color: var(--bg); background: var(--warn); }
.shell-badge-r { color: var(--bg); background: var(--err); opacity: 0.7; }

.shell-machinerow { display: flex; align-items: center; gap: 7px; min-width: 0; }
.shell-machinename { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shell-machinesub {
  font-size: 11px;
  color: var(--off);
  font-family: var(--mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding-left: 15px;
}


.shell-content {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  /* Equals --notch: the curve is then tangent to the content's straight edges
     and no straight band clips the corner. */
  padding: var(--notch);

  /* The chrome/content boundary, drawn ONCE and from the content side.
     Tracing it here rather than on the header and sidebar is what lets the
     chrome read as a single continuous L-shape: it follows where chrome meets
     content and never crosses the join between them.

     Built from SHADOW ALONE -- no border. A 1px hairline has a square corner
     and cannot follow the notch's curve: it would be hidden for exactly the
     notch's width and then restart abruptly, which reads as two different
     corner radii meeting. The notch carries a matching inset shadow of its own,
     so the recess runs continuously around the curve instead of breaking at it.
     Depth from shadow, not from boxes drawn around things.

     The second inset (x=0) adds a little more weight on the TOP edge only.
     Both use --shadow so they track any future profile. */
  box-shadow: inset 7px 7px 12px -7px var(--shadow), inset 0 4px 8px -5px var(--shadow);
}

/* ------------------------------------------------------------- the notch ---
   Softens the join where the topbar, sidebar and content meet, and it is the
   detail that makes the chrome read as one folded surface rather than two
   strips meeting at a corner.

   Two FIXED squares stacked at the inside corner: a chrome-coloured fill, then
   a content-coloured square whose rounded top-left corner reveals the chrome
   beneath as a concave curve. border-radius anti-aliases cleanly, which a
   gradient would not.

   Fixed rather than a border-radius on the content, so it stays put instead of
   scrolling away with the content beneath it. */
body::before {
  content: "";
  position: fixed;
  top: var(--topbar-h);
  left: var(--sidebar-w);
  width: var(--notch);
  height: var(--notch);
  z-index: 2;
  background: var(--chrome);
  pointer-events: none;
}
body::after {
  content: "";
  position: fixed;
  top: var(--topbar-h);
  left: var(--sidebar-w);
  width: var(--notch);
  height: var(--notch);
  z-index: 3;
  background: var(--bg);
  border-top-left-radius: var(--notch);
  pointer-events: none;
  /* Lighter than the content's edge shadow: on a box this small the top and
     left insets converge and would otherwise read heavier than the straight
     edges they are meant to continue. */
  box-shadow: inset 4px 4px 9px -5px var(--shadow);
}

/* The notch is anchored to a fixed corner, so it only makes sense while the
   sidebar is beside the content. Stacked, there is no inside corner. */
@media (max-width: 700px) {
  body::before, body::after { display: none; }
}

/* The root a panel owns entirely. It is a flex column so `.rmm-toolbar` sits
   above a `.rmm-scroll` that fills the rest. */
#panel-root {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  min-width: 0;
  /* Safety net: if a panel renders tall content without wrapping it in
     .rmm-scroll it scrolls here rather than being clipped. When .rmm-scroll IS
     used it clamps to the available height, so this never produces a second
     scrollbar. */
  overflow: auto;
}

@media (max-width: 700px) {
  .shell-body { flex-direction: column; }
  .shell-nav {
    flex: 0 0 auto;
    flex-direction: row;
    /* Still no divider: stacked under the header, the nav is the same chrome
       surface it was beside it. */
    overflow-x: auto;
  }
  /* Chrome is entirely ABOVE the content once stacked, so the recess is
     horizontal only -- a left-hand shadow would imply an edge that is not
     there. */
  .shell-content {
    box-shadow: inset 0 4px 8px -5px var(--shadow);
  }
  /* Stacked, the machine list becomes a horizontal strip: names only, since
     there is no room for the agent id underneath. */
  .shell-machine { width: auto; white-space: nowrap; }
  .shell-machine .shell-machinesub { display: none; }
  .shell-navgroup { display: none; }
}

/* ------------------------------------------------- the panel vocabulary ---- */

/* Horizontal control strip above content. */
.rmm-toolbar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 13px;
  color: var(--muted);
}

/* <select> / <input> inside a toolbar. */
.rmm-field {
  background: var(--raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 8px;
  font: 13px/1.25 var(--ui);
  min-width: 0;
  max-width: 100%;
}
.rmm-field:hover:not(:disabled) { border-color: #3a4553; }
.rmm-field:focus { outline: none; border-color: var(--accent); }
.rmm-field:disabled { opacity: 0.5; cursor: not-allowed; }
.rmm-field option { background: var(--panel); color: var(--text); }
input.rmm-field::placeholder { color: var(--off); }

/* Buttons. */
.rmm-btn {
  background: var(--raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 12px;
  font: 13px/1.25 var(--ui);
  cursor: pointer;
  white-space: nowrap;
}
.rmm-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.rmm-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.rmm-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.rmm-btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  font-weight: 600;
}
.rmm-btn.primary:hover:not(:disabled) { filter: brightness(1.12); color: #ffffff; }

/* Flex-filling scroll container. Panels are height-constrained; this is the
   only thing on the page that scrolls. */
.rmm-scroll {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  overflow: auto;
  /* Reserve the scrollbar's column so content lays out to its LEFT instead of
     underneath it -- right-aligned data (metric %/size labels) was colliding
     with the scrollbar. */
  scrollbar-gutter: stable;
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  /* Inset content off the border and the reserved scrollbar. Horizontal only,
     so sticky table headers (top:0) are unaffected. */
  padding-inline: 12px;
  overscroll-behavior: contain;
}

/* System panel: keep the sys.info sheet compact (sized to its content, capped)
   instead of growing to fill, so the history chart below gets the room. Other
   panels keep the default flex:1 .rmm-scroll. */
.rmm-sys-sheet {
  flex: 0 0 auto;
  max-height: 42vh;
}

/* Optional side-by-side row (registry: tree beside values). NOT in the contract
   table -- provided in case a panel needs a split; safe to ignore. */
/* Data table: sticky header, zebra rows, monospace body (event messages and
   registry data both read better fixed-width). */
.rmm-table {
  width: 100%;
  border-collapse: collapse;
  font: 12px/1.45 var(--mono);
  table-layout: auto;
}
.rmm-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  text-align: left;
  padding: 8px 10px;
  font: 600 12px/1.2 var(--ui);
  color: var(--muted);
  white-space: nowrap;
}
.rmm-table tbody td {
  padding: 6px 10px;
  vertical-align: top;
  /* Long unbroken strings must wrap, never widen the page. */
  overflow-wrap: anywhere;
  word-break: break-word;
  border-top: 1px solid rgba(42, 50, 61, 0.5);
}
.rmm-table tbody tr:first-child td { border-top: 0; }
.rmm-table tbody tr:nth-child(even) { background: var(--stripe); }
.rmm-table tbody tr:hover { background: rgba(var(--accent-rgb), 0.08); }
.rmm-table td .rmm-badge { font-family: var(--ui); }

/* Two-column key/value list. Works as <dl><dt><dd>... or as a container whose
   direct children simply alternate key, value. */
.rmm-kv {
  display: grid;
  grid-template-columns: minmax(120px, max-content) minmax(0, 1fr);
  gap: 7px 20px;
  align-items: baseline;
  margin: 0;
  padding: 14px 16px;
}
.rmm-kv > * { margin: 0; min-width: 0; }
.rmm-kv > *:nth-child(odd) {
  color: var(--muted);
  font-size: 13px;
  white-space: nowrap;
}
.rmm-kv > *:nth-child(even) {
  font-family: var(--mono);
  font-size: 13px;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* Nested navigation list. Items work as <li>, <button>, <a> or <div>. */
.rmm-tree {
  list-style: none;
  margin: 0;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.rmm-tree .rmm-tree {
  padding: 2px 0 2px 10px;
  margin-left: 9px;
  border-left: 1px solid var(--border);
}
.rmm-tree-item {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 5px 8px;
  color: var(--text);
  font: 13px/1.35 var(--ui);
  text-decoration: none;
  cursor: pointer;
  overflow-wrap: anywhere;
}
.rmm-tree-item:hover { background: var(--hover); }
.rmm-tree-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.rmm-tree-item.active {
  background: rgba(var(--accent-rgb), 0.16);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.35);
}

/* Breadcrumb strip. Crumbs are chips, so no separator glyph is injected --
   a panel adding its own separators will not double up. */
.rmm-crumbs {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  min-width: 0;
  font-size: 12px;
  color: var(--muted);
}
.rmm-crumbs > * {
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 8px;
  color: var(--text);
  font: 12px/1.35 var(--mono);
  text-decoration: none;
  cursor: pointer;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.rmm-crumbs > *:hover { border-color: var(--accent); color: var(--accent); }
/* If a panel marks the current crumb `.active` (the only "active" idiom in the
   vocabulary), it reads as the current location rather than a link. */
.rmm-crumbs > .active,
.rmm-crumbs > .rmm-tree-item.active {
  background: rgba(var(--accent-rgb), 0.16);
  border-color: rgba(var(--accent-rgb), 0.35);
  box-shadow: none;
  color: var(--text);
}

/* The three non-content states. */
.rmm-empty,
.rmm-loading,
.rmm-error {
  flex: 0 0 auto;
  padding: 16px;
  font: 13px/1.5 var(--ui);
  border-radius: 8px;
  overflow-wrap: anywhere;
}
.rmm-empty { color: var(--muted); }
.rmm-loading { color: var(--muted); }
.rmm-loading::before {
  content: "";
  display: inline-block;
  width: 11px;
  height: 11px;
  margin-right: 8px;
  vertical-align: -1px;
  border-radius: 50%;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  animation: rmm-spin 0.8s linear infinite;
}
@keyframes rmm-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .rmm-loading::before { animation: none; }
}
.rmm-error {
  color: var(--err-text);
  background: rgba(var(--err-rgb), 0.10);
  border: 1px solid rgba(var(--err-rgb), 0.35);
  /* THE CORNER FIX. By default the background is painted under the border
     (background-clip: border-box). With BOTH the fill and the ring
     semi-transparent, the two alphas composite wherever they overlap -- and at
     a rounded corner the border's per-pixel coverage varies, so that composite
     shifts and the curve reads darker than the straight edges. Clipping the
     fill to the padding box means the ring is the only thing drawn there, and
     the corner matches the edges.

     The general rule, and the reason this is worth a comment: a translucent
     fill and a translucent border on the same rounded box will always seam
     unless the fill is clipped. Build the ring from ONE layer and keep the fill
     out from under it. */
  background-clip: padding-box;
}
.rmm-error .rmm-btn { margin-top: 8px; }

/* Severity pills. Base (no modifier) is neutral -- use it for Verbose/unknown. */
.rmm-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font: 600 11px/1.7 var(--ui);
  color: var(--muted);
  background: rgba(139, 148, 158, 0.16);
  white-space: nowrap;
  vertical-align: baseline;
}
.rmm-badge.info { color: #9ecbff; background: rgba(var(--accent-rgb), 0.16); }
.rmm-badge.warn { color: #e3b341; background: rgba(210, 153, 34, 0.18); }

/* Critical is its own tier: folding it into error made the two worst
   severities indistinguishable, which is the one distinction that matters
   when scanning a log. */
.rmm-badge.critical {
  color: #ffdcd7;
  background: rgba(var(--err-rgb), 0.22);
  border-color: rgba(var(--err-rgb), 0.55);
}
.rmm-badge.error { color: #ff9492; background: rgba(var(--err-rgb), 0.18); }

/* ------------------------------------------------------- the screen panel ---
   The live desktop. Unlike every other panel this one wants ALL the space it
   can get and must not scroll -- a scrollbar on a remote desktop means the
   operator is dragging to see what they should already be looking at. */
.rmm-screen-stage {
  flex: 1 1 auto;
  position: relative;
  min-height: 0;
  background: #000;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}

.rmm-screen {
  width: 100%;
  height: 100%;
  display: block;
  /* contain, not cover: cover would crop the endpoint's screen, and the missing
     strip is exactly where the taskbar and the thing you were asked to look at
     tend to be. The letterboxing this creates is corrected for in the pointer
     mapping. */
  object-fit: contain;
  background: #000;
  /* It takes keyboard focus to forward keystrokes, but a focus ring drawn over
     someone's desktop is noise -- the cursor and the live picture already say
     where input is going. */
  outline: none;
}

.rmm-screen-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 14px;
  padding: 24px;
  color: var(--muted);
  font-size: 13px;
  background: rgba(0, 0, 0, 0.55);
  pointer-events: none;
}
.rmm-screen-spinner {
  width: 28px;
  height: 28px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: rmm-spin 0.8s linear infinite;
}
@keyframes rmm-spin {
  to { transform: rotate(360deg); }
}

/* Monitor selector in the screen toolbar -- shown only when the endpoint reports
   more than one display. Sits inline with the "Live desktop" label + status. */
.rmm-monitor-select {
  max-width: 240px;
  margin-left: auto;   /* push it (and the status after) to the right of the label */
}

/* -------------------------------------------------------- the shell panel ---
   A transcript, not a terminal: line-oriented output with no ANSI handling.
   Styled to read like a console anyway, because that is what tells an operator
   what kind of thing they are looking at. */
.rmm-term {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: 10px 12px;
  overflow: auto;
  background: var(--sunken, #0b0e13);
  border: 1px solid var(--border);
  border-radius: 6px;
  font: 12px/1.45 var(--mono);
  color: var(--text);
  /* Output is untrusted endpoint text and is inserted with textContent, so it
     cannot inject markup -- but it can contain very long unbroken lines, which
     would otherwise force the whole panel to scroll sideways. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.rmm-term-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.rmm-term-prompt {
  font: 13px/1 var(--mono);
  color: var(--accent);
  user-select: none;
}

.rmm-term-input {
  flex: 1 1 auto;
  font: 12px/1.4 var(--mono);
}

/* ------------------------------------------------------- live metrics ---- */

.rmm-metrics {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.rmm-metrics-note {
  color: var(--muted);
  font-size: 12px;
}

.rmm-meter-row {
  display: grid;
  /* label | bar (fills the rest) | value | detail -- fixed columns for the
     first three so every row's bar starts at the same x regardless of label
     length ("CPU" vs "C:\"), which is what makes a stack of rows read as one
     comparable chart rather than four unrelated lines. */
  grid-template-columns: 56px 1fr 44px auto;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}

.rmm-meter-label {
  color: var(--muted);
  font-family: var(--mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rmm-meter {
  height: 8px;
  border-radius: 4px;
  background: var(--sunken, #0b0e13);
  overflow: hidden;
}

.rmm-meter-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--off);
  transition: width 0.3s ease;
}
/* Same three-tier tone as the severity badges: under 70% reads as healthy,
   70-90 worth a look, over 90 is the reason this tab got opened. */
.rmm-meter-fill.ok { background: var(--ok); }
.rmm-meter-fill.warn { background: var(--warn); }
.rmm-meter-fill.err { background: var(--err); }

.rmm-meter-value {
  text-align: right;
  font-family: var(--mono);
  color: var(--text);
}

.rmm-meter-detail {
  color: var(--off);
  font-family: var(--mono);
  font-size: 11px;
  white-space: nowrap;
}

/* -------------------------------------------------------------- history --- */

.rmm-history {
  /* Grows into the space freed by the compact sys.info sheet, so the chart is
     readable instead of a 44px sliver at the bottom. */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 4px;
}

/* The chart block owns the leftover vertical room; the axis sits under it. */
.rmm-history-chart {
  flex: 1 1 auto;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.rmm-history-label {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--off);
}

.rmm-avail-strip {
  display: flex;
  gap: 2px;
  height: 20px;
}

.rmm-avail-cell {
  flex: 1 1 0;
  border-radius: 2px;
  /* No state recorded for this bucket -- distinct from "known offline", not
     the same colour as a real outage. */
  background: var(--sunken, #0b0e13);
}
.rmm-avail-cell.up { background: var(--ok); }
.rmm-avail-cell.down { background: var(--err); }

/* The chart wrapper: the plot fills the available height, the time axis sits
   under it. */
.rmm-chart-wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* The plot area itself -- position:relative so the hover cursor line and the
   readout tooltip can be absolutely positioned over the SVG. */
.rmm-chart {
  flex: 1 1 auto;
  min-height: 120px;
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.rmm-spark {
  width: 100%;
  height: 100%;
  display: block;
}

.rmm-spark-grid {
  stroke: var(--border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0.5;
}

.rmm-spark-line {
  fill: none;
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}
.rmm-spark-line.cpu { stroke: var(--ok); }
.rmm-spark-line.ram { stroke: var(--accent); }

/* Hover: a vertical guide line under the cursor + a small readout tip. */
.rmm-chart-cursor {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--muted);
  opacity: 0.6;
  pointer-events: none;
}
.rmm-chart-tip {
  position: absolute;
  top: 6px;
  background: var(--sunken, #0b0e13);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 8px;
  font: 11px/1.5 var(--mono);
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}
.rmm-chart-tip-time { color: var(--muted); margin-bottom: 2px; }
.rmm-tip-k { font-weight: 600; }
.rmm-tip-cpu { color: var(--ok); }
.rmm-tip-ram { color: var(--accent); }

/* The time axis under the plot: 5 ticks across the range. */
.rmm-chart-axis {
  display: flex;
  justify-content: space-between;
  font: 10px/1 var(--ui);
  color: var(--muted);
  flex: 0 0 auto;
}
.rmm-chart-axis > span:first-child { text-align: left; }
.rmm-chart-axis > span:last-child { text-align: right; }

/* ---------------------------------------------------------- file jobs ----
   Batch downloads that run on the backend (backend/src/filejobs.ts). A list
   below the file listing, one row per running or finished job -- deliberately
   quiet when empty (no header, no empty-state), since most of the time there
   are none. */
.rmm-jobs {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
}
.rmm-jobs:empty { margin-top: 0; }

.rmm-jobs-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--sunken, #0b0e13);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
}

.rmm-jobs-detail { color: var(--muted); }
.rmm-jobs-detail.error { color: var(--err); }

.rmm-jobs-actions {
  margin-left: auto;
  display: flex;
  gap: 6px;
  align-items: center;
}
.rmm-jobs-actions a {
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
  font-size: 12px;
}
