/* work-order-view.items.css -- v14 inline part adder and catalog popover; v15 Fees & Discounts sub-blocks and the Totals card

   Part 4 of 6. The stylesheet reached 79KB in one file, and the push tooling
   takes whole-file content, so every rule change re-emitted the whole thing.
   Split on the section boundaries that were already there. Load order is the
   cascade -- it is fixed in work-order-view.html and must not be reordered.
   No rule changed in this split. */

/* ============================================================
   v14 - INLINE PART ADDER
   "+ Part" appends a blank row to that group's Parts table, built from the
   same blank the ERP uses (createBlankWorkOrderPart: qty 1, cost 0, price 0,
   single-use, no catalog link, Not Required). It is a LINE from the moment it
   appears - no pending state, no commit step, nothing held out of the totals,
   which is why none of this needs styling beyond the name prompt below.
   Removing a row is the row kebab, which reuses the shared .menu-pop /
   .menu-item.danger pattern, so that needs no new styling either.
   ============================================================ */
/* the name prompt on a row nobody has named yet - a prompt, not a value */
.lg-table td.item .idn.ph{color:var(--text-disabled);font-style:italic;}
.lg-table .rowx iconify-icon{padding:4px;border-radius:5px;}
.lg-table .rowx iconify-icon:hover{background:var(--hover);color:var(--text);}
/* catalog search popover - the ledger's QuickAddNameAutocomplete. Anchored to
   the name line and rendered on <body>, because the subgroup tables scroll
   horizontally and would clip a dropdown rendered inside the cell. The ERP
   offers it only on a new row (negative id); our ids carry the same fact. */
.qa{display:none;position:fixed;width:430px;max-width:calc(100vw - 16px);background:var(--paper);border:1px solid var(--border-2);
    border-radius:10px;z-index:200;box-shadow:0 14px 40px rgba(0,0,0,.5);overflow:hidden;}
.qa.open{display:block;}
.qa-head{display:flex;align-items:center;gap:7px;padding:8px 12px;border-bottom:1px solid var(--border);
    font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--text-disabled);}
.qa-head iconify-icon{font-size:14px;}
.qa-list{max-height:250px;overflow-y:auto;padding:5px;}
.qa-list::-webkit-scrollbar{width:5px;} .qa-list::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:3px;}
.qa-row{display:flex;align-items:center;gap:10px;padding:8px 9px;border-radius:7px;cursor:pointer;}
.qa-row:hover,.qa-row.on{background:var(--hover);}
.qa-row .qn{font-size:13px;color:var(--text);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.qa-row .qm{font-size:11px;color:var(--text-secondary);margin-top:2px;}
.qa-row .qp{margin-left:auto;font-size:12.5px;font-weight:700;color:var(--text);white-space:nowrap;padding-left:10px;}
/* v56: .qtxt is a span, so .qn and .qm ran together on one line and .qm's
   margin-top did nothing - a block formatting context is what the two-line
   shape always assumed. */
.qa-row .qtxt{min-width:0;display:flex;flex-direction:column;}
/* v56: the one-off row is an ACTION, not a disclaimer (Tim). Italic +
   --text-secondary + a --text-disabled icon read as an unavailable option,
   which is the opposite of what it is: on a no-match query it is the only
   thing to click. Now it takes the blue affordance the rest of the design
   system uses for a primary choice. */
.qa-manual{border-top:1px solid var(--border);}
.qa-manual .qn{font-weight:600;color:var(--blue);}
.qa-manual iconify-icon{font-size:16px;color:var(--blue);flex-shrink:0;}
.qa-manual:hover,.qa-manual.on{background:var(--blue-16);}
/* .first = the fee/discount picker, where it heads the list: the separator
   belongs under it, and it needs air before the catalog rows below. */
.qa-manual.first{border-top:none;border-bottom:1px solid var(--border);
  border-radius:7px 7px 0 0;margin-bottom:4px;padding-bottom:9px;}
.qa-empty{padding:14px 12px;font-size:12.5px;color:var(--text-secondary);font-style:italic;}
/* ============================================================
   v15 - FEES & DISCOUNTS BREAKDOWN + TOTALS CARD
   Fees and Discounts stop sharing one anonymous table: each gets its own
   labelled sub-block using the same .lg-sub-head pattern as Parts / Labor /
   Sublets, with a + Fee / + Discount row underneath in the shared .lg-add
   style. The type pills below are the only new chrome.

   The Totals card sits bottom-right of the ledger, mirroring the ERP's Total
   block, and flips on the Rolling Closeout setting. Both are rendered from
   the JS model, so nothing here can drift from the persistent money bar.
   ============================================================ */
.tp-fee{background:var(--secondary-15);color:var(--secondary);}
.tp-discount{background:var(--green-15);color:var(--green);}
/* v63: the shipping lines' sub-block pill */
.tp-shipping{background:var(--blue-16);color:var(--blue);}
/* a discount reads as money coming off, so its total is green like the bar's */
.lg-table td.neg{color:var(--green);}
.lg-table td .cap-note{color:var(--text-secondary);font-size:11px;margin-left:4px;}
.lg-table td .waive-note{color:var(--text-secondary);font-weight:400;}
/* Totals card - right-aligned in the main column, ERP Total block proportions */
.lv-totals{width:100%;max-width:430px;margin:14px 0 0 auto;background:var(--paper);border:1px solid var(--border);
    border-radius:8px;overflow:hidden;}
.lvt-head{display:flex;align-items:center;gap:8px;padding:11px 16px;background:var(--panel);border-bottom:1px solid var(--border);}
.lvt-title{font-size:11px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--text-secondary);}
.lvt-badge{margin-left:auto;display:inline-flex;align-items:center;gap:5px;background:var(--blue-16);color:var(--blue);
    font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;padding:2px 8px;border-radius:10px;}
