/* SheerBooks theme layer (doc-34 pass, 34a; design doc 31.3).
   The RULES are static; the VALUES arrive as --sb-* CSS variables in a
   server-rendered style block in Site.master (BL_Theme resolves
   user -> company -> base). No JavaScript anywhere in theming. */

body {
    background-color: var(--sb-bg);
    color: var(--sb-text);
    font-family: var(--sb-font), system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: var(--sb-font-size);

    /* THE GENERAL RULE (the Slate label fix): Bootstrap 5.3 colors
       its components through :root variables that default to the
       LIGHT palette - .text-muted/.form-text via
       --bs-secondary-color, cards/list-groups via --bs-body-*, and
       rgba composites via the -rgb triplets. Aliasing them HERE, at
       body level, re-points every such component at the theme in
       one place - never patch a component that merely references
       these; patch only components carrying FIXED colors (below). */
    --bs-body-color: var(--sb-text);
    --bs-body-bg: var(--sb-bg);
    --bs-body-color-rgb: var(--sb-text-rgb);
    --bs-body-bg-rgb: var(--sb-bg-rgb);
    --bs-border-color: var(--sb-border);
    --bs-emphasis-color: var(--sb-text);
    --bs-secondary-bg: var(--sb-row2);
    --bs-tertiary-bg: var(--sb-hover);
    --bs-secondary-color: color-mix(in srgb, var(--sb-text) 80%, var(--sb-bg));
    --bs-tertiary-color: color-mix(in srgb, var(--sb-text) 70%, var(--sb-bg));
    /* 039: links are their OWN token - the Bootswatch sources
       diverge $link-color from $primary (Slate white, Darkly green)
       and primary-as-link failed both dark themes. */
    --bs-link-color: var(--sb-link);
}

a { color: var(--sb-link); }

/* Labels: belt over the inheritance chain - a future container that
   sets its own color cannot dim them. */
label, .form-label, .form-check-label { color: var(--sb-text); }

/* Muted text derives from the THEME, not Bootstrap's fixed gray
   (the owner-confirmed contrast fix). 80% text, NOT 60%: Slate's
   base text is itself gray (#AAA at 6.1:1), so a 60% mix landed at
   3.2:1 - the Slate-labels bug. 80% clears 4.5 on all four themes
   (the UxTests drift net proves it against the live rows).
   color-mix tracks any palette; browsers without it keep the
   Bootstrap gray (a fallback, not the behavior of record). */
.text-muted, .form-text {
    color: color-mix(in srgb, var(--sb-text) 80%, var(--sb-bg)) !important;
}

/* Components carrying FIXED colors (not variable references) - the
   only legitimate per-component patches under the general rule. */
/* 34y: hover consistency (HOVER_PLAN - all button types darken via
   the same filter, matching .btn-primary/.btn-secondary/.sb-linkbtn,
   Delete/outline-danger the one deliberate exception). Bootstrap's
   own fill-swap hover (--bs-btn-hover-bg flips solid) is CANCELED by
   pinning every hover/active custom property to the SAME value as
   resting state, then filter: brightness(0.9) does the actual
   darkening - the exact two-part pattern already used below, just
   via custom properties instead of direct declarations (outline
   buttons render color/background/border through --bs-btn-* vars,
   solid buttons through this file's own direct properties). */
