/* UDM DocTrack shared visual system.
   Palette: Institutional Green #174A37 · Gold #D5B86A · Khaki #F1EDDF
   Type: DM Sans / Space Grotesk, with system fallbacks.
   Legacy navy/teal token names retain their roles in the green palette. */

/* The light palette. Declared on the root, and again on the three things that
   are paper whatever the screen is (the sign-in screen, the printed memo, the
   routing slip), so in the dark theme they get every light value from this one
   list rather than from a partial copy that falls behind it. */
:root,
:root[data-theme="dark"] :is(.login-wrap, .memo-print, .routing-slip) {
  --udm-navy: #174a37;
  --udm-navy-text: var(--udm-navy);
  --udm-navy-700: #103326;
  --udm-navy-600: #286b45;
  --udm-gold: #d5b86a;
  --udm-gold-soft: #f4ecd8;
  --udm-teal: #286b45;
  --udm-teal-soft: #e5f1e7;
  --udm-green: #4d824e;
  --udm-green-soft: #e5f1e7;
  --udm-red: #b44b4b;
  --udm-red-600: #8f3838;
  --udm-red-soft: #fbe7e5;
  --udm-canvas: #f1eddf;
  --udm-surface: #f8f5eb;
  --udm-line: #d6d5c4;
  --udm-line-strong: #afbda8;
  --udm-line-soft: #dce0d0;
  --udm-label-ink: #365146;
  --udm-ink: #183126;
  --udm-muted: #576b5c;
  --udm-slate-text: #4f6358;
  --udm-slate-soft: #e7ebdd;
  --udm-slate-ink: #53685b;
  --udm-green-ink: #1f5a42;
  --udm-gold-ink: #725616;
  --udm-gold-ink-dark: #59420f;
  --udm-gold-ink-hover: #4f3a05;
  --udm-gold-border: #b9923e;
  --udm-gold-tint: #f5efdc;
  --udm-gold-tint-strong: #f1dfad;
  --udm-teal-ink: #1f5a42;
  --udm-teal-ink-dark: #174a37;
  --udm-red-ink: #8f3838;
  --udm-navy-soft: #e1e9db;
  --udm-primary: #286b45;
  --udm-primary-hover: #1d5034;
  --udm-primary-ink: #ffffff;
  --udm-selected-bg: #286b45;
  --udm-selected-bg-hover: #1d5034;
  --udm-selected-ink: #ffffff;
  --udm-on-accent: #ffffff;
  --udm-on-gold: #241f1b;
  --udm-row-line: #e4e3d5;
  --udm-surface-sunk: #ece8da;
  --udm-track: #e2e7d8;
  --udm-highlight: #f7efd9;
  --udm-note-bg: #f3edda;
  --udm-note-ink: #5a4a20;
  --bs-link-color: var(--udm-teal);
  --bs-link-color-rgb: var(--udm-link-rgb);
  --bs-link-hover-color: var(--udm-teal-ink);
  --bs-link-hover-color-rgb: var(--udm-link-hover-rgb);
  --chart-one: #0a6e9a;
  --chart-two: #b58c24;
  --chart-three: #2f7d4f;
  --chart-alert: #b4342b;
  --chart-alert-soft: #cf6a5e;
  --chart-track: #e2e7d8;
  --chart-grid: #e4e3d5;
  --status-draft: #6b778b;
  --status-draft-soft: #ebf1f8;
  --status-draft-ink: #424e5e;
  --status-pending: #bc7700;
  --status-pending-soft: #fceeda;
  --status-pending-ink: #65470f;
  --status-received: #2d557d;
  --status-received-soft: #e5f2ff;
  --status-received-ink: #194f81;
  --status-process: #ab6da6;
  --status-process-soft: #fce9fa;
  --status-process-ink: #6b3767;
  --status-upload: #389695;
  --status-upload-soft: #daf7f8;
  --status-upload-ink: #1b575a;
  --status-completed: #1d6835;
  --status-completed-soft: #e3f6e6;
  --status-completed-ink: #195c2e;
  --status-overdue: #b4342b;
  --status-overdue-soft: #ffebe8;
  --status-overdue-ink: #7a342e;
  --chart-created: #174a37;
  --chart-historical: #7d889a;
  --chart-received-part: #8fb3d6;
  --chart-neutral: #55637a;
  --sidebar-width: 236px;
  --radius: 4px;
  --shadow-card: none;
  --udm-focus: #286b45;
  --udm-link-rgb: 40, 107, 69;
  --udm-link-hover-rgb: 31, 90, 66;
  color-scheme: light;
}

* {
  box-sizing: border-box;
}

/* Bootstrap surfaces and native controls share the screen palette. */
body {
  --bs-body-bg-rgb: 241, 237, 223;
  --bs-tertiary-color: var(--udm-muted);
  --bs-tertiary-bg: var(--udm-surface-sunk);
  --bs-secondary-bg: var(--udm-surface);
  --bs-dropdown-bg: var(--udm-surface);
  --bs-modal-bg: var(--udm-surface);
}
:root[data-theme="dark"] body { --bs-body-bg-rgb: 17, 27, 21; }
.card, .modal-content, .dropdown-menu, .list-group-item {
  background-color: var(--udm-surface);
  color: var(--udm-ink);
  border-color: var(--udm-line);
}
.dropdown-menu {
  --bs-dropdown-link-color: var(--udm-ink);
  --bs-dropdown-link-hover-color: var(--udm-navy-text);
  --bs-dropdown-link-hover-bg: var(--udm-surface-sunk);
  --bs-dropdown-link-active-color: var(--udm-selected-ink);
  --bs-dropdown-link-active-bg: var(--udm-selected-bg);
}

body {
  margin: 0;
  background: var(--udm-canvas);
  color: var(--udm-ink);
  font-family: "Aptos", "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system,
    "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, .display-face {
  font-family: "Aptos Display", "Aptos", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  color: var(--udm-navy-text);
  letter-spacing: -0.01em;
}

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

:focus-visible {
  outline: 3px solid var(--udm-gold);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---------------------------------------------------------------- wordmark */
.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-family: "Aptos Display", "Segoe UI", system-ui, sans-serif;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.wordmark .udm { color: var(--udm-gold); }
.wordmark .doctrack { color: var(--udm-navy-text); text-transform: none; }
.wordmark--light .doctrack { color: #ffffff; }

/* ------------------------------------------------------------------ shell */
.app-shell { display: flex; min-height: 100vh; }

.app-sidebar {
  width: var(--sidebar-width);
  flex: 0 0 var(--sidebar-width);
  background: var(--udm-navy);
  color: #cdd9e8;
  padding: 22px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.app-sidebar .brand { padding: 4px 10px 22px; display: block; }

.app-sidebar .nav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: 8px;
  color: #cdd9e8;
  font-size: 14.5px;
  margin-bottom: 2px;
}
.app-sidebar .nav-item:hover { background: rgba(255, 255, 255, 0.08); color: #fff; text-decoration: none; }
.app-sidebar .nav-item .dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.28);
  flex: 0 0 9px;
}
.app-sidebar .nav-item.active { background: rgba(255, 255, 255, 0.12); color: #fff; font-weight: 600; }
.app-sidebar .nav-item.active:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }
.app-sidebar .nav-item.active .dot { background: var(--udm-gold); }
.nav-section {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(205, 217, 232, 0.72); padding: 18px 12px 8px;
}

.app-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; overflow-x: clip; }

.app-topbar {
  background:var(--udm-surface);
  border-bottom: 1px solid var(--udm-line);
  padding: 12px 26px;
  display: flex;
  align-items: center;
  gap: 18px;
  position: sticky;
  top: 0;
  z-index: 20;
}
.app-topbar .topbar-search { flex: 1 1 auto; max-width: 460px; }
.app-topbar .topbar-search input {
  border-radius: 999px;
  border: 1px solid var(--udm-line);
  padding: 7px 16px;
  width: 100%;
  font-size: 14px;
  background: var(--udm-canvas);
}
.avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--udm-primary); color: var(--udm-primary-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; letter-spacing: 0.02em;
}

.app-content { padding: 26px; flex: 1 1 auto; }
.page-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.page-head h1 { font-size: 25px; margin: 0 0 4px; }
.page-head .sub { color: var(--udm-muted); font-size: 14px; margin: 0; }
.eyebrow {
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--udm-gold-ink); font-weight: 700; margin-bottom: 6px;
}

/* ------------------------------------------------------------------ cards */
.card-udm {
  background:var(--udm-surface);
  border: 1px solid var(--udm-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}
.card-udm .card-udm-head {
  padding: 16px 20px;
  border-bottom: 1px solid var(--udm-line);
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.card-udm .card-udm-head h2 { font-size: 16px; margin: 0; }
.card-udm .card-udm-body { padding: 18px 20px; }

.stat-card {
  background:var(--udm-surface);
  border: 1px solid var(--udm-line);
  border-left: 4px solid var(--udm-teal);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-card);
  display: block;
  height: 100%;
}
.stat-card:hover { text-decoration: none; border-color: var(--udm-teal); }
/* Inert, like .pill-toggle.is-disabled: there is no count to show, and the
   hint says what would give it one. */
.stat-card.is-disabled { border-style:dashed; border-left-style:solid; box-shadow:none; opacity:.75; }
.stat-card.is-disabled:hover { border-color:var(--udm-line); }
.stat-card .label { color: var(--udm-muted); font-size: 13px; }
.stat-card .value {
  font-family: "Aptos Display", "Segoe UI", system-ui, sans-serif;
  font-size: 34px; font-weight: 700; color: var(--udm-navy-text); line-height: 1.1;
}
.stat-card .hint { font-size: 12.5px; color: var(--udm-muted); }
.stat-card.gold { border-left-color: var(--udm-gold); }
.stat-card.green { border-left-color: var(--udm-green); }
.stat-card.red { border-left-color: var(--udm-red); }
.stat-card.navy { border-left-color: var(--udm-navy); }

/* ----------------------------------------------------------------- pills */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 11px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap;
}
/* Status pills: one per status, from the --status-* tokens, so a pill and the
   chart slice for the same status are the same colour. Received and Completed
   were both green here, and In process and Completed - pending upload both
   teal: six statuses in four colours. */
.pill-received  { background: var(--status-received-soft);  color: var(--status-received-ink); }
.pill-completed { background: var(--status-completed-soft); color: var(--status-completed-ink); }
.pill-pending   { background: var(--status-pending-soft);   color: var(--status-pending-ink); }
.pill-upload    { background: var(--status-upload-soft);    color: var(--status-upload-ink); }
/* Not a status: a plain "this is fine" badge (an active account, text
   extracted), so those stop borrowing a status's colour. */
.pill-ok        { background: var(--udm-green-soft); color: var(--udm-green-ink); }
/* Approaching, not yet late. Gold rather than red, because red is the claim
   that something has already gone wrong and this one is still actionable — and
   the dark ink, not the plain: gold-ink on gold-soft is 4.34:1 and a pill runs
   at 11.5px, where AA wants 4.5. The dark variant clears 7:1 in both themes.
   Outlined as well as filled, so it reads as a different kind of thing from the
   solid red Overdue tag it will eventually become. */
.pill-warn {
  background: var(--udm-gold-soft); color: var(--udm-gold-ink-dark);
  box-shadow: inset 0 0 0 1px var(--udm-gold-border);
}
/* The date under the pills. Muted and small: it is the evidence for the tag
   above it, not a column in its own right. */
.deadline-when-cell { margin-top:4px; color:var(--udm-muted); font-size:12px; white-space:nowrap; }
.pill-process   { background: var(--status-process-soft);   color: var(--status-process-ink); }
.pill-overdue   { background: var(--status-overdue-soft);   color: var(--status-overdue-ink); }
/* Overdue is not a stage — it is a condition sitting on top of one, and it is
   rendered *beside* the status pill rather than instead of it. Soft-fill like
   its neighbour, it read as a second status and disappeared into the row; a
   filled red is the one thing on the line that is not a stage, which is exactly
   what it is. 6.06:1 in light, 3.27:1 in dark.

   Its own class rather than loudening .pill-overdue, which also carries
   "Suspended" on the users screen and "Urgent" on a record — neither of which
   was asked to change. */
.pill-alert {
  background: var(--udm-red); color: var(--udm-on-accent);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}
/* On paper it is ink on white, not white on a fill.
   Only the reports and memo sheets ask for `print-color-adjust:exact`; the
   routing slip — the page that physically travels with the document — does
   not, so its pills print with no background. A soft-filled pill survives that
   because its text is dark. This one's text is white, so the Overdue marker
   would have vanished from the one printout that follows the record around.
   Red ink and a red border read as loudly on paper and depend on nothing the
   print dialog can switch off. */
@media print {
  .pill-alert {
    background: transparent !important; color: var(--udm-red-ink) !important;
    box-shadow: inset 0 0 0 1.5px var(--udm-red) !important;
  }
}
/* Direction, not status — which way the document is moving relative to the
   office reading the page. Deliberately outside the status hues: gold, teal,
   green and red all mean a stage, and a direction wearing one of them would
   read as a stage the document is at.

   Filled for what is here to act on, outline for what has left — the same
   contrast the draft pill below draws between "in the workflow" and "not yet". */
/* A stage and a deadline condition are two answers, so a cell can hold two
   pills. Wrapping rather than overflowing: the Status column is already narrow
   and the routing slip is print CSS with no room to grow. */
.pill-stack { display:flex; flex-wrap:wrap; gap:4px; }
/* Why a column is empty, beside the control that fills it. */
.tracking-filter-note { margin:6px 0 0; color:var(--udm-muted); font-size:12.5px; }
/* The same note doing the opposite job: a caption for the row *below* it rather
   than an aside about the row above, so it carries no top margin of its own and
   lets the .tracking-filters gap do the spacing on both sides. */
.tracking-filter-note--lead { margin:0; }
.pill-incoming  { background: var(--udm-slate-soft); color: var(--udm-navy-text); }
.pill-outgoing  { background: transparent; color: var(--udm-slate-ink); box-shadow: inset 0 0 0 1px var(--udm-line); }
/* Draft is the one status that is not in the workflow yet: nobody has been
   sent it, nobody owes anything on it, and it is visible only to the office
   writing it. So it is drawn as an outline rather than a fill — the difference
   between "a stage this document is at" and "a document that has not started".
   It also stops Draft reading as another solid chip alongside Pending receipt,
   which is the one it was being confused with. */
.pill-draft     { background: transparent; color: var(--status-draft-ink); box-shadow: inset 0 0 0 1px var(--udm-line); }
.pill-muted     { background: var(--udm-slate-soft); color: var(--udm-slate-ink); }

/* ----------------------------------------------------------------- tables */
.table-udm { width: 100%; border-collapse: collapse; }
.table-udm th {
  text-align: left; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--udm-muted); font-weight: 700;
  padding: 10px 14px; border-bottom: 1px solid var(--udm-line); white-space: nowrap;
}
.table-udm td { padding: 13px 14px; border-bottom: 1px solid var(--udm-row-line); vertical-align: middle; }
.table-udm tbody tr:hover { background: var(--udm-surface-sunk); }
.table-udm .mono {
  font-family: "Cascadia Mono", "Consolas", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; color: var(--udm-navy-text); font-weight: 600; white-space: nowrap;
}
/* Office codes in the records-staff columns: short, scannable, and never the
   thing that forces a row to wrap. */
.table-udm .office-cell {
  font-size: 12.5px; font-weight: 600; color: var(--udm-navy-text);
  white-space: nowrap; letter-spacing: 0.02em;
}

/* --------------------------------------------------------------- timeline */
.timeline { list-style: none; margin: 0; padding: 0 0 0 26px; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px;
  width: 2px; background: var(--udm-line);
}
.timeline li { position: relative; padding: 0 0 20px 4px; }
.timeline li::before {
  content: ""; position: absolute; left: -25px; top: 4px;
  width: 14px; height: 14px; border-radius: 50%;
  background:var(--udm-surface); border: 3px solid var(--udm-teal);
}
.timeline li.is-pending::before { border-color: var(--udm-gold); }
/* Office time at a hop, under its receipt line. The basis sentence sits once
   under the card head rather than on every hop. */
.t-wait { color:var(--udm-muted); }
.t-wait span[title],.t-awaiting span[title] { text-decoration:underline dotted; text-underline-offset:3px; cursor:help; }
.timeline-basis { margin:0; padding:10px 20px 0; color:var(--udm-muted); font-size:12px; }
.timeline li.is-done::before { border-color: var(--udm-green); }
.timeline li.is-muted::before { border-color: var(--udm-line); }
.timeline .t-title { font-weight: 600; color: var(--udm-navy-text); }
.timeline .t-meta { color: var(--udm-muted); font-size: 13px; }
.timeline .t-detail {
  margin-top: 6px; background: var(--udm-canvas); border: 1px solid var(--udm-line);
  border-radius: 8px; padding: 9px 12px; font-size: 14px; white-space: pre-wrap;
}

/* --------------------------------------------------------------- relevance */
.relevance {
  display: inline-flex; flex-direction: column; align-items: flex-end; gap: 4px; min-width: 82px;
}
.relevance .score {
  font-family: "Aptos Display", "Segoe UI", system-ui, sans-serif;
  font-weight: 700; font-size: 19px; color: var(--udm-navy-text);
}
.relevance-bar { width: 78px; height: 5px; border-radius: 999px; background: var(--udm-track); overflow: hidden; }
.relevance-bar span { display: block; height: 100%; background: var(--udm-teal); border-radius: 999px; }
.relevance-bar.high span { background: var(--udm-green); }
.relevance-bar.low span { background: var(--udm-gold); }

.result-item { padding: 16px 20px; border-bottom: 1px solid var(--udm-row-line); display: flex; gap: 18px; }
.result-item:last-child { border-bottom: 0; }
.result-item h3 { font-size: 16px; margin: 0 0 3px; }
.result-item .meta { color: var(--udm-muted); font-size: 13px; }
.result-item mark { background: var(--udm-highlight); color: inherit; padding: 0 2px; border-radius: 3px; }

/* ------------------------------------------------------------------ misc */
.tag-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--udm-teal-soft); color: var(--udm-teal-ink);
  border-radius: 999px; padding: 3px 10px; font-size: 12.5px; margin: 0 4px 4px 0;
}
.tag-chip .remove { cursor: pointer; opacity: 0.6; }
.tag-chip.suggested { background: var(--udm-gold-soft); color: var(--udm-gold-ink); }

.confidence {
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--udm-muted); font-weight: 700;
}

.file-chip {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--udm-line); border-radius: 8px; padding: 9px 12px; background:var(--udm-surface);
}
.file-chip .ext {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
  background: var(--udm-primary); color: var(--udm-primary-ink); border-radius: 5px; padding: 3px 6px;
}

.smart-folder {
  display: flex; justify-content: space-between; align-items: center;
  padding: 9px 12px; border-radius: 8px; color: var(--udm-ink); font-size: 14px;
}
.smart-folder:hover { background: var(--udm-canvas); text-decoration: none; }
.smart-folder.active { background: var(--udm-teal-soft); color: var(--udm-teal-ink); font-weight: 600; }
.smart-folder.active:hover { background: var(--udm-teal-soft); color: var(--udm-teal-ink); }
.smart-folder .count { color: var(--udm-muted); font-size: 12.5px; }

.doc-tile {
  background:var(--udm-surface); border: 1px solid var(--udm-line); border-radius: var(--radius);
  padding: 16px; height: 100%; display: flex; flex-direction: column; gap: 8px;
  box-shadow: var(--shadow-card);
}
.doc-tile:hover { border-color: var(--udm-teal); }
.doc-tile h3 { font-size: 15px; margin: 0; overflow-wrap: anywhere; }
.doc-tile .mono { white-space: normal; overflow-wrap: anywhere; }
.doc-tile .meta { color: var(--udm-muted); font-size: 12.5px; }

.empty-state { text-align: center; padding: 46px 20px; color: var(--udm-muted); }
.empty-state h3 { color: var(--udm-navy-text); margin-bottom: 6px; }

.step-indicator { display: flex; gap: 10px; align-items: center; color: var(--udm-muted); font-size: 13px; }
.step-indicator .step { display: inline-flex; align-items: center; gap: 7px; }
.step-indicator .num {
  width: 22px; height: 22px; border-radius: 50%; background: var(--udm-track); color: var(--udm-slate-ink);
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700;
}
.step-indicator .step.active .num { background: var(--udm-selected-bg); color: var(--udm-selected-ink); }
.step-indicator .step.active { color: var(--udm-navy-text); font-weight: 600; }

.text-preview {
  background:var(--udm-surface); border: 1px solid var(--udm-line); border-radius: 8px;
  padding: 16px; max-height: 430px; overflow: auto;
  font-size: 13.5px; white-space: pre-wrap; color: var(--udm-slate-text);
}

.btn-udm {
  background: var(--udm-primary); border: 1px solid var(--udm-primary); color: var(--udm-primary-ink);
  border-radius: 8px; padding: 8px 16px; font-weight: 600; font-size: 14px;
}
.btn-udm:hover { background: var(--udm-primary-hover); border-color: var(--udm-primary-hover); color: var(--udm-primary-ink); }
.btn-udm-gold { background: var(--udm-gold); border-color: var(--udm-gold); color: var(--udm-on-gold); }
.btn-udm-gold:hover { background: var(--udm-gold); border-color: var(--udm-gold); filter: brightness(0.95); color: var(--udm-on-gold); }
.btn-udm-outline { background:var(--udm-surface); border: 1px solid var(--udm-line); color: var(--udm-navy-text); border-radius: 8px; padding: 8px 16px; font-weight: 600; font-size: 14px; }
.btn-udm-outline:hover { background:var(--udm-surface); border-color: var(--udm-primary); color: var(--udm-navy-text); }
.btn-udm-teal { background: var(--udm-teal); border-color: var(--udm-teal); color: var(--udm-on-accent); }
.btn-udm-teal:hover { background: var(--udm-teal); border-color: var(--udm-teal); filter: brightness(0.94); color: var(--udm-on-accent); }
.btn-udm-green { background: var(--udm-green); border-color: var(--udm-green); color: var(--udm-on-accent); }
.btn-udm-green:hover { background: var(--udm-green); border-color: var(--udm-green); filter: brightness(0.94); color: var(--udm-on-accent); }

.form-label { font-size: 13px; font-weight: 600; color: var(--udm-label-ink); margin-bottom: 4px; }
.form-control, .form-select { border-radius: 8px; border-color: var(--udm-line); font-size: 14.5px; padding: 8px 12px; }
.form-control:focus, .form-select:focus { border-color: var(--udm-teal); box-shadow: 0 0 0 3px color-mix(in srgb, var(--udm-teal) 12%, transparent); }
.form-text { font-size: 12.5px; color: var(--udm-muted); }
.required-mark { color: var(--udm-red); }

/* What the three office columns mean, above the table they explain: one line
   each, the term in bold, wrapping to two columns where there is room. */
.office-terms { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr)); gap:4px 22px; margin:0 0 12px; color:var(--udm-muted); font-size:12.5px; }
.office-terms dt { display:inline; margin-right:4px; color:var(--udm-navy-text); font-weight:700; }
.office-terms dd { display:inline; margin:0; }
.help-note {
  border-left: 3px solid var(--udm-gold); background: var(--udm-note-bg);
  padding: 10px 14px; border-radius: 0 8px 8px 0; font-size: 13.5px; color: var(--udm-note-ink);
}

/* --------------------------------------------------------------- deadline */
/* "Is there a deadline?" first, the calendar only if the answer is yes.
   The date panel is visible by default so the field still works without JS;
   doctrack.js hides it when "No deadline" is selected. */
/* Date and time on one line, the time narrower — it is optional and secondary,
   and giving it equal width would suggest it has to be answered. Stacks on a
   phone, where two controls side by side leave neither usable. */
.deadline-when { display:flex; flex-wrap:wrap; gap:12px; }
.deadline-when > div:first-child { flex:1 1 200px; min-width:0; }
.deadline-when > div:last-child { flex:0 1 130px; min-width:0; }
.deadline-field { min-width: 0; border: 1px solid var(--udm-line); border-radius: var(--radius); padding: 14px 16px; }
.deadline-field > legend {
  float: none; width: auto; padding: 0; margin-bottom: 8px; font-size: 13px; font-weight: 600; color: var(--udm-label-ink);
}
.deadline-options { display: flex; flex-wrap: wrap; gap: 8px; }
.deadline-option {
  display: inline-flex; align-items: center; gap: 9px; flex: 1 1 220px;
  border: 1px solid var(--udm-line); border-radius: 8px; padding: 9px 13px;
  background:var(--udm-surface); font-size: 14px; cursor: pointer;
}
.deadline-option:hover { border-color: var(--udm-teal); }
.deadline-option input { margin: 0; flex: 0 0 auto; }
.deadline-option:has(input:checked) { border-color: var(--udm-teal); background: var(--udm-teal-soft); }
.deadline-date { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--udm-line); max-width: 320px; }
.deadline-date[hidden] { display: none; }
.deadline-clear-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.deadline-clear-actions[hidden] { display:none; }

/* ------------------------------------------------- tracking slip: create/review */
.phase2-card-caption { margin-top: 2px; color: var(--udm-muted); font-size: 12.5px; }
.phase2-required-note { color: var(--udm-muted); font-size: 12px; white-space: nowrap; }
.phase2-form-section { padding-bottom: 20px; margin-bottom: 20px; border-bottom: 1px solid var(--udm-line); }
.phase2-form-section--last { padding-bottom: 0; margin-bottom: 0; border-bottom: 0; }
.phase2-section-title {
  font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--udm-muted); font-weight: 700; margin: 0 0 14px;
}
.phase2-upload-box {
  border: 1px dashed var(--udm-line-soft); border-radius: var(--radius);
  background: var(--udm-surface-sunk); padding: 16px;
}
.phase2-sticky-card { position: sticky; top: 84px; }
.phase2-checklist { margin: 0; padding-left: 20px; font-size: 13.5px; color: var(--udm-muted); }
.phase2-checklist li { margin-bottom: 10px; }
.phase2-checklist li:last-child { margin-bottom: 0; }
.phase2-checklist strong { color: var(--udm-navy-text); }
.phase2-review-table th {
  width: 190px; color: var(--udm-muted); font-size: 13px; font-weight: 600; vertical-align: top;
}
.phase2-review-table td { font-size: 14px; }
.phase2-preview-badge {
  display: inline-block; background: var(--udm-gold-soft); color: var(--udm-gold-ink);
  border-radius: 999px; padding: 1px 9px; font-size: 11px; font-weight: 700;
}
.phase2-inline-editor {
  border: 1px solid var(--udm-line); border-radius: var(--radius);
  padding: 16px; margin-bottom: 14px; background: var(--udm-canvas);
}
@media (max-width: 991.98px) { .phase2-sticky-card { position: static; } }

