/* Application chrome. The generated contract document has its own stylesheets
   (contract.css / contract-preview.css) and deliberately shares nothing with this
   one — restyling the app must never change what a contract looks like. */

:root {
  --brand: #1b3a80;          /* navy: wordmark, primary button, active nav */
  --brand-strong: #142c61;
  --brand-soft: #eef1fa;     /* selected row */
  --accent: #1d4ed8;         /* links and focus rings */
  --accent-rgb: 29, 78, 216;
  --accent-soft: #f5f8ff;    /* row hover */

  --text: #111827;
  --muted: #6b7280;
  --muted-strong: #4b5563;

  --surface: #ffffff;
  --surface-alt: #f8fafc;
  --border: #e8eaef;
  --border-strong: #d3d8e0;

  --amber-bg: #fffbeb;
  --amber-text: #92400e;
  --amber-border: #fcd34d;

  --radius: 6px;
  --radius-lg: 10px;
  --shadow: 0 10px 30px rgba(15, 23, 42, 0.1);
}

* {
  box-sizing: border-box;
}

/* A column flex box so the full-height pages (the builder and the review page)
   can claim "whatever is left under the header" without anyone having to know
   how tall the header is. They used to say `calc(100vh - 61px)` against a
   header that measures 64, so those pages always scrolled 3px; add a nav tab
   and the header wraps to two lines and they scroll by a whole one. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
}

/* The header is the measure; the page below it takes the remainder. */
.app-header {
  flex: 0 0 auto;
}

/* Visible to a screen reader, not to the eye.

   It is `position: absolute`, which means it is only clipped by a scrolling
   ancestor that is itself positioned — `overflow` does not clip an absolutely
   positioned descendant whose containing block is further out. One of these at
   the foot of the builder's merge-field list laid out ~1400px down the page,
   escaped the panel it lives in and stretched the document by 576px of empty
   white that scrolled independently of every panel. Every scroll container in
   this file therefore sets `position: relative`; see `.builder-panel`. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* ------------------------------------------------------------- app header -- */

.app-header {
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.app-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
  width: min(1600px, calc(100% - 3rem));
  margin: 0 auto;
  padding: 0.9rem 0;
}

.app-brand {
  display: flex;
  align-items: center;
  gap: 1rem;
  text-decoration: none;
}

.logo {
  display: block;
  width: 132px;
  height: 34px;
  object-fit: contain;
}

.app-name {
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--brand);
}

.app-nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  margin-left: auto;
  align-self: stretch;
}

.nav-tab {
  display: inline-flex;
  align-items: center;
  padding: 0.35rem 0;
  border-bottom: 2px solid transparent;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--muted-strong);
  text-decoration: none;
}

.nav-tab:hover {
  color: var(--brand);
}

.nav-tab.is-active {
  color: var(--brand);
  font-weight: 600;
  border-bottom-color: var(--brand);
}

/* An unread review note. Sits above the tab's baseline rather than beside the
   word, so the nav's spacing does not shift as notes come and go.

   Colour alone would carry the whole meaning, so the dot is paired with
   screen-reader text in base.html — it is decorative markup for a fact stated
   in words next to it. */
.nav-dot {
  width: 0.4rem;
  height: 0.4rem;
  margin-left: 0.3rem;
  align-self: flex-start;
  border-radius: 50%;
  background: #dc2626;
  flex: none;
}

/* How many contracts have reached the Desk that its tab has not been shown yet.
   A number rather than the plain dot the Review tab uses: this one is a queue
   of work, and "four waiting" and "one waiting" are worth acting on differently
   — where a note is either new or it is not. */
.nav-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  margin-left: 0.4rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: #dc2626;
  font-size: 0.7rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: #fff;
  flex: none;
}

/* Builder and Review need a trade to act on; without one they are inert rather
   than links to a route that would immediately bounce back to the queue. */
.nav-tab.is-disabled {
  color: #b6bcc7;
  cursor: default;
}

.build-ref {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  color: #9aa2af;
}

/* -------------------------------------------------------------- page shell -- */

.page-shell {
  width: min(1600px, calc(100% - 3rem));
  margin: 0 auto;
  padding: 1.5rem 0 3rem;
}

/* ----------------------------------------------------------- queue toolbar -- */

/* Filters left, actions right. This queue carries more controls than fit on one
   line below ~1600px, so the filter group wraps within itself while Refresh and
   Generate Contract stay pinned to the top right where they are always findable. */
.queue-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.6rem 1rem;
  padding: 0.85rem 0 1rem;
}

/* min-width:0 lets this shrink past its content width, so the filters wrap
   inside it rather than shoving the action cluster onto its own line. */
.toolbar-filters {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.toolbar-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.35rem;
}

.toolbar-title {
  margin: 0 0.4rem 0 0;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}

/* width:auto, or the base `select` rule below stretches these across the row. */
.toolbar-select {
  width: auto;
  min-height: 34px;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font: inherit;
  font-size: 0.85rem;
  color: var(--muted-strong);
  cursor: pointer;
}

/* An active quick-filter is easy to forget about, so it stops looking neutral. */
.toolbar-select.is-set,
.lookup-input.is-set {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.date-filter-form,
.lookup-form {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
}

/* The caption is a prefix inside the box, so the control is one line high —
   the same as the selects and Apply beside it — and the toolbar stays on one
   row rather than the date group standing taller than its neighbours. */
.date-field-label {
  padding-right: 0.5rem;
  border-right: 1px solid var(--border);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.date-range {
  display: flex;
  align-items: center;
  min-height: 34px;
  gap: 0.35rem;
  padding: 0 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
}

.date-range input[type="date"] {
  width: auto;
  min-height: 32px;
  padding: 0.3rem 0;
  border: none;
  background: transparent;
  font-size: 0.85rem;
  color: var(--muted-strong);
}

.date-range input[type="date"]:focus {
  outline: none;
  box-shadow: none;
  color: var(--text);
}

.date-range-sep {
  font-size: 0.8rem;
  color: #9aa2af;
}

.lookup-input {
  width: 190px;
  min-height: 34px;
  padding: 0.35rem 0.6rem;
  font-size: 0.85rem;
}

.awaiting-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--amber-border);
  border-radius: var(--radius);
  background: var(--amber-bg);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--amber-text);
  white-space: nowrap;
}

/*  The backlog pill, beside "N awaiting contract". Red rather than the amber
    of its neighbour: awaiting a contract is the normal state of a new trade,
    while work still open after days is the one thing on this toolbar that
    should not be there. */
.stale-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.6rem;
  border: 1px solid #fecaca;
  border-radius: var(--radius);
  background: #fef2f2;
  font-size: 0.8rem;
  font-weight: 600;
  color: #b91c1c;
  white-space: nowrap;
  cursor: help;
}

/*  Age of an unfinished contract, on its trade date. The row keeps its normal
    background — a whole row tinted red for being three days old would drown
    the status colours that say what it is actually waiting for — and takes a
    left edge instead, so a run of them reads as a block down the table. */
.queue-row.is-aged > td:first-child {
  box-shadow: inset 3px 0 0 #f87171;
}

.age-tag {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0 0.3rem;
  border-radius: 3px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  font-size: 0.7rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: #b91c1c;
  cursor: help;
}

.sync-note {
  font-size: 0.8rem;
  color: #9aa2af;
  white-space: nowrap;
}

/* The automatic refresh could not reach the server. The rows on screen are the
   last good ones, and saying so is the point — a grid that has quietly stopped
   updating looks exactly like one where nothing has happened. */
