/* ══════════════════════════════════════════════════════════════════════════
   canon-office.css — phone rows + visual polish for the office pages.

   Two flags, two root classes, stamped by js/books/office-look.js:
     html.ph-rows   ← feature_phone_rows    (phone cards, ≤640px only)
     html.of-polish ← feature_office_polish (pills, button weight, gaps)
   EVERY rule in this file sits under one of them, so with both flags off
   nothing here matches and the pages draw exactly as they did.

   UNLAYERED ON PURPOSE. The tables these rules reshape carry Tailwind
   utilities in their markup (truncate, whitespace-nowrap, px-5 …), which live
   in the utilities layer and outrank anything in @layer components. A phone
   card has to override those, and unlayered declarations beat every layered
   one. The flag class + the media query are what keep that power contained.

   Kept OUT of canon-books.css: that file is a verbatim port of the books
   mockup, pixel-diffed by scripts/canon-diff.js.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Phone rows: the shared two-line card (feature_phone_rows) ─────────
   Opt a table in with class="ph-card" (inert while the flag is off) and tag
   its cells — the markup keeps its <tr>/<td>, so every handler, sort and
   delegated click still finds what it bound to:

     .ph-t    who / what (+ its .sub line)  line 1, left, takes the room
     .ph-m    the money                     line 1, right
     .ph-d    a detail: date, method, pill  line 2, inline, in source order
     .ph-act  the row's own action          line 2, pushed right
     .ph-x    not on a phone                hidden

   Line 2 only exists when the row has a .ph-d or .ph-act. A cell spanning the
   whole table (the empty / loading / error row) takes the full card width. */
@media (max-width: 640px) {
  :root.ph-rows table.ph-card { display: block; width: 100%; min-width: 0; }
  :root.ph-rows table.ph-card > thead { display: none; }
  :root.ph-rows table.ph-card > tbody,
  :root.ph-rows table.ph-card > tfoot { display: block; width: 100%; }
  :root.ph-rows table.ph-card > tbody > tr,
  :root.ph-rows table.ph-card > tfoot > tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
    padding: 12px 16px; border-bottom: 1px solid var(--c-border);
  }
  :root.ph-rows table.ph-card > tbody > tr:last-child { border-bottom: 0; }
  :root.ph-rows table.ph-card > tbody > tr > td,
  :root.ph-rows table.ph-card > tfoot > tr > td {
    display: block; width: auto; min-width: 0; max-width: none;
    padding: 0; border: 0; text-align: left; white-space: normal;
  }
  :root.ph-rows table.ph-card .ph-t { order: 1; flex: 1 1 0; min-width: 0; font-size: 14px; }
  :root.ph-rows table.ph-card .ph-t .sub { white-space: normal; }
  :root.ph-rows table.ph-card .ph-m {
    order: 2; flex: none; margin-left: auto; text-align: right; white-space: nowrap;
    font-variant-numeric: tabular-nums; font-weight: 600;
  }
  :root.ph-rows table.ph-card tr:has(> .ph-d, > .ph-act)::after { content: ""; order: 3; flex-basis: 100%; height: 0; }
  :root.ph-rows table.ph-card .ph-d {
    order: 4; flex: none; font-size: 12px; color: var(--c-cap); white-space: nowrap;
  }
  :root.ph-rows table.ph-card .ph-d:empty { display: none; }
  :root.ph-rows table.ph-card .ph-act { order: 5; flex: none; margin-left: auto; }
  :root.ph-rows table.ph-card .ph-x { display: none; }
  :root.ph-rows table.ph-card td[colspan]:not([class*="ph-"]) { flex: 1 1 100%; }
  :root.ph-rows table.ph-card > tfoot > tr { align-items: center; background: var(--c-sunken); border-bottom: 0; border-radius: 0 0 9px 9px; }
  :root.ph-rows table.ph-card > tfoot > tr > td { background: transparent; }
  /* A table that used to scroll sideways inside its card no longer needs to. */
  :root.ph-rows :has(> table.ph-card) { overflow-x: visible; }
}

