/*
  Fervid Budget design system
  Dense server-rendered UI primitives for operational finance screens.
*/

:root {
  color-scheme: light;

  /* Surfaces and ink */
  --paper: #f3f0eb;
  --surface: #fbfaf7;
  --surface-2: #f1eee8;
  --surface-3: #e8e2d8;
  --line: #ddd6cc;
  --line-2: #cfc6b9;
  --ink: #282624;
  --ink-2: #403c37;
  --muted: #5f5952;
  --muted-2: #726a61;
  --brand: #a83a1d;
  --brand-2: #7f2b16;
  --brand-tint: #fff1ea;
  --brand-tint-2: #f8dccf;
  --sidebar: #191817;

  /* Status colours */
  --ok: #0f633d;
  --ok-soft: #e3f0e8;
  --bad: #b42318;
  --bad-soft: #f9e2df;
  --warn: #9a5b00;
  --warn-soft: #fff0cf;
  --info: #245b8f;
  --info-soft: #e2ecf6;
  --track: #5aa775;
  /* Tint borders — the 1px rules that sit on the *-soft fills. */
  --ok-line: #bfdccc;
  --bad-line: #edc3bd;
  --warn-line: #ecd39a;
  --info-line: #c5daed;

  --font-ui: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: Georgia, "Times New Roman", serif;
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;

  /* The single gutter between the sidebar and the page content. Every block in
     the content column is inset by this, so the whole product lines up on one
     vertical edge. Narrow screens override it below. */
  --page-gutter: 28px;

  --r: 9px;
  --r-sm: 6px;
  --r-pill: 999px;
  --shadow-1: 0 1px 2px rgba(31, 39, 37, .07);
  --shadow-2: 0 2px 4px rgba(31, 39, 37, .06), 0 12px 28px rgba(31, 39, 37, .10);
  --focus: 0 0 0 3px rgba(168, 58, 29, .26);

  /* Legacy aliases — every pre-redesign rule reads these. Do not delete. */
  --fb-bg: var(--paper);              --fb-surface: var(--surface);
  --fb-surface-2: var(--surface-2);   --fb-surface-3: var(--surface-3);
  --fb-text: var(--ink);              --fb-muted: var(--muted);
  --fb-subtle: var(--muted-2);        --fb-border: var(--line);
  --fb-border-strong: var(--line-2);  --fb-accent: var(--brand);
  --fb-accent-strong: var(--brand-2); --fb-accent-soft: var(--brand-tint);
  --fb-info: var(--info);             --fb-info-soft: var(--info-soft);
  --fb-warn: var(--warn);             --fb-warn-soft: var(--warn-soft);
  --fb-danger: var(--bad);            --fb-danger-soft: var(--bad-soft);
  --fb-success: var(--ok);            --fb-success-soft: var(--ok-soft);
  --fb-radius: var(--r);              --fb-radius-sm: var(--r-sm);
  --fb-font: var(--font-ui);          --fb-mono: var(--font-mono);
  --fb-focus: var(--focus);           --fb-shadow: var(--shadow-2);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  min-height: 100%;
  background: var(--fb-bg);
  font-size: 16px;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  color: var(--fb-text);
  background: var(--fb-bg);
  font-family: var(--fb-font);
  font-size: 14px;
  line-height: 1.45;
  letter-spacing: 0;
  text-rendering: optimizeLegibility;
}

img,
svg {
  display: block;
  max-width: 100%;
}

a {
  color: var(--fb-accent-strong);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

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

button {
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid transparent;
  box-shadow: var(--fb-focus);
}

::selection {
  color: #fff;
  background: var(--fb-accent);
}

[hidden],
.hidden {
  display: none !important;
}

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

/* App frame */
.app-shell,
.layout,
.page-shell {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
}

.sidebar,
.app-sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  height: 100dvh;
  padding: 16px 12px;
  overflow-y: auto;
  color: #f5fbf8;
  background: #20312d;
  border-right: 1px solid rgba(255, 255, 255, .08);
}

.brand,
.app-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 0 8px 14px;
  margin-bottom: 10px;
  color: #fff;
  font-weight: 760;
  letter-spacing: 0;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.brand img,
.app-brand img {
  width: 30px;
  height: 30px;
  border-radius: 6px;
}

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

.nav a,
.nav-item,
.app-nav a {
  display: flex;
  align-items: center;
  gap: 9px;
  min-height: 36px;
  padding: 8px 10px;
  color: rgba(255, 255, 255, .78);
  border-radius: 6px;
  text-decoration: none;
}

.nav a:hover,
.nav-item:hover,
.app-nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, .08);
  text-decoration: none;
}

.nav a[aria-current="page"],
.nav a.is-active,
.nav-item.is-active,
.app-nav a[aria-current="page"] {
  color: #fff;
  background: var(--fb-accent);
}

.main,
.app-main,
main {
  min-width: 0;
  padding: 20px 24px 32px;
}

.topbar,
.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 50px;
  padding: 10px 0 18px;
}

.container,
.page-container {
  width: min(100%, 1520px);
  margin: 0 auto;
}

.page-header,
.section-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.page-title,
h1 {
  margin: 0;
  color: var(--fb-text);
  font-size: 24px;
  line-height: 1.12;
  font-weight: 780;
  letter-spacing: 0;
}

h2,
.section-title {
  margin: 0 0 10px;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 740;
  letter-spacing: 0;
}

h3 {
  margin: 0 0 8px;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 720;
  letter-spacing: 0;
}

.eyebrow,
.kicker,
.subtle {
  color: var(--fb-muted);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0;
}

.muted,
.help,
.hint {
  color: var(--fb-muted);
}

/* Toolbars and filters */
.toolbar,
.filters,
.filter-bar,
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.toolbar,
.filter-bar {
  padding: 10px;
  margin-bottom: 12px;
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
  box-shadow: 0 1px 0 rgba(31, 39, 37, .03);
}

.toolbar-spacer {
  flex: 1 1 auto;
}

/* The toolbar's search box takes the width nothing else claimed, so the one
   control a person types a sentence into is not the same size as a three-option
   <select>.

   `class="field search"` has been on five toolbars since Phase 0 — requests,
   vendors, the accounts queue, approvals and the recoverables register — with no
   rule for the bare `search` token anywhere in this file, so the token rendered
   as nothing. It is not a token somebody invented: the approved stylesheet
   carries `.toolbar .search { flex: 1 1 200px; }` (mockups/mockup.css:934), and
   Phase 0 ported its two `.m-search` neighbours (see the 860px block) and
   dropped this one. Ported verbatim, the same omission a80e18f fixed for four
   other classes.

   Growing only ever spends free space, and flex-shrink stays at 1, so this
   cannot widen a toolbar or push a page sideways. */
.toolbar .search {
  flex: 1 1 200px;
}

.summary-strip,
.metric-strip,
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(160px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}

