/* ==========================================================================
   Payable — app-wide component styles.

   Written fresh, but in JOBBER'S CLASS VOCABULARY on purpose: the two apps sit
   on the same desks and must read as one family. .app/.side-wide/.side-rail/
   .side-none, #side, .main, #view, .viewbar, .subbar, .btn family, .chip
   family, .card, .tblwrap, table.wt, .modal family, #toasts/.toast all mean
   here exactly what they mean in Jobber.

   COLOUR RULE: every colour comes from tokens.css. There is no literal hex in
   this file. The ONE sanctioned exception form is rgba(255,255,255,α) used as a
   translucent veil on the sidebar chrome — the sidebar is theme-invariant by
   design (see tokens.css), and a white film at 5-14% is a lightening operator,
   not a colour choice. Everything else, including the unread badge, is a token.

   Dark mode therefore works by construction. The one thing to watch is
   documented in §D: --accent is a fine FILL in dark mode but only ~3:1 as TEXT,
   so anywhere it is a foreground colour it steps up to --accent-ink.

   --------------------------------------------------------------------------
   AP-SPECIFIC COMPONENTS — the pieces the screen lanes need. Their markup
   contract is written here so nobody has to reverse-engineer it from the CSS:

   .stagerail          §9  The horizontal stage breadcrumb: where this invoice
                           sits on the map. One .st per stage in rules.STAGES
                           order, carrying .done / .now / .todo, plus .gate on
                           the stages that are human gates (awaiting_approval,
                           a block). .now is the only one that is filled.
                             <div class="stagerail">
                               <div class="st done">Received</div>
                               <div class="st now gate">Awaiting approval</div>
                               <div class="st todo">Posted</div>
                             </div>

   .docpane / .evbox   §10 The invoice page viewer. .docpane is the column;
                           .docbar is its page pager; .docstage scrolls; .docpage
                           is the positioning context that WRAPS the <img> and
                           is sized by the image itself. Evidence boxes are
                           absolutely positioned in PERCENTAGES of the page, so
                           they survive any zoom:
                             <div class="docpage">
                               <img src="/static/pages/inv-12-p1.png" alt="">
                               <div class="evbox" data-field="total"
                                    style="left:62.4%;top:71.1%;width:14.2%;height:2.6%"></div>
                             </div>
                           Add .lit to light one up when its field is selected;
                           .evbox.miss marks a field the reader could not place.

   .matchgrid          §11 The four-column comparison: invoice | PO | receipt |
                           agreement. A <table class="matchgrid"> whose cells
                           carry .diff when they disagree with the invoice, and
                           .diff.up (vendor favoured — we would overpay, red) or
                           .diff.dn (Navillus favoured — info, green). .src is
                           the row-label column. .nosrc greys a source that has
                           nothing to say (no receipt yet).

   .exccard            §12 One exception case. Severity is a left stripe:
                           .exccard.block / .review / .info. Inside: .exhead
                           (kind chip + title + amount), .exnarr (what it
                           disagrees with and why), .exprop (the proposed
                           resolution), .exprior (prior cases), .exbtns.

   .blockbanner        §13 Payment is blocked. Full width, red, at the TOP of
                           the invoice — above the fields, because it is the
                           first fact about that invoice. .blockbanner .bbwhy
                           and .bbbtns.

   .actionbar          §14 The sticky bar of the actions THIS role may press.
                           .actionbar .abnote carries the sentence explaining
                           why an action is missing.

   .procmap            §15 The process-map screen. .pmrow is a rank, .pmnode a
                           node (with .pmname / .pmcount / .pmsub), .pmnode.gate
                           a human gate, .pmnode.exit a terminal, .pmnode.hot a
                           node with work waiting. .pmedge draws the connectors,
                           .pmlabel labels a branch ("yes" / "no PO").

   .stats / .stat      §7  The dashboard tiles.
   ========================================================================== */


/* ===== 0. reset + the app frame ===== */
*{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%;}
body{background:var(--bg);font-family:var(--ui);color:var(--ink);-webkit-font-smoothing:antialiased;}

/* Full-bleed. The chrome/canvas seam is the sidebar edge, not a border, and the
   app fills the viewport — an AP screen is a working surface, not a card
   floating in grey. --side-w is the single width knob the three modes set. */
.app{width:100vw;height:100vh;background:var(--surface);
  display:grid;grid-template-columns:var(--side-w,0px) 1fr;overflow:hidden;}
.app.side-wide{--side-w:212px;}
.app.side-rail{--side-w:72px;}
.app.side-none{grid-template-columns:1fr;}
.app.side-none #side{display:none;}

.main{display:flex;flex-direction:column;overflow:hidden;min-width:0;}
/* #side is a grid item (full height); its .side/.rail child must STRETCH or the
   dark chrome stops at its content and the canvas shows through underneath. */
#side{display:flex;flex-direction:column;min-height:0;}
#side>.side,#side>.rail{flex:1;min-height:0;}
#view{flex:1;min-height:0;display:flex;flex-direction:column;overflow:auto;}
button,input,select,textarea{font:inherit;color:inherit;}

/* The router's answer when a screen module did not load. Deliberately plain —
   it is a build fact, not an error a person can act on. */
.viewmissing{padding:28px;color:var(--muted);font-size:13px;}


/* ===== 1. the wide sidebar (212px) ===== */
.side{background:var(--sidebar);color:var(--ondark-1);display:flex;flex-direction:column;
  padding:22px 0;min-height:0;}
.side .brand{display:flex;align-items:center;gap:12px;padding:0 18px 20px;position:relative;
  border-bottom:1px solid rgba(255,255,255,.08);margin-bottom:14px;}
.side .brand .mark,.rail .mark{width:38px;height:38px;border-radius:10px;flex:none;
  background:linear-gradient(135deg,var(--accent),var(--accent-deep));
  display:flex;align-items:center;justify-content:center;
  color:var(--onaccent);font-family:var(--cond);font-weight:700;font-size:19px;letter-spacing:.5px;}
.side .brand .name{font-family:var(--cond);font-weight:700;color:var(--onaccent);font-size:17px;
  line-height:1.05;min-width:0;}
.side .brand .name small{display:block;font-family:var(--ui);font-weight:400;font-size:9.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--faint);margin-top:4px;white-space:nowrap;}

/* The one consequential gesture in the whole sidebar, and it looks like it. */
.add-inv{margin:0 12px 14px;display:flex;align-items:center;justify-content:center;gap:9px;
  padding:11px 12px;border-radius:10px;border:none;cursor:pointer;
  background:var(--accent);color:var(--onaccent);font-family:var(--ui);font-size:13.5px;
  font-weight:700;letter-spacing:.01em;box-shadow:0 6px 16px rgba(var(--accent-rgb),.32);}
.add-inv:hover{background:var(--accent-hover);}
.add-inv:focus-visible{outline:2px solid var(--onaccent);outline-offset:2px;}
.add-inv svg{width:16px;height:16px;stroke:var(--onaccent);fill:none;stroke-width:2.4;}

.side .nav{display:flex;flex-direction:column;gap:2px;padding:4px 12px;overflow-y:auto;min-height:0;}
.side .nav a{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:9px;
  color:var(--ondark-2);text-decoration:none;font-size:13.5px;font-weight:500;cursor:pointer;
  white-space:nowrap;}
.side .nav a .ic{width:17px;height:17px;flex:none;stroke:currentColor;fill:none;stroke-width:1.9;}
.side .nav a>span{min-width:0;overflow:hidden;text-overflow:ellipsis;}
.side .nav a:hover{background:rgba(255,255,255,.05);color:var(--ondark-hover);}
.side .nav a.active{background:var(--accent);color:var(--onaccent);
  box-shadow:0 6px 16px rgba(var(--accent-rgb),.35);}
