/* =========================================================================
   Bank2Ledger design system
   -------------------------------------------------------------------------
   Replicates the Next.js/Tailwind demo look on top of vanilla Bootstrap.
   Type scale calibrated from inspecting the reference app: a COMPACT scale —
   nav/body ~13px, small badges 9-11px, page title 22px (the largest text).
   Numbers render in Inter (the reference's .tabular-nums mono rule is not
   applied to the figures). Colors/radii centralized in :root below.
   ========================================================================= */

:root {
  /* Brand / primary (Tailwind emerald) */
  --b2l-primary:        #059669; /* emerald-600 */
  --b2l-primary-hover:  #047857; /* emerald-700 */
  --b2l-primary-050:    #e9fddf; /* light-green surface — banners, tabs, pills, emerald badges, active rows */
  --b2l-primary-100:    #baeea0; /* light-green border */
  --b2l-primary-600:    #059669;
  --b2l-primary-700:    #047857;

  /* Neutrals (Tailwind slate) */
  --b2l-ink:            #0f172a; /* slate-900 — headings / dark buttons */
  --b2l-ink-700:        #334155; /* slate-700 */
  --b2l-muted:          #64748b; /* slate-500 — secondary text */
  --b2l-muted-2:        #94a3b8; /* slate-400 */
  --b2l-border:         #e5e7eb; /* gray-200 — chrome (topbar, tabs, table headers/dividers) */
  --b2l-border-2:       #eef2f6;
  --b2l-border-card:    #f1f5f9; /* slate-100 — card & number-tile borders */
  --b2l-bg:             #ffffff; /* page background — white; cards use a visible border to stand out */
  --b2l-surface:        #ffffff;
  --b2l-surface-2:      #f8fafc; /* slate-50 — table header / hover */
  --b2l-surface-3:      #e2e8f0; /* slate-200 — the darker band: journal header & totals */
  --b2l-band:           #f1f5f9; /* slate-100 — zebra band, one step lighter than surface-3 */
  --b2l-border-strong:  #cbd5e1; /* slate-300 — edge of the darker bands */

  /* Accents */
  --b2l-amber:          #d97706; /* amber-600 — "needs attention" */
  --b2l-orange:         #f97316; /* orange-500 — count badges */
  --b2l-danger:         #dc2626; /* red-600 — debits / negative */
  --b2l-success:        #059669; /* credits / positive */
  --b2l-blue:           #1d4ed8; /* blue-700 — Asset */
  --b2l-blue-050:       #eff6ff;
  --b2l-rose:           #e11d48; /* rose-600 — Liability */
  --b2l-rose-050:       #fff1f2;

  /* Typography — compact px scale from reference inspection */
  --b2l-font: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --b2l-fs-9:   9px;   /* dropdown count badge          */
  --b2l-fs-10:  10px;  /* nav count badge, stepper label */
  --b2l-fs-11:  11px;  /* avatar text, table headers, badges */
  --b2l-fs-12:  12px;
  --b2l-fs-13:  13px;  /* body / nav / pill / cells (most text) */
  --b2l-fs-14:  14px;  /* base body                     */
  --b2l-fs-15:  15px;  /* brand text, section headings   */
  --b2l-fs-18:  18px;
  --b2l-fs-22:  22px;  /* page title                     */
  --b2l-fs-28:  28px;  /* big figures: stat tiles, ledger summary totals (largest) */
  /* Legacy rem tokens (kept for any remaining inline refs) */
  --b2l-fs-xs:   0.75rem;
  --b2l-fs-sm:   0.8125rem; /* 13px */
  --b2l-fs-base: 1rem;
  --b2l-fs-lg:   0.9375rem; /* 15px */
  --b2l-fs-2xl:  1.75rem;   /* 28px — big numeric displays */

  /* Radii + shadow */
  --b2l-radius:      0.5rem;   /* rounded-lg  — buttons/inputs */
  --b2l-radius-xl:   0.75rem;  /* rounded-xl  — cards */
  --b2l-radius-full: 9999px;
  --b2l-shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.04);
  --b2l-shadow:    0 1px 3px 0 rgba(15, 23, 42, 0.06), 0 1px 2px -1px rgba(15, 23, 42, 0.04);
}

/* ------------------------------------------------------------------ base */
body {
  background-color: var(--b2l-bg);
  font-family: var(--b2l-font);
  color: var(--b2l-ink);
  font-size: var(--b2l-fs-14);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { text-decoration: none; }

.b2l-page { max-width: 1180px; margin: 0 auto; padding: 1.75rem 1.5rem 3rem; }
.b2l-h1 { font-size: var(--b2l-fs-22); font-weight: 700; letter-spacing: -0.01em; color: var(--b2l-ink); margin: 0; }
.b2l-mono { font-variant-numeric: tabular-nums; }  /* numbers stay in Inter */
.b2l-sub { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.25rem; }
.b2l-muted { color: var(--b2l-muted); }

.b2l-eyebrow { /* uppercase section labels */
  font-size: var(--b2l-fs-11); font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--b2l-muted);
}

