/* Invoice show */
.nav-back {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-primary);
  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;

  /* 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. Both are the M3 orange
     (review) palette. */
  --int-orange: var(--review);
  --int-orange-dark: var(--warning-dark);
}

/* "Edit details" swaps the edit form into this frame, and Turbo scrolls the
   frame's first child to the top; without the margin the title lands under
   the sticky app bar. The margin matches .invoice-show's top padding, so the
   title stays where it was on the show page. */
.invoice-show > turbo-frame > :first-child { scroll-margin-top: calc(var(--nav-height) + 2.5rem); }

/* 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-color: var(--int-orange);
  border-color: transparent;
  color: var(--md-sys-color-on-primary);
}
.invoice-show .btn-danger:hover {
  background-color: var(--int-orange);
  color: var(--md-sys-color-on-primary);
}

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

.invoice-header h1 {
  font: var(--md-sys-typescale-headline-small);
  letter-spacing: var(--md-sys-typescale-headline-small-tracking);
  color: var(--md-sys-color-on-surface);
  margin-bottom: 0.35rem;
}

.invoice-meta {
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.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(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  padding: 1.25rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.invoice-party h3 {
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin-bottom: 0.5rem;
}

.party-name {
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
  color: var(--md-sys-color-on-surface);
}

.party-meta { color: var(--md-sys-color-on-surface-variant); }

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

.vendor-match-label {
  display: block;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  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(--md-sys-color-surface-container-low);
  border-radius: var(--md-sys-shape-corner-small);
}

/* 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: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
  text-align: center;
}

.vendor-match-choose-help {
  margin: 0;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
  text-align: center;
}

.vendor-match-choose-help strong { color: var(--md-sys-color-on-surface); font-weight: 500; }

/* 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 { text-align: center; }

/* Action button color coding. background-color, not the shorthand: the
   shorthand would wipe the hover state layer drawn as a background-image. */
.btn-overwrite {
  background-color: var(--warning);
  color: var(--md-sys-color-on-primary);
}
.btn-overwrite:hover { color: var(--md-sys-color-on-primary); }

.btn-new-vendor {
  background-color: var(--success);
  color: var(--md-sys-color-on-primary);
}
.btn-new-vendor:hover { color: var(--md-sys-color-on-primary); }

/* Match panel intro & legend */
.vendor-match-intro {
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin: 0 0 0.65rem;
}

.vendor-match-legend {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0.65rem 0.85rem;
  background: var(--md-sys-color-surface-container-low);
  border-radius: var(--md-sys-shape-corner-small);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.vendor-match-legend li + li { margin-top: 0.3rem; }
.vendor-match-legend strong { color: var(--md-sys-color-on-surface); font-weight: 500; }

.vendor-name-link {
  color: var(--md-sys-color-primary);
  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(--md-sys-color-outline-variant);
  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: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin: 0.5rem 0 0;
}

/* 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(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  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: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

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

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

/* Disabled look (container/label tints) comes from base.css's .btn[disabled]. */
.review-footer-actions .btn[disabled] {
  cursor: not-allowed;
}

.review-footer-warning {
  flex-basis: 100%;
  margin: 0.65rem 0 0;
  text-align: right;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--warning-dark);
}

.review-footer-warning .icon,
.review-footer-note .icon { width: 16px; height: 16px; margin-right: 0.25rem; vertical-align: -3px; }

/* 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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  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 — it's a
   setting, not the primary call to action. */
.german-vat-review {
  margin-top: 2rem;
  padding: 1rem 1.25rem;
  background: var(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  display: flex;
  align-items: center;
  gap: 1rem 1.5rem;
  flex-wrap: wrap;
}

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

.german-vat-review .inline-check {
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  color: var(--md-sys-color-on-surface);
  cursor: pointer;
}

.german-vat-review input[type="checkbox"] {
  width: auto;
  margin: 0;
  cursor: pointer;
  accent-color: var(--md-sys-color-primary);
}

.german-vat-review-hint {
  flex: 1;
  min-width: 240px;
  margin: 0;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.approved-footer,
.rejected-footer {
  margin-top: 2rem;
  padding: 1.25rem 1.5rem;
  border-radius: var(--md-sys-shape-corner-medium);
  display: flex;
  align-items: center;
  gap: 1rem;
  animation: approved-footer-in var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized-decelerate);
}

.approved-footer {
  background: var(--success-bg);
  color: var(--success-dark);
}

.rejected-footer {
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
}

.approved-footer-icon,
.rejected-footer-icon {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: var(--md-sys-shape-corner-full);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--md-sys-color-on-primary);
}
.approved-footer-icon .icon,
.rejected-footer-icon .icon { width: 20px; height: 20px; vertical-align: 0; }

.approved-footer-icon { background: var(--success); }
.rejected-footer-icon { background: var(--md-sys-color-error); }

.approved-footer-title,
.rejected-footer-title {
  margin: 0;
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
}

.approved-footer-meta,
.rejected-footer-meta {
  margin: 0.15rem 0 0;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--success-dark);
}

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

.approved-footer-blocked-note a {
  color: inherit;
  font-weight: 500;
  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-color: var(--review-bg); color: var(--review); }