.side .nav a.active .ic{stroke:var(--onaccent);}
.side .nav a:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:-2px;}

.side .foot{margin-top:auto;padding:14px 14px 2px;border-top:1px solid rgba(255,255,255,.08);}
.whobtn{display:flex;align-items:center;gap:10px;width:100%;padding:7px 8px;border-radius:9px;
  border:none;background:transparent;cursor:pointer;text-align:left;min-width:0;}
.whobtn:hover{background:rgba(255,255,255,.06);}
.whobtn:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:-2px;}
.whobtn .avatar{width:30px;height:30px;border-radius:50%;flex:none;background:var(--avatar-bg);
  color:var(--ondark-strong);display:flex;align-items:center;justify-content:center;
  font-size:11.5px;font-weight:700;}
.whobtn .whotext{min-width:0;display:flex;flex-direction:column;gap:1px;}
.whobtn .whotext b{font-size:12.5px;color:var(--ondark-strong);font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.whobtn .whotext small{font-size:10.5px;color:var(--faint);}
.side .foot .themetoggle,.side .foot .logout{margin-top:8px;width:100%;padding:7px 10px;
  border-radius:8px;cursor:pointer;background:transparent;border:1px solid rgba(255,255,255,.14);
  color:var(--ondark-1);font-size:11.5px;font-weight:600;font-family:var(--ui);text-align:center;}
.side .foot .themetoggle:hover,.side .foot .logout:hover{background:rgba(255,255,255,.06);
  color:var(--ondark-hover);}
.side .foot .themetoggle:focus-visible,.side .foot .logout:focus-visible{
  outline:2px solid var(--ondark-hover);outline-offset:2px;}


/* ===== 2. the narrow rail (72px) ===== */
.rail{background:var(--sidebar);display:flex;flex-direction:column;align-items:center;
  padding:16px 0;gap:4px;min-height:0;overflow-y:auto;}
.rail .mark{margin-bottom:8px;}
.rail .addbtn{width:44px;height:44px;border-radius:13px;border:none;cursor:pointer;flex:none;
  background:var(--accent);color:var(--onaccent);display:flex;align-items:center;justify-content:center;
  box-shadow:0 6px 15px rgba(var(--accent-rgb),.4);margin-bottom:2px;}
.rail .addbtn:hover{background:var(--accent-hover);}
.rail .addbtn:focus-visible{outline:2px solid var(--onaccent);outline-offset:2px;}
.rail .addbtn svg{width:22px;height:22px;stroke:var(--onaccent);fill:none;stroke-width:2.6;}
.rail .addcap{font-size:9px;letter-spacing:.04em;text-transform:uppercase;color:var(--faint);
  margin-bottom:10px;font-weight:700;}
.rail .ricon{width:44px;height:44px;border-radius:11px;display:flex;align-items:center;
  justify-content:center;color:var(--ondark-3);cursor:pointer;flex:none;position:relative;}
.rail .ricon svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.9;}
.rail .ricon:hover{background:rgba(255,255,255,.06);color:var(--ondark-hover);}
.rail .ricon.active{background:var(--accent);color:var(--onaccent);}
.rail .ricon:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:-2px;}
.rail .spring{margin-top:auto;}
.rail .avatar{width:34px;height:34px;border-radius:50%;border:none;background:var(--avatar-bg);
  color:var(--ondark-strong);display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;margin-top:10px;cursor:pointer;flex:none;font-family:var(--ui);}
.rail .avatar:hover{background:var(--avatar-bg-hover);}
.rail .avatar:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:2px;}

/* The sidebar chrome never changes colour between themes (tokens.css), but the
   canvas goes near-black in dark mode — the light-mode "huge contrast = free
   seam" disappears, so a hairline keeps the boundary from going flat. */
:root[data-theme="dark"] .side,
:root[data-theme="dark"] .rail{border-right:1px solid rgba(255,255,255,.07);}

/* fold controls */
.sidefold{margin-left:auto;width:26px;height:26px;border-radius:7px;flex:none;
  border:1px solid rgba(255,255,255,.14);background:transparent;color:var(--ondark-3);
  cursor:pointer;display:flex;align-items:center;justify-content:center;}
.sidefold:hover{background:rgba(255,255,255,.08);color:var(--ondark-hover);}
.sidefold svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;}
.railfold{width:44px;height:30px;border-radius:9px;border:none;background:transparent;flex:none;
  color:var(--ondark-3);cursor:pointer;display:flex;align-items:center;justify-content:center;margin-top:2px;}
.railfold:hover{background:rgba(255,255,255,.06);color:var(--ondark-hover);}
.railfold svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2;}
.sidefold:focus-visible,.railfold:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:2px;}

/* The unread/queue badge. Tokens, not literals — background --rej with white
   ink in light mode; in dark mode --rej is the LIFTED #E8695A, on which white
   measures under 3:1, so the ink flips to the (theme-invariant) sidebar navy.
   Same manoeuvre tokens.css documents for the accent-hover fills. */
.navbadge{display:inline-block;min-width:17px;padding:0 5px;margin-left:auto;border-radius:9px;
  background:var(--rej);color:var(--onaccent);font-family:var(--ui);font-size:10px;line-height:17px;
  font-weight:700;text-align:center;letter-spacing:.02em;flex:none;}
:root[data-theme="dark"] .navbadge{color:var(--sidebar);}
.rail .navbadge{position:absolute;top:2px;right:5px;margin:0;}

/* the account menu, rendered into the shared #popover host */
.acctmenu{display:flex;flex-direction:column;gap:2px;min-width:196px;}
.acctmenu .amwho{padding:7px 9px 9px;border-bottom:1px solid var(--line);margin-bottom:4px;}
.acctmenu .amwho b{display:block;font-size:12.5px;color:var(--ink);}
.acctmenu .amwho span{display:block;font-size:10.5px;color:var(--muted);margin-top:2px;}
.acctmenu .amwho .amlimit{font-family:var(--mono);color:var(--ink);margin-top:4px;}
.acctmenu button{display:flex;align-items:center;gap:8px;border:none;background:none;cursor:pointer;
  text-align:left;font-size:12px;color:var(--ink);padding:7px 9px;border-radius:6px;font-family:var(--ui);}
.acctmenu button:hover{background:var(--accent-soft);}
.acctmenu button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}

/* The pre-session outline (shell.js paintShellOutline). It is the REAL sidebar
   markup — right width, right shape — but the click delegation is not attached
   yet, so it must not look like it takes input. Up for one round trip. */
.bootskel{pointer-events:none;}
.bootskel .nav a,.bootskel .ricon,.bootskel .add-inv,.bootskel .addbtn{opacity:.72;}


/* ===== 3. viewbar / subbar / page scaffold =====
   Every screen is the same three bands: a .viewbar (who am I looking at and
   what can I do), an optional .subbar (filters, pagers, counts), and the
   scrolling body. .page is the body wrapper for a list screen; .dash for the
   dashboard's sectioned layout. */
.viewbar{display:flex;align-items:center;gap:14px;padding:9px 22px;min-height:62px;
  border-bottom:1px solid var(--line);flex:none;flex-wrap:wrap;row-gap:8px;background:var(--surface);}
/* min-height, not height: when the meta row wraps (vendor + PO + job + chips) a
   fixed bar clips the title's top half. The bar grows with its content. */
.viewbar .vbtitle{display:flex;flex-direction:column;gap:3px;min-width:0;}
.viewbar .vbtitle .vt{font-family:var(--cond);font-weight:700;font-size:19px;color:var(--ink);
  line-height:1.1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.viewbar .vbtitle .vmeta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0;
  font-size:11.5px;color:var(--muted);}
