/* ============================================================================
   juribooks-sharp-type-v5.css — the authoritative type layer.
   Loaded LAST, after every other application stylesheet.

   WHAT THE RENDER AUDIT FOUND (qa-sharp-type-v5/TYPOGRAPHY-RENDER-AUDIT-V5.md,
   measured with CSS.getPlatformFontsForNode on the running app, not inferred):

     1. Inter Tight LOADS at 400/500/600/700 — and was then never used, because
        --font-ui is 'IBM Plex Sans','Inter',system-ui,… with Inter Tight absent
        from the stack entirely. The font was downloaded and ignored.

     2. Fractional sizes everywhere, from multiplier chains:
          --f-xs: calc(var(--fbody) * 0.80 * var(--mult-sub,1))
        With --fbody:13px that is 10.4px — exactly the size measured on the
        account-name sublabel, and why it reads as faint.

     3. Two competing scales: --f-* (fractional, derived) and --t-* (integer),
        with #view-batch inputs on --t-md and .jcell on --f-md.

     4. Account-name sublabel rendered IBM Plex Sans 10.4px/400 rgb(105,112,121).
        Journal description IBM Plex Sans 13px/500. Table heading fell all the
        way through the stack to ARIAL. Amounts 13px/500 — no heavier than the
        description beside them.

   WHY INTEGERS HERE AND NOT EVERYWHERE. --fbody is the Settings font-size
   control, and its own comment in index.html says it drives "body text of
   tables and statements". So this file pins integers for INTERFACE CHROME —
   labels, headings, account names, badges, controls — and deliberately leaves
   statement/report body text deriving from --fbody. Settings keeps working,
   and the interface/report scope separation is preserved.

   Real weights only: 400, 500, 600, 700. No 450/550/650 — no variable font
   file carrying them is loaded, so they would be synthesised.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   0. SELF-HOSTED FONTS  (V5B)
   Both families are SIL OFL 1.1, so self-hosting is permitted — see
   FONT-LICENSES.md. Latin subset only: 205 KB for all six faces.

   These are declared in the LAST stylesheet, so for any family+weight pair they
   override the Google Fonts declarations from index.html. The app therefore
   renders from local files online and offline, and the network copy becomes a
   redundancy rather than the source of truth.

   WHY 600 AND NOT 700 FOR MONO. IBM Plex Mono 700 was genuinely available and
   genuinely rasterizing as IBMPlexMono-Bold — but document.fonts.check('700 …')
   returned false because Google's w700 face sat "unloaded" until something
   demanded it. Under font-synthesis:none that is a real first-paint race, so
   the account code now uses 600, which is self-hosted and deterministic.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------ */
:root {
  --font-ui:
    'Inter Tight',
    'Segoe UI Variable',
    'Segoe UI',
    Arial,
    sans-serif;

  --font-numeric:
    'Inter Tight',
    'Segoe UI Variable',
    'Segoe UI',
    Arial,
    sans-serif;

  --font-code:
    'IBM Plex Mono',
    Consolas,
    monospace;

  --type-ink:         #252933;
  --type-ink-soft:    #434A55;
  --type-secondary:   #4D5562;
  --type-muted:       #626B78;
  --type-account:     #596270;
  /* #7E8795 measured ~3.9:1 on white — below AA for normal text.
     #667085 lifts it over 4.5:1 while staying clearly lighter than entered
     text (#252933), so a placeholder is still distinguishable from a value. */
  --type-placeholder: #667085;
}

/* ---------------------------------------------------------------------------
   2. RENDERING
   The app previously forced -webkit-font-smoothing:antialiased, which on
   Windows thins stems — a direct contributor to "too light". Native rendering
   is restored. font-synthesis:none makes a missing weight fail visibly rather
   than being faked, so the tests can catch it.
   ------------------------------------------------------------------------ */
html, body {
  font-synthesis: none !important;
  font-kerning: normal;
  text-rendering: auto;
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
}
body, body[data-ui="clean"] {
  font-family: var(--font-ui) !important;
  color: var(--type-ink) !important;
}
/* Neutralise the broad antialiasing rules from earlier layers. */
body *, body[data-ui="clean"] * {
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
}