/* HOVER_WASH (found 2026-08-20 investigating a Light/Medium-only bug
   report on Receive Payment/Edit): filter: brightness(0.9) alone is
   background-dependent, not just theme-dependent - it darkens the
   BORDER/TEXT PIXELS ONLY (outline buttons keep a transparent fill),
   so its visibility rides on how much luminance headroom the resting
   color already has above the page background. Computed per theme:
   the swatch's own relative luminance drop is a uniform ~20%
   everywhere (the mechanism was never broken), but the ABSOLUTE
   luminance delta ranged from 0.032 on Light to 0.080 on Dark for
   Edit alone - a 2.5x spread, because Light/Medium's accent colors
   already sit close to their (bright) page background while
   Slate/Dark's sit far from theirs (dark). No single brightness
   factor closes that gap without either staying invisible on
   Light/Medium or overshooting Slate/Dark - it already pushes
   Receive Payment's hover contrast below 4.5:1 on Slate/Dark at 0.9
   (see UX_BACKLOG), so going steeper is not an option.
   The fix: --bs-btn-hover-bg is no longer pinned to plain transparent
   - it is a low-alpha (~12%) wash of the class's OWN accent token
   composited toward transparent via color-mix (the existing
   .text-muted/--bs-secondary-color pattern, not a new mechanism).
   An alpha blend's relative visibility scales with the percentage,
   not with the theme's own luminance range - computed contrast of
   the washed background against the page background came out
   nearly identical across all four themes at every alpha tested
   (e.g. 12%: 1.17/1.18/1.20/1.20), unlike the filter alone. filter:
   brightness(0.9) stays in place underneath it - this ADDS
   visibility, it does not replace the existing darkening. */
.btn-outline-secondary {
    --bs-btn-color: var(--sb-text);
    --bs-btn-border-color: var(--sb-secondary);
    --bs-btn-hover-color: var(--sb-text);
    --bs-btn-hover-bg: color-mix(in srgb, var(--sb-secondary) 12%, transparent);
    --bs-btn-hover-border-color: var(--sb-secondary);
    --bs-btn-active-color: var(--sb-text);
    --bs-btn-active-bg: transparent;
    --bs-btn-active-border-color: var(--sb-secondary);
}
.btn-outline-secondary:hover, .btn-outline-secondary:focus, .btn-outline-secondary:active {
    filter: brightness(0.9);
}
/* Outline-primary RESTS on the LINK token, not primary: the resting
   state sits directly on the page background, and dark-theme
   primaries are near-background by design (Slate #3A3F44 on #272B30
   is 1.3:1 - an ENABLED button that reads as disabled; the
   Update-totals bug). link_color is the primary-family color
   guaranteed readable on the background - the UxTests link/bg
   contrast pair enforces it per theme. Light/Medium are unchanged
   (their link IS primary). 34y: hover/active no longer fill with
   primary - pinned to the SAME resting values instead (transparent
   bg, link-colored text/border), then filter: brightness(0.9)
   darkens, matching every other button type now. The "click never
   flashes Bootstrap's stock blue" protection this originally existed
   for is preserved the same way - --bs-btn-active-bg is still
   explicitly pinned, just to transparent instead of a solid fill. */
.btn-outline-primary {
    --bs-btn-color: var(--sb-link);
    --bs-btn-border-color: var(--sb-link);
    --bs-btn-hover-color: var(--sb-link);
    --bs-btn-hover-bg: color-mix(in srgb, var(--sb-link) 12%, transparent);
    --bs-btn-hover-border-color: var(--sb-link);
    --bs-btn-active-color: var(--sb-link);
    --bs-btn-active-bg: transparent;
    --bs-btn-active-border-color: var(--sb-link);
}
.btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:active {
    filter: brightness(0.9);
}
/* 046: outline-warning (bill/expense/payment/refund/credit-memo void
   links, tax authority deactivate, reconciliation undo) rested on
   Bootstrap's fixed --bs-warning (#ffc107) since 34y - fine against
   Light/Medium's bright pages, glaring (8-10:1 contrast) against
   Slate/Dark's near-black ones, the same complaint Void's SOLID
   btn-warning had. FIRST ATTEMPT (reverted, found by the live
   contrast walk): text on --sb-warning directly, mirroring
   outline-primary - broke because warning_color's Light/Medium value
   is unchanged stock #FFC107, kept bright deliberately for the SOLID
   fill (paired with black text ON it), and #FFC107 as TEXT sitting
   directly on Light/Medium's own bright page background is only
   1.6:1 - a real, disruptive failure (every Light-base theme save
   tripped the readability gate, not just this button). CORRECTED to
   mirror outline-SECONDARY's shape instead: text on --sb-text (the
   token already guaranteed legible against the page - that is its
   whole job), border on --sb-btn-warning-border (the warning
   identity, same token the solid button's own border uses), hover
   wash on --sb-warning. outline-success (Receive payment) stays on
   the OLD fixed --bs-success pattern below - its own Slate/Dark
   hover-contrast gap was reviewed and accepted as-is (UX_BACKLOG.md),
   out of scope here; Delete (.btn-outline-danger) remains the one
   deliberate exception with no theme.css presence at all. */
