:root {
  color-scheme: light;
  font-family: "Segoe UI", "Inter", system-ui, Arial, sans-serif;
  --bg: #eef1f5;
  --panel: #ffffff;
  --panel-alt: #f8fafc;
  --ink: #16212e;
  --ink-soft: #334155;
  --muted: #5d6978;
  --faint: #94a3b8;
  --border: #dbe1e8;
  --border-soft: #eef2f6;
  --navy-900: #0b1b2d;
  --navy-800: #0e2038;
  --navy-700: #12263d;
  --brand: #f26722;
  --brand-dark: #d8531a;
  --accent: #146c94;
  --accent-dark: #0d4f6c;
  --accent-soft: #e9f4f8;
  --warning-bg: #fff6dc;
  --warning-ink: #8d6200;
  --danger-bg: #fce8e8;
  --danger-ink: #9b2c2c;
  --success-bg: #edf8ee;
  --success-ink: #1c6a38;

  /* Change Map state colours. Colour is never the only signal: states also differ
     by icon shape, solid vs dashed connectors, and accessible labels. */
  --cm-approved: #16a34a;
  --cm-mint: #45bfae;
  --cm-mint-bg: #eefaf7;
  --cm-hours: #f97316;
  --cm-hours-bg: #fff4ea;
  --cm-wording: #c78a04;
  --cm-wording-bg: #fdf7e7;
  --cm-task: #e8604c;
  --cm-task-bg: #fdf0ee;
  --cm-clarification: #2563eb;
  --cm-clarification-bg: #eef3fe;
  --cm-internal: #dc2626;
  --cm-internal-bg: #fdecec;
  --cm-accounts: #7c3aed;
  --cm-accounts-bg: #f6f1fd;
  --cm-writeoff: #0d9488;
  --cm-writeoff-bg: #ecf9f7;
  --cm-rejected: #475569;
  --cm-rejected-bg: #f1f5f9;
  /* Director Return Update — a magenta unused by any other Change Map state, so a line sent back
     by a director or finance admin cannot be mistaken for an AI suggestion or a clarification. */
  --cm-director-return: #c026a3;
  --cm-director-return-bg: #fdeefa;
}

* {
  box-sizing: border-box;
}

/* Author display rules (grid/flex) must never resurrect [hidden] elements. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  min-height: 100vh;
  font-size: 14px;
}

button,
input,
select,
textarea {
  font: inherit;
}

button {
  min-height: 34px;
  border: 1px solid var(--accent-dark);
  background: var(--accent);
  color: white;
  padding: 6px 12px;
  border-radius: 7px;
  cursor: pointer;
}

button.secondary {
  background: white;
  color: var(--accent-dark);
  border-color: var(--border);
}

button.secondary:hover:not(:disabled) {
  border-color: var(--faint);
}

button.danger {
  background: #c0392b;
  border-color: #a1291d;
  color: #fff;
}

button.danger:hover:not(:disabled) {
  background: #a1291d;
}

button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

h2,
h3,
h4 {
  margin: 0;
}

h3 {
  font-size: 13px;
  margin-bottom: 8px;
  color: #26313f;
}

h4 {
  font-size: 12px;
  margin-bottom: 6px;
  color: #26313f;
}

/* ---------- app navigation rail ---------- */

.app-nav {
  background: linear-gradient(180deg, var(--navy-900), var(--navy-700));
  color: #cdd8e6;
  display: flex;
  flex-direction: column;
  padding: 16px 12px;
  gap: 8px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.brand-lockup {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  padding: 2px 6px 14px;
}

.brand-mark {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--brand);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--brand);
  font-weight: 800;
  flex: none;
}

.app-nav-items {
  display: grid;
  gap: 3px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 11px;
  border-radius: 8px;
  color: #aebccd;
  font-weight: 600;
  font-size: 13px;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  min-height: 0;
}

.nav-item:hover:not(.disabled):not([aria-disabled="true"]) {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

.nav-item.active {
  background: var(--accent);
  color: #fff;
}

.nav-item.disabled,
.nav-item.locked {
  color: #5f7188;
  cursor: not-allowed;
}

.nav-item.locked {
  cursor: pointer;
}

.nav-ico {
  width: 16px;
  height: 16px;
  flex: none;
}

.nav-lock {
  margin-left: auto;
  display: inline-flex;
}

.nav-lock svg {
  width: 13px;
  height: 13px;
}

.nav-foot {
  margin-top: auto;
  padding: 10px 8px;
}

.nav-note {
  margin: 0;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  padding: 10px;
  font-size: 11.5px;
  line-height: 1.5;
  color: #b8c6d6;
}

/* ---------- main column ---------- */

.app-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 100vh;
}

.app-header {
  min-height: 62px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 18px;
  background: #ffffff;
  border-bottom: 1px solid var(--border);
}

.app-header h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
}

.app-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Xero-style work-in-progress reference chip (identifier only, never a value) */
.wip-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 5px;
  background: #eef1f4;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* inline analytical report tables (reviewer-safe: hours/counts only) */
.report-view-card { grid-column: 1 / -1; }

.report-summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0;
}

.report-summary-pill {
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 11px;
  font-size: 12px;
  color: var(--muted);
}

.report-table {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

.report-trow {
  display: grid;
  grid-template-columns: repeat(var(--report-cols, 4), minmax(0, 1fr));
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border-soft);
  font-size: 12.5px;
}

.report-trow:last-child { border-bottom: none; }
.report-trow span { overflow-wrap: anywhere; }

.report-thead {
  background: var(--panel-alt);
  font-weight: 700;
  color: var(--ink);
}

.report-table-wrap { margin-top: 6px; }

/* settings screen */
.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 14px;
}

.settings-panel {
  display: grid;
  gap: 4px;
  align-content: start;
}

.settings-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}

.settings-row:last-child {
  border-bottom: none;
}

.settings-row > span {
  color: var(--muted);
}

.settings-int {
  display: grid;
  justify-items: end;
  text-align: right;
}

.settings-int small {
  color: var(--muted);
  font-size: 11px;
  font-weight: 400;
}

.settings-note {
  color: var(--muted);
  font-size: 11.5px;
  padding: 6px 0 2px;
}

.settings-toggle-row {
  padding-top: 8px;
}

/* Project-manager tick list. Spans the full settings grid: it is a roster, and squeezing names,
   role groups and booked-hours evidence into one 320px column makes it unreadable. */
.settings-panel-wide {
  grid-column: 1 / -1;
}

.pm-directory-list {
  display: grid;
  gap: 2px;
  max-height: 340px;
  overflow-y: auto;
}

.pm-directory-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 6px;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
  cursor: pointer;
}

.pm-directory-row:last-child {
  border-bottom: none;
}

.pm-directory-row:hover {
  background: var(--panel-alt);
}

.pm-directory-row input[type="checkbox"] {
  flex: none;
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
  cursor: pointer;
}

.pm-directory-name {
  display: grid;
  gap: 1px;
  min-width: 0;
  flex: 1 1 auto;
}

.pm-directory-name strong {
  font-size: 13px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-directory-name small {
  color: var(--muted);
  font-size: 11px;
}

/* Booked-time evidence: hours and counts only. This panel is Director/Finance-gated, but it stays
   hours-only regardless so no value can leak through a future change of audience. */
.pm-directory-evidence {
  flex: none;
  color: var(--muted);
  font-size: 11px;
  text-align: right;
  white-space: nowrap;
}

.pm-directory-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 10px;
}

.pm-directory-actions .settings-note {
  padding: 0;
  flex: 1 1 auto;
}

/* sortable queue-table headers */
.queue-sort {
  min-height: 0;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.queue-sort:hover,
.queue-sort.active {
  color: var(--accent);
}

.source-warning {
  display: block;
  color: var(--warning-ink);
  background: var(--warning-bg);
  border-radius: 6px;
  padding: 4px 8px;
  margin-top: 4px;
  font-size: 11.5px;
}

/* nav-rail demo toggle: visible to all roles for now; restriction is a recorded follow-up */
.nav-demo-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  color: #d7e1ec;
  font-size: 12px;
  cursor: pointer;
}

.nav-demo-toggle input {
  accent-color: var(--cm-accounts);
}

/* demo isolation is always visibly flagged so demo data can't be mistaken for production */
.demo-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--cm-accounts);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  white-space: nowrap;
}

.app-header p,
#projectMeta {
  margin: 0;
  color: var(--muted);
  font-size: 12.5px;
}

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

.toolbar label,
.editor label {
  display: grid;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
}

.toolbar select,
.editor input,
.editor select,
.editor textarea,
.comment-box textarea,
.move-drawer select,
.move-drawer textarea {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 8px;
  background: white;
  color: var(--ink);
}

.app-shell {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  flex: 1;
  min-height: 0;
}

body.dashboard-active .app-shell {
  grid-template-columns: 1fr;
}

.app-footer {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  border-top: 1px solid var(--border);
  background: white;
  padding: 8px 18px;
  color: var(--muted);
  font-size: 12px;
}

#statusBar {
  flex: 1;
  min-height: 18px;
  color: var(--ink-soft);
  font-size: 12.5px;
}

.footer-note {
  white-space: nowrap;
}

/* ---------- sidebar (batch items + system panel) ---------- */

.item-list {
  border-right: 1px solid var(--border);
  background: #f3f5f8;
  padding: 14px;
  overflow: auto;
}

.item-list h2,
.workspace-head h2 {
  font-size: 15px;
}

.item-button {
  width: 100%;
  display: grid;
  gap: 4px;
  margin-top: 8px;
  text-align: left;
  color: var(--ink);
  background: white;
  border: 1px solid var(--border);
}

.item-button.active {
  border-color: var(--brand);
  box-shadow: inset 3px 0 0 var(--brand);
}

.item-button:disabled {
  color: var(--muted);
  background: #f7f8f9;
  border-color: var(--border);
}

.item-status {
  color: var(--muted);
  font-size: 12px;
}

.operations-panel {
  margin-top: 18px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}

.operations-panel summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink-soft);
}

.ops-note {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 11.5px;
  line-height: 1.45;
}

.stage-summary-panel {
  margin-top: 18px;
}

.compact-summary-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 10px;
  margin-bottom: 0;
}

.compact-summary-grid .summary-card {
  min-height: 84px;
}

.compact-summary-grid .summary-card strong {
  font-size: 20px;
}

.ops-grid {
  display: grid;
  gap: 7px;
  margin-top: 9px;
}

.ops-output {
  display: grid;
  gap: 4px;
  margin-top: 9px;
  padding: 9px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #ffffff;
  color: var(--muted);
  font-size: 12px;
}

.ops-output strong {
  color: var(--ink);
}

/* ---------- workspace ---------- */

.review-workspace {
  padding: 14px;
  overflow: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 236px;
  gap: 14px;
  align-items: start;
}

.workspace-main {
  min-width: 0;
}

/* ---------- right-side Review Actions rail (UX Image 1) ---------- */

.review-actions-rail {
  position: sticky;
  top: 0;
  display: grid;
  gap: 12px;
}

.rail-group {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  display: grid;
  gap: 8px;
}

.rail-group h3 {
  margin: 0 0 2px;
  font-size: 12.5px;
  font-weight: 700;
}

.rail-btn {
  width: 100%;
  min-height: 34px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}

.rail-btn:hover:not(:disabled) {
  background: #f8fafc;
}

.rail-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.rail-btn.rail-navy {
  background: var(--navy-700);
  border-color: var(--navy-700);
  color: #fff;
}

.rail-btn.rail-navy:hover:not(:disabled) {
  background: #1b3a57;
}

.rail-btn.rail-primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.rail-btn.rail-primary:hover:not(:disabled) {
  filter: brightness(1.05);
  background: var(--brand);
}

.rail-btn.rail-success {
  background: var(--cm-approved);
  border-color: #0f7a34;
  color: #fff;
}

.rail-btn.rail-success:hover:not(:disabled) {
  filter: brightness(1.05);
  background: var(--cm-approved);
}

.rail-btn.rail-danger {
  background: #c0392b;
  border-color: #a1291d;
  color: #fff;
}

.rail-btn.rail-danger:hover:not(:disabled) {
  filter: brightness(1.05);
  background: #c0392b;
}

/* A saturated colour (green/red/orange/navy) at the generic 55% opacity still reads as
   "clickable" — found live: a director saw a fully vivid green "Director Approve" on an item
   that hadn't reached their review stage, tried clicking it, and nothing happened (native
   disabled buttons fire no click event at all, so there was no error and no explanation either).
   Disabled coloured rail buttons now turn a clear, unambiguous neutral grey instead. */
.rail-btn.rail-navy:disabled,
.rail-btn.rail-primary:disabled,
.rail-btn.rail-success:disabled,
.rail-btn.rail-danger:disabled {
  background: #e2e8f0;
  border-color: #cbd5e1;
  color: #94a3b8;
  opacity: 1;
}

.rail-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink);
  cursor: pointer;
}

.rail-note {
  margin: 0;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--muted);
}

.issue-key-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
}

.issue-key-list li {
  display: flex;
  align-items: center;
  gap: 8px;
}

.key-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: var(--cm-color, #94a3b8);
}

.key-dot.state-awaiting {
  background: #fff;
  border: 2px dashed var(--cm-mint);
}

/* ---------- comparison grand-total rows ---------- */

.cmp-grand-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
  background: #eef2f7;
  border-top: 2px solid var(--border);
  font-weight: 700;
  font-size: 12.5px;
}

.grand-total-delta {
  margin-left: 8px;
  font-size: 11.5px;
  font-weight: 700;
}

.grand-total-delta.up { color: var(--cm-hours); }
.grand-total-delta.down { color: var(--cm-approved); }

/* ---------- top-bar icons (bell / help / avatar) ---------- */

.topbar-icons {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 6px;
  align-self: center;
}

/* first-class "Pull Data" (Xero import) header action */
.pull-data-button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  align-self: center;
  min-height: 34px;
  padding: 6px 14px;
  border: 1px solid var(--brand);
  background: var(--brand);
  color: #fff;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.pull-data-button:hover:not(:disabled) { filter: brightness(1.05); }
.pull-data-button:disabled { opacity: 0.6; cursor: not-allowed; }
.pull-data-button svg { width: 15px; height: 15px; }
.pull-data-button.loading svg { animation: pull-spin 0.8s linear infinite; }

@keyframes pull-spin { to { transform: rotate(360deg); } }

.icon-button {
  width: 32px;
  height: 32px;
  min-height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: #fff;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.icon-button svg {
  width: 17px;
  height: 17px;
}

.icon-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.user-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.help-popover {
  position: absolute;
  top: 40px;
  right: 0;
  z-index: 30;
  width: 250px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);
  padding: 12px;
  font-size: 12px;
}

.help-popover ul {
  margin: 8px 0;
  padding-left: 16px;
  display: grid;
  gap: 4px;
}

.help-popover kbd {
  background: #eef2f7;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0 4px;
  font-size: 11px;
}

.help-note {
  margin: 0;
  color: var(--muted);
}

.workspace-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}

.workspace-head-meta {
  display: grid;
  gap: 8px;
  min-width: 260px;
  justify-items: end;
}

.subbar-main {
  min-width: 0;
}

.subbar-title-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
}

.subbar-title-row h2 {
  font-size: 20px;
  font-weight: 700;
}

.link-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-dark);
  font-size: 12px;
  font-weight: 600;
}

.status-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}

.status-badge.tone-warning { background: var(--warning-bg); color: var(--warning-ink); }
.status-badge.tone-success { background: var(--success-bg); color: var(--success-ink); }
.status-badge.tone-danger { background: var(--danger-bg); color: var(--danger-ink); }

.safe-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border-radius: 8px;
  background: #eef2f6;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

.safe-shield {
  width: 13px;
  height: 13px;
  flex: none;
}

/* header workflow step tracker ("Step N of 8") */
.step-tracker {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  font-size: 12px;
}

.step-tracker .step-label {
  white-space: nowrap;
  font-weight: 600;
}

.step-tracker .track {
  display: flex;
  align-items: center;
}

.step-tracker .track-node {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #d3dae3;
  flex: none;
}

.step-tracker .track-node.done {
  background: var(--accent);
}

.step-tracker .track-node.active {
  background: var(--brand);
  box-shadow: 0 0 0 3px rgba(242, 103, 34, 0.22);
}

.step-tracker .track-seg {
  width: 16px;
  height: 2px;
  background: #d3dae3;
}

