/* ═══ WF-FIT — ONE responsive rule set for dense tables and KPI rows ═══════
   (Hal 2026-10-13: "figure out how we could automate this so when we build
   things it gets set properly"). Replaces the per-screen width hacks.

   HOW TO ADD A NEW TABLE / LIST / KPI ROW — nothing else is needed:
   1. Wrap the table or list in a container: give its card the class `wf-cq`
      (or add the card's selector to the `container` rule below). Tiers then
      follow the CARD's width, never the window's, so the sidebar, a split
      pane or a modal all just work.
   2. Size columns ONLY with the column variables, which every tier sets:
        --col-check  --col-thumb  --col-money  --col-date  --col-status
        --col-id     --col-details --col-act   --col-watch-min (main text min)
      e.g. `th[data-col="cost"] { width: var(--col-money) }`; the main text
      column gets no width (tables) or `minmax(var(--col-watch-min), 1fr)`
      (grid rows). Never a px width, never !important per column.
   3. Mark optional columns `data-cq="mid"` (shown from 1200px of container)
      or `data-cq="wide"` (from 1500px). Header and cells both.
   4. KPI row: class `wf-kpi-row` on the row. Cards share one row equally
      (min --kpi-min, then it slides), labels wrap to two lines (never "…"), the
      icon goes above the label on a narrow card, padding and figures scale.

   Tiers (container width):  wide ≥1500 · mid 1050-1499 · compact 1000-1049 ·
   narrow <1000 · scroll <760 (the photo + name stick, the rest slides).
   The phone switch (≤768 window: cards instead of a table) is the app's
   one viewport boundary and stays a media query.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── containers (desktop; phones keep their own card layouts untouched) ── */
@media (min-width: 769px) {
  .wf-cq,
  #page-inventory #inv-list-card,
  #page-payments .payments-table-card,
  #page-payments .loans-sec { container: wf-cq / inline-size; }
  .wf-kpi-row,
  #page-inventory.jj-r01 #jj-inv-stats.jj-kpis,
  #page-payments .payment-summary-grid.wf-kpi-rail { container: wf-kpis / inline-size; }
}

/* ── the column variables, one set per tier ── */
.wf-cq > *, #page-inventory #inv-list-card > *, #page-payments :is(.payments-table-card, .loans-sec) > * {
  --col-pad: 14px; /* cell side padding; the content-sized columns below include it */
  --col-check: calc(18px + 2 * var(--col-pad)); --col-thumb: calc(64px + 2 * var(--col-pad));
  --col-days: calc(46px + 2 * var(--col-pad)); --col-act: calc(40px + 2 * var(--col-pad));
  --col-money: 112px; --col-stack: 132px; --col-stage: 124px; --col-date: 92px; --col-status: 140px; --col-id: 112px; --col-details: 220px; --col-watch-min: 240px;
}
@container wf-cq (max-width: 1499px) {
  .wf-cq > *, #page-inventory #inv-list-card > *, #page-payments :is(.payments-table-card, .loans-sec) > * {
    --col-money: 108px; --col-stack: 124px; --col-stage: 116px; --col-status: 132px; --col-id: 108px; --col-details: 200px; --col-watch-min: 220px;
  }
}
@container wf-cq (max-width: 1049px) {
  .wf-cq > *, #page-inventory #inv-list-card > *, #page-payments :is(.payments-table-card, .loans-sec) > * {
    --col-money: 104px; --col-stack: 118px; --col-stage: 108px; --col-date: 88px; --col-status: 124px; --col-details: 180px; --col-watch-min: 200px;
  }
}
@container wf-cq (max-width: 999px) {
  .wf-cq > *, #page-inventory #inv-list-card > *, #page-payments :is(.payments-table-card, .loans-sec) > * {
    --col-money: 100px; --col-stack: 112px; --col-stage: 104px; --col-status: 116px; --col-details: 160px; --col-watch-min: 180px; --col-pad: 12px;
  }
}
/* generic tier hiding for new tables */
@container wf-cq (max-width: 1499px) { [data-cq="wide"] { display: none !important; } }
@container wf-cq (max-width: 1049px) { [data-cq="mid"] { display: none !important; } }