/* ── 2. Visual polish: shared pieces (feature_office_polish) ──────────────
   .ol-quiet on a .btn.primary steps it down to the ordinary outline button:
   Refresh / Check-now style actions, and a page's own create button when the
   top bar already offers "New". One primary per view. */
:root.of-polish .btn.primary.ol-quiet {
  background: var(--c-card); border-color: var(--c-border); color: var(--c-text); font-weight: 500;
}
:root.of-polish .btn.primary.ol-quiet:hover { background: var(--c-card-2); border-color: var(--c-border-2); }
/* The standard sentence-case pill, for chips that were drawn as UPPERCASE
   letter-spaced tags. Add .ol-pill next to the page's own chip class. */
:root.of-polish .ol-pill {
  text-transform: none; letter-spacing: normal; font-size: 11px; font-weight: 500;
}

/* ══ Per-page blocks. One section per page; keep each page's rules in its own. */

/* ── Payments ─────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  :root.ph-rows #pfRows .ph-net::before { content: "net "; }
}
/* "Payouts on the way" stood the full height of the figure card with one line
   in it. On a wide screen the fees and payouts cards stack in the right-hand
   column instead, each as tall as what it holds. */
@media (min-width: 1280px) {
  :root.of-polish #pfFigure > :nth-child(1) { grid-row: span 2; }
  :root.of-polish #pfFigure > :nth-child(2),
  :root.of-polish #pfFigure > :nth-child(3) { grid-column: span 7 / span 7; }
}

/* ── Bills ────────────────────────────────────────────────────────────── */
/* Line 2 reads "due 8 Sept · Overdue · Pay Edit": the date first, so the pill
   (earlier in source) moves after it, still ahead of the pushed-right actions.
   The "issued" sub-line stays on the wide table. The part-paid one stays on the
   card, beside the pill: a late part-paid bill's pill says Overdue, not Part
   paid, and the total on the right is what the bill WAS, not what is owing. */
@media (max-width: 640px) {
  :root.ph-rows #blRows .bl-st { order: 5; }
  :root.ph-rows #blRows .bl-due::before { content: "due "; }
  :root.ph-rows #blRows .ph-d .sub:not(.bl-part) { display: none; }
  :root.ph-rows #blRows .bl-st .bl-part { display: inline; margin-left: 6px; }
}

/* ── Expenses ─────────────────────────────────────────────────────────── */
/* The foot's GST total is off the phone card, so its note goes with it. */
@media (max-width: 640px) {
  :root.ph-rows #expTable .exp-gst-note { display: none; }
}

/* ── Purchase orders ──────────────────────────────────────────────────── */
/* A bare "15 Sept" beside the pill could be when it was raised. */
@media (max-width: 640px) {
  :root.ph-rows #poList .po-exp::before { content: "expected "; }
}

/* ── Suppliers ────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  :root.ph-rows #supRows .sup-last::before { content: "last bill "; }
}

/* ── Stripe ───────────────────────────────────────────────────────────── */
/* The activity rows and the lines inside a deposit share one row shape: what
   it was and what reached the bank on line one; the date, the invoice (its
   customer inline) and, when a fee made them differ, what the customer paid
   and the fee — labelled, since the column heads are gone. */
@media (max-width: 640px) {
  :root.ph-rows .sp-ph-inv .sub { display: inline; margin-left: 4px; }
  :root.ph-rows .sp-ph-inv .sub::before { content: "· "; }
  :root.ph-rows .sp-ph-gross::before { content: "paid "; }
  :root.ph-rows .sp-ph-fee::before { content: "fee "; }
}

/* ── Square ───────────────────────────────────────────────────────────── */
/* How it was paid and the amount on line one, Square's note under it, then
   the date and state. The actions take a line of their own at full tap
   height: attaching a payment is the whole job of this page. */
