/* ═══════════════════════════════════════════════════════════════════
   Invoices tab (AdminInvoices.vue) - `inv-`.

   A fourth data tab of /admin/payments. Inherits RTL from `.pay-page`
   (admin-payments.css), so nothing here re-declares direction; the
   component wraps every money figure, date, document number and email
   in `dir="ltr"` itself.

   Like `.pay-panel--cards` and `.pay-panel--links`, the panel must never
   gain `overflow`, `transform`, `filter`, `backdrop-filter`,
   `perspective`, `contain` or `will-change`: the toast inside it is
   `position: fixed`, and this screen also hosts three date-range
   pickers whose desktop popover and phone sheet are fixed too. Any one
   of those properties makes the panel their containing block, which
   clips the popover and unanchors the sheet. The table does its own
   scrolling inside `.inv-table-wrap`.

   Shared chrome (`.admin-table`, `.btn`, `.btn-icon`, `.empty-state`,
   `.toast`, `.admin-toolbar`, `.modal*`, `.reg-filter-bar`,
   `.reg-th-sort`, `.form-*`) comes from admin.css; only what is
   specific to this screen lives here. Shadows use the cool-blue
   rgba(0, 60, 130, *) family, never raw black.

   This file MUST keep its `admin` filename prefix: scripts/bundle-css.mjs
   partitions the two production bundles on `href.startsWith('/css/admin')`,
   so a rename ships it to every marketing visitor.
   ═══════════════════════════════════════════════════════════════════ */

/* Declared here rather than in admin-payments.css beside its two
   siblings because this sheet loads after it, so the two never race -
   and everything this screen owns then lives in one file. */
.pay-panel--invoices {
  min-width: 0;
}

/* ── Head ── */

.inv-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 0.9rem;
}

/* global.css only dims .btn-primary/.btn-secondary when disabled; the plain
   .btn.btn-sm here matched neither, so a dead button looked clickable (found in
   the visual pass). Same treatment admin-leads.css gives its own.

   Scoped to the TAB ROOT rather than to a list of containers: the pager's
   "הקודם" is disabled on every first page, and the stale banner's retry and both
   modal footers are disabled while their request is in flight. `.inv-panel` is
   the single root of this tab and nothing here is teleported, so this cannot
   reach another admin screen. */
.inv-panel .btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.inv-subtitle {
  flex: 1 1 30rem;
  margin: 0;
  max-width: 84ch;
  color: var(--text-secondary);
  font-size: 0.9rem;
  line-height: 1.6;
}

.inv-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  max-width: 56ch;
  margin-inline: auto;
  line-height: 1.6;
}

.inv-error p {
  margin: 0;
}

/* ── Filters ──
   Ten controls, so the bar wraps rather than compressing them; the
   search field is the one that takes the leftover width. */

.inv-filter-bar {
  row-gap: 0.6rem;
}

.inv-amount-input {
  width: 7rem;
  font-variant-numeric: tabular-nums;
}

.inv-search input {
  width: 15rem;
}

.inv-clear {
  align-self: flex-end;
}

/* Said when the cohort list itself failed to load, so the picker beside
   it cannot be read as "there are no cohorts". */
.inv-filter-note {
  display: block;
  margin-block-start: 0.25rem;
  padding: 0;
  background: none;
  border: none;
  color: #8A5A12;
  font-size: 0.72rem;
  text-align: start;
  cursor: pointer;
}

.inv-filter-note:hover {
  text-decoration: underline;
}

/* A cohort filter that arrived with a shared link, shown to a reader who
   has no access to the cohort list and so cannot be offered the picker. */
.inv-filter-locked {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  height: 2.1rem;
  padding-inline: 0.6rem;
  background: #F4F6FA;
  border: 1px solid #dfe4ec;
  border-radius: 8px;
}

.inv-filter-locked-name {
  font-size: 0.82rem;
  color: #5A5B6A;
}

.inv-filter-locked-clear {
  padding: 0;
  background: none;
  border: none;
  color: #8a93a3;
  cursor: pointer;
}

.inv-filter-locked-clear:hover {
  color: #C4551A;
}

/* ── The page-scoped summary line ── */

.inv-summary {
  margin: 0 0 0.6rem;
  font-size: 0.84rem;
  color: #5A5B6A;
  font-variant-numeric: tabular-nums;
}