.sync-note.is-stale {
  color: var(--amber-text);
  font-weight: 600;
}

.sync-note.is-stale::after {
  content: " · not updating";
}

.db-notice {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.6rem;
  border: 1px solid rgba(220, 38, 38, 0.3);
  border-radius: var(--radius);
  background: #fef2f2;
  color: #b91c1c;
  font-size: 0.8rem;
  font-weight: 600;
}

.refresh-icon {
  display: inline-block;
  margin-right: 0.35rem;
  font-size: 0.95rem;
  line-height: 1;
}

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

.spinning {
  animation: spin 0.8s linear infinite;
}

/* ------------------------------------------------------------ queue table -- */

.queue-card {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.queue-table {
  width: 100%;
  border-collapse: collapse;
}

.queue-table th,
.queue-table td {
  padding: 0.7rem 0.85rem;
  text-align: left;
  vertical-align: middle;
}

/* Solid brand fill. The card's overflow clips it to the rounded top corners, and
   every control inside the header switches to a light-on-dark palette below. */
.queue-table thead th {
  padding-top: 0.85rem;
  padding-bottom: 0.6rem;
  background: var(--brand);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #ffffff;
  white-space: nowrap;
}

.queue-table td {
  font-size: 0.82rem;
}

.trade-id-cell {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 600;
  white-space: nowrap;
}

.counterparty-cell {
  font-weight: 600;
  color: var(--brand);
}

.delivery-cell {
  color: #7b8194;
  white-space: nowrap;
}

.num-cell {
  white-space: nowrap;
}

.template-cell {
  color: var(--muted-strong);
  white-space: nowrap;
}

.template-role::before {
  content: "\00b7";
  margin: 0 0.3rem;
  color: #b6bcc7;
}

.template-role {
  color: var(--muted);
}

.status-cell {
  white-space: nowrap;
}

.queue-row {
  cursor: default;
}

.queue-row.is-complete td {
  color: var(--muted);
}

.queue-row:hover {
  background: var(--accent-soft);
}

.queue-row.row-selected,
.queue-row.row-selected:hover {
  background: var(--brand-soft);
}

.queue-footer {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.85rem 0.15rem 0;
}

.queue-hint {
  margin: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.queue-hint strong {
  color: var(--muted-strong);
}

.queue-count {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

.empty-queue {
  padding: 3rem 2rem;
  text-align: center;
  color: var(--muted);
}

.empty-queue p {
  margin: 0.35rem 0 0;
}

/* ---------------------------------------------------------------- badges -- */

/* Square-cornered tags rather than lozenges. Only the Contract column is a
   badge now; Position used to share this rule and is plain text, because two
   boxes on a row read as two statuses. */
.status-badge {
  display: inline-block;
  padding: 0.2rem 0.45rem;
  border: 1px solid transparent;
  border-radius: 3px;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.35;
  white-space: nowrap;
}

.status-badge.pending {
  color: var(--muted-strong);
  background: #f6f7f9;
  border-color: var(--border-strong);
}

.status-badge.under-review {
  color: var(--amber-text);
  background: #fef3c7;
  border-color: var(--amber-border);
}

.status-badge.generated {
  color: #1d4ed8;
  background: #dbeafe;
  border-color: #bfdbfe;
}

.status-badge.complete {
  color: #15803d;
  background: #dcfce7;
  border-color: #bbf7d0;
}

/* Bordered like the status tags: the fills alone were heavier than everything
   else in the row once the corners squared off. */

/* ------------------------------------------------- column drag-reorder -- */

.queue-table thead th[data-key] {
  cursor: grab;
}

.queue-table thead th.is-dragging {
  opacity: 0.45;
}

/* Drop line on the edge the dragged column will land against. Amber, so it is
   legible on the blue header fill. */
.queue-table thead th.is-drop-before {
  box-shadow: inset 3px 0 0 var(--amber-border);
}

.queue-table thead th.is-drop-after {
  box-shadow: inset -3px 0 0 var(--amber-border);
}

/* Applies to everything: elementFromPoint tracks the pointer over cells that
   would otherwise show a text or pointer cursor mid-drag. */
body.is-reordering,
body.is-reordering * {
  cursor: grabbing !important;
  user-select: none;
}

/* --------------------------------------------- column headers: sort/filter -- */

.th-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem;
}

.th-label {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: left;
  cursor: pointer;
  user-select: none;
}

.th-label:hover {
  color: #bfd4ff;
}

.th-label.sorted-asc::after {
  content: " \2191";
  color: #bfd4ff;
}

.th-label.sorted-desc::after {
  content: " \2193";
  color: #bfd4ff;
}

.th-label-group {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

/* Amber, not blue: a blue dot on the blue header would be invisible. */
.filter-indicator {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--amber-border);
}

.filter-indicator[hidden] {
  display: none;
}

.col-menu {
  position: relative;
}

.col-menu-btn {
  padding: 0.1rem 0.25rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
}

.col-menu-btn:hover {
  background: rgba(255, 255, 255, 0.16);
  color: #ffffff;
}

.col-menu-btn.active {
  color: var(--amber-border);
}

.col-menu-popover {
  position: fixed;
  z-index: 50;
  display: grid;
  gap: 0.15rem;
  min-width: 220px;
  padding: 0.4rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.col-menu-popover[hidden] {
  display: none;
}

.col-filter-search {
  min-height: auto;
  padding: 0.35rem 0.5rem;
  font-size: 0.8rem;
  font-weight: 400;
}

.col-filter-list {
  display: grid;
  gap: 0.1rem;
  max-height: 220px;
  overflow-y: auto;
}

.col-filter-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.35rem 0.45rem;
  border-radius: 4px;
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  user-select: none;
}

.col-filter-item:hover {
  background: var(--accent-soft);
}

.col-filter-item input[type="checkbox"],
.col-chooser-menu input[type="checkbox"] {
  width: 0.95rem;
  height: 0.95rem;
  min-height: 0;
  padding: 0;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.col-filter-item span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.col-filter-empty {
  padding: 0.35rem 0.45rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.col-filter-truncated {
  margin: 0.2rem 0.45rem 0;
  font-size: 0.7rem;
  line-height: 1.4;
  color: var(--muted);
}

.col-filter-clear {
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: transparent;
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}

.col-filter-clear:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.col-chooser {
  position: relative;
}

.col-chooser-menu {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 20;
  display: grid;
  gap: 0.35rem;
  min-width: 200px;
  padding: 0.7rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.col-chooser-menu[hidden] {
  display: none;
}

.col-chooser-menu label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}

/* ---------------------------------------------------------- context menu -- */

.row-context-menu {
  position: fixed;
  z-index: 120;
  display: grid;
  min-width: 248px;
  max-width: 320px;
  padding: 0.3rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.row-context-menu[hidden] {
  display: none;
}

/* Which trade(s) the menu is acting on — set by queue.js on open. */
.row-context-heading {
  margin: 0;
  padding: 0.45rem 0.7rem 0.5rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

.row-context-group {
  display: grid;
}

.row-context-sep {
  margin: 0.3rem 0.45rem;
  border: none;
  border-top: 1px solid var(--border);
}

.row-context-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  width: 100%;
  padding: 0.45rem 0.7rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  font-family: inherit;
  font-size: 0.83rem;
  font-weight: 500;
  text-align: left;
  color: var(--text);
  cursor: pointer;
}

.row-context-item:hover:not(:disabled) {
  background: var(--accent-soft);
}

.row-context-item:disabled {
  color: var(--muted);
  opacity: 0.55;
  cursor: default;
}

/* Marking complete removes the trade from the queue — the only state change in
   this menu, so it is set apart from the read-only copy/open items above it. Not
   styled as a danger action: it is reversible from the trade record. */
.row-context-item.emphasis {
  color: var(--brand);
  font-weight: 600;
}

.row-context-hint {
  flex-shrink: 0;
  padding: 0.1rem 0.32rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface-alt);
  font-family: inherit;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
}

.row-context-item:disabled .row-context-hint {
  opacity: 0.6;
}

/* ----------------------------------------------------------------- modal -- */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, 0.45);
}

.modal-overlay[hidden] {
  display: none;
}

.modal-box {
  width: min(420px, calc(100% - 2rem));
  padding: 1.5rem;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: 0 25px 60px rgba(15, 23, 42, 0.35);
}

.modal-message {
  margin: 0 0 1.35rem;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text);
}

/* A field inside a confirm prompt (currently just Send to Desk's name input) —
   full-width and clear of the message above it, same spacing rhythm as
   `.note-row` on the review page. */
.modal-box input {
  margin-bottom: 0.5rem;
}

/* `.modal-hint` is muted informational text by default (the mismatch dialog's
   copy); a validation message reads as a problem instead. */
.modal-hint.is-error {
  color: #b91c1c;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
}

/* ------------------------------------------------------- forms + buttons -- */

input,
textarea,
select {
  width: 100%;
  min-height: 36px;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font: inherit;
  font-size: 0.85rem;
  color: var(--text);
}

textarea {
  min-height: 110px;
  line-height: 1.5;
  resize: vertical;
}

input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.12);
}