.metric,
.stat,
.summary-card {
  min-width: 0;
  padding: 12px;
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

.metric-label,
.stat-label {
  display: block;
  color: var(--fb-muted);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
}

.metric-value,
.stat-value {
  display: block;
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
  font-size: 20px;
  line-height: 1.15;
  font-weight: 780;
}

/* Phase 0 defects, fixed in Phase 6. All four appear in the approved mockups,
   and .metric-foot is already emitted by shipped Phase-3, -4 and -5 templates,
   so until now that third line in every metric tile rendered unstyled. */
.metric-foot {
  display: block;
  margin-top: 4px;
  color: var(--fb-muted);
  font-size: 11.5px;
  line-height: 1.3;
}

/* The tone a metric carries when its number is the one to worry about, and the
   matching reassuring tone. Both are borrow-nothing: only the accent changes,
   so a strip of four tiles still reads as one row. */
.metric.warn {
  border-color: var(--fb-warn-border, #e6c9a8);
  background: var(--fb-warn-bg, #fff8ef);
}

.metric.warn .metric-value {
  color: var(--fb-warn-ink, #8a5a12);
}

.metric.good {
  border-color: var(--fb-good-border, #bcd9c2);
  background: var(--fb-good-bg, #f4fbf5);
}

.metric.good .metric-value {
  color: var(--fb-good-ink, #256b3a);
}

/* The affirmative terminal action, distinct from the neutral one beside it. */
.btn.approve {
  border-color: var(--fb-good-border, #bcd9c2);
  background: var(--fb-good-bg, #f4fbf5);
  color: var(--fb-good-ink, #256b3a);
}

.btn.approve:hover {
  border-color: var(--fb-good-ink, #256b3a);
}

/* Buttons */
.btn,
button,
input[type="submit"],
input[type="button"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 34px;
  padding: 7px 12px;
  color: var(--fb-text);
  background: var(--fb-surface);
  border: 1px solid var(--fb-border-strong);
  border-radius: 6px;
  font-weight: 680;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
}

.btn:hover,
button:hover,
input[type="submit"]:hover,
input[type="button"]:hover {
  background: var(--fb-surface-2);
  text-decoration: none;
}

.btn-primary,
button.primary,
button[name="save"],
input[type="submit"].primary {
  color: #fff;
  background: var(--fb-accent);
  border-color: var(--fb-accent);
}

.btn-primary:hover,
button.primary:hover,
button[name="save"]:hover,
input[type="submit"].primary:hover {
  background: var(--fb-accent-strong);
  border-color: var(--fb-accent-strong);
}

/* `.btn.danger` is the approved spelling: the mockups use it on anchors as
   well as buttons, and an <a class="btn danger"> matched none of the element
   selectors below, so a destructive link rendered as an ordinary one. */
.btn.danger,
.btn-danger,
button.danger,
button[name="delete"],
button[name="void"] {
  color: #fff;
  background: var(--fb-danger);
  border-color: var(--fb-danger);
}

.btn.danger:hover {
  background: #8f1b12;
  border-color: #8f1b12;
}

.btn-ghost,
.btn-link {
  color: var(--fb-accent-strong);
  background: transparent;
  border-color: transparent;
}

.icon-btn {
  width: 34px;
  min-width: 34px;
  padding: 0;
}

.btn-sm,
.compact button,
button.small {
  min-height: 28px;
  padding: 5px 9px;
  font-size: 12px;
}

.btn[disabled],
button[disabled],
input[disabled],
select[disabled],
textarea[disabled],
.is-disabled {
  cursor: not-allowed;
  opacity: .58;
}

.segmented,
.tabs {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--fb-surface-2);
  border: 1px solid var(--fb-border);
  border-radius: 7px;
}

/* A strip such as the roles switcher grows one item per row and has no upper
   bound a template can enforce. Every other wide surface in this system
   contains its own overflow rather than the page's -- .table-wrap,
   .grid-wrap, .budget-grid and .data-table all set `overflow: auto` below.
   .segmented matches that intent: past this width the strip scrolls in its
   own box, and the page -- with the sidebar and the mobile tab bar it
   carries along -- never does. The items keep their natural size (see
   flex-shrink below) so the strip scrolls rather than squishing into
   illegible tabs, and because they are <a>/<button> elements the scrollable
   region already contains focusable content, so it is keyboard-reachable
   without extra markup. */
.segmented {
  max-width: 100%;
  overflow-x: auto;
}

.segmented a,
.segmented button,
.tab {
  min-height: 28px;
  padding: 5px 10px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--fb-muted);
  font-weight: 680;
  flex-shrink: 0;
  white-space: nowrap;
}

.segmented [aria-selected="true"],
.segmented .is-active,
.tab[aria-selected="true"],
.tab.is-active {
  color: var(--fb-text);
  background: var(--fb-surface);
  box-shadow: 0 1px 2px rgba(31, 39, 37, .08);
}

/* Forms */
form {
  margin: 0;
}

.form,
.form-panel,
.panel,
.card {
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

.form,
.form-panel {
  padding: 16px;
}

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

/* The tracks above can already shrink, but a grid item defaults to
   min-width:auto — its content's intrinsic width — and an <input> refuses to go
   narrower than roughly its `size`. Without this, a narrow window pushes the
   whole document sideways instead of the field simply becoming narrower. */
.form-grid > * {
  min-width: 0;
}

.field input,
.field select,
.field textarea {
  min-width: 0;
  max-width: 100%;
}

.field,
.form-field {
  display: grid;
  gap: 5px;
  min-width: 0;
}

.field.span-2 { grid-column: span 2; }
.field.span-3 { grid-column: span 3; }
.field.span-4 { grid-column: span 4; }
.field.span-5 { grid-column: span 5; }
.field.span-6 { grid-column: span 6; }
.field.span-7 { grid-column: span 7; }
.field.span-8 { grid-column: span 8; }
.field.span-12 { grid-column: 1 / -1; }

label,
.label {
  color: var(--fb-text);
  font-size: 12px;
  font-weight: 720;
}

input,
select,
textarea {
  width: 100%;
  min-height: 34px;
  padding: 7px 9px;
  color: var(--fb-text);
  background: #fff;
  border: 1px solid var(--fb-border-strong);
  border-radius: 6px;
  box-shadow: inset 0 1px 1px rgba(31, 39, 37, .04);
}

textarea {
  min-height: 86px;
  resize: vertical;
}

input[type="checkbox"],
input[type="radio"] {
  width: 16px;
  min-height: 16px;
  padding: 0;
  accent-color: var(--fb-accent);
}

input[type="file"] {
  padding: 5px;
  background: var(--fb-surface);
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--fb-accent);
  outline: 0;
  box-shadow: var(--fb-focus);
}

input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"],
.field-error input,
.field-error select,
.field-error textarea {
  border-color: var(--fb-danger);
}

.error,
.field-error-message {
  color: var(--fb-danger);
  font-size: 12px;
  font-weight: 650;
}

.form-actions,
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 12px;
  margin-top: 12px;
  border-top: 1px solid var(--fb-border);
}

fieldset {
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

legend {
  padding: 0 5px;
  color: var(--fb-muted);
  font-size: 12px;
  font-weight: 760;
}

/* Tables and variance grid */
.table-wrap,
.grid-wrap,
.budget-grid,
.data-table {
  width: 100%;
  /* `overflow: auto` only contains the table if the box is allowed to be
     narrower than its contents. As a grid or flex item it is not: min-width
     defaults to auto, i.e. the table's min-content width, so the wrapper grew to
     the full width of the roles matrix and scrolled the page sideways instead of
     itself. width:100% cannot override that — only a real min-width can. */
  min-width: 0;
  overflow: auto;
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

th,
td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--fb-border);
  vertical-align: middle;
}

th {
  position: sticky;
  top: 0;
  z-index: 2;
  color: #33413e;
  background: var(--fb-surface-2);
  font-size: 11px;
  font-weight: 780;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

td {
  background: var(--fb-surface);
}

tbody tr:hover td {
  background: #fbfcfb;
}

tbody tr:last-child td {
  border-bottom: 0;
}

.num,
.money,
.amount,
.variance,
.percent,
td[data-type="money"],
td[data-type="number"] {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.sticky-col,
.project-col,
.head-col {
  position: sticky;
  left: 0;
  z-index: 1;
  background: inherit;
}

th.sticky-col,
th.project-col,
th.head-col {
  z-index: 3;
  background: var(--fb-surface-2);
}

.project-row td,
.group-row td {
  background: #edf4f1;
  font-weight: 760;
}

.subtotal-row td,
.total-row td,
tfoot td {
  background: #f4f6f2;
  border-top: 1px solid var(--fb-border-strong);
  font-weight: 780;
}

.grand-total td {
  color: #fff;
  background: #2d423d;
  border-color: #2d423d;
}

.variance-positive,
.over,
.text-danger {
  color: var(--fb-danger);
}

.variance-negative,
.under,
.text-success {
  color: var(--fb-success);
}

.variance-zero,
.on-track {
  color: var(--fb-accent-strong);
}

.budget-bar,
.variance-bar {
  position: relative;
  min-width: 110px;
  height: 8px;
  overflow: hidden;
  background: var(--fb-surface-3);
  border-radius: 999px;
}

.budget-bar > span,
.variance-bar > span,
.bar-fill {
  display: block;
  width: var(--value, 0%);
  max-width: 100%;
  height: 100%;
  background: var(--fb-accent);
  border-radius: inherit;
}

.budget-bar.over > span,
.variance-bar.over > span,
.bar-fill.over {
  background: var(--fb-danger);
}

.budget-bar.warn > span,
.variance-bar.warn > span,
.bar-fill.warn {
  background: #cf8b1a;
}

.row-actions {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
  white-space: nowrap;
}

/* Banners and badges */
.banner,
.alert,
.locked-banner,
.lock-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
  background: var(--fb-info-soft);
  color: var(--info);
}

.locked-banner,
.lock-banner,
.alert-warning {
  color: var(--warn);
  background: var(--fb-warn-soft);
  border-color: var(--warn-line);
}

.alert-danger {
  color: var(--bad);
  background: var(--fb-danger-soft);
  border-color: var(--bad-line);
}

.alert-success {
  color: var(--ok);
  background: var(--fb-success-soft);
  border-color: var(--ok-line);
}

.badge,
.status,
.status-badge,
[data-status] {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 22px;
  padding: 3px 8px;
  border: 1px solid var(--fb-border);
  border-radius: 999px;
  background: var(--fb-surface-2);
  color: var(--fb-muted);
  font-size: 12px;
  font-weight: 760;
  line-height: 1;
  white-space: nowrap;
}

.badge::before,
.status-badge::before,
[data-status]::before {
  width: 7px;
  height: 7px;
  content: "";
  background: currentColor;
  border-radius: 999px;
}

.badge.over,
.status-over,
[data-status="over"] {
  color: var(--fb-danger);
  background: var(--fb-danger-soft);
  border-color: var(--bad-line);
}

.badge.unbudgeted,
.status-unbudgeted,
[data-status="unbudgeted"] {
  color: var(--fb-warn);
  background: var(--fb-warn-soft);
  border-color: var(--warn-line);
}

.badge.under,
.status-under,
[data-status="under"] {
  color: var(--fb-success);
  background: var(--fb-success-soft);
  border-color: var(--ok-line);
}

.badge.on-track,
.status-on-track,
[data-status="on-track"],
[data-status="on_track"] {
  color: var(--fb-accent-strong);
  background: var(--fb-accent-soft);
  border-color: var(--brand-tint-2);
}

.badge.not-paid,
.status-not-paid,
[data-status="not-paid"],
[data-status="not_paid"] {
  color: var(--fb-muted);
  background: var(--fb-surface-2);
}

.badge.locked,
.status-locked,
[data-status="locked"] {
  color: var(--fb-warn);
  background: var(--fb-warn-soft);
  border-color: var(--warn-line);
}

.role-admin {
  color: var(--fb-info);
  background: var(--fb-info-soft);
}

.role-data-entry,
.role-data_entry {
  color: var(--fb-accent-strong);
  background: var(--fb-accent-soft);
}

/* Audit and detail views */
.details-grid,
.detail-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.detail,
.detail-item {
  min-width: 0;
  padding: 10px;
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius-sm);
}

.detail-label {
  display: block;
  color: var(--fb-muted);
  font-size: 11px;
  font-weight: 760;
  text-transform: uppercase;
}

.detail-value {
  display: block;
  margin-top: 3px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.audit-list,
.timeline {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.audit-entry,
.timeline-item {
  position: relative;
  padding: 10px 12px 10px 34px;
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

.audit-entry::before,
.timeline-item::before {
  position: absolute;
  top: 16px;
  left: 13px;
  width: 9px;
  height: 9px;
  content: "";
  background: var(--fb-accent);
  border-radius: 999px;
}

.audit-meta,
.timeline-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  color: var(--fb-muted);
  font-size: 12px;
}

.audit-diff,
.diff {
  display: grid;
  gap: 6px;
  margin-top: 8px;
  padding: 8px;
  overflow-x: auto;
  background: #f9faf8;
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius-sm);
  font-family: var(--fb-mono);
  font-size: 12px;
}

details {
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
}

summary {
  padding: 9px 11px;
  cursor: pointer;
  font-weight: 720;
}

details > :not(summary) {
  margin: 0 11px 11px;
}

dialog,
.modal {
  width: min(680px, calc(100vw - 24px));
  padding: 0;
  color: var(--fb-text);
  background: var(--fb-surface);
  border: 1px solid var(--fb-border);
  border-radius: var(--fb-radius);
  box-shadow: var(--fb-shadow);
}

dialog::backdrop,
.modal-backdrop {
  background: rgba(31, 39, 37, .42);
}

.modal-header,
.modal-body,
.modal-footer {
  padding: 14px 16px;
}

.modal-header {
  border-bottom: 1px solid var(--fb-border);
}

.modal-footer {
  border-top: 1px solid var(--fb-border);
}

/* HTMX affordances */
.htmx-indicator {
  display: none;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  display: inline-flex;
}

.htmx-request {
  cursor: progress;
}

.htmx-swapping {
  opacity: .65;
}

.htmx-settling {
  transition: opacity .12s ease;
}

/* Utilities */
.stack {
  display: grid;
  gap: 12px;
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.right {
  margin-left: auto;
}

.text-right {
  text-align: right;
}

.nowrap {
  white-space: nowrap;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.p-0 { padding: 0 !important; }
.mt-0 { margin-top: 0 !important; }
.mb-0 { margin-bottom: 0 !important; }



@media print {
  .sidebar,
  .app-sidebar,
  .topbar,
  .app-topbar,
  .toolbar,
  .filter-bar,
  .actions,
  .btn,
  button {
    display: none !important;
  }

  body,
  .main,
  .app-main,
  main {
    background: #fff;
    padding: 0;
  }

  .table-wrap,
  .grid-wrap,
  .budget-grid,
  .card,
  .panel {
    box-shadow: none;
    border-color: #999;
  }
}

/* v4 variance grid theme, adapted from docs/superpowers/specs/2026-06-29-v4-variance-grid.html */
html,
body {
  background: var(--paper);
}

body {
  color: var(--ink);
  font-family: var(--font-ui);
}

.appshell {
  display: grid;
  grid-template-columns: 238px minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--paper);
}

.sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100vh;
  height: 100dvh;
  padding: 18px 12px;
  overflow-y: auto;
  background: #191817;
  border-right: 1px solid rgba(255, 255, 255, .08);
}

.logo-link {
  display: flex;
  align-items: center;
  min-height: 58px;
  padding: 8px 10px 18px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.logo {
  width: 178px;
  height: auto;
}

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

.side-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  padding: 9px 11px;
  color: #bdb7af;
  border-radius: 6px;
  font-weight: 650;
  text-decoration: none;
}

.side-nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, .08);
}

.side-nav a.active {
  color: #fff;
  background: var(--brand);
}

.ico {
  width: 18px;
  color: currentColor;
  text-align: center;
}

.sgroup {
  margin: 14px 10px 5px;
  color: #aaa49d;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.side-user {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 12px 10px 8px;
  margin-top: auto;
  border-top: 1px solid rgba(255, 255, 255, .08);
}

.side-user strong {
  display: block;
  color: #fff;
  font-size: 12px;
}

.side-user small {
  color: #bdb7af;
  font-size: 11px;
}

.avatar {
  display: grid;
  width: 31px;
  height: 31px;
  place-items: center;
  color: #fff;
  background: var(--brand);
  border-radius: 50%;
  font-size: 11px;
  font-weight: 800;
}

.side-logout {
  padding: 0 10px;
}

.side-logout button {
  width: 100%;
  min-height: 30px;
  color: #d5cec5;
  background: transparent;
  border-color: rgba(255, 255, 255, .14);
}

.page {
  min-width: 0;
  padding: 0;
  background: var(--paper);
}

.page > h1,
.page > .panel,
.page > form:not(.toolbar),
.page > table,
.page > .table-wrap,
.page > .split,
.page > .details,
.page > h2,
.page > .alert,
.page > .locked,
.page > .toolbar:not(.gridhead .toolbar) {
  margin-right: 28px;
  margin-left: 28px;
}

.page > h1 {
  padding-top: 24px;
  margin-bottom: 14px;
  font-family: var(--font-display);
}

.page > .table-wrap {
  width: auto;
}

.gridhead {
  padding: 22px 28px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

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

.eyebrow {
  color: var(--brand);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.gridhead h1 {
  margin-top: 4px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 700;
}

.sub {
  margin-top: 4px;
}

.countpill {
  padding: 4px 10px;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: 11px;
  white-space: nowrap;
}

.gridhead .toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: end;
  padding: 0;
  margin-top: 16px;
  margin-bottom: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.gridhead .toolbar label {
  display: grid;
  gap: 4px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 750;
  text-transform: uppercase;
}

.gridhead .toolbar .input,
.gridhead .toolbar .select {
  min-width: 150px;
}

.gridhead .toolbar .search-label {
  flex: 0 1 300px;
}

.spacer {
  flex: 1 1 auto;
}

.btn,
.button,
button {
  border-radius: 6px;
}

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

.btn.primary:hover,
.button.primary:hover,
button.primary:hover {
  background: var(--brand-2);
}

.btn.outline {
  color: var(--ink);
  background: var(--surface);
  border-color: var(--line-2);
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 14px;
  color: var(--muted);
  font-size: 12px;
}

.legend .lk {
  display: flex;
  gap: 6px;
  align-items: center;
}

.legend .sw {
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: 3px;
}

.legend .sw.ok { background: var(--ok); }
.legend .sw.track { background: var(--track); }
.legend .sw.bad { background: var(--bad); }
.legend .sw.warn { background: var(--warn); }
.legend .sw.none { background: var(--surface-2); border: 1px solid var(--line-2); }

.gridwrap {
  padding: 18px 28px 22px;
}

.card.scroll {
  padding: 0;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 1px 0 rgba(40, 38, 36, .03);
}

table.matrix {
  --project-sticky-width: 112px;
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 12px;
}

table.matrix th {
  position: sticky;
  top: 0;
  z-index: 3;
  padding: 10px 10px;
  color: #e9e4df;
  text-align: left;
  white-space: nowrap;
  background: var(--ink);
  border-bottom: 1px solid #000;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}

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

table.matrix th.c,
table.matrix td.c {
  text-align: center;
}

table.matrix td {
  padding: 7px 10px;
  white-space: nowrap;
  vertical-align: middle;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

table.matrix td.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

table.matrix tr.head:nth-child(odd) td {
  background: var(--surface);
}

table.matrix tr.head:nth-child(even) td {
  background: var(--surface-2);
}

table.matrix tr.head:hover td {
  background: var(--brand-tint);
}

.project-name {
  color: var(--muted);
  font-weight: 650;
}

.hname {
  color: var(--ink-2);
  font-weight: 650;
}

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

tr.total td {
  padding: 13px 14px;
  color: #fff;
  background: var(--ink) !important;
  border-bottom: 0;
  font-size: 13px;
  font-weight: 800;
}

tr.total td.num {
  color: #fff;
}

tr.total .varpos {
  color: #7fe0a8 !important;
}

tr.total .varneg {
  color: #ff9f92 !important;
}

tr.total .pctxt {
  color: #f1eee8;
}

.tlabel {
  font-family: var(--font-display);
}

.usedcell {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 108px;
}

.vbar {
  position: relative;
  flex: 1;
  height: 9px;
  overflow: hidden;
  background: #e6e0d8;
  border: 1px solid #d8d0c5;
  border-radius: var(--r-pill);
}

.vbar i {
  display: block;
  width: var(--pct);
  max-width: 100%;
  height: 100%;
  background: var(--muted-2);
}

.vbar .mark {
  position: absolute;
  top: -2px;
  right: 0;
  width: 2px;
  height: 13px;
  background: var(--ink);
  opacity: .45;
}

.vbar.is-under i { background: var(--ok); }
.vbar.is-ontrack i { background: var(--track); }
.vbar.is-over i { background: var(--bad); }
.vbar.is-unbudgeted i { background: var(--warn); }

.pctxt {
  width: 38px;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 11px;
  text-align: right;
}

.varpos {
  color: var(--ok);
  font-weight: 750;
}

.varneg {
  color: var(--bad);
  font-weight: 750;
}

.varzero {
  color: var(--muted-2);
}

.badge {
  min-height: 22px;
  padding: 4px 8px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 800;
}

.badge.under {
  color: var(--ok);
  background: var(--ok-soft);
  border-color: var(--ok-line);
}

.badge.on-track {
  color: var(--brand-2);
  background: var(--brand-tint);
  border-color: var(--brand-tint-2);
}

.badge.over {
  color: var(--bad);
  background: var(--bad-soft);
  border-color: var(--bad-line);
}

.badge.unbudgeted {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-line);
}

.badge.not-paid {
  color: var(--muted);
  background: var(--surface-2);
  border-color: var(--line-2);
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(280px, .8fr);
  gap: 16px;
  padding-bottom: 36px;
}

.split > div,
.panel,
.details,
.page > table,
.page > form:not(.toolbar) {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.split > div {
  padding: 14px;
}

.login-body {
  display: grid;
  min-height: 100vh;
  min-height: 100dvh;
  place-items: center;
  background: var(--paper);
}

.login-card {
  width: min(420px, calc(100vw - 32px));
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.login-card::before {
  display: block;
  width: min(260px, 100%);
  height: 76px;
  margin-bottom: 18px;
  content: "";
  background-color: #191817;
  background-image: url("/static/fervid-logo.svg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 210px auto;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 8px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 8px 20px rgba(40,38,36,.10);
}

.login-card h1 {
  font-family: var(--font-display);
}


/* UX implementation pass */
.page-banner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 28px 16px;
  margin-bottom: 14px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.page-banner h1 {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: 30px;
}

/* Request titles in edit subtitles must shrink inside the banner's flex row. */
.page-banner > div:not(.pb-actions) {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The banner's action cluster. Without this the buttons stretch to the
   banner's own align-items and wrap onto separate lines. */
.page-banner .pb-actions {
  display: flex;
  flex: none;
  gap: 8px;
  align-items: center;
}

.page-banner > form,
.page-banner > .btn,
.page-banner > .badge {
  flex: 0 0 auto;
  margin-top: 8px;
}

.head-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.metric-strip.compact {
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  margin: 16px 0 4px;
}

.metric {
  background: #fffdf9;
  border-color: var(--line);
}

.metric-value {
  color: var(--ink);
}

.tabs {
  margin: 0 28px 12px;
}

.tab {
  text-decoration: none;
}

.tab.is-active {
  color: #fff;
  background: var(--brand);
}

.matrix .project-col {
  position: sticky;
  left: 0;
  z-index: 2;
}

.matrix th.project-col,
.matrix td.project-spacer {
  width: var(--project-sticky-width);
  min-width: var(--project-sticky-width);
  max-width: var(--project-sticky-width);
}

.matrix .head-col {
  position: sticky;
  left: var(--project-sticky-width);
  z-index: 2;
}

.matrix th.project-col,
.matrix th.head-col {
  z-index: 4;
}

.matrix .project-row td {
  background: #e8e0d4 !important;
  color: var(--ink);
  font-weight: 800;
}

.matrix .project-row .project-col {
  font-family: var(--font-display);
  font-size: 15px;
}

.matrix .project-toggle {
  width: 100%;
  appearance: none;
  border: 0;
  background: transparent;
  color: inherit;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.matrix .project-toggle:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 4px;
}

.matrix .project-toggle .chev {
  width: 16px;
  display: inline-flex;
  justify-content: center;
  font-family: var(--font-ui);
  font-size: 12px;
  transition: transform 140ms ease;
}

.matrix .project-toggle[aria-expanded="false"] .chev {
  transform: rotate(-90deg);
}

.matrix .project-count {
  margin-left: auto;
  color: var(--muted);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
}

.matrix .project-spacer {
  color: transparent;
}

.matrix [hidden] {
  display: none;
}

.matrix tr.unpaid .varpos {
  color: var(--muted);
}

.matrix tr.unpaid .vbar i {
  background: transparent;
}

.btn.small {
  min-height: 26px;
  padding: 4px 8px;
  font-size: 12px;
}

.badge.locked,
.badge.warn {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-line);
}

.badge.good {
  color: var(--ok);
  background: var(--ok-soft);
  border-color: var(--ok-line);
}

.badge.info {
  color: var(--info);
  background: var(--info-soft);
  border-color: var(--info-line);
}

.badge.danger {
  color: var(--bad);
  background: rgba(180, 35, 24, .11);
  border-color: rgba(180, 35, 24, .24);
}

.badge.neutral {
  color: var(--muted);
  background: var(--surface-2);
}

.locked,
.alert.error,
.alert.success {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border-radius: 8px;
}

.locked {
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid var(--warn-line);
}

.alert.error {
  color: var(--bad);
  background: var(--fb-danger-soft);
  border-color: var(--bad-line);
}

.alert.success {
  color: var(--ok);
  background: var(--fb-success-soft);
  border-color: var(--ok-line);
}

.due {
  display: grid;
  gap: 2px;
}

.due small {
  color: var(--muted-2);
  font-size: 10px;
}

.duepill {
  display: inline-flex;
  min-width: 74px;
  justify-content: center;
  padding: 3px 7px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  color: var(--muted);
  background: var(--surface-2);
  font-size: 11px;
  font-weight: 800;
}

.duepill.overdue {
  color: var(--bad);
  background: var(--bad-soft);
  border-color: var(--bad-line);
}

.duepill.today {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-line);
}

.duepill.upcoming {
  color: var(--info);
  background: var(--info-soft);
  border-color: var(--info-line);
}

.duepill.settled {
  color: var(--ok);
  background: var(--ok-soft);
  border-color: var(--ok-line);
}

.payment-form {
  display: grid;
  gap: 12px;
  padding: 16px;
}

.payment-form fieldset {
  background: #fffdf9;
}

.payment-form .form-grid {
  align-items: start;
  gap: 12px;
}

.payment-form .field {
  align-content: start;
  grid-template-rows: 18px 34px minmax(16px, auto);
}

.payment-form .field > input,
.payment-form .field > select {
  height: 34px;
}

.payment-form .field > textarea {
  min-height: 86px;
}

/* The three payment grids set their own column shapes. The lower bound of each
   track used to be a pixel floor, which added up to more than the column is wide
   between the 860px breakpoint and a full desktop — 766px of minimums inside a
   666px container on the reference row — and the excess pushed the whole
   document sideways. A floor of 0 leaves the proportions untouched wherever
   there is room (the fr value wins whenever it is the larger of the two), and
   lets the tracks shrink instead of overflowing when there is not. */
.payment-core .form-grid {
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
}

.payment-core .field {
  grid-column: auto;
}

.payment-reference .form-grid {
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, .8fr);
}

.payment-reference .field {
  grid-column: auto;
}

.payment-proof .form-grid {
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.35fr);
}

.payment-proof .field {
  grid-column: auto;
}

.field small,
.hint {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
}

/* Where a request type admits only one treatment, the form states it instead of
   offering a choice it would refuse. Styled as a settled fact, not a control. */
.fixed-treatment {
  margin: 4px 0 0;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 13px;
}

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

.detail-grid > div {
  min-width: 0;
  padding: 10px;
  background: #fffdf9;
  border: 1px solid var(--line);
  border-radius: 6px;
}

.detail-grid dt {
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
}

.detail-grid dd {
  margin: 3px 0 0;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.danger-zone {
  border-color: rgba(180, 35, 24, .28) !important;
  background: #fff9f8 !important;
}

.file-list {
  display: grid;
  gap: 6px;
  padding-left: 18px;
}

.file-list li {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}

.timeline {
  margin-right: 28px;
  margin-left: 28px;
}

.timeline-item p {
  margin: 5px 0 0;
}

.timeline-item.good::before {
  background: var(--ok);
}

.timeline-item.info::before {
  background: var(--info);
}

.timeline-item.warn::before {
  background: var(--warn);
}

.timeline-item.danger::before {
  background: var(--bad);
}

pre {
  max-width: 100%;
  overflow-x: auto;
  padding: 8px;
  background: #f8f6f1;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
}

.setup-form label,
.toolbar label {
  min-width: 140px;
}

/* Single definition — the design-system checkline and the legacy one are the
   same component, so this rule carries both sets of declarations. */
.checkline {
  display: inline-flex !important;
  align-items: center;
  gap: 8px;
  min-width: auto !important;
  font-size: 13px;
  font-weight: 650;
  /* A label is as long as its sentence, and a confirmation sentence is longer
     than a phone is wide. nowrap made the label as wide as its text, so the
     head-deactivation warning scrolled 103px sideways at 390px (F-G-024). Short
     labels still sit on one line wherever there is room for them. */
  max-width: 100%;
  white-space: normal;
}

.checkline input {
  flex: 0 0 auto;
}

.budget-editor {
  overflow-x: auto;
}

/* .table-wrap sets width:100%, so side margins here would push the box past
   the container and overflow the document by exactly the margin. width:auto
   lets a block fill what is left after its own margins, which is the inset
   this rule was always after. */
.payments-table {
  width: auto;
  margin-right: 28px;
  margin-left: 28px;
}

.payments-table tr.is-voided td {
  color: var(--muted);
  background: #f8f5ef;
}

.actions-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  min-width: 220px;
}

/* On a <td> the flex box took the cell out of table layout: it stopped
   stretching to the row's height, so its bottom rule sat above the row's
   (ui-1). The cell stays a cell and its single wrapper lays the buttons out.
   The phone restack (table.t-cards tbody td) outranks this and keeps its flex. */
td.actions-cell { display: table-cell; }
td.actions-cell > span { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.inline-danger {
  position: relative;
  border: 0;
  background: transparent;
}

.inline-danger summary {
  min-height: 26px;
  padding: 4px 8px;
  color: var(--bad);
  border: 1px solid rgba(180, 35, 24, .24);
  border-radius: 6px;
  background: rgba(180, 35, 24, .08);
  font-size: 12px;
  font-weight: 800;
}

.inline-danger form {
  display: grid;
  gap: 8px;
  min-width: 230px;
  margin-top: 6px;
  padding: 10px;
  background: #fff9f8;
  border: 1px solid rgba(180, 35, 24, .28);
  border-radius: 8px;
}

.budget-editor table input,
.page > table input,
.page > table select {
  min-width: 130px;
}

.page > table input[type="checkbox"] {
  min-width: 0;
}



.error-state {
  max-width: 760px;
  margin: clamp(2rem, 8vw, 7rem) auto;
  padding: clamp(1.5rem, 4vw, 3rem);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1.5rem;
  align-items: start;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}

.error-code {
  min-width: 4.5rem;
  color: var(--bad);
  font-family: var(--font-display);
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 700;
  line-height: 1;
}

.request-id {
  color: var(--muted);
  font-size: .875rem;
}

.request-id code {
  overflow-wrap: anywhere;
}

/* ==========================================================================
   New components — layout
   ========================================================================== */

/* The gutter between the sidebar and the content lives here, on the column
   itself, so every block inside it is inset by the same amount.

   It used to be applied the other way round — an opt-in list of `.page > h1,
   .page > .panel, …` selectors further up this file — which stopped matching
   anything when this `.page-inner` wrapper was introduced between `.page` and
   the content. The result was that only the two blocks carrying their own
   padding (`.page-banner` and `.gridhead`) were indented; the other thirty-odd
   block types sat flush against the sidebar, while the 1180px measure left a
   gap on the right. Setting it once, here, is what keeps it consistent: a new
   block cannot be forgotten because there is no list to add it to. */
.page-inner {
  width: 100%;
  max-width: calc(1180px + var(--page-gutter) * 2);
  padding-inline: var(--page-gutter);
  /* The same gutter above the first block. A page that opens on a card rather
     than a banner — a request, a payment — otherwise drew that card's border
     along the very top of the window. */
  padding-top: var(--page-gutter);
}

/* Bands drawn edge to edge — the page header and the grid header — cancel the
   gutter and re-apply it as their own padding. They keep spanning the full
   width of the column, and their text still lines up with the content below. */
.page-inner > .page-banner,
.page-inner > .gridhead {
  margin-inline: calc(var(--page-gutter) * -1);
}

/* …and a band that opens the page cancels the top gutter too, so it still
   meets the top of the window. */
.page-inner > .page-banner:first-child,
.page-inner > .gridhead:first-child {
  margin-top: calc(var(--page-gutter) * -1);
}

/* The layout draws its flash (.alert.error / .alert.success) ahead of the
   page's own content, so on a page that opens with a band the band is no
   longer :first-child: the flash took the top gutter and the band sat under
   it, off the top edge (rbac-11 review). When a flash — or the pair of them —
   is followed by a band, the flash opens the page in the band's place: it
   takes the top gutter and the full column width, drops its rounded corners
   and side borders, and the band follows it flush. A flash ahead of a card
   keeps the gutter, as the card would. */
.page-inner > .alert:first-child:has(+ .page-banner, + .gridhead, + .alert + .page-banner, + .alert + .gridhead),
.page-inner > .alert:first-child + .alert:has(+ .page-banner, + .gridhead) {
  margin-inline: calc(var(--page-gutter) * -1);
  margin-bottom: 0;
  padding-inline: var(--page-gutter);
  border-radius: 0;
  border-left: 0;
  border-right: 0;
}

.page-inner > .alert:first-child:has(+ .page-banner, + .gridhead, + .alert + .page-banner, + .alert + .gridhead) {
  margin-top: calc(var(--page-gutter) * -1);
}

/* Three blocks predate the gutter and carry a hand-written 28px of their own.
   Nested inside a card that margin is real spacing and must stay, so it is only
   cancelled where the block sits directly in the content column and the gutter
   has already done the job. */
.page-inner > .timeline,
.page-inner > .payments-table,
.page-inner > .tabs {
  margin-inline: 0;
}

.side-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 8px 16px;
  margin-bottom: 4px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.side-brand .sq {
  display: grid;
  width: 30px;
  height: 30px;
  place-items: center;
  color: #fff;
  background: var(--brand);
  border-radius: 7px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
}

.side-brand b {
  display: block;
  color: #fff;
  font-size: 14px;
  font-weight: 750;
  letter-spacing: .01em;
}

.side-brand small {
  color: #8f8880;
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.side-nav a .n {
  min-width: 19px;
  padding: 1px 6px;
  margin-left: auto;
  color: #fff;
  background: rgba(255, 255, 255, .14);
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 750;
  text-align: center;
}

.side-nav a.active .n {
  background: rgba(0, 0, 0, .28);
}

.side-nav a.soon {
  color: #6b655e;
  cursor: not-allowed;
}

.side-nav a.soon:hover {
  color: #6b655e;
  background: transparent;
}

.side-nav a.soon .n {
  color: #8f8880;
  background: rgba(255, 255, 255, .07);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 11px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  border-radius: var(--r) var(--r) 0 0;
}

.card-head h2,
.card-head h3 {
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 750;
}

.card-body {
  padding: 14px;
}

.panel-pad-sm {
  padding: 12px;
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 22px 0 9px;
}

.section-head:first-child {
  margin-top: 0;
}

.section-head h2 {
  font-size: 17px;
}

.section-head .more-link {
  font-size: 12.5px;
  font-weight: 700;
}

.greet {
  margin-bottom: 12px;
}

.greet h1 {
  font-size: 21px;
}

.greet p {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}

.muted { color: var(--muted); }
.small { font-size: 12px; }
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }

.stack-8 > * + * { margin-top: 8px; }
.stack-12 > * + * { margin-top: 12px; }
.stack-16 > * + * { margin-top: 16px; }

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

.row-end {
  margin-left: auto;
}

/* Device-only blocks. Each is hidden by the viewport that should NOT see it,
   so the element keeps its own display (grid, flex, table) on the viewport
   that should. `display: revert` cannot do this: it rolls the whole author
   origin back, so a .type-grid.m-only would come back as `block`, not `grid`
   — measured, not assumed. Hence the complement query; it is the same 860px
   line, not a new breakpoint. */
@media (min-width: 861px) {
  .m-only { display: none !important; }
}

/* ==========================================================================
   New components — status pills and the waiting-on line
   ========================================================================== */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px 2px 7px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: 11.5px;
  font-weight: 750;
  white-space: nowrap;
}

.pill::before {
  flex: none;
  width: 6px;
  height: 6px;
  content: "";
  background: currentColor;
  border-radius: 50%;
}

.pill.awaiting   { color: var(--info);    background: var(--info-soft);  border-color: var(--info-line); }
.pill.returned   { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }
.pill.rejected   { color: #8d5a54;        background: var(--surface-2);  border-color: var(--line-2); }
.pill.approved   { color: var(--brand-2); background: var(--brand-tint); border-color: var(--brand-tint-2); }
.pill.hold       { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }
.pill.cancelreq  { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }
.pill.cancelled  { color: var(--muted);   background: var(--surface-2);  border-color: var(--line-2); }
.pill.processing { color: var(--brand-2); background: var(--brand-tint); border-color: var(--brand-tint-2); }
.pill.partial    { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }
.pill.discussion { color: var(--warn);    background: var(--warn-soft);  border-color: #e0c48b; }
.pill.completed  { color: var(--ok);      background: var(--ok-soft);    border-color: var(--ok-line); }
.pill.completed-partial { color: var(--ok); background: var(--surface); border-color: var(--ok); }
.pill.recoverable { color: #59409a;       background: #ece7f7;           border-color: #d5c9ee; }
.pill.neutral    { color: var(--muted);   background: var(--surface-2);  border-color: var(--line-2); }
.pill.good       { color: var(--ok);      background: var(--ok-soft);    border-color: var(--ok-line); }
.pill.bad        { color: var(--bad);     background: var(--bad-soft);   border-color: var(--bad-line); }
.pill.info       { color: var(--info);    background: var(--info-soft);  border-color: var(--info-line); }
.pill.warn       { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }

/* Variance-grid tones. The grid renders statusFor() straight into the class,
   so these five names are fixed by internal/app.statusForView, not chosen
   here. They carry the same values the .badge equivalents did, so retiring
   .badge (decision D5) recolours nothing — except On track, whose copied
   brand rust read as a cousin of Over while its legend swatch and bar are the
   green --track. The pill is that green now, dot and rule included (BV22). */
.pill.under      { color: var(--ok);      background: var(--ok-soft);    border-color: var(--ok-line); }
.pill.on-track   { color: #25603a;        background: #e9f5ed;           border-color: var(--track); }
.pill.on-track::before { background: var(--track); }
.pill.over       { color: var(--bad);     background: var(--bad-soft);   border-color: var(--bad-line); }
.pill.unbudgeted { color: var(--warn);    background: var(--warn-soft);  border-color: var(--warn-line); }
.pill.not-paid   { color: var(--muted);   background: var(--surface-2);  border-color: var(--line-2); }

/* Urgent is a solid fill plus a glyph. As a tint it is indistinguishable
   from the terracotta .pill.approved. */
.pill.urgent {
  color: #fff;
  background: var(--bad);
  border-color: var(--bad);
  letter-spacing: .02em;
}

.pill.urgent::before {
  width: auto;
  height: auto;
  content: "!";
  background: none;
  border-radius: 0;
  font-weight: 800;
}

/* Striped and dashed treatments carry "someone is mid-action". */
.pill.hold,
.pill.processing {
  background-image: repeating-linear-gradient(135deg, rgba(255, 255, 255, .55) 0 5px, transparent 5px 10px);
}

.pill.discussion { border-style: dashed; }

/* Closed states are deliberately quieter than live ones, but the quietening
   used to be `opacity: .78` over the whole pill, which fades the text as well
   as the frame: "Rejected — final" measured 3.2:1 against the card behind it
   (#a57d78 on #f3f1eb) where AA asks for 4.5:1 at this size, and it is 11.5px
   bold — small text, where legibility matters most. Fading only the frame keeps
   the pill visually recessed while the words stay readable, which takes the
   same label back over 5:1. This was the single cause of every colour-contrast
   failure the capture run found. */
.pill.rejected,
.pill.cancelled {
  border-color: color-mix(in srgb, var(--line-2) 78%, transparent);
  background-color: color-mix(in srgb, var(--surface-2) 78%, transparent);
}
.pill.no-dot::before { display: none; }

/* The signature element: a plain sentence naming who owes the next action. */
.waiting {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 650;
}

.waiting::before {
  content: "→";
  color: var(--line-2);
  font-weight: 800;
}

.waiting.you {
  color: var(--brand-2);
  font-weight: 750;
}

.waiting.you::before { color: var(--brand); }

.waiting.done { color: var(--ok); }
.waiting.done::before { content: "✓"; color: var(--ok); }

/* Rejected and cancelled are closed, not achieved — never the green tick. */
.waiting.closed { color: var(--muted-2); }
.waiting.closed::before { content: "—"; color: var(--line-2); }

/* ==========================================================================
   New components — banners
   Adds tone modifiers to .banner without disturbing the legacy
   `.banner, .alert, .locked-banner, .lock-banner` rule above, which still
   owns .alert and .locked-banner.
   ========================================================================== */

.banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 13px;
  margin-bottom: 14px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--r-sm);
  font-size: 13px;
}

.banner .b-ico {
  flex: none;
  font-size: 15px;
  line-height: 1.3;
}

.banner > div {
  min-width: 0;
  overflow-wrap: anywhere;
}

.banner b { font-weight: 750; }

.banner p {
  margin: 2px 0 0;
  color: var(--ink-2);
}

.banner .b-actions {
  display: flex;
  flex: none;
  gap: 7px;
  margin-left: auto;
}

.banner.info  { background: var(--info-soft);  border-color: var(--info-line);      border-left-color: var(--info); }
.banner.warn  { background: var(--warn-soft);  border-color: var(--warn-line);      border-left-color: var(--warn); }
.banner.bad   { background: var(--bad-soft);   border-color: var(--bad-line);       border-left-color: var(--bad); }
.banner.good  { background: var(--ok-soft);    border-color: var(--ok-line);        border-left-color: var(--ok); }
.banner.brand { background: var(--brand-tint); border-color: var(--brand-tint-2);   border-left-color: var(--brand); }
.banner.locked { background: var(--surface-2); border-left-color: var(--muted-2); }

/* A banner with a live feel. */
.reserve-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 10px 13px;
  margin-bottom: 14px;
  background: var(--brand-tint);
  border: 1px solid var(--brand-tint-2);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-sm);
}

.reserve-bar .rb-dot {
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--brand);
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(168, 58, 29, .16);
}

.reserve-bar b {
  color: var(--brand-2);
  font-size: 13px;
  font-weight: 750;
}

.reserve-bar .rb-meta {
  color: var(--muted);
  font-size: 12.5px;
}

.reserve-bar .rb-actions {
  display: flex;
  gap: 7px;
  margin-left: auto;
}

/* ==========================================================================
   New components — forms
   ========================================================================== */

.field > label,
.flabel {
  display: flex;
  align-items: baseline;
  gap: 6px;
  color: var(--ink);
  font-size: 12px;
  font-weight: 750;
}

.field > label .req {
  color: var(--bad);
  font-weight: 800;
}

.field > label .opt {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
}

.err {
  display: block;
  color: var(--bad);
  font-size: 11.5px;
  font-weight: 650;
}

fieldset {
  margin: 0;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

fieldset + fieldset {
  margin-top: 12px;
}

legend {
  padding: 0 7px;
  color: var(--brand-2);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Money input — the field people get wrong on a phone. */
.money-field .money-wrap {
  position: relative;
  display: block;
}

.money-field .money-wrap .cur {
  position: absolute;
  top: 50%;
  left: 13px;
  color: var(--muted);
  font-size: 19px;
  font-weight: 700;
  pointer-events: none;
  transform: translateY(-50%);
}

.money-field input {
  min-height: 54px;
  padding-left: 34px;
  font-size: 24px;
  font-weight: 780;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

.money-field .in-words {
  display: block;
  margin-top: 5px;
  color: var(--brand-2);
  font-size: 12.5px;
  font-weight: 700;
}

.money-field .in-words.empty {
  color: var(--muted);
  font-weight: 600;
}

/* Type chooser */
.type-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 11px;
}

.type-card {
  display: block;
  padding: 15px;
  color: inherit;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  text-decoration: none;
}

.type-card:hover {
  background: #fff;
  border-color: var(--brand);
  box-shadow: var(--shadow-1);
  text-decoration: none;
}

.type-card .tc-ico {
  display: grid;
  width: 38px;
  height: 38px;
  place-items: center;
  margin-bottom: 9px;
  color: var(--brand-2);
  background: var(--brand-tint);
  border-radius: var(--r-sm);
  font-size: 18px;
}

.type-card b {
  display: block;
  font-size: 15px;
  font-weight: 750;
}

.type-card p {
  margin: 3px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}

.type-card .tc-tag {
  display: inline-block;
  margin-top: 8px;
}

/* Choice list — radio cards. The highlight is CSS, not JS. */
.choice {
  display: grid;
  gap: 8px;
}

.choice label {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: 13px;
  font-weight: 650;
}

.choice label:hover {
  background: #fff;
  border-color: var(--line-2);
}

.choice label input {
  flex: none;
  margin-top: 2px;
}

.choice label b {
  display: block;
  font-size: 13.5px;
  font-weight: 750;
}

.choice label small {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

.choice label:has(input:checked),
.choice label.is-on {
  background: var(--brand-tint);
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
}

.choice label .outcome {
  flex: none;
  padding: 2px 8px;
  margin-left: auto;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 750;
  white-space: nowrap;
}

.choice label .outcome.good { color: var(--ok); background: var(--ok-soft); }
.choice label .outcome.warn { color: var(--warn); background: var(--warn-soft); }

/* Combobox */
.combo {
  position: relative;
}

.combo .combo-input {
  padding-right: 34px;
}

.combo .combo-caret {
  position: absolute;
  top: 50%;
  right: 11px;
  color: var(--muted);
  font-size: 11px;
  pointer-events: none;
  transform: translateY(-50%);
}

.combo-list {
  display: block;
  max-height: 290px;
  margin-top: 5px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  box-shadow: var(--shadow-2);
}

.combo-list .co {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  color: inherit;
  text-align: left;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}

.combo-list .co:last-child { border-bottom: 0; }

.combo-list .co:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.combo-list .co .co-main { min-width: 0; }

.combo-list .co b {
  display: block;
  font-size: 13px;
  font-weight: 720;
}

.combo-list .co small {
  display: block;
  color: var(--muted);
  font-size: 11.5px;
}

.combo-list .co .co-amt {
  flex: none;
  margin-left: auto;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

.combo-list .co-add {
  color: var(--brand-2);
  background: var(--brand-tint);
  font-weight: 750;
}

.combo-list .co.is-taken {
  opacity: .55;
  cursor: not-allowed;
}

/* Attachment uploader */
.uploader {
  padding: 13px;
  text-align: center;
  background: var(--surface-2);
  border: 1px dashed var(--line-2);
  border-radius: var(--r);
}

.uploader .up-ico {
  color: var(--muted);
  font-size: 20px;
}

.uploader b {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  font-weight: 720;
}

.uploader small {
  display: block;
  color: var(--muted);
  font-size: 11.5px;
}

.file-row {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 10px;
  padding: 9px 11px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

.file-row .f-ico {
  display: grid;
  flex: none;
  width: 30px;
  height: 30px;
  place-items: center;
  color: var(--info);
  background: var(--info-soft);
  border-radius: var(--r-sm);
  font-size: 13px;
  font-weight: 750;
}

.file-row b {
  font-size: 13px;
  font-weight: 700;
}

/* Keep the full original filename readable without pushing Download offscreen. */
.file-row > span:not(.f-ico):not(.f-actions) {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.file-row small {
  display: block;
  color: var(--muted);
  font-size: 11.5px;
}

.file-row .f-actions {
  display: flex;
  flex-shrink: 0;
  gap: 6px;
  margin-left: auto;
}

/* Action bar */
.action-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px;
  padding: 13px 0 0;
  margin-top: 16px;
  border-top: 1px solid var(--line);
}

.action-bar .ab-note {
  color: var(--muted);
  font-size: 12px;
}

.action-bar .row-end {
  margin-left: auto;
}

/* ==========================================================================
   New components — lists and detail
   ========================================================================== */

.req-list {
  display: grid;
  gap: 9px;
}

.req-card {
  display: block;
  min-width: 0;
  padding: 12px 13px;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-1);
  text-decoration: none;
}

.req-card:hover {
  background: #fff;
  border-color: var(--line-2);
  text-decoration: none;
}

.req-card .rc-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.req-card .rc-no {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: -.01em;
}

.req-card .rc-amt {
  font-size: 17px;
  font-weight: 780;
  font-variant-numeric: tabular-nums;
}

.req-card .rc-title {
  display: block;
  overflow-wrap: anywhere;
  margin-top: 3px;
  font-size: 14px;
  font-weight: 720;
}

.req-card .rc-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  color: var(--muted);
  font-size: 12px;
}

.req-card .rc-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 7px;
  padding-top: 9px;
  margin-top: 9px;
  border-top: 1px solid var(--line);
}

/* Category and workflow labels can exceed a narrow request card. */
.req-card .pill {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
}

.req-card.is-urgent { border-left: 3px solid var(--bad); }
.req-card.is-mine { border-left: 3px solid var(--brand); }

/* Request header block */
.req-head {
  min-width: 0;
  overflow-wrap: anywhere;
  padding: 14px;
  margin-bottom: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--r);
}

.req-head .rh-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.req-head .rh-no {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 700;
}

.req-head .rh-amt {
  font-size: 27px;
  font-weight: 780;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.req-head h1 {
  overflow-wrap: anywhere;
  margin: 6px 0 0;
  font-size: 19px;
}

.req-head .rh-meta {
  margin-top: 3px;
  color: var(--muted);
  font-size: 12.5px;
}

.req-head .rh-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 11px;
}

/* Timeline and conversation as one stream. Distinct from the legacy
   .timeline component above; both are in use and both must keep working. */
.thread {
  position: relative;
  padding: 4px 0 0;
  margin: 0;
  list-style: none;
}

.thread::before {
  position: absolute;
  top: 12px;
  bottom: 24px;
  left: 13px;
  width: 2px;
  content: "";
  background: var(--line);
  border-radius: 2px;
}

.thread > li {
  position: relative;
  padding: 0 0 16px 38px;
}

.thread > li:last-child { padding-bottom: 4px; }

.thread .tl-dot {
  position: absolute;
  top: 1px;
  left: 4px;
  display: grid;
  width: 20px;
  height: 20px;
  place-items: center;
  color: var(--muted);
  background: var(--surface-2);
  border: 2px solid var(--paper);
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--line);
  font-size: 10px;
  font-weight: 800;
}

.thread .tl-dot.ok    { color: var(--ok);      background: var(--ok-soft);    box-shadow: 0 0 0 1px var(--ok-line); }
.thread .tl-dot.bad   { color: var(--bad);     background: var(--bad-soft);   box-shadow: 0 0 0 1px var(--bad-line); }
.thread .tl-dot.warn  { color: var(--warn);    background: var(--warn-soft);  box-shadow: 0 0 0 1px var(--warn-line); }
.thread .tl-dot.brand { color: var(--brand-2); background: var(--brand-tint); box-shadow: 0 0 0 1px var(--brand-tint-2); }

.thread .tl-head {
  display: flex;
  min-width: 0;
  overflow-wrap: anywhere;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.thread .tl-head b {
  min-width: 0;
  font-size: 13.5px;
  font-weight: 750;
}

.thread .tl-head time {
  color: var(--muted);
  font-size: 11.5px;
}

.thread .tl-body {
  min-width: 0;
  overflow-wrap: anywhere;
  margin-top: 2px;
  color: var(--ink-2);
  font-size: 13px;
}

.thread .tl-body p { margin: 0 0 4px; }
.thread .tl-body p:last-child { margin-bottom: 0; }

/* Human comments read differently from system events. */
.thread li.is-comment .tl-body {
  padding: 9px 11px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 3px var(--r) var(--r) var(--r);
}

.thread li.is-comment.is-me .tl-body {
  background: var(--brand-tint);
  border-color: var(--brand-tint-2);
}

.thread .tl-change {
  padding: 7px 10px;
  margin-top: 6px;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 11.5px;
}

.thread .tl-change .was { color: var(--bad); text-decoration: line-through; }
.thread .tl-change .now { color: var(--ok); font-weight: 700; }

.thread .tl-file {
  display: inline-flex;
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  margin-top: 5px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: 12px;
  font-weight: 650;
}

.comment-box {
  padding: 11px;
  margin-top: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.comment-box textarea { min-height: 68px; }

.comment-box .cb-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
}

.comment-box .cb-actions .row-end { margin-left: auto; }

/* Dashboard work areas */
.work-areas {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.area {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.area .a-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 13px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}

.area .a-head .a-ico {
  display: grid;
  flex: none;
  width: 26px;
  height: 26px;
  place-items: center;
  color: var(--brand-2);
  background: var(--brand-tint);
  border-radius: var(--r-sm);
  font-size: 13px;
}

.area .a-head h2 {
  font-family: var(--font-ui);
  font-size: 13.5px;
  font-weight: 780;
}

.area .a-head .n {
  min-width: 22px;
  padding: 2px 8px;
  margin-left: auto;
  color: #fff;
  background: var(--brand);
  border-radius: var(--r-pill);
  font-size: 12px;
  font-weight: 780;
  text-align: center;
}

.area .a-head .n.zero {
  color: var(--muted);
  background: var(--surface-3);
}

.a-list { display: grid; }

.a-list a {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 13px;
  color: inherit;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}

.a-list a:last-child { border-bottom: 0; }

.a-list a:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.a-list .al-main {
  flex: 1 1 auto;
  min-width: 0;
}

.a-list .al-main b {
  display: block;
  font-size: 13px;
  font-weight: 720;
}

.a-list .al-main small {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 3px;
  color: var(--muted);
  font-size: 11.5px;
}

.a-list .al-amt {
  flex: none;
  font-size: 13.5px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

.area .a-foot {
  display: block;
  padding: 9px 13px;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  font-size: 12.5px;
  font-weight: 700;
}

.is-empty .a-list {
  padding: 20px 13px;
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
}

/* Notifications */
.notif-list { display: grid; }

.notif {
  display: flex;
  gap: 11px;
  padding: 12px 13px;
  color: inherit;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}

.notif:last-child { border-bottom: 0; }

.notif:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.notif.unread { background: var(--brand-tint); }
.notif.unread:hover { background: #ffe9de; }

.notif .n-ico {
  display: grid;
  flex: none;
  width: 30px;
  height: 30px;
  place-items: center;
  color: var(--muted);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  font-size: 13px;
}

.notif .n-main { min-width: 0; }

.notif .n-main b {
  font-size: 13px;
  font-weight: 720;
}

.notif .n-main p {
  margin: 1px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}

/* The request link inside a row's body. The row is itself the <a> to that
   request, so this is link text rather than a nested anchor; underline and
   the link colour say it is clickable, and a long URL may break anywhere so it
   never widens the row at 390px. */
.notif .n-link {
  color: var(--fb-accent-strong);
  text-decoration: underline;
  overflow-wrap: anywhere;
}

.notif time {
  flex: none;
  margin-left: auto;
  color: var(--muted);
  font-size: 11.5px;
}

/* Detail lists */
.dl {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  margin: 0;
}

.dl > div {
  min-width: 0;
  padding: 10px 13px;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.dl > div:nth-child(2n) { border-right: 0; }
.dl > div:last-child { border-bottom: 0; }

.dl dt {
  color: var(--muted);
  font-size: 11px;
  font-weight: 750;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.dl dd {
  overflow-wrap: anywhere;
  margin: 3px 0 0;
  font-size: 13.5px;
  font-weight: 650;
}

#payment-history li {
  overflow-wrap: anywhere;
}

.dl dd.big {
  font-size: 16px;
  font-weight: 780;
  font-variant-numeric: tabular-nums;
}

/* Accordion — the mobile face of the variance grid */
.acc {
  display: grid;
  gap: 9px;
}

.acc-item {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.acc-head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 13px;
  color: inherit;
  text-align: left;
  background: var(--surface-2);
  border: 0;
}

.acc-head .chev {
  flex: none;
  color: var(--muted);
  font-size: 11px;
  transition: transform .15s ease;
}

.acc-item.is-open .acc-head .chev { transform: rotate(90deg); }

.acc-head .ah-main { min-width: 0; }

.acc-head b {
  display: block;
  font-size: 14px;
  font-weight: 750;
}

.acc-head small {
  display: block;
  color: var(--muted);
  font-size: 11.5px;
}

.acc-head .ah-amt {
  flex: none;
  margin-left: auto;
  text-align: right;
}

.acc-head .ah-amt b {
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

.acc-body { padding: 4px 13px 11px; }
.acc-item:not(.is-open) .acc-body { display: none; }

.head-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}

.head-row:last-child { border-bottom: 0; }

.head-row .hr-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.head-row .hr-name {
  font-size: 13.5px;
  font-weight: 700;
}

.head-row .hr-figs {
  display: flex;
  gap: 14px;
  margin-top: 5px;
}

.head-row .hr-fig .l {
  display: block;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 750;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.head-row .hr-fig .v {
  font-size: 13px;
  font-weight: 720;
  font-variant-numeric: tabular-nums;
}

.head-row .hr-bar { margin-top: 8px; }

.head-row .hr-bar .vbar {
  display: block;
  width: 100%;
}

.good-num { color: var(--ok); }
.bad-num { color: var(--bad); }

/* Permission matrix */
.perm-table td.c input { margin: 0 auto; }
.perm-row-head { font-weight: 720; }

.perm-scope {
  display: inline-flex;
  gap: 4px;
}

.perm-scope label {
  /* Positioned so it becomes the containing block for the absolutely-positioned
     radio below. Without this the radio resolves against the document instead,
     which puts it outside the permission table's scrolling wrapper: it escapes
     that wrapper's clipping and drags the whole page 39px sideways at narrower
     desktop widths, even though the table itself scrolls correctly. */
  position: relative;
  padding: 3px 8px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 700;
}

.perm-scope label.is-on {
  color: var(--brand-2);
  background: var(--brand-tint);
  border-color: var(--brand);
}

/* The mockup's scope pills are static labels; production needs a real radio
   inside each one so a keyboard can reach it. The input is taken out of the
   visual flow and the label carries its focus ring. */
.perm-scope input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.perm-scope label:has(input:focus-visible) {
  box-shadow: 0 0 0 2px var(--brand);
}

.perm-acc {
  display: grid;
  gap: 8px;
}

.perm-acc .pa-item {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.perm-acc .pa-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 11px 12px;
  color: inherit;
  text-align: left;
  background: transparent;
  border: 0;
}

.perm-acc .pa-head b {
  font-size: 13.5px;
  font-weight: 720;
}

.perm-acc .pa-head .n {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.perm-acc .pa-body {
  display: grid;
  gap: 8px;
  padding: 0 12px 12px;
}

.perm-acc .pa-item:not(.is-open) .pa-body { display: none; }

/* Variance bars. As an inline span a .vbar ignores width and the bar
   disappears — inline-block is load-bearing, not cosmetic.
   .ok/.warn/.bad are aliases; the legacy .is-* modifiers stay. */
.vbar { display: inline-block; }
.vbar.ok i { background: var(--ok); }
.vbar.warn i { background: var(--warn); }
.vbar.bad i { background: var(--bad); }

/* ==========================================================================
   New components — overlay, sheet and tables
   ========================================================================== */

/* Fixed, unconditionally. The mockup only makes this absolute because its
   .appshell is a fake phone bezel. */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(24, 22, 20, .48);
}

.sheet {
  width: min(520px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  box-shadow: var(--shadow-2);
}

.sheet .sh-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 15px 16px 12px;
  border-bottom: 1px solid var(--line);
}

.sheet .sh-head h2 { font-size: 17px; }

.sheet .sh-head .sh-sub {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}

.sheet .sh-close {
  display: grid;
  flex: none;
  width: 30px;
  height: 30px;
  place-items: center;
  margin-left: auto;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: 15px;
}

.sheet .sh-body { padding: 15px 16px; }

.sheet .sh-foot {
  display: flex;
  gap: 9px;
  padding: 12px 16px;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--r) var(--r);
}

.sheet .sh-foot .row-end { margin-left: auto; }

/* Settlement comparison block */
.compare {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.compare .cmp-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 13px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.compare .cmp-row:last-child { border-bottom: 0; }

.compare .cmp-row .l {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 700;
}

.compare .cmp-row .v {
  font-size: 16px;
  font-weight: 780;
  font-variant-numeric: tabular-nums;
}

.compare .cmp-row.diff { background: var(--warn-soft); }
.compare .cmp-row.diff .l,
.compare .cmp-row.diff .v { color: var(--warn); }
.compare .cmp-row.match { background: var(--ok-soft); }
.compare .cmp-row.match .l,
.compare .cmp-row.match .v { color: var(--ok); }

/* Table chrome */
thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 9px 11px;
  color: var(--muted);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .06em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

tfoot td {
  padding: 10px 11px;
  color: #f0eae2;
  background: var(--sidebar);
  font-weight: 750;
}

tfoot td.num { font-variant-numeric: tabular-nums; }

td .t-sub {
  display: block;
  color: var(--muted);
  font-size: 11.5px;
}

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

/* Empty states put their one useful action inline in the sentence — "No
   payments match these filters. Record a payment" — where the link was told
   apart from the words around it by colour alone. Against this muted grey that
   is 1.34:1, well under the 3:1 that colour-only differentiation needs, so an
   underline carries the difference instead. Buttons are excluded: they already
   look like controls. */
.empty a:not(.btn) {
  text-decoration: underline;
}

/* Mobile filter row. .filter-btn is a desktop-visible control too. */
.m-filters { display: none; }

.filter-btn {
  position: relative;
  flex: none;
}

.filter-btn .n {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 16px;
  height: 16px;
  color: #fff;
  background: var(--brand);
  border-radius: var(--r-pill);
  font-size: 10px;
  font-weight: 750;
  line-height: 16px;
  text-align: center;
}

/* ==========================================================================
   New components — mobile chrome
   The three pieces are hidden on desktop and switched on inside the 860px
   block below.
   ========================================================================== */

.m-topbar,
.tabbar {
  display: none;
}

.m-topbar .m-back {
  display: grid;
  flex: none;
  width: 30px;
  height: 30px;
  place-items: center;
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border-radius: var(--r-sm);
  font-size: 15px;
  text-decoration: none;
}

.m-topbar .m-back:hover {
  background: rgba(255, 255, 255, .18);
  text-decoration: none;
}

.m-topbar .m-title { min-width: 0; }

.m-topbar .m-title b {
  display: block;
  font-size: 14.5px;
  font-weight: 720;
  line-height: 1.2;
}

.m-topbar .m-title small {
  display: block;
  color: #9d968e;
  font-size: 11px;
}

.m-topbar .m-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}

.m-topbar .m-icon {
  position: relative;
  display: grid;
  width: 32px;
  height: 32px;
  place-items: center;
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border-radius: var(--r-sm);
  font-size: 14px;
  text-decoration: none;
}

.m-topbar .m-icon:hover {
  background: rgba(255, 255, 255, .18);
  text-decoration: none;
}

.m-topbar .m-icon .dot {
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  color: #fff;
  background: var(--brand);
  border: 2px solid var(--sidebar);
  border-radius: var(--r-pill);
  font-size: 10px;
  font-weight: 750;
  line-height: 16px;
  text-align: center;
}

.m-topbar .m-cta {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 11px;
  color: #fff;
  background: var(--brand);
  border-radius: var(--r-sm);
  font-size: 12.5px;
  font-weight: 720;
  white-space: nowrap;
  text-decoration: none;
}

.m-topbar .m-cta:hover {
  background: var(--brand-2);
  text-decoration: none;
}

.tabbar a {
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: 5px 2px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
  text-decoration: none;
}

.tabbar a:hover { text-decoration: none; }

.tabbar a .ti {
  font-size: 16px;
  line-height: 1;
}

.tabbar a.active { color: var(--brand-2); }

.tabbar .fab {
  display: grid;
  width: 50px;
  height: 50px;
  place-items: center;
  justify-self: center;
  margin-bottom: 2px;
  color: #fff;
  background: var(--brand);
  border-radius: var(--r-pill);
  box-shadow: 0 6px 14px rgba(168, 58, 29, .38);
  font-size: 22px;
  line-height: 1;
}

.tabbar .fab-wrap {
  display: grid;
  justify-items: center;
  gap: 2px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
  text-decoration: none;
}

.tabbar .fab-wrap:hover { text-decoration: none; }

/* Fixed, like .overlay — the mockup's absolute positioning only works
   because its shell is a fake phone. */
.more-sheet {
  position: fixed;
  inset: 0;
  z-index: 40;
  padding: 0 0 90px;
  overflow-y: auto;
  background: var(--paper);
}

.more-sheet .ms-head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px;
  color: #fff;
  background: var(--sidebar);
}

.more-sheet .ms-head b {
  font-size: 15px;
  font-weight: 720;
}

.more-sheet .ms-close {
  display: grid;
  width: 30px;
  height: 30px;
  place-items: center;
  margin-left: auto;
  color: #fff;
  background: rgba(255, 255, 255, .12);
  border: 0;
  border-radius: var(--r-sm);
  font-size: 16px;
}

.more-sheet .ms-group {
  margin: 14px 14px 5px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.more-sheet .ms-list {
  margin: 0 14px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.more-sheet .ms-list a {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 13px;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  font-weight: 650;
  text-decoration: none;
}

.more-sheet .ms-list a:last-child { border-bottom: 0; }

.more-sheet .ms-list a:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.more-sheet .ms-list a .ico {
  width: 18px;
  color: var(--muted);
  text-align: center;
}

.more-sheet .ms-list a .n {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
  font-weight: 650;
}

.more-sheet .ms-list a.soon {
  color: var(--muted-2);
  opacity: .72;
  cursor: not-allowed;
}

.more-sheet .ms-list a.soon .n {
  padding: 1px 7px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  font-size: 10px;
  font-weight: 750;
}

/* ==========================================================================
   Responsive — two breakpoints, 860 and 560. Nothing else.
   860 is the desktop/mobile line: the shell collapses here exactly once.
   ========================================================================== */

@media (max-width: 860px) {
  /* There is no sidebar at this width, but the content still needs an edge.
     This used to be 0px, on the belief that each narrow block set its own 14px
     inset. Only the page banner and the grid header did; every card, list,
     filter row and heading sat flush against the glass with its border and
     corners clipped. The column carries the gutter here as it does on desktop,
     and the two bands re-apply the same value as their own padding below. */
  :root {
    --page-gutter: 16px;
  }

  body {
    font-size: 13px;
  }

  .d-only { display: none !important; }

  .banner { flex-wrap: wrap; }

  .banner .b-actions {
    width: 100%;
    margin-left: 0;
  }

  .form-grid > .field.m-half {
    grid-column: span 6;
  }

  .type-grid {
    grid-template-columns: 1fr;
  }

  /* On a phone the types must fit one view, so the icon sits beside the
     text instead of above it. */
  .type-card {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr);
    padding: 13px;
    column-gap: 12px;
    row-gap: 2px;
  }

  .type-card .tc-ico {
    grid-row: 1 / span 3;
    width: 36px;
    height: 36px;
    margin-bottom: 0;
    font-size: 16px;
  }

  .type-card .tc-tag {
    justify-self: start;
    margin-top: 6px;
  }

  /* No negative side margin: the production .page does not carry the
     mockup's 14px padding, and -14px pushes the document 14px wide. */
  .action-bar {
    position: sticky;
    bottom: 0;
    z-index: 15;
    padding: 11px 14px;
    margin: 16px 0 0;
    background: rgba(251, 250, 247, .97);
    border-top: 1px solid var(--line);
    box-shadow: 0 -6px 18px rgba(31, 39, 37, .07);
    backdrop-filter: blur(6px);
  }

  .action-bar .btn { flex: 1 1 auto; }
  .action-bar .btn.wide { flex-basis: 100%; }

  /* Some actions carry a person's name ("Save and notify …"), so a label has
     no length a template can promise. A button that refused to wrap was as
     wide as its name and ran off the right edge of the bar. */
  .action-bar .btn {
    max-width: 100%;
    text-align: center;
    white-space: normal;
  }

  .work-areas {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .dl {
    grid-template-columns: 1fr;
  }

  .dl > div {
    border-right: 0;
  }

  .overlay {
    align-items: end;
    padding: 0;
  }

  .sheet {
    width: 100%;
    max-height: 88%;
    border-bottom: 0;
    border-radius: 16px 16px 0 0;
  }

  .sheet .sh-foot { flex-wrap: wrap; }
  .sheet .sh-foot .btn { flex: 1 1 auto; }

  /* Restack tables into labelled cards. */
  table.t-cards { display: block; }
  table.t-cards thead { display: none; }

  table.t-cards tbody {
    display: grid;
    gap: 9px;
  }

  table.t-cards tbody tr {
    display: block;
    padding: 11px 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
  }

  table.t-cards tbody tr:hover { background: var(--surface); }

  table.t-cards tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 3px 0;
    text-align: right;
    border: 0;
  }

  table.t-cards tbody td::before {
    flex: none;
    color: var(--muted);
    content: attr(data-label);
    font-size: 11px;
    font-weight: 750;
    letter-spacing: .05em;
    text-align: left;
    text-transform: uppercase;
  }

  table.t-cards tbody td[data-label=""]::before { content: none; }

  table.t-cards tbody td.t-lead {
    display: block;
    padding-bottom: 7px;
    margin-bottom: 5px;
    border-bottom: 1px solid var(--line);
    font-size: 14px;
    font-weight: 720;
    text-align: left;
  }

  table.t-cards tbody td.t-lead::before { content: none; }

  table.t-cards tfoot {
    display: block;
    margin-top: 9px;
    overflow: hidden;
    border-radius: var(--r);
  }

  table.t-cards tfoot tr { display: block; }

  table.t-cards tfoot td {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 12px;
  }

  table.t-cards tfoot td::before {
    color: #a9a29a;
    content: attr(data-label);
    font-size: 11px;
    font-weight: 750;
    text-transform: uppercase;
  }

  table.t-cards tfoot td[data-label=""] {
    display: block;
    padding-top: 10px;
    font-size: 13.5px;
    text-align: left;
  }

  /* Only the wrapper around a restacking table loses its frame; wrappers
     around tables that still scroll horizontally keep theirs. */
  .table-wrap:has(table.t-cards) {
    overflow: visible;
    background: transparent;
    border: 0;
    border-radius: 0;
  }

  /* The desktop toolbar only steps aside once a mobile filter row exists to
     replace it. Hiding it unconditionally would remove working controls from
     every screen that has not been rebuilt yet. */
  .m-filters {
    display: flex;
    align-items: center;
    gap: 8px;
    /* room for the .filter-btn count badge, which overhangs by 5px */
    padding-right: 6px;
    margin-bottom: 11px;
  }

  .m-filters .m-search { flex: 1 1 auto; }
  .m-filters .m-search input { min-height: 36px; }

  .page:has(.m-filters) .toolbar,
  .page-inner:has(.m-filters) .toolbar {
    display: none;
  }

  /* Touch targets ------------------------------------------------------
     Desktop is a pointer: 34px controls are precise and keep screens dense.
     A phone is a thumb, and 34px is where mis-taps start. Everything the
     user can operate grows to 44px here, and nowhere else -- desktop
     density is a deliberate choice, not an oversight to correct. */
  .btn,
  button,
  input[type="submit"],
  .acc-head,
  .pa-head,
  .segmented a,
  .segmented button,
  .tab {
    min-height: 44px;
  }

  /* Row-level actions sit inside dense lists, where 44px would push the row
     past a thumb's reach anyway. 40px is the floor. */
  .btn-sm,
  .btn.small,
  .compact button,
  button.small,
  .actions-cell .btn {
    min-height: 40px;
    padding-right: 12px;
    padding-left: 12px;
  }

  input,
  select,
  textarea {
    /* 16px also stops iOS Safari zooming the viewport on focus. */
    min-height: 44px;
    font-size: 16px;
  }

  /* Mobile chrome ------------------------------------------------------ */

  /* Nothing may sit under the fixed tab bar. The bar measures a hair over
     96px once its own border/backdrop are laid out (96.2px observed), so a
     reserve of exactly 96px left a sub-pixel gap that a sticky .action-bar
     could round the wrong way into an overlap. 100px keeps a real margin
     instead of a coin flip. */
  .page {
    padding-bottom: calc(100px + env(safe-area-inset-bottom));
  }

  /* Padding protects the *end* of the document. It does nothing for a control
     in the middle of a long page: scrolling that into view aligns it with the
     bottom edge, which is exactly where the fixed bar sits, and the tap lands
     on the tab bar instead. scroll-margin-bottom reserves the band during
     scroll-into-view, so anything the user can operate stops above it. */
  .page a,
  .page button,
  .page summary,
  .page input,
  .page select,
  .page textarea,
  .page [tabindex] {
    scroll-margin-bottom: calc(112px + env(safe-area-inset-bottom));
  }

  .m-topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 54px;
    padding: 8px 14px 8px 12px;
    color: #fff;
    background: var(--sidebar);
  }

  /* Fixed to the viewport, not the shell, and clear of the home indicator. */
  .tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 30;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    align-items: end;
    padding: 6px 6px 10px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom));
    background: rgba(251, 250, 247, .97);
    border-top: 1px solid var(--line);
    backdrop-filter: blur(6px);
  }

  .appshell,
  .app-shell,
  .layout,
  .page-shell {
    display: block;
    grid-template-columns: 1fr;
  }

  /* The mobile chrome replaces the sidebar outright — the top bar, tab bar and
     More sheet carry the same nav the sidebar does. Leaving it on screen put
     two "Primary" navigation landmarks in the accessibility tree and pushed
     every page down by half a viewport before its first heading. */
  .sidebar,
  .app-sidebar {
    display: none;
  }


  .side-nav {
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  }

  .brand,
  .app-brand {
    margin-bottom: 8px;
    padding-bottom: 8px;
  }

  .nav,
  .app-nav {
    display: flex;
    gap: 4px;
    overflow-x: auto;
    padding-bottom: 2px;
  }

  .nav a,
  .nav-item,
  .app-nav a {
    flex: 0 0 auto;
  }

  .main,
  .app-main,
  main {
    padding: 14px 12px 24px;
  }

  .page-header,
  .section-header,
  .topbar,
  .app-topbar {
    align-items: stretch;
    flex-direction: column;
  }

  .split {
    grid-template-columns: 1fr;
  }

  .toolbar,
  .filter-bar,
  .actions,
  .filters {
    align-items: stretch;
  }

  .toolbar > *,
  .filter-bar > *,
  .actions > *,
  .filters > * {
    flex: 1 1 auto;
  }

  .summary-strip,
  .stats-grid,
  .details-grid,
  .detail-grid,
  .detail-grid.details {
    grid-template-columns: 1fr;
  }

  .metric-strip,
  .metric-strip.compact {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .form-grid {
    grid-template-columns: 1fr;
  }

  .field,
  .field.span-2,
  .field.span-3,
  .field.span-4,
  .field.span-5,
  .field.span-6,
  .field.span-7,
  .field.span-8,
  .field.span-9,
  .field.span-12 {
    grid-column: 1 / -1;
  }

  .payment-core .form-grid,
  .payment-reference .form-grid,
  .payment-proof .form-grid {
    grid-template-columns: 1fr;
  }

  .form-actions,
  .modal-actions {
    flex-direction: column-reverse;
  }

  .form-actions .btn,
  .form-actions button,
  .modal-actions .btn,
  .modal-actions button {
    width: 100%;
  }

  th,
  td {
    padding: 7px 8px;
  }

  table.matrix {
    --project-sticky-width: 104px;
    min-width: 980px;
  }

  .gridhead,
  .gridwrap {
    padding-right: var(--page-gutter);
    padding-left: var(--page-gutter);
  }

  .page > h1,
  .page > .panel,
  .page > form:not(.toolbar),
  .page > table,
  .page > .table-wrap,
  .page > .split,
  .page > .details,
  .page > h2,
  .page > .alert,
  .page > .locked,
  .page > .toolbar:not(.gridhead .toolbar) {
    margin-right: 14px;
    margin-left: 14px;
  }

  .page-banner {
    flex-direction: column;
    padding-right: var(--page-gutter);
    padding-left: var(--page-gutter);
  }

  .page-banner h1,
  .gridhead h1 {
    font-size: 28px;
  }

  .tabs {
    margin-right: 14px;
    margin-left: 14px;
    overflow-x: auto;
  }

  .timeline,
  .payments-table {
    margin-right: 14px;
    margin-left: 14px;
  }
}

@media (max-width: 560px) {
  /* The pre-redesign sidebar-as-sticky-panel and its two-column nav lived
     here. Both are unreachable now that the 860px block hides the sidebar
     outright, so they are gone rather than left to contradict it. */

  .toolbar > *,
  .toolbar label,
  .toolbar .btn,
  .toolbar button {
    width: 100%;
  }

  .metric-strip,
  .metric-strip.compact {
    grid-template-columns: 1fr;
  }

  table.matrix {
    min-width: 1080px;
  }

  .error-state {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   form-7 (2026-09-25 fix wave): sibling controls share a height and a width.

   Height. .field is a grid, and a .form-grid row stretches every field in it
   to the tallest — the one carrying a hint or the amount-in-words line. With
   align-content left at its default the leftover height was shared out across
   the field's rows, so the control in a hint-less field grew and sat lower
   than its neighbour (Head 47px beside Project 35px, Needed by 62px beside
   Amount). Rows keep their natural height; the field still fills the row.

   Width. Below 860px the form is one column, but `.form-grid > .field.m-half
   { grid-column: span 6 }` (0,3,0) outranked `.field.span-* { grid-column:
   1 / -1 }` (0,2,0), so an m-half field still spanned six tracks of a
   one-track grid — five implicit zero-width columns plus five 12px gaps —
   and every other field in the same grid came out 60px narrower than it.
   ========================================================================== */
.field,
.form-field {
  align-content: start;
}

@media (max-width: 860px) {
  .form-grid > .field.m-half {
    grid-column: 1 / -1;
  }
}

/* UX review: keyboard navigation, control boundaries and narrow-screen text. */
:root {
  --input-border: #81766b;
  --focus: 0 0 0 3px #245b8f;
}

input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
  border-color: var(--input-border);
}
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"],
.field-error input,
.field-error select,
.field-error textarea {
  border-color: var(--fb-danger);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--fb-accent);
}

.sidebar :focus-visible {
  outline: 3px solid #ffdc8c;
  outline-offset: 2px;
  box-shadow: none;
}

/* Keep mobile navigation focus inside the rounded, clipped list. */
.more-sheet .ms-list a:focus-visible {
  outline: 3px solid #245b8f;
  outline-offset: -3px;
  box-shadow: none;
}
.more-sheet .ms-close:focus-visible {
  outline: 3px solid #ffdc8c;
  outline-offset: 2px;
  box-shadow: none;
}

.skip-link {
  position: fixed;
  left: 12px;
  top: 8px;
  z-index: 10000;
  padding: 10px 16px;
  color: #fff;
  background: #245b8f;
  border-radius: 6px;
  transform: translateY(-160%);
}
.skip-link:focus {
  transform: translateY(0);
  color: #fff;
  outline: 3px solid #ffdc8c;
  outline-offset: 2px;
}
main.page:focus { outline: none; box-shadow: none; }

.type-card,
.type-card > * { min-width: 0; }
.type-card .tc-tag {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
}

.error-summary {
  border: 2px solid var(--fb-danger);
  border-radius: 6px;
  padding: 14px 18px;
  margin-bottom: 18px;
  background: #fff;
}
.error-summary a { color: var(--fb-danger); text-decoration: underline; }
.error-summary h2 { margin: 0 0 8px; font-size: 18px; }
.error-summary ul { margin: 0; padding-left: 20px; }
.field-error-message { margin: 4px 0; }

/* Contact links embedded in explanatory text remain identifiable without color. */
a[href^="mailto:"] { text-decoration: underline; }

/* Constraint errors use the same layout on native, HTMX and row-edit forms. */
.client-error-summary { margin-top: 6px; flex: 0 0 100%; grid-column: 1 / -1; width: 100%; box-sizing: border-box; }
.client-error-summary p { margin: 0 0 8px; }
.client-error-summary:focus { outline: 3px solid var(--fb-danger); outline-offset: 3px; }
.client-field-error { display: block; color: var(--fb-danger); font-size: 13px; line-height: 1.45; white-space: normal; }
