:root {
  --bg: #1c1a17;
  --fg: #f3f0e8;
  --muted: #a8a29e;
  --faint: #78716c;
  --line: #3a3631;
  --code: #2a2723;
  --code2: #34302a;
  --codefg: #d6d3d1;
  --hover: #24211d;
  --accent: #fb923c;
  --accent-solid: #ea580c;
  --accent-solid-hover: #c2410c;
  --accent-fg: #fff7ed;
  --err: #fca5a5;
  --ok: #86efac;
  --overlay: rgba(12, 11, 9, 0.72);
  --shadow: 0 40px 80px -20px rgba(0, 0, 0, 0.6);
}

:root[data-theme="light"] {
  --bg: #f3f0e8;
  --fg: #1c1a17;
  --muted: #57534e;
  --faint: #78716c;
  --line: #e2dccf;
  --code: #ede8dd;
  --code2: #e2dccf;
  --codefg: #1c1a17;
  --hover: #faf8f3;
  --accent: #c2410c;
  --accent-solid: #ea580c;
  --accent-solid-hover: #c2410c;
  --accent-fg: #fff7ed;
  --err: #b91c1c;
  --ok: #15803d;
  --overlay: rgba(28, 26, 23, 0.4);
  --shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.25);
}

* { box-sizing: border-box; }
html, body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Geist', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
a.link { color: var(--accent); }
a.link:hover { text-decoration: underline; }
code, .mono { font-family: 'Geist Mono', monospace; }

.shell {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 48px);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

header.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 72px;
  font-size: 13px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  gap: 12px;
}
.brand { display: flex; align-items: center; gap: 10px; font-size: 16px; letter-spacing: -0.02em; }
.brand .mark {
  width: 26px; height: 26px; border-radius: 7px; background: var(--code2);
  display: flex; align-items: center; justify-content: center; color: var(--accent); font-weight: 600; font-size: 13px;
}
.brand b { font-weight: 600; }
.brand .dim { color: var(--muted); }
nav.main { display: flex; align-items: center; gap: 20px; color: var(--muted); }
nav.main a:hover { color: var(--accent); }

.iconbtn {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--line); border-radius: 8px;
  background: transparent; color: var(--fg); cursor: pointer;
}
.iconbtn:hover { border-color: var(--accent); }

main.content { flex: 1; padding: 36px 0 64px; display: flex; flex-direction: column; gap: 28px; }

h1 { margin: 0; font-size: clamp(26px, 4vw, 34px); font-weight: 600; letter-spacing: -0.03em; }
h2 { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.02em; }
p.lead { color: var(--muted); margin: 0; font-size: 14px; }

.page-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 38px; padding: 0 16px; border-radius: 9px; border: 1px solid var(--line);
  background: transparent; color: var(--fg); font-family: inherit; font-size: 13.5px;
  cursor: pointer; white-space: nowrap;
}
.btn:hover { border-color: var(--accent); }
.btn-primary { border: none; background: var(--accent-solid); color: var(--accent-fg); font-weight: 500; }
.btn-primary:hover { background: var(--accent-solid-hover); }
.btn-danger { border: 1px solid var(--err); color: var(--err); background: transparent; }
.btn-danger:hover { background: var(--err); color: var(--bg); }
.btn-sm { height: 30px; padding: 0 12px; font-size: 12.5px; border-radius: 7px; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

.card {
  border: 1px solid var(--line); border-radius: 14px; background: var(--bg);
  padding: 20px; display: flex; flex-direction: column; gap: 10px;
}
.cards-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%,280px), 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
}
.cards-grid > a, .cards-grid > div.tile {
  background: var(--bg); padding: 20px; display: flex; flex-direction: column; gap: 10px; min-width: 0;
}
.cards-grid > a:hover { background: var(--hover); }
.tile-label { font-family: 'Geist Mono', monospace; font-size: 11px; color: var(--faint); }
.tile-title { font-size: 18px; font-weight: 600; letter-spacing: -0.02em; }
.tile-sub { font-size: 13px; color: var(--muted); }

.statusdot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; }
.statusdot.ok { background: var(--ok); }
.statusdot.bad { background: var(--err); }
.statusdot.warn { background: var(--accent); }

