/* Invoice show */
.nav-back {
  font-size: 0.88rem;
  color: var(--teal);
  text-decoration: none;
}

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

.invoice-show {
  /* Primarily a desktop review screen: the line-items table carries a status
     column plus three assignment selects, so give every section room. */
  max-width: 1250px;
  margin: 0 auto;
  /* Extra room at the foot: the fixed project-notes launcher (40px at
     right/bottom 24px, project_notes.css) sits over this column's right gutter
     once the viewport is near the 1250px max-width, and the review footer's
     Approve / Reject buttons are right-aligned at the very bottom of the page.
     2.5rem left them level with the launcher's top edge; 5rem clears it. */
  padding: 2.5rem 2rem 5rem;

  /* INT brand palette, scoped to this screen (INT-54). Teal primary, grey for
     borders/secondary text. Overrides the app-wide vars only within the invoice
     review screen — no global recolour. */
  --teal: #009ba0;
  --teal-dark: #00787c;
  --gray-mid: #8f8f8f;

  /* INT orange — used ONLY for the reject action and formatting-difference
     highlights on this screen. Kept as its own token (not the shared --warning)
     so amber warning states keep their colour. */
  --int-orange: #e86721;
  --int-orange-dark: #c9551a;
}

/* Reject is an orange action on this screen, not the app-wide danger red.
   Error/rejected states keep their own (red) classes. */
.invoice-show .btn-danger {
  background: var(--int-orange);
  border-color: var(--int-orange);
  color: var(--white);
}
.invoice-show .btn-danger:hover {
  background: var(--int-orange-dark);
  border-color: var(--int-orange-dark);
  color: var(--white);
}

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

.invoice-header h1 {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gray-dark);
  margin-bottom: 0.35rem;
}

.invoice-meta {
  font-size: 0.85rem;
  color: var(--gray-mid);
}

.invoice-header-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
}

.invoice-parties {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

@media (max-width: 600px) {
  .invoice-parties { grid-template-columns: 1fr; }
}

.invoice-party {
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--teal);
  border-radius: 8px;
  padding: 1.25rem;
  font-size: 0.88rem;
  color: var(--gray-mid);
  line-height: 1.7;
}

.invoice-party h3 {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 0.5rem;
}

.party-name {
  font-weight: 600;
  color: var(--gray-dark);
  font-size: 0.95rem;
}

.party-meta { color: var(--gray-mid); }

.vendor-match {
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--border);
}

.vendor-match-label {
  display: block;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-mid);
  margin-bottom: 0.5rem;
}

.vendor-match-actions {
  margin-top: 0.5rem;
}

.vendor-match-confirm-btn { width: 100%; }

.vendor-match-choices {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.85rem;
  background: var(--surface-muted);
  border: 1px solid var(--teal-border);
  border-radius: 6px;
}

/* Empty first track, prompt, link. The two outer tracks are both 1fr, so the
   prompt stays centred on the whole box while the link keeps the right corner
   — and tracks can't overlap however the prompt wraps. */
.vendor-match-choose-header--with-create {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: 0.75rem;
}

.vendor-match-choose-header--with-create .vendor-match-choose-prompt { grid-column: 2; }

.vendor-match-choose-header--with-create > form.button_to {
  grid-column: 3;
  justify-self: end;
  margin: 0;
}

/* Too narrow for a corner: stack the link under the prompt. */
@media (max-width: 40rem) {
  .vendor-match-choose-header--with-create {
    grid-template-columns: 1fr;
  }

  .vendor-match-choose-header--with-create .vendor-match-choose-prompt,
  .vendor-match-choose-header--with-create > form.button_to { grid-column: 1; }
}

.vendor-match-choose-prompt {
  margin: 0;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--gray-dark);
  text-align: center;
}

.vendor-match-choose-help {
  margin: 0;
  font-size: 0.8rem;
  color: var(--gray-mid);
  line-height: 1.5;
  text-align: center;
}

.vendor-match-choose-help strong { color: var(--gray-dark); }

/* Grid, not flex: a bare <a class="btn"> and a button_to <form> sized
   differently under flex. Equal tracks, equal heights, any number of choices. */
.vendor-match-choose-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.5rem;
}

/* base.css inline-blocks form.button_to, which would shrink-wrap the button. */
.vendor-match-choose-row > form.button_to { display: flex; }
.vendor-match-choose-row > form .btn { width: 100%; }
.vendor-match-choose-row .btn {
  line-height: 1.5;
  text-align: center;
}

/* Action button color coding */
.btn-overwrite {
  background: var(--warning);
  color: var(--white);
}
.btn-overwrite:hover { background: var(--warning-dark); color: var(--white); }

.btn-new-vendor {
  background: var(--success);
  color: var(--white);
}
.btn-new-vendor:hover { background: var(--success-dark); color: var(--white); }

/* Match panel intro & legend */
.vendor-match-intro {
  font-size: 0.85rem;
  color: var(--gray-mid);
  margin: 0 0 0.65rem;
  line-height: 1.5;
}

.vendor-match-legend {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0.65rem 0.85rem;
  background: var(--surface-muted);
  border: 1px solid var(--teal-border);
  border-radius: 6px;
  font-size: 0.82rem;
  color: var(--gray-mid);
  line-height: 1.55;
}

.vendor-match-legend li + li { margin-top: 0.3rem; }
.vendor-match-legend strong { color: var(--gray-dark); }

.vendor-name-link {
  color: var(--teal);
  text-decoration: none;
}

.vendor-name-link:hover { text-decoration: underline; }

.vendor-match-create-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--border);
  flex-wrap: wrap;
}

.vendor-match-create-row form { flex: 0 0 auto; }

.vendor-match-choices--create {
  align-items: center;
  margin-top: 0.5rem;
}

.vendor-match-empty {
  font-size: 0.88rem;
  color: var(--gray-mid);
  margin: 0.5rem 0 0;
  line-height: 1.5;
}

/* Stacked parties layout (review state) */
.invoice-parties--stacked { grid-template-columns: 1fr; }

/* Bottom approve/reject footer */
.review-footer {
  margin-top: 2rem;
  padding: 1.5rem;
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--teal);
  border-radius: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.review-footer-text {
  flex: 1;
  min-width: 240px;
  margin: 0;
  font-size: 0.9rem;
  color: var(--gray-mid);
  line-height: 1.55;
}

.review-footer-actions {
  display: flex;
  gap: 0.75rem;
}

.review-footer-actions form { display: inline; }

.review-footer-actions .btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.review-footer-warning {
  flex-basis: 100%;
  margin: 0.65rem 0 0;
  text-align: right;
  font-size: 0.82rem;
  color: var(--warning-dark);
}

/* Non-blocking advisory (e.g. a quantity × unit price ≠ total row): same warm
   palette as the blocker warnings above, but NOT a .review-footer-warning, so
   the review-footer controller never counts it against the Approve button. */
.review-footer-note {
  flex-basis: 100%;
  margin: 0.65rem 0 0;
  text-align: right;
  font-size: 0.82rem;
  color: var(--warning-dark);
}

/* Inline German-VAT (net vs gross) toggle, between the supporting-documents
   section and the approve footer. Matches the review-footer card, minus the
   teal accent — it's a setting, not the primary call to action. */
.german-vat-review {
  margin-top: 2rem;
  padding: 1rem 1.25rem;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 1rem 1.5rem;
  flex-wrap: wrap;
}