@media (max-width: 640px) {
  :root.ph-rows #sqRows .sq-ph-note { order: 3; flex: 1 1 100%; white-space: normal; }
  :root.ph-rows #sqRows .sq-ph-note .sq-note { max-width: none; white-space: normal; font-size: 13px; }
  :root.ph-rows #sqRows .ph-act {
    flex: 1 1 100%; display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; margin-top: 4px;
  }
  :root.ph-rows #sqRows .ph-act:empty { display: none; }
  :root.ph-rows #sqRows .ph-act .sq-btn + .sq-btn { margin-left: 0; }
  :root.ph-rows #sqRows .ph-act .sq-btn.sm { height: 34px; padding: 0 12px; font-size: 12px; }
}
/* The state pills were lowercase tags; the standard pill is sentence case. */
:root.of-polish .sq-pl::first-letter { text-transform: uppercase; }

/* ── Timesheets ───────────────────────────────────────────────────────── */
/* Entries: who and the hours on line one, the job under them, then the day,
   the time, the kind and Edit. */
@media (max-width: 640px) {
  :root.ph-rows #tsRows .ts-ph-job { order: 3; flex: 1 1 100%; white-space: normal; font-size: 13px; color: var(--c-text-2); }
  :root.ph-rows #tsRows .ph-m .ts-muted { margin-left: 4px; font-weight: 400; }
  :root.ph-rows #tsRows .ph-act .ts-btn.sm { height: 32px; padding: 0 12px; font-size: 12px; }
}
/* The week grid stopped at Wednesday on a phone (it scrolled, with nothing to
   say so). It now fits: a fixed layout, a narrow name column that truncates,
   the weekday and date number only (the week bar above names the month), and
   tighter figures. Chosen over a sideways scroll with a sticky name column
   because the grid's job is the whole week at a glance — Sunday and the Total
   column are exactly what a scroll would hide. At 390px each day gets ~30px:
   a 10+ hour day ("10.50") still fits at 11px. */
@media (max-width: 640px) {
  :root.ph-rows .ts-table { min-width: 0; table-layout: fixed; font-size: 12px; }
  :root.ph-rows .ts-table th,
  :root.ph-rows .ts-table td { padding: 8px 1px; }
  :root.ph-rows .ts-table th:first-child { width: 92px; padding-left: 12px; overflow: hidden; text-overflow: ellipsis; }
  :root.ph-rows .ts-table th:last-child,
  :root.ph-rows .ts-table td:last-child { width: 44px; padding-right: 10px; }
  :root.ph-rows .ts-table thead th { letter-spacing: 0; text-align: center; }
  :root.ph-rows .ts-table thead th:first-child { text-align: left; }
  :root.ph-rows .ts-table thead th:last-child { text-align: right; }
  :root.ph-rows .ts-table .ts-mo { display: none; }
  :root.ph-rows .ts-table .ts-cell,
  :root.ph-rows .ts-table .ts-tot { font-size: 11px; }
  :root.ph-rows .ts-table .ts-dot { margin-right: 5px; }
}

/* ── BAS ──────────────────────────────────────────────────────────────── */
/* The document lists: the party and the amount on line one; the date, the
   document and its GST under them, the GST pushed right beneath the amount.
   The figures lose their column heads on a phone, so each says what it is. */
@media (max-width: 640px) {
  :root.ph-rows #basRoot .bas-ph-gst { margin-left: auto; }
  :root.ph-rows #basRoot .bas-ph-gst::before { content: "GST "; }
  :root.ph-rows #basRoot .bas-ph-was::before { content: "was "; }
  :root.ph-rows #basRoot .bas-ph-gstwas::before { content: "GST was "; }
  :root.ph-rows #basRoot .bas-ph-gstnow::before { content: "GST now "; }
}

/* ── Tax ──────────────────────────────────────────────────────────────── */
/* The provenance chips were UPPERCASE letter-spaced tags. They become the
   standard pill — sentence case, 11px, the 6px dot — and keep their three
   colours, which are the page's rule (measured / declared / partial never look
   alike). Inline-block rather than flex so ::first-letter can capitalise the
   lowercase word the controller writes (the page check reads that word), and
   the dot is a background so it does not become the first letter. */
