/* The pre-R13 sheet. Its scope has shrunk to the public pages (login,
   register, reset) plus a handful of globals every page still inherits —
   everything else now lives in shell.css under `.r13`.

   `--accent` was #635bff, a violet from the very first mockup. The product's
   accent has been green since R13, and every screen that mattered overrode
   the violet locally — except the ones nobody remembered to override, which
   is how a filter chip on Clients came to be a #635bff pill on #f0f2ff in
   both themes (owner 2026-08-06: "shreds of the violet mockup in the clients filter
   mockup"). Overriding one more rule would have left the next one waiting, so
   the TOKEN is repointed at the product's own green: the ~30 legacy rules
   that reference it (banners, auth marks, tabs, link buttons, focus rings)
   all land on the right colour at once, whether or not they are reachable
   today. `--focus` follows, from lavender at 1.63:1 to the same ring the R13
   sheet paints. */
:root {
  --bg: #f6f8f9; --fg: #30313d; --muted: #6a7383; --faint: #8792a2;
  --hairline: #e8eaed; --border: #d8dce3; --border-strong: #b7bdc9;
  --accent: #08785a; --accent-fg: #ffffff; --accent-tint: #e4f2ec;
  --danger-bg: #FCEBEB; --danger-fg: #A32D2D; --ok-bg: #e8f6ec; --ok-fg: #0e8420;
  --focus: rgba(8, 120, 90, 0.3); --panel: #f6f8f9; --hover: #f8f9fb;
  --radius-control: 8px; --radius-card: 10px;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;
  --fs-xs: 12px; --fs-sm: 13px; --fs-md: 14px; --fs-lg: 16px; --fs-xl: 20px;
  --tr: 120ms ease; --card-shadow: 0 1px 2px rgba(0,0,0,.03);
}
* { box-sizing: border-box; }
html { height: 100%; scrollbar-gutter: stable; }
/* min-height uses dvh (dynamic viewport height) so the visible viewport — not
   iOS Safari's larger layout viewport — sets the floor; 100vh here left the
   page a toolbar-height too tall on iPad/iPhone, causing a phantom scroll. */
body { margin: 0; min-height: 100dvh; display: flex;
  background: var(--bg); color: var(--fg);
  font: var(--fs-md)/1.55 -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif; }
.side { width: 210px; flex: none; background: #fff;
  border-right: 1px solid var(--hairline); padding: 16px 10px;
  display: flex; flex-direction: column; gap: 6px;
  position: sticky; top: 0; height: 100dvh; }
.side .brand { font-weight: 700; font-size: 15px; padding: 4px 12px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.side-toggle { background: none; border: none; color: var(--muted); cursor: pointer;
  padding: 4px; border-radius: 6px; display: inline-flex; }
.side-toggle svg { width: 18px; height: 18px; }
.side-toggle:hover { background: var(--hover); color: var(--fg); }
.side nav { display: flex; flex-direction: column; gap: 1px; }
.side nav a { display: flex; gap: 9px; align-items: center; padding: 8px 12px;
  border-radius: var(--radius-control); color: var(--muted); text-decoration: none;
  font-size: var(--fs-sm); transition: background var(--tr), color var(--tr); }
.side nav a:hover { background: var(--hover); color: var(--fg); }
.side nav a.on { background: var(--accent-tint); color: var(--accent); font-weight: 600; }
.glyph { width: 16px; height: 16px; flex: none; }
.sysinfo { margin-top: auto; padding: 10px 12px; color: var(--faint);
  font-size: 11px; line-height: 1.5; border-top: 1px solid var(--hairline);
  word-break: break-all; }
/* Collapsed sidebar: icon rail only */
html.side-collapsed .side { width: 58px; padding: 16px 8px; }
html.side-collapsed .side .brand { justify-content: center; padding: 4px 0 14px; }
html.side-collapsed .side .brand-name,
html.side-collapsed .side nav a .lbl,
html.side-collapsed .side .sysinfo { display: none; }
html.side-collapsed .side nav a { justify-content: center; padding: 8px 0; }
.content { flex: 1; min-width: 0; }
/* --- the small layout vocabulary item 17b moved off the templates ---------
   Thirty-six hard-coded `style=` attributes lived in the screens: a gap above
   a block, a control that fills its row, a measure that keeps a column of
   prose readable, the same handful of intentions written out again and again.
   They are named here instead. The values are kept EXACT — this sweep was
   never meant to move a pixel, and a 13px that quietly became 12 would be a
   restyle smuggled in as a cleanup.

   Two kinds of inline style deliberately STAY, and the web-shell spec records
   both so the next sweep does not re-litigate them: values the SERVER computes
   (a chart bar's height, a palette swatch's colour) and initial-state
   visibility toggles. Each carries its own comment where it sits. */
.mt-3 { margin-top: 3px; }
.mt-4 { margin-top: 4px; }
.mt-6 { margin-top: 6px; }
.mt-10 { margin-top: 10px; }
.mt-12 { margin-top: 12px; }
.mt-13 { margin-top: 13px; }
.mb-4 { margin: 0 0 4px; }
.mb-12 { margin-bottom: 12px; }
.mb-14 { margin: 0 0 14px; }
.my-12 { margin: 12px 0; }
.m-0 { margin: 0; }
.fill-row { width: 100%; }
/* a readable column of prose, and the narrow one a lone control sits in */
.measure { max-width: 480px; }
.measure-narrow { max-width: 240px; }
.inline-form { display: inline; }
/* a label and its short field, sharing one baseline */
.field-row { display: flex; gap: 8px; align-items: end; }
.w-90 { width: 90px; }
.w-110 { width: 110px; }
.text-left { text-align: left; }
.justify-start { justify-content: flex-start; }
/* a file input is as wide as the browser wants it, so it is told otherwise */
.file-field { min-width: 0; max-width: 100%; }
.text-xs { font-size: var(--fs-xs); }
/* the Data card's rows: a control, its file field and its button, wrapping
   together rather than one at a time */
.data-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin: 12px 0; }