.german-vat-review-form { margin: 0; }

.german-vat-review .inline-check {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--gray-dark);
  cursor: pointer;
}

.german-vat-review input[type="checkbox"] {
  width: auto;
  margin: 0;
  cursor: pointer;
}

.german-vat-review-hint {
  flex: 1;
  min-width: 240px;
  margin: 0;
  font-size: 0.82rem;
  color: var(--gray-mid);
  line-height: 1.5;
}

.approved-footer,
.rejected-footer {
  margin-top: 2rem;
  padding: 1.25rem 1.5rem;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 1rem;
  animation: approved-footer-in 0.35s ease-out;
}

.approved-footer {
  background: var(--success-bg);
  border: 1px solid var(--success-border);
  border-left: 4px solid var(--success);
  color: var(--success-dark);
}

.rejected-footer {
  background: var(--danger-bg);
  border: 1px solid var(--danger-border);
  border-left: 4px solid var(--danger);
  color: var(--danger-dark);
}

.approved-footer-icon,
.rejected-footer-icon {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--white);
}

.approved-footer-icon { background: var(--success); }
.rejected-footer-icon { background: var(--danger); }

.approved-footer-title,
.rejected-footer-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}

.approved-footer-meta,
.rejected-footer-meta {
  margin: 0.15rem 0 0;
  font-size: 0.85rem;
  opacity: 0.85;
}

@keyframes approved-footer-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Pushes the revert action to the right edge of the approved footer's flex row. */
.approved-footer-actions { margin-left: auto; }

/* Why the revert button is absent: a line item is billed on a donor invoice, so
   the state machine locks the revert (Invoice#can_transition_to?). Sits in the
   footer's right slot where the button would be; muted, since it's guidance, not
   an action. The lock glyph mirrors the cashbook frozen-state language. */
.approved-footer-blocked-note {
  margin: 0 0 0 auto;
  max-width: 24rem;
  text-align: right;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--success-dark);
  opacity: 0.9;
}

.approved-footer-blocked-note .icon { margin-right: 0.3rem; }

.approved-footer-blocked-note a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
}

/* State-machine transition button: .btn-state chrome lives in badges.css.
   Tinted with the colour of the state it moves the invoice TO, so the revert
   reads in the same colour language as the status badges. The U-turn icon
   carries the revert meaning. .btn-state-review uses the review status
   palette (badges.css .status-review). */
.btn-state-review { background: var(--review-bg); color: var(--review); border-color: var(--review-border); }
.btn-state-review:hover { background: var(--review-bg-hover); color: var(--review); }

.vendor-match-list {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.vendor-match-item {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.65rem 0.75rem;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.vendor-match-item-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.vendor-fields {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 0.75rem;
  row-gap: 0.2rem;
  margin: 0.4rem 0 0;
}

.vendor-fields dt {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.7rem;
  color: var(--gray-mid);
  align-self: center;
}

.vendor-fields dd {
  margin: 0;
  color: var(--gray-dark);
  font-size: 0.85rem;
  word-break: break-word;
}

/* Side-by-side comparison */
.vendor-compare {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5rem 0 0.85rem;
  font-size: 0.85rem;
  table-layout: fixed;
}

.vendor-compare thead th {
  text-align: left;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gray-mid);
  padding: 0.4rem 0.65rem;
  border-bottom: 1px solid var(--border);
}

.vendor-compare-label-col { width: 5.5rem; }

.vendor-compare-label {
  text-align: left;
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gray-mid);
  padding: 0.45rem 0.65rem;
  vertical-align: top;
  width: 5.5rem;
}

.vendor-compare-cell {
  padding: 0.45rem 0.65rem;
  color: var(--gray-dark);
  vertical-align: top;
  word-break: break-word;
  border-bottom: 1px solid var(--divider);
}

.vendor-compare-row--diff .vendor-compare-cell {
  background: var(--overflow-bg);
  color: var(--overflow-dark);
  font-weight: 500;
}

.vendor-compare-row--diff .vendor-compare-label {
  color: var(--overflow-dark);
}

/* Must stay after --diff to win at equal specificity. */
.vendor-compare-row--bank-diff .vendor-compare-cell {
  background: var(--danger-bg);
  color: var(--danger-dark);
  font-weight: 600;
}

.vendor-compare-row--bank-diff .vendor-compare-label {
  color: var(--danger-dark);
  border-left: 3px solid var(--danger);
}

.vendor-compare-bank-flag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  margin-left: 0.3rem;
  border-radius: 50%;
  background: var(--danger);
  color: var(--white);
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
}

/* --match rows are deliberately unstyled: only disagreement is coloured. */

/* Whitespace-only agreement: deliberately neither tint. The note row below
   carries the pair's bottom border. */
.vendor-compare-row--spacing .vendor-compare-cell {
  background: var(--surface-muted);
  border-bottom: none;
}

.vendor-compare-note {
  padding: 0 0.65rem 0.45rem;
  background: var(--surface-muted);
  font-size: 0.75rem;
  font-style: italic;
  color: var(--gray-mid);
  border-bottom: 1px solid var(--divider);
}

.vendor-compare-empty {
  color: var(--text-faint);
  font-style: italic;
}

.vendor-match-use { width: 100%; }

.vendor-match-item .vendor-match-name {
  font-weight: 600;
  color: var(--gray-dark);
  font-size: 0.9rem;
}

.vendor-match-meta {
  font-size: 0.78rem;
  color: var(--gray-mid);
}

.vendor-match-badges {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;
}

.vendor-match-confidence {
  font-size: 0.72rem;
  color: var(--gray-mid);
  font-variant-numeric: tabular-nums;
}

.vendor-match-confidence--tax_id_exact {
  color: var(--success);
  font-weight: 600;
}

/* Colours match the comparison rows below, so badge and table agree. */
.vendor-match-fields {
  font-size: 0.72rem;
  font-weight: 600;
}

.vendor-match-fields--match { color: var(--success); }
.vendor-match-fields--diff  { color: var(--overflow-dark); }

/* base.css inline-blocks form.button_to, which shrink-wraps it; without this
   the button's width:100% resolves against the form's content width. */
.vendor-match-actions > form.button_to { display: block; }
.vendor-match-link-btn { width: 100%; }

/* Expert-link dialog: two equal buttons side by side. */
.expert-link-select { display: block; width: 100%; margin-top: 1rem; }
.expert-link-actions { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.expert-link-actions > form.button_to { display: flex; }
.expert-link-actions > form.button_to .btn { flex: 1; }

/* Two-line action buttons (title + subtitle) in the match-choice row (INT-54). */
.vendor-match-action-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Stretched to the tallest choice, so centre the two lines. */
  justify-content: center;
  gap: 0.1rem;
  height: auto;
  padding: 0.45rem 0.7rem;
  line-height: 1.3;
}

/* The quieter of the two teal choices. */
.vendor-match-soft-btn {
  background: var(--teal-light);
  color: var(--teal-dark);
  border: 1.5px solid var(--teal);
}

.vendor-match-soft-btn:hover {
  background: var(--teal);
  color: var(--white);
}

.vendor-match-action-title { font-weight: 600; }

.vendor-match-action-subtitle {
  font-size: 0.72rem;
  font-weight: 400;
  opacity: 0.9;
}