.viewbar .vbtitle .vmeta .mono{font-family:var(--mono);}
.viewbar .vbstatus{display:flex;align-items:center;gap:7px;flex-wrap:wrap;min-width:0;}
.vbright{margin-left:auto;display:flex;align-items:center;gap:9px;flex-wrap:wrap;justify-content:flex-end;}
/* A sticky identity on a long invoice: the header stays while the page image
   scrolls under it. Opaque in both themes — --surface is theme-scoped. */
.viewbar.vbpin{position:sticky;top:0;z-index:8;}

.backb{width:34px;height:34px;border-radius:9px;border:1px solid var(--line-strong);
  background:var(--surface);cursor:pointer;display:flex;align-items:center;justify-content:center;
  color:var(--ink);flex:none;text-decoration:none;}
.backb:hover{border-color:var(--accent);color:var(--accent);}
.backb svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.2;}

.subbar{display:flex;align-items:center;gap:10px;padding:10px 22px;border-bottom:1px solid var(--line);
  flex:none;flex-wrap:wrap;row-gap:8px;background:var(--surface-2);}
.subbar .sbcount{font-size:11.5px;color:var(--muted);font-family:var(--mono);}
.subbar .sbpush{margin-left:auto;}

.page{flex:1;min-height:0;display:flex;flex-direction:column;overflow:auto;}
.page>.pagebody{padding:18px 22px 40px;flex:1;min-height:0;}
.dash{flex:1;min-height:0;display:flex;flex-direction:column;}
.dash .main-scroll{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;}
.dash .section{padding:20px 26px;}
/* The divider is an inset ::before rather than a full-bleed border-top, so the
   rule lines up with the content edges instead of the window's. */
.dash .section+.section{position:relative;}
.dash .section+.section::before{content:"";position:absolute;top:0;left:26px;right:26px;height:1px;
  background:var(--line);}
.dash .s-head{display:flex;align-items:baseline;gap:14px;margin-bottom:14px;flex-wrap:wrap;}
.dash .s-head h2{font-family:var(--cond);font-size:18px;font-weight:700;letter-spacing:.01em;
  position:relative;padding-bottom:5px;}
.dash .s-head h2::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2.5px;
  background:var(--accent);border-radius:2px;}
.dash .s-head .sub{font-size:12px;color:var(--muted);}
.dash .s-head .push{margin-left:auto;}

/* A section heading outside the dashboard's sectioned layout. */
.hd{font-family:var(--cond);font-size:15px;font-weight:700;color:var(--ink);margin:0 0 10px;}
.hd .sub{font-family:var(--ui);font-size:11.5px;font-weight:400;color:var(--muted);margin-left:8px;}


/* ===== 4. buttons =====
   Four names, and every surface converges on them:
     .btn-primary    the ONE consequential action here
     .btn-secondary  a real supporting action
     .btn-ghost      a quiet action
     .btn-danger     destructive/refusing — reject, release, void
   .btn-group is a segmented cluster that reads as one control. */
.btn{border:1px solid var(--line-strong);background:var(--surface);color:var(--ink);cursor:pointer;
  font-family:var(--ui);font-size:13px;font-weight:600;padding:9px 14px;border-radius:9px;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;text-decoration:none;
  white-space:nowrap;}
.btn svg{width:1.15em;height:1.15em;stroke:currentColor;fill:none;stroke-width:2.1;}
.btn:hover{border-color:var(--faint);}
/* Keyboard focus is not optional on the surfaces where an approver works. */
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-color:var(--accent);}
/* In-flight: callers set data-busy while the request is open. Silence after a
   press is what produces click storms, and a double-approve is expensive. */
.btn[data-busy]{opacity:.6;cursor:progress;pointer-events:none;}
.btn[data-busy]::after{content:"";width:.85em;height:.85em;border-radius:50%;
  border:2px solid currentColor;border-right-color:transparent;animation:btnspin .6s linear infinite;}
@keyframes btnspin{to{transform:rotate(360deg);}}
.btn[disabled]{opacity:.5;cursor:default;}
.btn[disabled]:hover{border-color:var(--line-strong);}
.btn.sm{padding:5px 10px;font-size:11.5px;border-radius:7px;}
.btn.lg{padding:11px 20px;font-size:14px;}
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--onaccent);
  box-shadow:0 6px 14px rgba(var(--accent-rgb),.28);}
.btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);}
.btn-secondary{background:var(--surface-2);border-color:var(--line-strong);}
.btn-secondary:hover{border-color:var(--accent);color:var(--accent);}
.btn-ghost{background:transparent;border-color:transparent;box-shadow:none;}
.btn-ghost:hover{background:var(--surface-2);border-color:var(--line-strong);}
.btn-danger{background:var(--rej);border-color:var(--rej);color:var(--onaccent);box-shadow:none;}
.btn-danger:hover{background:var(--rej);border-color:var(--rej);filter:brightness(1.06);}
:root[data-theme="dark"] .btn-danger{color:var(--sidebar);}
.btn-group{display:inline-flex;align-items:center;flex:none;background:var(--surface);
  border:1px solid var(--line-strong);border-radius:9px;overflow:hidden;}
.btn-group>.btn{border:none;border-radius:0;background:transparent;padding:9px 12px;box-shadow:none;}
.btn-group>.btn:hover{background:var(--accent-soft);color:var(--accent);}
.btn-group>.btn:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}
.btn-group>.btn.on{background:var(--accent);color:var(--onaccent);}
.btn-group>.btn[disabled]:hover{background:transparent;color:inherit;}

/* segmented toggle (list / map, all / mine) */
.seg{display:inline-flex;background:var(--bg);border:1px solid var(--line);border-radius:9px;
  padding:3px;gap:2px;}
.seg button{border:none;background:transparent;cursor:pointer;font-family:var(--ui);font-size:12.5px;
  font-weight:600;color:var(--muted);padding:6px 13px;border-radius:7px;display:flex;align-items:center;gap:6px;}
.seg button svg{width:1.1em;height:1.1em;stroke:currentColor;fill:none;stroke-width:2;}
.seg button.on{background:var(--surface);color:var(--ink);box-shadow:0 1px 3px rgba(var(--shadow-rgb),.12);}
.seg button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}

/* A plain text link inside prose or a table cell. */
.lk{color:var(--accent);cursor:pointer;text-decoration:none;font-weight:600;}
.lk:hover{color:var(--accent-hover);text-decoration:underline;}


/* ===== 5. form controls =====
   .field is the label+control unit every dialog and settings row is built from.
   Money and quantity inputs take .mono so a column of them lines up. */
.field{display:flex;flex-direction:column;gap:5px;font-size:12px;font-weight:600;color:var(--muted);
  min-width:0;}
.field>span{font-size:11px;letter-spacing:.02em;}
.field input,.field select,.field textarea{border:1px solid var(--line-strong);border-radius:8px;
  padding:9px 11px;font-size:13px;font-family:var(--ui);color:var(--ink);outline:none;
  background:var(--surface);width:100%;font-weight:400;}
.field textarea{resize:vertical;min-height:64px;line-height:1.5;}
.field input.mono,.field textarea.mono{font-family:var(--mono);}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(var(--accent-rgb),.14);}
.field input[disabled],.field select[disabled],.field textarea[disabled]{background:var(--surface-2);
  color:var(--muted);cursor:not-allowed;}
.field .help{font-size:10.5px;font-weight:400;font-style:normal;color:var(--faint);line-height:1.5;}
.field.bad input,.field.bad textarea,.field.bad select{border-color:var(--rej);}
.field .fielderr{font-size:11px;font-weight:600;color:var(--rej);}
.inrow{display:flex;gap:12px;flex-wrap:wrap;}
.inrow>.field{flex:1 1 180px;}
/* Number spinners are a hazard on money fields (see shell.js's wheel guard) —
   remove the buttons so the only way in is typing. */
