:root {
  --bg:#f2f2f2;--surface:#fff;--border:#d4d4d4;--border-focus:#2563a8;
  --text:#1a1916;--muted:#888;--accent:#2563a8;--accent-h:#1d4f8a;
  --accent2:#7c3aed;--accent2-h:#6d28d9;
  --danger:#c0392b;--warn:#d97706;--ok:#1a7a4a;
  --hdr:#fafafa;--row-h:#f5f8ff;
  --faint:#bbb;--surface-2:#f0f4f8;--line-soft:#eee;--danger-bg:#fdf1f0;
  --info-bg:#eff6ff;--info-bd:#bfdbfe;
  color-scheme:light;
  --mono:'JetBrains Mono','Fira Mono',monospace;
}
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);font-size:13px;min-height:100vh;display:flex;flex-direction:column;}
/* #login-screen / #app-screen (the single top-level element {% block body %}
   renders) grow to fill whatever space the banner + footer don't use, so the
   footer sits right at the visible bottom of the viewport on short pages
   instead of floating mid-page, while still following normal document flow
   (and scrolling to the true end) once real content — the journal's
   transaction list — is taller than the viewport. */
#login-screen,#app-screen{flex:1 0 auto;}
#legal-footer{flex-shrink:0;text-align:center;font-size:10px;color:var(--faint);padding:10px 16px 14px;}

/* Login */
#login-screen{display:flex;align-items:center;justify-content:center;}
.login-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:32px;width:320px;box-shadow:0 4px 20px rgba(0,0,0,.08);}
.login-card h2{font-size:18px;font-weight:700;margin-bottom:20px;}
.login-card .field{margin-bottom:12px;}
.login-card .field label{display:block;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);margin-bottom:4px;}
.login-card .field input{width:100%;height:36px;padding:0 10px;border:1px solid var(--border);border-radius:4px;font-size:14px;}
.login-card .field input:focus{outline:none;border-color:var(--border-focus);}
.login-card button{width:100%;height:36px;background:var(--accent);color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:600;cursor:pointer;margin-top:4px;}
.login-card button:hover{background:var(--accent-h);}
.login-err{color:var(--danger);font-size:12px;margin-top:8px;display:none;}
.login-err.show{display:block;}
.login-msg{color:var(--muted);font-size:12px;margin-top:8px;display:none;}
.login-msg.show{display:block;}
.login-links{margin-top:16px;font-size:13px;color:var(--muted);}
.login-links a{color:inherit;text-decoration:underline;}
.login-links a:hover{color:var(--accent);}

/* Build/version banner — commit + date this container was built from
   (tools/deploy.py bakes build_info.json in at build time). Absent on local
   dev (no build), so it never displaces the login card there. */
#build-info-banner{flex-shrink:0;text-align:center;font-size:10px;color:var(--muted);padding:2px 0;background:var(--hdr);border-bottom:1px solid var(--border);letter-spacing:.2px;}