.btn-outline-warning {
    --bs-btn-color: var(--sb-text);
    --bs-btn-border-color: var(--sb-btn-warning-border);
    --bs-btn-hover-color: var(--sb-text);
    --bs-btn-hover-bg: color-mix(in srgb, var(--sb-warning) 12%, transparent);
    --bs-btn-hover-border-color: var(--sb-btn-warning-border);
    --bs-btn-active-color: var(--sb-text);
    --bs-btn-active-bg: transparent;
    --bs-btn-active-border-color: var(--sb-btn-warning-border);
}
.btn-outline-warning:hover, .btn-outline-warning:focus, .btn-outline-warning:active {
    filter: brightness(0.9);
}
.btn-outline-success {
    --bs-btn-hover-color: var(--bs-success);
    --bs-btn-hover-bg: color-mix(in srgb, var(--bs-success) 12%, transparent);
    --bs-btn-hover-border-color: var(--bs-success);
    --bs-btn-active-color: var(--bs-success);
    --bs-btn-active-bg: transparent;
    --bs-btn-active-border-color: var(--bs-success);
}
.btn-outline-success:hover, .btn-outline-success:focus, .btn-outline-success:active {
    filter: brightness(0.9);
}
.bg-light { background-color: var(--sb-row2) !important; }
.pagination {
    --bs-pagination-bg: var(--sb-row1);
    --bs-pagination-color: var(--sb-link);
    --bs-pagination-border-color: var(--sb-border);
    --bs-pagination-hover-bg: var(--sb-hover);
    --bs-pagination-hover-color: var(--sb-link);
    --bs-pagination-focus-bg: var(--sb-hover);
    --bs-pagination-focus-color: var(--sb-link);
    --bs-pagination-active-bg: var(--sb-primary);
    --bs-pagination-disabled-bg: var(--sb-row2);
    --bs-pagination-disabled-color: color-mix(in srgb, var(--sb-text) 50%, var(--sb-bg));
}
.list-group-item-action:hover, .list-group-item-action:focus {
    background-color: var(--sb-hover);
    color: var(--sb-text);
}

.btn-primary {
    background-color: var(--sb-primary);
    border-color: var(--sb-btn-primary-border);
    color: var(--sb-btn-primary-text);
}
.btn-primary:hover, .btn-primary:focus, .btn-primary:active {
    background-color: var(--sb-primary);
    border-color: var(--sb-btn-primary-border);
    color: var(--sb-btn-primary-text);
    filter: brightness(0.9);
}
.btn-secondary {
    background-color: var(--sb-secondary);
    border-color: var(--sb-btn-secondary-border);
    color: var(--sb-btn-secondary-text);
}
/* 042: without this, .btn-secondary:hover fell through to
   Bootstrap's own hardcoded --bs-btn-hover-bg (a class+pseudo-class
   selector beats theme.css's plain class rule on specificity alone,
   regardless of load order) - a stock gray totally disconnected from
   the theme, found while building the link-button style below and
   fixed here rather than deferred (the 041 precedent). Same
   filter-darken mechanism as .btn-primary, not a second mechanism. */