/* Vendor card heading row: title + secondary "create new vendor" link. */
.invoice-party-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.vendor-create-link {
  background: none;
  border: none;
  padding: 0;
  font-size: 0.8rem;
  color: var(--teal);
  text-decoration: underline;
  cursor: pointer;
}

.vendor-create-link:hover { color: var(--teal-dark); }

/* InforEuro exchange-rate link under the invoice details (INT-54). */
.invoice-inforeuro {
  margin: -0.75rem 0 1.5rem;
  font-size: 0.85rem;
}

.invoice-inforeuro a {
  color: var(--teal);
  text-decoration: none;
  font-weight: 500;
}

.invoice-inforeuro a:hover { text-decoration: underline; }

.invoice-inforeuro-hint {
  color: var(--gray-mid);
  margin-left: 0.4rem;
}

.vendor-match-empty {
  font-size: 0.85rem;
  color: var(--gray-mid);
  margin: 0 0 0.75rem;
  font-style: italic;
}

.vendor-match-create { width: 100%; }

.invoice-details-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 1.5rem;
}

/* Row carrying info-tips in its cells: don't clip, so a tooltip bubble can open
   past the row edge. */
.invoice-details-row--tips { overflow: visible; }

.detail-cell {
  flex: 1 1 160px;
  padding: 0.85rem 1.1rem;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.detail-cell:last-child { border-right: none; }

/* Full-width cell for prose. overflow-wrap because the row is overflow:hidden:
   an unbroken token would otherwise widen the cell and be clipped. */
.detail-cell--full {
  flex: 1 1 100%;
  border-right: none;
  min-width: 0;
  overflow-wrap: anywhere;
}

.detail-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-mid);
  margin-bottom: 0.2rem;
}

.detail-value {
  font-size: 0.9rem;
  color: var(--gray-dark);
  font-weight: 500;
}

/* ── Inline service-period editor (review state) ───────────────────────────
   A compact pencil inside the detail cell opens a native popover (top layer,
   so the row's overflow:hidden can't clip it; light-dismiss closes it) with
   the month tiles — no trip to the edit view for the approval gate's
   only routinely-missing field. */
.service-period-edit-btn {
  width: 1.5rem;
  height: 1.5rem;
  margin-left: 0.15rem;
  vertical-align: text-bottom;
}

.service-period-popover {
  position: fixed;
  /* Center explicitly (inset + margin + fit-content) instead of leaning on
     the UA popover defaults, which app-level resets can override. */
  inset: 0;
  margin: auto;
  width: fit-content;
  height: fit-content;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.25rem;
  background: var(--white);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
  min-width: 320px;
}

.service-period-popover-hint {
  font-size: 0.8rem;
  color: var(--gray-mid);
  line-height: 1.4;
  max-width: 340px;
  margin-bottom: 0.6rem;
}

/* Per-line sub-line under the description: dates + a compact pencil, or just
   the "Set service period" text link while the line inherits the header's. */
.li-service-period {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

.li-service-period .service-period-edit-btn {
  margin-left: 0;
}

.li-service-period-dates {
  margin-top: 0.35rem;
}

.li-service-period-inherited {
  color: var(--text-faint);
  font-weight: 400;
}

.service-period-popover-title {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-mid);
  margin-bottom: 0.6rem;
}

.service-period-popover-fields {
  display: flex;
  gap: 0.75rem;
}

.service-period-popover-fields .form-field {
  flex: 1 1 0;
}

.service-period-popover-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

/* Month-tile pickers (service_period_controller), header and line. The grid
   itself is the shared month_grid.css component; only the popover chrome
   lives here. */
.service-period-popover-months { width: 420px; }

/* Sized for the grid so switching to the date fields doesn't re-centre the popover. */
.service-period-panels { min-height: 15rem; }

.service-period-mode {
  display: inline-flex;
  margin-bottom: 0.75rem;
  border: 1px solid var(--border-input);
  border-radius: 6px;
  overflow: hidden;
}

.service-period-mode-btn {
  padding: 0.3rem 0.75rem;
  border: 0;
  background: var(--white);
  color: var(--gray-mid);
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}
.service-period-mode-btn + .service-period-mode-btn { border-left: 1px solid var(--border-input); }
.service-period-mode-btn:hover { color: var(--teal); }
.service-period-mode-btn.is-active {
  background: var(--teal-light);
  color: var(--teal);
  font-weight: 500;
}

.service-period-popover [hidden] { display: none; }

/* Split wizard: "+ Add line" beside "One row per month". */
.split-add-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Split wizard card: a line's months, as the invoice page shows them. */
.split-line-period {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.5rem;
  min-height: 2.1rem;
  font-size: 0.85rem;
  color: var(--text-strong);
}
.split-line-period .li-service-period-inherited { font-size: 0.8rem; }
.split-line-period .li-service-period-set { margin-top: 0; }

/* Shown by service_period_controller while Save is disabled for a backwards
   or out-of-header range. */
.service-period-popover-error {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--danger);
}
.service-period-popover-error[hidden] { display: none; }

.invoice-section {
  margin-bottom: 1.5rem;
}

.invoice-section h3,
.invoice-section-title {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-mid);
  margin-bottom: 0.75rem;
}

.invoice-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.invoice-table th {
  text-align: left;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray-mid);
  padding: 0.6rem 0.75rem;
  border-bottom: 2px solid var(--border);
}

.invoice-table td {
  padding: 0.7rem 0.75rem;
  border-bottom: 1px solid var(--divider);
  color: var(--gray-dark);
}

.invoice-table tfoot td {
  border-bottom: none;
  padding-top: 0.5rem;
  color: var(--gray-mid);
  font-size: 0.88rem;
}

.invoice-table .total-row td {
  font-weight: 700;
  font-size: 1rem;
  color: var(--gray-dark);
  border-top: 2px solid var(--border);
  padding-top: 0.75rem;
}

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

.vat-note {
  font-size: 0.8rem;
  color: var(--gray-mid);
  margin-top: 0.75rem;
}

.invoice-pending-card {
  text-align: center;
  padding: 4rem 2rem;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.pending-icon {
  font-size: 2.5rem;
  color: var(--teal);
  margin-bottom: 0.75rem;
}

.pending-title {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--gray-dark);
  margin-bottom: 0.5rem;
}

.pending-body {
  font-size: 0.9rem;
  color: var(--gray-mid);
}

/* Processing spinner */
@keyframes spin {
  to { transform: rotate(360deg); }
}

.processing-spinner {
  width: 48px;
  height: 48px;
  border: 4px solid var(--teal-light);
  border-top-color: var(--teal);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin: 0 auto 1.25rem;
}

/* Skeleton shimmer for processing state */
@keyframes shimmer {
  from { background-position: -600px 0; }
  to   { background-position:  600px 0; }
}

.skeleton-block {
  background: linear-gradient(90deg, var(--divider) 25%, var(--border) 50%, var(--divider) 75%);
  background-size: 600px 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: 4px;
}

.invoice-skeleton {
  margin-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  text-align: left;
}

.invoice-skeleton-row {
  display: flex;
  gap: 1rem;
}

.invoice-skeleton-row .skeleton-block { flex: 1; height: 64px; }

/* The invoice index's filter form is the shared .filter-row (filters.css). */

