/* GENERATED — do not edit by hand. Source: invoiceTest/src/styles.css + styles-owner.css,
   scoped to body.vt by scripts/build-vt-css.mjs (owner 2026-09-05: transplanted tenant screens
   identical to invoiceTest). Edit the invoiceTest sheets, then re-run the script. */

/* ── from src/styles.css ── */
body.vt{
  color-scheme: dark;
  --bg:#0c2429; --surface:#15414a; --surface-2:#123840; --panel:#0e2e33;
  --ink:#eaf3f2; --muted:#8fb1b0; --faint:#5f8b8a;
  --line:#2e575e; --line-soft:#22434b;
  --brand:#2ae0e0; --brand-ink:#08252b;
  /* SEMANTIC COLOUR LADDER (owner 2026-07-29: "green is good, yellow warning, red bad").
     --ok    good / settled / healthy  · --warn escalating attention · --warn-2 worse · --bad bad.
     Anything INERT (draft, void, converted, a role, a contact type) stays neutral grey and takes
     NO ladder colour — colour here means a judgement, so a neutral fact must not borrow one.
     --info/--violet are NOT status colours; keep them off pills. */
  --ok:#4bd6a0; --warn:#e6b45a; --warn-2:#e08a4a; --bad:#f27a7a; --info:#63bcd8; --violet:#a99be0;
  --neutral:#cfe0df; --neutral-bg:rgba(143,177,176,.16);
  --radius:12px; --radius-sm:8px;
  --sans:"Sora","Segoe UI",system-ui,-apple-system,Roboto,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}

/* LIGHT THEME (UI-standards audit 2026-08-07 — Xero/QBO/Zoho are light-default; dark stays OUR
   default, this is the ☀/🌙 toggle's other half). Same variable contract as :root; WCAG-checked:
   ink 12+:1 on bg, muted ≥5:1, brand-as-text ≥4.5:1, brand button 4.7:1. The invoice paper is
   deliberately theme-independent (always white). Flip the default by shipping data-theme="light". */
html[data-theme="light"] body.vt{
  color-scheme: light;
  --bg:#edf3f3; --surface:#ffffff; --surface-2:#f3f8f8; --panel:#e4eeee;
  --ink:#10282c; --muted:#4e7373; --faint:#4e7175;
  --line:#c2d6d7; --line-soft:#d4e2e3;
  --brand:#0a7f7f; --brand-ink:#ffffff;
  --ok:#157a56; --warn:#92651a; --warn-2:#9d5218; --bad:#bb3f3f; --info:#1d6f86; --violet:#6353ad;
  --neutral:#3d5c60; --neutral-bg:rgba(64,96,100,.14);
}

html[data-theme="light"] body.vt .alert{color:#a12c28}
                        /* was hardcoded pale-red for dark */
html[data-theme="light"] body.vt thead th{background:rgba(0,0,0,.05)}
        /* dark 20% overlay is too heavy on white */
html[data-theme="light"] body.vt table.list tr.clickable:hover td{background:rgba(10,127,127,.07)}

html[data-theme="light"] body.vt .ss-opt.sel:not(.active){background:rgba(10,127,127,.12)}


body.vt *{box-sizing:border-box}

body.vt{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.5;-webkit-font-smoothing:antialiased;font-size:14.5px}

body.vt h1,
body.vt h3{margin:0;text-wrap:balance}

body.vt code,
body.vt .mono{font-family:var(--mono)}

body.vt .num{font-variant-numeric:tabular-nums}

body.vt .ta-r{text-align:right}

body.vt .muted{color:var(--muted)}

body.vt .eyebrow{font-size:10.5px;text-transform:uppercase;letter-spacing:.15em;color:var(--faint);font-weight:700}


/* topbar */
body.vt .topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 22px;flex-wrap:wrap;
  background:var(--panel);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:10}


/* simulated role switcher (demo lens, not real auth) */
body.vt .role-switch{display:flex;align-items:center;gap:8px}

body.vt .role-pill{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;padding:3px 9px;border-radius:999px}

body.vt .role-pill.role-admin{color:var(--brand-ink);background:var(--brand)}

body.vt .role-pill.role-employee{color:var(--neutral);background:var(--neutral-bg)}

body.vt .role-select{width:auto;font-size:12.5px;padding:6px 8px}

body.vt .brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:18px;letter-spacing:-.01em}

body.vt .brand .dot{width:13px;height:13px;border-radius:50%;background:var(--brand);box-shadow:0 0 0 4px rgba(42,224,224,.15),0 0 12px rgba(42,224,224,.45)}

body.vt .brand .sub{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.14em;color:var(--brand);opacity:.85;margin-left:4px}


/* buttons */
body.vt .btn{font-family:inherit;font-size:13.5px;font-weight:650;border-radius:var(--radius-sm);padding:8px 14px;
  border:1px solid var(--line);background:var(--surface);color:var(--ink);cursor:pointer;white-space:nowrap}

body.vt .btn:hover{border-color:var(--brand)}

body.vt .btn.primary{background:var(--brand);border-color:var(--brand);color:var(--brand-ink);box-shadow:0 3px 12px rgba(42,224,224,.22)}

body.vt .btn.ghost{background:transparent}

body.vt .btn.sm{padding:4px 9px;font-size:12px;margin-left:6px}

body.vt .btn.bad{border-color:var(--bad);color:var(--bad)}

body.vt .row-actions{display:flex;gap:9px;flex-wrap:wrap}

body.vt .nowrap{white-space:nowrap}

body.vt .form-err{color:var(--bad);font-size:12.5px}


/* page scaffold */
body.vt .page{max-width:1000px;margin:0 auto;padding:26px 22px 80px}

body.vt .page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px;flex-wrap:wrap}

body.vt .page-head h1{font-size:24px;font-weight:800;letter-spacing:-.02em;margin-top:3px}

body.vt .empty{color:var(--muted);text-align:center;padding:60px 0;border:1px dashed var(--line);border-radius:var(--radius)}

body.vt .empty b{color:var(--brand)}

body.vt h3{font-size:14px;font-weight:700;margin:22px 0 9px;display:flex;align-items:baseline;gap:8px}

body.vt h3 small{color:var(--faint);font-weight:400;font-size:11.5px}


/* tables */
body.vt .tbl-wrap{overflow-x:auto;border:1px solid var(--line-soft);border-radius:var(--radius-sm)}

body.vt table{width:100%;border-collapse:collapse;font-size:13.5px}

body.vt thead th{font-size:10.5px;text-transform:uppercase;letter-spacing:.09em;color:var(--faint);font-weight:700;text-align:left;
  padding:10px 13px;background:rgba(0,0,0,.2);border-bottom:1px solid var(--line-soft)}

body.vt tbody td{padding:10px 13px;border-bottom:1px solid var(--line-soft);vertical-align:middle}

body.vt tbody tr:last-child td{border-bottom:none}

body.vt table.list tr.clickable{cursor:pointer}

body.vt table.list tr.clickable:hover td{background:rgba(42,224,224,.06)}

body.vt .c-check{width:36px;text-align:center}

body.vt .cell-sub{display:block;color:var(--faint);font-size:11px}

body.vt .bulk-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;padding:8px 12px;border:1px solid var(--brand);border-radius:var(--radius-sm);background:rgba(42,224,224,.08)}

body.vt .bulk-bar .btn.sm{margin-left:0}


/* unified Billing tab bar (Invoices / Estimates / Claims) */
body.vt .billing-tabbar{max-width:1000px;margin:0 auto;padding:16px 22px 0}

body.vt .billing-tabbar .seg{font-size:13px;padding:7px 16px}

body.vt .billing-tabbar.sub{padding-top:8px}

body.vt .billing-umbrellas{max-width:1000px;margin:0 auto;padding:16px 22px 0}

body.vt .billing-umbrellas .seg{font-size:13.5px;font-weight:800;padding:8px 22px}

/* quick-create card (Claims-style form above the grid) */
body.vt .qc{border-color:var(--brand)}

body.vt .qc-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}

body.vt .qc-row .ss{min-width:240px;flex:0 1 auto}


/* list toolbar: search + status tabs + sortable headers + pager */
body.vt .list-toolbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:14px}

body.vt .search{max-width:300px}

body.vt .segs{display:flex;gap:5px;flex-wrap:wrap}

body.vt .seg{font-family:inherit;font-size:12.5px;font-weight:650;border:1px solid var(--line);background:var(--surface);color:var(--muted);border-radius:999px;padding:5px 12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}

body.vt .seg:hover{border-color:var(--brand)}

body.vt .seg.on{background:var(--brand);border-color:var(--brand);color:var(--brand-ink)}

body.vt .seg-n{font-size:11px;opacity:.8;font-variant-numeric:tabular-nums}

body.vt .subtabs{margin:0 0 16px}
   /* in-screen tab bar spacing (Products & services: Items | Categories) */
body.vt th.srt{cursor:pointer;user-select:none;white-space:nowrap}

body.vt th.srt:hover{color:var(--brand)}

body.vt .pager{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:14px;flex-wrap:wrap}

body.vt .pager-info{font-size:12.5px;color:var(--muted)}

body.vt .pager-per{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12.5px}

body.vt .pager-per select{font-family:inherit;font-size:12.5px;padding:4px 6px;background:var(--surface);color:var(--ink);
  border:1px solid var(--line);border-radius:6px}


/* app-bar global search (desktop chrome — mobile deferred, owner 2026-08-07) */
body.vt .global-search .ss{width:280px}

body.vt .theme-toggle{padding:8px 10px}

@media (max-width:760px){
body.vt .global-search{display:none}
}


/* editor validation banner — sits under the page-head, at the click point (audit 2026-08-07) */
body.vt .editor-alert{margin-bottom:14px}


/* ── UX deep-search round (2026-08-07) ─────────────────────────────────────────────────────────── */
/* action feedback (finding E): transient notices, bottom-centre, above everything */
body.vt .notice-stack{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:10000;display:flex;
  flex-direction:column;align-items:center;gap:8px;pointer-events:none;max-width:min(92vw,560px)}

body.vt .app-notice{padding:10px 16px;border-radius:10px;font-size:13.5px;font-weight:600;border:1px solid;
  background:var(--panel);box-shadow:0 6px 24px rgba(0,0,0,.35);animation:noticeIn .18s ease-out}

body.vt .app-notice.is-ok{color:var(--ok);border-color:var(--ok)}

body.vt .app-notice.is-bad{color:var(--bad);border-color:var(--bad)}

body.vt .app-notice.is-info{color:var(--info);border-color:var(--info)}

body.vt .app-notice.is-leaving{opacity:0;transition:opacity .3s ease}

@keyframes noticeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

html[data-theme="light"] body.vt .app-notice{box-shadow:0 6px 24px rgba(16,40,44,.18)}


/* the saved row flashes so you never hunt for it after Save (finding E / parent-repo flashRow) */
@keyframes rowFlash{from{background:rgba(42,224,224,.28)}to{background:transparent}}

body.vt tr.row-hl td{animation:rowFlash 1.8s ease-out}

html[data-theme="light"] body.vt tr.row-hl td{animation-name:rowFlashLight}

@keyframes rowFlashLight{from{background:rgba(10,127,127,.22)}to{background:transparent}}


/* unsaved-changes bar in the editor (finding A). The [hidden] rule is LOAD-BEARING: display:flex
   on the class beats the UA's [hidden]{display:none}, so without it the bar shows on every editor
   from mount and "Keep editing" looks dead (owner hit exactly this, 2026-08-07). */
body.vt .leave-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px;padding:10px 14px;
  border:1px solid var(--warn);border-radius:var(--radius-sm);background:rgba(230,180,90,.12);color:var(--warn);font-size:13.5px;font-weight:600}

body.vt .leave-bar[hidden]{display:none}

body.vt .leave-bar .btn.sm{margin-left:0}


/* keyboard users get their caret back (finding K) */
body.vt .btn:focus-visible,
body.vt [role="button"]:focus-visible,
body.vt .nav-item:focus-visible,
body.vt summary:focus-visible{
  outline:2px solid var(--brand);outline-offset:2px}


/* per-row line actions in the editor (finding H) */
body.vt button.x.dup{margin-right:2px}