.step-tracker .track-seg.done {
  background: var(--accent);
}

.workspace-context-bar {
  margin-top: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
}

.workspace-context-bar p {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
}

.totals-overview,
.entry-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.summary-pill,
.tag {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0 8px;
  border-radius: 999px;
  background: #eef3f7;
  color: #314255;
  font-size: 12px;
}

.summary-pill.up,
.tag.success {
  background: var(--success-bg);
  color: var(--success-ink);
}

.summary-pill.down,
.tag.blocked,
.blocked {
  background: var(--danger-bg);
  color: var(--danger-ink);
}

.tag.note {
  background: var(--warning-bg);
  color: var(--warning-ink);
}

.tag.muted {
  background: #eef1f4;
  color: var(--muted);
}

.warning-panel {
  display: grid;
  gap: 8px;
  margin-bottom: 12px;
}

.warning-row,
.warning-empty {
  border: 1px solid #eadfb6;
  background: var(--warning-bg);
  color: var(--warning-ink);
  border-radius: 6px;
  padding: 9px 10px;
  font-size: 12px;
}

.warning-row {
  display: grid;
  gap: 2px;
}

/* ---------- issue summary strip ---------- */

.issue-strip {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

/* mockup-style summary chips: white card, coloured icon box, inline count + label */
.issue-tile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 13px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  flex: 1;
  min-width: 138px;
}

.issue-tile > div {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  white-space: nowrap;
}

.issue-tile strong {
  font-size: 19px;
  font-weight: 750;
  line-height: 1.1;
}

.issue-tile span {
  color: var(--muted);
  font-size: 11.5px;
}

/* outline variant (mockup "Accounts context (n)" chip) */
.issue-tile.issue-outline {
  border: 1px solid var(--cm-accounts);
  background: #fff;
  flex: 0 1 auto;
}

.issue-tile.issue-outline strong,
.issue-tile.issue-outline span {
  color: var(--cm-accounts);
}

.issue-ico {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.issue-ico svg {
  width: 16px;
  height: 16px;
}

.issue-task .issue-ico { background: var(--cm-task-bg); color: var(--cm-task); }
.issue-wording .issue-ico { background: var(--cm-wording-bg); color: var(--cm-wording); }
.issue-hours .issue-ico { background: var(--cm-hours-bg); color: var(--cm-hours); }
.issue-clarification .issue-ico { background: var(--cm-clarification-bg); color: var(--cm-clarification); }
.issue-writeoff .issue-ico { background: var(--cm-writeoff-bg); color: var(--cm-writeoff); }
.issue-changed .issue-ico { background: #eef2f7; color: #475569; }
.issue-pending .issue-ico { background: var(--cm-mint-bg); color: var(--cm-mint); }
.issue-accounts .issue-ico { background: var(--cm-accounts-bg); color: var(--cm-accounts); }

/* ---------- review toolbar ---------- */

.review-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 12px;
  margin-bottom: 12px;
  position: sticky;
  top: 0;
  z-index: 4;
  box-shadow: 0 2px 6px rgba(15, 30, 50, 0.05);
}

.toolbar-nav,
.toolbar-progress,
.toolbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.toolbar-stat {
  color: var(--muted);
  font-size: 12.5px;
  white-space: nowrap;
}

.progress-track {
  width: 140px;
  height: 7px;
  border-radius: 999px;
  background: #e2e8f0;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--cm-approved);
  transition: width 0.25s ease;
}

.save-state {
  color: var(--success-ink);
  font-weight: 600;
}

.save-state.saving {
  color: var(--warning-ink);
}

.keyboard-hint {
  color: var(--faint);
  font-size: 11.5px;
  white-space: nowrap;
}

/* ---------- comparison grid ---------- */

.comparison-panel {
  padding: 0;
  overflow: hidden;
  margin-bottom: 12px;
}

.comparison-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-alt);
}

.comparison-filters:empty {
  display: none;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.filter-chip:hover {
  border-color: var(--faint);
}

.filter-chip.active {
  background: var(--navy-800);
  border-color: var(--navy-800);
  color: #fff;
}

.filter-chip .chip-count {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.filter-chip.active .chip-count {
  color: #cbd5e1;
}

.filter-chip.bulk-approve {
  margin-left: auto;
  background: var(--success-bg);
  border-color: #cce3d0;
  color: var(--success-ink);
}

.filter-chip.bulk-approve:hover {
  border-color: var(--cm-approved);
}

.compare-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 118px minmax(0, 1fr);
  /* default connector colour; per-row .state-* classes override it */
  --cm-color: var(--faint);
}

.compare-contents {
  display: contents;
}

.compare-header {
  background: var(--panel-alt);
  border-bottom: 1px solid var(--border);
  padding: 10px 12px 6px;
}

.compare-title {
  font-weight: 700;
  font-size: 13.5px;
  color: #26313f;
}

.compare-header-meta {
  color: var(--muted);
  font-weight: 400;
  font-size: 11.5px;
  margin-left: 6px;
}

.cm-column-header {
  text-align: center;
}

.col-labels {
  display: grid;
  grid-template-columns: 24px 76px 46px minmax(0, 1fr) 34px 92px;
  gap: 6px;
  margin-top: 8px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

.col-labels .num {
  text-align: right;
}

.cmp-group {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: #f1f5f9;
  border-bottom: 1px solid var(--border-soft);
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 650;
  color: var(--ink-soft);
}

.group-hours {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cm-group-spacer {
  background: #f1f5f9;
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  justify-content: center;
}

.cm-group-spacer::after {
  content: "";
  border-left: 2px dotted #cbd5e1;
}

/* comparison rows: shared grid rows keep left, map, and right aligned */

.cmp-row {
  display: grid;
  grid-template-columns: 24px 76px 46px minmax(0, 1fr) 34px 92px;
  gap: 6px;
  align-items: start;
  text-align: left;
  background: #fff;
  border: none;
  border-bottom: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 8px 12px;
  color: var(--ink);
  font-size: 12.5px;
  cursor: pointer;
  min-height: 0;
}

.cmp-row:hover {
  background: #f8fafc;
}

.cmp-row .row-num {
  color: var(--faint);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.cmp-row .cell.date {
  color: var(--muted);
  white-space: nowrap;
}

.cmp-row .cell.hours {
  font-variant-numeric: tabular-nums;
}

.cmp-row .cell.num {
  text-align: right;
}

.cmp-row .cell.desc {
  line-height: 1.4;
  min-width: 0;
  overflow-wrap: anywhere;
}

.cmp-row .cell.staff {
  color: var(--muted);
  font-weight: 600;
}

.cmp-row .cell.task {
  color: var(--muted);
  font-size: 11.5px;
  overflow-wrap: anywhere;
  position: relative;
}

/* inline edit pencil on suggested rows */
.cmp-row .row-edit {
  min-height: 0;
  margin-left: 6px;
  padding: 1px 5px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.4;
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.12s ease;
}

.cmp-row:hover .row-edit,
.cmp-row.selected .row-edit,
.cmp-row .row-edit:focus-visible {
  opacity: 1;
}

.cmp-row .row-edit:hover {
  border-color: var(--brand);
  color: var(--brand);
}

.cmp-row.inline-editing {
  background: #fff8f2;
  box-shadow: inset 0 0 0 2px var(--brand);
  cursor: default;
}

.cmp-row .inline-hours {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 5px;
  font: inherit;
  font-size: 12px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.inline-desc-cell {
  display: grid;
  gap: 6px;
}

.cmp-row .inline-desc {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 7px;
  font: inherit;
  font-size: 12.5px;
  resize: vertical;
}

.cmp-row .inline-task {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 5px;
  font: inherit;
  font-size: 11.5px;
  background: #fff;
  color: var(--ink);
}

.inline-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.inline-actions .inline-save {
  min-height: 0;
  padding: 3px 10px;
  border-color: var(--accent-dark);
  background: var(--accent);
  color: #fff;
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
}

.inline-actions .inline-cancel {
  min-height: 0;
  padding: 3px 10px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--ink-soft);
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
}

.inline-hint {
  color: var(--faint);
  font-size: 10.5px;
}

.prev-alloc {
  display: block;
  color: var(--faint);
  font-size: 10.5px;
  margin-top: 2px;
  line-height: 1.35;
}

/* original values being corrected: restrained red treatment on the value only */
.cmp-row.before .flagged {
  color: #b3261e;
}

/* proposed values on the suggested side take the row's state colour */
.cmp-row .proposed {
  color: var(--cm-color, var(--ink));
  font-weight: 600;
}

/* once approved, accepted revised values read green */
.cmp-row.after.resolved .proposed {
  color: var(--cm-approved);
}

.line-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 5px;
}

.line-chip {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  background: #eef1f4;
  color: var(--muted);
}

/* state colour custom property per row */
.state-approved-clean { --cm-color: var(--cm-approved); }
.state-awaiting { --cm-color: var(--cm-mint); }
.state-hours { --cm-color: var(--cm-hours); }
.state-wording { --cm-color: var(--cm-wording); }
.state-task { --cm-color: var(--cm-task); }
.state-clarification { --cm-color: var(--cm-clarification); }
.state-internal { --cm-color: var(--cm-internal); }
.state-accounts { --cm-color: var(--cm-accounts); }
.state-writeoff { --cm-color: var(--cm-writeoff); }
.state-rejected { --cm-color: var(--cm-rejected); }
.state-director-return { --cm-color: var(--cm-director-return); }

/* suggested-side row tints (pending states use the incomplete pale treatment) */
.cmp-row.after.state-awaiting { background: var(--cm-mint-bg); }
.cmp-row.after.pending.state-hours { background: var(--cm-hours-bg); }
.cmp-row.after.pending.state-wording { background: var(--cm-wording-bg); }
.cmp-row.after.pending.state-task { background: var(--cm-task-bg); }
.cmp-row.after.state-clarification { background: var(--cm-clarification-bg); }
.cmp-row.after.pending.state-internal { background: var(--cm-internal-bg); }
.cmp-row.after.pending.state-accounts { background: var(--cm-accounts-bg); }
.cmp-row.after.pending.state-writeoff { background: var(--cm-writeoff-bg); }
.cmp-row.after.state-rejected { background: var(--cm-rejected-bg); }
/* Not gated on .pending, unlike the AI-suggestion tints above: a returned line has been reverted
   to its original state so it carries no diff, and a .pending-only rule would leave it untinted —
   the reviewer would lose the colour exactly on the rows that most need it. */
.cmp-row.after.state-director-return { background: var(--cm-director-return-bg); }

/* Written off / non-billable: struck through so it reads at a glance as "not on the invoice".
   These rows are also sorted to the bottom of their task heading (see displayGroups in app.js).
   The strike is applied to the text cells, not the row, so the row's own chrome (chips, the
   inline-edit pencil) stays legible. */
.cmp-row.after.written-off .cell.date,
.cmp-row.after.written-off .cell.hours,
.cmp-row.after.written-off .cell.desc,
.cmp-row.after.written-off .cell.staff,
.cmp-row.after.written-off .cell.task {
  text-decoration: line-through;
  color: var(--muted);
}

/* The chips and the inline-edit pencil sit inside those cells, so lift the strike back off them
   — a struck-through "Non-billable" chip or pencil icon just reads as broken. */
.cmp-row.after.written-off .line-chips,
.cmp-row.after.written-off .row-edit,
.cmp-row.after.written-off .prev-alloc {
  text-decoration: none;
}

.line-chip.chip-awaiting { background: var(--cm-mint-bg); color: #1c7f72; }
.line-chip.chip-hours { background: var(--cm-hours-bg); color: var(--cm-hours); }
.line-chip.chip-wording { background: var(--cm-wording-bg); color: var(--cm-wording); }
.line-chip.chip-task { background: var(--cm-task-bg); color: var(--cm-task); }
.line-chip.chip-clarification { background: var(--cm-clarification-bg); color: var(--cm-clarification); }
.line-chip.chip-internal { background: var(--cm-internal-bg); color: var(--cm-internal); }
.line-chip.chip-accounts { background: var(--cm-accounts-bg); color: var(--cm-accounts); }
.line-chip.chip-writeoff { background: var(--cm-writeoff-bg); color: var(--cm-writeoff); }
.line-chip.chip-rejected { background: var(--cm-rejected-bg); color: var(--cm-rejected); }
.line-chip.chip-approved-clean { background: var(--success-bg); color: var(--success-ink); }
.line-chip.chip-muted { background: #eef1f4; color: var(--muted); }

/* selection is visible across all three surfaces, not colour-only (outline + weight) */
.cmp-row.selected {
  background: #fff8f2;
  box-shadow: inset 0 0 0 2px var(--brand);
}

.cm-row.selected {
  background: #fff8f2;
  box-shadow: inset 0 0 0 2px var(--brand);
  border-radius: 8px;
}

/* ---------- change map rail ---------- */

/* Drawn per UX Image 1: every row connects current -> suggested with a state-coloured
   dot, line, central badge, line, and an arrowhead into the Suggested Revision side.
   Awaiting-review rows use a dashed connector + hollow badge (incomplete, never blank). */
.cm-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: none;
  background: #fff;
  border-bottom: 1px solid var(--border-soft);
  padding: 6px 6px;
  cursor: pointer;
  min-height: 0;
}

.cm-row:hover {
  background: #f8fafc;
}

.cm-row::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: #e2e8f0;
}

.cm-row:first-of-type::before {
  top: 50%;
}

.cm-row:last-of-type::before {
  bottom: 50%;
}

.cm-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cm-color, #94a3b8);
  flex: none;
}

.cm-line {
  flex: 1;
  min-width: 6px;
  height: 0;
  border-top: 2px solid var(--cm-color, #cbd5e1);
}

/* arrowhead pointing into the Suggested Revision side */
.cm-arrow {
  width: 0;
  height: 0;
  flex: none;
  margin-left: -4px;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 6px solid var(--cm-color, #cbd5e1);
}

/* 2026-07-26 redesign, revised twice same day per Zac's direct spec. Every row (pending or
   resolved) renders the full dot-line-badge-line-arrowhead-dot structure, so the badge always
   sits exactly centred on the rail — both connector segments share the same flex-grow, so the
   badge lands in the true middle instead of being pushed off-centre by an asymmetric layout.
   The right-hand segment (.cm-line-right) is only PAINTED for resolved rows; for pending rows
   it stays present (reserving its share of the centring space) but invisible, so the badge and
   arrowhead read as a real, visible gap rather than a fully connected chain — see
   .cm-row.pending .cm-line-right below. Pending rows are uniformly black (dot, line, arrowhead —
   not the type colour) via .cm-row.pending{--cm-color:#000}; resolved rows (except rejected)
   recolour the WHOLE connector to match the resulting icon via
   .cm-row.resolved:not(.state-rejected){--cm-color:var(--cm-approved)} — not just the badge,
   since --cm-color also drives .cm-dot/.cm-line/.cm-arrow. Superseded the earlier design, where
   a pending row had no right-hand element at all and a resolved TYPED row's dot/line/arrowhead
   stayed in the type's original colour while only the badge turned green — both reported by Zac
   as off-centre and mismatched (see outputs/checkpoints/20260726-changemaprework/handoff.md). */
.cm-row.pending {
  --cm-color: #000;
}

.cm-row.resolved:not(.state-rejected) {
  --cm-color: var(--cm-approved);
}

.cm-row.pending .cm-line-right {
  visibility: hidden;
}

.cm-glyph {
  position: relative;
  z-index: 1;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--cm-color);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  box-shadow: 0 0 0 2px #fff;
  /* Reset browser <button> defaults — a reviewer-actionable pending badge renders as a real
     <button> (see changeMapCell in app.js) so it's a native click/keyboard target; without these
     resets the global `button` rule's min-height/padding/border would distort the 22px circle,
     the same class of bug already hit once with the old standalone accept button. */
  border: none;
  padding: 0;
  min-height: 0;
}

.cm-glyph[data-quick-accept] {
  cursor: pointer;
}

.cm-glyph svg {
  width: 13px;
  height: 13px;
}

/* Not yet accepted: uniform grey badge with a dashed black ring and a black question mark,
   regardless of change type — a single "awaiting your decision" signal, not a different icon
   per issue type while still pending. */
.cm-row.pending .cm-glyph {
  background: var(--faint);
  border: 2px dashed #000;
  color: #000;
}

/* ---------- totals ---------- */

.totals-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 12px;
  margin-bottom: 12px;
}

.totals-matrix-panel {
  min-width: 0;
}

.totals-legend {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--muted);
}

.legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
}