/* Vendor show's linked-invoices list spans the full page width, so a plain
   two-part row would strand the status badge far from the invoice number.
   Lay each row out as aligned columns (number · project · date · status)
   that fill the width and read like a table. Scoped to this list only. */
.invoice-scan-row {
  display: grid;
  /* Number and project flex; date, amount and status are fixed so the columns
     line up across rows (each row is its own grid, so variable-width tracks
     wouldn't). */
  grid-template-columns: minmax(140px, 1.2fr) minmax(120px, 1.8fr) 104px 120px 96px;
  align-items: center;
  gap: 1rem;
}

.invoice-scan-number { font-size: 0.9rem; font-weight: 500; color: var(--gray-dark); }
.invoice-scan-project { font-size: 0.85rem; color: var(--gray-mid); }
.invoice-scan-date { font-size: 0.85rem; color: var(--gray-mid); white-space: nowrap; }
.invoice-scan-amount { font-size: 0.85rem; font-weight: 500; color: var(--gray-dark); text-align: right; white-space: nowrap; }
.invoice-scan-row .status-badge { justify-self: end; }

/* Narrow screens: the four fixed columns won't fit, so fold to a 2×2 —
   number + status on top, project + date below. */
@media (max-width: 640px) {
  .invoice-scan-row {
    grid-template-columns: 1fr auto;
    row-gap: 0.3rem;
    column-gap: 0.75rem;
  }
  .invoice-scan-number { grid-area: 1 / 1; }
  .invoice-scan-row .status-badge { grid-area: 1 / 2; }
  .invoice-scan-project { grid-area: 2 / 1; }
  .invoice-scan-date { grid-area: 2 / 2; text-align: right; }
  .invoice-scan-amount { grid-area: 3 / 1 / 4 / 3; text-align: right; }
}

/* Upload form */
.upload-title {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--gray-dark);
  text-align: center;
  margin-bottom: 1.5rem;
  letter-spacing: 0.02em;
}

.auth-select {
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  font-size: 0.95rem;
  color: var(--gray-dark);
  background: var(--white);
  transition: border-color 0.15s, box-shadow 0.15s;
  outline: none;
  appearance: none;
  background-image: var(--dropdown-arrow);
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2rem;
}

.auth-select:focus {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0,154,149,0.12);
}

.auth-file {
  font-size: 0.9rem;
  color: var(--gray-mid);
}

.auth-hint {
  font-size: 0.8rem;
  color: var(--gray-mid);
}

/* ── Check results ─────────────────────────────────────────── */
/* Section headers on the invoice review screen (Invoice Checker Results,
   Invoice data) — matches the app's other uppercase section headings. */
.invoice-section-title { margin-top: 2rem; }

.check-results {
  margin-top: 0;
}

.check-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1.25rem;
  border-radius: 8px;
  margin-bottom: 1.25rem;
  font-size: 0.95rem;
}

.check-summary--pass   { background: var(--success-bg); border: 1px solid var(--success); color: var(--success); }
.check-summary--warning { background: var(--warning-bg); border: 1px solid var(--review); color: var(--warning-dark); }
.check-summary--fail   { background: var(--danger-bg); border: 1px solid var(--danger); color: var(--danger-dark); }

.check-summary-icon { font-size: 1.1rem; font-weight: 700; }

.check-all-passed {
  color: var(--success);
  font-size: 0.9rem;
  padding: 0.5rem 0;
}

/* .data-table / .data-table-wrap live in tables.css. */

/* Sticky headers for the invoice-review tables: they scroll with the page, so
   headers pin just below the sticky nav. The opaque fill stops body rows
   bleeding through; z-index stays under the nav (100). */
.invoice-table thead th,
.check-table thead th,
.vendor-compare thead th {
  position: sticky;
  top: var(--nav-height);
  z-index: 2;
  background: var(--surface-muted);
}

.check-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.check-table thead th {
  text-align: left;
  padding: 0.5rem 0.75rem;
  color: var(--gray-mid);
  font-weight: 500;
  border-bottom: 2px solid var(--gray-light);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.check-table tbody tr + tr { border-top: 1px solid var(--gray-light); }

.check-table td { padding: 0.6rem 0.75rem; vertical-align: top; }

.check-result-cell {
  font-weight: 700;
  white-space: nowrap;
  width: 80px;
}

.check-row--fail .check-result-cell   { color: var(--danger); }
.check-row--warning .check-result-cell { color: var(--warning); }

.check-reason { color: var(--gray-mid); }

/* ── Reject page ───────────────────────────────────────────── */
.reject-page {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding-top: 1rem;
}

.reject-header h2 {
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--gray-dark);
  margin-bottom: 0.4rem;
}

/* .review-banner carries its own margin-bottom for normal flow; .reject-page
   spaces its children with a flex gap, so drop the duplicate margin here. */
.reject-page .review-banner {
  margin-bottom: 0;
}

.reject-email-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--danger);
  border-radius: 8px;
  overflow: hidden;
}

.reject-email-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.25rem;
  background: var(--gray-light);
  border-bottom: 1px solid var(--border);
  gap: 1rem;
}

.reject-email-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.88rem;
  color: var(--gray-dark);
}

.reject-email-label {
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray-mid);
}

.reject-email-body {
  width: 100%;
  padding: 1.25rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  margin: 0.75rem;
  width: calc(100% - 1.5rem);
  outline: none;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--gray-dark);
  resize: vertical;
  background: var(--surface-muted);
  transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}

.reject-email-body:hover {
  border-color: var(--text-faint);
  background: var(--white);
}

.reject-email-body:focus {
  border-color: var(--teal);
  background: var(--white);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}

/* ── Review banner ─────────────────────────────────────────── */
.review-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  background: var(--teal-light);
  border: 1px solid var(--teal-border);
  border-left: 4px solid var(--teal);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  margin-bottom: 1.5rem;
}

.review-banner-icon {
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--teal);
  color: var(--white);
  font-weight: 700;
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.review-banner-text {
  flex: 1 1 240px;
  margin: 0;
  font-size: 0.9rem;
  color: var(--gray-dark);
  line-height: 1.4;
}

.review-banner-btn {
  background: var(--teal);
  color: var(--white);
  border: 1px solid var(--teal);
}
.review-banner-btn:hover {
  background: var(--teal-dark);
  border-color: var(--teal-dark);
  color: var(--white);
}

/* Amber variant: an advisory that withholds an action (line items locked until
   the header period exists), unlike the teal "how review works" reminder. */
.review-banner--warning {
  background: var(--warning-bg);
  border-color: var(--warning);
  margin-bottom: 0.9rem;
}
.review-banner--warning .review-banner-icon { background: var(--warning); }

body:has([data-large-payment]) { background: var(--warning-bg); }
body:has([data-large-payment]) .invoice-show {
  max-width: min(1250px, calc(100% - 2rem));
  margin: 1rem auto;
  background: var(--white);
  border: 1px solid var(--warning);
  border-radius: 8px;
}
.review-banner--warning .review-banner-btn,
.review-banner--warning .review-banner-btn:hover {
  background: var(--warning-dark);
  border-color: var(--warning-dark);
}

@media (max-width: 600px) {
  .review-banner { align-items: flex-start; }
}

.rejected-banner {
  background: var(--danger-bg);
  border: 1px solid var(--danger-border);
  border-radius: 8px;
  padding: 0.875rem 1.25rem;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
  color: var(--danger-dark);
  line-height: 1.5;
}