/* ---------------------------------------------------------------------------
   3. FONT STACK REPOINTING
   The older tokens are kept alive (many files read them) but repointed at
   Inter Tight, so a rule this file does not name still gets the right face.
   ------------------------------------------------------------------------ */
:root {
  --font-ui-legacy: var(--font-ui);
  --fsans: var(--font-ui);
  --fui: var(--font-ui);
}
html body :is(.view, .card, .modal, .panel, nav, header, footer, .topbar, .sidebar) {
  font-family: var(--font-ui) !important;
}

/* ---------------------------------------------------------------------------
   4. NUMERIC TREATMENT — tabular lining figures for money
   ------------------------------------------------------------------------ */
.num, .money, .amt,
td.r, th.r,
.amount-cell,
.jcell.num, .jcell.deb, .jcell.cr,
.kpi .v, .dkpi .v, .mx .v,
#view-batch input.num, #view-post input.num {
  font-family: var(--font-numeric) !important;
  font-variant-numeric: tabular-nums lining-nums !important;
  font-feature-settings: 'tnum' 1, 'lnum' 1 !important;
  font-weight: 600 !important;
  letter-spacing: -0.01em !important;
  text-align: right !important;
  white-space: nowrap;
  color: var(--type-ink) !important;
}

/* IBM Plex Mono is reserved for IDENTIFIERS only — codes, refs, document
   numbers. Ordinary money uses Inter Tight tabular figures, which is both
   narrower and heavier at the same nominal size.

   The rule itself lives at the END of this file, after the table rules it has
   to out-rank. See "IDENTIFIER FACE" there. */

/* ---------------------------------------------------------------------------
   5. INTERFACE CHROME — the approved specification, integer sizes
   ------------------------------------------------------------------------ */

/* Brand */
.brand .nm, .brand-name, .logo-text { font-size: 17px !important; font-weight: 700 !important; color: var(--type-ink) !important; }
.brand .sub, .brand-sub            { font-size: var(--text-xs) !important; font-weight: 600 !important; color: var(--type-muted) !important; }

/* Navigation */
.nav-group-label, .navgrp, .rail-group { font-size: 12px !important; font-weight: 600 !important; letter-spacing: .035em !important; color: var(--type-ink-soft) !important; }
.nav-group-label.active, .navgrp.active { font-weight: 700 !important; }
.side-nav .grp, .sidebar .grp          { font-size: 11px !important; font-weight: 600 !important; letter-spacing: .035em !important; color: var(--type-muted) !important; }
.side-nav a, .sidebar a, .nav-item     { font-size: 13px !important; font-weight: 500 !important; color: var(--type-ink) !important; }
.side-nav a.active, .nav-item.active   { font-weight: 600 !important; }

/* ---- Shared-component values below read tokens (defaults = the values
   V5 always used), so a theme can change them by setting a token rather
   than by out-ranking these !important rules. Same technique as section 14. */
/* Page header */
.view h1, .page-title       { font-size: 22px !important; font-weight: 700 !important; color: var(--type-ink) !important; }
.page-subtitle, .view .sub  { font-size: 12px !important; font-weight: 500 !important; color: var(--type-secondary) !important; }

/* Tabs */
.tab, .tabs a         { font-size: var(--type-tab-size, 13px) !important; font-weight: 600 !important; color: var(--type-secondary) !important; }
.tab.active, .tabs a.active { font-size: var(--type-tab-size, 13px) !important; font-weight: 700 !important; color: var(--type-ink) !important; }

/* Card and panel headings */
.card > h2, .card > h3, .section-heading { font-size: var(--type-panel-size, 15px) !important; font-weight: 700 !important; color: var(--type-ink) !important; }
.card h4, .panel-heading                 { font-size: 14px !important; font-weight: 600 !important; color: var(--type-ink) !important; }

/* The app's eyebrow is a real section heading, not a caption. */
.eyebrow {
  font-size: 11px !important;
  font-weight: var(--type-eyebrow-weight, 700) !important;
  letter-spacing: .06em !important;
  color: var(--type-ink-soft) !important;
  opacity: 1 !important;
}