.field input[type="number"]{-moz-appearance:textfield;}
.field input[type="number"]::-webkit-outer-spin-button,
.field input[type="number"]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0;}
.chk{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink);cursor:pointer;
  font-weight:500;}
.chk input{width:15px;height:15px;accent-color:var(--accent);flex:none;}

/* filter bar — chips, a date bound and a text bound in one visual family */
.fbar{display:flex;flex-wrap:wrap;align-items:center;gap:7px;}
.fchipwrap{display:inline-flex;align-items:center;border:1px solid var(--line-strong);border-radius:9px;
  background:var(--surface);overflow:hidden;max-width:100%;}
.fchipwrap.on{border-color:var(--accent);}
.fchip{display:inline-flex;align-items:center;gap:5px;min-width:0;border:0;background:none;cursor:pointer;
  color:var(--muted);font-family:var(--ui);font-size:11px;font-weight:600;letter-spacing:.02em;padding:5px 9px;}
.fchip:hover{color:var(--ink);}
.fchipwrap.on .fchip{color:var(--accent);}
.fchip .fchipv{font-family:var(--mono);font-weight:700;font-size:10.5px;color:var(--ink);
  max-width:18ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.fchipx{border:0;border-left:1px solid var(--accent);background:none;cursor:pointer;color:var(--accent);
  font-size:10px;line-height:1;padding:6px 7px;font-family:var(--ui);}
.fchipx:hover{background:var(--accent-soft);}
.fchip:focus-visible,.fchipx:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}
.ftextwrap{flex:0 1 240px;}
.ftext{border:0;background:none;color:var(--ink);font-family:var(--ui);font-size:11.5px;
  padding:6px 9px;width:100%;min-width:0;outline:none;}
.ftext::placeholder{color:var(--faint);}
.filterin{border:1px solid var(--line-strong);border-radius:8px;padding:7px 11px;font-size:12px;
  font-family:var(--ui);color:var(--ink);width:220px;outline:none;background:var(--surface);}
.filterin:focus{border-color:var(--accent);}
.filterin::placeholder{color:var(--faint);}


/* ===== 6. the chip family =====
   Fixed geometry on purpose: the box is pinned (height + zeroed vertical
   padding + margin/border resets) so no colliding class and no leftover inline
   style can change a chip's height. Exactly three sizes — 22 / 18 / 26.

   Four semantic colours and what they MEAN in this app:
     .ok      settled          matched, approved, posted, released
     .review  in flight        extracting, matching, awaiting, informational
     .due     needs a person   needs_person, low confidence, over-due
     .rej     refused/stopped  rejected, blocked, duplicate, overbilled */
.chip{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;gap:5px;
  height:22px;margin:0;padding:0 11px;border:none;font-size:10.5px;font-weight:700;border-radius:20px;
  white-space:nowrap;background:var(--tag-bg);color:var(--tag-ink);}
.chip.sm{height:18px;padding:0 8px;font-size:9.5px;}
.chip.lg{height:26px;padding:0 13px;font-size:12px;}
.chip.ok{color:var(--dchip-ok-ink);background:var(--ok-bg);}
.chip.review{color:var(--dchip-review-ink);background:var(--review-bg);}
.chip.due{color:var(--dchip-attn-ink);background:var(--attn-bg);}
.chip.rej{color:var(--dchip-rej-ink);background:var(--rej-bg);}
/* .mono for identifiers (an invoice number, a PO), .out for a neutral outline
   chip that must not claim a status colour. */
.chip.mono{font-family:var(--mono);font-weight:600;letter-spacing:.01em;}
.chip.out{background:transparent;color:var(--muted);border:1px solid var(--line-strong);}
.chip.accent{background:var(--accent-soft);color:var(--accent-ink);}
.chip button,.chip .x{border:none;background:none;cursor:pointer;color:inherit;font-size:11px;
  line-height:1;padding:0;opacity:.7;}
.chip button:hover,.chip .x:hover{opacity:1;}
/* A tag is not a status: no colour meaning, just a name (a job, a cost code). */
.tag{display:inline-flex;align-items:center;font-size:10.5px;font-weight:600;letter-spacing:.03em;
  padding:3px 8px;border-radius:20px;background:var(--tag-bg);color:var(--tag-ink);white-space:nowrap;}
.tag.mono{font-family:var(--mono);}

/* ===== the live process map (#/process) ================================= */
/* Every colour here is a token. A literal hex would read correctly in light
   mode and disappear in dark — the map is the one screen where that failure is
   total rather than cosmetic. */
.pm-intro{color:var(--muted);font-size:12.5px;max-width:860px;margin:2px 18px 10px;line-height:1.55;}
.pm-wrap{overflow-x:auto;padding:0 18px 6px;}
svg.procmap{min-width:1180px;width:100%;height:auto;font-family:var(--ui);}

.pm-edges path{fill:none;stroke:var(--faint);stroke-width:1.5;}
.pm-arrowhead{fill:var(--faint);}
.pm-edgelabels text{font-size:9.6px;font-weight:700;fill:var(--muted);}
.pm-reads path{fill:none;stroke:var(--accent);stroke-width:1.35;stroke-dasharray:5 4;opacity:.75;}
.pm-arrowhead-read{fill:var(--accent);}
.pm-readlabels text{font-size:9px;font-weight:600;fill:var(--accent-ink);}
.pm-write{fill:none;stroke:var(--ink);stroke-width:2.6;}
.pm-arrowhead-write{fill:var(--ink);}

.pm-node rect,.pm-node path{fill:var(--surface);stroke:var(--line-strong);stroke-width:1.5;}
.pm-node .pm-label{font-size:11px;font-weight:700;fill:var(--ink);}
.pm-node .pm-sub{font-size:9.4px;font-weight:600;fill:var(--muted);}
.pm-node .pm-dlabel{font-size:10.5px;font-weight:700;fill:var(--accent-ink);}
.pm-spine{stroke:var(--ink);stroke-width:1.6;fill:none;}

.pm-ai rect{stroke:var(--accent);stroke-width:1.6;}
.pm-aitag rect{fill:var(--accent);stroke:none;}
.pm-aitag text{font-size:8.5px;font-weight:800;fill:var(--onaccent);}
.pm-diamond-ai path{fill:var(--accent-soft);stroke:var(--accent);}
.pm-diamond-human path{fill:var(--tag-bg);stroke:var(--line-strong);}
.pm-diamond-human .pm-dlabel{fill:var(--ink);}
.pm-exception rect{stroke:var(--attn);stroke-width:2;}
.pm-terminal-write rect{stroke:var(--ink);stroke-width:2;}
.pm-terminal-hold rect{stroke:var(--line-strong);stroke-width:1.5;}
.pm-door rect{stroke:var(--line);}

/* A node with work waiting is emphasised — the map should answer "where is the
   work" before it answers "what is the process". */
.pm-node.hot rect,.pm-node.hot path{stroke-width:2.4;}
.pm-node.pm-click{cursor:pointer;}
.pm-node.pm-click:hover rect,.pm-node.pm-click:hover path{stroke:var(--accent-hover);}
.pm-node.pm-click:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}

.pm-badge rect{fill:var(--track-bg);stroke:none;}
.pm-badge text{font-size:11px;font-weight:800;fill:var(--muted);}
.pm-badge.hot rect{fill:var(--accent);}
.pm-badge.hot text{fill:var(--onaccent);}

.pm-store rect{fill:var(--bg);stroke:var(--line-strong);stroke-width:1.4;}
.pm-store.dashed rect{fill:var(--surface);stroke-dasharray:4 3;}
.pm-storecap{fill:var(--accent) !important;stroke:none !important;}
.pm-storelbl{font-size:11px;font-weight:700;fill:var(--ink);}
.pm-storesub{font-size:9.2px;font-weight:600;fill:var(--muted);}