/* --------------------------------------------------------------- buttons */
.b2l-btn {
  display: inline-flex; align-items: center; gap: 0.5rem; justify-content: center;
  font-weight: 600; font-size: var(--b2l-fs-13); line-height: 1;
  padding: 0.55rem 0.9rem; border-radius: var(--b2l-radius);
  border: 1px solid transparent; cursor: pointer; transition: background-color .12s, border-color .12s;
  white-space: nowrap;
}
.b2l-btn i, .b2l-btn svg { width: 15px; height: 15px; }
.b2l-btn-primary { background: var(--b2l-primary); color: #fff; }
.b2l-btn-primary:hover { background: var(--b2l-primary-hover); color: #fff; }
.b2l-btn-dark { background: var(--b2l-ink); color: #fff; width: 100%; padding: 0.7rem 1rem; }
.b2l-btn-dark:hover { background: #1e293b; color: #fff; }
.b2l-btn-outline { background: #fff; color: var(--b2l-ink); border-color: #cbd5e1; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06); }
.b2l-btn-outline:hover { background: var(--b2l-surface-2); border-color: #94a3b8; }
.b2l-btn.is-disabled { opacity: 0.5; pointer-events: none; }
.b2l-btn-sm { padding: 0.4rem 0.7rem; font-size: var(--b2l-fs-12); }
.b2l-btn-full { width: 100%; padding: 0.7rem 1rem; }

/* ----------------------------------------------------------------- cards */
.b2l-card {
  background: var(--b2l-surface); border: 1px solid var(--b2l-border);
  border-radius: var(--b2l-radius-xl);
}
.b2l-card-body { padding: 1.25rem 1.5rem; }

/* -------------------------------------------------------------- top nav */
.b2l-topbar {
  background: var(--b2l-surface); border-bottom: 1px solid var(--b2l-border);
  padding: 0 1.5rem; display: flex; align-items: center; gap: 1rem; height: 56px;
  position: sticky; top: 0; z-index: 1040;  /* pinned on scroll; above tabs so dropdowns overlay them */
}
.b2l-brand { display: inline-flex; align-items: center; gap: 0.45rem; font-weight: 700; color: var(--b2l-ink); font-size: var(--b2l-fs-15); letter-spacing: -0.01em; }
.b2l-brand-2 { color: var(--b2l-primary); }
.b2l-logo { flex: none; display: block; }
.b2l-auth-logo { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin-bottom: 1rem; }
.b2l-auth-wordmark { font-size: 21px; font-weight: 700; color: var(--b2l-ink); letter-spacing: -0.01em; }
.b2l-topbar-divider { width: 1px; height: 24px; background: var(--b2l-border); }
/* Firm name: context, not a control. Lighter than the brand and flat next to the
   tinted client pill, so the eye reads product > firm > client and only the pill
   invites a click. Truncates rather than shoving the client switcher rightwards —
   "Sharma, Iyer & Associates LLP" is a normal practice name. */
.b2l-firm {
  font-weight: 600; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700);
  max-width: 15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.b2l-client-pill {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: var(--b2l-primary-050); color: var(--b2l-primary-700);
  border: 1px solid var(--b2l-primary-100); border-radius: var(--b2l-radius);
  padding: 0.4rem 0.7rem; font-weight: 600; font-size: var(--b2l-fs-13); cursor: pointer;
}
.b2l-count { /* orange count chip */
  display: inline-grid; place-items: center; min-width: 1.05rem; height: 1.05rem; padding: 0 0.28rem;
  background: var(--b2l-orange); color: #fff; border-radius: var(--b2l-radius-full);
  font-size: var(--b2l-fs-10); font-weight: 700; line-height: 1;
}
.b2l-user { display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer; color: var(--b2l-ink); font-weight: 600; font-size: var(--b2l-fs-13); border: 0; background: none; padding: 0; }
.b2l-avatar { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: var(--b2l-radius-full); background: var(--b2l-ink); color: #fff; font-size: var(--b2l-fs-11); font-weight: 700; }
.b2l-chev { transition: transform .15s; }
[aria-expanded="true"] > .b2l-chev { transform: rotate(180deg); }

/* ------------------------------------------------------------ user menu */
/* b2l-navmenu is the tab strip's Settings dropdown. Same chrome as the user menu,
   separate class so markup and tests can tell the two apart. */
.b2l-usermenu, .b2l-navmenu { min-width: 220px; padding: 0.4rem; border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius-xl); box-shadow: var(--b2l-shadow); }
.b2l-usermenu-head { padding: 0.5rem 0.7rem 0.35rem; }
.b2l-usermenu-firm {
  display: flex; align-items: center; gap: 0.3rem; margin-top: 0.3rem;
  font-size: 12px; font-weight: 600; color: var(--b2l-ink-700);
}
.b2l-usermenu-firm svg { color: var(--b2l-muted); flex: none; }
.b2l-usermenu-firm span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b2l-usermenu form { margin: 0; }
.b2l-usermenu-item { display: flex; align-items: center; gap: 0.55rem; width: 100%; text-align: left; padding: 0.55rem 0.7rem; font-size: 14px; color: var(--b2l-ink-700); border: 0; background: none; border-radius: var(--b2l-radius); cursor: pointer; }
.b2l-usermenu-item:hover { background: var(--b2l-surface-2); color: var(--b2l-ink); }
.b2l-usermenu-item svg { color: var(--b2l-muted); }

/* large avatar (profile) */
.b2l-avatar-lg { display: inline-grid; place-items: center; width: 64px; height: 64px; border-radius: 50%; background: var(--b2l-ink); color: #fff; font-size: 22px; font-weight: 700; }

/* uploaded photo fills the circle and crops rather than squashing */
.b2l-avatar, .b2l-avatar-lg { overflow: hidden; }
.b2l-avatar-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.b2l-avatar-actions { display: flex; justify-content: center; gap: 0.5rem; margin-top: 0.9rem; }
.b2l-avatar-actions form { margin: 0; }

/* --------------------------------------------------- dropdown menu (client switcher) */
.b2l-menu { min-width: 264px; padding: 0.4rem; border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius-xl); box-shadow: var(--b2l-shadow); }
.b2l-menu-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; font-size: var(--b2l-fs-10); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--b2l-muted-2); padding: 0.5rem 0.6rem 0.4rem; }
/* Client count against the plan limit, in the switcher head. tabular-nums so the
   digits don't jiggle as the count changes. */
.b2l-menu-usage { letter-spacing: 0; font-variant-numeric: tabular-nums; color: var(--b2l-muted); }
.b2l-menu-usage.is-at { color: var(--b2l-amber); }
.b2l-menu-usage.is-over { color: var(--b2l-rose); }
.b2l-client-item { display: flex; align-items: center; gap: 0.6rem; padding: 0.5rem 0.6rem; border-radius: var(--b2l-radius); color: var(--b2l-ink-700); font-size: var(--b2l-fs-13); font-weight: 500; }
.b2l-client-item:hover { background: var(--b2l-surface-2); color: var(--b2l-ink); }
.b2l-client-item.active { background: var(--b2l-primary-050); color: var(--b2l-primary-700); font-weight: 600; }
.b2l-client-av { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: #e2e8f0; color: var(--b2l-muted); font-size: var(--b2l-fs-11); font-weight: 700; flex: none; }
.b2l-client-item.active .b2l-client-av { background: var(--b2l-primary-100); color: var(--b2l-primary-700); }
.b2l-client-name { flex: 1; }
.b2l-client-alerts { color: var(--b2l-amber); font-size: var(--b2l-fs-12); font-weight: 600; }
.b2l-menu-divider { height: 1px; background: var(--b2l-border); margin: 0.4rem 0.3rem; }
.b2l-menu-add { display: flex; align-items: center; gap: 0.5rem; width: 100%; padding: 0.55rem 0.6rem; color: var(--b2l-primary-700); font-weight: 600; font-size: var(--b2l-fs-13); border: 0; background: none; border-radius: var(--b2l-radius); cursor: pointer; text-align: left; }
.b2l-menu-add:hover { background: var(--b2l-primary-050); color: var(--b2l-primary-700); }

/* text button (e.g. Cancel on the add-client bar) */
.b2l-btn-text { border: 0; background: none; color: var(--b2l-ink-700); font-weight: 600; font-size: var(--b2l-fs-13); cursor: pointer; padding: 0.55rem 0.7rem; }
.b2l-btn-text:hover { color: var(--b2l-ink); }

/* ------------------------------------------------------------------ tabs */
/* The nav itself must NOT clip: the Settings dropdown hangs out of it. overflow-x
   on a container forces overflow-y to auto as well, so anything absolutely
   positioned inside gets cut at the box — which silently swallowed the whole
   dropdown. The horizontal scroll therefore lives on .b2l-tabs-scroll (the links
   only), and the dropdown is its sibling. */
.b2l-tabs { background: var(--b2l-primary-050); border-bottom: 1px solid var(--b2l-border); padding: 0 1.5rem; display: flex; align-items: stretch; position: sticky; top: 56px; z-index: 1020; }  /* pinned below the top bar on scroll */
.b2l-tabs-scroll { display: flex; gap: 1.5rem; overflow-x: auto; scrollbar-width: none; min-width: 0; }  /* min-width:0 lets it shrink and scroll instead of shoving the dropdown off the edge */
.b2l-tabs-scroll::-webkit-scrollbar { display: none; }
.b2l-tab {
  display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.8rem 0.15rem;
  color: var(--b2l-ink-700); font-weight: 600; font-size: var(--b2l-fs-13);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  white-space: nowrap; flex: none;
}
.b2l-tab:hover { color: var(--b2l-ink); }
.b2l-tab.active { color: var(--b2l-primary-700); border-bottom-color: var(--b2l-primary-700); }
.b2l-tab .b2l-tab-count { background: var(--b2l-primary); color: #fff; border-radius: var(--b2l-radius-full); font-size: var(--b2l-fs-10); font-weight: 700; line-height: 1; min-width: 18px; height: 18px; padding: 0 5px; display: inline-flex; align-items: center; justify-content: center; }
/* The Settings dropdown trigger is a <button> among <a> siblings — strip the UA
   button chrome so it sits on the same baseline as the real tabs. */
button.b2l-tab { background: none; border: 0; border-bottom: 2px solid transparent; cursor: pointer; font-family: inherit; }
.b2l-tab-settings { margin-left: auto; flex: none; }  /* pinned to the right edge, under the user menu */
.b2l-tab-settings svg { color: currentColor; }
/* Menu items that need a client (Client/Tax Settings) while the firm has none.
   pointer-events:none is what makes it genuinely inert rather than merely faded —
   the title attribute carries the reason. */
.b2l-usermenu-item.is-disabled { opacity: 0.5; cursor: default; pointer-events: none; }
/* Current screen, when reached from inside the Settings menu. */
.b2l-usermenu-item.active { background: var(--b2l-primary-050); color: var(--b2l-primary-700); }

/* ---------------------------------------------------------- admin chrome */
/* Ink-dark topbar + amber-tinted tab strip: an operator on any screen knows at
   a glance they are outside every tenant. Reuses .b2l-topbar/.b2l-tabs
   mechanics (sticky pinning, scroll); the modifiers only recolor. */
.b2l-admin-topbar { background: var(--b2l-ink); border-bottom-color: var(--b2l-ink-700); }
.b2l-admin-topbar .b2l-brand-name { color: #fff; }
.b2l-admin-tag {
  background: var(--b2l-amber); color: #fff; font-size: var(--b2l-fs-10);
  font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 2px 8px; border-radius: var(--b2l-radius-full);
}
.b2l-admin-user { display: inline-flex; align-items: center; gap: 0.5rem; color: #e2e8f0; font-size: var(--b2l-fs-13); font-weight: 600; }
.b2l-admin-user > svg { color: var(--b2l-amber); }
.b2l-admin-signout {
  display: inline-flex; align-items: center; gap: 0.4rem; margin-left: 0.75rem;
  background: none; border: 0; color: var(--b2l-muted-2); font-size: var(--b2l-fs-13);
  font-weight: 600; cursor: pointer; padding: 0.35rem 0.5rem; border-radius: var(--b2l-radius);
}
.b2l-admin-signout:hover { color: #fff; background: var(--b2l-ink-700); }
.b2l-admin-tabs { background: #fffbeb; }  /* amber-50 — vs the app's emerald strip */
.b2l-admin-tabs .b2l-tab.active { color: var(--b2l-amber); border-bottom-color: var(--b2l-amber); }

/* ---------------------------------------------------------------- banner */
.b2l-banner {
  background: var(--b2l-primary-050); border: 1px solid var(--b2l-primary-100);
  border-radius: var(--b2l-radius-xl); padding: 1.25rem 1.5rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.b2l-banner h3 { font-size: var(--b2l-fs-15); font-weight: 700; margin: 0 0 0.25rem; }

/* ------------------------------------------------------------- stat tiles */
.b2l-stats { display: grid; grid-template-columns: repeat(5, 1fr); border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius-xl); overflow: hidden; background: var(--b2l-surface); }
.b2l-stat { padding: 1.35rem 1.5rem; border-right: 1px solid var(--b2l-border-card); }
.b2l-stat:last-child { border-right: 0; }
.b2l-stat-num { font-size: var(--b2l-fs-28); font-weight: 700; line-height: 1.1; color: var(--b2l-ink); font-variant-numeric: tabular-nums; }
.b2l-stat-label { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.35rem; }
.b2l-stat.is-success .b2l-stat-num { color: var(--b2l-success); }
.b2l-stat.is-amber .b2l-stat-num,
.b2l-stat.is-amber .b2l-stat-label { color: var(--b2l-amber); }

/* ---------------------------------------------------- statement detail */
.b2l-detail-sum { display: flex; align-items: center; gap: 1rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.4rem; flex-wrap: wrap; }
.b2l-reconcile { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--b2l-primary-700); font-weight: 600; }

/* numbered stepper */
.b2l-steps { display: flex; align-items: center; margin: 1.75rem 0 0.5rem; }
.b2l-step-node { display: inline-flex; align-items: center; gap: 0.5rem; }
.b2l-step-circle { width: 26px; height: 26px; border-radius: 50%; display: inline-grid; place-items: center; font-size: var(--b2l-fs-12); font-weight: 700; background: #e2e8f0; color: var(--b2l-muted); flex: none; }
.b2l-step-node.done .b2l-step-circle, .b2l-step-node.active .b2l-step-circle { background: var(--b2l-primary); color: #fff; }
.b2l-step-name { font-weight: 600; font-size: var(--b2l-fs-15); color: var(--b2l-muted); }
.b2l-step-node.done .b2l-step-name { color: var(--b2l-ink); }
.b2l-step-node.active .b2l-step-name { color: var(--b2l-primary-700); }
.b2l-step-conn { flex: 1; height: 2px; background: var(--b2l-border); margin: 0 0.9rem; min-width: 36px; }
.b2l-step-conn.done { background: var(--b2l-primary); }
/* A step not yet earned — Review before everything is categorised. Reads as
   unavailable rather than merely "not current": faded, with a padlock. */
.b2l-step-node.locked { opacity: 0.55; }
.b2l-step-node.locked .b2l-step-circle { background: transparent; border: 1px dashed var(--b2l-border); }

/* Review: the double-entry journal. One <tbody> per entry, two rows inside it.
 *
 * In a journal the ATOM IS THE ENTRY, not the line — the two legs share a `correlate`
 * and are one balanced transaction. So the banding alternates per ENTRY: one band is
 * one transaction, and the pair is legible standing still, with no hover and no
 * counting. Ordinary zebra striping would band every ROW, which says the row is the
 * unit and works directly against the grouping.
 *
 * Scoped to `.b2l-journal` — every other table in the app still bands per row, because
 * in those the row genuinely IS the unit.
 *
 * SPECIFICITY IS LOAD-BEARING HERE. Three earlier attempts at this were silently dead:
 * a `border-top` on <tbody> and one on <tr> (neither renders — the table is
 * `border-collapse: separate`), and `.b2l-journal-entry td { border-bottom: 0 }`, which
 * lost to `.b2l-table tbody td` (0,1,1 against 0,1,2). Each selector below is qualified
 * hard enough to beat the base rule it overrides, and the hover sits AFTER the band so
 * it wins their deliberate tie. */

/* The band. Alternating tbody, not alternating tr. */
.b2l-table.b2l-journal tbody.b2l-journal-entry:nth-of-type(even) td { background: var(--b2l-band); }

/* No line between the legs of one entry — a line is exactly what would split them —
   and they sit tight together so the eye takes them as one thing. */
.b2l-table.b2l-journal tbody.b2l-journal-entry td {
  border-bottom: 0; padding-top: 0.45rem; padding-bottom: 0.45rem;
}
.b2l-table.b2l-journal tbody.b2l-journal-entry tr:first-child td { padding-top: 0.9rem; }
.b2l-table.b2l-journal tbody.b2l-journal-entry tr:last-child td { padding-bottom: 0.9rem; }

/* Hover is now only "where is my cursor" — the band already did the grouping. Green,
   not grey, so it can never be mistaken for a band. It still lights the whole ENTRY:
   the default `tbody tr:hover` lights one leg, which teaches the wrong unit. */
.b2l-table.b2l-journal tbody.b2l-journal-entry:hover td { background: var(--b2l-primary-050); }

/* Header and totals: the darker rails the entries sit between. */
.b2l-table.b2l-journal thead th {
  background: var(--b2l-surface-3); color: var(--b2l-ink-700);
  border-bottom: 1px solid var(--b2l-border-strong);
}
.b2l-table.b2l-journal tfoot td {
  background: var(--b2l-surface-3); color: var(--b2l-ink); font-weight: 700;
  border-top: 2px solid var(--b2l-border-strong);
}

/* the transaction being categorised, at the top of the offcanvas */
.b2l-categorise-txn { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.7rem 0.85rem; margin-bottom: 1.1rem; border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius); background: var(--b2l-bg); font-size: var(--b2l-fs-13); }

/* sub-tabs (For Review / Categorised / Excluded) */
.b2l-subtabs { display: flex; gap: 1.5rem; border-bottom: 1px solid var(--b2l-border); }
.b2l-subtab { padding: 0.65rem 0.1rem; font-weight: 600; font-size: var(--b2l-fs-13); color: var(--b2l-muted); border: 0; background: none; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; }
.b2l-subtab.active { color: var(--b2l-ink); border-bottom-color: var(--b2l-primary); }

/* segmented control (Line-item / Consolidated; export formats) */
.b2l-seg { display: inline-flex; background: #eef2f6; border-radius: var(--b2l-radius); padding: 0.25rem; gap: 0.25rem; }
.b2l-seg.b2l-seg-full { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; width: 100%; }
.b2l-seg-btn { border: 0; background: transparent; color: var(--b2l-muted); font-weight: 600; font-size: var(--b2l-fs-13); padding: 0.5rem 0.9rem; border-radius: 0.4rem; cursor: pointer; text-align: center; }
.b2l-seg-btn.active { background: #fff; color: var(--b2l-ink); box-shadow: var(--b2l-shadow-sm); }

/* green "balanced" alert */
.b2l-alert-ok { display: flex; align-items: center; gap: 0.5rem; background: var(--b2l-primary-050); border: 1px solid var(--b2l-primary-100); color: var(--b2l-primary-700); border-radius: var(--b2l-radius-xl); padding: 0.85rem 1.1rem; font-weight: 600; font-size: var(--b2l-fs-13); }

/* suggestion cell */
.b2l-suggest-src { color: var(--b2l-muted); font-size: var(--b2l-fs-11); margin-top: 0.25rem; }
.b2l-suggest-hint { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); font-weight: 600; }
.b2l-suggest-hint svg { color: var(--b2l-primary-700); }

/* dark code preview */
.b2l-code { background: #0b1727; color: #e2e8f0; border-radius: var(--b2l-radius-xl); padding: 1rem 1.1rem; font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: var(--b2l-fs-12); line-height: 1.55; overflow: auto; max-height: 340px; white-space: pre; margin: 0; }

/* dark (ink) auto-width button — export "Download file" */
.b2l-btn-ink { background: var(--b2l-ink); color: #fff; }
.b2l-btn-ink:hover { background: #1e293b; color: #fff; }

/* import-help card + tip */
.b2l-help { border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius-xl); background: var(--b2l-surface); padding: 1.25rem 1.5rem; }
.b2l-help-title { display: flex; align-items: center; gap: 0.5rem; font-weight: 700; font-size: var(--b2l-fs-15); color: var(--b2l-ink); }
.b2l-help-title svg { color: var(--b2l-muted); }
.b2l-help-intro { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin: 0.35rem 0 0.9rem; }
.b2l-help-steps { margin: 0; padding-left: 1.25rem; display: flex; flex-direction: column; gap: 0.5rem; color: var(--b2l-ink-700); font-size: var(--b2l-fs-13); line-height: 1.55; }
.b2l-help-tip { margin-top: 1rem; background: #fffbeb; border: 1px solid #fde68a; color: #92400e; border-radius: var(--b2l-radius); padding: 0.7rem 0.9rem; font-size: var(--b2l-fs-13); line-height: 1.5; }
.b2l-help-tip strong { color: #92400e; }

/* ---------------------------------------------------- chart of accounts */
.b2l-coa { display: flex; gap: 1.5rem; align-items: flex-start; }
.b2l-coa-main { flex: 1; min-width: 0; }
.b2l-coa-panel { width: 360px; flex: none; border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius-xl); background: var(--b2l-surface); box-shadow: var(--b2l-shadow-sm); }
.b2l-coa-panel-head { display: flex; align-items: flex-start; justify-content: space-between; padding: 1.1rem 1.25rem 0.9rem; border-bottom: 1px solid var(--b2l-border-card); }
.b2l-coa-panel-head h3 { font-size: var(--b2l-fs-15); font-weight: 700; margin: 0; }
.b2l-coa-panel-head p { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin: 0.2rem 0 0; }
.b2l-coa-panel-body { padding: 1.25rem; }

/* Statements: the bank-account selector above the table. Medium cards — enough room for the two
   figures that decide which account someone opens, without the balance block that makes the
   ledgernext originals tall. auto-fill rather than auto-fit so three accounts stay card-sized
   instead of stretching to fill a 1600px row. */
.b2l-acct-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 0.75rem; }

/* border-strong, not border-card: these are CHOICES, and the edge has to be findable. The soft
   slate-100 the content cards use disappears against the page. No shadow either — depth reads as
   decoration on a control whose selected state is already carrying a tint and a ring. */
.b2l-acct-card { display: flex; flex-direction: column; gap: 0.7rem; padding: 0.85rem 1rem;
  border: 1px solid var(--b2l-border-strong); border-radius: var(--b2l-radius-xl);
  background: var(--b2l-surface); color: var(--b2l-ink);
  text-decoration: none; transition: border-color .12s, background .12s; }
.b2l-acct-card:hover { border-color: var(--b2l-primary); background: var(--b2l-surface-2); }

/* Selection is carried by the border and a tint, never by colour alone — the cards sit in a row
   and the active one has to be findable at a glance. */
.b2l-acct-card.is-selected { border-color: var(--b2l-primary); background: var(--b2l-primary-050);
  box-shadow: 0 0 0 1px var(--b2l-primary); }

.b2l-acct-card-head { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.b2l-acct-card-name { display: flex; align-items: center; gap: 0.3rem; font-size: var(--b2l-fs-13);
  font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b2l-acct-card.is-selected .b2l-acct-card-name { color: var(--b2l-primary-700); }
.b2l-acct-card-sub { font-size: var(--b2l-fs-11); color: var(--b2l-muted); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

.b2l-acct-card-figures { display: flex; gap: 1.25rem; margin-top: auto; }
.b2l-acct-fig { display: flex; flex-direction: column; gap: 0.05rem; }
.b2l-acct-fig-num { font-size: var(--b2l-fs-18); font-weight: 700; line-height: 1.1; }
.b2l-acct-fig-label { font-size: var(--b2l-fs-10); font-weight: 600; letter-spacing: .02em;
  text-transform: uppercase; color: var(--b2l-muted); }
.b2l-acct-fig.is-amber .b2l-acct-fig-num { color: var(--b2l-amber); }

.b2l-acct-card.is-orphan .b2l-acct-card-name { color: var(--b2l-muted); }
.b2l-acct-card.is-orphan.is-selected .b2l-acct-card-name { color: var(--b2l-primary-700); }

/* ---------------------------------------------- new/edit account offcanvas */
.b2l-offcanvas { width: 420px; max-width: 92vw; display: flex; flex-direction: column; background: var(--b2l-surface); border-left: 1px solid var(--b2l-border-card); }
.b2l-offcanvas-head { display: flex; align-items: flex-start; justify-content: space-between; padding: 1.15rem 1.35rem 0.95rem; border-bottom: 1px solid var(--b2l-border-card); }
.b2l-offcanvas-title { font-size: var(--b2l-fs-16); font-weight: 700; margin: 0; }
.b2l-offcanvas-sub { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin: 0.15rem 0 0; }
.b2l-offcanvas-body { padding: 1.35rem; overflow-y: auto; flex: 1; }
.b2l-offcanvas-foot { display: flex; justify-content: flex-end; gap: 0.6rem; padding: 0.9rem 1.35rem; border-top: 1px solid var(--b2l-border-card); background: var(--b2l-bg); }
.b2l-offcanvas-body .select2-container { display: block; }

/* WIDE variant, for forms whose rows are horizontal. The rule form packs a field, an operator, a
   value and a remove button onto ONE line, and 420px leaves the value box too narrow to read what
   you typed. Ladders down to full width on a phone, where the row wraps anyway.
   Same breakpoints as ledgernext's .offcanvas-wide, which its rule form uses for this reason.
   Doubled-up selector so it beats .b2l-offcanvas's own width regardless of source order. */
.b2l-offcanvas.b2l-offcanvas-wide { width: 100%; }
@media (min-width: 576px)  { .b2l-offcanvas.b2l-offcanvas-wide { width: 85%; } }
@media (min-width: 768px)  { .b2l-offcanvas.b2l-offcanvas-wide { width: 75%; } }
@media (min-width: 992px)  { .b2l-offcanvas.b2l-offcanvas-wide { width: 65%; } }
@media (min-width: 1200px) { .b2l-offcanvas.b2l-offcanvas-wide { width: 60%; } }
.b2l-textarea { width: 100%; background: #fff; border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius); padding: 0.6rem 0.8rem; font-size: var(--b2l-fs-13); color: var(--b2l-ink); resize: vertical; min-height: 70px; font-family: inherit; }
.b2l-subtype { padding: 0.8rem 0; border-top: 1px solid var(--b2l-border-card); }
.b2l-subtype-name { font-weight: 600; font-size: var(--b2l-fs-13); color: var(--b2l-ink); }
.b2l-subtype-type { color: var(--b2l-muted); font-size: var(--b2l-fs-12); }

/* -------------------------------------------------------------- toast */
.b2l-toast { position: fixed; bottom: 1.25rem; right: 1.25rem; background: var(--b2l-ink); color: #fff; padding: 0.7rem 1rem; border-radius: var(--b2l-radius); font-size: var(--b2l-fs-13); font-weight: 600; box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25); z-index: 1080; opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; }
.b2l-toast.show { opacity: 1; transform: translateY(0); }

/* flash toast stack (shared/_flash) — children lose fixed positioning so they stack */
.b2l-toasts { position: fixed; top: 1.25rem; right: 1.25rem; z-index: 1090; display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; max-width: min(420px, calc(100vw - 2rem)); }
.b2l-toasts .b2l-toast {
  position: static; display: flex; align-items: center; gap: 0.55rem; transform: translateY(-8px);
  /* Translucent white panel — overrides the dark base .b2l-toast (still used by
     rules_controller's bottom-right toast). backdrop-filter frosts whatever scrolls
     behind the panel so the copy stays crisp even though the fill is see-through. */
  background: rgba(255, 255, 255, 0.85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: var(--b2l-ink);
  border: 1px solid var(--b2l-border);
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.12);
}
.b2l-toasts .b2l-toast.show { transform: translateY(0); }
.b2l-toast-notice > svg { color: var(--b2l-success); flex: none; }
.b2l-toast-alert  > svg { color: var(--b2l-amber); flex: none; }
.b2l-toast-msg { flex: 1; font-weight: 500; min-width: 0; }
.b2l-toast-x { border: 0; background: none; color: var(--b2l-muted); cursor: pointer; padding: 0.1rem; display: inline-grid; place-items: center; flex: none; }
.b2l-toast-x:hover { color: var(--b2l-ink); }

/* -------------------------------------------------------------- modal */
.b2l-modal-backdrop { display: none; position: fixed; inset: 0; background: rgba(15, 23, 42, 0.45); z-index: 1060; padding: 1.5rem; overflow-y: auto; }
.b2l-modal-backdrop.is-open { display: grid; place-items: start center; }
.b2l-modal { width: 100%; max-width: 640px; margin: auto; background: var(--b2l-surface); border-radius: var(--b2l-radius-xl); box-shadow: 0 20px 60px rgba(15, 23, 42, 0.25); }
.b2l-modal-head { padding: 1.25rem 1.5rem 1rem; border-bottom: 1px solid var(--b2l-border-card); }
.b2l-modal-title { display: flex; align-items: center; justify-content: space-between; font-size: 18px; font-weight: 700; color: var(--b2l-ink); }
.b2l-modal-x { border: 0; background: none; color: var(--b2l-muted-2); cursor: pointer; padding: 0.2rem; }
.b2l-modal-x:hover { color: var(--b2l-ink); }
.b2l-modal-body { padding: 1.5rem; }
.b2l-modal-foot { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-top: 1px solid var(--b2l-border-card); }

/* bordered inputs / selects (forms & modals) */
.b2l-inp, .b2l-select { width: 100%; background: #fff; border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius); padding: 0.6rem 0.8rem; font-size: var(--b2l-fs-13); color: var(--b2l-ink); }
.b2l-inp:focus, .b2l-select:focus { outline: none; border-color: var(--b2l-primary); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.12); }
/* Native <select> (e.g. the ledger period preset): custom chevron, no OS arrow. */
select.b2l-select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.6rem center;
}

/* ------------------------------------------------- select2 (b2l theme) */

/* A `required` <select> that select2 has taken over.
   select2 hides the real element with `clip`, and a clipped control is not
   focusable — so the browser refuses to submit the form AND declines to show
   its "Please select an item" bubble, which reads as a dead button. Give the
   element a real (if invisible) box so validation can anchor to it. It stays
   out of the layout, and pointer-events: none keeps it unclickable. */
select.select2-hidden-accessible[required] {
  display: block !important;
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; border: 0 !important;
  opacity: 0; pointer-events: none;
  clip: auto !important; clip-path: none !important;
}

/* Control matches .b2l-select: white, gray border, .5rem radius, 13px text */
.select2-container .select2-selection--single {
  height: auto; background: #fff; border: 1px solid var(--b2l-border);
  border-radius: var(--b2l-radius); transition: border-color .12s, box-shadow .12s;
}
.select2-container .select2-selection--single .select2-selection__rendered {
  padding: 0.6rem 2rem 0.6rem 0.8rem; line-height: 1.5;
  font-size: var(--b2l-fs-13); color: var(--b2l-ink); font-family: var(--b2l-font);
}
.select2-container .select2-selection--single .select2-selection__placeholder { color: var(--b2l-muted-2); }
.select2-container .select2-selection--single .select2-selection__arrow { height: 100%; top: 0; right: 0.5rem; }
.select2-container .select2-selection--single .select2-selection__arrow b { border-color: var(--b2l-muted-2) transparent transparent transparent; }
.select2-container--open .select2-selection--single .select2-selection__arrow b { border-color: transparent transparent var(--b2l-muted-2) transparent; }

/* focus ring = b2l emerald ring */
.select2-container--open .select2-selection--single,
.select2-container--focus .select2-selection--single {
  border-color: var(--b2l-primary); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.12); outline: none;
}

/* dropdown panel — elevate only the OPEN dropdown so a closed control never
   paints over the field below it (it renders in <body>, above modal 1060 / offcanvas 1045). */
/* Every select2 dropdown sits BELOW the sticky header (topbar 1040 / tabs 1020)
   by default, so a flipped-up dropdown can never cover the logo/nav on any
   screen — this applies to both halves of an open select2 (the body-appended
   options panel and the inline selection box). */
.select2-container--open { z-index: 1010; }

/* Exception: while an overlay is open, its picker must clear the overlay panel.
   The overlay's own backdrop already covers the header, so raising the dropdown
   here can't hide a visible header. Covers the account offcanvas (.offcanvas.show)
   and any .b2l-modal-backdrop (rule wizard, new-client, …). */
body:has(.offcanvas.show) .select2-container--open,
body:has(.b2l-modal-backdrop.is-open) .select2-container--open { z-index: 1090; }
.select2-dropdown {
  border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius);
  box-shadow: var(--b2l-shadow); font-family: var(--b2l-font); overflow: hidden;
  min-width: min(240px, 90vw);
}
.select2-search--dropdown { padding: 0.5rem; }
.select2-search--dropdown .select2-search__field {
  border: 1px solid var(--b2l-border); border-radius: 0.4rem; padding: 0.45rem 0.65rem;
  font-size: var(--b2l-fs-13); font-family: var(--b2l-font); color: var(--b2l-ink);
}
.select2-search--dropdown .select2-search__field:focus {
  outline: none; border-color: var(--b2l-primary); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.12);
}
.select2-results__option { padding: 0.5rem 0.8rem; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700); }
.select2-container .select2-results__option--highlighted.select2-results__option--selectable {
  background: var(--b2l-primary-050); color: var(--b2l-primary-700);
}
.select2-container .select2-results__option--selected { background: var(--b2l-surface-2); color: var(--b2l-ink); font-weight: 600; }
.select2-results__group { padding: 0.5rem 0.8rem 0.25rem; font-size: var(--b2l-fs-10); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--b2l-muted-2); }
.select2-results__options--nested .select2-results__option { padding-left: 1.1rem; }

/* ------------------------------------------------- stepped form (the Rule form) */
/* Numbered cards joined by a spine. The three questions a rule answers — what is it, when does it
   fire, what does it do — are genuinely sequential, and a flat column of eight controls gives the
   user no clue which ones belong together.
   NOT a wizard: every step stays visible and it is ONE form with one save, so a validation error
   still lands on the field that caused it with no step to re-open. The numbering is a reading
   order, not a state machine.
   NAMED formstep, NOT step: .b2l-step / .b2l-steps are the statement WORKFLOW stepper (Upload ->
   Categorise -> Review -> Export), which is a horizontal, centred flex row. Reusing those names
   here inherited its `align-items: center` and centred every card at a different width — the
   markers ended up on different x positions with no spine between them. A flat class namespace has
   no scoping, so a new component has to check the names it wants. */
.b2l-formsteps { display: flex; flex-direction: column; align-items: stretch; }
.b2l-formstep { position: relative; padding-left: 2.6rem; padding-bottom: 1.35rem; text-align: left; }
.b2l-formstep:last-child { padding-bottom: 0; }

/* The spine, joining this marker to the next. Dropped on the last step so the line terminates on
   the final marker instead of trailing away into the footer. */
.b2l-formstep::before { content: ""; position: absolute; left: 0.84rem; top: 2.15rem; bottom: 0; width: 2px; background: var(--b2l-border-card); }
.b2l-formstep:last-child::before { display: none; }

/* Rounded SQUARE marker, deliberately: a circled badge on a grey header strip is the Bootstrap
   default this app does not use anywhere else. */
.b2l-formstep-n { position: absolute; left: 0; top: 0; width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; display: grid; place-items: center; background: var(--b2l-primary-050); color: var(--b2l-primary-700); border: 1px solid var(--b2l-primary); font-weight: 700; font-size: var(--b2l-fs-12); }
.b2l-formstep-title { font-weight: 700; font-size: var(--b2l-fs-15); color: var(--b2l-ink); margin: 0; line-height: 1.75rem; }
.b2l-formstep-hint { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin: 0.1rem 0 0.7rem; max-width: 60ch; }
/* The card holds only the fields — the title and hint sit OUTSIDE it, on the spine, so the eye
   reads the sequence down the left edge rather than through three header bars. */
.b2l-formstep-card { border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius); background: var(--b2l-surface-2); padding: 1rem 1.1rem; }
.b2l-formstep-card .b2l-field:last-child { margin-bottom: 0; }

/* Rule condition rows: field · operator · value · remove, on one line.
   THE TRAP: the two selects are select2, which hides the <select> and renders its own
   .select2-container — so a rule targeting .b2l-select never touches the visible control. And
   select2_controller passes width: "100%" (right everywhere else: controls fill their box), which
   it writes as an INLINE style. Two flex items each asking for 100% eat the whole row and the value
   box collapses to a few pixels.
   Pin the two controls by flex-basis: for a flex item, flex-basis wins over width for the main-axis
   size, so this beats the inline style without !important. The value takes what's left; wrap rather
   than crush once the panel is narrow. */
.b2l-cond { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; flex-wrap: wrap; }
.b2l-cond .select2-container,
.b2l-cond .b2l-select { flex: 0 0 11rem; }
.b2l-cond .b2l-inp { flex: 1 1 14rem; width: auto; min-width: 0; }
.b2l-cond-x { border: 0; background: none; color: var(--b2l-muted-2); cursor: pointer; padding: 0.2rem; flex: 0 0 auto; }
.b2l-cond-x:hover { color: var(--b2l-danger); }
.b2l-add-cond { display: inline-flex; align-items: center; gap: 0.3rem; border: 0; background: none; color: var(--b2l-primary-700); font-weight: 600; font-size: var(--b2l-fs-13); cursor: pointer; padding: 0.3rem 0; }

/* Key/value summary rows (Profile) */
.b2l-review { background: var(--b2l-surface-2); border-radius: var(--b2l-radius); padding: 1rem 1.25rem; }
.b2l-review-row { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0; font-size: var(--b2l-fs-13); }
.b2l-review-row .k { color: var(--b2l-muted); }
.b2l-review-row .v { color: var(--b2l-ink); font-weight: 600; }

/* --------------------------------------------------------- breadcrumbs */
.b2l-crumbs { display: flex; align-items: center; gap: 0.4rem; font-size: var(--b2l-fs-13); color: var(--b2l-muted); margin-bottom: 0.75rem; }
.b2l-crumbs a { color: var(--b2l-primary-700); font-weight: 600; }
.b2l-crumbs .b2l-crumb-current { color: var(--b2l-ink); font-weight: 600; }
.b2l-crumbs .b2l-crumb-sep { color: var(--b2l-muted-2); display: inline-grid; place-items: center; }

/* ------------------------------------------------------------ upload screen */
/* Upload form: a centred card, so the fields read as one panel rather than
   floating on the page background. Pairs with .b2l-card in the markup. */
.b2l-upload { max-width: 720px; margin: 1.5rem auto 0; padding: 2rem 2rem 2.25rem; }
.b2l-upload-head { text-align: center; }
.b2l-upload-head h2 { font-size: 20px; font-weight: 700; margin: 0; }
.b2l-upload-head p { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin: 0.35rem 0 0; }
.b2l-format-chips { display: flex; justify-content: center; flex-wrap: wrap; gap: 0.5rem; margin: 1rem 0 1.25rem; }
.b2l-chip { display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius); padding: 0.3rem 0.6rem; font-size: var(--b2l-fs-12); font-weight: 600; color: var(--b2l-ink-700); background: var(--b2l-surface); }
.b2l-chip svg { color: var(--b2l-muted-2); }
.b2l-dropzone {
  border: 2px dashed var(--b2l-border); border-radius: var(--b2l-radius-xl);
  padding: 2.5rem 1.5rem; text-align: center; cursor: pointer; background: var(--b2l-surface);
  transition: border-color .12s, background-color .12s;
}
.b2l-dropzone:hover, .b2l-dropzone.is-dragover { border-color: var(--b2l-primary); background: var(--b2l-primary-050); }
/* Inside the white upload card a white dropzone disappears — inset it. The
   hover rule needs the same specificity or the tint would win over it. */
.b2l-upload .b2l-dropzone { background: var(--b2l-surface-2); }
.b2l-upload .b2l-dropzone:hover,
.b2l-upload .b2l-dropzone.is-dragover { background: var(--b2l-primary-050); }
.b2l-dropzone-icon { color: var(--b2l-muted-2); }
.b2l-dropzone-title { font-size: var(--b2l-fs-15); font-weight: 700; color: var(--b2l-ink); margin-top: 0.6rem; }
.b2l-dropzone-hint { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.2rem; }
.b2l-dropzone-file { display: inline-block; margin-top: 0.6rem; color: var(--b2l-primary-700); font-weight: 600; font-size: var(--b2l-fs-13); }
.b2l-upload-note { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin-top: 0.9rem; line-height: 1.5; }

/* --------------------------------------------------- chart-of-accounts import */
/* Add-vs-Replace mode picker */
.b2l-radio-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 0.5rem; }
@media (max-width: 640px) { .b2l-radio-cards { grid-template-columns: 1fr; } }
.b2l-radio-card { display: flex; align-items: flex-start; gap: 0.6rem; border: 1px solid var(--b2l-border-card); border-radius: var(--b2l-radius-xl); padding: 0.85rem 1rem; cursor: pointer; background: var(--b2l-surface); transition: border-color .12s, background-color .12s; }
.b2l-radio-card:hover { border-color: var(--b2l-primary); }
.b2l-radio-card:has(input:checked) { border-color: var(--b2l-primary); background: var(--b2l-primary-050); }
.b2l-radio-card.is-disabled { opacity: 0.55; cursor: not-allowed; background: var(--b2l-surface-2, #f9fafb); }
.b2l-radio-card.is-disabled:hover { border-color: var(--b2l-border-card); }
.b2l-radio-card input { margin-top: 0.2rem; flex: none; }
.b2l-radio-card strong { display: flex; align-items: center; gap: 0.35rem; font-size: var(--b2l-fs-14); }
.b2l-radio-card .b2l-muted { display: block; font-size: var(--b2l-fs-12); margin-top: 0.2rem; line-height: 1.4; }

/* Bootstrap form-check controls (radios/checkboxes), tinted to the app primary. */
.form-check-input { cursor: pointer; }
.form-check-input:checked { background-color: var(--b2l-primary); border-color: var(--b2l-primary); }
.form-check-input:focus { border-color: var(--b2l-primary); box-shadow: 0 0 0 0.15rem var(--b2l-primary-050); }
.form-check-input:disabled { cursor: not-allowed; }
.b2l-radio-line { display: flex; align-items: center; gap: 0.5rem; margin: 0.3rem 0; font-size: var(--b2l-fs-14); cursor: pointer; }
.b2l-radio-line .form-check-input { flex: none; margin: 0; }

/* Sub-stepper inside step 1 (Upload → Map → Review) of the statement workflow */
.b2l-substeps { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0.9rem 0 0.25rem; }
.b2l-substep { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); }
.b2l-substep.active { color: var(--b2l-primary); font-weight: 600; }
.b2l-substep.done { color: var(--b2l-emerald, #059669); }
.b2l-substep-sep { color: var(--b2l-border); display: inline-flex; }

/* Review table: mark invalid rows and compact the inline inputs */
.b2l-import-summary { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.9rem 0; }
.b2l-import-map { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin: 0.25rem 0 0; }
.b2l-import-row.is-invalid > td { background: var(--b2l-rose-050, #fff1f2); }
.b2l-import-row .b2l-inp, .b2l-import-row .b2l-select { padding: 0.3rem 0.45rem; font-size: var(--b2l-fs-13); min-width: 8rem; }
.b2l-import-row .b2l-inp-num { min-width: 6rem; }
.b2l-import-row .select2-container { min-width: 10rem; }
/* overflow-wrap: anywhere, not break-word: the message quotes the cell it could
   not read, and a bank's footer row can be a 130-character URL with no space in
   it to break at. Without this the Problem column simply grows until the table
   needs a horizontal scrollbar. */
.b2l-import-msg { color: var(--b2l-danger); font-size: var(--b2l-fs-12); overflow-wrap: anywhere; }

/* Opt a single cell out of a nowrap table. .b2l-pin-actions sets nowrap on every
   body cell to keep the pinned Actions column aligned, which is right for dates
   and figures and wrong for a description — bank narrations run to 80 characters
   and would push the table sideways forever. */
.b2l-cell-wrap { white-space: normal; overflow-wrap: anywhere; min-width: 14rem; }

/* Instructions shown before upload */
.b2l-instr-head { display: flex; align-items: center; gap: 0.5rem; font-size: var(--b2l-fs-15); font-weight: 700; color: var(--b2l-ink); margin: 0 0 0.25rem; }
.b2l-instr-head svg { color: var(--b2l-primary); }
.b2l-instr { margin: 0.75rem 0 0; padding-left: 1.35rem; }
.b2l-instr li { margin-bottom: 0.6rem; line-height: 1.5; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700); }
.b2l-instr li::marker { color: var(--b2l-primary); font-weight: 700; }
.b2l-instr li strong { color: var(--b2l-ink); }
.b2l-inline-code { background: var(--b2l-primary-050); color: var(--b2l-primary-700); border-radius: 6px; padding: 0.1rem 0.4rem; font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: var(--b2l-fs-12); }
.b2l-details { margin-top: 0.5rem; }
.b2l-details > summary { display: inline-flex; align-items: center; gap: 0.35rem; cursor: pointer; color: var(--b2l-primary-700); font-weight: 600; font-size: var(--b2l-fs-13); list-style: none; }
.b2l-details > summary::-webkit-details-marker { display: none; }
.b2l-details > summary::marker { content: ""; }
.b2l-details[open] > summary .b2l-details-chev { transform: rotate(180deg); }
.b2l-details-chev { transition: transform .15s; }
.b2l-details[open] > summary { margin-bottom: 0.6rem; }

/* ----------------------------------------------------------- dashboard */
/* amber attention banner */
.b2l-banner-amber { display: flex; align-items: center; gap: 0.9rem; background: #fffbeb; border: 1px solid #fde68a; color: #92400e; border-radius: var(--b2l-radius-xl); padding: 1rem 1.25rem; }
.b2l-banner-amber > svg { color: var(--b2l-amber); flex: none; }
.b2l-banner-amber-body { flex: 1; min-width: 0; }
.b2l-banner-amber strong { display: block; font-size: var(--b2l-fs-14); }
.b2l-banner-amber p { margin: 0.1rem 0 0; font-size: var(--b2l-fs-13); }
.b2l-btn-amber { background: #fff; color: #92400e; border-color: #fde68a; }
.b2l-btn-amber:hover { background: #fef3c7; color: #78350f; }

/* status banners — the Trial Balance states up front whether the books tie. Same shape as the
   amber banner, but WITHOUT its `strong { display: block }`: these read as one sentence. */
.b2l-banner-emerald,
.b2l-banner-rose { display: flex; align-items: center; gap: 0.7rem; border-radius: var(--b2l-radius-xl); padding: 0.85rem 1.15rem; font-size: var(--b2l-fs-14); }
.b2l-banner-emerald { background: var(--b2l-primary-050); border: 1px solid #a7f3d0; color: var(--b2l-primary-700); }
.b2l-banner-rose { background: var(--b2l-rose-050); border: 1px solid #fecdd3; color: var(--b2l-rose); }
.b2l-banner-emerald > svg,
.b2l-banner-rose > svg { flex: none; }

/* categorisation progress bar (KPI card) */
.b2l-progress { height: 5px; background: #eef2f6; border-radius: 999px; margin-top: 0.5rem; overflow: hidden; }
.b2l-progress-bar { display: block; height: 100%; background: var(--b2l-primary); border-radius: 999px; }
/* Over the limit is a legitimate state after a downgrade (ADR 0008), so the bar
   has to render it rather than just clamp silently. */
.b2l-progress-bar.is-over { background: var(--b2l-rose); }

/* --- Billing: the current-subscription card ------------------------------- */
/* Facts grid. auto-fit rather than a fixed column count so it degrades to two
   columns and then one without a media query. */
.b2l-subfacts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1.1rem 1.5rem; }
.b2l-subfact { font-weight: 600; color: var(--b2l-ink); font-size: var(--b2l-fs-15); margin-top: 0.15rem; font-variant-numeric: tabular-nums; }
.b2l-submeters { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem 1.5rem; margin-top: 1.35rem; }
.b2l-submeter-num { font-size: var(--b2l-fs-13); font-weight: 600; color: var(--b2l-ink-700); font-variant-numeric: tabular-nums; }
.b2l-submeter-num.is-over { color: var(--b2l-rose); }
/* Status notes: cancelling, failed payment, over-limit. */
.b2l-subnote { display: flex; align-items: flex-start; gap: 0.5rem; margin-top: 1.35rem; padding: 0.7rem 0.85rem; border-radius: var(--b2l-radius); font-size: var(--b2l-fs-13); }
.b2l-subnote svg { flex: none; margin-top: 1px; }
.b2l-subnote.is-amber { background: #fff7ed; color: #c2410c; }
.b2l-subnote.is-rose { background: var(--b2l-rose-050); color: var(--b2l-rose); }

/* work queue rows */
.b2l-queue-row { display: flex; align-items: center; gap: 0.9rem; padding: 1rem 1.25rem; border-bottom: 1px solid var(--b2l-border-2); }
.b2l-queue-row:last-child { border-bottom: 0; }

/* whole-row click targets (row-link controller) */
.b2l-row-click { cursor: pointer; }
.b2l-row-click:hover { background: var(--b2l-surface-2); }
.b2l-queue-main { flex: 1; min-width: 0; }
.b2l-queue-meta { color: var(--b2l-muted); font-size: var(--b2l-fs-11); margin-top: 0.15rem; }
.b2l-queue-row .b2l-stepper { margin-top: 0.55rem; }
.b2l-queue-row .b2l-btn { flex: none; }
.b2l-queue-check { color: var(--b2l-primary); display: inline-grid; place-items: center; }
.b2l-queue-clear { display: flex; align-items: center; gap: 0.6rem; padding: 1.25rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); font-weight: 500; }
.b2l-queue-clear svg { color: var(--b2l-primary); }

.b2l-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.b2l-kpi { display: flex; align-items: center; gap: 0.9rem; padding: 1.1rem 1.25rem; }
.b2l-kpi-icon { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 0.6rem; background: var(--b2l-primary-050); color: var(--b2l-primary-700); flex: none; }
.b2l-kpi-icon svg { width: 18px; height: 18px; }
.b2l-kpi.is-amber .b2l-kpi-icon { background: #fff7ed; color: var(--b2l-amber); }
.b2l-kpi-num { font-size: var(--b2l-fs-22); font-weight: 700; line-height: 1.1; color: var(--b2l-ink); font-variant-numeric: tabular-nums; }
.b2l-kpi-label { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.1rem; }
.b2l-card-head { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.25rem; border-bottom: 1px solid var(--b2l-border-card); }
.b2l-card-head h2 { font-size: var(--b2l-fs-15); font-weight: 700; margin: 0; }
/* card header that toggles a collapsible section */
button.b2l-collapse-head { width: 100%; border: 0; background: none; cursor: pointer; font: inherit; text-align: left; }
button.b2l-collapse-head:hover { background: var(--b2l-surface-2); }
.b2l-card.is-collapsed .b2l-acc-chev { transform: rotate(-90deg); }
.b2l-card.is-collapsed .b2l-collapse-head { border-bottom: 0; }
.b2l-quick { display: flex; align-items: center; gap: 0.7rem; padding: 0.7rem 0.85rem; border-radius: var(--b2l-radius); border: 1px solid var(--b2l-border-card); color: var(--b2l-ink-700); font-weight: 600; font-size: var(--b2l-fs-13); }
.b2l-quick:hover { background: var(--b2l-surface-2); color: var(--b2l-ink); }
.b2l-quick-ic { display: inline-grid; place-items: center; color: var(--b2l-primary-700); }
.b2l-quick .b2l-ml-auto { color: var(--b2l-muted-2); }

/* -------------------------------------------------------- billing plans */
/* Pricing cards on /billing. Same 4-across ladder as .b2l-kpis but its own
   class — the kpi media queries and child styles are keyed to stat tiles. */
.b2l-plans { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; align-items: stretch; }
.b2l-plan-card { position: relative; display: flex; }  /* anchors the flag; body stretches */
.b2l-plan-card.is-highlighted { border-color: var(--b2l-primary); box-shadow: var(--b2l-shadow-sm); }
.b2l-plan-flag { position: absolute; top: -0.55rem; left: 50%; transform: translateX(-50%); }
.b2l-plan-body { display: flex; flex-direction: column; flex: 1; }
.b2l-plan-name { display: flex; align-items: center; gap: 0.45rem; font-weight: 700; font-size: var(--b2l-fs-15); color: var(--b2l-ink); }
.b2l-plan-name svg { color: var(--b2l-primary); }
/* min-heights keep the four price rows level when a tagline or hint wraps */
.b2l-plan-tagline { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin: 0.35rem 0 0; min-height: 3em; }  /* two lines, so a wrapped tagline can't push its price row down */
.b2l-plan-price { margin: 0.9rem 0 0.25rem; }
/* 32px raw: one step above the 28px stat-tile token, per the one-off-px precedent */
.b2l-plan-figure { font-size: 32px; font-weight: 700; letter-spacing: -0.02em; color: var(--b2l-ink); font-variant-numeric: tabular-nums; }
.b2l-plan-per { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-left: 0.15rem; }
.b2l-plan-hint { color: var(--b2l-muted); font-size: var(--b2l-fs-12); min-height: 1.2em; }
.b2l-plan-features { list-style: none; padding: 0; margin: 1rem 0 1.25rem; }
.b2l-plan-features li { display: flex; align-items: flex-start; gap: 0.5rem; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700); padding: 0.3rem 0; }
.b2l-plan-features svg { color: var(--b2l-primary); flex: none; margin-top: 0.2rem; }
.b2l-plan-cta { margin-top: auto; }

/* --------------------------------------------------------------- tables */
.b2l-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--b2l-fs-13); }
.b2l-table thead th {
  text-align: left; font-size: var(--b2l-fs-11); font-weight: 600; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--b2l-muted); padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--b2l-border); background: var(--b2l-surface-2);
}
.b2l-table tbody td { padding: 0.85rem 1rem; border-bottom: 1px solid var(--b2l-border-2); color: var(--b2l-ink-700); vertical-align: middle; }
/* A totals row lives in <tfoot>, which the tbody rule above doesn't reach — so its
   cells had NO padding and its right-aligned figures sat a full 1rem to the right of
   the column they were meant to total. Same padding, same alignment. */
.b2l-table tfoot td { padding: 0.85rem 1rem; color: var(--b2l-ink-700); vertical-align: middle; }
.b2l-table tbody tr:hover td { background: var(--b2l-surface-2); }
.b2l-table .num { text-align: right; font-variant-numeric: tabular-nums; }  /* Inter, not mono */
.b2l-table .strong { color: var(--b2l-ink); font-weight: 600; }
.b2l-amount-neg { color: var(--b2l-danger); }
.b2l-amount-pos { color: var(--b2l-success); }

/* -------------------------------------------------------------- badges */
.b2l-badge {
  display: inline-flex; align-items: center; gap: 0.3rem; font-size: var(--b2l-fs-11); font-weight: 600;
  padding: 0.2rem 0.5rem; border-radius: var(--b2l-radius); line-height: 1.2;
}
.b2l-badge-gray    { background: #f1f5f9; color: var(--b2l-muted); }
.b2l-badge-emerald { background: var(--b2l-primary-050); color: var(--b2l-primary-700); }
.b2l-badge-blue    { background: var(--b2l-blue-050); color: var(--b2l-blue); }
.b2l-badge-rose    { background: var(--b2l-rose-050); color: var(--b2l-rose); }
.b2l-badge-credit  { background: var(--b2l-primary-050); color: var(--b2l-primary-700); }
.b2l-badge-debit   { background: var(--b2l-rose-050); color: var(--b2l-rose); }
.b2l-badge-amber   { background: #fff7ed; color: #c2410c; }
/* A rule's suggestion. OUTLINED, unlike every other badge, on purpose: the others state a fact about
   the row (Duplicate, Compound, a tax) while this one is a PROPOSAL the user has not accepted yet.
   The outline is what says "provisional" — so both variants keep it, and only the colour differs.
   Green proposes a category; amber proposes taking the row OUT of the books, which deserves a
   second look (--b2l-amber is this app's "needs attention"). */
.b2l-badge-suggest { background: var(--b2l-primary-050); color: var(--b2l-primary-700); border: 1px solid var(--b2l-primary); }
.b2l-badge-suggest-warn { background: #fff7ed; color: #c2410c; border: 1px solid var(--b2l-amber); }
.b2l-badge-violet  { background: #f3e8ff; color: #7c3aed; }

/* --------------------------------------------------------- match tokens */
.b2l-match-op { background: #f1f5f9; color: var(--b2l-muted); border-radius: 0.35rem; padding: 0.1rem 0.4rem; font-size: var(--b2l-fs-11); font-weight: 600; }

/* ------------------------------------------------------ workflow stepper */
/* Table pager (kaminari). "Showing X–Y of Z" left, Prev/Next right. */
/* Long tables carry a pager above and below, so the nav is always in reach.
   The partial owns its own padding + divider; the modifier only picks the side. */
.b2l-pager { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding: 0.85rem 1.5rem; }
.b2l-pager.is-top { border-bottom: 1px solid var(--b2l-border-card); }
.b2l-pager.is-bottom { border-top: 1px solid var(--b2l-border-card); }
/* A pager alone in its card (Subtypes renders cards, not one table) needs no
   divider — the card edge already draws one. */
.b2l-card > .b2l-pager:only-child { border: 0; }
.b2l-pager-nav { display: inline-flex; align-items: center; gap: 0.6rem; }

.b2l-stepper { display: flex; align-items: center; gap: 0.25rem; }
.b2l-step { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; }
.b2l-step-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--b2l-border); }
.b2l-step-label { font-size: var(--b2l-fs-10); color: var(--b2l-muted-2); }
.b2l-step.done .b2l-step-dot,
.b2l-step.active .b2l-step-dot { background: var(--b2l-primary); }
.b2l-step.done .b2l-step-label,
.b2l-step.active .b2l-step-label { color: var(--b2l-ink-700); }
/* A failed upload — the current step is an error, not in progress. */
.b2l-step.error .b2l-step-dot { background: var(--b2l-danger); }
.b2l-step.error .b2l-step-label { color: var(--b2l-danger); }
.b2l-step-line { width: 26px; height: 2px; background: var(--b2l-border); margin-bottom: 0.9rem; }
.b2l-step-line.done { background: var(--b2l-primary); }

/* ------------------------------------------------------ activity timeline */
/* The stepper above, turned on its side: the same 9px dot and the same 2px
   connector, only the axis changes. Nothing new is invented, so a timeline row
   and a statement's workflow read as the same object.

   The rail is drawn ONCE per date group as an ::before on the <ol>, never
   per-row: a per-row connector leaves a hairline gap at every row boundary,
   which over a hundred rows reads as a dashed line. */
.b2l-timeline { list-style: none; margin: 0; padding: 0; }

/* Day header. Deliberately NOT sticky: the topbar and the tab strip are already
   sticky, so a third layer would have to hard-code their combined height and
   would float mid-page the moment either changes. On a paged feed the repeated
   header is enough of a wayfinder. Same weight as a table's thead — it IS the
   column head here. */
.b2l-tl-date {
  display: flex; align-items: baseline; gap: 0.5rem;
  margin: 0; padding: 0.7rem 1.5rem;
  background: var(--b2l-surface-2);
  border-bottom: 1px solid var(--b2l-border-card);
  font-size: var(--b2l-fs-11); font-weight: 600; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--b2l-muted);
}
.b2l-tl-group + .b2l-tl-group .b2l-tl-date { border-top: 1px solid var(--b2l-border-card); }
.b2l-tl-date-count { text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--b2l-muted-2); }

.b2l-tl-events { list-style: none; margin: 0; padding: 0.6rem 1.5rem 0.8rem; position: relative; }
/* The rail. A 9px dot at the row's left edge centres at +4.5px, so a 2px line
   starts at +3.5px. Inset top and bottom so it stops at the first and last dot
   instead of trailing into the padding. */
.b2l-tl-events::before {
  content: ""; position: absolute; left: calc(1.5rem + 3.5px); top: 1.5rem; bottom: 1.5rem;
  width: 2px; background: var(--b2l-border);
}

.b2l-tl-event {
  position: relative; display: flex; align-items: flex-start; gap: 0.7rem;
  padding: 0.55rem 0.5rem 0.55rem 1.5rem; border-radius: var(--b2l-radius);
}
.b2l-tl-event:hover { background: var(--b2l-surface-2); }

/* The stepper's dot, unchanged at 9px. The ring is the surface colour, which
   punches the marker out of the rail so the line doesn't run through it. */
.b2l-tl-dot {
  position: absolute; left: 0; top: 0.95rem; width: 9px; height: 9px;
  border-radius: 50%; background: var(--b2l-border);
  box-shadow: 0 0 0 3px var(--b2l-surface); flex: none;
}
.b2l-tl-dot-statements { background: var(--b2l-primary); }
.b2l-tl-dot-ledger     { background: var(--b2l-ink); }
.b2l-tl-dot-accounts   { background: var(--b2l-blue); }
.b2l-tl-dot-rules      { background: var(--b2l-amber); }
.b2l-tl-dot-taxes,
.b2l-tl-dot-reports    { background: var(--b2l-muted); }
.b2l-tl-dot-clients,
.b2l-tl-dot-users      { background: var(--b2l-muted-2); }
.b2l-tl-dot-admin      { background: var(--b2l-amber); }
.b2l-tl-dot-billing    { background: var(--b2l-blue); }

/* Plan-locked feature cards: dimmed but still clickable — they lead to Billing. */
.b2l-report-card.is-locked { opacity: 0.6; }
.b2l-report-card.is-locked:hover { opacity: 0.8; }
/* Severity beats domain, matching activity_domain_badge. */
.b2l-tl-event.is-destructive .b2l-tl-dot { background: var(--b2l-danger); }

/* A job, not a person. Lighter than the ink-filled user avatar so a screenful of
   automatic events doesn't read as a screenful of people. */
.b2l-tl-avatar-system { background: var(--b2l-surface-3); color: var(--b2l-muted); flex: none; }
.b2l-tl-event > .b2l-avatar { flex: none; margin-top: 0.1rem; }

.b2l-tl-body { flex: 1; min-width: 0; }
.b2l-tl-summary { margin: 0; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700); line-height: 1.45; }
.b2l-tl-actor { color: var(--b2l-ink); font-weight: 600; }
.b2l-tl-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem;
  margin-top: 0.25rem; font-size: var(--b2l-fs-11); color: var(--b2l-muted);
}
.b2l-tl-client { display: inline-flex; align-items: center; gap: 0.25rem; }
/* The History link appears on hover/focus only — a hundred rows each advertising
   an action is exactly the noise this screen exists to avoid. focus-visible
   keeps it keyboard-reachable. */
.b2l-tl-link {
  display: inline-flex; align-items: center; gap: 0.25rem;
  color: var(--b2l-primary-700); font-weight: 600;
  opacity: 0; transition: opacity .12s;
}
.b2l-tl-event:hover .b2l-tl-link,
.b2l-tl-link:focus-visible { opacity: 1; }
.b2l-tl-link:hover { color: var(--b2l-primary-hover); }

.b2l-tl-time {
  flex: none; padding-top: 0.15rem; color: var(--b2l-muted);
  font-size: var(--b2l-fs-11); font-variant-numeric: tabular-nums; /* Inter, not mono */
}

/* The timeline reused inside the Dashboard's "Recent activity" card. The card is
   a third of the page rather than the full width, so the row padding tightens and
   the rail moves in to match. Same partial, same dots — only the gutter changes. */
.b2l-tl-events-compact { padding: 0.5rem 1.25rem 0.6rem; }
.b2l-tl-events-compact::before { left: calc(1.25rem + 3.5px); top: 1.1rem; bottom: 1.1rem; }
/* Narrow column: the timestamp column would squeeze the sentence, and show_date
   already puts the date in the meta row. */
.b2l-tl-events-compact .b2l-tl-time { display: none; }
/* No per-row History here. This card is a glance, not a workspace: five rows each
   offering a drill-down competes with the date and client already in the meta
   row, and "View all activity" below is the one action the card is asking for.
   The History affordance stays on the full timeline where there is room for it. */
.b2l-tl-events-compact .b2l-tl-link { display: none; }

/* Footer action on a card whose body is a list (Recent activity → View all). */
.b2l-card-foot { padding: 0.6rem 1.25rem 0.9rem; border-top: 1px solid var(--b2l-border-card); }

/* Domain chips. Real links, so the counts and the filtering both come from the
   server — see the partial's comment.

   The chip bar sits between the filter card and the feed card, and .b2l-card
   carries no margin of its own, so the separation has to come from here. It is
   deliberately asymmetric: a larger gap above pushes the chips away from the
   filter card they are NOT part of, and a smaller gap below keeps them visually
   attached to the feed they control. */
.b2l-tl-chipbar { margin: 1.25rem 0 0.75rem; }
.b2l-tl-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
a.b2l-chip:hover { border-color: var(--b2l-primary); color: var(--b2l-ink); }
a.b2l-chip.is-active {
  background: var(--b2l-primary-050); border-color: var(--b2l-primary-100); color: var(--b2l-primary-700);
}

/* Turbo sets aria-busy on the frame while a filter round-trips. Dim rather than
   blank, so the previous results stay readable and a fast filter doesn't flash. */
#activity_results[aria-busy="true"] { opacity: 0.55; transition: opacity .12s; }

@media (max-width: 575.98px) {
  .b2l-tl-events { padding-left: 1rem; padding-right: 1rem; }
  .b2l-tl-events::before { left: calc(1rem + 3.5px); }
  .b2l-tl-date { padding-left: 1rem; padding-right: 1rem; }
  .b2l-tl-time { display: none; } /* the day header still dates the row */
}

/* ---------------------------------------------------------- firm toggle */
.b2l-toggle { display: inline-flex; background: #eef2f6; border-radius: var(--b2l-radius); padding: 0.25rem; gap: 0.25rem; }
.b2l-toggle button, .b2l-toggle a { display: inline-flex; align-items: center; gap: 0.4rem; border: 0; background: transparent; color: var(--b2l-muted); font-weight: 600; font-size: var(--b2l-fs-13); padding: 0.4rem 0.8rem; border-radius: 0.4rem; cursor: pointer; }
.b2l-toggle button.active, .b2l-toggle a.active { background: var(--b2l-ink); color: #fff; }
.b2l-toggle .b2l-toggle-count { opacity: 0.8; font-weight: 700; }

/* ---------------------------------------------------------- group rows */
.b2l-group-row td { background: var(--b2l-surface-2); font-weight: 600; }
.b2l-group-asset    { color: var(--b2l-blue); }
.b2l-group-liability{ color: var(--b2l-rose); }
.b2l-group-income   { color: var(--b2l-primary-700); }
.b2l-group-expense  { color: #c2410c; }
.b2l-group-equity   { color: #7c3aed; }

/* ------------------------------------------------ chart-of-accounts accordion */
.b2l-coa-tree { padding: 0.4rem 0.4rem 0.6rem; }
.b2l-acc-type + .b2l-acc-type { border-top: 1px solid var(--b2l-border-card); }
.b2l-acc-type-head, .b2l-acc-sub-head {
  width: 100%; display: flex; align-items: center; gap: 0.5rem; border: 0; background: none;
  cursor: pointer; text-align: left; padding: 0.7rem 0.6rem; border-radius: var(--b2l-radius);
}
.b2l-acc-type-head:hover, .b2l-acc-sub-head:hover { background: var(--b2l-surface-2); }
.b2l-acc-type-name { font-weight: 700; font-size: var(--b2l-fs-14); }
.b2l-acc-sub-head { padding-left: 1.6rem; }
.b2l-acc-sub-name { font-weight: 600; font-size: var(--b2l-fs-13); color: var(--b2l-ink-700); }
.b2l-acc-count {
  font-weight: 600; font-size: var(--b2l-fs-11); background: var(--b2l-surface-2);
  border-radius: 999px; padding: 0.05rem 0.5rem;
}
.b2l-acc-chev { color: var(--b2l-muted-2); transition: transform 0.15s ease; }
.is-collapsed > .b2l-acc-type-head .b2l-acc-chev,
.is-collapsed > .b2l-acc-sub-head .b2l-acc-chev { transform: rotate(-90deg); }
.b2l-acc-empty { padding: 0.4rem 1rem 0.6rem 2.6rem; font-size: var(--b2l-fs-12); }
.b2l-acc-card {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.55rem 0.75rem 0.55rem 2.6rem; border-radius: var(--b2l-radius);
}
.b2l-acc-card:hover { background: var(--b2l-surface-2); }
.b2l-acc-card-title { display: flex; align-items: center; gap: 0.5rem; }
.b2l-acc-meta { font-size: var(--b2l-fs-12); margin-top: 0.15rem; }
.b2l-acc-card-side { display: flex; align-items: center; gap: 0.9rem; flex: none; }
.b2l-acc-bal { min-width: 90px; text-align: right; font-size: var(--b2l-fs-13); }
/* filter card + new-subtype row (shared layout) */
.b2l-coa-filters { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; }
.b2l-coa-filters .b2l-field { margin: 0; flex: 1; min-width: 160px; }
.b2l-filter-search { flex: 2 1 240px !important; }
.b2l-filter-actions { display: flex; gap: 0.5rem; align-items: center; }

/* full-screen subtype rows */
.b2l-sub-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0.6rem; border-radius: var(--b2l-radius); }
.b2l-sub-row:hover { background: var(--b2l-surface-2); }
.b2l-sub-rename { display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 0; }
.b2l-sub-rename .b2l-inp { flex: 1; min-width: 0; }
.b2l-sub-count { font-size: var(--b2l-fs-12); flex: none; white-space: nowrap; }
/* icon-only action buttons (table rows) — pair with title + aria-label in markup */
/* Icons. The server renders <i data-icon="name" class="b2l-icon">; lucide swaps
   it for an <svg> carrying the same class and size. The placeholder has to hold
   the icon's box, or every icon shifts the layout as it hydrates. */
i.b2l-icon { display: inline-block; flex: none; }

.b2l-icon-btn { border: 0; background: none; color: var(--b2l-muted-2); cursor: pointer; min-width: 30px; min-height: 30px; border-radius: 0.35rem; display: inline-grid; place-items: center; }
.b2l-icon-btn:hover { color: var(--b2l-ink); background: var(--b2l-surface-2); }
.b2l-icon-btn:focus-visible { outline: 2px solid var(--b2l-primary); outline-offset: 1px; color: var(--b2l-ink); }
.b2l-icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.b2l-icon-btn:disabled:hover { color: var(--b2l-muted-2); background: none; }

/* Per-row actions: icon + label, always visible. An icon alone reads as a
   puzzle on a row of money; the word says what the button does. */
.b2l-row-actions { white-space: nowrap; text-align: right; }
.b2l-th-actions { text-align: center; }
.b2l-row-action {
  display: inline-flex; align-items: center; gap: 0.35rem;
  border: 0; background: none; cursor: pointer; color: var(--b2l-muted);
  padding: 0.3rem 0.5rem; border-radius: 0.35rem;
  font-size: var(--b2l-fs-12); font-weight: 600; line-height: 1;
  transition: color .12s, background-color .12s;
}
.b2l-row-action + .b2l-row-action { margin-left: 0.15rem; }
.b2l-row-action:hover { color: var(--b2l-ink); background: var(--b2l-surface-2); }
.b2l-row-action:focus-visible { outline: 2px solid var(--b2l-primary); outline-offset: 1px; color: var(--b2l-ink); }
.b2l-row-action:disabled { opacity: 0.45; cursor: not-allowed; }
.b2l-row-action:disabled:hover { color: var(--b2l-muted); background: none; }
.b2l-row-action-primary { color: var(--b2l-primary); }
.b2l-row-action-primary:hover { color: #fff; background: var(--b2l-primary); }
.b2l-row-action-danger:hover { color: var(--b2l-danger); background: var(--b2l-rose-050, #fff1f2); }

tr.is-editing > td { background: var(--b2l-surface-2); }

/* Loading spinner for the import loading screen. Bootstrap's .spinner-border owns
   the animation (and its own reduced-motion handling); this only sizes and tints
   it, via the custom properties Bootstrap exposes. It draws the ring from
   `currentColor`, so `color` is what sets it. Pair the two classes:
   <div class="spinner-border b2l-spinner" role="status"> */
.b2l-spinner {
  --bs-spinner-width: 2.25rem;
  --bs-spinner-height: 2.25rem;
  --bs-spinner-border-width: 3px;
  color: var(--b2l-primary);
}

/* Bulk-action bar: revealed by the review controller once rows are selected
   (it toggles the `hidden` attribute). Sticky to the bottom of the viewport so
   it stays in reach on a long statement. */
.b2l-bulk-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap;
  padding: 0.75rem 1.25rem;
  background: var(--b2l-surface); border-top: 1px solid var(--b2l-border);
  box-shadow: 0 -6px 16px -12px rgba(15, 23, 42, 0.4);
}
.b2l-bulk-summary { font-size: var(--b2l-fs-13); color: var(--b2l-muted); }
.b2l-bulk-summary strong { color: var(--b2l-ink); }
.b2l-bulk-summary .b2l-sep { margin: 0 0.5rem; color: var(--b2l-border); }

/* --------------------------------------------------------------- forms */
.b2l-label { display: block; font-size: var(--b2l-fs-13); font-weight: 600; color: var(--b2l-ink-700); margin-bottom: 0.4rem; }
.b2l-input {
  width: 100%; background: #eef2f9; border: 1px solid transparent; border-radius: var(--b2l-radius);
  padding: 0.7rem 0.9rem; font-size: var(--b2l-fs-14); color: var(--b2l-ink);
}
.b2l-input:focus { outline: none; border-color: var(--b2l-primary); background: #fff; box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.12); }
.b2l-field { margin-bottom: 1.1rem; }
.b2l-link { color: var(--b2l-primary-700); font-weight: 600; }
.b2l-link-dark { color: var(--b2l-ink); font-weight: 600; }

/* form error summary (Devise) */
.b2l-form-errors {
  background: var(--b2l-rose-050); border: 1px solid #fecdd3; color: var(--b2l-rose);
  border-radius: var(--b2l-radius); padding: 0.75rem 0.9rem; margin-bottom: 1.1rem;
  font-size: var(--b2l-fs-13);
}
.b2l-form-errors-title { display: flex; align-items: center; gap: 0.45rem; font-weight: 700; }
.b2l-form-errors ul { margin: 0.4rem 0 0; padding-left: 1.5rem; }
.b2l-form-errors li { margin-top: 0.15rem; }

/* danger zone (account settings) */
.b2l-danger-card { border-color: #fecdd3; }
.b2l-btn-danger-outline { background: #fff; color: var(--b2l-danger); border-color: #fecdd3; }
.b2l-btn-danger-outline:hover { background: var(--b2l-rose-050); color: var(--b2l-danger); }

/* terms checkbox (registration) */
.b2l-terms { display: flex; align-items: flex-start; gap: 0.5rem; font-size: var(--b2l-fs-13); color: var(--b2l-muted); margin: 0.25rem 0 1.1rem; }
.b2l-terms a { color: var(--b2l-ink-700); text-decoration: underline; }

/* ------------------------------------------------------------ auth page */
.b2l-auth {
  min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: radial-gradient(900px 480px at 50% -120px, #dcfce9 0%, rgba(220, 252, 233, 0) 70%), var(--b2l-bg);
  padding: 2rem 1rem;
}
.b2l-auth::before { content: ""; position: fixed; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, #22d3ee, #34d399); }
.b2l-auth-head { text-align: center; margin-bottom: 1.5rem; }
.b2l-auth-head h1 { font-size: 26px; font-weight: 700; margin: 0; }
.b2l-auth-head p { color: var(--b2l-muted); margin: 0.4rem 0 0; font-size: var(--b2l-fs-13); }
.b2l-auth-card { width: 100%; max-width: 560px; background: var(--b2l-surface); border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius-xl); box-shadow: var(--b2l-shadow); padding: 1.75rem; }
.b2l-auth-foot { text-align: center; margin-top: 1.1rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); }

/* sign-up benefit checklist (echoes the logo's green tick) */
.b2l-auth-perks { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 0.35rem 1.1rem; padding: 0; margin: -0.4rem 0 1.4rem; color: var(--b2l-muted); font-size: var(--b2l-fs-13); }
.b2l-auth-perks li { display: inline-flex; align-items: center; gap: 0.35rem; }
.b2l-auth-perks svg { color: var(--b2l-primary); flex: none; }

/* password show/hide */
.b2l-pass-wrap { position: relative; }
.b2l-pass-wrap .b2l-input { padding-right: 2.7rem; }
.b2l-pass-toggle { position: absolute; right: 0.55rem; top: 50%; transform: translateY(-50%); border: 0; background: none; color: var(--b2l-muted-2); cursor: pointer; padding: 0.25rem; border-radius: 0.35rem; display: inline-grid; place-items: center; }
.b2l-pass-toggle:hover { color: var(--b2l-ink); }
.b2l-pass-toggle:focus-visible { outline: 2px solid var(--b2l-primary); outline-offset: 1px; }
.b2l-pass-toggle span { display: inline-grid; place-items: center; }

/* ---------------------------------------------- flatpickr (b2l theme) */
.flatpickr-calendar {
  font-family: var(--b2l-font); font-size: var(--b2l-fs-13);
  border: 1px solid var(--b2l-border); border-radius: var(--b2l-radius-xl);
  box-shadow: var(--b2l-shadow); width: 308px; padding: 0.35rem 0.35rem 0.5rem;
}
.flatpickr-calendar.arrowTop::before, .flatpickr-calendar.arrowTop::after,
.flatpickr-calendar.arrowBottom::before, .flatpickr-calendar.arrowBottom::after { display: none; }

/* month header */
.flatpickr-months { margin-bottom: 0.25rem; }
.flatpickr-months .flatpickr-month { color: var(--b2l-ink); height: 34px; }
.flatpickr-current-month { font-size: var(--b2l-fs-14); font-weight: 700; padding-top: 5px; }
.flatpickr-current-month .numInputWrapper { font-weight: 700; }
.flatpickr-current-month input.cur-year { font-weight: 700; }
.flatpickr-months .flatpickr-prev-month, .flatpickr-months .flatpickr-next-month {
  height: 34px; padding: 7px 10px; color: var(--b2l-muted); fill: var(--b2l-muted); border-radius: var(--b2l-radius);
}
.flatpickr-months .flatpickr-prev-month:hover svg, .flatpickr-months .flatpickr-next-month:hover svg { fill: var(--b2l-primary-700); }

/* weekday row */
span.flatpickr-weekday { font-size: var(--b2l-fs-10); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--b2l-muted-2); }

/* days */
.flatpickr-day { color: var(--b2l-ink-700); font-size: var(--b2l-fs-13); border-radius: var(--b2l-radius); height: 36px; line-height: 36px; }
.flatpickr-day:hover, .flatpickr-day.prevMonthDay:hover, .flatpickr-day.nextMonthDay:hover {
  background: var(--b2l-primary-050); border-color: var(--b2l-primary-050); color: var(--b2l-primary-700);
}
.flatpickr-day.today { border-color: var(--b2l-primary); color: var(--b2l-primary-700); font-weight: 600; }
.flatpickr-day.today:hover, .flatpickr-day.today:focus { background: var(--b2l-primary-050); border-color: var(--b2l-primary); color: var(--b2l-primary-700); }
.flatpickr-day.selected, .flatpickr-day.startRange, .flatpickr-day.endRange,
.flatpickr-day.selected:hover, .flatpickr-day.startRange:hover, .flatpickr-day.endRange:hover,
.flatpickr-day.selected:focus, .flatpickr-day.startRange:focus, .flatpickr-day.endRange:focus {
  background: var(--b2l-primary); border-color: var(--b2l-primary); color: #fff; font-weight: 600;
}
.flatpickr-day.inRange {
  background: var(--b2l-primary-050); border-color: var(--b2l-primary-050); color: var(--b2l-primary-700);
  box-shadow: -5px 0 0 var(--b2l-primary-050), 5px 0 0 var(--b2l-primary-050);
}
.flatpickr-day.prevMonthDay, .flatpickr-day.nextMonthDay { color: var(--b2l-muted-2); }
.flatpickr-day.flatpickr-disabled, .flatpickr-day.flatpickr-disabled:hover { color: #d1d9e2; }

/* ------------------------------------------------- ledger report hub cards */
.b2l-report-card { display: flex; align-items: center; gap: 1rem; padding: 1.25rem 1.4rem; height: 100%; transition: border-color .12s, box-shadow .12s; }
.b2l-report-card:hover { border-color: var(--b2l-primary); box-shadow: var(--b2l-shadow); }
.b2l-report-icon { display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 0.75rem; background: var(--b2l-primary-050); color: var(--b2l-primary-700); flex: none; }
.b2l-report-main { flex: 1; min-width: 0; }
.b2l-report-title { display: block; font-weight: 700; font-size: var(--b2l-fs-15); color: var(--b2l-ink); }
.b2l-report-desc { display: block; color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin-top: 0.15rem; }
.b2l-report-arrow { color: var(--b2l-muted-2); flex: none; transition: transform .12s, color .12s; }
.b2l-report-card:hover .b2l-report-arrow { color: var(--b2l-primary-700); transform: translateX(2px); }
/* A report-card rendered as a <button> (a button_to POST action, e.g. the async Excel
   export): strip native button chrome so it matches the <a> cards exactly. */
button.b2l-report-card { width: 100%; text-align: left; font: inherit; color: inherit;
  appearance: none; -webkit-appearance: none; cursor: pointer; }

/* ------------- ledger reports (QuickBooks / Xero / Sage-style, printable) */
.b2l-report-head { text-align: center; padding: 1.4rem 1rem 1.2rem; border-bottom: 1px solid var(--b2l-border); }
.b2l-report-company { font-size: var(--b2l-fs-18); font-weight: 700; color: var(--b2l-ink); }
.b2l-report-name { font-size: var(--b2l-fs-15); font-weight: 600; color: var(--b2l-ink-700); margin-top: 0.15rem; }
.b2l-report-meta { font-size: var(--b2l-fs-13); color: var(--b2l-muted); margin-top: 0.25rem; }

.b2l-gl { min-width: 820px; }
/* account section header row (grouping) — clickable to collapse */
.b2l-gl-acct td { background: var(--b2l-surface-2); font-weight: 700; color: var(--b2l-ink); border-top: 1px solid var(--b2l-border); cursor: pointer; user-select: none; }
.b2l-gl-acct:hover td { background: #eef2f6; }
.b2l-gl-acct-type { font-weight: 500; color: var(--b2l-muted); }
.b2l-gl-chev { color: var(--b2l-muted-2); transition: transform 0.15s ease; vertical-align: middle; margin-right: 0.4rem; }
/* collapsed: keep only the account header row (with its closing balance) */
tbody.is-collapsed > tr:not(.b2l-gl-acct) { display: none; }
tbody.is-collapsed .b2l-gl-chev { transform: rotate(-90deg); }
/* brought-forward opening balance */
.b2l-gl-begin td { color: var(--b2l-muted); font-style: italic; }
/* per-account subtotal */
.b2l-gl-total td { font-weight: 600; color: var(--b2l-ink); background: var(--b2l-surface); border-top: 1px solid var(--b2l-border); border-bottom: 2px solid var(--b2l-border); }
/* report grand total */
.b2l-gl-grand td { font-weight: 700; background: var(--b2l-primary-050); color: var(--b2l-primary-700); border-bottom: 0; }

/* keep the report clean on paper: drop app chrome, print just the report card */
@media print {
  .b2l-topbar, .b2l-tabs, .b2l-crumbs, .b2l-filter-card, .b2l-toasts, #mini-profiler-globals, .b2l-h1 + .b2l-sub { display: none !important; }
  .b2l-card { border: 0 !important; box-shadow: none !important; }
  .b2l-table tbody tr:hover td { background: transparent; }
}

/* ---------------------------------------------------------- empty states */
.b2l-empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 2.5rem 1.5rem; }
.b2l-empty-icon { display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 0.75rem; background: var(--b2l-primary-050); color: var(--b2l-primary-700); }
.b2l-empty-title { font-weight: 700; font-size: var(--b2l-fs-15); color: var(--b2l-ink); margin-top: 0.75rem; }
.b2l-empty-msg { color: var(--b2l-muted); font-size: var(--b2l-fs-13); margin: 0.25rem 0 0; max-width: 380px; }
.b2l-empty .b2l-btn { margin-top: 1rem; }

/* --------------------------------------------------------------- utils */
.b2l-flex { display: flex; align-items: center; }
.b2l-between { display: flex; align-items: center; justify-content: space-between; }
.b2l-gap-sm { gap: 0.5rem; } .b2l-gap { gap: 1rem; }
.b2l-mt { margin-top: 1.5rem; } .b2l-mt-lg { margin-top: 2rem; }
.b2l-ml-auto { margin-left: auto; }

/* wide tables scroll inside their card (cards clip with overflow:hidden) */
.b2l-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.b2l-table-scroll > .b2l-table { min-width: 640px; }

/* The twin of the scrollbar a .b2l-table-scroll already has, sitting above the
   table instead of below it — built and kept in step by table_scrollers_controller.
   Its only child is a spacer stretched to the table's width; there is nothing to
   see in the strip itself, so it stays as short as a scrollbar can be drawn.
   scrollbar-width: thin keeps Firefox from reserving a full-height gutter. */
.b2l-table-topscroll { overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.b2l-table-topscroll > div { height: 1px; }
.b2l-table-topscroll[hidden] { display: none; }

/* Categorised / Excluded tables behave like a data grid: a bounded scroll WINDOW, so a long
   page (up to PER_PAGE = 100 rows) scrolls vertically inside it — with the header pinned to the
   top — while the info scrolls sideways under the Actions column, pinned to the right. Bounding
   the height is the point: it keeps the horizontal scrollbar on screen instead of stranding it
   5,000px below, at the foot of 100 rows. The pinned cells are opaque with a soft edge shadow so
   scrolled content passes cleanly beneath them; the top-right corner (Actions header) sits above
   both freezes. */
.b2l-pin-actions { max-height: min(34rem, 60vh); overflow: auto; }
.b2l-pin-actions .b2l-table thead th,
.b2l-pin-actions .b2l-table tbody td { white-space: nowrap; }
.b2l-pin-actions .b2l-table thead th { position: sticky; top: 0; z-index: 3; }
.b2l-pin-actions .b2l-table thead th.b2l-th-actions,
.b2l-pin-actions .b2l-table td.b2l-row-actions {
  position: sticky; right: 0;
  box-shadow: -8px 0 8px -8px rgba(2, 6, 23, 0.18);
}
.b2l-pin-actions .b2l-table td.b2l-row-actions { z-index: 2; background: var(--b2l-surface); }
.b2l-pin-actions .b2l-table thead th.b2l-th-actions { z-index: 4; background: var(--b2l-surface-2); }
.b2l-pin-actions .b2l-table tbody tr:hover td.b2l-row-actions { background: var(--b2l-surface-2); }

/* filter rows wrap instead of overflowing on narrow screens */
.b2l-filter-row { flex-wrap: wrap; }
.b2l-filter-row > * { min-width: 0; }

/* The Categorise filter bar, inside the panel card below the tab strip. A tinted band that reads as
   part of the card, set off from the tab bar above and the table below. */
.b2l-categorise-filters { padding: 0.85rem 1.25rem; background: var(--b2l-surface-2); border-bottom: 1px solid var(--b2l-border); }

/* ---------------------------------------------------------- responsive */
@media (max-width: 991.98px) {
  .b2l-kpis { grid-template-columns: repeat(2, 1fr); }
  .b2l-plans { grid-template-columns: repeat(2, 1fr); }
  .b2l-stats { grid-template-columns: repeat(2, 1fr); }
  .b2l-stat { border-bottom: 1px solid var(--b2l-border-card); }
  .b2l-stat:nth-child(even) { border-right: 0; }
  .b2l-stat:last-child { border-bottom: 0; }
  .b2l-coa { flex-direction: column; }
  .b2l-coa-panel { width: 100%; }
}

@media (max-width: 575.98px) {
  .b2l-topbar { gap: 0.6rem; padding: 0 1rem; }
  .b2l-topbar-divider { display: none; }
  .b2l-brand-name { display: none; }             /* logo stays; text yields space to the client pill */
  .b2l-firm { display: none; }                   /* same reason; the user menu still shows it here */
  .b2l-user > span:not(.b2l-avatar) { display: none; }
  .b2l-tabs { padding: 0 1rem; }
  .b2l-tabs-scroll { gap: 1.1rem; }  /* the gap moved with the links */
  .b2l-page { padding: 1.25rem 1rem 2.5rem; }
  .b2l-kpis { grid-template-columns: 1fr; }
  .b2l-plans { grid-template-columns: 1fr; }
  .b2l-stats { grid-template-columns: 1fr; }
  .b2l-stat { border-right: 0; }
  .b2l-banner { flex-direction: column; align-items: flex-start; }
  .b2l-steps { overflow-x: auto; padding-bottom: 0.25rem; }
}

/* "+ New bank account" inside a select2 dropdown (statements/_bank_account_picker).
   Reads as an action, not a value: accent colour, medium weight, and a rule above it so it
   sits apart from the accounts it is listed with. */
.b2l-select2-add-new {
  display: flex;
  align-items: center;
  gap: .4rem;
  color: var(--b2l-primary);
  font-weight: 500;
}
.b2l-select2-add-new-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05rem;
  height: 1.05rem;
  border-radius: var(--b2l-radius-full);
  background: var(--b2l-primary);
  color: #fff;
  font-size: var(--b2l-fs-12);
  line-height: 1;
}
/* It sits first, under the prompt — so the rule goes underneath it, separating the action
   from the accounts it is listed above. */
.select2-results__option:has(.b2l-select2-add-new) {
  border-bottom: 1px solid var(--b2l-border);
}

/* ---------------------------------------------- admin: Stripe-owned plan card
 *
 * Replaces the assign-plan form on a firm whose subscription Stripe writes
 * (ADR 0010). Reads as a quotation from another system rather than a disabled
 * version of our own control: banded ground, no inputs, and the ids in mono so
 * they can be matched against the Stripe dashboard by eye. */
.b2l-stripe-panel {
  margin-top: 0.85rem; padding: 0.9rem 1rem;
  background: var(--b2l-band); border: 1px solid var(--b2l-border-card);
  border-radius: var(--b2l-radius);
}
/* Label/value pairs, not a table — two rows, and a table would out-weigh them. */
.b2l-stripe-ids {
  display: grid; grid-template-columns: auto 1fr; gap: 0.2rem 0.75rem;
  margin: 0.6rem 0 0; font-size: var(--b2l-fs-12);
}
.b2l-stripe-ids dt { color: var(--b2l-muted); }
.b2l-stripe-ids dd {
  margin: 0; font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  color: var(--b2l-ink); overflow-wrap: anywhere;
}

/* Platform vitals on the admin dashboard. Wraps into as many columns as fit
   rather than a fixed grid: the table-count rows are generated from a hash, so
   the number of pairs is not fixed at design time. */
.b2l-vitals { display: flex; flex-wrap: wrap; gap: 0.75rem 2.5rem; margin: 0; font-size: var(--b2l-fs-13); }
.b2l-vitals dt { color: var(--b2l-muted); font-weight: 500; }
.b2l-vitals dd { margin: 0; color: var(--b2l-ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ------------------------------------------- admin: firm statement health
 *
 * Deliberately NOT .b2l-kpis. The strip above a firm's detail page is scale
 * (members, clients, statements); this is exceptions. Rendering both as tiles
 * gave four permanent zeros the same weight as the numbers that matter, so this
 * lists only what is wrong and collapses to one line when nothing is. */
.b2l-health { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.85rem; }
.b2l-health li { display: flex; align-items: flex-start; gap: 0.75rem; }
/* The count leads: an operator scans the numbers, then reads why. */
.b2l-health-num {
  flex: none; min-width: 2rem; height: 1.75rem; padding: 0 0.4rem;
  display: inline-grid; place-items: center; border-radius: var(--b2l-radius);
  font-weight: 700; font-variant-numeric: tabular-nums; font-size: var(--b2l-fs-13);
  background: var(--b2l-band); color: var(--b2l-ink);
}
.b2l-health li.is-amber .b2l-health-num { background: #fff7ed; color: var(--b2l-amber); }
.b2l-health li.is-rose  .b2l-health-num { background: #fff1f2; color: var(--b2l-rose); }
.b2l-health-label { font-weight: 600; font-size: var(--b2l-fs-13); color: var(--b2l-ink); }
.b2l-health-note { color: var(--b2l-muted); font-size: var(--b2l-fs-12); margin-top: 0.1rem; }
/* The healthy state is a full sentence, not an empty card. */
.b2l-health-clear {
  display: flex; align-items: center; gap: 0.5rem; margin: 0;
  color: var(--b2l-success); font-weight: 600; font-size: var(--b2l-fs-13);
}
/* Always-on context that is never an alert: counts an operator wants nearby but
   which are not problems, so they sit quiet and below the rule. */
.b2l-health-foot {
  margin: 0.9rem 0 0; padding-top: 0.75rem; border-top: 1px solid var(--b2l-border-card);
  color: var(--b2l-muted); font-size: var(--b2l-fs-12);
}

/* Date ranges and other pairs that must not break mid-value in a table cell. */
.b2l-nowrap { white-space: nowrap; }