.approved-banner {
  background: var(--success-bg);
  border: 1px solid var(--success-border);
  border-radius: 8px;
  padding: 0.875rem 1.25rem;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
  color: var(--success-dark);
  line-height: 1.5;
}

.approved-banner p { margin: 0; }
.rejected-banner p { margin: 0; }

/* ── Invoice edit form ─────────────────────────────────────── */
.form-section {
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--teal);
  border-radius: 8px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.form-section h3 {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 1.25rem;
}

.form-section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.form-section-header h3 { margin-bottom: 0; }

.form-section-header-actions {
  display: flex;
  align-items: baseline;
  gap: 1rem;
}

.form-section-count {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.1rem 0.5rem;
  background: var(--gray-light);
  color: var(--gray-mid);
  border-radius: 10px;
  font-size: 0.7rem;
  letter-spacing: 0;
  font-weight: 600;
}

.btn-link {
  appearance: none;
  -webkit-appearance: none;
  background: var(--teal-light);
  border: 1px solid var(--teal-border);
  padding: 0.3rem 0.75rem;
  margin: 0;
  border-radius: 4px;
  color: var(--teal);
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.btn-link:hover {
  background: var(--teal);
  border-color: var(--teal);
  color: var(--white);
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 1rem;
}

/* Line items — the .form-field, .line-item-row, .line-item-fields and
   .btn-remove-line-item primitives now live in base.css (shared with the ToR
   builder). Invoices only sets its own column layout for the fields grid. */
.line-item-fields {
  grid-template-columns: 2fr 70px 110px 110px;
}

@media (max-width: 640px) {
  .line-item-fields { grid-template-columns: 1fr 1fr; }
}

.line-items-warning {
  margin-top: 0.75rem;
  padding: 0.6rem 0.85rem;
  background: var(--warning-bg);
  border: 1px solid var(--review);
  border-radius: 4px;
  color: var(--warning-dark);
  font-size: 0.85rem;
}

/* Supporting invoice documents */
.supporting-documents-help {
  color: var(--gray-mid);
  font-size: 0.9rem;
  margin: 0 0 1rem;
}

/* Text colour, not amber — amber means a document is actually missing. */
.supporting-documents-help--required {
  margin-top: -0.5rem;
  color: var(--text-strong);
}

.supporting-documents-list {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.supporting-document {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--white);
}

.supporting-document-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.supporting-document-kind {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--teal);
  background: var(--teal-light);
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
}

.supporting-document-link {
  color: var(--text-strong);
  font-weight: 500;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.supporting-document-link:hover { color: var(--teal); text-decoration: underline; }

.supporting-document-meta {
  color: var(--gray-mid);
  font-size: 0.8rem;
}

.supporting-documents-form {
  display: grid;
  grid-template-columns: minmax(160px, 220px) minmax(220px, 1fr) auto;
  align-items: end;
  gap: 1rem;
  padding: 1rem;
  border: 1px dashed var(--border-input);
  border-radius: 6px;
  background: var(--surface-muted);
}

.supporting-documents-form input[type="file"] {
  padding: 0.45rem 0.5rem;
  background: var(--white);
}

@media (max-width: 640px) {
  .supporting-documents-form { grid-template-columns: 1fr; }
}

.btn-small {
  padding: 0.3rem 0.7rem;
  font-size: 0.8rem;
}

.supporting-confirmations {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.supporting-confirmation {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.65rem 0.9rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--white);
  font-size: 0.9rem;
}

.supporting-confirmation:has(.supporting-confirmation-check) {
  border-color: var(--success-border);
  background: var(--success-bg);
  color: var(--success-dark);
}

.supporting-confirmation-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 999px;
  background: var(--success);
  color: var(--white);
  font-size: 0.8rem;
  font-weight: 700;
}

.supporting-confirmation-text { flex: 1; min-width: 200px; }

/* Line items section header (show view) */
.invoice-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.invoice-section-header h3 { margin-bottom: 0; }
.invoice-section-header .btn-link { white-space: nowrap; }

.budget-line-unassigned {
  color: var(--warning-dark);
  font-size: 0.85rem;
  font-style: italic;
  white-space: nowrap;
}

/* Line-item cells with nothing to show: neutral, never amber. A ToR line item
   is optional, and a missing required document is flagged by .li-doc-hint. */
.line-item-tor-none,
.li-docs-none {
  color: var(--gray-mid);
  font-size: 0.85rem;
  white-space: nowrap;
}

.li-docs-none { font-style: italic; }

/* Assign-budget-lines modal */
/* Inline budget-line assignment on the invoice line items table */
.line-items-hint {
  color: var(--gray-mid);
  font-size: 0.85rem;
}

.line-items-check-col { width: 2.2rem; }
.line-items-status-col { width: 6rem; }

/* Per-row completion status. A coloured left bar + a pill make assigned,
   evidence-pending and done rows scannable at a glance. The three classes are
   set server-side on first render and kept live by line_item_status_controller. */
.invoice-table--line-items tbody tr.is-unassigned td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.invoice-table--line-items tbody tr.is-needs-doc  td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.invoice-table--line-items tbody tr.is-done       td:first-child { box-shadow: inset 3px 0 0 var(--success); }

.invoice-table--line-items tbody tr.is-done       { background: var(--success-bg); }
.invoice-table--line-items tbody tr.is-needs-doc  { background: var(--warning-tint); }

/* A row whose quantity × unit price doesn't equal its stored total (typically
   an OCR-import drift). Same warm-orange treatment as needs-doc, plus a ⚠ chip
   beside the total; it also blocks invoice approval until corrected. Placed
   after the rules above so it wins the left bar when a row is both. */
.invoice-table--line-items tbody tr.is-amount-mismatch td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.invoice-table--line-items tbody tr.is-amount-mismatch { background: var(--warning-tint); }
.li-amount-warning {
  position: relative;
  margin-right: 0.3rem;
  color: var(--warning-dark);
  cursor: help;
  font-size: 0.85em;
}

/* In-page tooltip bubble carrying the copy via data-tip — mirrors the .info-tip
   marker in base.css so the warning shows instantly and styled on hover, instead
   of the unstyled native `title` (which also never renders in the preview). Opens
   leftward (cf. .info-tip--left). Hover only — no focus/keyboard affordance by
   design. */
.li-amount-warning[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: max-content;
  max-width: 260px;
  white-space: normal;
  text-align: left;
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--white);
  background: var(--gray-dark);
  padding: 0.5rem 0.65rem;
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
  pointer-events: none;
}
.li-amount-warning[data-tip]::before {
  content: "";
  position: absolute;
  top: calc(100% + 3px);
  right: 4px;
  border: 5px solid transparent;
  border-bottom-color: var(--gray-dark);
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
  pointer-events: none;
}
.li-amount-warning[data-tip]:hover::after,
.li-amount-warning[data-tip]:hover::before {
  opacity: 1;
  visibility: visible;
}

