/* aboo brand layer over tina4css — admin PWA shell, mobile-first.
   tina4css provides btn/card/badge/grid/forms; this adds the app frame + brand tokens. */
/* Brand tokens mapped from the canonical aboo palette (brand/aboo-colors.css).
   --aboo-accent / --aboo-bg / --aboo-fg flip with [data-theme]; we layer surfaces on top. */
:root{
  --brand: var(--aboo-accent);   /* teal #19C4C4 light / #2AE0E0 dark */
  --brand-ink: var(--aboo-ink);  /* #0E2E33 deep teal — drawer, code chips */
  --bg: var(--aboo-bg);          /* #EAF3F2 mist (light) / #0E2E33 (dark) */
  --ink: var(--aboo-fg);         /* text */
  --surface:#ffffff; --muted:#2E575E; --line:#d3e6e4;
  --ok:#15803d; --bad:#b91c1c; --warn:#b45309; --info:#0e7490;
  --drawer-w:248px; --bar-h:58px; --radius:14px;
  /* mobile bottom nav: bar height, and the padding pages need so content clears it (+ the
     iPhone home-indicator inset, available because index.html sets viewport-fit=cover) */
  --bottom-nav-h:56px; --bottom-nav-space:calc(var(--bottom-nav-h) + env(safe-area-inset-bottom,0px));
}
/* aboo-colors.css lists `:root` in the LIGHT selector after the dark block (equal specificity →
   :root wins), so --aboo-bg/fg/accent never flip. Re-assert the dark values at higher specificity. */