/* FORM LABELS — 11px/700, and never faint */
.fld, label.fld, .pf label, .field-label {
  font-size: 11px !important;
  font-weight: var(--type-label-weight, 700) !important;
  letter-spacing: .025em !important;
  color: var(--type-ink-soft) !important;
  opacity: 1 !important;
}

/* INPUTS AND SELECTS — 14px/500 */
.inp, input, select, textarea,
.pf input, .pf select, .pf textarea {
  font-family: var(--font-ui) !important;
  font-size: var(--type-input-size, 14px) !important;
  font-weight: 500 !important;
  color: var(--type-ink) !important;
}
/* The theme layer sets colour with !important; match it so V5 actually wins. */
html[data-jb-theme] :is(.inp, .pf input, .pf select, .pf textarea, input, select, textarea) {
  color: var(--type-ink) !important;
}

/* PLACEHOLDERS — real colour, opacity 1 (Firefox defaults it to .54) */
::placeholder             { font-size: 13px !important; font-weight: 400 !important; color: var(--type-placeholder) !important; opacity: 1 !important; }
::-webkit-input-placeholder { font-size: 13px !important; font-weight: 400 !important; color: var(--type-placeholder) !important; opacity: 1 !important; }

/* BUTTONS */
.btn, button, .toolbar button, .jbar button {
  font-family: var(--font-ui) !important;
  font-size: var(--type-button-size, 13px) !important;
  font-weight: 600 !important;
}

/* Helper text and status badges */
.help, .hint, .helper { font-size: 11px !important; font-weight: 500 !important; color: var(--type-muted) !important; opacity: 1 !important; }
.tag, .badge, .chip-status { font-size: 11px !important; font-weight: var(--type-badge-weight, 700) !important; }

/* TABLES */
/* :not(:where([data-jb-doc] *)) keeps these INTERFACE sizes out of the fee note and any
   other document subtree. Without it an 11px/13px interface table rule wins,
   with !important, inside a 12pt client document (TYPOGRAPHY-CONFLICTS, INV-01). */
table thead th:not(:where([data-jb-doc] *)), .tb-tbl thead th:not(:where([data-jb-doc] *)),
.jtbl thead th:not(:where([data-jb-doc] *)), .lines-tbl thead th:not(:where([data-jb-doc] *)) {
  font-family: var(--font-ui) !important;
  font-size: 11px !important;
  font-weight: var(--type-th-weight, 700) !important;
  letter-spacing: .035em !important;
  color: var(--type-ink-soft) !important;
  opacity: 1 !important;
}
table tbody td:not(:where([data-jb-doc] *)), .tb-tbl tbody td:not(:where([data-jb-doc] *)),
.jtbl tbody td:not(:where([data-jb-doc] *)), .lines-tbl tbody td:not(:where([data-jb-doc] *)) {
  font-family: var(--font-ui) !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  color: var(--type-ink) !important;
}

/* Subtotals and grand totals */
tfoot td:not(:where([data-jb-doc] *)), .subtotal:not(:where([data-jb-doc] *)) { font-size: 13px !important; font-weight: 700 !important; color: var(--type-ink) !important; }
.grand-total:not(:where([data-jb-doc] *)), tfoot .tot:not(:where([data-jb-doc] *)), tr.tot td:not(:where([data-jb-doc] *)) { font-size: 14px !important; font-weight: 700 !important; color: var(--type-ink) !important; }

/* KPI */
.kpi .l, .dkpi .l, .mx .l { font-size: 11px !important; font-weight: 700 !important; letter-spacing: .04em !important; color: var(--type-ink-soft) !important; opacity: 1 !important; }
.kpi .v, .dkpi .v, .mx .v { font-size: 24px !important; font-weight: 700 !important; }

/* ---------------------------------------------------------------------------
   6. JOURNAL ENTRY — the primary acceptance screen
   These are the exact elements in the reference screenshot.
   ------------------------------------------------------------------------ */