/* bulk print batch — hidden on screen; only it prints */
body.vt .print-batch{display:none}

@media print{

  body.vt.printing-batch #app{display:none !important}

  body.vt.printing-batch .print-batch{display:block}

  body.vt .print-page{page-break-after:always}

  body.vt .print-page:last-child{page-break-after:auto}

}


/* pills */
body.vt .pill{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;padding:3px 9px;border-radius:999px;display:inline-flex;align-items:center;gap:6px}

body.vt .pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}

body.vt .pill-draft{color:var(--neutral);background:var(--neutral-bg)}
                 /* inert: not issued yet */
body.vt .pill-due{color:var(--warn);background:rgba(230,180,90,.15)}
                   /* waiting on payment */
body.vt .pill-partial{color:var(--warn);background:rgba(230,180,90,.15)}
               /* part paid, still owed */
body.vt .pill-overdue{color:var(--bad);background:rgba(242,122,122,.15)}

body.vt .pill-paid{color:var(--ok);background:rgba(75,214,160,.15)}

body.vt .pill-credited{color:var(--neutral);background:var(--neutral-bg)}
              /* settled by credit — inert */
body.vt .pill-void{color:var(--faint);background:rgba(95,139,138,.15)}

body.vt .pill-written_off{color:var(--bad);background:rgba(242,122,122,.15)}
           /* a loss — bad */

/* editor form */
body.vt .grid2{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:18px}

body.vt .fld{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--muted)}

body.vt .fld>span{font-size:10.5px;text-transform:uppercase;letter-spacing:.11em;color:var(--faint);font-weight:700}

body.vt .fld.inline{flex-direction:row;align-items:center;gap:8px}

body.vt .fld.inline>span{white-space:nowrap}

body.vt input,
body.vt select,
body.vt textarea{font-family:inherit;font-size:13.5px;color:var(--ink);background:var(--surface-2);
  border:1px solid var(--line);border-radius:7px;padding:8px 10px;width:100%}

/* Uniform field-control height so a row of fields lines up cleanly regardless of control type — a
   text input, a native date input and the search-selector otherwise render at 36/38/… px (owner
   2026-08-28: "text is not aligned"). Textareas keep their own multi-line height. */
body.vt .fld>input:not([type=checkbox]),
body.vt .fld>select,
body.vt .fld .ss-input,
body.vt .fld .fixed-val{box-sizing:border-box;height:38px}

body.vt input:focus,
body.vt select:focus,
body.vt textarea:focus{outline:2px solid rgba(42,224,224,.5);outline-offset:-1px;border-color:var(--brand)}

body.vt textarea{resize:vertical}

body.vt input.is-invalid,
body.vt select.is-invalid,
body.vt textarea.is-invalid{border-color:var(--bad);background:rgba(242,122,122,.08)}

body.vt .req{color:var(--bad)}


/* search-selector — the single control that replaces every native <select>/<datalist>.
   Popup (.ss-list) is fixed-position on <body> so it never clips inside a .tbl-wrap table. */
body.vt .ss{position:relative;display:block}

body.vt .ss-input{width:100%;cursor:text}

body.vt .ss-list{position:fixed;z-index:9999;margin:0;padding:4px;list-style:none;max-height:264px;overflow-y:auto;
  background:var(--surface);border:1px solid var(--brand);border-radius:var(--radius-sm);box-shadow:0 12px 34px rgba(0,0,0,.5)}

body.vt .ss-opt{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:7px 10px;border-radius:6px;
  font-size:13.5px;color:var(--ink);cursor:pointer;white-space:nowrap}

body.vt .ss-opt .ss-sub{color:var(--faint);font-size:11.5px;font-variant-numeric:tabular-nums}

body.vt .ss-opt.active{background:var(--brand);color:var(--brand-ink)}

body.vt .ss-opt.active .ss-sub{color:var(--brand-ink);opacity:.8}

body.vt .ss-opt.sel:not(.active){background:rgba(42,224,224,.12)}

body.vt .ss-opt.is-empty{color:var(--faint);cursor:default;justify-content:flex-start}

body.vt .role-switch .ss{width:auto}

body.vt .ss-input.role-select{width:132px}

body.vt .adj .fld.inline .ss{width:auto}

body.vt .adj .fld.inline .ss-input{width:96px}


body.vt table.lines input.in,
body.vt table.lines select.in{padding:6px 8px;background:transparent;border:1px solid transparent;border-radius:6px}

body.vt table.lines input.in:hover,
body.vt table.lines select.in:hover{border-color:var(--line-soft)}

body.vt table.lines input.in:focus,
body.vt table.lines select.in:focus{background:var(--surface-2)}

body.vt table.lines .c-desc{width:34%}
body.vt table.lines .c-num{width:9%}
body.vt table.lines .c-unit{width:8%}
body.vt table.lines .c-vat{width:13%}
body.vt table.lines .c-x{width:34px}

body.vt table.lines td.amt{font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}

body.vt table.lines.ro td{color:var(--ink)}

body.vt .x{background:none;border:1px solid var(--line-soft);color:var(--faint);border-radius:6px;cursor:pointer;padding:3px 8px;font-size:12px}

body.vt .x:hover{color:var(--bad);border-color:var(--bad)}

body.vt .add-line{margin-top:10px}

body.vt .suggest-bar{display:flex;align-items:center;gap:12px;margin-top:10px;font-size:13px;color:var(--muted);flex-wrap:wrap}

body.vt .suggest-bar:empty{display:none}


/* editor footer / totals */
body.vt .foot{display:flex;flex-direction:column;gap:14px;margin-top:18px}

body.vt .foot-left{display:flex;flex-direction:column;gap:12px}

/* Notes box and totals box side by side as an equal-height pair, so their bottom edges line up
   (owner 2026-08-28). The row is as tall as the taller box; the Notes textarea grows to fill. */
body.vt .foot-pair{display:grid;grid-template-columns:1fr 340px;gap:18px;align-items:stretch}

body.vt .foot-pair>.fld{height:100%}

body.vt .foot-pair>.fld textarea{flex:1;min-height:96px}

body.vt .foot-totals{display:flex;flex-direction:column}

body.vt .foot-totals>.tp{flex:1;margin:0}

body.vt .adj{display:flex;gap:16px;flex-wrap:wrap}

body.vt .adj .fld.inline input{width:110px}

body.vt .adj .fld.inline select{width:auto}

body.vt .alert{background:rgba(242,122,122,.12);border:1px solid rgba(242,122,122,.4);color:#ffd9d9;padding:9px 12px;border-radius:8px;font-size:13px}


body.vt .tp{border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;display:flex;flex-direction:column}

body.vt .tp .tp-row.total{margin-top:auto}
   /* pin the Total row to the box bottom so it aligns with the Notes box */
body.vt .tp-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:9px 14px;font-size:13.5px}

body.vt .tp-row span:first-child{color:var(--muted)}

body.vt .tp-row em{font-style:normal;font-family:var(--mono);font-size:10.5px;color:var(--faint)}

body.vt .tp-row code{font-size:11.5px}

body.vt .tp-row.disc span:last-child{color:var(--ok)}

body.vt .tp-row.total{background:rgba(42,224,224,.10);border-top:1px solid var(--line);padding:12px 14px}

body.vt .tp-row.total span:first-child{color:var(--ink);font-weight:700}

body.vt .tp-row.total b{color:var(--brand);font-size:18px;font-weight:800}

body.vt .tp-row.dep{border-top:1px dashed var(--line-soft);font-size:12.5px}


/* settings / forms */
body.vt .card{border:1px solid var(--line-soft);border-radius:var(--radius-sm);padding:16px 18px;margin-bottom:16px;background:var(--panel)}

body.vt .card>h3:first-child{margin-top:0}

body.vt .form-actions{display:flex;align-items:center;gap:12px;margin-top:8px}

body.vt .notice{background:rgba(75,214,160,.12);border:1px solid rgba(75,214,160,.4);color:#bff3dd;padding:8px 12px;border-radius:8px;font-size:13px}

/* .notice is a SUCCESS box (green) — right for "invite emailed" or "generated 3 invoices", wrong for
   a statement of what a grid is filtered to. A 60+ overdue summary was being framed in green, which is
   the ladder saying "good" about the worst money on the screen. Neutral variant for informational panels;
   the ladder-toned figures inside carry the meaning. */
body.vt .notice.is-info{background:var(--surface-2);border-color:var(--line);color:var(--ink)}

body.vt .hint{font-size:11.5px;color:var(--faint);margin-top:2px}

body.vt .logo-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap}

body.vt .logo-prev{height:56px;width:auto;max-width:180px;border:1px solid var(--line-soft);border-radius:6px;background:#fff;padding:4px;object-fit:contain}

body.vt input.chk,
body.vt input[type=checkbox]{width:auto}


/* client detail — key/values, notes, documents (F5) */
body.vt .kv{display:grid;grid-template-columns:1fr 1fr;gap:10px 22px}

body.vt .kv>div{display:flex;flex-direction:column;gap:3px}

body.vt .kv span{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--faint);font-weight:700}

body.vt .kv b{font-weight:600}

body.vt .notes-list{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}

body.vt .note-row{border:1px solid var(--line-soft);border-radius:var(--radius-sm);padding:8px 12px;font-size:13.5px}

body.vt .note-row .note-date{color:var(--faint);font-size:11px;margin-bottom:3px}

body.vt .docs-list{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}

body.vt .doc-row{display:flex;align-items:center;gap:10px;border:1px solid var(--line-soft);border-radius:var(--radius-sm);padding:7px 11px;font-size:13.5px}

body.vt .doc-row a{color:var(--brand);text-decoration:none;font-weight:600}

body.vt .doc-row a:hover{text-decoration:underline}

body.vt .doc-row .doc-meta{color:var(--faint);font-size:11.5px}

body.vt .doc-row .spacer{flex:1}


/* detail */
body.vt .detail-grid{display:grid;grid-template-columns:1fr 300px;gap:20px;margin-top:6px}

body.vt .journal .acct small{display:block;color:var(--faint);font-size:11px;font-family:var(--sans)}

body.vt .journal tfoot td{border-top:1px solid var(--line);font-weight:700;padding:9px 13px}

body.vt .bal.ok{color:var(--ok)}
body.vt .bal.bad{color:var(--bad)}
body.vt .bal.warn{color:var(--warn)}


/* invoice paper — client-facing SARS tax invoice (white/ink, print-ready) */
body.vt .invoice-paper{background:#fff;color:#1a2b2b;border-radius:var(--radius-sm);padding:34px 38px;max-width:820px;margin:0 auto;
  box-shadow:0 8px 30px rgba(0,0,0,.35);font-size:13px;line-height:1.5}