.btn-state-review: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(--md-sys-color-surface-container-low);
  border-radius: var(--md-sys-shape-corner-small);
}

.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: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  align-self: center;
}

.vendor-fields dd {
  margin: 0;
  color: var(--md-sys-color-on-surface);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  word-break: break-word;
}

/* Side-by-side comparison */
.vendor-compare {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5rem 0 0.85rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  table-layout: fixed;
}

.vendor-compare thead th {
  text-align: left;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  padding: 0.4rem 0.65rem;
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

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

.vendor-compare-label {
  text-align: left;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  padding: 0.45rem 0.65rem;
  vertical-align: top;
  width: 5.5rem;
}

.vendor-compare-cell {
  padding: 0.45rem 0.65rem;
  color: var(--md-sys-color-on-surface);
  vertical-align: top;
  word-break: break-word;
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

.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(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
  font-weight: 500;
}

.vendor-compare-row--bank-diff .vendor-compare-label {
  color: var(--md-sys-color-on-error-container);
  border-left: 3px solid var(--md-sys-color-error);
}

.vendor-compare-bank-flag {
  display: inline-flex;
  margin-left: 0.3rem;
  vertical-align: -0.2em;
  color: var(--md-sys-color-error);
}
.vendor-compare-bank-flag .icon { width: 16px; height: 16px; vertical-align: 0; }

/* --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(--md-sys-color-surface-container-low);
  border-bottom: none;
}

.vendor-compare-note {
  padding: 0 0.65rem 0.45rem;
  background: var(--md-sys-color-surface-container-low);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  font-style: italic;
  color: var(--md-sys-color-on-surface-variant);
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

.vendor-compare-empty {
  color: var(--md-sys-color-outline);
  font-style: italic;
}

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

.vendor-match-item .vendor-match-name {
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
}

.vendor-match-meta {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

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

.vendor-match-confidence {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
  font-variant-numeric: tabular-nums;
}

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

/* Colours match the comparison rows below, so badge and table agree. */
.vendor-match-fields {
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
}

.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. */
.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.5rem 1.5rem;
}

/* The quieter of the two teal choices: tonal rather than filled. */
.vendor-match-soft-btn {
  background-color: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  border-color: transparent;
}

.vendor-match-soft-btn:hover {
  color: var(--md-sys-color-on-secondary-container);
}

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

.vendor-match-action-subtitle {
  font: var(--md-sys-typescale-label-small);
  letter-spacing: var(--md-sys-typescale-label-small-tracking);
  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: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  color: var(--md-sys-color-primary);
  text-decoration: underline;
  cursor: pointer;
}

.vendor-create-link:hover { color: var(--md-sys-color-on-primary-container); }

/* InforEuro exchange-rate link under the invoice details. */
.invoice-inforeuro {
  margin: -0.75rem 0 1.5rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

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

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

.invoice-inforeuro-hint {
  color: var(--md-sys-color-on-surface-variant);
  margin-left: 0.4rem;
}

.vendor-match-empty {
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  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(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  background: var(--md-sys-color-surface-container-lowest);
  overflow: hidden;
  margin-bottom: 1.5rem;
}

/* A row whose cells were all conditional and absent would draw as a bare
   outline; hide it instead. */
.invoice-details-row:not(:has(*)) { display: none; }


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

.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: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin-bottom: 0.2rem;
}

.detail-value {
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
}

/* ── 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;
}

/* M3 docked date picker: drops below the button that opened it (the popover's
   implicit anchor), flipping above or leftward when the viewport is short;
   white like the dialogs (modals.css says why the container is remapped from
   surface-container-high), large (16dp) corners, elevation 3, no scrim —
   outside click or Escape dismisses it. Without anchor positioning it
   centres on screen. */
.service-period-popover {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(22.5rem, calc(100vw - 2rem));
  height: fit-content;
  max-height: calc(100vh - 2rem);
  overflow: auto;
  border: none;
  border-radius: var(--md-sys-shape-corner-large);
  padding: 1rem 1.25rem 0.75rem;
  background: var(--md-sys-color-surface-container-lowest);
  color: var(--md-sys-color-on-surface);
  box-shadow: var(--md-sys-elevation-level3);
}

@supports (position-area: bottom) {
  @media (min-width: 600px) {
    .service-period-popover {
      inset: auto;
      margin: 0.25rem 0;
      position-area: bottom span-right;
      position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
    }
  }
}

/* Compact windows: M3 puts the picker in a dialog — centred over a scrim. */
@media (max-width: 599px) {
  .service-period-popover {
    border-radius: var(--md-sys-shape-corner-extra-large);
    padding: 1.5rem 1.5rem 1rem;
  }
  .service-period-popover::backdrop { background: rgb(0 0 0 / 0.32); }
}

.service-period-popover:popover-open {
  animation: app-menu-enter var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-emphasized-decelerate);
}

@media (prefers-reduced-motion: reduce) {
  .service-period-popover:popover-open { animation: none; }
}

.service-period-popover-hint {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin-bottom: 0.75rem;
}
.service-period-popover-hint strong { font-weight: 500; color: var(--md-sys-color-on-surface); }
.month-grid + .service-period-popover-hint { margin: 0.75rem 0 0; }

/* 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(--md-sys-color-outline);
  font-weight: 400;
}

.service-period-popover-title {
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
  color: var(--md-sys-color-on-surface);
  margin-bottom: 0.25rem;
}
.service-period-popover-title + form { margin-top: 0.75rem; }

/* Exact dates: two outlined date fields, stacked — side by side in the 360dp
   picker each got ~150px, which clipped the year where the browser writes
   the date wider (Firefox's "01 / 15 / 2024"). The native calendar they open
   is tinted primary by the root accent-color. */
.service-period-popover-fields {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.service-period-popover-fields .form-field {
  flex: 1 1 0;
  min-width: 0;
  margin-bottom: 0;
}

/* Text-button actions on the trailing edge (Cancel, then the filled Save);
   "Use invoice period" parks on the leading edge. */
.service-period-popover-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem -0.5rem 0 0;
}
.service-period-popover-actions .service-period-clear { margin: 0 auto 0 -0.75rem; }

/* M3 segmented button: 40dp outlined pill split into equal segments; the
   selected segment is filled with the secondary container and leads with a
   check. */
.service-period-mode {
  display: flex;
  margin-bottom: 1rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-full);
  overflow: hidden;
}

