/* DigiTS Release Manager -- shared shell + Excel-like grid */
:root {
  --bg: #f1f5f9;
  --panel: #ffffff;
  --ink: #0f172a;
  --ink-soft: #475569;
  --ink-faint: #94a3b8;
  --line: #dbe2ea;
  --line-hard: #c3ccd8;
  --brand: #0b63c5;
  --brand-dark: #084a94;
  --brand-soft: #e7f1fc;
  --ok: #15803d;
  --ok-soft: #dcfce7;
  --warn: #b45309;
  --warn-soft: #fef3c7;
  --bad: #b91c1c;
  --bad-soft: #fee2e2;
  --sel: #cfe3fb;
  --head: #1f3b57;
  --radius: 6px;
  --shadow: 0 1px 2px rgba(15, 23, 42, .08), 0 8px 24px rgba(15, 23, 42, .06);
  --mono: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
}

* { box-sizing: border-box; }

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

body {
  background: var(--bg);
  color: var(--ink);
  font: 13px/1.45 "Segoe UI", Roboto, system-ui, sans-serif;
  display: flex;
  flex-direction: column;
}

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------------------------------------------------------------- topbar */
.topbar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 14px;
  height: 46px;
  background: var(--head);
  color: #fff;
  flex: 0 0 auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  font-size: 14px;
  letter-spacing: .2px;
  white-space: nowrap;
}