/* ═══ KPI rows ════════════════════════════════════════════════════════════ */
@media (min-width: 769px) {
  .wf-kpi-row,
  html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis,
  html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin {
    /* One row, the cards share it equally (any count: 2 in Private view, 5 for
       an owner); never a wrapped orphan card. Below --kpi-min a card stops
       shrinking and the row slides instead. The 4px pad keeps the selected
       ring and focus outline inside the row's scroll box. */
    --kpi-min: 140px;
    display: grid !important; grid-auto-flow: column !important; grid-template-columns: none !important;
    grid-auto-columns: minmax(var(--kpi-min), 1fr) !important;
    gap: 10px !important; align-items: stretch !important;
    overflow-x: auto !important; overflow-y: hidden !important; scrollbar-width: thin;
    padding: 4px !important; margin: -4px -4px 10px !important;
  }
  /* payments-clip-1027: a Payment Tracker card carries a sub-line and a note that now wrap (never "…"), so at a 140px floor (four
     163px cards on the Fold at 984) it became a 163x180 pillar. Its cards keep a wide 204px floor instead: four still share the
     row from ~1180 up (270px at 1440); on the Fold the row slides as one row with the 4th card peeking in, like the QB rails (U1). */
  html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin { --kpi-min: min(204px, 100%); }
  /* the gap below the KPI row is the Payment Tracker's --pt-gap (end of this file) */
  /* each card is a container too: its icon stacks over the label when narrow */
  .wf-kpi-row > *,
  html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis > .jj-stat,
  html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin > .pay-kpi {
    container: wf-kpi / inline-size;
    min-width: 0 !important; max-width: none !important; width: auto !important;
    padding: clamp(12px, 1.6cqw, 22px) clamp(12px, 2cqw, 24px) !important;
    column-gap: clamp(10px, 1.2cqw, 14px) !important;
  }
  html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin > .pay-kpi.wf-kpi-faced { padding: 0 !important; }
  html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin .wf-kpi-face { padding: clamp(12px, 1.6cqw, 22px) clamp(12px, 2cqw, 24px) !important; }
  /* the rail's slide affordance has nothing to do in a grid */
  html body #page-payments .wf-kpi-railwrap:has(> .payment-summary-grid.wf-kpi-rail.wf-kpi-thin) > .wf-kpi-progress { display: none !important; }

  /* labels: wrap to two lines, never an ellipsis */
  :is(.wf-kpi-row, #page-inventory.jj-r01 #jj-inv-stats.jj-kpis, #page-payments .payment-summary-grid.wf-kpi-rail) :is(.jj-stat-k, .pay-kpi-label, .wf-kpi-label) {
    white-space: normal !important; overflow: hidden; text-overflow: clip !important;
    display: -webkit-box !important; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
    line-height: 1.3 !important; overflow-wrap: normal; word-break: normal; hyphens: none;
  }
  /* the "Filtered" tag rides after the label text instead of being a flex sibling */
  html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis .jj-stat.is-filtered .jj-stat-k::after { display: inline-block; margin-left: 6px; vertical-align: 1px; }
  /* figures scale with the card, always on one line */
  :is(.wf-kpi-row, #page-inventory.jj-r01 #jj-inv-stats.jj-kpis, #page-payments .payment-summary-grid.wf-kpi-rail) :is(.jj-stat-v, .pay-kpi-value, .wf-kpi-value) {
    font-size: clamp(18px, 9.5cqw, 26px) !important; line-height: 1.2 !important; white-space: nowrap !important;
  }
  :is(.wf-kpi-row, #page-inventory.jj-r01 #jj-inv-stats.jj-kpis, #page-payments .payment-summary-grid.wf-kpi-rail) :is(.jj-stat-ic, .wf-kpi-ic) {
    width: clamp(30px, 15cqw, 40px) !important; height: clamp(30px, 15cqw, 40px) !important; min-width: 0 !important; flex: none !important;
  }
  :is(.wf-kpi-row, #page-inventory.jj-r01 #jj-inv-stats.jj-kpis, #page-payments .payment-summary-grid.wf-kpi-rail) :is(.jj-stat-ic, .wf-kpi-ic) svg { width: 45%; height: 45%; }
  /* narrow card: icon on its own line above the label, the text gets the full width */
  @container wf-kpi (max-width: 159px) {
    :is(.jj-stat-ic, .wf-kpi-ic) { grid-column: 1 / -1; align-self: start; width: 30px !important; height: 30px !important; margin-bottom: 6px; }
    :is(.jj-stat-body, .wf-kpi-body) { grid-column: 1 / -1; align-self: start; }
  }
  /* where a label may wrap, every label holds two lines, bottom-aligned, so the figures line up across the row */
  @container wf-kpi (max-width: 199px) {
    :is(.jj-stat-k, .pay-kpi-label, .wf-kpi-label) { display: flex !important; flex-wrap: wrap; align-items: flex-end; align-content: flex-end; min-height: 2.6em; }
  }
}

.inv-stage-inline { display: none; }

/* ═══ Inventory table ═════════════════════════════════════════════════════
   COLUMNS BY AVAILABLE WIDTH (Hal 2026-10-18: "show what fits, never cramped").
   The measure is the list CARD's width (container wf-cq), never the window's, so the
   sidebar, a split pane or a modal all just work. Priority, narrowest first:
   Hal's order: Watch · Cost · Paid · Retail · Wholesale · Sold · Status · Stage. As the card widens:
     base      Watch · Cost / Paid (one stacked cell) · Sold · Status · Stage
     ≥ 940     FIRST Cost / Paid splits into a Cost column and a Paid column (money columns get tighter)
     ≥ 1030    + Retail
     ≥ 1100    + Wholesale (the full set; a 1456 window's list card is about 1124)
     ≥ 1400    + SKU and Days
   Each rule HIDES a column below its width, so every other rule that hides a column (no cost
   permission, runner, Private view…) keeps winning on its own. The thresholds are guarded by
   tests/unit/inventory-list-columns.test.js (it reads this block).
   ═════════════════════════════════════════════════════════════════════════ */
@media (min-width: 769px) {
  /* The measuring fit-check script (index.html, wf-inv-fit) stands down while
     this is set: the tiers below own column widths and hiding. */
  #page-inventory #inv-list-card table { --wf-cq-table: 1; }
  html body #page-inventory.jj-r01 #inv-list-card table { width: 100%; table-layout: auto; }
  html body #page-inventory.jj-r01 #inv-list-card table :is(th, td) { padding-left: var(--col-pad) !important; padding-right: var(--col-pad) !important; }
  html body #page-inventory.jj-r01 #inv-list-card table tbody td { padding-top: 14px !important; padding-bottom: 14px !important; vertical-align: middle !important; }
  html body #page-inventory.jj-r01 #inv-list-card th.inv-row-check { width: var(--col-check) !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="thumb"] { width: var(--col-thumb) !important; }
  html body #page-inventory.jj-r01 #inv-list-card th:nth-child(3) { width: auto !important; min-width: var(--col-watch-min); }
  html body #page-inventory.jj-r01 #inv-list-card tr[data-inv-id] > td:nth-child(3) { min-width: var(--col-watch-min) !important; white-space: normal; }
  /* money: right-aligned, header over its figures */
  html body #page-inventory.jj-r01 #inv-list-card th:is([data-col="costpaid"], [data-col="cost"], [data-col="paid"], [data-col="retail"], [data-col="wholesale"], [data-col="sold"]) { width: var(--col-money) !important; text-align: right !important; }
  html body #page-inventory.jj-r01 #inv-list-card td:is([data-col="costpaid"], [data-col="cost"], [data-col="paid"], [data-col="retail"], [data-col="wholesale"], [data-col="sold"]) { text-align: right !important; font-size: 14px !important; white-space: nowrap; }
  html body #page-inventory.jj-r01 #inv-list-card th:is([data-col="costpaid"], [data-col="sold"]) { width: var(--col-stack) !important; }
  /* badges: centred under a centred header */
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="status"] { width: var(--col-status) !important; text-align: center !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="stage"] { width: var(--col-stage) !important; text-align: center !important; }
  html body #page-inventory.jj-r01 #inv-list-card td:is([data-col="status"], [data-col="stage"]) { text-align: center !important; white-space: nowrap; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="stock-id"] { width: var(--col-id) !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="days-in-stock"] { width: var(--col-days) !important; text-align: center !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="days-in-stock"] { text-align: center !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="row-actions"] { width: var(--col-act) !important; }
  html.wf-private-view body #page-inventory.jj-r01 #inv-list-card [data-col="details"] { width: var(--col-details) !important; min-width: 0 !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="stock-id"] .stock-id { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* With money hidden, give the two remaining scan columns a fair share of the row.
     The watch name still grows; status/stage never collapse into the right gutter. */
  html body #page-inventory.jj-r01.wf-no-cost.wf-no-retail.wf-no-wholesale #inv-list-card th[data-col="status"] { width: 18% !important; min-width: 132px; }
  html body #page-inventory.jj-r01.wf-no-cost.wf-no-retail.wf-no-wholesale #inv-list-card th[data-col="stage"] { width: 20% !important; min-width: 144px; }
  html body #page-inventory.jj-r01 #inv-list-card td:is([data-col="status"], [data-col="stage"]) { overflow: visible; }
  /* Stage pill: ONE line, never split mid-word (Hal 10-26: "Me / mo / In"). Its width is capped by the column
     (a px cap, because an auto-layout table would otherwise grow the column to fit); a longer custom stage
     ends in "…" and the full name is the pill's title. */
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="stage"] .inv-stage-pill {
    display: inline-block; height: 26px; line-height: 26px; padding: 0 10px; vertical-align: middle;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; word-break: normal;
    max-width: calc(var(--col-stage) - 2 * var(--col-pad));
  }
  html body #page-inventory.jj-r01.wf-no-cost.wf-no-retail.wf-no-wholesale #inv-list-card td[data-col="stage"] .inv-stage-pill { max-width: 124px; }
  /* Sold: the "to / from <name>" line never widens the column; it wraps between words to a second line
     (never mid-word), and only a name longer than two lines ends in "…" (full text in its title) */
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="sold"] .inv-sold-to {
    contain: inline-size; white-space: normal; overflow-wrap: normal; word-break: normal;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="sold"] { width: calc(var(--col-stack) + 16px) !important; }
  html body #page-inventory.jj-r01 #inv-list-card tr > :last-child { padding-right: max(20px, var(--col-pad)) !important; }

  /* Watch cell: name ≤ 2 lines, ref/specs (+ dial) ONE line; the title keeps the full text */
  html body #page-inventory.jj-r01 #inv-list-card tr[data-inv-id] > td:nth-child(3) > div:first-child {
    display: -webkit-box !important; -webkit-box-orient: vertical !important; -webkit-line-clamp: 2 !important; line-clamp: 2; overflow: hidden !important; overflow-wrap: anywhere; line-height: 1.3; white-space: normal !important;
  }
  html body #page-inventory.jj-r01 #inv-list-card tr[data-inv-id] > td:nth-child(3) > .text-muted {
    white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; line-height: 1.35;
    contain: inline-size; /* its one long line never widens the column */
  }
  html body #page-inventory.jj-r01 #inv-list-card tr[data-inv-id] > td:nth-child(3) > .text-muted > .jj-dial { display: none; font-size: inherit; margin: 0; color: inherit; }
  html body #page-inventory.jj-r01.jj-filtered #inv-list-card tr[data-inv-id] > td:nth-child(3) > .text-muted > .jj-dial { display: inline; }
  html body #page-inventory.jj-r01.jj-filtered #inv-list-card tr[data-inv-id] > td:nth-child(3) > .text-muted > .jj-dial::before { content: " · "; }

  /* Cost / Paid and Sold: a figure over a muted line, both right-aligned, one line each */
  #page-inventory #inv-list-card .inv-cp-main { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--white); }
  #page-inventory #inv-list-card .inv-cp-sub { font-size: 12px; line-height: 1.3; margin-top: 2px; color: var(--muted); font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  #page-inventory #inv-list-card .inv-cp-sub.is-owes { color: var(--amber); font-weight: 500; }
  #page-inventory #inv-list-card td[data-col="sold"] .inv-sold-to { font-size: 12px; line-height: 1.3; margin-top: 2px; color: var(--muted); font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #page-inventory #inv-list-card .inv-sold-to-k { margin-right: 4px; }
  #page-inventory #inv-list-card .inv-sold-to-name[role="link"]:hover { color: var(--white); text-decoration: underline; cursor: pointer; }

  /* Status: the canonical status tile only, centred, one line */
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .row-status-picker.wf-ctile { display: inline-flex !important; width: auto !important; max-width: 100% !important; vertical-align: middle; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .wf-ctile-sub { display: none !important; }
  /* Stage: a quiet pill in the stage's own colour (nothing in it = a muted dash) */
  #page-inventory #inv-list-card .inv-stage-pill {
    --stg: var(--muted); display: inline-flex; align-items: center; height: 26px; padding: 0 11px; border-radius: 999px; max-width: 100%;
    font-size: 12.5px; font-weight: 500; line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    color: var(--stg); background: color-mix(in srgb, var(--stg) 13%, transparent);
  }
  #page-inventory #inv-list-card td[data-col="stage"] .inv-ship-code { margin-left: 6px; }

  /* Search match: one small muted chip in the Watch cell, same row (no strip under the row) */
  #page-inventory .inv-mchip {
    display: block; max-width: 100%; margin-top: 4px; padding: 1px 7px; border-radius: 5px; width: fit-content;
    font-size: 10.5px; line-height: 1.5; color: var(--muted); background: rgba(201, 169, 110, 0.14);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #page-inventory .inv-mchip b { font-weight: 600; color: var(--off-white); }
  #page-inventory .inv-mchip mark { background: rgba(201, 169, 110, 0.35); color: inherit; border-radius: 2px; padding: 0 1px; }
  #page-inventory .inv-mchip-k { opacity: 0.8; }
  #page-inventory .inv-mchip-more { opacity: 0.8; }
}