.service-period-mode-btn {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 38px;
  padding: 0 0.75rem;
  border: 0;
  background-color: transparent;
  color: var(--md-sys-color-on-surface);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  cursor: pointer;
  --md-state-layer: transparent;
  background-image: linear-gradient(var(--md-state-layer), var(--md-state-layer));
  transition:
    background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.service-period-mode-btn + .service-period-mode-btn { border-left: 1px solid var(--md-sys-color-outline); }
.service-period-mode-btn:hover { --md-state-layer: color-mix(in srgb, currentColor var(--md-sys-state-hover-opacity), transparent); }
.service-period-mode-btn:is(:focus-visible, :active) { --md-state-layer: color-mix(in srgb, currentColor var(--md-sys-state-pressed-opacity), transparent); }
.service-period-mode-btn:focus-visible { outline-offset: -3px; }
.service-period-mode-btn .icon { display: none; width: 18px; height: 18px; vertical-align: 0; }
.service-period-mode-btn.is-active {
  background-color: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}
.service-period-mode-btn.is-active .icon { display: inline-block; }

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

/* Split wizard: "Add line" beside "One row per month", as text buttons (the
   negative margin lines the first label up with the cards' edge). */
.split-add-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0 0 -0.75rem;
}

/* 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.25rem 0.5rem;
  min-height: 2.25rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
}
.split-line-period .li-service-period-inherited {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}
.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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-error);
}
.service-period-popover-error[hidden] { display: none; }

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

.invoice-section h3,
.invoice-section-title {
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
  color: var(--md-sys-color-on-surface);
  margin-bottom: 0.75rem;
}

.invoice-table {
  width: 100%;
  border-collapse: collapse;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

.invoice-table th {
  text-align: left;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

.invoice-table td {
  padding: 0.7rem 0.75rem;
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
  color: var(--md-sys-color-on-surface);
}

.invoice-table tfoot td {
  border-bottom: none;
  padding-top: 0.5rem;
  color: var(--md-sys-color-on-surface-variant);
}

/* Totals sit under the narrow Total column; keep "USD 1,190.00" on one line. */
.invoice-table tfoot td.text-right {
  white-space: nowrap;
}

.invoice-table .total-row td {
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
  color: var(--md-sys-color-on-surface);
  border-top: 1px solid var(--md-sys-color-outline);
  padding-top: 0.75rem;
}

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

.vat-note {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
  margin-top: 0.75rem;
}

.invoice-pending-card {
  text-align: center;
  padding: 4rem 2rem;
  background: var(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
}

.pending-icon {
  color: var(--md-sys-color-primary);
  margin-bottom: 0.75rem;
}
.pending-icon .icon { width: 40px; height: 40px; vertical-align: 0; }
.pending-icon--failed { color: var(--md-sys-color-error); }

.pending-title {
  font: var(--md-sys-typescale-title-large);
  letter-spacing: var(--md-sys-typescale-title-large-tracking);
  color: var(--md-sys-color-on-surface);
  margin-bottom: 0.5rem;
}

.pending-body {
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

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

.processing-spinner {
  width: 48px;
  height: 48px;
  border: 4px solid var(--md-sys-color-secondary-container);
  border-top-color: var(--md-sys-color-primary);
  border-radius: var(--md-sys-shape-corner-full);
  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(--md-sys-color-surface-container) 25%,
    var(--md-sys-color-surface-container-highest) 50%,
    var(--md-sys-color-surface-container) 75%);
  background-size: 600px 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: var(--md-sys-shape-corner-extra-small);
}

.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: var(--md-sys-typescale-title-small); letter-spacing: var(--md-sys-typescale-title-small-tracking); color: var(--md-sys-color-on-surface); }
.invoice-scan-project { font: var(--md-sys-typescale-body-medium); letter-spacing: var(--md-sys-typescale-body-medium-tracking); color: var(--md-sys-color-on-surface-variant); }
.invoice-scan-date { font: var(--md-sys-typescale-body-medium); letter-spacing: var(--md-sys-typescale-body-medium-tracking); color: var(--md-sys-color-on-surface-variant); white-space: nowrap; }
.invoice-scan-amount { font: var(--md-sys-typescale-title-small); letter-spacing: var(--md-sys-typescale-title-small-tracking); color: var(--md-sys-color-on-surface); 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: var(--md-sys-typescale-title-large);
  letter-spacing: var(--md-sys-typescale-title-large-tracking);
  color: var(--md-sys-color-on-surface);
  text-align: center;
  margin-bottom: 1.5rem;
}