body.vt .doc-head{display:flex;justify-content:space-between;gap:24px;border-bottom:2px solid #1a2b2b;padding-bottom:18px;margin-bottom:18px}

body.vt .doc-supplier{max-width:60%}

body.vt .doc-logo{max-height:60px;max-width:220px;object-fit:contain;margin-bottom:8px;display:block}

body.vt .doc-org-name{font-size:20px;font-weight:800;letter-spacing:-.01em;margin-bottom:6px}

body.vt .doc-address{color:#3a4d4d;margin-bottom:6px}

body.vt .doc-meta-line{color:#3a4d4d;font-size:12px}

body.vt .doc-title-block{text-align:right;min-width:230px}

body.vt .doc-title{font-size:24px;font-weight:800;letter-spacing:.04em;color:#0d6b6b;margin-bottom:10px}

body.vt .doc-meta{margin-left:auto;font-size:12px;width:auto}

body.vt .doc-meta td{padding:2px 0;border:none}

body.vt .doc-meta td:first-child{color:#6a7d7d;text-align:right;padding-right:12px;text-transform:uppercase;font-size:10px;letter-spacing:.08em}

body.vt .doc-meta td:last-child{text-align:right;font-weight:600}

body.vt .doc-bill-to{margin-bottom:18px}

body.vt .doc-label{font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:#6a7d7d;font-weight:700;margin-bottom:4px}

body.vt .doc-client-name{font-size:15px;font-weight:700}

body.vt .doc-lines-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:18px}

body.vt .doc-lines-tbl{width:100%;border-collapse:collapse;font-size:12.5px}

body.vt .doc-lines-tbl thead th{background:#f0f5f5;color:#4a5d5d;text-transform:uppercase;font-size:10px;letter-spacing:.06em;
  text-align:left;padding:8px 10px;border-bottom:2px solid #d5e0e0}

body.vt .doc-lines-tbl tbody td{padding:8px 10px;border-bottom:1px solid #e6eeee;color:#1a2b2b;vertical-align:top}

body.vt .doc-lines-tbl .c-desc{width:44%}

body.vt .doc-lines-tbl .ta-c{text-align:center}

body.vt .doc-summary{display:flex;justify-content:space-between;gap:24px;align-items:flex-start}

body.vt .doc-notes{max-width:55%;font-size:11.5px;color:#3a4d4d}

body.vt .doc-statement{margin-top:10px;font-size:10.5px;color:#6a7d7d;font-style:italic}

body.vt .doc-abridged{color:#0d6b6b}

body.vt .doc-totals{min-width:270px;margin-left:auto}

body.vt .dt-row{display:flex;justify-content:space-between;gap:20px;padding:5px 0;font-size:13px;color:#3a4d4d}

body.vt .dt-row.muted{color:#8aa0a0}

body.vt .dt-row .num{color:#1a2b2b;font-variant-numeric:tabular-nums}

body.vt .dt-total{border-top:2px solid #1a2b2b;margin-top:6px;padding-top:9px;font-size:16px;font-weight:800;color:#0d6b6b}

body.vt .dt-total .num{color:#0d6b6b;font-weight:800}

body.vt .dt-dep{border-top:1px dashed #c5d2d2;font-size:12px}

body.vt .pre{white-space:pre-line}

body.vt .paid-stamp{display:inline-block;margin-top:8px;border:2.5px solid #1a9d6b;color:#1a9d6b;font-weight:800;letter-spacing:.14em;padding:2px 12px;border-radius:6px;transform:rotate(-4deg);font-size:15px}

body.vt .void-stamp{display:inline-block;margin-top:8px;border:2.5px solid #c23b3b;color:#c23b3b;font-weight:800;letter-spacing:.14em;padding:2px 12px;border-radius:6px;transform:rotate(-4deg);font-size:15px}

body.vt .muted-block{color:var(--muted);padding:14px;border:1px dashed var(--line);border-radius:var(--radius-sm)}

body.vt .is-hidden{display:none!important}

body.vt .accounting{margin-top:26px}


/* payments panel */
body.vt .ok{color:var(--ok)}

body.vt .pay-summary{display:flex;gap:26px;flex-wrap:wrap;margin:4px 0 12px;font-size:14px;color:var(--muted)}

body.vt .pay-summary b{margin-left:6px;color:var(--ink)}

body.vt .pay-form{display:flex;gap:14px;align-items:flex-end;flex-wrap:wrap;margin-top:12px;padding:12px 14px;border:1px solid var(--line-soft);border-radius:var(--radius-sm);background:var(--panel)}

body.vt .pay-form .fld.inline{flex-direction:column;align-items:flex-start;gap:5px}

body.vt .pay-form .fld.inline input{width:150px}

body.vt .pay-journal{margin-top:10px}

body.vt .pay-journal .muted{margin-bottom:4px;font-size:12px}

body.vt .pay-online{display:flex;flex-direction:column;gap:6px;margin-top:14px;padding-top:12px;border-top:1px dashed var(--line-soft)}

body.vt .center-card{max-width:460px;margin:40px auto;text-align:center}

body.vt .center-card h1{font-size:22px;margin:12px 0 6px}


/* activity trail */
body.vt .activity{border:1px solid var(--line-soft);border-radius:var(--radius-sm);overflow:hidden}

body.vt .act-row{display:flex;align-items:center;gap:12px;padding:8px 12px;border-bottom:1px solid var(--line-soft);font-size:13px}

body.vt .act-row:last-child{border-bottom:none}

body.vt .act-date{color:var(--faint);font-size:11.5px}

body.vt .act-tag{font-size:10px;text-transform:uppercase;letter-spacing:.06em;font-weight:700;padding:2px 8px;border-radius:999px;background:rgba(143,177,176,.16);color:var(--muted)}

body.vt .act-tag.act-reminder{background:rgba(230,180,90,.16);color:var(--warn)}

body.vt .act-tag.act-void{background:rgba(242,122,122,.16);color:var(--bad)}

body.vt .act-tag.act-approve{background:rgba(75,214,160,.16);color:var(--ok)}

body.vt .act-tag.act-decline{background:rgba(242,122,122,.16);color:var(--bad)}

body.vt .approval-box{margin-bottom:16px}

body.vt .approval-head{display:flex;align-items:center;gap:10px;margin-bottom:6px}


/* modal overlay (ui.js) — AI draft confirm, approvals, onboarding preview */
body.vt .modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:100;padding:18px}

body.vt .modal-panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);max-width:560px;width:100%;max-height:88vh;overflow:auto;padding:20px 22px;box-shadow:0 20px 60px rgba(0,0,0,.5)}

body.vt .modal-panel:focus{outline:none}

body.vt .modal-title{font-size:16px;font-weight:800;margin-bottom:10px}

body.vt .modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:16px}

body.vt .ai-livebar{display:flex;align-items:center;gap:12px;margin:8px 0}

body.vt .ai-draft-live{min-height:60px}

body.vt .ai-draft .eyebrow{display:block;margin-bottom:8px}

/* embedded AI dictation control (in the client form + invoice/quote editor) */
body.vt .ai-embed{margin-bottom:14px}

body.vt .ai-dictate{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 12px;border:1px solid var(--brand);border-radius:var(--radius-sm);background:rgba(42,224,224,.06)}

body.vt .ai-dictate .ai-cmd{flex:1;min-width:220px}

body.vt .ai-dictate [data-status]{white-space:nowrap;color:var(--brand)}

body.vt .ai-embed [data-ai-revert]{margin-left:10px}


/* customer-facing surface (customer.js) — simulated emailed link, no admin nav */
body.vt .cust{min-height:100vh;display:flex;flex-direction:column}

body.vt .cust-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 22px;border-bottom:1px solid var(--line);background:var(--panel)}

body.vt .cust-sub{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.14em;color:var(--brand)}

body.vt .cust-main{flex:1;max-width:820px;width:100%;margin:0 auto;padding:28px 22px}

body.vt .cust-card{border:1px solid var(--line-soft);border-radius:var(--radius);padding:24px 26px;background:var(--panel)}

body.vt .cust-card h1{font-size:22px;font-weight:800;margin-bottom:8px}

body.vt .cust-token{font-size:12.5px;color:var(--muted);margin-top:10px}

body.vt .cust-foot{padding:14px 22px;text-align:center;font-size:11.5px;color:var(--faint);border-top:1px solid var(--line-soft)}


/* dashboard */
body.vt .kpis{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:18px}

body.vt .kpi{border:1px solid var(--line-soft);border-radius:var(--radius-sm);padding:14px 16px;background:var(--panel)}

body.vt .kpi-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.1em;color:var(--faint);font-weight:700}

body.vt .kpi-value{font-size:20px;font-weight:800;margin-top:6px;letter-spacing:-.01em}

body.vt .kpi-sub{font-size:11.5px;color:var(--muted);margin-top:2px}

body.vt .kpi-brand .kpi-value{color:var(--brand)}

body.vt .kpi-bad .kpi-value{color:var(--bad)}

body.vt .kpi-warn .kpi-value{color:var(--warn)}

body.vt .kpi-ok .kpi-value{color:var(--ok)}

body.vt .dash-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}

body.vt .dash-sub{margin:16px 0 7px;font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:var(--faint);font-weight:700}

body.vt .age-bar{display:flex;height:16px;border-radius:999px;overflow:hidden;background:var(--surface-2);margin:6px 0 12px}

body.vt .age-seg{height:100%}

body.vt .age-cur{background:var(--ok)}
body.vt .age-1{background:var(--warn)}
body.vt .age-2{background:var(--warn-2)}
body.vt .age-3{background:var(--bad)}

body.vt .age-legend{display:flex;flex-wrap:wrap;gap:14px;font-size:12.5px;color:var(--muted)}

body.vt .age-legend span{display:inline-flex;align-items:center;gap:6px}

body.vt .age-legend i{width:10px;height:10px;border-radius:2px;display:inline-block}

body.vt .age-legend i.age-cur{background:var(--ok)}
body.vt .age-legend i.age-1{background:var(--warn)}
body.vt .age-legend i.age-2{background:var(--warn-2)}
body.vt .age-legend i.age-3{background:var(--bad)}

body.vt .age-legend b{color:var(--ink)}

body.vt .recent{display:flex;flex-direction:column;gap:2px;margin-bottom:12px}

body.vt .recent-row{display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:12px;padding:8px 10px;border-radius:var(--radius-sm);cursor:pointer}

body.vt .recent-row:hover{background:rgba(42,224,224,.06)}

body.vt .recent-amt{color:var(--ink)}


/* print — only the paper survives */
@media print{

  body.vt .topbar,
body.vt .no-print{display:none !important}

  body.vt{background:#fff}

  body.vt .page{padding:0;max-width:none;margin:0}

  body.vt .invoice-paper{box-shadow:none;max-width:none;border-radius:0;margin:0;padding:0}

  body.vt .doc-lines-wrap{overflow:visible}

}


@media (max-width:820px){

  body.vt .grid2{grid-template-columns:1fr 1fr}

  body.vt .kv{grid-template-columns:1fr}

  body.vt .foot-pair,
body.vt .detail-grid{grid-template-columns:1fr}

  body.vt .kpis{grid-template-columns:1fr 1fr}

  body.vt .dash-grid{grid-template-columns:1fr}

  body.vt .doc-head,
body.vt .doc-summary{flex-direction:column}

  body.vt .doc-title-block{text-align:left}

  body.vt .doc-meta{margin-left:0}

  body.vt .doc-notes,
body.vt .doc-totals{max-width:none;min-width:0;width:100%}

  body.vt .invoice-paper{padding:22px 20px}

}


/* ── from src/styles-owner.css ── */
/* Styles for the 2026-07-28 owner-feedback round (Andre + Lloyd review).
   Kept in its own file so the round is easy to review/revert; loaded after styles.css.
   Sections are owned by one screen each — see plan/owner-feedback-2026-07-28.md. */

/* ── App shell: side-nav drawer (transcript ruling — Lloyd: "even with sleek, we don't deal with
      tabs like that, we're dealing with this BAR"; Callan: "so you guys want the side nav";
      Andre: "try it"). Structure mirrors the real app's src/admin/shell.js: drawer + scrim +
      app-bar + ☰. Static column from 901px; slide-over drawer with a scrim below that. ───────── */
/* THE CONTENT AREA SCROLLS, NOT THE WINDOW (owner 2026-07-29: clicking a side-panel button "must not
   jump to the top like that, it is jarring on the eyes"). When the window was the scroller, leaving a
   screen from halfway down snapped the whole page to 0 on arrival. Now the offset belongs to
   `.shell-main`, which render() rebuilds on every navigation — so the new screen is simply born at the
   top and nothing visibly moves. The drawer and app bar become physically static rather than
   sticky-tracking a moving page. `100dvh` keeps it right on mobile browser chrome (vh first as the
   fallback). @media print undoes all of it — a clipped overflow container would truncate a printed
   invoice. */
body.vt .shell-layout{ display: flex; height: 100vh; height: 100dvh; overflow: hidden; }

body.vt .shell-main{ overflow-y: auto; overscroll-behavior: contain; }

/* position:relative (not the base .drawer's fixed) so the drawer is an in-flow FLEX item beside
   .shell-main on desktop — otherwise a fixed drawer overlaps the content (its flex basis is ignored).
   The max-width:900px block below re-fixes it as the off-canvas overlay. (owner 2026-09-06 bug) */
body.vt .drawer{ position: relative; width: 232px; flex: 0 0 232px; box-sizing: border-box; background: var(--panel);
  border-right: 1px solid var(--line); padding: 14px 10px 24px;
  height: 100%; overflow-y: auto; }

body.vt .drawer-brand{ padding: 2px 10px 14px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }

body.vt .nav-section{ font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .12em;
  color: var(--faint); padding: 16px 10px 5px; }

body.vt .nav-item{ display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px;
  cursor: pointer; color: var(--muted); font-size: 13.5px; user-select: none; }

body.vt .nav-item:hover{ background: var(--surface-2); color: var(--ink); }

body.vt .nav-item.active{ background: var(--surface-2); color: var(--brand); font-weight: 600; }

body.vt .nav-ico{ width: 18px; text-align: center; opacity: .8; }

body.vt .nav-lbl{ flex: 1; }

body.vt .shell-main{ flex: 1; min-width: 0; display: flex; flex-direction: column; }

body.vt .shell-content{ flex: 1; min-width: 0; }

body.vt .app-bar-left{ align-items: center; }

body.vt .app-title{ font-weight: 700; font-size: 15px; }

body.vt .hamb{ display: none; }

body.vt .scrim{ display: none; }

@media (max-width: 900px){

  body.vt .drawer{ position: fixed; left: 0; top: 0; z-index: 70; transform: translateX(-105%);
    transition: transform .18s ease; box-shadow: 0 0 44px rgba(0,0,0,.55); }

  body.vt .shell-layout.nav-open .drawer{ transform: translateX(0); }

  body.vt .shell-layout.nav-open .scrim{ display: block; position: fixed; inset: 0; z-index: 65; background: rgba(0,0,0,.5); }

  body.vt .hamb{ display: inline-flex; }

}

/* Printing must escape the fixed-height scroll container, or a long invoice is clipped to one screen. */
@media print{

  body.vt .drawer,
body.vt .scrim,
body.vt .app-bar{ display: none !important; }

  body.vt .shell-layout{ display: block; height: auto; overflow: visible; }

  body.vt .shell-main,
body.vt .shell-content{ overflow: visible; display: block; }

}

@media (prefers-reduced-motion: reduce){
 body.vt .drawer{ transition: none; }
 }


/* ── Setup guide (Xero pattern Andre asked us to steal) ─────────────────────────── */
body.vt .setup-guide{ margin-bottom: 18px; }

body.vt .setup-head{ display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }

body.vt .setup-head h3{ margin: 0; }

body.vt .setup-count{ color: var(--muted); font-size: 13px; }

body.vt .setup-head .btn{ margin-left: auto; }

body.vt .setup-cards{ display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin-top: 12px; }

body.vt .setup-card{ background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; text-align: left; cursor: pointer; display: flex; flex-direction: column; gap: 6px; }

body.vt .setup-card:hover{ border-color: var(--brand); }

body.vt .setup-card.done{ opacity: .62; }

body.vt .setup-card-title{ font-weight: 600; color: var(--brand); display: flex; align-items: center; gap: 6px; }

body.vt .setup-card-desc{ color: var(--muted); font-size: 12.5px; line-height: 1.45; flex: 1; }

body.vt .setup-meter{ height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }

body.vt .setup-meter > i{ display: block; height: 100%; background: var(--brand); border-radius: 3px; }

body.vt .setup-card.done .setup-meter > i{ background: var(--ok); }

body.vt .setup-pct{ font-size: 11.5px; color: var(--muted); }


/* ── Dashboard grids with their own search + status tabs + sortable columns ──────── */
/* styles.css:313 declares `.dash-grid{grid-template-columns:1fr 1fr}`. A grid item's automatic minimum
   is min-content, which IGNORES an inner `.tbl-wrap` scroll container — so a wide table stretches its
   cell and pushes the page sideways (a long-standing dashboard bug, ~6px here, 140px with a wide grid).
   `minmax(0, …)` lets the cell shrink so the table scrolls inside its own wrapper instead. */
body.vt .dash-grid{ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

@media (max-width: 820px){
 body.vt .dash-grid{ grid-template-columns: minmax(0, 1fr); }
 }


/* Collapsible grid panels — <details>/<summary>, so the browser handles show/hide + keyboard. */
body.vt .dash-grid-panel{ margin-bottom: 22px; }

body.vt .dash-grid-panel:last-child{ margin-bottom: 0; }

body.vt .dash-grid-summary{ cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px;
  padding: 4px 0; border-radius: 7px; }

body.vt .dash-grid-summary::-webkit-details-marker{ display: none; }
   /* replaced by our own chevron */
body.vt .dash-grid-summary::before{ content: '▸'; color: var(--muted); font-size: 12px; transition: transform .15s ease; }

body.vt .dash-grid-panel[open] > .dash-grid-summary::before{ transform: rotate(90deg); }

body.vt .dash-grid-summary:hover .dash-sub{ color: var(--brand); }

body.vt .dash-grid-summary .dash-sub{ margin: 0; }

body.vt .grid-count{ margin-left: 8px; font-size: 11.5px; font-weight: 600; color: var(--muted);
  background: var(--surface-2); border-radius: 999px; padding: 1px 8px; }

body.vt .dash-grid-panel .list-toolbar{ margin: 6px 0 10px; }

body.vt .dash-grid-panel .search{ max-width: 260px; }

body.vt .dash-grid-panel .segs{ flex-wrap: wrap; }


/* ── Aging legend (the bar itself is gone — the column chart replaced it, and a bucket now
      deep-links to the filtered invoice grid rather than expanding a drill table) ──────────── */
body.vt .age-legend span[role="button"]{ cursor: pointer; }

body.vt .age-legend span[role="button"]:hover b{ text-decoration: underline; }

body.vt .age-healthy{ color: var(--ok); font-size: 12px; }


/* ── Contacts: You owe / They owe + customer/supplier badges ────────────────────── */
body.vt .contact-tags{ display: inline-flex; gap: 4px; margin-left: 6px; }

body.vt .tag-cust,
body.vt .tag-supp{ font-size: 10.5px; padding: 1px 6px; border-radius: 999px; border: 1px solid var(--line); color: var(--muted); }

body.vt .tag-cust{ border-color: var(--brand); color: var(--brand); }

body.vt .tag-supp{ border-color: var(--muted); color: var(--muted); }
   /* a type, not a warning */
body.vt .tag-incomplete{ font-size: 10.5px; padding: 1px 6px; border-radius: 999px; border: 1px solid var(--bad); color: var(--bad); }


/* ── Inline "create contact" row inside a search-selector popup ─────────────────── */
body.vt .ss-create{ border-top: 1px solid var(--line); color: var(--brand); font-weight: 600; }


/* ── Approvals queue (universal document approvals) ─────────────────────────────── */
body.vt .appr-doc{ display: flex; flex-direction: column; gap: 2px; }

body.vt .appr-type{ font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

body.vt .nav-badge{ display: inline-block; min-width: 17px; padding: 0 5px; margin-left: 5px; border-radius: 999px;
             /* warn, not bad: a queue of things to do is attention, not a failure (ladder in styles.css). */
             background: var(--warn); color: var(--brand-ink); font-size: 11px; font-weight: 700; text-align: center; line-height: 17px; }


/* ── Global "+ New" document menu ───────────────────────────────────────────────── */
body.vt .newmenu{ position: relative; }

body.vt .newmenu-pop{ position: fixed; z-index: 60; min-width: 210px; background: var(--surface); border: 1px solid var(--line);
               border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.38); padding: 6px; }

body.vt .newmenu-pop button{ display: block; width: 100%; text-align: left; background: none; border: 0; color: var(--ink);
                      padding: 8px 10px; border-radius: 7px; cursor: pointer; font-size: 13.5px; }

body.vt .newmenu-pop button:hover{ background: var(--surface-2); }

body.vt .newmenu-sep{ height: 1px; background: var(--line); margin: 5px 2px; }

body.vt .newmenu-cap{ font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; padding: 6px 10px 3px; }


/* ── Sales / Purchases overview: Xero's 4-tile status strip ─────────────────────── */
/* `.kpis` in styles.css is repeat(5,1fr); the overview strip has exactly 4 tiles. The mobile guard
   must repeat here, otherwise this rule outranks the 640px 2-column rule and 375px overflows. */
body.vt .kpis.kpis-4{ grid-template-columns: repeat(4, 1fr); }

@media (max-width: 640px){
 body.vt .kpis.kpis-4{ grid-template-columns: 1fr 1fr; }
 }

body.vt .kpi.clickable{ cursor: pointer; }

body.vt .kpi.clickable:hover{ border-color: var(--brand); }


/* Statuses that had no colour rule (quotes + purchase orders) — they rendered as bare grey pills
   on the overview and dashboard tables. Mapped onto the existing semantic colours. */
/* Same ladder as the invoice pills in styles.css — green good, yellow waiting, red bad, grey inert.
   `sent`/`open` were an off-ladder blue and `converted` was sharing a yellow with `part_received`,
   which said "needs attention" about a document that had already done its job. */
body.vt .pill-sent,
body.vt .pill-open{ background: rgba(230,180,90,.15); color: var(--warn); }
        /* awaiting a reply */
body.vt .pill-part_received{ background: rgba(230,180,90,.15); color: var(--warn); }
           /* half delivered */
body.vt .pill-accepted,
body.vt .pill-received{ background: rgba(75,214,160,.15); color: var(--ok); }
  /* good outcome */
body.vt .pill-declined,
body.vt .pill-cancelled{ background: rgba(242,122,122,.15); color: var(--bad); }

body.vt .pill-converted{ background: var(--neutral-bg); color: var(--neutral); }
               /* done its job — inert */

/* ── Per-list action row (Xero puts New X ▾ / New Repeating / New Credit Note here) ─ */
body.vt .list-actions{ margin-bottom: 12px; }


/* ── List toolbar: date range + created-by ──────────────────────────────────────── */
body.vt .filter-dates{ display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

body.vt .filter-dates label{ display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--muted); }

body.vt .filter-dates input[type="date"]{ padding: 5px 7px; }

body.vt .by-cell{ font-size: 12px; color: var(--muted); }


/* (Expenses reuses the existing .cell-sub / .pill / .tbl-wrap styles — no new CSS needed.) */

/* ── Bill dropzone (drag & drop a supplier invoice) ─────────────────────────────── */
body.vt .dropzone{ border: 2px dashed var(--line); border-radius: 12px; padding: 22px 16px; text-align: center; color: var(--muted); cursor: pointer; }

body.vt .dropzone.over{ border-color: var(--brand); color: var(--brand); background: var(--surface-2); }

body.vt .dropzone-title{ font-weight: 600; color: var(--ink); margin-bottom: 4px; }

body.vt .dropzone-hint{ font-size: 12.5px; }


/* ── Editor line grid: the new Account column (Xero parity) ─────────────────────── */
/* Rebalanced from styles.css:149 (desc 34% / num 9% / unit 8% / vat 13%) to make room. */
body.vt table.lines .c-desc{ width: 27%; }

body.vt table.lines .c-acct{ width: 12%; }

body.vt table.lines .c-vat{ width: 11%; }

body.vt table.lines .c-unit{ width: 7%; }


/* ── Form action rows must wrap on phones ───────────────────────────────────────── */
/* styles.css declares .form-actions as flex with the default nowrap. The credit-note / RTS pickers
   put three buttons + an error span in one row ("Credit the full ZAR 71 300,00 instead" is ~263px
   alone), which dragged the invoice detail 250px past a 375px viewport. Wrapping is the correct
   mobile-first behaviour for every action row, so this is a global override, not a picker-only one. */
body.vt .form-actions{ flex-wrap: wrap; }


/* ── Repeat-last-document prompt in the editor ──────────────────────────────────── */
body.vt .repeat-prompt{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: var(--surface-2);
                 border: 1px solid var(--brand); border-radius: 9px; padding: 9px 12px; margin-bottom: 10px; font-size: 13px; }

body.vt .repeat-prompt .grow{ flex: 1; }


@media (max-width: 640px){

  body.vt .setup-cards{ grid-template-columns: 1fr; }

  body.vt .newmenu-pop{ min-width: 180px; }

  /* styles.css:120 sets `.fld.inline > span { white-space: nowrap }`. On a phone a long inline label
     (e.g. the GRNI toggle) then has a min-content wider than the column and drags the whole .grid2
     past the viewport — a real 235px overflow on Settings. Let those labels wrap on small screens;
     desktop keeps the tidy single-line look. */
  body.vt .fld.inline > span{ white-space: normal; }

}


/* ── Charts (src/charts.js): Xero-style column chart + compact trend strip ───────── */
/* Owner, 2026-07-28 — our stacked aging bar is "just not familiar, what I'm familiar with";
   Xero's home charts are "a more acceptable… familiar is the word", and useful because
   "you can say, gee, our sales have fallen this month". Plain divs, no chart library.
   Bar heights are stamped by charts.js after render (same trick as .age-seg widths). */

/* The chart scrolls INSIDE its own box: 12 monthly columns × 64px minimum cannot fit a
   375px phone, and a card must never drag the page sideways. */
body.vt .chart-scroll{ overflow-x: auto; overflow-y: hidden; padding-bottom: 2px; }

body.vt .chart-col-plot{ display: flex; align-items: flex-end; gap: 6px; min-width: min-content; padding: 4px 2px 0; }

/* 64px = the width a full money() value needs before it ellipsizes; also a fair touch target. */
body.vt .chart-col-item{ flex: 1 1 0; min-width: 64px; display: flex; flex-direction: column; gap: 4px; }

/* Definite height — this is what the bar's percentage resolves against. Bottom-aligned, so the
   value label rides directly on top of the bar and moves with it. */
body.vt .chart-col-track{ height: 132px; display: flex; flex-direction: column; justify-content: flex-end; gap: 3px; }

body.vt .chart-col-value{ flex: 0 0 auto; font-size: 10.5px; line-height: 1.1; color: var(--muted);
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

body.vt .chart-col-bar{ flex: 0 0 auto; min-height: 3px; border-radius: 5px 5px 2px 2px; background: var(--brand); }

body.vt .chart-col-bar-zero{ background: var(--line); }
        /* zero / all-zero → flat baseline */
body.vt .chart-col-bar[role="button"]{ cursor: pointer; }

body.vt .chart-col-bar[role="button"]:hover{ filter: brightness(1.2); }

body.vt .chart-col-bar:focus-visible{ outline: 2px solid var(--brand); outline-offset: 2px; }

body.vt .chart-col-label{ font-size: 10.5px; color: var(--faint); text-align: center; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; border-top: 1px solid var(--line); padding-top: 4px; }


/* Per-bar accents a caller can pass as `cls` (declared after .chart-col-bar so they win). */
body.vt .chart-bar-ok{ background: var(--ok); }

body.vt .chart-bar-warn{ background: var(--warn); }

body.vt .chart-bar-bad{ background: var(--bad); }

body.vt .chart-bar-muted{ background: var(--muted); }

body.vt .chart-bar-warn2{ background: var(--warn-2); }
   /* escalation step between warn and bad */

/* miniTrend — sparkline strip + latest value + period-on-period change. */
body.vt .chart-mini{ display: flex; flex-direction: column; gap: 5px; }

body.vt .chart-mini-bars{ display: flex; align-items: flex-end; gap: 3px; height: 34px; }

body.vt .chart-mini-bar{ flex: 1 1 0; min-width: 3px; min-height: 2px; border-radius: 2px; background: var(--brand); opacity: .55; }

body.vt .chart-mini-bar-last{ opacity: 1; }
                    /* the period being talked about */
body.vt .chart-mini-bar-zero{ background: var(--line); opacity: 1; }

body.vt .chart-mini-foot{ display: flex; align-items: baseline; gap: 8px; font-size: 11.5px; color: var(--muted); flex-wrap: wrap; }

body.vt .chart-mini-last{ color: var(--ink); font-weight: 600; }

body.vt .chart-mini-delta{ font-weight: 700; }

/* Reads correctly for money coming IN; a money-going-OUT caller can flip it with its own class. */
body.vt .chart-mini-up{ color: var(--ok); }

body.vt .chart-mini-down{ color: var(--bad); }

body.vt .chart-mini-flat{ color: var(--muted); }


body.vt .chart-empty{ color: var(--muted); font-size: 12px; padding: 10px 0; }


@media (max-width: 640px){

  body.vt .chart-col-track{ height: 108px; }

  body.vt .chart-col-value{ font-size: 10px; }

}


/* ── Dashboard tables: NO horizontal scrollbar, everything visible ────────────────── */
/* Owner, 2026-07-28: "the grids on the dashboard must not have a scroll bar, they must all be fully
   visible." So inside dashboard cards we (a) drop the scroll container, and (b) let cells WRAP so the
   columns compress to fit instead of being clipped. Document-list screens keep their scrolling tables —
   this override is scoped to the dashboard only. */
body.vt .page .card .tbl-wrap{ overflow-x: visible; }

body.vt .page .card table.list{ table-layout: auto; width: 100%; }

/* Wrapping is what makes "fit without scrolling" possible — `nowrap` cells are the thing that forces
   a table wider than its container, so they must yield inside a dashboard card. */
body.vt .page .card table.list th,
body.vt .page .card table.list td,
body.vt .page .card table.list td.nowrap,
body.vt .page .card table.list th.nowrap{ white-space: normal; overflow-wrap: anywhere; }

body.vt .page .card table.list th,
body.vt .page .card table.list td{ padding-left: 8px; padding-right: 8px; }

/* Action buttons stack rather than forcing a wide column. */
body.vt .page .card table.list td.nowrap .btn{ margin: 1px 0; }


/* Under 760px a 7-column table cannot be readable AND fully visible, so each row restacks into
   label: value pairs — nothing hidden, nothing scrolls. Labels come from the `data-label` that
   dashGrid stamps on every cell. */
@media (max-width: 760px){

  body.vt .dash-grid-panel table.list thead{ position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; }
         /* visually hidden, still read by screen readers */
  body.vt .dash-grid-panel table.list,
body.vt .dash-grid-panel table.list tbody,
body.vt .dash-grid-panel table.list tr,
body.vt .dash-grid-panel table.list td{ display: block; width: auto; }

  body.vt .dash-grid-panel table.list tr{ border: 1px solid var(--line); border-radius: 9px;
    padding: 8px 10px; margin-bottom: 8px; background: var(--surface-2); }

  body.vt .dash-grid-panel table.list td{ display: flex; gap: 10px; align-items: baseline;
    border: 0; padding: 3px 0; text-align: left !important; }

  body.vt .dash-grid-panel table.list td::before{ content: attr(data-label); flex: 0 0 40%;
    font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
    color: var(--faint); }

  body.vt .dash-grid-panel table.list td.ta-r{ justify-content: flex-start; }

  body.vt .dash-grid-panel table.list td:empty{ display: none; }
   /* e.g. an empty Action cell */
}


/* ZAR-only (owner 2026-07-29: "this app must be only ZAR for now"). The editor's currency picker
   became a fixed readout, so it needs to look like a settled value rather than a disabled input. */
/* A read-only field value that must sit on the same line and height as the sibling inputs so a field
   row stays aligned (owner 2026-08-28). Single line, vertically centred; any detail rides inline as a
   faint suffix rather than a second line that would make this field taller than its neighbours. */
body.vt .fixed-val{display:flex;align-items:center;gap:7px;padding:0 2px;font-weight:600;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

body.vt .fixed-val .fv-sub{font-weight:400;font-size:11.5px;color:var(--faint);overflow:hidden;text-overflow:ellipsis}


/* Totals strip under a deep-linked grid's banner (owner 2026-07-29: "provide totals for both … it can
   be just below the show all invoices message"). The figure the chart was built from is highlighted so
   the reconciliation is unambiguous — sales matches Total invoiced, aging matches Amount due. */
body.vt .focus-totals{ display: flex; flex-wrap: wrap; gap: 8px 22px; align-items: flex-end;
  margin-top: 11px; padding-top: 11px; border-top: 1px solid var(--line); }

body.vt .focus-total{ display: flex; flex-direction: column; gap: 2px; }

body.vt .focus-total small{ color: var(--faint); font-size: 11px; }

body.vt .focus-total b{ font-size: 15px; }

/* "This is the chart's figure" is EMPHASIS, not meaning — so it gets weight and a ring, never a
   colour. Colour on these figures is reserved for the ladder below, or the 60+ bucket's overdue debt
   ends up painted brand-teal (reads as green) while being the worst number on the screen. */
body.vt .focus-total.is-match{ padding: 2px 9px 3px; margin: -2px -3px -3px; border-radius: 8px;
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); }

body.vt .focus-total.is-match small{ font-weight: 700; }

body.vt .focus-total.is-match b{ font-weight: 800; }


/* Semantic tones — the same ladder as the pills and the aging chart (see styles.css). Untoned cells
   (Total invoiced, Credited, the invoice count) are neutral facts and stay the default ink. */
body.vt .focus-total.tone-ok b{ color: var(--ok); }

body.vt .focus-total.tone-warn b{ color: var(--warn); }

body.vt .focus-total.tone-warn2 b{ color: var(--warn-2); }

body.vt .focus-total.tone-bad b{ color: var(--bad); }

/* Heading + the way out, on one line above the figures (owner 2026-07-29: "remove the copy around
   the totals, just show the totals"). */
body.vt .focus-head{ display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

body.vt .focus-head b{ font-size: 14px; }

body.vt .focus-head .btn{ margin-left: auto; }


/* ── "History and notes" (owner 2026-07-29) ───────────────────────────────────────────────────────
   Xero's shape, captured from the owner's org: a collapsible panel at the foot of every document AND
   of a contact — chevron + title on the left, "Add note" on the right, then Date · User · Action ·
   Detail newest-first. Action tones follow the ladder in styles.css: bad news red, good news green,
   everything else a neutral fact. */
body.vt .hn-card{ margin-top: 18px; }

body.vt .hn-head{ display: flex; align-items: center; gap: 12px; }

body.vt .hn-toggle{ display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }

body.vt .hn-toggle:hover b{ color: var(--brand); }

body.vt .hn-chev{ color: var(--muted); font-size: 12px; width: 10px; }

body.vt .hn-head .btn{ margin-left: auto; }

body.vt .hn-compose{ margin-top: 12px; }

body.vt .hn-compose textarea{ width: 100%; box-sizing: border-box; }

body.vt .hn-table{ margin-top: 10px; }

body.vt .hn-date{ white-space: nowrap; }

body.vt .hn-action{ font-weight: 600; }

body.vt .hn-action.hn-bad{ color: var(--bad); }

body.vt .hn-action.hn-ok{ color: var(--ok); }

body.vt .hn-intro{ margin: 10px 0 2px; font-size: 12.5px; }

/* Products & services grouped into category sections */
body.vt .cat-row td{ font-weight: 700; color: var(--brand); border-top: 2px solid var(--line); padding-top: 12px; }

body.vt .cat-row .grid-count{ color: var(--muted); }

/* Inline category rename (Categories tab) + the "N items → Uncategorised" delete warning. */
body.vt .cat-rename{ padding: 5px 9px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--ink); font: inherit; width: 100%; max-width: 240px; }

body.vt .cat-del-warn{ color: var(--warn); font-size: 12px; margin-right: 6px; white-space: normal; }

/* "Investigate" — the accounting/ledger deep-dive tucked under a magnifying-glass toggle */
body.vt .investigate{ margin-top: 18px; }

body.vt .investigate > .investigate-summary{ cursor: pointer; user-select: none; display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 15px; padding: 10px 0; list-style: none; }

body.vt .investigate-summary::-webkit-details-marker{ display: none; }

body.vt .investigate-summary::marker{ content: ''; }

body.vt .investigate-summary .mag{ font-size: 18px; }

body.vt .investigate-summary small{ font-weight: 400; color: var(--muted); }

body.vt .investigate-summary:hover{ color: var(--brand); }

body.vt .investigate[open] > .investigate-summary{ border-bottom: 1px solid var(--line); margin-bottom: 8px; }

/* Investigate flags issues BY the control, coloured by severity — orange = attention, red = a real
   error. Neutral (muted) when the document is clean, so it's always available without alarming. */
body.vt .investigate--warn > .investigate-summary,
body.vt .investigate--warn > .investigate-summary .mag{ color: var(--warn); }

body.vt .investigate--bad > .investigate-summary,
body.vt .investigate--bad > .investigate-summary .mag{ color: var(--bad); }

body.vt .investigate--warn > .investigate-summary:hover,
body.vt .investigate--bad > .investigate-summary:hover{ filter: brightness(1.08); }

body.vt .inv-flag{ font-weight: 700; font-size: 12px; padding: 2px 10px; border-radius: 999px; }

body.vt .inv-flag--warn{ color: var(--warn); background: rgba(230,180,90,.16); }

body.vt .inv-flag--bad{ color: var(--bad); background: rgba(242,122,122,.16); }

/* The issues themselves, listed at the top of the panel and highlighted red/orange by seriousness */
body.vt .inv-issues{ display: flex; flex-direction: column; gap: 8px; margin: 2px 0 14px; }

/* Each issue is a BUTTON — clicking it jumps to + flashes the grid that evidences it. */
body.vt .inv-issue{ display: flex; flex-direction: column; gap: 3px; width: 100%; text-align: left; cursor: pointer;
  padding: 10px 12px; border: 1px solid transparent; border-left-width: 3px; border-radius: 6px; font: inherit; font-size: 13px; }

body.vt .inv-issue:hover{ filter: brightness(1.06); }

body.vt .inv-issue:focus-visible{ outline: 2px solid var(--brand); outline-offset: 2px; }

body.vt .inv-issue-hd{ font-weight: 700; }

body.vt .inv-issue-hint{ font-weight: 400; opacity: .85; }

body.vt .inv-issue-go{ font-weight: 700; font-size: 12px; opacity: .9; }

body.vt .inv-issue--warn{ color: var(--warn); background: rgba(230,180,90,.10); border-color: rgba(230,180,90,.35); border-left-color: var(--warn); }

body.vt .inv-issue--bad{ color: var(--bad); background: rgba(242,122,122,.10); border-color: rgba(242,122,122,.35); border-left-color: var(--bad); }

/* The chip target: scroll it in and flash a ring + tint, coloured by the issue's severity. */
body.vt .acc-sec{ scroll-margin-top: 16px; border-radius: 8px; }

body.vt .acc-flash{ animation: accFlashWarn 2.6s ease-out; }

body.vt .acc-flash.acc-flash--bad{ animation: accFlashBad 2.6s ease-out; }

@keyframes accFlashWarn{ 0%, 55% { box-shadow: 0 0 0 2px var(--warn) inset; background: rgba(230,180,90,.12); } 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0) inset; background: transparent; } }

@keyframes accFlashBad{ 0%, 55% { box-shadow: 0 0 0 2px var(--bad) inset;  background: rgba(242,122,122,.12); } 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0) inset; background: transparent; } }

/* Plain-language bad-debt explanation sitting above its ledger entries. */
body.vt .baddebt-explain{ margin: 8px 0 10px; padding: 10px 12px; border-radius: 6px; background: rgba(230,180,90,.08); border-left: 3px solid var(--warn); font-size: 13px; line-height: 1.5; }

/* Accounts-Receivable trail: the running "owed" balance of one invoice from raise → payments → write-off. */
body.vt .ar-trail th,
body.vt .ar-trail td{ font-size: 12.5px; }

body.vt .ar-trail td:last-child{ font-weight: 600; }

body.vt .ar-trail .ar-raise td{ color: var(--ink); }

body.vt .ar-trail .ar-writeoff td{ background: rgba(230,180,90,.14); color: var(--warn); font-weight: 700; }

/* Second grid inside the one Bad-debt block — the write-off double entry, sitting under the AR trail. */
body.vt .wo-subhead{ margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--line); }

/* Bad debt is a loss, so every figure in its one ledger grid reads red (owner 2026-08-31). */
body.vt .pay-journal[data-look="baddebt"] .num{ color: var(--bad); }

body.vt .wo-confirm{ display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }

body.vt .wo-confirm .num{ color: var(--bad); }


/* Approval-state banner on a draft document (editor) + the rejection reason in the Approvals grid. */
body.vt .appr-banner{ display: flex; gap: 12px; align-items: flex-start; margin: 0 0 16px; padding: 12px 14px; border-radius: 8px; border: 1px solid var(--line); }

body.vt .appr-banner .appr-banner-icon{ font-size: 20px; line-height: 1.1; }

body.vt .appr-banner-reason{ margin: 3px 0; font-style: italic; color: var(--ink); }

body.vt .appr-banner-hint{ font-size: 12.5px; color: var(--muted); }

body.vt .appr-banner--rejected{ border-color: var(--bad); background: rgba(242,122,122,.10); }

body.vt .appr-banner--rejected > .appr-banner-icon,
body.vt .appr-banner--rejected b{ color: var(--bad); }

body.vt .appr-banner--pending{ border-color: var(--warn); background: rgba(230,180,90,.10); }

body.vt .appr-banner--pending > .appr-banner-icon,
body.vt .appr-banner--pending b{ color: var(--warn); }

body.vt .appr-reason{ display: inline-block; max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; color: var(--bad); }

/* On-document approve/reject decision (owner 2026-08-31: a pending doc is decided on the document, not
   only from the Approvals list). Sits in the pending banner (editor) and in a card (detail/quote). */
body.vt .appr-decide{ display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }

body.vt .appr-decide-row{ display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }

body.vt .appr-decide-lbl{ font-weight: 600; font-size: 12.5px; color: var(--muted); }

/* The submitter's context note — why the document was created — shown to the approver before they decide. */
body.vt .appr-note{ font-size: 13px; line-height: 1.5; }

body.vt .appr-note-lbl{ display: block; font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: 2px; }

body.vt .appr-note-body{ font-style: italic; color: var(--ink); }

body.vt .appr-note--empty{ color: var(--faint); font-style: italic; }

body.vt .appr-decide-card{ border-left: 3px solid var(--warn); }

body.vt .appr-decide-card .appr-decide{ margin-top: 10px; }


/* Key/value details panel — the expense (claim) detail view reached by click-through from Approvals /
   Expenses. A two-column grid: label, then value; collapses to one column on a phone. */
body.vt .kv-list{ display: grid; grid-template-columns: max-content 1fr; gap: 7px 20px; margin-top: 8px; align-items: baseline; }

body.vt .kv-k{ color: var(--muted); font-size: 13px; }

body.vt .kv-v{ color: var(--ink); }

@media (max-width: 560px){

  body.vt .kv-list{ grid-template-columns: 1fr; gap: 2px; }

  body.vt .kv-k{ margin-top: 8px; font-weight: 600; }

}


/* The expense form's full-width "note for the approver" field, sitting between the grid and the rebill row. */
body.vt .fld-wide{ margin-bottom: 16px; }

body.vt .fld-wide textarea{ min-height: 52px; }

/* The submitter's note echoed on an Expenses list row so the approver sees the "why" without opening it. */
body.vt .cell-note{ display: block; color: var(--muted); font-size: 11.5px; font-style: italic; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 62ch; }


/* "Viewed by customer" line under an invoice/quote title — grey until opened, green once the customer opens it. */
body.vt .seen-line{ font-size: 12px; color: var(--muted); margin-top: 3px; }

body.vt .seen-line.seen-yes{ color: var(--ok); font-weight: 600; }

/* Customer-facing invoice pay panel. */
body.vt .pay-due{ font-size: 15px; margin-bottom: 10px; }

body.vt .pay-due .num{ color: var(--ink); font-size: 18px; }


/* Guided empty state with a one-click CTA (first-run Invoices / Quotes). */
body.vt .empty-cta{ text-align: center; padding: 30px 16px; }

body.vt .empty-cta .empty-title{ font-size: 16px; font-weight: 700; color: var(--ink); margin-bottom: 4px; }

body.vt .empty-cta .muted{ margin: 0 auto 14px; max-width: 42ch; }


/* Dashboard "Needs your attention" worklist — the day's next actions in one place. */
body.vt .attention-card{ border-left: 3px solid var(--brand); }

body.vt .attention-list{ display: flex; flex-direction: column; gap: 2px; margin-top: 6px; }

body.vt .attention-row{ display: flex; align-items: center; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line); }

body.vt .attention-row:last-child{ border-bottom: none; }

body.vt .attention-ico{ font-size: 18px; width: 22px; text-align: center; }

body.vt .attention-text{ flex: 1; }

@media (max-width: 560px){

  body.vt .attention-row{ flex-wrap: wrap; }

  body.vt .attention-text{ flex-basis: 100%; }

}


/* Quick due/expiry-date presets under the date field in the editor. */
body.vt .date-presets{ display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }

body.vt .chip-btn{ border: 1px solid var(--line); background: var(--surface-2); color: var(--muted);
  border-radius: 999px; padding: 3px 10px; font-size: 11.5px; cursor: pointer; line-height: 1.4; }

body.vt .chip-btn:hover{ border-color: var(--brand); color: var(--brand); }


/* ── Inline "add a contact" popover (Xero's flow, captured 2026-07-29) ───────────────────────────
   Anchored under the contact selector on every document, so adding a customer never takes you off the
   document you are writing. Cancel/Save sit on the head row, as they do in Xero. */
body.vt .cqa{ margin-top: 10px; max-width: 620px; }

body.vt .cqa-head{ display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }

body.vt .cqa-head b{ font-size: 14px; }

body.vt .cqa-actions{ margin-left: auto; display: flex; gap: 6px; }

body.vt .cqa .fld{ margin-bottom: 8px; }

body.vt .cqa textarea{ resize: vertical; }

body.vt .cqa-banner{ display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 14px; }

body.vt .cqa-banner-actions{ margin-left: auto; }

/* The chip that survives "Later" — the only way back to a dismissed completion prompt. */
body.vt .cqa-chip{ margin-top: 6px; border-color: var(--warn); color: var(--warn); }

body.vt .cqa-chip:hover{ border-color: var(--warn); filter: brightness(1.15); }


/* ── Attachments ("Files") on every document + contact ──────────────────────────────────────────── */
body.vt .att-card{ margin-top: 18px; }

body.vt .att-zone{ margin-top: 10px; }

body.vt .att-table{ margin-top: 10px; }

body.vt .att-table a{ color: var(--brand); }


/* ── App-bar notification shortcuts (owner 2026-07-29): Expenses + Approvals next to + New ────────── */
body.vt .app-notifs{ display: inline-flex; gap: 6px; align-items: center; }

body.vt .app-notif{ display: inline-flex; align-items: center; gap: 6px; position: relative; }

body.vt .app-notif .nav-ico{ opacity: .85; }

body.vt .app-notif .nav-badge{ margin-left: 2px; }

/* the count badge already uses the ladder's warn colour via .nav-badge (a queue = attention, not failure) */
@media (max-width: 640px){
 body.vt .app-notif-lbl{ display: none; }
 }
   /* icon + count only on a phone */

/* ================================================================================================
   UI pass 2026-08-31 — commercial-product patterns (Xero/QuickBooks/Stripe/FreshBooks/Gmail).
   One merged section: each parallel builder reported its CSS; reconciled + appended here.
   ================================================================================================ */

/* Undo-capable notices (Gmail pattern) — flex added here (base .app-notice in styles.css has none). */
body.vt .app-notice{ display: flex; align-items: center; gap: 10px; }

body.vt .notice-undo{ background: none; border: 1px solid currentColor; border-radius: 6px; color: inherit;
  font: inherit; font-size: 12px; padding: 2px 10px; cursor: pointer; opacity: .9; }

body.vt .notice-undo:hover{ opacity: 1; }


/* Customer pay-page hero (Stripe hosted-invoice pattern). */
body.vt .cust-hero{ display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }

body.vt .cust-hero-logo{ max-height: 42px; max-width: 180px; object-fit: contain; }

body.vt .cust-hero-num{ font-size: 13px; opacity: .75; }

body.vt .cust-hero-amt{ font-size: 30px; font-weight: 700; letter-spacing: .2px; }

body.vt .cust-hero-amt small,
body.vt .cust-hero-due{ font-size: 13px; opacity: .7; font-weight: 400; }

body.vt .cust-trust{ font-size: 12px; opacity: .65; margin-top: 2px; }


/* Compose-before-send dialog (Xero pattern). .fld display comes from the global rule in styles.css —
   only the between-field spacing is added for modals (per the builder caveat, no display override). */
body.vt .mailc-preview{ margin-top: 10px; max-height: 260px; overflow: auto; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; padding: 4px; }
   /* emails are light-themed HTML — stays white */
body.vt .mailc-preview-label{ font-size: 12px; opacity: .7; margin-top: 10px; }

body.vt .modal-panel .fld{ margin-bottom: 8px; }


/* Money-in strip above the invoices list (QuickBooks money bar) — each chip drives the status tabs. */
body.vt .money-strip{ display: flex; gap: 8px; flex-wrap: wrap; margin: 2px 0 10px; }

body.vt .mchip{ display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--ink); cursor: pointer;
  font: inherit; font-size: 12.5px; }

body.vt .mchip:hover{ border-color: var(--brand); }

body.vt .mchip b{ font-size: 13.5px; }

body.vt .mchip.is-overdue b{ color: var(--bad); }

body.vt .mchip.is-soon b{ color: var(--warn); }

body.vt .mchip.is-draft b{ color: var(--muted); }


/* Document lifecycle strip (Stripe/FreshBooks): Issued → Sent → Viewed → Paid, dates on done steps. */
body.vt .lifec{ display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; font-size: 12px; }

body.vt .lifec-step{ display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px;
  border: 1px solid var(--line); border-radius: 999px; color: var(--muted); }

body.vt .lifec-step.done{ color: var(--ok); border-color: var(--ok); }

body.vt .lifec-step.now{ font-weight: 700; }

body.vt .lifec-step small{ font-weight: 400; opacity: .8; margin-left: 2px; }


/* Editor sticky action bar (Xero keeps Save/Approve visible) + autosave chip + money-input alignment. */
body.vt .editor-stickybar{ position: sticky; bottom: 0; z-index: 5; display: flex; align-items: center;
  justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 14px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 -6px 18px rgba(0, 0, 0, .18); }

body.vt .editor-stickybar .row-actions{ display: flex; gap: 8px; flex-wrap: wrap; }

body.vt .sticky-total{ font-size: 13px; color: var(--muted); }

body.vt .sticky-total b{ color: var(--ink); font-size: 15px; margin-left: 4px; }

body.vt .autosave-chip{ font-size: 12px; color: var(--ok); }

body.vt .editor input.num-input{ text-align: right; font-variant-numeric: tabular-nums; }

body.vt .editor-stickybar .sticky-left{ display: flex; align-items: baseline; gap: 10px; min-width: 0; }


/* ================================================================================================
   Document-page pass 2026-08-31 — Xero/Stripe/QuickBooks patterns on the detail pages.
   ================================================================================================ */

/* Xero-style "⋯" overflow menu (actionsmenu.js) */
body.vt .actions-menu{ display: inline-flex; }

body.vt .am-pop{ position: fixed; z-index: 70; min-width: 200px; background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.35); padding: 5px; display: flex; flex-direction: column; }

body.vt .am-item{ text-align: left; background: none; border: 0; color: var(--ink); font: inherit; font-size: 13px;
  padding: 8px 12px; border-radius: 7px; cursor: pointer; }

body.vt .am-item:hover{ background: var(--surface-2); }

body.vt .am-item:focus-visible{ background: var(--surface-2); outline: 1px solid var(--brand); }

body.vt .am-item.danger{ color: var(--bad); }

body.vt .am-item[disabled]{ opacity: .45; cursor: default; }


/* Stripe/Xero two-column document layout: paper left, sticky rail right; stacks under 1100px. */
body.vt .detail-cols{ display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }

body.vt .detail-main{ min-width: 0; }

/* top clears the sticky .topbar (its live height is published as --topbar-h by shellWrap; the 62px
   fallback is the desktop single-row height, so the first paint is right before the observer fires). */
body.vt .detail-side{ position: sticky; top: calc(var(--topbar-h, 62px) + 10px); display: flex; flex-direction: column; gap: 12px; }

body.vt .side-card{ margin: 0; }

body.vt .side-card h3{ margin-top: 0; }

body.vt .side-card input[readonly]{ width: 100%; font-size: 12px; margin-bottom: 8px; }

@media (max-width: 1100px){
 body.vt .detail-cols{ grid-template-columns: 1fr; }
 body.vt .detail-side{ position: static; }
 }

@media print{
 body.vt .detail-cols{ display: block; }
 }


/* Balance card (Xero's amount-due panel + QuickBooks "Receive payment") */
body.vt .balance-card .bc-due{ font-size: 14px; color: var(--muted); display: flex; align-items: baseline;
  justify-content: space-between; gap: 8px; }

body.vt .balance-card .bc-due b{ font-size: 22px; color: var(--ink); }

body.vt .bc-rows{ display: flex; flex-direction: column; gap: 4px; margin: 8px 0; font-size: 13px; color: var(--muted); }

body.vt .bc-rows span{ display: flex; justify-content: space-between; gap: 8px; }

body.vt .bc-rows b{ color: var(--ink); }

/* align-items:stretch resets the flex-end inherited from .pay-form (styles.css) so the fields fill the
   card width and their labels/values left-align (owner 2026-09-01). */
body.vt .side-payform{ display: flex; flex-direction: column; align-items: stretch; gap: 8px; margin-top: 8px;
  padding-top: 10px; border-top: 1px solid var(--line); }

body.vt .side-payform .fld{ align-items: stretch; text-align: left; }

body.vt .side-payform .btn[type=submit]{ width: 100%; }

body.vt .bc-markpaid{ margin-top: 8px; width: 100%; }


/* Contextual banners (QuickBooks/FreshBooks) */
body.vt .hint-banner{ border: 1px solid var(--line); background: var(--surface-2); color: var(--muted);
  border-radius: 10px; padding: 9px 13px; font-size: 13px; margin-bottom: 12px; }

body.vt .ovd-banner{ border: 1px solid var(--bad); background: color-mix(in srgb, var(--bad) 12%, transparent);
  color: var(--ink); border-radius: 10px; padding: 9px 13px; font-size: 13px; margin-bottom: 12px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }


/* "How to pay" banking block on the invoice paper */
body.vt .doc-paybox{margin-top:18px;padding-top:12px;border-top:1px solid #d5e0e0;break-inside:avoid}

body.vt .doc-pay-tbl{border-collapse:collapse}

body.vt .doc-pay-tbl td{font-size:12px;padding:2px 12px 2px 0;border:none;color:#1a2b2b}

body.vt .doc-pay-tbl td:first-child{color:#6a7d7d;text-transform:uppercase;font-size:10px;letter-spacing:.08em;padding-right:14px}

body.vt .doc-pay-note{font-size:10.5px;color:#6a7d7d;font-style:italic;margin-top:6px}


/* Wave 2 (2026-08-31): Xero's derived "Expired" quote state — same alarm tone as overdue. */
body.vt .pill-expired{color:var(--bad);background:rgba(242,122,122,.15)}


/* Wave 3 (2026-08-31): Xero contact-screen aging chips on the customer statement card. */
body.vt .aging-chips{ display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 10px; }

body.vt .aging-chip{ display: inline-flex; flex-direction: column; gap: 1px; padding: 5px 10px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--surface-2); }

body.vt .aging-chip small{ font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

body.vt .aging-chip b{ font-size: 13px; color: var(--ink); }

body.vt .aging-chip--warn b{ color: var(--warn); }

body.vt .aging-chip--bad b{ color: var(--bad); }


/* ── Status-visibility pass 2026-09-01 — the user is never left guessing ─────────────────────────── */
/* Amber cousin of .ovd-banner: urgent-but-not-broken (quote expiring soon, delivery late). */
body.vt .warn-banner{ border: 1px solid var(--warn); border-left-width: 4px; background: var(--surface-2);
  color: var(--ink); border-radius: 10px; padding: 10px 14px; margin: 10px 0; font-size: 13px; }

/* Sent/Viewed micro-line under a list row's status pill (Xero's list indicators). 12px = a11y floor. */
body.vt .sent-line{ font-size: 12px; color: var(--muted); margin-top: 3px; white-space: nowrap; cursor: default; }

body.vt .sent-line.sl-ok{ color: var(--ok); }

body.vt .sent-line.sl-warn{ color: var(--warn); }

body.vt .sent-line.sl-bad{ color: var(--bad); font-weight: 650; }


/* Client activity feed (dashboard) — rows echo the attention-row anatomy; the ROW is the click target */
body.vt .cact-list{ display: flex; flex-direction: column; }

body.vt .cact-row{ display: flex; align-items: center; gap: 10px; padding: 8px 6px;
  border-top: 1px solid var(--line); border-radius: 6px; cursor: pointer; }

body.vt .cact-row:first-child{ border-top: 0; }

body.vt .cact-row:hover,
body.vt .cact-row:focus-visible{ background: var(--surface-2); }

body.vt .cact-head{ display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }

body.vt .cact-head h3{ margin: 0; flex: 0 1 auto; }

body.vt .cact-head [data-cact-actions]{ margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }

/* Filter rows under the header (owner 2026-09-01): the STATUS tabs sit directly below the header —
   "below the header where all documents is" — with the document-type tabs on their own row beneath;
   the search moved up beside the title ("put the search next to the header"). */
body.vt .cact-subhead{ display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 8px; }

body.vt .cact-search{ max-width: 250px; font-size: 12.5px; padding: 5px 10px; }


/* Collapsible dashboard blocks (owner 2026-09-01: "make client activity and needs your attention
   blocks collapsable") — the header is the toggle; folded cards keep a small count so they still
   say how much they hide. State persists per browser (sleek-dash-coll). */
body.vt .coll-toggle{ cursor: pointer; user-select: none; }

body.vt .coll-ico{ display: inline-block; width: 16px; color: var(--muted); font-size: 12px; }

body.vt .coll-n{ display: none; color: var(--muted); font-weight: 500; font-size: 12.5px; margin-left: 8px; }

body.vt .dash-coll.is-collapsed .coll-n{ display: inline; }

body.vt .dash-coll.is-collapsed .coll-body,
body.vt .dash-coll.is-collapsed .cact-search,
body.vt .dash-coll.is-collapsed [data-cact-actions]{ display: none !important; }

body.vt .dash-coll.is-collapsed .cact-head,
body.vt .dash-coll.is-collapsed h3{ margin-bottom: 0; }

body.vt .segs-inline{ margin: 0; }

body.vt .segs-inline .seg{ padding: 3px 9px; font-size: 12px; }

body.vt .cact-confirm{ font-size: 12px; color: var(--muted); margin-right: 2px; }

body.vt .cact-scroll{ max-height: 430px; overflow-y: auto; }

body.vt .cact-foot{ display: flex; align-items: center; gap: 10px; padding-top: 8px; color: var(--muted); font-size: 12px; }

body.vt .cact-ico{ flex: 0 0 auto; width: 1.6em; text-align: center; }

body.vt .cact-text{ flex: 1 1 auto; min-width: 0; color: var(--ink); }

body.vt .cact-when{ flex: 0 0 auto; color: var(--muted); font-size: 12px; white-space: nowrap; }

/* Per-row status cluster: the doc's current pill + the LIFECYCLE-STRIP capsules (● done / ○ pending,
   owner 2026-09-01) so a row filtered to one kind still shows what else was fulfilled — compacted to
   fit the 38px feed rows, and never wrapping. */
body.vt .cact-badges{ display: flex; flex-wrap: nowrap; align-items: center; gap: 6px; flex: 0 0 auto; white-space: nowrap; margin-top: 0; }

body.vt .cact-badges .lifec-step{ padding: 1px 8px; white-space: nowrap; }

body.vt .lifec-step.bad{ color: var(--bad); border-color: var(--bad); }


/* Customer pay page: partial-payment amount next to Pay now (UX research 2026-09-01). */
body.vt .cust-payrow{ display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }

body.vt .cust-amt-fld{ max-width: 200px; margin: 0; }

body.vt .cust-amt-fld input{ text-align: right; font-weight: 600; }

body.vt .cust-amt-hint{ font-size: 12px; margin-top: 6px; }


/* ── List-UX pass 2026-09-01 (industry sweep: Xero/QBO/FreshBooks/Zoho/Stripe + NN/g) ───────────── */
/* Sticky header: the list tables scroll INSIDE a height-capped wrapper — position:sticky can never
   fire against the window once the wrapper has overflow-x:auto, so the wrapper becomes the scroller.
   Bonus: the pager and bulk bar stay on screen while the rows scroll. */
body.vt .tbl-sticky{ max-height: calc(100vh - 260px); min-height: 260px; overflow: auto; }

body.vt .tbl-sticky thead th{ position: sticky; top: 0; background: var(--surface-2, var(--surface)); z-index: 5;
  box-shadow: 0 1px 0 var(--line); }


/* Compact density (Xero shipped exactly this on its newest list, Oct 2025). 12px stays the floor. */
body.vt .page.dense .list th,
body.vt .page.dense .list td{ padding: 5px 8px; }

body.vt .page.dense .list{ font-size: 12.5px; }

body.vt .page.dense .tbl-sticky{ max-height: calc(100vh - 220px); }


/* Keyboard list navigation (j/k/Enter/x — the Gmail/Stripe/Linear convention). */
body.vt .list tbody tr.kb-focus{ outline: 2px solid var(--brand); outline-offset: -2px; }

body.vt .list tbody tr.kb-focus td{ background: rgba(42, 224, 224, .06); }


/* Cell subtexts: overdue-days on the invoices Due-date column, expiry countdown on quotes.
   12px (not the base 11px) — the a11y floor. */
body.vt .cell-sub.sub-bad{ color: var(--bad); font-size: 12px; font-weight: 600; }

body.vt .cell-sub.sub-warn{ color: var(--warn); font-size: 12px; font-weight: 600; }


/* Row-level actions: contextual primary + ⋯ overflow, right-aligned, never wrapping. */
body.vt td.row-act .btn{ margin-left: 6px; }

body.vt td.row-act .btn:first-child{ margin-left: 0; }

body.vt .btn.sm.am-trigger{ padding: 2px 9px; font-weight: 700; }


/* Wide list screens (owner 2026-09-01: "show the full page if the browser allows, users must not
   need to scroll left and right") — the document LISTS get a wider cap so their tables fit; detail
   pages keep the 1000px reading width. Horizontal scroll remains only when the window is small. */
body.vt .page.page-wide{ max-width: 1440px; }


/* Uniform list stack (owner): toolbar → money strip → status tabs → table, with air between the
   tabs and the table header on every list (invoices, quotes, bills — tabs were touching the grid). */
body.vt .segs.segs-list{ margin: 4px 0 14px; }

body.vt .money-strip{ margin-bottom: 10px; }


/* Scan-a-document chooser: the kind tabs and the Choose-a-file button were sitting flush against
   the dropzone (owner). */
body.vt .scan-chooser .segs{ margin: 10px 0 12px; }

body.vt .dropzone ~ .row-actions{ margin-top: 10px; }


/* The Apply-credit button sat flush under "Mark paid in full" (owner). */
body.vt .bc-applycredit{ margin-top: 8px; }


/* Feed rows: the status pill rides the END of the description with a little air (owner 2026-09-01:
   "make a slight space between the OVERDUE … and the status pins — maybe add it to the end of the
   description"), leaving the lifecycle capsules as their own right-hand cluster. */
body.vt .cact-pill{ margin-left: 8px; vertical-align: middle; }


/* ══ List-UX sweep №2 (2026-09-01, owner: "implement all") ══════════════════════════════════════ */

/* Money-strip: the GOOD half of the picture (QBO) — open-but-fine and recently-received tones. */
body.vt .mchip.is-open b{ color: var(--ink); }

body.vt .mchip.is-in b{ color: var(--ok); }


/* Advanced filters panel (Xero's expandable search / FreshBooks Advanced Search). */
body.vt .adv-panel{ display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; margin: -6px 0 14px;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }

body.vt .adv-panel.adv-hide{ display: none; }

body.vt .adv-panel .fld.inline{ display: flex; flex-direction: column; gap: 4px; margin: 0; }

body.vt .adv-panel .fld.inline > span{ font-size: 12px; color: var(--muted); }

body.vt .adv-panel input,
body.vt .adv-panel select{ min-width: 130px; }

body.vt .btn.adv-on{ border-color: var(--brand); color: var(--brand); }


/* Expected payment date (Xero's Awaiting-Payment column) — a quiet inline date the row can carry. */
body.vt .exp-input{ background: transparent; border: 1px solid transparent; border-radius: 6px; color: var(--ink);
  font: inherit; font-size: 12.5px; padding: 2px 4px; max-width: 130px; }

body.vt .exp-input:hover,
body.vt .exp-input:focus{ border-color: var(--line); background: var(--surface); }


/* Saved views: ★ tabs after the built-ins + the ☆ save control (Zoho custom views / Polaris). */
body.vt .seg.seg-view{ border-style: dashed; }

body.vt .seg.seg-save{ color: var(--muted); border-style: dashed; }

body.vt .seg .seg-x{ margin-left: 7px; opacity: .7; font-size: 11px; }

body.vt .seg .seg-x:hover{ opacity: 1; color: var(--bad); }


/* Compose-dialog extras: attach checkbox + Send later row (Xero schedule send). */
body.vt .mail-extra{ display: flex; align-items: center; gap: 8px; font-size: 12.5px; margin: 8px 0 0; }

body.vt .mail-later-row{ gap: 12px; }

body.vt .mail-later-row .mail-date{ max-width: 160px; }


/* Batch payment dialog (Xero "Deposit"): the settled-in-full list + shared fields. */
body.vt .bp-hint{ font-size: 12.5px; margin: 0 0 10px; }

body.vt .bp-list{ max-height: 200px; overflow-y: auto; margin-bottom: 12px; }

body.vt .bp-fields{ display: flex; gap: 12px; flex-wrap: wrap; }

body.vt .bp-fields .fld{ flex: 1 1 140px; }


/* Activity peek (QBO/Invoice Ninja slide-over): right panel, timeline rows, meta grid. */
body.vt .peek-overlay{ position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.35); opacity: 0; transition: opacity .16s ease; }

body.vt .peek-overlay.open{ opacity: 1; }

body.vt .peek-panel{ position: absolute; top: 0; right: 0; height: 100%; width: 430px; max-width: 92vw;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: -14px 0 40px rgba(0,0,0,.3);
  padding: 18px 20px 22px; overflow-y: auto; transform: translateX(100%); transition: transform .18s ease; outline: none; }

body.vt .peek-overlay.open .peek-panel{ transform: translateX(0); }

body.vt .peek-head{ position: relative; padding-right: 34px; margin-bottom: 10px; }

body.vt .peek-title{ font-size: 17px; font-weight: 700; display: flex; align-items: center; gap: 10px; }

body.vt .peek-title .pill{ font-size: 11px; }

body.vt .peek-sub{ color: var(--muted); font-size: 12.5px; margin-top: 3px; }

body.vt .peek-x{ position: absolute; top: -2px; right: -4px; background: none; border: none; color: var(--muted);
  font-size: 15px; cursor: pointer; padding: 6px; border-radius: 8px; }

body.vt .peek-x:hover{ background: var(--surface-2); color: var(--ink); }

body.vt .peek-meta{ border: 1px solid var(--line); border-radius: 10px; padding: 4px 12px; margin: 12px 0; }

body.vt .peek-meta-row{ display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--line); font-size: 12.5px; }

body.vt .peek-meta-row:last-child{ border-bottom: none; }

body.vt .peek-meta-label{ color: var(--muted); }

body.vt .peek-meta-val{ font-weight: 600; text-align: right; }

body.vt .peek-events{ margin: 12px 0 4px; }

body.vt .peek-ev{ display: flex; gap: 10px; padding: 8px 2px; border-top: 1px solid var(--line); font-size: 12.5px; }

body.vt .peek-ev:first-child{ border-top: none; }

body.vt .peek-ev-ico{ flex: 0 0 20px; text-align: center; }

body.vt .peek-ev-body{ flex: 1 1 auto; min-width: 0; }

body.vt .peek-ev-label{ font-weight: 600; }

body.vt .peek-ev-sub{ color: var(--muted); margin-top: 1px; overflow-wrap: anywhere; }

body.vt .peek-ev-when{ flex: 0 0 auto; color: var(--muted); font-size: 12px; white-space: nowrap; }

body.vt .peek-ev-bad .peek-ev-label{ color: var(--bad); }

body.vt .peek-foot{ display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }


/* Column chooser popover (colchooser.js) — .am-pop's look for a checkbox list. */
body.vt .col-menu{ position: fixed; z-index: 70; min-width: 220px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.35);
  padding: 6px; display: flex; flex-direction: column; }

body.vt .col-head{ font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); padding: 6px 10px 5px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }

body.vt .col-row{ display: flex; align-items: center; gap: 9px; padding: 7px 10px; border-radius: 7px;
  font-size: 13px; color: var(--ink); cursor: pointer; user-select: none; }

body.vt .col-row:hover{ background: var(--surface-2); }

body.vt .col-row input[type="checkbox"]{ margin: 0; flex: none; accent-color: var(--brand); }

body.vt .col-row input[type="checkbox"]:disabled{ opacity: .55; cursor: default; }

body.vt .col-row input[type="checkbox"]:disabled + span{ color: var(--muted); }

body.vt .col-menu .btn.col-reset{ margin: 6px 4px 2px; align-self: flex-start; }


/* Saved-views name dialog (savedviews.js). */
body.vt .view-hint{ font-size: 12px; margin: 6px 0 0; }


/* Statement + delivery-note papers (paperextras.js) — paper palette literals match the paper's own. */
body.vt .stmt-aging{ display: flex; gap: 10px; margin: 16px 0 6px; }

body.vt .stmt-aging .stmt-bucket{ flex: 1; border: 1px solid #e6eeee; border-radius: 8px; padding: 8px 10px; text-align: right; }

body.vt .stmt-aging .num{ font-size: 13px; font-weight: 600; }

body.vt .statement-paper .doc-meta-line{ font-size: 12px; }

body.vt .dn-signoff{ display: flex; gap: 28px; margin-top: 44px; }

body.vt .dn-signoff .dn-sign{ flex: 1; }

body.vt .dn-signoff .dn-rule{ height: 34px; border-bottom: 1px solid #1a2b2b; margin-bottom: 6px; }


/* Statement picker dialog (reports → Statement: print/email upgrades). */
body.vt .stmt-tools{ display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin: 10px 0 14px; }


/* Printing a document page must yield THE PAPER ONLY — banners, the sticky rail, receiving grids
   and every list control were leaking into PDFs (and Chrome's print emulation made pages look
   full-bleed "landscape" while the dialog was open). */
@media print{

  body.vt .sidebar,
body.vt aside,
body.vt .detail-side,
body.vt .warn-banner,
body.vt .ovd-banner,
body.vt .segs,
body.vt .money-strip,
body.vt .list-toolbar,
body.vt .bulk-bar,
body.vt .pager,
body.vt .list-actions,
body.vt .attention-card,
body.vt .scan-chooser,
body.vt .adv-panel,
body.vt .peek-overlay{ display: none !important; }

  body.vt .detail-main > :not(.invoice-paper){ display: none !important; }

  body.vt .detail-cols{ display: block !important; }

}


/* Keyboard-shortcut sheet (the "?" overlay). */
body.vt .kbd-sheet{ max-width: 440px; }

body.vt .kbd-sheet h3{ margin: 0 0 10px; }

body.vt .kbd-table{ width: 100%; border-collapse: collapse; }

body.vt .kbd-table td{ padding: 7px 8px; border-top: 1px solid var(--line); font-size: 13px; }

body.vt .kbd-table td:first-child{ white-space: nowrap; }

body.vt kbd{ display: inline-block; padding: 1px 6px; border: 1px solid var(--line); border-bottom-width: 2px;
  border-radius: 5px; background: var(--surface-2, var(--surface)); font-family: inherit; font-size: 12px; }