/* Account code pill — IBM Plex Mono 14/700 */
#view-batch .pill:not(.flag):not(.plain), #view-post .pill:not(.flag):not(.plain), .jtbl .pill:not(.flag):not(.plain) {
  font-family: var(--font-code) !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  font-variant-numeric: lining-nums tabular-nums !important;
  letter-spacing: 0 !important;
}

/* Account-name sublabel — was 10.4px/400 IBM Plex Sans in rgb(105,112,121).
   This single rule is the most visible defect in the reference screenshot. */
.gl-sub, .jtbl .sub, .acct-sub {
  font-family: var(--font-ui) !important;
  font-size: 12px !important;
  font-weight: 500 !important;
  line-height: 1.35 !important;
  color: var(--type-account) !important;
  opacity: 1 !important;
  letter-spacing: 0 !important;
}

/* Journal grid cells — descriptions at 14/500, amounts at 14/600 tabular */
.jcell {
  font-family: var(--font-ui) !important;
  font-size: 14px !important;
  font-weight: 500 !important;
  color: var(--type-ink) !important;
}
.jcell.num, .jcell.deb, .jcell.cr {
  font-family: var(--font-numeric) !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  font-variant-numeric: tabular-nums lining-nums !important;
  font-feature-settings: 'tnum' 1, 'lnum' 1 !important;
}
/* Selects inside the grid stay one step down so the row does not shout. */
select.jcell, .jobsel { font-size: 13px !important; font-weight: 500 !important; }

/* #view-batch/#view-post inputs were on the OTHER scale (--t-md). Pin them. */
#view-batch input, #view-batch select, #view-post input, #view-post select {
  font-size: var(--type-worksheet-input-size, 14px) !important;
  font-weight: 500 !important;
}
#view-batch input.num, #view-batch input.jcell.num,
#view-post input.num { font-size: 14px !important; font-weight: 600 !important; }
#view-batch select.jcell, #view-batch .jobsel, #view-post select.jcell { font-size: 13px !important; }

/* ---------------------------------------------------------------------------
   7. NO LOW-OPACITY OPERATIONAL TEXT
   Opacity stays legitimate for disabled controls and decorative icons only.
   ------------------------------------------------------------------------ */
.view, .card, .modal, .panel,
.view p, .view span, .view div, .view td, .view th, .view label, .view a {
  opacity: 1 !important;
}
.mute, .muted, .sub, .secondary { color: var(--type-muted) !important; opacity: 1 !important; }
[disabled], .disabled, button:disabled, input:disabled, select:disabled { opacity: .55 !important; }

/* ---------------------------------------------------------------------------
   8. DENSITY — 36px standard rows, journal rows tall enough for a sublabel
   ------------------------------------------------------------------------ */
