/* TWAD console — deliberately framework-free. Dark sidebar, light content, no build step. */
* { box-sizing: border-box; margin: 0; }
:root {
  --sidebar-bg: #151b28;
  --sidebar-fg: #b8c1d1;
  --accent: #3d6df2;
  --accent-dark: #2d54c4;
  --accent-soft: #eaf0ff;
  --bg: #f5f6f9;
  --card: #ffffff;
  --border: #e3e6ec;
  --border-strong: #d3d8e0;
  --text: #1b2330;
  --muted: #69727f;
  --ok: #1d8a4a;
  --warn: #b58a1f;
  --bad: #c23b3b;
  --shadow-sm: 0 1px 2px rgba(20,28,45,.05);
  --shadow-md: 0 4px 16px rgba(20,28,45,.08);
}
body {
  display: flex; flex-direction: column; min-height: 100vh;
  font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--bg); color: var(--text);
}

/* The sidebar+main split. Banners live in <body> above this, so they take a full-width row of
   their own instead of becoming a third column that squashes the page. */
#shell { display: flex; flex: 1; min-height: 0; }

#sidebar {
  width: 220px; flex-shrink: 0; padding: 16px 12px 12px;
  background: var(--sidebar-bg); color: var(--sidebar-fg);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh;
  overflow-y: auto;
}
.brand { font-size: 19px; font-weight: 700; color: #fff; padding: 4px 10px 16px; letter-spacing: .2px; }
.brand-sub { display: block; font-size: 10px; font-weight: 400; opacity: .55; letter-spacing: .5px; margin-top: 3px; }

/* Grouped, AD-console style: a labelled section per area rather than one flat list of 18. */
.nav-group { margin-bottom: 14px; }
.nav-label {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .8px;
  color: rgba(255,255,255,.32); padding: 4px 10px 5px;
}
#sidebar a {
  display: block; padding: 7px 10px; margin: 1px 0; border-radius: 8px;
  color: var(--sidebar-fg); text-decoration: none; font-size: 13.5px; line-height: 1.3;
  transition: background .12s ease, color .12s ease;
}
#sidebar a:hover { background: rgba(255,255,255,.07); color: #fff; }
#sidebar a.active { background: var(--accent); color: #fff; font-weight: 600; box-shadow: 0 2px 6px rgba(0,0,0,.28); }
/* Pushed to the bottom with the footer, because signing out is not navigation and should not
   sit among the pages. There was no way to end a session at all before this — only clearing
   cookies. */
.sidebar-signout {
  margin-top: auto; padding: 8px 10px; font-size: 12px; opacity: .75;
  border-top: 1px solid rgba(255,255,255,.08);
}
.sidebar-signout:hover { opacity: 1; }
.sidebar-foot { padding: 10px; font-size: 10.5px; opacity: .4; }

#main { flex: 1; padding: 28px 34px; max-width: 1240px; }
h1 { font-size: 22px; font-weight: 650; letter-spacing: -.2px; margin-bottom: 4px; }
h2 { font-size: 15px; font-weight: 650; margin: 18px 0 8px; }
.sub { color: var(--muted); margin-bottom: 20px; }
.toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.spacer { flex: 1; }

table { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; box-shadow: var(--shadow-sm); }
th, td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--border); vertical-align: top; }
th { background: #fafbfd; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }
tr:last-child td { border-bottom: none; }
tr.clickable { cursor: pointer; transition: background .1s ease; }
tr.clickable:hover td { background: var(--accent-soft); }

.card { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 20px; margin-bottom: 16px; box-shadow: var(--shadow-sm); }
/* A card that is telling you something is not set up, rather than reporting on something that
   is. Bordered rather than filled, so it reads as a note and not as an error. */
.card.warn { border-color: var(--warn); border-left-width: 4px; }
.card.warn h2 { color: var(--warn); }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
dl.facts { display: grid; grid-template-columns: 160px 1fr; row-gap: 6px; }
dl.facts dt { color: var(--muted); }
dl.facts dd { word-break: break-all; }

button, .btn, .button {
  font: inherit; font-weight: 500; padding: 8px 15px; border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card); color: var(--text); cursor: pointer; text-decoration: none;
  display: inline-block; line-height: 1.2;
  transition: background .12s ease, border-color .12s ease, color .12s ease, box-shadow .12s ease, transform .04s ease;
}
button:hover, .btn:hover { border-color: var(--accent); color: var(--accent); background: #f7f9ff; }
button:active, .btn:active { transform: translateY(1px); }
button:focus-visible, .btn:focus-visible { outline: 2px solid rgba(61,109,242,.4); outline-offset: 1px; }
button:disabled, .btn:disabled { opacity: .5; cursor: default; transform: none; }
button.primary {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: 0 1px 2px rgba(61,109,242,.35);
}
button.primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); color: #fff; }
/* Lower-priority action: reads as available without competing with the primary button. */
button.secondary {
  background: transparent; border-color: var(--border); color: var(--muted); box-shadow: none;
}
button.secondary:hover { background: #eef1f6; border-color: var(--border); color: var(--text); }
button.danger { color: var(--bad); }
button.danger:hover { border-color: var(--bad); background: #fdf2f2; color: var(--bad); }
button.small { padding: 4px 11px; font-size: 12px; }

/* A segmented row of view toggles (Active / Revoked, Saved script / One-off). Grouped tight so
   they read as one control rather than two loose buttons. */
.tabs { display: inline-flex; gap: 6px; align-items: center; }

/* Sub-navigation across the pages of one area (the Directory: Users / Groups / Delegation /
   Org units), so they read as sections of one place rather than four separate screens. */
.subnav { display: flex; gap: 6px; align-items: center; margin: 0 0 20px; padding-bottom: 14px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.subnav-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px; color: var(--muted); margin-right: 8px; }
.subnav button.subnav-active { background: var(--accent-soft); border-color: #cfe0ff; color: var(--accent-dark); font-weight: 600; box-shadow: none; }

input, select, textarea {
  font: inherit; padding: 8px 11px; border: 1px solid var(--border); border-radius: 8px;
  background: #fff; color: var(--text); max-width: 100%;
  transition: border-color .12s ease, box-shadow .12s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(61,109,242,.18);
}
textarea { width: 100%; font-family: ui-monospace, monospace; font-size: 12px; }

/* Text inputs and selects fill their container rather than sitting at the browser's default
   text-box width, which on a roomy card or form truncates the value behind a box a third its
   length. Everything but checkboxes, radios and the search box — those keep their own sizing. */
input:not([type=checkbox]):not([type=radio]):not(.searchbox), select { width: 100%; box-sizing: border-box; }

/* The script editor's code field: a real editor look — dark, monospace, roomy, and no wrap so
   long lines scroll rather than fold (like Tactical RMM's editor). */
textarea.code-editor {
  background: #10151f; color: #e6e9f0; border-color: #2a3242;
  min-height: 360px; font-size: 13px; line-height: 1.55; tab-size: 2; white-space: pre; overflow: auto;
}
textarea.code-editor:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(61,109,242,.28); }
textarea.code-editor::placeholder { color: #5b6678; }
label.field { display: block; margin-bottom: 10px; }
label.field > span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 3px; }

/* The help line sits under its box, so it reads as guidance for the field just filled in
   rather than a heading for the next one. */
label.field > span.help {
  margin: 4px 0 0; font-size: 12px; color: var(--muted); line-height: 1.45;
}
span.req { color: var(--bad); font-weight: 700; }

.badge { display: inline-block; padding: 1px 9px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.badge.Active { background: #e2f4e9; color: var(--ok); }
.badge.Pending { background: #fbf3dd; color: var(--warn); }
.badge.Revoked, .badge.Wiped, .badge.Failed, .badge.Expired { background: #fbe4e4; color: var(--bad); }
.badge.Sent, .badge.Running { background: #e4ecfb; color: var(--accent-dark); }
.badge.Succeeded { background: #e2f4e9; color: var(--ok); }
.badge.neutral { background: #eceef2; color: var(--muted); }

/* Package and compliance states. Without these the badge renders unstyled, which reads as
   "no state" rather than as the state it is. */
.badge.Installed, .badge.Detected, .badge.Compliant { background: #e2f4e9; color: var(--ok); }
.badge.Installing { background: #e4ecfb; color: var(--accent-dark); }
.badge.Uninstalled { background: #eceef2; color: var(--muted); }
.badge.NonCompliant { background: #fbe4e4; color: var(--bad); }
.badge.Unknown { background: #eceef2; color: var(--muted); }

.pin-display {
  font: 700 34px ui-monospace, monospace; letter-spacing: 4px; text-align: center;
  padding: 18px; background: #f0f4ff; border: 2px dashed var(--accent); border-radius: 10px; margin: 12px 0;
  user-select: all;
}
dialog {
  border: 1px solid var(--border); border-radius: 14px; padding: 24px; min-width: 420px; max-width: 640px;
  box-shadow: 0 24px 60px rgba(15,23,42,.28);
}
dialog::backdrop { background: rgba(15,23,42,.45); }

/* Remote control is not a form in a box. It is somebody's whole screen, and a 640px dialog
   in the corner of a 27" monitor is a magnifying glass held at arm's length. This one takes
   the window, and the Fullscreen button takes the display. */
dialog.remote-control {
  width: 96vw; max-width: 96vw; height: 94vh; padding: 12px;
  display: flex; flex-direction: column;
}
dialog.remote-control .screen {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  background: #0b1220; border-radius: 6px; overflow: hidden;
}
dialog.remote-control canvas {
  /* contain, not fill: a remote 16:9 screen shown at 4:3 is a screen where nothing is where
     the operator points. */
  max-width: 100%; max-height: 100%; object-fit: contain;
}
/* No fullscreen rules: the button is gone (it never worked reliably on a modal dialog, by
   the API or by a CSS fallback). Popping the session into its own window is the answer, and
   that is the .popout rule below. */

/* In its own window there is nothing else on screen to leave room for, so it takes all of it. */
dialog.remote-control.popout {
  width: 100vw; max-width: 100vw; height: 100vh; border-radius: 0; margin: 0; border: 0;
}
body.popout #sidebar, body.popout .sidebar, body.popout .topbar { display: none; }
body.popout main { padding: 0; }
dialog h2 { margin-top: 0; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

.setting-editor { border: 1px solid var(--border); border-radius: 8px; padding: 12px; margin-bottom: 10px; background: #fafbfd; }
.setting-editor .head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.setting-editor .head .key { font-family: ui-monospace, monospace; font-size: 12px; color: var(--muted); }
.setting-elements { margin-top: 8px; padding-left: 12px; border-left: 3px solid var(--border); }
.mono { font-family: ui-monospace, monospace; font-size: 12px; }
.muted { color: var(--muted); }
.error-text { color: var(--bad); margin: 8px 0; }
.ok-text { color: var(--ok); margin: 8px 0; }

/* Explanatory paragraph at the top of a card, above the thing it explains. */
.hint { color: var(--muted); font-size: 13px; line-height: 1.5; margin: 0 0 12px; }

/* A checkbox and its label on one line — the permission picker, where a stacked
   label-above-control layout would read as nine unrelated fields. */
.check-row { display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 13px; }
.check-row input { width: auto; margin: 0; }
pre.output { background: #10151f; color: #d5dbe8; padding: 10px 12px; border-radius: 6px; font-size: 12px; overflow-x: auto; white-space: pre-wrap; }
.provenance { font-size: 12px; color: var(--muted); margin-top: 4px; padding-left: 10px; border-left: 2px solid var(--border); }
.tree-row { display: flex; gap: 8px; align-items: center; padding: 5px 6px; border-radius: 6px; }
.tree-row:hover { background: var(--accent-soft); }
.tree-row > a { color: var(--text); text-decoration: none; font-weight: 500; cursor: pointer; }
.tree-row > a:hover { color: var(--accent); text-decoration: underline; }
/* Fixed width so the names line up whether or not a node has children — a tree whose labels
   jitter by one character per level is one nobody can scan down. */
.twisty {
  width: 22px; padding: 0; text-align: center; font-family: ui-monospace, monospace;
  background: none; border: 1px solid var(--border); border-radius: 4px; cursor: pointer;
}
.twisty:disabled { border-color: transparent; color: var(--muted); cursor: default; }
ul.plain { list-style: none; padding-left: 0; margin: 6px 0; }
ul.plain li { padding: 3px 0; }
.searchbox { min-width: 260px; }

/* The registry browser's key list: a scrolling column beside the values, like regedit's. */
.reg-keys {
  max-height: 50vh; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px;
  padding: 6px; font-family: ui-monospace, monospace; font-size: 12px;
}
.reg-keys .clickable { padding: 2px 4px; border-radius: 4px; }
.reg-keys .clickable:hover { background: #eef2ff; }

/* The catalog browser: Group Policy Editor's shape. Tree on the left, settings on the right,
   both scrolling independently so picking a deep category does not scroll the tree away. */
dialog.wide { width: 92vw; max-width: 1200px; }
.catalog-browser { display: grid; grid-template-columns: 320px 1fr; gap: 14px; }
.catalog-tree, .catalog-results {
  height: 56vh; overflow: auto; border: 1px solid var(--border); border-radius: 6px; padding: 8px;
}
.catalog-tree .tree-row { padding: 2px 0; font-size: 13px; }
.catalog-tree .tree-row.selected { background: #e4ecfb; border-radius: 4px; }

/* A popout is opened to do one thing; a second copy of the navigation is just less room. */
body.popout #sidebar, body.popout .sidebar { display: none; }
body.popout main { padding: 16px; }

@media (max-width: 900px) {
  .catalog-browser { grid-template-columns: 1fr; }
  .catalog-tree { height: 30vh; }
}

/* ---- The terminal -------------------------------------------------------------------------
   A grid of character cells, so everything a shell draws lines up: a table from `ps`, a
   progress bar, the box-drawing an editor puts round a menu. That needs a monospace font AND
   `white-space: pre` — the moment a space collapses or a line wraps on its own, every column
   after it is in the wrong place and the screen looks corrupt. */
.terminal-host { flex: 1; min-height: 0; }

.terminal {
  background: #1c1c1c;
  color: #d3d7cf;
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.25;
  padding: 8px 10px;
  border-radius: 10px;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  outline: none;
  /* Selecting output to copy it is half of what a terminal is for. */
  user-select: text;
}

.terminal:focus-visible { box-shadow: inset 0 0 0 2px var(--accent, #3465a4); }

.terminal-row { white-space: pre; }

/* History is written once and never touched again; only the live screen below it is rebuilt
   each frame. Redrawing five thousand lines of scrollback sixty times a second, which is what
   a build scrolling past would cost, is the difference between a terminal and a slideshow. */
.terminal-history[hidden] { display: none; }

/* Measured, not assumed: the cell size depends on the font the viewer's machine actually
   resolved, and guessing it wrongly means the far end is told the wrong window size. */
.terminal-probe { position: absolute; visibility: hidden; white-space: pre; }

/* The popout is the terminal and nothing else, so the screen takes the height that is left.
   Scoped to the terminal popouts: the registry and file browsers are their own layouts and a
   full-height flex column would fight them. */
body.terminal-popout main { display: flex; flex-direction: column; height: 100vh; padding: 12px; }
.terminal-toolbar { flex: 0 0 auto; }
.terminal-shell { min-width: 8rem; }

/* ---- The licence banner --------------------------------------------------------------------
   Above everything, on every page, with no close button. A lapsed licence is the one thing here
   that has to be acted on outside this console, and a banner that can be dismissed is one that
   gets dismissed on day one and never seen again -- which is how a cluster reaches Locked
   without anybody having noticed Expired. */
.licence-banner {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 10px 16px;
  background: #fff3cd;
  color: #6b5200;
  border-bottom: 1px solid #e6cf7a;
  font-size: 14px;
}

.licence-banner.locked { background: #fbe9e7; color: #7f1d1d; border-bottom-color: #e4b4ad; }
.licence-banner a { color: inherit; font-weight: 600; }

/* The popout windows are one thing on purpose -- a terminal, a file browser -- and a banner
   across the top of a shell somebody is working in helps nobody. */
body.popout .licence-banner { display: none; }

/* ---- Managed clients -----------------------------------------------------------------------
   The stripe across the top of a client panel (the console served under /clients/{id}/). It is
   the one visual cue that this window is somebody else's directory, so it stays put and cannot
   be closed -- an MSP technician with six tabs open needs to know which one bites. */
.client-proxy-banner {
  position: sticky;
  top: 0;
  z-index: 101;
  padding: 8px 16px;
  background: #e4ecfb;
  color: #1e3a6e;
  border-bottom: 1px solid #b9cdf2;
  font-size: 13px;
}

.badge.Detached, .badge.Unreachable, .badge.Locked { background: #fbe4e4; color: var(--bad); }
.badge.Paid { background: #e2f4e9; color: var(--ok); }
.badge.Free { background: #eceef2; color: var(--muted); }