table.tbl { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.tbl th {
  text-align: left; font-family: 'Geist Mono', monospace; font-size: 11px; font-weight: 500;
  color: var(--faint); text-transform: uppercase; letter-spacing: 0.04em;
  padding: 10px 14px; border-bottom: 1px solid var(--line);
}
table.tbl td { padding: 12px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
table.tbl tr:last-child td { border-bottom: none; }
table.tbl tbody tr:hover { background: var(--hover); }
.tbl-wrap { border: 1px solid var(--line); border-radius: 14px; overflow: hidden; overflow-x: auto; }

/* table.tbl normally sizes columns by content, which falls apart as
   soon as a cell's content wraps (a .chip-row full of badges): the
   browser measures the row of badges at its unwrapped width first, so
   that one column balloons and crowds or misaligns every other column
   in the table, worse the more badges a row has. table-layout: fixed
   plus explicit widths on exactly the badge-bearing columns keeps every
   column's width stable regardless of how many badges end up wrapped
   inside it. */
table.tbl.tbl-fixed { table-layout: fixed; }
table.tbl.tbl-fixed .col-user { width: 160px; }
table.tbl.tbl-fixed .col-group { width: 150px; }
table.tbl.tbl-fixed .col-badges { width: 240px; }
table.tbl.tbl-fixed .col-actions { width: 48px; }
/* Narrow categorical/numeric columns (capture results, etc.): without
   an explicit width, auto table layout stretches them unevenly across
   whatever space is left over once the widest column (usually an IP or
   hostname) is sized, leaving odd, inconsistent gaps between columns.
   Fixing these narrow and leaving the IP/hostname column unclassed (so
   it absorbs the rest) keeps the row visually even regardless of how
   short the numbers in it are. */
table.tbl.tbl-fixed .col-proto { width: 90px; }
table.tbl.tbl-fixed .col-port { width: 90px; }
table.tbl.tbl-fixed .col-num { width: 130px; }
/* Unlike col-badges, a username/group name is one unbroken run of
   text with nowhere to wrap, so it needs its own clipping — scoped to
   just this column, not the blanket rule that used to clip badges too. */
table.tbl.tbl-fixed .col-user { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* No overflow:hidden here on purpose: a .chip-row of badges wraps to
   however many lines it needs instead of overflowing sideways, so
   clipping was never needed to keep it in its column — and it was
   actively harmful, slicing the rounded border off any badge that
   didn't fully fit before wrapping. */

.badge {
  display: inline-flex; align-items: center; gap: 6px; font-family: 'Geist Mono', monospace;
  font-size: 11px; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line); color: var(--muted);
}
.badge.accent { color: var(--accent); border-color: var(--accent); }
.badge-removable { cursor: pointer; background: none; font: inherit; }
.badge-removable:hover { color: var(--err); border-color: var(--err); }
.chip-row { display: flex; gap: 6px; flex-wrap: wrap; min-width: 0; }
.select-sm {
  width: 100%; font-size: 12.5px; padding: 5px 8px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--code); color: var(--fg);
}

form.stack { display: flex; flex-direction: column; gap: 14px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 12.5px; color: var(--muted); }
.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px,1fr)); gap: 14px; }
input, select {
  height: 40px; padding: 0 12px; border: 1px solid var(--line); border-radius: 9px;
  background: var(--code); color: var(--fg); font-family: inherit; font-size: 14px; outline: none;
}
input:focus, select:focus { border-color: var(--accent); }
input::placeholder { color: var(--faint); }
label.check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--fg); cursor: pointer; }
label.check input { width: 16px; height: 16px; padding: 0; }
.hint { font-size: 12px; color: var(--faint); }

.flash { padding: 12px 16px; border-radius: 10px; font-size: 13.5px; border: 1px solid var(--line); }
.flash.error { border-color: var(--err); color: var(--err); }
.flash.ok { border-color: var(--ok); color: var(--ok); }

.kv { display: flex; flex-direction: column; }
.kv-row { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.kv-row:last-child { border-bottom: none; }
.kv-row .k { color: var(--faint); }
.kv-row .v { text-align: right; overflow-wrap: anywhere; font-family: 'Geist Mono', monospace; }

pre.codeblock {
  background: var(--code); color: var(--codefg); border-radius: 10px; padding: 14px 16px;
  font-family: 'Geist Mono', monospace; font-size: 12.5px; overflow-x: auto; white-space: pre-wrap; word-break: break-all;
}

.modal-overlay {
  position: fixed; inset: 0; z-index: 20; display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(40px, 10vh, 100px) 16px 16px; background: var(--overlay); backdrop-filter: blur(4px);
}
.modal {
  width: 100%; max-width: 560px; background: var(--bg); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow); overflow: hidden; max-height: 86vh; display: flex; flex-direction: column;
}
.modal-head { display: flex; justify-content: space-between; align-items: center; padding: 18px 20px 0; flex: none; }
.modal-head span { font-size: 16px; font-weight: 600; letter-spacing: -0.02em; }
.modal-body { padding: 16px 20px 20px; overflow-y: auto; }

footer.pagefoot {
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; padding: 18px 0;
  border-top: 1px solid var(--line); font-family: 'Geist Mono', monospace; font-size: 11.5px; color: var(--faint);
}

.center-screen { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
.auth-card { width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: 20px; }
.auth-card .card { gap: 18px; }

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.right { text-align: right; }
.row-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

/* A table row's actions collapse into one menu button instead of a
   stack of individual buttons, which is what was making every row in
   node_detail's tables as tall as its longest action list. The menu
   itself is positioned with JS (position: fixed, computed from the
   trigger button's own position on open) rather than relying on CSS
   absolute positioning, because .tbl-wrap clips vertical overflow to
   keep the table's square corners from poking out of its rounded
   border — an ordinary absolutely-positioned menu over a bottom row
   would get cut off by that same clipping. */
.dropdown { display: inline-block; }
.dropdown-toggle { width: 30px; height: 30px; padding: 0; font-size: 16px; line-height: 1; }
.dropdown-menu {
  display: none; flex-direction: column; gap: 2px;
  position: fixed; z-index: 30; min-width: 150px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--shadow); padding: 6px;
}
.dropdown-menu.open { display: flex; }
.dropdown-menu form { margin: 0; }
.dropdown-menu button, .dropdown-menu a {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border-radius: 7px;
  border: none; background: none; color: var(--fg); font-family: inherit; font-size: 13px; cursor: pointer;
}
.dropdown-menu button:hover, .dropdown-menu a:hover { background: var(--hover); }
.dropdown-menu button.danger, .dropdown-menu a.danger { color: var(--err); }

@media (max-width: 640px) {
  .page-head { flex-direction: column; }
  .row-actions { justify-content: flex-start; }
}