:root.of-polish .tx-prov,
:root.of-polish .dw-prov {
  display: inline-block; padding: 3px 9px 3px 19px;
  font-size: 11px; font-weight: 500; letter-spacing: normal; text-transform: none; line-height: 1.5;
  background-image: radial-gradient(circle at 10px 50%, currentColor 0 3px, transparent 3.5px);
  background-repeat: no-repeat;
}
:root.of-polish .tx-prov::first-letter,
:root.of-polish .dw-prov::first-letter { text-transform: uppercase; }
/* "Put away" stood beside the reserve's arithmetic with ~300px of nothing
   under it. On a wide screen the three buckets move up into that column: the
   top row's wrapper lets its two cards join the page grid, the reserve spans
   both rows, and everything else keeps the full width. Only while the reserve
   is shown — without it the number already takes the whole row. Halves, from
   1400px: the buckets table needs ~660px before it scrolls sideways. */
@media (min-width: 1400px) {
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 16px; align-items: start;
  }
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) > * { grid-column: 1 / -1; }
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) > .tx-top { display: contents; }
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) #txHero { grid-column: 1; }
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) #txReserveCard { grid-column: 2; grid-row: span 2; }
  :root.of-polish #txCanonRoot:has(> .tx-top > #txReserveCard:not(.tx-hidden)) > #txBucketsCard { grid-column: 1; }
}

/* ── Drawings ─────────────────────────────────────────────────────────── */
/* The chips share Tax's pill rule above. The arithmetic card held a 620px sum
   and a 300px side column pushed to opposite edges, with a wide empty middle.
   On a wide screen the two columns share the card, split by an inset rule. */
@media (min-width: 900px) {
  :root.of-polish .dw-hero-grid { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 0; align-items: stretch; }
  :root.of-polish .dw-sum { max-width: none; padding-right: 32px; }
  :root.of-polish .dw-side { min-width: 0; padding-left: 32px; border-left: 1px solid var(--c-border); }
  :root.of-polish .dw-hero-grid:has(> .dw-side:empty) { grid-template-columns: minmax(0, 1fr); }
  :root.of-polish .dw-side:empty { display: none; }
}

/* ── Charts ───────────────────────────────────────────────────────────── */
/* On a phone the five dropdowns came first and the chart sat a screen below
   them. The chart leads; the builder follows it. */
@media (max-width: 640px) {
  :root.ph-rows #chApp > .ch-view { order: -1; }
}

/* ── Mileage ──────────────────────────────────────────────────────────── */
/* A trip row on a phone squeezed the time, the trip's name, the evidence chip,
   Business / Private and the kilometres onto one line: names shrank to "H",
   and the chips overlapped. Now two lines — the time, the name (allowed to
   wrap) and the kilometres; then the evidence chip under the name and the
   classification under the kilometres. The anchor spans both lines and shares
   the row's tracks (subgrid), so its chip lines up with the classification. */
@media (max-width: 640px) {
  :root.ph-rows .ml-rowline {
    grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto;
    column-gap: 10px; row-gap: 6px; align-items: center; padding: 11px 0;
  }
  :root.ph-rows .ml-rowline .ml-row {
    grid-column: 1; grid-row: 1 / span 2; grid-template-rows: subgrid;
    grid-template-columns: 52px minmax(0, 1fr); column-gap: 8px; padding: 0;
  }
  :root.ph-rows .ml-rowline .ml-row > .ml-when { grid-column: 1; grid-row: 1; }
  :root.ph-rows .ml-rowline .ml-row > .ml-leg { grid-column: 2; grid-row: 1; white-space: normal; overflow-wrap: anywhere; }
  :root.ph-rows .ml-rowline .ml-row > .ml-chip { grid-column: 2; grid-row: 2; justify-self: start; }
  :root.ph-rows .ml-rowline > .ml-km { grid-column: 2; grid-row: 1; }
  :root.ph-rows .ml-rowline > .ml-cls { grid-column: 2; grid-row: 2; justify-self: end; }
  /* The odometer and drive-home rows: the note takes the width, its buttons
     the line under it (it stood five lines tall beside them). */
  :root.ph-rows .ml-odo { flex-wrap: wrap; row-gap: 8px; }
  :root.ph-rows .ml-odo > .ml-row-main { flex: 1 1 100%; }
}
/* A trip with no route drew a 220–316px empty map panel around one sentence;
   a logbook day with nothing to picture repeated a boxed note under every day.
   Both become one quiet line. */