label {
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--muted-strong);
}

.field,
.clause-field {
  display: grid;
  gap: 0.35rem;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--text);
  cursor: pointer;
}

.checkbox-label input[type="checkbox"],
.complete-checkbox {
  width: 1rem;
  height: 1rem;
  min-height: 0;
  padding: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.complete-form {
  margin: 0;
  display: flex;
  justify-content: center;
}

.input-with-icon {
  position: relative;
}

.input-with-icon input {
  padding-right: 2rem;
}

.required-warning {
  position: absolute;
  top: 50%;
  right: 0.7rem;
  transform: translateY(-50%);
  color: #dc2626;
  font-size: 0.85rem;
  font-weight: 700;
}

/* Fields a person is expected to fill in, as opposed to those carried over
   from the trade record. */
.user-editable {
  border-color: rgba(var(--accent-rgb), 0.4);
}

.btn-primary,
.btn-secondary,
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border-radius: var(--radius);
  font-family: inherit;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
}

.btn-primary {
  padding: 0.55rem 1rem;
  border: 1px solid var(--brand);
  background: var(--brand);
  color: #fff;
  font-size: 0.88rem;
}

.btn-primary:hover:not(:disabled) {
  background: var(--brand-strong);
  border-color: var(--brand-strong);
}

.btn-secondary {
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--muted-strong);
  font-size: 0.88rem;
}

.btn-secondary:hover:not(:disabled) {
  background: var(--surface-alt);
  color: var(--text);
}

/* Low-emphasis toolbar affordances (Columns, Export) — available without
   competing with Generate Contract for attention. */
.btn-icon {
  padding: 0.45rem 0.6rem;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 500;
}

.btn-icon:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.btn-sm {
  padding: 0.4rem 0.8rem;
  font-size: 0.82rem;
  min-height: 34px;
}

.btn-primary:disabled,
.btn-secondary:disabled {
  opacity: 0.5;
  cursor: default;
}

.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-icon:focus-visible,
.nav-tab:focus-visible,
.col-menu-btn:focus-visible,
.row-context-item:focus-visible,
.footer-link:focus-visible,
.version-link:focus-visible,
.th-label:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The blue focus ring disappears against the blue table header. */
.queue-table thead .th-label:focus-visible,
.queue-table thead .col-menu-btn:focus-visible {
  outline-color: #ffffff;
}

.form-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.35rem;
}

/* ------------------------------------------------------------ flash + links -- */

.flash-stack {
  display: grid;
  gap: 0.6rem;
  margin-bottom: 1rem;
}

.flash {
  padding: 0.7rem 0.9rem;
  border: 1px solid #f2c0c0;
  border-radius: var(--radius);
  background: #fff5f5;
  font-size: 0.85rem;
  color: #0f172a;
}

.flash.success {
  border-color: rgba(34, 197, 94, 0.35);
  background: #f0fdf4;
}

.footer-link {
  display: inline-flex;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.footer-link:hover {
  text-decoration: underline;
}

.version-link {
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.version-link:hover {
  text-decoration: underline;
}

/* ------------------------------------------------------- record + history -- */

.page-card {
  padding: 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.page-header {
  margin-bottom: 1.1rem;
}

.page-title-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.page-title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 700;
}

.page-sub {
  margin: 0.3rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.page-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.1rem;
}

.detail-list {
  display: grid;
  gap: 0.3rem;
  margin: 0;
}

.detail-row {
  padding: 0.4rem 0.55rem;
  border-radius: 4px;
  background: var(--surface-alt);
}

.detail-list dt {
  font-size: 0.75rem;
  color: var(--muted);
}

.detail-list dd {
  margin: 0;
  padding: 0;
  font-weight: 600;
  color: var(--text);
}

.lookup-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.5rem;
}

.lookup-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 1.35rem;
}

.complete-notice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  border-color: rgba(220, 38, 38, 0.3);
  background: #fef2f2;
}

.complete-notice strong {
  color: #b91c1c;
}

.complete-notice p {
  margin: 0.3rem 0 0;
  font-size: 0.85rem;
  color: var(--text);
}

/* -------------------------------------------------------- contract builder -- */

/* Full-height three-panel workspace: the whole thing is one <form>, so the merge
   fields on the left are the controls that drive both the preview and the export. */
.builder {
  display: flex;
  flex-direction: column;
  /* Zero basis, not `auto`: body only sets `min-height`, so a content-sized
     basis would let this grow to its content instead of taking the remainder. */
  flex: 1 1 0;                  /* the viewport, less however tall the header is */
  min-height: 0;
  overflow: hidden;
  margin: 0;
}

.builder-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.builder-back {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.builder-back:hover {
  text-decoration: underline;
}

.builder-trade {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  font-weight: 600;
}

.builder-cpty {
  font-size: 0.9rem;
  font-weight: 700;
}

.builder-product,
.builder-field-label {
  font-size: 0.78rem;
  color: var(--muted);
}

.builder-field-label {
  margin-left: 0.5rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Looks like the control it stands in for, but the template is derived rather
   than chosen: there is exactly one per pipeline and role. */
.builder-template {
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-alt);
  font-size: 0.82rem;
  color: var(--muted-strong);
  white-space: nowrap;
}

.builder-bar-spacer {
  flex: 1 1 0;
  min-width: 0;
}

.pill {
  display: inline-flex;
  align-items: center;
  padding: 0.18rem 0.5rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
}

.pill-ok {
  color: #15803d;
  background: #dcfce7;
  border-color: #bbf7d0;
}

.pill-alert {
  color: #b91c1c;
  background: #fef2f2;
  border-color: #fecaca;
}

.seg {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-alt);
}

.seg-btn {
  padding: 0.28rem 0.7rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--muted-strong);
  cursor: pointer;
}

.seg-btn.is-active {
  background: var(--surface);
  color: var(--brand);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12);
}

/* ------------------------------------------------------------ panel frame -- */