/* ── columns by width (hide below the tier's width) ── */
@container wf-cq (max-width: 1399px) {
  #page-inventory.jj-r01 table [data-col="stock-id"] { display: none !important; }
  /* the Accessories list scans by Type (that column's header), so it stays at every width */
  #page-inventory.jj-r01:not(:has(#inv-kind-switch .inv-kind-tab.active[data-kind="accessory"])) table [data-col="days-in-stock"] { display: none !important; }
  #page-inventory .inv-mchip[data-mcol~="sku"] { display: block; }
}
@container wf-cq (min-width: 1400px) { #page-inventory .inv-mchip[data-mcol~="sku"] { display: none; } }
@container wf-cq (max-width: 939px) {
  #page-inventory.jj-r01 table :is([data-col="cost"], [data-col="paid"]) { display: none !important; }
}
/* full set on a tight card (1100-1299: a 1440 window's card is ~1106). Every column must fit WITHOUT the table
   growing past the card (it used to: 1141 in 1106, the row "⋯" was cut off and Stage got 63px):
   a smaller photo, the status tile drops its chevron (as below 900), the row-action cell loses its extra gutter. */
@container wf-cq (min-width: 1100px) and (max-width: 1299px) {
  #page-inventory #inv-list-card > * { --col-thumb: calc(52px + 2 * var(--col-pad)); --col-watch-min: 190px; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="thumb"] .watch-thumb-sm { width: 52px !important; height: 52px !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .wf-ctile-chev { display: none !important; }
  html body #page-inventory.jj-r01 #inv-list-card tr > :last-child { padding-right: 12px !important; }
}
/* split tier: Cost and Paid are their own columns; the stacked cell goes (not while an entity filter hides Paid) */
@container wf-cq (min-width: 940px) {
  /* short figures: tighter money columns, the Watch column takes the rest */
  #page-inventory #inv-list-card > * { --col-money: 90px; --col-pad: 10px; --col-stack: 112px; --col-status: 118px; --col-stage: 108px; --col-watch-min: 200px; }
  #page-inventory.jj-r01:not(.jj-filtered) table [data-col="costpaid"] { display: none !important; }
}
#page-inventory.jj-r01.jj-filtered table [data-col="cost"] { display: none !important; }
@container wf-cq (max-width: 1099px) {
  #page-inventory.jj-r01 table [data-col="wholesale"] { display: none !important; }
}
@container wf-cq (min-width: 1100px) { #page-inventory .inv-mchip[data-mcol~="wholesale"] { display: none; } }
@container wf-cq (max-width: 1029px) {
  #page-inventory.jj-r01 table [data-col="retail"] { display: none !important; }
}
@container wf-cq (min-width: 1030px) { #page-inventory .inv-mchip[data-mcol~="retail"] { display: none; } }
/* tight (< 900): smaller photo column and padding so the five core columns still fit without a sideways scroll */
@container wf-cq (max-width: 899px) {
  html body #page-inventory.jj-r01 #inv-list-card table :is(th, td) { padding-left: 8px !important; padding-right: 8px !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="thumb"] { width: 64px !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="thumb"] .watch-thumb-sm { width: 46px; height: 46px; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .wf-ctile-chev { display: none !important; }
}
/* tablet (<760: a 984 window with the sidebar open = a ~678px card). The table does NOT slide sideways (Hal 10-26):
   Stage rides under the status tile in the same cell (header "Status / Stage"), the photo is 44px, the name keeps
   150px, Sold is one stacked width, the row-action cell loses its extra gutter. */
@container wf-cq (max-width: 759px) {
  #page-inventory.jj-r01 table [data-col="stage"] { display: none !important; }
  #page-inventory #inv-list-card > * { --col-watch-min: 150px; --col-status: 120px; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="thumb"] { width: 60px !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="thumb"] .watch-thumb-sm { width: 44px !important; height: 44px !important; }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="sold"] { width: var(--col-stack) !important; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .inv-stage-inline { display: block; margin-top: 6px; line-height: 0; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="status"] .inv-stage-inline .inv-stage-pill {
    display: inline-block; height: 24px; line-height: 24px; padding: 0 10px; font-size: 12px; vertical-align: middle;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(var(--col-status) - 2 * var(--col-pad));
  }
  html body #page-inventory.jj-r01 #inv-list-card th[data-col="status"]::after { content: " / Stage"; }
  html body #page-inventory.jj-r01 #inv-list-card tr > :last-child { padding-right: 8px !important; }
}
/* scroll (<600): last resort — the photo + name stay put, the rest slides */
@container wf-cq (max-width: 599px) {
  #page-inventory.jj-r01 #inv-list-card .table-wrap { overflow-x: auto; }
  html body #page-inventory.jj-r01 #inv-list-card td[data-col="sold"] .inv-sold-to { min-width: 96px; }
  #page-inventory.jj-r01 #inv-list-card table :is(th, td):is(.inv-row-check, [data-col="thumb"], :nth-child(3)) { position: sticky; z-index: 1; background-color: var(--jj-card); }
  #page-inventory.jj-r01 #inv-list-card table :is(th, td).inv-row-check { left: 0; }
  #page-inventory.jj-r01 #inv-list-card table :is(th, td)[data-col="thumb"] { left: var(--col-check); }
  #page-inventory.jj-r01 #inv-list-card table :is(th, td):nth-child(3) { left: calc(var(--col-check) + var(--col-thumb)); box-shadow: 1px 0 0 var(--jj-line); }
  #page-inventory.wf-runner-locked.jj-r01 #inv-list-card table :is(th, td)[data-col="thumb"] { left: 0; }
  #page-inventory.wf-runner-locked.jj-r01 #inv-list-card table :is(th, td):nth-child(3) { left: var(--col-thumb); }
  #page-inventory.jj-r01 #inventory-tbody tr:has(.jj-row-tint) > td:is(.inv-row-check, [data-col="thumb"], :nth-child(3)) {
    background: linear-gradient(var(--red-dim), var(--red-dim)), var(--jj-card);
  }
}

/* ═══ Payment Tracker rows (Receivables / Payables / Loans / Returns) ═════
   ONE column per field, spread across the whole card (Hal 2026-10-18). Desktop rows are flex rows, not grids:
   every cell has a basis and a grow factor, a hidden cell simply leaves, and the money columns share the free width
   instead of bunching in the middle. Header cells carry the same classes as the cells (pt-h-* / pt-c-*), so a column
   lines up in the header and in every row.

     Contact · Deal/Invoice · Owed · Paid · Remaining · [Sold] · Due · Status · Stage/Type · actions

   Status and Stage/Type are ALWAYS their own centred columns, never stacked (Hal's rule). Priority, highest first:
   Contact · Deal · Owed · Remaining · Status · Stage · Paid · Due · Sold. What leaves, from the end, by the CARD's width:
     ≥1500      every column
     1100–1499  no Sold                                   (a 1456 window)
     960–1099   Due folds under Remaining as a muted line (Paid stays)
     740–959    compact: 8px gaps, 80px money columns, Contact/Deal truncate (full text in the tooltip)
     <740       Paid goes too                             (a 1100 window with the sidebar open is a ~770 card: Paid still fits)
   Below ~1000px of window (a card of ~660) the page switches to the phone card row instead. */
/* Stage / Type: its own centred badge */
html body #page-payments.wfil-pg .pt-c-stage .pt-stage { display: inline-flex; align-items: center; max-width: 100%; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; line-height: 1.35; white-space: nowrap; letter-spacing: 0; text-transform: none; background: color-mix(in srgb, var(--wfil-grey) 12%, var(--wfil-surface)); color: color-mix(in srgb, var(--wfil-grey) 55%, var(--wfil-ink)); border: 1px solid color-mix(in srgb, var(--wfil-grey) 24%, var(--wfil-line)); }
html body #page-payments.wfil-pg .pt-stage.pt-stage-amber { background: color-mix(in srgb, var(--wfil-amber) 12%, var(--wfil-surface)); color: color-mix(in srgb, var(--wfil-amber) 75%, var(--wfil-ink)); border-color: color-mix(in srgb, var(--wfil-amber) 28%, var(--wfil-line)); }
html body #page-payments.wfil-pg .pt-stage.pt-stage-gold { background: color-mix(in srgb, var(--gold) 14%, var(--wfil-surface)); color: color-mix(in srgb, var(--gold) 75%, var(--wfil-ink)); border-color: color-mix(in srgb, var(--gold) 30%, var(--wfil-line)); }
/* the small Stage copy exists for the PHONE card only (the table never stacks it); the folded due date shows only where Due folds */
html body #page-payments.wfil-pg .pt-stage-sm { display: none; }
html body #page-payments.wfil-pg .pt-rem-due { display: none; }
html body #page-payments.wfil-pg .pt-h-short { display: none; }
@media (min-width: 1001px) {
  html body #page-payments.wfil-pg .payments-table-card > *, html body #page-payments.wfil-pg .loans-sec > * { --col-act: 108px; --col-act-wide: 176px; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):is(.wfil-row, .wfil-thead):not(.pt-recent) {
    display: flex !important; flex-wrap: nowrap; align-items: center; grid-template-columns: none !important;
    column-gap: clamp(8px, 1cqw, 16px) !important; padding-left: 24px !important; padding-right: 14px !important;
  }
  /* the basis + grow of each column; min-width keeps a figure whole, Contact and Deal give way first */
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-contact, .pt-h-contact) { flex: 4 1 150px; min-width: 90px; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-deal, .pt-h-deal) { flex: 3 1 120px; min-width: 80px; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-owed, .pt-h-owed, .pt-c-paid, .pt-h-paid, .pt-c-rem, .pt-h-rem) { flex: 1 0 96px; min-width: 96px; text-align: right; justify-self: auto; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-owed, .pt-h-owed) { min-width: 104px; flex-basis: 104px; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-sold, .pt-h-sold, .pt-c-due, .pt-h-due) { flex: 0 0 88px; min-width: 88px; text-align: center; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-due, .pt-h-due) { margin-left: 8px; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > .pt-c-sold { white-space: nowrap; }
  html body #page-payments.wfil-pg .pt-ret:not(.pt-recent) > :is(.pt-c-sold, .pt-h-sold) { flex: 0 0 104px; min-width: 104px; text-align: center; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-status, .pt-h-status) { flex: 1 0 128px; min-width: 128px; justify-content: center; justify-self: auto; text-align: center; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-stage, .pt-h-stage) { flex: .9 0 116px; min-width: 116px; display: flex; align-items: center; justify-content: center; text-align: center; }
  html body #page-payments.wfil-pg .pt-ret:not(.pt-recent) > :is(.pt-c-memo, .pt-h-memo) { flex: 1 1 130px; min-width: 0; }
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-act, .pt-h-act) { flex: 0 0 var(--col-act); min-width: 0; justify-content: flex-end; }
  html body #page-payments.wfil-pg :is(.pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-act, .pt-h-act) { flex-basis: var(--col-act-wide); }
  /* the header's alignment follows its column */
  html body #page-payments.wfil-pg .pt-thead > :is(.pt-h-status, .pt-h-stage) { text-align: center; }
  html body #page-payments.wfil-pg .pt-thead > :is(.pt-h-owed, .pt-h-paid, .pt-h-rem) { text-align: right; }
  html body #page-payments.wfil-pg .pt-thead > .wfil-h { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  html body #page-payments.wfil-pg .pt-row .pt-c-contact .pt-contact { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: unset; }
  /* a long contact name takes a 2nd line (the deal cell is 2-3 lines tall anyway) instead of being cut to "Fix1 Export Hous…" */
  html body #page-payments.wfil-pg .pt-row .pt-c-contact .pt-contact { display: -webkit-box; white-space: normal; overflow-wrap: anywhere; -webkit-box-orient: vertical; -webkit-line-clamp: 2; text-align: left; }
  html body #page-payments.wfil-pg .pt-overdue-note { color: var(--wfil-red); }
  /* the small notes under an amount stay on ONE line so rows stay the same height; the full text is the tooltip */
  html body #page-payments.wfil-pg .pt-row > .wfil-c-amt .pt-note { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* a long name or number is cut with an ellipsis (the cell carries the full text as its tooltip) rather than wrapping the row taller */
  html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-name .ph-link, html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-name .pt-deal { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: top; }
  html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-name { flex-wrap: nowrap; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
  /* F6 (jj-sync-1026 verify): the invoice / deal NUMBER is never cut ("Invoice WF-10…" at 1280/1440). The Deal column
     is wide enough for "Invoice WF-1028"; if a long word still runs short, the word gives way first, the number stays whole. */
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-deal, .pt-h-deal) { min-width: 116px; }
  /* ...and the Due column (a short date or "—") gives back the room, so a two-word contact name keeps its second word */
  html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-due, .pt-h-due) { flex-basis: 72px; min-width: 72px; }
  html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-name .pt-deal:has(> .pt-num) { display: inline-flex; align-items: baseline; text-overflow: clip; }
  html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-deal > .pt-pre { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: pre; }
  html body #page-payments.wfil-pg .pt-row > .pt-c-deal .pt-deal > .pt-num { flex: none; }
}
@container wf-cq (max-width: 1499px) {
  @media (min-width: 1001px) {
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-sold, .pt-h-sold) { display: none !important; }
  }
}
@container wf-cq (max-width: 1099px) {
  @media (min-width: 1001px) {
    html body #page-payments.wfil-pg .pt-ret:not(.pt-recent) > :is(.pt-c-sold, .pt-h-sold) { display: none !important; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-due, .pt-h-due) { display: none !important; }
    html body #page-payments.wfil-pg .pt-rem-due { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 400; color: var(--wfil-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    html body #page-payments.wfil-pg .pt-rem-due.is-over { color: var(--wfil-red); font-weight: 600; }
  }
}
@container wf-cq (max-width: 959px) {
  @media (min-width: 1001px) {
    html body #page-payments.wfil-pg .payments-table-card > *, html body #page-payments.wfil-pg .loans-sec > * { --col-act: 92px; --col-act-wide: 52px; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):is(.wfil-row, .wfil-thead):not(.pt-recent) { column-gap: 8px !important; padding-left: 16px !important; padding-right: 8px !important; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-contact, .pt-h-contact) { min-width: 94px; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-deal, .pt-h-deal) { min-width: 64px; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-owed, .pt-h-owed, .pt-c-paid, .pt-h-paid, .pt-c-rem, .pt-h-rem) { flex: 1 0 76px; min-width: 76px; }
    html body #page-payments.wfil-pg .pt-row .wfil-c-amt { font-size: 13.5px; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-status, .pt-h-status) { flex-basis: 108px; min-width: 106px; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-stage, .pt-h-stage) { flex-basis: 96px; min-width: 94px; }
    html body #page-payments.wfil-pg .pt-row .pt-c-status .invoice-status-badge { font-size: 12px; padding: 3px 8px; }
    html body #page-payments.wfil-pg .pt-c-stage .pt-stage { font-size: 11.5px; padding: 3px 7px; }
    html body #page-payments.wfil-pg .pt-row .pt-pay { padding: 0 8px; }
    /* compact: the Deal cell keeps the NUMBER ("WF-1647", "#3054", "#84"), not the word before it; the word is in the tooltip and the Type column */
    html body #page-payments.wfil-pg .pt-c-deal .pt-pre { display: none; }
    html body #page-payments.wfil-pg .pt-h-deal .pt-h-long { display: none; }
    html body #page-payments.wfil-pg .pt-h-deal .pt-h-short { display: inline; }
    html body #page-payments.wfil-pg :is(.pt-loan, .pt-ret) .pt-c-act .pt-pay { display: none !important; }
  }
}
/* 800-959px card (~1130-1290px window): room for an ordinary two-word name on one line before it truncates */
@container wf-cq (min-width: 800px) and (max-width: 959px) {
  @media (min-width: 1001px) {
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-contact, .pt-h-contact) { min-width: 132px; }
  }
}
@container wf-cq (max-width: 739px) {
  @media (min-width: 1001px) {
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan):not(.pt-recent) > :is(.pt-c-paid, .pt-h-paid) { display: none !important; }
    html body #page-payments.wfil-pg :is(.pt-rec, .pt-ap, .pt-loan, .pt-ret):not(.pt-recent) > :is(.pt-c-contact, .pt-h-contact) { min-width: 104px; }
  }
}