:root.ph-rows .ml-tp-map:has(> .ml-tp-nomap) { height: auto; }
:root.ph-rows .ml-tp-map > .ml-tp-nomap { display: block; height: auto; padding: 12px 20px; text-align: left; font-size: 13px; }
:root.ph-rows .ml-day-pic:has(> .ml-nopic) { border: 0; border-radius: 0; background: none; }
:root.ph-rows .ml-day-pic > .ml-nopic { padding: 0; text-align: left; font-size: 12px; }
@media (max-width: 640px) {
  :root.ph-rows .ml-nopic > .ml-nopic-l { display: none; }
  :root.ph-rows .ml-nopic > .ml-nopic-s { display: inline; }
}
/* Every chip carries the pill's dot, as .pill does on the other pages — the
   evidence chips (Route, Approx, Driversnote) as well as Business / Private. */
:root.of-polish .ml-chip { padding-left: 7px; }
:root.of-polish .ml-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

/* ── Stock ────────────────────────────────────────────────────────────── */
/* Low / Out / Default and the movement kinds take the standard pill: its
   padding and the 6px dot. On order keeps its truck icon in the dot's place. */
:root.of-polish .stk-pill,
:root.of-polish .stk-tag { gap: 6px; padding: 3px 9px 3px 7px; line-height: 1.5; }
:root.of-polish .stk-pill:not(:has(> i))::before,
:root.of-polish .stk-tag::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

/* ── Catalog ──────────────────────────────────────────────────────────── */
/* COST / RRP / SELL / MARGIN headed the money columns at the 13px Inter of the
   figures below them (.catv2-n), bigger than ITEM and SUPPLIER beside them.
   A header cell takes the header's own type. */
:root.of-polish .catv2-head .catv2-n { font-family: inherit; font-size: inherit; }

/* ── Overview ─────────────────────────────────────────────────────────── */
/* "Got it" on the board's first-run hint was a second solid button beside
   "New" in the top bar; it is a dismissal, and takes the outline weight. */
:root.of-polish #booksWidgetHost .wgt-intro .btn-primary {
  background: var(--c-card); border-color: var(--c-border); color: var(--c-text); font-weight: 500;
}
:root.of-polish #booksWidgetHost .wgt-intro .btn-primary:hover { background: var(--c-card-2); border-color: var(--c-border-2); }
/* "Customize" stood alone on a row of its own under the page head. Where the
   head is one row (lg+) and the button exists (a fine pointer — widget-host
   hides it on touch), the toolbar rides up into that row, right of the head's
   own buttons, which step left to make room. The toolbar spans the page, so it
   lets clicks through to the head beneath it. While customising, the toolbar
   holds Add / Reset / Done and goes back to its own row. */
@media (min-width: 1024px) and (pointer: fine) {
  :root.of-polish #ovCanonRoot:has(#booksWidgetHost:not(.wgt-editing) #wgtEditBtn) #ovHeadActions { margin-right: 116px; }
  :root.of-polish #booksWidgetHost:not(.wgt-editing) > .wgt-toolbar {
    position: relative; z-index: 1; margin: -58px 0 24px; pointer-events: none;
  }
  :root.of-polish #booksWidgetHost:not(.wgt-editing) > .wgt-toolbar > * { pointer-events: auto; }
  :root.of-polish #booksWidgetHost:not(.wgt-editing) #wgtEditBtn { width: 108px; height: 34px; justify-content: center; }
}
/* Needs attention filled its tile (360px) whatever it held: three rows left a
   120px empty tail. The card is as tall as its rows; the tile's leftover sits
   under it, which on the default board is the foot of the page. */