/* M3 outlined select: 1px outline, extra-small corners, primary on focus. */
.auth-select {
  min-height: 48px;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  font: var(--md-sys-typescale-body-large);
  letter-spacing: var(--md-sys-typescale-body-large-tracking);
  color: var(--md-sys-color-on-surface);
  background-color: var(--md-sys-color-surface-container-lowest);
  transition:
    border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
  outline: none;
  appearance: none;
  background-image: var(--dropdown-arrow);
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.5rem;
}

.auth-select:hover { border-color: var(--md-sys-color-on-surface); }

.auth-select:focus {
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

.auth-file {
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.auth-hint {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

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

/* An outlined card, like the vendor/customer cards below it: the summary
   banner and the checks table sit together on one white surface. */
.check-results {
  margin-top: 0;
  padding: 1rem 1rem 0.5rem;
  background: var(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
}

.check-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1.25rem;
  /* Nested inside the card's 16dp padding: small (8dp) corners. */
  border-radius: var(--md-sys-shape-corner-small);
  margin-bottom: 1rem;
  font: var(--md-sys-typescale-body-large);
  letter-spacing: var(--md-sys-typescale-body-large-tracking);
}

.check-summary--pass   { background: var(--success-bg); color: var(--success-dark); }
.check-summary--warning { background: var(--warning-bg); color: var(--warning-dark); }
.check-summary--fail   { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }

.check-summary-icon { display: flex; }
.check-summary-icon .icon { width: 20px; height: 20px; vertical-align: 0; }

.check-all-passed {
  color: var(--success);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  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(--md-sys-color-surface-container-low);
}

.check-table {
  width: 100%;
  border-collapse: collapse;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

.check-table thead th {
  text-align: left;
  padding: 0.5rem 0.75rem;
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

.check-table tbody tr + tr { border-top: 1px solid var(--md-sys-color-outline-variant); }

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

/* Holds a .status-badge (badges.css). */
.check-result-cell {
  white-space: nowrap;
  width: 1%;
}

.check-reason { color: var(--md-sys-color-on-surface-variant); }

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

.reject-header h2 {
  font: var(--md-sys-typescale-title-large);
  letter-spacing: var(--md-sys-typescale-title-large-tracking);
  color: var(--md-sys-color-on-surface);
  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(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  overflow: hidden;
}

.reject-email-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.25rem;
  background: var(--md-sys-color-surface-container);
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
  gap: 1rem;
}

.reject-email-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
}

.reject-email-label {
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

/* M3 outlined text area. */
.reject-email-body {
  width: 100%;
  padding: 1.25rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  margin: 0.75rem;
  width: calc(100% - 1.5rem);
  outline: none;
  font: var(--md-sys-typescale-body-large);
  letter-spacing: var(--md-sys-typescale-body-large-tracking);
  color: var(--md-sys-color-on-surface);
  resize: vertical;
  background: var(--md-sys-color-surface-container-lowest);
  transition:
    border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}

.reject-email-body:hover {
  border-color: var(--md-sys-color-on-surface);
}

.reject-email-body:focus {
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

/* ── Review banner ─────────────────────────────────────────── */
.review-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  background: var(--md-sys-color-secondary-container);
  border-radius: var(--md-sys-shape-corner-medium);
  padding: 1rem;
  margin-bottom: 1.5rem;
}

/* M3 banner: a 24dp leading icon in the banner's own content colour. */
.review-banner-icon {
  flex-shrink: 0;
  display: flex;
  color: var(--md-sys-color-on-secondary-container);
}
.review-banner-icon .icon { width: 24px; height: 24px; vertical-align: 0; }

.review-banner-text {
  flex: 1 1 240px;
  margin: 0;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-secondary-container);
}

.review-banner-btn {
  background-color: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  border-color: transparent;
}
.review-banner-btn:hover {
  color: var(--md-sys-color-on-primary);
}

/* 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);
  margin-bottom: 0.9rem;
}
.review-banner--warning .review-banner-text { color: var(--warning-dark); }
.review-banner--warning .review-banner-icon { color: var(--warning-dark); }

/* A large payment tints the whole page in the warning fill and frames the
   invoice as one white outlined card, so it can't be mistaken for routine. */
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(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--warning);
  border-radius: var(--md-sys-shape-corner-medium);
}
.review-banner--warning .review-banner-btn,
.review-banner--warning .review-banner-btn:hover {
  background-color: var(--warning-dark);
}

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

.rejected-banner {
  background: var(--md-sys-color-error-container);
  border-radius: var(--md-sys-shape-corner-medium);
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-error-container);
}

.approved-banner {
  background: var(--success-bg);
  border-radius: var(--md-sys-shape-corner-medium);
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--success-dark);
}

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

/* ── Invoice edit form ─────────────────────────────────────── */
/* M3 outlined card. Shared: other features reuse .form-section / .form-grid. */
.form-section {
  background: var(--md-sys-color-surface-container-lowest);
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-large);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.form-section h3 {
  font: var(--md-sys-typescale-title-medium);
  letter-spacing: var(--md-sys-typescale-title-medium-tracking);
  color: var(--md-sys-color-on-surface);
  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;
}

/* M3 count badge, neutral. */
.form-section-count {
  display: inline-block;
  margin-left: 0.4rem;
  min-width: 1rem;
  padding: 0 0.4rem;
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  border-radius: var(--md-sys-shape-corner-full);
  font: var(--md-sys-typescale-label-small);
  letter-spacing: var(--md-sys-typescale-label-small-tracking);
  text-align: center;
}

/* Compact tonal button. */
.btn-link {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--md-sys-color-secondary-container);
  border: none;
  padding: 0.375rem 1rem;
  margin: 0;
  border-radius: var(--md-sys-shape-corner-full);
  color: var(--md-sys-color-on-secondary-container);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  cursor: pointer;
  text-decoration: none;
  transition:
    background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}