.legend-dot.up { background: var(--cm-approved); }
.legend-dot.down { background: var(--cm-internal); }
.legend-dot.flat { background: var(--faint); }

.totals-impact {
  overflow-x: auto;
}

.impact-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}

.impact-table th {
  text-align: left;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-alt);
}

.impact-table td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--border-soft);
  font-variant-numeric: tabular-nums;
}

.impact-table th.num,
.impact-table td.num {
  text-align: right;
}

.impact-table tfoot td {
  font-weight: 700;
  border-top: 1px solid var(--border);
  border-bottom: none;
}

.impact-table .delta.up { color: var(--success-ink); }
.impact-table .delta.down { color: var(--danger-ink); }
.impact-table .delta.flat { color: var(--muted); }

.delta-glyph {
  margin-right: 3px;
  font-size: 9px;
}

/* per-task role-group matrix */
.matrix-table th.matrix-section {
  text-align: center;
  background: #eef2f7;
  border-left: 1px solid var(--border);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.matrix-table .matrix-role-row th {
  font-weight: 600;
  white-space: nowrap;
}

.matrix-table .matrix-task {
  font-weight: 600;
  white-space: nowrap;
}

.matrix-table .matrix-subtotal {
  font-weight: 700;
  border-left: 1px solid var(--border-soft);
}

.matrix-table td.changed-up {
  color: var(--success-ink);
  background: rgba(22, 163, 74, 0.08);
  font-weight: 600;
}

.matrix-table td.changed-down {
  color: var(--danger-ink);
  background: rgba(220, 38, 38, 0.07);
  font-weight: 600;
}

/* ---------- selected change review + discussion ---------- */

.lower-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr);
  gap: 12px;
  align-items: start;
}

.selected-change-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.cm-badge {
  font-weight: 600;
}

.badge-approved-clean { background: var(--success-bg); color: var(--success-ink); }
.badge-awaiting { background: var(--cm-mint-bg); color: #1c7f72; }
.badge-hours { background: var(--cm-hours-bg); color: var(--cm-hours); }
.badge-wording { background: var(--cm-wording-bg); color: var(--cm-wording); }
.badge-task { background: var(--cm-task-bg); color: var(--cm-task); }
.badge-clarification { background: var(--cm-clarification-bg); color: var(--cm-clarification); }
.badge-internal { background: var(--cm-internal-bg); color: var(--cm-internal); }
.badge-accounts { background: var(--cm-accounts-bg); color: var(--cm-accounts); }
.badge-writeoff { background: var(--cm-writeoff-bg); color: var(--cm-writeoff); }
.badge-rejected { background: var(--cm-rejected-bg); color: var(--cm-rejected); }

.selected-change-body {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.field-list {
  display: grid;
  gap: 8px;
  align-content: start;
}

.field-static {
  display: grid;
  gap: 3px;
  font-size: 12.5px;
}

.field-static .k {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
}

.selected-change-body .proposed {
  color: #b45309;
  font-weight: 600;
}

.selected-change-body.resolved .proposed {
  color: var(--cm-approved);
}

.field-static .prev-alloc {
  color: var(--faint);
}

.field-static .detected-by {
  color: var(--cm-accounts);
  font-weight: 600;
}

.button-row.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

/* ---------- editor drawer ---------- */

.editor {
  display: grid;
  align-content: start;
  gap: 10px;
  margin-top: 14px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}

.entry-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.button-row {
  display: grid;
  gap: 8px;
}

.button-row.two-up {
  grid-template-columns: 1fr 1fr;
}

.checkbox-row {
  display: flex !important;
  align-items: center;
  gap: 8px;
}

.checkbox-row input {
  width: auto;
}

.billable-row {
  align-self: end;
  min-height: 36px;
  color: var(--ink-soft) !important;
  font-size: 13px !important;
}

.issue-selector {
  display: grid;
  gap: 6px;
}

.issue-type-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.issue-option {
  display: flex !important;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #f8fafb;
}

.issue-option input {
  width: auto;
}

/* ---------- move-to-project drawer ---------- */

.move-drawer {
  display: grid;
  gap: 10px;
  margin-top: 14px;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}

.move-drawer label {
  display: grid;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
}

.move-warning {
  margin: 0;
  padding: 8px 10px;
  border-radius: 7px;
  background: var(--cm-hours-bg);
  color: #9a4a08;
  font-size: 12.5px;
  border: 1px solid #f2d0ab;
}

.move-message {
  padding: 8px 10px;
  border-radius: 7px;
  background: var(--panel-alt);
  border: 1px dashed var(--border);
  color: var(--muted);
  font-size: 12.5px;
}

/* ---------- discussion ---------- */

.discussion-panel {
  min-width: 0;
}

.activity-list {
  display: grid;
  gap: 8px;
  max-height: 420px;
  overflow-y: auto;
}

.activity-entry {
  display: grid;
  gap: 6px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #f8fafb;
}

.activity-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  color: var(--muted);
  font-size: 12px;
}

.activity-detail,
.activity-empty {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

.activity-empty {
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 12px;
  background: #fbfcfd;
}

.comment-box {
  margin-top: 10px;
  display: grid;
  gap: 8px;
}

.comment-box label {
  display: grid;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
}

/* ---------- shared panels ---------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
}

.panel-header {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.panel-header p {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.segmented-control {
  display: inline-grid;
  grid-auto-flow: column;
  gap: 6px;
}

.segmented-control button.active {
  background: var(--accent);
  color: white;
  border-color: var(--accent-dark);
}

.summary-card-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}

.summary-card {
  display: grid;
  gap: 6px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}

.summary-card span {
  color: var(--muted);
  font-size: 12px;
}

.summary-card strong {
  font-size: 22px;
  line-height: 1;
}

.summary-card small {
  color: var(--muted);
  font-size: 12px;
}

.summary-card.tone-warning,
.pipeline-stage.tone-warning,
.dashboard-list-item.tone-warning {
  background: var(--warning-bg);
  color: var(--warning-ink);
  border-color: #eadfb6;
}

.summary-card.tone-danger,
.pipeline-stage.tone-danger,
.dashboard-list-item.tone-danger {
  background: var(--danger-bg);
  color: var(--danger-ink);
  border-color: #f0cccc;
}

.summary-card.tone-success,
.pipeline-stage.tone-success,
.dashboard-list-item.tone-success {
  background: var(--success-bg);
  color: var(--success-ink);
  border-color: #cce3d0;
}

.summary-card.tone-finance {
  background: #eff4ff;
  color: #24437c;
  border-color: #d5dff7;
}

.role-insight-panel {
  margin-bottom: 12px;
}

.workflow-summary-panel {
  margin-bottom: 12px;
}

.workflow-step-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.workflow-step {
  display: grid;
  gap: 6px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fbfcfd;
}

.workflow-step strong {
  font-size: 16px;
  text-transform: capitalize;
}

.workflow-step small {
  color: var(--muted);
  font-size: 12px;
}

.workflow-step-complete {
  background: var(--success-bg);
  border-color: #cce3d0;
  color: var(--success-ink);
}

.workflow-step-current {
  background: #eef4fb;
  border-color: #d5e1ef;
  color: #244266;
}

.workflow-step-returned {
  background: var(--danger-bg);
  border-color: #f0cccc;
  color: var(--danger-ink);
}

.workflow-summary-notes {
  display: grid;
  gap: 8px;
  margin-top: 10px;
}

.workflow-note {
  display: grid;
  gap: 4px;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fbfcfd;
  font-size: 12px;
}

.workflow-note-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.role-action-summary {
  display: grid;
  gap: 10px;
  margin-bottom: 12px;
}

.role-action-summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.role-action-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
}

.role-action-card {
  display: grid;
  gap: 6px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fbfcfd;
  font-size: 12px;
}

.role-action-card strong {
  font-size: 14px;
}

.role-action-card span {
  font-weight: 600;
}

.role-action-card.enabled {
  border-color: #cce3d0;
}

.role-action-card.blocked {
  border-color: #eadfb6;
}

.role-summary-grid {
  margin-bottom: 10px;
}

.commercial-impact {
  margin-bottom: 12px;
}

.commercial-impact h4 {
  margin-bottom: 8px;
}

.commercial-impact-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.impact-cell {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #eff4ff;
}

.impact-cell span {
  color: var(--muted);
  font-size: 12px;
}

.impact-cell strong {
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  color: #24437c;
}

.impact-change.up { background: var(--success-bg); border-color: #cce3d0; }
.impact-change.up strong { color: var(--success-ink); }
.impact-change.down { background: var(--danger-bg); border-color: #f0cccc; }
.impact-change.down strong { color: var(--danger-ink); }
.impact-change.flat strong { color: var(--muted); }

.commercial-breakdown {
  margin-bottom: 12px;
}

.commercial-breakdown h4 {
  margin-bottom: 8px;
}

.breakdown-note {
  color: var(--muted);
  font-weight: 400;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

.commercial-breakdown-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
}

@media (max-width: 1200px) {
  .commercial-impact-grid,
  .commercial-breakdown-grid {
    grid-template-columns: 1fr;
  }
}

.finance-strip {
  min-width: 220px;
  text-align: right;
  font-size: 13px;
}

.finance-strip strong {
  display: block;
  font-size: 18px;
}

.trigger-list,
.finance-detail-panel {
  display: grid;
  gap: 10px;
}

.trigger-list {
  margin-top: 2px;
}

.trigger-empty,
.finance-empty {
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 10px;
  background: #fbfcfd;
  color: var(--muted);
  font-size: 12px;
}

.trigger-item {
  border: 1px solid #eadfb6;
  border-radius: 6px;
  padding: 9px 10px;
  background: var(--warning-bg);
  color: var(--warning-ink);
  font-size: 12px;
}

.finance-detail-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.finance-line-table {
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  background: #fbfcfd;
}

.finance-line-header,
.finance-line-row {
  display: grid;
  grid-template-columns: minmax(70px, 0.8fr) minmax(100px, 1.2fr) minmax(70px, 0.7fr) minmax(90px, 0.9fr) minmax(100px, 0.9fr);
  gap: 10px;
  padding: 9px 10px;
  font-size: 12px;
}

.finance-line-header {
  background: #eef3f7;
  color: #314255;
  font-weight: 600;
}

.finance-line-row {
  border-top: 1px solid var(--border);
  color: var(--ink);
}

.finance-line-row span:last-child,
.finance-line-header span:last-child,
.finance-line-row span:nth-child(4),
.finance-line-header span:nth-child(4),
.finance-line-row span:nth-child(3),
.finance-line-header span:nth-child(3) {
  text-align: right;
}

/* ---------- projects ---------- */

.projects-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

#projectsSummaryCards {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

.projects-budget-note {
  background: #eff4ff;
  border-color: #d5dff7;
}

.projects-analytics {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.3fr);
  gap: 12px;
  align-items: start;
}

.queue-table-header.projects-row,
.queue-row.projects-row {
  grid-template-columns: minmax(80px, 0.7fr) minmax(150px, 1.4fr) minmax(100px, 0.9fr) minmax(85px, 0.75fr) minmax(110px, 0.9fr) minmax(90px, 0.7fr) minmax(90px, 0.75fr) minmax(160px, 1.3fr);
}

@media (max-width: 1200px) {
  #projectsSummaryCards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .projects-analytics {
    grid-template-columns: 1fr;
  }
  .queue-table-header.projects-row,
  .queue-row.projects-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- approvals ---------- */

.approvals-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

#approvalsSummaryCards {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

.approvals-commercial-note {
  background: #eff4ff;
  border-color: #d5dff7;
}

.queue-table-header.approvals-row,
.queue-row.approvals-row {
  grid-template-columns: minmax(80px, 0.75fr) minmax(150px, 1.6fr) minmax(100px, 1fr) minmax(85px, 0.85fr) minmax(120px, 1fr) minmax(70px, 0.7fr) minmax(95px, 0.85fr) minmax(190px, 1.3fr);
}

.queue-row.approvals-row.needs-attention {
  background: #fff7f2;
}

@media (max-width: 1200px) {
  #approvalsSummaryCards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .queue-table-header.approvals-row,
  .queue-row.approvals-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- reports ---------- */

.reports-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
  align-content: start;
}

.reports-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.report-card {
  display: grid;
  gap: 8px;
  align-content: start;
}

.report-card h3 {
  margin: 0;
  font-size: 14px;
}

.report-card p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 12.5px;
}

.report-card-foot {
  margin-top: 4px;
}

.report-planned {
  opacity: 0.72;
}

.report-result {
  font-size: 12px;
  color: var(--ink-soft);
  border-top: 1px dashed var(--border-soft);
  padding-top: 6px;
}

@media (max-width: 1200px) {
  .reports-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- audit trail & amendment analytics ---------- */

.audit-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

#auditSummaryCards {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

.audit-analytics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  align-items: start;
}

.audit-breakdowns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  align-items: start;
  margin-bottom: 12px;
}

.queue-table-header.audit-row,
.queue-row.audit-row {
  grid-template-columns: minmax(80px, 0.6fr) minmax(130px, 1fr) minmax(80px, 0.6fr) minmax(85px, 0.6fr) minmax(220px, 2.4fr);
}

@media (max-width: 1200px) {
  #auditSummaryCards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .audit-analytics {
    grid-template-columns: 1fr;
  }
  .queue-table-header.audit-row,
  .queue-row.audit-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- invoices ---------- */

.invoices-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

#invoicesSummaryCards {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

.invoices-billing-note {
  background: #eff4ff;
  border-color: #d5dff7;
}

.queue-table-header.invoices-row,
.queue-row.invoices-row {
  grid-template-columns: minmax(95px, 0.85fr) minmax(150px, 1.5fr) minmax(85px, 0.8fr) minmax(90px, 0.8fr) minmax(115px, 1fr) minmax(120px, 1fr) minmax(75px, 0.65fr) minmax(95px, 0.9fr);
}

.queue-table-header.invoices-row.has-ar,
.queue-row.invoices-row.has-ar {
  grid-template-columns: minmax(95px, 0.85fr) minmax(150px, 1.2fr) minmax(85px, 0.7fr) minmax(90px, 0.7fr) minmax(115px, 0.9fr) minmax(110px, 0.9fr) minmax(120px, 0.9fr) minmax(75px, 0.6fr) minmax(95px, 0.8fr);
}

@media (max-width: 1200px) {
  #invoicesSummaryCards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .queue-table-header.invoices-row,
  .queue-row.invoices-row,
  .queue-table-header.invoices-row.has-ar,
  .queue-row.invoices-row.has-ar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- reviews queue ---------- */

.reviews-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

#reviewsSummaryCards {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

.reviews-analytics {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.3fr);
  gap: 12px;
  align-items: start;
}

.queue-table-header.reviews-row,
.queue-row.reviews-row {
  grid-template-columns: minmax(75px, 0.7fr) minmax(150px, 1.5fr) minmax(80px, 0.8fr) minmax(80px, 0.75fr) minmax(115px, 1fr) minmax(55px, 0.5fr) minmax(65px, 0.6fr) minmax(120px, 1fr) minmax(90px, 0.85fr);
}

.queue-row.reviews-row.needs-attention {
  background: #fff7f2;
}