/* App */
.app{max-width:1400px;margin:0 auto;padding:16px;}
.mode-badge{font-size:11px;font-weight:600;padding:2px 8px;border-radius:10px;letter-spacing:.3px;}
.mode-new{background:#dbeafe;color:var(--accent);}
.mode-edit{background:#fef3c7;color:#92400e;}
.mode-locked{background:#fee2e2;color:#991b1b;}
.logout-btn{margin-left:auto;font-size:11px;color:var(--muted);background:none;border:none;cursor:pointer;padding:4px 8px;}
.logout-btn:hover{color:var(--danger);}

/* Card */
.card{background:var(--surface);border:1px solid var(--border);border-radius:6px;margin-bottom:14px;overflow:hidden;}
.card-hdr{padding:10px 14px;background:var(--hdr);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;flex-wrap:wrap;}
.card-title{font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:var(--muted);}

/* Mode tabs (e.g. Journal/Imported) — clickable sections with a live count,
   not buttons: this is navigation between two views of the same data, not
   an action, so it reads as tabs rather than a pair of competing buttons. */
.mode-tabs{display:flex;}
.mode-tab{display:flex;flex-direction:column;gap:1px;padding:4px 16px;border-bottom:3px solid transparent;cursor:pointer;user-select:none;border-radius:4px 4px 0 0;}
.mode-tab:hover{background:rgba(0,0,0,.03);}
.mode-tab.active{border-bottom-color:var(--accent);}
.mode-tab-title{font-size:12px;font-weight:700;color:var(--muted);}
.mode-tab.active .mode-tab-title{color:var(--accent);}
.mode-tab-count{font-size:10px;color:var(--muted);}
/* Journal and Imported read as genuinely different modes, not just two tabs
   with one of them dimmed — Imported (bank statement reconciliation) gets
   its own color so which list you're looking at is clear without reading
   the label. */
#browser-mode-imported-btn.active{border-bottom-color:var(--accent2);}
#browser-mode-imported-btn.active .mode-tab-title{color:var(--accent2);}

/* Fields */
.field{display:flex;flex-direction:column;gap:3px;}
/* Company pane (Admin › Company) */
.co-form{padding:0 14px 14px;display:flex;flex-direction:column;gap:12px;}
.co-group{border:1px solid var(--border);border-radius:6px;padding:8px 12px 12px;margin:0;}
.co-group legend{font-size:11px;font-weight:600;color:var(--muted);padding:0 4px;}
.co-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;}
.co-grid .field input,.co-grid .field select{width:100%;box-sizing:border-box;}
.co-grid .field input.co-dirty,.co-grid .field select.co-dirty{border-color:var(--border-focus);}
.co-section{margin-top:10px;padding-top:12px;border-top:2px solid var(--border);display:flex;flex-direction:column;gap:2px;}
.co-section-title{font-size:13px;font-weight:600;}
@media (max-width:720px){.co-grid{grid-template-columns:repeat(2,minmax(0,1fr));}}
.field label{font-size:10px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);}
.field input,.field select{height:30px;padding:0 8px;border:1px solid var(--border);border-radius:4px;font-size:13px;font-family:inherit;background:var(--surface);color:var(--text);}
/* Entry header (date/reference/concept/type/BP) gets normal-contrast labels
   — it's the always-active part of the form, unlike the items section which
   is intentionally muted/disabled until the header is complete. Scoped to
   #entry-header specifically so the report/browse section's identical
   .card-title/.field label styling elsewhere is untouched. */
#entry-header .card-title,#entry-header .field label{color:var(--text);}
.ms-btn{height:30px;padding:0 8px;border:1px solid var(--border);border-radius:4px;font-size:13px;font-family:inherit;background:var(--surface);color:var(--text);text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;}
.ms-btn:focus{outline:none;border-color:var(--border-focus);box-shadow:0 0 0 2px rgba(37,99,168,.1);}
.field input:focus,.field select:focus{outline:none;border-color:var(--border-focus);box-shadow:0 0 0 2px rgba(37,99,168,.1);}
.hint{font-size:10px;color:var(--muted);min-height:13px;}

/* Excel-style single-field date filter (bank import): the visible control is
   just one button showing the current operator+date (or "All"); the actual
   operator/date pickers live in a popover, not as permanent extra fields. */
.date-filter-btn{height:30px;padding:0 8px;border:1px solid var(--border);border-radius:4px;font-size:12px;font-family:inherit;background:var(--surface);color:var(--text);cursor:pointer;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.date-filter-btn:hover{border-color:var(--border-focus);}
.date-filter-pop{position:fixed;z-index:9999;background:var(--surface);border:1px solid var(--border);border-radius:6px;box-shadow:0 6px 20px rgba(0,0,0,.15);padding:8px;display:none;flex-direction:column;gap:6px;min-width:150px;}
.date-filter-pop .dfp-row{display:flex;gap:4px;}
.date-filter-pop .dfp-op{flex:1;padding:4px 0;border:1px solid var(--border);border-radius:4px;background:var(--surface);color:var(--text);cursor:pointer;font-size:13px;}
.date-filter-pop .dfp-op:hover{border-color:var(--border-focus);}
.date-filter-pop .dfp-op.active{background:var(--accent);color:#fff;border-color:var(--accent);}
.date-filter-pop input[type=date],.date-filter-pop input[type=number]{width:100%;height:28px;padding:0 6px;border:1px solid var(--border);border-radius:4px;font-size:12px;font-family:inherit;}
.kebab-btn{font-size:16px;line-height:1;padding:0 9px;}
#btn-attach-doc{opacity:.55;}
#btn-attach-doc.has-doc{opacity:1;background:var(--accent);color:#fff;border-color:var(--accent);}
.kebab-pop{min-width:150px;padding:4px;gap:0;}
.kebab-item{background:none;border:none;color:var(--text);font-size:12px;text-align:left;cursor:pointer;padding:7px 10px;border-radius:4px;white-space:nowrap;}
.kebab-item:hover:not(:disabled){background:var(--surface-2);}
.kebab-item.active{font-weight:700;color:var(--accent);}
.mode-kebab-row{display:none;}
.kebab-btn,.kebab-item,.sp-ghost{touch-action:manipulation;-webkit-tap-highlight-color:transparent;}
.th-kebab{height:20px;font-size:13px;padding:0 5px;margin-right:4px;vertical-align:middle;}
.lt td.sp-off{background:var(--surface-2);}
.lt td.sp-off .acw,.lt td.sp-off .acn{display:none;}
.lt td:not(.sp-off) > .sp-ghost{display:none;}
.sp-ghost{height:27px;line-height:27px;text-align:center;color:var(--faint);cursor:pointer;border-radius:3px;}
.sp-ghost:hover,.sp-ghost:focus{color:var(--text);outline:1px dashed var(--border-focus);}
.kebab-item:disabled{color:var(--faint);cursor:not-allowed;}
.kebab-item.kebab-danger:not(:disabled){color:var(--danger);}
.kebab-hdr{font-size:11px;color:var(--muted);padding:5px 10px 4px;border-bottom:1px solid var(--border);margin-bottom:2px;}
.doc-bill-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.date-filter-pop .dfp-clear{background:none;border:none;color:var(--muted);font-size:11px;text-align:left;cursor:pointer;padding:2px 0;}
.date-filter-pop .dfp-clear:hover{color:var(--danger);}
/* Row-actions popover (e.g. admin users table): plain menu items, same look
   as .dfp-clear, but the destructive one is red by default rather than only
   on hover — it needs to read as dangerous even before the pointer reaches it. */
.date-filter-pop .dfp-clear.dfp-danger{color:var(--danger);}
.date-filter-pop .dfp-clear.dfp-danger:hover{opacity:.75;}

/* Lines table — key: overflow visible on table and cells.
   Cells align top, not middle: three of them (Soll, Haben, Amount) carry a
   second line under the box — the account name, the net base — and stretch
   the row. Centred, every *other* cell then floated in the taller row while
   those three kept their box at the top, which is why Amount used to sit 7px
   above Curr. Top-aligned, all ten fields share one 27px band and the hints
   hang below it; anything in a cell that isn't a 27px control (the ⇌, the
   CHF figure, the checkboxes) is put on that band by hand. */
.lines-wrap{overflow-x:auto;overflow-y:visible;}
table.lt{width:100%;border-collapse:collapse;font-size:12px;overflow:visible;}
.lt thead tr th{padding:5px 4px;font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);background:var(--hdr);border-bottom:1px solid var(--border);white-space:nowrap;}
.lt thead tr th.r{text-align:right;padding-right:10px;}
.lt tbody tr td{padding:3px 4px;border-bottom:1px solid var(--line-soft);vertical-align:top;overflow:visible;position:relative;}
.lt tbody tr:hover td{background:var(--row-h);}

/* Account autocomplete — critical z-index fix */
.acw{position:relative;}
.acinp{width:100%;height:27px;padding:0 6px;border:1px solid var(--border);border-radius:3px;font-size:12px;font-family:var(--mono);font-weight:600;display:block;}
.acinp:focus{outline:none;border-color:var(--border-focus);}
.acinp.invalid-account{border-color:var(--danger);background:var(--danger-bg);}
/* A foreign-currency line whose month has no row in FX_Rates. The cell is
   empty because there is no rate to show, not because the user forgot to
   type one — the rate is never typed in — so it is flagged the same way an
   unknown account is, and validateEntry names the currency and month. */
.li.rate-missing{border-color:var(--danger);background:var(--danger-bg);}
/* A proposed (not locked) default account — editable, styled as a hint that
   it came from the type's allowed-accounts list rather than the user. */
.acinp.locked-default{background:var(--surface-2);}
/* External ref. holding a legacy payment's inherited identity — disabled, and
   tinted the same way as a system-supplied value so it doesn't read as broken. */
#f-ref.locked-default{background:var(--surface-2);color:var(--muted);cursor:not-allowed;}
.acn{font-size:10px;color:var(--muted);margin-top:1px;white-space:nowrap;max-width:110px;overflow:hidden;text-overflow:ellipsis;min-height:13px;}
.acl{position:fixed;z-index:9999;background:var(--surface);border:1px solid var(--border);border-radius:4px;box-shadow:0 6px 20px rgba(0,0,0,.15);max-height:200px;overflow-y:auto;min-width:280px;display:none;}
.acl.show{display:block;}
.ali{padding:6px 10px;cursor:pointer;font-size:12px;display:flex;gap:8px;align-items:center;}
.ali:hover,.ali.sel{background:var(--row-h);}
.ali .ac{font-family:var(--mono);font-weight:700;color:var(--accent);min-width:50px;}
.ali .an{color:var(--text);}

/* Line inputs */
.li{height:27px;padding:0 5px;border:1px solid var(--border);border-radius:3px;font-size:12px;font-family:inherit;background:var(--surface);color:var(--text);width:100%;}
.li:focus{outline:none;border-color:var(--border-focus);}
.li.r{font-family:var(--mono);text-align:right;}
.ls{height:27px;padding:0 4px;border:1px solid var(--border);border-radius:3px;font-size:11px;background:var(--surface);width:100%;}
/* A line select the app fixed rather than the user: an imported bank line's
   currency, a derived VAT line's code. Tinted like .acinp.locked-default so a
   locked field looks the same whichever control it happens to be. */
.ls:disabled{background:var(--surface-2);color:var(--muted);cursor:not-allowed;}
.ls:focus{outline:none;border-color:var(--border-focus);}
.chfd{font-family:var(--mono);font-size:12px;line-height:27px;text-align:right;color:var(--muted);padding-right:6px;}
.bdel{width:22px;height:22px;border:none;background:none;color:var(--muted);cursor:pointer;font-size:15px;border-radius:3px;display:flex;align-items:center;justify-content:center;}
.bdel:hover{background:#fee2e2;color:var(--danger);}
.lsel{width:15px;height:15px;margin:0 auto;display:block;cursor:pointer;accent-color:var(--danger);}
/* Gross/Net per line. Sits in the accent colour, not the danger red the
   Select boxes use — ticking it changes how the amount is read, it does
   not mark the row for deletion. */
.lgross{width:15px;height:15px;margin:0 auto;display:block;cursor:pointer;accent-color:var(--accent);}
.lgross:disabled{cursor:not-allowed;opacity:.5;}
/* The derived base under a gross amount, right-aligned under it. */
.acn.r{text-align:right;max-width:none;padding-right:6px;}
.lsel:disabled{cursor:not-allowed;}
/* Centred on the 27px control band the row's inputs occupy: (27-15)/2, and
   one more for .gsel, which is the browser's own 13px box. */
.lt tbody td .lsel,.lt tbody td .lgross{margin-top:6px;}
.lt tbody td .gsel{margin-top:7px;}
/* The ⇌ between Soll and Haben — text, so it needs the band spelled out. */
.larr{color:var(--faint);font-size:13px;line-height:27px;text-align:center;}

/* Line grid on a phone: the desktop table (11 fixed-width columns, ~690px)
   doesn't fit a phone screen, and .lines-wrap's horizontal scroll gave no
   visual hint there was more to the right — a loaded entry's VAT/Gross/
   Amount/Curr./Rate/CHF looked simply missing (reported testing on iPhone,
   2026-09-08). Below the breakpoint each row becomes a stacked card instead:
   every <td> drops out of table layout and shows a small caps label — set as
   data-label by addLine/addSplitLine/relabelLineCells in app.js, since these
   rows are built once in JS and the language switch re-labels them in place
   rather than rebuilding (see onLanguageChange). A <td> with no data-label
   (the ⇌ divider, the row-select checkbox) gets no label line. */
@media (max-width:600px){
  table.lt,.lt tbody,.lt tr{display:block;width:100%;}
  .lt thead{display:none;}
  .larr{display:none;}
  .mode-kebab-row{display:flex;align-items:center;justify-content:space-between;padding:8px 14px 0;}
  .lt thead .th-kebab{display:none;}
  .lt tbody tr{border:1px solid var(--border);border-radius:6px;margin-bottom:10px;padding:4px 0;}
  .lt tbody tr td{display:block;width:auto;padding:5px 10px;border-bottom:none;}
  .lt tbody tr td[data-label]::before{content:attr(data-label);display:block;font-size:9px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);margin-bottom:2px;}
  .lt tbody tr td .li.r,.lt tbody tr td .chfd{text-align:left;padding-right:0;}
  .lt tbody td .lsel,.lt tbody td .lgross{margin:0;}
  .acn{max-width:none;}
}

/* Totals */
.totbar{display:flex;gap:20px;align-items:center;padding:8px 14px;background:var(--hdr);border-top:1px solid var(--border);font-family:var(--mono);font-size:13px;flex-wrap:wrap;}
.tg{display:flex;gap:7px;align-items:baseline;}
.tl{font-size:10px;font-family:inherit;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);}
.tv{font-weight:700;}
.ok{color:var(--ok);}.bad{color:var(--danger);}

/* Actions */
.actbar{display:flex;gap:8px;align-items:center;padding:10px 14px;border-top:1px solid var(--border);background:var(--hdr);flex-wrap:wrap;}
.btn-export{display:inline-flex;align-items:center;gap:6px;}
.btn-export .ico-xls{flex:none;}
.btn-conf{display:inline-flex;align-items:center;gap:6px;}
.btn-conf .ico-conf{flex:none;}
.btn{height:32px;padding:0 14px;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;transition:all .12s;border:none;white-space:nowrap;}
.bp{background:var(--accent);color:#fff;}
.bp:hover:not(:disabled){background:var(--accent-h);}
.bp:disabled{background:#9ab4d4;cursor:not-allowed;}
.bs{background:none;border:1px solid var(--border);color:var(--text);}
.bs:hover{border-color:#999;}
.bdd{background:none;border:1px solid #fca5a5;color:var(--danger);}
.bdd:hover{background:#fee2e2;}
/* Bank-import list toolbar (Ignore / Undo / Delete): each stays disabled until
   the ticked rows include one its endpoint accepts (updateImportActionBar). */
.imp-act:disabled{opacity:.4;cursor:not-allowed;}
.imp-act:disabled:hover{background:none;}
.badd{background:none;border:1px dashed var(--border);color:var(--accent);font-size:11px;}
.badd:hover{border-color:var(--accent);background:var(--info-bg);}
.sp{flex:1;}

/* Status */
.sts{padding:7px 12px;border-radius:4px;font-size:12px;margin:6px 14px 0;display:none;}
.sts.show{display:block;}
.sts.success{background:#ecfdf5;border:1px solid #a7f3d0;color:var(--ok);}
.sts.error{background:#fef2f2;border:1px solid #fecaca;color:var(--danger);}
.sts.warn{background:#fffbeb;border:1px solid #fde68a;color:var(--warn);}
.sts.info{background:var(--info-bg);border:1px solid var(--info-bd);color:var(--accent);}
.dupw{padding:5px 12px;background:#fffbeb;border-left:3px solid #fbbf24;font-size:11px;color:var(--warn);display:none;margin:4px 14px;}
.dupw.show{display:block;}

/* Browser */
.brf{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;}
/* Lets a wrapper group its mode-specific fields for a single JS toggle while
   its .field children still flex-flow as if unwrapped. */
.filter-group{display:contents;}
/* 13 columns (14 with Contra) outgrow a narrow window — the table scrolls
   inside its own wrapper rather than being clipped by the card. */
#tx-wrap{overflow-x:auto;}
.btx{width:100%;border-collapse:collapse;font-size:12px;}
.btx th{padding:6px 8px;font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);border-bottom:2px solid var(--border);background:var(--hdr);text-align:left;white-space:nowrap;}
.btx td{padding:6px 8px;border-bottom:1px solid var(--line-soft);vertical-align:top;}
.btx tr.dr:hover td{background:var(--row-h);cursor:pointer;}
/* Suggested bank-import group (suggested-groups) — a hint only, never
   auto-selected; the user still ticks the rows themselves for "Match as group". */
.btx tr.imp-suggested td{background:rgba(59,130,246,.07);border-left:2px solid var(--accent);}
.btx tr.imp-suggested:hover td{background:rgba(59,130,246,.14);}
/* Free-text cells (concept, business partner) stay on one line and truncate
   to whatever width the row has left; the full text is the cell's tooltip.
   max-width:0 lets the % column widths, not the text length, size the column. */
.btx td.nw{white-space:nowrap;}
/* Reconciliation tick: one small centred box, so the row keeps its height. */
.btx td.rc{text-align:center;padding-left:2px;padding-right:2px;}
.btx td.rc input{margin:0;width:14px;height:14px;cursor:pointer;accent-color:var(--accent);vertical-align:middle;}
.btx td.rc input:disabled{cursor:not-allowed;opacity:.7;}
/* Statement-balance check above the list, shown for a single bank account. */
#ledger-recon{gap:18px;font-size:12px;}
#ledger-recon label{display:flex;align-items:center;gap:6px;font-size:10px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;}
#ledger-recon input{height:28px;padding:0 6px;border:1px solid var(--border);border-radius:4px;font-size:12px;font-family:inherit;}
#ledger-recon input[type=number]{width:120px;text-align:right;font-family:var(--mono);}
#ledger-recon .tl{font-weight:600;color:var(--muted);text-transform:uppercase;font-size:10px;letter-spacing:.5px;}
#ledger-recon .tv{margin-left:6px;font-family:var(--mono);font-weight:700;}
#ledger-recon .rp-ok{color:var(--ok, #1a7f37);}
#ledger-recon .rp-off{color:var(--danger);}

.btx td.clip{max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.btx .mo{font-family:var(--mono);}
.btx .r{text-align:right;white-space:nowrap;}
.btx .mu{color:var(--muted);font-size:11px;}
/* Sortable headers: the whole cell is the target, and the arrow marks which
   column the server actually ordered by. */
.doc-filter-row th{padding:2px 8px 6px;background:var(--hdr);border-bottom:2px solid var(--border);}
.doc-col-filter{width:100%;height:24px;padding:0 6px;border:1px solid var(--border);border-radius:4px;font-size:11px;font-family:inherit;background:var(--surface);color:var(--text);box-sizing:border-box;}
.doc-notes{width:100%;height:24px;padding:0 6px;border:1px solid transparent;border-radius:4px;font-size:12px;font-family:inherit;background:transparent;color:var(--text);box-sizing:border-box;}
.doc-notes:hover{border-color:var(--border);}
.doc-notes:focus{outline:none;border-color:var(--border-focus);background:var(--surface);}
.doc-date{width:100%;height:24px;padding:0 4px;border:1px solid transparent;border-radius:4px;font-size:12px;font-family:inherit;background:transparent;color:var(--text);box-sizing:border-box;}
.doc-date:hover{border-color:var(--border);}
.doc-date:focus{outline:none;border-color:var(--border-focus);background:var(--surface);}
.btx th.sortable,.pr-table th.sortable{cursor:pointer;user-select:none;}
.btx th.sortable:hover,.pr-table th.sortable:hover{color:var(--text);}
.btx th.sorted,.pr-table th.sorted{color:var(--accent);}
.btx th .sarr,.pr-table th .sarr{margin-left:4px;font-size:9px;}
.btx th.sortlocked{cursor:not-allowed;opacity:.55;}
/* Vendor Bills report only: fixed column widths so every row stays exactly
   one line (long titles/vendor names truncate with an ellipsis instead of
   wrapping) — the full value is still available via each cell's title
   tooltip. Scoped to #vb-wrap so other .btx reports keep wrapping. */
#vb-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
#vb-wrap table{table-layout:fixed;}
#vb-wrap td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
/* Excel-style per-column filters, one row under the headers. Inputs are kept
   small — the goal is "narrow this column", not a full form. */
.btx tr.filter-row td{padding:3px 6px;background:var(--hdr);border-bottom:2px solid var(--border);}
.btx .cf-input{width:100%;box-sizing:border-box;font-size:11px;padding:2px 4px;border:1px solid var(--border);border-radius:3px;background:var(--surface);}
.btx .cf-range{display:flex;gap:3px;}
.btx .cf-range .cf-input{width:50%;min-width:0;}
.btx button.cf-input{cursor:pointer;text-align:left;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.btx .notes-input{width:100%;box-sizing:border-box;font-size:11px;padding:2px 4px;border:1px solid var(--border);border-radius:3px;background:var(--surface);color:var(--text);}
/* Running balance: the column the eye follows down an account statement. */
.btx td.bal{font-weight:600;}
/* Totals over the whole filtered set — styled like the report totals it mirrors. */
.btx tfoot tr.tx-totals td{padding:8px;font-weight:700;background:var(--row-h);border-top:2px solid var(--border);}
.btx tfoot tr.tx-totals .tl{font-weight:600;color:var(--muted);text-transform:uppercase;font-size:10px;letter-spacing:.5px;}
.btx tfoot tr.tx-totals .tv{margin-left:8px;font-family:var(--mono);}
/* Value date input: grayed out while the checkbox that enables it is off, so
   it reads as inert rather than as an editable field nobody has touched yet
   — same treatment as .pr-date's disabled state. */
#f-value-date:disabled{background:var(--hdr);color:var(--muted);}

/* Checkbox that sits in a .field next to the text filters without inheriting
   the 30px bordered input styling. */
.chkline{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text);text-transform:none;letter-spacing:0;font-weight:400;}
.chkline input[type=checkbox]{height:auto;width:auto;padding:0;border:none;box-shadow:none;margin:0;}
.chkline input[type=checkbox]:disabled + span{color:var(--muted);}

/* Reports — row emphasis mirrors the hierarchy depth: sections/L1 heaviest,
   totals highlighted, plain accounts indented and lightest. */
.report-tbl tr.rpt-section td, .report-tbl tr.rpt-l1 td{font-weight:700;background:var(--hdr);border-top:2px solid var(--border);}
.report-tbl tr.rpt-group td, .report-tbl tr.rpt-l2 td{font-weight:600;}
.report-tbl tr.rpt-subgroup td, .report-tbl tr.rpt-l3 td{font-weight:600;color:var(--muted);}
.report-tbl tr.rpt-account td:nth-child(2){padding-left:28px;}
.report-tbl tr.rpt-total td, .report-tbl tr.rpt-subtotal td{font-weight:700;border-top:2px solid var(--border);background:var(--row-h);}
.badge{display:inline-block;padding:1px 5px;border-radius:3px;font-size:10px;font-weight:700;font-family:var(--mono);}
.bdr{background:#dbeafe;color:#1e3a5f;}.bcr{background:#ede9fe;color:#4c1d95;}
/* Each state carries two colours: the pale one it paints as a background
   (chip in a list, or the whole status strip) and --bst-ink, the solid one
   the strip's own badge is filled with so the label reads as a label. */
.bst-pending{background:#fef3c7;--bst-tint:#fef3c7;color:#92400e;--bst-ink:#b45309;}.bst-posted{background:#dcfce7;--bst-tint:#dcfce7;color:#166534;--bst-ink:#15803d;}.bst-ignored{background:#f1f5f9;--bst-tint:#f1f5f9;color:#64748b;--bst-ink:#475569;}.bst-reconciled{background:#dbeafe;--bst-tint:#dbeafe;color:#1e40af;--bst-ink:#1e40af;}
.bst-draft{background:#f1f5f9;--bst-tint:#f1f5f9;color:#64748b;--bst-ink:#475569;}.bst-open{background:#fef3c7;--bst-tint:#fef3c7;color:#92400e;--bst-ink:#b45309;}.bst-overdue{background:#fde2e1;--bst-tint:#fde2e1;color:#c0392b;--bst-ink:#c0392b;}.bst-partial{background:#e0e7ff;--bst-tint:#e0e7ff;color:#3730a3;--bst-ink:#4338ca;}.bst-paid{background:#dcfce7;--bst-tint:#dcfce7;color:#166534;--bst-ink:#15803d;}.bst-cancelled{background:#e2e8f0;--bst-tint:#e2e8f0;color:#334155;--bst-ink:#334155;}
/* A standalone Cancelled chip (the transaction browser's Status column, not
   inside a .status-strip) strikes its own text — see the scoped rule below
   for the strip case, where only the status word (not Saved/Created) gets it. */
.badge.bst-cancelled{text-decoration:line-through;}

/* Bill status band — full width above the header fields, so the state is
   visible at a glance and its text length can never move the fields (both
   editors: #entry-status-strip, #group-status-strip). The strip takes the
   state's pale colour from its own .bst-* class; the badge on it takes the
   solid one. */
.status-strip{display:flex;align-items:center;gap:8px;padding:7px 14px;background:var(--bst-tint,var(--hdr));border-bottom:1px solid var(--border);}
.status-strip .badge{background:var(--bst-ink,#475569);color:#fff;font-size:11px;padding:3px 9px;letter-spacing:.5px;}
/* Reconciled is about the bank match, not the bill's state — it keeps its own
   colour whatever the strip is tinted. */
.status-strip .badge.bst-reconciled{background:#1e40af;color:#fff;}
/* Amount locked (matched to a bank import) — same amber as the warn status
   line it used to live in alone, but in the always-visible band at the top
   of the card instead of down by Save. */
.status-strip .badge.bst-locked{background:#92400e;color:#fff;}
/* Whether what's on screen exists in the database yet — secondary to the bill
   state beside it, so it reads as an outline pill rather than a second solid
   one, and stays legible on every tint. */
.status-strip .badge.save-state{background:rgba(255,255,255,.85);color:#334155;border:1px solid rgba(15,23,42,.15);}
/* Cancelled: strike through the status word itself only — not the
   Saved/creation-time text sharing the same tinted strip. */
.status-strip.bst-cancelled .badge:not(.save-state):not(.bst-locked):not(.bst-reconciled){text-decoration:line-through;}
/* Creation timestamp, pinned to the far end of the band. */
.strip-created{margin-left:auto;font-size:11px;font-family:var(--mono);color:var(--muted);white-space:nowrap;}
.grp-matched-row{background:var(--info-bg);}
.grp-matched-row td{border-left:3px solid #93c5fd;}
.pgn{display:flex;gap:8px;align-items:center;padding:8px 14px;font-size:12px;color:var(--muted);border-top:1px solid var(--border);}
.pgn button{height:25px;padding:0 10px;border:1px solid var(--border);border-radius:3px;background:none;cursor:pointer;font-size:11px;}
.pgn button:disabled{opacity:.4;cursor:not-allowed;}
.pgn label{font-size:11px;color:var(--muted);}
.pgn select{height:25px;padding:0 4px;border:1px solid var(--border);border-radius:3px;background:var(--surface);color:var(--text);font-size:11px;font-family:inherit;}
.loading{padding:20px;text-align:center;color:var(--muted);font-size:13px;}
.spin{display:inline-block;width:13px;height:13px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:sp .7s linear infinite;vertical-align:middle;margin-right:6px;}
@keyframes sp{to{transform:rotate(360deg);}}

/* Template modal */
.modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:500;align-items:center;justify-content:center;display:none;}
.modal-bg.show{display:flex;}
.modal{background:var(--surface);border-radius:8px;padding:20px;min-width:340px;max-width:500px;box-shadow:0 8px 32px rgba(0,0,0,.18);}
.modal h3{font-size:15px;font-weight:700;margin-bottom:14px;}
#bp-modal.select-mode #bp-form-section{display:none;}
#bp-modal.select-mode #bp-list{max-height:min(60vh,420px);}
.tpl-item{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border:1px solid var(--border);border-radius:4px;margin-bottom:6px;cursor:pointer;}
.tpl-item:hover{background:var(--row-h);border-color:var(--accent);}
.ti-name{font-weight:600;font-size:13px;}
.ti-lines{font-size:11px;color:var(--muted);}
.ti-del{color:var(--danger);font-size:18px;cursor:pointer;padding:0 4px;}
.tpl-empty{color:var(--muted);font-size:13px;padding:12px 0;}

/* Busy overlay — shown while a save/post/open/delete request is in flight.
   No dimming by design: it only needs to swallow clicks, not obscure the
   screen, since the point is blocking double-submits, not hiding content. */
.busy-overlay{display:none;position:fixed;inset:0;z-index:10000;align-items:center;justify-content:center;cursor:wait;}
.busy-overlay.show{display:flex;}
.busy-spinner{width:40px;height:40px;border:4px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:sp .7s linear infinite;}

/* Confirmation dialog — replaces window.confirm(), which the in-app browser
   auto-dismisses (returns false without ever rendering), silently turning
   every confirmed action into a no-op. Sits above the busy overlay. */
.confirm-overlay{display:none;position:fixed;inset:0;z-index:10001;align-items:center;justify-content:center;background:rgba(15,23,42,.35);}
.confirm-overlay.show{display:flex;}
.confirm-box{background:var(--surface);border:1px solid var(--border);border-radius:6px;box-shadow:0 10px 30px rgba(0,0,0,.18);max-width:420px;padding:18px;}
.confirm-msg{font-size:13px;line-height:1.5;color:var(--text);margin-bottom:16px;}
.confirm-actions{display:flex;justify-content:flex-end;gap:8px;}
.prompt-overlay{display:none;position:fixed;inset:0;z-index:10001;align-items:center;justify-content:center;background:rgba(15,23,42,.35);}
.prompt-overlay.show{display:flex;}
.prompt-box{background:var(--surface);border:1px solid var(--border);border-radius:6px;box-shadow:0 10px 30px rgba(0,0,0,.18);width:360px;max-width:90vw;padding:18px;}
.prompt-msg{font-size:13px;line-height:1.5;color:var(--text);margin-bottom:10px;}
.prompt-input{width:100%;box-sizing:border-box;font-size:13px;padding:6px 8px;border:1px solid var(--border);border-radius:4px;background:var(--surface);color:var(--text);}
.prompt-err{font-size:12px;line-height:1.4;color:var(--danger);margin-top:6px;min-height:0;}
.prompt-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px;}

/* ── Top navigation bar ───────────────────────────────────────
   Always visible, never collapsed: it (with the section bar below it) sticks to the top of the page while the
   content scrolls beneath it. Items are grouped by function (bookkeeping /
   purchasing + payroll / reporting / admin) with a divider between groups.
   On a narrow screen the row scrolls sideways instead of wrapping, so it stays
   one line tall. */
.chrome{position:sticky;top:0;z-index:100;}
.sectionbar{display:flex;align-items:center;gap:12px;padding:8px 16px;background:var(--bg);border-bottom:1px solid var(--border);
  font-size:17px;font-weight:700;letter-spacing:-.3px;}
.navbar{display:flex;align-items:center;gap:18px;height:48px;
  padding:0 16px;background:var(--surface);border-bottom:1px solid var(--border);}
.navbar-brand{display:flex;align-items:center;gap:9px;flex:0 0 auto;}
.navbar-mark{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  flex:0 0 26px;border-radius:6px;background:var(--accent);color:#fff;font-size:15px;font-weight:700;}
.navbar-brand-text{font-size:14px;font-weight:700;letter-spacing:-.2px;white-space:nowrap;}
.navbar-nav{display:flex;align-items:center;gap:0;min-width:0;flex:1 1 auto;overflow-x:auto;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;}
.navbar-nav::-webkit-scrollbar{display:none;}
.nav-group{display:flex;align-items:center;gap:2px;flex:0 0 auto;padding:0 10px;}
.nav-group + .nav-group{border-left:1px solid var(--border);}
.nav-group:first-child{padding-left:0;}
.nav-group:has(> .nav-item[style*="display:none"]:only-child){display:none;}
.nav-item{display:flex;align-items:center;gap:7px;height:32px;padding:0 10px;
  border:none;border-radius:6px;background:none;color:var(--muted);font-family:inherit;font-size:13px;
  font-weight:600;cursor:pointer;white-space:nowrap;transition:background .12s,color .12s;}
.nav-item:hover{background:rgba(0,0,0,.04);color:var(--text);}
.nav-item.active{background:var(--row-h);color:var(--accent);}
.nav-icon{flex:0 0 auto;text-align:center;font-size:14px;}
.nav-label{white-space:nowrap;}
/* Set by app.js's fitNavbar when the labelled menu is wider than its space. */
.navbar-nav.nav-compact .nav-label{display:none;}
.navbar-nav.nav-compact .nav-icon{font-size:16px;}
/* The entry's mode badge, document reference and period hint sit at the right
   of the section bar (Journal only; see setAppSection). */
.sectionbar-state{display:flex;align-items:center;gap:10px;margin-left:auto;font-size:12px;font-weight:400;letter-spacing:0;min-width:0;}
/* Right-hand cluster: theme / language / sign out. */
.navbar-tools{display:flex;align-items:center;gap:8px;flex:0 0 auto;margin-left:auto;}
.navbar-tools select{height:26px;font-size:11px;}
/* Phone and narrow windows (under 900px, where the full bar would not fit):
   two compact rows. Logo row on top; below it the section buttons as
   icons only (the section bar already names the current one), spread evenly so
   every button is a full-size tap target and the whole menu is visible with no
   sideways scrolling. Group dividers stay. */
@media (max-width:900px){
  .navbar{flex-wrap:wrap;height:auto;gap:0 8px;padding:4px 8px 0;}
  .navbar-brand{order:1;height:34px;}
  .navbar-tools{order:2;height:34px;gap:6px;}
  .navbar-nav{order:3;flex:1 0 100%;overflow-x:visible;justify-content:space-between;border-top:1px solid var(--border);}
  .nav-group{flex:1 1 auto;justify-content:space-around;padding:0 2px;gap:0;}
  .nav-group:first-child{padding-left:2px;}
  .nav-item{flex:1 1 0;justify-content:center;height:40px;padding:0 4px;min-width:40px;}
  .nav-item .nav-label{display:none;}
  .nav-icon{font-size:18px;}
  .sectionbar{padding:5px 10px;font-size:15px;}
  .sectionbar-state .hint{display:none;}
}

/* ── Bank-import match modal ─────────────────────────────────────
   Opens on clicking any Pending import row, before anything loads into the
   entry form -- see openBankMatchModal in app.js. Reuses .pr-grid/.pr-col
   (payroll's two-column layout) for the "two sides": the bank line itself,
   read-only, and either a confident one-click match or a search. */
/* width:min(...) rather than min-width+max-width: a fixed min-width overflows
   a viewport narrower than it regardless of any @media override, since an
   element's own intrinsic min-width always wins over a later, less specific
   rule trying to shrink it -- this doesn't have that failure mode at all. */
.recon-modal-box{width:min(94vw,820px);}
.recon-modal-grid{margin:0 -20px;border-top:1px solid var(--border);max-height:60vh;overflow-y:auto;}
.recon-bank-summary{padding:12px 14px;font-size:12px;line-height:1.9;}
.recon-bank-summary .rbs-l{color:var(--muted);display:inline-block;min-width:90px;}
.recon-cand-summary{font-size:13px;margin-top:6px;}
.recon-cand{padding:8px 10px;border:1px solid var(--border);border-radius:4px;margin-bottom:6px;
  font-size:12px;cursor:pointer;background:var(--surface);}
.recon-cand:hover{border-color:var(--border-focus);background:var(--hdr);}
.recon-cand .rc-ref{font-weight:700;color:var(--accent);}
.recon-cand .rc-amt{float:right;font-family:var(--mono);}
@media (max-width:600px){
  .recon-modal-grid{grid-template-columns:1fr;max-height:70vh;}
  #bank-match-modal .pr-col{border-right:none;border-bottom:1px solid var(--border);}
}

/* ── Payroll ──────────────────────────────────────────────────
   Two columns: what comes off the employee's gross, and what the employer owes
   on top. The posting table below is what the PY entry will be pre-filled with. */
.pr-grid{display:grid;grid-template-columns:1fr 1fr;gap:0;}
.pr-col{padding:0;border-right:1px solid var(--border);}
.pr-col:last-child{border-right:none;}
.pr-col-hdr{padding:8px 14px;font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
  color:var(--muted);background:var(--hdr);border-bottom:1px solid var(--border);}
.pr-table{width:100%;border-collapse:collapse;font-size:12px;}
.pr-table th{padding:7px 14px;text-align:left;font-size:10px;font-weight:700;letter-spacing:.5px;
  text-transform:uppercase;color:var(--muted);background:var(--hdr);border-bottom:1px solid var(--border);}
.pr-table td{padding:6px 14px;border-bottom:1px solid var(--line-soft);}
.pr-table td.r,.pr-table th.r{text-align:right;font-family:var(--mono);white-space:nowrap;}
.pr-table th.r{font-family:inherit;}
.pr-rate{color:var(--muted);font-size:11px;font-family:var(--mono);}
.pr-table tr.pr-gross td{font-weight:600;}
.pr-table tfoot td{padding:8px 14px;font-weight:700;border-top:1px solid var(--border);border-bottom:none;}
.pr-table tfoot tr.pr-net td{color:var(--accent);font-size:13px;}
.pr-posting-hdr{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--hdr);
  border-top:1px solid var(--border);border-bottom:1px solid var(--border);font-size:11px;
  font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);}
.pr-posting td{font-size:12px;}
.pr-posting .pr-acc{font-family:var(--mono);}
.pr-warn{margin:12px 14px 0;padding:9px 12px;border-radius:4px;background:#fef3c7;color:#92400e;
  font-size:12px;border:1px solid #fcd34d;}
.pr-warn ul{margin:5px 0 0 18px;}
.pr-warn code{font-family:var(--mono);}
/* Missing/unknown account in the payroll account plan — bexio's red marker. */
.pr-flag{color:var(--danger);font-weight:700;margin-left:5px;}

/* Employee modal */
.pr-form-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr auto;gap:10px;margin-bottom:6px;}
.pr-modal-sec{margin-top:16px;padding-top:10px;border-top:1px solid var(--border);font-size:11px;
  font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);}
.pr-rates td,.pr-accounts td{padding:4px 0;border-bottom:none;}
.pr-rates input[type=checkbox]{width:16px;height:16px;}
.pr-rates input[type=number],.pr-accounts input[type=text]{height:26px;padding:0 7px;border:1px solid var(--border);
  border-radius:4px;font-size:12px;font-family:var(--mono);text-align:right;background:var(--surface);color:var(--text);}
.pr-accounts input[type=text]{text-align:left;width:90px;}
.pr-rates input:focus,.pr-accounts input:focus{outline:none;border-color:var(--border-focus);}
.pr-unit{color:var(--muted);font-size:11px;padding-left:5px;}
.pr-acc-name{color:var(--muted);font-size:11px;}
/* The employee modal is the tallest in the app (rate rows + the full account
   map), so it scrolls inside itself rather than off the bottom of short viewports. */
#pr-modal .modal{max-height:88vh;overflow-y:auto;}

/* ── Payroll sub-navigation ───────────────────────────────────
   The Payroll screen has two jobs — running a month and configuring how a
   month is run — and they want different layouts, so they're separate panes
   rather than one long page. */
.sub-tabs{display:flex;gap:2px;margin-bottom:12px;border-bottom:1px solid var(--border);}
.sub-tab{padding:7px 16px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;
  user-select:none;border-bottom:2px solid transparent;margin-bottom:-1px;}
.sub-tab:hover{color:var(--text);}
.sub-tab.active{color:var(--accent);border-bottom-color:var(--accent);}

/* Period control table */
.pr-runs td,.pr-employees td{padding:7px 14px;}
.pr-runs tr:hover{background:var(--row-h);}
.pr-period{font-weight:600;}
.pr-runs .pr-ref{font-family:var(--mono);font-size:11px;color:var(--muted);}
.pr-actions{display:flex;gap:6px;}
.pr-actions .btn{height:26px;padding:0 10px;font-size:11px;}
/* Status of a month: never run, calculated but not released, in the books, or
   backed out again. */
.pr-badge{display:inline-block;font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;
  letter-spacing:.3px;text-transform:uppercase;}
.pr-st-none{background:var(--line-soft);color:var(--muted);}
.pr-st-generated{background:#fef3c7;color:#92400e;}
.pr-st-posted{background:#dcfce7;color:var(--ok);}
.pr-st-reversed{background:#fee2e2;color:var(--danger);}
.pr-runs tr.pr-row-none td{color:var(--muted);}

/* ── Configuration: FX rates ──────────────────────────────────
   The published-rate table reads as a register, so rows behave like the
   payroll ones: the whole row opens the editor. A row whose period is closed
   is shown greyed and is not clickable — the server refuses the edit, and a
   row that opens an editor only to reject the save is worse than one that
   plainly says it is fixed. */
/* Fixed column widths plus a note that has to stay readable, so the table
   scrolls inside its own box rather than wrapping the note to seven lines in
   a narrow window — same shape as .pr-runs-wrap. */
.cf-fx-wrap{overflow-x:auto;}
/* Admin → Settings: one block per App_Settings key */
.settings-row{margin:10px 14px 14px;padding:12px;border:1px solid var(--border);border-radius:4px;display:flex;flex-direction:column;gap:8px;}
.settings-label{font-weight:600;font-size:13px;color:var(--text);}
.settings-options{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:4px 16px;}
.settings-foot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
.settings-foot .sp{flex:1;}
/* User maintenance: the table's controls match the app's .field controls
   (30px tall, 13px text, same border and focus ring) so the add row, the
   per-row role selects and the Create account form all read as one size. */
.admin-users-table select{min-width:120px;}
.admin-users-table input[type=email],.admin-users-table input[type=text],.admin-users-table select{width:100%;box-sizing:border-box;height:30px;padding:0 8px;
  border:1px solid var(--border);border-radius:4px;font-size:13px;font-family:inherit;background:var(--surface);color:var(--text);}
.admin-users-table input[type=email]:focus,.admin-users-table input[type=text]:focus,.admin-users-table select:focus{outline:none;border-color:var(--border-focus);box-shadow:0 0 0 2px rgba(37,99,168,.1);}
.admin-users-table input[type=checkbox]{width:16px;height:16px;vertical-align:middle;}
.admin-users-table td{vertical-align:middle;}
.cf-fx-table{min-width:820px;}
.cf-fx-table td{padding:7px 14px;}
.cf-fx-table td:first-child{font-weight:600;}
.cf-fx-table tbody tr{cursor:pointer;}
.cf-fx-table tbody tr:hover{background:var(--row-h);}
.cf-fx-table tbody tr.cf-fx-locked{cursor:default;color:var(--muted);}
.cf-fx-table tbody tr.cf-fx-locked:hover{background:transparent;}
/* A row Baserow holds with no rate or no currency — real data the ledger
   ignores, which is exactly why the maintenance screen has to show it. */
.cf-fx-table tbody tr.cf-fx-incomplete td{color:var(--danger);}
.cf-fx-note{font-size:11px;color:var(--muted);}

/* Result of a year import: counts, then the months that actually changed.
   A bulk write to the table the ledger converts through is worth being able
   to read back, so this stays on screen until dismissed rather than passing
   by as a status message. */
.cf-import-result{margin:0 14px 12px;border:1px solid var(--border);border-radius:4px;
  background:var(--hdr);font-size:12px;}
.cf-import-hdr{display:flex;align-items:center;gap:10px;padding:8px 12px;
  border-bottom:1px solid var(--border);font-weight:600;}
.cf-import-hdr .btn{height:24px;padding:0 10px;font-size:11px;}
.cf-import-result .cf-import-group{padding:8px 12px;border-bottom:1px solid var(--border);}
.cf-import-result .cf-import-group:last-child{border-bottom:none;}
.cf-import-label{font-weight:600;margin-bottom:4px;}
.cf-import-months{font-family:var(--mono);font-size:11px;color:var(--muted);
  display:flex;flex-wrap:wrap;gap:4px 10px;}
.cf-import-months .cf-was{text-decoration:line-through;opacity:.65;}
.cf-import-fail{color:var(--danger);}
.cf-import-none{color:var(--muted);}

/* Payroll account (Lohnkonto) */
.lk-wrap{overflow-x:auto;}
.lk-table{width:100%;border-collapse:collapse;font-size:12px;}
/* Columns carry their own minimum instead of the table carrying one, so a
   two-month year fits without scrolling while a full twelve still can. */
.lk-table th,.lk-table td{min-width:86px;}
.lk-table th:first-child,.lk-table td:first-child{min-width:190px;}
.lk-table th{padding:7px 10px;text-align:right;font-size:10px;font-weight:700;letter-spacing:.5px;
  text-transform:uppercase;color:var(--muted);background:var(--hdr);border-bottom:1px solid var(--border);
  white-space:nowrap;}
.lk-table th:first-child{text-align:left;}
.lk-table td{padding:6px 10px;text-align:right;font-family:var(--mono);white-space:nowrap;
  border-bottom:1px solid var(--line-soft);}
.lk-table td:first-child{text-align:left;font-family:inherit;}
.lk-table td.lk-total,.lk-table th.lk-total{font-weight:700;border-left:1px solid var(--border);
  background:var(--hdr);}
.lk-table tr.lk-net td{font-weight:700;color:var(--accent);border-top:1px solid var(--border);}
.lk-table tr.lk-group-employer td:first-child{color:var(--muted);}
.lk-sep td{padding:0;height:6px;border-bottom:1px solid var(--border);background:var(--hdr);}
/* The runs table has a wide fixed shape (reference + six figures + actions),
   so it scrolls inside its own box rather than wrapping the reference onto
   four lines or clipping the action buttons off the right edge. */
.pr-runs-wrap{overflow-x:auto;}
.pr-runs{min-width:1040px;}
.pr-runs .pr-ref,.pr-runs .pr-period{white-space:nowrap;}
.pr-runs td.pr-actions{white-space:nowrap;}
/* Posting date sits inline in the runs table, so it stays compact. */
.pr-date{height:26px;padding:0 6px;border:1px solid var(--border);border-radius:4px;
  font-size:11px;font-family:var(--mono);background:var(--surface);color:var(--text);}
.pr-date:focus{outline:none;border-color:var(--border-focus);}
.pr-date:disabled{background:var(--hdr);color:var(--muted);}

/* ── Year-end closing roadmap ──────────────────────────────────────────────
   Four steps across the top of the Closing report. Colour carries the state
   (green done / blue current / red blocked / grey pending) but never alone:
   each node also shows a glyph and its status word, so the roadmap still
   reads correctly in greyscale or to a colour-blind user. */
.cl-road{display:flex;align-items:flex-start;gap:0;padding:14px 16px 10px;
  background:var(--hdr);border-bottom:1px solid var(--border);flex-wrap:wrap;}
.cl-step{flex:1 1 150px;min-width:150px;display:flex;flex-direction:column;align-items:center;
  text-align:center;position:relative;padding:0 4px;}
/* The connector is drawn from each node back to the previous one, so it
   inherits that node's own colour and the line reads as progress. */
.cl-step::before{content:'';position:absolute;top:13px;left:-50%;width:100%;height:2px;
  background:var(--cl-line,var(--border));z-index:0;}
.cl-step:first-child::before{display:none;}
.cl-dot{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:13px;font-weight:700;background:var(--surface);
  border:2px solid var(--border);color:var(--muted);position:relative;z-index:1;}
.cl-label{margin-top:6px;font-size:11px;font-weight:600;color:var(--text);line-height:1.3;}
.cl-note{font-size:10px;color:var(--muted);margin-top:2px;line-height:1.3;}
.cl-step.done{--cl-line:var(--ok);}
.cl-step.done .cl-dot{border-color:var(--ok);background:var(--ok);color:#fff;}
.cl-step.current{--cl-line:var(--accent);}
.cl-step.current .cl-dot{border-color:var(--accent);background:var(--accent);color:#fff;
  box-shadow:0 0 0 3px rgba(37,99,168,.18);}
.cl-step.blocked{--cl-line:var(--danger);}
.cl-step.blocked .cl-dot{border-color:var(--danger);background:var(--danger);color:#fff;}
.cl-step.pending .cl-dot{border-style:dashed;}
.cl-step.done .cl-note{color:var(--ok);}
.cl-step.current .cl-note{color:var(--accent);}
.cl-step.blocked .cl-note{color:var(--danger);}
/* Blockers listed under the roadmap — why step 4 will not go yet. */
.cl-blockers{padding:8px 16px;background:#fdf2f2;border-bottom:1px solid var(--border);
  font-size:11px;color:var(--danger);}
.cl-blockers ul{margin:4px 0 0;padding-left:18px;}
.cl-blockers li{margin:2px 0;}

/* VAT return: a warning, which informs but never blocks. */
.cl-blockers.vat-warn{background:#fef9e7;color:#92400e;}
/* VAT return: the hand-entered boxes of an open quarter. */
.vat-adj{padding:12px 14px 14px;border-top:1px solid var(--border);display:flex;flex-direction:column;gap:10px;align-items:flex-start;}
.vat-adj-head{display:flex;flex-direction:column;gap:2px;}
.vat-adj-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:10px 16px;width:100%;}
.vat-adj-grid label{text-transform:none;letter-spacing:0;font-size:11px;}
/* A label that wraps must not push its input below the rest of the row. */
.vat-adj-grid .field{justify-content:flex-end;}
.vat-adj-grid input{width:100%;}

#entry-card{position:relative;}

/* Theme — System / Light / Dark. static/theme.js resolves the saved choice
   (or the OS setting) to data-theme="light"|"dark" on <html>; everything above
   is the light palette, so only the dark values live here. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#121417;--surface:#1c1f24;--border:#343a42;--border-focus:#5aa0e3;
  --text:#e6e6e3;--muted:#9aa0a6;--accent:#4590d6;--accent-h:#5aa0e3;
  --accent2:#a78bfa;--accent2-h:#c4b5fd;
  --danger:#f0776a;--warn:#f0a03c;--ok:#4cc38a;
  --hdr:#22262c;--row-h:#1f2b3a;
  --faint:#6b7178;--surface-2:#262b32;--line-soft:#2a2f36;--danger-bg:#3a1f1e;
  --info-bg:#1a2a3d;--info-bd:#2b4a70;
}
:root[data-theme="dark"] .mode-new{background:#1a2a3d;}
:root[data-theme="dark"] .mode-edit,:root[data-theme="dark"] .pr-st-generated,:root[data-theme="dark"] .pr-warn,:root[data-theme="dark"] .cl-blockers.vat-warn{background:#3a2e12;color:#f3c86b;}
:root[data-theme="dark"] .pr-warn{border-color:#6b5316;}
:root[data-theme="dark"] .mode-locked,:root[data-theme="dark"] .pr-st-reversed,:root[data-theme="dark"] .bdel:hover,:root[data-theme="dark"] .bdd:hover{background:#3a1f1e;color:#f59a90;}
:root[data-theme="dark"] .pr-st-posted{background:#173324;}
:root[data-theme="dark"] .bdd{border-color:#7a3a35;}
:root[data-theme="dark"] .bdr{background:#1a2a3d;color:#9cc4f0;}
:root[data-theme="dark"] .bcr{background:#2a2244;color:#c4b5fd;}
:root[data-theme="dark"] .bst-pending,:root[data-theme="dark"] .bst-open{background:#3a2e12;--bst-tint:#3a2e12;color:#f3c86b;--bst-ink:#b45309;}
:root[data-theme="dark"] .bst-posted,:root[data-theme="dark"] .bst-paid{background:#173324;--bst-tint:#173324;color:#7ddba7;--bst-ink:#15803d;}
:root[data-theme="dark"] .bst-ignored,:root[data-theme="dark"] .bst-draft{background:#262b32;--bst-tint:#262b32;color:#a4abb4;--bst-ink:#475569;}
:root[data-theme="dark"] .bst-reconciled{background:#1a2a3d;--bst-tint:#1a2a3d;color:#9cc4f0;--bst-ink:#1e40af;}
:root[data-theme="dark"] .bst-overdue{background:#3a1f1e;--bst-tint:#3a1f1e;color:#f59a90;--bst-ink:#c0392b;}
:root[data-theme="dark"] .bst-partial{background:#232a4d;--bst-tint:#232a4d;color:#a5b4fc;--bst-ink:#4338ca;}
:root[data-theme="dark"] .bst-cancelled{background:#2f353d;--bst-tint:#2f353d;color:#c3cad3;--bst-ink:#475569;}
:root[data-theme="dark"] .sts.success{background:#12281d;border-color:#1f5a3c;}
:root[data-theme="dark"] .sts.error{background:#3a1f1e;border-color:#7a3a35;}
:root[data-theme="dark"] .sts.warn,:root[data-theme="dark"] .dupw{background:#33290f;border-color:#6b5316;}
:root[data-theme="dark"] .status-strip .badge.save-state{background:rgba(255,255,255,.08);color:var(--text);border-color:rgba(255,255,255,.2);}
:root[data-theme="dark"] .bp:disabled{background:#2c4460;}
:root[data-theme="dark"] .bs:hover{border-color:#6b7178;}
:root[data-theme="dark"] .mode-tab:hover,:root[data-theme="dark"] .nav-item:hover{background:rgba(255,255,255,.06);}
:root[data-theme="dark"] .cl-blockers{background:#2f1c1c;}
:root[data-theme="dark"] .login-card,:root[data-theme="dark"] .modal,:root[data-theme="dark"] .acl,:root[data-theme="dark"] .date-filter-pop{box-shadow:0 8px 32px rgba(0,0,0,.6);}

/* Account ledger */
/* Account navigator: a single scrollable line. Section names sit inline as
   sticky labels (the current section's name stays at the left edge while its
   numbers scroll past), a hairline separates sections, edge fades and arrow
   buttons show when there is more to scroll to, and chips are 32px tall for
   touch. */
.ledger-nav{padding:8px 16px 10px;border-bottom:1px solid var(--border);}
.ledger-nav-hdr{display:flex;align-items:center;gap:12px;margin-bottom:6px;font-size:11px;color:var(--muted);}
.ln-row{display:flex;align-items:center;gap:4px;}
.ln-arrow{flex:0 0 28px;height:32px;border:1px solid var(--border);border-radius:6px;background:var(--surface);color:var(--muted);font-size:16px;line-height:1;cursor:pointer;padding:0;}
.ln-arrow:hover:not(:disabled){color:var(--text);border-color:var(--border-focus);}
.ln-arrow:disabled{opacity:.35;cursor:default;}
.ln-row.no-overflow .ln-arrow{display:none;}
.ln-scroll{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:0;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 calc(100% - 24px),transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 calc(100% - 24px),transparent 100%);}
.ln-scroll::-webkit-scrollbar{display:none;}
.ln-scroll.at-start{-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 24px),transparent 100%);mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 24px),transparent 100%);}
.ln-scroll.at-end{-webkit-mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 100%);mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 100%);}
.ln-scroll.at-start.at-end{-webkit-mask-image:none;mask-image:none;}
.ln-sec{flex:0 0 auto;display:flex;align-items:center;gap:5px;padding:0 12px;border-left:1px solid var(--border);}
.ln-sec:first-child{padding-left:0;border-left:none;}
.ln-sec-label{position:sticky;left:0;z-index:1;padding-right:6px;background:var(--surface);font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);white-space:nowrap;}
.ln-scroll .chip{flex:0 0 auto;min-height:32px;border:1px solid var(--border);background:var(--surface);border-radius:16px;padding:0 11px;font-family:var(--mono);font-size:12px;cursor:pointer;color:var(--text);}
.ln-scroll .chip:hover{border-color:var(--border-focus);}
.ln-scroll .chip.empty{color:var(--muted);}
.ln-scroll .chip.active{background:var(--accent);border-color:var(--accent);color:#fff;}
.btx td.r,.btx th.r{text-align:right;font-variant-numeric:tabular-nums;}
.btx tr.ledger-open td,.btx tr.ledger-close td{font-weight:700;background:var(--hdr);cursor:default;}
.btx tr.ledger-mismatch td{color:var(--muted);font-style:italic;}
/* The ledger has up to 13 columns; scroll sideways inside the card instead of
   letting the table run past (and get clipped by) it. */
#ledger-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
/* Free-text columns are capped and ellipsized (full text in the cell tooltip)
   so one long concept cannot stretch the whole table. */
#ledger-wrap .btx td.tx{max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
#ledger-wrap .btx td.tx.tx-s{max-width:200px;}

/* The Purchasing section is a frame around /purchasing-app, its own document. */
#purchasing-frame,#sales-frame,#articles-frame{display:block;width:100%;height:calc(100vh - 190px);min-height:600px;border:0;background:transparent;}

/* Vendor Bills on a phone (Purchasing screen): each bill is a card instead of
   a sideways-scrolling table row. Cells carry data-col / data-label (renderBills
   in static/purchasing.js). */
.vb-sort-m{display:none;}
@media (max-width:600px){
  .vb-sort-m{display:flex;align-items:center;gap:8px;padding:8px 14px;}
  .vb-sort-m label{font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);}
  .vb-sort-m select{flex:1;height:30px;}
  #vb-wrap{overflow-x:visible;}
  #vb-wrap table,#vb-wrap tbody{display:block;width:100%;}
  #vb-wrap thead{display:none;}
  #vb-wrap tr.dr{display:grid;grid-template-columns:52px 1fr auto;grid-template-areas:"vendor vendor gross" "no title cur" "status date pending" "status due pending";
    gap:2px 8px;padding:10px 14px;border-bottom:1px solid var(--border);cursor:pointer;}
  #vb-wrap tr.dr td{display:block;padding:0;border:0;min-width:0;}
  #vb-wrap td[data-col="business_partner"]{grid-area:vendor;font-weight:600;font-size:13px;}
  #vb-wrap td[data-col="gross"]{grid-area:gross;font-weight:700;font-size:13px;}
  #vb-wrap td[data-col="document_number"]{grid-area:no;}
  #vb-wrap td[data-col="title"]{grid-area:title;color:var(--muted);font-size:12px;}
  #vb-wrap td[data-col="currency"]{grid-area:cur;text-align:right;}
  #vb-wrap td[data-col="status"]{grid-area:status;padding-top:4px;}
  #vb-wrap td[data-col="date"]{grid-area:date;padding-top:4px;}
  #vb-wrap td[data-col="due_date"]{grid-area:due;}
  #vb-wrap td[data-col="pending"]{grid-area:pending;text-align:right;padding-top:4px;}
  #vb-wrap tr.dr td[data-col="net"],#vb-wrap tr.dr td[data-col="booking_account"]{display:none;}
  #vb-wrap td[data-col="date"]::before,#vb-wrap td[data-col="due_date"]::before,#vb-wrap td[data-col="pending"]::before{
    content:attr(data-label) " ";font-family:var(--font, inherit);font-size:9px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:var(--muted);}
}

/* Documents section: drag/drop upload zone + the badge that opens a bill's
   linked PDF from the entry editor's status strip. */
.document-badge{cursor:pointer;background:#e0e7ff;color:#3730a3;border:0;font-family:var(--mono);}
.document-badge:hover{background:#c7d2fe;}
/* PDF drop strip (static/dropzone.js) — Documents report and Purchasing bill.
   Slim at rest; expands and tints while a file is dragged over the page
   (.drop-armed); stronger while the file is right over it (.drop-over). */
.dropzone{display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;
  margin:10px 14px;padding:6px 12px;border:1px dashed var(--border);border-radius:8px;
  font-size:12px;color:var(--muted);text-align:center;
  transition:padding .15s,background .15s,border-color .15s,color .15s;}
.dropzone[hidden]{display:none;}
.dropzone .btn{height:26px;font-size:11px;}
.dropzone-icon{font-size:15px;transition:font-size .15s;}
.dropzone-status:empty{display:none;}
.dropzone.drop-armed{padding:30px 12px;border:2px dashed var(--accent);color:var(--accent);font-size:14px;font-weight:600;
  background:color-mix(in srgb,var(--accent) 7%,transparent);}
.dropzone.drop-armed .dropzone-icon{font-size:22px;}
.dropzone.drop-over{border-style:solid;background:color-mix(in srgb,var(--accent) 18%,transparent);}
.doc-link-picker{padding:8px 14px;background:var(--row-h);}
.doc-link-picker input{margin-right:6px;}
#doc-link-results{margin-left:8px;display:inline-flex;gap:4px;flex-wrap:wrap;}

/* ── Purchasing screen (templates/purchasing.html, static/purchasing.js) ──
   Its own document, framed by the Journal page's Purchasing section; framed,
   the host's bars are the only ones, so the banner and footer go. */
.pu [hidden]{display:none !important;}
html.pu-framed #build-info-banner,html.pu-framed #legal-footer{display:none !important;}
.pu{max-width:1400px;margin:0 auto;padding:12px 16px 24px;width:100%;}
.pu .sts{position:fixed;top:8px;left:50%;transform:translateX(-50%);z-index:900;margin:0;max-width:min(720px,calc(100vw - 24px));box-shadow:0 6px 20px rgba(0,0,0,.18);}
.pu-filters{width:100%;}
.pu-filter-actions{display:flex;gap:8px;align-items:flex-end;}
.pu-filter-actions .btn{height:30px;font-size:11px;}
.pu-w-num{width:70px;}
.pu-w-vendor{width:160px;}
.pu-w-status{width:150px;}
.pu-pop{position:absolute;z-index:500;background:var(--surface);border:1px solid var(--border);border-radius:6px;
  box-shadow:0 8px 24px rgba(0,0,0,.14);padding:6px;display:flex;flex-direction:column;min-width:170px;}
.pu-pop .chkline{display:flex;gap:8px;align-items:center;padding:5px 8px;font-size:12px;cursor:pointer;}
.pu-menu-wrap{position:relative;}
.pu-menu{top:calc(100% + 4px);right:0;}
.pu-err{color:var(--danger);}
.pu-list td,.pu-list th{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
/* Width = the visible columns' widths (--vb-w, set by renderBills), so hidden
   columns free their space and dragged widths are exact. */
@media (min-width:601px){#vb-wrap table.pu-list{width:var(--vb-w);}}
.pu-list th{position:relative;}
.pu-list .col-rs{position:absolute;top:0;right:0;width:7px;height:100%;cursor:col-resize;touch-action:none;}
@media (pointer:coarse){.pu-list .col-rs{width:18px;}}
.pu-list .col-rs.on{background:var(--accent);opacity:.5;}
@media (hover:hover){.pu-list .col-rs:hover{background:var(--accent);opacity:.5;}}
body.col-resizing{cursor:col-resize;user-select:none;}
/* Documents report: same resizable columns as the Purchasing list. */
#doc-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.doc-list td,.doc-list th{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
/* Every cell's content on one line: text, date/notes inputs, checkboxes and
   the compact ⋮ all centred on the row; Reconciled's header over its box. */
.doc-list td,.doc-list th{vertical-align:middle;}
.doc-list .th-kebab{height:22px;}
.doc-list th[data-col="reconciled"]{text-align:center;}
.doc-list .doc-fill{padding:0;}
@media (min-width:601px){#doc-wrap table.doc-list{width:max(100%,var(--doc-w));table-layout:fixed;}}
.doc-list th{position:relative;}
.doc-list .col-rs{position:absolute;top:0;right:0;width:7px;height:100%;cursor:col-resize;touch-action:none;}
@media (pointer:coarse){.doc-list .col-rs{width:18px;}}
.doc-list .col-rs.on{background:var(--accent);opacity:.5;}
@media (hover:hover){.doc-list .col-rs:hover{background:var(--accent);opacity:.5;}}
.doc-list .doc-filter-row th{overflow:visible;}
/* The row checkbox + ⋮ column: never clipped to an ellipsis, and pinned to
   the right edge so it stays in view while a wide table scrolls sideways. */
.doc-list th:last-child,.doc-list td:last-child{overflow:visible;text-overflow:clip;
  position:sticky;right:0;z-index:1;}
.doc-list td:last-child{background:var(--surface);}
.doc-list tr.dr:hover td:last-child{background:var(--row-h);}

.pu-back-row{margin-bottom:10px;}
.pu-bill{overflow:visible;}
.pu-band{display:flex;align-items:center;gap:10px;padding:8px 14px;background:var(--bst-tint,var(--hdr));border-bottom:1px solid var(--border);}
.pu-band.pu-band-new{background:var(--info-bg);}
.pu-band .badge{font-size:11px;padding:2px 8px;}
.pu-ref{font-family:var(--mono);font-size:13px;}
.pu-created{margin-left:auto;font-size:11px;color:var(--muted);}

.pu-top{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding:12px 14px;border-bottom:1px solid var(--line-soft);}
.pu-figs{display:flex;gap:22px;flex-wrap:wrap;}
.pu-fig{display:flex;flex-direction:column;gap:2px;}
.pu-fig-l{font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);}
.pu-fig-v{font-family:var(--mono);font-size:18px;font-weight:700;}
.pu-actions{display:flex;gap:8px;flex-wrap:wrap;margin-left:auto;align-items:center;}
.pu-clip{font-size:14px;padding:0 10px;}
.pu-clip.pu-clip-on{border-color:var(--accent);background:var(--info-bg);}
.pu-hint{font-size:12px;color:var(--muted);padding:6px 14px 0;min-height:0;}
.pu-hint:empty{display:none;}
.pu-warn{margin:8px 14px 0;padding:7px 12px;border-radius:4px;font-size:12px;background:#fffbeb;border:1px solid #fde68a;color:var(--warn);}

.pu-form{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px 14px;padding:14px;}
.pu-form .field input,.pu-form .field select{width:100%;}
.pu-form .field #pu-currency{width:5.5em;}   /* a 3-letter code */
.pu-f-vendor,.pu-f-title{grid-column:span 2;}
.pu-inline{display:flex;gap:8px;}
.pu-inline select{flex:1;min-width:0;}
.pu-chk{display:flex;align-items:center;gap:6px;cursor:pointer;flex-direction:row;}
.pu-form .field .pu-chk input{width:14px;height:14px;padding:0;accent-color:var(--accent);}
.pu-ro{height:30px;display:flex;align-items:center;font-family:var(--mono);font-size:13px;}
.pu-bad-text{color:var(--danger);font-family:inherit;font-size:12px;}

.pu-items,.pu-raw,.pu-payments{padding:0 14px 14px;}
.pu-items-tbl input,.pu-items-tbl select{width:100%;height:30px;padding:0 6px;border:1px solid var(--border);border-radius:4px;
  font-size:13px;font-family:inherit;background:var(--surface);color:var(--text);}
.pu-items-tbl input:focus,.pu-items-tbl select:focus{outline:none;border-color:var(--border-focus);}
.pu-items-tbl input.pu-bad{border-color:var(--danger);}
.pu-items-tbl input:disabled,.pu-items-tbl select:disabled{background:var(--hdr);color:var(--text);}
.pu-items-tbl .pu-amt{text-align:right;font-family:var(--mono);}
.pu-items-tbl td{vertical-align:middle;}
.pu-items{overflow-x:auto;}
.pu-items-tbl{min-width:900px;}
.pu-items-tbl th:nth-child(1){width:13%;}
.pu-items-tbl th:nth-child(2){width:17%;}
.pu-items-tbl th:nth-child(4){width:64px;}
.pu-items-tbl th:nth-child(5){width:92px;}
.pu-items-tbl th:nth-child(6){width:104px;}
.pu-items-tbl .pu-qty,.pu-items-tbl .pu-price{text-align:right;font-family:var(--mono);}
.pu-items-tbl .pu-amt[readonly]{background:var(--hdr);}
.pu-items-tbl td.pu-c-art{position:relative;}
.pu-art-pop{position:absolute;left:0;top:100%;z-index:30;min-width:320px;max-height:240px;overflow:auto;background:var(--surface);
  border:1px solid var(--border);border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,.18);}
.pu-art-opt{display:flex;gap:10px;justify-content:space-between;padding:6px 10px;font-size:12px;cursor:pointer;}
.pu-art-opt:hover,.pu-art-opt.on{background:var(--hdr);}
.pu-art-opt .mo{color:var(--muted);white-space:nowrap;}
.ar-check input{width:auto;height:auto;}
.ar-check{display:flex;align-items:center;gap:6px;height:30px;font-size:12px;}
.ar-box{width:640px;max-width:94vw;max-height:92vh;overflow:auto;}
.ar-wide{grid-column:span 2;}
.ar-row{cursor:pointer;}
.ar-prices input,.ar-prices select{width:100%;height:28px;padding:0 6px;border:1px solid var(--border);border-radius:4px;font-size:12px;background:var(--surface);color:var(--text);}
.ar-prices .pr-price{text-align:right;font-family:var(--mono);}
.pu-art-empty{padding:8px 10px;font-size:12px;color:var(--muted);}
.pu-items-tbl .pu-c-gross{width:56px;text-align:center;}
.pu-items-tbl .pu-c-gross input{width:16px;height:16px;accent-color:var(--accent);}
.pu-items-tbl th:nth-child(8){width:104px;}
.pu-items-tbl .pu-c-vat{width:80px;}
.pu-items-tbl .pu-c-del{width:32px;text-align:center;}
.pu-del{background:none;border:0;color:var(--muted);font-size:18px;line-height:1;cursor:pointer;padding:2px 6px;border-radius:4px;}
.pu-del:hover{color:var(--danger);background:var(--danger-bg);}
.pu-items-foot{display:flex;align-items:flex-start;gap:12px;padding-top:10px;}
.pu-sum{display:grid;grid-template-columns:auto auto;gap:3px 18px;font-size:12px;}
.pu-sum dt{color:var(--muted);text-align:right;}
.pu-sum dd{font-family:var(--mono);text-align:right;}
.pu-sum dt:nth-of-type(3),.pu-sum dd:nth-of-type(3){font-weight:700;color:var(--text);border-top:1px solid var(--border);padding-top:3px;}
.pu-note{font-size:12px;color:var(--muted);padding:8px 0;}
.pu-sec-hdr{display:flex;align-items:center;gap:10px;padding:10px 0 6px;border-top:1px solid var(--line-soft);}
.pu-pay-acts{white-space:nowrap;text-align:right;}
.pu-pay-acts .btn{height:26px;padding:0 10px;font-size:11px;}

.pu-pay-box{width:440px;max-width:92vw;}
.pu-pay-box h3{font-size:14px;margin-bottom:12px;}
.pu-pay-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px;margin-bottom:10px;}
.pu-pay-grid .field:last-child{grid-column:span 2;}
.pu-pay-grid input,.pu-pay-grid select{width:100%;}
/* Yes/no questions asked from inside the vendor dialog sit above it. */
.pu #confirm-overlay{z-index:10002;}
.pu-bp-box{width:520px;max-width:94vw;max-height:92vh;overflow-y:auto;}
.pu-bp-box h3{font-size:14px;margin-bottom:12px;}
.pu-bp-tools{display:flex;gap:8px;margin-bottom:8px;}
.pu-bp-tools .field{flex:1;min-width:0;}
.pu-bp-tools input{width:100%;}
.pu-bp-list{max-height:min(320px,50vh);overflow-y:auto;border:1px solid var(--border);border-radius:4px;margin-bottom:12px;}
.pu-bp-row{display:flex;align-items:center;gap:8px;padding:6px 8px;border-bottom:1px solid var(--border);cursor:pointer;}
.pu-bp-row:last-child{border-bottom:none;}
.pu-bp-row:hover{background:var(--surface-2);}
.pu-bp-row.current{font-weight:600;}
.pu-bp-row .pu-bp-txt{flex:1;min-width:0;}
.pu-bp-row .pu-bp-sub{font-size:11px;color:var(--muted);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.pu-bp-row .pu-bp-ed{padding:2px 8px;}
.pu-bp-empty{padding:10px;font-size:12px;color:var(--muted);}
.pu-bp-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px;margin-bottom:10px;}
.pu-bp-grid .pu-bp-wide{grid-column:span 2;}
.pu-bp-grid input,.pu-bp-grid select{width:100%;}
.pu-pay-info{font-size:12px;color:var(--muted);min-height:16px;margin-bottom:6px;}
.pu-pay-err{font-size:12px;color:var(--danger);min-height:16px;margin-bottom:10px;}

:root[data-theme="dark"] .pu-pop{box-shadow:0 8px 32px rgba(0,0,0,.6);}
:root[data-theme="dark"] .pu-warn{background:#33290f;border-color:#6b5316;}

@media (max-width:900px){
  .pu-form{grid-template-columns:repeat(2,minmax(0,1fr));}
  .pu-actions{margin-left:0;}
}
@media (max-width:600px){
  .pu{padding:8px 8px 16px;}
  /* Header: two fields to a row; the long ones (partner, type, title, reference) take the full width. */
  .pu-form{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 10px;padding:10px;}
  .pu-form .field{min-width:0;}
  .pu-form .field input,.pu-form .field select{height:34px;min-width:0;max-width:100%;}
  .pu-f-vendor,.pu-f-type,.pu-f-title,.pu-form .field:has(#pu-extref){grid-column:span 2;}
  /* iOS gives a native date input an intrinsic width wider than its column. */
  .pu-form input[type=date]{-webkit-appearance:none;appearance:none;display:block;width:100%;min-width:0;max-width:100%;text-align:left;line-height:32px;padding-top:0;padding-bottom:0;}
  .pu-form .field:has(#pu-currency){order:1;}
  .pu-f-title,.pu-form .field:has(#pu-extref){order:2;}
  /* List filters: two to a row; search and partner full width; the buttons on one line. */
  .pu-filters{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 10px;align-items:end;}
  .pu-filters .field{min-width:0;}
  .pu-filters input,.pu-filters select,.pu-filters .ms-btn{width:100%;min-width:0;max-width:100%;}
  .pu-filters .field:has(#vb-search),.pu-filters .field:has(#vb-vendor){grid-column:span 2;}
  .pu-filters .sp{display:none;}
  .pu-filters .pu-filter-actions:not(.pu-menu-wrap){grid-column:1;}
  .pu-filters .pu-filter-actions.pu-menu-wrap{justify-content:flex-end;}
  .pu-filters input[type=date]{-webkit-appearance:none;appearance:none;display:block;text-align:left;line-height:32px;padding-top:0;padding-bottom:0;}
  .pu-figs{gap:14px;}
  .pu-fig-v{font-size:15px;}
  /* Items and payments as stacked cards. */
  .pu-items-tbl thead,.pu-pay-tbl thead{display:none;}
  .pu-items-tbl,.pu-items-tbl tbody,.pu-pay-tbl,.pu-pay-tbl tbody{display:block;width:100%;}
  /* One line = a six-column grid: article|account, description, qty|price|amount, VAT code|gross|VAT|remove. */
  .pu-items-tbl tr{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:6px 8px;padding:10px 0;border-bottom:1px solid var(--border);}
  .pu-items-tbl td{display:block;padding:0;border:0;min-width:0;}
  .pu-items-tbl td:nth-child(1){order:1;grid-column:span 2;}
  .pu-items-tbl td:nth-child(2){order:2;grid-column:span 4;}
  .pu-items-tbl td:nth-child(3){order:3;grid-column:span 6;}
  .pu-items-tbl td:nth-child(4){order:4;grid-column:span 2;}
  .pu-items-tbl td:nth-child(5){order:5;grid-column:span 2;}
  .pu-items-tbl td:nth-child(8){order:6;grid-column:span 2;}
  .pu-items-tbl td:nth-child(6){order:7;grid-column:span 2;}
  .pu-items-tbl td:nth-child(7){order:8;grid-column:span 1;}
  .pu-items-tbl td:nth-child(9){order:9;grid-column:span 2;}
  .pu-items-tbl td:nth-child(10){order:10;grid-column:span 1;align-self:end;text-align:right;}
  .pu-items-tbl td::before,.pu-pay-tbl td[data-label]::before{content:attr(data-label);display:block;font-size:9px;font-weight:700;
    letter-spacing:.4px;text-transform:uppercase;color:var(--muted);margin-bottom:2px;}
  .pu-items-tbl{min-width:0;}
  .pu-items-tbl .pu-c-gross,.pu-items-tbl .pu-c-vat,.pu-items-tbl .pu-c-del{width:auto;text-align:left;}
  .pu-items-tbl .pu-c-del::before{content:none;}
  .pu-pay-tbl tr{display:grid;grid-template-columns:1fr 1fr;gap:4px 8px;padding:10px 0;border-bottom:1px solid var(--border);}
  .pu-pay-tbl td{display:block;padding:0;border:0;}
  .pu-pay-tbl .pu-pay-acts{grid-column:span 2;text-align:left;}
  /* Payment dialog: date | amount on one row, the account below. */
  .pu-pay-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
  .pu-pay-grid .field{min-width:0;}
  .pu-pay-grid .field:nth-child(2){order:1;grid-column:span 2;}
  .pu-pay-grid .field:last-child{grid-column:auto;}
  .confirm-box input[type=date]{-webkit-appearance:none;appearance:none;display:block;width:100%;min-width:0;max-width:100%;text-align:left;line-height:32px;padding-top:0;padding-bottom:0;}
  /* iOS Safari zooms the page into any focused field under 16px — and the partner dialog focuses its search box on open. */
  .pu input,.pu select,.confirm-box input,.confirm-box select{font-size:16px;}
  .pu-bp-grid{grid-template-columns:1fr 1fr;}
  .pu-bp-grid .pu-bp-wide{grid-column:span 2;}
}

/* The Journal's read-only notice on a vendor bill carries an Open in Purchasing button. */
.sts .sts-action{height:24px;padding:0 10px;font-size:11px;margin-left:8px;}

/* ── Configuration screen: section rail + page ─────────────── */
.cfg-layout{display:flex;gap:16px;align-items:flex-start;}
.cfg-rail{flex:0 0 210px;position:sticky;top:8px;background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:6px 0;max-height:calc(100vh - 120px);overflow-y:auto;}
.cfg-main{flex:1;min-width:0;}
.cfg-rail-section{padding:4px 0;border-top:1px solid var(--line-soft);}
.cfg-rail-hdr{display:flex;align-items:center;gap:6px;padding:6px 12px 3px;font-size:10px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--muted);}
.cfg-rail-icon{display:inline-block;width:16px;text-align:center;}
.cfg-rail-item{display:block;width:100%;text-align:left;background:none;border:none;border-left:3px solid transparent;padding:5px 12px 5px 31px;font-size:12px;color:var(--text);cursor:pointer;}
.cfg-rail-item:hover{background:var(--row-h);}
.cfg-rail-item.active{border-left-color:var(--accent);color:var(--accent);font-weight:700;background:var(--surface-2);}
.cfg-rail-overview{padding-left:12px;font-weight:600;margin-bottom:4px;}
.cfg-overview{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:12px;}
.cfg-card{background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:12px 14px;display:flex;flex-direction:column;gap:6px;}
.cfg-card-hdr{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:700;}
.cfg-card-desc{font-size:11px;min-height:28px;}
.cfg-card-pages{display:flex;flex-direction:column;gap:4px;margin-top:2px;}
.cfg-card-page{display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--hdr);border:1px solid var(--line-soft);border-radius:4px;padding:6px 10px;font-size:12px;color:var(--text);cursor:pointer;text-align:left;}
.cfg-card-page:hover{border-color:var(--accent);color:var(--accent);}
.cfg-count{font-size:10px;color:var(--muted);font-family:var(--mono);}
.cfg-reload-note{display:flex;align-items:center;gap:10px;padding:8px 12px;margin-bottom:12px;border-radius:4px;background:var(--info-bg);border:1px solid var(--info-bd);color:var(--accent);font-size:12px;}
.cfg-table tr.cfg-row{cursor:pointer;}
.cfg-table tr.cfg-row:hover td{background:var(--row-h);}
.cfg-table tr.cfg-inactive td{color:var(--muted);}
.cfg-table tr.coa-grp td{background:var(--hdr);cursor:pointer;user-select:none;}
.cfg-table tr.coa-grp:hover td{background:var(--row-h);}
.cfg-table tr.coa-l1 td{font-weight:700;}
.cfg-table tr.coa-l2 td,.cfg-table tr.coa-l3 td{font-weight:600;}
.coa-caret{display:inline-block;width:16px;color:var(--muted);}
.coa-ind .cfg-count{margin-left:8px;font-weight:400;}
.cfg-table .coa-menu-cell{position:sticky;right:0;z-index:1;background:var(--surface);}
.cfg-table th.coa-menu-cell{background:var(--hdr);}
.cfg-table .coa-menu-btn{height:20px;font-size:13px;padding:0 6px;}
.cfg-modal{min-width:min(560px,calc(100vw - 32px));max-width:min(640px,calc(100vw - 32px));max-height:calc(100vh - 40px);overflow-y:auto;}
.cfg-form{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;}
.cfg-field{min-width:0;}
.cfg-field .chkline{font-size:12px;text-transform:none;letter-spacing:0;font-weight:400;color:var(--text);}
#cfg-table-wrap{overflow-x:auto;}
.cfg-field-wide{grid-column:1 / -1;}
.cfg-single{padding:10px 14px 14px;}
.cfg-single-foot{display:flex;margin-top:12px;border-top:1px solid var(--border);padding-top:12px;}
.cfg-chips{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px;min-height:22px;}
.cfg-chip{display:inline-flex;align-items:center;gap:2px;padding:2px 4px 2px 8px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2);font-size:11px;}
.cfg-chip:first-child{border-color:var(--accent);}
.cfg-chip-btn{background:none;border:none;color:var(--muted);cursor:pointer;font-size:12px;padding:0 3px;line-height:1;}
.cfg-chip-btn:hover{color:var(--accent);}
.cfg-delete{color:var(--danger);}
.cfg-delete:disabled{opacity:.4;cursor:not-allowed;}
@media (max-width:800px){
  .cfg-layout{flex-direction:column;align-items:stretch;}
  .cfg-rail{position:static;flex:none;width:100%;max-height:none;display:flex;flex-wrap:wrap;padding:6px;}
  .cfg-rail-section{border-top:none;padding:2px 6px;}
  .cfg-rail-item{display:inline-block;width:auto;padding:4px 8px;border-left:none;border-bottom:2px solid transparent;}
  .cfg-rail-item.active{border-bottom-color:var(--accent);}
  .cfg-form{grid-template-columns:1fr;}
}