.lvt-badge iconify-icon{font-size:12px;}
.lvt-body{padding:9px 16px 11px;}
.tot-row{display:flex;align-items:baseline;justify-content:space-between;gap:18px;padding:5px 0;font-size:13px;}
.tot-row .k{color:var(--text-secondary);}
.tot-row .v{color:var(--text);font-weight:500;white-space:nowrap;}
.tot-row .v.neg{color:var(--green);}
/* a row the ledger has no model for yet reads muted rather than being dropped */
.tot-row.n-a .k,.tot-row.n-a .v{color:var(--text-disabled);}
.tot-row.strong{padding-top:8px;}
.tot-row.strong .k,.tot-row.strong .v{color:var(--text);font-weight:700;}
.tot-sep{height:1px;background:var(--border);margin:7px 0;}
.lvt-foot{display:flex;align-items:baseline;justify-content:space-between;gap:18px;padding:12px 16px;
    background:var(--panel);border-top:1px solid var(--border);}
.lvt-foot .k{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:var(--text);}
.lvt-foot .v{font-size:17px;font-weight:700;color:var(--text);}
.toast.err iconify-icon{color:var(--red);}
.uc-overlay{align-items:center;padding:24px;}
.uc-modal{max-width:420px;}
.uc-body{padding:18px 20px;font-size:13.5px;color:var(--text-secondary);line-height:1.5;}
.tp{display:inline-flex;align-items:center;padding:2px 9px;border-radius:5px;font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;}
.tp-labor{background:var(--blue-16);color:var(--blue);}
.tp-part{background:var(--green-15);color:var(--green);}
.tp-sublet{background:var(--amber-15);color:var(--amber);}
.lg-table .muted{color:var(--text-disabled);}
.lg-status{display:inline-flex;align-items:center;padding:3px 9px;border-radius:5px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;margin-left:8px;}
/* v65: the pill carried its own amber fill when there was only ever one of
   them. A group can now show several at once (SPD-2700), so the colour moves
   onto modifiers and the base rule keeps only the shape. AMBER = nothing has
   happened to it yet; BLUE = it is in flight. Both tints are the design
   system's existing ones, and the pill is unstyled without a modifier, so a
   new status that nobody has coloured is visibly wrong rather than silently
   amber. */