/* The side columns are driven by custom properties the drag handles write to
   (panes.js). The 6px tracks are the handles themselves — keep them in step with
   DIVIDER_PX there. */
.builder-body {
  display: grid;
  grid-template-columns:
    var(--pane-left, 320px) 6px minmax(0, 1fr) 6px var(--pane-right, 330px);
  flex: 1 1 auto;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  background: var(--surface-alt);
}

/* `position: relative` is load-bearing, not decoration: it makes this panel the
   containing block for its absolutely positioned descendants, so `overflow-y`
   actually clips them. Without it an `.sr-only` label inside escapes the panel
   and extends the whole document. Every scrolling panel below does the same. */
.builder-panel {
  position: relative;
  height: 100%;
  min-height: 0;
  overflow-y: auto;
}

.builder-fields {
  border-right: 1px solid var(--border);
  background: var(--surface);
}

.builder-checks {
  border-left: 1px solid var(--border);
  background: var(--surface);
}

.builder-doc {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 1.5rem;
  overflow: hidden;
  position: relative;
}

/* Stacked: one column, panels above the document. Focus: document only. */
.builder-body.is-stacked {
  position: relative;
  display: block;
  overflow-y: auto;
}

.builder-body.is-stacked .builder-panel {
  overflow: visible;
}

.builder-body.is-stacked .builder-fields,
.builder-body.is-stacked .builder-checks {
  border: none;
  border-bottom: 1px solid var(--border);
}

.builder-body.is-focus {
  grid-template-columns: minmax(0, 1fr);
}

.builder-body.is-focus .builder-fields,
.builder-body.is-focus .builder-checks {
  display: none;
}

/* ---------------------------------------------------------- pane dividers -- */

.pane-divider {
  position: relative;
  border: none;
  padding: 0;
  background: var(--border);
  cursor: col-resize;
  touch-action: none;      /* the drag is handled in JS, not by scrolling */
}

/* A 6px track is a small target, so the grab area reaches past it on both
   sides without changing the layout. */
.pane-divider::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -4px;
  right: -4px;
}

.pane-divider:hover,
.pane-divider:focus-visible,
.pane-divider.is-dragging {
  background: var(--accent);
  outline: none;
}

/* Only the panel edges move, so the cursor stays a resize cursor everywhere
   during the drag — including over the preview iframe. */
body.is-resizing,
body.is-resizing * {
  cursor: col-resize !important;
  user-select: none;
}

/* Nothing to drag once the panels are stacked or hidden. */
.builder-body.is-stacked .pane-divider,
.builder-body.is-focus .pane-divider {
  display: none;
}

.panel-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
}

.panel-title {
  margin: 0;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.panel-title-standalone {
  margin-top: 0.75rem;
  padding: 1rem 0.9rem 0.5rem;
  border-top: 1px solid var(--border);
}

.panel-note {
  font-size: 0.7rem;
  color: #9aa2af;
  white-space: nowrap;
}

/* ----------------------------------------------------------- merge fields -- */

.mf-group-title {
  margin: 0;
  padding: 0.6rem 0.9rem 0.3rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.mf-row {
  display: grid;
  grid-template-columns: 10px 96px minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.3rem 0.4rem;
  padding: 0.3rem 0.9rem;
  border-bottom: 1px solid #f4f5f8;
}

.mf-row:hover {
  background: var(--accent-soft);
}

.mf-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #34a58a;          /* merged: a system of record supplied it */
}

.mf-row.is-missing .mf-dot {
  background: #dc2626;
}

.mf-row.is-optional .mf-dot {
  background: var(--border-strong);
}

.mf-label {
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.mf-value {
  font-size: 0.78rem;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mf-row.is-missing .mf-value,
.mf-row.is-missing .mf-input::placeholder {
  color: #b91c1c;
  opacity: 1;
}

/* Editable values read as text until touched, so the panel scans as an
   inventory of what the document will say rather than as a form. */
.mf-input {
  width: 100%;
  min-height: 0;
  padding: 0.15rem 0.3rem;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  font-size: 0.78rem;
}

.mf-input:hover {
  border-color: var(--border-strong);
  background: var(--surface);
}

.mf-input:focus {
  border-color: var(--accent);
  background: var(--surface);
}

.mf-textarea {
  grid-column: 1 / -1;
  min-height: 3.6rem;
  padding: 0.35rem 0.45rem;
  border-color: var(--border);
  background: var(--surface);
  line-height: 1.45;
  resize: vertical;
}

.mf-clause-state {
  font-size: 0.78rem;
  color: var(--muted-strong);
}

.mf-row.is-merged .mf-clause-state {
  color: var(--text);
  font-weight: 600;
}

.mf-row.is-missing .mf-clause-state {
  color: #b91c1c;
  font-weight: 600;
}

.mf-clause-note {
  margin: 0;
  padding: 0.25rem 0.9rem 0.5rem 1.55rem;
  border-bottom: 1px solid #f4f5f8;
  font-size: 0.68rem;
  line-height: 1.45;
  color: #9aa2af;
}

.mf-toggle {
  display: flex;
  justify-content: flex-end;
}

.mf-toggle input[type="checkbox"] {
  width: 0.95rem;
  height: 0.95rem;
  min-height: 0;
  padding: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.mf-source {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #b6bcc7;
  white-space: nowrap;
}

#creatorNameWarning {
  color: #dc2626;
  font-size: 0.85rem;
  font-weight: 700;
}

#creatorNameWarning[hidden] {
  display: none;
}

.mf-note {
  margin: 0;
  padding: 0.4rem 0.9rem 1.25rem;
  font-size: 0.7rem;
  color: var(--muted);
}

/* ----------------------------------------------------------------- checks -- */

.check {
  margin: 0.6rem 0.75rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
}

.check.is-error {
  border-left-color: #dc2626;
  background: #fffbfb;
}

.check.is-warning {
  border-left-color: var(--amber-border);
  background: var(--amber-bg);
}

.check.is-ok {
  border-left-color: #34a58a;
}

.check-title {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--text);
}

.check-icon {
  font-size: 0.75rem;
  line-height: 1;
}

.check.is-error .check-icon {
  color: #dc2626;
}

.check.is-warning .check-icon {
  color: var(--amber-text);
}

.check.is-ok .check-icon {
  color: #34a58a;
}

.check-detail {
  margin: 0.3rem 0 0;
  padding: 0 0.05rem;
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--muted-strong);
}

.check-actions {
  margin-top: 0.5rem;
}

.btn-xs {
  min-height: 0;
  padding: 0.25rem 0.55rem;
  font-size: 0.74rem;
}

.clause-log {
  margin: 0;
  padding: 0 0.9rem 1.5rem;
  list-style: none;
}

.clause-log li {
  display: flex;
  gap: 0.6rem;
  padding: 0.3rem 0;
  font-size: 0.73rem;
  line-height: 1.5;
  color: var(--muted-strong);
}

.log-time {
  flex-shrink: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: #9aa2af;
}

.preview-frame {
  display: block;
  flex: 0 0 auto;
  width: min(100%, 816px);
  height: 100%;
  max-height: calc(100vh - 150px);
  border: 1px solid var(--border);
  border-radius: 2px;
  background: #fff;
}

/* ------------------------------------------------------------- review page -- */

/* `overflow: hidden` and `min-height: 0` for the same reason `.builder` has
   them: this is a fixed-height workspace whose panels do their own scrolling,
   and without them a tall panel pushes the page taller than the viewport and
   the document grows a second scrollbar that no panel is in step with. */
.review {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}

.review .builder-bar {
  background: var(--surface-alt);
}