/* ------------------------------------------------------------------ login */
.login-wrap { display: grid; grid-template-columns: 1.05fr 1fr; min-height: 100vh; }
.login-art {
  background: linear-gradient(155deg, #0b315a 0%, #123f70 55%, #16697a 100%);
  color: #fff; padding: 54px 56px; display: flex; flex-direction: column; justify-content: space-between;
  position: relative; overflow: hidden;
}
.login-art h1 { color: #fff; font-size: 42px; line-height: 1.12; margin: 0 0 18px; max-width: 12ch; }
.login-art p { color: rgba(255, 255, 255, 0.82); max-width: 42ch; font-size: 15.5px; }
.login-art .rule { width: 96px; height: 4px; background: var(--udm-gold); border-radius: 2px; margin: 26px 0; }
.login-art .grid-lines {
  position: absolute; inset: 0; opacity: 0.16; pointer-events: none;
  background-image: linear-gradient(rgba(255,255,255,.5) 1px, transparent 1px),
                    linear-gradient(90deg, rgba(255,255,255,.5) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(circle at 78% 22%, #000 0%, transparent 62%);
}
.login-form { display: flex; align-items: center; justify-content: center; padding: 40px; background:var(--udm-surface); }
.login-form .inner { width: 100%; max-width: 372px; }

.lockout-timer {
  margin: 6px 0 20px; padding: 18px 20px; border-radius: 10px;
  background: var(--udm-canvas); border: 1px solid var(--udm-line); text-align: center;
}
.lockout-timer__clock {
  font-size: 34px; font-weight: 700; letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums; color: var(--udm-navy);
}

@media (max-width: 900px) {
  .login-wrap { grid-template-columns: 1fr; }
  .login-art { padding: 34px 26px; }
  .login-art h1 { font-size: 32px; }
  .app-sidebar {
    position: static; height: auto; width: 100%; flex: 1 1 100%;
    display: flex; gap: 6px; overflow-x: auto; padding: 10px;
  }
  .app-shell { flex-direction: column; }
  .nav-section { display: none; }
  .app-sidebar .nav-item { white-space: nowrap; }
  .app-content { padding: 16px; }
}

@media print {
  .app-sidebar, .app-topbar, .no-print { display: none !important; }
  /* A dialog is a control surface, not content. Printing one lays it over the
     page behind it and prints both; no page wants that, so the rule is shared
     rather than repeated per page. */
  .modal, .modal-backdrop { display: none !important; }
  body { background:var(--udm-surface); }
  .app-content { padding: 0; }
  .card-udm { box-shadow: none; border: 1px solid #cfd6e0; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ================================================================
   PHASE 1: clean consolidated additions
   ================================================================ */
.app-topbar { min-height:64px; padding:10px 26px; }
.app-topbar .topbar-brand { display:inline-flex !important; align-items:center; flex:0 0 auto; gap:10px; min-width:max-content; color:var(--udm-ink); text-decoration:none; }
.app-topbar .topbar-brand:hover,.app-topbar .topbar-brand:focus { color:var(--udm-ink); text-decoration:none; }
.app-topbar .topbar-brand-icon { display:block !important; width:36px !important; height:36px !important; min-width:36px !important; max-width:36px !important; min-height:36px !important; max-height:36px !important; flex:0 0 36px !important; border-radius:9px; object-fit:contain; }
.app-topbar .wordmark { display:inline-flex; align-items:baseline; flex-wrap:nowrap; gap:6px; font-size:13px; white-space:nowrap; }
.app-topbar .topbar-search { flex:1 1 auto; min-width:180px; max-width:460px; }
.app-topbar .topbar-search input:focus { border-color:var(--udm-teal); background:var(--udm-surface); outline:none; box-shadow:0 0 0 3px color-mix(in srgb, var(--udm-teal) 12%, transparent); }
.app-topbar .topbar-account-button { display:inline-flex; align-items:center; gap:9px; width:auto; min-width:0; max-width:280px; padding:4px 6px; border:0 !important; border-radius:8px; background:transparent !important; color:var(--udm-ink); text-align:left; box-shadow:none !important; }
.app-topbar .topbar-account-button:hover,.app-topbar .topbar-account-button:focus { background:var(--udm-canvas) !important; color:var(--udm-ink); }
.app-topbar .topbar-account-copy { flex-direction:column; align-items:flex-start; width:auto; min-width:0; max-width:190px; }
.app-topbar .topbar-account-name,.app-topbar .topbar-account-office { display:block; width:100%; overflow:hidden; line-height:1.25; text-align:left; text-overflow:ellipsis; white-space:nowrap; }
.app-topbar .topbar-account-name { color:var(--udm-ink); font-size:13.5px; font-weight:600; }
.app-topbar .topbar-account-office { color:var(--udm-muted); font-size:11.5px; }
.app-topbar .topbar-account-arrow { flex:0 0 auto; color:var(--udm-muted); font-size:12px; }
	.topbar-notifications { position:relative; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border-radius:8px; color:var(--udm-navy-text); text-decoration:none; }
	.topbar-notifications:hover { background:var(--udm-canvas); color:var(--udm-teal-ink); }
	.topbar-notifications:focus-visible { outline:3px solid color-mix(in srgb, var(--udm-teal) 35%, transparent); outline-offset:2px; }
	.notification-bell { width:21px; height:21px; }
	.notification-count { position:absolute; top:-4px; right:-6px; display:inline-flex; align-items:center; justify-content:center; min-width:18px; height:18px; padding:0 5px; border:2px solid var(--udm-surface); border-radius:999px; background:var(--udm-red); color:var(--udm-on-accent); font-size:10px; font-weight:700; line-height:1; }
	.notification-page-head { align-items:flex-start; }
	.notification-toolbar { border-radius:var(--radius); }
	.notification-filters { display:flex; flex-wrap:wrap; gap:6px; }
	.notification-filter { display:inline-flex; align-items:center; min-height:34px; padding:6px 13px; border:1px solid var(--udm-line); border-radius:999px; color:var(--udm-navy-text); font-size:13px; font-weight:600; text-decoration:none; }
	.notification-filter:hover,.notification-filter:focus-visible { border-color:var(--udm-teal); background:var(--udm-teal-soft); color:var(--udm-teal-ink); }
	.notification-filter:focus-visible { outline:3px solid color-mix(in srgb, var(--udm-teal) 20%, transparent); outline-offset:2px; }
	.notification-filter.is-active { border-color:var(--udm-selected-bg); background:var(--udm-selected-bg); color:var(--udm-selected-ink); }
	.notification-filter.is-active:hover,.notification-filter.is-active:focus-visible {
	  border-color:var(--udm-selected-bg-hover); background:var(--udm-selected-bg-hover); color:var(--udm-selected-ink);
	}
	.notification-list { display:flex; flex-direction:column; gap:8px; }
	.notification-day-heading { margin:19px 0 3px; color:var(--udm-muted); font-size:12px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }
	.notification-row { display:grid; grid-template-columns:38px minmax(0,1fr) auto; align-items:start; gap:12px; padding:15px 16px; border:1px solid var(--udm-line); border-left:4px solid var(--udm-line); border-radius:var(--radius); background:var(--udm-surface); box-shadow:var(--shadow-card); }
	.notification-row.is-actionable { border-left-color:var(--udm-red); }
	.notification-row.is-received { border-left-color:var(--udm-teal); }
	.notification-row.is-completed { border-left-color:var(--udm-navy); }
	.notification-row.is-shared { border-left-color:#96743a; }
	.notification-row.is-read { background:var(--udm-canvas); box-shadow:none; }
	.notification-kind-icon { display:flex; align-items:center; justify-content:center; width:30px; height:30px; border-radius:50%; background:var(--udm-navy-soft); color:var(--udm-navy-text); font-size:15px; font-weight:700; }
	.notification-row.is-actionable .notification-kind-icon { background:var(--udm-red-soft); color:var(--udm-red); }
	.notification-row.is-received .notification-kind-icon { background:var(--udm-teal-soft); color:var(--udm-teal-ink); }
	.notification-row-heading { display:flex; align-items:center; justify-content:space-between; gap:12px; color:var(--udm-muted); font-size:11px; }
	.notification-kind-label { font-weight:700; letter-spacing:.05em; text-transform:uppercase; }
	.notification-row-title { margin:3px 0 2px; color:var(--udm-ink); font-size:15px; }
	.notification-row-message { margin:0; color:var(--udm-muted); font-size:13px; }
	.notification-row-action { align-self:center; }
	.notification-empty { margin-top:12px; }
	@media (max-width:575.98px) { .notification-row { grid-template-columns:32px minmax(0,1fr); } .notification-row-action { grid-column:2; justify-self:start; } .notification-row-heading { align-items:flex-start; flex-direction:column; gap:2px; } .notification-page-head { gap:12px; } }
	.account-dropdown { min-width:235px; border:1px solid var(--udm-line); border-radius:10px; box-shadow:var(--shadow-card); }

.account-dropdown-header { padding-top:10px; padding-bottom:10px; }
.account-dropdown-name { color:var(--udm-ink); font-weight:600; }
.account-signout { color:var(--udm-red); }
.account-signout:hover,.account-signout:focus { background:var(--udm-red-soft); color:var(--udm-red); }
.sidebar-brand-content { display:flex; align-items:center; gap:10px; }
.sidebar-brand-icon { display:block; width:44px; height:44px; min-width:44px; max-width:44px; min-height:44px; max-height:44px; flex:0 0 44px; border-radius:50%; object-fit:contain; }
.app-sidebar .wordmark { display:inline-flex; align-items:baseline; flex-wrap:nowrap; gap:6px; font-size:14px; white-space:nowrap; }
.sidebar-office { padding:0 12px; color:#cdd9e8; font-size:13px; }
.sidebar-office-name { color:#fff; font-weight:600; }
.sidebar-office-role { margin-top:2px; color:rgba(205,217,232,.72); font-size:12.5px; }
/* Which queue you are looking at. Both navs previously gave no indication at
   all, so every queue looked identical once the page had loaded. */
/* ------------------------------------------------------------ pill toggles
   One pill design for the whole page. The queue nav and the filter rows below
   it are the same control doing the same job — narrow the list by clicking a
   thing — so they are the same class rather than two rulesets that drift.
   `.tracking-queue-*` was that ruleset; it is now just the row that holds them. */
.pill-toggle {
  display:inline-flex; align-items:center; justify-content:center;
  min-height:36px; padding:7px 14px;
  border:1px solid var(--udm-line); border-radius:999px;
  background:var(--udm-surface); color:var(--udm-navy-text);
  font-size:13px; font-weight:600; line-height:1;
  white-space:nowrap; text-decoration:none;
}
.pill-toggle:hover,.pill-toggle:focus { border-color:var(--udm-teal); background:var(--udm-teal-soft); color:var(--udm-teal-ink); text-decoration:none; }
.pill-toggle.is-active { border-color:var(--udm-selected-bg); background:var(--udm-selected-bg); color:var(--udm-selected-ink); }
/* Selected *and* hovered, said out loud rather than left to the cascade.
   Written down, the pair cannot come apart: whatever later rule sets the
   background here also sets the text, so there is no arrangement of these rules
   that paints navy on navy. It also gives the state some feedback — without it
   a selected pill was the one control on the page that did not respond to the
   pointer at all. The same hover every selected control uses
   (--udm-selected-bg-hover), so the whole app answers a hover the same way. */
.pill-toggle.is-active:hover,.pill-toggle.is-active:focus {
  border-color:var(--udm-selected-bg-hover); background:var(--udm-selected-bg-hover); color:var(--udm-selected-ink);
}
/* A queue that cannot be asked from where the reader is standing. Dimmed and
   inert rather than removed: a row that loses two pills when the office picker
   changes reads as the page breaking, and the pill's title says why it is off.
   Not a <button disabled>, because it never was a button — it is a link that
   has nowhere to go, so it becomes a <span>. */
.pill-toggle.is-disabled {
  border-style:dashed; background:var(--udm-surface); color:var(--udm-muted);
  cursor:not-allowed; opacity:.7;
}
.pill-toggle--alert { color:var(--udm-red-ink); }
.pill-toggle--alert:hover,.pill-toggle--alert:focus { border-color:var(--udm-red); background:var(--udm-red-soft); color:var(--udm-red-ink); }
.pill-toggle--alert.is-active { border-color:var(--udm-red); background:var(--udm-red); color:var(--udm-on-accent); }
.pill-toggle--alert.is-active:hover,.pill-toggle--alert.is-active:focus {
  border-color:var(--udm-red-600); background:var(--udm-red-600); color:var(--udm-on-accent);
}

/* A row of pills: scrolls sideways rather than stacking into a tall column,
   which is what a wrapped checkbox list did on a phone. */
/* position:relative for the reason .table-responsive has it: the pills carry
   .visually-hidden labels, which are absolute and escaped an unpositioned
   scroller, so the Tracking page scrolled sideways on a phone. */
.pill-row { position:relative; overflow-x:auto; padding-bottom:3px; scrollbar-width:thin; }
.pill-row-list { display:flex; align-items:center; gap:8px; min-width:max-content; }

.tracking-queue-nav { position:relative; overflow-x:auto; padding-bottom:3px; scrollbar-width:thin; }
.tracking-queue-list { display:flex; align-items:center; gap:8px; min-width:max-content; }

/* ------------------------------------------------- tracking filter rows */
/* No card, no border, no Apply button — the filters read as the same surface
   as the queue pills above them, because they are the same control. */
.tracking-filters { display:flex; flex-direction:column; gap:10px; margin-bottom:16px; }
.tracking-filter-row { display:flex; align-items:center; gap:10px; min-width:0; }
.tracking-filter-label { flex:0 0 auto; font-size:12px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:var(--udm-muted); }
@media (max-width:767.98px) {
  /* The label sits above its pills once the row runs out of width, rather than
     squeezing the scrolling strip into what is left beside it. */
  .tracking-filter-row { flex-direction:column; align-items:stretch; gap:5px; }
}
@media print { .tracking-queue-nav,.tracking-filters { display:none !important; } }

/* ================================================================
   PHASE 3: routing slip and print presentation
   ================================================================ */
.routing-slip-actions { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:14px; }
.routing-slip { width:100%; max-width:1120px; margin:0 auto; padding:24px; border:1px solid var(--udm-line); border-radius:var(--radius); background:var(--udm-surface); box-shadow:var(--shadow-card); color:var(--udm-ink); }
.routing-slip-header { display:flex; align-items:flex-start; justify-content:space-between; gap:24px; padding-bottom:18px; border-bottom:2px solid var(--udm-navy); }
.routing-slip-heading { min-width:0; }
.routing-slip-school { color:var(--udm-muted); font-size:11px; font-weight:700; letter-spacing:.15em; text-transform:uppercase; }
.routing-slip-heading h1 { margin:3px 0 2px; font-size:25px; }
.routing-slip-office { color:var(--udm-muted); font-size:13px; }
.routing-slip-identity { display:flex; flex:0 0 auto; align-items:flex-start; gap:12px; }
.routing-slip-qr { width:112px; min-height:112px; padding:8px; border:1px solid var(--udm-ink); background:var(--udm-surface); text-align:center; }
.routing-slip-qr small { display:block; margin-top:5px; color:var(--udm-muted); font-size:9px; text-transform:uppercase; }
/* The status pill sits in the narrow QR column of the letterhead. `.pill` is
   nowrap by default, so a long status ("PENDING RECEIPT", "IN PROCESS",
   "COMPLETED - PENDING UPLOAD") ran past the column and was clipped at the paper's edge —
   printed slips came out with the status cut off mid-word. Let it wrap and shrink to the
   column instead of overflowing it. */
.routing-slip-header-status .pill {
  display:inline-flex; max-width:100%; white-space:normal; overflow-wrap:anywhere; text-align:center;
}
/* Holds the generated QR svg. No border or padding: the code carries its own
   quiet zone (QR_BORDER), and framing it again would eat scannable area. */
.routing-slip-qr-pattern { width:78px; height:78px; margin:0 auto; background:var(--udm-surface); }
.routing-slip-qr-pattern svg { display:block; width:100%; height:100%; }
.routing-slip-control { min-width:160px; padding:8px 10px; border-bottom:1px solid var(--udm-ink); }
.routing-slip-control span { display:block; color:var(--udm-muted); font-size:10px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }
.routing-slip-control strong { display:block; margin-top:8px; font-family:"Cascadia Mono","Consolas",monospace; font-size:13px; letter-spacing:.04em; }
.routing-slip-number-block { position:relative; margin:18px 0; padding:14px 18px; border:2px solid var(--udm-navy); border-radius:8px; background:#f8fbfe; text-align:center; }
.routing-slip-number-label { color:var(--udm-muted); font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; }
.routing-slip-number { margin-top:2px; color:var(--udm-navy); font-size:24px; font-weight:800; letter-spacing:.035em; overflow-wrap:anywhere; }
.routing-slip-status { position:absolute; top:50%; right:16px; transform:translateY(-50%); }
.routing-slip-summary { border:1px solid var(--udm-line); border-radius:8px; overflow:hidden; }
.routing-slip-summary-row { display:grid; grid-template-columns:190px minmax(0,1fr); border-bottom:1px solid var(--udm-line); }
.routing-slip-summary-row:last-child { border-bottom:0; }
.routing-slip-summary-label { padding:10px 13px; background:var(--udm-canvas); color:var(--udm-label-ink); font-size:12px; font-weight:700; }
.routing-slip-summary-value { padding:10px 13px; }
.routing-slip-summary-row--subject .routing-slip-summary-value { color:var(--udm-navy); font-size:16px; font-weight:700; }
.routing-slip-notes { white-space:normal; }
.routing-slip-privacy { margin:16px 0; padding:10px 13px; border-left:3px solid var(--udm-gold); background:var(--udm-note-bg); color:var(--udm-note-ink); font-size:11px; line-height:1.45; }
.routing-slip-section-head { display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin:20px 0 8px; }
.routing-slip-section-head h2 { margin:0; font-size:16px; }
.routing-slip-section-head span { color:var(--udm-muted); font-size:11px; }
.routing-slip-table { width:100%; border-collapse:collapse; table-layout:fixed; }
.routing-slip-table th,.routing-slip-table td { padding:9px 8px; border:1px solid #aeb8c5; vertical-align:top; }
.routing-slip-table th { background:#eef3f8; color:var(--udm-navy); font-size:10px; font-weight:800; letter-spacing:.06em; text-align:center; text-transform:uppercase; }
.routing-slip-table td { font-size:11px; line-height:1.4; overflow-wrap:anywhere; }
.routing-slip-col-date { width:22%; }
.routing-slip-col-office { width:11%; }
.routing-slip-col-signature { width:20%; }
.routing-slip-time,.routing-slip-person { color:var(--udm-muted); font-size:10px; }
.routing-slip-sender-name { display:block; min-height:28px; }
.routing-slip-signature-line { display:block; height:24px; margin-top:7px; border-bottom:1px solid var(--udm-ink); }
.routing-slip-receipt-note { margin-top:6px; padding-top:6px; border-top:1px dashed var(--udm-line); }
.routing-slip-empty { padding:24px !important; color:var(--udm-muted); text-align:center; }
.routing-slip-action-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:5px 16px; padding:12px 14px; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface); font-size:11px; }
.routing-slip-action-grid strong { display:inline-flex; align-items:center; justify-content:center; width:24px; height:22px; margin-right:6px; border:1px solid var(--udm-line); border-radius:4px; color:var(--udm-navy); }
.routing-slip-action-pending { margin:7px 0 0; color:var(--udm-muted); font-size:10px; }
.routing-slip-attachments { margin-top:20px; padding-top:2px; }
.routing-slip-attachments ol { margin:8px 0 0; padding-left:22px; font-size:12px; }
.routing-slip-attachments p { margin:8px 0 0; color:var(--udm-muted); font-size:12px; }
.routing-slip-footer { display:flex; align-items:flex-end; justify-content:space-between; gap:16px; margin-top:22px; padding-top:10px; border-top:1px solid var(--udm-line); color:var(--udm-muted); font-size:9.5px; }
.routing-slip-page-number { white-space:nowrap; }
.routing-slip-current-page::after { content:counter(page); }
@media (max-width:767.98px) {
  .routing-slip { padding:16px; }
  .routing-slip-header { flex-direction:column; }
  .routing-slip-identity { width:100%; justify-content:space-between; }
  .routing-slip-number { padding-right:0; font-size:18px; }
  .routing-slip-status { position:static; margin-top:7px; transform:none; }
  .routing-slip-summary-row { grid-template-columns:1fr; }
  .routing-slip-summary-label { padding-bottom:3px; }
  .routing-slip-summary-value { padding-top:3px; }
  .routing-slip-action-grid { grid-template-columns:1fr; }
}
/* One @page for the whole stylesheet. There were three — this, plus a
   `margin:12mm` inside the reports print block and another inside the
   dashboard's, each silently re-margining whichever printed last. These are
   the deliberate ones: 12mm head, 10mm sides so a six-column table is not
   squeezed, 14mm foot to clear the printed footer line. */
@page { size:A4 portrait; margin:12mm 10mm 14mm; }
@media print {
  html,body { background:var(--udm-surface) !important; }
  .app-content { padding:0 !important; }
  .routing-slip { max-width:none; margin:0; padding:0; border:0; border-radius:0; box-shadow:none; }
  .routing-slip-header { break-inside:avoid; }
  .routing-slip-number-block,.routing-slip-summary,.routing-slip-privacy,.routing-slip-action-reference,.routing-slip-attachments { break-inside:avoid; }
  .routing-slip-table { font-size:9pt; }
  .routing-slip-table thead { display:table-header-group; }
  .routing-slip-table tr { break-inside:avoid; page-break-inside:avoid; }
  .routing-slip-table th,.routing-slip-table td { padding:6px 5px; }
  .routing-slip-qr { width:28mm; min-height:28mm; }
  .routing-slip-qr-pattern { width:19mm; height:19mm; }
  /* Sized to fit the 23mm letterhead column on one line at the longest label. */
  .routing-slip-header-status .pill {
    padding:1px 5px; gap:3px; font-size:6.5pt; letter-spacing:0; line-height:1.25;
  }
  .routing-slip-header-status .pill-dot { width:4px; height:4px; flex:0 0 4px; }
  .routing-slip-footer { position:relative; break-inside:avoid; }
  .routing-slip-action-reference { page-break-before:auto; }
  .routing-slip-attachments { page-break-before:auto; }
}

/* ================================================================
   Clickable text visibility
   ================================================================ */

/* Prose links — the ones running through a sentence — are underlined and bold
   so they can be found without hovering for them.

   Wrapped in :where(), which contributes no specificity, so the whole thing
   weighs `a` and `a:hover` and nothing more. That is the entire fix to a bug
   this rule caused everywhere at once: written as
   `.app-content a:not(.btn):not(.nav-link)…:hover`, each :not() counted as a
   class, so the hover rule weighed eight classes and beat every component's own
   colour. A selected pill kept its navy *background* from .is-active and took
   its *text* colour from here — navy on navy, so the label vanished the moment
   the pointer touched it. The same went for the notification filters and the
   rows-per-page control, and every pill in the app was underlined at rest by
   the declaration above.

   The :not() list still reads as documentation of what is not prose, but it no
   longer has to be complete: at zero specificity a component's own rule wins by
   being a class, so a control added tomorrow needs no entry here. That is the
   property worth having — the old list could only ever be one component behind.

   `text-decoration: underline` rather than leaving it to the browser default:
   Bootstrap's reboot removes it, and the two stylesheets tie on specificity, so
   this file has to put it back explicitly. */
:where(.app-content) a:not(:where(.btn, .nav-link, .doc-tile, .stat-card, .smart-folder, .tag-chip)),
:where(.app-sidebar) a:not(:where(.nav-item, .brand)) {
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

:where(.app-content) a:not(:where(.btn, .nav-link, .doc-tile, .stat-card, .smart-folder, .tag-chip)):hover,
:where(.app-content) a:not(:where(.btn, .nav-link, .doc-tile, .stat-card, .smart-folder, .tag-chip)):focus {
  color: var(--udm-navy-text);
  text-decoration-thickness: 2px;
}

/* ================================================================
   Reports and analytics
   Chart colour tokens (--chart-one, --chart-two, --chart-track,
   --chart-grid) live in the :root block at the top of this file.
   ================================================================ */

.report-caption { margin-top:2px; color:var(--udm-muted); font-size:12.5px; }
.card-udm-caption { margin-top:2px; color:var(--udm-muted); font-size:12.5px; }
.report-print-header,.report-print-footer { display:none; }
/* Document Tracking's own pages, Tracking and Reports: an underlined strip
   under the page head. The module's tabs, so it looks nothing like the queue
   pills and filters under it, which narrow a list rather than change page. */
.subtabs { display:flex; gap:4px; margin:-4px 0 18px; border-bottom:1px solid var(--udm-line); }
.subtab { margin-bottom:-1px; padding:9px 14px; border-bottom:3px solid transparent; color:var(--udm-muted); font-size:14px; font-weight:600; text-decoration:none; }
.subtab:hover,.subtab:focus { color:var(--udm-navy-text); text-decoration:none; }
.subtab.is-active { border-bottom-color:var(--udm-teal); color:var(--udm-navy-text); }
.app-sidebar .nav-item--child {
  margin-left:24px; margin-bottom:6px; min-height:44px;
  padding:8px 18px; border-radius:6px; font-size:13.5px;
}
.app-sidebar .nav-item--child.active { box-shadow:inset 3px 0 0 var(--udm-gold); }
.app-sidebar .nav-item:focus-visible { outline:2px solid var(--udm-gold); outline-offset:2px; }

/* Repository: permission-scoped office folders and two distinct record lists. */
.repository-page { width:100%; min-width:0; }
.repository-page h2 { margin:0; font-size:16px; line-height:1.4; }
.repository-section-head,.repository-list-head { display:flex; align-items:center; justify-content:space-between; gap:16px; }
.repository-section-head { padding:18px 20px 12px; }
.repository-section-head p,.repository-list-head p { margin:4px 0 0; font-size:13px; color:var(--udm-muted); }
.repository-total { font-size:12.5px; color:var(--udm-muted); white-space:nowrap; }
.repository-folder-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(max(225px,calc(100% / var(--folder-columns,4) - 12px)),1fr)); gap:12px; padding:4px 20px 20px; }
.repository-folder { display:flex; align-items:center; gap:12px; padding:16px; min-height:108px; min-width:0; border:1px solid var(--udm-line); border-radius:10px; color:var(--udm-navy-text); background:var(--udm-canvas); text-decoration:none; }
.repository-folder:hover { color:var(--udm-navy-text); border-color:var(--udm-teal); text-decoration:none; }
.repository-folder.is-selected { background:var(--udm-teal-soft); border-color:var(--udm-teal); box-shadow:inset 0 0 0 1px var(--udm-teal); }
.repository-folder-icon { width:40px; flex:0 0 40px; color:var(--udm-gold-ink); }
.repository-folder-icon svg { display:block; width:40px; height:32px; }
.repository-folder-copy { display:flex; flex-direction:column; gap:4px; min-width:0; }
.repository-folder-copy strong { font-size:13.5px; line-height:1.4; overflow-wrap:anywhere; }
.repository-folder-copy>span { font-size:12px; color:var(--udm-muted); }
.repository-folder-copy .repository-folder-code { font-size:10.5px; font-weight:700; letter-spacing:.07em; color:var(--udm-teal-ink); }
.repository-workspace { min-width:0; }
.repository-breadcrumb { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:0 0 12px; font-size:12.5px; }
.repository-breadcrumb strong { overflow-wrap:anywhere; }
.repository-views { display:flex; gap:6px; border-bottom:1px solid var(--udm-line); margin-bottom:20px; }
.repository-view { display:flex; align-items:center; gap:8px; padding:12px 14px; color:var(--udm-muted); font-size:14px; border-bottom:3px solid transparent; margin-bottom:-1px; text-decoration:none; }
.repository-view:hover { color:var(--udm-navy-text); text-decoration:none; }
.repository-view.is-active { color:var(--udm-teal-ink); border-bottom-color:var(--udm-teal); font-weight:700; }
.repository-view .num { padding:2px 7px; border-radius:5px; background:var(--udm-canvas); color:var(--udm-navy-text); font-size:12px; }
.repository-pending-preview { border:1px solid var(--udm-gold-border); border-radius:10px; background:var(--udm-surface); margin-bottom:24px; }
.repository-pending-preview .repository-section-head { background:var(--udm-gold-soft); border-radius:10px 10px 0 0; padding-bottom:16px; }
.repository-pending-preview h2 .num { margin-left:6px; }
.repository-queue { list-style:none; padding:0; margin:0; }
.repository-queue li { display:flex; align-items:center; justify-content:space-between; gap:18px; padding:14px 20px; border-top:1px solid var(--udm-line); }
.repository-queue li:first-child { border-top:0; }
.repository-queue-copy { display:flex; flex-direction:column; gap:4px; min-width:0; }
.repository-queue-title { font-size:14px; font-weight:600; overflow-wrap:anywhere; }
.repository-queue-copy>.mono { font-size:12px; overflow-wrap:anywhere; }
.repository-queue-meta { display:flex; flex-wrap:wrap; gap:4px 12px; color:var(--udm-muted); font-size:12px; }
.repository-queue .btn { flex-shrink:0; min-height:40px; display:inline-flex; align-items:center; }
.repository-queue-empty p { font-size:13px; margin:4px 0 0; color:var(--udm-muted); }
.repository-list-head { margin-bottom:12px; }
.repository-list-head>a { font-size:13px; white-space:nowrap; }
.repository-filters { padding:16px 18px; margin-bottom:14px; }
.repository-filters label { display:block; margin-bottom:5px; color:var(--udm-muted); font-size:12px; font-weight:600; }
.repository-filters input:not([type=hidden]):not([type=checkbox]),.repository-filters select { min-height:42px; }
.deletion-review-tabs { display:flex; flex-wrap:wrap; gap:8px; margin:16px 0; }
.deletion-review-tabs a { display:flex; align-items:center; gap:10px; min-height:44px; padding:10px 14px; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface); }
.deletion-review-tabs a[aria-current=page] { background:var(--udm-green-soft); border-color:var(--udm-green); font-weight:700; }
.deletion-review-filters { margin-top:0; }
.deletion-review-list { display:grid; gap:12px; }
.deletion-review-item { display:flex; justify-content:space-between; align-items:center; gap:16px; padding:20px; }
.deletion-review-item>div { min-width:0; }
.deletion-review-item h2 { font-size:17px; overflow-wrap:anywhere; margin:0 0 6px; }
.deletion-review-item .btn { flex-shrink:0; min-height:44px; display:inline-flex; align-items:center; }
.deletion-review-metadata dt { color:var(--udm-muted); font-weight:400; font-size:13px; }
.deletion-review-metadata dd { margin-bottom:14px; overflow-wrap:anywhere; }
.deletion-review-history summary { padding:18px 20px; font-weight:700; cursor:pointer; }
.deletion-review-history li+li { border-top:1px solid var(--udm-line); margin-top:16px; padding-top:16px; }
.deletion-review-page [data-review-removal] .form-field { display:grid; grid-template-columns:20px minmax(0,1fr); gap:8px; align-items:start; }
.deletion-review-page [data-review-removal] .form-check-input { margin-top:4px; }
.deletion-review-page [data-review-removal] .form-check-label { margin-left:0 !important; }
.deletion-review-page [data-review-removal] .field-errors { grid-column:1 / -1; }
@media(max-width:767.98px) { .deletion-review-item { align-items:flex-start; flex-direction:column; padding:16px; } }
.repository-search { display:grid; grid-template-columns:minmax(0,1fr) auto auto; align-items:end; gap:8px; }
.repository-search .btn { min-height:42px; display:inline-flex; align-items:center; justify-content:center; }
.repository-filter-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; margin-top:14px; }
.repository-filter-grid>div { min-width:0; }
.repository-apply { margin-top:12px; min-height:40px; }
.repository-type-folders,.repository-tags { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:10px 0; font-size:12.5px; }
.repository-type-folders>span,.repository-tags>span { margin-right:4px; color:var(--udm-muted); font-size:12px; }
.repository-type-folders a,.repository-tags a { display:inline-flex; align-items:center; gap:7px; min-height:38px; padding:6px 10px; border:1px solid var(--udm-line); border-radius:7px; background:var(--udm-surface); overflow-wrap:anywhere; }
.repository-type-folders .num,.repository-tags .num { color:var(--udm-muted); }
.repository-type-folders a.is-selected { color:var(--udm-teal-ink); border-color:var(--udm-teal); background:var(--udm-teal-soft); }
.repository-retention { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:12px 16px; margin-top:14px; border:1px solid var(--udm-gold-border); border-radius:8px; background:var(--udm-gold-soft); }
.repository-retention>div { display:flex; flex-direction:column; gap:3px; font-size:13px; }
.repository-retention span { color:var(--udm-muted); font-size:12px; }
.repository-retention .btn { flex-shrink:0; }
.repository-results { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px; margin:16px 0 10px; color:var(--udm-muted); font-size:13px; }
.repository-results .pagination-size { margin:0; }
.repository-document-list { display:flex; flex-direction:column; gap:9px; }
.repository-document { display:grid; grid-template-columns:34px minmax(0,1fr) auto auto; align-items:center; gap:16px; padding:16px 18px; box-shadow:none; }
.repository-file-icon { color:var(--udm-teal-ink); width:28px; }
.repository-file-icon svg { display:block; width:28px; height:32px; }
.repository-document-copy { min-width:0; }
.repository-document h3 { font-size:14px; line-height:1.45; margin:0 0 5px; overflow-wrap:anywhere; }
.repository-document-meta { display:flex; align-items:center; flex-wrap:wrap; gap:5px 12px; font-size:12px; color:var(--udm-muted); }
.repository-document-copy p { margin:5px 0 0; font-size:12px; overflow-wrap:anywhere; }
.repository-document-tags { display:flex; flex-wrap:wrap; gap:5px; }
.repository-document-tags span { font-size:11.5px; color:var(--udm-muted); background:var(--udm-canvas); padding:2px 6px; border-radius:4px; margin-top:6px; overflow-wrap:anywhere; }
.repository-document-state { display:flex; flex-direction:column; align-items:flex-end; gap:5px; font-size:12px; color:var(--udm-muted); }
.repository-open { min-height:40px; display:flex; align-items:center; justify-content:center; }
.repository-page a:focus-visible,.repository-page button:focus-visible { outline:2px solid var(--udm-teal); outline-offset:3px; }
@media (max-width:767.98px) {
  .subtabs--repository .subtab { display:flex; align-items:center; justify-content:center; flex:1; min-width:0; min-height:44px; padding:9px 8px; text-align:center; font-size:13px; }
  .repository-page .page-head { flex-direction:column; align-items:stretch; }
  .repository-page .page-head>.btn { align-self:flex-start; min-height:44px; display:flex; align-items:center; }
  .repository-folder-grid { grid-template-columns:repeat(2,minmax(0,1fr)); padding:4px 14px 14px; gap:8px; }
  .repository-folder { padding:12px; min-height:112px; align-items:flex-start; flex-direction:column; gap:8px; }
  .repository-folder-icon { width:32px; flex-basis:auto; }
  .repository-folder-icon svg { width:32px; height:26px; }
  .repository-section-head,.repository-list-head { flex-wrap:wrap; gap:10px; }
  .repository-section-head { padding:14px; }
  .repository-filter-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .repository-search { grid-template-columns:1fr 1fr; }
  .repository-search>div { grid-column:1/-1; }
  .repository-document { grid-template-columns:28px minmax(0,1fr); align-items:start; gap:10px; padding:14px; }
  .repository-document-state { grid-column:2; flex-direction:row; flex-wrap:wrap; align-items:center; }
  .repository-open { grid-column:2; justify-self:start; min-width:90px; }
  .repository-queue li { padding:14px; flex-wrap:wrap; gap:10px; }
  .repository-queue-copy { flex-basis:100%; }
  .repository-retention { flex-wrap:wrap; }
}
@media (max-width:399.98px) {
  .repository-folder-grid { grid-template-columns:1fr; }
  .repository-folder { flex-direction:row; align-items:center; min-height:84px; }
  .repository-view { padding:10px 8px; font-size:12.5px; gap:5px; }
  .repository-filter-grid { grid-template-columns:1fr; }
}
.report-count-link { font-weight:700; text-decoration:underline; text-underline-offset:3px; }
#report-records { scroll-margin-top:90px; }
#report-records td:first-child { min-width:220px; max-width:440px; overflow-wrap:anywhere; }
@media (max-width:575.98px) {
  #report-records .card-udm-head { flex-direction:column; align-items:stretch; }
  #report-records .card-udm-head > .btn { align-self:flex-start; }
}
.dashboard-turnaround-summary { margin-top:20px; }
.reports-tabs { display:inline-flex; gap:4px; margin-bottom:18px; padding:4px; border:1px solid var(--udm-line); border-radius:10px; background:var(--udm-surface); box-shadow:var(--shadow-card); }
.reports-tab { padding:8px 15px; border:0; border-radius:7px; background:transparent; color:var(--udm-muted); font-size:13px; font-weight:700; }
.reports-tab:hover,.reports-tab:focus { background:var(--udm-canvas); color:var(--udm-navy-text); }
.reports-tab.active { background:var(--udm-selected-bg); color:var(--udm-selected-ink); }
.reports-tab.active:hover,.reports-tab.active:focus { background:var(--udm-selected-bg-hover); color:var(--udm-selected-ink); }
.report-panel { display:none; }
.report-panel.active { display:block; }
.report-section-head { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin:0 0 14px; }
.report-section-head h2 { margin:0; font-size:19px; }
.report-section-head p { margin:3px 0 0; color:var(--udm-muted); font-size:13px; }
.report-empty { padding:24px 10px; color:var(--udm-muted); text-align:center; }

/* Numbers that sit in a column line up; standalone figures keep proportional
   digits, where tabular spacing reads loose. */
.num { font-variant-numeric:tabular-nums; }

/* ------------------------------------------------------------ legend keys */
.chart-legend { display:flex; flex-wrap:wrap; gap:14px; }
.chart-key { display:inline-flex; align-items:center; gap:6px; color:var(--udm-muted); font-size:12px; font-weight:600; }
.chart-swatch { width:10px; height:10px; border-radius:3px; flex:0 0 10px; }
/* Named for what they mean, not for their position in a palette: a legend
   swatch, a bar and a column for the same thing take the same class suffix. */
.chart-swatch--draft { background:var(--status-draft); }
.chart-swatch--pending { background:var(--status-pending); }
.chart-swatch--received { background:var(--status-received); }
.chart-swatch--process { background:var(--status-process); }
.chart-swatch--upload { background:var(--status-upload); }
.chart-swatch--completed { background:var(--status-completed); }
.chart-swatch--created { background:var(--chart-created); }
.chart-swatch--historical { background:var(--chart-historical); }
.chart-swatch--received-part { background:var(--chart-received-part); }
.chart-swatch--neutral { background:var(--chart-neutral); }

/* ------------------------------------------------------- horizontal bars */
.report-office-row { padding:12px 0; border-bottom:1px solid var(--chart-grid); }
.report-office-row:last-child { border-bottom:0; }
.report-office-label { margin-bottom:7px; color:var(--udm-navy-text); font-size:13px; font-weight:700; }
.report-series { display:grid; gap:6px; }
/* The label column fits the longest series label the panels use, "Awaiting
   receipt"; at 82px it was cut to "Awaiting recei…". Fixed rather than sized to
   content: every row is its own grid, and a content-sized column would start
   each row's bar at a different x. */
.report-series-item { display:grid; grid-template-columns:100px minmax(0,1fr) 44px; align-items:center; gap:9px; font-size:11.5px; }
.report-series-item--wide { grid-template-columns:minmax(0,190px) minmax(0,1fr) 44px; padding:7px 0; font-size:12.5px; }
/* A fourth column for rows that carry a share beside the count. Without it the
   share was a fourth child in a three-column grid and wrapped onto a line of
   its own under the label. Every bar is drawn at that share: the track is the
   whole the panel states, never its largest row. */
.report-series-item--share { grid-template-columns:100px minmax(0,1fr) 44px 40px; }
.report-series-item--wide.report-series-item--share { grid-template-columns:minmax(0,190px) minmax(0,1fr) 44px 40px; }
/* And a fifth for "+n this month" beside the share, on Documents received by
   office. */
.report-series-item--wide.report-series-item--month { grid-template-columns:minmax(0,190px) minmax(0,1fr) 44px 40px 40px; }
.report-series-item--wide + .report-series-item--wide { border-top:1px solid var(--chart-grid); }
/* "Other (n offices)": what a top-N cap left out, as one row, so the rows add up
   to the total above them. Secondary ink, because it is an aggregate and not a
   peer of the ranked rows beside it. Its bar is drawn at its share like every
   other row's, faded for the same reason: with bars measured against the
   whole, a long "everything else" is a true finding, not one row's scale
   flattening the others. */
.report-series-item--remainder,.report-office-row--remainder .report-office-label { color:var(--udm-muted); font-style:italic; }
.report-series-item--remainder strong { color:var(--udm-muted); }
.report-series-item--remainder .report-bar i,.report-office-row--remainder .report-bar i { opacity:.55; }
.report-series-item > span { color:var(--udm-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.report-series-item strong { text-align:right; color:var(--udm-navy-text); }
.report-bar { height:10px; border-radius:2px; background:var(--chart-track); }
/* Square at the baseline, 4px rounded at the data end. No min-width: a zero
   value must paint nothing (the view floors real values at 1% instead). */
.report-bar i { display:block; height:100%; border-radius:0 4px 4px 0; }
.bar-pending { background:var(--status-pending); }
.bar-received { background:var(--status-received); }
.bar-completed { background:var(--status-completed); }
.bar-completed-strong { background:var(--status-completed-ink); }
.bar-neutral { background:var(--chart-neutral); }
/* The end of a bar, in the second series' colour: a figure that is part of the
   bar it sits in, rather than a second bar on a scale of its own. */
.bar-part { display:block; height:100%; margin-left:auto; border-radius:0 4px 4px 0; background:var(--chart-received-part); }
.bar-alert { background:var(--chart-alert); }
.bar-alert-soft { background:var(--chart-alert-soft); }
.chart-swatch--alert { background:var(--chart-alert); }
.chart-swatch--alert-soft { background:var(--chart-alert-soft); }

/* -------------------------------------------------------- column charts */
/* --column-value-band is the strip above the tallest column that holds its
   value label, so a label at 100% sits inside the plot rather than over the
   card head. The grid starts below it: the band is not part of the scale. */
/* --column-gutter holds the y-axis labels. The column charts only: the trend
   chart states its scale in words and dropped its gutter as dead space, which
   was right for it. Here four unlabelled hairlines could not say what the
   second one meant. */
.column-chart { --column-value-band:18px; --column-gutter:38px; --column-slot:22px; position:relative; padding:6px 0 0 var(--column-gutter); }
/* The axis and the grid cover exactly the columns' own area: below the value
   band, above the month labels. Ticks are placed by the value they print. */
.column-chart-axis,.column-chart-grid { position:absolute; top:calc(6px + var(--column-value-band)); bottom:22px; pointer-events:none; }
.column-chart-axis { left:0; width:calc(var(--column-gutter) - 8px); }
.column-chart-axis span { position:absolute; right:0; transform:translateY(50%); color:var(--udm-muted); font-size:10.5px; line-height:1; white-space:nowrap; }
/* Hairline, solid, one shade off the surface — never dashed. */
.column-chart-grid { left:var(--column-gutter); right:0; }
.column-chart-grid i { position:absolute; left:0; right:0; height:1px; transform:translateY(50%); background:var(--chart-grid); }
.column-chart-plot { position:relative; display:flex; align-items:flex-end; gap:6px; height:190px; }
/* Heights are percentages, so every box between the plot and the mark keeps a
   definite height — flex-grow here would leave the percentage unresolvable. */
.column-group { flex:1 1 0; min-width:0; height:100%; }
/* The 2px gap is the surface doing the separating — no stroke around a mark. */
.column-pair { position:relative; display:flex; align-items:flex-end; justify-content:center; gap:2px; height:calc(100% - 22px - var(--column-value-band)); margin-top:var(--column-value-band); }
/* ------------------------------------------------ the number on each bar

   Every column is a slot as wide as the number it carries, with the bar centred
   in it. The slot, not the 12px bar, is what the month is divided between, so
   two neighbouring numbers cannot overlap while the month has room for them.

   When it has not, the numbers turn on their side (.column-chart--turned):
   still one per bar, still on its cap, and no wider than the bar. Whether they
   fit is measured in the browser (static/js/doctrack.js) rather than guessed
   from the viewport, because it depends on the chart's width, how many series
   it has, and how many digits the biggest number runs to. Without script, the
   container query further down turns them wherever three three-digit numbers
   would not fit.

   Text ink, never the series colour: a light series hue is illegible as text,
   and the legend and the bar beside the number already say which series it is.
   The current month is set in the heading ink, because it is the one read. */
.column-item { position:relative; display:flex; align-items:flex-end; justify-content:center; flex:0 1 var(--column-slot); min-width:0; height:100%; }
.column-value { position:absolute; left:50%; margin-bottom:3px; transform:translateX(-50%); color:var(--udm-slate-text); font-size:10.5px; font-weight:600; line-height:1; letter-spacing:-.01em; font-variant-numeric:tabular-nums; text-align:center; white-space:nowrap; pointer-events:none; }
/* A zero has no bar to sit on, so it sits on the baseline, lighter, saying the
   series is there and empty rather than leaving a gap nobody can read. */
.column-value--zero { color:var(--udm-muted); font-weight:500; }
.column-group:last-child .column-value { color:var(--udm-navy-text); font-weight:700; }
.column-group:last-child .column-value--zero { color:var(--udm-muted); font-weight:500; }
.column-chart--turned { --column-value-band:34px; --column-slot:12px; }
.column-chart--turned .column-value { writing-mode:vertical-rl; transform:translateX(-50%) rotate(180deg); margin-bottom:4px; letter-spacing:0; }
.column { display:block; width:100%; max-width:12px; border-radius:4px 4px 0 0; }
.column--created { background:var(--chart-created); }
.column--endorsement { background:var(--status-pending); }
.column--completed { background:var(--status-completed); }
.column--historical { background:var(--chart-historical); }
.column-label { height:22px; color:var(--udm-muted); font-size:11px; text-align:center; line-height:22px; }
.chart-scale { margin-top:10px; color:var(--udm-muted); font-size:11.5px; }
/* Administration filter bars: a labelled row, then one line saying how many
   rows the filters left and how to undo them. */
.admin-filters .form-label { margin-bottom:4px; color:var(--udm-muted); font-size:12px; font-weight:600; }
.admin-filter-summary { margin-top:10px; color:var(--udm-muted); font-size:12.5px; }
/* A date input's native width is wider than a narrow column; let it fit. */
.admin-filter-date .form-control { min-width:0; padding-inline:8px; }

/* One office's own endorsement figures, where the rankings sit for every office. */
.office-activity { display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:14px; }
.office-activity-figure { display:flex; flex-direction:column; gap:2px; padding:12px 14px; border:1px solid var(--chart-grid); border-radius:8px; }
.office-activity-figure span { color:var(--udm-muted); font-size:12.5px; font-weight:600; }
.office-activity-figure strong { color:var(--udm-navy-text); font-size:26px; font-weight:800; line-height:1.15; }
.office-activity-figure small { color:var(--udm-muted); font-size:12px; }
.report-section-subhead { margin:-6px 0 10px; color:var(--udm-muted); font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }

/* The reasoning a reader needs once and not on every visit: why a series is
   cumulative, what "historical" means, why office hours. One plain line stays
   under every title; this holds the rest. */
.chart-note { margin-top:10px; }
.chart-note p { margin:12px 0 0; color:var(--udm-slate-text); font-size:14px; line-height:1.7; max-width:70ch; }
.chart-table { margin-top:12px; }
.chart-table table { margin-top:8px; }
/* Shared native disclosures: the entire row is a target, and the browser
   provides the expanded state and Enter/Space behavior without JavaScript. */
.disclosure-control { display:grid; grid-template-columns:12px minmax(0,1fr) auto; align-items:center; gap:12px; width:100%; min-height:48px; padding:12px 14px; border:1px solid var(--udm-line-strong); border-radius:8px; background:var(--udm-surface-sunk); color:var(--udm-navy-text); font-size:15px; line-height:1.4; list-style:none; cursor:pointer; }
.disclosure-control::-webkit-details-marker { display:none; }
.disclosure-control::before { content:""; width:8px; height:8px; border-right:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(-45deg); }
details[open] > .disclosure-control::before { transform:rotate(45deg); }
.disclosure-control:hover { border-color:var(--udm-teal); background:var(--udm-teal-soft); }
.disclosure-control:focus-visible { outline:3px solid var(--udm-teal); outline-offset:3px; }
.disclosure-copy { min-width:0; }
.disclosure-title { display:block; font-weight:650; overflow-wrap:anywhere; }
.disclosure-description { display:block; margin-top:3px; color:var(--udm-slate-text); font-size:13px; font-weight:400; line-height:1.5; }
.disclosure-state { padding:4px 8px; border:1px solid var(--udm-line); border-radius:6px; background:var(--udm-surface); color:var(--udm-navy-text); font-size:12px; font-weight:600; white-space:nowrap; }
.disclosure-hide { display:none; }
details[open] > .disclosure-control .disclosure-show { display:none; }
details[open] > .disclosure-control .disclosure-hide { display:inline; }
/* The site-wide `.table-responsive > .table-udm { min-width:720px }` is for the
   record lists. A chart's table has three to five short columns, and under that
   minimum it scrolled sideways inside a 435px dashboard card, hiding the
   Completed column behind a scroll nobody could see. */
.chart-table .table-responsive > .table-udm { min-width:0; }

/* ------------------------------------------- column charts, by their width */
/* Sized by the chart's own width, not the viewport's. The dashboard chart sits
   in a half-width column beside the sidebar from 1200px up, so it is at its
   narrowest on a desktop: 395px at a 1200px viewport and 435px on a 1280px
   laptop (a 1920px panel at 150%), against 679px on a 768px tablet. Viewport
   breakpoints would have shrunk the chart where it had room and left it full
   size where it had none. Measured widths, 320px to 1920px viewports:
   dashboard 245-755px, Reports 245-891px.

   Pitch per month is (width - gutter - 11 gaps) / 12. A three-digit value label
   is about 20px at 11px type.
     >= 420px  full: 190px plot, 38px gutter, every label.
     360-419px compact: 170px plot, 10px type, narrower columns. Every label
               still fits: the pitch never drops below 27px.
     < 360px   the grouped plot stops pretending. Twelve months of three
               columns come to under 5px a column, so the plot is hidden and
               the "View as table" fallback is shown open instead. Every phone
               held upright lands here (300px at 375, 339px at 414). */
.column-chart-frame { container:column-chart / inline-size; }
.chart-month-short { display:none; }
/* Without script there is no measurement, so turn the numbers wherever three
   three-digit numbers would not fit side by side: twelve months of three 22px
   slots need about 900px of chart. Script marks each chart it has measured, and
   from then on the measurement decides. */
@container column-chart (max-width:939.98px) {
  .column-chart:not(.column-chart--measured) { --column-value-band:34px; --column-slot:12px; }
  .column-chart:not(.column-chart--measured) .column-value { writing-mode:vertical-rl; transform:translateX(-50%) rotate(180deg); margin-bottom:4px; letter-spacing:0; }
}
@container column-chart (max-width:419.98px) {
  .column-chart { --column-gutter:30px; }
  .column-chart-plot { height:170px; gap:4px; }
  .column { max-width:10px; }
  .column-chart--turned,.column-chart:not(.column-chart--measured) { --column-slot:10px; }
  .column-label,.column-chart-axis span { font-size:10px; }
}
@container column-chart (max-width:359.98px) {
  .column-chart,.chart-scale { display:none; }
  .chart-table { margin-top:0; }
  /* The table is the chart now, so it has to fit: up to five columns in 245px.
     Short month names, and headers that may wrap onto two lines. */
  .chart-table .table-udm th,.chart-table .table-udm td { padding:9px 4px; font-size:12px; }
  .chart-table .table-udm th { font-size:9.5px; letter-spacing:0; white-space:normal; vertical-align:bottom; }
  .chart-month-long { display:none; }
  .chart-month-short { display:inline; white-space:nowrap; }
}
/* Open by default at that width. `open` is an attribute, not something a query
   can set, so the closed content is made visible instead and the summary that
   would toggle nothing is hidden. Browsers without ::details-content keep the
   summary, so the table is one tap away rather than gone. */
@supports selector(::details-content) {
  @container column-chart (max-width:359.98px) {
    .chart-table::details-content { content-visibility:visible; }
    .chart-table > summary { display:none; }
    .chart-table table { margin-top:0; }
  }
}

/* A chart's legend is its identity channel, so it must never be clipped. The
   card head is one flex row inside a card that hides overflow: a long caption
   squeezed the legend into a single column at 1280px and cut it off at 375px
   ("Awaitin"). The caption keeps at least 260px and the legend drops below it
   when the two do not fit on one line. */
.card-udm .card-udm-head:has(> .chart-legend),.card-udm .card-udm-head:has(> .segmented) { flex-wrap:wrap; align-items:flex-start; }
.card-udm .card-udm-head:has(> .chart-legend) > div:first-child,
.card-udm .card-udm-head:has(> .segmented) > div:first-child { flex:1 1 260px; }
.card-udm .card-udm-head > .chart-legend { flex:0 1 auto; }
/* The month a turnaround card answers for. Wraps under the title like a legend
   when the head is narrow, rather than squeezing the title into a column. */
.card-udm .card-udm-head:has(> .month-picker) { flex-wrap:wrap; align-items:flex-start; }
.card-udm .card-udm-head:has(> .month-picker) > div:first-child { flex:1 1 260px; }
.month-picker { display:flex; align-items:center; gap:8px; flex:0 0 auto; margin:0; }
.month-picker .form-select { width:auto; min-width:11.5rem; }
.month-picker-label { color:var(--udm-muted); font-size:12.5px; font-weight:600; }
/* A turnaround stage: its average on one line, then the fastest and slowest
   documents under it. The rule sits under the whole stage, not between the
   average and its extremes. */
.turnaround-stage { padding-bottom:6px; border-bottom:1px solid var(--chart-grid); }
.turnaround-stage:last-child { border-bottom:0; }
.turnaround-stage .report-metric { border-bottom:0; padding-bottom:4px; }
.turnaround-extremes { display:flex; flex-wrap:wrap; gap:2px 16px; margin:0 0 4px; font-size:12px; }
.turnaround-extremes > div { display:flex; align-items:baseline; gap:4px; min-width:0; }
.turnaround-extremes dt { margin:0; }
.turnaround-extremes dd { margin:0; min-width:0; color:var(--udm-navy-text); }
/* A tracking number is one token: it moves to its own line whole rather than
   breaking after "2026-09-". */
.turnaround-extremes dd a { white-space:nowrap; }
.turnaround-outside { margin:0 0 4px; color:var(--udm-muted); font-size:11.5px; }
/* Beside the trend the stages are columns, not rows: no rule between them.
   The column is too narrow for a label and a labelled figure side by side,
   so each stage reads top to bottom: what it is, then its average. */
.trend-summary-figures .turnaround-stage { border-bottom:0; }
.trend-summary-figures .turnaround-stage .report-metric { flex-direction:column; align-items:flex-start; gap:2px; }
.trend-summary-figures .turnaround-stage .report-metric > strong { text-align:left; }
/* "Average", "Fastest", "Slowest": which kind of figure this is, said in words
   beside the figure rather than left to the heading. */
.metric-kind { margin-right:4px; color:var(--udm-muted); font-size:11.5px; font-weight:600; text-transform:uppercase; letter-spacing:.04em; }

/* ---------------------------------------------------------- status by row */
/* The label column is a fixed width rather than sized to its own content
   (auto/max-content) because every row here is its own independent grid —
   sizing to content would let each row's bar start at a different x position
   and break the one thing a bar chart needs, that lengths are comparable at a
   glance. 152px is measured, not guessed: the widest pill in the status set,
   "Pending receipt", renders at ~144px, and 108px — sized for the shorter
   labels this used to be — clipped it, with the bar painted on top of the
   overflow. overflow:hidden on the cell is the fallback for a future label
   longer than this margin: a clean clip at the column edge instead of a pill
   bleeding into the bar again. */
.status-row {
  display:grid; grid-template-columns:152px minmax(0,1fr) 34px 40px;
  align-items:center; gap:10px; padding:9px 0; border-bottom:1px solid var(--chart-grid);
}
.status-row:last-child { border-bottom:0; }
.status-row-label { min-width:0; }
/* "Completed - pending upload" is 26 characters, and .pill sets them uppercase
   at 0.06em tracking with `white-space:nowrap` — about 210px against a 152px
   column that also clipped its overflow, so the row read "COMPLETED - PENDIN".

   The pill wraps here rather than the column widening to fit it: 210px spent on
   a label every other status uses half of would take that width off the bar,
   which is the thing carrying the comparison. Two lines for the one long status
   costs a few pixels of row height and nothing else. `overflow:hidden` goes
   with it — once the text can wrap, clipping can only hide something. */
.status-row-label .pill { white-space:normal; text-align:center; }
.status-row strong { text-align:right; color:var(--udm-navy-text); font-size:14px; }
/* The incoming/outgoing split, under the bar it belongs to rather than beside
   it: the row is already pill + bar + count + share, and four columns plus two
   more would wrap on any screen narrower than a desktop. */
.status-direction {
  display:flex; flex-wrap:wrap; gap:4px 18px;
  margin:-4px 0 10px; padding-left:2px;
  color:var(--udm-muted); font-size:12px;
}
.status-direction .num { color:var(--udm-navy-text); }
.status-share { color:var(--udm-muted); font-size:12px; text-align:right; }

/* -------------------------------------------------------------- metrics */
.report-metric,.report-quality-row,.report-search-row { display:flex; align-items:center; justify-content:space-between; gap:15px; padding:9px 0; border-bottom:1px solid var(--chart-grid); font-size:13.5px; }
.report-metric:last-child,.report-quality-row:last-child,.report-search-row:last-child { border-bottom:0; }
.report-metric strong { color:var(--udm-navy-text); font-size:14px; text-align:right; white-space:nowrap; }
/* The figure itself must not split — "2 days 5 hrs" broken across lines reads
   as two numbers — but nowrap inherits, and the caption below it is a whole
   phrase: "4 days 9 hrs on the calendar". That made the caption the widest
   unbreakable thing in the column, so it pushed out of its grid cell and over
   the next figure. Only the figure needs holding together. */
.report-metric small { display:block; font-size:11.5px; white-space:normal; }

.meter-head { display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:6px; font-size:13px; }
.meter-head strong { color:var(--udm-navy-text); font-size:17px; }
/* Unfilled track is a lighter step of the fill's own ramp, so state reads
   across the whole bar. */
.meter-track { height:10px; border-radius:2px; background:var(--udm-green-soft); }
.meter-fill { display:block; height:100%; min-width:3px; border-radius:0 4px 4px 0; background:var(--udm-green); }
.meter-foot { margin-top:6px; color:var(--udm-muted); font-size:11.5px; }

@media (max-width:767.98px) {
  .reports-tabs { position:relative; display:flex; overflow-x:auto; }
  .reports-tab { flex:0 0 auto; }
  .report-series-item { grid-template-columns:96px minmax(0,1fr) 38px; }
  .report-series-item--wide { grid-template-columns:minmax(0,110px) minmax(0,1fr) 38px; }
  .report-series-item--share { grid-template-columns:96px minmax(0,1fr) 38px 36px; }
  .report-series-item--wide.report-series-item--share { grid-template-columns:minmax(0,110px) minmax(0,1fr) 38px 36px; }
  .report-series-item--wide.report-series-item--month { grid-template-columns:minmax(0,110px) minmax(0,1fr) 38px 36px 36px; }
  /* Same label width as the desktop rule — the content that has to fit does
     not shrink on a narrow screen, only the bar column does. */
  .status-row { grid-template-columns:152px minmax(0,1fr) 30px 36px; gap:8px; }
}
/* Phones: three figures beside the office name left the bar about 40px wide.
   The bar takes a full line under the name and its figures instead; placed
   explicitly, so the other four children auto-place along the first line. */
@media (max-width:575.98px) {
  .report-series-item--wide.report-series-item--month { grid-template-columns:minmax(0,1fr) 38px 36px 36px; row-gap:5px; }
  .report-series-item--month > .report-bar { grid-column:1 / -1; grid-row:2; }
}
@media print {
  .reports-page-head .no-print,.reports-tabs,.card-udm.no-print { display:none !important; }
  .report-print-header,.report-print-footer { display:flex; justify-content:space-between; gap:18px; color:var(--udm-slate-text); font-size:9pt; }
  .report-print-header { margin-bottom:8mm; padding-bottom:3mm; border-bottom:1px solid #8793a3; }
  .report-print-header strong,.report-print-header span { display:block; }
  .report-print-footer { margin-top:8mm; padding-top:3mm; border-top:1px solid #8793a3; }
  /* Print what is on screen, which means the active panel only.
     This used to be `.report-panel { display:block !important }`, which forced
     *both* panels into every print job: asking for the tracking report handed
     you the repository report stapled behind it, and there was no way to print
     either one alone. The !important also beat the `.report-panel { display:none }`
     rule that does the tab switching, so the screen and the paper disagreed
     about what the reader had selected. Now only the active panel prints, and
     it is the last one on the page, so it needs no page break after it. */
  .report-panel { display:none; }
  .report-panel.active { display:block; page-break-after:auto; }
  .report-section-head { margin-top:0; }
  /* `.card-udm { overflow:hidden }` is declared later in this file, so it wins
     the cascade in print too and clips any card taller than the space left on
     the page — Records by status stopped after two rows, Overdue after one.
     !important rather than reordering, because the hidden overflow is
     load-bearing on screen: it is what clips the card head's border to the
     rounded corners. */
  .card-udm { overflow:visible !important; break-inside:auto; box-shadow:none; }
  /* A heading must not be the last thing on a page. */
  .card-udm .card-udm-head { break-inside:avoid; break-after:avoid; }
  .stat-card { break-inside:avoid; box-shadow:none; }

  /* Break between rows, never through one. */
  .status-row,.status-direction,.report-direction,.report-all-offices,.report-series-item,.report-office-row,
  .report-metric,.report-quality-row,.column-group,
  .column-chart,.meter { break-inside:avoid; }

  /* Bootstrap's h-100 equalises card heights inside a flex row; on paper that
     is a fixed height with nowhere to flow. */
  .h-100 { height:auto !important; }
  .row > [class*="col-"] { width:100% !important; max-width:100% !important; }
  /* Bars and columns are background paint; without this they print blank. */
  .report-bar i,.report-direction-bar,.report-direction-bar > span,
  .column,.chart-swatch,.meter-fill,.meter-track,.report-bar,.pill,.column-chart-grid i {
    -webkit-print-color-adjust:exact; print-color-adjust:exact;
  }
  .chart-table { display:none; }
  .donut-tooltip { display:none !important; }
}

/* ================================================================
   The dashboard memo, printed
   Its own page — templates/core/dashboard_memo_print.html — rather than the
   dashboard with a print stylesheet over it. Fixed units throughout: pt for
   type, mm for the page. The dashboard's rem/%/flex grid lays out against the
   viewport, so printing it gave a different result depending on how wide the
   window happened to be when somebody pressed the button. A memo is a document
   and has to come out the same every time.

   None of the screen's classes are reused here. .memo-sheet and .card-udm
   carry borders, radii and shadows that belong to a panel sitting on a canvas,
   and there is no canvas on paper.
   ================================================================ */
/* A sheet of paper that happens to be shown on a screen first, so it stays
   white and dark-inked in both themes. Written in tokens and pinned below
   rather than hardcoded, which is how .login-wrap holds the sign-in screen
   light — a hardcoded surface cannot re-point, and the rule against it is
   what keeps the dark theme a matter of re-aiming tokens.

   Following the dark palette here would give a readable tab and a blank
   printout; inheriting the dark canvas without a ground of its own would put
   document ink on a dark page, which tests/test_theme_contrast.py caught. */
.memo-print { max-width: 180mm; margin: 0 auto; padding: 14mm 12mm; background: var(--udm-surface); color: var(--udm-ink); font-size: 10.5pt; line-height: 1.5; }
.memo-print-head { display: flex; justify-content: space-between; gap: 10mm; padding-bottom: 3mm; border-bottom: 1px solid #8793a3; font-size: 9pt; color: var(--udm-slate-text); }
.memo-print-title { margin: 6mm 0 2mm; font-size: 17pt; font-weight: 700; letter-spacing: -0.01em; }
.memo-print-meta { display: flex; flex-wrap: wrap; gap: 2mm 8mm; padding-bottom: 4mm; border-bottom: 1px solid #cfd6e0; font-size: 9pt; color: var(--udm-slate-text); }
.memo-print-section { margin-top: 6mm; break-inside: avoid; }
.memo-print-heading { margin: 0 0 2mm; font-size: 9pt; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; color: var(--udm-slate-ink); }
/* Label and figure as two columns. The label column takes its width from the
   longest label — office names here — and the figures line up against it. */
.memo-print-lines { display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); gap: 1.5mm 8mm; margin: 0; }
.memo-print-lines dt { color: var(--udm-slate-text); }
.memo-print-lines dd { margin: 0; font-weight: 600; }
/* The memo is laid out for paper; opened on a phone, its label column and the
   paper margins left no room, and the page scrolled sideways. On a narrow
   screen the labels sit above their figures. Screen only: print is untouched. */
@media screen and (max-width: 575.98px) {
  .memo-print { padding: 16px; }
  .memo-print-head { flex-wrap: wrap; gap: 4px 16px; }
  .memo-print-lines { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .memo-print-lines dd { margin-bottom: 6px; }
}
.memo-print-statement { grid-column: 1 / -1; font-weight: 400 !important; }
.memo-print-foot { margin-top: 8mm; padding-top: 3mm; border-top: 1px solid #8793a3; font-size: 8.5pt; color: var(--udm-slate-ink); }

@media print {
  /* The page owns the margin, so the wrapper stops adding a second one. */
  .memo-print { max-width: none; margin: 0; padding: 0; }
}

/* ================================================================
   PHASE 6: final polish, accessibility, and responsive navigation
   ================================================================ */
html { scroll-behavior:smooth; }
body.sidebar-open { overflow:hidden; }
.skip-link { position:fixed; top:-100px; left:16px; z-index:2000; padding:9px 13px; border:2px solid var(--udm-gold); border-radius:8px; background:var(--udm-surface); color:var(--udm-navy-text); font-weight:700; }
.skip-link:focus { top:14px; }
.app-footer { display:flex; flex-wrap:wrap; gap:6px; padding:18px 26px; border-top:1px solid var(--udm-line); background:var(--udm-surface); color:var(--udm-muted); font-size:12.5px; }
.sidebar-toggle,.sidebar-close,.sidebar-backdrop { display:none; }
.sidebar-mobile-head { display:block; }
.app-content:focus { outline:none; }
.card-udm { overflow:hidden; }
.card-udm-head > div { min-width:0; }
.btn { transition:transform 100ms ease,box-shadow 100ms ease,background-color 100ms ease,border-color 100ms ease; }
.btn:active { transform:translateY(1px); }
.btn:disabled { cursor:not-allowed; opacity:.65; }
.pill-dot { width:6px; height:6px; flex:0 0 6px; border-radius:50%; background:currentColor; opacity:.75; }
.form-field--error .form-control,.form-field--error .form-select { border-color:var(--udm-red); }
.field-errors { margin-top:5px; color:var(--udm-red); font-size:12.5px; font-weight:600; }
.message-stack { display:grid; gap:9px; margin-bottom:16px; }
/* Django tags an error message "error", which Bootstrap has no class for: the
   banner came out uncoloured in both themes. It takes the danger colours. */
.alert-error {
  --bs-alert-color: var(--bs-danger-text-emphasis);
  --bs-alert-bg: var(--bs-danger-bg-subtle);
  --bs-alert-border-color: var(--bs-danger-border-subtle);
  --bs-alert-link-color: var(--bs-danger-text-emphasis);
}
.app-alert { display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:start; gap:10px; margin:0; border-radius:10px; }
.app-alert-icon { width:9px; height:9px; margin-top:7px; border-radius:50%; background:currentColor; opacity:.75; }
.app-pagination .page-link { border-color:var(--udm-line); color:var(--udm-navy-text); font-weight:700; text-decoration:none; }
.app-pagination .page-item:not(.disabled) .page-link:hover { border-color:var(--udm-teal); background:var(--udm-teal-soft); }

/* ------------------------------------------------- rows-per-page control */
/* Two halves of one control, in the two places they are wanted. The size row
   sits above the list — "1–25 of 312 · Per page 10 25 50 100 All" is read
   before the rows, since it is what says whether the answer is on this screen
   at all — and the step buttons sit under the rows, which is where the reader
   is standing when they want the next page.

   The size options are links rather than a <select> for the same reason the
   filter pills are — no form to submit, so no JavaScript, which django-csp
   would not let us attach inline anyway.

   No justify-content on the base rule: neither half wants the same one, and a
   default here would only be a value both of them override. */
.page-controls { display:flex; flex-wrap:wrap; align-items:center; gap:10px 16px; }
/* The size row is ranged right, with the picker last in it, so the control
   lands on the same edge as the "Export CSV" and "Advanced relevance search"
   links these lists already carry — the right-hand column is where this app
   puts the things you do to a list, as against the headings that say what it
   is. The count sits to its left rather than at the far edge: it is a fact to
   read, not a control to reach for.

   Margin below rather than above, because it sits over the list it describes;
   the step buttons take the mirror of that. */
.page-controls--size { margin:0 0 10px; justify-content:flex-end; }
.page-controls--steps { margin-top:16px; justify-content:center; }
.page-size { display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.page-size-label { color:var(--udm-muted); font-size:12.5px; font-weight:700; }
/* A single bordered strip rather than five separate buttons: these are one
   choice with five values, and five outlines read as five unrelated actions. */
.page-size-options {
  display:inline-flex; overflow:hidden;
  border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface);
}
.page-size-option {
  padding:4px 11px; border-left:1px solid var(--udm-line);
  color:var(--udm-navy-text); font-size:12.5px; font-weight:700;
  text-decoration:none; line-height:1.6;
}
.page-size-option:first-child { border-left:0; }
.page-size-option:hover,.page-size-option:focus-visible { background:var(--udm-teal-soft); color:var(--udm-teal-ink); text-decoration:none; }
/* The selected state the filter pills and the notification filters use for
   "this is the state you are in", rather than a colour of its own. */
.page-size-option.is-active { background:var(--udm-selected-bg); color:var(--udm-selected-ink); cursor:default; }
/* It renders as a <span>, so it takes no pointer; stated anyway, so the day it
   becomes a link again it cannot go dark-on-dark. */
.page-size-option.is-active:hover { background:var(--udm-selected-bg); color:var(--udm-selected-ink); }
.page-size-count { color:var(--udm-muted); font-size:12.5px; }

@media (max-width: 575.98px) {
  /* Wrapped onto two lines on a phone, a right-ragged block reads worse than a
     left-aligned one — there is no facing column left to align to. */
  .page-controls--size { justify-content:flex-start; }
}
.account-facts th { width:130px; color:var(--udm-muted); font-weight:500; }
.account-sticky-note { position:sticky; top:86px; }
.login-brand { position:relative; z-index:1; display:inline-flex; align-items:center; gap:11px; color:#fff; text-decoration:none; }
.login-brand:hover { text-decoration:none; }
.login-brand img { width:42px; height:42px; border-radius:10px; }
.login-brand .login-brand-mark { width:56px; height:56px; flex:0 0 56px; border-radius:50%; object-fit:contain; }
.login-institution { position:relative; z-index:1; margin:0; color:rgba(255,255,255,.68); font-size:13px; }
.login-form-heading { margin-bottom:20px; }
.login-form-heading h2 { margin:2px 0 5px; font-size:27px; }
.login-form-heading p { margin:0; color:var(--udm-muted); font-size:14px; }
.login-security-note { display:grid; gap:2px; margin-top:18px; padding:10px 12px; border-left:3px solid var(--udm-gold); border-radius:0 8px 8px 0; background:var(--udm-note-bg); color:var(--udm-note-ink); font-size:12.5px; }
.login-account-note { margin:16px 0 0; color:var(--udm-muted); font-size:12.5px; }
.lockout-icon { display:inline-flex; align-items:center; justify-content:center; width:48px; height:48px; margin-bottom:13px; border-radius:50%; background:var(--udm-gold-soft); color:#806414; font-size:23px; font-weight:800; }
.error-page { max-width:680px; margin:7vh auto; padding:48px 28px; border:1px solid var(--udm-line); border-radius:var(--radius); background:var(--udm-surface); box-shadow:var(--shadow-card); text-align:center; }
.error-code { color:var(--udm-gold); font-family:"Aptos Display","Segoe UI",sans-serif; font-size:54px; font-weight:800; line-height:1; }
.error-page h1 { margin:10px 0 6px; font-size:26px; }
.error-page p { max-width:560px; margin:0 auto 12px; }
/* position:relative makes the scroller the containing block of anything
   absolutely positioned inside it. Without it a .visually-hidden header label
   (absolute) escaped the scroller at its static position, far right in a wide
   table, and on a phone the whole Tracking page scrolled sideways by the
   table's width. */
.table-responsive { position: relative; max-width: 100%; overflow-x: auto; scrollbar-width: thin; -webkit-overflow-scrolling: touch; }
.table-responsive > .table-udm { min-width: 720px; }
.search-filters-card .card-udm-body { min-width: 0; }
.search-query-card .form-control { min-width: 0; }
/* What matched and how it is ordered on the left; the page-length control on
   the right. One line, because these were three stacked rows answering one
   question — and two of them answered it with the same number. */
.search-results-head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 8px 16px; margin-bottom: 10px;
}
.search-results-summary { font-size: 13.5px; }
/* The row owns the spacing now, so the control inside it brings none of its own. */
.search-results-head .page-controls--size { margin: 0; }

@media (max-width: 767.98px) {
  .table-responsive > .table-udm { min-width: 660px; }
  /* Stacked on a phone, and the control ranges left with the summary above it
     rather than hanging off the right edge of a column it no longer faces. */
  .search-results-head { align-items: flex-start; flex-direction: column; }
  .search-results-head .page-controls--size { justify-content: flex-start; }
  .search-filters-card .card-udm-body { padding-top: 14px; }
}

@media (max-width: 575.98px) {
  .search-query-card .card-udm-body { padding: 13px; }
  .search-date-range { margin-left: 0; margin-right: 0; }
  .search-date-range > [class*="col-"] { padding-left: 0; padding-right: 0; }
}
@media (max-width:900px) {
  .app-shell { display:block; }
  .app-sidebar { position:fixed; top:0; bottom:0; left:0; z-index:1050; display:block; width:min(82vw,286px); height:100vh; padding:18px 14px; overflow-y:auto; visibility:hidden; transform:translateX(-105%); transition:transform 180ms ease; box-shadow:12px 0 32px rgba(6,28,52,.24); }
  body.sidebar-open .app-sidebar { visibility:visible; transform:translateX(0); }
  .sidebar-mobile-head { display:flex; align-items:flex-start; justify-content:space-between; gap:10px; }
  .sidebar-close { display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; padding:0; border:0; border-radius:7px; background:rgba(255,255,255,.08); color:#fff; font-size:25px; line-height:1; }
  .sidebar-backdrop { position:fixed; inset:0; z-index:1040; display:block; border:0; background:rgba(6,20,36,.5); opacity:0; pointer-events:none; transition:opacity 180ms ease; }
  body.sidebar-open .sidebar-backdrop { opacity:1; pointer-events:auto; }
  .sidebar-toggle { display:inline-flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; width:38px; height:38px; flex:0 0 38px; padding:0; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface); color:var(--udm-navy-text); }
  .sidebar-toggle span { display:block; width:17px; height:2px; border-radius:2px; background:currentColor; }
  .app-sidebar nav { display:block; }
  .app-sidebar .brand { padding:2px 5px 20px; }
  .nav-section { display:block; }
  .app-topbar { position:sticky; top:0; }
  .app-footer { padding:16px; }
}
@media (max-width:575.98px) {
  /* The search box kept its 180px desktop minimum (.app-topbar .topbar-search,
     which outranks the input rule below), so at 360px the account menu, the
     only way to sign out, sat past the right edge of the screen. */
  .app-topbar { gap:8px; padding:10px 12px; }
  .app-topbar .topbar-search { min-width:0; }
  .topbar-search input { min-width:0; }
  .app-content { padding:14px; }
  .card-udm .card-udm-head,.card-udm .card-udm-body { padding-left:15px; padding-right:15px; }
  .stat-card { padding:13px 14px; }
  .stat-card .value { font-size:29px; }
  .login-form { padding:28px 20px; }
  .login-art { padding:28px 22px; }
  .login-art h1 { font-size:29px; }
  .error-page { margin:3vh auto; padding:36px 20px; }
}
@media print {
  .skip-link,.sidebar-backdrop { display:none !important; }
  .app-footer { display:none !important; }
}
@media (prefers-reduced-motion:reduce) { html { scroll-behavior:auto; } .app-sidebar,.sidebar-backdrop { transition:none; } }
/* ================================================================
   Confirm Receipt action
   Dedicated style used on Dashboard, Tracking list, and record detail
   ================================================================ */
.btn-receipt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: auto;
  min-width: max-content;
  min-height: 38px;
  padding: 8px 13px;
  border: 1px solid var(--udm-gold-border);
  border-radius: 8px;
  background: var(--udm-gold-tint);
  color: var(--udm-gold-ink-dark);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none !important;
  box-shadow: 0 1px 2px rgba(11, 49, 90, 0.06);
  transition: background-color 120ms ease, border-color 120ms ease,
              color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

.btn-receipt:hover {
  border-color: var(--udm-gold);
  background: var(--udm-gold-soft);
  color: var(--udm-gold-ink-hover);
  text-decoration: none !important;
  box-shadow: 0 3px 8px color-mix(in srgb, var(--udm-gold) 16%, transparent);
  transform: translateY(-1px);
}

.btn-receipt:active {
  background: var(--udm-gold-tint-strong);
  transform: translateY(0);
}

.btn-receipt:focus-visible {
  border-color: var(--udm-gold);
  outline: 3px solid color-mix(in srgb, var(--udm-gold) 25%, transparent);
  outline-offset: 2px;
  box-shadow: none;
}

.btn-receipt-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  border-radius: 50%;
  background: var(--udm-gold);
  color: var(--udm-on-gold);
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
}

.btn-receipt.btn-sm {
  min-height: 36px;
  padding: 7px 11px;
  font-size: 12.5px;
}

.btn-receipt:disabled,
.btn-receipt.disabled {
  cursor: not-allowed;
  opacity: 0.6;
  transform: none;
}

@media (max-width: 575.98px) {
  .btn-receipt {
    min-height: 36px;
    padding: 7px 10px;
    font-size: 12.5px;
  }
}

@media print {
  .btn-receipt {
    display: none !important;
  }
}

/* ================================================================
   Dashboard card actions
   Visible secondary actions for Open Tracking and Search
   ================================================================ */
.btn-dashboard-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 34px;
  padding: 6px 11px;
  border: 1px solid var(--udm-line-strong);
  border-radius: 8px;
  background:var(--udm-surface);
  color: var(--udm-navy-text);
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none !important;
  box-shadow: 0 1px 2px rgba(11, 49, 90, 0.05);
  transition: background-color 120ms ease, border-color 120ms ease,
              color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

.btn-dashboard-action:hover {
  border-color: var(--udm-teal);
  background: var(--udm-teal-soft);
  color: var(--udm-teal-ink-dark);
  text-decoration: none !important;
  box-shadow: 0 3px 8px color-mix(in srgb, var(--udm-teal) 12%, transparent);
  transform: translateY(-1px);
}

.btn-dashboard-action:active {
  transform: translateY(0);
}

.btn-dashboard-action:focus-visible {
  border-color: var(--udm-teal);
  outline: 3px solid color-mix(in srgb, var(--udm-teal) 20%, transparent);
  outline-offset: 2px;
  box-shadow: none;
}

.btn-dashboard-action-arrow {
  display: block;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  color: inherit;
  transition: transform 120ms ease;
}

.btn-dashboard-action:hover .btn-dashboard-action-arrow {
  transform: translateX(2px);
}

@media (max-width: 575.98px) {
  .card-udm .card-udm-head:has(.btn-dashboard-action) {
    align-items: flex-start;
    flex-direction: column;
  }

  .btn-dashboard-action {
    min-height: 32px;
    padding: 6px 10px;
    font-size: 12px;
  }
}

@media print {
  .btn-dashboard-action {
    display: none !important;
  }
}

/* ================================================================
   Office selector (searchable multi-select)
   buildSearchableMultiSelect() in js/doctrack.js builds this from a
   plain <select multiple>. Without JS the native select is left alone
   and still submits, so everything here styles the enhanced version.
   ================================================================ */
.multiselect {
  border: 1px solid var(--udm-line);
  border-radius: 8px;
  background:var(--udm-surface);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(11, 49, 90, 0.05);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

/* Matches the focus treatment on .form-control / .form-select so the
   control reads as one field rather than a box of loose checkboxes. */
.multiselect:focus-within {
  border-color: var(--udm-teal);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--udm-teal) 12%, transparent);
}

.multiselect-search {
  display: block;
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--udm-line);
  border-radius: 0;
  padding: 9px 12px;
  background: var(--udm-canvas);
  color: var(--udm-ink);
  font-size: 14px;
  font-family: inherit;
}

.multiselect-search::placeholder { color: var(--udm-muted); }
.multiselect-search:focus { outline: none; background:var(--udm-surface); }

.multiselect-list {
  max-height: 232px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.multiselect-option {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 9px 12px;
  border-bottom: 1px solid var(--udm-row-line);
  color: var(--udm-ink);
  font-size: 14px;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.multiselect-option:last-child { border-bottom: 0; }
.multiselect-option:hover { background: var(--udm-surface-sunk); }

.multiselect-option input {
  flex: 0 0 15px;
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--udm-navy);
  cursor: pointer;
}

.multiselect-option input:focus-visible {
  outline: 3px solid var(--udm-gold);
  outline-offset: 2px;
}

.multiselect-option.is-selected {
  background: var(--udm-teal-soft);
  color: var(--udm-teal-ink);
  font-weight: 600;
}

.multiselect-empty {
  padding: 16px 12px;
  color: var(--udm-muted);
  font-size: 13px;
  text-align: center;
}

.multiselect-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border-top: 1px solid var(--udm-line);
  background: var(--udm-canvas);
}

.multiselect-count { color: var(--udm-muted); font-size: 12.5px; font-weight: 600; }

.multiselect-clear {
  padding: 0;
  border: 0;
  background: none;
  color: var(--udm-teal);
  font-size: 12.5px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}

.multiselect-clear:hover { text-decoration: underline; }
.multiselect-clear:focus-visible { outline: 3px solid var(--udm-gold); outline-offset: 2px; border-radius: 4px; }

.multiselect-summary {
  display: flex;
  flex-wrap: wrap;
  padding: 10px 12px 6px;
  border-top: 1px solid var(--udm-line);
}

.multiselect-summary:empty { display: none; }

.multiselect-chip-remove {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font-size: 15px;
  line-height: 1;
  font-family: inherit;
  opacity: 0.55;
  cursor: pointer;
}

.multiselect-chip-remove:hover { opacity: 1; }
.multiselect-chip-remove:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 50%; }

/* Type selections need practical targets for removing or clearing choices. */
[data-document-type-picker] .multiselect-clear,
[data-document-type-picker] .multiselect-chip-remove {
  min-width: 32px;
  min-height: 32px;
}

@media (max-width: 575.98px) {
  [data-document-type-picker] .multiselect-clear,
  [data-document-type-picker] .multiselect-chip-remove {
    min-width: 44px;
    min-height: 44px;
  }
}

.form-field--error .multiselect { border-color: var(--udm-red); }

@media print {
  .multiselect-search,
  .multiselect-footer { display: none !important; }
  .multiselect-list { max-height: none; overflow: visible; }
}

/* --- Idle sign-out warning ------------------------------------------------
   Built by doctrack.js as a native <dialog>, so focus trapping and the
   backdrop come from the browser rather than from more JavaScript. */
.session-dialog {
  /* width, not just max-width: a bare max-width leaves the box shrink-wrapped
     to its text on a narrow phone, and the two buttons then wrap awkwardly. */
  width: min(420px, calc(100vw - 32px));
  max-width: 420px; padding: 26px 28px; border: 1px solid var(--udm-line);
  border-radius: 12px; background:var(--udm-surface); color: var(--udm-ink);
  box-shadow: 0 18px 44px rgba(11, 49, 90, 0.22);
}
@media (max-width: 400px) {
  .session-dialog { padding: 20px 18px; }
  /* Below this the two buttons cannot sit side by side without truncating. */
  .session-dialog__actions { flex-direction: column; }
}
.session-dialog::backdrop { background: rgba(11, 32, 56, 0.55); }
.session-dialog h2 { margin: 0 0 10px; font-size: 20px; font-weight: 700; color: var(--udm-navy-text); }
.session-dialog p { margin: 0; font-size: 14px; color: var(--udm-slate-text); }
.session-dialog__clock {
  margin: 16px 0 20px; font-size: 34px; font-weight: 700; letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums; color: var(--udm-navy-text); text-align: center;
}
.session-dialog__actions { display: flex; flex-wrap: wrap; gap: 10px; }
.session-dialog__actions .btn { flex: 1 1 auto; }

@media print { .session-dialog { display: none !important; } }

/* --- Office badges --------------------------------------------------------
   Deliberately not shaped like a status pill. A status is a state and a pill
   is the reserved shape for one; an office is an identity, and two things that
   look alike in the same table would be read as the same kind of fact. Hence
   the square-ish chip and the solid key down its left edge.

   Colours arrive as custom properties from Office.badge, already checked for
   contrast, so nothing here has to guess whether the text will be readable. */
.office-badge {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 100%; padding: 2px 8px 2px 4px;
  border: 1px solid color-mix(in srgb, var(--office-ink, #63718a) 22%, transparent);
  border-radius: 6px;
  background: var(--office-tint, #eceff4);
  color: var(--office-ink, #55637a);
  font-size: 12px; font-weight: 700; letter-spacing: 0.02em; line-height: 1.5;
  vertical-align: baseline; white-space: nowrap;
}
.office-badge-key {
  width: 3px; align-self: stretch; min-height: 13px; flex: 0 0 3px;
  border-radius: 2px; background: var(--office-base, #63718a);
}
.office-badge-code { overflow: hidden; text-overflow: ellipsis; }
.office-badge-name {
  overflow: hidden; font-weight: 500; opacity: 0.85; text-overflow: ellipsis; white-space: nowrap;
}
a .office-badge, .office-badge a { text-decoration: none; }

.office-badge-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.office-badge-more {
  color: var(--udm-muted); font-size: 11.5px; font-weight: 600; white-space: nowrap;
}

/* The swatch picker is square; the full-width form-control look makes a
   400px-wide colour well, which reads as a broken text box. */
.form-control-colour {
  width: 56px; height: 38px; padding: 3px; cursor: pointer;
}

/* A badge inside a link or a heading should not shout over it. */
h1 .office-badge, h2 .office-badge { font-size: 12.5px; }

@media print {
  /* Backgrounds are commonly dropped when printing, and a mono printer flattens
     the key to grey. The code is text, so the badge still says which office it
     is — the border keeps it looking deliberate rather than broken. */
  .office-badge {
    border-color: #8793a3; background: transparent !important; color: #16202c !important;
  }
  .office-badge-key { background: #8793a3 !important; }
}

/* --- Text boxes -----------------------------------------------------------
   Vertical resize only. A textarea is resizable in both directions by default,
   and dragging one wider pushed it straight out of its card and gave the page
   a horizontal scrollbar — the same failure as an unbreakable filename, just
   user-driven. Height stays adjustable, which is the useful half. */
.form-control,
textarea.form-control { max-width: 100%; }
textarea.form-control { resize: vertical; min-height: 64px; }

.char-count {
  margin-top: 4px; color: var(--udm-muted); font-size: 12px;
  font-variant-numeric: tabular-nums; text-align: right;
}
.char-count.is-near { color: var(--udm-gold-ink); }
.char-count.is-full { color: var(--udm-red); font-weight: 600; }
@media print { .char-count { display: none !important; } }

/* --- Folded history -------------------------------------------------------
   Native <details>, so it works with the keyboard, is announced properly, and
   needs no JavaScript to open. doctrack.js closes it on load when the list is
   long; the markup ships open so a blocked script leaves the whole history
   readable rather than hidden. */
.fold { margin: 0 0 14px; }
.fold[open] > summary { margin-bottom: 12px; }

/* A paper record has to carry the whole history whatever the screen was
   showing. doctrack.js also reopens these on beforeprint, for browsers that
   will not lay out a closed <details>. */
@media print {
  .fold > summary { display: none !important; }
  .fold > *:not(summary) { display: block !important; }
}

/* --- Long unbroken text ---------------------------------------------------
   Document titles are taken from the uploaded filename, so
   "Purchase_Request_Laboratory_Consumables_2025.pdf" arrives as one unbreakable
   token. With nothing to break it, it ran past the edge of its card and gave
   the whole page a horizontal scrollbar on a phone. Applied to the containers
   that hold text people typed or named, rather than globally, so table column
   sizing is left alone. */
.page-head h1,
.page-head .sub,
.doc-tile h3,
.doc-tile .meta,
.file-chip-name,
.file-chip-meta,
.timeline .t-title,
.timeline .t-detail,
.timeline .t-meta,
.result-item h3,
.smart-folder,
.tag-chip,
.card-udm-head h2 { overflow-wrap: anywhere; }

.file-chip-name { font-size: 14px; }
.file-chip-meta { color: var(--udm-muted); font-size: 12px; }
.timeline .t-received { color: var(--udm-green); }
.timeline .t-awaiting { color: var(--udm-gold-ink); }

/* Key/value tables read as stacked pairs on a narrow screen. Two columns in
   320px gave the value four characters a line. */
@media (max-width: 575.98px) {
  .table-stacked tr { display: block; padding: 7px 0; border-bottom: 1px solid var(--udm-line); }
  .table-stacked tr:last-child { border-bottom: 0; }
  .table-stacked th,
  .table-stacked td { display: block; width: auto !important; padding: 0 !important; border: 0 !important; }
  .table-stacked th { color: var(--udm-muted); font-size: 12px; font-weight: 400; }
  .table-stacked td { font-size: 14px; }
}

/* ================================================================
   Dashboard: combined breakdown, write-up, and printing
   ================================================================ */
.dashboard-page-head { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; flex-wrap:wrap; }
.dashboard-head-actions { display:flex; gap:8px; flex-wrap:wrap; }

/* One bar, one segment per slice. Segment widths are the same percentages the
   list prints beside each label, so the picture and the numbers cannot drift. */
.breakdown-bar { display:flex; height:16px; margin-bottom:16px; border-radius:8px; overflow:hidden; background:var(--chart-track); }
.breakdown-seg { display:block; height:100%; }
.breakdown-swatch { width:10px; height:10px; border-radius:3px; flex:0 0 10px; }

/* Colour is never the only carrier: every slice is named in the list, and the
   status palette is reserved, so these reuse it rather than inventing a second
   vocabulary for the same states. */
/* Keyed to the slice names in views.BREAKDOWN_COLOURS. There is no --overdue
   segment any more: overdue lies across the live stages instead of beside them,
   so it is a stat card rather than a slice. */
.breakdown-seg--pending_receipt { background:var(--status-pending); }
.breakdown-seg--received { background:var(--status-received); }
.breakdown-seg--in_process { background:var(--status-process); }
.breakdown-seg--pending_upload { background:var(--status-upload); }
.breakdown-seg--historical { background:var(--chart-historical); }
.breakdown-seg--completed { background:var(--status-completed); }

.breakdown-list { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:2px 18px; }
.breakdown-item { display:grid; grid-template-columns:10px minmax(0,1fr) auto auto; align-items:center; gap:9px; padding:7px 4px; border-radius:6px; color:var(--udm-navy-text); font-size:13px; text-decoration:none; }
.breakdown-item:hover,.breakdown-item:focus { background:var(--udm-canvas); }
.breakdown-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.breakdown-percent { min-width:44px; color:var(--udm-muted); text-align:right; font-size:12px; }

.dashboard-writeup { margin-top:18px; padding-top:14px; border-top:1px solid var(--udm-line); }
.dashboard-writeup h3 { margin:0 0 6px; font-size:14px; color:var(--udm-navy-text); }
.dashboard-writeup p { margin:0 0 6px; color:var(--udm-slate-text); font-size:13px; line-height:1.55; }
.dashboard-writeup p:last-child { margin-bottom:0; }
/* The write-up used to close the "All documents" card, where the rule above it
   separated it from the chart. It is now a card of its own beneath the two
   rings, so the border and the offset would draw a line under nothing. */
.dashboard-writeup--standalone { margin-top:0; padding-top:0; border-top:0; }

/* No .dashboard-print-header any more. It gave Ctrl+P a letterheaded,
   timestamped sheet that looked official and was never recorded, since the
   audit marker belongs to a document and this page is not one. What is left is
   the page size and the rings' fills — a plain printout that prints what is on
   screen rather than a document pretending to be one.

   The .dashboard-writeup print rule went too: the panel was removed with the
   wireframe rebuild and its figures in 3cc3226, so there is nothing left to
   keep off a page break. FIXME: its screen rules above (.dashboard-writeup and
   --standalone) are dead for the same reason and outlive this comment.

   .report-print-header, the shared base class, stays — Reports and the memo
   print page both use it. */
@media print {
  /* Segment fills and swatches are background paint; without this they print blank. */
  .breakdown-seg,.breakdown-swatch,.breakdown-bar,.desk-block-title { -webkit-print-color-adjust:exact; print-color-adjust:exact; }
  .breakdown-item { break-inside:avoid; }
}

/* ================================================================
   Dashboard analytics panels
   Two chart types the reports toolkit did not already have — the ring and
   the trend line — plus the overdue banner and the memo sheet. Everything
   else on the dashboard reuses .report-bar / .column-chart / .status-row /
   .report-metric as they stand.

   Every colour here is a --udm-* or --chart-* token. No panel introduces a
   palette of its own.
   ================================================================ */

/* ------------------------------------------------------------ Tracking queues */
/* Two blocks in one card, and they were reading as one list with a line through
   it: same grey, same weight, same size, so the half that needs doing looked
   like the half that already happened.

   The separation is carried by the titles rather than by a heavier rule. A
   stronger line would divide the card more loudly without saying which side to
   read first, which is the only thing the reader actually needs to know here. */
.desk-block--secondary { margin-top:10px; }
/* The tracking queue panel's queue chips: the Tracking page's pills, so a queue looks
   the same wherever it can be picked, each with its count. They wrap rather than
   scroll: seven pills and a Clear fit two rows on a phone, and a scrolling row
   hides the queues nobody sees. */
.desk-chips { display:flex; flex-wrap:wrap; gap:8px; padding:14px 20px 12px; }
.desk-attention-label { align-self:center; color:var(--udm-muted); font-size:13px; font-weight:600; }
/* Keep direction above its stages in every tracking surface. */
.direction-filters { margin:0 0 16px; }
.direction-filters--desk { margin:0; padding:14px 20px 0; }
.direction-filter-groups { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:12px; }
.direction-filter-group { min-width:0; padding:12px; border:1px solid var(--udm-line); border-radius:10px; background:var(--udm-surface); }
.direction-filter-heading { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:10px; color:var(--udm-navy-text); }
.direction-filter-stages { display:flex; flex-wrap:wrap; gap:8px; }
.direction-filter-stages .pill-toggle, .direction-filter-heading .pill-toggle { min-height:38px; }
.direction-filter-note { margin:8px 0 0; color:var(--udm-muted); font-size:13px; }
@media (max-width:991.98px) { .direction-filter-groups { grid-template-columns:1fr; } }
@media print { .direction-filters { display:none; } }
.desk-chip-count { margin-left:6px; padding:1px 7px; border-radius:999px; background:var(--udm-canvas); color:var(--udm-navy-text); font-size:11.5px; }
/* Opaque, so its contrast is what it looks like: white on the next navy up. */
.pill-toggle.is-active .desk-chip-count { background:var(--udm-selected-ink); color:var(--udm-selected-bg); }
.desk-chip-clear { font-weight:500; }
.desk-block-count { margin-left:6px; font-weight:600; letter-spacing:0; text-transform:none; }
.action-centre-head { flex-wrap:wrap; gap:10px 16px; }
.action-centre-head > .btn { margin-left:auto; flex-shrink:0; }
.desk-block-caption { margin:0; padding:8px 20px; color:var(--udm-slate-text); font-size:14px; line-height:1.5; }
.desk-update-time { margin-top:3px; color:var(--udm-muted); font-size:13px; }
/* Sits at the same weight as the card heading it lives under rather than at
   browser-default h3 size, which next to a 16px h2 would read as the larger of
   the two. Uppercase and tracked so it reads as a divider, not a second title
   competing with the h2 above it. */
.desk-block-title {
  margin:0; padding:9px 20px;
  font-size:11.5px; font-weight:700;
  letter-spacing:.11em; text-transform:uppercase;
}
/* A colour each, as a band rather than as coloured lettering: a band is picked
   up before anything is read, which is the point — these two tables look
   identical from a distance and only one of them is work.

   Both use the soft-background / ink-text pairing the status pills already use
   (.pill-pending, .pill-process), so the card introduces no colour the page has
   not already taught. The darker ink of each pair, not the plain one: gold-ink
   on gold-soft is 4.34:1, which misses AA for text this size, and these run at
   11.5px. The dark variants clear 7:1 in both themes.

   Gold for what needs doing and teal for what has already happened — the same
   two hues those states wear on the pills in these very rows. Not red: red is
   overdue, which is a property of individual rows here and not of the block,
   and some of the rows waiting for action are not late at all. */
.desk-block--primary .desk-block-title {
  background:var(--udm-gold-soft); color:var(--udm-gold-ink-dark);
}
.desk-block--secondary .desk-block-title {
  background:var(--udm-teal-soft); color:var(--udm-teal-ink-dark);
}
/* The tables carry their own top padding through .card-udm-body.p-0, so the
   title would otherwise sit hard against the first row. */
.desk-block-title + .card-udm-body { padding-top:10px; }

/* ------------------------------------------ fixed-width panel cells */
/* The two Tracking queues tables and the Repository list beside them sit in a
   two-column row, and every one of them is a list of documents whose subject or
   title is written by whoever filed it. Left to size themselves, one long
   subject set the width of a column and therefore of the card, and the card
   beside it got whatever was left — so the same dashboard looked different
   every day depending on what had been filed.

   The cap has to reach the block inside the cell, not only the cell: a
   `max-width` on a `<td>` in an auto-layout table is advisory and the browser
   overrides it whenever the content wants more, which is exactly the case this
   is here to handle. It is a custom property so the two cannot drift apart —
   the `<td>` takes it as the hint browsers may honour, the block as the rule
   they must.

   Two lines rather than one. One line ellipsised at this width cuts most real
   subjects at about four words, which is not enough to tell two memos apart;
   two is enough to recognise a document you are looking for, and the full text
   is on the title attribute for the case where it is not. */
.desk-cell { --desk-cell-cap: 300px; max-width: var(--desk-cell-cap); }
.desk-cell--wide { --desk-cell-cap: 420px; }
.desk-cell-title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  max-width: var(--desk-cell-cap, 100%);
  overflow: hidden; overflow-wrap: anywhere;
}
/* Fallback for engines without the line clamp: one ellipsised line beats a
   subject that runs to six. */
@supports not (-webkit-line-clamp: 2) {
  .desk-cell-title { display: block; white-space: nowrap; text-overflow: ellipsis; }
}

/* Newest in the Document Repository. A list rather than a table, so the cap is
   the row's own width; the fixed minimum height is what keeps five rows the
   same height whether the titles are short or long, which is what stops this
   card and the Tracking queues disagreeing about how tall their shared row is. */
.newest-row { min-height: 62px; }
.newest-title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; overflow-wrap: anywhere;
  max-width: 100%; font-weight: 600;
}
@supports not (-webkit-line-clamp: 2) {
  .newest-title { display: block; white-space: nowrap; text-overflow: ellipsis; }
}
.newest-meta { font-size: 12.5px; }

@media (max-width: 1199.98px) {
  /* Below xl the two panels stack, so each has the full width and a 300px cap
     is no longer earning anything — it would only cut subjects there is room
     for. One property to raise, and the cell and its block move together. */
  .desk-cell { --desk-cell-cap: 480px; }
  .desk-cell--wide { --desk-cell-cap: 620px; }
}

/* --------------------------------------------------------- scope picker */
.dashboard-scope { display:flex; align-items:center; gap:8px; }
.dashboard-scope-label { color:var(--udm-muted); font-size:12.5px; font-weight:700; white-space:nowrap; }
.dashboard-scope .form-select { min-width:210px; border-color:var(--udm-line); color:var(--udm-navy-text); font-size:13px; font-weight:600; }
.dashboard-scope .form-select:focus { border-color:var(--udm-teal); box-shadow:0 0 0 .18rem color-mix(in srgb, var(--udm-teal) 18%, transparent); }

/* -------------------------------------------------------- overdue banner */
/* The left rule is the same device .stat-card.red uses, at the width a full
   card needs. Red is reserved for this on the dashboard: it is the one panel
   describing something that has gone wrong. */
.dashboard-alert { border-left:5px solid var(--udm-red); }
.dashboard-alert .card-udm-head h2 { color:var(--udm-red-ink); }
.alert-figures { display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px 30px; padding-bottom:14px; margin-bottom:4px; border-bottom:1px solid var(--chart-grid); }
.alert-figure-value { color:var(--udm-navy-text); font-size:23px; font-weight:800; line-height:1.1; letter-spacing:-.02em; }
.alert-figure-label { margin-top:2px; color:var(--udm-muted); font-size:12px; }
/* The lead figure is the count itself — the one number somebody acts on. */
.alert-figure--lead .alert-figure-value { color:var(--udm-red); font-size:38px; }
.alert-figure--lead .alert-figure-label { color:var(--udm-red-ink); font-weight:700; }
.overdue-office-list { margin-top:4px; }
.overdue-oldest { color:var(--udm-muted); font-size:12px; text-align:right; white-space:nowrap; }
/* Four columns rather than the three .report-series-item--wide gives, because
   these rows carry the age of the oldest item as well as the count. */
.overdue-office-list .report-series-item--wide { grid-template-columns:minmax(0,1fr) minmax(0,1.1fr) 44px 116px; }

/* ------------------------------------------------------------------ ring */
.donut-layout { position:relative; display:flex; align-items:center; gap:26px; flex-wrap:wrap; }
/* Inline SVG, one path per slice, geometry computed server-side so the ring
   always closes at 100%. The paths are annular sectors, so the hole is really
   empty; the disc behind the figure stays for the figure's legibility. */
.donut { position:relative; flex:0 0 190px; width:190px; height:190px; border-radius:50%; }
.donut-ring { position:absolute; inset:0; display:block; width:100%; height:100%; overflow:visible; }
/* Pointing at a slice brings it forward by setting the others back, rather than
   by moving it: the ring's geometry stays exactly the numbers it encodes. The
   legend row for the same slice lights up with it, so the reader sees which
   line of figures the slice is. */
.donut-slice { cursor:pointer; transition:opacity 120ms ease; }
.donut-layout.has-active-slice .donut-slice:not(.is-active) { opacity:.4; }
.donut-layout .breakdown-item.is-active { background:var(--udm-canvas); }
/* The value leads and the label follows; the key is a short stroke of the
   slice's colour, and the text stays in text ink. */
.donut-tooltip { position:absolute; z-index:5; display:flex; align-items:baseline; gap:7px; max-width:240px; padding:6px 10px; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface); box-shadow:0 6px 18px rgba(6,28,52,.16); color:var(--udm-muted); font-size:12px; line-height:1.3; pointer-events:none; }
.donut-tooltip[hidden] { display:none; }
.donut-tooltip-key { flex:0 0 12px; align-self:center; height:3px; border-radius:2px; }
.donut-tooltip strong { color:var(--udm-navy-text); font-size:14px; }
.donut-hole { position:absolute; inset:46px; display:flex; flex-direction:column; align-items:center; justify-content:center; border-radius:50%; background:var(--udm-surface); text-align:center; }
.donut-hole-value { color:var(--udm-navy-text); font-size:26px; font-weight:800; letter-spacing:-.02em; line-height:1.1; }
/* .06em, not .1em: "DOCUMENTS" at .1em is 76px, which touched the rim of the
   78px hole a 150px ring has. */
.donut-hole-label { color:var(--udm-muted); font-size:10.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; }
.donut-legend { flex:1 1 260px; min-width:0; display:grid; gap:1px; }

/* Incoming and Outgoing side by side, sized by the card rather than the
   viewport for the reason the column charts are (the card is half-width, and
   narrowest, on a desktop: 395px inside the card at 1200px, 435px at 1280px).
   Each ring stacks its legend beneath it, and the two stack on each other only
   when the card cannot hold two 150px rings with their legends, below 360px.
   Stacked on a desktop, the Tracking card ran twice the height of the
   Repository card it shares a row with. */
/* The grid is on .ring-pair-rings, inside the container: a container query
   styles what is in a container, never the container itself. */
.ring-pair { container:ring-pair / inline-size; }
.ring-pair--split .ring-pair-rings { display:grid; grid-template-columns:1fr; gap:22px; }
@container ring-pair (min-width:360px) {
  .ring-pair--split .ring-pair-rings { grid-template-columns:repeat(2, minmax(0,1fr)); gap:18px; }
  .ring-pair--split .breakdown-item { gap:6px; font-size:12.5px; }
  .ring-pair--split .breakdown-percent { min-width:34px; }
}
.ring-pair-item { min-width:0; }
.ring-title { display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 8px; margin:0 0 12px; color:var(--udm-navy-text); font-size:13px; font-weight:800; letter-spacing:.02em; }
.ring-title span { color:var(--udm-muted); font-size:12px; font-weight:500; letter-spacing:0; }
.ring-pair--split .donut-layout { flex-direction:column; align-items:stretch; gap:14px; }
.ring-pair--split .donut { flex:0 0 auto; width:150px; height:150px; margin:0 auto; }
.ring-pair--split .donut-hole { inset:36px; }
.ring-pair--split .donut-hole-value { font-size:21px; }
.ring-pair--split .donut-hole-label { font-size:9.5px; }
.ring-pair--split .donut-legend { flex:0 0 auto; }
/* Two options, one pressed. The pressed one is filled rather than merely
   underlined so it reads at a glance which view the rings are in. */
.segmented { display:inline-flex; flex:0 0 auto; padding:2px; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-canvas); }
.segmented-option { padding:4px 12px; border-radius:6px; color:var(--udm-muted); font-size:12.5px; font-weight:700; text-decoration:none; }
.segmented-option:hover,.segmented-option:focus-visible { color:var(--udm-navy-text); }
.segmented-option.is-active { background:var(--udm-surface); box-shadow:0 1px 2px rgba(6,28,52,.12); color:var(--udm-navy-text); }
.ring-note { margin:16px 0 0; padding-top:9px; border-top:1px solid var(--chart-grid); color:var(--udm-muted); font-size:12.5px; }
.ring-note[hidden],.ring-aside[hidden] { display:none; }
.ring-aside { display:grid; grid-template-columns:10px minmax(0,1fr) auto; align-items:center; gap:9px; margin-top:16px; padding:9px 4px 0; border-top:1px solid var(--chart-grid); color:var(--udm-muted); font-size:13px; text-decoration:none; }
.ring-aside strong { color:var(--udm-navy-text); }
.ring-aside:hover,.ring-aside:focus { color:var(--udm-navy-text); }
.tracking-pending-upload { display:grid; grid-template-columns:10px minmax(0,1fr) auto; align-items:center; gap:12px; margin-top:16px; padding:10px 14px; min-height:44px; border:1px solid var(--status-upload); border-radius:8px; background:var(--status-upload-soft); color:var(--status-upload-ink); font-size:14px; font-weight:600; text-decoration:none; }
.tracking-pending-upload[hidden] { display:none; }
.tracking-pending-upload .breakdown-swatch { background:var(--status-upload); }
.tracking-pending-upload strong { font-size:22px; }
.tracking-pending-upload small { display:block; margin-top:2px; font-size:12px; font-weight:400; line-height:1.5; }
.tracking-pending-upload:hover { color:var(--status-upload-ink); border-color:var(--status-upload-ink); }
.tracking-pending-upload:focus-visible { outline:2px solid var(--status-upload-ink); outline-offset:3px; }

/* ------------------------------------------------------------ trend line */
/* Chart and summary side by side. They stacked while this panel sat in a
   half-width column, where two columns inside one gave neither enough room; the
   panel spans the page again. The wrap is kept so a narrow viewport still
   stacks them rather than crushing both. */
.trend-layout { display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap; }
/* Grows faster than the summary so the extra width goes to the plot, which is
   the part that gets harder to read as the series crowd together. */
.trend-chart { flex:3 1 420px; min-width:0; }
.trend-legend { margin-bottom:12px; }
/* Fixed viewBox, fluid box. Height comes from the viewBox's own ratio rather
   than a fixed pixel height, so the plot scales uniformly and the data points
   stay circular — stretching it to fill a set height would flatten them into
   ovals. vector-effect="non-scaling-stroke" then holds the line weight steady
   across the range of widths this column takes.

   Keep this in step with TREND_WIDTH/TREND_HEIGHT in views.py — a mismatch
   letterboxes the plot inside its own card without erroring anywhere, which is
   why a test asserts the two agree. */
.trend-svg { display:block; width:100%; height:auto; aspect-ratio:640/170; }
/* The plot and its y-axis. The SVG keeps the whole width it is given (it has no
   gutter of its own); the gutter is here, and the month labels under it are
   padded by the same amount so each stays under its point. */
.trend-plot { --trend-gutter:26px; position:relative; padding-left:var(--trend-gutter); }
.trend-axis-values { position:absolute; top:0; bottom:0; left:0; width:calc(var(--trend-gutter) - 6px); }
.trend-axis-values span { position:absolute; right:0; transform:translateY(-50%); color:var(--udm-muted); font-size:10.5px; line-height:1; }
.trend-plot + .trend-axis-labels { padding-left:var(--trend-gutter); }
.trend-summary-none { color:var(--udm-muted) !important; font-weight:600 !important; font-size:13px !important; }

/* ---------------------------------------------------- the line, and its hover

   The lines are revealed from the left once, by a clip on their group that
   opens to the plot's full width, then the dots arrive. Not a stroke dash: with
   non-scaling-stroke the browser lays a dash out in screen pixels, so a dash one
   "pathLength" long stopped short on a stretched chart and left each line cut
   off part way. Readers who ask for less motion get the finished chart at once. */
.trend-line { fill:none; stroke-width:2.25; stroke-linejoin:round; stroke-linecap:round; }
.trend-lines { clip-path:inset(0 100% 0 0); animation:trend-reveal 900ms cubic-bezier(.3,.7,.3,1) 80ms forwards; }
@keyframes trend-reveal { to { clip-path:inset(0 0 0 0); } }

.trend-key { gap:8px; font-weight:500; }
.trend-key strong { color:var(--udm-navy-text); font-weight:700; }
.trend-key-line { position:relative; display:inline-flex; align-items:center; justify-content:center; flex:0 0 20px; width:20px; height:10px; color:var(--dot); }
.trend-key-line::before { content:""; position:absolute; left:0; right:0; top:4px; height:2px; background:currentColor; }
.trend-marker { position:relative; display:block; width:10px; height:10px; fill:none; stroke:var(--dot); stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; overflow:visible; }

/* The hover layer sits exactly over the SVG: past the axis gutter, the same
   height. Each month's target is a full-height column, so a reader aims at a
   month, not at a 6px dot. */
.trend-hover { position:absolute; top:0; bottom:0; left:var(--trend-gutter); right:0; outline:none; border-radius:6px; }
.trend-hover:focus-visible { box-shadow:0 0 0 2px var(--udm-teal); }
.trend-hit { position:absolute; top:0; bottom:0; cursor:crosshair; }
.trend-cross { position:absolute; top:var(--plot-top); bottom:var(--plot-bottom); left:50%; width:0;
  border-left:1px solid var(--udm-line-strong); opacity:0; transition:opacity 140ms ease; }
/* Persistent markers have one ten-pixel footprint, including on hover. The
   transparent circle, diamond and cross retain their measured centres and
   expose portions of all three colours even when the measurements coincide. */
.trend-dot { position:absolute; left:50%; width:10px; height:10px; margin:-5px 0 0 -5px; pointer-events:none; }
.trend-tip { position:absolute; top:var(--plot-top); z-index:6; min-width:200px; max-width:260px; padding:9px 11px 10px;
  border:1px solid var(--udm-line); border-radius:9px; background:var(--udm-surface);
  box-shadow:0 10px 24px rgba(6,28,52,.16); pointer-events:none;
  opacity:0; visibility:hidden; transform:translateY(6px);
  transition:opacity 150ms ease, transform 170ms cubic-bezier(.2,.8,.2,1), visibility 0s; }
.trend-hit--right .trend-tip { left:calc(50% + 12px); }
.trend-hit--left .trend-tip { right:calc(50% + 12px); }
.trend-tip-month { margin-bottom:6px; color:var(--udm-muted); font-size:10.5px; font-weight:700; letter-spacing:.09em; text-transform:uppercase; }
.trend-tip-row { display:grid; grid-template-columns:14px auto; column-gap:8px; align-items:baseline; padding:2px 0; }
.trend-tip-row i { grid-row:span 3; align-self:center; width:14px; height:3px; border-radius:2px; }
.dashboard-context { padding:16px; background:var(--udm-surface); border:1px solid var(--udm-line); border-radius:12px; }
.dashboard-metric-guide { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr)); gap:16px; margin-top:16px; }
.dashboard-metric-guide dt { margin-bottom:4px; }
.dashboard-metric-guide dd { margin:0; line-height:1.6; }
.page-help-panel { --bs-offcanvas-width:420px; background:var(--udm-surface); color:var(--udm-ink); border-left:1px solid var(--udm-line); }
.page-help-panel .offcanvas-header { border-bottom:1px solid var(--udm-line); }
.page-help-panel .offcanvas-body { padding:24px; }
.page-help-panel .form-select { min-height:44px; }
.page-help-section h3 { font-size:18px; margin-bottom:20px; }
.page-help-section p,.page-help-section dd { font-size:14px; line-height:1.7; color:var(--udm-slate-text); }
.page-help-panel details > summary { display:none; }
.page-help-panel .dashboard-context { padding:0; border:0; background:none; }
.page-help-panel .dashboard-metric-guide { display:block; }
.page-help-panel .dashboard-metric-guide > div { margin-bottom:20px; }
.page-help-panel .chart-note { margin-top:0; }
.page-help-info,.page-help-launch { display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box; height:36px; min-width:36px; padding:7px; flex:0 0 auto; border:1px solid var(--udm-line); border-radius:7px; color:var(--udm-slate-text); background:var(--udm-surface); font-family:inherit; font-size:14px; font-weight:500; line-height:1; vertical-align:middle; }
.page-help-icon { display:block; width:20px; height:20px; flex:0 0 20px; }
.page-help-launch { gap:7px; padding-inline:10px; white-space:nowrap; }
.card-udm .card-udm-head.has-page-help { position:relative; padding-right:60px; }
.card-udm-head.has-page-help > .page-help-info { position:absolute; top:10px; right:14px; }
.page-help-info:hover,.page-help-launch:hover { background:var(--udm-slate-soft); color:var(--udm-ink); border-color:var(--udm-line-strong); }
.page-help-info:focus-visible,.page-help-launch:focus-visible { outline:2px solid var(--udm-navy-text); outline-offset:2px; }
.page-help-launch[hidden],.page-help-section[hidden] { display:none; }
@media (pointer:coarse) {
  .page-help-info,.page-help-launch { min-width:44px; height:44px; }
  .card-udm .card-udm-head.has-page-help { padding-right:68px; min-height:64px; }
}
.trend-tip-row strong { color:var(--udm-navy-text); font-size:13.5px; font-weight:800; line-height:1.2; }
.trend-tip-row span { grid-column:2; color:var(--udm-muted); font-size:12px; line-height:1.4; }
.trend-tip-empty { display:block; color:var(--udm-muted); font-size:12.5px; }

.trend-hover:not(.is-dismissed):not(:has(.is-active)) .trend-hit:hover .trend-cross,.trend-hit.is-active .trend-cross { opacity:1; }
.trend-hover:not(.is-dismissed):not(:has(.is-active)) .trend-hit:hover .trend-tip,.trend-hit.is-active .trend-tip {
  opacity:1; visibility:visible; transform:translateY(0); transition-delay:0s; }
/* While one month is shown, the lines step back so its dots read first. */
.trend-plot:has(.trend-hit:hover) .trend-line,.trend-plot:has(.trend-hit.is-active) .trend-line { opacity:.55; transition:opacity 150ms ease; }

@media (prefers-reduced-motion: reduce) {
  .trend-lines { animation:none; clip-path:none; }
  .trend-dot,.trend-tip,.trend-cross { transition:none; }
}
@media print {
  .trend-lines { animation:none; clip-path:none; }
  .trend-line { opacity:1 !important; }
  .trend-hover { display:block; pointer-events:none; box-shadow:none; }
  .trend-tip,.trend-cross { display:none; }
}
.trend-summary-figures .report-metric > span small { display:block; font-size:11px; font-weight:500; }
.trend-grid { stroke:var(--chart-grid); stroke-width:1; }
.trend-axis { stroke:var(--udm-line); stroke-width:1; }
/* The month labels sit outside the SVG so they are real text at a real size —
   inside the scaled viewBox an 11px label would render at about seven. No left
   inset: the plot has no gutter, having previously reserved one for y-axis
   labels that were never drawn. */
.trend-axis-labels { display:flex; }
.trend-axis-labels span { flex:1 1 0; min-width:0; color:var(--udm-muted); font-size:11px; text-align:center; }
.trend-summary { flex:1 1 250px; min-width:0; padding:12px 14px; border:1px solid var(--udm-line); border-radius:10px; }
.trend-summary-head { margin-bottom:6px; color:var(--udm-muted); font-size:11px; font-weight:700; letter-spacing:.11em; text-transform:uppercase; }
/* auto-fit, so the figures sit in one column beside the chart and spread into
   two when the layout wraps and the summary has the full width to itself.
   min(190px,100%) rather than a bare 190px, because a bare minimum is a floor
   the track will not go below: once the panel is narrower than it — a magnified
   screen being the usual way to get there — the column stayed 190px wide and
   its contents hung over the figure beside them. Capping the minimum at the
   container's own width lets the track shrink with it instead. */
.trend-summary-figures { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(190px,100%),1fr)); gap:0 18px; }
/* The border between rows belongs to a single column of figures; across a grid
   it draws a rule through the middle of the group. flex-wrap is the last
   resort, past the point where label and figure fit on one line: the figure
   drops below its label rather than the two printing over each other. */
.trend-summary-figures .report-metric { border-bottom:0; padding:6px 0; min-width:0; flex-wrap:wrap; gap:0 12px; }
/* A flex item will not shrink below its own content unless it is told it may. */
.trend-summary-figures .report-metric > span,
.trend-summary-figures .report-metric > strong { min-width:0; }
.trend-summary .meter-head { margin-top:10px; padding-top:10px; border-top:1px solid var(--chart-grid); }

/* The tracking side owns the entire turnaround panel. Put its figures below
   the plot so neither is squeezed by a second column inside the dashboard. */
.dashboard-turnaround .trend-layout { display:grid; grid-template-columns:minmax(0,1fr); gap:20px; }
.dashboard-turnaround { scroll-margin-top:90px; }
.dashboard-turnaround-filters { display:flex; flex-wrap:wrap; align-items:flex-end; gap:12px; padding-bottom:14px; border-bottom:1px solid var(--udm-line); }
.dashboard-turnaround-filters > div { flex:1 1 190px; min-width:0; }
.dashboard-turnaround-filters label { display:block; margin-bottom:4px; color:var(--udm-slate-text); font-size:12px; font-weight:600; }
.dashboard-turnaround-filters .form-select { width:100%; }
.dashboard-turnaround-filters .dashboard-turnaround-filter-actions { flex:0 1 auto; display:flex; gap:8px; }
.dashboard-turnaround-period { margin:10px 0 16px; color:var(--udm-muted); font-size:12px; }
.dashboard-turnaround-statistics { margin-top:16px; padding-top:14px; border-top:1px solid var(--udm-line); }
.dashboard-turnaround-statistics .dashboard-turnaround-summary { margin-top:16px; }
.dashboard-turnaround-summary { padding:0; border:0; border-radius:0; }
.dashboard-turnaround-summary .trend-summary-head { margin-bottom:8px; font-size:12px; color:var(--udm-navy-text); }
.dashboard-turnaround-guide { margin:0 0 16px; color:var(--udm-muted); font-size:13px; line-height:1.6; }
.dashboard-turnaround-stages { display:grid; grid-template-columns:minmax(0,1fr); gap:10px; }
.report-turnaround-stages { container:dashboard-side / inline-size; }
.report-turnaround-stages .dashboard-turnaround-stage { border-bottom:1px solid var(--udm-line); }
.dashboard-turnaround-stage { min-width:0; padding:14px 16px; border:1px solid var(--udm-line); border-radius:8px; background:var(--udm-surface); }
.dashboard-turnaround-stage--receipt { --stage-colour:var(--status-pending); --stage-tint:var(--status-pending-soft); --stage-ink:var(--status-pending-ink); }
.dashboard-turnaround-stage--processing { --stage-colour:var(--status-process); --stage-tint:var(--status-process-soft); --stage-ink:var(--status-process-ink); }
.dashboard-turnaround-stage--lifetime { --stage-colour:var(--status-completed); --stage-tint:var(--status-completed-soft); --stage-ink:var(--status-completed-ink); }
.dashboard-turnaround-stage { border-left:4px solid var(--stage-colour); background:linear-gradient(var(--stage-tint),var(--stage-tint)) top / 100% 46px no-repeat,var(--udm-surface); }
.dashboard-turnaround-stage .dashboard-turnaround-stage-head h3 { color:var(--stage-ink); }
.dashboard-turnaround-stage .dashboard-turnaround-primary { color:var(--stage-ink); }
.dashboard-turnaround-stage-head { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:6px 12px; }
.dashboard-turnaround-stage h3 { margin:0; color:var(--udm-navy-text); font-size:16px; font-weight:700; }
.dashboard-turnaround-samples { color:var(--udm-slate-text); font-size:14px; white-space:nowrap; }
.dashboard-turnaround-measure { margin:3px 0; color:var(--udm-slate-text); font-size:14px; }
.turnaround-period-note { margin:0 0 12px; color:var(--udm-slate-text); font-size:13px; line-height:1.5; }
.turnaround-time-guide { margin:0 0 12px; padding:10px 12px; border-left:3px solid var(--udm-teal); background:var(--udm-surface); color:var(--udm-slate-text); font-size:13px; line-height:1.6; }
.turnaround-time-guide p { margin:0; }
.turnaround-time-guide p + p { margin-top:5px; }
.turnaround-time-guide strong { color:var(--udm-navy-text); }
.turnaround-time-guide .turnaround-rounding-note { font-size:12px; }
.turnaround-calculation-control { grid-column:1 / -1; margin-top:10px; padding-top:8px; border-top:1px solid var(--udm-line); }
.turnaround-equation { padding:10px 12px; background:var(--udm-surface); border:1px solid var(--udm-line); border-radius:6px; color:var(--udm-navy-text); font-size:15px; line-height:1.7; overflow-wrap:anywhere; }
.trend-tip-row .trend-tip-equation { padding-top:3px; color:var(--udm-slate-text); border-top:1px solid var(--udm-line); }
.trend-tip-formula-key { margin:0 0 7px; color:var(--udm-slate-text); font-size:11px; line-height:1.45; }
.turnaround-sample-basis { margin:0 0 10px; color:var(--udm-slate-text); font-size:13px; line-height:1.5; }
.turnaround-zero-note { margin:8px 0 0; color:var(--udm-slate-text); font-size:12.5px; line-height:1.5; }
.turnaround-waiting-note { margin:12px 0 0; padding-top:10px; border-top:1px solid var(--udm-line); color:var(--udm-slate-text); font-size:13px; line-height:1.5; }
.turnaround-waiting-note > span { display:block; margin-top:3px; }
.turnaround-table-value { min-width:180px; }
.turnaround-table-value strong { display:block; font-size:14px; }
.turnaround-table-value > span,.turnaround-table-count { display:block; color:var(--udm-slate-text); font-size:12.5px; line-height:1.5; }
.report-metric .turnaround-sample-basis { margin:3px 0 0; }
.dashboard-turnaround-averages { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px 16px; margin:0; }
.dashboard-turnaround-averages dt { margin-bottom:3px; color:var(--udm-slate-text); font-size:14px; font-weight:500; }
.dashboard-turnaround-averages dd { margin:0; line-height:1.35; }
.dashboard-turnaround-primary { color:var(--udm-navy-text); font-size:20px; font-weight:750; }
.dashboard-turnaround-calendar { color:var(--udm-slate-text); font-size:16px; font-weight:600; }
.dashboard-turnaround-extremes { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px 20px; margin:12px 0 0; padding-top:10px; border-top:1px solid var(--udm-line); }
.dashboard-turnaround-extremes > div { min-width:0; }
.dashboard-turnaround-extremes dt { margin-bottom:4px; color:var(--udm-slate-text); font-size:14px; font-weight:600; }
.dashboard-turnaround-extremes dd { display:flex; flex-direction:column; align-items:flex-start; gap:3px; margin:0; min-width:0; }
.dashboard-turnaround-extremes strong { color:var(--udm-navy-text); font-size:16px; line-height:1.4; }
.dashboard-turnaround-extremes a { display:inline-flex; align-items:center; min-height:28px; max-width:100%; overflow-wrap:anywhere; font-size:14px; font-weight:600; line-height:1.5; text-underline-offset:3px; }
.dashboard-turnaround-extremes dd > span { color:var(--udm-slate-text); font-size:14px; line-height:1.5; }
.dashboard-turnaround-calculation { margin:10px 0 0; padding-left:10px; border-left:2px solid var(--udm-line-strong); color:var(--udm-muted); font-size:12px; line-height:1.6; }
.dashboard-turnaround-empty { margin:0; color:var(--udm-muted); font-size:14px; }
.dashboard-turnaround-on-time { margin-top:16px; padding:14px 16px; border:1px solid var(--udm-line); border-radius:10px; }
.dashboard-turnaround-on-time .meter-head { margin:0 0 8px; padding:0; border:0; }
.dashboard-turnaround-on-time .meter-head > span { color:var(--udm-navy-text); font-weight:600; }
.dashboard-turnaround-on-time .meter-head > strong { font-size:22px; }
.dashboard-turnaround-on-time .meter-foot { margin:8px 0 0; line-height:1.5; }
@container dashboard-side (min-width:620px) {
  .dashboard-turnaround-stage { display:grid; grid-template-columns:minmax(160px,.65fr) minmax(0,2fr); column-gap:20px; }
  .dashboard-turnaround-stage-head,.dashboard-turnaround-measure,.dashboard-turnaround-stage > .turnaround-sample-basis,.dashboard-turnaround-stage > .turnaround-zero-note,.dashboard-turnaround-stage > .dashboard-turnaround-calculation,.dashboard-turnaround-stage > .dashboard-turnaround-empty { grid-column:1 / -1; }
  .dashboard-turnaround-averages { grid-template-columns:minmax(0,1fr); }
  .dashboard-turnaround-averages--only { grid-column:1 / -1; grid-template-columns:repeat(2,minmax(0,1fr)); }
  .dashboard-turnaround-extremes { margin:0; padding:0 0 0 20px; border-top:0; border-left:1px solid var(--udm-line); }
}
@media (pointer:coarse) {
  .dashboard-turnaround-extremes a { min-height:44px; }
}
@container dashboard-side (max-width:400px) {
  .dashboard-turnaround-extremes { grid-template-columns:minmax(0,1fr); }
  .dashboard-turnaround-extremes > div + div { border-top:1px solid var(--udm-line); padding-top:10px; }
}
@container dashboard-side (max-width:400px) {
  .dashboard-turnaround-stage { padding:14px; }
  .dashboard-turnaround-averages { grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .dashboard-turnaround-primary { font-size:18px; }
  .dashboard-turnaround-calendar { font-size:16px; }
  .dashboard-turnaround-extremes { grid-template-columns:minmax(0,1fr); }
}
@media print {
  .dashboard-turnaround-statistics::details-content { content-visibility:visible; }
  .dashboard-turnaround-statistics > summary { display:none; }
  .dashboard-turnaround-stage { break-inside:avoid; }
}

/* ------------------------------------------------------- dashboard sides
   Document Tracking on the left, Document Repository on the right, each under
   its own heading and in its own colour, so a figure's module is visible before
   its title is read: teal for what is moving, the Completed green for what has
   been filed. The accent runs along the heading and across the top of every
   card on that side. Below xl the sides stack, tracking first. */
.dashboard-side { display:flex; flex-direction:column; min-width:0; }
.dashboard-side--tracking { --side-accent:var(--udm-teal); }
.dashboard-side--repository { --side-accent:var(--status-completed); }
/* Title and link on one line, the caption under both at full width, so the
   narrow repository side's heading is as tall as the tracking side's and the
   first cards on each side start level. */
.dashboard-side-head {
  display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:4px 14px;
  margin-bottom:14px; padding-bottom:10px; border-bottom:3px solid var(--side-accent);
}
.dashboard-side-head .dashboard-side-caption { grid-column:1 / -1; }
.dashboard-side-title { color:var(--side-accent); font-size:13px; font-weight:800; letter-spacing:.11em; text-transform:uppercase; }
.dashboard-side-caption { margin-top:2px; color:var(--udm-muted); font-size:13px; }
.dashboard-side-stack { display:flex; flex-direction:column; gap:1.5rem; min-width:0; container:dashboard-side / inline-size; }
.dashboard-side-stack > .row { margin-bottom:0 !important; }
/* height:auto over Bootstrap's .h-100: in a stretched column, 100% was the
   whole side, and the first card grew as tall as every card below it. */
.dashboard-side-stack > .card-udm { height:auto !important; border-top:3px solid var(--side-accent); }
/* The repository side is a third of the page on a wide screen. Its office bars
   had a 190px label, a count and a share beside them, which left the bar about
   40px: there the name and figures take one line and the bar the next. */
@container dashboard-side (max-width: 520px) {
  .report-series-item--wide.report-series-item--share { grid-template-columns:minmax(0,1fr) 44px 40px; row-gap:5px; }
  .report-series-item--wide.report-series-item--share > .report-bar { grid-column:1 / -1; grid-row:2; }
}
@media print {
  .dashboard-side-stack > .card-udm { border-top-width:1px; }
}

/* ------------------------------------------------------------- uploads */
.uploads-leader { display:flex; align-items:center; gap:11px; flex-wrap:wrap; padding:10px 13px; margin-bottom:12px; border:1px solid var(--udm-gold-tint-strong); border-radius:10px; background:var(--udm-gold-tint); color:var(--udm-gold-ink-dark); font-size:13px; }
.uploads-leader-tag { padding:2px 9px; border-radius:999px; background:var(--udm-gold); color:var(--udm-on-gold); font-size:10.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; white-space:nowrap; }

/* ---------------------------------------------------------------- memo */
.memo-sheet { padding:22px 24px; border:1px solid var(--udm-line); border-radius:8px; }
.memo-meta { display:flex; flex-wrap:wrap; gap:8px 26px; padding-bottom:13px; margin-bottom:15px; border-bottom:1px solid var(--chart-grid); color:var(--udm-muted); font-size:12.5px; }
.memo-meta strong { color:var(--udm-navy-text); }
.memo-sheet p { margin:0 0 11px; color:var(--udm-ink); font-size:14px; line-height:1.65; }
.memo-sheet p:last-child { margin-bottom:0; }
.memo-footnote { flex:1 1 auto; color:var(--udm-muted); font-size:11.5px; text-align:left; }
/* The memo on screen. Label left, figure right, the same shape the print page
   sets in fixed units — see .memo-print-* near the report print rules. */
.memo-section + .memo-section { margin-top:17px; padding-top:15px; border-top:1px solid var(--chart-grid); }
.memo-section h3 { margin:0 0 9px; color:var(--udm-muted); font-size:11px; font-weight:700; letter-spacing:.11em; text-transform:uppercase; }
.memo-lines { display:grid; grid-template-columns:minmax(0,auto) minmax(0,1fr); gap:5px 18px; margin:0; font-size:13.5px; }
.memo-lines dt { color:var(--udm-slate-text); font-weight:500; }
.memo-lines dd { margin:0; color:var(--udm-ink); font-weight:600; }
/* A statement has no label, so it spans both columns rather than sitting in
   the value column with an empty space where a label would be. */
.memo-line-statement { grid-column:1 / -1; font-weight:500 !important; }

@media (max-width:991.98px) {
  .donut { flex-basis:150px; width:150px; height:150px; }
  .donut-hole { inset:36px; }
  .donut-hole-value { font-size:21px; }
  .alert-figure--lead .alert-figure-value { font-size:31px; }
  .overdue-office-list .report-series-item--wide { grid-template-columns:minmax(0,1fr) minmax(0,1fr) 38px 92px; }
  .dashboard-scope .form-select { min-width:150px; }
}

/* The dashboard's print rules lived here and are gone with the button that
   needed them. They existed to make the *screen* printable — keeping the donut
   and trend panels from splitting across a page break — and the dashboard is
   no longer something the app offers to print. The memo is, and it prints from
   templates/core/dashboard_memo_print.html with rules of its own.

   The paragraph they also carried, `.modal,.modal-backdrop{display:none}`, has
   moved up to the shared print block: hiding a dialog when printing is right
   on every page, not just this one, and it is the rule that used to make Print
   inside the memo print the dashboard behind it. */

/* ---------------------------------------------------- repository folders */
/* Equal columns across the full width. The count comes from
   REPOSITORY_FOLDER_COLUMNS via a custom property on the element, so changing
   it is a settings change rather than a template edit. auto-fill with a minimum
   keeps it from producing unreadably narrow drawers on a small screen: the
   configured count is a ceiling, not a promise. */
.folder-grid {
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(max(160px,calc(100%/var(--folder-columns,4) - 12px)),1fr));
  gap:12px;
}
.folder-tile {
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  min-height:58px; padding:13px 15px;
  border:1px solid var(--udm-line); border-radius:10px;
  background:var(--udm-surface); color:var(--udm-navy-text); font-size:13.5px; text-decoration:none;
}
.folder-tile:hover,.folder-tile:focus { border-color:var(--udm-teal); text-decoration:none; }
.folder-tile.active { border-color:var(--udm-teal); background:var(--udm-teal-soft); color:var(--udm-teal-ink); font-weight:600; }
.folder-tile.active:hover,.folder-tile.active:focus {
  background:var(--udm-teal-soft); color:var(--udm-teal-ink);
}
/* Two lines before it clips, so an office name is legible rather than cut to a
   prefix that reads the same as its neighbour's. */
.folder-tile-name { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.folder-tile-count { flex:0 0 auto; color:var(--udm-muted); font-size:12.5px; }
.folder-tile.active .folder-tile-count { color:inherit; }

/* ================================================================
   Dark theme
   ================================================================
   Applied inside the app only. The sign-in and lockout pages replace the body
   block wholesale and carry their own full-bleed navy artwork; they are also
   the one screen somebody sees before the system knows who they are, so there
   is no stored preference to read. `.login-wrap` pins its tokens back below.

   Implemented by re-pointing the existing tokens rather than as a second
   stylesheet. Every rule above already draws from them, so a component added
   later is themed without anybody remembering to theme it — which is how a
   parallel dark stylesheet always eventually fails. Introducing --udm-surface
   is what made this possible: the raised surface was #fff literal in thirty-one
   places, so there was nothing to re-point.

   One selector, [data-theme="dark"], and no prefers-color-scheme block:
   doctrack.js resolves the operating-system preference and writes the
   attribute. The alternative is duplicating a forty-line palette into a media
   query, and two copies drift. The cost is that dark mode needs JavaScript,
   which is the right trade — it is a preference, not content, and the light
   theme is fully usable without it.

   Values are re-tuned, never reused. The light palette was validated for 3:1
   contrast against white, and the same hexes fail against a dark ground: the
   soft tints go near-black, and the gold and green inks disappear into them. A
   status pill nobody can read is worse than no colour at all. */
:root[data-theme="dark"] {
  --udm-canvas: #111b15;
  --udm-surface: #1a2920;
  --udm-navy: #174a37;
  --udm-navy-text: var(--udm-ink);
  --udm-navy-700: #103326;
  --udm-navy-600: #286b45;
  --udm-gold: #e0b757;
  --udm-teal: #8ccc9f;
  --udm-green: #8ccc9f;
  --udm-red: #e2695f;
  --udm-red-600: #ee8a80;
  --chart-alert: #ff8a7a;
  --chart-alert-soft: #c0554b;
  --udm-gold-soft: #3a2f14;
  --udm-teal-soft: #233e2c;
  --udm-green-soft: #233e2c;
  --udm-red-soft: #3a1e1b;
  --udm-slate-soft: #27352b;
  --udm-gold-ink: #f0d391;
  --udm-gold-ink-dark: #f6e2b4;
  --udm-gold-ink-hover: #fbeed0;
  --udm-gold-border: #8a6a12;
  --udm-gold-tint: #241d0d;
  --udm-gold-tint-strong: #4a3c19;
  --udm-teal-ink: #b6e1bd;
  --udm-teal-ink-dark: #ceeacf;
  --udm-green-ink: #b6e1bd;
  --udm-red-ink: #f3ada6;
  --udm-slate-ink: #bdcdbd;
  --udm-ink: #e7eddf;
  --udm-label-ink: #cfddcc;
  --udm-slate-text: #bdcdbd;
  --udm-muted: #adbeaa;
  --udm-line: #37493a;
  --udm-line-strong: #566b55;
  --udm-line-soft: #425744;
  --chart-one: #4aa9d4;
  --chart-two: #d8ae4e;
  --chart-three: #5cb37e;
  --chart-track: #304233;
  --chart-grid: #304233;
  --status-draft: #8e9bb0;
  --status-draft-soft: #2c3136;
  --status-draft-ink: #c7d6e8;
  --status-pending: #e3ad4b;
  --status-pending-soft: #3d2d14;
  --status-pending-ink: #f0cf9d;
  --status-received: #7fb6ee;
  --status-received-soft: #1e3246;
  --status-received-ink: #b7d8fb;
  --status-process: #c876c1;
  --status-process-soft: #3d283b;
  --status-process-ink: #f1c3ec;
  --status-upload: #9cd7da;
  --status-upload-soft: #0d3739;
  --status-upload-ink: #98e4e8;
  --status-completed: #62946c;
  --status-completed-soft: #1f3724;
  --status-completed-ink: #b2e3bb;
  --status-overdue: #ff8a7a;
  --status-overdue-soft: #442724;
  --status-overdue-ink: #fac6bf;
  --chart-created: #ceeacf;
  --chart-historical: #bdcdbd;
  --chart-received-part: #c9e2fb;
  --chart-neutral: #bdcdbd;
  --udm-navy-soft: #253d2c;
  --udm-primary: #286b45;
  --udm-primary-hover: #317951;
  --udm-primary-ink: #ffffff;
  --udm-selected-bg: var(--udm-teal);
  --udm-selected-bg-hover: #afe0b7;
  --udm-selected-ink: var(--udm-canvas);
  --udm-on-accent: var(--udm-canvas);
  --udm-on-gold: var(--udm-canvas);
  --udm-row-line: #304233;
  --udm-surface-sunk: #142219;
  --udm-track: #304233;
  --udm-highlight: #4a3c19;
  --udm-note-bg: #241f12;
  --udm-note-ink: #f0e2c0;
  --shadow-card: none;
  --udm-focus: #8ccc9f;
  --udm-link-rgb: 140, 204, 159;
  --udm-link-hover-rgb: 182, 225, 189;
  color-scheme: dark;
}

/* Bootstrap paints its own form controls and tables from its variables, which
   are not ours. Re-pointed here rather than restyled, so the controls keep
   Bootstrap's behaviour and only change colour. */
body {
  --bs-body-bg: var(--udm-canvas);
  --bs-body-color: var(--udm-ink);
  --bs-border-color: var(--udm-line);
  --bs-border-color-translucent: var(--udm-line);
  --bs-secondary-color: var(--udm-muted);
  --bs-secondary-bg: var(--udm-surface);
  --bs-tertiary-bg: var(--udm-slate-soft);
  --bs-emphasis-color: var(--udm-ink);
  --bs-heading-color: var(--udm-ink);
  /* Bootstrap's link blue was #0d6efd, 3.6:1 on the card: tabs and link
     buttons read in it. Links take the theme's teal instead. */
  --bs-link-color: var(--udm-teal);
  --bs-link-color-rgb: var(--udm-link-rgb);
  --bs-link-hover-color: var(--udm-teal-ink);
  --bs-link-hover-color-rgb: var(--udm-link-hover-rgb);
  /* The message banners, in the palette's own washes and inks. */
  --bs-success-bg-subtle: var(--udm-green-soft);
  --bs-success-border-subtle: #2c5a45;
  --bs-success-text-emphasis: var(--udm-green-ink);
  --bs-info-bg-subtle: var(--udm-teal-soft);
  --bs-info-border-subtle: #22535d;
  --bs-info-text-emphasis: var(--udm-teal-ink);
  --bs-warning-bg-subtle: var(--udm-gold-soft);
  --bs-warning-border-subtle: var(--udm-gold-border);
  --bs-warning-text-emphasis: var(--udm-gold-ink);
  --bs-danger-bg-subtle: var(--udm-red-soft);
  --bs-danger-border-subtle: #6b2f29;
  --bs-danger-text-emphasis: var(--udm-red-ink);
  --bs-light-bg-subtle: var(--udm-surface);
  --bs-light-border-subtle: var(--udm-line);
  --bs-light-text-emphasis: var(--udm-ink);
  background: var(--udm-canvas);
  color: var(--udm-ink);
}
/* background-color, not the background shorthand: the shorthand also reset
   background-image, which is where a select draws its arrow, so every dropdown
   in the dark theme had lost its arrow and read as a text box. */
:root[data-theme="dark"] .form-control,
:root[data-theme="dark"] .form-select,
:root[data-theme="dark"] textarea {
  background-color: var(--udm-canvas);
  border-color: var(--udm-line);
  color: var(--udm-ink);
}
:root[data-theme="dark"] .form-control::placeholder { color: var(--udm-muted); }
:root[data-theme="dark"] .form-control:focus,
:root[data-theme="dark"] .form-select:focus {
  background-color: var(--udm-canvas);
  color: var(--udm-ink);
}
:root[data-theme="dark"] .dropdown-menu {
  background: var(--udm-surface);
  border-color: var(--udm-line);
  color: var(--udm-ink);
}
:root[data-theme="dark"] .dropdown-item { color: var(--udm-ink); }
:root[data-theme="dark"] .dropdown-item:hover,
:root[data-theme="dark"] .dropdown-item:focus { background: var(--udm-canvas); color: var(--udm-ink); }
:root[data-theme="dark"] .table-udm th { color: var(--udm-muted); }
:root[data-theme="dark"] .table-udm tbody tr:hover { background: var(--udm-canvas); }

/* Paper stays paper. The sign-in and lockout screens (their own full-bleed
   composition, shown before anybody has a preference), the printed memo and the
   routing slip take the whole light palette from the :root rule at the top of
   this file, which also names them; here they only say so to the browser, for
   scrollbars and form controls. Bootstrap is told in the templates, with
   data-bs-theme="light" on the same elements. */
:root[data-theme="dark"] :is(.login-wrap, .memo-print, .routing-slip) { color-scheme: light; }

/* Paper is white whatever the screen is. Printing a dark theme wastes toner and
   comes out unreadable on the panels that rely on tinted fills, so print always
   uses the light palette — the tokens are simply reset for the print context.
   Every token the dark block sets is reset here (tests/test_dark_mode.py holds
   the two lists together), or print gets the lightened brand hues on white. */
@media print {
  :root[data-theme="dark"] {
    color-scheme: light;
    --udm-navy: #174a37;
    --udm-navy-text: var(--udm-navy);
    --udm-navy-700: #103326;
    --udm-navy-600: #286b45;
    --udm-gold: #d5b86a;
    --udm-gold-soft: #f4ecd8;
    --udm-teal: #286b45;
    --udm-teal-soft: #e5f1e7;
    --udm-green: #4d824e;
    --udm-green-soft: #e5f1e7;
    --udm-red: #b44b4b;
    --udm-red-600: #8f3838;
    --udm-red-soft: #fbe7e5;
    --udm-canvas: #ffffff;
    --udm-surface: #ffffff;
    --udm-line: #d6d5c4;
    --udm-line-strong: #afbda8;
    --udm-line-soft: #dce0d0;
    --udm-label-ink: #365146;
    --udm-ink: #183126;
    --udm-muted: #576b5c;
    --udm-slate-text: #4f6358;
    --udm-slate-soft: #e7ebdd;
    --udm-slate-ink: #53685b;
    --udm-green-ink: #1f5a42;
    --udm-gold-ink: #725616;
    --udm-gold-ink-dark: #59420f;
    --udm-gold-ink-hover: #4f3a05;
    --udm-gold-border: #b9923e;
    --udm-gold-tint: #f5efdc;
    --udm-gold-tint-strong: #f1dfad;
    --udm-teal-ink: #1f5a42;
    --udm-teal-ink-dark: #174a37;
    --udm-red-ink: #8f3838;
    --udm-navy-soft: #e1e9db;
    --udm-primary: #286b45;
    --udm-primary-hover: #1d5034;
    --udm-primary-ink: #ffffff;
    --udm-selected-bg: #286b45;
    --udm-selected-bg-hover: #1d5034;
    --udm-selected-ink: #ffffff;
    --udm-on-accent: #ffffff;
    --udm-on-gold: #241f1b;
    --udm-row-line: #e4e3d5;
    --udm-surface-sunk: #ece8da;
    --udm-track: #e2e7d8;
    --udm-highlight: #f7efd9;
    --udm-note-bg: #f3edda;
    --udm-note-ink: #5a4a20;
    --bs-link-color: var(--udm-teal);
    --bs-link-color-rgb: var(--udm-link-rgb);
    --bs-link-hover-color: var(--udm-teal-ink);
    --bs-link-hover-color-rgb: var(--udm-link-hover-rgb);
    --chart-one: #0a6e9a;
    --chart-two: #b58c24;
    --chart-three: #2f7d4f;
    --chart-alert: #b4342b;
    --chart-alert-soft: #cf6a5e;
    --chart-track: #e2e7d8;
    --chart-grid: #e4e3d5;
    --status-draft: #6b778b;
    --status-draft-soft: #ebf1f8;
    --status-draft-ink: #424e5e;
    --status-pending: #bc7700;
    --status-pending-soft: #fceeda;
    --status-pending-ink: #65470f;
    --status-received: #2d557d;
    --status-received-soft: #e5f2ff;
    --status-received-ink: #194f81;
    --status-process: #ab6da6;
    --status-process-soft: #fce9fa;
    --status-process-ink: #6b3767;
    --status-upload: #389695;
    --status-upload-soft: #daf7f8;
    --status-upload-ink: #1b575a;
    --status-completed: #1d6835;
    --status-completed-soft: #e3f6e6;
    --status-completed-ink: #195c2e;
    --status-overdue: #b4342b;
    --status-overdue-soft: #ffebe8;
    --status-overdue-ink: #7a342e;
    --chart-created: #174a37;
    --chart-historical: #7d889a;
    --chart-received-part: #8fb3d6;
    --chart-neutral: #55637a;
    --sidebar-width: 236px;
    --radius: 4px;
    --shadow-card: none;
    --udm-focus: #286b45;
    --udm-link-rgb: 40, 107, 69;
    --udm-link-hover-rgb: 31, 90, 66;
  }
}

/* Office badges: each office's own pair for the dark card, computed server-side
   like the light one (apps.core.utils.badge_palette_dark), so an office colour
   an administrator picks is legible here too rather than a pale chip on a dark
   page. Screen only: the pair arrives inline on each badge rather than through
   the tokens, so the print reset above cannot reach it, and on paper the dark
   wash is dropped while its lightened ink is kept — pale text on white. */
@media screen {
  :root[data-theme="dark"] .office-badge {
    border-color: color-mix(in srgb, var(--office-ink-dark, #a8b6c8) 28%, transparent);
    background: var(--office-tint-dark, var(--udm-slate-soft));
    color: var(--office-ink-dark, var(--udm-slate-ink));
  }
}

/* ------------------------------------------------------------ the control */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex: 0 0 38px; padding: 0;
  border: 1px solid var(--udm-line); border-radius: 8px;
  background: var(--udm-surface); color: var(--udm-navy-text);
  font-size: 15px; line-height: 1;
}
.theme-toggle:hover, .theme-toggle:focus { border-color: var(--udm-teal); color: var(--udm-teal); }
:root[data-theme="dark"] .theme-toggle { color: var(--udm-gold); }
/* One button, two glyphs: the icon shows what pressing it will switch *to*,
   which is what the label announces too. */
.theme-toggle .theme-icon-dark { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-icon-light { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-icon-dark { display: inline; }

/* ================================================================
   2026 design decision panel direction
   Instrument panel + Green Ledger + Human-centered stewardship

   The selected direction is intentionally expressed as a shared layer. The
   Django templates already share these primitives, so one token pass keeps
   Dashboard, Tracking, Repository, Reports, Search, and Administration in the
   same visual language without changing their data contracts.
   ================================================================ */


body {
  background: var(--udm-canvas);
  color: var(--udm-ink);
  font-family: "DM Sans", "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
  font-size: 15px;
}

h1, h2, h3, h4, h5, .display-face {
  font-family: "Space Grotesk", "DM Sans", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0;
}

a { color: var(--udm-teal); }
a:hover { color: var(--udm-teal-ink-dark); }

.app-shell { background: var(--udm-canvas); }
.app-sidebar {
  width: var(--sidebar-width);
  background: #174a37;
  border-right: 1px solid #285d43;
  box-shadow: none;
}
.sidebar-brand-icon { filter: none; }
.wordmark--light .udm { color: #d5b86a; }
.wordmark--light .doctrack { color: #f7fbf3; }
.app-sidebar .nav-section {
  color: #9fbb9f;
  letter-spacing: .14em;
  font-size: 10px;
}
.app-sidebar .nav-item {
  border-radius: 2px;
  color: #bfd1bc;
  min-height: 40px;
  transition: background-color 120ms ease-out, color 120ms ease-out, border-color 120ms ease-out;
}
.app-sidebar .nav-item .dot {
  width: 7px;
  height: 7px;
  border-radius: 1px;
  border: 1px solid currentColor;
  background: transparent;
}
.app-sidebar .nav-item:hover,
.app-sidebar .nav-item:focus-visible,
.app-sidebar .nav-item.active:hover,
.app-sidebar .nav-item.active:focus-visible,
.app-sidebar .nav-item.active {
  background: #28563d;
  color: #ffffff;
  border-left-color: #d5b86a;
}
.app-sidebar .nav-item.active .dot { background: #d5b86a; border-color: #d5b86a; }
.app-sidebar .nav-item--child { color: #a8c4ad; }
.sidebar-office { border-color: #426b50; background: #1a4330; border-radius: 2px; }

.app-topbar {
  min-height: 68px;
  background: var(--udm-surface);
  border-bottom: 1px solid var(--udm-line);
  box-shadow: none;
}
.topbar-search input,
.topbar-search .form-control {
  background: var(--udm-surface-sunk);
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 4px;
}
.topbar-search input:focus { border-bottom-color: var(--udm-teal); box-shadow: none; }
.app-content { max-width: none; padding: 32px clamp(20px, 3vw, 48px) 56px; }
.app-footer { background: var(--udm-canvas); color: var(--udm-muted); border-top-color: var(--udm-line); }

.page-head {
  border-bottom: 1px solid var(--udm-line);
  padding-bottom: 24px;
  margin-bottom: 28px;
}
.page-head h1 { font-weight: 800; }
.eyebrow { color: var(--udm-green-ink); letter-spacing: .14em; font-weight: 800; }
.sub, .form-text, .text-muted { color: var(--udm-muted) !important; }

.card-udm,
.stat-card,
.search-panel,
.admin-panel,
.detail-panel,
.folder-tile,
.table-wrap,
.filter-bar,
.dashboard-context {
  border: 1px solid var(--udm-line);
  border-radius: 4px;
  box-shadow: none;
  background: var(--udm-surface);
}
.card-udm-head,
.card-udm-body { border-color: var(--udm-line); }
.card-udm-head { background: var(--udm-surface); }
.stat-card:hover,
.folder-tile:hover { transform: none; border-color: var(--udm-teal); box-shadow: none; }
.stat-card .value { font-weight: 800; }
.dashboard-side-head { border-bottom: 2px solid var(--udm-navy); }
.dashboard-side-title { color: var(--udm-navy-text); font-weight: 800; }

.btn,
.btn-udm,
.btn-udm-outline,
.btn-dashboard-action,
.page-help-launch,
.theme-toggle {
  border-radius: 4px;
  min-height: 40px;
  font-weight: 700;
  transition: background-color 120ms ease-out, border-color 120ms ease-out, color 120ms ease-out;
}
.btn-udm,
.btn-dashboard-action { background: var(--udm-primary); border-color: var(--udm-primary); color: var(--udm-primary-ink); }
.btn-udm:hover,
.btn-dashboard-action:hover { background: var(--udm-primary-hover); border-color: var(--udm-primary-hover); color: var(--udm-primary-ink); }
.btn-udm-outline { background: transparent; border-color: var(--udm-primary); color: var(--udm-navy-text); }
.btn-udm-outline:hover { background: var(--udm-teal-soft); border-color: var(--udm-primary); color: var(--udm-teal-ink); }
.segmented { border-radius: 4px; border: 1px solid var(--udm-line-strong); padding: 3px; background: var(--udm-surface-sunk); }
.segmented-option { border-radius: 2px; }
.segmented-option.is-active { background: var(--udm-selected-bg); color: var(--udm-selected-ink); }

.form-control,
.form-select,
textarea,
input[type="date"],
input[type="datetime-local"],
input[type="month"],
input[type="time"] {
  background-color: var(--udm-surface-sunk);
  border: 1px solid transparent;
  border-radius: 4px;
  min-height: 40px;
  color: var(--udm-ink);
}
.form-control:focus,
.form-select:focus,
textarea:focus,
input:focus {
  background-color: var(--udm-surface);
  border-color: var(--udm-teal);
  box-shadow: 0 0 0 2px var(--udm-surface), 0 0 0 4px var(--udm-focus);
}
.filter-bar { background: var(--udm-surface-sunk); }

.table-udm { border-color: var(--udm-line); }
.table-udm thead th { background: var(--udm-slate-soft); color: var(--udm-label-ink); border-bottom: 2px solid var(--udm-line-strong); }
.table-udm tbody tr:hover { background: var(--udm-surface-sunk); }
.table-udm td, .table-udm th { border-color: var(--udm-row-line); }

.status-pill, .badge, .office-badge, .overdue-tag { border-radius: 999px; }
.subtabs { border-bottom-color: var(--udm-line); }
.subtab { border-radius: 2px 2px 0 0; }
.subtab.is-active { color: var(--udm-navy-text); border-bottom-color: var(--udm-gold); }

:focus-visible {
  outline: 2px solid var(--udm-surface);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--udm-focus);
}

@media (max-width: 767.98px) {
  .app-content { padding: 24px 16px 40px; }
  .page-head { margin-bottom: 22px; }
  .dashboard-sides { display: flex; flex-direction: column; }
  .dashboard-side--tracking { order: 1; }
  .dashboard-side--repository { order: 2; }
  .dashboard-head-actions { align-items: stretch; }
  .dashboard-head-actions > * { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* Dashboard workload cards: metric first, explanation second, action visible. */
.stat-card {
  position: relative;
  min-height: 150px;
  padding-right: 34px;
}
.stat-card .label {
  color: var(--udm-label-ink);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .02em;
}
.stat-card .hint { max-width: 25ch; }
.stat-card-arrow,
.repository-pending-filing-arrow {
  color: var(--udm-teal);
  font-size: 20px;
  line-height: 1;
  transition: transform 120ms ease-out, color 120ms ease-out;
}
.stat-card-arrow {
  position: absolute;
  right: 16px;
  bottom: 16px;
}
.stat-card:hover .stat-card-arrow,
.repository-pending-filing:hover .repository-pending-filing-arrow { color: var(--udm-teal-ink); transform: translateX(3px); }
.stat-card.red { background: var(--udm-red-soft); border-color: var(--udm-red); }
.stat-card.red .label,
.stat-card.red .value { color: var(--udm-red-ink); }
.stat-card.is-disabled { opacity: .7; }

.repository-pending-filing {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 12px 16px;
  border: 1px solid var(--udm-gold-border);
  border-left: 4px solid var(--udm-gold);
  border-radius: 4px;
  background: var(--udm-gold-tint);
  color: var(--udm-ink);
  text-decoration: none;
}
.repository-pending-filing:hover { color: var(--udm-ink); border-color: var(--udm-gold-ink); text-decoration: none; }
.repository-pending-filing-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--udm-gold-soft);
  color: var(--udm-gold-ink);
  font-weight: 800;
}
.repository-pending-filing > span:nth-child(2) { display: grid; gap: 2px; }
.repository-pending-filing > span:nth-child(2) > span { color: var(--udm-muted); font-size: 12px; }
.repository-pending-filing-value { color: var(--udm-gold-ink); font-size: 20px; }

@media (max-width: 575.98px) {
  .repository-pending-filing { grid-template-columns: auto minmax(0, 1fr) auto; }
  .repository-pending-filing-arrow { display: none; }
  .repository-pending-filing-value { grid-column: 2; grid-row: 2; justify-self: start; }
}

/* The selected Green Ledger direction still supports the existing dark-mode
   preference. These rules override the light-only surface choices above so
   newly added dashboard components do not flash back to paper colours. */
:root[data-theme="dark"] .app-topbar,
:root[data-theme="dark"] .app-footer {
  background: var(--udm-surface);
  color: var(--udm-ink);
}
:root[data-theme="dark"] .stat-card,
:root[data-theme="dark"] .card-udm,
:root[data-theme="dark"] .dashboard-context,
:root[data-theme="dark"] .repository-pending-filing {
  background: var(--udm-surface);
  color: var(--udm-ink);
}
:root[data-theme="dark"] .stat-card.red {
  background: var(--udm-red-soft);
  border-color: var(--udm-red);
}
:root[data-theme="dark"] .stat-card.red .label,
:root[data-theme="dark"] .stat-card.red .value,
:root[data-theme="dark"] .stat-card.red .hint {
  color: var(--udm-red-ink);
}
:root[data-theme="dark"] .table-udm thead th {
  background: var(--udm-slate-soft);
  color: var(--udm-label-ink);
  border-color: var(--udm-line-strong);
}
:root[data-theme="dark"] .table-udm tbody tr:hover { background: var(--udm-surface-sunk); }
:root[data-theme="dark"] .repository-pending-filing {
  background: var(--udm-gold-tint);
  border-color: var(--udm-gold-border);
}
:root[data-theme="dark"] .repository-pending-filing > span:nth-child(2) > span { color: var(--udm-muted); }
:root[data-theme="dark"] .repository-pending-filing-icon { background: var(--udm-gold-soft); color: var(--udm-gold-ink); }

/* Sidebar hierarchy and office identity. */
.app-sidebar { display: flex; flex-direction: column; }
.app-sidebar nav { flex: 0 0 auto; }
.app-sidebar .nav-section {
  margin-top: 24px;
  padding: 0 12px 8px;
  color: #9fbb9f;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .15em;
  line-height: 1;
  text-transform: uppercase;
}
.nav-section--first { margin-top: 22px; }
.app-sidebar .nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 9px 12px;
}
.app-sidebar .nav-item > span:last-child { min-width: 0; }
.app-sidebar .nav-icon {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  border: 1px solid rgba(213, 184, 106, .42);
  border-radius: 3px;
  color: #d5b86a;
  font-size: 13px;
  line-height: 1;
}
.app-sidebar .nav-item .dot { display: none; }
.app-sidebar .nav-item--child {
  margin-left: 22px;
  min-height: 36px;
  padding-top: 6px;
  padding-bottom: 6px;
  border-left: 1px solid #426b50;
  border-radius: 0 2px 2px 0;
  color: #a8c4ad;
  font-size: 12px;
}
.app-sidebar .nav-item--child .nav-icon { width: 18px; height: 18px; flex-basis: 18px; font-size: 11px; }
.app-sidebar .nav-item.active .nav-icon,
.app-sidebar .nav-item:hover .nav-icon,
.app-sidebar .nav-item:focus-visible .nav-icon { background: #d5b86a; border-color: #d5b86a; color: #174a37; }
.sidebar-office-wrap { margin-top: auto; }
.sidebar-office {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 10px 8px;
  padding: 10px;
}
.sidebar-office-mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border: 1px solid #d5b86a;
  border-radius: 4px;
  color: #d5b86a;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .04em;
}
.sidebar-office-name,
.sidebar-office-role { display: block; }

/* Sign-in refresh: same institutional palette, with a clearer first-visit
   hierarchy and a compact workflow cue instead of extra decoration. */
.login-wrap { background: var(--udm-canvas); }
.login-art {
  background: #174a37;
  border-right: 1px solid #285d43;
}
.login-art h1 { max-width: 13ch; font-weight: 800; letter-spacing: 0; }
.login-art .rule { width: 72px; height: 3px; border-radius: 0; }
.login-kicker {
  display: block;
  margin-bottom: 14px;
  color: #d5b86a;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.login-workflow {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  max-width: 42ch;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}
.login-workflow li { display: grid; gap: 3px; padding-top: 9px; border-top: 1px solid rgba(213, 184, 106, .58); }
.login-workflow strong { color: #fff; font-size: 12px; }
.login-workflow span { color: rgba(255, 255, 255, .68); font-size: 11px; line-height: 1.3; }
.login-form { background: var(--udm-surface); }
.login-form .inner { max-width: 390px; padding: 8px 0; }
.login-form-heading { margin-bottom: 24px; }
.login-form-heading h2 { font-weight: 800; }
.login-security-note { border-radius: 0 4px 4px 0; background: var(--udm-gold-soft); }
.login-form .btn-udm { min-height: 44px; }

@media (max-width: 767.98px) {
  .login-workflow { max-width: none; }
  .login-form .inner { padding: 0; }
}

/* Sign-in is a paper surface by design, even when the authenticated app is
   remembered in dark mode. Keep its text and action tokens paired with that
   light surface rather than inheriting dark app tokens through the root. */

.login-form { color: #183126; }
.login-form h2 { color: #183126; }
.login-form .btn-udm { background: #286b45; border-color: #286b45; color: #ffffff; }
.login-form .btn-udm:hover { background: #1d5034; border-color: #1d5034; color: #ffffff; }

/* Shared typography also applies when record details are printed. */
.section-heading { margin: 0 0 12px; font-size: 16px; font-weight: 600; line-height: 1.4; }
.body-copy { font-size: 14px; line-height: 1.6; }
.supporting-copy { font-size: 13px; line-height: 1.5; }
.page-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.form-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 24px; }
.topbar-controls { gap: 16px; flex-shrink: 0; }
.btn-udm { --bs-btn-active-bg: var(--udm-primary-hover); --bs-btn-active-color: var(--udm-primary-ink); --bs-btn-active-border-color: var(--udm-primary-hover); }
.btn-udm-outline { --bs-btn-active-bg: var(--udm-surface-sunk); --bs-btn-active-color: var(--udm-navy-text); --bs-btn-active-border-color: var(--udm-primary); }
.btn-udm-teal { --bs-btn-active-bg: var(--udm-teal); --bs-btn-active-color: var(--udm-on-accent); --bs-btn-active-border-color: var(--udm-teal); }
.btn-udm-green { --bs-btn-active-bg: var(--udm-green); --bs-btn-active-color: var(--udm-on-accent); --bs-btn-active-border-color: var(--udm-green); }
.btn-udm-gold { --bs-btn-active-bg: var(--udm-gold); --bs-btn-active-color: var(--udm-on-gold); --bs-btn-active-border-color: var(--udm-gold); }

/* Shared screen layouts. Paper slips and memos retain their print geometry. */
@media screen {
  .app-content { --page-gap: 24px; --panel-padding: 20px; }
  .page-head { margin-bottom: var(--page-gap); flex-wrap: wrap; }
  .page-head > div:first-child { flex: 1 1 280px; min-width: 0; }
  .page-head h1 { line-height: 1.25; }
  .page-head .sub { line-height: 1.55; }
  .page-head > .btn, .page-head > form { flex: 0 0 auto; }
  .card-udm .card-udm-head { flex-wrap: wrap; padding: 16px var(--panel-padding); }
  .card-udm .card-udm-body { padding: 20px var(--panel-padding); }
  .card-udm-head h2 { line-height: 1.4; }
  .btn:is(.btn-udm,.btn-udm-outline,.btn-udm-gold,.btn-udm-teal,.btn-udm-green) {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 40px; gap: 6px; line-height: 1.4; text-align: center;
    padding: 8px 16px; border-radius: 8px; font-size: 14px; font-weight: 600;
    white-space: normal; overflow-wrap: anywhere;
  }
  .btn.btn-sm:is(.btn-udm,.btn-udm-outline,.btn-udm-gold,.btn-udm-teal,.btn-udm-green) {
    min-height: 32px; padding: 5px 12px; font-size: 13px;
  }
  .step-indicator { flex-wrap: wrap; gap: 8px 12px; line-height: 1.5; }
  .step-indicator .num { flex-shrink: 0; }
  .phase2-upload-box { padding: 20px; }
  .form-control:not(textarea), .form-select { min-height: 40px; }
  .form-control-sm, .form-select-sm { min-height: 32px; }
  .table-stacked { font-size: 14px; }
  .table-stacked th, .table-stacked td { overflow-wrap: anywhere; }
  .empty-state h3 { font-size: 18px; line-height: 1.4; }
  .empty-state p:last-child, .body-copy > :last-child { margin-bottom: 0; }

  /* Bootstrap action tabs and page tabs use the same underline and spacing.
     Sidebar nav-item styles must never apply to these list items. */
  .subtabs, .app-content .nav-tabs { gap: 4px; margin-bottom: 20px; border-bottom: 1px solid var(--udm-line); }
  .subtabs { flex-wrap: wrap; }
  .subtab, .app-content .nav-tabs .nav-link {
    display: inline-flex; align-items: center; min-height: 44px;
    padding: 9px 14px; border: 0; border-bottom: 3px solid transparent;
    border-radius: 0; background: transparent; color: var(--udm-muted);
    font-size: 14px; font-weight: 600; line-height: 1.4; text-decoration: none;
  }
  .subtab:hover, .app-content .nav-tabs .nav-link:hover { color: var(--udm-teal-ink); background: var(--udm-surface-sunk); border-bottom-color: var(--udm-line-soft); }
  .subtab.is-active, .app-content .nav-tabs .nav-link.active {
    color: var(--udm-navy-text); background: transparent; border-bottom-color: var(--udm-teal);
  }
  .subtab:focus-visible, .app-content .nav-tabs .nav-link:focus-visible { outline: 2px solid var(--udm-teal); outline-offset: -2px; }
  .subtabs--administration { margin-top: -4px; }
  .account-access .login-form-heading h1 { font-size: 27px; line-height: 1.25; margin: 2px 0 8px; }
  .account-access .login-form-heading p { line-height: 1.6; }
  .file-chip .body-copy, .file-chip .mono { overflow-wrap: anywhere; }

  @media (max-width: 900px) {
    .app-content { --panel-padding: 16px; }
    .app-topbar { padding-inline: 16px; }
  }
  @media (max-width: 575.98px) {
    .app-content { --page-gap: 20px; --panel-padding: 15px; }
    .app-topbar, .app-footer { padding-inline: 14px; }
    .app-topbar { flex-wrap: wrap; }
    .app-topbar .topbar-search { order: 1; flex: 1 1 100%; max-width: none; }
    .app-topbar .topbar-search input { min-height: 44px; font-size: 16px; }
    .app-topbar .topbar-controls { gap: 8px; }
    .app-topbar :is(.sidebar-toggle,.theme-toggle,.topbar-notifications,.page-help-launch) { width: 44px; height: 44px; flex: 0 0 44px; }
    .app-topbar .topbar-account-button { min-height: 44px; }
    .page-head { flex-direction: column; align-items: stretch; gap: 12px; }
    .page-head > div:first-child { flex-basis: auto; }
    .page-head h1 { font-size: 23px; }
    .page-head > .btn { align-self: flex-start; }
    .page-actions { justify-content: flex-start; }
    .btn:is(.btn-udm,.btn-udm-outline,.btn-udm-gold,.btn-udm-teal,.btn-udm-green),
    .btn.btn-sm:is(.btn-udm,.btn-udm-outline,.btn-udm-gold,.btn-udm-teal,.btn-udm-green) { min-height: 44px; }
    .form-control:not(textarea), .form-select { min-height: 44px; font-size: 16px; }
    textarea.form-control { font-size: 16px; }
    .form-actions { align-items: stretch; }
    .form-actions > .btn { flex: 1 1 auto; }
    .form-actions > .btn:first-child { flex-basis: 100%; }
    .subtab, .app-content .nav-tabs .nav-link { padding-inline: 10px; font-size: 13px; }
    .phase2-upload-box { padding: 16px; }
    .account-sticky-note { position: static; }
  }
}

/* Filters expose the common controls first; secondary choices stay available. */
.repository-filters { padding: 18px 20px; }
.repository-search { gap: 10px; align-items: end; }
.repository-search > div { min-width: 0; }
.repository-filter-grid { gap: 12px; margin: 14px 0 0; }
.repository-filter-grid > div { min-width: 0; }
@media (min-width: 992px) {
  .repository-filter-grid--primary { grid-template-columns: repeat(4,minmax(0,1fr)); }
}
.repository-filters label { color: var(--udm-label-ink); font-size: 13px; font-weight: 600; }
.repository-more-filters { border-top: 1px solid var(--udm-line); margin-top: 16px; padding-top: 4px; }
.repository-more-filters > summary {
  min-height: 44px; padding: 9px 0; color: var(--udm-teal-ink);
  cursor: pointer; font-size: 14px; font-weight: 600;
}
.repository-more-filters > summary span { color: var(--udm-muted); font-size: 12px; font-weight: 400; margin-left: 8px; }
.repository-more-filters .repository-filter-grid { margin-top: 4px; }
.repository-more-filters :is(.repository-type-folders,.repository-tags) { margin: 14px 0 0; gap: 6px; }
.repository-more-filters :is(.repository-type-folders,.repository-tags) a { font-size: 12px; }
.active-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0; font-size: 13px; }
.active-filters > span { color: var(--udm-muted); }
.active-filters a {
  display: inline-flex; align-items: center; gap: 10px; max-width: 100%;
  min-height: 36px; padding: 5px 10px; border: 1px solid var(--udm-line-strong);
  background: var(--udm-teal-soft); color: var(--udm-teal-ink); border-radius: 6px;
}
.active-filters a > span:first-child { overflow-wrap: anywhere; }
.active-filters a > span:last-child { flex-shrink: 0; font-size: 20px; line-height: 1; }
.repository-filters .errorlist { color: var(--udm-red-ink); list-style: none; padding: 0; margin: 5px 0 0; font-size: 12px; }

.report-panel { border: 0; background: transparent; padding: 0; }
.report-metrics { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 16px; margin-bottom: 24px; }
.report-metrics--tracking { grid-template-columns: repeat(3,minmax(0,1fr)); }
.report-metric-incoming { background: var(--udm-slate-soft); }
.report-metric-outgoing { background: var(--udm-surface); }
.report-direction + .report-direction { margin-top: 24px; padding-top: 24px; border-top: 1px solid var(--udm-line); }
.report-chart-summary { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.report-chart-summary h3 { margin: 0; font-size: 16px; }
.report-chart-summary strong { display: block; font-size: 44px; line-height: 1.2; color: var(--udm-navy-text); }
.report-direction-bar { display: flex; width: 100%; height: 48px; overflow: hidden; border-radius: 8px; background: var(--chart-track); }
.report-direction-bar > span { flex-basis: 0; min-width: 0; }
.report-direction-bar > span + span { box-shadow: inset 1px 0 0 var(--udm-surface); }
.report-direction-stages { list-style: none; margin: 20px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 10px; }
.report-stage-link { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: 10px; align-items: center; min-height: 44px; padding: 8px 10px; border: 1px solid var(--udm-line); border-radius: 5px; color: var(--udm-navy-text); }
.report-stage-link .pill { justify-self: start; white-space: normal; }
.report-stage-link:hover { background: var(--udm-slate-soft); }
.report-all-offices-stages { grid-template-columns: repeat(4,minmax(0,1fr)); }
@media (min-width: 768px) and (max-width: 1199.98px) { .report-all-offices-stages { grid-template-columns: repeat(2,minmax(0,1fr)); } }
@media (max-width: 767.98px) { .report-direction-stages { grid-template-columns: 1fr; } }
.report-metrics > div { width: auto; min-width: 0; padding: 0; }
.report-metrics .stat-card { min-height: 0; height: 100%; padding: 16px 18px; border-left: 3px solid var(--udm-navy-text); }
.report-metrics .stat-card.gold { border-left-color: var(--status-pending); }
.report-metrics .stat-card.red { border-left-color: var(--status-overdue); }
.report-metrics .stat-card.green { border-left-color: var(--status-completed); }
.report-metrics .stat-card .value { font-size: 30px; line-height: 1.2; margin: 3px 0 5px; }
.report-metrics .stat-card .label { font-size: 13px; font-weight: 600; }
.report-metrics .stat-card .hint { max-width: none; font-size: 12px; line-height: 1.5; }
.report-metric-note { display: block; margin-top: 3px; }
.report-year-picker { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: end; gap: 10px; }
.report-year-picker > div { flex: 0 0 auto; }
.report-year-picker .form-select { min-width: 8rem; width: 8rem; padding-right: 2.5rem; }
.report-year-picker label { display: block; margin-bottom: 4px; }
#annual-turnaround-title { scroll-margin-top: 100px; }
.report-scope-card { display: flex; flex-wrap: wrap; align-items: center; }
.report-scope-card .card-udm-head { flex: 1 1 260px; border: 0; padding: 16px 20px; }
.report-scope-card .card-udm-body { flex: 1 1 380px; padding: 16px 20px; }
.report-scope-picker { display: flex; align-items: end; gap: 10px; }
.report-scope-picker > div { width: auto; min-width: 0; }
.report-scope-picker > div:first-of-type { flex: 1 1 0; }
.report-scope-picker > div:last-of-type { flex: 0 0 auto; }
.report-scope-picker .form-label { font-size: 13px; margin-bottom: 4px; }
.report-scope-picker .btn { white-space: nowrap; }
.form-select { padding-right: 2.5rem; text-overflow: ellipsis; }

@media (max-width: 991.98px) {
  .report-metrics { grid-template-columns: repeat(2,minmax(0,1fr)); gap: 12px; }
}
@media (max-width: 575.98px) {
  .report-metrics--tracking { grid-template-columns: 1fr; }
  .repository-filters { padding: 15px; }
  .repository-search { display: flex; flex-wrap: wrap; }
  .repository-search > div { flex: 1 1 100%; }
  .repository-search > .btn { flex: 1 1 auto; }
  .repository-filter-grid { grid-template-columns: 1fr; }
  .repository-more-filters > summary span { display: block; margin-left: 18px; }
  .active-filters a { min-height: 44px; }
  .report-year-picker { width: 100%; }
  .report-year-picker > div { flex: 1 1 8rem; }
  .report-year-picker .form-select { width: 100%; }
  #annual-turnaround-title { scroll-margin-top: 150px; }
  .report-scope-card .card-udm-head { padding: 15px 15px 0; }
  .report-scope-card .card-udm-body { padding: 10px 15px 15px; }
  .report-metrics .stat-card { padding: 13px; }
}
@media (max-width: 359.98px) { .report-metrics { grid-template-columns: 1fr; } }

/* Keep subjects readable when office and status columns need their own space.
   Excess width belongs to the named, keyboard-focusable table scroller. */
.tracking-records-table .tracking-subject { min-width: 280px; overflow-wrap: break-word; }
.tracking-records-table .tracking-updated { min-width: 120px; }
.desk-records-table .desk-cell { min-width: 240px; }
.tracking-records-table th, .desk-records-table th { white-space: normal; }
.tracking-records-table .deadline-when-cell { white-space: normal; }
.table-udm .btn { white-space: nowrap; overflow-wrap: normal; }
.table-responsive:focus-visible { outline: 3px solid var(--udm-focus); outline-offset: -3px; }
.dashboard-scope { flex-wrap: wrap; }
.dashboard-scope .form-select { width: auto; max-width: 100%; }
.form-error-summary h2 { margin: 0 0 8px; font-size: 16px; }
.form-error-summary ul { margin-bottom: 0; padding-left: 20px; }
@media (max-width: 575.98px) {
  .dashboard-head-actions { width: 100%; min-width: 0; }
  .dashboard-scope { min-width: 0; }
  .dashboard-scope .form-select { flex: 1 1 100%; width: 100%; min-width: 0; }
}

/* Operational work leads; totals and historical breakdowns stay secondary. */
.dashboard-head-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 100%; }
.dashboard-head-actions .dashboard-scope { grid-column: 1 / -1; }
.dashboard-attention h2 { margin: 0 0 12px; font-size: 18px; font-weight: 750; }
.dashboard-attention-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.dashboard-attention .stat-card,
.dashboard-attention .repository-pending-filing { display: block; min-width: 0; padding: 16px 20px; }
.dashboard-attention .label { color: var(--udm-gold-ink); font-size: 14px; font-weight: 750; }
.dashboard-attention .stat-card.red .label { color: var(--udm-red-ink); }
.dashboard-attention .value { margin: 5px 0; color: var(--udm-gold-ink); font-size: 36px; font-weight: 800; line-height: 1.2; }
.dashboard-attention .stat-card.red .value { color: var(--udm-red-ink); }
.dashboard-attention .hint { max-width: none; color: var(--udm-muted); font-size: 13px; font-weight: 400; }
.dashboard-secondary-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--udm-line); border-radius: 4px; overflow: hidden; }
.dashboard-secondary-stats .stat-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 12px; min-height: 0; padding: 12px 14px; border: 0; border-radius: 0; background: var(--udm-surface); }
.dashboard-secondary-stats .stat-card:only-child { grid-column: 1 / -1; }
.dashboard-secondary-stats .stat-card + .stat-card { border-left: 1px solid var(--udm-line); }
.dashboard-secondary-stats .stat-card:hover { background: var(--udm-surface-sunk); }
.dashboard-secondary-stats .label { color: var(--udm-navy-text); font-size: 12.5px; letter-spacing: 0; text-transform: none; text-decoration: underline; text-underline-offset: 3px; }
.dashboard-secondary-stats .value { grid-column: 2; grid-row: 1 / 3; align-self: center; margin: 0; color: var(--udm-navy-text); font-size: 23px; }
.dashboard-secondary-stats .hint { grid-column: 1; max-width: none; font-size: 12px; }
.dashboard-recent-activity { margin: 0; padding: 12px 16px; border-top: 1px solid var(--udm-line); }
.dashboard-recent-activity .desk-block--secondary { margin-top: 12px; }
.repository-filed-total { margin: 0 0 12px; color: var(--udm-muted); font-size: 14px; }
.repository-filed-total strong { margin-right: 6px; color: var(--udm-navy-text); font-size: 26px; }
.repository-source-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--udm-line); color: var(--udm-navy-text); font-size: 13px; }
.repository-source-row > span:first-child { text-decoration: underline; text-underline-offset: 3px; }
.repository-source-row:hover { color: var(--udm-teal-ink); }
/* Screen actions lead the history; the plain record print retains its history
   before draft/help text. Official routing slips use their separate template. */
@media print {
  .tracking-record-work { display: flex; flex-direction: column; }
  .tracking-record-history { order: 0; }
  .tracking-record-actions { order: 1; }
}
@media (max-width: 575.98px) {
  .dashboard-attention-grid { gap: 10px; }
  .dashboard-attention .stat-card,
  .dashboard-attention .repository-pending-filing { padding: 14px 12px; }
  .dashboard-secondary-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dashboard-secondary-stats .stat-card:first-child { grid-column: 1 / -1; }
  .dashboard-secondary-stats .stat-card:nth-child(2) { border-left: 0; }
  .dashboard-secondary-stats .stat-card:not(:first-child) { border-top: 1px solid var(--udm-line); }
}
/* Routine filter feedback is visually hidden; only errors occupy this space. */
.filter-update-status { padding: .45rem 1.5rem 0; color: var(--udm-muted); font-size: .8rem; }
.filter-update-status.is-error { color: var(--udm-red-ink); }
.filter-update-status [data-filter-retry] { margin-left: .5rem; }
