/* ==========================================================================
   SF Books — white-label skin for the self-hosted Bigcapital instance
   at acct.sf-listing-mirror.us.

   Injected by nginx sub_filter before </head>. Nothing here is a fork: no
   container is rebuilt and no file inside Bigcapital is patched, so
   `docker compose pull` cannot wipe it.

   Palette sampled directly from the Southern Fabric Accounting artwork
   rather than guessed:
       green  #0C372E   the S of the monogram, and the wordmark
       gold   #B28842   the F of the monogram, and the ACCOUNTING rule
   The sister mark, Southern Fabric Listing Mirror, is navy #06294E with a
   lighter gold #D2A865 — deliberately a different colourway, so the ledger
   and the operational app are never mistaken for one another at a glance.
   ========================================================================== */

:root {
  --sfb-green: #0C372E;
  --sfb-green-soft: #1C5343;
  --sfb-gold: #B28842;
  --sfb-gold-dark: #96702F;
  --sfb-cream: #F7F6F3;
  --sfb-ink: #22312C;
}

/* --------------------------------------------------------------------------
   1. The logo.

   Bigcapital renders its mark as a Blueprint icon span containing an inline
   SVG with hardcoded width/height. The SVG cannot be replaced from CSS, so it
   is zeroed out and our artwork painted into the same span via ::after — the
   approach flip-tracker arrived at for the same problem.
   -------------------------------------------------------------------------- */
.bp4-icon-bigcapital,
.bp4-icon-mini-bigcapital {
  position: relative !important;
  display: inline-block !important;
}

.bp4-icon-bigcapital > svg,
.bp4-icon-mini-bigcapital > svg,
svg[data-icon="bigcapital-alt"] {
  opacity: 0 !important;
}

.bp4-icon-bigcapital::after,
.bp4-icon-mini-bigcapital::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("/sfbooks/sf-accounting-mark.png") center / contain no-repeat;
}

/* --------------------------------------------------------------------------
   2. Login / signup.

   `body.authentication` is upstream's own class on the auth routes, so this
   whole block is inert everywhere else.
   -------------------------------------------------------------------------- */
body.authentication {
  background: var(--sfb-cream) !important;
}

/* The login splash gets the FULL lockup — monogram plus the "Southern Fabric
   Accounting" wordmark. The bare monogram is for the sidebar and the favicon,
   where a wordmark would be illegible. */
body.authentication::before {
  content: "";
  display: block;
  width: 300px;
  height: 259px;
  margin: 32px auto 0;
  background: url("/sfbooks/sf-accounting-logo.png") center / contain no-repeat;
}

/* The lockup above carries the identity, so upstream's own mark in the
   column would be a second logo. */
body.authentication .bp4-icon-bigcapital { display: none !important; }

body.authentication div:has(> form) {
  background: #FFFFFF !important;
  border: 1px solid #DDD8CF !important;
  border-radius: 10px !important;
  box-shadow: 0 2px 14px rgba(58, 54, 48, .09) !important;
}

/* --------------------------------------------------------------------------
   3. Accents. Upstream's blue becomes the medallion gold.
   -------------------------------------------------------------------------- */
.bp4-button.bp4-intent-primary,
.bp4-button.bp4-intent-primary:hover {
  background: var(--sfb-gold) !important;
  color: #FFFFFF !important;
  border: none !important;
}

.bp4-button.bp4-intent-primary:active {
  background: var(--sfb-gold-dark) !important;
}

/* NO BLANKET LINK COLOUR.
 *
 * The first cut had `a { color: var(--sfb-green) !important }`, which painted
 * EVERY link dark green — including the sidebar navigation, which sits on dark
 * navy. Dark green on dark navy is invisible, and it made the entire nav
 * unreadable while looking perfectly fine in the content area where it was
 * being judged.
 *
 * Upstream's own link colours are legible everywhere. Branding is applied only
 * where the context is known: our own dashboard cards, and the selected tab. */
.bp4-tab[aria-selected="true"] { color: var(--sfb-green) !important; }