.brand .logo {
  width: 24px; height: 24px;
  border-radius: 5px;
  background: linear-gradient(140deg, #38bdf8, #0b63c5);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700;
}

.nav { display: flex; gap: 2px; margin-left: 6px; }

.nav a {
  color: #cbd5e1;
  padding: 6px 12px;
  border-radius: var(--radius);
  font-weight: 500;
}

.nav a:hover { background: rgba(255, 255, 255, .1); color: #fff; text-decoration: none; }
.nav a.active { background: var(--brand); color: #fff; }

.topbar .spacer { flex: 1; }

.userbox { display: flex; align-items: center; gap: 7px; font-size: 12px; color: #cbd5e1; }
.userbox select {
  background: rgba(255, 255, 255, .12);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: var(--radius);
  padding: 4px 6px;
  font-size: 12px;
  max-width: 190px;
}
.userbox select option { color: #0f172a; }

/* ---------------------------------------------------------------- layout */
main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 12px 14px 14px;
  gap: 12px;
  overflow: auto;
}

/* The grid panel is meant to absorb all remaining height (flex: 1) and scroll
 * its own rows internally, so the page itself normally has nothing left to
 * scroll. But on a tall/high-res screen the flex children's combined natural
 * height can still exceed the viewport (a wrapped filter/toolbar row, a wide
 * saved-filters list, browser chrome, OS scaling…), and with overflow:hidden
 * that excess was simply unreachable — no scrollbar, nothing to click.
 * overflow-y:auto is a no-op in the normal case (nothing to scroll, so no
 * scrollbar appears) and a safety net in the tall-content case. */
main.fixed { overflow-y: auto; overflow-x: hidden; }

.page-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* The hops of a pipeline, offered as the choice a release actually makes.
 * One button per adjacent pair of stages: DEV > UAT, UAT > PROD. */
.hops { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.hops .hop {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px 5px 7px;
  background: #fff;
  border: 1px solid var(--line-hard);
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
}
.hops .hop:hover { background: var(--brand-soft); border-color: var(--brand); }
.hops .hop.active {
  background: var(--brand-soft);
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}
.hops .hop.quiet:not(.active) { opacity: .72; }
.hops .hop .step {
  padding: 2px 9px;
  border-radius: 999px;
  color: #fff;
  font-size: 11px;
  font-weight: 650;
}
.hops .hop-arrow { color: var(--ink-faint); font-size: 11px; }
.hops .hop-count {
  font-size: 11px;
  font-weight: 600;
  color: var(--brand-dark);
  margin-left: 2px;
}
.hops .hop-count.none { color: var(--ink-faint); font-weight: 500; }
.page-head h1 { font-size: 17px; margin: 0; font-weight: 650; }
.page-head .sub { color: var(--ink-soft); font-size: 12px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.panel > header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  font-size: 12.5px;
  color: var(--ink);
  background: #f8fafc;
  border-radius: var(--radius) var(--radius) 0 0;
  flex-wrap: wrap;
}

.panel > header .spacer { flex: 1; }
.panel .body { padding: 12px; }
.panel .body.tight { padding: 0; }

.grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 1100px) { .grid2, .grid3 { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------- controls */
button, .btn {
  font: inherit;
  font-size: 12px;
  padding: 5px 11px;
  border-radius: var(--radius);
  border: 1px solid var(--line-hard);
  background: #fff;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

button:hover, .btn:hover { background: #f1f5f9; text-decoration: none; }
button:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.btn-primary, button.primary, .btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 550;
}
.btn-primary:hover, button.primary:hover, .btn.primary:hover {
  background: var(--brand-dark);
}

button.danger { color: var(--bad); border-color: #f3c9c9; }
button.danger:hover { background: var(--bad-soft); }
button.ghost { border-color: transparent; background: transparent; }
button.ghost:hover { background: #eef2f7; }
/* .btn.sm as well, because a download is a link and not a button -- it has to
   be an <a href> for the browser to save the file, and it should not be the one
   oversized control in a row of small ones. */
button.sm, .btn.sm { padding: 3px 8px; font-size: 11.5px; }

/* The file picker's tree. Rows rather than a nested list: the indent is drawn
   from the depth, so one flat pass renders any depth and nothing reflows when a
   folder deep in the tree is opened. */
.ftree { font-size: 12.5px; padding: 4px 0; }
.ftrow {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 10px 3px 0;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.ftrow:hover { background: var(--bg); }
.ftrow.picked { background: var(--brand-soft); }
.ftrow.byparent { opacity: .75; }
.ftcaret {
  width: 18px; min-width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; padding: 0;
  color: var(--ink-faint); font-size: 11px; cursor: pointer;
}
.ftcaret:hover { background: none; color: var(--ink); }
.fticon { font-size: 12px; }
.ftname { font-family: var(--mono); }
.ftname.isdir { cursor: pointer; font-weight: 550; }
.ftname.isdir:hover { text-decoration: underline; }
.ftmeta { margin-left: auto; color: var(--ink-faint); font-size: 11px; padding-left: 16px; }
.ftrow.fterr { color: var(--bad); font-size: 11.5px; white-space: normal; }

/* The numbered walk-through in the agent install dialog. */
.steps { margin: 10px 0 0; padding-left: 20px; display: grid; gap: 9px; }
.steps li { font-size: 12.5px; line-height: 1.45; }
.steps code {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 4px 7px;
  font-size: 11.5px;
  user-select: all;
}

/* A switch rather than an action: pressed reads as on, and stays on. */
button.toggle[aria-pressed="true"] {
  background: var(--brand-soft);
  border-color: var(--brand);
  color: var(--brand-dark);
  font-weight: 600;
}
button.toggle[aria-pressed="true"]:hover { background: #d7e7fb; }

input, select, textarea {
  font: inherit;
  font-size: 12.5px;
  padding: 5px 7px;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  background: #fff;
  color: var(--ink);
  max-width: 100%;
}

input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--brand-soft);
  border-color: var(--brand);
}

textarea { font-family: var(--mono); font-size: 12px; resize: vertical; }
label.field { display: flex; flex-direction: column; gap: 3px; font-size: 11.5px; color: var(--ink-soft); }
label.field > span { font-weight: 550; }
label.inline { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; }

.toolbar {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}

/* A checkbox that lines up with the drop-downs beside it: the label sits on the
 * same baseline as every other field caption, the box under it where a control
 * would be. */
label.field.check .checkline {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 28px;
  font-weight: 400;
  white-space: nowrap;
  cursor: pointer;
}
label.field.check input { margin: 0; cursor: pointer; }
/* label.field sets display:flex, which outranks the browser's own
 * [hidden] { display: none } -- so hiding one has to be said explicitly. */
label.field[hidden] { display: none; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  background: #eef2f7;
  color: var(--ink-soft);
  border: 1px solid var(--line);
}

.chip .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.chip.ok { background: var(--ok-soft); color: var(--ok); border-color: #bbf7d0; }
.chip.warn { background: var(--warn-soft); color: var(--warn); border-color: #fde68a; }
.chip.bad { background: var(--bad-soft); color: var(--bad); border-color: #fecaca; }

.tabs { display: flex; gap: 3px; flex-wrap: wrap; justify-content: flex-end; }
.tabs button {
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-soft);
  font-weight: 550;
  padding: 5px 12px;
}
.tabs button:hover { background: #eef2f7; }
.tabs button.active { background: var(--brand-soft); border-color: #bfdbfe; color: var(--brand-dark); }

.pipeline { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.pipeline .step {
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 650;
  color: #fff;
}
.pipeline .arrow { color: var(--ink-faint); font-size: 11px; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.kpi { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 11px 13px; box-shadow: var(--shadow); }
.kpi .n { font-size: 22px; font-weight: 680; line-height: 1.1; }
.kpi .l { font-size: 11px; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .5px; margin-top: 2px; }

.empty { padding: 26px; text-align: center; color: var(--ink-faint); font-size: 12.5px; }

/* ---------------------------------------------------------------- tables */
table.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
table.tbl th {
  text-align: left;
  background: #f8fafc;
  color: var(--ink-soft);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .4px;
  padding: 7px 9px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 2;
}
table.tbl td { padding: 6px 9px; border-bottom: 1px solid #eef2f7; vertical-align: top; }
table.tbl tbody tr:hover { background: #f8fbff; }
table.tbl td.num, table.tbl th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.tbl td.actions { white-space: nowrap; text-align: right; }
.mono { font-family: var(--mono); font-size: 11.5px; }

/* ---------------------------------------------------------------- the grid */
.gridwrap {
  flex: 1 1 auto;
  min-height: 260px;
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  position: relative;
}

table.xl {
  border-collapse: separate;
  border-spacing: 0;
  font-size: 12px;
  table-layout: fixed;
  width: max-content;
  min-width: 100%;
}

table.xl th, table.xl td {
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 0;
  overflow: hidden;
  background-clip: padding-box;
}

table.xl thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: #eaf2fb;
  color: #12324e;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .35px;
  padding: 6px 7px;
  text-align: left;
  border-bottom: 1px solid var(--line-hard);
  white-space: nowrap;
  cursor: default;
}

table.xl thead th.env {
  text-align: center;
  background: #dfeaf6;
}

table.xl thead th.rowhead, table.xl tbody td.rowhead {
  position: sticky;
  left: 0;
  z-index: 4;
  background: #eaf2fb;
  text-align: center;
  width: 34px;
  min-width: 34px;
}

table.xl tbody td.rowhead {
  z-index: 2;
  background: #f3f7fb;
  color: var(--ink-faint);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

table.xl tbody td.rowhead.picked { background: var(--brand-soft); color: var(--brand-dark); }

/* A picked row is a whole-row selection -- Del deletes it -- so the whole line
 * is tinted rather than just its number, and a bar down the row number says
 * where the block starts and ends. The green applied ticks keep their own
 * colour: the tint sits behind them, not over them. */
table.xl tbody tr.picked > td.cell { background: #e8f1fd; }
table.xl tbody tr.picked > td.cell.envcell.yes { background: #dff0e6; }
table.xl tbody tr.picked > td.rowhead.picked {
  box-shadow: inset 3px 0 0 var(--brand);
  font-weight: 700;
}

/* The corner square selects every row on screen, so it reads as a button. */
table.xl thead th.rowhead.selall { cursor: pointer; }
table.xl thead th.rowhead.selall:hover { background: var(--brand-soft); color: var(--brand-dark); }
table.xl thead th.rowhead.selall.picked { background: var(--brand-soft); color: var(--brand-dark); }

table.xl tbody tr.newrow td { background: #fcfdff; }
table.xl tbody tr.saving td.cell { box-shadow: inset 0 -2px 0 var(--brand); }
table.xl tbody tr.err td.cell { background: var(--bad-soft) !important; }

td.cell {
  cursor: cell;
  height: 25px;
  max-height: 25px;
  position: relative;
}

td.cell .v {
  padding: 4px 7px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
  min-height: 24px;
}

td.cell.multiline .v {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-soft);
}

td.cell.ro { background: #f8fafc; color: var(--ink-soft); cursor: default; }

/* A released row is the record of what went out, so the whole line reads as
 * frozen: a hatched row number, flat cells and no hover anywhere in it. The
 * applied ticks stay green -- just muted -- because that is the information
 * the row exists to carry. */
table.xl tbody tr.locked td.cell {
  background: #f7f8fa;
  color: var(--ink-soft);
  cursor: default;
}
table.xl tbody tr.locked td.cell.envcell.yes {
  background: #edf7f0;
  color: var(--ok);
}
table.xl tbody tr.locked td.rowhead.lockhead {
  background: repeating-linear-gradient(135deg, #eef1f5 0 3px, #e3e8ef 3px 6px);
  color: var(--ink-faint);
}
td.cell.sl .v { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
td.cell.date .v { font-variant-numeric: tabular-nums; }
td.cell.inrange { background: var(--sel) !important; }
td.cell.active { outline: 2px solid var(--brand); outline-offset: -2px; z-index: 1; background: #fff; }
td.cell.dirty::after {
  content: "";
  position: absolute;
  top: 0; right: 0;
  border: 4px solid transparent;
  border-top-color: var(--warn);
  border-right-color: var(--warn);
}

td.cell input.editor, td.cell select.editor, td.cell textarea.editor {
  width: 100%;
  height: 100%;
  min-height: 24px;
  border: 0;
  outline: none;
  padding: 3px 6px;
  font: inherit;
  border-radius: 0;
  background: #fff;
}

td.cell textarea.editor {
  position: absolute;
  top: 0; left: 0;
  width: 420px;
  height: 150px;
  z-index: 30;
  border: 2px solid var(--brand);
  box-shadow: var(--shadow);
  font-family: var(--mono);
  font-size: 11.5px;
  resize: both;
}

td.envcell {
  text-align: center;
  cursor: default;
  user-select: none;
  width: 62px;
  min-width: 62px;
}

td.envcell .v { padding: 4px 0; font-weight: 700; }
td.envcell.yes { background: var(--ok-soft); color: var(--ok); }
td.envcell.no { color: var(--ink-faint); }
td.envcell.stale { background: var(--warn-soft); color: var(--warn); }

/* The SL number is tinted by change type, so the ALL tab reads at a glance. */
tr.type-TABLE td.cell.sl .v,
tr.type-ALTER td.cell.sl .v   { color: #7c3aed; }
tr.type-INDEX td.cell.sl .v   { color: #9333ea; }
tr.type-VIEW td.cell.sl .v    { color: #0891b2; }
tr.type-FUNC td.cell.sl .v    { color: #0d9488; }
tr.type-TRIGGER td.cell.sl .v { color: #c026d3; }
tr.type-QUERY td.cell.sl .v,
tr.type-DATA td.cell.sl .v    { color: #b45309; }
tr.type-FILE td.cell.sl .v    { color: #0369a1; }

.gridstatus {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 11.5px;
  color: var(--ink-soft);
  padding: 2px 2px 0;
  flex-wrap: wrap;
}

.gridstatus kbd {
  font-family: var(--mono);
  font-size: 10.5px;
  background: #fff;
  border: 1px solid var(--line-hard);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 0 4px;
}

/* ---------------------------------------------------------------- modal */
.modal-back {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, .45);
  display: grid;
  place-items: center;
  z-index: 100;
  padding: 20px;
}

.modal {
  background: var(--panel);
  border-radius: 8px;
  box-shadow: 0 24px 60px rgba(15, 23, 42, .3);
  width: min(880px, 100%);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}

.modal > header {
  padding: 12px 15px;
  border-bottom: 1px solid var(--line);
  font-weight: 650;
  display: flex;
  align-items: center;
  gap: 10px;
}

.modal > header .spacer { flex: 1; }
.modal > .body { padding: 15px; overflow: auto; display: flex; flex-direction: column; gap: 12px; }
.modal > footer { padding: 11px 15px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; background: #f8fafc; border-radius: 0 0 8px 8px; }
/* The confirm dialog opens with its finishing button already focused so Enter
 * settles it. A mouse raised that dialog, so :focus-visible would not match --
 * the ring has to hang off :focus to be seen at all. */
.modal > footer button:focus { outline: none; box-shadow: 0 0 0 3px var(--brand-soft); }
.modal > footer button.danger:focus { box-shadow: 0 0 0 3px var(--bad-soft); }

pre.script {
  margin: 0;
  padding: 12px;
  background: #0f172a;
  color: #e2e8f0;
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  overflow: auto;
  max-height: 52vh;
  white-space: pre;
}

/* ---------------------------------------------------------------- toast */
#toasts {
  position: fixed;
  right: 14px;
  bottom: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
}

.toast {
  background: #0f172a;
  color: #fff;
  padding: 9px 13px;
  border-radius: var(--radius);
  font-size: 12.5px;
  box-shadow: var(--shadow);
  max-width: 380px;
  animation: pop .16s ease-out;
}

.toast.ok { background: #14532d; }
.toast.err { background: #7f1d1d; }
.toast.warn { background: #78350f; }

@keyframes pop { from { transform: translateY(6px); opacity: 0; } to { transform: none; opacity: 1; } }

.sortable-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  margin-bottom: 5px;
}

.sortable-item .seq {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand-dark);
  display: grid; place-items: center;
  font-size: 10.5px; font-weight: 700;
}

.sortable-item .grow { flex: 1; }
.hint { font-size: 11.5px; color: var(--ink-faint); }
.warnbar { background: var(--warn-soft); border: 1px solid #fde68a; color: #7c4a06; padding: 8px 11px; border-radius: var(--radius); font-size: 12px; }

/* ----------------------------------------------------------- busy buttons */
/* A button that has to fetch something before it can show anything. The label
 * is hidden rather than replaced, so the button keeps the exact width the text
 * gave it and nothing on the toolbar moves -- a row of buttons that reflows
 * every time one is pressed is its own kind of broken.
 *
 * pointer-events is belt and braces: the handler refuses a second call anyway,
 * but the cursor should stop saying the button is worth clicking. */
button.is-busy, .btn.is-busy {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
button.is-busy::after, .btn.is-busy::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 13px;
  height: 13px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .4);
  border-top-color: #fff;
  animation: btn-spin .6s linear infinite;
}
/* The light buttons: a white spinner on a white face is nothing at all. */
button.is-busy:not(.primary):not(.danger)::after,
.btn.is-busy:not(.primary):not(.danger)::after {
  border-color: rgba(15, 23, 42, .18);
  border-top-color: var(--ink-soft);
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  button.is-busy::after, .btn.is-busy::after {
    animation-duration: 1.6s;
  }
}

/* ------------------------------------------------------------- progress bar */
/* Shown while a pipeline run is going. The counted part is real -- it comes
 * from the items the server has already recorded -- and the stripes are the
 * part that says "still working" between two items, which on a batch scripted
 * across a WAN can be several seconds apart. Without that, a truthful bar that
 * sits still looks exactly like a page that has hung. */
.progress {
  height: 8px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
  margin: 8px 0 5px;
}
.progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--brand);
  /* The width is set from the item count, so it must ease into its new value
     rather than jump -- a bar that steps in eight visible jerks reads as eight
     separate stalls. */
  transition: width .45s cubic-bezier(.4, 0, .2, 1);
  background-image: linear-gradient(
    120deg,
    rgba(255, 255, 255, .28) 25%, transparent 25%,
    transparent 50%, rgba(255, 255, 255, .28) 50%,
    rgba(255, 255, 255, .28) 75%, transparent 75%);
  background-size: 22px 22px;
  animation: progress-stripes 900ms linear infinite;
}
.progress-fill.done { animation: none; background-image: none; }
.progress-fill.bad { background-color: var(--bad); }
@keyframes progress-stripes {
  from { background-position: 0 0; }
  to   { background-position: 22px 0; }
}
/* Somebody who has asked not to see motion still gets the bar and the count;
   only the part that moves for its own sake is dropped. */
@media (prefers-reduced-motion: reduce) {
  .progress-fill { animation: none; transition: none; }
}
.progress-line {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 12px;
  color: var(--ink-soft);
}
.progress-line .count { font-weight: 600; color: var(--ink); }
/* Tabular figures so a ticking clock does not shuffle the text beside it every
   second as the digit widths change. */
.progress-line .elapsed {
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  white-space: nowrap;
}
.progress-line .what {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: ui-monospace, Consolas, monospace;
  color: var(--ink-faint);
}

/* frozen SL column (sits right after the row header) */
table.xl thead th.slh { position: sticky; left: 34px; z-index: 5; }
table.xl tbody td.cell.sl {
  position: sticky;
  left: 34px;
  z-index: 1;
  background: #fdfefe;
  border-right: 1px solid var(--line-hard);
}
table.xl tbody td.cell.sl.active { z-index: 6; }

/* the grid panel eats the remaining viewport height */
.panel.grow {
  flex: 1 1 auto;
  /* A floor, not zero.
   *
   * This needs to be *some* explicit value so the panel is allowed to shrink
   * below its natural height -- that is what lets the rows scroll inside it
   * rather than the whole page growing. But it must not be zero, because the
   * children have floors of their own (.gridwrap is 260px, plus this panel's
   * header and its pager). Given zero, a short viewport squeezes the panel's
   * box below its own content; the content then paints outside the box, and
   * whatever follows the panel is laid out against the shrunken box and lands
   * on top of it. On the register that put the keyboard hints over the pager,
   * and since the hints come later in the DOM they swallowed the clicks -- the
   * page-back arrows looked dead.
   *
   * 360px = the grid's 260 floor + this panel's header + the pager, with a
   * little headroom. Past that the page scrolls (main has overflow:auto),
   * which is the honest outcome: the content genuinely does not fit.
   */
  min-height: 360px;
  display: flex;
  flex-direction: column;
}
.panel.grow > .gridwrap {
  border: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: none;
  flex: 1 1 auto;
}

/* ---------------------------------------------------------- dropdowns */
/* The app-wide dropdown (see RM.enhance in app.js). The real <select> stays
   in the DOM, hidden, and drives everything. */
.ms {
  position: relative;
  display: inline-flex;
  vertical-align: middle;
  min-width: 0;
}

select.ms-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  pointer-events: none;
}

.ms-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  min-height: 29px;
  padding: 5px 8px 5px 10px;
  font: inherit;
  font-size: 12.5px;
  text-align: left;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}

.ms-btn:hover:not(:disabled) { background: #fbfdff; border-color: #a3b3c6; }
.ms-btn:focus-visible { outline: none; }
.ms-btn:focus-visible,
.ms.open .ms-btn {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
  background: #fff;
}
.ms-btn:disabled { background: #f4f7fa; color: var(--ink-faint); cursor: not-allowed; }
.ms.is-placeholder .ms-main { color: var(--ink-faint); }

.ms-label {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.ms-label .ms-main {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.ms-label .ms-swatch { align-self: center; }

.ms-sub {
  color: var(--ink-faint);
  font-size: 11px;
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ms-caret {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--ink-faint);
  transition: transform .2s cubic-bezier(.2, .8, .3, 1);
}
.ms-caret svg { display: block; width: 100%; height: 100%; }
.ms.open .ms-caret { transform: rotate(180deg); color: var(--brand); }

.ms-menu {
  position: fixed;
  z-index: 500;
  padding: 5px;
  background: #fff;
  border: 1px solid rgba(15, 23, 42, .07);
  border-radius: 10px;
  box-shadow: 0 2px 4px rgba(15, 23, 42, .06),
              0 12px 20px -6px rgba(15, 23, 42, .16),
              0 28px 56px -16px rgba(15, 23, 42, .26);
  max-height: 340px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  overscroll-behavior: contain;
  transform-origin: top center;
  animation: ms-drop .16s cubic-bezier(.2, .8, .3, 1);
}

.ms-menu.flip { transform-origin: bottom center; }

/* a long list gets a search box and, when it takes several answers, All/None */
.ms-list { overflow-y: auto; overscroll-behavior: contain; min-height: 0; }
.ms-head {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 1px 1px 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 5px;
}
.ms-search {
  width: 100%;
  font: inherit;
  font-size: 12px;
  padding: 4px 8px;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
}
.ms-search:focus { outline: none; border-color: var(--brand); }
.ms-bulks { display: flex; align-items: center; gap: 5px; }
.ms-bulk {
  padding: 2px 8px;
  font-size: 11px;
  border-radius: var(--radius);
}
.ms-count {
  margin-left: auto;
  font-size: 11px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.ms-none { padding: 10px 8px; font-size: 11.5px; color: var(--ink-faint); }

@keyframes ms-drop {
  from { opacity: 0; transform: translateY(-5px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.ms-opt {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px 7px 8px;
  border-radius: 7px;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  transition: background-color .1s ease;
}

.ms-opt + .ms-opt { margin-top: 1px; }
.ms-opt.hi { background: #eef4fb; }
.ms-opt[aria-selected="true"] {
  background: var(--brand-soft);
  color: var(--brand-dark);
}
.ms-opt[aria-selected="true"] .ms-main { font-weight: 650; }

/* multi-select: the ticks stay, so the menu reads as a checklist */
.ms-opt.picked { background: var(--brand-soft); }
.ms-opt.picked.hi { background: #dbe9fa; }
.ms-more {
  flex: 0 0 auto;
  margin-left: 5px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand-dark);
  font-size: 10px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ms-opt[aria-selected="true"].hi { background: #d8e8fa; }
.ms-opt.disabled { color: var(--ink-faint); cursor: not-allowed; }
.ms-opt.placeholder .ms-main { color: var(--ink-faint); font-style: italic; }
.ms-opt .ms-main { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis;
                   white-space: nowrap; }
.ms-opt .ms-sub { flex: 1 1 auto; }

.ms-tick {
  flex: 0 0 auto;
  width: 13px;
  height: 13px;
  color: var(--brand);
  opacity: 0;
  transform: scale(.7);
  transition: opacity .12s ease, transform .12s ease;
}
.ms-tick svg { display: block; width: 100%; height: 100%; }
.ms-opt[aria-selected="true"] .ms-tick { opacity: 1; transform: none; }

.ms-swatch {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px rgba(15, 23, 42, .12);
}

/* dark topbar variant */
.topbar .ms-btn {
  background: rgba(255, 255, 255, .12);
  border-color: rgba(255, 255, 255, .22);
  color: #fff;
}
.topbar .ms-btn:hover:not(:disabled) { background: rgba(255, 255, 255, .2); }
.topbar .ms.open .ms-btn,
.topbar .ms-btn:focus-visible {
  background: rgba(255, 255, 255, .2);
  border-color: #7dd3fc;
  box-shadow: 0 0 0 3px rgba(56, 189, 248, .25);
}
.topbar .ms-sub { color: #a8c3dc; }
.topbar .ms-caret { color: #cbd5e1; }
.topbar .ms.open .ms-caret { color: #7dd3fc; }

/* filter row: dropdowns stretch like the inputs beside them */
.toolbar .ms, label.field .ms { width: 100%; }
label.field .ms-btn { min-height: 28px; }

/* an auto-generated, read-only field */
input.auto-value {
  background: #f4f7fa;
  color: var(--ink-soft);
  font-family: var(--mono);
  letter-spacing: .3px;
  cursor: default;
}
input.auto-value:focus { outline: none; border-color: var(--line-hard); box-shadow: none; }
.field-note { font-size: 10.5px; color: var(--ink-faint); font-weight: 400; }

/* -------------------------------------------------------- date picker */
.dp {
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  min-width: 0;
  background: #fff;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  transition: border-color .15s ease, box-shadow .15s ease;
}

input.dp-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  pointer-events: none;
}

.dp-text {
  flex: 1;
  min-width: 0;
  width: 100%;
  min-height: 27px;
  padding: 4px 2px 4px 9px;
  border: 0;
  border-radius: var(--radius) 0 0 var(--radius);
  background: transparent;
  font-variant-numeric: tabular-nums;
  letter-spacing: .2px;
}
.dp-text:focus { outline: none; box-shadow: none; border: 0; }

.dp:focus-within, .dp.open {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
.dp.bad { border-color: var(--bad); box-shadow: 0 0 0 3px var(--bad-soft); }

.dp-btn {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  min-height: 27px;
  padding: 0;
  border: 0;
  border-left: 1px solid transparent;
  border-radius: 0 var(--radius) var(--radius) 0;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color .15s ease, background-color .15s ease;
}
.dp-btn svg { width: 14px; height: 14px; display: block; }
.dp-btn:hover { background: #eff5fc; color: var(--brand); }
.dp.open .dp-btn { color: var(--brand); }
.dp-btn:disabled { color: #cbd5e1; cursor: not-allowed; background: transparent; }

.toolbar .dp, label.field .dp { width: 100%; }

/* the calendar itself */
.cal {
  position: fixed;
  z-index: 500;
  width: 258px;
  padding: 9px;
  background: #fff;
  border: 1px solid rgba(15, 23, 42, .07);
  border-radius: 12px;
  box-shadow: 0 2px 4px rgba(15, 23, 42, .06),
              0 12px 20px -6px rgba(15, 23, 42, .16),
              0 28px 56px -16px rgba(15, 23, 42, .26);
  animation: ms-drop .16s cubic-bezier(.2, .8, .3, 1);
  user-select: none;
}

.cal-head {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 6px;
}

.cal-title { flex: 1; text-align: center; }

.cal-month {
  padding: 4px 10px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  font-size: 12.5px;
  font-weight: 650;
  color: var(--ink);
}
.cal-month:hover { background: #eff5fc; color: var(--brand-dark); }

.cal-nav {
  width: 26px;
  height: 26px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: 17px;
  line-height: 1;
}
.cal-nav:hover { background: #eff5fc; color: var(--brand); }

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}

.cal-dow {
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 3px 0 5px;
}

.cal-day {
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  display: grid;
  place-items: center;
  transition: background-color .1s ease, color .1s ease;
}
.cal-day:hover { background: #eff5fc; }
.cal-day.out { color: #cbd5e1; }
.cal-day.today { font-weight: 700; box-shadow: inset 0 0 0 1px var(--line-hard); }
.cal-day.cur { box-shadow: inset 0 0 0 2px var(--brand); }
.cal-day.sel {
  background: var(--brand);
  color: #fff;
  font-weight: 650;
  box-shadow: none;
}
.cal-day.sel:hover { background: var(--brand-dark); }

.cal-foot {
  display: flex;
  align-items: center;
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid var(--line);
}

.cal-link {
  padding: 3px 9px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink-soft);
  font-size: 11.5px;
  font-weight: 600;
}
.cal-link:hover { background: #eff5fc; color: var(--brand-dark); }
.cal-link.strong { color: var(--brand); }

/* ------------------------------------------- dropdowns inside grid cells */
td.cell .ms { width: 100%; height: 100%; }

td.cell .ms-btn {
  min-height: 24px;
  padding: 2px 4px 2px 6px;
  border: 0;
  border-radius: 0;
  background: #fff;
  box-shadow: inset 0 0 0 2px var(--brand);
  font-size: 12px;
}
td.cell .ms-btn:hover:not(:disabled) { background: #fff; }
td.cell .ms-label .ms-main { font-weight: 500; }
td.cell .ms-label .ms-sub { display: none; }   /* no room in a 25px cell */
td.cell .ms-caret { width: 12px; height: 12px; color: var(--brand); }

/* cells that are picked from a list rather than typed */
td.cell.pick .v { padding-right: 15px; }
td.cell.pick::before {
  content: "";
  position: absolute;
  right: 5px;
  top: 50%;
  margin-top: -2px;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid var(--ink-faint);
  opacity: .5;
  transition: opacity .12s ease, border-top-color .12s ease;
  pointer-events: none;
}
td.cell.pick:hover::before { opacity: 1; border-top-color: var(--brand); }
td.cell.pick.active::before { opacity: 1; border-top-color: var(--brand); }

/* --------------------------------------------------- setup section sub-nav */
.subnav {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  flex: 0 0 auto;
}

.subnav a.btn {
  border-color: transparent;
  background: transparent;
  color: var(--ink-soft);
  font-weight: 550;
  padding: 6px 13px;
}

.subnav a.btn:hover { background: #e9eff6; color: var(--ink); text-decoration: none; }

.subnav a.btn.active {
  background: var(--panel);
  border-color: var(--line);
  color: var(--brand-dark);
  box-shadow: var(--shadow);
}

.subnav .navcount {
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: #dde5ee;
  color: var(--ink-soft);
  font-size: 10.5px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.subnav a.btn.active .navcount { background: var(--brand-soft); color: var(--brand-dark); }

/* a master list scrolls inside its panel, so the page itself never grows */
.listwrap {
  flex: 1 1 auto;
  min-height: 200px;
  overflow: auto;
}

.panel.grow > .listwrap { border-radius: 0 0 var(--radius) var(--radius); }


/* ------------------------------------------------------- the data table */
/* Every list in the app is an RMTable: a filter bar, the rows, and a pager.
   Only the rows scroll, so the controls stay reachable in a long list. */
.dt {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.dt-fill { flex: 1 1 auto; }

/* a host that hands its height to the table (a .panel.grow body, say) */
.dt-host {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
}

.dt-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  background: #fbfdff;
}

.dt-spacer { flex: 1 1 auto; min-width: 4px; }

.dt-searchbox {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 180px;
  flex: 0 1 280px;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  background: #fff;
  padding: 0 7px;
}

.dt-searchbox:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.dt-searchbox .dt-icon { color: var(--ink-faint); font-size: 14px; line-height: 1; }

input.dt-q {
  border: 0;
  outline: none;
  padding: 5px 0;
  background: transparent;
  width: 100%;
  min-width: 0;
  font-size: 12.5px;
}

input.dt-q:focus { outline: none; box-shadow: none; border: 0; }
input.dt-q.on { font-weight: 600; }

.dt-shown {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  background: #eef2f7;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 8px;
}

select.dt-size { font-size: 11.5px; padding: 4px 6px; }

.dt-scroll {
  overflow: auto;
  min-height: 0;
  flex: 1 1 auto;
  position: relative;
}

.dt-scroll > table.tbl { min-width: 100%; }

/* two sticky header rows: the labels, then the drop-down filters */
.dt table.tbl thead tr.dt-head th {
  top: 0;
  z-index: 4;
  height: 28px;
  box-sizing: border-box;
  white-space: nowrap;
}

.dt table.tbl thead tr.dt-filters th {
  position: sticky;
  top: 28px;
  z-index: 3;
  background: #f3f7fb;
  padding: 3px 5px;
  border-bottom: 1px solid var(--line-hard);
  text-transform: none;
  letter-spacing: 0;
}

.dt th.sortable { cursor: pointer; user-select: none; }
.dt th.sortable:hover { background: #eef4fb; color: var(--brand-dark); }
.dt th.sorted { color: var(--brand-dark); }
.dt .dt-sort { font-size: 8px; margin-left: 4px; vertical-align: 1px; }

.dt-filters select.dt-filter { width: 100%; min-width: 70px; font-size: 11px; }
.dt-filters .ms { width: 100%; }
.dt-filters .ms-btn {
  min-height: 23px;
  padding: 1px 5px 1px 7px;
  font-size: 11px;
  background: #fff;
}
.dt-filters .ms.on .ms-btn {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand-dark);
  font-weight: 600;
}
.dt-filters .ms-caret { width: 13px; height: 13px; }
.dt-filters .ms-sub { display: none; }

.dt-empty { border-bottom: 1px solid var(--line); }

.dt-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 6px 10px;
  border-top: 1px solid var(--line);
  background: #fbfdff;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.dt-count { font-variant-numeric: tabular-nums; }

.dt-pager { display: flex; align-items: center; gap: 4px; }
.dt-pager button.dt-nav {
  min-width: 26px;
  justify-content: center;
  padding: 2px 6px;
  font-size: 13px;
  line-height: 1.2;
}

.dt-pageno {
  padding: 0 8px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

/* inside a modal the table gets a frame of its own */
.modal .dt {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

/* a table dropped straight into a panel body keeps the panel's corners */
.panel .body.tight > .dt > .dt-bar:first-child { border-radius: 0; }

/* ------------------------------------------------- change register extras */
/* One header row, spreadsheet style: the name sorts, the funnel at the right
   filters. This replaced a second row of twenty "all" drop-downs, which cost
   25px on every screen to say nothing. */
table.xl thead tr.xlhead th { height: 26px; box-sizing: border-box; padding: 0; }
table.xl thead tr.xlhead th.rowhead { padding: 6px 7px; }

.xl .hcell {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: 2px;
  height: 100%;
  min-width: 0;
}

/* The heading text is a button so it is reachable by keyboard, but it has to
   look exactly like the heading it replaced. */
.xl .hlabel {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 4px;
  border: none;
  background: none;
  padding: 0 2px 0 7px;
  font: inherit;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .35px;
  color: inherit;
  cursor: pointer;
  border-radius: 0;
  white-space: nowrap;
}

.xl .hlabel:hover { background: #dbe8f6; }
.xl .hlabel .htext { overflow: hidden; text-overflow: ellipsis; }
.xl .hlabel .harrow { flex: none; font-size: 8px; color: var(--brand); }

.xl thead th.env .hlabel { justify-content: center; padding-left: 4px; }

/* The funnel: quiet until the column is filtered, and always clickable. */
.xl .hfilter {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 0;
  color: #93a9c0;
  cursor: pointer;
}

.xl .hfilter:hover { background: #dbe8f6; color: var(--brand-dark); }
.xl .hfilter .funnel { display: flex; }
.xl .hfilter.on { color: var(--brand-dark); background: #cfe3fb; }
.xl thead th.is-filtered { background: #dbeafe; }

/* ---------------------------------------------------- resizing a column */
/* Each heading carries two grips, one per edge: the right one resizes this
   column, the left one resizes the column before it (see grid.js). They meet at
   the border, so the draggable strip runs continuously across it instead of
   stopping at the edge of one cell -- which is what made half of every attempt
   to grab a line miss.

   The <th> is padded by 7px, so a grip of that width fills the padding exactly
   and never covers the heading text or the filter funnel. The sticky <th> is
   itself a positioned box, which is what the absolute placement hangs off. */
.xl .hgrip {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 7px;
  cursor: col-resize;
  z-index: 4;
  touch-action: none;
}

.xl .hgrip.left { right: auto; left: 0; }

.xl .hgrip::after {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  right: 2px;
  width: 2px;
  border-radius: 1px;
  background: var(--brand);
  opacity: 0;
  transition: opacity .08s;
}

/* The left grip draws no line of its own: the column it resizes already has one
   at that border, and two lines a few pixels apart read as two places to grab
   rather than one. */
.xl .hgrip.left::after { content: none; }

/* Faint on any heading the pointer is over, solid on the grip itself. The lines
   were invisible until the pointer was already on one, which meant knowing
   where to aim before there was anything to aim at. */
.xl thead tr:hover .hgrip::after { opacity: .3; }
.xl .hgrip:hover::after { opacity: .85; }

/* While a drag is running the pointer must not turn into a text caret or an
   I-beam wherever it happens to be, and nothing may be selected by the drag. */
body.col-resizing { cursor: col-resize; user-select: none; }
body.col-resizing * { cursor: col-resize !important; }

/* ------------------------------------------------------------ wrapped text */
/* Cells normally clip to one line so every row is the same 25px. With wrapping
   on they lay the text out over as many lines as the column width needs and the
   row grows to the tallest cell -- capped, so one 300-line script cannot turn
   the page into a single row. The cap clips rather than scrolls: the cell is
   still a cell, and the editor (or the tooltip) is where the whole text lives. */
table.xl.wrap td.cell,
table.xl.wrap td.rowhead {
  height: auto;
  max-height: none;
  vertical-align: top;
}

table.xl.wrap td.cell .v {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  text-overflow: clip;
  max-height: 104px;
  line-height: 1.45;
}

/* Remarks carries the script itself, so it is allowed to run longer. */
table.xl.wrap td.cell.multiline .v { max-height: 168px; }

/* An environment tick is one character; centring it against a tall neighbour
   reads better than pinning it to the top of the row. */
table.xl.wrap td.cell.envcell { vertical-align: middle; }
.xl thead th.is-sorted .htext { color: var(--brand-dark); }

/* Both header buttons keep a visible focus ring -- this is the only way to
   reach sort and filter without a mouse. */
.xl .hlabel:focus-visible, .xl .hfilter:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}

/* -------------------------------------------------- the column filter popup */
/* On the body rather than inside the <th>: a sticky cell clips its children,
   so a menu rendered in one is cut off at the column edge. */
.xlf-pop {
  position: fixed;
  z-index: 70;
  width: 244px;
  max-height: min(420px, 80vh);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line-hard);
  border-radius: 8px;
  box-shadow: var(--shadow);
  padding: 5px;
  font-size: 12px;
  color: var(--ink);
}

.xlf-head {
  padding: 4px 7px 6px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .35px;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.xlf-sep { height: 1px; background: var(--line); margin: 4px 0; }

.xlf-pop .xlf-sort,
.xlf-pop .xlf-opt,
.xlf-pop .xlf-clear {
  display: flex;
  align-items: center;
  gap: 3px;
  width: 100%;
  border: none;
  background: none;
  padding: 5px 7px;
  font: inherit;
  font-size: 12px;
  text-align: left;
  color: var(--ink);
  border-radius: var(--radius);
  cursor: pointer;
  white-space: nowrap;
}

.xlf-pop .xlf-sort:hover,
.xlf-pop .xlf-opt:hover,
.xlf-pop .xlf-clear:hover { background: #eef4fb; }

.xlf-pop .xlf-sort.chosen,
.xlf-pop .xlf-opt.chosen { background: var(--brand-soft); font-weight: 650;
                           color: var(--brand-dark); }

.xlf-tick { flex: none; width: 13px; color: var(--brand); font-size: 11px; }
.xlf-text { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }

.xlf-search {
  width: 100%;
  margin: 0 0 4px;
  font-size: 12px;
  padding: 4px 7px;
}

/* Only the value list scrolls, so sort and clear stay put on a long column. */
.xlf-list { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

.xlf-opt.xlf-all, .xlf-opt.xlf-blank { color: var(--ink-soft); font-style: italic; }
.xlf-opt.xlf-all.chosen, .xlf-opt.xlf-blank.chosen { color: var(--brand-dark); }
.xlf-none { padding: 8px 7px; color: var(--ink-faint); font-size: 11.5px; }

.xlf-pop .xlf-clear {
  margin-top: 4px;
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
  color: var(--bad);
  font-size: 11.5px;
}
.xlf-pop .xlf-clear:hover { background: var(--bad-soft); }

/* ------------------------------------------------ the right-click row menu */
/* Same shell as the column filter, sized to its labels rather than a value
   list, and with the shortcut spelled out on the right the way a desktop menu
   does it. */
.xlf-pop.ctxmenu { width: auto; min-width: 208px; }
.xlf-pop.ctxmenu .xlf-sort { gap: 18px; }
.xlf-pop.ctxmenu .xlf-text { flex: 1 1 auto; }

.ctx-key {
  flex: none;
  margin-left: auto;
  font-size: 10.5px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.xlf-pop.ctxmenu .ctx-danger { color: var(--bad); }
.xlf-pop.ctxmenu .ctx-danger:hover { background: var(--bad-soft); }

/* The funnel glyph inline in the status bar hint, so "click the funnel" points
   at the same mark the headings use rather than describing it in words. */
.kbdfunnel {
  display: inline-block;
  width: 9px;
  height: 9px;
  vertical-align: -1px;
  background: currentColor;
  opacity: .75;
  clip-path: polygon(0 8%, 100% 8%, 62% 52%, 62% 100%, 38% 82%, 38% 52%);
}

.gridpager {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 10px;
  border-top: 1px solid var(--line);
  background: #fbfdff;
  font-size: 11.5px;
  color: var(--ink-soft);
  /* Its own stacking context, above whatever is laid out after the panel.
   * The min-height floor above is what stops an overlap happening at all; this
   * is the guarantee that even if one ever does, the page-back arrows are still
   * the thing under the cursor. A pager you cannot click is a page you cannot
   * leave. */
  position: relative;
  z-index: 1;
}

.gridpager .spacer { flex: 1 1 auto; }
.gridpager select { font-size: 11.5px; padding: 3px 6px; }

/* with a pager under it, the scroll area is no longer the panel's last row */
.panel.grow > .gridwrap:not(:last-child) { border-radius: 0; }
.panel.grow > .gridpager { border-radius: 0 0 var(--radius) var(--radius); }

/* buttons and flex boxes carry a display of their own, which beats the
   browser's default rule for [hidden] -- make hidden mean hidden. */
[hidden] { display: none !important; }

/* ------------------------------------------------- password + test blocks */
/* A password box with a reveal toggle. What is stored never reaches the
   browser, so an empty box always means "leave it as it is". */
.pw {
  display: flex;
  align-items: center;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
}

.pw:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.pw input { flex: 1; min-width: 0; border: 0; border-radius: 0; }
.pw input:focus { outline: none; box-shadow: none; border: 0; }

.pw-eye {
  border: 0;
  background: transparent;
  padding: 3px 8px;
  font-size: 13px;
  line-height: 1;
  opacity: .45;
  cursor: pointer;
}

.pw-eye:hover { background: #eff5fc; opacity: .8; }
.pw-eye.on { opacity: 1; }

label.field > span { display: flex; align-items: center; gap: 6px; }
button.pw-remove { padding: 0 5px; font-size: 10.5px; color: var(--bad); }
button.pw-remove:hover { background: var(--bad-soft); }

/* a titled section of a dialog, with its own test button and result area */
.sechead {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
}

.sechead .sectitle { font-weight: 600; font-size: 12.5px; }
.testout:empty { display: none; }
.testout {
  /* a flex item in the modal body: overflow:hidden lets it shrink to
     nothing, so pin it to its content height */
  flex: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fbfdff;
  overflow: hidden;
}
.testout table.tbl th { position: static; }

/* a field note that is a warning, not a hint */
.field-note.bad-note { color: var(--bad); font-weight: 550; }

/* ------------------------------------------------------------------ sign-in */
/* The login page stands alone: no topbar, no navigation, one card centred on
   the same slate background the rest of the app uses. */
body.signin-page { background: var(--bg); }

.signin {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px 16px;
}

.signin-card {
  width: 100%;
  max-width: 372px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 22px 22px 20px;
}

.signin-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 18px; }
.signin-brand .logo {
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: var(--brand);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .5px;
  flex: none;
}
.signin-title { font-weight: 650; font-size: 14.5px; color: var(--ink); }
.signin-sub { font-size: 11.5px; color: var(--ink-soft); margin-top: 1px; }

.signin-form { display: flex; flex-direction: column; gap: 12px; }
.signin-form input[type="text"],
.signin-form input[type="password"] { padding: 7px 9px; font-size: 13px; }
.signin-remember { margin-top: -2px; color: var(--ink-soft); }
.signin-remember .hint { font-size: 11px; }

button.block, .btn.block {
  display: flex;
  justify-content: center;
  width: 100%;
  padding: 8px 12px;
  font-size: 13px;
}

.signin-alert {
  border-radius: var(--radius);
  padding: 8px 11px;
  font-size: 12px;
  margin-bottom: 14px;
  border: 1px solid transparent;
}
.signin-alert.err { background: var(--bad-soft); border-color: #fecaca; color: #7f1d1d; }
.signin-alert.info { background: var(--brand-soft); border-color: #bfdbfe; color: var(--brand-dark); }

/* A rule with the word "or" sitting in the gap. */
.signin-or {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 15px 0;
  color: var(--ink-faint);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .6px;
}
.signin-or::before, .signin-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.signin-sso { font-weight: 550; }
.signin-note { font-size: 11px; color: var(--ink-faint); margin: 11px 0 0; line-height: 1.45; }
.signin-foot { font-size: 11px; color: var(--ink-faint); margin: 0; }

/* ------------------------------------------- the signed-in user in the topbar */
/* Replaces the old "Acting as" picker. Who you are is now a fact, not a choice,
   so this is a label with a menu rather than a <select>. */
.whoami { position: relative; }

.whoami-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .18);
  color: #fff;
  border-radius: var(--radius);
  padding: 4px 9px;
  cursor: pointer;
}
.whoami-btn:hover { background: rgba(255, 255, 255, .2); }
.whoami.open .whoami-btn { background: rgba(255, 255, 255, .22); }

.whoami-initials {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.whoami-name { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.whoami-name b { font-size: 12px; font-weight: 600; }
.whoami-name span { font-size: 10px; color: #a8c3dc; text-transform: uppercase; letter-spacing: .4px; }

.whoami-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 232px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
  padding: 6px;
  z-index: 60;
  color: var(--ink);
}
.whoami-menu .head {
  padding: 7px 9px 9px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 5px;
}
.whoami-menu .head b { display: block; font-size: 12.5px; }
.whoami-menu .head .hint { margin-top: 2px; }
.whoami-menu button, .whoami-menu a {
  display: flex;
  width: 100%;
  justify-content: flex-start;
  border: none;
  background: transparent;
  padding: 6px 9px;
  font-size: 12px;
  color: var(--ink);
  border-radius: var(--radius);
}
.whoami-menu button:hover, .whoami-menu a:hover { background: #eef2f7; text-decoration: none; }
.whoami-menu form { margin: 0; }
.whoami-menu .sep { height: 1px; background: var(--line); margin: 5px 0; }

/* ------------------------------------------------------------------- audit */
.audit-filters { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.audit-filters label.field { min-width: 132px; }
.audit-agent {
  display: block;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------ the filter and saved-filter pops */
/* One button owns the filters, so the next filter added has an obvious home
 * and the toolbar stops growing sideways. The host is the positioning context
 * for the panel, which is why it is relative and the panel absolute. */
.filterhost { position: relative; display: inline-flex; }

.filterhost > button .funnel {
  display: inline-block;
  width: 10px;
  height: 10px;
  background: currentColor;
  opacity: .8;
  clip-path: polygon(0 8%, 100% 8%, 62% 52%, 62% 100%, 38% 82%, 38% 52%);
}

/* The red dot is the whole point of the indicator: "something is being hidden
 * from you". It sits on the button whether or not the panel is open. */
.filterhost > button .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--bad);
  box-shadow: 0 0 0 2px #fff;
}
.filterhost > button.on {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand-dark);
}
.filterhost > button .navcount {
  min-width: 17px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--bad);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
#btnSaved .navcount { background: #dde5ee; color: var(--ink-soft); }

.filterpop {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 60;
  min-width: 320px;
  max-width: min(94vw, 420px);
  background: #fff;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.filterpop-head, .filterpop-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  font-size: 11.5px;
  font-weight: 650;
  background: #f6f9fc;
}
.filterpop-head { border-bottom: 1px solid var(--line); }
.filterpop-foot { border-top: 1px solid var(--line); font-weight: 400; }

.filterpop-body {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 10px;
  max-height: 62vh;
  overflow: auto;
}
.filterpop-body label.field { width: 100%; }
.filterpop-body label.field > select,
.filterpop-body label.field > input { width: 100%; }
.filterpop-sep { height: 1px; background: var(--line); margin: 1px 0; }

/* the saved list */
.savedlist { max-height: 50vh; overflow: auto; padding: 4px; }
.savedlist .savedrow {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px;
  border-radius: var(--radius);
}
.savedlist .savedrow:hover { background: #f1f5f9; }
.savedlist .savedrow .name {
  flex: 1;
  min-width: 0;
  text-align: left;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.savedlist .savedrow .name:hover { color: var(--brand-dark); text-decoration: underline; }
.savedlist .savedrow.applied { background: var(--brand-soft); }
.savedlist .savedrow.applied .name { font-weight: 650; color: var(--brand-dark); }
.savedlist .star {
  border: 0;
  background: none;
  padding: 2px;
  cursor: pointer;
  color: var(--ink-faint);
  font-size: 13px;
  line-height: 1;
}
.savedlist .star.on { color: var(--warn); }
.savedlist .empty { padding: 12px 8px; font-size: 11.5px; }

/* what is currently narrowing the list, spelled out under the toolbar */
.filterchips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.filterchips:empty { display: none; }
.filterchips { margin-top: 8px; }
.filterchips .chip.act { padding-right: 4px; }
.filterchips .chip.act button {
  border: 0;
  background: none;
  padding: 0 3px;
  margin: 0;
  cursor: pointer;
  color: inherit;
  font-size: 12px;
  line-height: 1;
  opacity: .65;
}
.filterchips .chip.act button:hover { opacity: 1; background: none; }

/* ------------------------------------------------- the role x page matrix */
/* Three buttons per cell rather than a dropdown: the whole grid is then
 * readable at a glance, which is the point of showing it as a grid. */
.lvl { display: inline-flex; border: 1px solid var(--line-hard); border-radius: var(--radius); overflow: hidden; }
.lvl button {
  border: 0;
  border-radius: 0;
  padding: 3px 9px;
  font-size: 11px;
  background: #fff;
  color: var(--ink-soft);
  min-width: 30px;
  justify-content: center;
}
.lvl button + button { border-left: 1px solid var(--line); }
.lvl button:hover { background: #eef4fb; color: var(--ink); }
.lvl button.on { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 650; }
.lvl-none button.on { background: var(--ink-faint); }
.lvl-view button.on { background: var(--warn); }
.lvl-edit button.on { background: var(--ok); }
.lvl.saving { opacity: .55; pointer-events: none; }
th.lvlh { white-space: normal; line-height: 1.25; }