main { max-width: 1140px; margin: 0 auto; padding: var(--sp-5) 28px var(--sp-6); }
h1 { font-size: 17px; font-weight: 600; margin: 0 0 var(--sp-4); letter-spacing: -0.01em; }
h2 { font-size: var(--fs-lg); font-weight: 600; margin: var(--sp-5) 0 var(--sp-3); }
table { width: 100%; border-collapse: separate; border-spacing: 0;
  background: #fff; border: 1px solid var(--hairline);
  border-radius: var(--radius-card); box-shadow: var(--card-shadow);
  overflow: hidden; }
th { font-size: 11px; color: var(--muted); font-weight: 600; text-align: left;
  padding: 9px 12px; border-bottom: 1px solid var(--hairline);
  background: #fbfcfd; }
td { padding: 9px 12px; border-bottom: 1px solid #f0f1f4; font-size: var(--fs-sm);
  vertical-align: middle; }
tr:last-child td { border-bottom: none; }
table tr:hover td { background: var(--hover); }
th.num, td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
input, select, textarea { border: 1px solid var(--border); border-radius: var(--radius-control);
  background: #fff; color: var(--fg); padding: 7px 10px; font: inherit;
  transition: border-color var(--tr), box-shadow var(--tr); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus); }
/* Checkboxes/radios keep native geometry so focus never resizes them (v06 §8) */
input[type="checkbox"], input[type="radio"] { border: 0; padding: 0; box-shadow: none; }
input[type="checkbox"]:focus, input[type="radio"]:focus { border: 0; box-shadow: none;
  outline: 2px solid var(--accent); outline-offset: 1px; }
label { display: block; font-size: var(--fs-xs); color: var(--muted); margin: var(--sp-3) 0 var(--sp-1); }
button, .btn { display: inline-block; border: 1px solid var(--border); background: #fff; color: var(--fg);
  border-radius: var(--radius-control); padding: 8px 16px; font: inherit; cursor: pointer;
  text-decoration: none; transition: background var(--tr), border-color var(--tr); }