.row-subtext {
  display: block;
  color: var(--text-soft, #64748b);
  font-size: 11px;
  margin-top: 2px;
}

.mini-progress {
  display: block;
  height: 7px;
  border-radius: 4px;
  background: #e6ecf3;
  overflow: hidden;
  max-width: 130px;
}

.mini-progress-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: linear-gradient(90deg, #146c94, #1c8ec0);
}

.perf-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.perf-cell {
  border: 1px solid var(--border-soft, #e2e8f0);
  border-radius: 8px;
  padding: 10px;
  display: grid;
  gap: 4px;
}

.perf-cell strong {
  font-size: 20px;
}

.perf-cell span {
  color: var(--text-soft, #64748b);
  font-size: 12px;
}

@media (max-width: 1200px) {
  #reviewsSummaryCards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .reviews-analytics {
    grid-template-columns: 1fr;
  }
  .queue-table-header.reviews-row,
  .queue-row.reviews-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- dashboard ---------- */

.dashboard-view {
  display: grid;
  gap: 12px;
  padding: 14px;
  overflow: auto;
}

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

.dashboard-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(300px, 0.95fr);
  gap: 12px;
}

.dashboard-queue-panel {
  min-width: 0;
  overflow: auto;
}

.dashboard-queue-tools {
  display: grid;
  gap: 8px;
  margin-bottom: 10px;
}

.dashboard-queue-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.dashboard-filter-bar {
  flex-wrap: wrap;
}

.dashboard-search {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: 1;
  min-width: 180px;
  max-width: 320px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}

.dashboard-search:focus-within {
  border-color: var(--faint);
}

.dashboard-search-icon {
  width: 15px;
  height: 15px;
  color: var(--muted);
  flex: none;
}

.dashboard-search input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--ink);
  font-size: 13px;
  padding: 7px 0;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.dashboard-queue-summary {
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}

.dashboard-side-panels {
  display: grid;
  gap: 12px;
}

.dashboard-side-panel {
  min-height: 0;
}

.pipeline-grid {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 10px;
}

.pipeline-stage {
  display: grid;
  gap: 6px;
  padding: 12px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fbfcfd;
  text-align: center;
}

.pipeline-stage-actionable {
  cursor: pointer;
}

.pipeline-stage strong {
  font-size: 20px;
}

.pipeline-label {
  color: var(--muted);
  font-size: 12px;
}

.queue-table {
  display: grid;
  min-width: 0;
}

.queue-table-header,
.queue-row {
  display: grid;
  grid-template-columns: minmax(180px, 1.4fr) minmax(140px, 1.25fr) minmax(120px, 1fr) minmax(80px, 0.7fr) minmax(120px, 1fr) minmax(110px, 0.9fr) minmax(110px, 0.9fr);
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  font-size: 12px;
}

.queue-table-header {
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-weight: 600;
}

.queue-row {
  border-bottom: 1px solid #edf1f4;
}

.queue-row:last-child {
  border-bottom: none;
}

.queue-row span,
.queue-table-header span {
  min-width: 0;
}

.queue-row span:first-child {
  display: grid;
  gap: 3px;
}

.queue-row small {
  color: var(--muted);
  font-size: 11px;
}

.queue-open-button {
  min-height: 32px;
  padding: 5px 10px;
}

.approvals-row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.queue-reject-button,
.queue-approve-button {
  min-height: 32px;
  padding: 5px 10px;
  white-space: nowrap;
}

/* Distinct green so "Approve" doesn't read as just another plain (accent-coloured) button next
   to Open Review — matches the green already used for "approved" elsewhere (Change Map badge). */
.queue-approve-button {
  background: var(--cm-approved);
  border-color: #0f7a34;
}

.queue-approve-button:hover:not(:disabled) {
  background: #0f7a34;
}

.row-reviewer-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.row-reviewer-picker .reviewer-select {
  min-height: 32px;
  padding: 4px 6px;
  font-size: 12px;
  width: 100%;
  max-width: 150px;
}

.row-reviewer-picker .queue-open-button {
  white-space: nowrap;
}

.dashboard-list {
  display: grid;
  gap: 8px;
}

.dashboard-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fbfcfd;
  font-size: 12px;
}

.dashboard-list-action {
  width: 100%;
  cursor: pointer;
  text-align: left;
}

.dashboard-list-meta {
  color: var(--ink-soft);
  font-size: 11px;
  white-space: nowrap;
}

/* dashboard analytics (Projects by Status donut + Hours by Reviewer bars + Review Insights) */
.dashboard-analytics {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.3fr) minmax(0, 0.95fr);
  gap: 12px;
  align-items: start;
}

.insight-list {
  display: grid;
  gap: 6px;
}

.insight-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border: 1px solid var(--border-soft);
  border-radius: 7px;
  background: var(--panel-alt);
  font-size: 12.5px;
  color: var(--ink-soft);
}

.insight-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--muted);
}

.insight-row.tone-success .insight-dot { background: var(--cm-approved); }
.insight-row.tone-warning .insight-dot { background: var(--cm-hours); }
.insight-row.tone-danger .insight-dot { background: var(--cm-internal); }
.insight-row.tone-success { border-color: #cce3d0; }
.insight-row.tone-warning { border-color: #eadfb6; }
.insight-row.tone-danger { border-color: #f0cccc; }

.donut-wrap {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}

.donut-svg {
  width: 150px;
  height: 150px;
  flex: none;
  transform: rotate(-90deg);
}

.donut-seg {
  transition: stroke-dasharray 0.3s ease;
}

.donut-center-value,
.donut-center-label {
  transform: rotate(90deg);
  transform-origin: 21px 21px;
  text-anchor: middle;
  fill: var(--ink);
}

.donut-center-value {
  font-size: 7px;
  font-weight: 750;
}

.donut-center-label {
  font-size: 2.6px;
  fill: var(--muted);
  letter-spacing: 0.3px;
}

.chart-legend {
  display: grid;
  gap: 5px;
  min-width: 150px;
  flex: 1;
}

.chart-legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-soft);
}

.chart-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

.chart-legend-label {
  flex: 1;
  min-width: 0;
}

.chart-legend-value {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.hours-chart {
  display: grid;
  gap: 8px;
}

.hours-bar-row {
  display: grid;
  grid-template-columns: minmax(90px, 0.9fr) minmax(0, 2.4fr) auto;
  align-items: center;
  gap: 10px;
  font-size: 12px;
}

.hours-bar-name {
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hours-bar-track {
  height: 12px;
  border-radius: 999px;
  background: var(--border-soft);
  overflow: hidden;
}

.hours-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #2f6fe0, #146c94);
}

.hours-bar-value {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.hours-bar-total {
  margin-top: 4px;
  color: var(--muted);
  font-size: 11.5px;
}

/* ---------- responsive ---------- */

/* the actions rail costs ~240px, so the comparison columns compact earlier */
@media (max-width: 1680px) {
  .compare-grid {
    grid-template-columns: minmax(0, 1fr) 84px minmax(0, 1fr);
  }

  .cmp-row,
  .col-labels {
    grid-template-columns: 20px 66px 42px minmax(0, 1fr) 30px 70px;
  }
}

@media (max-width: 1360px) {
  .lower-grid {
    grid-template-columns: 1fr;
  }

  .totals-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  /* not enough width for a side rail: it drops below the review content */
  .review-workspace {
    grid-template-columns: 1fr;
  }

  .review-actions-rail {
    position: static;
  }
}

@media (max-width: 1200px) {
  .dashboard-grid,
  .dashboard-analytics {
    grid-template-columns: 1fr;
  }

  .pipeline-grid,
  .queue-table-header,
  .queue-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .dashboard-head {
    display: grid;
  }

  .button-row.two-up {
    grid-template-columns: 1fr;
  }

  .summary-card-grid {
    grid-template-columns: 1fr;
  }

  .workflow-step-grid {
    grid-template-columns: 1fr;
  }

  .finance-detail-grid {
    grid-template-columns: 1fr;
  }

  .finance-line-header,
  .finance-line-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .finance-line-row span:last-child,
  .finance-line-header span:last-child,
  .finance-line-row span:nth-child(4),
  .finance-line-header span:nth-child(4),
  .finance-line-row span:nth-child(3),
  .finance-line-header span:nth-child(3) {
    text-align: left;
  }

  .compare-grid {
    grid-template-columns: minmax(0, 1fr) 84px minmax(0, 1fr);
  }

  .cmp-row,
  .col-labels {
    grid-template-columns: 20px 66px 42px minmax(0, 1fr) 30px 70px;
  }

  .selected-change-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 1000px) {
  body {
    grid-template-columns: 64px minmax(0, 1fr);
  }

  .brand-name,
  .nav-item span,
  .nav-note {
    display: none;
  }

  .nav-item {
    justify-content: center;
    font-size: 0;
    gap: 0;
  }

  .nav-ico {
    width: 18px;
    height: 18px;
  }

  .nav-lock {
    display: none;
  }

  .app-shell {
    grid-template-columns: 1fr;
  }

  .item-list {
    border-right: none;
    border-bottom: 1px solid var(--border);
  }

  .workspace-head {
    grid-template-columns: 1fr;
    display: grid;
  }

  .review-workspace {
    grid-template-columns: 1fr;
  }

  .review-actions-rail {
    position: static;
  }

  .totals-grid,
  .issue-type-list {
    grid-template-columns: 1fr;
  }
}

body.login-page {
  display: flex;
  grid-template-columns: none;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
  padding: 32px 20px;
  background:
    radial-gradient(1200px 600px at 50% -10%, rgba(20, 108, 148, 0.28), transparent 55%),
    linear-gradient(180deg, var(--navy-900), var(--navy-700));
}

.login-shell {
  width: min(440px, 100%);
}

.login-card {
  width: 100%;
  background: #fff;
  border-radius: 16px;
  padding: 40px 36px 32px;
  text-align: center;
  box-shadow: 0 24px 60px rgba(8, 18, 32, 0.35);
}

.login-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--navy-800);
  font-weight: 700;
  font-size: 15px;
}

.login-brand-name {
  letter-spacing: 0.01em;
}

.login-card h1 {
  margin: 22px 0 8px;
  font-size: 22px;
  line-height: 1.25;
  color: var(--ink);
}

.login-lead,
.login-footnote {
  margin: 0 auto;
  max-width: 34ch;
  color: var(--muted);
  line-height: 1.5;
}

.login-footnote {
  margin-top: 18px;
  font-size: 12px;
}

.login-error {
  background: var(--danger-bg);
  color: var(--danger-ink);
  padding: 10px 12px;
  border-radius: 8px;
  margin: 16px 0 0;
  text-align: left;
}

/* Microsoft identity platform sign-in button (light). */
.ms-signin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: min(280px, 100%);
  height: 41px;
  margin-top: 24px;
  padding: 0 12px;
  background: #fff;
  border: 1px solid #8c8c8c;
  border-radius: 0;
  color: #5e5e5e;
  font-family: "Segoe UI", sans-serif;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}

.ms-signin:hover {
  background: #f3f2f1;
  border-color: #8c8c8c;
}

.ms-signin:focus-visible {
  outline: 2px solid #000;
  outline-offset: 2px;
}

.ms-signin-logo {
  width: 21px;
  height: 21px;
  flex: 0 0 21px;
}

.sign-out-link {
  font-size: 12px;
  color: var(--accent);
  text-decoration: none;
  margin-left: 8px;
}

.sign-out-link:hover {
  text-decoration: underline;
/* ---------------------------------------------------------------------------
   Project history matrix (tasks down, dates across).
   Sits in a native <dialog> so focus trapping and Esc-to-close come for free.
   The matrix can be wide, so it scrolls inside its own container rather than
   letting the dialog itself scroll sideways.
   --------------------------------------------------------------------------- */

.history-dialog {
  border: 1px solid #cbd5f5;
  border-radius: 12px;
  padding: 0;
  max-width: min(1100px, 94vw);
  width: min(1100px, 94vw);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.25);
}

.history-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.history-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px 12px;
  border-bottom: 1px solid #e2e8f0;
}

.history-head h2 {
  margin: 0;
  font-size: 1.05rem;
}

.history-subtitle {
  margin: 4px 0 0;
  font-size: 0.82rem;
  color: #64748b;
}

.history-body {
  padding: 16px 20px 20px;
}

.history-scroll {
  overflow-x: auto;
  max-height: 60vh;
  overflow-y: auto;
}

.history-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.84rem;
}

.history-table th,
.history-table td {
  border-bottom: 1px solid #e2e8f0;
  padding: 6px 10px;
  text-align: right;
  white-space: nowrap;
}

/* The task column is the row label and the only left-aligned, wrapping cell. */
.history-table .history-task {
  text-align: left;
  white-space: normal;
  min-width: 220px;
  font-weight: 600;
}

.history-table thead th {
  position: sticky;
  top: 0;
  background: #f8fafc;
  z-index: 1;
}

.history-table tfoot th,
.history-table tfoot td {
  border-top: 2px solid #cbd5f5;
  border-bottom: none;
  font-weight: 700;
}

.history-table .history-total {
  font-weight: 700;
}

.history-nil {
  color: #cbd5f5;
}

.history-empty {
  margin: 0;
  color: #64748b;
}

/* Anchor styled as a rail button. It is an <a>, not a <button>, so middle-click and
   open-in-new-tab behave as users expect for something that leaves the app. */
.rail-btn.rail-link {
  display: block;
  text-align: center;
  text-decoration: none;
  line-height: 1.4;
}

.history-footnote {
  margin: 10px 0 0;
  font-size: 0.75rem;
  color: #64748b;
}

/* ---------------------------------------------------------------------------
   "Invoice in Xero" setup card.
   Reuses the history dialog shell (native <dialog>, same border, backdrop and
   header) and adds only the checklist and reference-copy layout. Narrower than
   the history matrix because this is prose, not a wide table.
   --------------------------------------------------------------------------- */

.xero-setup-dialog {
  max-width: min(620px, 94vw);
  width: min(620px, 94vw);
  max-height: 90vh;
}

/* Same idea as the history matrix - the content scrolls inside the card so the
   dialog never outgrows the viewport - but driven by flex rather than a fixed
   cap, so the checklist and the Reference are both fully visible whenever there
   is room and only the checklist scrolls when there is not.
   The [open] guard matters: a bare `display: flex` on a <dialog> overrides the
   UA rule that hides it while closed, and the card would sit on the page. */
.xero-setup-dialog[open],
.xero-setup-dialog .history-body {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.xero-setup-scroll {
  overflow-y: auto;
  min-height: 0;
}

/* Rail buttons are full-width by design; the header Close is not a rail item. */
.xero-setup-dialog .history-head .rail-btn {
  width: auto;
  min-width: 92px;
}

/* The sequencing warning. Danger tone rather than the softer warning palette
   because the outcome it describes is permanent: a locking invoice cannot be
   edited afterwards. The heavy left rule and the tinted panel are what make it
   read before the numbered list it sits above, which is the whole point of it. */
.xero-setup-warning {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid #f0c3c3;
  border-left: 4px solid var(--danger-ink);
  border-radius: 8px;
  background: var(--danger-bg);
  color: var(--danger-ink);
  font-size: 0.82rem;
}

.xero-setup-warning h3 {
  margin: 0 0 6px;
  font-size: 0.9rem;
  font-weight: 700;
}

.xero-setup-warning p {
  margin: 0 0 6px;
}

.xero-setup-warning p:last-child {
  margin-bottom: 0;
}

/* The observed instance. Set apart so it reads as evidence for the claim above
   rather than as another instruction. */
.xero-setup-warning-evidence {
  padding-left: 10px;
  border-left: 2px solid #e0a5a5;
  font-style: italic;
}

/* The remedy for the warning, directly beneath it. Sits inside the same red band visually so it
   reads as the answer to that alert rather than as an unrelated control. */
.xero-setup-writeback {
  margin: -8px 0 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
}

/* The step-7 round trip. A plain ordered list would read as four more instructions to follow; these
   are STATES, most of which the person cannot act on, so each carries its own availability line. */
.xero-setup-sequence {
  margin: 0 0 18px;
  padding: 12px 14px 12px 30px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-alt);
  font-size: 0.82rem;
}

.xero-setup-sequence-heading {
  margin: 0 0 10px -16px;
  font-size: 0.9rem;
  font-weight: 700;
}

.xero-setup-move {
  margin: 0 0 10px;
}

.xero-setup-move:last-child {
  margin-bottom: 0;
}

.xero-setup-move h3 {
  margin: 0 0 2px;
  font-size: 0.83rem;
  font-weight: 600;
}

.xero-setup-move p {
  margin: 0 0 2px;
}

/* Availability, colour-coded to how much agency the reader has over it. Never green for a move the
   platform cannot perform - that is the whole point of showing the sequence. */
.xero-setup-move-state {
  font-weight: 600;
}

.xero-setup-move-blocked .xero-setup-move-state { color: var(--danger-ink); }
/* No --warn-ink token exists in this sheet; a literal is used rather than a var() that silently
   drops the whole declaration, which is what happened here with --line on the first attempt. */