.tb-tbl tbody td, table.tb-tbl tbody td { height: 36px; }
.jtbl tbody tr { min-height: 52px; }
.jcell { height: 34px; }
button, .btn, a.btn, [role="button"] { min-height: 32px; }
@media (pointer: coarse) {
  button, .btn, a.btn, [role="button"], select, input { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   9. MOBILE — 16px inputs prevent iOS focus-zoom
   ------------------------------------------------------------------------ */
@media (max-width: 760px) {
  input, select, textarea, .inp, .jcell {
    font-size: 16px !important;
    font-weight: 500 !important;
  }
  .view h1, .page-title { font-size: 20px !important; font-weight: 700 !important; }
  table tbody td, .tb-tbl tbody td, .jtbl tbody td { font-size: 13px !important; }
  .num, .money, .jcell.num { font-size: 13px !important; font-weight: 600 !important; }
  .kpi .v, .dkpi .v, .mx .v { font-size: 21px !important; }
  .side-nav a, .nav-item, .nav-group-label { font-size: var(--text-xs) !important; font-weight: 600 !important; }
  .gl-sub, .jtbl .sub { font-size: 12px !important; font-weight: 500 !important; }
}

/* ---------------------------------------------------------------------------
   10. REPORT AND FEE-NOTE SCOPE — deliberately NOT repointed.
   Report body keeps deriving from --fbody so the Settings font-size control
   and the report/interface separation both keep working. Only the numeric
   treatment is shared, because money is tabular in every scope.
   ------------------------------------------------------------------------ */
#feeNote .num, #feeNote .money,
.report .num, .report .money, .stmt .num {
  font-variant-numeric: tabular-nums lining-nums !important;
  font-feature-settings: 'tnum' 1, 'lnum' 1 !important;
}

/* ---------------------------------------------------------------------------
   11. SPECIFICITY PARITY
   Two earlier rules out-specify V5's own selectors even with !important, so
   they are matched exactly rather than escalated with a blunt instrument.
   Measured winners before this block:
     #view-batch .jtbl .pill:not(.flag) { font-size:12.5px !important }   (1,3,0)
     #view-batch .sw-title .st          { font-size:var(--f-xs) !important } (1,2,0)
   12.5px is a fractional size and --f-xs computes to 10.4px; both are the
   multiplier-chain anti-pattern this layer exists to end.

   NOTE on the table heading: it audits as "Arial (1 glyph), Inter Tight (10
   glyphs)". That is NOT a fallback failure — the single Arial glyph is the "↕"
   sort indicator, which Inter Tight does not contain. The heading text itself
   is Inter Tight. Left alone deliberately.
   ------------------------------------------------------------------------ */
#view-batch .jtbl .pill:not(.flag),
#view-post .jtbl .pill:not(.flag) {
  font-family: var(--font-code) !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  letter-spacing: 0 !important;
  font-variant-numeric: lining-nums tabular-nums !important;
}
#view-batch .sw-title .st,
#view-post .sw-title .st {
  font-size: 11px !important;
  font-weight: 700 !important;
  letter-spacing: .05em !important;
}
/* The account sublabel is written by the grid as .gl-sub inside a td; make the
   V5 rule outrank the theme's td rules at the same depth. */
#view-batch .jtbl tbody td .gl-sub,
#view-post .jtbl tbody td .gl-sub,
#view-batch .jtbl tbody td .sub {
  font-family: var(--font-ui) !important;
  font-size: 12px !important;
  font-weight: 500 !important;
  color: var(--type-account) !important;
  opacity: 1 !important;
}

/* ---------------------------------------------------------------------------
   12. MOBILE SPECIFICITY PARITY
   The desktop rule #view-batch input (1,0,1) out-specifies the media query's
   bare `input` (0,0,1), so at 390px the journal inputs measured 14px — under
   the 16px iOS needs to not zoom the page on focus. Media queries add no
   specificity; only the selector does. Matched exactly.
   ------------------------------------------------------------------------ */
@media (max-width: 760px) {
  #view-batch input, #view-batch select, #view-batch textarea,
  #view-post input, #view-post select, #view-post textarea,
  #view-batch input.num, #view-batch input.jcell, #view-batch select.jcell,
  #view-post input.num, #view-post input.jcell,
  #view-batch .jcell, #view-post .jcell,
  .jcell, .inp {
    font-size: 16px !important;
  }
  #view-batch input.num, #view-post input.num,
  #view-batch .jcell.num, .jcell.num { font-weight: 600 !important; }
  #view-batch select.jcell, #view-batch .jobsel { font-size: 16px !important; }
}

/* ---------------------------------------------------------------------------
   13. THE DERIVED SCALE — integer pixels, without breaking Settings  (V5B)

   Auditing all 34 rendered pages found 2,245 fractional font sizes and 475
   elements under 10.5px. V5 pinned only the selectors it named on Journal
   Entry; everything else still derived from the multiplier chain in
   index.html:1130 —

       --f-xs: calc(var(--fbody) * 0.80 * var(--mult-sub,1))

   With --fbody:13px that is 10.4px, and with the Settings control at other
   values it lands on 9.36px, 11.44px and so on. That is the fractional-size
   defect at its SOURCE, and no amount of per-selector pinning would have
   reached the whole application.

   Pinning these to constants would have killed the Settings font-size control,
   which is a shipped feature. So they are rounded instead: the proportional
   relationship to --fbody is preserved exactly, and the result is always a
   whole pixel. A floor is applied so no derived step can fall into the
   unreadable range regardless of the Settings value.

   round() is CSS Values 4, supported in Chrome 112+/Safari 15.4+/Firefox 118+.
   The max() floor degrades safely on anything older: the calc() still applies,
   only the rounding is lost.
   ------------------------------------------------------------------------ */