.btn-secondary:hover, .btn-secondary:focus, .btn-secondary:active {
    background-color: var(--sb-secondary);
    border-color: var(--sb-btn-secondary-border);
    color: var(--sb-btn-secondary-text);
    filter: brightness(0.9);
}
/* 046: Void's solid warning button, same shape as .btn-primary/
   .btn-secondary (direct properties, not --bs-btn-* custom
   properties - solid buttons never went through those). The hover
   rule is added in the SAME pass as the color theming - leaving it
   on Bootstrap's stock #ffca2c fill-swap would mean the button looks
   right at rest but flashes an unrelated hardcoded color on hover,
   the exact gap the .btn-secondary comment above already caught
   once. */
.btn-warning {
    background-color: var(--sb-warning);
    border-color: var(--sb-btn-warning-border);
    color: var(--sb-btn-warning-text);
}
.btn-warning:hover, .btn-warning:focus, .btn-warning:active {
    background-color: var(--sb-warning);
    border-color: var(--sb-btn-warning-border);
    color: var(--sb-btn-warning-text);
    filter: brightness(0.9);
}
/* 042: the Links category's opt-in button style
   (BUTTON_AND_LINK_STYLE_PLAN.md) - its own independent color set,
   never button_secondary_* or outline-secondary. Bootstrap's .btn
   base rule supplies padding/border-radius/etc; only the three
   colors and hover need declaring here, exactly like
   .btn-primary/.btn-secondary above. */
.sb-linkbtn {
    background-color: var(--sb-linkbtn-bg);
    border-color: var(--sb-linkbtn-border);
    color: var(--sb-linkbtn-text);
}
.sb-linkbtn:hover, .sb-linkbtn:focus, .sb-linkbtn:active {
    background-color: var(--sb-linkbtn-bg);
    border-color: var(--sb-linkbtn-border);
    color: var(--sb-linkbtn-text);
    filter: brightness(0.9);
}

.btn, .card, .form-control, .form-select, .alert, .badge {
    border-radius: var(--sb-radius);
}

.card, .form-control, .form-select, .table, .border-top, .border, hr {
    border-color: var(--sb-border) !important;
}
.card { background-color: var(--sb-row1); }
.form-control, .form-select {
    background-color: var(--sb-row1);
    color: var(--sb-text);
}

/* The five table controls (doc 35.4): row_1 / row_2 / hover /
   selected / header. Plain background-color rules with enough
   specificity to beat Bootstrap's table variables. */
.table { color: var(--sb-text); }
.table > :not(caption) > * > * {
    background-color: var(--sb-row1);
    color: var(--sb-text);
    border-color: var(--sb-border);
}
.table-striped > tbody > tr:nth-of-type(odd) > * {
    background-color: var(--sb-row2);
}
.table > thead > tr > th {
    background-color: var(--sb-header);
}
.table-hover > tbody > tr:hover > * {
    background-color: var(--sb-hover);
}
.table > tbody > tr.sb-selected > * {
    background-color: var(--sb-selected);
}

footer.sb-footer {
    background-color: var(--sb-row1);
    border-top: 1px solid var(--sb-border);
}

/* The navigation sidebar (doc 34; 34c). Position via order classes
   inside the flex shell; three states; the size arrives as an inline
   width for vertical positions. Colors are the theme's sidebar pair. */