.lg-status.amber{background:var(--amber-15);color:var(--amber);}
.lg-status.blue{background:var(--blue-16);color:var(--blue);}
/* per-type subgroup sections (Parts / Labor / Sublets mini-tables) */
.lg-sub-head{display:flex;align-items:center;gap:10px;padding:7px 14px;background:var(--panel);border-top:1px solid var(--border);border-bottom:1px solid var(--border);}
.lg-ghead+.lg-sub .lg-sub-head{border-top:none;}
.lg-sub-head .cnt{font-size:11px;color:var(--text-secondary);font-weight:600;}
.lg-sub-head .samt{margin-left:auto;font-size:12px;font-weight:700;color:var(--text);}
.lg-add{display:flex;gap:8px;padding:11px 14px;background:var(--panel);border-top:1px solid var(--border);}
/* v58: THE ADD BUTTONS ARE GREEN (Tim), dashed ghost shape kept. Green is the
   design system's "add" colour - the Add Items fab and Quick Quote both use it
   - and these are the only add-a-line affordance inside a card. Hover follows,
   because a blue hover on a green button says the resting colour was a state
   rather than an identity.
   THIS ROW IS SHARED with the Fees & Discounts card's + Fee / + Discount pair
   (grid.js), which was deliberate when it was written and stays deliberate:
   both are "add a line", so both are green.
   The bulk-edit Save (.lg-save, grid.css) also lives in this row and was
   ALREADY green - solid border and a --green-15 fill against these dashed
   outlines, which is what keeps the two apart now that they share a hue. */
.lg-add button{display:flex;align-items:center;gap:5px;background:transparent;border:1px dashed var(--green);border-radius:16px;padding:6px 13px;color:var(--green);font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.2px;}
.lg-add button iconify-icon{font-size:15px;} .lg-add button:hover{border-color:var(--green);color:var(--green);background:var(--green-15);}
.lg-breakdown{display:flex;gap:22px;padding:11px 16px;background:var(--panel);border-top:1px solid var(--border);font-size:12px;font-weight:600;color:var(--text-secondary);letter-spacing:.3px;}
.lg-breakdown .b{display:inline-flex;align-items:center;gap:7px;} .lg-breakdown .b .amt{color:var(--text);font-weight:700;}
.build-est{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;background:transparent;border:1px dashed var(--border-2);border-radius:8px;padding:14px;color:var(--text-secondary);font-size:12.5px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;margin-top:2px;}
.build-est iconify-icon{font-size:19px;color:var(--blue);} .build-est:hover{border-color:var(--blue);color:var(--text);}
/* right rail */
.lv-rail{background:var(--paper);border:1px solid var(--border);border-radius:8px;overflow:hidden;position:sticky;top:0;}
.rail-tabs{display:flex;border-bottom:1px solid var(--border);}
.rail-tab{flex:1;padding:11px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-secondary);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;}
.rail-tab.active{color:var(--blue);border-bottom-color:var(--blue);}
.rail-pane{padding:14px 16px;max-height:calc(100vh - 280px);overflow-y:auto;}
.rail-pane::-webkit-scrollbar{width:5px;} .rail-pane::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:3px;}
.rail-sec-title{font-size:11px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--text-disabled);margin:16px 0 8px;}
.rail-sec-title:first-child{margin-top:0;}
.rail-row{display:flex;justify-content:space-between;gap:10px;padding:6px 0;font-size:13px;}
.rail-row .k{color:var(--text-secondary);} .rail-row .v{color:var(--text);font-weight:500;text-align:right;} .rail-row .v.link{color:var(--blue);cursor:pointer;}
.rail-reqs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:6px;}
.rq{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;padding:4px 10px;border-radius:12px;cursor:pointer;}
.rq:hover{filter:brightness(1.08);}
.rq iconify-icon{font-size:14px;}
.rq.red{background:var(--red-15);color:var(--red);} .rq.green{background:var(--green-15);color:var(--green);}
.rail-labor{margin-top:4px;} .rl{display:flex;justify-content:space-between;font-size:12.5px;padding:5px 0;color:var(--text);} .rl span:first-child{color:var(--text-secondary);}
.rail-veh{font-size:13.5px;font-weight:600;color:var(--text);} .rail-vehsub{font-size:12px;color:var(--text-secondary);margin:3px 0 8px;}
/* v63: the rail's Client section - name + portal chip on one line, contact
   details in the shared .rail-row shape below it. .client-name is the shared
   primitive (work-order-view.css since v55), so V1 styles it without
   classic.css; the chip mirrors Classic's Portal Active badge. */