.li-status-pill {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.li-status-pill--unassigned { background: var(--danger-bg); color: var(--danger); }
.li-status-pill--needs-doc  { background: var(--warning-bg); color: var(--warning-dark); }
.li-status-pill--done       { background: var(--success-bg); color: var(--success); }

.li-doc-hint {
  margin-top: 0.35rem;
  font-size: 0.78rem;
  line-height: 1.3;
}
.li-doc-hint--missing { color: var(--warning-dark); }
.li-doc-hint--ok      { color: var(--success); }
.li-doc-hint[hidden]  { display: none; }

/* Fee line whose effective period spans several months — advisory, never a
   blocker. Sentence-length, so it wraps (unlike .budget-line-unassigned). */
.li-fee-period-hint {
  margin: 0.35rem 0 0;
  font-size: 0.78rem;
  line-height: 1.3;
  font-style: italic;
  color: var(--warning-dark);
}
.li-fee-period-hint[hidden] { display: none; }

/* A row whose assigned budget line is over budget (live, advisory — the hard
   stop is at donor billing). The inline hint under the budget-line picker names
   the overage; a deeper-orange left bar + tint set it apart from the amber
   needs-doc / amount-mismatch rows. Placed last so it wins the left bar when a
   row is both over budget and (say) missing a document. */
.invoice-table--line-items tbody tr.is-over-budget td:first-child { box-shadow: inset 3px 0 0 var(--overflow); }
.invoice-table--line-items tbody tr.is-over-budget { background: var(--warning-tint); }
.li-overflow-hint {
  margin-top: 0.35rem;
  font-size: 0.78rem;
  line-height: 1.3;
  font-weight: 600;
  color: var(--overflow-dark);
}
.li-overflow-hint[hidden] { display: none; }

/* Selection (transient, during bulk edit) layers over the status bar/tint. */
.invoice-table--line-items tbody tr.is-selected {
  background: var(--teal-light);
}

.invoice-table--line-items tbody tr.is-selected td:first-child {
  box-shadow: inset 3px 0 0 var(--teal);
}

/* Landing target for the donor-invoice blocker links. A ring, not a tint:
   the row's status colours must survive. Drawn as background gradients on the
   cells because older Safari never painted an outline on a <tr>, and box-shadow
   would be replaced by the td:first-child status-bar shadows above. The status
   bar itself (an inset box-shadow) still paints over the ring's left edge. */
.invoice-table--line-items tbody tr:target td {
  background-image:
    linear-gradient(var(--teal), var(--teal)),
    linear-gradient(var(--teal), var(--teal));
  background-size: 100% 2px, 100% 2px;
  background-position: top left, bottom left;
  background-repeat: no-repeat;
}

.invoice-table--line-items tbody tr:target td:first-child {
  background-image:
    linear-gradient(var(--teal), var(--teal)),
    linear-gradient(var(--teal), var(--teal)),
    linear-gradient(var(--teal), var(--teal));
  background-size: 100% 2px, 100% 2px, 2px 100%;
  background-position: top left, bottom left, top left;
}

.invoice-table--line-items tbody tr:target td:last-child {
  background-image:
    linear-gradient(var(--teal), var(--teal)),
    linear-gradient(var(--teal), var(--teal)),
    linear-gradient(var(--teal), var(--teal));
  background-size: 100% 2px, 100% 2px, 2px 100%;
  background-position: top left, bottom left, top right;
}

.invoice-table--line-items tbody tr {
  scroll-margin-top: 5rem;
}


.budget-line-inline {
  width: 100%;
  max-width: 240px;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  font-size: 0.85rem;
  font-family: inherit;
  color: var(--gray-dark);
}

.budget-line-inline:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}

/* Locked state (e.g. the budget line once a ToR line item is chosen on the
   travel-claim verdict form): same grey signal as base.css's
   .form-field select:disabled, which can't reach these inline selects —
   they sit in plain <label>s, and the #fff background above would win. */
.budget-line-inline:disabled {
  background: var(--gray-light);
  color: var(--gray-mid);
  cursor: not-allowed;
}

/* Compact scrollable multi-select list box for supporting documents.
   Now used only by the bulk toolbar — the per-row picker is the trigger
   button + modal below. Attached docs are highlighted in teal. */
.supporting-docs-multi {
  width: 100%;
  max-width: 240px;
  height: auto;
  padding: 0.2rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  font-size: 0.8rem;
  font-family: inherit;
  color: var(--gray-dark);
  overflow-y: auto;
}

.supporting-docs-multi:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}

.supporting-docs-multi option {
  padding: 0.2rem 0.35rem;
  border-radius: 3px;
}

/* The gradient (rather than a plain background-color) is the cross-browser
   way to force the selected-option highlight to honour our colour. */
.supporting-docs-multi option:checked {
  background: linear-gradient(0deg, var(--teal) 0%, var(--teal) 100%);
  color: var(--white);
}

/* Per-row supporting-document picker: a compact trigger button (styled like
   the inline budget-line select) that opens the shared checkbox modal. Its
   label summarises the row's attached filenames, or a muted placeholder. */
.supporting-docs-trigger {
  width: 100%;
  max-width: 240px;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  font-size: 0.85rem;
  font-family: inherit;
  color: var(--gray-dark);
  text-align: left;
  cursor: pointer;
}
.supporting-docs-trigger:hover { border-color: var(--teal); }
.supporting-docs-trigger:focus-visible {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}
.supporting-docs-trigger--empty {
  color: var(--gray-mid);
  font-style: italic;
}

/* The travel-details trigger appears below a row's budget-line select
   only when that row's budget line requires travel details. The modal
   it opens captures traveler name, transport, route and dates. */
/* .li-service-period-set (the line's "Set service period" affordance) shares
   the look but keeps its own class: tests and JS target .travel-details-link
   as the travel affordance specifically. */
.travel-details-link,
.li-service-period-set,
.li-flex-unallocate,
.split-allocate-auth-toggle {
  display: inline-block;
  margin-top: 0.35rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: inherit;
  font-size: 0.8rem;
  text-decoration: underline;
  cursor: pointer;
}

.travel-details-link:hover,
.li-service-period-set:hover,
.li-flex-unallocate:hover,
.split-allocate-auth-toggle:hover { color: var(--teal-dark, var(--teal)); }

.li-flex-allocation {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.5rem;
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--gray-mid);
}
.li-flex-allocation .overflow-chip { margin-left: 0; }
.li-flex-allocation a { color: var(--teal); }
.li-flex-allocation .li-flex-unallocate { margin-top: 0; }
.li-flex-allocation .li-flex-auth-missing { color: var(--warning-dark); }

.travel-details-summary {
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--gray-mid);
  line-height: 1.4;
}

.travel-modal {
  /* The native UA centers a `dialog` via `inset: 0; margin: auto` once it
     enters the top layer, but a sibling rule in this app sets one of those
     properties for all dialogs and shifts ours to the top-left. Re-assert
     the centering explicitly so we don't depend on UA stylesheet ordering. */
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(34rem, 92vw);
  max-height: 90vh;
  padding: 0;
  border: 1px solid var(--border-input);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
}
.travel-modal::backdrop { background: rgba(0, 0, 0, 0.35); }

.travel-modal-form { padding: 1.25rem 1.5rem; }

.travel-modal-header { margin-bottom: 1rem; }
.travel-modal-header h3 { margin: 0 0 0.15rem; }
.travel-modal-subtitle {
  margin: 0;
  font-size: 0.85rem;
  color: var(--gray-mid);
}

.travel-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.travel-modal-error {
  margin: 0.75rem 0 0;
  color: var(--danger);
  font-size: 0.85rem;
}

