/* Steward review UI.
   Dense, keyboard-friendly, and readable for hours - this is a tool someone
   works in for a whole afternoon, not a dashboard they glance at. */

:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --border: #dfe3e8;
  --text: #1a1d21;
  --muted: #667085;
  --accent: #1f3864;
  --accent-soft: #eaf0fb;
  --review: #fff8e1;
  --review-edge: #f0c000;
  --ok: #1a7f43;
  --ok-soft: #e8f5ec;
  --bad: #b42318;
  --bad-soft: #fdecea;
  --edit: #6941c6;
  --edit-soft: #f3eeff;
  --radius: 6px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* --- chrome --- */

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 10px 20px;
  background: var(--accent); color: #fff;
}
.brand { color: #fff; text-decoration: none; font-weight: 600; letter-spacing: .2px; }
.brand span { font-weight: 400; opacity: .7; font-size: 12px; margin-left: 6px; }
.topbar .meta { font-size: 12px; opacity: .85; }

/* Sign out sits at the far right of the bar. */
.signout-form { margin-left: auto; }
.signout-btn {
  font: inherit; font-size: 12px; cursor: pointer; color: #fff;
  background: rgba(255, 255, 255, .12); border: 1px solid rgba(255, 255, 255, .28);
  padding: 5px 12px; border-radius: 6px;
}
.signout-btn:hover { background: rgba(255, 255, 255, .22); }

/* --- the login page ---------------------------------------------------------
   A single centred card. Standalone (it does not extend base.html), so no app
   chrome shows before a steward is in. */
.login-page {
  margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 24px; background: linear-gradient(160deg, #eef1f6 0%, #dfe5ef 100%);
}
.login-card {
  width: 350px; max-width: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 14px;
  background: var(--surface); padding: 30px 30px 28px;
  border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 20px 55px rgba(15, 22, 38, .16);
}
.login-brand {
  font-weight: 700; font-size: 15px; color: var(--accent); line-height: 1.2;
}
.login-brand span {
  display: block; margin-top: 3px; font-weight: 500; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .5px; color: var(--muted);
}
.login-title { font-size: 21px; margin: 8px 0 0; }
.login-sub { margin: 0 0 4px; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.login-error {
  background: var(--bad-soft); border: 1px solid #f3c4c0; color: var(--bad);
  padding: 9px 12px; border-radius: var(--radius); font-size: 13px;
}
.login-field { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--muted); }
.login-field input { width: 100%; box-sizing: border-box; padding: 10px 12px; font-size: 14px; }
.login-submit { margin-top: 6px; width: 100%; justify-content: center; text-align: center; padding: 11px; font-size: 14px; }

main { padding: 20px; max-width: 1600px; margin: 0 auto; }

h1 { font-size: 20px; margin: 0 0 4px; }
h2 { font-size: 15px; margin: 24px 0 10px; }
.sub { color: var(--muted); font-size: 13px; margin: 0 0 18px; }

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px; margin-bottom: 18px;
}

/* --- stats --- */

.stats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 16px; }
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 8px 14px; min-width: 110px;
}
.stat b { display: block; font-size: 20px; line-height: 1.2; }
.stat span { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }
/* A tile is a shortcut to its tab; dim the empty ones so the working numbers lead. */
a.stat { text-decoration: none; color: inherit; transition: border-color .1s; }
a.stat:hover { border-color: var(--accent); }
.stat.is-zero { opacity: .5; }
.stat.is-queue b { color: var(--review-edge); }
.stat.is-ok b { color: var(--ok); }
.stat.is-edit b { color: var(--edit); }

/* --- tabs & controls --- */

.tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 12px; }
.tab {
  padding: 6px 13px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--muted);
  text-decoration: none; font-size: 13px; white-space: nowrap;
}
.tab:hover { border-color: var(--accent); color: var(--accent); }
.tab.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.tab .n { opacity: .65; margin-left: 5px; font-variant-numeric: tabular-nums; }

.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.toolbar form { display: flex; gap: 6px; }
.spacer { flex: 1; }

/* Right-hand clusters: the two display controls (Sort, View) on the confidence
   row, and the page actions (Excluded, Approve all, Download) on the toolbar.
   Grouped so each reads as one set, and separated from the filters on the left. */