.review-summary {
  font-size: 0.78rem;
  color: var(--muted);
}

.review-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 6px var(--pane-right, 380px);
  flex: 1 1 auto;
  min-height: 0;
}

.review-doc {
  position: relative;
  min-height: 0;
  padding: 1.75rem;
  overflow-y: auto;
  background: var(--surface-alt);
}

.review-side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-left: 1px solid var(--border);
  background: var(--surface);
}

/* ---------------------------------------------------------------- redline -- */

.redline-sheet {
  width: min(760px, 100%);
  margin: 0 auto;
  padding: 2.5rem 3rem 3rem;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface);
}

.redline-kicker {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

.redline-title {
  margin: 0.35rem 0 1.75rem;
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--text);
}

.redline-empty,
.panel-empty {
  margin: 0;
  padding: 1rem 0.9rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.redline-block {
  padding: 0 0 0 0.85rem;
  margin-bottom: 1.1rem;
  border-left: 3px solid var(--border-strong);
}

.redline-block.is-added {
  border-left-color: var(--accent);
}

.redline-block.is-removed {
  border-left-color: #dc2626;
}

.redline-label {
  margin: 0 0 0.3rem;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}

.redline-block.is-added .redline-label,
.redline-block.is-added .redline-label span {
  color: var(--accent);
}

.redline-block.is-removed .redline-label,
.redline-block.is-removed .redline-label span {
  color: #dc2626;
}

.redline-line {
  margin: 0 0 0.35rem;
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--muted-strong);
}

.redline-block.is-added .redline-line {
  color: var(--text);
}

/* Struck through, and left in place: a reviewer needs to see what the wording
   used to be, not just that something went. */
.redline-block.is-removed .redline-line {
  color: #b91c1c;
  text-decoration: line-through;
}

.redline-collapsed {
  margin: 0 0 1.1rem;
  padding-left: 0.85rem;
  border-left: 3px solid transparent;
  font-size: 0.72rem;
  font-style: italic;
  color: #9aa2af;
}

/* ------------------------------------------------------ document + trail -- */

/* The stored version, shown through the same page the builder previews. The
   frame is the document's paper width and is sized to its content by review.js,
   so it reads as a sheet on the desk rather than a scrolling window onto one;
   the audit trail below is reached by scrolling the page, not the frame. */
.review-frame {
  display: block;
  width: min(816px, 100%);
  height: 60vh;                 /* until review.js has measured the content */
  margin: 0 auto;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: #fff;
}

.review-legend {
  width: min(816px, 100%);
  margin: 0.5rem auto 0;
  font-size: 0.72rem;
  color: var(--muted);
}

/* The two highlights the framed document uses, as swatches beside their
   meaning. Colours match contract-review.css exactly — the legend is only
   worth having if it looks like the thing it explains. */
.review-legend .swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  margin: 0 0.3rem -0.1rem 0;
  vertical-align: baseline;
}

.review-legend .swatch.is-field {
  background: #fff9c4;
  border-radius: 2px;
}

.review-legend .swatch.is-change {
  margin-left: 0.8rem;
  border-left: 3px solid #1d4ed8;
  background: #eff6ff;
}

/* What the redline used to be, moved underneath the document as the record of
   who changed what and when. Same width as the paper above it, so the two read
   as one column. */
.audit-trail {
  width: min(816px, 100%);
  margin: 1.5rem auto 0;
  padding: 1.5rem 2rem 2rem;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface);
}

.audit-section + .audit-section {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.audit-title {
  margin: 0.3rem 0 0.35rem;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
}

/* Who exported the version under review and when, and who accepted it. This
   is the line the change list answers to — it is what makes the list an audit
   trail rather than a diff. */
.audit-meta {
  margin: 0 0 1.1rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--muted);
}

.audit-meta strong {
  color: var(--text);
  font-weight: 600;
}

.audit-accepted {
  color: #15803d;
}

/* Everything recorded against the trade, newest first: versions exported and
   notes written, each with a timestamp and a name. The redline blocks above
   say what changed; this says who did what around those changes. */
.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}

.timeline-item {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: 0.2rem 1rem;
  padding: 0.65rem 0;
  border-top: 1px solid var(--border);
}

.timeline-item:first-child {
  border-top: 0;
  padding-top: 0;
}

.timeline-when {
  padding-top: 0.15rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  color: #9aa2af;
}

.timeline-what {
  margin: 0;
  font-size: 0.82rem;
  color: var(--text);
}

.timeline-who {
  font-weight: 600;
}

.timeline-detail,
.timeline-text {
  grid-column: 2;
  margin: 0;
  font-size: 0.76rem;
  line-height: 1.5;
}

.timeline-detail {
  color: var(--muted);
}

/* Whatever was typed, kept as typed. */
.timeline-text {
  color: var(--muted-strong);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The kind of event, as a small tag before it: a version exported, a move
   between the desks, a sign-off, a note. Coloured by kind so a glance down the
   trail finds the moves among the comments. */
.timeline-tag {
  display: inline-block;
  margin-right: 0.45rem;
  padding: 0.05rem 0.4rem;
  border-radius: 3px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  vertical-align: 0.05rem;
  background: var(--surface-alt);
  color: var(--muted-strong);
}

.timeline-item.is-version .timeline-tag {
  background: #dbeafe;
  color: #1d4ed8;
}

.timeline-item.is-move .timeline-tag {
  background: var(--brand-soft);
  color: var(--brand);
}

.timeline-item.is-signoff .timeline-tag,
.timeline-item.is-accept .timeline-tag {
  background: #dcfce7;
  color: #15803d;
}

/* ------------------------------------------------------------------- tabs -- */

.tabs {
  display: flex;
  flex-shrink: 0;
  gap: 1.25rem;
  padding: 0 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.tab {
  padding: 0.75rem 0;
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--muted-strong);
  cursor: pointer;
}

.tab:hover {
  color: var(--brand);
}

.tab.is-active {
  border-bottom-color: var(--brand);
  color: var(--brand);
  font-weight: 600;
}

.tab-panel {
  position: relative;
  min-height: 0;
  padding: 0.75rem 0;
  overflow-y: auto;
}

.tab-panel[hidden] {
  display: none;
}

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

.approval {
  display: flex;
  gap: 0.6rem;
  margin: 0.5rem 1rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.approval-mark {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: var(--surface-alt);
  color: #b6bcc7;
  font-size: 0.7rem;
  line-height: 1;
}

.approval.is-signed .approval-mark {
  background: #dcfce7;
  color: #15803d;
}

.approval-body {
  min-width: 0;
}

.approval-head {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0;
  font-size: 0.82rem;
  color: var(--text);
}

.approval-who {
  font-size: 0.74rem;
  color: var(--muted);
}

.approval-text {
  margin: 0.25rem 0 0;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--muted-strong);
  overflow-wrap: anywhere;
}

.approval-muted {
  color: #9aa2af;
}

.approval-at {
  margin: 0.3rem 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  color: #9aa2af;
}

.note {
  margin: 0.5rem 1rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ------------------------------------------------------------- note form -- */

.note-form {
  margin: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--border);
}

.note-form .panel-title {
  margin-bottom: 0.5rem;
}

.note-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
}

.note-form textarea {
  min-height: 4.5rem;
}

/*  Save note, and Accept changes when it is offered. */
.note-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35rem;
  margin-top: 0.5rem;
}

/*  The three workflow moves, on a row of their own and always one row: each
    takes an equal share of the width, and a label wraps inside its button
    before the row does. The panel is resizable down to 280px, where three
    labels do not fit side by side unwrapped — a two-line label in one button
    still reads as one set of three choices, where a button pushed onto a
    second line behind Save note read as an afterthought. */