.xero-setup-move-action .xero-setup-move-state { color: #8a6100; }
.xero-setup-move-manual .xero-setup-move-state { color: var(--ink-soft); }
.xero-setup-move-done .xero-setup-move-state { color: var(--success-ink); }

.xero-setup-steps {
  margin: 0;
  padding-left: 22px;
  display: grid;
  gap: 14px;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.xero-setup-steps li::marker {
  font-weight: 700;
  color: var(--accent);
}

.xero-setup-steps h3 {
  margin: 0 0 4px;
  font-size: 0.88rem;
  color: var(--ink);
}

.xero-setup-steps p {
  margin: 0 0 4px;
}

.xero-setup-steps p:last-child {
  margin-bottom: 0;
}

/* A concrete value the user has to transcribe onto the Xero screen. */
.xero-setup-fact {
  font-weight: 700;
  color: var(--ink);
}

.xero-setup-note {
  color: var(--muted);
}

/* The count is the cross-check that the date filter is right, so it is the one
   thing in this card that has to be readable at a glance rather than read. */
.xero-setup-count {
  font-size: 0.95rem;
  color: var(--ink);
}

.xero-setup-count strong {
  font-size: 1.4rem;
  line-height: 1;
  padding: 0 2px;
  color: var(--accent);
}

.xero-setup-reference {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.xero-setup-label {
  display: block;
  margin-bottom: 6px;
  font-size: 12.5px;
  font-weight: 700;
}

.xero-setup-copy-row {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 8px;
}

.xero-setup-input {
  flex: 1 1 240px;
  min-width: 0;
  min-height: 34px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-alt);
  color: var(--ink);
  font-family: inherit;
  font-size: 12.5px;
}

/* Rail buttons are full-width by default; inside the card they sit beside things. */
.rail-btn.xero-setup-copy {
  width: auto;
  flex: 0 0 auto;
  min-width: 88px;
}

.rail-btn.xero-setup-copy.is-copied {
  background: var(--success-bg);
  border-color: var(--cm-approved);
  color: var(--success-ink);
}

/* Reserves its line so confirming a copy does not shift the buttons below it. */
.xero-setup-copy-status {
  margin: 6px 0 0;
  min-height: 1.15em;
  font-size: 0.78rem;
  color: var(--danger-ink);
}

.xero-setup-copy-status.is-copied {
  color: var(--success-ink);
}

.xero-setup-actions {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.xero-setup-actions .rail-btn {
  width: auto;
  min-width: 120px;
}

/* .rail-btn.rail-link is display:block for the rail; in the action row it needs
   to sit inline beside "Not now". */
.rail-btn.xero-setup-open {
  display: inline-block;
}

/* Fixed-fee totals (STAGE8_DESIGN 3.17 Decision 2 refinement).
   The money view: agreed fee, what has been billed, what this invoice adds, what is left. */
.fee-totals-dialog { max-width: 62rem; width: 92vw; }
.fee-totals-scroll { overflow: auto; max-height: min(62vh, 34rem); }

.fee-totals-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.fee-totals-table th, .fee-totals-table td { padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--line, #d9dee5); text-align: left; vertical-align: top; }
.fee-totals-table thead th { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.75; }
/* Money right-aligns and uses tabular figures so columns of digits line up and can be scanned for
   an outlier - the main thing anyone does with a totals table. */
.fee-totals-table .fee-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fee-totals-table tfoot th, .fee-totals-table tfoot td { border-top: 2px solid var(--line, #d9dee5); border-bottom: none; padding-top: 0.65rem; }

.fee-totals-range { display: block; font-size: 0.78rem; opacity: 0.7; font-weight: 400; }
.fee-totals-sub { display: block; font-size: 0.78rem; opacity: 0.7; font-weight: 400; }
.fee-totals-flag { display: inline-block; margin-top: 0.25rem; padding: 0.05rem 0.4rem; border-radius: 0.6rem; font-size: 0.72rem; font-weight: 600; background: #fdf0d5; color: #7a4b00; }

/* An adjusted row is marked on the ROW, not by replacing the recommendation - both values stay
   visible, which is the point of the refinement. */
.fee-totals-adjusted { background: rgba(37, 99, 235, 0.06); }
.fee-totals-adjusted th[scope="row"] { box-shadow: inset 3px 0 0 0 var(--accent, #2563eb); }

.fee-totals-input { width: 4.5rem; padding: 0.25rem 0.35rem; text-align: right; font-variant-numeric: tabular-nums; border: 1px solid var(--line, #d9dee5); border-radius: 0.3rem; background: inherit; color: inherit; }
.fee-totals-input:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }

.fee-totals-note { font-size: 0.85rem; opacity: 0.8; margin: 0 0 0.75rem; }
/* "No recorded position" is the one that can cost real money, so it is not styled like ordinary
   help text. */
.fee-totals-note-warn { opacity: 1; font-weight: 600; color: #7a2e2e; background: #fdeaea; border-left: 3px solid #b3261e; padding: 0.5rem 0.65rem; border-radius: 0.25rem; }

@media (prefers-color-scheme: dark) {
  .fee-totals-flag { background: #4a3609; color: #f7d99a; }
  .fee-totals-note-warn { color: #ffb4ab; background: rgba(179, 38, 30, 0.18); }
}

/* Per-task notes: why a requested percentage was clamped, or that no prior position is recorded.
   Rendered on the row rather than pooled at the top, because the refusal belongs beside the number
   the person just typed. */
.fee-totals-task-note { display: block; margin-top: 0.3rem; font-size: 0.78rem; font-weight: 400; line-height: 1.35; color: #7a4b00; }
@media (prefers-color-scheme: dark) { .fee-totals-task-note { color: #f7d99a; } }

/* Fee confirmation: a confirmed fee reads as settled, an unconfirmed one as outstanding work. */
.fee-confirm-ok { font-size: 0.78rem; font-weight: 600; color: #1b5e20; }
@media (prefers-color-scheme: dark) { .fee-confirm-ok { color: #a5d6a7; } }

/* Stage chip: how far through the nine-stage pipeline a project is, with the meaning on hover.
   Sits beside the status badge rather than replacing it - the badge says WHAT state, this says HOW
   FAR, and they answer different questions. */
/* `inline-flex`, NOT `flex`: the status cell is itself a flex/grid container, so a bare `flex` child
   stretches to the full column width and the chip reads as a filled bar rather than a badge.
   `align-self: start` and `width: fit-content` hold that even where the parent sets `align-items:
   stretch`, which is what actually caused it. */
.stage-chip {
  display: inline-flex;
  align-items: center;
  align-self: start;
  width: fit-content;
  flex: 0 0 auto;
  gap: 0.25rem;
  margin-left: 0.4rem;
  padding: 0.05rem 0.4rem;
  border-radius: 0.6rem;
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  background: rgba(37, 99, 235, 0.1);
  color: #1e40af;
  cursor: help;
}

/* The "i" affordance (Zac, backlog 11.42). A title attribute alone says nothing on screen, so the
   explanation is only found by accident; the glyph is what makes it discoverable. Slightly dimmed so
   it supports the step number rather than competing with it, and full strength on hover/focus. */
.stage-chip-i {
  width: 0.85em;
  height: 0.85em;
  flex: none;
  opacity: 0.65;
}
.stage-chip:hover .stage-chip-i,
.stage-chip:focus-visible .stage-chip-i { opacity: 1; }

/* Stages this item previously passed and has now LOST by going backwards (Zac, backlog 11.22:
   "it should show red dots for stage 4 & 5 until it passes them again"). One dot per lost stage.
   Red is the correct register: ground that was held and is now gone is a regression, not a warning. */
/* `flex-direction: row` and `nowrap` are stated explicitly rather than left to the default: this
   container is nested inside another flex context, and the dots were WRAPPING into a vertical stack
   that read as a single dot — two lost stages looked like one. The count is the whole message here,
   so it must never wrap. */
/* Specificity is deliberate and load-bearing. `.queue-row span:first-child { display: grid }`
   (declared above, for the project-number cell) ALSO matches this wrapper, and at 0,2,1 it beat both
   a bare `.stage-lost-dots` and `.stage-chip .stage-lost-dots` — which is exactly how the dots ended
   up STACKED VERTICALLY, so two lost stages read as one. `.queue-row` here takes it to 0,3,0 and
   wins outright, and the chip is rendered with the icon first so the wrapper is not `:first-child`
   in the first place. Belt and braces, because this bug was invisible to a passing test: the class
   was applied, the rule was present, and it was silently ignored. Found only by screenshotting. */
.stage-chip .stage-lost-dots,
.queue-row .stage-chip .stage-lost-dots {
  display: inline-flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.15rem;
}
.stage-lost-dot {
  display: inline-block;
  width: 0.4em;
  height: 0.4em;
  flex: 0 0 auto;
  border-radius: 50%;
  background: #b3261e;
}
/* The chip itself shifts to the danger palette, so a reverted item is legible from across the row
   rather than only on close inspection of the dots. */
.stage-chip-reverted { background: rgba(179, 38, 30, 0.12); color: #8c1d18; }
@media (prefers-color-scheme: dark) {
  .stage-lost-dot { background: #ff8a80; }
  .stage-chip-reverted { background: rgba(255, 138, 128, 0.18); color: #ffb4ab; }
}
/* Focusable because a title attribute alone is invisible to keyboard users, and this chip carries
   the only plain-English explanation of the pipeline in the product. */
.stage-chip:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }
@media (prefers-color-scheme: dark) {
  .stage-chip { background: rgba(96, 165, 250, 0.18); color: #bfdbfe; }
}

/* An hourly task in the confirmation dialog: shown for completeness, needs no fee. Muted rather than
   flagged, because it is not outstanding work - it is context. */
.fee-confirm-muted { font-size: 0.78rem; opacity: 0.7; }

/* Fee confirmation: per-row selection, the billing-model badge and its pencil, and the revealed
   dormant rows (Zac, 2026-08-01). */

/* Narrow, and the checkbox is centred in it rather than left-aligned with the task names - a column
   of ticks reads as a column only when they line up. */
.fee-totals-table .fee-confirm-select-col { width: 2.25rem; text-align: center; padding-right: 0.2rem; }
.fee-confirm-select { width: 1rem; height: 1rem; accent-color: var(--accent, #2563eb); cursor: pointer; }
.fee-confirm-select:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 2px; }

/* The EFFECTIVE billing model, not Xero's charge type. Neutral rather than coloured: it states how a
   task bills, which is not itself good or bad news, and colouring it would compete with the status
   column beside it that IS a judgement. */
.fee-confirm-model { font-size: 0.78rem; font-weight: 600; white-space: nowrap; }
/* The badge and its pencil are one control group and must stay on one line. Left to normal flow the
   allowance sub-line ("6 included") pushed the pencil onto a third row, which read as an orphaned
   button belonging to nothing. */
.fee-totals-table .fee-confirm-model-cell { white-space: nowrap; }
.fee-totals-table .fee-confirm-model-cell .fee-totals-sub { white-space: normal; }

/* Pencil: quiet until the row is hovered or it is focused, so eighteen of them down a table do not
   read as eighteen calls to action. It never disappears entirely - a control that only exists on
   hover is unusable by touch and invisible to anyone scanning for it. */
.fee-confirm-pencil {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  margin-left: 0.2rem;
  padding: 0;
  vertical-align: -0.3rem;
  border: 1px solid transparent;
  border-radius: 0.3rem;
  background: none;
  color: inherit;
  opacity: 0.45;
  cursor: pointer;
}
.fee-confirm-pencil svg { width: 0.85rem; height: 0.85rem; }
.fee-totals-table tr:hover .fee-confirm-pencil { opacity: 0.9; }
.fee-confirm-pencil:hover { opacity: 1; border-color: var(--line, #d9dee5); }
.fee-confirm-pencil:focus-visible { opacity: 1; outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }

/* A revealed dormant row is de-emphasised but NOT disabled: it is fully confirmable, it just has
   nothing booked against it yet. Striping it keeps the in-use rows at the top distinguishable once
   the table grows to the full template length. */
.fee-confirm-dormant-row { background: rgba(127, 127, 127, 0.05); }
.fee-confirm-dormant-row th[scope="row"] { font-weight: 500; }

/* The reveal control sits inline at the end of the dormant sentence, so it reads as part of it. */
.rail-btn.fee-confirm-reveal {
  display: inline;
  width: auto;
  margin-left: 0.35rem;
  padding: 0;
  border: none;
  background: none;
  font-size: inherit;
  text-align: left;
}

/* Billing model editor: narrower than the totals dialogs - it is one question about one task. */
.fee-model-dialog { max-width: 34rem; width: 92vw; }
.fee-model-fieldset { margin: 0 0 0.9rem; padding: 0; border: none; }
.fee-model-choice {
  display: flex;
  gap: 0.55rem;
  align-items: flex-start;
  margin-top: 0.5rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--line, #d9dee5);
  border-radius: 0.35rem;
  font-size: 0.88rem;
  cursor: pointer;
}
.fee-model-choice:hover { border-color: var(--accent, #2563eb); }
.fee-model-choice input { margin-top: 0.15rem; accent-color: var(--accent, #2563eb); }
.fee-model-choice > span { display: flex; flex-direction: column; gap: 0.15rem; }
/* The hint is what makes the three choices distinguishable to somebody who does not already know the
   difference - which is the whole reason the pencil was asked for. */
.fee-model-hint { font-size: 0.78rem; font-weight: 400; opacity: 0.75; line-height: 1.35; }

.fee-model-overage { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.fee-model-field { flex: 1 1 12rem; min-width: 10rem; }
.fee-model-field .xero-setup-input { width: 100%; }

.fee-linked-indicator { font-size: 0.85rem; font-weight: 500; color: var(--accent, #2563eb); margin-left: 0.3rem; white-space: nowrap; }

/* Linked task indicator in checkbox area */
.fee-linked-badge { display: inline-block; margin-right: 0.3rem; font-size: 0.9rem; }

/* Linked task reference text next to task name. Deliberately small (Zac, 2026-08-03: "30% smaller"):
   it names the task this allowance draws from, which is supporting detail beside the task's own
   name, not a second heading competing with it. */
.fee-linked-reference { font-size: 0.6rem; font-weight: 500; color: var(--accent, #2563eb); margin-left: 0.5rem; white-space: nowrap; }

/* Linked row styling - slightly different appearance */
.fee-linked-row { background-color: rgba(37, 99, 235, 0.03); border-left: 3px solid var(--accent, #2563eb); padding-left: 0.5rem; }
.fee-linked-row th { font-weight: 600; }
/* The linked row sits DIRECTLY beneath the task it draws from, so the name is indented to read as
   subordinate to it rather than as the next item in a flat list. */
.fee-linked-row th { padding-left: 1.1rem; }

/* A link whose target has left the project. Warning-coloured, not hidden: the stored record still
   says this allowance draws from somewhere, and a silently-dropped link would read as a standalone
   allowance that nobody needs to look at. */
.fee-link-broken-row { border-left: 3px solid var(--warn, #b45309); background-color: rgba(180, 83, 9, 0.04); }
.fee-link-broken { font-size: 0.85rem; font-weight: 500; color: var(--warn, #b45309); margin-left: 0.5rem; }

/* Make the fee model dialog body scrollable if needed */
#feeModelBody { max-height: 70vh; overflow-y: auto; }

/* ---------------------------------------------------------------------------------------------
   Fee confirmation dialog — visual corrections (Zac: "still a bit away from this appearance")
   --------------------------------------------------------------------------------------------- */

/* `.rail-btn` carries `width: 100%` because it is built for the sidebar rail, where buttons fill
   their column. Reused inside a dialog header it stretched the Close button into a full-width bar
   across the top — the single most obvious departure from the intended design. */
.history-head .rail-btn,
.xero-setup-actions .rail-btn {
  width: auto;
  min-width: 92px;
  flex: 0 0 auto;
}

/* The header is a title block and one button, not two equal columns. Without this the flex row let
   the button claim half the width and squeezed the subtitle into three wrapped lines. */
.history-head { align-items: center; }
.history-head > div:first-child { flex: 1 1 auto; min-width: 0; }
.history-subtitle { margin: 2px 0 0; max-width: 60ch; line-height: 1.35; }

/* Centred over the page. A `<dialog>` opened with showModal() centres itself, but only once it is
   not being laid out inside a positioned ancestor — pinning it explicitly removes the dependency. */
.history-dialog {
  margin: auto;
  max-height: 88vh;
}

/* Rows were jumping in height wherever a long task name wrapped, which reads as a broken table
   rather than a dense one. A fixed line-height and consistent vertical padding hold the rhythm. */
.fee-totals-table th[scope="row"],
.fee-totals-table td {
  padding-top: 10px;
  padding-bottom: 10px;
  line-height: 1.35;
  vertical-align: middle;
}

/* The task column carries the longest strings on the screen; giving it the slack keeps the numeric
   columns from being pushed around by a single long name. */
.fee-totals-table th[scope="row"] { width: 46%; }

/* The status column reads as a label, not a sentence — "Hourly — no fee to confirm" wrapping onto
   two lines made every hourly row taller than the ones that need attention. */
.fee-confirm-muted { display: inline-block; max-width: 22ch; }

/* `margin: auto` only centres a <dialog> once `inset` is symmetrical. The UA stylesheet leaves the
   inline start pinned, so the modal sat left of centre with the page visible down the right — the
   thing that most made it read as unfinished. `inset: 0` plus auto margins centres it on both axes. */
.history-dialog[open] {
  inset: 0;
  margin: auto;
}

/* Hourly rows were taller than the row that needs attention, because "Hourly — no fee to confirm"
   wrapped. That inverts the visual hierarchy: the row a person must act on should be the prominent
   one. The status column now holds its line and the em dash breaks instead. */
.fee-totals-table td:last-child { white-space: nowrap; }
.fee-confirm-muted { max-width: none; white-space: nowrap; }

/* With "Show hidden" expanded the table grows past the viewport: the footer scrolled away and the
   reveal toggle itself vanished, so a person could expand the list and then not find the button that
   collapses it. The dialog becomes a column — head and actions pinned, only the TABLE scrolls. */
.fee-totals-dialog[open] { display: flex; flex-direction: column; }
.fee-totals-dialog[open] .history-head { flex: 0 0 auto; }
.fee-totals-dialog[open] .history-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
/* The TABLE is the only part that scrolls. The 34rem cap was fighting the flex height and letting
   the dialog outgrow the viewport instead, which pushed the footer - and the "Show hidden" toggle
   that got you here - off the bottom of the screen. */
.fee-totals-dialog[open] .fee-totals-scroll {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}
.fee-totals-dialog[open] .xero-setup-actions { flex: 0 0 auto; }

/* =============================================================================================
   VISUAL AUDIT — 2026-08-01. Found by screenshotting the running app at 1600x1000, not by reading
   CSS. Every item here was visible on screen and caught by no test.
   ============================================================================================= */

/* 1. THE WORKSPACE HEADER CLIPPED MONEY. "Invoice total $580.2" and "Net -0.75l" were cut off
   mid-number by the right rail — the worst class of visual defect on a billing screen, because a
   truncated figure still reads as a figure. The head block could not shrink (no min-width: 0 on a
   flex child defaults to min-content) so the meta column overflowed instead of wrapping. */
.workspace-head { flex-wrap: wrap; align-items: flex-start; }
.workspace-head > div:first-child { flex: 1 1 24rem; min-width: 0; }
.workspace-head-meta {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
}
.finance-strip { min-width: 0; white-space: nowrap; }

/* 2. ISSUE TILE LABELS TRUNCATED — "Wording improvem…". `.issue-tile` had `flex: 1` with
   `min-width: 138px`, so every tile was forced to the same width regardless of its label, and the
   longest one clipped. Flexing on CONTENT instead lets each tile be as wide as its own label needs;
   the row still fills because they grow together. */
.issue-tile { flex: 1 1 auto; min-width: max-content; }

/* 3+4. THE DASHBOARD PROJECT QUEUE OVERFLOWED ITS PANEL. `.queue-row` is a CSS grid of divs (not a
   table), and its seven `minmax()` floors sum to ~860px plus gaps — wider than the panel once the
   right-hand column is on screen. Grid does not shrink below a minmax floor, so the last columns were
   pushed out: "Warnings" text ran under the status badge and the Package button was clipped off the
   edge entirely.

   Floors lowered and every cell given `min-width: 0`, which grid items need before their content is
   allowed to wrap rather than force the track wider. */
.queue-row,
.queue-table-header {
  grid-template-columns:
    minmax(0, 1.35fr) minmax(0, 1fr) minmax(0, 0.95fr) minmax(0, 0.5fr)
    minmax(0, 1.35fr) minmax(0, 0.75fr) minmax(0, 0.9fr);
}
/* The status cell stacks its pill and step pill; both stay on their own line. */
.queue-row .queue-status { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.queue-row > *, .queue-table-header > * { min-width: 0; overflow-wrap: anywhere; }

/* Superseded by the design-system pill rules further down: a status pill now holds ONE line and the
   column gives way instead. Wrapping inside the pill was the incremental-phase compromise and it
   looked broken - "ManualInterventio / nRequired" split mid-word. */

/* 5. THE "PENDING APPROVALS" ITEM WAS INVISIBLE — a blank white pill on the dashboard. It is a
   <button>, and the rule styling it set only width/cursor/alignment, so it fell back to the user
   agent's button colours (and its own background) rather than inheriting the panel's. On a light
   surface that renders as near-white text on near-white: the item was there, clickable, and unreadable.

   Inheriting is the fix rather than hard-coding a colour, so the item keeps whatever tone its row
   carries — tone-warning and tone-danger rows set `color` on the parent and must continue to win. */
.dashboard-list-action {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
}

/* =============================================================================================
   DESIGN SYSTEM — target renders (docs/design/DESIGN_SPEC.md)
   =============================================================================================
   The previous look was not a rougher version of the target; it was a different system. These are
   the primitives every screen is rebuilt on. Added at the end so they win by cascade order without
   rewriting rules that other screens still depend on.
   ============================================================================================= */

:root {
  /* Canvas is light grey, never white — white is reserved for cards, which is what gives the
     renders their depth. A white canvas makes cards invisible. */
  --canvas: #f4f6fa;
  --card: #ffffff;
  --card-radius: 12px;
  --card-shadow: 0 1px 2px rgba(15, 23, 42, 0.05), 0 1px 3px rgba(15, 23, 42, 0.04);
  --card-shadow-lift: 0 4px 12px rgba(15, 23, 42, 0.08);
  --card-pad: 18px;

  --rail-bg: #0b1f3a;
  --rail-bg-deep: #081729;
  --rail-ink: #c8d4e4;
  --rail-ink-dim: #7f92ab;
  --rail-active: #1d6fe8;

  /* Tinted icon tiles. Each is a bg/ink pair so the glyph always has contrast on its own square. */
  --tile-blue-bg: #e8f0fe;    --tile-blue-ink: #1a73e8;
  --tile-orange-bg: #fff1e3;  --tile-orange-ink: #e8710a;
  --tile-green-bg: #e6f4ea;   --tile-green-ink: #1e8e3e;
  --tile-purple-bg: #f1ecfd;  --tile-purple-ink: #7b3ff2;
  --tile-red-bg: #fce8e6;     --tile-red-ink: #d93025;
  --tile-teal-bg: #e0f7f5;    --tile-teal-ink: #0f9b8e;

  /* Status pills. Semantic pairs, used by every table and badge on every screen. */
  --pill-green-bg: #e6f4ea;   --pill-green-ink: #137333;
  --pill-amber-bg: #fef7e0;   --pill-amber-ink: #a56100;
  --pill-blue-bg: #e8f0fe;    --pill-blue-ink: #1849a9;
  --pill-purple-bg: #f3e8fd;  --pill-purple-ink: #6b21a8;
  --pill-red-bg: #fce8e6;     --pill-red-ink: #b3261e;
  --pill-grey-bg: #eef1f5;    --pill-grey-ink: #475569;

  --chart-1: #1a73e8;
  --chart-2: #e8710a;
  --chart-3: #1e8e3e;
  --chart-4: #7b3ff2;
  --chart-5: #d93025;
  --chart-6: #94a3b8;
}

/* --- SHELL: dark navy rail, light canvas ----------------------------------------------------- */

body { background: var(--canvas); }

.app-nav {
  background: linear-gradient(180deg, var(--rail-bg) 0%, var(--rail-bg-deep) 100%);
  border-right: 0;
  width: 232px;
  padding: 18px 12px 14px;
}

/* The wordmark: orange "concept" over a letter-spaced grey "ENGINEERS", as in every render. */
.brand-lockup { padding: 2px 8px 20px; gap: 10px; }
.brand-mark {
  background: var(--brand);
  color: #fff;
  border-radius: 9px;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800;
}
.brand-name { color: var(--brand); font-weight: 800; letter-spacing: -0.01em; }

.app-nav-items { gap: 2px; }

.nav-item {
  color: var(--rail-ink);
  background: transparent;
  border: 0;
  border-radius: 9px;
  padding: 9px 11px;
  gap: 11px;
  font-size: 13.5px;
  font-weight: 500;
  display: flex;
  align-items: center;
  width: 100%;
  text-align: left;
}
.nav-item .nav-ico { color: currentColor; opacity: 0.85; flex: 0 0 auto; }
.nav-item:hover:not(.locked) { background: rgba(255, 255, 255, 0.07); color: #fff; }

/* Active is a FILLED blue pill, not an underline or a tint — the single most recognisable element
   of the target shell. */
.nav-item.active {
  background: var(--rail-active);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(29, 111, 232, 0.35);
}
.nav-item.active .nav-ico { opacity: 1; }

/* Locked items stay VISIBLE with a padlock. Hiding a restricted screen tells a reviewer nothing;
   showing it locked tells them it exists and is not theirs — which is the honest message and is
   what the reviewer render actually shows. */
.nav-item.locked { color: var(--rail-ink-dim); cursor: not-allowed; }
.nav-item.locked .nav-lock { margin-left: auto; opacity: 0.75; }
.nav-item.locked .nav-lock svg { width: 13px; height: 13px; }

.nav-foot {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.nav-note { color: var(--rail-ink-dim); font-size: 11px; line-height: 1.45; }
.nav-demo-toggle { color: var(--rail-ink); font-size: 12px; }

/* --- HEADER --------------------------------------------------------------------------------- */

.app-header {
  background: transparent;
  border-bottom: 0;
  padding: 22px 26px 14px;
  align-items: flex-start;
}
#appTitle { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
#batchSummary { color: var(--muted); font-size: 13px; margin-top: 3px; }

.toolbar { gap: 10px; align-items: center; }
.toolbar label { font-size: 11px; color: var(--muted); font-weight: 600; }
.toolbar select {
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 7px 10px;
  background: var(--card);
  font-size: 13px;
}

.icon-button {
  width: 34px; height: 34px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink-soft);
}
.user-avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}

.app-shell { padding: 0 26px 26px; }

/* --- CARDS AND PANELS ------------------------------------------------------------------------ */

.panel, .summary-card, .dashboard-card, .projects-analytics > *, .workspace-panel {
  background: var(--card);
  border: 1px solid var(--border-soft);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
.panel { padding: var(--card-pad); }

.panel > h2, .panel > h3, .dashboard-card > h3 {
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 2px;
}

/* --- METRIC TILES: the coloured icon square is the signature element ------------------------- */

.summary-card {
  padding: 16px 18px;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px;
  align-items: center;
}
.summary-card .metric-ico {
  width: 40px; height: 40px;
  border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--tile-blue-bg);
  color: var(--tile-blue-ink);
  flex: 0 0 auto;
}
.summary-card .metric-ico svg { width: 19px; height: 19px; }
.summary-card .metric-body { min-width: 0; }
.summary-card .metric-label {
  font-size: 12px;
  color: var(--muted);
  font-weight: 600;
  display: block;
  margin-bottom: 2px;
}
.summary-card .metric-value {
  font-size: 26px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.summary-card .metric-delta { font-size: 11.5px; color: var(--muted); margin-top: 3px; display: block; }
.summary-card .metric-delta.up { color: var(--tile-green-ink); }
.summary-card .metric-delta.down { color: var(--tile-red-ink); }

/* Tone variants recolour the TILE, not the whole card. The renders keep every card white; a fully
   tinted card competes with the pills and charts for attention and makes the row read as an alert. */
.summary-card.tone-warning, .summary-card.tone-danger, .summary-card.tone-success {
  background: var(--card);
  border-color: var(--border-soft);
  color: inherit;
}
.summary-card.tone-warning .metric-ico { background: var(--tile-orange-bg); color: var(--tile-orange-ink); }
.summary-card.tone-danger  .metric-ico { background: var(--tile-red-bg);    color: var(--tile-red-ink); }
.summary-card.tone-success .metric-ico { background: var(--tile-green-bg);  color: var(--tile-green-ink); }
.summary-card.tone-info    .metric-ico { background: var(--tile-purple-bg); color: var(--tile-purple-ink); }

/* --- STATUS PILLS --------------------------------------------------------------------------- */

.tag, .status-badge, .pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.5;
  background: var(--pill-grey-bg);
  color: var(--pill-grey-ink);
  border: 0;
  /* Long CamelCase statuses ("ManualInterventionRequired") were breaking mid-word into two lines and
     shoving the next column sideways. Kept on one line; the column gives way instead. */
  white-space: nowrap;
}
.tag.success, .status-badge.success, .tag.tone-success { background: var(--pill-green-bg); color: var(--pill-green-ink); }
.tag.warning, .status-badge.warning, .tag.tone-warning { background: var(--pill-amber-bg); color: var(--pill-amber-ink); }
.tag.danger,  .status-badge.danger,  .tag.tone-danger  { background: var(--pill-red-bg);   color: var(--pill-red-ink); }
.tag.info,    .status-badge.info,    .tag.tone-info    { background: var(--pill-blue-bg);  color: var(--pill-blue-ink); }
.tag.accent,  .status-badge.accent                     { background: var(--pill-purple-bg); color: var(--pill-purple-ink); }

/* The step pill sits under the status as a quieter second line — it is context, not the headline. */
.queue-row .step-pill, .stage-pill {
  background: var(--pill-blue-bg);
  color: var(--pill-blue-ink);
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 999px;
  font-weight: 600;
}

/* --- REVIEWER WORKSPACE: reclaiming width for the entry text ---------------------------------- */

/* The description was rendering one fragment per line ("Coord / inate / drawi / ng"), which is the
   single worst thing on any screen in the app — the reviewer cannot read the entry they are being
   asked to approve.
   
   Cause is cumulative chrome, not one bad rule: 232px nav + 280px batch list + 236px action rail =
   748px, leaving ~850px to be split across TWO comparison tables of six sub-columns each. Each
   description got roughly 120px. The target render solves this by giving the table the full width
   and letting the right panel BE the detail view rather than a separate action rail. */

/* Narrower batch list — it holds two short lines per item and never needed 280px. */
.workspace-body { grid-template-columns: 232px minmax(0, 1fr); }

/* The row's fixed columns are trimmed to what their content actually needs, and the description is
   allowed to take everything left over. #, hours and staff are all short. */
.cmp-row,
.cmp-head-row {
  grid-template-columns: 22px 68px 40px minmax(0, 1fr) 30px 74px;
  gap: 5px;
}

/* Description text must WRAP ON WORDS, never mid-word. `overflow-wrap: anywhere` elsewhere in this
   file was breaking "Coordinate" into "Coord/inate" once the column got narrow. */
.cmp-row .cmp-desc,
.cmp-row .cmp-text {
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: none;
  line-height: 1.4;
}

/* Column headers were overlapping ("DESCRIPTIONSTAFF") because they sat in the same tight grid with
   no gap discipline. Small-caps and a hard clip stop them colliding. */
.cmp-head-row > * {
  font-size: 9.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- DASHBOARD LAYOUT CORRECTIONS ------------------------------------------------------------ */

/* The rail was `height: 100vh` + sticky, so on a page taller than the viewport it simply STOPPED
   two-thirds down and the canvas showed through underneath. Sticky positioning keeps it in view
   while scrolling; the height needs to fill the grid row, not one screen. */
.app-nav {
  height: auto;
  min-height: 100vh;
  max-height: 100vh;
}

/* THE DEAD VOID. `.dashboard-grid` is a two-column grid, and grid items stretch to the tallest row
   by default — so the Project Queue (2 rows of content) was stretched to match a right column of
   five stacked panels, leaving ~600px of empty white inside a bordered card. That reads as a
   rendering failure, not as spare room.
   
   `align-items: start` lets each column be its own height. */
.dashboard-grid { align-items: start; }
.dashboard-queue-panel { overflow: visible; }

/* Charts were STRANDED below the fold, under a 600px void, when the renders put them in the primary
   reading position. Moving them up in the DOM is a bigger change than this pass warrants, so they
   are pulled into the same visual band instead: a three-across row that sits directly under the
   queue rather than after it. */
.dashboard-analytics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 12px;
  align-items: start;
}

/* Right-column context cards: compact, per the renders. They were reading as full-height panels
   competing with the queue for attention. */
.dashboard-side .panel { padding: 14px 16px; }
.dashboard-side .panel + .panel { margin-top: 12px; }
.dashboard-list { display: grid; gap: 6px; }
.dashboard-list-item {
  border: 1px solid var(--border-soft);
  border-radius: 9px;
  padding: 9px 11px;
  background: var(--card);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
}

/* The left column now holds the queue AND the analytics, so the charts fill the height the right
   column dictates instead of leaving a ~600px void and stranding themselves below the fold. This
   also matches the renders, where charts sit in the primary reading area rather than in a postscript
   after every side panel. */
.dashboard-main-col { display: grid; gap: 12px; align-content: start; min-width: 0; }
.dashboard-analytics { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* The body grid still declared the OLD 210px rail width while `.app-nav` had been widened to 232px,
   so the rail overhung its own column by 22px and the canvas began underneath it. The two must be
   declared together or they drift again. */
body { grid-template-columns: 232px minmax(0, 1fr); }

/* The navy must run the FULL page height, not one viewport. `max-height: 100vh` (set above for the
   sticky behaviour) left bare canvas showing below the rail on any page taller than the screen —
   the most conspicuous break in the shell. A sticky inner column keeps the nav in view while the
   rail background itself fills the grid row. */
.app-nav {
  max-height: none;
  height: 100%;
  position: relative;
}
.app-nav-items { position: sticky; top: 18px; }

/* The projects row's status column was too narrow for its widest pill, so "Manual Intervention
   Required" overhung into Unbilled Hours. Status carries the longest content in the row and is given
   the width; the numeric columns need very little. */
.queue-table-header.projects-row,
.queue-row.projects-row {
  grid-template-columns:
    minmax(0, 0.65fr) minmax(0, 1.25fr) minmax(0, 0.8fr) minmax(0, 0.75fr)
    minmax(0, 1.35fr) minmax(0, 0.6fr) minmax(0, 0.7fr) minmax(0, 1.05fr);
}

/* Metric card rows were locked to THREE columns, so a five-card screen (Invoices, Projects) produced
   a 3+2 split with the second row stretched to fill — leaving the icon tile floating at the top of a
   tall empty card. Auto-fit sizes the row to however many cards a screen has. */
.summary-card-grid {
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  align-items: stretch;
}
/* The card's own content stays vertically centred whatever height the row settles on. */
.summary-card { align-content: center; }

/* Invoices: the status column could not hold "Manual Intervention Required" and overhung Review
   Progress. Same fix as the projects row — status carries the longest content and gets the width. */
.queue-table-header.invoices-row,
.queue-row.invoices-row {
  grid-template-columns:
    minmax(0, 0.8fr) minmax(0, 1.4fr) minmax(0, 0.75fr) minmax(0, 0.8fr)
    minmax(0, 1.4fr) minmax(0, 0.95fr) minmax(0, 0.6fr) minmax(0, 0.85fr);
}

/* THE STRETCHED-CARD DEFECT, root cause. The screen containers (`.invoices-view`, `.projects-view`,
   `.approvals-view` …) are grids with no explicit rows, so their implicit rows divide the available
   height EVENLY. On a short page that stretched the metric-card row to ~203px for 65px of content,
   stranding the icon tile at the top of a mostly-empty card.
   
   Probed rather than guessed: the card's children measured 40px + 65px while the card measured 203px,
   which ruled out padding, min-height and the card's own layout and pointed at the row.
   
   `align-content: start` makes every row take its natural height and leaves the slack at the bottom,
   where it belongs. */
.invoices-view,
.projects-view,
.approvals-view,
.reviews-view,
.reports-view,
.audit-view {
  align-content: start;
}

/* =============================================================================================
   COLOUR AND ICONOGRAPHY (Zac: "a bit more colour and icons to beautify this")
   =============================================================================================
   The structure was right but the surfaces were flat: rows of black text on white, with colour only
   on status pills. The renders carry a glyph on every list row, a tinted accent edge, and semantic
   colour throughout. Restraint still applies — colour must MEAN something here, because this screen
   also has to say "financial details hidden" credibly.
   ============================================================================================= */

/* The small tinted square before a list row's text. Same visual family as the metric-card tile, one
   size down, so the two read as one system rather than two. */
.list-ico {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  background: var(--pill-grey-bg);
  color: var(--pill-grey-ink);
}
.list-ico svg { width: 14px; height: 14px; }
.list-ico.tone-danger  { background: var(--tile-red-bg);    color: var(--tile-red-ink); }
.list-ico.tone-warning { background: var(--tile-orange-bg); color: var(--tile-orange-ink); }
.list-ico.tone-success { background: var(--tile-green-bg);  color: var(--tile-green-ink); }
.list-ico.tone-info    { background: var(--tile-blue-bg);   color: var(--tile-blue-ink); }

/* List rows: icon, then text, then the count/value pinned right. A coloured LEFT EDGE carries the
   tone — it reads at a glance down a column of rows, where a tinted background competes with the
   pills and washes the panel out. */
.dashboard-list-item {
  gap: 10px;
  border-left: 3px solid transparent;
  transition: background 120ms ease, border-color 120ms ease;
}
.dashboard-list-item > strong { flex: 1 1 auto; min-width: 0; font-weight: 600; font-size: 12.5px; }
.dashboard-list-item.tone-danger  { border-left-color: var(--tile-red-ink);    background: #fffafa; }
.dashboard-list-item.tone-warning { border-left-color: var(--tile-orange-ink); background: #fffcf6; }
.dashboard-list-item.tone-success { border-left-color: var(--tile-green-ink);  background: #fafefb; }
.dashboard-list-item.tone-info    { border-left-color: var(--tile-blue-ink);   background: #fafcff; }
.dashboard-list-action:hover { background: var(--panel-alt); border-color: var(--border); }

/* The count is the point of an exceptions/approvals row — give it weight instead of letting it read
   as trailing punctuation. */
.dashboard-list-count {
  font-weight: 700;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  min-width: 1.4rem;
  text-align: right;
}
.dashboard-list-value { font-size: 11.5px; font-weight: 600; color: var(--muted); }

/* Audit rows carry two lines, so they stack rather than sitting on one baseline. */
.audit-row { align-items: flex-start; }
.dashboard-list-body { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.dashboard-list-body strong { font-size: 12.5px; font-weight: 600; line-height: 1.35; }
.dashboard-list-meta { font-size: 11px; color: var(--muted); }

/* Panel headers gain a coloured rule so a column of panels has rhythm rather than reading as one
   undifferentiated stack. */
.panel-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-soft);
}
.panel-header h3 { font-size: 14px; font-weight: 700; margin: 0; }
.panel-header p { font-size: 11.5px; color: var(--muted); margin: 2px 0 0; }

/* Pipeline stages: the active stage should be obvious at a glance, and completed ones should read as
   done rather than as empty. */
.pipeline-stage {
  border-radius: 10px;
  border: 1px solid var(--border-soft);
  background: var(--card);
  padding: 12px 10px;
  text-align: center;
}
.pipeline-stage strong { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pipeline-stage.tone-warning { background: var(--tile-orange-bg); border-color: #f5d9b8; }
.pipeline-stage.tone-warning strong { color: var(--tile-orange-ink); }
.pipeline-stage.tone-success { background: var(--tile-green-bg); border-color: #bfe3c8; }
.pipeline-stage.tone-success strong { color: var(--tile-green-ink); }

/* Bars pick up the chart palette rather than a single flat blue. */
.hours-bar-fill {
  background: linear-gradient(90deg, var(--chart-1), #4d97f5);
  border-radius: 999px;
}
.hours-bar-track { background: var(--pill-grey-bg); border-radius: 999px; }
.hours-bar-row { gap: 10px; align-items: center; }
.hours-bar-value { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12px; }

/* Insight rows carried a bare dot, which conveyed the tone but not the KIND. A glyph says what sort
   of signal it is at a glance, which is the whole job of this panel. */
.insight-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border: 1px solid var(--border-soft);
  border-left: 3px solid transparent;
  border-radius: 9px;
  font-size: 12.5px;
}
.insight-row + .insight-row { margin-top: 6px; }
.insight-row .list-ico { width: 22px; height: 22px; border-radius: 6px; }
.insight-row .list-ico svg { width: 12px; height: 12px; }
.insight-label { min-width: 0; }
.insight-row.tone-danger  { border-left-color: var(--tile-red-ink); }
.insight-row.tone-warning { border-left-color: var(--tile-orange-ink); }
.insight-row.tone-success { border-left-color: var(--tile-green-ink); }
.insight-row.tone-info    { border-left-color: var(--tile-blue-ink); }
.insight-dot { display: none; }

/* Donut segments gain a little separation so adjacent slices read as distinct arcs rather than one
   ring, and the centre total is given the weight it carries in the renders. */
.donut-seg { stroke-linecap: butt; }
.status-chart .donut-total { font-weight: 700; }

/* Pipeline stage icons. The stage is a PROCESS STEP, so the icon sits above the label and count as a
   small badge — a left-aligned glyph would make each stage read as a list row rather than as one of
   nine steps in a sequence. */
.pipeline-stage {
  display: grid;
  justify-items: center;
  gap: 4px;
}
.pipeline-ico {
  width: 28px;
  height: 28px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--pill-grey-bg);
  color: var(--muted);
  margin-bottom: 2px;
}
.pipeline-ico svg { width: 15px; height: 15px; }
.pipeline-label { font-size: 11.5px; font-weight: 600; color: var(--muted); }

/* The icon square picks up the stage's tone, so the active stage and completed ones are legible from
   the icon alone rather than only from the count. */
.pipeline-stage.tone-warning .pipeline-ico { background: #fdebd5; color: var(--tile-orange-ink); }
.pipeline-stage.tone-warning .pipeline-label { color: var(--tile-orange-ink); }
.pipeline-stage.tone-success .pipeline-ico { background: #d5efdc; color: var(--tile-green-ink); }
.pipeline-stage.tone-danger .pipeline-ico { background: var(--tile-red-bg); color: var(--tile-red-ink); }

/* An actionable stage should look clickable — these filter the queue. */
.pipeline-stage-actionable { cursor: pointer; }
.pipeline-stage-actionable:hover {
  border-color: var(--rail-active);
  box-shadow: var(--card-shadow-lift);
}

/* --- PAGINATION ------------------------------------------------------------------------------ */

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 2px 2px;
  margin-top: 8px;
  border-top: 1px solid var(--border-soft);
}
.pager-summary { font-size: 11.5px; color: var(--muted); }
.pager-controls { display: flex; align-items: center; gap: 4px; }

.pager-page,
.pager-step {
  min-width: 28px;
  height: 28px;
  padding: 0 7px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--card);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.pager-page:hover:not(.active),
.pager-step:hover:not(:disabled) { background: var(--panel-alt); border-color: var(--rail-active); }

/* The current page is filled, matching the active nav pill — one idea, used consistently. */
.pager-page.active {
  background: var(--rail-active);
  border-color: var(--rail-active);
  color: #fff;
  cursor: default;
}
.pager-step:disabled { opacity: 0.4; cursor: not-allowed; }
.pager-gap { padding: 0 2px; color: var(--faint); font-size: 12px; }

/* --- PROGRESS BARS AND ROW ACTIONS ------------------------------------------------------------ */

/* The bar was a thin grey track with a flat blue fill, identical at 5% and 95%. The renders colour it
   by completion, which lets a column of rows be scanned for what is STALLED without reading a single
   percentage — the actual job of this column. */
.mini-progress {
  height: 6px;
  border-radius: 999px;
  background: var(--pill-grey-bg);
  max-width: 120px;
}
.mini-progress-fill { border-radius: 999px; transition: width 200ms ease; }
.mini-progress.is-low .mini-progress-fill      { background: var(--tile-red-ink); }
.mini-progress.is-mid .mini-progress-fill      { background: var(--tile-orange-ink); }
.mini-progress.is-high .mini-progress-fill     { background: var(--chart-1); }
.mini-progress.is-complete .mini-progress-fill { background: var(--tile-green-ink); }
.row-subtext { display: block; margin-top: 3px; font-size: 10.5px; color: var(--muted); }

/* Compact icon button for a row action, per the renders. A full-width text button per row makes the
   actions column dominate a table that is mostly data. */
.icon-action {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--card);
  color: var(--ink-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.icon-action svg { width: 14px; height: 14px; }
.icon-action:hover { background: var(--panel-alt); border-color: var(--rail-active); color: var(--rail-active); }
.icon-action:focus-visible { outline: 2px solid var(--rail-active); outline-offset: 1px; }

/* The text "Open Review" button stays, but reads as a quiet secondary rather than competing with the
   status pills for attention. */
.queue-open-button {
  padding: 5px 11px;
  border-radius: 7px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink-soft);
}
.queue-open-button:hover { border-color: var(--rail-active); color: var(--rail-active); background: var(--panel-alt); }

/* A row with nothing to open says so quietly rather than with a full pill. */
.tag.muted { background: transparent; color: var(--faint); font-weight: 500; }

/* Status pills were stretching to fill their grid cell, so a short status rendered as a long bar. A
   pill should hug its text — that is what makes it read as a pill rather than a coloured row. */
.queue-row .tag,
.queue-row .status-badge { align-self: flex-start; width: fit-content; }
.queue-row > span { display: flex; flex-direction: column; gap: 3px; justify-content: center; }

/* --- CONTEXT PANEL LISTS (My Tasks / Recent Activity / Overdue Reviews idiom) ------------------ */

/* The renders use one shape for every context list: a glyph, two lines of text, and a timestamp.
   The old shape put a raw event-type tag ("BATCH_PREPARED") first, which is machine vocabulary in
   the most human-facing panel on the screen. */
.activity-item { align-items: flex-start; }
.activity-item .dashboard-list-body strong {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  /* Two lines then ellipsis: a long audit summary should not push the timestamp out of view or make
     one row four times the height of its neighbours. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* "View all →" in the panel header, per the renders — a quiet link, not a button competing with the
   panel title. */
.panel-link {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--rail-active);
  text-decoration: none;
  white-space: nowrap;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}
.panel-link:hover { text-decoration: underline; }

/* The WIP reference chip sat in the same grid cell as the project number and overlapped the next
   column. It is a second line under the project number, not a sibling of it. */
.queue-row .wip-ref-chip,
.queue-row .row-subtext {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- FUNNEL AND LINE CHARTS ------------------------------------------------------------------- */

.funnel-chart { display: grid; gap: 10px; }
.funnel-chart svg { width: 100%; height: auto; max-height: 190px; }
.funnel-legend { display: grid; gap: 4px; }
.funnel-legend-row {
  display: grid;
  grid-template-columns: 10px 1fr auto;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
}
.funnel-swatch { width: 10px; height: 10px; border-radius: 3px; }
.funnel-legend-label { color: var(--ink-soft); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.funnel-legend-value { font-weight: 700; font-variant-numeric: tabular-nums; }

.line-chart { display: grid; gap: 8px; }
.line-chart svg { width: 100%; height: auto; }
.chart-axis-label { font-size: 8px; fill: var(--muted); }
.chart-legend { display: flex; flex-wrap: wrap; gap: 10px; font-size: 11.5px; color: var(--ink-soft); }
.chart-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.chart-legend-swatch { width: 9px; height: 9px; border-radius: 2px; }

/* --- REPORTS ---------------------------------------------------------------------------------- */

/* Report cards carry an icon and a two-line head, matching every other card in the app. Without it
   this was the flattest screen: six full-width blocks of black text with a button underneath. */
.report-card { display: flex; flex-direction: column; gap: 10px; }
.report-card-head { display: flex; align-items: flex-start; gap: 10px; }
.report-card-title { min-width: 0; }
.report-card h3 { font-size: 13.5px; font-weight: 700; margin: 0; }
.report-card p { font-size: 11.5px; color: var(--muted); margin: 3px 0 0; line-height: 1.4; }

/* Foot pinned to the bottom so a row of cards has its buttons on one line regardless of how long each
   description runs. */
.report-card-foot { margin-top: auto; padding-top: 4px; }

/* A view-card expands to full width ONLY once it holds a rendered table — before that it is just
   another card and should sit in the grid with its peers. Previously every view-card broke the grid
   whether or not it had anything to show. */
.reports-grid { align-items: start; }
.report-view-card { grid-column: auto; }
.report-view-card:has(.report-table) { grid-column: 1 / -1; }

/* Report tables inherit the app's table treatment rather than browser defaults. */
.report-table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 10px; }
.report-table th {
  text-align: left;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-alt);
}
.report-table td { padding: 8px 10px; border-bottom: 1px solid var(--border-soft); }
.report-table tr:last-child td { border-bottom: 0; }

/* --- ALLOWANCE QUANTITY ENTRY ----------------------------------------------------------------- */

/* The INCLUDED column. Narrow on purpose — it holds "2" or "12", not a sentence — and right-aligned
   with the money columns so the numeric block reads as one. */
.fee-totals-table .fee-included-cell { width: 5.5rem; text-align: right; white-space: nowrap; }
.fee-included-input {
  width: 3.4rem;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12.5px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.fee-included-input:focus-visible { outline: 2px solid var(--rail-active); outline-offset: 1px; }
/* An empty box on an allowance task is the thing that needs attention, so it is tinted rather than
   left looking like an ordinary blank field. */
.fee-included-input:placeholder-shown { background: var(--pill-amber-bg); border-color: #e8d5a8; }
.fee-included-unit { font-size: 11px; color: var(--muted); margin-left: 2px; }

/* The carve-out shown under the fee: what the allowance is worth, and what the phase keeps. This is
   the arithmetic Zac asked to see — "a subtotal then is established on the fee entering screen". */
.fee-carve-out {
  display: block;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 3px;
}
.fee-carve-out-line { display: flex; justify-content: space-between; gap: 8px; }
.fee-carve-out-net { font-weight: 600; color: var(--ink-soft); }
.fee-carve-out-warn { color: var(--tile-red-ink); font-weight: 600; }

/* --- SHARE BAND on the commercial breakdown ---------------------------------------------------- */

/* "0% to 77%" beside each task, so a dollar figure carries its proportion. $3,100 means nothing
   without knowing whether it is a tenth of the invoice or most of it (Zac, 2026-08-02). */
.share-band {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  vertical-align: 1px;
}

/* Colour tracks MAGNITUDE, not sentiment. Green/red would read as good/bad, and a share is neither —
   a task being most of the invoice is worth noticing whichever direction it moved. */
.share-band.share-minor { background: var(--pill-grey-bg);   color: var(--pill-grey-ink); }
.share-band.share-mid   { background: var(--tile-blue-bg);   color: var(--tile-blue-ink); }
.share-band.share-major { background: var(--tile-purple-bg); color: var(--tile-purple-ink); }

/* --- FIXED-FEE DRAWDOWN PANEL ------------------------------------------------------------------ */

/* Sits under the value breakdown and answers a DIFFERENT question: that table says what changed in
   this review, this one says where each agreed fee stands. */
.fee-drawdown-panel { margin-top: 14px; }
.fee-drawdown-panel h4 { margin: 0 0 8px; font-size: 13px; font-weight: 700; }

.fee-drawdown-table { width: 100%; }
.fee-drawdown-table .num { font-variant-numeric: tabular-nums; }
/* The task name carries the longest content; the numeric columns need very little. */
.fee-drawdown-table th:first-child,
.fee-drawdown-table td:first-child { width: 32%; }

/* The unrounded figure is context, not the headline — it explains why "This invoice" may sit slightly
   ahead, without competing with the number actually being billed. */
.drawdown-earned { font-size: 11.5px; color: var(--muted); }
.drawdown-earned-same { opacity: 0.4; }

.fee-drawdown-note {
  margin: 8px 0 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
  max-width: 68ch;
}

/* A task with nothing to bill this period says "no change" rather than restating its current position
   as though it were a movement — "40%" beside "$0.00" reads as a contradiction. */
.drawdown-nochange { font-size: 11px; color: var(--faint); font-style: italic; }

/* Reconciles the drawdown table against the invoice total. Without it, a mostly-hourly project shows
   $0.00 drawn down beside an invoice of thousands, and the two panels appear to contradict each
   other — a reader either distrusts both or believes the wrong one. */
.fee-drawdown-reconcile {
  margin: 8px 0 0;
  padding: 8px 10px;
  border-left: 3px solid var(--tile-blue-ink);
  background: var(--tile-blue-bg);
  border-radius: 0 7px 7px 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 72ch;
}

/* --- TASK CODE CHIPS --------------------------------------------------------------------------- */

/* Xero's own short code beside the task name. The codes were in the data all along and simply never
   rendered — "DD-D" is what staff say out loud, where the full phase name is long and differs between
   the Urban Utilities and Unitywater variants of the same stage. */
.task-code {
  display: inline-block;
  margin-right: 7px;
  padding: 1px 6px;
  border-radius: 5px;
  background: var(--pill-blue-bg);
  color: var(--pill-blue-ink);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  vertical-align: 1px;
}

/* A code Xero holds but the catalogue does not know. Shown rather than hidden — the firm adds codes
   faster than the catalogue is updated, and hiding one would make the screen quietly disagree with
   Xero — but visibly distinct, so an unrecognised code is not mistaken for a known one. */
.task-code-unknown {
  background: var(--pill-grey-bg);
  color: var(--pill-grey-ink);
  border: 1px dashed var(--border);
}

/* The task column now carries a code chip AND a name, so it needs the room. Previously it held only
   a bare identifier and the narrow default was fine. */
.impact-table th:first-child,
.impact-table td:first-child { width: 46%; }
.impact-table .task-code { display: inline-block; margin-bottom: 2px; }

/* --- APPROVAL QUEUE ---------------------------------------------------------------------------- */

/* Nine columns now (Project No, Name, Client, PM, Stage, Hours, Submitted, Status, Open Review).
   The trailing icon column is fixed-width because it holds one 28px button, and letting it flex
   pushed the pills around as the row content changed. Overrides the earlier 8-column rule. */
.queue-table-header.approvals-row,
.queue-row.approvals-row {
  grid-template-columns:
    minmax(78px, 0.7fr) minmax(150px, 1.55fr) minmax(100px, 1fr) minmax(85px, 0.85fr)
    minmax(118px, 1.05fr) minmax(60px, 0.55fr) minmax(95px, 0.85fr) minmax(78px, 0.7fr) 92px;
}

/* Right-aligned so the icon column reads as an action rail rather than a stray ninth data field. */
.approvals-row .approvals-open-head,
.queue-row.approvals-row .approvals-row-actions {
  justify-content: flex-end;
  text-align: right;
}
.approvals-row .approvals-open-head { display: flex; }

@media (max-width: 1200px) {
  .queue-table-header.approvals-row,
  .queue-row.approvals-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .approvals-row .approvals-open-head,
  .queue-row.approvals-row .approvals-row-actions {
    justify-content: flex-start;
    text-align: left;
  }
}

/* Stage pills. Colour encodes WHICH DESK the item is sitting on, so a column of rows can be scanned
   for "what is stuck at Director" without reading the labels. These are workflow-stage colours, not
   good/bad sentiment. */
.tag.stage-pm       { background: var(--pill-blue-bg);   color: var(--pill-blue-ink); }
.tag.stage-director { background: var(--pill-purple-bg); color: var(--pill-purple-ink); }
.tag.stage-finance  { background: var(--tile-teal-bg);   color: var(--tile-teal-ink); }
.tag.stage-ready    { background: var(--pill-green-bg);  color: var(--pill-green-ink); }

/* Status pills DO carry sentiment: blue is routine, red is past the point of routine. */
.tag.stage-pending  { background: var(--pill-blue-bg);   color: var(--pill-blue-ink); }
.tag.stage-overdue  { background: var(--pill-red-bg);    color: var(--pill-red-ink); }

/* Panel header: title and count on the left, stage filter and refresh on the right. */
.approvals-panel-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.approvals-count {
  color: var(--muted);
  font-weight: 600;
}

.approvals-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.approvals-stage-select select {
  min-height: 28px;
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--card);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.approvals-stage-select select:hover { border-color: var(--rail-active); }

/* Rows-per-page control, at the pager's leading edge. `.pager` is already space-between, so this
   sits left while the range summary and page buttons stay right. */
.pager-size {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
}

.pager-size select {
  min-height: 26px;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--ink-soft);
  font-size: 11.5px;
  cursor: pointer;
}
.pager-size select:hover { border-color: var(--rail-active); }

/* With a size control present the pager has three children; the summary should hug the controls
   rather than float in the middle. */
.pager-size ~ .pager-summary { margin-left: auto; }

/* ---------------------------------------------------------------------------
   Report a bug / request a feature (Zac, 2026-08-02).

   The trigger lives inside the existing help popover rather than as a competing
   top-bar icon, so it needs a separated action row at the popover's foot.
   --------------------------------------------------------------------------- */

.help-popover-actions {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

/* Rail buttons are full-width by default, which is what this one wants inside the
   narrow popover — but it also needs its icon and label on one baseline. */
.rail-btn.help-report-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  font-size: 12px;
}

.help-report-button svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
}

.report-dialog {
  width: min(560px, 94vw);
}

.report-form {
  display: grid;
  gap: 6px;
}

.report-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  margin-top: 8px;
}

.report-fieldset {
  border: 0;
  padding: 0;
  margin: 0;
}

.report-fieldset .report-label {
  margin-top: 0;
  padding: 0;
}

.report-type-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
}

.report-type-option {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-alt);
  font-size: 12.5px;
  cursor: pointer;
}

.report-type-option:has(input:checked) {
  border-color: var(--rail-active);
  background: var(--card);
  font-weight: 600;
}

.report-input,
.report-textarea {
  width: 100%;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-alt);
  color: var(--ink);
  font-family: inherit;
  font-size: 12.5px;
}

.report-textarea {
  resize: vertical;
  min-height: 96px;
  line-height: 1.45;
}

/* The captured-context block. Identifiers and build posture only — never a figure. */
.report-context {
  margin-top: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-alt);
}

.report-context-heading {
  margin: 0 0 8px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.report-context-list {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 4px 16px;
}

.report-context-row {
  display: flex;
  gap: 8px;
  font-size: 11.5px;
  min-width: 0;
}

.report-context-row dt {
  color: var(--muted);
  flex: 0 0 auto;
}

/* User agents are long; truncate rather than let one row stretch the dialog. */
.report-context-row dd {
  margin: 0;
  color: var(--ink-soft);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.report-context-note {
  margin: 8px 0 0;
  font-size: 11px;
  color: var(--muted);
}

/* Takes the free space so the buttons stay right-aligned in the shared action row. */
.report-status {
  margin: 0;
  margin-right: auto;
  align-self: center;
  font-size: 11.5px;
  color: var(--danger-ink);
}

/* ---- Lodged reports list (Settings, Director/Finance only) ---- */

.feedback-report-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.feedback-report {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-alt);
}

.feedback-report-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.feedback-report-type {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.feedback-type-bug { border-color: var(--cm-rejected, var(--border)); color: var(--danger-ink); }
.feedback-type-feature { border-color: var(--cm-approved, var(--border)); color: var(--success-ink); }
.feedback-type-question { color: var(--ink-soft); }

.feedback-report-title {
  font-size: 13px;
  min-width: 0;
}

/* User-typed text: wrap and break rather than let one long token widen the panel. */
.feedback-report-description {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-soft);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.feedback-report-meta {
  margin-top: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-size: 11px;
  color: var(--muted);
}

/* ---------------------------------------------------------------------------
   INCLUDED HOURS — the "(Hourly Rates) - Xh included" allowance.

   Reuses .fee-totals-dialog for the shell, .summary-card-grid for the tiles and
   .tag for the state pills, so this screen reads as part of the same system
   rather than a new one. Only the meter and the strategy cards are new.
   --------------------------------------------------------------------------- */

.hours-allowance-summary {
  margin-bottom: 14px;
}

/* The tiles sit inside a dialog, not a full screen, so they wrap at a narrower
   track than the dashboard grid and do not stretch to fill the row. */
.hours-allowance-summary.summary-card-grid {
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.hours-allowance-table th[scope="row"] {
  font-weight: 600;
  max-width: 22rem;
  /* Task names are long and contain hyphens ("Construction Support (Hourly
     Rates) - 12h included"). break-word, never anywhere: the reviewer-workspace
     defect was descriptions shredding one fragment per line. */
  overflow-wrap: break-word;
  word-break: normal;
}

.hours-allowance-row-note {
  display: block;
  margin-top: 3px;
  font-weight: 400;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
}

.hours-allowance-table .hours-allowance-over {
  color: var(--danger-ink);
  font-weight: 600;
}

/* The meter. Scaled to max(included, used) in JS, so the fill past the marker is
   the overrun drawn to scale rather than clipped at the end of the track. */
.hours-allowance-meter {
  display: block;
  min-width: 10rem;
}

.hours-allowance-track {
  position: relative;
  display: block;
  width: 100%;
  height: 8px;
  border-radius: 999px;
  background: #e2e8f0;
  overflow: hidden;
}

.hours-allowance-fill,
.hours-allowance-over-fill {
  position: absolute;
  top: 0;
  height: 100%;
}

.hours-allowance-fill {
  left: 0;
  border-radius: 999px 0 0 999px;
  background: var(--cm-approved);
}

/* Orange, matching --cm-hours: the overrun is an hours signal, and this is the
   colour hours adjustments already carry everywhere else in the app. */
.hours-allowance-over-fill {
  background: var(--cm-hours);
}

/* A hairline at the allowance boundary, so "how far past" is readable without
   comparing the two numbers in the columns beside it. */
.hours-allowance-marker {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--navy-900);
}

.hours-allowance-meter-label {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--muted);
  white-space: nowrap;
}

/* An allowance whose hours were never set has nothing to draw. A zero-width bar
   would read as "none used"; a dashed empty track reads as "not established",
   the same choice the funnel chart makes for an empty stage. */
.hours-allowance-meter.is-unset {
  display: block;
  height: 8px;
  min-width: 10rem;
  border: 1px dashed var(--border);
  border-radius: 999px;
}

.hours-allowance-plans {
  margin-top: 18px;
}

.hours-allowance-plans:empty {
  margin-top: 0;
}

.hours-allowance-plans-heading {
  margin: 0 0 6px;
  font-size: 14px;
  color: var(--ink);
}

.hours-allowance-plan-card {
  margin-top: 12px;
  padding: 14px 16px;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-left: 3px solid var(--cm-hours);
  border-radius: 10px;
}

.hours-allowance-plan-task {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink);
  overflow-wrap: break-word;
  word-break: normal;
}

.hours-allowance-plan-over {
  margin: 4px 0 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--danger-ink);
}

.hours-allowance-options {
  display: grid;
  gap: 8px;
}

.hours-allowance-option {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}

.hours-allowance-option:hover {
  border-color: var(--accent);
}

.hours-allowance-option.is-chosen {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
  background: var(--accent-soft);
}

.hours-allowance-option input[type="radio"] {
  margin-top: 2px;
}

/* A strategy the backend returned no plan for is disabled, so it must not still
   look clickable. */
.hours-allowance-option:has(input:disabled) {
  opacity: 0.55;
  cursor: not-allowed;
}

.hours-allowance-option-body {
  display: block;
  min-width: 0;
}

.hours-allowance-option-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.hours-allowance-option-hint {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--muted);
  overflow-wrap: break-word;
  word-break: normal;
}

/* The resulting task name is the concrete consequence of the choice, so it is
   set apart from the prose rather than buried in it. */
.hours-allowance-option-rename {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  font-family: "Cascadia Mono", Consolas, monospace;
  color: var(--ink-soft);
  overflow-wrap: break-word;
  word-break: normal;
}

.hours-allowance-footnote {
  margin-top: 14px;
  margin-bottom: 0;
}

.hours-allowance-status {
  margin: 0;
  flex: 1;
  min-width: 0;
}

/* "Waiting on: Director" — whose turn it is, beside the stage number.
   Deliberately quieter than the status pill: it is orientation, not an alert. */
.waiting-on-chip {
  display: inline-flex;
  align-items: center;
  align-self: start;
  width: fit-content;
  flex: 0 0 auto;
  margin-top: 0.25rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  border: 1px dashed var(--border, #d7dce5);
  background: transparent;
  color: var(--muted, #5c6674);
  font-size: 0.72rem;
  line-height: 1.5;
  white-space: nowrap;
}
.waiting-on-chip.waiting-on-done {
  border-style: solid;
  border-color: #1f9254;
  color: #1f9254;
}
@media (prefers-color-scheme: dark) {
  .waiting-on-chip { border-color: #3a4354; color: #9aa4b2; }
  .waiting-on-chip.waiting-on-done { border-color: #35c07a; color: #35c07a; }
}