/* ── Stale wash ──
   One class for every block rendered from the last payload. Dimming a
   subset is worse than dimming nothing: the un-dimmed half reads as the
   authoritative one while the rest says otherwise. */

.inv-stale {
  opacity: 0.55;
  filter: saturate(0.7);
}

.inv-stale-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
  padding: 0.6rem 0.9rem;
  background: #FDF6E7;
  border: 1px solid #EDD9A3;
  border-radius: var(--radius-sm);
  color: #7A5C10;
  font-size: 0.85rem;
  line-height: 1.6;
}

/* ── Table ── */

.inv-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

.inv-table {
  min-width: 1420px;
}

.inv-table th,
.inv-table td {
  white-space: nowrap;
  vertical-align: top;
}

.inv-td-person {
  font-weight: 600;
  color: #191A23;
}

.inv-person-link {
  color: var(--primary-color);
  text-decoration: none;
}

.inv-person-link:hover {
  text-decoration: underline;
}

.inv-sub {
  display: block;
  margin-block-start: 0.15rem;
  font-weight: 400;
  font-size: 0.74rem;
  color: #8E8F9E;
}

.inv-td-cohort {
  color: #5A5B6A;
}

.inv-td-amount,
.inv-td-day {
  font-variant-numeric: tabular-nums;
}

.inv-td-amount {
  font-weight: 600;
  color: #191A23;
}

/* Which instalment of the charge this row is. The whole reason this table
   has more rows than the payments ledger does, so it sits next to the
   figure rather than in a column of its own. */
.inv-chip-inst {
  display: inline-block;
  margin-inline-start: 0.35rem;
  padding: 0.05rem 0.35rem;
  background: #EAF2FD;
  border-radius: 999px;
  color: #0B5CC4;
  font-weight: 500;
  font-size: 0.7rem;
}

.inv-sku {
  font-size: 0.82rem;
  color: #5A5B6A;
}

.inv-sku--none {
  color: #8E8F9E;
}

/* The deadline column carries the warning too, not only the chip two
   columns over: this is the column a reader scans when asking "what is
   about to be late". */
.inv-due-date {
  color: #B3261E;
  font-weight: 600;
}

/* ── Status chip ──
   `לטיפול` is the only FILLED chip on the screen. It means the money is
   in the bank account and the fourteen-day statutory clock is running
   with no document issued, which is the one state this table exists to
   surface - so it is deliberately louder than every other state,
   including the failures. */

.inv-chip {
  display: inline-block;
  padding: 0.14rem 0.5rem;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}

.inv-chip--due {
  background: #B3261E;
  color: #fff;
  font-weight: 600;
}

.inv-chip--not_due {
  background: #EEF0F4;
  color: #6E7180;
}

.inv-chip--issued {
  background: #E7F6ED;
  color: #1B7F4C;
}

.inv-chip--reconciled {
  background: #EAF2FD;
  color: #0B5CC4;
}

.inv-chip--failed {
  background: #FDECEC;
  color: #A32020;
  box-shadow: inset 0 0 0 1px #F3C4C0;
}

.inv-chip--ambiguous {
  background: #FDF3E3;
  color: #8A5A12;
  box-shadow: inset 0 0 0 1px #EDD9A3;
}

.inv-chip--refund {
  background: #F1ECFD;
  color: #5B3BC4;
}

.inv-chip--excluded {
  background: #EEF0F4;
  color: #6E7180;
  box-shadow: inset 0 0 0 1px #dfe4ec;
}

/* The row itself, so a long table can be scanned without reading chips.
   Keyed on the same status the chip is, and kept pale enough that the
   chip stays the loud thing. */
.inv-row--due td {
  background: #FFF7F5;
}

/* ── Document number and the duplicate marker ── */

.inv-td-doc {
  font-variant-numeric: tabular-nums;
}

/* More than one legal document points at this instalment. Never quiet:
   two running numbers for the same money is a correction an accountant
   has to make, and the only fix is a credit note. */
.inv-dup {
  display: inline-block;
  margin-inline-start: 0.3rem;
  padding: 0.05rem 0.32rem;
  background: #FDECEC;
  border-radius: 999px;
  color: #A32020;
  font-weight: 600;
  font-size: 0.68rem;
}

/* ── Email outcome ── */

.inv-td-email {
  font-size: 0.8rem;
  color: #5A5B6A;
}