.rail-client{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:2px;}
.rail-client .client-name{font-size:13.5px;font-weight:600;}
.rail-portal{display:inline-flex;align-items:center;gap:4px;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;color:var(--green);background:var(--green-15);border-radius:10px;padding:2px 8px;}
.rail-portal iconify-icon{font-size:12px;}
/* v49: the rail's Description and Expectations were clamped to three lines
   with NO way to read the rest - the text was simply cut off and nothing said
   so. They expand on click and the clamp stays at three lines.
   v50: HOVER-TO-EXPAND IS GONE (Tim). Click on, click off - nothing opens
   because the pointer happened to cross it. The rail is a dense column of
   short rows, so a block that unfolded on the way past would reflow everything
   under it while you were reaching for something else. Only .stuck lifts the
   clamp now; the hover colour shift went with it, since hovering no longer
   does anything and colouring it would promise that it did. */
.rail-desc{position:relative;font-size:12.5px;color:var(--text-secondary);line-height:1.5;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;cursor:pointer;}
.rail-desc.stuck{-webkit-line-clamp:unset;overflow:visible;color:var(--text);}
.rail-more{display:flex;align-items:center;gap:4px;margin-top:3px;font-size:11px;font-weight:600;color:var(--blue);cursor:pointer;user-select:none;}
.rail-more iconify-icon{font-size:14px;transition:transform .12s ease;}
.rail-more.stuck iconify-icon{transform:rotate(180deg);}
/* persistent bottom bar */
.lv-bottombar{flex-shrink:0;display:flex;align-items:center;gap:22px;padding:12px 22px;background:var(--paper);border-top:1px solid var(--border-2);box-shadow:0 -6px 18px rgba(0,0,0,.18);}
/* v57: THE BAR'S BUTTONS ARE SQUARED OFF (Tim), to the same 7px the rest of
   the ledger uses - .lv-addbtns, .lv-send-btn and .lv-more-btn are all 7px,
   and the 26px pill was the only thing in the view still shaped like a FAB.
   The heavy pill shadow goes with it: these sit on a bar that already has its
   own top border and shadow, so the drop shadow was doing nothing but
   thickening the edge.
   SCOPED TO .lv-bottombar ON PURPOSE. `.fab` is shared with `.fab-stack`,
   which is CLASSIC-ONLY (v55) - and Classic is the control group, so a bare
   `.fab{border-radius:7px}` would have reshaped it. */
.lv-bottombar .fab{border-radius:7px;box-shadow:none;padding:11px 18px;}
/* v56: Send moves down here too, ahead of Add Items (Tim). Same #sendMenu the
   tabs-row button opens - one menu, two entry points, so they can never
   disagree. Pill geometry and the uppercase label come from .fab so all three
   buttons in the bar are the same height.
   v57: the bar is + Add Items / Send / kebab, so Send is the middle of three
   and the kebab below matches it.
   v58: SOLID BLUE (Tim). v56/v57 had it as a bordered secondary shape on the
   reasoning that Add Items was the ledger's own loud action and Send should
   not compete - that call is REVERSED here, and the note is left rather than
   deleted so the code does not sit next to a comment arguing against it. The
   bar now reads green / blue / kebab, which is the pairing the tabs row uses
   too. Blue comes from .fab.blue's fill, not a second blue. */