/* FALLBACK FIRST — integers for any engine without CSS round().
   Without this, an unsupported round() makes the whole declaration invalid and
   the token falls back to the ORIGINAL fractional calc() in index.html, which
   is the defect this section exists to remove. Tested by overriding @supports. */
:root {
  --f-2xs: 11px;
  --f-xs:  11px;
  --f-sm:  12px;
  --f-rd:  13px;
  --f-md:  13px;
  --f-lg:  14px;
  --f-xl:  16px;
  --f-2xl: 20px;
  --f-3xl: 25px;
  --f-num: 27px;
}

/* ENHANCED — keeps the Settings font-size control proportional AND integer.
   round() is CSS Values 4: Chrome 112+, Safari 15.4+, Firefox 118+. */
@supports (font-size: round(13px, 1px)) {
  :root {
    --f-2xs: max(11px, round(calc(var(--fbody) * 0.72 * var(--mult-sub, 1)), 1px));
    --f-xs:  max(11px, round(calc(var(--fbody) * 0.80 * var(--mult-sub, 1)), 1px));
    --f-sm:  max(12px, round(calc(var(--fbody) * 0.88 * var(--mult-sub, 1)), 1px));
    --f-rd:  max(13px, round(calc(var(--fbody) * 0.94), 1px));
    --f-md:  max(13px, round(var(--fbody), 1px));
    --f-lg:  round(calc(var(--fbody) * 1.08), 1px);
    --f-xl:  round(calc(var(--fbody) * 1.24 * var(--mult-heading, 1)), 1px);
    --f-2xl: round(calc(var(--fbody) * 1.55 * var(--mult-heading, 1)), 1px);
    --f-3xl: round(calc(var(--fbody) * 1.90 * var(--mult-heading, 1)), 1px);
    --f-num: round(calc(var(--fbody) * 2.05 * var(--mult-heading, 1)), 1px);
  }
}

/* ---------------------------------------------------------------------------
   14. COMPONENT TYPOGRAPHY TOKENS  (V5C)

   THE ARCHITECTURAL FIX. juribooks-journal-v3.js and juribooks-nav-v2.js inject
   <style> blocks at runtime, which land after every <link>. V5B answered that
   with a MutationObserver that kept re-appending the V5 sheet — an arms race,
   and a typography system that depended on winning a race is not a system.

   A custom property is resolved AT USE TIME from :root, not at parse time. So
   once the injected rules read these tokens, it no longer matters where in the
   cascade those rules sit: they resolve to the values below. Stylesheet order
   stops being load-bearing, and the observer is not merely unwanted — it is
   unnecessary. It has been deleted.

   These are the single source of truth for those components. Changing a value
   here changes the injected rule too, with no JavaScript edit.
   ------------------------------------------------------------------------ */
:root {
  /* navigation */
  --type-nav-group-size: 12px;
  --type-nav-group-weight: 600;
  --type-nav-item-size: 13px;
  --type-nav-item-weight: 500;
  --type-nav-item-active-weight: 600;
  --type-nav-line-height: 1.3;
  /* the collapsed-group label and the badge were font:700 10.5px and
     font:700 9px — fractional and far under the 11px floor. */
  --type-nav-badge-size: 11px;
  --type-nav-badge-weight: 700;

  /* journal grid */
  --type-journal-account-size: 14px;
  --type-journal-account-weight: 600;
  --type-journal-name-size: 12px;
  --type-journal-name-weight: 500;
  --type-journal-description-size: 14px;
  --type-journal-description-weight: 500;
  --type-journal-amount-size: 14px;
  --type-journal-amount-weight: 600;
  --type-journal-th-size: 11px;
  --type-journal-th-weight: 700;
  --type-journal-th-tracking: .035em;
  --type-journal-label-weight: 700;
  --type-journal-reveal-size: 12px;
  --type-journal-reveal-weight: 600;
}