:root.of-polish #booksWidgetHost .wgt-body > .card.ov-att { height: auto; max-height: 100%; }

/* ── Bills / Purchases wide table (unconditional) ─────────────────────────────
 * The table sized itself to its longest line: a bill description is a .sub,
 * which is white-space:nowrap, so "Level Spirit, Right Angle Adaptor, …" grew
 * the Supplier column until Pay / Edit / Open fell off the card. Fixed layout
 * keeps every column at its header width and gives Supplier what is left; the
 * description ellipsises (its full text is the row's title). Below 641px the
 * table keeps its old auto layout and scrolls — or becomes cards under
 * feature_phone_rows, whose min-width:0 is untouched by this block. */
@media (min-width: 641px) {
  #blTable { table-layout: fixed; min-width: 1000px; }
  #blTable > thead > tr > th:last-child { width: 160px; }
  #blTable > thead > tr > th.bl-ck { width: 2.5rem; }
  #blTable .ph-t .sub { overflow: hidden; text-overflow: ellipsis; }
}

/* ── Bills: several from one supplier (unconditional) ─────────────────────────
 * A tick on every bill, one supplier at a time; the bar above the table pays
 * them in one go or sends one remittance advice. On a phone card the tick has
 * no ph-* slot, so it sits first on line one, beside the supplier. */
#blTable .bl-ck { padding-right: var(--sp-0); }
#blTable .bl-ck input { width: 1rem; height: 1rem; margin: var(--sp-0); accent-color: var(--c-accent); cursor: pointer; vertical-align: middle; }
#blTable .bl-ck input:disabled { cursor: not-allowed; opacity: .3; }
#blTable tr.bl-picked > td { background: var(--c-accent-soft); }
.bl-selbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3);
  margin: var(--sp-0) var(--sp-5) var(--sp-4); padding: var(--sp-2_5) var(--sp-3_5);
  border: 1px solid var(--c-accent-edge, var(--c-accent)); border-radius: 9px;
  background: var(--c-card-2); position: sticky; top: var(--sp-2); z-index: 3;
}
.bl-selbar[hidden] { display: none; }
.bl-selbar .bl-sel-what { font-size: 13px; }
.bl-selbar .bl-sel-acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-left: auto; }
.bl-pm-list { margin-top: var(--sp-2_5); }
.bl-pm-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-0); border-top: 1px solid var(--app-border, var(--c-border));
}
.bl-pm-row .bl-pm-bill { min-width: 0; }
.bl-pm-row .bl-pm-bill .hint { display: block; }
.bl-pm-row input { width: 8.5rem; flex: none; text-align: right; }
.bl-rm-bill { padding: var(--sp-2_5) var(--sp-0) var(--sp-1); border-top: 1px solid var(--app-border, var(--c-border)); }
.bl-rm-pay { display: flex; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-1) var(--sp-0) var(--sp-1) var(--sp-1); cursor: pointer; font-size: 13px; }
.bl-rm-pay input { width: auto; margin: var(--sp-0_5) var(--sp-0) var(--sp-0); }
.bl-link {
  margin-top: var(--sp-2_5); padding: var(--sp-2_5) var(--sp-3);
  border: 1px solid color-mix(in srgb, var(--c-warn) 45%, var(--c-border)); border-radius: 9px;
  background: color-mix(in srgb, var(--c-warn) 9%, var(--c-card)); font-size: 13px; color: var(--c-text-2, inherit);
}
.bl-link p { margin: var(--sp-0) var(--sp-0) var(--sp-2); }
.bl-link .hint { margin: var(--sp-2) var(--sp-0) var(--sp-0); }
.bl-link-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.bl-link-row select { flex: 1 1 12rem; min-width: 0; }