.inv-email {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.inv-email--sent {
  color: #1B7F4C;
}

.inv-email--pending {
  color: #0B5CC4;
}

.inv-email--failed,
.inv-email--no_transport {
  color: #A32020;
}

.inv-email--no_address {
  color: #8A5A12;
}

.inv-email--not_applicable,
.inv-email--none {
  color: #8E8F9E;
}

/* ── Row actions ──
   Labelled, never icon-only. A glyph cannot say whether the customer
   gets the document by email, and it cannot say that one of these
   buttons creates a legal number that can never be deleted. */

.inv-col-actions {
  width: 1%;
}

.inv-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.3rem;
}

/* ── Pagination ── */

.inv-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-block-start: 0.9rem;
}

.inv-pagination-mid {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.inv-pagination-info {
  font-size: 0.84rem;
  color: #5A5B6A;
}

.inv-page-size {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: #8E8F9E;
}

.inv-page-size-select {
  padding: 0.2rem 0.4rem;
  border: 1px solid #dfe4ec;
  border-radius: 6px;
  background: #fff;
  font-size: 0.8rem;
  font-family: inherit;
}

/* ── Modals ── */

.inv-modal {
  width: 640px;
}

.inv-modal-lead {
  margin: 0 0 1rem;
  color: #5A5B6A;
  font-size: 0.88rem;
  line-height: 1.7;
}

.inv-report {
  width: 860px;
}

/* A scan that stopped before the end of Morning's documents. Louder than the
   stale banner on purpose: the report below it can be read as a to-do list, and
   issuing off an incomplete one mints a second legal number. */
.inv-report-truncated {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  margin-bottom: 1.1rem;
  padding: 0.8rem 1rem;
  background: #FCEDEC;
  border: 1px solid #E9B4AF;
  border-inline-start: 4px solid #B3261E;
  border-radius: var(--radius-sm);
  color: #7A1C16;
  font-size: 0.85rem;
  line-height: 1.65;
}

.inv-report-truncated > i {
  margin-block-start: 0.15rem;
  color: #B3261E;
}

.inv-report-truncated-title {
  margin: 0 0 0.25rem;
  font-size: 0.92rem;
  font-weight: 600;
}

.inv-report-truncated-text {
  margin: 0;
}

.inv-report-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1.1rem;
}

.inv-report-count {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 8rem;
  padding: 0.6rem 0.8rem;
  background: #F7F9FC;
  border: 1px solid #e6ebf2;
  border-radius: 10px;
}

.inv-report-count-of {
  font-size: 0.9rem;
  font-weight: 400;
  color: #8a93a3;
}

.inv-report-count-value {
  font-size: 1.35rem;
  font-weight: 600;
  color: #191A23;
  font-variant-numeric: tabular-nums;
}

.inv-report-count-label {
  font-size: 0.74rem;
  color: #8a93a3;
}

.inv-report-count--warn .inv-report-count-value {
  color: #8A5A12;
}

.inv-report-count--due .inv-report-count-value {
  color: #B3261E;
}

.inv-report-section {
  margin-block-start: 1.1rem;
}

.inv-report-title {
  margin: 0 0 0.5rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: #191A23;
}

.inv-report-empty {
  margin: 0;
  color: #8E8F9E;
  font-size: 0.85rem;
}

.inv-report-table {
  width: 100%;
  font-size: 0.82rem;
}

.inv-report-table td {
  vertical-align: top;
  white-space: normal;
}