/* ---------------------------------------------------------------------------
   15. #glChip IS NOW A REAL BUTTON  (V5C)
   It was a <span class="pill plain">, so the G/L account picker on the Payment
   Voucher could not be reached or activated from the keyboard at all — measured:
   tabIndex -1, no role. A real <button> gets focus, Enter/Space and the correct
   role natively, which a span with tabindex only imitates.

   The element carries .pill styling, so the browser's button defaults have to
   be neutralised or it renders as a chrome button rather than a pill.
   ------------------------------------------------------------------------ */
button.pill, button.pill.plain {
  font: inherit;
  font-size: var(--f-sm) !important;
  font-weight: 600 !important;
  line-height: inherit;
  text-align: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
button.pill:focus-visible {
  outline: 2px solid var(--navy, #0B4D3A);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   16. LAYOUT-SHIFT RESERVATION  (V5D)

   MEASURED, not guessed. A buffered layout-shift observer installed before
   application boot attributed 0.112 of the 0.147 cold CLS — 76% — to a single
   shift at 2704ms whose sources were:

       section#view-home  [224, 65,1216,835] -> [224,115,1216,785]   (down 50px)
       nav#nav            [0,  161, 223,656] -> [0,  174, 223,643]   (down 13px)

   The topbar does NOT grow: it measures [0,65] throughout. The cause is
   div#jbHomeTabs — the dashboard tab strip from juribooks-home-nav-v1.js —
   inserted at 2010ms, exactly 50px tall, as the sibling immediately before
   #view-home. It mounts late because its anchor (#view-home) does not exist
   until the app has rendered, so the module's early boot attempts no-op.

   This is NOT a font problem. Fonts were ready well before the shift, and the
   service-worker run measured 0.0325 with the same fonts.

   THE FIX: reserve the strip's height while it is absent, and release the
   reservation the moment it mounts, so the insertion fills space that was
   already there. :has() makes this purely declarative — no JS, no timing
   assumption, and it cannot desynchronise from the real DOM the way a fixed
   placeholder would.

   Without :has() support nothing is reserved, which is exactly today's
   behaviour — a no-op, never a regression.
   ------------------------------------------------------------------------ */
@supports selector(:has(*)) {
  .main:not(:has(#jbHomeTabs)) > #view-home { margin-top: 50px; }
}
/* And pin the strip's own height so filling it with buttons cannot resize it. */
#jbHomeTabs { min-height: 50px; box-sizing: border-box; }

/* ---------------------------------------------------------------------------
   IDENTIFIER FACE — placed last, deliberately

   IBM Plex Mono is for identifiers: account codes, journal ids, invoice and
   voucher references, tax references, document numbers. Never for money, a
   percentage, a date, a name, a description, a heading, a label or a button.

   Two things about the selector are deliberate.

   WHY IT SITS AT THE END. `.tb-tbl tbody td` above is (0,1,2) and carries
   !important; a bare `.mono` is (0,1,0) and loses to it. That is why the trial
   balance rendered 24 account codes in Inter Tight for as long as this file
   has existed -- a pre-existing defect the typography suite found (T11), not
   one introduced by the document scoping. Prefixing `html body` brings the
   identifier rule to (0,1,2) as well, and placing it after the table rules
   settles the tie in favour of the identifier. It declares only font-family
   and numeric variant, so it cannot disturb any size cascade: the report size
   setting still governs statement type (exec-theme R6).

   WHY THE GUARD IS :not(:where(...)). `:where()` contributes zero specificity,
   so excluding document subtrees costs the rule nothing. A bare
   :not([data-jb-doc] *) would add (0,1,0) and silently re-rank everything it
   touches -- which is exactly what broke R6 when it was tried.
   ------------------------------------------------------------------------ */
html body :is(.mono, code, kbd, .pill.mono, .jrefdisp, .acct-code, .doc-ref,
              .coa-code, .jrn-no, .inv-no, .pv-ref, .tax-ref):not(:where([data-jb-doc] *)),
html body :is(#view-batch, #view-post) .pill:not(.flag):not(.plain) {
  font-family: var(--font-code) !important;
  font-variant-numeric: lining-nums tabular-nums !important;
}