.display-group { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.toolbar-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

input[type=text], input[type=search], select, textarea {
  font: inherit; padding: 5px 8px; border: 1px solid var(--border);
  border-radius: 4px; background: #fff; color: inherit;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent-soft); border-color: var(--accent);
}

.btn {
  font: inherit; padding: 6px 13px; border-radius: 4px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  text-decoration: none; display: inline-block;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { opacity: .9; color: #fff; }
.btn-ok { background: var(--ok-soft); border-color: #bcdcc8; color: var(--ok); }
.btn-bad { background: var(--bad-soft); border-color: #f3c4c0; color: var(--bad); }
.btn-sm { padding: 3px 9px; font-size: 12px; }

/* --- table --- */

/* No overflow here: an overflow-x scroll container makes the browser compute
   overflow-y as auto too, which pins the sticky header to this box (it scrolls
   away with the page) instead of the viewport. Any horizontal overflow falls
   to the page, which keeps `thead` sticking to the top of the screen. */
.table-wrap { background: var(--surface); border: 1px solid var(--border);
              border-radius: var(--radius); }
/* A floor on the table width so the text-heavy columns (Why, Detail) keep a
   readable measure instead of being crushed to a two-word-per-line ribbon on a
   laptop screen. Below this the overflow falls to the page, not to a scroll box
   on `.table-wrap`, so the sticky header still tracks the viewport. */
table { border-collapse: collapse; width: 100%; min-width: 1240px; font-size: 13px; }
thead th {
  /* Sits just below the sticky filter bar; keys.js measures that bar and sets
     --filterbar-h so the two never overlap. Falls back to the top when the
     variable is absent (e.g. the filter bar is hidden before a batch is ready). */
  position: sticky; top: var(--filterbar-h, 0px); z-index: 2;
  background: #eef1f5; text-align: left; font-size: 11px; text-transform: uppercase;
  letter-spacing: .4px; color: var(--muted); padding: 8px 12px;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
tbody td { padding: 9px 12px; border-bottom: 1px solid #eef0f3; vertical-align: top; }
tbody tr:hover { background: #fafbfc; }
tbody tr.is-review { background: var(--review); }
tbody tr.is-review:hover { background: #fff3cd; }
tbody tr.is-approved { background: var(--ok-soft); }
tbody tr.is-rejected { background: var(--bad-soft); opacity: .72; }

td.company input { width: 100%; min-width: 160px; }
td.domains textarea { width: 100%; min-width: 200px; resize: vertical; font-size: 12px; }
/* The row's own actions stack vertically, so the column stays narrow and gives
   its width to Why and Detail. Only the direct-child buttons stack; the buttons
   inside the split and reason boxes keep their own horizontal layout. */
td.actions { white-space: nowrap; }
td.actions > .btn {
  display: block; width: 100%; margin: 0 0 4px; text-align: center;
}
td.actions > .btn:last-of-type { margin-bottom: 0; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }

.pill {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 600; white-space: nowrap;
}
.pill-review { background: #fdf0c8; color: #7a5c00; }
.pill-ok { background: var(--ok-soft); color: var(--ok); }
.pill-bad { background: var(--bad-soft); color: var(--bad); }
.pill-edit { background: var(--edit-soft); color: var(--edit); }
.pill-prior { background: #e3f0e8; color: #1f6b40; border: 1px solid #bfe0cd; }
.pill-verified { background: #eaf5ee; color: #2f7d51; }
.pill-unverified { background: #fde7e3; color: #b3502f; }
.prior-note { font-size: 12px; color: #1f6b40; margin: -8px 0 14px; }
.prior-note .pill { vertical-align: middle; }

.reason { color: #3a424e; font-size: 12.5px; max-width: 520px; line-height: 1.5; }
.evidence { margin-top: 5px; font-size: 11.5px; color: #4a5568; }
.evidence summary { cursor: pointer; color: var(--accent); }
.evidence li { margin: 3px 0; }
.was { color: var(--edit); font-size: 11px; margin-top: 3px; }

td.ai-owner-col { font-size: 12px; color: #4a5568; }

/* Risk flags: quiet until you look for them, so they never read as errors. */
.risk-flags { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 3px; }
.risk-flag { font-size: 10px; line-height: 1.5; padding: 0 5px; border-radius: 3px;
             background: #fbeede; color: #8a5a1a; border: 1px solid #f0d8b8;
             text-transform: uppercase; letter-spacing: .2px; cursor: help; white-space: nowrap; }
.risk-flag.risk-public-domain { background: #f0e6f8; color: #6b3fa0; border-color: #ddccef; }
.risk-flag.risk-reporting-only { background: #e6eef8; color: #2f5c9e; border-color: #ccdcf0; }
.risk-flag.risk-duplicate { background: #fde3ea; color: #a51e52; border-color: #f3c2d3; }
.risk-flag.risk-lowconf { background: #fff3cd; color: #7a5c00; border-color: #f0e0a8; }
/* The strongest signal - the domain names a different company - reads as an
   error, not a note, so it carries the bad-red the others do not. */
.risk-flag.risk-name-mismatch { background: var(--bad-soft); color: var(--bad); border-color: #f3c4c0; font-weight: 600; }
.parent-evidence { margin-top: 4px; font-size: 11px; font-style: italic; color: #5a6b7a; line-height: 1.35; }
.evidence-top { margin-top: 5px; font-size: 12px; color: #4a5568; line-height: 1.4; }
.evidence-top a { color: var(--accent); white-space: nowrap; margin-left: 4px; }
.evidence summary { cursor: pointer; color: var(--accent); font-size: 12px; }

.banner-error { background: var(--bad-soft); border: 1px solid #f3c4c0; color: var(--bad); }

.split-box { margin-top: 8px; padding: 8px; border: 1px solid var(--border);
             border-radius: 6px; background: #fafbfc; font-size: 12px; }
.split-label { font-weight: 600; margin-bottom: 4px; color: var(--muted); }
.split-domain { display: block; margin: 2px 0; cursor: pointer; }
.split-domain input { margin-right: 5px; }
.split-target { display: block; margin: 6px 0; }
.split-target input { width: 100%; margin-top: 3px; padding: 3px 6px;
                      border: 1px solid var(--border); border-radius: 5px; }
.split-actions { display: flex; gap: 6px; margin-top: 6px; }

.empty { padding: 40px; text-align: center; color: var(--muted); }

/* --- misc --- */

.pager { display: flex; gap: 6px; align-items: center; justify-content: center;
         flex-wrap: wrap; margin: 14px 0; color: var(--muted); font-size: 13px; }
.page-num { min-width: 30px; text-align: center; padding: 3px 7px; border-radius: 6px;
            border: 1px solid var(--border); background: var(--surface);
            color: var(--text); text-decoration: none; font-variant-numeric: tabular-nums; }
.page-num:hover { border-color: var(--accent); color: var(--accent); }
.page-num.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.page-gap { padding: 0 2px; color: var(--muted); }
.page-jump { display: flex; align-items: center; gap: 6px; margin-left: 6px; }
.page-jump input { width: 58px; padding: 3px 6px; border: 1px solid var(--border);
                   border-radius: 6px; font-size: 13px; }
.page-of { margin-left: 8px; font-weight: 600; color: var(--text); }
.page-meta { margin-left: 8px; }

/* The tabs/confidence/sort bar, pinned so filters are always in reach. The
   negative margin lets the opaque background bleed to the page edges so rows
   scrolling underneath do not show past the content column. */
.filterbar { position: sticky; top: 0; z-index: 5; background: var(--bg);
             margin: 0 -20px 12px; padding: 6px 20px 0;
             border-bottom: 1px solid var(--border); }
.filterbar .tabs, .filterbar .conf-bar { margin-bottom: 8px; }

.band-approve { display: inline; }

/* One Download button with a menu of scopes, in place of three side-by-side
   buttons. A native <details>: the summary is the button, the panel drops below
   it, and keys.js closes it on an outside click. */
.download-menu { position: relative; display: inline-block; }
.download-menu > summary { list-style: none; cursor: pointer; }
.download-menu > summary::-webkit-details-marker { display: none; }
.download-options {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  min-width: 250px; padding: 4px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 10px 28px rgba(15, 22, 38, .14);
}
.download-option {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 8px 10px; border-radius: 5px; font-size: 13px;
  text-decoration: none; color: var(--text);
}
a.download-option:hover { background: var(--accent-soft); color: var(--accent); }
.download-option.is-disabled { color: var(--muted); cursor: default; }
.download-count { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }

.banner { padding: 10px 14px; border-radius: var(--radius); margin-bottom: 14px; font-size: 13px; }
.banner-run { background: var(--accent-soft); border: 1px solid #c6d5f0; color: var(--accent); }
.banner-bad { background: var(--bad-soft); border: 1px solid #f3c4c0; color: var(--bad); }
.rerun-form { margin-top: 10px; }

/* A degraded run is the one banner that must stop a steward, not just inform
   them - so it is louder than the rest: a left rule, a heading, and the one
   action that helps set apart from the mechanics. */
.banner-degraded {
  background: #fdece9; border: 1px solid #f3c4c0; border-left: 4px solid var(--bad);
  color: #7a2318; padding: 14px 16px; margin-bottom: 16px; border-radius: var(--radius);
}
.degraded-head { font-size: 15px; font-weight: 700; color: var(--bad); margin-bottom: 6px; }
.banner-degraded .banner-reason { margin: 4px 0; font-size: 13px; line-height: 1.5; }
.degraded-do { margin: 8px 0 0; font-size: 13px; line-height: 1.5; }
/* The export buttons on a degraded run: still there, but styled as the wrong
   move so the eye is not drawn to them the way the primary blue would draw it. */
.btn-degraded-export {
  background: var(--surface); border-color: #f3c4c0; color: var(--bad); font-weight: 600;
}
.btn-degraded-export:hover { border-color: var(--bad); color: var(--bad); }
.htmx-request { opacity: .55; transition: opacity .1s; }
code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 12px; }
.muted { color: var(--muted); }

/* --- keyboard navigation --- */

/* The focused row must be unmistakable at a glance: a steward driving with the
   keyboard needs to know what "a" is about to approve. The left bar reads
   clearly over the status tints (review yellow, approved green) that already
   colour these rows. */
tbody tr.is-focused { box-shadow: inset 4px 0 0 var(--accent); }
tbody tr.is-focused > td:first-child { position: relative; }
tbody tr.is-focused > td { background-color: rgba(31, 56, 100, .045); }

.kb-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 6px 12px; margin-bottom: 10px; font-size: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--muted);
}
.kb-bar kbd { margin-right: 3px; }
.kb-bar .pos { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--accent); font-weight: 600; }

kbd {
  display: inline-block; min-width: 18px; text-align: center;
  padding: 1px 5px; border-radius: 4px;
  border: 1px solid #ccd2da; border-bottom-width: 2px;
  background: #f4f6f8; color: #2c3440;
  font: 600 11px/1.5 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

.kb-help {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  background: rgba(16, 22, 34, .55);
}
.kb-help[hidden] { display: none; }
.kb-help .panel {
  background: var(--surface); border-radius: 10px; padding: 22px 26px;
  min-width: 400px; max-width: 90vw; max-height: 85vh; overflow: auto;
  box-shadow: 0 18px 50px rgba(0,0,0,.28);
}
.kb-help h2 { margin: 0 0 14px; font-size: 16px; }
.kb-help table { width: 100%; }
.kb-help td { border: 0; padding: 4px 8px 4px 0; }
.kb-help td:first-child { width: 90px; white-space: nowrap; }
.kb-help .close { margin-top: 16px; color: var(--muted); font-size: 12px; }

/* --- run progress ---
   A run takes minutes, and the page used to be blank for all of them: the
   review UI renders only when the batch is ready, so a steward who pressed
   "Upload and run" landed on an empty page and had no way to tell a working
   run from a broken one. This panel is the answer, and it reports the stages
   the pipeline actually reached rather than animating a guess. */

.run-panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 20px 22px; margin-bottom: 18px;
}
.run-head { display: flex; align-items: flex-start; gap: 14px; }
.run-head h2 { margin: 0 0 3px; font-size: 16px; }
.run-head p { margin: 0; font-size: 12.5px; max-width: 60ch; }
.run-count { margin-left: auto; text-align: right; white-space: nowrap; }
.run-count b { display: block; font-size: 22px; line-height: 1.1; color: var(--accent); }
.run-count b span { font-size: 14px; color: var(--muted); font-weight: 400; }
.run-count > span { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }

.run-track {
  height: 4px; border-radius: 999px; background: #e7ebf1;
  margin: 16px 0 4px; overflow: hidden;
}
.run-fill {
  height: 100%; background: var(--accent); border-radius: 999px;
  transition: width .4s ease;
}

.spinner {
  flex: none; width: 18px; height: 18px; margin-top: 2px;
  border: 2px solid #d7dee9; border-top-color: var(--accent);
  border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.steps { list-style: none; margin: 14px 0 0; padding: 0; }
.step {
  display: flex; align-items: baseline; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid #f1f3f6; font-size: 13px;
}
.step:last-child { border-bottom: 0; }
.step .dot {
  flex: none; width: 9px; height: 9px; border-radius: 50%;
  background: #d7dee9; align-self: center;
}
.step .what { flex: 1; color: var(--muted); }
.step .detail { color: var(--muted); opacity: .8; font-size: 12px; margin-left: 8px; }
.step .state { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); }

.step.is-done .dot { background: var(--ok); }
.step.is-done .what { color: var(--text); }
.step.is-done .state { color: var(--ok); }
.step.is-active .dot { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.step.is-active .what { color: var(--text); font-weight: 600; }
.step.is-active .state { color: var(--accent); font-weight: 600; }
.step.is-todo { opacity: .6; }

/* A running batch in the history list, without the weight of the full panel. */
.dot-run {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; margin-right: 5px; vertical-align: middle;
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

@media (prefers-reduced-motion: reduce) {
  .spinner, .dot-run { animation: none; }
  .run-fill { transition: none; }
}

/* --- comparison --- */

.crumbs { font-size: 12.5px; color: var(--muted); margin-bottom: 12px; }
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--accent); }
.crumbs span { margin: 0 6px; opacity: .6; }

.split {
  display: grid; gap: 16px; margin-bottom: 4px;
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
}
.split .card { margin-bottom: 0; }

.upload-card input[type=file] { font: inherit; }

table.mini { font-size: 13px; }
table.mini td { padding: 6px 0; border-bottom: 1px solid #f1f3f6; vertical-align: middle; }
table.mini tr:last-child td { border-bottom: 0; }
table.mini td.num { text-align: right; font-variant-numeric: tabular-nums; padding-left: 12px; }
table.mini a { color: var(--accent); text-decoration: none; }
table.mini a:hover { text-decoration: underline; }
table.mini .pill { margin-left: 6px; }

tbody tr.is-extra { background: var(--edit-soft); }
tbody tr.is-extra:hover { background: #ece4ff; }

th.actions-head { width: 1%; }

/* The two ways a domain goes missing. They are shown as a choice rather than a
   statistic because they are not the same kind of problem: one is a domain we
   read and dropped, the other is one the source never had. Different fix,
   different person, so each is its own filter. */

.miss-split { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 12px; }
.miss {
  display: block; padding: 11px 13px; text-decoration: none; color: inherit;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.miss:hover { border-color: var(--accent); }
.miss.active { border-color: var(--accent); background: var(--accent-soft); }
.miss b { display: block; font-size: 21px; line-height: 1.15; color: var(--accent); }
.miss span {
  display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .4px; color: var(--muted); margin-top: 1px;
}
.miss em { display: block; font-style: normal; font-size: 11.5px; color: var(--muted); margin-top: 5px; }

@media (max-width: 560px) { .miss-split { grid-template-columns: 1fr; } }

/* --- the twelve rules ---
   A reference page someone reads once to understand the system, so it is set
   wider-spaced and in longer measure than the review table: the constraint here
   is comprehension, not density. */

.page-head { display: flex; align-items: flex-start; gap: 16px; }
.page-head > div { flex: 1; }
.page-head .btn { flex: none; }

.card.note p { margin: 0 0 8px; font-size: 13px; max-width: 78ch; }
.card.note p:last-child { margin-bottom: 0; }
.card.note h2 { font-size: 15px; }

.rules { list-style: none; counter-reset: none; margin: 0 0 18px; padding: 0; }
.rule {
  display: flex; gap: 16px; align-items: flex-start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px 18px; margin-bottom: 10px;
}
.rule:target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.rule-id { flex: none; width: 42px; }
.rule-id a {
  display: inline-block; padding: 3px 0; width: 100%; text-align: center;
  background: var(--accent-soft); color: var(--accent); border-radius: 4px;
  font: 600 12px/1.4 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  text-decoration: none;
}
.rule-id a:hover { background: var(--accent); color: #fff; }

.rule-body { flex: 1; min-width: 0; }
.rule-body h2 { margin: 1px 0 9px; font-size: 14.5px; line-height: 1.35; }
.rule-body p { margin: 0 0 6px; font-size: 13px; line-height: 1.5; max-width: 82ch; }
.rule-body p:last-child { margin-bottom: 0; }
.rule-body .why, .rule-body .eg { color: var(--muted); }

/* The tag sits on the text baseline rather than floating above it, so each line
   reads as one sentence beginning with its label. */
.tag {
  display: inline-block; min-width: 34px; margin-right: 8px;
  padding: 0 6px; border-radius: 3px; text-align: center;
  font: 600 10px/1.7 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  text-transform: uppercase; letter-spacing: .5px; vertical-align: 1px;
}
.tag-do { background: var(--ok-soft); color: var(--ok); }
.tag-why { background: #eef1f5; color: var(--muted); }
.tag-eg { background: var(--edit-soft); color: var(--edit); }

@media (max-width: 560px) {
  .page-head { flex-direction: column; }
  .rule { flex-direction: column; gap: 8px; }
  .rule-id { width: 42px; }
}

/* --- confidence filter ---
   A second axis on the review table, not another tab: the useful question is
   "the review queue, least certain first", so it narrows whatever tab is open
   rather than replacing it. Set apart from .tabs visually so the two rows do
   not read as one list of seven things. */

.conf-bar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 7px 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.conf-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); margin-right: 4px;
}
.conf {
  padding: 3px 11px; border-radius: 999px; border: 1px solid transparent;
  background: #eef1f5; color: var(--muted);
  text-decoration: none; font-size: 12.5px; white-space: nowrap;
}
.conf:hover { border-color: var(--accent); color: var(--accent); }
.conf .n { font-variant-numeric: tabular-nums; opacity: .7; margin-left: 3px; }
.conf.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.conf.active .n { opacity: .85; }

/* The band colours match the row tints already used in the table, so "low"
   here and a review-flagged row there read as the same idea. */
.conf-high { background: var(--ok-soft); color: var(--ok); }
.conf-medium { background: var(--review); color: #7a5c00; }
.conf-low { background: var(--bad-soft); color: var(--bad); }
.conf-high.active { background: var(--ok); border-color: var(--ok); color: #fff; }
.conf-medium.active { background: var(--review-edge); border-color: var(--review-edge); color: #3d2f00; }
.conf-low.active { background: var(--bad); border-color: var(--bad); color: #fff; }

/* --- why / detail ---
   The Why column is a closed set of sentences, worded identically on every row,
   so a column of six hundred can be scanned. The row's own specifics - which
   domain, which competing company - live in Detail beside it. Splitting them is
   what makes the column groupable by eye; one free-text column never was. */

td.why { max-width: 280px; }
.reason-tag {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .2px;
  background: #eef1f5; color: var(--muted); white-space: nowrap;
}
.reason-sentence { font-size: 12px; color: #3a424e; margin-top: 4px; line-height: 1.45; }

/* Only the reasons that mean something happened to the row get a colour. The
   routine ones stay grey so the exceptions are what the eye lands on. */
.reason-domain_conflict { background: var(--bad-soft); color: var(--bad); }
.reason-merged { background: var(--edit-soft); color: var(--edit); }
.reason-enriched { background: var(--accent-soft); color: var(--accent); }
.reason-no_domain { background: var(--review); color: #7a5c00; }
.reason-model_unavailable { background: var(--bad-soft); color: var(--bad); }

/* Auto-approved is not "approved". A steward has to be able to see which rows a
   human actually looked at. */
.pill-auto { background: #eef1f5; color: var(--muted); }

.sort-form { display: flex; align-items: center; gap: 6px; }
.sort-form select { font-size: 12.5px; padding: 3px 6px; }

/* --- groups ---------------------------------------------------------------

   A batch is not a flat list of companies; it is a list of LIMS parents, each
   of which the pipeline may have split into several. Reading it flat is what
   made "which company in the source made us go and find this domain?"
   unanswerable, so the parent is now the visible unit and every row carries its
   handle. */

tbody.group { border-bottom: 2px solid var(--border); }

/* Group and Source company are merged down the side of each group with rowspan
   and centred in it, so a parent is named once next to all the companies that
   came out of it rather than repeated on every row. */
td.gcell {
  vertical-align: middle; text-align: center;
  background: var(--accent-soft);
  border-right: 1px solid var(--border);
  padding: 8px 8px;
}
td.gcell-parent { text-align: center; }

.gid {
  display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; font-weight: 700; letter-spacing: .3px;
  color: #fff; background: var(--accent);
  padding: 2px 6px; border-radius: 4px;
}

.gparent { font-weight: 600; font-size: 13px; line-height: 1.3; }
.gmeta { color: var(--muted); font-size: 11px; margin-top: 4px; line-height: 1.5; }

/* --- the two domain columns ---

   Origin is carried by the column a domain sits in, not by a tag beside it.
   Colour still separates them, but the layout is what does the work: one column
   is what the workbook gave us, the next is what we added to it. */

td.dom-col { line-height: 1.7; }
.dom-empty { color: #b6bcc7; }

.dom {
  display: inline-block; font-size: 12px; text-decoration: none;
  padding: 1px 5px; margin: 0 3px 2px 0; border-radius: 3px;
  border: 1px solid transparent; word-break: break-all;
}
a.dom:hover { text-decoration: underline; border-color: currentColor; }
.dom-source { color: var(--accent); background: #f4f6f9; }
/* Enrichment is the claim that needs the most scrutiny, so it is the one thing
   in the row with a visible edge. */
.dom-enriched { color: var(--edit); background: var(--edit-soft); border-color: #d9ccf5; }
.dom-added { color: var(--ok); background: var(--ok-soft); }
.dom-placeholder { color: var(--muted); background: #f1f3f6; font-style: italic; }

/* Anything in the enriched column that is not an agent discovery says so, so
   the column is never read as a bigger claim than it is. */
.dom-tag {
  margin-left: 4px; font-size: 9px; text-transform: uppercase; letter-spacing: .3px;
  opacity: .75; font-style: normal;
}

.dom-note { color: var(--muted); font-size: 11px; font-style: italic; margin-top: 2px; }

.dom-edit, .context-toggle {
  display: inline-block; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--muted); font-size: 11px; text-decoration: underline;
  font-family: inherit;
}
.dom-edit { margin-top: 3px; }
.dom-edit:hover, .context-toggle:hover { color: var(--accent); }

tr.group-context-toggle td { padding: 4px 10px; border-bottom: 1px solid #eef0f3; }

/* Context rows are siblings pulled in to explain a group, not work. They are
   dimmed and inset so that expanding a group never looks like the queue grew. */
tbody tr.is-context > td { background-color: #fbfbfc; opacity: .75; }
tbody tr.is-context > td:first-child { box-shadow: inset 3px 0 0 #dfe3e8; }

/* --- source lineage ---

   The AR breadcrumb, and the workbook rows behind it. Collapsed by default: it
   answers a question a steward asks on a minority of rows, and open by default
   it would triple the height of every row in the table. */

details.lineage { margin-top: 4px; }
details.lineage > summary {
  cursor: pointer; font-size: 11px; list-style: none;
  display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap;
}
details.lineage > summary::-webkit-details-marker { display: none; }
details.lineage > summary::before { content: "\25B8"; color: var(--muted); font-size: 9px; }
details.lineage[open] > summary::before { content: "\25BE"; }

.ar {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--accent); background: var(--accent-soft);
  padding: 1px 5px; border-radius: 3px; font-size: 11px;
}

table.lineage-table {
  margin-top: 5px; width: 100%; border-collapse: collapse; font-size: 11px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
table.lineage-table th {
  text-align: left; font-weight: 600; color: var(--muted); font-size: 10px;
  text-transform: uppercase; letter-spacing: .3px;
  padding: 4px 6px; border-bottom: 1px solid var(--border); background: transparent;
}
table.lineage-table td {
  padding: 3px 6px; border-bottom: 1px solid #f1f3f6; vertical-align: top;
}
table.lineage-table tr:last-child td { border-bottom: 0; }
table.lineage-table td:first-child {
  border-right: 1px solid var(--border); white-space: nowrap;
}
table.lineage-table td div { line-height: 1.4; }

.lineage-source {
  display: inline-block; margin-top: 4px; font-size: 11px;
  color: var(--muted); text-decoration: underline;
}
.lineage-source:hover { color: var(--accent); }

/* --- discarded domains ---

   What the source offered and screening declined. Merged over the group like
   the parent name, because screening happens before a parent is split into
   companies. Muted throughout: this column exists so a steward can check that
   nothing was thrown away wrongly, not to compete with the work. */

td.gcell-discarded { text-align: left; vertical-align: middle; }

.discard { margin-bottom: 5px; line-height: 1.35; }
.discard:last-child { margin-bottom: 0; }
.discard-domain {
  font-size: 12px; color: var(--muted); text-decoration: line-through;
  text-decoration-color: #c3c9d4; word-break: break-all;
}
.discard-why {
  font-size: 10px; text-transform: uppercase; letter-spacing: .3px;
  background: #eceef2; color: var(--muted);
  padding: 1px 4px; border-radius: 3px; margin-left: 3px; white-space: nowrap;
}
/* A model judgement is the one exclusion that is a decision about a real
   domain rather than a rule, so it is the one that has to catch the eye. */
.discard-review .discard-why { background: #fdf0c8; color: #7a5c00; }
/* A small link to the actual source rows behind a dropped domain; the cell
   itself stays about which domains were dropped and why. */
.discard-rows {
  font: inherit; font-size: 10px; color: var(--accent); margin-left: 4px;
  white-space: nowrap; text-decoration: underline; cursor: pointer;
  background: none; border: 0; padding: 0;
}
.discard-rows:hover { color: var(--accent); text-decoration: none; }

/* --- the row-detail modal -------------------------------------------------

   One <dialog> serves every row; HTMX swaps its body and keys.js calls
   showModal(). The dialog is the card itself (padding 0, so a click anywhere
   that is not a child lands on the ::backdrop and closes it), a comfortable
   width, and scrolls inside rather than growing the page. */
dialog.row-modal {
  width: min(1080px, 94vw); max-height: 88vh; padding: 0; border: 0;
  border-radius: 12px; box-shadow: 0 24px 60px rgba(15, 22, 38, .35);
  overflow: hidden; position: fixed; inset: 0; margin: auto;
}
dialog.row-modal::backdrop { background: rgba(18, 24, 38, .55); }
.row-modal-body {
  overflow: auto; max-height: 88vh; padding: 22px 26px 26px;
}
.modal-close {
  position: absolute; top: 10px; right: 12px; z-index: 2;
  width: 30px; height: 30px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--surface); color: var(--muted); font-size: 20px; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.modal-close:hover { color: var(--text); border-color: var(--muted); }

.modal-title { font-size: 19px; margin: 0 40px 2px 0; }
.modal-sub { color: var(--muted); font-size: 12.5px; margin: 0 0 12px; }
.modal-domain { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--accent); }

/* The at-a-glance summary of what the row's cells say, before the detail. */
.modal-summary {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 18px;
  padding: 12px 0 14px; margin: 6px 0 4px; border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.ms-item { font-size: 13px; }
.ms-item.ms-wide { grid-column: 1 / -1; }
.ms-label {
  display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); margin-bottom: 2px;
}
.ms-domains .dom { margin: 0 4px 3px 0; }

.modal-section { margin-top: 18px; }
.modal-section h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
  margin: 0 0 8px; padding-bottom: 4px; border-bottom: 1px solid #eef0f3;
}
/* The headline of the Why section: the reason badge and its one-line meaning,
   aligned so the badge reads as a label on the sentence beside it. */
.modal-headline {
  display: flex; gap: 8px; align-items: baseline; margin: 4px 0 8px;
  font-size: 13px; color: var(--text); line-height: 1.5;
}
.modal-headline .reason-tag { flex: none; }

/* Each source on one line: [what kind] [what it says] [link]. The badge and the
   link never wrap, so the eye can run down the kinds on the left and the "source"
   links on the right without reading the prose unless a line earns it. */
.modal-evidence { list-style: none; margin: 10px 0 0; padding: 0; }
.modal-evidence li {
  display: grid; grid-template-columns: auto 1fr auto; gap: 4px 10px;
  align-items: baseline; padding: 8px 0; border-top: 1px solid #eef0f3;
  font-size: 12.5px; color: #3a424e; line-height: 1.5;
}
.ev-kind {
  flex: none; font-size: 10px; text-transform: uppercase; letter-spacing: .3px;
  font-weight: 600; color: var(--muted); background: #eef1f5;
  padding: 1px 8px; border-radius: 999px; white-space: nowrap;
}
.ev-text { min-width: 0; }
.ev-source { color: var(--accent); white-space: nowrap; font-size: 12px; text-decoration: none; }
.ev-source:hover { text-decoration: underline; }
.modal-section .lineage-source { display: inline-block; margin-top: 10px; }

/* The accounts table can be wider than the modal on a row with several ARs, so
   it scrolls within its own strip rather than clipping its rightmost column. */
.lineage-scroll { overflow-x: auto; }
.lineage-scroll .lineage-table { min-width: 560px; }

/* The source-rows page (opened in its own tab): the workbook rows verbatim. */
.source-rows-page { padding: 20px; }
.source-rows-page h1 { font-size: 17px; margin: 0 0 14px; }
.source-rows-scroll { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.source-rows-table { border-collapse: collapse; font-size: 12px; white-space: nowrap; }
.source-rows-table th, .source-rows-table td {
  border: 1px solid #e6e9ee; padding: 4px 8px; text-align: left; vertical-align: top;
}
.source-rows-table thead th {
  position: sticky; top: 0; background: #eef1f5; color: var(--muted);
  font-size: 11px; text-transform: uppercase; letter-spacing: .3px;
}
.source-rows-table .src-rownum { color: var(--muted); font-variant-numeric: tabular-nums; }
.source-rows-table tbody tr:nth-child(even) { background: #fafbfc; }

/* A LIMS parent folded into another company by reconciliation. It has no group
   of its own, so this line is the only place it appears - and the only answer
   to "what happened to it?". */
.gmerged { font-size: 10px; color: var(--muted); margin-top: 3px; line-height: 1.5; }
.gmerged span {
  display: inline-block; background: #eceef2; border-radius: 3px;
  padding: 0 4px; margin: 1px 2px 0 0;
}

/* --- source-rows button on the company cell ---

   The AR breadcrumb read as inert text, so a steward never realised it opened
   anything. This is a plain, obvious link that opens the workbook rows behind the
   company in a new tab - the primary affordance; the AR expander below it is now
   secondary. */
.lineage-rows {
  display: inline-block; margin-top: 4px; font: inherit; font-size: 11px; font-weight: 600;
  color: var(--accent); text-decoration: none; cursor: pointer;
  border: 1px solid var(--accent-soft); background: var(--accent-soft);
  padding: 2px 8px; border-radius: 4px;
}
.lineage-rows:hover { border-color: var(--accent); background: #e4ebf5; }

/* The Source (LIMS) column, flat view only. Muted: it is the bucket the row came
   in under, context for the mapped company beside it, not the decision. */
td.source-parent { color: var(--muted); font-size: 12px; line-height: 1.3; }

/* --- the two-view toggle in the toolbar --- */
.layout-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; }
.layout-toggle .btn.active {
  background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 600;
}

/* --- parent-company view: full-width group header ---

   The parent is named once above its rows rather than merged down the side, so
   the header is a single full-width cell. Single-company parents get no header at
   all (see `_parent_group.html`), which is the fix for "no groups for many rows". */
tr.pgroup-head > td {
  background: var(--accent-soft); border-bottom: 1px solid var(--border);
  padding: 6px 12px;
}
.pghead { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
.pgname { font-weight: 700; font-size: 14px; }
.pgmeta { color: var(--muted); font-size: 11px; }
.pgabsorbed { font-size: 10px; color: var(--muted); }
.pgabsorbed span {
  display: inline-block; background: #eceef2; border-radius: 3px;
  padding: 0 4px; margin: 0 2px;
}
/* Discarded domains ride along the header, dropped under one of the parents these
   companies came in under. Kept compact so the header stays one band, not a wall. */
.pgdiscarded { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; font-size: 11px; }
.pgdiscarded-label {
  font-size: 10px; text-transform: uppercase; letter-spacing: .3px; color: var(--muted);
}
/* A group's own rows sit tight under its header, with a hairline before the next
   group so the boundaries read without a heavy rule. */
tbody.pgroup { border-bottom: 2px solid var(--border); }

/* The incremental download. Distinguished from the two full-sheet buttons
   because it is the one with a side effect: taking it moves the line the next
   one is measured from. */
.btn-changes { border-color: var(--edit); color: var(--edit); font-weight: 600; }
.btn-changes:hover { background: var(--edit-soft); }
.btn-disabled { opacity: .5; cursor: default; }

/* --- confidence, explained -------------------------------------------------

   The score is the column a steward sorts by, so it is where they ask what it
   means. The method sits under the number permanently and the full sentence is
   on the cell's title, which keeps a 600-row column scannable while putting the
   answer one hover away rather than in a document nobody opens. */

td.conf-cell { cursor: help; }
.conf-basis {
  font-size: 9.5px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .3px; font-weight: 600; margin-top: 2px; line-height: 1.2;
  white-space: normal;
}

/* --- outcomes that carry a reason -----------------------------------------

   Modified is its own outcome, not a shade of approved: both load into MDM, and
   only one of them says the agent was right. */

.pill-mod { background: var(--edit-soft); color: var(--edit); }
.btn-mod { border-color: #d9ccf5; color: var(--edit); }
.btn-mod:hover { background: var(--edit-soft); }

/* Why the system approved a row nobody opened. Collapsed by default - it is
   reassurance a steward reaches for, not something to read six hundred times. */
.auto-why { margin-top: 4px; font-size: 11px; }
.auto-why summary { cursor: pointer; color: var(--muted); text-decoration: underline; }
.auto-why p { margin: 4px 0 0; color: #4a5568; line-height: 1.45; }

/* The steward's own words. Newest first, all of them kept: a row modified twice
   has two reasons, and the second does not replace the first. */
ul.notes { list-style: none; margin: 6px 0 0; padding: 0; font-size: 11.5px; }
ul.notes li {
  margin: 0 0 4px; padding: 4px 6px; line-height: 1.4;
  background: #f7f8fa; border-left: 2px solid var(--border); border-radius: 2px;
}

/* The reason box sits inside the row rather than in a modal: a steward writing
   what is wrong with a row wants to keep reading it while they type. */
.reason-box { margin-top: 6px; white-space: normal; min-width: 210px; }
.reason-box label { display: block; font-size: 11px; color: var(--muted); }
.reason-box textarea {
  width: 100%; margin-top: 3px; font-size: 12px; resize: vertical;
  font-family: inherit; padding: 4px 5px;
}
.reason-actions { display: flex; gap: 5px; margin-top: 4px; }

/* A run can be degraded in more than one way at once - the model unreachable
   and the searches rate limited - so the banner carries a paragraph per reason
   rather than one run-on block that buries the second. */
.banner-reason { margin: 4px 0 0; line-height: 1.45; }
.banner-reason:first-of-type { margin-top: 2px; }

/* --- account nav + admin portal + account page --- */
.account-nav { display: flex; align-items: center; gap: 14px; margin-left: auto; }
.account-nav a { color: #fff; text-decoration: none; font-size: 13px; opacity: .9; }
.account-nav a:hover { opacity: 1; text-decoration: underline; }

.admin-panel, .account-panel { max-width: 760px; margin: 24px auto; padding: 0 16px; }
.admin-panel h1, .account-panel h1 { font-size: 20px; margin: 0 0 16px; }
.admin-panel h2 { font-size: 16px; margin: 28px 0 10px; }

.users-table { width: 100%; border-collapse: collapse; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.users-table th, .users-table td { text-align: left; padding: 9px 12px;
  border-bottom: 1px solid var(--border); font-size: 13px; vertical-align: middle; }
.users-table th { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.users-table tr:last-child td { border-bottom: none; }
.users-table .user-name { font-weight: 600; }

.inline-form { display: flex; gap: 6px; }
.inline-form input { flex: 1; min-width: 0; }

.add-user-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; }
.add-user-form label { display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--muted); }
.add-user-form label.checkbox { flex-direction: row; align-items: center;
  gap: 6px; font-size: 13px; color: var(--text); }
.account-form { display: flex; flex-direction: column; gap: 12px; max-width: 360px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; }
.account-form label { display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--muted); }

.admin-panel input[type=text], .admin-panel input[type=password],
.account-form input[type=password] {
  padding: 7px 9px; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 13px; }
.admin-panel button, .account-form button { padding: 7px 14px; border: none;
  border-radius: var(--radius); background: var(--accent); color: #fff;
  font-size: 13px; cursor: pointer; }
.admin-panel button:hover, .account-form button:hover { filter: brightness(1.08); }
.admin-panel button.danger { background: var(--bad); }

.form-error { background: var(--bad-soft); color: var(--bad); border: 1px solid var(--bad);
  border-radius: var(--radius); padding: 9px 12px; font-size: 13px; margin: 0 0 14px; }
.form-ok { background: var(--ok-soft); color: var(--ok); border: 1px solid var(--ok);
  border-radius: var(--radius); padding: 9px 12px; font-size: 13px; margin: 0 0 14px; }
.policy-note { color: var(--muted); font-size: 12px; margin: 10px 0 0; }

/* Who decided a row - a quiet attribution next to the status pills. */
.decided-by { display: inline-block; margin-left: 4px; font-size: 11px;
  color: var(--muted); white-space: nowrap; }

/* Show/hide toggle beside a password field (see pw.js). */
.pw-toggle { margin-left: 8px; margin-top: 4px; padding: 2px 8px;
  font-size: 11px; color: var(--accent); background: transparent;
  border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; }
.pw-toggle:hover { background: var(--accent-soft); }
.inline-form .pw-toggle { margin-top: 0; }

/* Editable company boxes are auto-growing textareas: a long parent or operating
   company name wraps and stays fully readable at rest, instead of clipping to the
   column width. keys.js sets each one's height to its content. */
td.company .cell-edit,
td.ai-owner-col .cell-edit {
  width: 100%; box-sizing: border-box; resize: none; overflow: hidden;
  white-space: pre-wrap; overflow-wrap: anywhere; min-height: 2.1em;
  font: inherit; line-height: 1.35; padding: 5px 7px; color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius); background: #fff; }
td.company .cell-edit:focus,
td.ai-owner-col .cell-edit:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft); }

/* Custom autocomplete dropdown for the wrapping company boxes (see keys.js). */
.cell-suggest { display: none; position: fixed; z-index: 40; margin: 0; padding: 4px 0;
  list-style: none; max-height: 260px; overflow-y: auto; max-width: 60vw;
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .18); font-size: 13px; }
.cell-suggest li { padding: 6px 12px; cursor: pointer; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.cell-suggest li:hover, .cell-suggest li.active { background: var(--accent-soft); }

/* The "Approved by" column - a quiet, compact name. */
td.col-approver { font-size: 12px; color: var(--muted); white-space: nowrap; }