button:hover, .btn:hover { background: var(--panel); }
.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-primary:hover { background: #056146; }   /* --green-dark */
.btn-accent { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.btn-accent:hover { background: #056146; }
.btn-sm { padding: 4px 10px; font-size: var(--fs-xs); }
.error { background: var(--danger-bg); color: var(--danger-fg); padding: 10px 14px;
  border-radius: var(--radius-control); margin: 0 0 var(--sp-4); }
.ok { background: var(--ok-bg); color: var(--ok-fg); padding: 10px 14px;
  border-radius: var(--radius-control); margin: 0 0 var(--sp-4); }
.muted { color: var(--faint); font-size: var(--fs-xs); }
.cards { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin: 0 0 var(--sp-5); }
.card { background: #fff; border: 1px solid var(--hairline); border-radius: var(--radius-card);
  padding: var(--sp-3) 18px; min-width: 140px; box-shadow: var(--card-shadow); }
.card b { display: block; font-size: var(--fs-xl); font-variant-numeric: tabular-nums; }
.row-actions { display: flex; gap: var(--sp-1); justify-content: flex-end; align-items: center; }
.row-actions form { display: inline; }
/* `.toolbar` is the shared filter band (shell.css, `.r13 .toolbar`). The copy
   that lived here set `justify-content: space-between`, a property the band
   does not declare — so it still won the cascade and spread three selects
   across the whole row with 50px holes between them. */
/* Wrap a wide table in this so the page body never scrolls horizontally. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
details.items { margin-top: 6px; }
details.items summary { cursor: pointer; color: var(--accent); font-size: var(--fs-xs); }
.item-row { display: flex; gap: var(--sp-2); margin: 6px 0; align-items: center; }
.item-row input.desc { flex: 1; }
.item-row input.amt { width: 120px; text-align: right; font-variant-numeric: tabular-nums; }
.item-row .idx { color: var(--faint); font-size: var(--fs-xs); width: 18px; text-align: right; }
.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600;
  padding: 3px 9px; border-radius: 999px; background: var(--accent-tint);
  color: var(--accent); white-space: nowrap; }
.badge-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
/* Payment-status badges (batch detail + reports invoice list) — Unpaid/Paid + Void */
.badge.st-unpaid { background: var(--hairline); color: var(--muted); }
.badge.st-paid { background: var(--ok-bg); color: var(--ok-fg); }
.badge.st-voided { background: var(--danger-bg); color: var(--danger-fg); }
.paycell { white-space: nowrap; }
.paidon { color: var(--faint); font-size: var(--fs-xs); margin-left: 6px; }
tr.voided td { opacity: .55; }
tr.voided .invno { text-decoration: line-through; }
/* Row "⋯" actions menu (batch detail) */
details.rowmenu { position: relative; display: inline-block; }
details.rowmenu > summary { list-style: none; cursor: pointer; color: var(--muted);
  border: 1px solid var(--border); border-radius: var(--radius-control);
  padding: 3px 10px; line-height: 1; display: inline-flex; align-items: center; }
details.rowmenu > summary:hover { color: var(--fg); background: var(--panel); }
details.rowmenu > summary::-webkit-details-marker { display: none; }
/* vertical "kebab" — thicker than a thin glyph, the conventional actions icon */
.kebab { font-weight: 900; font-size: 19px; line-height: 1; letter-spacing: normal; }
details.rowmenu[open] > summary { background: var(--panel); color: var(--fg); }
details.rowmenu .menu-list { right: 0; top: calc(100% + 4px); }
.menu-list form { display: block; margin: 0; }
.menu-list a { white-space: nowrap; }
.menu-list .linkbtn { display: block; width: 100%; text-align: left; padding: 6px 14px;
  font-size: var(--fs-sm); color: var(--fg); }
.menu-list .linkbtn:hover { background: var(--panel); text-decoration: none; }
.menu-list .linkbtn.danger { color: var(--danger-fg); }
.linkbtn { background: none; border: none; padding: 0; cursor: pointer; color: var(--accent);
  font: inherit; font-size: var(--fs-xs); }
.linkbtn:hover { text-decoration: underline; }
.linkbtn.danger { color: var(--danger-fg); }
/* Bulk action bar (batch detail) */
.bulkbar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  background: var(--accent); color: #fff; border-radius: var(--radius-card);
  padding: 8px 14px; margin: 0 0 var(--sp-3); box-shadow: var(--card-shadow); }
/* an explicit display rule overrides the [hidden] UA default — restore it so the
   bar stays hidden until a row is selected */
.bulkbar[hidden] { display: none; }
.bulkcount { font-size: var(--fs-sm); }
.bulkcount b { font-weight: 700; }
.bulksep { flex: 1; }
.bulkbar .btn { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .34);
  color: #fff; }
.bulkbar .btn:hover { background: rgba(255, 255, 255, .28); }
.chkcol { width: 30px; text-align: center; }
.chkcol input { margin: 0; vertical-align: middle; }
.setup-checklist { line-height: 1.9; padding-left: 20px; margin: 0 0 var(--sp-3); }
/* Guided setup (/setup) step cards */
.setup-steps { list-style: none; padding: 0; margin: 0 0 var(--sp-4); max-width: 560px; }
.setup-step { display: flex; gap: 14px; align-items: flex-start; padding: 16px;
  border: 1px solid var(--hairline); border-radius: var(--radius-card);
  margin-bottom: var(--sp-3); box-shadow: var(--card-shadow); background: #fff; }
.setup-step.done { background: var(--panel); }
.setup-step-mark { flex: none; width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-weight: 700;
  background: var(--accent-tint); color: var(--accent); }
.setup-step.done .setup-step-mark { background: var(--accent); color: #fff; }
.setup-step-body { flex: 1; }
.setup-step-body > div { margin-top: 6px; }
.setup-cta { margin-top: var(--sp-5); }
.steps { display: flex; gap: 10px; align-items: center; margin: 0 0 22px;
  font-size: var(--fs-md); color: var(--faint); flex-wrap: wrap; }
.steps .cur { color: var(--accent); font-weight: 700;
  background: var(--accent-tint); padding: 4px 14px; border-radius: 999px; }
.steps .sep { color: var(--border); font-size: var(--fs-sm); }
dialog { border: 1px solid var(--border); border-radius: var(--radius-card); padding: 0;
  width: min(560px, 92vw); color: var(--fg); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.18); }
dialog::backdrop { background: rgba(20, 19, 15, 0.35); }
dialog .modal-head { display: flex; justify-content: space-between; align-items: center;
  padding: 16px 20px; border-bottom: 1px solid var(--hairline); }
dialog .modal-head h2 { margin: 0; font-size: var(--fs-lg); }
dialog .modal-body { padding: 4px 20px 16px; max-height: 70vh; overflow: auto; }
dialog .modal-foot { display: flex; justify-content: flex-end; gap: var(--sp-2);
  padding: 14px 20px; border-top: 1px solid var(--hairline); }
.modal-close { background: none; border: none; font-size: 20px; line-height: 1;
  color: var(--muted); cursor: pointer; padding: 0 4px; }
.modal-close:hover { color: var(--fg); background: none; }
.logo-block { display: flex; gap: var(--sp-4); align-items: center; margin-top: var(--sp-2); }
.logo-preview { max-width: 160px; max-height: 80px; border: 1px solid var(--hairline);
  border-radius: 6px; padding: 6px; background: #fff; object-fit: contain; }
.tabs { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin: 0 0 var(--sp-3); }
.tab { text-decoration: none; color: var(--muted); background: #fff; border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 14px; font-size: var(--fs-sm);
  transition: background var(--tr), color var(--tr); }
.tab b { font-variant-numeric: tabular-nums; }
.tab:hover { background: var(--panel); color: var(--fg); }
.tab.on { background: var(--accent-tint); color: var(--accent); border-color: var(--accent); }
.total-row td { border-top: 1px solid var(--border); font-weight: 600; }
.pagination { display: flex; gap: var(--sp-3); align-items: center; margin: var(--sp-3) 0; }
.wizfoot { position: sticky; bottom: 0; background: var(--bg);
  border-top: 1px solid var(--border); margin-top: var(--sp-3);
  padding: var(--sp-3) 0; display: flex; justify-content: space-between;
  align-items: center; gap: var(--sp-3); }
nav a.on { background: var(--accent-tint); color: var(--accent); }
.steps a { color: var(--muted); text-decoration: none; font-weight: 600; }
.steps a:hover { color: var(--accent); }
a.cardlink { text-decoration: none; color: inherit; display: block; }
a.cardlink:hover { background: var(--hover); }
.menu { position: relative; }
.menu summary { list-style: none; cursor: pointer; font-size: var(--fs-sm);
  color: var(--muted); border: 1px solid var(--border); border-radius: var(--radius-control);
  padding: 4px 10px; }
.menu[open] summary { background: var(--panel); }
.menu-list { position: absolute; z-index: 10; background: #fff; border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 8px 30px rgba(0,0,0,.12); padding: 6px 0; min-width: 150px; }
.menu-list a { display: block; padding: 6px 14px; color: var(--fg);
  text-decoration: none; font-size: var(--fs-sm); }
.menu-list a:hover { background: var(--panel); }
.eur-note { color: var(--faint); font-size: var(--fs-xs); }
.mrow { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
/* `.chip` / `.chiprow` are the shared filter band's (shell.css, `.r13`). The
   copy that used to live here was the one the entity screens fell back to. */
.mlink { color: var(--accent); font-size: var(--fs-xs); text-decoration: none; }
.btn-danger { background: var(--danger-bg); color: var(--danger-fg); border-color: #d9a7a7; }
.btn-danger:hover { background: #f6dede; }
/* The wizard's step-1 row pick, its step-3 mode cards and its step-3 rate
   rows were styled here. Every one of those anchors went with the screens
   themselves; the JS that drove them went in the same sweep (item 20).
   `.rate-row` is NOT Settings' rate editor — that one keys on the
   attribute `data-rate-row`, and it is untouched. */
.rename-input { width: 200px; max-width: 100%; }
/* Templates page cards + preview radio-cards */
.template-cards { display: grid; gap: 20px; margin-top: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.template-card { border: 1px solid var(--hairline); border-radius: 10px; overflow: hidden;
  background: #fff; }
.template-preview { height: 230px; overflow: hidden; background: #f4f3ef;
  border-bottom: 1px solid var(--hairline); }
.template-preview iframe { position: absolute; top: 0; left: 50%; width: 794px; height: 1123px;
  border: 0; transform: translateX(-50%) scale(0.31); transform-origin: top center;
  pointer-events: none; }
.template-card form { padding: 14px; display: flex; flex-direction: column; gap: 6px; }
.template-picker { display: flex; gap: 14px; flex-wrap: wrap; margin: 4px 0 var(--sp-2); }
.template-radio { cursor: pointer; border: 1px solid var(--hairline); border-radius: 8px;
  overflow: hidden; width: 150px; display: block; }
.template-radio:has(input:checked) {
  border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.template-radio input { position: absolute; opacity: 0; pointer-events: none; }
.template-radio .template-radio-preview { height: 150px; overflow: hidden; background: #f4f3ef;
  display: block; position: relative; }
.template-radio .template-radio-preview iframe { position: absolute; top: 0; left: 50%;
  width: 794px; height: 1123px; border: 0;
  transform: translateX(-50%) scale(0.189); transform-origin: top center; pointer-events: none; }
.template-radio .template-radio-label { display: block; padding: 6px 10px; text-align: center;
  text-transform: capitalize; }
/* Enlarge preview (pickers + Templates page) */
.tpl-enlarge { background: none; border: none; cursor: pointer; padding: 0 2px;
  color: var(--muted); font-size: 13px; line-height: 1; }
.tpl-enlarge:hover { color: var(--accent); }
.template-preview { position: relative; }
.tpl-enlarge.on-card { position: absolute; bottom: 10px; right: 10px; padding: 0;
  width: 40px; height: 40px; border-radius: 50%; background: var(--blue-fixed); color: #fff;
  font-size: 18px; display: flex; align-items: center; justify-content: center; }
.tpl-enlarge.on-card:hover { background: var(--blue-fixed-strong); color: #fff; }
.tpl-preview-dialog { width: min(600px, 94vw); }
.tpl-preview-body { padding: 0; background: #f4f3ef; position: relative; overflow: hidden; }
.tpl-preview-body iframe { position: absolute; top: 0; left: 50%; width: 794px; height: 1123px;
  border: 0; transform: translateX(-50%) scale(var(--tpl-scale, 0.72)); transform-origin: top center; }
/* "Preview" watermark — host chrome over the iframe, never inside the invoice */
.tpl-watermark { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; pointer-events: none; font-weight: 500; letter-spacing: 0.1em;
  color: var(--blue-fixed); opacity: 0.22; transform: rotate(-24deg); }
.tpl-preview-body .tpl-watermark { font-size: 60px; }
.template-radio-preview .tpl-watermark { font-size: 15px; }
/* Accent palette swatches */
.accent-palette { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px;
  align-items: center; margin: 2px 0 var(--sp-2); }
.accent-palette .swatch { height: 28px; border: 1px solid rgba(0, 0, 0, 0.14);
  border-radius: 6px; cursor: pointer; padding: 0; }
.accent-palette .swatch.sel { border-color: transparent;
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--blue); }
.accent-palette .accent-hex { grid-column: 1 / -1; font-variant-numeric: tabular-nums; }
/* Total card: right-align the figures so the decimals line up */
.total-card { text-align: right; }
/* Clickable, truncated output path */
.pathlink { background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  color: var(--accent); font: inherit; max-width: 380px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.pathlink:hover { text-decoration: underline; }
.banner { background: var(--accent-tint); color: var(--fg); padding: 12px 16px;
  border-radius: var(--radius-control); margin: 0 0 var(--sp-4);
  border: 1px solid var(--blue-soft); }
.banner a:not(.btn) { color: var(--accent); }
.banner .btn-primary { color: #fff; }
/* Vertical multi-currency breakdowns share one right edge (invariant: numbers
   right-aligned): the note shrinks to its widest line and right-aligns within. */
.eur-note { font-variant-numeric: tabular-nums; }
.kpi .eur-note { width: max-content; max-width: 100%; text-align: right; }
.update-banner { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; background: var(--accent-tint); color: var(--fg);
  border: 1px solid var(--blue-soft); border-radius: var(--radius-control);
  padding: 8px 14px; margin: 0 0 var(--sp-4); font-size: var(--fs-sm); }
.update-banner a { color: var(--accent); }
.update-banner .banner-x { background: none; border: none; color: var(--faint);
  font-size: 18px; line-height: 1; cursor: pointer; padding: 0 4px; }
.update-banner .banner-x:hover { color: var(--fg); }
.chart { display: flex; gap: 6px; align-items: flex-end; height: 120px; }
.cbar { flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
  align-items: center; gap: 4px; text-decoration: none; height: 100%; }
.cbar .bar { width: 100%; max-width: 42px; border-radius: 4px 4px 0 0;
  background: #dcdafc; transition: background var(--tr); }
.cbar:hover .bar { background: #b9b4ff; }
.cbar.prev .bar { background: #a79fff; }
.cbar.cur .bar { background: var(--accent); }
.cbar .clab { font-size: 10px; color: var(--faint); }
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-3); margin: 0 0 var(--sp-4); }
.kpi { background: #fff; border: 1px solid var(--hairline);
  border-radius: var(--radius-card); padding: 12px 16px; flex: 1;
  box-shadow: var(--card-shadow); }
.kpi .lbl { color: var(--muted); font-size: 11.5px; }
.kpi .val { font-size: 20px; font-weight: 650; margin: 2px 0; }
.delta { font-size: 11px; padding: 1px 8px; border-radius: 999px;
  background: var(--ok-bg); color: var(--ok-fg); }
.delta.down { background: var(--danger-bg); color: var(--danger-fg); }
.chart-card { margin: 0 0 var(--sp-4); }
tr.row-dup td { background: #fdf6ec; }
tr.row-dup td:first-child { box-shadow: inset 3px 0 0 #D97917; }
tr.row-dup:hover td { background: #fbf0df; }
.dup-note { color: #9A6414; font-size: 11px; }
.banner.warn { background: #FBEFD9; border-color: #ecd9ae; }

/* Auth pages (multi-tenant public chrome): brand header + centered card */
body.public .content { display: flex; align-items: center; justify-content: center; }
body.public main { width: 100%; max-width: 400px; padding: 24px 16px 40px; }
.auth-brand { display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin-bottom: 20px; }
.auth-mark { width: 44px; height: 44px; border-radius: 12px; background: var(--accent);
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 20px; }
.auth-brand b { font-size: var(--fs-lg); }
.auth-tagline { color: var(--muted); font-size: var(--fs-sm); margin: 0; text-align: center; }
.auth-card { background: #fff; border: 1px solid var(--hairline); border-radius: 12px;
  padding: 24px; box-shadow: 0 1px 2px rgba(16,24,40,.04), 0 8px 24px rgba(16,24,40,.06); }
.auth h1 { font-size: var(--fs-xl); margin: 0 0 var(--sp-4); }
.auth-form { display: flex; flex-direction: column; }
.auth-form input { width: 100%; }
.auth-form button[type="submit"] { margin-top: var(--sp-4); width: 100%; padding: 9px 14px; }
.auth .hint { font-size: var(--fs-xs); color: var(--muted); margin: var(--sp-1) 0 0; }
.auth-alt { margin-top: var(--sp-4); font-size: var(--fs-sm); color: var(--muted); }
.auth-links { display: flex; justify-content: space-between; gap: 12px;
  margin-top: var(--sp-4); font-size: var(--fs-sm); }
.auth a { color: var(--accent); }
.auth-foot { margin-top: 18px; text-align: center; color: var(--faint);
  font-size: var(--fs-xs); }
.pw-field { position: relative; display: block; }
.pw-field input { padding-right: 58px; }
.pw-toggle { position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  border: none; background: none; color: var(--muted); font-size: var(--fs-xs);
  cursor: pointer; padding: 4px 6px; }
.pw-toggle:hover { color: var(--fg); }

/* Account block in the sidebar (multi-tenant) — pinned to the bottom above sysinfo */
.account { margin-top: auto; padding: 10px 12px; border-top: 1px solid var(--hairline); }
.account-email { display: block; font-size: var(--fs-xs); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.logout-form { margin: 6px 0 0; }
.logout-btn { width: 100%; font-size: var(--fs-xs); padding: 4px 10px; }
a.account-email { color: var(--muted); text-decoration: none; }
a.account-email:hover { color: var(--accent); }

/* ===================== Responsive: tablet & phone =====================
   --bp-tablet 900px  → sidebar becomes a top bar + slide-over
   --bp-phone  560px  → list/wizard card layouts, full-screen dialogs
   No dark mode; white background and the same palette throughout. */
.topbar { display: none; }
.nav-backdrop { display: none; }

@media (max-width: 900px) {
  body { flex-direction: column; }
  .topbar { display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 10px 16px; background: #fff;
    border-bottom: 1px solid var(--hairline); position: sticky; top: 0; z-index: 30; }
  .topbar .brand-name { font-weight: 700; font-size: 15px; }
  .nav-hamburger { background: none; border: none; color: var(--fg); cursor: pointer;
    padding: 8px; display: inline-flex; border-radius: 6px; min-width: 44px;
    min-height: 44px; align-items: center; justify-content: center; }
  .nav-hamburger:hover { background: var(--hover); }
  /* the existing nav aside becomes an off-canvas slide-over (same markup) */
  .side { position: fixed; top: 0; left: 0; height: 100dvh; width: 264px; z-index: 50;
    transform: translateX(-100%); transition: transform var(--tr);
    box-shadow: 0 8px 30px rgba(0,0,0,.18); }
  html.nav-open .side { transform: translateX(0); }
  html.nav-open .nav-backdrop { display: block; position: fixed; inset: 0; z-index: 40;
    background: rgba(0,0,0,.35); }
  .side-toggle { display: none; }   /* hamburger replaces the collapse control */
  /* the desktop collapse state never applies on mobile — the slide-over is full width */
  html.side-collapsed .side { width: 264px; padding: 16px 10px; }
  html.side-collapsed .side .brand,
  html.side-collapsed .side nav a { justify-content: flex-start; padding: 8px 12px; }
  html.side-collapsed .side .brand { padding: 4px 12px 14px; }
  html.side-collapsed .side .brand-name,
  html.side-collapsed .side nav a .lbl,
  html.side-collapsed .side .sysinfo { display: revert; }
  main { padding: var(--sp-4) 16px var(--sp-6); }
}

/* The entity lists' card breakpoint is where THEIR table stops having room —
   and the width a media query is compared against INCLUDES the scrollbar.
   That is the whole history of this number: 990 was measured on the checker's
   synthetic book, 1015 on the demo book, and BOTH were measured in headless
   Chromium, where scrollbars are hidden and `clientWidth == innerWidth`. On
   a machine with a classic bar the table is handed 15–17px less than the
   number it was tested against, which is why the owner still saw Clients
   scroll at viewport 1019 while every gate was green (round 2b, item 7).

   The arithmetic, stated so the next reader does not re-derive it wrong:
   table minimum 753 (checker book — the wider of the two; the demo book is
   750) + shell chrome 276 + a 17px gutter = 1046, so the first width a table
   fits at is 1047. Cards own everything below it. The minimum grew 13px in
   round 4: the kebab became a 36px square (+17 on the actions column) and the
   title column's floor gave 17 back in the two bands that had no slack.
   Measured with a REAL classic bar, which is the sweep's own environment —
   shrinking the holder instead under-measures by 2, `.table-scroll` being
   border-box with 1px sides. 17 rather than 15 because macOS classic bars are 15 and Windows Chrome
   is 17, and this ships hosted. The sweep now renders WITH a 17px bar, so
   the fit point and the checker speak the same quantity.

   NOTE the threshold is a BOOK constant, not a bound: at eight-figure
   Outstanding values the table's minimum grows ~62px and this band reopens.
   Invoices keeps its own 900 — its grid fits from 901 up on the same book.
   The dialog full-screen sheet rules stay phone-only in the 560 block. */
@media (max-width: 1046px) {
  /* clients/products/companies lists → labeled cards (num stays right-aligned) */
  table.list-cards, table.list-cards tbody { display: block; border: 0; box-shadow: none;
    background: transparent; }
  table.list-cards tr:has(th) { display: none; }   /* the header row */
  /* The card IS the surface the shell's ink lands on, so it takes the shell's
     surface tokens (`--paper`/`--line`, themed in shell.css) — a hard #fff here
     painted white text on a white card in dark theme on every list screen at
     once (FORMS-02). One rule, three screens: Clients, Products, Companies. */
  table.list-cards tr { display: block; background: var(--paper); border: 1px solid var(--line);
    border-radius: var(--radius-card); box-shadow: var(--card-shadow); margin: 0 0 10px;
    padding: 6px 14px; }
  table.list-cards tr:hover td { background: transparent; }
  /* the last card has nothing left to separate itself from: its 10px was half
     of the 45px band under a 390 list (owner round 4, №14) */
  table.list-cards tr:last-child { margin-bottom: 0; }
  /* the live search hides rows with [hidden]; the display above would win */
  table.list-cards tr[hidden] { display: none; }
  table.list-cards td { display: flex; justify-content: space-between; gap: 12px; border: 0;
    padding: 5px 0; font-size: var(--fs-sm); text-align: right; }
  table.list-cards td::before { content: attr(data-th); color: var(--muted); font-weight: 600;
    font-size: 11px; text-align: left; }
  table.list-cards td.row-actions { justify-content: flex-end; flex-wrap: wrap; gap: 6px;
    padding-top: 8px; border-top: 1px solid var(--line-2); margin-top: 4px; }
  table.list-cards td.row-actions::before { content: none; }
  /* A labelled key/value list is a DEBUGGING view, not a browsing view: five
     labels per card repeated the column header 25 times and buried the two
     facts that identify a record. 25 products came to ~8,300px of scrolling
     against the prototype's ~2,835 (design critique P14/CO-09).

     A row declares each cell's card ROLE — `title`, `figure`, `meta` — and the
     card is composed from those: name and figure on line one, everything else
     joined into one meta line, actions last. A cell with no role is not shown
     on a phone; it is still in the table above 560px. */
  table.list-cards tr:has(td[data-card]) { display: flex; flex-wrap: wrap;
    align-items: baseline; column-gap: 8px; row-gap: 2px; }
  table.list-cards tr:has(td[data-card]) td { display: block; padding: 2px 0;
    text-align: left; border: 0; }
  table.list-cards td[data-card]::before { content: none; }
  /* Two lines, always the same two: WHAT it is and what it amounts to on line
     one, everything else on line two. The money rides BESIDE the title in the
     top-right, which was empty for the full height of the name (owner verdict
     R2, round 4: "the figure moves up into the empty space on the right»); the band it
     used to sit on goes with it. The pseudo-element is the line break — a flex
     item of its own, 100% wide and 0 high, so `order` alone composes the card
     without a wrapper element in the markup. */
  table.list-cards tr:has(td[data-card])::after { content: ""; order: 2;
    flex: 0 0 100%; height: 0; }
  table.list-cards tr:has(td[data-card]) td[data-card="title"] { order: 1;
    flex: 1 1 0; min-width: 0; padding-bottom: 0; font-size: var(--fs-md); }
  table.list-cards tr:has(td[data-card]) td[data-card="title"] .entity-name,
  table.list-cards tr:has(td[data-card]) td[data-card="title"] .meta {
    max-width: 100%; }
  /* The name and its currency flag stay ONE line: released to the full band a
     68-char client pushed the flag onto a second line, and that one card stood
     124.5px against the list's 102.4 — a column of cards with one ragged
     height reads as a rendering fault. Ellipsised, every card is one height and
     the full name is still in the title attribute. */
  table.list-cards tr:has(td[data-card]) td[data-card="title"] b {
    display: flex; min-width: 0; gap: 6px; align-items: baseline; }
  table.list-cards td[data-card="figure"] { order: 1; margin-left: auto;
    text-align: right; font-weight: 650; font-variant-numeric: tabular-nums; }
  /* The card has no header row — it is hidden above — so the ONE figure on it
     says what it is and what it is IN. The label is the `data-th` the table's
     own `th` carries; the unit is the column header's parenthetical, as an
     attribute so the DOM text stays a bare sortable number. Not the five-label
     key/value list rejected above: one cell, and the one whose meaning left
     with the header ("no explanation of what the sum even is" / "the currency in the list is not
     shown in the card mode" — owner round 3). */
  table.list-cards td[data-card="figure"]::before { content: attr(data-th) " ";
    color: var(--muted); font-weight: 600; font-size: 11px; }
  table.list-cards td[data-card="figure"][data-unit]::after {
    content: " " attr(data-unit); }
  /* the identifying line stays ONE line: the description meta used to wrap and
     push the figures around */
  table.list-cards td[data-card="title"] .meta { overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  table.list-cards td[data-card="meta"] { order: 3; font-size: 11.5px; color: var(--muted); }
  table.list-cards td[data-card="meta"]:empty { display: none; }
  table.list-cards td[data-card="meta"][data-unit]::after { content: " " attr(data-unit); }
  /* a GENERAL sibling: the figure cell sits between two metas in the DOM on
     Products, and `+` dropped the separator there */
  table.list-cards td[data-card="meta"] ~ td[data-card="meta"]::before { content: "· ";
    color: var(--faint); }
  /* A row's actions end at the row's RIGHT edge on every surface: the table
     cell, the invoice phone card (`margin-left: auto`, shell.css
     `.cardacts-btns`) and this one. `tr:has(td[data-card]) td` above turns
     every card cell into a left-aligned block, which is what put the kebab
     183–693px from the card's right edge (owner round 3, items 3/5/9);
     `justify-content: flex-end` was already computed on this cell and was
     simply inert until it became a flex container. */
  /* `width: auto` is load-bearing: the table rule `.entity-table td.row-actions
     { width: 1% }` otherwise resolves this cell's flex basis to 7px and the
     three controls stack VERTICALLY inside it — measured, 124px tall. */
  /* The actions close line two, and the auto margin is theirs on every screen
     now that the money has left that line — Companies (which has no figure)
     needs no rule of its own any more. */
  table.list-cards tr:has(td[data-card]) td.row-actions { order: 4; flex: 0 0 auto;
    width: auto; margin: 0 0 0 auto; display: flex; justify-content: flex-end;
    align-items: center; }
  table.list-cards tr:has(td[data-card]) td:not([data-card]):not(.row-actions) {
    display: none; }
}

@media (max-width: 560px) {
  main { padding: var(--sp-3) 12px var(--sp-5); }
  /* No phone rule any more: with the money on line one the actions share line
     two with the meta at every width, so the card is the same two lines from
     360 to 1046 (round 4, R2). The round-3 rule that gave them a line of their
     own at ≤560 is what that band was. */
  /* modal forms (client/product) become full-screen sheets on phones */
  dialog { width: 100vw; max-width: none; height: 100dvh; max-height: none;
    border: 0; border-radius: 0; }
  dialog .modal-body { max-height: none; }
  .tpl-preview-dialog { width: 100vw; }
  .cards { flex-direction: column; }
  /* The wizard's step-2 card layout was here, on the `#wt2` table nothing
     has rendered since the matrix took the screen over (item 20). */
  /* sticky selection footer + full-width buttons */
  .wizfoot { flex-direction: column; align-items: stretch; gap: 10px; }
  .wizfoot > div { display: flex; gap: 8px; }
  .wizfoot > div > * { flex: 1; text-align: center; }
  .finalize-bar { position: sticky; bottom: 0; background: var(--bg);
    border-top: 1px solid var(--border); padding: 10px 0; z-index: 10; margin-top: 0; }
  .finalize-bar > div { display: flex; gap: 8px; flex-wrap: wrap; }
  .finalize-bar > div > * { flex: 1; text-align: center; }
}

/* Touch devices: ≥44px targets and ≥16px inputs (the latter stops iOS focus-zoom) */
@media (pointer: coarse) {
  button, .btn, .nav-hamburger, select { min-height: 44px; }
  input, select, textarea { font-size: 16px; }
}

/* Anonymous sandbox banner (try-before-register) */
.anon-banner { background: var(--accent-tint); color: var(--accent);
  border: 1px solid #c3ded2; border-radius: var(--radius-control);
  padding: 10px 14px; margin: 0 0 var(--sp-4); font-size: var(--fs-sm); }
.anon-banner a { color: var(--accent); font-weight: 600; }
