/* Project-specific overrides for the Tabler theme.
   Keep this file small — prefer Tabler's built-in classes over overrides. */

/* Self-hosted Inter variable font. Drop InterVariable.woff2 /
   InterVariable-Italic.woff2 into /static/fonts/inter/ — Tabler's default
   font stack ("Inter Var", Inter, ...) will pick this up automatically.
   If files are missing, the browser falls back to system fonts gracefully. */
@font-face {
    font-family: 'Inter Var';
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    src: url('/fonts/inter/InterVariable-2bf3d951bf9d6109437ea0874bbf12fb.woff2') format('woff2-variations');
}
@font-face {
    font-family: 'Inter Var';
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    src: url('/fonts/inter/InterVariable-Italic-8d1dc86da25893737b6bb8a9c64b790e.woff2') format('woff2-variations');
}

/* Sidebar collapse (toggled by #sidebarToggleBtn in topbar) — hides the
   vertical nav and lets .page-wrapper reclaim the full viewport width.
   Persisted via localStorage in scripts.js.
   Uses `margin-left` because Tabler's .page-wrapper rules set `margin-left: 15rem`
   in multiple media queries; `margin-inline-start` alone didn't beat them in LTR. */
body.sidebar-collapsed .navbar-vertical { display: none !important; }
body.sidebar-collapsed .page-wrapper {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* --- DataTables footer (info + pagination) --- */
/* Kill default DataTables margin/padding so info+pagination sit cleanly in the flex footer */
.dt-footer .dataTables_info { padding: 0; }
.dt-footer .dataTables_paginate { padding: 0; margin: 0; }
.dt-footer .pagination { margin: 0; }
/* Small muted page-links matching Tabler's compact button sizing */
.dt-footer .page-link {
    padding: .25rem .5rem;
    font-size: .8125rem;
}
/* Hide the whole footer row when there's nothing to page (only 1 page of results).
   DataTables still renders the bar; this keeps cards tight on small tables. */
.dt-footer:has(.paginate_button.current:only-child) .dataTables_paginate { display: none; }

/* --- Accessibility: visible focus ring for keyboard users --- */
/* Browsers show :focus-visible only for keyboard navigation, not mouse clicks,
   so interactive targets stay clean when clicked but prominent when tabbed to. */
*:focus-visible {
    outline: 2px solid var(--tblr-primary, #066fd1);
    outline-offset: 2px;
    border-radius: 2px;
}
/* Override inside form controls — BS5 already shows a box-shadow on :focus,
   the outline would duplicate. Use outline only on buttons and links. */
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
    outline: none;
}

/* --- Required field indicator: red asterisk after the label --- */
/* Uses :has() to detect when the immediately-following input is required.
   Falls back silently on browsers without :has() support (Chrome 105+, Safari 15.4+, Firefox 121+). */
.form-label:has(+ input[required]),
.form-label:has(+ textarea[required]),
.form-label:has(+ select[required]) {
    position: relative;
}
.form-label:has(+ input[required])::after,
.form-label:has(+ textarea[required])::after,
.form-label:has(+ select[required])::after {
    content: " *";
    color: var(--tblr-danger, #d63939);
    font-weight: 600;
}

/* --- Card header dropdowns: let menus escape the card's overflow:hidden clipping.
   Targeted via :has() so only cards that actually have a header dropdown lose the clip. */
.card:has(> .card-header .dropdown),
.card:has(> .card-header .dropend),
.card:has(> .card-header .dropstart) {
    overflow: visible;
}

/* --- Row-level dropdowns inside DataTables: same clipping pattern, but inside
   .table-responsive (which has overflow-x:auto). Open the parent card while a
   menu is shown so it isn't cut by the row container. */
.card:has(.table-responsive .dropdown-menu.show) {
    overflow: visible;
}
.card:has(.table-responsive .dropdown-menu.show) .table-responsive {
    overflow: visible;
}

/* --- Linked primary cells in list tables.
   Click the name/account/reference to open the detail page. Hover affordance
   matches Tabler's link styles; truncation + native title attribute handles
   long values on narrow viewports without breaking row height.
   Hover styling is scoped to anchor variants only — a bare .row-link <div>
   is non-interactive and must not look clickable. */
.row-link {
    max-width: 100%;
}
a.row-link:hover .fw-medium,
a.row-link:focus-visible .fw-medium {
    color: var(--tblr-primary);
    text-decoration: underline;
}
.row-link .text-truncate {
    max-width: 28ch;
}
@media (min-width: 992px) {
    .row-link .text-truncate { max-width: 32ch; }
}

/* --- Sticky first column for tables that may overflow on narrow viewports.
   Add class="table-sticky-first" to the <table>. Keeps the primary identifier
   (name / reference) in view while the rest scrolls horizontally. */
.table-sticky-first > thead > tr > th:first-child,
.table-sticky-first > tbody > tr > td:first-child {
    position: sticky;
    left: 0;
    background-color: var(--tblr-bg-surface, #fff);
    z-index: 1;
}
.table-sticky-first > thead > tr > th:first-child {
    z-index: 2;
}
[data-bs-theme="dark"] .table-sticky-first > thead > tr > th:first-child,
[data-bs-theme="dark"] .table-sticky-first > tbody > tr > td:first-child {
    background-color: var(--tblr-bg-surface, #1a2234);
}
/* Striping must keep working under the sticky cell. */
.table-sticky-first.card-table > tbody > tr:nth-child(even) > td:first-child {
    background-color: var(--tblr-bg-surface-tertiary, rgba(0, 0, 0, .025));
}
[data-bs-theme="dark"] .table-sticky-first.card-table > tbody > tr:nth-child(even) > td:first-child {
    background-color: rgba(255, 255, 255, .03);
}

/* --- Skeleton row placeholders for server-side DataTables initial load --- */
/* Shimmer effect matches Bootstrap 5 .placeholder-glow. Rows are replaced
   automatically by DataTables on first draw. */
tr.dt-skeleton td .placeholder {
    height: 0.75rem;
    background-color: var(--tblr-bg-surface-secondary, rgba(0, 0, 0, .08));
}

/* --- Alternating row colors for card-table data tables --- */
/* Global zebra striping — applies to every Tabler .card-table so list pages
   don't each need their own .table-striped class. Uses a subtle background
   that works in both light and dark themes via the --tblr-bg-surface-tertiary var. */
.table.card-table > tbody > tr:nth-child(even) > * {
    background-color: var(--tblr-bg-surface-tertiary, rgba(0, 0, 0, .025));
}
[data-bs-theme="dark"] .table.card-table > tbody > tr:nth-child(even) > * {
    background-color: rgba(255, 255, 255, .03);
}

/* Sidebar submenu — inline expansion (BS5 collapse) inside .navbar-vertical.
   Nested nav items use the same look as top-level but slightly muted so the
   hierarchy reads clearly. */
.navbar-vertical .nav-sidebar-submenu { margin: 0; padding-left: 0; list-style: none; }
.navbar-vertical .nav-sidebar-submenu .nav-link { padding-block: .35rem; opacity: .85; }
.navbar-vertical .nav-sidebar-submenu .nav-link:hover { opacity: 1; }

/* Tabler's .nav-link-toggle class draws the chevron via ::after
   and rotates it 180° on [aria-expanded=true] — no custom rules needed. */

/* The sidebar has a small fixed set of items — suppress the browser scrollbar
   and OS-level scroll arrow buttons that Tabler's default overflow: auto causes
   when content is near the viewport boundary. */
.navbar-vertical .navbar-collapse {
    overflow: visible !important;
}
.navbar-vertical {
    overflow-y: auto;
    scrollbar-width: none;               /* Firefox */
}
.navbar-vertical::-webkit-scrollbar {    /* Chrome, Safari, Edge */
    width: 0;
    height: 0;
}

/* --- Sidebar hover + active states (dark theme) --- */

/* Hover on any top-level or submenu nav link — subtle lighter tint. */
.navbar-vertical .nav-link:hover {
    background-color: rgba(255, 255, 255, 0.06);
    color: #fff;
}

/* Active (current page) — accented background + left border + white text. */
.navbar-vertical .nav-item.active > .nav-link,
.navbar-vertical .nav-sidebar-submenu .nav-item.active > .nav-link {
    background-color: rgba(var(--tblr-primary-rgb, 6, 111, 209), 0.15);
    color: #fff;
    border-left: 3px solid var(--tblr-primary, #066fd1);
    padding-left: calc(var(--tblr-navbar-nav-link-padding-x, .75rem) - 3px);
}

/* Submenu items — tighter left padding accounts for the active border. */
.navbar-vertical .nav-sidebar-submenu .nav-item.active > .nav-link {
    padding-left: calc(1rem - 3px);
    opacity: 1;
}

/* --- Acumatica: error message viewer inside the batch-detail modal.
     Acumatica's 422 bodies can be hundreds of lines, so we cap height and
     allow line wrapping rather than horizontal scroll. */
.acumatica-error-block {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 320px;
    overflow: auto;
}

/* --- Acumatica: technical-details summary needs an obvious affordance.
     Default <summary> renders a tiny native marker that's easy to miss; we hide it
     and use a chevron that rotates 90deg when the accordion is open. */
.acumatica-tech-details summary {
    cursor: pointer;
    list-style: none;
}
.acumatica-tech-details summary::-webkit-details-marker {
    display: none;
}
.acumatica-tech-details summary .icon-chevron {
    transition: transform 0.15s ease;
}
.acumatica-tech-details[open] summary .icon-chevron {
    transform: rotate(90deg);
}

/* --- Acumatica: BR account chips on the error card.
     Yellow-on-yellow was overwhelming when there are dozens of unmapped accounts;
     this is a neutral chip with monospace digits and a per-chip copy button. */
.acumatica-account-chip {
    padding: 0.125rem 0.25rem 0.125rem 0.5rem;
    border: 1px solid var(--tblr-border-color, #dee2e6);
    border-radius: 0.25rem;
    background: var(--tblr-bg-surface-secondary, #f8f9fa);
    font-size: 0.8125rem;
    color: var(--tblr-body-color, #1f2937);
}

/* --- Acumatica: GL lines table can be 100+ rows; keep the header visible while scrolling. */
.acumatica-lines-table {
    max-height: 60vh;
    overflow: auto;
}
.acumatica-lines-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--tblr-bg-surface, #fff);
}
.acumatica-lines-table tfoot td {
    position: sticky;
    bottom: 0;
    z-index: 1;
    background: var(--tblr-bg-surface, #fff);
    box-shadow: inset 0 1px 0 var(--tblr-border-color, #dee2e6);
}

/* --- Readability: WCAG contrast fixes (audited 2026-06-11, 4.5:1 target).
     Dark mode: Tabler's stock primary (#066fd1) and muted gray (#6b7280) sit
     at 2.9–3.7:1 on the dark surfaces — lighten links, outline buttons and
     secondary text only there. Ghost-danger red was 2.9:1 dark / 4.46:1 on
     striped rows in light — nudged both ways. */
[data-bs-theme="dark"] {
    --tblr-link-color: #74b6f3;
    --tblr-link-hover-color: #a3cdf6;
    --tblr-secondary-color: #98a2b3;  /* .text-secondary, footer, inactive tabs */
    --tblr-muted: #98a2b3;
}
[data-bs-theme="dark"] .btn-outline-primary {
    --tblr-btn-color: #74b6f3;
    --tblr-btn-border-color: #74b6f3;
}
[data-bs-theme="dark"] .btn-ghost-danger {
    --tblr-btn-color: #f27d7d;
}
/* These take a literal gray from the vendor build, not --tblr-secondary-color,
   so the variable override above can't reach them. */
[data-bs-theme="dark"] .footer {
    color: #98a2b3;
}
[data-bs-theme="dark"] .nav-tabs .nav-link:not(.active) {
    color: #98a2b3;
}
/* Row-link hover highlight uses --tblr-primary, which is too dim on dark rows. */
[data-bs-theme="dark"] a.row-link:hover .fw-medium,
[data-bs-theme="dark"] a.row-link:focus-visible .fw-medium {
    color: #74b6f3;
}
.btn-ghost-danger {
    --tblr-btn-color: #c92a2a;  /* stock #d63939 measured 4.46:1 on striped table rows */
}

/* Amber notes (stalled batches, stale balances): Tabler's .text-warning is
   2.1:1 on light surfaces — far too faint for text that carries information.
   Readable amber pair for both themes. */
.note-warning {
    color: #9a6700;
}
[data-bs-theme="dark"] .note-warning {
    color: #f0b357;
}

/* --- Dashboard: staggered card reveal. Each card animates in slightly after
     the previous one (driven by --dash-delay), so the page builds itself
     instead of popping in at once. Respects reduced-motion. */
.dash-reveal {
    opacity: 0;
    animation: dash-reveal 0.45s ease forwards;
    animation-delay: calc(var(--dash-delay, 0) * 70ms);
}
@keyframes dash-reveal {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .dash-reveal { animation: none; opacity: 1; }
}

/* --- Dashboard: pulse dot on the verdict strip. Breathing ring while healthy,
     solid + urgent ring when something needs attention. */
.dash-pulse-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    flex: 0 0 auto;
    position: relative;
    background: var(--tblr-secondary, #6c7a91);
}
.dash-pulse-dot::after {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px solid currentColor;
    opacity: 0;
}
.dash-pulse-dot[data-tone="ok"]      { background: var(--tblr-success, #2fb344); color: var(--tblr-success, #2fb344); }
.dash-pulse-dot[data-tone="warning"] { background: var(--tblr-warning, #f59f00); color: var(--tblr-warning, #f59f00); }
.dash-pulse-dot[data-tone="danger"]  { background: var(--tblr-danger, #d63939);  color: var(--tblr-danger, #d63939); }
.dash-pulse-dot[data-tone="ok"]::after,
.dash-pulse-dot[data-tone="warning"]::after,
.dash-pulse-dot[data-tone="danger"]::after {
    animation: dash-pulse 2s ease-out infinite;
}
@keyframes dash-pulse {
    0%   { transform: scale(0.6); opacity: 0.8; }
    70%  { transform: scale(1.6); opacity: 0; }
    100% { transform: scale(1.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .dash-pulse-dot::after { animation: none !important; }
}

/* --- Dashboard: provider health pills — status-page style, one dot per provider. */
.dash-provider-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid var(--tblr-border-color, #dee2e6);
    border-radius: 2rem;
    font-size: 0.8125rem;
    color: var(--tblr-body-color, #1f2937);
    background: var(--tblr-bg-surface, #fff);
}
.dash-provider-pill .dash-provider-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--tblr-success, #2fb344);
}
.dash-provider-pill.is-degraded {
    border-color: var(--tblr-danger, #d63939);
    color: var(--tblr-danger, #d63939);
}
.dash-provider-pill.is-degraded .dash-provider-dot {
    background: var(--tblr-danger, #d63939);
    animation: dash-pulse 1.2s ease-out infinite;
}

/* --- Dashboard: attention chips on the pulse strip — each is a deep link to
     the page where the problem gets fixed. */
.dash-attention-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.3rem 0.75rem;
    border-radius: 2rem;
    font-size: 0.8125rem;
    font-weight: 500;
    text-decoration: none;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.dash-attention-chip:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
    text-decoration: none;
}
.dash-attention-chip.is-warning {
    background: var(--tblr-warning-lt, #fcf0db);
    /* NOT var(--tblr-warning): that amber is 2.1:1 on the -lt background. */
    color: #9a6700;
}
[data-bs-theme="dark"] .dash-attention-chip.is-warning {
    color: #f0b357;
}
.dash-attention-chip.is-danger {
    background: var(--tblr-danger-lt, #fbebeb);
    color: var(--tblr-danger, #d63939);
}

/* --- Soft action buttons (btn-soft-*) — the paved-path family for action
     buttons per CLAUDE.md. Tabler v1.4.0 ships no soft button variant, so the
     classes rendered as bare white .btn until defined here. Built on Tabler's
     --tblr-btn-* variable API: tinted -lt resting state (same pairing as the
     soft badges), solid fill on hover/active so the pressed affordance is
     unmistakable. The -lt tokens are theme-scoped, so dark mode tints follow
     automatically; text colors reuse the values from the 2026-06 contrast pass
     where the stock token fell below AA. */
.btn-soft-primary {
    --tblr-btn-color: var(--tblr-primary);
    --tblr-btn-bg: var(--tblr-primary-lt);
    --tblr-btn-border-color: transparent;
    --tblr-btn-hover-color: var(--tblr-primary-fg, #fff);
    --tblr-btn-hover-bg: var(--tblr-primary);
    --tblr-btn-hover-border-color: transparent;
    --tblr-btn-active-color: var(--tblr-primary-fg, #fff);
    --tblr-btn-active-bg: var(--tblr-primary-darken, var(--tblr-primary));
    --tblr-btn-active-border-color: transparent;
    --tblr-btn-disabled-color: var(--tblr-primary);
    --tblr-btn-disabled-bg: var(--tblr-primary-lt);
}
.btn-soft-secondary {
    --tblr-btn-color: var(--tblr-secondary);
    --tblr-btn-bg: var(--tblr-secondary-lt);
    --tblr-btn-border-color: transparent;
    --tblr-btn-hover-color: var(--tblr-secondary-fg, #fff);
    --tblr-btn-hover-bg: var(--tblr-secondary);
    --tblr-btn-hover-border-color: transparent;
    --tblr-btn-active-color: var(--tblr-secondary-fg, #fff);
    --tblr-btn-active-bg: var(--tblr-secondary-darken, var(--tblr-secondary));
    --tblr-btn-active-border-color: transparent;
    --tblr-btn-disabled-color: var(--tblr-secondary);
    --tblr-btn-disabled-bg: var(--tblr-secondary-lt);
}
.btn-soft-success {
    --tblr-btn-color: var(--tblr-success);
    --tblr-btn-bg: var(--tblr-success-lt);
    --tblr-btn-border-color: transparent;
    --tblr-btn-hover-color: var(--tblr-success-fg, #fff);
    --tblr-btn-hover-bg: var(--tblr-success);
    --tblr-btn-hover-border-color: transparent;
    --tblr-btn-active-color: var(--tblr-success-fg, #fff);
    --tblr-btn-active-bg: var(--tblr-success-darken, var(--tblr-success));
    --tblr-btn-active-border-color: transparent;
    --tblr-btn-disabled-color: var(--tblr-success);
    --tblr-btn-disabled-bg: var(--tblr-success-lt);
}
.btn-soft-warning {
    /* NOT var(--tblr-warning) for text: that amber is 2.1:1 on the -lt tint
       (same finding as .note-warning / .dash-attention-chip). */
    --tblr-btn-color: #9a6700;
    --tblr-btn-bg: var(--tblr-warning-lt);
    --tblr-btn-border-color: transparent;
    --tblr-btn-hover-color: var(--tblr-warning-fg, #fff);
    --tblr-btn-hover-bg: var(--tblr-warning);
    --tblr-btn-hover-border-color: transparent;
    --tblr-btn-active-color: var(--tblr-warning-fg, #fff);
    --tblr-btn-active-bg: var(--tblr-warning-darken, var(--tblr-warning));
    --tblr-btn-active-border-color: transparent;
    --tblr-btn-disabled-color: #9a6700;
    --tblr-btn-disabled-bg: var(--tblr-warning-lt);
}
.btn-soft-danger {
    /* #c92a2a: stock danger red measured 4.46:1 on light tints (see .btn-ghost-danger). */
    --tblr-btn-color: #c92a2a;
    --tblr-btn-bg: var(--tblr-danger-lt);
    --tblr-btn-border-color: transparent;
    --tblr-btn-hover-color: var(--tblr-danger-fg, #fff);
    --tblr-btn-hover-bg: var(--tblr-danger);
    --tblr-btn-hover-border-color: transparent;
    --tblr-btn-active-color: var(--tblr-danger-fg, #fff);
    --tblr-btn-active-bg: var(--tblr-danger-darken, var(--tblr-danger));
    --tblr-btn-active-border-color: transparent;
    --tblr-btn-disabled-color: #c92a2a;
    --tblr-btn-disabled-bg: var(--tblr-danger-lt);
}
/* Dark-theme text legibility on the darker -lt tints — same audited values as
   the link/outline/ghost overrides above. */
[data-bs-theme="dark"] .btn-soft-primary {
    --tblr-btn-color: #74b6f3;
    --tblr-btn-disabled-color: #74b6f3;
}
[data-bs-theme="dark"] .btn-soft-secondary {
    --tblr-btn-color: #98a2b3;
    --tblr-btn-disabled-color: #98a2b3;
}
[data-bs-theme="dark"] .btn-soft-warning {
    --tblr-btn-color: #f0b357;
    --tblr-btn-disabled-color: #f0b357;
}
[data-bs-theme="dark"] .btn-soft-danger {
    --tblr-btn-color: #f27d7d;
    --tblr-btn-disabled-color: #f27d7d;
}

/* --- Bill payment provider form: product/package cards collapse to a one-line
     header so a provider with many products stays scannable. Chevron points
     right when collapsed, down when expanded. Direct-child selector so a
     product's chevron is not affected by its nested package cards. */
.js-toggle-card .icon-chevron {
    transition: transform 0.15s ease;
    transform: rotate(90deg);
}
.card-collapsed > .card-header .js-toggle-card .icon-chevron {
    transform: none;
}

/* Bootstrap sizes a scrollable modal's .modal-body as a flex child of .modal-content. Our modals
   wrap header, body and footer in a <form>, which breaks that chain: the body never shrinks, so
   long content (the role permission matrix) is clipped with no scrollbar. Restore the chain on
   the form so the body scrolls and the footer stays in view. */
.modal-dialog-scrollable .modal-content > form {
    display: flex;
    flex-direction: column;
    min-height: 0;
    max-height: 100%;
    overflow: hidden;
}