.flow-actions {
  display: flex;
  gap: 0.35rem;
  margin-top: 0.4rem;
}

.flow-actions .btn-flow {
  flex: 1 1 0;
  min-width: 0;
  white-space: normal;
  text-align: center;
  /* Sized so the longest label, "Send to Contracts", fits on one line at the
     panel's default 380px; narrower than that it wraps inside its button. */
  padding: 0.3rem 0.2rem;
  font-size: 0.68rem;
}

/*  The final step, on a row of its own once the Desk has approved: solid
    rather than tinted, because unlike the moves between the desks this one
    leaves the company, and it should not look like one more of them. */
.flow-actions.is-final .btn-flow {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.flow-actions.is-final .btn-flow:hover {
  background: var(--brand-strong);
  border-color: var(--brand-strong);
}

/*  The three workflow moves. One brand blue for all of them: they are the same
    kind of gesture — hand this contract to the other desk — and which one is
    right depends on who is looking at the page rather than on any ranking
    between them. Tinted rather than solid, so they do not compete with the
    solid navy of a real primary button elsewhere on the page. */
.btn-flow {
  min-height: 26px;
  padding: 0.2rem 0.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  border-radius: var(--radius);
  cursor: pointer;
}

.btn-flow:hover {
  background: #e3eafa;
  border-color: rgba(var(--accent-rgb), 0.5);
}

.btn-flow:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*  Shown at the top of the Approvals panel straight after a move, confirming
    what was recorded and offering the draft again if the click-through was
    blocked. */
.draft-ready {
  display: grid;
  gap: 0.4rem;
  justify-items: start;
  margin: 0 0 0.75rem;
  padding: 0.7rem 0.8rem;
  background: var(--amber-bg);
  border: 1px solid var(--amber-border);
  border-radius: var(--radius);
}

.draft-ready-head {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--amber-text);
}

.draft-ready-text {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--muted-strong);
}

.note-hint {
  margin: 0.6rem 1rem 1rem;
  font-size: 0.68rem;
  line-height: 1.5;
  color: #9aa2af;
}

.note-form .note-hint {
  margin: 0.6rem 0 0;
}

/* --------------------------------------------------------------- versions -- */

.version-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0.5rem 1rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.version-row.is-selected {
  border-color: var(--brand);
  background: var(--brand-soft);
}

.version-links {
  display: grid;
  gap: 0.2rem;
  text-align: right;
  white-space: nowrap;
}

.version-links a {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.version-links a:hover {
  text-decoration: underline;
}

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

/* Below this the three panels cannot all hold their minimum width beside an
   816px document, so the builder falls back to the stacked arrangement. */
@media (max-width: 1240px) {
  /* Stacked, so the page scrolls as one rather than the panels scrolling
     inside a fixed-height shell. `flex` and `overflow` are both undone: the
     shell is now as tall as its content, and clipping it would cut the
     content off instead of letting the document scroll to it. */
  .builder {
    flex: 0 0 auto;
    height: auto;
    overflow: visible;
  }
  .builder-body {
    display: block;
    overflow-y: visible;
  }
  .builder-body .builder-panel {
    overflow: visible;
  }
  .builder-body .builder-fields,
  .builder-body .builder-checks {
    border: none;
    border-bottom: 1px solid var(--border);
  }
  .seg {
    display: none;      /* the layout is forced here, so the switch would lie */
  }
  .review {
    flex: 0 0 auto;
    height: auto;
    overflow: visible;
  }
  .review-body {
    display: block;
  }
  /* Its own scrolling would trap the redline in a short box on a page that is
     already scrolling as one. */
  .review-doc {
    overflow-y: visible;
  }
  .review-side {
    border-left: none;
    border-top: 1px solid var(--border);
  }
  /* Stacked panels are full width, so there is no edge left to drag. */
  .pane-divider {
    display: none;
  }
}

@media (max-width: 720px) {
  .app-header-inner,
  .page-shell {
    width: calc(100% - 1.5rem);
  }
  .app-name {
    font-size: 1.2rem;
  }
  .app-nav {
    gap: 1.1rem;
  }
  .queue-footer {
    flex-direction: column;
    gap: 0.5rem;
  }
}

/* ------------------------------------------------------------------ admin -- */

/* A reading column rather than the queue's full width: these are paragraphs of
   contract wording, and a 1600px-wide textarea is unreadable to proofread. */
.admin-shell {
  width: min(940px, calc(100% - 3rem));
}

.admin-head {
  padding: 0.5rem 0 0.25rem;
}

.admin-title {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.admin-lede {
  margin: 0.35rem 0 0;
  max-width: 62ch;
  color: var(--muted-strong);
  line-height: 1.55;
}

.admin-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.1rem 0 0.5rem;
}

.admin-jump a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-alt);
  color: var(--muted-strong);
  font-size: 0.8rem;
  font-weight: 500;
  text-decoration: none;
}

.admin-jump a:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.admin-pill {
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 0.7rem;
  font-weight: 700;
}

.admin-card {
  margin: 1rem 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  /* Anchored jumps must not tuck the card title under the sticky header. */
  scroll-margin-top: 1rem;
}

.admin-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.1rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.admin-card-head form {
  margin: 0;
}

.admin-card-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
}

.admin-card-sub {
  margin: 0.3rem 0 0;
  max-width: 62ch;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
}

.admin-form {
  display: grid;
  gap: 1.1rem;
  padding: 1.1rem;
}

.admin-field {
  display: grid;
  gap: 0.35rem;
}

.admin-field-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.admin-tags {
  display: inline-flex;
  gap: 0.35rem;
  flex-shrink: 0;
}

.admin-tag {
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-alt);
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  /* Every tag carries a title= explaining itself. */
  cursor: help;
}

.admin-tag.is-edited {
  border-color: var(--amber-border);
  background: var(--amber-bg);
  color: var(--amber-text);
}

/* This term's token is in a template, so editing it changes the document. */
.admin-tag.is-live {
  border-color: #a7d8b4;
  background: #ecfdf3;
  color: #15803d;
}

/* This term is reported on the Builder but no template merges it. */
.admin-tag.is-panel {
  border-color: var(--border-strong);
  background: var(--surface);
  color: var(--muted);
}

.admin-tag.is-missing {
  border-color: #f2c0c0;
  background: #fef2f2;
  color: #b91c1c;
}

.admin-help {
  margin: 0;
  max-width: 70ch;
  color: var(--muted);
  font-size: 0.76rem;
  line-height: 1.5;
}

.admin-help code,
.admin-filename {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
}

.admin-field.is-flag .admin-field-head {
  justify-content: flex-start;
}

.admin-field.is-flag .checkbox-label {
  font-weight: 500;
  color: var(--muted-strong);
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
}

.admin-table th,
.admin-table td {
  padding: 0.55rem 1.1rem;
  text-align: left;
}

.admin-table th {
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The email groups, one row each: who a draft goes to and who is copied, side
   by side rather than stacked, so the two lists can be compared at a glance and
   the second group is not below the fold. The address boxes take the width the
   other three columns do not need. */
.admin-email-table td {
  vertical-align: top;
}

.admin-email-table th:nth-child(3),
.admin-email-table th:nth-child(4) {
  width: 30%;
}

.admin-email-table textarea {
  min-width: 14rem;
  font-size: 0.8rem;
}

/* Prose, not a label: it wraps rather than stretching the column. */
.admin-email-when {
  max-width: 18rem;
  color: var(--muted);
  line-height: 1.45;
}

.admin-upload {
  display: grid;
  gap: 0.75rem;
  justify-items: start;
  padding: 1.1rem;
}

.admin-upload .field {
  width: 100%;
}

.admin-subtitle {
  margin: 0;
  padding: 0 1.1rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.admin-uploads {
  margin: 0.5rem 0 0;
  padding: 0 1.1rem 1.1rem;
  list-style: none;
  display: grid;
  gap: 0.5rem;
}

.admin-uploads li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-alt);
}