.pm-legend{display:flex;flex-wrap:wrap;gap:16px;list-style:none;margin:6px 18px 14px;padding:0;
  font-size:11px;color:var(--muted);align-items:center;}
.pm-legend li{display:flex;align-items:center;gap:7px;}
.pm-legend li.wide{color:var(--faint);font-style:italic;}
.pm-legend .sw{width:18px;height:12px;display:inline-block;border-radius:3px;}
.pm-legend .sw.dia-ai{background:var(--accent-soft);border:1px solid var(--accent);}
.pm-legend .sw.dia-human{background:var(--tag-bg);border:1px solid var(--line-strong);}
.pm-legend .sw.exc{background:transparent;border:2px solid var(--attn);}
.pm-legend .sw.read{height:0;border-top:2px dashed var(--accent);border-radius:0;}
.pm-legend .sw.write{height:0;border-top:3px solid var(--ink);border-radius:0;}

.pm-tally{display:flex;flex-wrap:wrap;gap:8px;margin:0 18px 24px;}
.pm-tallyitem{display:flex;align-items:baseline;gap:7px;background:var(--surface);cursor:pointer;
  border:1px solid var(--line-strong);border-radius:9px;padding:7px 12px;font-size:12px;color:var(--ink);}
.pm-tallyitem:hover{border-color:var(--accent);}
.pm-tallyitem b{font-size:15px;font-weight:800;}
.pm-tallyitem i{font-style:normal;color:var(--muted);font-family:var(--mono);font-size:11px;}

/* ===== the invoice screen =============================================== */
.stagerail{display:flex;flex-wrap:wrap;gap:2px;list-style:none;margin:0 18px 12px;padding:0;}
.strail-step{font-size:10.5px;font-weight:700;padding:4px 12px 4px 16px;position:relative;
  background:var(--surface-2);color:var(--faint);clip-path:polygon(0 0,calc(100% - 8px) 0,100% 50%,calc(100% - 8px) 100%,0 100%,8px 50%);}
.strail-step.done{background:var(--ok-bg);color:var(--dchip-ok-ink);}
.strail-step.here{background:var(--accent);color:var(--onaccent);}
.strail-step.rej{background:var(--rej-bg);color:var(--dchip-rej-ink);}

.invsplit{display:grid;grid-template-columns:minmax(380px,46%) 1fr;gap:14px;padding:0 18px 90px;align-items:start;}
@media (max-width:1180px){.invsplit{grid-template-columns:1fr;}}
.invdoc{position:sticky;top:8px;height:min(78vh,860px);border:1px solid var(--line);border-radius:12px;
  overflow:hidden;background:var(--surface);}
.invdata{display:flex;flex-direction:column;gap:12px;min-width:0;}
.invdata .card{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:14px 16px;}
.invdata .card h3{font-family:var(--cond);font-size:14px;font-weight:700;margin-bottom:10px;
  display:flex;gap:8px;align-items:baseline;}

.fldrow{display:grid;grid-template-columns:150px 1fr auto;gap:10px;align-items:center;
  padding:6px 8px;border-radius:7px;font-size:12.5px;}
.fldrow.has-ev{cursor:pointer;}
.fldrow.has-ev:hover{background:var(--surface-2);}
.fldrow.lit{background:var(--flash-bg);}
.fldlbl{color:var(--muted);}
.fldval{font-weight:600;overflow-wrap:anywhere;}
.fldmeta{display:flex;gap:6px;align-items:center;}
.faint{color:var(--faint);}
.num{text-align:right;font-family:var(--mono);white-space:nowrap;}
.narrative{font-size:12.5px;line-height:1.6;color:var(--ink);margin-bottom:10px;}
.mutedbox{margin:0 18px 12px;padding:10px 14px;border-radius:9px;background:var(--surface-2);
  color:var(--muted);font-size:12.5px;}
.mutedbox.attn{background:var(--attn-bg);color:var(--dchip-attn-ink);}

table.wt.matchgrid td.diff{background:var(--attn-bg);color:var(--dchip-attn-ink);font-weight:700;}
table.wt.matchgrid td.desc{white-space:normal;max-width:280px;}

.exccard{border:1px solid var(--line);border-left:4px solid var(--attn);border-radius:9px;
  padding:10px 12px;margin-bottom:9px;font-size:12.5px;line-height:1.55;}
.exccard.sev-block{border-left-color:var(--rej);}
.exccard.sev-info{border-left-color:var(--ok);}
.exccard header{display:flex;gap:8px;align-items:center;margin-bottom:6px;}
.exccard .proposed{color:var(--muted);}
.exccard .excact{margin-top:8px;}

.blockbanner{display:flex;gap:14px;align-items:center;justify-content:space-between;
  margin:0 18px 12px;padding:11px 15px;border-radius:10px;
  background:var(--rej-bg);color:var(--dchip-rej-ink);font-size:12.5px;line-height:1.5;}

.dupcard{border:1px solid var(--line);border-radius:9px;padding:9px 12px;margin-bottom:8px;font-size:12.5px;}
.dupcard ul{margin:6px 0 0 18px;color:var(--muted);}
.approw{display:flex;gap:12px;align-items:center;padding:6px 2px;border-bottom:1px solid var(--line);font-size:12.5px;}
.approw:last-child{border-bottom:0;}

.actionbar{position:fixed;left:var(--side-w,0);right:0;bottom:0;display:flex;gap:9px;justify-content:flex-end;
  padding:11px 20px;background:var(--surface);border-top:1px solid var(--line);z-index:60;
  box-shadow:0 -6px 18px rgba(var(--shadow-rgb),.06);}

/* --- export preflight: what Sage will reject -------------------------------
   Grouped by field, because "9 descriptions are too long" is one decision a
   person makes once. Tokens only, like everything else here. */
.pfgroup {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 8px 10px;
  margin: 8px 0;
  background: var(--attn-bg);
}
.pfhead {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink);
  margin-bottom: 4px;
}
.pfcount {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  background: var(--attn);
  color: var(--bg);
  border-radius: 10px;
  padding: 0 7px;
  font-size: 11.5px;
}
.pfgroup ul {
  margin: 0;
  padding-left: 18px;
}
.pfgroup li {
  font-size: 12px;
  color: var(--muted);
  line-height: 1.5;
}
.pfnote {
  font-size: 12px;
  color: var(--muted);
  border-left: 2px solid var(--line);
  padding-left: 8px;
  margin-top: 10px;
}

/* ===== the keying surface (T1) ==========================================
   The editable header, the Sage side-by-side row, the confirm gate and the
   distributions editor on #/invoice/{id}. Tokens only, like everything else
   in this file — a literal hex here is a colour dark mode cannot reach. */

/* An editable header row is still a .fldrow; the input inside it borrows the
   .field input recipe at row scale. Money inputs are mono and right-aligned
   because a column of amounts is read as a column. */
.fldrow .fldwrap{display:flex;flex-direction:column;gap:3px;min-width:0;}
.fldin{border:1px solid var(--line-strong);border-radius:7px;padding:4px 8px;
  font-family:var(--ui);font-size:12.5px;color:var(--ink);background:var(--surface);
  width:100%;box-sizing:border-box;}
.fldin.mono{font-family:var(--mono);}
.fldin.money{font-family:var(--mono);text-align:right;}
.fldin:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 2px var(--accent-soft);}
.fldin[disabled],.fldin[readonly]{background:var(--surface-2);color:var(--muted);}
.fldrow.bad .fldin{border-color:var(--rej);}
.flderr{font-size:11px;font-weight:600;color:var(--rej);line-height:1.4;}
/* Provenance under a field: where the value came from (auto-fill basis, or
   "picked from page 2 — read 92% sure"). Never louder than the value. */
.fldnote{font-size:10.5px;color:var(--faint);line-height:1.4;}
.fldnote.cap{color:var(--accent-ink);}