/* Sidebar navigation stays legible against its dark ground.
 *
 * SCOPED TO THE REAL CONTAINER, NOT TO `nav`/`aside`/`.bp4-menu`.
 * Corrected twice on 2026-09-09, and the two mistakes are the same mistake:
 *
 *   1. `nav a, aside a { color:#C9D6E4 }` — correct on the navy rail, but
 *      Bigcapital renders its flyout submenu inside `nav` on a WHITE popover.
 *      Measured: #C9D6E4 on #FFFFFF is 1.48:1 against WCAG AA's 4.5:1. Every
 *      flyout item was invisible.
 *   2. The first repair added `.bp4-menu .bp4-menu-item { color:#1C2B3A }` to
 *      darken the flyout — but the SIDEBAR is itself `ul.bp4-menu.sidebar-menu`
 *      and its items are `a.bp4-menu-item`, so that painted the rail dark ink
 *      on navy: 1.17:1. Worse than the bug it fixed.
 *
 * Both times the selector was written from the context being looked at and
 * applied to a context nobody measured. The DOM says the discriminator is the
 * CONTAINER, not the element class:
 *
 *     div.sidebar__inner > ... > ul.bp4-menu.sidebar-menu > li > a.bp4-menu-item
 *
 * So: colour only inside `.sidebar__inner`. Everything else — the flyout,
 * dropdowns, popovers anywhere — keeps upstream's own colours, which were
 * legible before we touched them. We add no rule for the flyout at all; the
 * bug was ever having matched it.
 *
 * If a nav item reads wrong again, measure the computed colour against its real
 * background first. Do not add another !important. */
.sidebar__inner a,
.sidebar__inner .bp4-menu-item,
.sidebar-menu > li > a {
  color: #C9D6E4 !important;
}
.sidebar__inner a:hover,
.sidebar__inner .bp4-menu-item:hover,
.sidebar-menu > li > a:hover {
  color: #FFFFFF !important;
}

/* The nav is pinned open, so the control that collapses it is hidden.
 *
 * `sf-dashboard.js` re-expands the sidebar whenever it finds it mini, which
 * would make the hamburger look broken — press it and it springs back. The
 * honest thing is not to offer it. The script stamps `data-sf-nav-pinned` on
 * <html> and takes it off again on /preferences, which collapses the nav on
 * purpose to make room for its own settings sidebar; there the hamburger is
 * real and stays visible.
 *
 * VISIBILITY, NOT DISPLAY. `display:none` collapsed the button's 44px box and
 * the page title went flush against the navy rail — `Vendors List` began two
 * pixels off the sidebar. Hiding it with `visibility` keeps upstream's own
 * gutter, so the title still starts at 268px and lines up with `Table Views`
 * in the toolbar below it. The gap is the button's own box, which is why no
 * padding is invented here and nothing has to be re-tuned if upstream resizes
 * its topbar.
 *
 * Neither `display:none` nor `visibility:hidden` stops `HTMLElement.click()`,
 * which is how the script still drives the app's own toggle action rather
 * than restyling the pane. Both also take the button out of the tab order and
 * out of hit-testing, so there is nothing to press by accident. */
html[data-sf-nav-pinned] .dashboard__topbar-sidebar-toggle { visibility: hidden !important; }

/* Nav entries `sf-dashboard.js` has trimmed — Items, and the customer half of
 * Contacts and Quick new. The script matches them by label text, which CSS
 * cannot do, so it marks them and this hides them. `display`, not
 * `visibility`: these are whole rows, and an invisible one would leave a hole
 * in the list. Nothing is deleted — /items and /customers still answer. */
.sf-nav-trimmed { display: none !important; }

/* --------------------------------------------------------------------------
   4. Residual upstream wordmarks in text nodes CSS cannot reach are left
      alone deliberately. Rewriting them would mean either forking the bundle
      or a MutationObserver rewriting the DOM on every render — both cost more
      than they are worth for a two-person tool. The tab title, favicon, login
      page and sidebar are what people actually see.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   5. The dashboard injected by sf-dashboard.js.

   Upstream's homepage is a directory of fifteen features, eight of which are
   dead here — 0 customers, 0 sale invoices, 0 expenses, 1 item. The three
   cards below are the questions actually asked of these books.
   -------------------------------------------------------------------------- */