.sb-topbar { background-color: var(--sb-sidebar); }
.sb-sidebar {
    background-color: var(--sb-sidebar);
    color: var(--sb-sidebar-text);
    flex-shrink: 0;
    padding: 0.5rem 0;
}
.sb-pos-left { order: 0; }
.sb-pos-right { order: 2; }
.sb-pos-top { order: 0; }
.sb-pos-bottom { order: 2; }
.sb-main { order: 1; min-width: 0; }
.sb-pos-top, .sb-pos-bottom { width: 100%; }
.sb-pos-top .sb-nav-link, .sb-pos-bottom .sb-nav-link { display: inline-flex; }
.sb-pos-top .sb-nav-head, .sb-pos-bottom .sb-nav-head { display: inline-flex !important; float: right; }
.sb-nav-link {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 1rem;
    color: var(--sb-sidebar-text);
    text-decoration: none;
    white-space: nowrap;
}
.sb-nav-link:hover { color: var(--sb-sidebar-text); filter: brightness(1.15); text-decoration: underline; }
.sb-nav-link.sb-active { background-color: rgba(255, 255, 255, 0.14); font-weight: 600; }
.sb-nav-tool {
    color: var(--sb-sidebar-text);
    padding: 0.25rem 0.6rem;
    text-decoration: none;
    background: none;
    border: none;
    cursor: pointer;
}
.sb-nav-tool:hover { color: var(--sb-sidebar-text); filter: brightness(1.2); }
.sb-collapsed { width: 56px !important; }
.sb-collapsed .sb-nav-label { display: none; }
.sb-collapsed .sb-nav-link { justify-content: center; padding: 0.45rem 0.25rem; }
.sb-nav-showstrip {
    background-color: var(--sb-sidebar);
    order: 0;
    flex-shrink: 0;
    align-self: stretch;
    display: flex;
    align-items: flex-start;
}

/* Toast-style status messages (doc-34 pass, 34q). Opt-in via the
   sb-toast class LAYERED onto the existing alert markup every page
   already uses (Panel.Visible + Panel.CssClass + Literal.Text) -
   this changes only how the message is positioned/dismissed, not the
   underlying mechanism, so adopting it elsewhere later is a one-line
   CssClass-string change, not a new control. Pure CSS, no JS: the
   message is fully present and readable in the initial HTML exactly
   as before - there is no JS path to fall back FROM here, so the
   no-JS floor is trivially satisfied rather than merely defended.
   animation-fill-mode "forwards" (the trailing keyword below) is what
   makes the auto-dismiss stick without any script: the element keeps
   the last keyframe's opacity:0/visibility:hidden permanently once
   the animation completes. No opacity/visibility is set OUTSIDE the
   animation, so a browser without @keyframes support just shows the
   message at its default (fully opaque) style, positioned correctly,
   staying visible indefinitely - a safe degradation, not a broken
   one. position:fixed takes it out of the normal flow entirely, so it
   cannot push page content by construction. z-index 1100 clears every
   layer already in use anywhere in this app, checked directly rather
   than guessed: Coloris' own popup sits at 1000, and Bootstrap's CSS
   (whose JS this app never loads, so its own layers are inert) tops
   out at --bs-toast-zindex: 1090. */
.sb-toast {
    position: fixed;
    top: 1rem;
    right: 1rem;
    max-width: min(420px, calc(100vw - 2rem));
    z-index: 1100;
    animation: sb-toast-life 3s ease forwards;
}
@keyframes sb-toast-life {
    0%   { opacity: 0; transform: translateY(-0.5rem); }
    8%   { opacity: 1; transform: translateY(0); }
    85%  { opacity: 1; transform: translateY(0); }
    100% { opacity: 0; transform: translateY(-0.5rem); visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
    .sb-toast { animation-name: sb-toast-life-reduced; }
    @keyframes sb-toast-life-reduced {
        0%   { opacity: 0; }
        8%   { opacity: 1; }
        85%  { opacity: 1; }
        100% { opacity: 0; visibility: hidden; }
    }
}

/* Print (doc 31.4): chrome unprinted; dark themes forced readable.
   d-print-none remains the per-element tool the report screens
   already use. */
@media print {
    nav, .navbar, .sb-sidebar, .btn, footer.sb-footer, .d-print-none {
        display: none !important;
    }
    body {
        background-color: #FFFFFF !important;
        color: #000000 !important;
    }
    .table > :not(caption) > * > * {
        background-color: #FFFFFF !important;
        color: #000000 !important;
    }
}