/* The character counter (ui.js charCounter). States mirror the server. */
.charcount{font-family:var(--mono);font-size:10.5px;color:var(--faint);white-space:nowrap;}
.charcount.warn{color:var(--dchip-attn-ink);font-weight:700;}
.charcount.over{color:var(--rej);font-weight:700;}

/* "Read it again" affordance on a field the reader found no ink for. */
.rereadb{border:1px dashed var(--line-strong);background:transparent;color:var(--muted);
  border-radius:6px;padding:2px 7px;font-size:10px;font-family:var(--ui);cursor:pointer;white-space:nowrap;}
.rereadb:hover{border-color:var(--accent);color:var(--accent);}

/* The header-confirm gate. The problems list is red text beside the button;
   per-field problems land in each row's .flderr instead. */
.gatefoot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:10px;
  padding-top:10px;border-top:1px solid var(--line);}
.gateprobs{margin:8px 0 0;padding:0 0 0 18px;font-size:12px;color:var(--rej);line-height:1.55;}

/* The distributions editor. */
.balstrip{padding:7px 12px;border-radius:8px;font-size:12.5px;font-weight:700;
  font-family:var(--mono);}
.balstrip.bal-ok{background:var(--ok-bg);color:var(--dchip-ok-ink);}
.balstrip.bal-off{background:var(--rej-bg);color:var(--dchip-rej-ink);}
.distctl{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:10px;}
.distctl .splitn{width:52px;border:1px solid var(--line-strong);border-radius:7px;
  padding:4px 6px;font-family:var(--mono);font-size:12px;color:var(--ink);background:var(--surface);}
/* A picker cell renders as a button so it is honest about being a chooser,
   not a free-text field. Empty-but-expected ("left for the PM") is muted
   italic — a state, not an error. */
.distpick{border:1px solid var(--line-strong);background:var(--surface);color:var(--ink);
  border-radius:7px;padding:4px 8px;font-family:var(--mono);font-size:12px;cursor:pointer;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;}
.distpick:hover{border-color:var(--accent);}
.distpick:focus-visible{outline:2px solid var(--accent);outline-offset:1px;}
.distpick.empty{color:var(--faint);font-family:var(--ui);}
.distpick.pmleft{color:var(--muted);font-style:italic;font-family:var(--ui);}
.distpick[disabled]{opacity:.55;cursor:default;}
.distpick[disabled]:hover{border-color:var(--line-strong);}
.distbasis{font-size:10px;color:var(--faint);margin-top:2px;line-height:1.35;overflow-wrap:anywhere;}
.distamt{width:110px;}
.distdel{border:none;background:none;color:var(--faint);cursor:pointer;font-size:14px;
  padding:2px 6px;border-radius:6px;}
.distdel:hover{color:var(--rej);background:var(--rej-bg);}
.distdel[disabled]{opacity:.4;cursor:default;}
/* Collapsed state of the card while the header is unconfirmed. */
.distlock{padding:14px 4px;color:var(--muted);font-size:12.5px;line-height:1.6;}

/* The D5 description suggestion chip — clickable, visibly a proposal. */
.suggchip{cursor:pointer;border:1px dashed var(--accent);background:var(--accent-soft);
  color:var(--accent-ink);border-radius:11px;padding:1px 10px;font-size:10.5px;font-weight:700;
  font-family:var(--mono);}
.suggchip:hover{border-style:solid;}

/* Prev/next through the filtered inbox set, in the viewbar. */
.prevnext{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted);}
.prevnext .pnpos{font-family:var(--mono);white-space:nowrap;}
/* A single input refused by the server, outside a .fldrow (distribution
   amounts): the same red border, same meaning — the keystrokes stay. */
.fldin.bad{border-color:var(--rej);}

/* ===== the flow layer (T2) ==============================================
   Rejection banner, Workflow card, History/Notes cards, the mark-up layer.
   Tokens only — same rule as everything above. */

/* The rejection banner: the FIRST thing above the fold on a rejected
   invoice. Same red family as .blockbanner, but it carries the round's
   reason verbatim and the way back — it is a to-do, not just a stop. */
.rejbanner{background:var(--rej-bg);border:1px solid var(--rej);border-radius:10px;
  padding:13px 16px;margin-bottom:14px;font-size:12.5px;line-height:1.55;}
.rejbanner .rbhead{display:flex;align-items:center;gap:9px;flex-wrap:wrap;}
.rejbanner .rbhead b{color:var(--dchip-rej-ink);font-size:13px;}
.rejbanner .rbwhen{color:var(--muted);font-size:11.5px;}
/* The reason is the payload — quoted, larger than the chrome around it. */
.rejbanner .rbreason{margin-top:7px;font-size:13.5px;font-weight:600;color:var(--ink);
  overflow-wrap:anywhere;}
.rejbanner .rbwhat{margin-top:6px;color:var(--muted);font-size:12px;}
.rejbanner .rbbtns{margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;}

/* The Workflow card: the resolved route and the submit that explains itself. */
.wfcard{border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--surface);}
.wfcard .wfname{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px;color:var(--ink);}
.wfcard .wfdesc{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.5;}
.wfcard .wfsteps{margin-top:8px;display:flex;flex-direction:column;gap:4px;}
.wfcard .wfstep{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink);flex-wrap:wrap;}
/* The step number wears the quiet tag recipe, not a status colour — order is
   a fact, not a verdict. */
.wfcard .wfstep b{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;
  border-radius:50%;background:var(--tag-bg);color:var(--tag-ink);font-size:10.5px;flex:none;}
.wfcard .wfsubmit{margin-top:11px;padding-top:11px;border-top:1px solid var(--line);}
.wfcard .wfsubrow{display:flex;align-items:center;gap:9px;flex-wrap:wrap;}
/* The named reasons a grey submit stands on. Red text, list form — each line
   is one thing a person can go fix, not one grey mystery. */
.wfcard .wfreasons{margin:8px 0 0;padding:0 0 0 18px;font-size:12px;color:var(--rej);line-height:1.6;}
.wfcard .wfskip{margin-top:11px;padding-top:11px;border-top:1px solid var(--line);
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;}

/* History / Notes (T6): popover-cards anchored to the DOCUMENT toolbar's
   `Notes (n)` / `History` buttons — hh2's placement. Rendered into the
   shared #popover host; the timeline (.tl*) and note (.note*) recipes below
   are unchanged, this is only the card around them. */
.flowpop{min-width:320px;max-width:400px;max-height:min(60vh,520px);overflow:auto;
  display:flex;flex-direction:column;}
.flowpop .fphead{display:flex;align-items:baseline;gap:7px;padding:2px 2px 8px;
  border-bottom:1px solid var(--line);font-family:var(--cond);font-size:14px;font-weight:700;
  color:var(--ink);}
.flowpop .fpcount{font-family:var(--mono);font-size:11px;font-weight:400;color:var(--muted);}
.flowpop .fpbody{padding:2px 2px 4px;min-height:0;}
.flowpop .fcempty{font-size:12.5px;color:var(--muted);margin:9px 0 2px;line-height:1.55;}

/* The timeline rows. */
.tllist{display:flex;flex-direction:column;}
.tlround{font-family:var(--cond);font-size:11.5px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted);margin:10px 0 3px;padding-bottom:3px;
  border-bottom:1px solid var(--line);}
.tlrow{display:grid;grid-template-columns:118px 1fr;gap:10px;padding:6px 0;
  border-bottom:1px solid var(--line);font-size:12.5px;align-items:baseline;}
.tlrow:last-child{border-bottom:none;}
.tlts{font-family:var(--mono);font-size:10.5px;color:var(--faint);white-space:nowrap;}
.tlmain{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap;min-width:0;}
.tlwho{font-size:12px;color:var(--ink);}
.tlsum{color:var(--ink);overflow-wrap:anywhere;}
.tldet{flex-basis:100%;font-size:11.5px;color:var(--muted);overflow-wrap:anywhere;}