.bb-send{background:var(--blue);border:none;color:#fff;box-shadow:none;}
.bb-send iconify-icon{color:#fff;}
.bb-send .chev{font-size:16px;color:#fff;margin-left:-3px;}
/* v57: the bar's kebab. Same shape and hover as .lv-more-btn in the tabs row,
   sized to the bar's button height rather than the tab row's. */
.bb-kebab{background:transparent;border:1px solid var(--border-2);color:var(--text-secondary);
  box-shadow:none;padding:11px 12px;}
.bb-kebab iconify-icon{font-size:19px;}
.bb-kebab:hover{border-color:var(--blue);color:var(--text);filter:none;background:var(--hover);}
.bb-gp{display:flex;align-items:center;gap:14px;color:var(--text-secondary);font-size:12.5px;font-weight:600;}
.bb-gp>iconify-icon{font-size:19px;color:var(--text-secondary);}
.bb-gp b{color:var(--text);} .bb-gp b.red{color:var(--red);}
.bb-stats{display:flex;gap:26px;margin-left:auto;}
.bb-stats .s{text-align:right;} .bb-stats .s .k{display:block;font-size:10.5px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.3px;} .bb-stats .s .v{font-size:14px;font-weight:700;color:var(--text);}
.bb-stats .s.big .v{font-size:16px;color:var(--text);} .bb-stats .s.big .k{color:var(--text-secondary);}
.bb-auth{display:flex;align-items:center;gap:7px;background:var(--green);color:#fff;border:none;border-radius:7px;padding:11px 18px;font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;}
.bb-auth iconify-icon{font-size:17px;}
.bb-auth:hover{filter:brightness(1.05);}

/* ============================================================
   v24 - SHIPPING INPUT, FEE / DISCOUNT PICKER, ONE-OFF MARKER
   Three additions, all on the money surfaces.

   SHIPPING was the only editable figure in the Totals card until v63
   itemized it into lines (grid.js shipSub); the row is a derived sum now,
   and the click affordance and .shipin input rules went with the direct
   edit. Only the zero-state muting survives below.

   The PICKER is the .qa catalog popover's shape, deliberately: + Fee and
   + Discount were asked to behave like the parts catalog, so they reuse its
   list, row, meta and empty-state rules and add only a search bar and the
   default badge. Rendered on <body> for the same reason .qa is.
   ============================================================ */
/* the Shipping row reads only (v63) - its figure is the shipping lines' sum */
.tot-row.ship.zero .v{color:var(--text-secondary);}

/* fee / discount picker - same furniture as the parts catalog popover */
.fp{display:none;position:fixed;width:430px;max-width:calc(100vw - 16px);background:var(--paper);
    border:1px solid var(--border-2);border-radius:10px;z-index:200;
    box-shadow:0 14px 40px rgba(0,0,0,.5);overflow:hidden;}
.fp.open{display:block;}
.fp .qa-head iconify-icon{color:var(--blue);}
.fp-search{display:flex;align-items:center;gap:7px;padding:8px 12px;border-bottom:1px solid var(--border);}
.fp-search iconify-icon{font-size:16px;color:var(--text-disabled);}
.fp-search input{flex:1;min-width:0;background:transparent;border:none;outline:none;
    color:var(--text);font-size:13px;font-family:inherit;}
/* a fee the shop applies by default (location_fees.default) */
.fp-dflt{margin-left:7px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;
    color:var(--text-disabled);border:1px solid var(--border);border-radius:9px;padding:1px 6px;}
/* a discount reads as money coming off, here as well as on the line */
.fp .qa-row .qp.neg{color:var(--green);}

/* the marker on a fee or discount line with no catalog row behind it */
.one-off{margin-left:8px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;
    color:var(--amber);background:var(--amber-15);border-radius:9px;padding:1px 7px;white-space:nowrap;}
.one-off .nw-flag{font-size:12px;margin-left:3px;}

/* ============================================================
   v27 - LINE + GROUP DISCOUNTS
   The Discount column and the group-header control. Both belong to
   work-order-view.discounts.js and are dead rules without it, which is the
   point - that part is meant to be liftable.
   ============================================================ */
/* what came off reads as money off, like the Fees & Discounts lines do */
.disc-v{color:var(--green);font-weight:600;}
/* a percentage says nothing about the money, so the entered value rides
   alongside what it worked out to */
.disc-k{margin-left:6px;font-size:10.5px;font-weight:700;color:var(--text-disabled);}
/* the group-header control: quiet until it holds a value */
.g-disc{display:inline-flex;align-items:center;gap:5px;margin-left:12px;
    background:transparent;border:1px dashed var(--border-2);border-radius:14px;
    padding:3px 10px;color:var(--text-secondary);
    font-size:11px;font-weight:600;white-space:nowrap;}
.g-disc iconify-icon{font-size:14px;}
.g-disc:hover{border-color:var(--green);color:var(--green);}
.g-disc.on{border-style:solid;border-color:var(--green-15);background:var(--green-15);color:var(--green);}
.g-disc-k{margin-left:5px;font-size:10px;font-weight:700;opacity:.75;}
.g-disc-input{margin-left:12px;width:130px;background:var(--bg);border:1px solid var(--green);
    border-radius:14px;padding:3px 10px;font-family:inherit;font-size:11.5px;font-weight:600;
    color:var(--text);outline:none;}

/* ============================================================
   v27 - TECHNICIAN NOTES IN THE HEADER (comparison variant)
   Same panel, different placement: a strip directly under the header row
   rather than at the foot of the card.
   ============================================================ */
.lg-notes.head{padding:8px 14px 10px;border-bottom:1px solid var(--border);}
.lg-notes.head .lg-notes-panel{margin-top:8px;}