/* Supporting-documents picker modal. Shares the travel-modal's centering,
   sizing and chrome; the body is a scrollable checkbox checklist so a long
   document list keeps a clear overview instead of a cramped scroll box. */
.supporting-docs-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(34rem, 92vw);
  max-height: 90vh;
  padding: 0;
  border: 1px solid var(--border-input);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
}
.supporting-docs-modal::backdrop { background: rgba(0, 0, 0, 0.35); }

.supporting-docs-modal-form { padding: 1.25rem 1.5rem; }

.supporting-docs-modal-header { margin-bottom: 1rem; }
.supporting-docs-modal-header h3 { margin: 0 0 0.15rem; }
.supporting-docs-modal-subtitle {
  margin: 0;
  font-size: 0.85rem;
  color: var(--gray-mid);
}

.supporting-docs-checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 50vh;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
}
.supporting-docs-checklist li + li { border-top: 1px solid var(--divider); }
.supporting-docs-checklist label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.75rem;
  font-size: 0.9rem;
  cursor: pointer;
}
.supporting-docs-checklist label:hover { background: var(--surface-muted); }
.supporting-docs-checklist input[type="checkbox"] {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--teal);
  cursor: pointer;
}

.supporting-docs-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

/* Floating toolbar shown when ≥1 row is selected. Kept on a single line
   so the user's mental model is "one row of bulk controls"; the long
   supporting-doc filenames are truncated server-side rather than wrapped.
   Visibility is driven by the `.is-visible` class set from the bulk-edit
   Stimulus controller — keeping it in CSS lets the responsive rules
   below cleanly override layout without fighting `[hidden]`. */
/* On-brand light surface (INT-51 #4), mirroring .donor-invoicing-summary —
   replaces the old dark (#111827) bar. Shared by the donor billable pool and
   the invoice bulk-edit screen. */
.budget-line-toolbar {
  display: none;
  position: sticky;
  bottom: 1rem;
  margin-top: 1rem;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: nowrap;
  padding: 0.75rem 1rem;
  background: var(--white);
  color: var(--gray-dark);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
  z-index: 5;
}
.budget-line-toolbar.is-visible { display: flex; }

.budget-line-toolbar-count {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--gray-dark);
}

/* One toolbar group per bulk action (budget line, supporting doc, ...).
   The label is a small caption above the select; on narrow widths the
   toolbar wraps and each group keeps its label glued to its controls. */
.bulk-action-group {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.6rem;
  border-left: 1px solid var(--border);
  min-width: 0; /* allow the inner <select> to shrink below its content width */
}

.bulk-action-group:first-of-type { border-left: 0; padding-left: 0; }

.bulk-action-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gray-mid);
  margin-right: 0.15rem;
}

.bulk-clear-btn { margin-left: auto; }

/* Wraps Apply + Clear so they can stay together on mobile (one row at the
   bottom of the stacked toolbar). On desktop the wrapper itself floats to
   the right edge, taking the role `margin-left: auto` used to play on the
   Clear button. */
.budget-line-toolbar-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-left: auto;
}

.budget-line-toolbar select {
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  color: var(--gray-dark);
  font-size: 0.85rem;
  font-family: inherit;
  /* Wide enough for readable budget-line labels, narrow enough that two
     groups plus Apply / Clear still fit on one line in a typical viewport.
     Long supporting-doc filenames are truncated server-side so the
     selected option label doesn't overflow this box. */
  min-width: 0;
  width: 16rem;
  max-width: 100%;
}

/* Phone / narrow viewports: position:sticky inside the invoice section
   doesn't reliably land at the *viewport* bottom — if the table is taller
   than the viewport the toolbar sticks to the bottom of the parent, which
   is below the fold. Switch to position:fixed so it's always on screen,
   stack each control on its own row (so nothing can overflow past the
   right edge), and reserve space at the bottom of the page so the last
   invoice rows aren't trapped underneath the toolbar. */
/* Phone / narrow viewports. We override the base `.budget-line-toolbar`
   rule (which uses position:sticky + a horizontal flex row) so the toolbar
   anchors to the visible viewport bottom and stacks each control on its
   own row. Kept deliberately minimal — past attempts that piled on extra
   constraints (overflow-x:hidden on html/body, env() insets, width:100vw)
   have repeatedly broken visibility on iOS Safari or in Chrome's mobile
   emulator, so this version sticks to the boring set of properties that
   are known to compose cleanly. */
@media (max-width: 700px) {
  .budget-line-toolbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    border-radius: 0;
    flex-direction: column;
    align-items: stretch;
    z-index: 50;
  }

  .budget-line-toolbar-count { text-align: center; }

  .bulk-action-label { display: none; }

  .bulk-action-group {
    padding: 0;
    border-left: 0;
    min-width: 0;
  }

  .budget-line-toolbar select {
    width: 100%;
    min-width: 0;
  }

  .budget-line-toolbar-actions > .btn-small { flex: 1 1 0; }
  .bulk-clear-btn { margin-left: 0; }

  body { padding-bottom: 14rem; }
}

/* ── Split wizard ─────────────────────────────────────────────────────── */

/* Description cell holds the text plus the split-action icon. */
.li-desc {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* Click-to-edit description (description_edit_controller). Takes the cell's
   remaining width, leaving the split button and flex-allocation chip beside it. */
.li-desc-edit {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  flex: 1 1 auto;
  min-width: 0;
}

/* Width floor + padding (cancelled by the negative margin, as in
   .inline-edit-display) keep a blank description's "—" clickable. */
.li-desc-text {
  cursor: text;
  border-radius: 3px;
  min-width: 3rem;
  padding: 0.15rem 0.3rem;
  margin: -0.15rem -0.3rem;
}

.li-desc-text:hover {
  text-decoration: underline dotted var(--gray-mid);
  text-underline-offset: 2px;
}

.li-desc-text:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
}

.li-desc-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  font-size: 0.85rem;
  font-family: inherit;
  color: var(--gray-dark);
}

.li-desc-input:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}

/* Keystroke hint while editing, then the save confirmation. */
.li-desc-hint {
  flex: 0 0 100%;
  font-size: 0.72rem;
  color: var(--gray-mid);
}

.li-desc-hint--saved { color: var(--success); }

.li-split-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.15rem;
  border: 0;
  background: transparent;
  color: var(--gray-mid);
  cursor: pointer;
  border-radius: 4px;
  flex: 0 0 auto;
}
.li-split-btn:hover { color: var(--teal); background: var(--teal-light); }
.li-split-btn .icon { width: 1.05rem; height: 1.05rem; }

/* Mirrors .travel-modal centering/chrome (see note there). */
.split-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(46rem, 94vw);
  max-height: 90vh;
  padding: 0;
  border: 1px solid var(--border-input);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  overflow: auto;
}
.split-modal::backdrop { background: rgba(0, 0, 0, 0.35); }

.split-modal-inner { padding: 1.25rem 1.5rem; }

.split-modal-header { margin-bottom: 1rem; }
.split-modal-header h3 { margin: 0 0 0.15rem; }
.split-modal-subtitle {
  margin: 0;
  font-size: 0.85rem;
  color: var(--gray-mid);
}

.split-confirm-sub { margin: 0; color: var(--gray-mid); font-size: 0.85rem; }
/* Under the original-line strip: the split replaces it. */
.split-replace-note { margin: -0.4rem 0 0.9rem; color: var(--gray-mid); font-size: 0.85rem; }