/* Notes. */
.noterow{padding:8px 0;border-bottom:1px solid var(--line);font-size:12.5px;}
.noterow .notehead{display:flex;align-items:baseline;gap:8px;margin-bottom:3px;}
.noterow .notehead b{font-size:12px;color:var(--ink);}
.noterow .notehead span{font-size:10.5px;color:var(--faint);font-family:var(--mono);}
.noterow .notebody{line-height:1.55;overflow-wrap:anywhere;}
.noteadd{margin-top:10px;}
.noteadd textarea{width:100%;border:1px solid var(--line-strong);border-radius:8px;padding:8px 10px;
  font-size:12.5px;font-family:var(--ui);color:var(--ink);background:var(--surface);resize:vertical;
  min-height:44px;line-height:1.5;}
.noteadd textarea:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 2px var(--accent-soft);}
.noteaddrow{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:6px;}

/* The mark-up toggle moved into the document toolbar (T6) — its button and
   badge recipes live in viewer.css (.dtool family). The annotation layer,
   marks and tool chrome remain viewer.css §annotation (.antlayer et al),
   owned by the viewer/annotate pair; nothing here may restyle them. */

/* ===== T6 · hh2 keying conformance (invoice header + distributions) ===== */

/* The 'More fields' fold under hh2's eight header rows: a quiet full-width
   row, visibly a fold and not a field. Remembered per person (localStorage —
   invoice.js MORE_PREF). */
.morefold{display:flex;align-items:center;gap:7px;width:100%;border:none;background:none;
  cursor:pointer;padding:7px 8px;margin-top:2px;border-radius:7px;text-align:left;
  font-family:var(--ui);font-size:11.5px;font-weight:700;letter-spacing:.02em;color:var(--muted);}
.morefold:hover{background:var(--surface-2);color:var(--ink);}
.morefold:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}
.morefold .mfchev{color:var(--faint);font-size:10px;flex:none;}
.morefold .mfsub{font-weight:400;color:var(--faint);font-size:10.5px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;}
[data-morefields]{border-left:2px solid var(--line);margin-left:4px;padding-left:4px;}
[data-morefields][hidden]{display:none;}

/* Read-only cells in the distributions grid — the Commitment / Comm. Item
   pair, read off the posting linkage, deliberately NOT buttons: the PO leg
   is changed by attaching/detaching the PO, never typed in the grid. */
.distro{font-family:var(--mono);font-size:12px;color:var(--ink);white-space:nowrap;}
.distro.none{color:var(--faint);font-family:var(--ui);}

/* ===== the shared #popover host + the picker inside it ==================
   The single anchored-popover slot ui.js placePopover/openPicker position
   with inline left/top — which only mean something on a fixed-position box.
   z-index sits above the maximized viewer (#viewerbig at 70 — Notes opens
   from the document toolbar in full screen too) and below the modal (90). */
#popover{position:fixed;left:0;top:0;z-index:80;background:var(--surface);
  border:1px solid var(--line-strong);border-radius:10px;padding:8px;
  box-shadow:0 12px 40px rgba(var(--shadow-rgb),.28);max-width:min(420px,94vw);}
#popover[hidden]{display:none;}
/* openPicker's search box + result list. */
#popover .pin{width:100%;border:1px solid var(--line-strong);border-radius:7px;
  padding:6px 9px;font-family:var(--ui);font-size:12.5px;color:var(--ink);
  background:var(--surface);outline:none;box-sizing:border-box;}
#popover .pin:focus{border-color:var(--accent);}
#popover .plist{list-style:none;margin:6px 0 0;padding:0;min-width:240px;
  max-height:min(46vh,340px);overflow:auto;}
#popover .pitem{display:flex;flex-direction:column;gap:1px;padding:6px 8px;border-radius:6px;
  cursor:pointer;font-size:12.5px;color:var(--ink);}
#popover .pitem b{font-weight:600;}
#popover .pitem span{font-size:10.5px;color:var(--muted);}
#popover .pitem:hover{background:var(--accent-soft);}
#popover .pitem.danger{color:var(--rej);}
#popover .pitem.pfree b{color:var(--accent-ink);}
#popover .pnone{padding:8px;font-size:12px;color:var(--muted);}

/* =====================================================================
   T3 · register + export surfaces (inbox pinned views, chips, thumbnails,
   line-item search, batch pre-export cards, D10 banner). Token-only.
   ===================================================================== */

/* Pinned working views — the 6-click hh2 filter dialog collapsed to one
   click. A row of quiet links above the filter bar; the active view is the
   one the hash already says, so "on" is a fact, not a toggle state. */
.pinrow{display:flex;align-items:center;gap:7px;flex-wrap:wrap;padding:9px 0 2px;}
.pinview{display:inline-flex;align-items:center;font-size:12px;font-weight:600;color:var(--muted);
  text-decoration:none;border:1px solid var(--line-strong);border-radius:999px;padding:4px 12px;
  background:var(--surface);}
.pinview:hover{color:var(--ink);border-color:var(--accent);}
.pinview.on{color:var(--accent-ink,var(--accent));border-color:var(--accent);background:var(--accent-soft);}
.pinview:focus-visible{outline:2px solid var(--accent);outline-offset:1px;}
.pinsep{width:1px;align-self:stretch;background:var(--line-strong);margin:2px 3px;}
.savedchip .fchip{text-decoration:none;}

/* Sortable table headers (ui.js table() sortable option). The button fills
   the th so the whole header is the target, exactly like the inbox's own
   headers were. */
.thsort{background:none;border:0;padding:0;font:inherit;font-weight:inherit;color:inherit;
  cursor:pointer;white-space:nowrap;}
.thsort:hover{color:var(--accent);}
.thsort:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-radius:3px;}
.tsarrow{color:var(--faint);font-size:10px;}
th[aria-sort="ascending"] .tsarrow,th[aria-sort="descending"] .tsarrow{color:var(--accent);}

/* Queue rows: the page-1 thumbnail (recognise-the-paper), the selected
   tint, and the red left edge on rejected-and-mine — hh2's red-bordered
   card, kept as a row treatment so it survives the denser grid. */
.rowthumb{display:block;width:34px;height:44px;object-fit:cover;object-position:top;
  border:1px solid var(--line);border-radius:4px;background:var(--surface-2);}
tr.selrow td{background:var(--accent-soft);}
tr.rowrej td{background:var(--rej-bg);}
tr.rowrej td:first-child{box-shadow:inset 3px 0 0 var(--rej);}

/* The result-count line — above and below the grid, hh2's own honest
   affordance ("50+ Results…"), plus our truncation sentence. */
.countline{color:var(--muted);font-size:12.5px;}

/* Line-item search results. The <mark> is the point of the screen: WHICH
   line hit, not just that some invoice did. */
.searchhit{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:12px 15px;margin-bottom:10px;}
.searchhithead{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:7px;}
.sniplist{margin:0;padding:0 0 0 18px;}
.snip{font-size:12.5px;line-height:1.55;color:var(--ink);overflow-wrap:anywhere;}
.snip mark{background:var(--attn-bg);color:var(--dchip-attn-ink,var(--ink));font-weight:700;
  border-radius:3px;padding:0 2px;}

/* The D10 do-not-import banner. Red and unmissable by decision: export is
   permitted while TEMPLATE_CONFIRMED is false, importing the file is not. */
.d10banner{background:var(--rej-bg);border:1px solid var(--rej);border-left:4px solid var(--rej);
  border-radius:10px;padding:12px 15px;margin-bottom:14px;font-size:12.5px;color:var(--ink);}
.d10banner b{display:block;color:var(--rej);font-size:13px;letter-spacing:.01em;margin-bottom:3px;
  text-transform:uppercase;}