#sf-dash { margin: 0 0 28px; }

.sf-dash-grid {
  display: grid;
  gap: 16px;
  /* Exactly three columns on a wide screen. auto-fit with a 272px minimum
     made four tracks and left one empty, so the cards huddled at the left
     while the banner spanned the full width. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 1100px) {
  .sf-dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .sf-dash-grid { grid-template-columns: 1fr; }
}

.sf-card {
  background: #FFFFFF;
  border: 1px solid #E3DFD7;
  border-top: 3px solid var(--sfb-green);
  border-radius: 8px;
  padding: 16px 18px 12px;
  box-shadow: 0 1px 3px rgba(34, 49, 44, .06);
}

.sf-card-t {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--sfb-green);
  margin-bottom: 10px;
}

.sf-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 5px 0;
  font-size: 13.5px;
  color: var(--sfb-ink);
}
.sf-row span { opacity: .78; }
/* Tabular figures so the decimal points line up down the column — the whole
   point of a money list. */
.sf-row b {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}
.sf-row i { font-style: normal; opacity: .55; font-size: 12px; }

.sf-row.sf-total {
  border-top: 1px solid #EAE6DE;
  margin-top: 6px;
  padding-top: 9px;
}
.sf-row.sf-total span { opacity: 1; font-weight: 600; }
.sf-row.sf-total b { color: var(--sfb-green); }

.sf-card-f {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid #F0EDE7;
  font-size: 12px;
}
.sf-card-f a { color: var(--sfb-gold-dark) !important; text-decoration: none; }
.sf-card-f a:hover { text-decoration: underline; }

.sf-none { font-size: 13px; opacity: .6; padding: 6px 0 2px; }
.sf-dash-loading { font-size: 13px; opacity: .5; padding: 8px 0 20px; }

/* An unreachable ledger must never render as zero. */
.sf-dash-err {
  background: #FDF6E7;
  border: 1px solid var(--sfb-gold);
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 13px;
  color: #6B4E12;
}

/* Sections that will always read zero on these books. */
[data-sf-dead] { display: none !important; }
[data-sf-dead] + div { display: none !important; }

/* The completeness banner. Deliberately loud: a ledger three months behind
   rendering as "cash on hand" is the failure this whole dashboard could
   otherwise cause. */
.sf-stale {
  grid-column: 1 / -1;
  background: #FDF6E7;
  border: 1px solid var(--sfb-gold);
  border-left: 4px solid var(--sfb-gold);
  border-radius: 6px;
  padding: 10px 14px;
  margin-bottom: 4px;
  font-size: 13px;
  color: #6B4E12;
}
.sf-stale b { font-variant-numeric: tabular-nums; }

/* A real account reading zero is dimmed, not hidden — the reader should see
   that it is zero, and wonder why. */
.sf-row.sf-zero span,
.sf-row.sf-zero b { opacity: .38; }

/* Due dates sit inline after the vendor, quiet by default. */
.sf-row i.sf-od { color: #A4442E; opacity: .9; }
.sf-row.sf-overdue b { color: #A4442E; }

/* -- "What we owe", grouped by vendor -------------------------------------
   A flat list of 27 bills made this card three times the height of its
   neighbours and repeated the same vendor name eleven times. The vendor is
   now a heading carrying its own subtotal, and the bills beneath it carry
   only a date. */
.sf-row.sf-vendor {
  margin-top: 12px;
  padding-bottom: 3px;
  border-bottom: 1px solid #EFEBE3;
}
.sf-dash-vendors > .sf-row.sf-vendor:first-child { margin-top: 0; }
.sf-row.sf-vendor span { opacity: 1; font-weight: 600; }
.sf-row.sf-vendor b { color: var(--sfb-ink); }

.sf-row.sf-bill { padding: 3px 0 3px 12px; font-size: 13px; }
.sf-row.sf-bill span { opacity: .6; font-variant-numeric: tabular-nums; }

/* Due today or earlier: the WHOLE row reads red, not just the date. The
   amount is the thing being scanned for, so colouring only the date left the
   urgent number looking exactly like the rest. */
.sf-row.sf-bill.sf-overdue span,
.sf-row.sf-bill.sf-overdue b { color: #A4442E; opacity: 1; }

/* A vendor with anything due carries the mark on its subtotal too, so the
   card reads at a glance without scanning every line under every vendor. */
.sf-row.sf-vendor.sf-vendor-od b { color: #A4442E; }

/* No due date is a DATA problem, not a money problem — the bill cannot be
   aged, so it is amber and named in the footer rather than painted red as
   though we knew it were late. */
.sf-row.sf-bill.sf-nodate span { color: var(--sfb-gold-dark); opacity: .95; }
.sf-card-f .sf-warn { color: #A4442E; }

/* ── Account Transactions: what each row actually was ───────────────────────
 *
 * The register's cells carry only an opaque SF-#### / CF-#####. These add the
 * description and the other side of the entry.
 *
 * ONE LINE ONLY. The table absolutely-positions every row at a fixed 32px and
 * computes each row's `top` itself, so a second line does not grow the row --
 * it overlaps the next one. Each addition therefore rides on the RIGHT of a
 * cell that has room, pushed over by margin-left:auto, and truncates rather
 * than wraps.
 *
 * The `.td` is a flex row, so the existing .cell-inner must be told not to
 * stretch and the addition must be allowed to shrink -- min-width:0 is what
 * lets text-overflow work inside a flex item at all.
 */
.bigcapital-datatable .tbody .td.transaction_number > .cell-inner,
.bigcapital-datatable .tbody .td.reference_number > .cell-inner {
  flex: 0 0 auto;
}

.sf-tx-desc,
.sf-tx-cat {
  flex: 1 1 auto;
  min-width: 0;
  margin-left: auto;
  padding-left: 10px;
  text-align: right;
  font-size: 11.5px;
  line-height: 32px;            /* match the fixed row height */
  font-weight: 400;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--color-text-muted, #7a8896);
}

/* The category is the one worth catching from across the room: it is what makes
 * a misposting -- stock expensed to Uncategorized Expense -- visible without
 * opening anything. */
.sf-tx-cat {
  color: var(--color-accent-green, #0C372E);
  font-weight: 500;
}

/* ── Account Transactions: give each column the width its content needs ─────
 *
 * Upstream sizes this table for its own demo data, and the result overflowed:
 * measured at 1920px the nine columns wanted 1784px of a 1785px viewport, so
 * anything narrower pushed WITHDRAWAL and RUNNING BALANCE off the right edge --
 * the two columns someone opens a register to read. Meanwhile DATE held 171px
 * for "09/08/2026" and STATUS 231px for a 70px pill.
 *
 * The widths come from react-table as INLINE styles -- `flex: 140 0 auto;
 * width: 140px` -- so they need `!important` to move. flex-shrink is 0, which
 * is why the table overflowed rather than compressing: the numbers below are a
 * real minimum, not a hint. They total 1160px against the 1784px upstream
 * wanted, so the register now fits a 1280px laptop.
 *
 * The flex-GROW value is kept equal to the width, which is upstream's own
 * convention here: columns then share any extra space in proportion to their
 * size, so a wide screen still fills edge to edge and the proportions hold at
 * every width.
 *
 * SCOPED TO THE PAGE, on purpose. `.td-status` and the unclassed status header
 * `.th[class="th"]` are generic enough to hit other tables in the app;
 * `.dashboard__insider--account-transactions` is the route's own class and
 * keeps this off every other datatable.
 */
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.date,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.date
  { flex: 95 0 auto !important; width: 95px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.type,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.type
  { flex: 115 0 auto !important; width: 115px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.transaction_number,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.transaction_number
  { flex: 195 0 auto !important; width: 195px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.reference_number,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.reference_number
  { flex: 170 0 auto !important; width: 170px !important; }
/* The contact column sf-dashboard.js injects. It is sized here rather than only
   inline so it obeys the same rule as its neighbours -- flex-grow equal to the
   width, so it takes its share of a wide screen and holds 120px on a narrow one.
   120 fits "Southern Fabric"; 21 counterparties were measured and none is wider.

   IT COST THE TABLE NOTHING. Every other column was re-cut against its measured
   content to pay for it, so the TEN columns total the same 1160px the nine did.
   Each minimum is the widest of its header and its values plus the cell's 16px
   of padding, measured in the page: RUNNING BALANCE needs 132 for its header
   alone and keeps 135, DEPOSIT needed 78 and dropped from 115 to 95.

   THE BUDGET IS REAL BECAUSE THE TABLE CLIPS RATHER THAN SCROLLS. Rows live in
   a `ReactVirtualized__Grid__innerScrollContainer` with `overflow-x: hidden`, so
   a column past the right edge is not scrolled to -- it is silently gone, and
   the one that goes first is RUNNING BALANCE. Measured 2026-09-11. */
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.sf-contact,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.sf-contact
  { flex: 120 0 auto !important; width: 120px !important; }

.dashboard__insider--account-transactions .bigcapital-datatable .thead .th[class="th"],
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.td-status
  { flex: 95 0 auto !important; width: 95px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.deposit,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.deposit
  { flex: 95 0 auto !important; width: 95px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.withdrawal,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.withdrawal
  { flex: 95 0 auto !important; width: 95px !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead .th.running_balance,
.dashboard__insider--account-transactions .bigcapital-datatable .tbody .td.running_balance
  { flex: 135 0 auto !important; width: 135px !important; }

/* The duplicate half of REF.#
 *
 * bc_push.py writes the same id twice: journalNumber `SF-1989` and reference
 * `SF-TX-1989`. Measured on the INCOME register, 22 of 26 rows carried the
 * pair, so a whole column was spending its width restating the one beside it.
 * The class is added by sf-dashboard.js and ONLY when the two provably match,
 * so a genuine reference -- one that is not the transaction number wearing a
 * prefix -- still renders. */
.dashboard__insider--account-transactions .bigcapital-datatable .tbody
  .td.reference_number > .cell-inner.sf-ref-dup { display: none !important; }

/* With the duplicate gone the column carries the contra account, so the header
 * "REF.#" is no longer what is underneath it. font-size:0 hides the original
 * text and ::after restores the header type exactly -- 13px, 1px tracking,
 * uppercase, matching every other column head. */
.dashboard__insider--account-transactions .bigcapital-datatable .thead
  .th.reference_number > .cell-inner { font-size: 0 !important; }
.dashboard__insider--account-transactions .bigcapital-datatable .thead
  .th.reference_number > .cell-inner::after {
  content: "Posted against";
  font-size: 13px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 400;
}

/* -- "What we owe": what each line is, not just when it is due ---------------
 *
 * A due date alone answers "when" and not "for what". The bill number is what a
 * vendor quotes on the phone and the purchase date is what you actually
 * recognise, so both belong on the line. Three columns: number, dates, amount.
 *
 * The row is an ANCHOR now, not a div, so it needs the flex layout restated --
 * `display:flex` does not survive the element change on its own, and an <a>
 * brings its own colour and underline that would fight the overdue red. */
.sf-dash .sf-row.sf-bill {
  display: flex;
  align-items: baseline;
  gap: 8px;
  text-decoration: none;
  color: inherit;
}
.sf-dash .sf-row.sf-bill:hover {
  background: var(--color-hover, rgba(12, 55, 46, 0.06));
}
.sf-dash .sf-bill-no {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}
/* The dates are context, not the point — they recede so the number and the
 * amount stay the things the eye lands on. */
.sf-dash .sf-bill-when {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 11.5px;
  color: var(--color-text-muted, #7a8896);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Overdue already colours the whole row; keep the muted dates in step rather
 * than leaving a grey stripe through a red line. */
.sf-dash .sf-row.sf-bill.sf-overdue .sf-bill-when { color: inherit; opacity: 0.8; }

/* -- "On the cards", under the cash total -----------------------------------
 *
 * A card balance is money already spent and not yet paid. It is deliberately
 * BELOW the cash total and never folded into it: adding it would overstate what
 * is available, and quietly subtracting it would understate the bank. Both
 * figures show, and the net sits beneath them, so it is clear which question
 * each one answers. */
.sf-dash .sf-subhead {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--color-border, #e3e8ee);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted, #7a8896);
}
/* Owed, not held — the same muted treatment the dates get, so it does not read
   as another pile of cash. */
.sf-dash .sf-row.sf-cards-total b { color: var(--color-text-muted, #7a8896); }
.sf-dash .sf-row.sf-net {
  border-top: 1px solid var(--color-border, #e3e8ee);
}

/* A dashboard row that goes somewhere. It has to restate the layout because the
   element changed from div to <a>, and neutralise the anchor's own colour and
   underline — the row's colour is carrying meaning (muted for zero, red for
   overdue) and a link colour would overwrite it. */
.sf-dash .sf-row.sf-linked {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  text-decoration: none;
  color: inherit;
}
.sf-dash .sf-row.sf-linked:hover {
  background: var(--color-hover, rgba(12, 55, 46, 0.06));
}

/* --------------------------------------------------------------------------
   The journal detail drawer, which upstream ships unreadable.

   Bigcapital paints this panel dark and then writes on it in its own dark navy
   #1F3255 -- a colour chosen for a light background. Measured on 2026-09-11:
   21 elements below WCAG AA, the worst at a contrast ratio of 1.13. "Journal
   Type", "Journal No.", "Reference No", "Description" and the whole
   Subtotal/Total footer were effectively invisible. This is upstream's bug,
   not ours; none of the rules above touch the drawer.

   SCOPED THROUGH A STABLE ANCHOR, NEVER THE sc-* HASHES. The element painting
   the dark ground is a styled-component whose class (`sc-dtBdUo jBqwsl`)
   changes on every upstream build. `…-drawer__content-footer` is a real
   semantic name, and the dark panel is exactly the element holding it as a
   direct child -- so :has() names the right box in a way that survives a
   rebuild. Where :has() is unsupported the rule is dropped whole and the
   drawer degrades to upstream's appearance rather than to something worse.

   ONE DRAWER PER CLASS NAME, AND THERE IS MORE THAN ONE DRAWER. The first cut
   anchored on `.journal-drawer__content-footer` exactly, which is the manual
   journal's. Open a bank-feed row instead -- a cashflow transaction, every CF-
   row on the register -- and the footer is `.cashflow-drawer__content-footer`,
   so nothing matched and the Subtotal/Total lines were back to #1F3255 on
   #252A31: a contrast ratio of 1.1, measured 2026-09-11. Bill payments and
   invoices ship the same panel under their own prefixes. The substring match
   covers all of them and cannot reach outside a drawer, because `.bp4-drawer`
   still leads.

   The same lesson as the sidebar above: scope to the real container. A blanket
   colour here would repaint the register behind the drawer, which is light. */
.bp4-drawer div:has(> [class*="drawer__content-footer"]) *,
.bp4-drawer .detail-item__content {
  color: #E6EBF2 !important;
}

/* Labels stay deliberately quieter than their values -- the hierarchy upstream
   intended, which is fine on dark and only the value colour was wrong. */
.bp4-drawer div:has(> [class*="drawer__content-footer"]) .detail-item__label,
.bp4-drawer .detail-item__label {
  color: rgba(255, 255, 255, .72) !important;
}

.bp4-drawer div:has(> [class*="drawer__content-footer"]) .big-number,
.bp4-drawer .big-number {
  color: #F2B8B5 !important;
}

/* The status pill carries its own ground, so the blanket rule above would put
   pale text on a pale chip. Give it a translucent light ground instead: 14%
   white over the dark panel reads as a raised chip and keeps the text at 5.7.
   (A contrast check that treats rgba(255,255,255,.14) as OPAQUE white scores
   this 1.08 and calls it broken. Composite the alpha before believing it.) */
.bp4-drawer div:has(> [class*="drawer__content-footer"]) .bp4-tag,
.bp4-drawer div:has(> [class*="drawer__content-footer"]) .bp4-tag * {
  background: rgba(255, 255, 255, .14) !important;
  color: #F3F6FA !important;
}