/* ═══════════════════════════════════════════════════════════════════
   Tablet / phone: rows become cards.

   Twelve columns do not fit below 1024px and the generic .admin-table
   rules crush them into an overlap, so each cell prints its own
   data-label caption instead - the same treatment .cpay-table and
   .apl-table get. An empty labelled cell hides itself, so a row with no
   document grows no blank "מספר מסמך" line.
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  .inv-table-wrap {
    overflow-x: visible;
  }

  .inv-table {
    display: block;
    min-width: 0;
    background: transparent;
    border: none;
    box-shadow: none;
  }

  .inv-table thead {
    display: none;
  }

  .inv-table tbody {
    display: block;
    width: 100%;
  }

  .inv-table tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.2rem 0.7rem;
    width: 100%;
    margin-block-end: 0.85rem;
    padding: 0.8rem 1rem 0.65rem;
    background: #fff;
    border: 1px solid #e6ebf2;
    border-radius: 14px;
    box-shadow: 0 1px 3px rgba(0, 60, 130, 0.05);
  }

  /* The row tint is a cell background on the desktop table; on a card the
     card itself is what carries it. */
  .inv-table tbody tr.inv-row--due {
    background: #FFF7F5;
    border-color: #F3C4C0;
  }

  .inv-table tbody tr:hover td,
  .inv-table tbody tr.inv-row--due td {
    background: transparent;
  }

  .inv-table td {
    white-space: normal;
    border: none;
    padding: 0;
  }

  /* Name and cohort lead the card unlabelled - a caption above the name
     would only repeat it, and that is also what keeps the two out of the
     generic `td[data-label]` rule below, which would otherwise beat their
     own ordering on equal specificity. Everything else stacks as a
     labelled row, and the actions land last. */
  .inv-table td.inv-td-person {
    order: 0;
    flex: 1 1 auto;
    font-size: 1rem;
  }

  .inv-table td.inv-td-cohort {
    order: 2;
    flex: 1 1 100%;
    font-size: 0.82rem;
  }

  .inv-table td[data-label] {
    order: 3;
    flex: 1 1 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.15rem 0.6rem;
    padding-block: 0.34rem;
    border-block-start: 1px solid #f1f4f8;
  }

  .inv-table td[data-label]:empty {
    display: none;
  }

  .inv-table td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 8rem;
    color: #8a93a3;
    font-weight: 600;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    line-height: 1.7;
  }

  .inv-table td.inv-col-actions {
    order: 4;
    width: auto;
    flex: 1 1 100%;
    padding-block-start: 0.5rem;
    border-block-start: 1px solid #f1f4f8;
  }

  /* A reader with no write grant, or a row whose only controls are writes, gets
     no buttons at all - and the rule above would leave a stray divider line
     under the card. `td[data-label]:empty` cannot cover this one: the cell is
     not labelled, and it is never truly `:empty` either. */
  .inv-table td.inv-col-actions:not(:has(button)) {
    display: none;
  }

  .inv-report,
  .inv-modal {
    width: auto;
  }

  /* ── Touch floors (admin mobile revamp) ──
     44px targets and 16px input text below 1025px. 16px exactly on text
     inputs: anything smaller makes iOS Safari zoom the whole page on
     focus. The issue buttons stay labelled - only their hit area grows. */
  .inv-panel .btn,
  .inv-panel .btn-icon {
    min-height: 44px;
    min-width: 44px;
  }

  .inv-panel .form-input,
  .inv-panel .form-select,
  .inv-panel .inv-page-size-select {
    font-size: 16px;
    min-height: 44px;
  }

  /* The clear glyph keeps admin.css's physical right-side anchor here (this
     screen never mirrored it), which in the RTL island is the text-start
     side - so the input reserves the strip the enlarged button occupies. */
  .inv-panel .search-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
  }

  .inv-panel .admin-search input {
    padding-right: 48px;
  }

  .inv-filter-note {
    min-height: 44px;
  }

  .inv-filter-locked {
    height: auto;
    min-height: 44px;
  }

  .inv-filter-locked-clear {
    min-width: 44px;
    min-height: 44px;
  }
}

@media (max-width: 767px) {
  .inv-search input,
  .inv-amount-input {
    width: 100%;
  }

  .inv-pagination {
    gap: 0.5rem;
  }

  .inv-pagination-info {
    order: 3;
    flex: 1 1 100%;
    text-align: center;
  }

  .inv-report-count {
    flex: 1 1 40%;
    min-width: 0;
  }
}

/* ── Print ──
   The reconciliation report is the pre-go-live document the owner hands
   to an accountant, so `העתקת הדוח` (plain text on the clipboard) is the
   primary route out of this screen. These rules only stop a browser
   print from CLIPPING it: the overlay is fixed and scrolls internally,
   which prints as a single cropped page. The panel behind it still
   prints; hiding it would mean reaching outside this screen's own
   subtree. */
@media print {
  .inv-report-overlay {
    position: static;
    background: none;
  }

  .inv-report-overlay .modal {
    width: 100%;
    max-width: none;
    max-height: none;
    overflow: visible;
    box-shadow: none;
  }

  .inv-no-print {
    display: none;
  }
}