.admin-uploads form {
  margin: 0 0 0 auto;
}

.admin-empty {
  padding: 0 1.1rem 1.1rem;
}

@media (max-width: 720px) {
  .admin-shell {
    width: calc(100% - 1.5rem);
  }
  .admin-card-head,
  .admin-field-head {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* The source-chip legend on the Admin tab. The chips reuse .mf-source so they
   are visually the same token the builder prints; here they need a little more
   presence than they have sitting quietly beside a merge field. */
.source-table td:first-child {
  width: 1%;
  white-space: nowrap;
}

.source-chip {
  display: inline-block;
  padding: 0.15rem 0.45rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-alt);
  /* .mf-source is deliberately low-contrast in the builder's field list; as the
     subject of its own row it has to be readable. */
  color: var(--muted-strong);
  font-size: 0.7rem;
}

.source-blank {
  color: var(--muted);
}

/* --------------------------------------------------- admin: collapsing -- */

/* Each admin section is a <details>. The page opens as an index of what can be
   configured; a card is expanded on demand, or by the server after a save. */
details.admin-card > summary {
  cursor: pointer;
  /* Both are needed: Safari uses the WebKit pseudo-element, everyone else
     honours list-style. Without them the browser prints its own triangle
     alongside the chevron below. */
  list-style: none;
}

details.admin-card > summary::-webkit-details-marker {
  display: none;
}

/* A closed card is a single bar, so the header's bottom edge and square lower
   corners would read as a panel with nothing under it. */
details.admin-card:not([open]) > summary {
  border-bottom: none;
  border-radius: var(--radius-lg);
}

details.admin-card > summary:hover {
  background: var(--brand-soft);
}

details.admin-card > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Drawn rather than a character so it rotates cleanly and needs no font. */
summary.admin-card-head::after {
  content: '';
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  margin-left: auto;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transform-origin: center;
  transition: transform 0.15s ease;
}

details.admin-card[open] > summary.admin-card-head::after {
  transform: rotate(-135deg);
}

/* The summary keeps .admin-card-head's flex row; the pill must not stretch. */
summary.admin-card-head > .admin-pill {
  flex: none;
  align-self: center;
}

/* Save and Restore sit together at the foot of an open card. Restore is its own
   form — it cannot nest inside the terms form — so this row holds both, and the
   Save button reaches its form by `form=`. */
.admin-card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0 1.1rem 1.1rem;
}

.admin-card-actions form {
  margin: 0;
  /* Pushes Restore to the left, keeping the primary action furthest right. */
  margin-right: auto;
}

@media (max-width: 720px) {
  /* .admin-card-head stacks on narrow screens; the chevron would then sit on
     its own line below the description. */
  summary.admin-card-head::after {
    margin-left: 0;
  }
}

/* ------------------------------------------------- review: unread notes -- */

/* A note the builder has not read yet. The filled mark is what catches the eye
   scrolling the list; .new-tag says so in words, because the fill is colour
   only and would otherwise carry the whole meaning on its own. */
.approval.is-new .approval-mark,
.approval.is-signed.is-new .approval-mark {
  background: var(--amber-border);
  color: var(--amber-text);
}

.approval.is-new,
.note.is-new {
  border-color: var(--amber-border);
  background: var(--amber-bg);
}

.new-tag {
  flex: none;
  margin-left: auto;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  background: var(--amber-border);
  color: var(--amber-text);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ------------------------------------------- review: pinned comments -- */

/* The comments panel carries its own head so it can hold the pin control and,
   once pinned, name itself where nothing else would. */
.comments-head {
  position: static;   /* the tab strip above is already sticky */
}

/* Pinned: the panel has been moved inside the approvals panel, below the note
   form, so it needs a rule of its own to read as a separate section rather
   than as more of the form. */
.tab-panel.is-pinned {
  margin-top: 0.75rem;
  border-top: 1px solid var(--border);
}

/* The tab stays in the strip and becomes a jump link to the pinned section.
   Dimmed so it is clear it is no longer a panel you switch to, and it can
   never show as selected while its content lives elsewhere. */
.tab.is-pinned {
  color: var(--muted);
  font-style: italic;
}

.tab.is-pinned::after {
  content: ' ↓';
  font-style: normal;
}

/* A stored contract version whose text was partly typed by hand on the builder
   rather than merged from the template — reviewers need to know at a glance. */
.hand-edit-tag {
  flex: none;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--amber-bg);
  border: 1px solid var(--amber-border);
  color: var(--amber-text);
  font-size: 0.64rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: help;
}

/* The builder-bar pill is a <button> when it counts hand edits. */
button.pill {
  font: inherit;
  cursor: pointer;
}

/* Any `display` of our own outranks the [hidden] attribute's user-agent rule,
   so an element hidden by script stays visible unless we say otherwise. This
   has caught two controls already (the hand-edit pill, the Continue button);
   one rule covering everything that sets a display is cheaper than finding the
   third. */
[hidden] {
  display: none !important;
}

/* ------------------------------------------------------------ grid tables -- */

/* Shared ruling for the application's data tables — the queue and the Admin
   tab's tables today. A new table gets it by adding `grid-table` alongside its
   own class and needs no borders of its own; that is the whole point of it
   being one class rather than a rule per table.
   
   Never add it to .doc-table. The generated contract has its own stylesheet
   (contract.css) and must not pick up application chrome — a contract's table
   borders are the document's business, not the app's.
   
   Internal lines only. Every grid table sits inside a card that already draws
   the outer edge and rounds the corners, so ruling the table's own perimeter
   would double up against it and square off the corners. */
.grid-table {
  --grid-line: var(--border);
  border-collapse: collapse;
}

/* Column separators. The `+` skips the first cell of every row, which is
   exactly where an outer edge would otherwise appear. */
.grid-table th + th,
.grid-table td + td {
  border-left: 1px solid var(--grid-line);
}

/* Row separators, and none under the last row — the card's own edge closes it.
   `> *` so a row built from <th> cells is ruled like one built from <td>. */
.grid-table tbody tr:not(:last-child) > * {
  border-bottom: 1px solid var(--grid-line);
}

.grid-table thead th {
  border-bottom: 1px solid var(--grid-line);
}

/* The queue's header is a solid brand fill, so its dividers are drawn
   light-on-dark instead of in the page's border grey, which would vanish
   against it. Scoped to the header: the body rows keep the default. */
.queue-table thead {
  --grid-line: rgba(255, 255, 255, 0.22);
}

/* ------------------------------------------------- combined contracts -- */

/* Tick box column: the first column, directly before the trade number. It
   replaced the selection caret that used to sit between them — the caret was
   `aria-hidden` and could only ever repeat what the box already shows — so it
   carries that column's left padding now. Narrow enough not to read as data. */
.select-col,
.select-cell {
  width: 2.4rem;
  padding-right: 0.35rem !important;
  padding-left: 0.75rem !important;
  text-align: center;
}