:root[data-theme="dark"]{
  /* depth: drawer (darkest) < content bg < elevated surfaces (cards/app-bar) */
  --bg:#0c2429; --ink:#EAF3F2; --surface:#15414A; --muted:#8fb1b0; --line:#2E575E;
  --brand: var(--aboo-teal-bright);   /* #2AE0E0 bright teal in dark */
}
:root[data-theme="dark"] .drawer{ background:#081e22; }
:root[data-theme="dark"] .form-control{ background:#0c2429; color:var(--ink); border-color:var(--line); }
:root[data-theme="dark"] .form-control::placeholder{ color:#6f9694; }
:root[data-theme="dark"] .cat-code,
:root[data-theme="dark"] .iso-badge{ background:#081e22; color:var(--aboo-teal-bright); }
:root[data-theme="dark"] .row-card:hover,
:root[data-theme="dark"] .kpi{ box-shadow:0 1px 2px rgba(0,0,0,.3); }
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{background:var(--bg);color:var(--ink);
  font:15px/1.45 "Sora",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;-webkit-font-smoothing:antialiased}
#app{height:100%}
a{color:var(--brand);text-decoration:none}

/* ---------- brand lockup ---------- */
.brand-lockup{display:flex;align-items:center;gap:8px;font-weight:800;letter-spacing:-.01em}
.brand-dot{width:14px;height:14px;border-radius:50%;background:var(--brand);box-shadow:0 0 0 4px rgba(25,196,196,.25)}
.brand-name{font-size:20px}
.brand-sub{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.12em;opacity:.6;margin-left:2px}

/* ---------- layout ---------- */
.layout{min-height:100%}
.drawer{position:fixed;top:0;left:0;width:var(--drawer-w);height:100%;background:var(--brand-ink);
  color:#cfe9e8;display:flex;flex-direction:column;z-index:40;transition:transform .22s ease;overflow-y:auto}
.drawer-brand{padding:16px 18px;color:#fff;border-bottom:1px solid rgba(255,255,255,.08)}
.nav-list{padding:10px 10px 24px}
.nav-section{font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:#7fb1ad;
  padding:14px 12px 6px;font-weight:700}
.nav-item{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;color:#cfe9e8;
  cursor:pointer;font-weight:500;user-select:none}
.nav-item:hover{background:rgba(255,255,255,.06);color:#fff}
.nav-item.active{background:var(--brand);color:var(--aboo-ink);font-weight:600}
.nav-item.soon{opacity:.45;cursor:default}
.nav-item.soon:hover{background:none;color:#cfe9e8}
.nav-ico{width:20px;text-align:center;font-size:15px;opacity:.9}
.nav-lbl{flex:1}
.soon-badge{font-size:12px;opacity:.8}

.main{margin-left:var(--drawer-w);min-height:100%;display:flex;flex-direction:column}
.app-bar{position:sticky;top:0;height:var(--bar-h);background:var(--surface);border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:12px;padding:0 16px;z-index:30}
.app-title{font-weight:700;font-size:16px;flex:1}
.app-user{display:flex;align-items:center;gap:10px}
.user-name{font-size:13px;color:var(--muted);max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* NOTE: the app-bar hamburger is gone. On mobile the menu is the bottom bar (its "More" tab opens
   this drawer); on desktop the drawer is always visible. Nothing left for a top-left ☰ to do. */
.content{padding:18px 16px 64px;flex:1}
.scrim{display:none;position:fixed;inset:0;background:rgba(15,23,42,.45);z-index:35}

/* mobile */
@media (max-width:767px){
  .drawer{transform:translateX(-100%)}
  .layout.nav-open .drawer{transform:translateX(0)}
  .layout.nav-open .scrim{display:block}
  .main{margin-left:0}

}

/* ---------- page ---------- */
.page{max-width:920px;margin:0 auto}
.page-head{margin:2px 0 16px}
/* keep the title + "+ Add" action in reach while scrolling long grids (#9) */
.page-head.with-action{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  position:sticky;top:var(--bar-h);z-index:20;background:var(--bg);padding:10px 0;margin:0 0 12px}
.page-title{font-size:22px;margin:0 0 2px}
.page-sub{color:var(--muted);font-size:13px;display:flex;align-items:center;gap:8px}
.muted-block{color:var(--muted);text-align:center;padding:42px 0}
.count-line{font-size:12px;color:var(--muted);margin:0 2px 10px}
.toolbar{display:flex;gap:8px;margin:6px 0 12px;flex-wrap:wrap}
.toolbar .form-control{flex:1 1 200px}
.per-select{flex:0 0 130px;max-width:140px}

/* ---------- list pager (Prev · page numbers · Next · range) — top & bottom of lists ---------- */
.pager{display:flex;align-items:center;justify-content:center;gap:6px;flex-wrap:wrap;margin:12px 2px}
.pager-hidden{display:none}
.pager-info{font-size:12.5px;color:var(--muted);margin-left:6px}
.pager-btn{background:var(--surface);color:var(--brand);border:1px solid var(--line);
  border-radius:var(--radius);padding:7px 14px;font-weight:600;cursor:pointer}
.pager-btn:hover:not(:disabled){background:var(--brand);color:#fff;border-color:var(--brand)}
.pager-btn:disabled{opacity:.4;cursor:not-allowed;color:var(--muted);background:var(--surface)}
.pager-num{min-width:36px;text-align:center;background:var(--surface);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--radius);padding:7px 10px;font-weight:600;cursor:pointer}
.pager-num:hover{border-color:var(--brand);color:var(--brand)}
.pager-num.active{background:var(--brand);color:#fff;border-color:var(--brand);cursor:default}
.pager-gap{color:var(--muted);padding:0 2px;user-select:none}

/* ---------- KPI dashboard ---------- */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.kpi{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);
  border-left:4px solid var(--line);box-shadow:0 1px 2px rgba(15,23,42,.04)}
.kpi .card-body{padding:14px 16px}
.kpi-label{font-size:12.5px;color:var(--muted);font-weight:600}
.kpi-val{font-size:30px;font-weight:800;line-height:1.1;margin:6px 0 4px;letter-spacing:-.02em}
.kpi-sub{font-size:12.5px;color:var(--muted)}
.kpi-sub.pending{color:var(--warn)}
.kpi.accent-primary{border-left-color:var(--brand)}
.kpi.accent-success{border-left-color:var(--ok)}
.kpi.accent-danger{border-left-color:var(--bad)}
.kpi.accent-info{border-left-color:var(--info)}
.kpi.accent-dark{border-left-color:var(--brand-ink)}

/* ---------- ledger categories ---------- */
.cat-root{margin:0 0 16px}
.cat-root-head{display:flex;align-items:baseline;gap:8px;padding:0 2px 7px}
.cat-root-head h2{font-size:14px;margin:0;text-transform:uppercase;letter-spacing:.05em}
.cat-stmt{font-size:12.5px;color:var(--muted)}
.cat-cards{display:flex;flex-direction:column;gap:8px}
.cat-card{display:flex;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);padding:11px 14px}
.cat-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:700;font-size:12.5px;
  background:var(--brand-ink);color:#fff;padding:3px 8px;border-radius:8px;min-width:48px;text-align:center}
.cat-name{flex:1;font-weight:600}
.cat-edit{padding:2px 9px;line-height:1.4}

/* ---------- list rows (clickable) ---------- */
.row-list{display:flex;flex-direction:column;gap:8px}
.row-card.inactive{opacity:.55}
.row-card.is-root{cursor:default;border-left:3px solid var(--brand)}
.trans-key{flex:0 0 auto;max-width:42%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--brand);
  background:var(--bg);border:1px solid var(--line);padding:3px 9px;border-radius:7px}
.row-card{display:flex;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);padding:12px 14px;cursor:pointer;transition:border-color .12s,box-shadow .12s}
.row-card:hover{border-color:var(--brand);box-shadow:0 2px 10px rgba(79,70,229,.12)}
.iso-badge{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:700;font-size:12px;
  background:var(--brand-ink);color:#fff;padding:4px 9px;border-radius:8px;min-width:42px;text-align:center}
.row-main{flex:1;display:flex;flex-direction:column;min-width:0}
.row-main b{font-weight:600}
.row-sub{font-size:12px;color:var(--muted)}
.row-chevron{color:var(--muted);font-size:22px;line-height:1}
/* billing status pill on a company row (green = active, per the colour convention) */
.row-status{font-size:12px;font-weight:600;padding:4px 10px;border-radius:999px;white-space:nowrap}
.row-status.ok{background:color-mix(in srgb,#16a34a 16%,transparent);color:#16a34a}

/* ---------- DEMO badge ----------
   The demo company is a sandbox. Everything it produces must be impossible to mistake for the real
   thing, so the badge is deliberately LOUD and does not reuse .row-status / .badge (both of which
   read as ordinary metadata): amber, uppercase, letter-spaced, with a solid border. Amber is the
   convention's "V" colour — attention, not error. */
.demo-badge{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;
  font-size:12px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;white-space:nowrap;
  padding:3px 9px;border-radius:6px;line-height:1.4;
  color:#92400e;background:color-mix(in srgb,#f59e0b 26%,transparent);border:1px solid #f59e0b;
  /* align-self, not just flex, because .row-main is a COLUMN flex container: `flex:0 0 auto`
     governs the main (vertical) axis there, and the default `align-items:stretch` then blew the
     badge out to the full row width. Measured at 375px before this line: 313px wide. */
  align-self:flex-start}
:root[data-theme="dark"] .demo-badge{color:#fde68a;background:color-mix(in srgb,#f59e0b 22%,transparent)}
/* in the app bar (a ROW flex) it sits beside the title and should stay vertically centred */
.app-bar .demo-badge{margin-left:10px;align-self:center}
/* on a row card it sits on the name's line, not under it */
.row-main > b + .demo-badge{margin:3px 0 1px}
.demo-note{font-size:12px;color:var(--muted);line-height:1.35}

/* dashboard quick links (#2) */
.quick-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;margin:0 0 20px}
.quick-card{display:flex;align-items:center;gap:12px;text-align:left;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius);padding:14px;cursor:pointer;
  transition:border-color .12s,box-shadow .12s}
.quick-card:hover{border-color:var(--brand);box-shadow:0 2px 10px rgba(79,70,229,.12)}
.quick-ico{font-size:20px;color:var(--brand);line-height:1}
.quick-text{flex:1;display:flex;flex-direction:column;min-width:0}
.quick-sub{font-size:12px;color:var(--muted)}

/* flash the just-added / just-edited row so the user sees where it went */
@keyframes rowflash{0%{background:rgba(56,178,172,.28)}100%{background:transparent}}
.row-card.row-hl,.cat-card.row-hl,.tier.row-hl{animation:rowflash 1.8s ease-out}

/* inline delete (no window.confirm) — trash button + in-place "Delete? Yes/No" */
.btn-row-del{appearance:none;border:1px solid var(--line);background:none;cursor:pointer;line-height:1;
  display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:8px;font-size:12.5px;font-weight:600;
  color:var(--muted);transition:color .12s,background .12s,border-color .12s}
.btn-row-del .del-ico{font-size:13px;filter:grayscale(.35)}
.btn-row-del:hover{color:var(--bad);border-color:var(--bad);background:rgba(185,28,28,.10)}
.btn-row-del:hover .del-ico{filter:none}
.confirm-inline{display:inline-flex;align-items:center;gap:7px}
.confirm-q{font-size:13px;font-weight:600;color:var(--bad)}
/* delete blocked → show why, inline on the row (#34) */
.confirm-err{flex-wrap:wrap;max-width:320px;text-align:right}
.confirm-errmsg{font-size:12px;color:var(--bad);line-height:1.35}
/* blocked-delete message shown beside the name so the row's action buttons stay put */
.row-err{flex:1 1 auto;min-width:120px;font-size:12px;color:var(--bad);line-height:1.35}
.row-card.row-blocked .row-main{flex:0 0 auto}
/* required-field validation highlight (#10) */
.form-control.is-invalid{border-color:var(--bad)}
.form-control.is-invalid:focus{border-color:var(--bad);box-shadow:0 0 0 3px rgba(185,28,28,.15)}
.field-required{color:var(--bad);font-size:12px;margin:-4px 0 8px}
/* forgot-password link under the login password field */
.login-forgot{text-align:right;font-size:13px}
.login-forgot a{color:var(--brand);cursor:pointer}
/* email templates (per-country) */
.tpl-card{cursor:pointer}
.tpl-vars{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 6px}
.tpl-vars-lbl{font-size:12px;color:var(--muted)}
.tpl-var{appearance:none;border:1px solid var(--line);background:var(--bg,#f8fafc);color:var(--ink);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;padding:2px 8px;
  border-radius:6px;cursor:pointer}
.tpl-var:hover{border-color:var(--brand);color:var(--brand)}
.tpl-body{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;line-height:1.5}
.tpl-preview-head{display:flex;align-items:center;gap:12px;margin:2px 0 6px}
.tpl-preview-wrap{border:1px solid var(--line);border-radius:10px;overflow:hidden;margin:0 0 10px}
.tpl-preview{width:100%;height:280px;border:0;background:#eef2f3;display:block}
.btn-danger-text{color:var(--bad);border-color:var(--bad)}
/* tenant home / onboarding (no admin drawer) */
.tenant-main{margin-left:0}
.onboard-wrap{max-width:520px;margin:32px auto;padding:0 16px}
.onboard-card{width:100%}
.onboard-title{font-size:22px;font-weight:800;margin:0 0 4px}
.onboard-page{max-width:720px;margin:0 auto}
/* regime reporting-fields editor rows */
.rg-field-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.rg-field-row .form-control{flex:1;margin:0}
/* idle auto-logout warning (#1) */
.idle-overlay{z-index:1200}
.idle-card{max-width:400px}
.idle-msg{margin:4px 0 16px;color:var(--ink);line-height:1.5}
.btn-confirm-yes,.btn-confirm-no{appearance:none;border:1px solid var(--line);border-radius:8px;
  padding:4px 12px;font-size:13px;font-weight:600;cursor:pointer;background:var(--surface);color:var(--ink)}
.btn-confirm-yes{background:var(--bad);border-color:var(--bad);color:#fff;min-width:44px}
.btn-confirm-yes:hover{filter:brightness(.93)}
.btn-confirm-yes:disabled{opacity:.6;cursor:default}
.btn-confirm-no:hover{border-color:var(--muted)}

/* ---------- detail: back link, tabs, fields ---------- */
.back-link{display:inline-block;color:var(--muted);font-size:13px;cursor:pointer;margin:0 0 6px}
.back-link:hover{color:var(--brand)}
.tabbar{display:flex;gap:4px;border-bottom:1px solid var(--line);margin:4px 0 16px;overflow-x:auto}
.tab{appearance:none;background:none;border:none;border-bottom:2px solid transparent;color:var(--muted);
  font-size:14px;font-weight:600;padding:9px 12px;cursor:pointer;white-space:nowrap}
.tab:hover{color:var(--ink)}
.tab.active{color:var(--brand);border-bottom-color:var(--brand)}
.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px}
.field{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px}
.field-label{font-size:12.5px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em}
.field-val{font-size:15px;font-weight:600;margin-top:3px}
.hint{margin-top:14px;font-size:12.5px;color:var(--muted);background:#e3f2f1;border-radius:10px;padding:10px 12px}

/* tina4: tina4-css sets .badge{font-size:0.75em}, so a badge inherits 75% of whatever it sits in —
   measured at 9.75px inside a 13px .page-sub and 11.25px inside body copy. Relative sizing means
   there is no floor, so badges get illegible wherever the context is small. Pin an absolute
   readable size; the em-based default is part of the upstream write-up
   (plan/upstream-tina4-css-touch-targets.md). */
.badge{font-size:12px}
/* tina4css button/badge primaries → aboo teal (dark text for contrast on the bright teal) */
.btn-primary{background:var(--brand);border-color:var(--brand);color:var(--aboo-ink)}
.btn-primary:hover{background:var(--brand);border-color:var(--brand);filter:brightness(.94)}
.badge-primary{background:var(--brand);color:var(--aboo-ink)}
.brand-dot{background:var(--brand)}
/* outline / secondary button — theme-aware (tina4css default has dark text invisible on dark) */
.btn-outline{background:transparent;border:1px solid var(--line);color:var(--ink)}
.btn-outline:hover{background:rgba(127,160,160,.14);border-color:var(--muted);color:var(--ink)}
/* comfortable, consistent modal actions */
.form-actions .btn{padding:9px 18px;border-radius:10px;font-weight:600;min-width:96px}
.muted-sub{font-size:12.5px;color:var(--muted)}

/* ---------- pricing tiers ---------- */
.tier-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px}
.tier{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface)}
.tier.inactive{opacity:.55}
.tier-head{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.tier-name{font-weight:700;font-size:15px}
.tier-head-actions{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap}
.tier-code{font-size:12.5px;color:var(--muted);letter-spacing:.04em;text-transform:uppercase;margin-top:1px}
.tier-price{font-size:22px;font-weight:800;margin:8px 0 0;color:var(--brand)}
.tier-per{font-size:12px;font-weight:600;color:var(--muted)}
.tier-year{font-size:12.5px;color:var(--muted);margin-top:1px}
.tier-caps{font-size:12px;color:var(--muted);margin-top:8px}
.tier-badges{margin-top:8px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}

/* form layout helpers (side-by-side fields + left-aligned destructive action) */
.form-row{display:flex;gap:10px}
.form-col{flex:1;min-width:0}
.form-actions-spacer{flex:1}
.tier-delete{color:var(--bad);border-color:var(--bad)}
.tier-delete:hover{background:var(--bad);color:#fff}

/* ---------- account add/edit form + modal ---------- */
.tab-actions{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 12px}
.tab-actions-right{display:flex;align-items:center;gap:8px}
.tab-actions-right .per-select{flex:0 0 120px}
.ledger-search{margin:0 0 12px}
.modal-overlay{position:fixed;inset:0;background:rgba(15,23,42,.55);display:flex;align-items:flex-start;
  justify-content:center;z-index:50;padding:24px 16px;overflow-y:auto}
.modal-card{background:var(--surface);color:var(--ink);border-radius:16px;width:100%;max-width:440px;
  padding:20px 22px;box-shadow:0 24px 60px rgba(0,0,0,.4)}
.modal-wide{max-width:620px}
/* default-codes picker — scrollable checklist of the country chart */
.code-picker{max-height:48vh;overflow-y:auto;border:1px solid var(--line);border-radius:10px;
  background:var(--bg);padding:4px}
.code-row{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:8px;cursor:pointer;font-size:14px}
.code-row:hover{background:var(--surface)}
.code-row.on{background:color-mix(in srgb, var(--brand) 14%, transparent)}
.code-row .cat-code{flex:0 0 auto}
.code-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.modal-head h3{margin:0;font-size:18px}
.modal-x{appearance:none;border:none;background:none;font-size:18px;color:var(--muted);cursor:pointer;line-height:1}
.form-check{display:flex;align-items:center;gap:8px;font-size:14px;margin:8px 0;cursor:pointer}
.form-note{font-size:13px;color:var(--muted);margin:-2px 0 10px}
.form-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}
.cat-card.inactive{opacity:.55}
.tag-off{font-size:12px;background:#fee2e2;color:var(--bad);padding:1px 6px;border-radius:999px;margin-left:8px;font-weight:600}

/* ---------- theme toggle ---------- */
.theme-toggle{appearance:none;border:1px solid var(--line);background:var(--surface);color:var(--ink);
  border-radius:9px;padding:5px 9px;cursor:pointer;font-size:15px;line-height:1}

/* ---------- dark mode (brand) — token mapping handles bg/ink/surface; these are tweaks ---------- */
:root[data-theme="dark"] .hint{background:#123339}
:root[data-theme="dark"] .tag-off{background:#3b1414}
:root[data-theme="dark"] .row-card:hover{box-shadow:0 2px 10px rgba(0,0,0,.4)}

/* ---------- login ---------- */
.login-wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:20px;
  background:radial-gradient(1200px 600px at 50% -10%,#1a4d54 0%,#0E2E33 55%,#07191c 100%)}
/* The login card is a fixed white card on the teal gradient — theme-independent (don't inherit
   dark-mode text colours, or it goes invisible on white). */
/* theme toggle floating on the gradient (light styling so it shows on the dark backdrop) */
.login-toggle{position:fixed;top:16px;right:16px;z-index:2;background:rgba(255,255,255,.12);
  border-color:rgba(255,255,255,.25);color:#EAF3F2}
/* login card adapts to the theme (white card / dark text in light; dark card / light text in dark) */
.login-card{width:100%;max-width:380px;border:1px solid var(--line);border-radius:18px;
  box-shadow:0 24px 60px rgba(0,0,0,.45);background:var(--surface);color:var(--ink)}
.login-card .card-body{padding:28px 26px 30px}
.login-card .brand-name{color:var(--ink)}
.login-title{font-size:22px;margin:6px 0 0;color:var(--ink)}
.login-hint{font-size:13px;color:var(--muted)}
.login-remember{margin:2px 0 14px;color:var(--muted)}
.login-card .btn-primary{background:var(--brand);border-color:var(--brand);color:var(--aboo-ink)}
.form-label{display:block;font-size:12.5px;font-weight:600;color:var(--muted);margin:0 0 5px}
/* ---------- sign-up ---------- */
.login-card{max-width:420px}
.login-alt{font-size:13px;color:var(--muted);text-align:center;margin:0}
.login-alt a{color:var(--brand);cursor:pointer;font-weight:600}
.signup-kinds{display:flex;gap:10px}
.signup-kind{flex:1;display:flex;flex-direction:column;gap:2px;align-items:flex-start;text-align:left;
  padding:11px 13px;border:1px solid var(--line);border-radius:12px;background:var(--surface);
  color:var(--ink);cursor:pointer;transition:border-color .15s,background .15s}
.signup-kind:hover{border-color:var(--brand)}
.signup-kind.active{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 12%,transparent)}
.signup-kind-label{font-weight:700;font-size:14px}
.signup-kind-sub{font-size:13px;color:var(--muted)}
.signup-done{text-align:center}
.signup-done .brand-lockup{justify-content:center}
.signup-tick{width:56px;height:56px;margin:14px auto 4px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:28px;color:#fff;background:var(--brand)}

/* ---------- data import (CSV -> chart of accounts) ---------- */
/* Phases are shown/hidden with [hidden] so the file input never sits in a reactive block. */
.import-phase[hidden]{display:none}
.import-counts{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 10px}
.import-rows{margin:10px 0 4px}
/* Mobile-first: each row stacks, then becomes one line from tablet up. */
.import-row{flex-wrap:wrap;cursor:default;align-items:flex-start;gap:8px}
.import-row .row-main{flex:1 1 100%}
.import-row .form-control{flex:1 1 140px;min-width:0;font-size:13px;padding:6px 9px;margin:0}
.import-row.row-warn{border-left:3px solid var(--warn,#d97706)}
.import-row:hover{border-color:var(--line);box-shadow:none}
.import-errors{margin:6px 0 0;padding-left:20px;font-size:13px}
.import-offer{border-top:1px solid var(--line);margin:14px 0 4px;padding-top:14px}
@media (min-width:720px){
  .import-row{flex-wrap:nowrap;align-items:center}
  .import-row .row-main{flex:1 1 auto}
  .import-row .import-action{flex:0 0 150px}
  .import-row .import-target{flex:0 0 96px}
  .import-row .import-category{flex:0 0 190px}
}

/* ---------- bottom navigation (MOBILE) ----------
   Product decision 2026-07-23 (Andre): on a phone the menu belongs under the thumb — a top-left
   hamburger is the hardest one-handed target on a modern handset. So below the breakpoint the
   bottom bar IS the navigation and the drawer only appears when its "More" tab asks for it; from
   767px up the bar disappears and the drawer is the static desktop sidebar.
   The SAME max-width:767px query the drawer already uses — deliberately not a new breakpoint. */
.bottom-nav{display:none}
.form-actions-center{justify-content:center}
@media (max-width:767px){
  .bottom-nav{display:flex;align-items:stretch;position:fixed;left:0;right:0;bottom:0;z-index:45;
    background:var(--surface);border-top:1px solid var(--line);box-shadow:0 -2px 10px rgba(15,23,42,.07);
    /* iPhone home indicator — without this the tabs sit under it and are unhittable */
    padding-bottom:env(safe-area-inset-bottom,0px)}
  .bn-item{flex:1 1 0;min-width:0;min-height:var(--bottom-nav-h);display:flex;flex-direction:column;
    align-items:center;justify-content:center;gap:3px;padding:8px 4px;appearance:none;border:none;
    background:none;color:var(--muted);font:inherit;cursor:pointer}
  .bn-item.active{color:var(--brand)}
  .bn-ico{font-size:18px;line-height:1}
  .bn-lbl{font-size:12px;font-weight:600;line-height:1.1;max-width:100%;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .bn-confirm{flex:1;display:flex;align-items:center;justify-content:center;gap:10px;
    min-height:var(--bottom-nav-h);padding:8px 14px}
  .bn-confirm-q{font-size:14px;font-weight:600;color:var(--bad)}
  /* content must clear the bar — otherwise the last row of every list hides behind it */
  .content{padding-bottom:calc(24px + var(--bottom-nav-space))}
  .drawer{padding-bottom:var(--bottom-nav-space)}
  .modal-overlay{padding-bottom:calc(24px + var(--bottom-nav-space))}
  /* the tenant screens' session actions now live in the bottom bar — don't show them twice.
     (Admin keeps its app-bar "Sign out": its bar's five slots are all navigation.) */
  .tenant-main .app-user .btn,
  .tenant-main .app-user .confirm-inline{display:none}
}

/* ---------- touch targets: >= 44px on touch devices (WCAG 2.5.5 / Apple HIG) ----------
   tina4: LOCAL OVERRIDE of tina4-css. public/css/tina4.min.css ships
     .btn         { padding:.375rem .75rem; font-size:1rem; line-height:1.5 }
     .form-control{ padding:.375rem .75rem; font-size:1rem; line-height:1.5;
                    min-height:calc(1.5em + .75rem + 2px) }
   which renders 38px — under the 44px touch minimum. That is a Bootstrap-derived default that
   predates touch guidance, and it fails on EVERY tina4 app, not just aboo, so the real fix belongs
   upstream in tina4-css (CLAUDE.md rule #7). The case is written up in
   plan/upstream-tina4-css-touch-targets.md. DO NOT edit or fork public/css/tina4.min.css.
   TEMPORARY: delete this block once a tina4-css release ships touch-sized controls.
   Scoped to (pointer: coarse) so mouse/trackpad density on desktop is untouched. */
@media (pointer: coarse){
  .btn,.form-control,.theme-toggle,.pager-btn,.pager-num,.tab,.quick-card,.cat-edit,
  .btn-confirm-yes,.btn-confirm-no,.btn-row-del,.tpl-var,.modal-x,.nav-item,.code-row,
  .form-check,.signup-kind{min-height:44px}
  .btn{padding-top:10px;padding-bottom:10px}
  .btn-sm{padding-top:9px;padding-bottom:9px;font-size:14px}
  /* 16px is also what stops iOS Safari zooming the page when a field takes focus */
  .form-control{padding-top:10px;padding-bottom:10px;font-size:16px}
  .import-row .form-control{min-height:44px;padding:10px 9px;font-size:16px}
  .theme-toggle{min-width:44px;padding:8px 11px;font-size:17px}
  .modal-x{min-width:44px}
  .pager-num{min-width:44px}
  .form-check input[type=checkbox]{width:22px;height:22px}
  /* inline text links measured 16.5px tall — the smallest real targets on the public screens */
  .login-forgot a,.login-alt a,.back-link{display:inline-flex;align-items:center;min-height:44px}
}

/* ---------------------------------------------------------------------------------------------
   MOBILE STACKING — must live at the END of this file.
   These override base rules (.row-main{flex:1} at ~line 149, .app-title{flex:1} at ~line 65) which
   have the SAME specificity, so they only win by coming later. An earlier @media block silently
   loses — measured: flex-wrap took effect but .row-main stayed on the buttons' line.

   The bug being fixed (measured on staging at 375px): .row-card is flex/nowrap, and once the
   touch-target pass grew the action buttons (92px + 197px + gaps inside a 343px card) the flex:1
   .row-main was squeezed to width:0, so the company name painted straight over the buttons.

   NOTE this class of bug does NOT surface as horizontal overflow — scrollWidth stayed exactly ==
   the viewport, because the elements collide INSIDE the viewport instead of spilling outside it.
   The no-overflow tests all passed while the screen was visibly broken.
   --------------------------------------------------------------------------------------------- */
@media (max-width:767px){
  /* Row cards: title on its own line, actions wrapping beneath it. */
  .row-card{flex-wrap:wrap}
  .row-card > .row-main{flex:1 0 100%}
  .row-card > .btn{flex:1 1 auto}

  /* App bar: brand + title + user could not share 375px and .app-user's right edge landed past the
     viewport edge. The bottom nav already says which screen you are on, so the middle title goes. */
  .app-bar .app-title{display:none}
  .app-bar .app-user{min-width:0;flex:0 1 auto}

  /* The ACTION must never be the thing that shrinks — the NAME is what may ellipsise.

     Kept as a DEFENSIVE rule, and the comment says so honestly rather than claiming a repro it
     does not have. A report described the app-bar "Sign out" as collapsed to 0x0 at 375px and
     blamed the `min-width:0` above for letting the flex algorithm crush the last child. Measured
     against this stylesheet in a real browser (Chromium, 375px AND 320px, long and short user
     names), with these two rules present and again with them reverted, the button measured
     78x31 every single time. The crush does not reproduce here.

     What DOES measure 0x0 at 375px is the TENANT bar's "Sign out", and the cause is
     `display:none` from the deliberate `.tenant-main .app-user .btn` rule ~50 lines above — the
     tenant's session actions moved to the bottom nav, which really does carry a 188x56 "Sign out"
     tab. Measured tenant bar at 375px: brand 16..91, .app-title display:none, .app-user at
     x=103, "Sign out" display:none 0x0 — which matches the report exactly. So that is intent,
     not breakage. (Admin keeps its app-bar button, and needs it: the admin drawer and bottom nav
     have no sign-out of their own. Measured visible at both 375px and 320px.)

     These two lines stay because they make the intent explicit and cost nothing: whatever the
     available width, pin the button and let the name be the flexible item. */
  .app-bar .app-user > .btn{flex:0 0 auto;white-space:nowrap}
  .app-bar .user-name{flex:0 1 auto;min-width:0;max-width:92px}

  /* The DEMO badge must survive the same squeeze — it is a safety label, not decoration. */
  .app-bar .demo-badge{margin-left:6px}

  /* Page heading and its primary action, stacked so neither gets crushed. */
  .page-head.with-action{flex-wrap:wrap}
  .page-head.with-action > :first-child{flex:1 0 100%}
}

/* ---------------------------------------------------------------------------------------------
   APP BAR — the action must never shrink or wrap, at ANY width. GLOBAL, deliberately NOT inside a
   media query.

   Reported with a screenshot: "Sign out" wrapped onto two lines and clipped at the right edge.
   The earlier fix for this lived inside @media (max-width:767px), so it did nothing in the band
   just above the breakpoint — measured at 820px: .app-title{flex:1 1 0%} claimed 444px and the
   user block was squeezed until the button wrapped. Chasing that with another breakpoint would
   just move the failure, so the rule is stated once, unconditionally:

     the TITLE is the flexible item and truncates; the ACTION is fixed and stays whole.

   .app-title needs min-width:0 because a flex item's default min-width:auto refuses to shrink
   below its content — without it the title pushes the button out instead of ellipsising.
   --------------------------------------------------------------------------------------------- */
.app-bar .app-user{flex:0 0 auto}
.app-bar .app-user > .btn{flex:0 0 auto;white-space:nowrap}
.app-bar .app-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---------------------------------------------------------------------------------------------
   CHART OF ACCOUNTS — read-only chart screen (src/tenant/chart.js).

   MUST STAY AT THE END OF THIS FILE. `.chart-row > .row-main` and the MOBILE STACKING block's
   `.row-card > .row-main{flex:1 0 100%}` have IDENTICAL specificity (two classes + a child
   combinator), so these rules only win by coming later — exactly the trap documented in the
   MOBILE STACKING header above. Appending anything after this block is fine; MOVING this block
   above MOBILE STACKING silently reverts the phone layout.

   The generic mobile rule would give each account row three stacked lines (code, name, nothing),
   wasting a third of a phone screen on an 86-row list. The chart wants the CODE and the NAME on
   the SAME line — the code is the mapping key, so it is the thing being scanned — with the
   classification wrapping underneath it. Hence the override.
   --------------------------------------------------------------------------------------------- */
.chart-count{font-size:13px;color:var(--muted);font-weight:600;margin:0 2px 12px}
.chart-groups{display:flex;flex-direction:column;gap:18px}
.chart-group-head{display:flex;align-items:baseline;gap:8px;padding:0 2px 7px;flex-wrap:wrap}
.chart-group-head h2{font-size:14px;margin:0;text-transform:uppercase;letter-spacing:.05em}
.chart-group-root{font-size:12.5px;color:var(--muted)}
.chart-group-n{margin-left:auto;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
/* The CODE is the mapping key — mono, boxed and the first thing the eye lands on. */
.chart-code{flex:0 0 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:700;
  font-size:13px;background:var(--brand-ink);color:#fff;padding:4px 9px;border-radius:8px;
  min-width:54px;text-align:center;font-variant-numeric:tabular-nums}
.chart-row{cursor:default}
.chart-row:hover{border-color:var(--line);box-shadow:none}
/* A system-role account (retained earnings, year-end contra, FX, rounding, suspense) is one an
   import must never remap — flagged so it reads as special, not as an ordinary account. */
.chart-row.chart-system{border-left:3px solid var(--brand)}
.chart-row.inactive .chart-code{background:var(--muted)}

@media (max-width:767px){
  /* Code and name share line 1; the classification wraps beneath. See the header above for why
     this must not be hoisted anywhere earlier in the file. */
  .chart-row{flex-wrap:wrap;align-items:flex-start;gap:10px}
  .chart-row > .chart-code{flex:0 0 auto}
  /* flex-basis MUST be 0, not auto. Measured in Chromium at 375px with `flex:1 1 auto`: flex line
     breaking uses each item's HYPOTHETICAL main size (here the name's max-content width) BEFORE
     any shrinking, so a long account name — "Machinery and Equipment - Cost" — pushed .row-main
     onto its own line and the code sat alone above it, making that one row twice as tall as its
     neighbours. Basis 0 means it always fits beside the code and then grows into the space. */
  .chart-row > .row-main{flex:1 1 0;min-width:0}
  .chart-group-n{margin-left:0}
}