/* Allocate-mode (whole entry → Flexible Remuneration): space the intro and the
   stacked fields so they breathe instead of running together. */
.split-allocate .split-confirm-sub { margin-bottom: 0.5rem; }
.split-allocate .form-field { margin-top: 0.9rem; }

.split-original {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.6rem 0.75rem;
  margin-bottom: 0.9rem;
  background: var(--teal-light);
  border-radius: 6px;
  font-size: 0.9rem;
}
.split-original-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gray-mid);
}
.split-original-desc { font-weight: 600; }
.split-original-meta {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
}
.split-original-fact-label {
  color: var(--gray-mid);
  font-size: 0.78rem;
  margin-right: 0.2rem;
}
.split-original-fact strong { font-variant-numeric: tabular-nums; }
.split-original-total { font-weight: 600; font-variant-numeric: tabular-nums; }

.split-prefill {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.6rem;
  margin: 0 0 0.75rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-strong);
  cursor: pointer;
}
.split-prefill input { width: 1rem; height: 1rem; margin: 0; accent-color: var(--teal); }
.split-prefill-hint { font-weight: 400; color: var(--gray-mid); }

/* One card per child: numbered head over a grid of labelled fields; a flexible child turns teal. */
.split-lines {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.split-line {
  border: 1px solid var(--border-input);
  border-radius: 8px;
  background: var(--white);
}
.split-line.is-flexible { border-color: var(--teal); }

.split-line-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0.5rem 0.4rem 0.75rem;
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
  border-radius: 8px 8px 0 0;
  font-size: 0.85rem;
}
.split-line.is-flexible .split-line-head { background: var(--teal-light); }

.split-line-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--teal);
  color: var(--white);
  font-size: 0.78rem;
  font-weight: 600;
}

.split-line-title { font-weight: 600; color: var(--text-strong); }
.split-line-head .split-flex-hint { margin: 0; }
.split-line-total {
  margin-left: auto;
  font-weight: 600;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
/* The cashbook card has no total, so the remove button takes the right edge. */
.split-line-head .split-remove-row { margin-left: auto; }
.split-line-total + .split-remove-row { margin-left: 0; }

.split-line-body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.7rem 0.75rem 0.8rem;
}

.split-line-grid {
  display: grid;
  gap: 0.6rem;
}
.split-line-grid--invoice  { grid-template-columns: 2fr 2fr 0.8fr 1fr; }
.split-line-grid--cashbook { grid-template-columns: 2fr 2fr 0.8fr 1fr; }
.split-line-grid--details  { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Below the dialog's 46rem four columns squeeze the figures to ~40px. */
@media (max-width: 48rem) {
  .split-line-grid--invoice,
  .split-line-grid--cashbook,
  .split-line-grid--details { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.split-field { display: block; min-width: 0; }
.split-field-label {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gray-mid);
}
/* Matches .budget-line-inline. */
.split-line input,
.split-line select {
  width: 100%;
  box-sizing: border-box;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-input);
  border-radius: 4px;
  background: var(--white);
  font-size: 0.85rem;
  font-family: inherit;
  color: var(--gray-dark);
}
.split-line input:focus,
.split-line select:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 153, 153, 0.12);
}
.split-line input[type="checkbox"] { width: auto; }
.split-line input[type="file"] { padding: 0.25rem; font-size: 0.8rem; }
.split-line input[data-split-field="quantity"],
.split-line input[data-split-field="unit_price"],
.split-line input[data-split-field="amount"] { text-align: right; font-variant-numeric: tabular-nums; }

/* Standing note under the split table: a cashbook line's amount is the full cost,
   never quantity × a rate. Plain grey, not a warning — nothing is wrong. */
.split-amount-note {
  margin: 0.5rem 0 0;
  color: var(--gray-mid);
  font-size: 0.85rem;
}

.split-add-line { margin-top: 0.6rem; }

.split-balance {
  display: flex;
  gap: 1.5rem;
  justify-content: flex-end;
  align-items: baseline;
  margin-top: 1rem;
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  font-size: 0.85rem;
  background: var(--gray-light);
}
.split-balance strong { font-variant-numeric: tabular-nums; margin-left: 0.3rem; }
.split-balance.is-balanced { color: var(--success); background: rgba(21, 128, 61, 0.08); }
.split-balance.is-unbalanced { color: var(--warning-dark); background: rgba(217, 119, 6, 0.08); }

.split-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.split-modal-error {
  margin: 0.75rem 0 0;
  color: var(--danger);
  font-size: 0.85rem;
}

/* Inline reason the split can't be created yet (decimal comma, non-positive
   amount, unacknowledged overflow, missing GIZ file). Advisory, in the warning
   palette — distinct from the red error. */
.split-modal-hint {
  margin: 0.6rem 0 0;
  color: var(--warning-dark);
  font-size: 0.85rem;
}

/* Loud-but-non-blocking amber banner: the children's tracked days no longer add
   up to the original record's. Distinct from the plain-text .split-modal-hint —
   a tinted box with a left accent bar so it can't be missed — but the split can
   still be created (it reconciles on amount, not quantity). */
.split-modal-warning {
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.85rem;
  background: rgba(217, 119, 6, 0.1);
  border: 1px solid var(--warning);
  border-left: 4px solid var(--warning);
  border-radius: 4px;
  color: var(--warning-dark);
  font-size: 0.85rem;
  font-weight: 500;
}

/* Per-row teal hint: this child is allocated to the Flexible Remuneration line
   (priced at the original line, needs the GIZ approval document). */
.split-flex-hint {
  margin: 0.35rem 0 0;
  color: var(--teal);
  font-size: 0.78rem;
  line-height: 1.3;
}

/* Per-card amber hints: advisory, no tick needed (unlike the overflow ack). */
.split-fee-period-hint,
.split-never-billed-hint,
.split-billable-move-hint {
  margin: 0.35rem 0 0;
  color: var(--warning-dark);
  font-size: 0.78rem;
  line-height: 1.3;
}

/* Per-row amber acknowledgement: the child's amount exceeds its budget line.
   Advisory (the hard gate is at donor billing) — but it must be ticked before
   the split can be created. */
.split-overflow-ack {
  display: flex;
  gap: 0.4rem;
  align-items: flex-start;
  margin: 0.35rem 0 0;
  color: var(--warning-dark);
  font-size: 0.78rem;
  line-height: 1.3;
  cursor: pointer;
}
.split-overflow-ack input { margin-top: 0.15rem; accent-color: var(--warning-dark); }

/* GIZ authorization upload, revealed when any child is allocated to the flexible
   line. Teal accent to match the flexible-allocation hints. */
.split-flex-auth {
  margin-top: 0.85rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--teal-light);
  border-left: 3px solid var(--teal);
  border-radius: 6px;
  background: var(--teal-light);
}
.split-flex-auth label { display: block; font-weight: 600; font-size: 0.82rem; margin-bottom: 0.3rem; }
.split-flex-auth-hint { margin: 0.4rem 0 0; color: var(--gray-mid); font-size: 0.78rem; }
.split-allocate .form-hint--ok { color: var(--success); }
.split-allocate-auth-toggle { align-self: flex-start; margin-right: auto; }
.split-allocate-auth-toggle[hidden] { display: none; }