.btn-link:hover {
  background-image: linear-gradient(
    color-mix(in srgb, currentColor 8%, transparent),
    color-mix(in srgb, currentColor 8%, transparent));
  box-shadow: var(--md-sys-elevation-level1);
}

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

/* The edit form swaps in where the show page was, so its fields use the show
   page's 14px values (M3 density -3, as in the dense line-item rows) instead
   of the 16px form default. Not on phones: iOS Safari zooms the page into any
   focused field under 16px. */
@media (min-width: 601px) {
  .invoice-form .form-field :is(input:not([type="checkbox"], [type="radio"], [type="file"]), select, textarea) {
    min-height: 40px;
    padding: 0.5rem 0.75rem;
    font: var(--md-sys-typescale-body-medium);
    letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  }
}
/* Its cards take the show page's card shape and padding (.invoice-party). */
.invoice-form .form-section {
  border-radius: var(--md-sys-shape-corner-medium);
  padding: 1.25rem;
}

/* 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 {
  /* The second column also takes the wrapped "Service to" date, so it must
     fit a dd.mm.yyyy value in the dense field below. */
  grid-template-columns: 2fr 108px 110px 110px;
}

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

.line-items-warning {
  margin-top: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--warning-bg);
  border-radius: var(--md-sys-shape-corner-medium);
  color: var(--warning-dark);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

/* Supporting invoice documents */
.supporting-documents-help {
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  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(--md-sys-color-on-surface);
}

.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-radius: var(--md-sys-shape-corner-small);
  background: var(--md-sys-color-surface-container-low);
}

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

/* Compact in-list label chip. */
.supporting-document-kind {
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-secondary-container);
  background: var(--md-sys-color-secondary-container);
  padding: 0.25rem 0.5rem;
  border-radius: var(--md-sys-shape-corner-small);
}

.supporting-document-link {
  color: var(--md-sys-color-on-surface);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  text-decoration: none;
  overflow-wrap: anywhere;
}

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

.supporting-document-meta {
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}

.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(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-medium);
  background: var(--md-sys-color-surface-container-low);
}

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

/* Dense (32px) button variant. */
/* M3 extra-small button: 32px, 12px side padding, 4px icon gap — for
   buttons that sit in table rows. */
.btn-small {
  min-height: 32px;
  padding: 0.25rem 0.75rem;
  gap: 0.25rem;
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
}
.btn-small .icon { width: 16px; height: 16px; }
.btn-small:has(> .icon:first-child) { padding-left: 0.5rem; }

.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: var(--md-sys-shape-corner-small);
  background: var(--md-sys-color-surface-container-low);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

.supporting-confirmation:has(.supporting-confirmation-check) {
  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: var(--md-sys-shape-corner-full);
  background: var(--success);
  color: var(--md-sys-color-on-primary);
}
.supporting-confirmation-check .icon { width: 16px; height: 16px; vertical-align: 0; }