.select-cell input {
  width: 1rem;
  height: 1rem;
  min-height: 0;
  padding: 0;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* The builder's banner when one contract covers several trades. */
.group-banner {
  margin: 0 0 0.75rem;
  padding: 0.8rem 1rem;
  border: 1px solid var(--accent);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--accent-soft);
}

/* A pipeline or side mismatch is not a warning to read past — the export is
   refused — so it is coloured as the error it is. */
.group-banner.is-blocked {
  border-color: #dc2626;
  background: #fef2f2;
}

.group-banner-head {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--text);
}

.group-banner-ids {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0 0;
}

.group-chip {
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  color: var(--muted-strong);
  cursor: help;
}

/* The trade every value the contract states once is taken from. */
.group-chip.is-lead {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand);
  font-weight: 700;
}

.group-banner-note {
  margin: 0.6rem 0 0;
  max-width: 80ch;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--muted-strong);
}

/* Field-by-field comparison, in the queue's dialog and the builder's banner. */
.mismatch-table {
  margin-top: 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.mismatch-table th,
.mismatch-table td {
  padding: 0.4rem 0.7rem;
  font-size: 0.78rem;
}

/* `th.` rather than the class alone: .admin-table th is (0,1,1) and would
   outrank a bare class whatever the order. It uppercases column headings, but
   these are row labels naming a field — "PRICE / DIFFERENTIAL" reads as
   shouting. */
th.mismatch-field {
  white-space: nowrap;
  color: var(--muted-strong);
  text-transform: none;
  font-size: 0.78rem;
  letter-spacing: 0;
}

/* Counterparty, volume and differential: a mismatch here means the trades are
   not the same deal, so they lead the table and are marked. */
.mismatch-table tr.is-critical > * {
  background: var(--amber-bg);
  color: var(--amber-text);
  font-weight: 600;
}

.mismatch-table tr.is-blocking > * {
  background: #fef2f2;
  color: #b91c1c;
  font-weight: 700;
}

/* The comparison needs more width than a confirm prompt, and can scroll
   sideways for a selection of several trades rather than squeezing columns. */
.modal-box.modal-wide {
  width: min(760px, calc(100% - 2rem));
}

.mismatch-table-wrap {
  max-height: 45vh;
  overflow: auto;
}

.modal-hint {
  margin: 0.9rem 0 1.2rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--muted);
}

/* Who last generated a document for the trade. Self-attested — the app has no
   accounts — so it is a record of who has worked on it, not an assignment. */
.user-cell {
  font-size: 0.82rem;
  white-space: nowrap;
}

.user-unassigned {
  color: #9aa2af;
  font-style: italic;
}

/* Right-aligned per-row action in an Admin table (Remove, and anything after). */
.admin-row-action {
  width: 1%;
  white-space: nowrap;
}

.admin-row-action form {
  margin: 0;
}

/* The queue's assignee picker. Sized to the column and quiet until used, so a
   row of them does not read as a form. */
.assign-form {
  margin: 0;
}

.assign-select {
  width: 100%;
  min-width: 8rem;
  min-height: 30px;
  padding: 0.2rem 0.4rem;
  font-size: 0.8rem;
  border-color: var(--border);
  background: transparent;
}

.assign-select:hover {
  border-color: var(--border-strong);
  background: var(--surface);
}

/* Nobody assigned: reads as absence rather than as a chosen value. */
.assign-select.is-unassigned {
  color: #9aa2af;
  font-style: italic;
}

/* Who signed the contract off for Contracts, on the Desk grid. Taken from the
   handover note rather than from the assignment picker beside it — see
   `review.reviewed_by` — so the two columns can, and sometimes should, differ. */
.reviewer-cell {
  font-size: 0.82rem;
  white-space: nowrap;
}

/* No note names a reviewer, which is what a status moved by hand leaves behind.
   Reads as absence, the way an unassigned row does, rather than as a name. */
.reviewer-unrecorded {
  color: #9aa2af;
  font-style: italic;
}

/* A warning that belongs to the whole grid rather than to the toolbar row.
   `.db-notice` is inline-flex so it shrink-wraps; this gives it its own line. */
.desk-notice-row {
  margin: 0 0 0.75rem;
}

/* The three review-workflow statuses a person sets by hand. Coloured by what
   they ask of the reader: something to do, something to wait for, something
   cleared. Distinct from `complete`, which is the end of the line. */
/* A shade deeper than Under Review's amber on purpose: the two sat side by side
   in the queue and read as the same colour, and they mean opposite things —
   one is the app watching a draft being edited, the other is the Desk having
   sent a contract back with work to do. */
.status-badge.needs-review {
  color: #9a3412;
  background: #fed7aa;
  border-color: #fdba74;
}

.status-badge.pending-dd-approval {
  color: #6d28d9;
  background: #ede9fe;
  border-color: #ddd6fe;
}

.status-badge.approved-by-dd {
  color: #0f766e;
  background: #ccfbf1;
  border-color: #99f6e4;
}

/* Out to the counterparty: the last step before Complete, so the last of the
   workflow colours. */
.status-badge.sent-to-counterparty {
  color: #3730a3;
  background: #e0e7ff;
  border-color: #c7d2fe;
}


/* Builder bar: when this trade's changes were last remembered (verify.js). */
.builder-saved {
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
}

.builder-saved.is-error {
  color: #b91c1c;
}

/* Admin: a button with its explanation beside it (the Database card's test). */
.admin-inline-form {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.75rem;
}

/* Review: the fixed version on the page no longer matches Allegro's record. */
.review-notice {
  margin: 0.6rem 1.25rem 0;
  padding: 0.55rem 0.8rem;
  border: 1px solid #fde68a;
  border-radius: var(--radius);
  background: #fffbeb;
  color: #92400e;
  font-size: 0.82rem;
}

/* Review: Document / Audit trail tabs at the top of the document column. Sticky
   against the column's scroll and pulled out over its padding, so the strip
   runs edge to edge and the flip is within reach however far down a long
   contract the reader is. */
.doc-tabs {
  position: sticky;
  top: -1.75rem;
  z-index: 2;
  margin: -1.75rem -1.75rem 1.25rem;
  padding: 0 1.75rem;
}

.doc-tab-panel[hidden] {
  display: none;
}

/* The trail no longer sits below a document, so it needs no gap above it. */
#doc-tab-audit .audit-trail {
  margin-top: 0;
}

/* Admin: the queue feed form inside the Database card. */
.admin-subtitle {
  margin: 1.25rem 0 0.25rem;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--text);
}

.admin-feed-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.9rem 1.25rem;
  margin-top: 0.75rem;
}

.admin-feed-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
}

.admin-feed-field > span:first-child {
  font-size: 0.77rem;         /* a point under the card's 0.85rem */
  font-weight: 700;
  color: var(--text);          /* bold reads as bold only against the full ink */
}

.admin-feed-field small {
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.35;
}

.admin-feed-field input[type="date"],
.admin-feed-field input[type="number"],
.admin-feed-field select {
  width: auto;
  min-height: 34px;
  font: inherit;
  font-size: 0.77rem;
}

.admin-feed-check {
  grid-column: 1 / -1;
}

.admin-feed-inline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.admin-feed-days {
  width: 5rem;
}

/* The base input rule stretches a checkbox across the row; this one sits
   inline in a sentence. */
.admin-feed-inline input[type="checkbox"] {
  width: auto;
  min-height: 0;
  height: 1rem;
  flex: 0 0 auto;
  margin: 0;
}

/* Review: which trades a grouped contract's document actually covers. */
.review-reference {
  margin: 0 0 1rem;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-alt);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted-strong);
}