/* ═══ Payment Tracker vertical rhythm (Hal 2026-10-18) ═══════════════════════
   ONE gap (--pt-gap, 20px) between the KPI row, the status pills, the search / Sort / Views / Filters row and the list,
   on every tab. The KPI row used to sit flush on whatever came next (its margin was pulled to -4px), so the cards touched
   the pills on Payables and the "owed" box on Receivables. The KPI grid keeps its 4px scroll padding, which is why the
   margin below it is gap - 4. */
html body #page-payments { --pt-gap: 20px; }
html body #page-payments .wf-kpi-railwrap > .payment-summary-grid.wf-kpi-rail.wf-kpi-thin,
html body #page-payments .payment-summary-grid.wf-kpi-thin { margin-bottom: calc(var(--pt-gap) - 4px) !important; }
html body #page-payments.wfil-pg :is(#pay-filter-card, #ap-filter-card, #returns-filter-card, #loans-filter-card) { margin-bottom: var(--pt-gap) !important; }
html body #page-payments.wfil-pg .pay-refunds-line { margin: 0 0 var(--pt-gap); }
html body #page-payments.wfil-pg .loans-dir-switch { margin: 0 0 var(--pt-gap); }
html body #page-payments.wfil-pg .loans-head { margin-bottom: var(--pt-gap); }
html body #page-payments.wfil-pg :is(.payments-table-card, .loans-sec) { margin-bottom: var(--pt-gap); }