.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: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  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(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  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(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

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

/* Rows hold up to three stacked controls, so every cell starts at the top. */
.invoice-table--line-items tbody td { vertical-align: top; }

/* Column floors sit on the content, not the cells: an auto-layout table
   ignores min-width on a cell and squeezes a width: 100% select to nothing. */
.li-desc { min-width: 14rem; }

.li-qty-col,
.li-amount-col { white-space: nowrap; }
.li-qty-col { font-variant-numeric: tabular-nums; }
.invoice-table td.li-qty-col--empty { color: var(--md-sys-color-on-surface-variant); }
.li-amount { font-variant-numeric: tabular-nums; }
.li-amount-detail {
  margin-top: 0.125rem;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  font-variant-numeric: tabular-nums;
  color: var(--md-sys-color-on-surface-variant);
}

.li-coding-col-sub { display: block; }
.li-coding-col .budget-line-inline { min-width: 14rem; max-width: none; }
.li-coding-col .budget-line-inline + .budget-line-inline { margin-top: 0.5rem; }
.li-approval { margin-top: 0.5rem; }

.li-docs-col { overflow-wrap: anywhere; }
.li-docs-col .supporting-docs-trigger { min-width: 12rem; max-width: 16rem; }

/* Under the description: the Flexible Remuneration chip, then the service
   period, wrapping as one body-small line. */
.li-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  margin-top: 0.25rem;
}
.li-meta .overflow-chip { margin-left: 0; }
.li-meta .li-service-period-dates { margin-top: 0; }
.li-meta .li-service-period-set {
  margin-top: 0;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  white-space: nowrap;
}

/* 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.
   Rows stay white: Material keeps a row fill for hover and selection, so a
   status never tints the whole row. */
.invoice-table--line-items tbody tr.is-unassigned td:first-child { box-shadow: inset 3px 0 0 var(--md-sys-color-error); }
.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 {
  transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.invoice-table--line-items tbody tr:hover {
  background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
}

/* A row whose quantity × unit price doesn't equal its stored total (typically
   an OCR-import drift): the needs-doc bar, plus a warning icon 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); }
/* Its data-tip copy shows in the shared tooltip (base.css .md-tooltip). */
.li-amount-warning {
  display: inline-flex;
  margin-right: 0.25rem;
  vertical-align: -0.2em;
  color: var(--warning-dark);
  cursor: help;
}
.li-amount-warning .icon { width: 16px; height: 16px; vertical-align: 0; }

/* Compact in-table status label (24px chip). */
.li-status-pill {
  display: inline-block;
  padding: 0.25rem 0.5rem;
  border-radius: var(--md-sys-shape-corner-small);
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  white-space: nowrap;
}
.li-status-pill--unassigned { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
.li-status-pill--needs-doc  { background: var(--warning-bg); color: var(--warning-dark); }
.li-status-pill--done       { background: var(--success-bg); color: var(--success-dark); }

.li-doc-hint {
  margin-top: 0.35rem;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}
.li-doc-hint--missing { color: var(--warning-dark); }
.li-doc-hint--ok      { color: var(--success); }
.li-doc-hint[hidden]  { display: none; }

/* line_item_status_controller rewrites these hints' text, so their leading
   icons are drawn here rather than in the markup. */
.li-doc-hint--ok::before,
.li-overflow-hint::before {
  content: "";
  display: inline-block;
  width: 16px;
  height: 16px;
  margin-right: 0.25rem;
  vertical-align: -3px;
  background-color: currentColor;
  -webkit-mask: var(--md-icon-check) center / contain no-repeat;
  mask: var(--md-icon-check) center / contain no-repeat;
}
.li-overflow-hint::before { -webkit-mask-image: var(--md-icon-warning); mask-image: var(--md-icon-warning); }

/* 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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  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 sets 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); }
.li-overflow-hint {
  margin-top: 0.35rem;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  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(--md-sys-color-secondary-container);
}

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

/* 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(--md-sys-color-primary), var(--md-sys-color-primary)),
    linear-gradient(var(--md-sys-color-primary), var(--md-sys-color-primary));
  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(--md-sys-color-primary), var(--md-sys-color-primary)),
    linear-gradient(var(--md-sys-color-primary), var(--md-sys-color-primary)),
    linear-gradient(var(--md-sys-color-primary), var(--md-sys-color-primary));
  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(--md-sys-color-primary), var(--md-sys-color-primary)),
    linear-gradient(var(--md-sys-color-primary), var(--md-sys-color-primary)),
    linear-gradient(var(--md-sys-color-primary), var(--md-sys-color-primary));
  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;
}


/* M3 outlined select, dense (40px) for in-table use. */
.budget-line-inline {
  width: 100%;
  max-width: 240px;
  min-height: 40px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background-color: var(--md-sys-color-surface-container-lowest);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
}

/* Room for the base.css dropdown arrow. */
select.budget-line-inline { padding-right: 2rem; background-position: right 0.25rem center; }

.budget-line-inline:hover { border-color: var(--md-sys-color-on-surface); }

.budget-line-inline:focus {
  outline: none;
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

/* Locked state (e.g. the budget line once a ToR line item is chosen on the
   travel-claim verdict form): same disabled signal as base.css's
   .form-field select:disabled, which can't reach these inline selects —
   they sit in plain <label>s, and the background above would win. */
.budget-line-inline:disabled {
  background: color-mix(in srgb, var(--md-sys-color-on-surface) 4%, transparent);
  border-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
  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 primary. */
.supporting-docs-multi {
  width: 100%;
  max-width: 240px;
  height: auto;
  padding: 0.2rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background: var(--md-sys-color-surface-container-lowest);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface);
  overflow-y: auto;
}

.supporting-docs-multi:focus {
  outline: none;
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

.supporting-docs-multi option {
  padding: 0.2rem 0.35rem;
  border-radius: var(--md-sys-shape-corner-extra-small);
}

/* 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(--md-sys-color-primary) 0%, var(--md-sys-color-primary) 100%);
  color: var(--md-sys-color-on-primary);
}

/* 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;
  min-height: 40px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background: var(--md-sys-color-surface-container-lowest);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
  text-align: left;
  cursor: pointer;
}
/* A long file name ends in an ellipsis inside the field; the dialog it opens
   lists the full names. */
.supporting-docs-trigger > span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.supporting-docs-trigger:hover { border-color: var(--md-sys-color-on-surface); }
.supporting-docs-trigger:focus-visible {
  outline: none;
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}
.supporting-docs-trigger--empty {
  color: var(--md-sys-color-on-surface-variant);
  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(--md-sys-color-primary);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  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(--md-sys-color-on-primary-container); }

/* A Flexible Remuneration row's chip, pricing line, authorization and
   Unallocate action: one body-small line under the description, like
   .li-meta below it. */
.li-flex-allocation {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  margin-top: 0.25rem;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}
.li-flex-allocation .overflow-chip { margin-left: 0; }
.li-flex-allocation a { color: var(--md-sys-color-primary); }
.li-flex-allocation .li-flex-unallocate {
  margin-top: 0;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
}
.li-flex-allocation .li-flex-auth-missing { color: var(--warning-dark); }

.travel-details-summary {
  margin-top: 0.35rem;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

/* Travel-details and supporting-documents dialogs: the shell, header and
   actions are modals.css's shared M3 dialog. */
.travel-modal-error { margin: 0.75rem 0 0; }

/* The supporting-documents body is a checkbox list (M3 list, one 48dp row per
   document) so a long document list keeps a clear overview. */
/* An M3 list inside a dialog: full-width dividers above and below (carried
   out to the dialog's edges), 48dp rows, no box of its own. */
.supporting-docs-checklist {
  list-style: none;
  margin: 0 -1.5rem;
  padding: 0.5rem 0;
  max-height: 50vh;
  overflow-y: auto;
  border-block: 1px solid var(--md-sys-color-outline-variant);
}
.supporting-docs-checklist label {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 48px;
  padding: 0 1.5rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  cursor: pointer;
}
.supporting-docs-checklist label:hover { background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent); }
.supporting-docs-checklist input[type="checkbox"] {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--md-sys-color-primary);
  cursor: pointer;
}

/* 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]`. */
/* A floating M3 surface (surface-container, elevation 2), mirroring
   .donor-invoicing-summary. 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(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface);
  border-radius: var(--md-sys-shape-corner-large);
  box-shadow: var(--md-sys-elevation-level2);
  z-index: 5;
}
.budget-line-toolbar.is-visible { display: flex; }

.budget-line-toolbar-count {
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
}

/* 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(--md-sys-color-outline-variant);
  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: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
  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 {
  min-height: 40px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background-color: var(--md-sys-color-surface-container-lowest);
  color: var(--md-sys-color-on-surface);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  /* 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%;
}

.budget-line-toolbar select:hover { border-color: var(--md-sys-color-on-surface); }

/* 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: flex-start;
  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: var(--md-sys-shape-corner-extra-small);
  min-width: 3rem;
  padding: 0.15rem 0.3rem;
  margin: -0.15rem -0.3rem;
}

.li-desc-text:hover {
  text-decoration: underline dotted var(--md-sys-color-on-surface-variant);
  text-underline-offset: 2px;
}

.li-desc-text:focus-visible {
  outline: var(--md-focus-ring);
  outline-offset: 1px;
}

.li-desc-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 40px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background: var(--md-sys-color-surface-container-lowest);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
}

.li-desc-input:hover { border-color: var(--md-sys-color-on-surface); }

.li-desc-input:focus {
  outline: none;
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

/* Keystroke hint while editing, then the save confirmation. */
.li-desc-hint {
  flex: 0 0 100%;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.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-color: transparent;
  color: var(--md-sys-color-on-surface-variant);
  cursor: pointer;
  border-radius: var(--md-sys-shape-corner-full);
  flex: 0 0 auto;
  transition:
    background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.li-split-btn:hover {
  color: var(--md-sys-color-on-surface);
  background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
}
.li-split-btn .icon { width: 20px; height: 20px; vertical-align: 0; }

/* In a record's header the split/flag toggles sit beside the standard
   40px icon buttons (edit, delete), so they take the same size. */
.entry-header-actions .li-split-btn { width: 40px; height: 40px; padding: 0; }

/* Split wizard: the shared M3 dialog (modals.css). The line cards' four-field
   grid widens the split section to 736dp — past the 560dp basic-dialog
   maximum, deliberately, so a line's fields sit on one row; the allocate-only
   section keeps the basic width. */
.split-modal:has([data-split-wizard-target="stepSplit"]:not([hidden])) {
  width: min(46rem, calc(100vw - 2rem));
}

.split-confirm-sub,
.split-replace-note {
  margin: 0;
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}
/* Under the original-line card: the split replaces it. */
.split-replace-note { margin: -0.5rem 0 1rem; }

/* 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; }

/* The original line, as a filled card above the children: tertiary
   container, M3's contrasting accent, so the read-only reference stands
   apart from the white editable cards without borrowing the teal that marks
   selection (secondary container) or the primary actions. */
.split-original {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  background: var(--md-sys-color-tertiary-container);
  border-radius: var(--md-sys-shape-corner-medium);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-tertiary-container);
}
.split-original-label {
  font: var(--md-sys-typescale-label-small);
  letter-spacing: var(--md-sys-typescale-label-small-tracking);
  color: var(--md-sys-color-on-tertiary-container);
}
.split-original-desc { font-weight: 500; }
.split-original-meta {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
}
.split-original-fact-label {
  color: var(--md-sys-color-on-tertiary-container);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  margin-right: 0.2rem;
}
.split-original-fact strong { font-weight: 500; font-variant-numeric: tabular-nums; }
.split-original-total { font-weight: 500; font-variant-numeric: tabular-nums; }

/* "Pre-fill new lines from the original": an M3 checkbox row. */
.split-prefill {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.75rem;
  min-height: 40px;
  margin: 0 0 0.75rem;
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  color: var(--md-sys-color-on-surface);
  cursor: pointer;
}
.split-prefill input { width: 18px; height: 18px; margin: 0; }
.split-prefill-hint {
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

/* One white card per child: a numbered first row over a grid of labelled
   fields, all on one fill (no header band), so each line reads as one unit
   against the dialog's surface. A child allocated to Flexible Remuneration
   takes the primary outline. */
.split-lines {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.split-line {
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: var(--md-sys-shape-corner-medium);
  background: var(--md-sys-color-surface-container-lowest);
}
.split-line.is-flexible { border-color: var(--md-sys-color-primary); }

.split-line-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.25rem 0 1rem;
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

.split-line-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--md-sys-shape-corner-full);
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
}

.split-line-title {
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
}
.split-line-head .split-flex-hint { margin: 0; }
.split-line-total {
  margin-left: auto;
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  color: var(--md-sys-color-on-surface);
  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.75rem;
  padding: 0.75rem 1rem 1rem;
}

.split-line-grid {
  display: grid;
  gap: 0.75rem;
}
.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)); }
/* A file field needs room for the M3 "Choose files" button and the file name. */
.split-line-grid--details .split-field:has(input[type="file"]) { grid-column: span 2; }
/* 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)); }
}

/* Field labels above each control: label-medium, sentence case (M3 never
   sets labels in capitals). */
.split-field { display: block; min-width: 0; }
.split-field-label {
  display: block;
  margin-bottom: 0.25rem;
  font: var(--md-sys-typescale-label-medium);
  letter-spacing: var(--md-sys-typescale-label-medium-tracking);
  color: var(--md-sys-color-on-surface-variant);
}
/* Dense (40px) outlined fields, like the invoice table's inline controls.
   A file input keeps base.css's file-picker look instead. */
.split-line input:not([type="file"]),
.split-line select {
  width: 100%;
  box-sizing: border-box;
  min-height: 40px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  background-color: var(--md-sys-color-surface-container-lowest);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
}
.split-line select {
  appearance: none;
  background-image: var(--dropdown-arrow);
  background-repeat: no-repeat;
  background-position: right 0.25rem center;
  background-size: 24px;
  padding-right: 2rem;
}
.split-line input:not([type="file"]):hover,
.split-line select:hover { border-color: var(--md-sys-color-on-surface); }
.split-line input:not([type="file"]):focus,
.split-line select:focus {
  outline: none;
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}
.split-line input[type="checkbox"] { width: auto; }
.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(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}


.split-balance {
  display: flex;
  gap: 1.5rem;
  justify-content: flex-end;
  align-items: baseline;
  margin-top: 1rem;
  padding: 0.6rem 0.75rem;
  border-radius: var(--md-sys-shape-corner-small);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  background: var(--md-sys-color-surface-container);
}
.split-balance strong { font-weight: 500; font-variant-numeric: tabular-nums; margin-left: 0.3rem; }
.split-balance.is-balanced { color: var(--success-dark); background: var(--success-bg); }
.split-balance.is-unbalanced { color: var(--warning-dark); background: var(--warning-bg); }

.split-modal-error {
  margin: 0.75rem 0 0;
  color: var(--md-sys-color-error);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

/* 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: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

/* 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 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.75rem 1rem;
  background: var(--warning-bg);
  border-radius: var(--md-sys-shape-corner-medium);
  color: var(--warning-dark);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}

/* Per-row 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(--md-sys-color-primary);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}

/* 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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}
:is(.split-fee-period-hint, .split-never-billed-hint, .split-billable-move-hint) .icon {
  width: 16px;
  height: 16px;
  margin-right: 0.25rem;
  vertical-align: -3px;
}

/* 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: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  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. Secondary-container fill to match the flexible-allocation hints. */
.split-flex-auth {
  margin-top: 0.85rem;
  padding: 0.7rem 0.8rem;
  border-radius: var(--md-sys-shape-corner-small);
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}
.split-flex-auth label {
  display: block;
  font: var(--md-sys-typescale-title-small);
  letter-spacing: var(--md-sys-typescale-title-small-tracking);
  margin-bottom: 0.3rem;
}
.split-flex-auth-hint {
  margin: 0.4rem 0 0;
  color: var(--md-sys-color-on-secondary-container);
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
}
.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; }