/* Pre-export cards — the final-review checklist as a surface: approved by
   whom · amount · coding · tax · backup pages, then the thumbnails and the
   coding table. */
.precard{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:13px 15px;margin-bottom:12px;}
.prehead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:7px;}
.prechecks{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:9px;}
.thumbstrip{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:9px;}
.thumbstrip .ptn{display:block;width:56px;height:72px;object-fit:cover;object-position:top;
  border:1px solid var(--line-strong);border-radius:5px;background:var(--surface-2);}
.thumbstrip a:hover .ptn{border-color:var(--accent);}
.ptnmore{font-size:11px;color:var(--muted);}

/* Preflight report: blocking and advisory kept visibly apart. */
.pfsection{margin-top:10px;}
.pfsecthead{font-family:var(--cond);font-size:12px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);margin-bottom:5px;}
.pfblocking .pfsecthead{color:var(--rej);}
.pfgroup.blocking{border-left:3px solid var(--rej);padding-left:9px;}

/* Small copy affordance beside a sha/path. */
.copybtn{font-size:10.5px;padding:1px 7px;vertical-align:baseline;}

/* =====================================================================
   T4 — intelligence & tax: the notifications bell, the notification menu,
   and the shared modal-form vocabulary the agreements/tax dialogs use.
   Tokens only, as everywhere in this file. */

/* The bell — wide sidebar. Sits in the .foot with the identity controls: it
   is chrome about ME (my notifications), not navigation. */
.bellbtn{display:flex;align-items:center;gap:10px;width:100%;padding:7px 8px;border-radius:9px;
  border:none;background:transparent;cursor:pointer;text-align:left;
  color:var(--ondark-2);font-family:var(--ui);font-size:12.5px;font-weight:600;}
.bellbtn:hover{background:rgba(255,255,255,.06);color:var(--ondark-hover);}
.bellbtn:focus-visible{outline:2px solid var(--ondark-hover);outline-offset:-2px;}
.bellbtn .ic{width:17px;height:17px;flex:none;stroke:currentColor;fill:none;stroke-width:1.9;}
.bellbtn>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;}
.bellbtn .navbadge{margin-left:auto;}

/* The bell — rail. .ricon is written for divs; as a button it needs its
   default chrome stripped or it renders a grey pill in the rail. */
.rail .bellricon{border:none;background:transparent;font-family:var(--ui);}
.rail .bellricon:hover{background:rgba(255,255,255,.06);}

/* The notification menu, in the shared #popover host. */
.notifmenu{display:flex;flex-direction:column;min-width:300px;max-width:360px;max-height:70vh;overflow:auto;}
.notifmenu .nmhead{display:flex;align-items:baseline;gap:10px;padding:7px 9px 8px;
  border-bottom:1px solid var(--line);margin-bottom:3px;}
.notifmenu .nmhead b{font-size:12.5px;color:var(--ink);}
.notifmenu .nmall{margin-left:auto;border:none;background:none;cursor:pointer;font-family:var(--ui);
  font-size:11px;color:var(--accent-ink);padding:2px 4px;border-radius:5px;}
.notifmenu .nmall:hover{background:var(--accent-soft);}
.notifmenu .nmempty{padding:14px 12px;font-size:12px;color:var(--muted);line-height:1.5;max-width:300px;}
.nmrow{display:flex;gap:9px;align-items:flex-start;border:none;background:none;cursor:pointer;
  text-align:left;padding:8px 9px;border-radius:8px;font-family:var(--ui);}
.nmrow:hover{background:var(--accent-soft);}
.nmrow:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;}
.nmrow .nmdot{width:7px;height:7px;border-radius:50%;background:transparent;flex:none;margin-top:5px;}
.nmrow.unread .nmdot{background:var(--accent);}
.nmrow .nmbody{display:flex;flex-direction:column;gap:2px;min-width:0;}
.nmrow .nmmsg{font-size:12.5px;color:var(--ink);line-height:1.4;}
.nmrow.unread .nmmsg{font-weight:600;}
.nmrow .nmwhen{font-size:10.5px;color:var(--muted);}

/* The T4 modal forms (lock-in-a-quote, certificate upload) — the same .f /
   .fh / .c vocabulary the settings route editor uses, hoisted here so two
   screens do not carry two private copies. */
.agform{display:flex;flex-direction:column;gap:11px;margin-top:12px;}
.agform label.f{display:flex;flex-direction:column;gap:3px;font-size:12.5px;}
.agform label.f>span{font-weight:600;}
.agform input[type=text],.agform input[type=number],.agform input[type=date],
.agform input[type=file],.agform select,.agform textarea{font:inherit;font-size:13px;color:var(--ink);
  background:var(--surface);border:1px solid var(--line-strong);border-radius:8px;padding:6px 9px;
  box-sizing:border-box;width:100%;}
.agform .fh{font-size:11px;color:var(--muted);line-height:1.45;font-weight:400;}
.agform label.c{display:flex;gap:8px;align-items:flex-start;font-size:12.5px;}

/* The BASE modal family from the build-contract vocabulary (§4 F names
   .modal + .mrow/.msub/.mbtns/.mwarn), which until now existed only as
   per-screen :has() copies — leaving ui.js confirmDialog (no variant class)
   rendering as an unstyled div in document flow. One base recipe here; the
   per-screen variants keep their own overrides at equal-or-higher
   specificity, so nothing they styled moves. */
#modalwrap:not([hidden]){position:fixed;inset:0;z-index:90;display:flex;align-items:center;
  justify-content:center;padding:16px;background:rgba(var(--shadow-rgb),.45);}
#modalwrap[hidden]{display:none !important;}
.modal{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 18px 60px rgba(var(--shadow-rgb),.35);width:min(520px,94vw);max-height:92vh;
  overflow:auto;padding:16px 18px;color:var(--ink);}
.modal.wide{width:min(660px,94vw);}
.modal h3{margin:0 0 2px;font-size:16px;}
.modal .msub{color:var(--muted);font-size:12.5px;line-height:1.5;}
.modal .mconf{font-size:13px;margin:8px 0;line-height:1.5;}
.modal .mwarn{font-size:12.5px;color:var(--ink);background:var(--attn-bg);
  border:1px solid var(--attn-border);border-radius:8px;padding:7px 9px;margin:8px 0;}
.modal .mbtns{display:flex;gap:8px;align-items:center;justify-content:flex-end;margin-top:12px;
  padding-top:10px;border-top:1px solid var(--line);}
.modal .mnote{display:flex;flex-direction:column;gap:3px;font-size:12.5px;margin:8px 0;}
.modal .mnote textarea{font:inherit;font-size:13px;color:var(--ink);background:var(--surface);
  border:1px solid var(--line-strong);border-radius:8px;padding:7px;}
.modal .mnote .help{font-size:11px;color:var(--muted);font-style:normal;}

/* The T4 dialogs' own box (agreements / certificates / vendor links). */
#modalwrap:has(.agmodal){position:fixed;inset:0;z-index:90;display:flex;align-items:center;
  justify-content:center;padding:16px;background:rgba(var(--shadow-rgb),.45);}
.modal.agmodal{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 18px 60px rgba(var(--shadow-rgb),.35);width:min(560px,94vw);max-height:92vh;
  overflow:auto;padding:16px 18px;color:var(--ink);}
.modal.agmodal.wide{width:min(660px,94vw);}
.agmodal h3{margin:0 0 2px;font-size:16px;}
.agmodal .msub{color:var(--muted);font-size:12.5px;line-height:1.5;}
.agmodal .mbtns{display:flex;gap:8px;align-items:center;margin-top:12px;padding-top:10px;
  border-top:1px solid var(--line);}

/* The drilled-open history row under an item / a job's certificates. */
tr.itemhist>td{border-top:none;}