/* Scrolled toolbars (2026-10-18): the eye/bell icons float at the top-right. When a search/Sort/Views/Filters row scrolls up
   to that height, the script at the end of index.html adds .wf-under-icons and the row keeps its right edge left of the icons
   (the search box absorbs the width), so Filters is never under them and nothing is covered. Desktop only. */
@media (min-width: 1025px) {
  .inv-toolbar { transition: padding-right .15s ease; }
  html body .inv-toolbar.wf-under-icons { padding-right: 44px !important; }
}

/* Inventory KPI sizing follows only the cards the seat can see. Flex layout
   has no empty grid tracks when financial/count cards are permission-hidden. */
html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis {
  display: flex !important; flex-flow: row nowrap; gap: 10px !important;
  width: 100%; box-sizing: border-box; align-items: stretch !important;
  overflow-x: auto; overflow-y: hidden;
}
html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis > .jj-stat {
  flex: 1 0 140px; width: auto !important; min-width: 0 !important; max-width: none !important;
  box-sizing: border-box;
}
@media (max-width: 768px) {
  html body #page-inventory.jj-r01 #jj-inv-stats.jj-kpis > .jj-stat {
    flex-basis: max(112px, calc((100% - 20px) / 3));
  }
}

/* A location change is a small action beside the watch, never a money/editor control. */
#page-inventory .inv-location-quick { display: block; max-width: 100%; margin-top: 6px; padding: 4px 0; border: 0; background: transparent; color: var(--blue, #2863a8); font: inherit; font-size: 12px; line-height: 1.4; text-align: left; white-space: normal; overflow-wrap: anywhere; cursor: pointer; }
#page-inventory .inv-location-quick:hover { text-decoration: underline; }
#page-inventory .inv-location-quick:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 3px; }
@media (max-width: 768px) { #page-inventory .inv-location-quick { min-height: 44px; } }

/* F15 (jj-sync-1026 verify): Contacts phone, the type chips are ONE sliding line (as the Inventory status bar), not a
   7-chip block wrapped into three rows. Every chip keeps its whole label (min-width: max-content, never shrinks). */
@media (max-width: 768px) {
  html body #page-contacts #contacts-type-bar.inv-status-bar {
    display: flex !important; flex-wrap: nowrap !important; grid-template-columns: none !important; justify-content: flex-start !important;
    overflow-x: auto !important; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  html body #page-contacts #contacts-type-bar.inv-status-bar::-webkit-scrollbar { display: none; }
  html body #page-contacts #contacts-type-bar.inv-status-bar > * { flex: 0 0 auto !important; min-width: max-content !important; }
}
/* Contacts KPI row = the shared thin card (F15). The page's old kpi-grid rules squeezed the figure's line box (21px for a
   20px figure) and kept a long label on one line past the card edge; the thin card's own sizes apply, and on a phone a
   two-word label breaks between words (wf-kpi-align.js keeps the figures level). */
html body #page-contacts #contacts-kpis.wf-kpi-thin .pay-kpi-value { line-height: 26px !important; overflow: visible !important; }
html body #page-contacts #contacts-kpis.wf-kpi-thin .wf-kpi-body { min-width: 0; }
@media (max-width: 639.98px) {
  html body #page-contacts #contacts-kpis.wf-kpi-thin .pay-kpi-value { line-height: 24px !important; }
  html body #page-contacts #contacts-kpis.wf-kpi-thin .pay-kpi-label { white-space: normal !important; overflow-wrap: normal; word-break: normal; line-height: 14px; }
}
