/* ==========================================================================
   ERP — application shell and shared component styles
   --------------------------------------------------------------------------
   Loaded after bootstrap.min.css, which is served from wwwroot/lib. There is no
   CDN reference anywhere in this application: a POS terminal in a shop has to
   work on a LAN with the internet down, and a stylesheet that arrives from
   somewhere else is a stylesheet that can fail to arrive.

   Section order:
     1.  Design tokens (light)
     2.  Dark theme
     3.  Base and typography
     4.  Accessibility primitives
     5.  Icons
     6.  Topbar
     7.  Sidebar
     8.  Content region
     9.  Breadcrumbs and page header
     10. Filter bar and chips
     11. Dense tables
     12. Forms
     13. Badges
     14. Empty state
     15. Pagination
     16. Toasts
     17. Confirm modal and loading overlay
     18. Auth layout
     19. Error pages
     20. Responsive
     21. Print
     22. Reduced motion
   ========================================================================== */

/* ---------- 1. Design tokens (UI_WIREFRAMES.md §0) ---------------------- */

:root {
    /* Neutrals — the actual UI */
    --bg-app: #f2f4f7;
    --bg-surface: #ffffff;
    --bg-subtle: #f7f9fb;
    --bg-sidebar: #1b2534;
    --bg-sidebar-hi: #26334a;
    --border: #d5dbe3;
    --border-strong: #b3bcc9;
    --text-primary: #1a2230;
    --text-secondary: #5a6675;
    --text-muted: #8a94a3;
    --text-invert: #e8edf4;
    --text-invert-muted: #98a5b8;

    /* Brand accent — exactly one, used for primary action and active nav only */
    --accent: #1c64d1;
    --accent-hover: #164fa6;
    --accent-subtle: #e8f0fd;

    /* Semantic. Every pairing below is verified at >= 4.5:1 for text. */
    --success: #1f7a45;
    --success-subtle: #e6f4ec;
    --warning: #9a6400;
    --warning-subtle: #fdf3e2;
    --danger: #b3261e;
    --danger-subtle: #fdeceb;
    --info: #0f6b7a;
    --info-subtle: #e5f4f6;
    --slate: #4a5563;
    --slate-subtle: #eef1f5;

    /* Typography — system stack. No webfont on the POS critical path. */
    --font-ui: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --font-num: "Segoe UI", "SF Mono", Consolas, monospace;
    --text-xs: .75rem;
    --text-sm: .8125rem;
    --text-base: .875rem;  /* 14px. ERP density baseline, not 16px. */
    --text-md: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;

    /* Spacing — 4px grid */
    --space-1: .25rem;
    --space-2: .5rem;
    --space-3: .75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-12: 3rem;

    /* Structure */
    --sidebar-w: 240px;
    --sidebar-w-collapsed: 64px;
    --topbar-h: 56px;
    --posbar-h: 44px;
    --content-max: 1600px;
    --radius: 4px;
    --radius-lg: 6px;
    --row-h: 36px;
    --control-h: 32px;
    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);
    --shadow-md: 0 4px 12px rgba(16, 24, 40, .10);
    --shadow-modal: 0 16px 48px rgba(16, 24, 40, .22);
    --z-topbar: 1030;   /* superseded: .erp-topbar now sits above --z-sidebar so its dropdowns are not clipped */
    --z-sidebar: 1040;
    --z-modal: 1055;
    --z-toast: 1080;

    /* Bootstrap variable overrides, so Bootstrap's own components inherit the palette
       instead of us re-skinning every one of them by hand. */
    --bs-body-font-family: var(--font-ui);
    --bs-body-font-size: var(--text-base);
    --bs-body-color: var(--text-primary);
    --bs-body-bg: var(--bg-app);
    --bs-border-color: var(--border);
    --bs-border-radius: var(--radius);
    --bs-border-radius-sm: var(--radius);
    --bs-primary: var(--accent);
    --bs-link-color: var(--accent);
    --bs-link-hover-color: var(--accent-hover);
}

/* ---------- 2. Dark theme -----------------------------------------------
   POS terminals run in dim retail units for long shifts, so dark mode is a
   requirement, not decoration. The explicit [data-theme] attributes win over
   the media query in both directions, so a user who has chosen light on a
   dark-set OS keeps light.
   ---------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg-app: #12171f;
        --bg-surface: #1a212c;
        --bg-subtle: #212a37;
        --bg-sidebar: #151b25;
        --bg-sidebar-hi: #242f40;
        --border: #2e3a4a;
        --border-strong: #415063;
        --text-primary: #e6ebf2;
        --text-secondary: #a3aebd;
        --text-muted: #788494;
        --accent: #4b8ef0;
        --accent-hover: #6ba3f5;
        --accent-subtle: #1b2c47;
        --success: #4cc38a;
        --success-subtle: #14301f;
        --warning: #e0a13a;
        --warning-subtle: #33260d;
        --danger: #f27c72;
        --danger-subtle: #3a1714;
        --info: #4fbdd0;
        --info-subtle: #102c31;
        --slate: #97a3b3;
        --slate-subtle: #242c37;
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
        --shadow-md: 0 4px 12px rgba(0, 0, 0, .5);
        --shadow-modal: 0 16px 48px rgba(0, 0, 0, .6);
    }
}

:root[data-theme="dark"] {
    --bg-app: #12171f;
    --bg-surface: #1a212c;
    --bg-subtle: #212a37;
    --bg-sidebar: #151b25;
    --bg-sidebar-hi: #242f40;
    --border: #2e3a4a;
    --border-strong: #415063;
    --text-primary: #e6ebf2;
    --text-secondary: #a3aebd;
    --text-muted: #788494;
    --accent: #4b8ef0;
    --accent-hover: #6ba3f5;
    --accent-subtle: #1b2c47;
    --success: #4cc38a;
    --success-subtle: #14301f;
    --warning: #e0a13a;
    --warning-subtle: #33260d;
    --danger: #f27c72;
    --danger-subtle: #3a1714;
    --info: #4fbdd0;
    --info-subtle: #102c31;
    --slate: #97a3b3;
    --slate-subtle: #242c37;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, .5);
    --shadow-modal: 0 16px 48px rgba(0, 0, 0, .6);
}

:root[data-theme="dark"] {
    color-scheme: dark;
}

:root[data-theme="light"] {
    color-scheme: light;
}

/* ---------- 3. Base and typography -------------------------------------- */

html,
body {
    height: 100%;
}

.erp-body {
    margin: 0;
    background: var(--bg-app);
    color: var(--text-primary);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--text-primary);
    font-weight: 600;
    margin: 0;
}

a {
    color: var(--accent);
    text-decoration: none;
}

a:hover {
    color: var(--accent-hover);
    text-decoration: underline;
}

/* Numbers right-align with tabular figures and fixed decimals — a column of
   money that jitters as digits change is a column nobody can scan. */
.erp-num,
.erp-table td.erp-num,
.erp-table th.erp-num {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* ---------- 4. Accessibility primitives ---------------------------------- */

.erp-skiplink {
    position: absolute;
    left: var(--space-2);
    top: -100%;
    z-index: calc(var(--z-toast) + 1);
    padding: var(--space-2) var(--space-4);
    background: var(--bg-surface);
    color: var(--accent);
    border: 2px solid var(--accent);
    border-radius: var(--radius);
    font-weight: 600;
}

.erp-skiplink:focus {
    top: var(--space-2);
}

/* One visible focus ring, everywhere, never removed without replacement. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius);
}

/* Inside the dark sidebar the accent ring is too low-contrast, so the ring
   inverts there rather than disappearing. */
.erp-sidebar :where(a, button):focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: -2px;
}

/* Focus moved programmatically to <main> or <h1> must not draw a ring the user
   did not ask for, but focus-visible still applies for keyboard users. */
#main-content:focus:not(:focus-visible),
.erp-pageheader__title:focus:not(:focus-visible) {
    outline: none;
}

/* ---------- 5. Icons ----------------------------------------------------- */

.erp-sprite {
    display: none;
}

.erp-icon {
    width: 1.125em;
    height: 1.125em;
    flex: 0 0 auto;
    vertical-align: -.15em;
}

/* ---------- 6. Topbar ---------------------------------------------------- */

/* Above the sidebar, not below it. The sidebar sits at --z-sidebar (1040) and the topbar was at
   1030, so the branch switcher's dropdown — which hangs down over the sidebar's column — was
   painted behind it and the lower entries could not be read or clicked. The topbar is a fixed
   56px strip that nothing needs to overlap, so raising it costs nothing. */
.erp-topbar {
    position: fixed;
    inset: 0 0 auto 0;
    height: var(--topbar-h);
    z-index: calc(var(--z-sidebar) + 1);
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: 0 var(--space-4);
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
}

.erp-topbar__left {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
}

.erp-topbar__search {
    flex: 1 1 auto;
    display: flex;
    justify-content: center;
    min-width: 0;
}

.erp-topbar__right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

.erp-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid transparent;
    border-radius: var(--radius);
    background: transparent;
    color: var(--text-secondary);
    padding: 0;
}

.erp-iconbtn:hover {
    background: var(--bg-subtle);
    color: var(--text-primary);
    text-decoration: none;
}

.erp-brand {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--text-primary);
    font-weight: 600;
    white-space: nowrap;
}

.erp-brand:hover {
    text-decoration: none;
    color: var(--text-primary);
}

.erp-brand__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: var(--radius);
    background: var(--accent);
    color: #ffffff;
    font-weight: 700;
    font-size: var(--text-sm);
}

.erp-brand__mark--lg {
    width: 44px;
    height: 44px;
    font-size: var(--text-xl);
}

/* Branch switcher — visually distinctive because operating in the wrong branch
   is the most expensive user error in the product. */
.erp-branch {
    margin: 0;
}

.erp-branch__btn,
.erp-branch--static {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: var(--control-h);
    padding: 0 var(--space-3);
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--bg-subtle);
    color: var(--text-primary);
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
}

.erp-branch__btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.erp-branch--static {
    margin: 0;
    cursor: default;
}

.erp-search {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
    max-width: 520px;
}

.erp-search__icon {
    position: absolute;
    left: var(--space-3);
    color: var(--text-muted);
    pointer-events: none;
}

.erp-search__input {
    width: 100%;
    height: var(--control-h);
    padding: 0 3.25rem 0 2.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-subtle);
    color: var(--text-primary);
    font-size: var(--text-sm);
}

.erp-search__input::placeholder {
    color: var(--text-muted);
}

.erp-search__input:focus {
    background: var(--bg-surface);
    border-color: var(--accent);
}

.erp-search__kbd {
    position: absolute;
    right: var(--space-2);
    padding: .1rem .35rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-surface);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-family: var(--font-num);
}

.erp-badgebtn {
    position: relative;
}

.erp-badgebtn__count {
    position: absolute;
    top: 1px;
    right: 1px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    color: #ffffff;
}

.erp-badgebtn__count--info {
    background: var(--accent);
}

.erp-badgebtn__count--warning {
    background: #8a5a00;
}

/* Red once anything has been waiting more than four hours. An invisible
   approval queue stalls the shop floor; this is the escalation signal. */
.erp-badgebtn__count--overdue {
    background: var(--danger);
}

.erp-usermenu__btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: var(--control-h);
    padding: 0 var(--space-2);
    border: 1px solid transparent;
    border-radius: var(--radius);
    background: transparent;
    color: var(--text-primary);
    font-size: var(--text-sm);
}

.erp-usermenu__btn:hover {
    background: var(--bg-subtle);
}

.erp-usermenu__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 999px;
    background: var(--slate-subtle);
    color: var(--text-secondary);
    font-weight: 700;
    font-size: var(--text-xs);
}

.erp-dropdown {
    min-width: 240px;
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-surface);
    box-shadow: var(--shadow-md);
    font-size: var(--text-sm);
}

.erp-dropdown__title {
    margin: 0 0 var(--space-2);
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.erp-dropdown__header {
    padding: var(--space-2);
}

.erp-dropdown__name {
    margin: 0;
    font-weight: 600;
}

.erp-dropdown__meta {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.erp-dropdown .dropdown-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    width: 100%;
    border-radius: var(--radius);
    padding: var(--space-2);
    color: var(--text-primary);
    text-align: left;
}

.erp-dropdown .dropdown-item:hover,
.erp-dropdown .dropdown-item:focus {
    background: var(--accent-subtle);
    color: var(--text-primary);
}

.erp-dropdown__item.is-active {
    font-weight: 600;
    color: var(--accent);
}

.erp-dropdown__item--danger {
    color: var(--danger);
}

/* ---------- 7. Sidebar --------------------------------------------------- */

.erp-sidebar {
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    z-index: var(--z-sidebar);
    display: flex;
    flex-direction: column;
    background: var(--bg-sidebar);
    color: var(--text-invert);
    transition: width .15s ease, transform .15s ease;
}

.erp-sidebar__scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--space-2) 0;
}

.erp-nav,
.erp-nav__leaves {
    list-style: none;
    margin: 0;
    padding: 0;
}

.erp-nav__group-toggle,
.erp-nav__group-link,
.erp-sidebar__footer-btn {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    min-height: 38px;
    padding: 0 var(--space-4);
    border: 0;
    background: transparent;
    color: var(--text-invert);
    font-size: var(--text-base);
    text-align: left;
}

.erp-nav__group-toggle:hover,
.erp-nav__group-link:hover,
.erp-sidebar__footer-btn:hover {
    background: var(--bg-sidebar-hi);
    color: #ffffff;
    text-decoration: none;
}

.erp-nav__group-toggle.is-active,
.erp-nav__group-link.is-active {
    background: var(--bg-sidebar-hi);
    color: #ffffff;
    box-shadow: inset 3px 0 0 var(--accent);
}

.erp-nav__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.erp-nav__caret {
    flex: 0 0 auto;
    transition: transform .15s ease;
    color: var(--text-invert-muted);
}

.erp-nav__group-toggle[aria-expanded="true"] .erp-nav__caret {
    transform: rotate(180deg);
}

.erp-nav__panel {
    padding: var(--space-1) 0 var(--space-2);
}

.erp-nav__section-title {
    margin: var(--space-2) 0 var(--space-1);
    padding: 0 var(--space-4) 0 calc(var(--space-4) + 1.9rem);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-invert-muted);
}

.erp-nav__leaf {
    display: block;
    padding: 5px var(--space-4) 5px calc(var(--space-4) + 1.9rem);
    color: #c4cfdd;
    font-size: var(--text-sm);
}

.erp-nav__leaf:hover {
    background: var(--bg-sidebar-hi);
    color: #ffffff;
    text-decoration: none;
}

.erp-nav__leaf.is-active {
    background: var(--bg-sidebar-hi);
    color: #ffffff;
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--accent);
}

/* Category folders. Indented less than a plain leaf because the icon supplies the indent, and
   laid out as a row so the brand count can sit hard right without wrapping the name. */
.erp-nav__leaf--folder {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding-left: calc(var(--space-4) + .9rem);
}

.erp-nav__leaf--folder .erp-icon {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    opacity: .75;
}

.erp-nav__leaf--folder > span:first-of-type {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The brand count. Tabular figures so the numbers line up down the column rather than jittering
   with the width of each digit. */
.erp-nav__count {
    flex: 0 0 auto;
    min-width: 1.5rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .1);
    color: var(--text-invert-muted);
    font-size: .7rem;
    line-height: 1.35;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.erp-nav__leaf--folder:hover .erp-nav__count,
.erp-nav__leaf--folder.is-active .erp-nav__count {
    background: rgba(255, 255, 255, .18);
    color: #ffffff;
}

.erp-sidebar__footer {
    flex: 0 0 auto;
    border-top: 1px solid rgba(255, 255, 255, .08);
    padding: var(--space-2) 0;
}

.erp-sidebar__version {
    margin: var(--space-1) 0 0;
    padding: 0 var(--space-4);
    font-size: var(--text-xs);
    color: var(--text-invert-muted);
}

/* Collapsed 64px icon rail. Labels are hidden visually but the accessible name
   survives, because a rail whose buttons announce nothing is unusable. */
.erp-shell--collapsed .erp-sidebar {
    width: var(--sidebar-w-collapsed);
}

.erp-shell--collapsed .erp-nav__label,
.erp-shell--collapsed .erp-nav__caret,
.erp-shell--collapsed .erp-nav__section-title,
.erp-shell--collapsed .erp-sidebar__version {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.erp-shell--collapsed .erp-nav__leaf {
    padding-left: var(--space-4);
    font-size: var(--text-xs);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.erp-shell--collapsed .erp-content {
    margin-left: var(--sidebar-w-collapsed);
}

.erp-sidebar-backdrop {
    position: fixed;
    inset: var(--topbar-h) 0 0 0;
    z-index: calc(var(--z-sidebar) - 1);
    background: rgba(16, 24, 40, .45);
}

.erp-sidebar-backdrop[hidden] {
    display: none;
}

/* ---------- 8. Content region -------------------------------------------- */

.erp-content {
    margin-left: var(--sidebar-w);
    padding-top: var(--topbar-h);
    min-height: 100vh;
    transition: margin-left .15s ease;
}

.erp-content__inner {
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-3) var(--space-5) var(--space-8);
}

.erp-main {
    display: block;
}

.erp-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-4);
}

/* ---------- 9. Breadcrumbs and page header ------------------------------- */

.erp-breadcrumbs {
    min-height: 32px;
    display: flex;
    align-items: center;
}

.erp-breadcrumbs__list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.erp-breadcrumbs__item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.erp-breadcrumbs__sep {
    color: var(--text-muted);
}

.erp-breadcrumbs__current {
    color: var(--text-primary);
    font-weight: 600;
}

.erp-breadcrumbs__gap {
    color: var(--text-muted);
    cursor: help;
}

.erp-pageheader {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    min-height: 52px;
    padding: var(--space-2) 0 var(--space-3);
}

.erp-pageheader__titlerow {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.erp-pageheader__title {
    font-size: var(--text-xl);
    font-weight: 600;
}

.erp-pageheader__subtitle {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.erp-pageheader__actions {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.erp-pageheader__actions .btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* ---------- 10. Filter bar and chips ------------------------------------- */

.erp-filterbar {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-3);
    margin-bottom: var(--space-3);
}

/* Page-header on a white card too, so a page opens on a clean surface rather than the page title
   floating on the grey background. The standard header is a flex row holding the title and the
   primary action; give it a card surface wherever it appears at the top of a content page. */
.erp-content__inner .d-flex.justify-content-between.align-items-start.mb-3 {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-3) !important;
}

.erp-filterbar__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.erp-filterbar__search {
    position: relative;
    flex: 1 1 260px;
    min-width: 200px;
}

.erp-filterbar__searchicon {
    position: absolute;
    left: .75rem;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--text-muted);
    pointer-events: none;
}

/* Clear the icon: padding must beat Bootstrap's own .form-control(-sm) left padding, hence
   !important — otherwise the placeholder text starts under the magnifier. */
.erp-filterbar__input.erp-filterbar__input,
.erp-filterbar .erp-filterbar__input {
    padding-left: 2.4rem !important;
}

.erp-filterbar__field {
    flex: 0 1 180px;
}

.erp-filterbar__popover {
    min-width: 280px;
    padding: var(--space-3);
}

.erp-filterbar__popfield + .erp-filterbar__popfield {
    margin-top: var(--space-3);
}

.erp-filterbar__buttons {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

.erp-filterbar__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px dashed var(--border);
}

.erp-filterbar__chipslabel {
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.erp-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-1) 2px var(--space-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-subtle);
    font-size: var(--text-xs);
}

.erp-chip__remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--text-secondary);
    padding: 0;
}

.erp-chip__remove:hover {
    background: var(--danger-subtle);
    color: var(--danger);
}

/* ---------- 11. Dense tables (UI_WIREFRAMES.md §3.3) --------------------- */

.erp-tablewrap {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: auto;
}

.erp-table {
    width: 100%;
    margin: 0;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--text-sm);
}

.erp-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    height: var(--row-h);
    padding: var(--space-2) var(--space-3);
    background: var(--bg-subtle);
    border-bottom: 1px solid var(--border-strong);
    color: var(--text-secondary);
    font-weight: 600;
    text-align: left;
    white-space: nowrap;
}

.erp-table tbody td {
    height: var(--row-h);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

.erp-table tbody tr:nth-child(even) td {
    background: var(--bg-subtle);
}

.erp-table tbody tr:hover td {
    background: var(--accent-subtle);
}

.erp-table tbody tr:last-child td {
    border-bottom: 0;
}

.erp-table th.erp-col-status,
.erp-table td.erp-col-status {
    text-align: center;
}

.erp-table th.erp-col-actions,
.erp-table td.erp-col-actions {
    text-align: right;
    width: 1%;
    white-space: nowrap;
}

/* Sortable headers are real buttons so they are reachable and operable by
   keyboard; aria-sort carries the state. */
.erp-table__sort {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    border: 0;
    background: transparent;
    padding: 0;
    color: inherit;
    font: inherit;
    font-weight: 600;
}

.erp-table th[aria-sort="ascending"] .erp-table__sort,
.erp-table th[aria-sort="descending"] .erp-table__sort {
    color: var(--text-primary);
}

/* Busy state during an in-place refresh: the body dims, the header stays crisp. */
.erp-tablewrap[aria-busy="true"] tbody {
    opacity: .4;
    pointer-events: none;
}

/* ---------- 12. Forms ---------------------------------------------------- */

.form-label {
    margin-bottom: var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
}

.form-control,
.form-select {
    min-height: var(--control-h);
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-surface);
    color: var(--text-primary);
    font-size: var(--text-sm);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-subtle);
}

.form-control::placeholder {
    color: var(--text-muted);
}

/* A disabled field still has to be readable — an unreadable disabled field is
   an unreadable field. 3:1 minimum against its own background. */
.form-control:disabled,
.form-select:disabled,
.form-control[readonly] {
    background: var(--bg-subtle);
    color: var(--text-secondary);
    opacity: 1;
}

.form-control.is-invalid,
.form-select.is-invalid {
    border-color: var(--danger);
}

.erp-required {
    color: var(--danger);
    margin-left: 2px;
}

.erp-field-error {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-xs);
    color: var(--danger);
}

.erp-formgrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3) var(--space-5);
}

.erp-formgrid--full {
    grid-column: 1 / -1;
}

.btn {
    font-size: var(--text-sm);
    border-radius: var(--radius);
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}

.btn-primary:hover,
.btn-primary:focus {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: #ffffff;
}

.erp-validation {
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-4);
}

.erp-validation__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.erp-validation__title {
    margin: 0;
    font-weight: 600;
}

.erp-validation__list {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-6);
}

/* ---------- 13. Badges (UI_WIREFRAMES.md §13.6) -------------------------- */

.erp-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 1px var(--space-2);
    border: 1px solid transparent;
    border-radius: var(--radius);
    font-size: var(--text-xs);
    font-weight: 600;
    white-space: nowrap;
}

.erp-badge--draft {
    background: var(--slate-subtle);
    border-color: var(--border-strong);
    color: var(--text-secondary);
}

.erp-badge--pending {
    background: var(--warning-subtle);
    border-color: var(--warning);
    color: var(--warning);
}

.erp-badge--success {
    background: var(--success-subtle);
    border-color: var(--success);
    color: var(--success);
}

.erp-badge--progress {
    background: var(--info-subtle);
    border-color: var(--info);
    color: var(--info);
}

.erp-badge--negative {
    background: var(--danger-subtle);
    border-color: var(--danger);
    color: var(--danger);
}

.erp-badge--closed {
    background: var(--slate-subtle);
    border-color: var(--slate);
    color: var(--slate);
}

/* ---------- 14. Empty state ---------------------------------------------- */

.erp-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-12) var(--space-4);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    text-align: center;
}

.erp-empty__icon {
    width: 40px;
    height: 40px;
    color: var(--text-muted);
}

.erp-empty__title {
    margin: 0;
    font-size: var(--text-md);
    font-weight: 600;
}

.erp-empty__message {
    margin: 0;
    max-width: 44ch;
    color: var(--text-secondary);
}

.erp-empty__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

/* ---------- 15. Pagination ------------------------------------------------ */

.erp-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-1);
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.erp-pagination__summary {
    margin: 0;
}

.erp-pagination__size,
.erp-pagination__jump {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.erp-pagination__size .form-select,
.erp-pagination__jump .form-control {
    width: auto;
    min-width: 74px;
}

.erp-pagination__sizelabel {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
    white-space: nowrap;
}

.erp-pagination__pages {
    margin: 0 0 0 auto;
}

/* ---------- 16. Toasts ---------------------------------------------------- */

.erp-toasts {
    position: fixed;
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: var(--z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    pointer-events: none;
    max-width: min(380px, calc(100vw - 2rem));
}

.erp-toasts__stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.erp-toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-left: 3px solid var(--slate);
    border-radius: var(--radius-lg);
    background: var(--bg-surface);
    box-shadow: var(--shadow-md);
    pointer-events: auto;
}

.erp-toast--success {
    border-left-color: var(--success);
}

.erp-toast--success .erp-toast__icon {
    color: var(--success);
}

.erp-toast--error {
    border-left-color: var(--danger);
}

.erp-toast--error .erp-toast__icon {
    color: var(--danger);
}

.erp-toast--warning {
    border-left-color: var(--warning);
}

.erp-toast--warning .erp-toast__icon {
    color: var(--warning);
}

.erp-toast--info {
    border-left-color: var(--info);
}

.erp-toast--info .erp-toast__icon {
    color: var(--info);
}

.erp-toast__body {
    flex: 1 1 auto;
    min-width: 0;
}

.erp-toast__message {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.erp-toast__action {
    display: inline-block;
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
}

.erp-toast__close {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    color: var(--text-muted);
    padding: 0;
}

.erp-toast__close:hover {
    background: var(--bg-subtle);
    color: var(--text-primary);
}

/* ---------- 17. Confirm modal and loading overlay ------------------------ */

.erp-confirm .modal-content {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-surface);
    box-shadow: var(--shadow-modal);
}

.erp-confirm .modal-title {
    font-size: var(--text-md);
}

.erp-confirm__body {
    margin: 0;
}

.erp-confirm__consequence {
    margin: var(--space-3) 0 0;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    background: var(--warning-subtle);
    color: var(--text-primary);
    font-size: var(--text-sm);
}

.erp-confirm__typed {
    margin-top: var(--space-3);
}

.erp-confirm__expected {
    margin: 0 0 var(--space-1);
    font-family: var(--font-num);
    font-weight: 700;
}

.erp-loading {
    position: fixed;
    inset: 0;
    z-index: calc(var(--z-modal) + 5);
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(16, 24, 40, .35);
}

.erp-loading[hidden] {
    display: none;
}

.erp-loading__panel {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-6);
    border-radius: var(--radius-lg);
    background: var(--bg-surface);
    box-shadow: var(--shadow-modal);
    font-size: var(--text-sm);
}

.erp-loading__spinner {
    width: 1.25rem;
    height: 1.25rem;
    border-width: .15em;
    color: var(--accent);
}

/* Inline button busy state. The width is preserved so the layout cannot shift
   under the user's cursor mid-click. */
.btn[data-erp-busy="true"] {
    pointer-events: none;
    opacity: .75;
}

/* ---------- 18. Auth layout ----------------------------------------------- */

.erp-body--auth {
    background: var(--bg-app);
}

.erp-auth {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    padding: var(--space-6) var(--space-4);
}

.erp-auth__card {
    width: 100%;
    max-width: 400px;
    padding: var(--space-8);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.erp-auth__brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-6);
}

.erp-auth__company {
    margin: 0;
    font-size: var(--text-lg);
    font-weight: 600;
}

.erp-auth__footer {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

/* ---------- 19. Error pages ----------------------------------------------- */

.erp-errorpage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    max-width: 560px;
    margin: var(--space-12) auto;
    padding: var(--space-8);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    text-align: center;
}

.erp-errorpage__icon {
    width: 48px;
    height: 48px;
    color: var(--text-muted);
}

.erp-errorpage__code {
    margin: 0;
    font-family: var(--font-num);
    font-size: var(--text-2xl);
    font-weight: 700;
    color: var(--text-muted);
    letter-spacing: .08em;
}

.erp-errorpage__title {
    margin: 0;
    font-size: var(--text-xl);
}

.erp-errorpage__message {
    margin: 0;
    max-width: 46ch;
    color: var(--text-secondary);
}

.erp-errorpage__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.erp-errorpage__ref {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.erp-errorpage__ref code {
    font-family: var(--font-num);
    color: var(--text-secondary);
}

/* ---------- 20. Responsive (NAVIGATION.md §10) ---------------------------- */

@media (max-width: 1279px) {
    .erp-search__kbd {
        display: none;
    }
}

/* 992–1199: sidebar becomes a 64px icon rail by default. */
@media (max-width: 1199px) {
    .erp-shell:not(.erp-shell--expanded) .erp-sidebar {
        width: var(--sidebar-w-collapsed);
    }

    .erp-shell:not(.erp-shell--expanded) .erp-content {
        margin-left: var(--sidebar-w-collapsed);
    }

    .erp-shell:not(.erp-shell--expanded) .erp-nav__label,
    .erp-shell:not(.erp-shell--expanded) .erp-nav__caret,
    .erp-shell:not(.erp-shell--expanded) .erp-nav__section-title,
    .erp-shell:not(.erp-shell--expanded) .erp-sidebar__version {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }
}

/* Below 992: off-canvas drawer, backdrop, closes on navigate. */
@media (max-width: 991px) {
    /* The drawer is the FULL sidebar width, never the 64px icon rail.
       The selector is deliberately as specific as the 1199px rule above it
       (`.erp-shell:not(.erp-shell--expanded) .erp-sidebar`, 0,3,0). Written as a
       bare `.erp-sidebar` at 0,1,0 it loses, and the drawer opens as a ~64px
       sliver with every label truncated — "Outgoing / Sale" rendering as "Ou /
       Sal". The menu looks broken rather than narrow, which is how this was
       reported: "the menu is still not opening".

       Same defect as the .erp-content margin below; both must carry the extra
       specificity or the 992–1199 rail rules leak into phone width. */
    .erp-sidebar,
    .erp-shell:not(.erp-shell--expanded) .erp-sidebar {
        width: var(--sidebar-w);
        box-shadow: var(--shadow-md);
    }

    /* Open and closed are stated at MATCHING specificity, and the closed state is
       written as :not(drawer-open) rather than as a blanket rule.

       Getting this wrong breaks the menu in one of two ways, and this file has now
       done both: too LOW and the 992–1199 rail rules win, so the drawer opens as a
       64px sliver with truncated labels; too HIGH on the closed state and it beats
       the open rule, so the drawer never slides in at all. Neither fails visibly in
       CSS — both look like "the menu is broken". */
    .erp-shell:not(.erp-shell--drawer-open) .erp-sidebar {
        transform: translateX(-100%);
    }

    .erp-shell--drawer-open .erp-sidebar,
    .erp-shell--drawer-open:not(.erp-shell--expanded) .erp-sidebar {
        transform: translateX(0);
    }

    /* The sidebar is a slide-over drawer below 991px, so the content must reclaim
       the full width.

       All three selectors are needed, and the third is the one that was missing:
       the 1199px block above sets `.erp-shell:not(.erp-shell--expanded) .erp-content`
       to the collapsed sidebar width. That selector scores 0,3,0 against the plain
       `.erp-content` here at 0,1,0 — so BELOW 991px the wider rule kept winning and
       every screen carried a phantom 64px margin, pushing its right-hand edge off a
       phone. Buttons, table columns and the Charge button were all cut off.

       Found by rendering the app at 390px rather than by reading the stylesheet:
       the breakpoints look correct in isolation and only conflict when both match. */
    .erp-content,
    .erp-shell--collapsed .erp-content,
    .erp-shell:not(.erp-shell--expanded) .erp-content {
        margin-left: 0;
    }

    /* Labels come back when the drawer is open.
       Paired with `:not(.erp-shell--expanded)` for the same specificity reason as
       the width above: the 1199px block visually-hides these at 0,3,0, and a bare
       `.erp-shell--drawer-open .erp-nav__label` at 0,2,0 loses — leaving an open
       drawer full of icons with no text. */
    /* TEXT elements only. `width/height: auto` is safe on a span of text and wrong
       on an SVG: the caret has no intrinsic size, so `auto` lets it expand to fill
       the row and the chevron renders several times the height of the icon beside
       it. The caret is un-hidden separately below, keeping its own dimensions.

       `white-space` is NOT reset either. The rail hides these with `nowrap`, and
       forcing `normal` here makes every label wrap — "Products / Goods" becomes
       three lines and each row grows to ~65px, so six items fill a phone screen. */
    .erp-shell--drawer-open .erp-nav__label,
    .erp-shell--drawer-open .erp-nav__section-title,
    .erp-shell--drawer-open .erp-sidebar__version,
    .erp-shell--drawer-open:not(.erp-shell--expanded) .erp-nav__label,
    .erp-shell--drawer-open:not(.erp-shell--expanded) .erp-nav__section-title,
    .erp-shell--drawer-open:not(.erp-shell--expanded) .erp-sidebar__version {
        position: static;
        width: auto;
        height: auto;
        overflow: visible;
        clip: auto;
    }

    /* The caret is an icon: make it visible again WITHOUT touching its box, and
       restate the size the sprite expects so it cannot inherit a stray one. */
    .erp-shell--drawer-open .erp-nav__caret,
    .erp-shell--drawer-open:not(.erp-shell--expanded) .erp-nav__caret {
        position: static;
        width: 1rem;
        height: 1rem;
        flex: none;
        overflow: visible;
        clip: auto;
    }

    .erp-branch__name {
        max-width: 6.5rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .erp-usermenu__name {
        display: none;
    }
}

@media (max-width: 767px) {
    .erp-topbar__search {
        display: none;
    }

    /* On a phone the topbar has no room for the brand wordmark and the branch label as well as the
       three right-hand icons — they were colliding. Keep the logo mark and the branch's building
       icon (both still tap to their destinations) and drop the two text labels, so nothing overlaps
       and the bar stays legible. The full names remain in the sidebar and the user menu. */
    .erp-brand__name { display: none; }
    .erp-branch__name { display: none; }
    .erp-branch__caret { display: none; }
    .erp-branch__btn,
    .erp-branch--static { padding-left: .4rem; padding-right: .4rem; }
    .erp-topbar { gap: var(--space-2); }

    .erp-content__inner {
        padding: var(--space-2) var(--space-3) var(--space-6);
    }

    .erp-formgrid {
        grid-template-columns: minmax(0, 1fr);
    }

    .erp-pagination__pages {
        margin-left: 0;
    }
}

/* ---------- 21. Print ------------------------------------------------------
   Chrome is removed entirely. What prints is the record, at full width, in
   black on white — an invoice with a navy sidebar down the side of it is a
   waste of toner and an embarrassment in front of a customer.
   -------------------------------------------------------------------------- */

@media print {
    :root {
        --bg-app: #ffffff;
        --bg-surface: #ffffff;
        --bg-subtle: #ffffff;
        --text-primary: #000000;
        --text-secondary: #000000;
        --border: #999999;
    }

    .erp-topbar,
    .erp-sidebar,
    .erp-sidebar-backdrop,
    .erp-skiplink,
    .erp-toasts,
    .erp-loading,
    .erp-filterbar,
    .erp-pagination,
    .erp-pageheader__actions,
    .erp-breadcrumbs,
    .modal,
    .modal-backdrop {
        display: none !important;
    }

    .erp-content {
        margin-left: 0;
        padding-top: 0;
    }

    .erp-content__inner {
        max-width: none;
        padding: 0;
    }

    .erp-card,
    .erp-tablewrap {
        border: 0;
        box-shadow: none;
    }

    .erp-table {
        font-size: 10pt;
    }

    .erp-table thead {
        display: table-header-group; /* repeat headers across pages */
    }

    .erp-table tbody tr {
        break-inside: avoid;
    }

    /* A printed page loses the href, so spell out where a link went. */
    .erp-print-url a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 9pt;
    }

    a {
        color: #000000;
        text-decoration: none;
    }

    /* ---- List pages print as a report, not a screenshot -------------------
       A list screen (Purchases, Invoices, Stock counts, …) carries a print-only head with the
       company letterhead and a title. On screen it is hidden; here it becomes the report header.
       The action buttons, filter card and pager are marked d-print-none on the page, and the
       last "Actions" column of on-screen buttons is dropped so paper shows data, not controls. */
    .erp-printhead { display: block !important; }
    .erp-printhead__title {
        font-size: 15pt;
        font-weight: 700;
        margin: 6pt 0 0;
        color: #000;
    }
    .erp-printhead__meta {
        font-size: 8.5pt;
        color: #333;
        margin: 1pt 0 8pt;
    }

    /* A list table prints as a plain bordered grid even when it is an erp-table-cards table (whose
       card-stacking is a SCREEN affordance for phones — on paper it must stay a real table). */
    .erp-table-cards table,
    .erp-table-cards thead,
    .erp-table-cards tbody,
    .erp-table-cards tr,
    .erp-table-cards th,
    .erp-table-cards td { display: revert !important; }
    .erp-table-cards thead { display: table-header-group !important; }
    .erp-table-cards td::before { content: none !important; }

    .erp-table th,
    .erp-table td,
    table.table th,
    table.table td { border: 1px solid #999; padding: 2pt 5pt; }

    /* The row of View / Open / Edit buttons is screen navigation, useless on paper. A column
       marked .erp-col-actions on the page (header and cells) is dropped on print. */
    .erp-col-actions { display: none !important; }

    /* Controls are screen-only on EVERY page, not just those that remembered d-print-none:
       PDF / Print, Excel, CSV, Edit, Pay, the filter form and the pager all came out in the PDF. */
    .erp-main .btn,
    .erp-main .btn-group,
    .erp-main .dropdown,
    .erp-main .pagination,
    .erp-main form[method="get"],
    .erp-main form[method="GET"] { display: none !important; }
}

/* ---------- 22. Reduced motion -------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------- 23. List tables on a phone ------------------------------------
   Staff use phones as well as desktops, and every list screen carries 8–10
   columns. Bootstrap's .table-responsive only adds a sideways scrollbar, which
   is technically not broken and practically unreadable: the reader scrolls right
   to find a figure, loses the row it belonged to, and scrolls back.

   Below 768px a .erp-table becomes one card per row. Each cell keeps its column
   heading through data-label, so nothing has to be remembered from a header that
   is no longer on screen. Opt-in by class — report tables and the trial balance
   are genuine grids where a card per row would lose the comparison. */

@media (max-width: 767.98px) {
    .erp-table-cards > .table-responsive { overflow-x: visible; }

    .erp-table-cards table,
    .erp-table-cards tbody,
    .erp-table-cards tr,
    .erp-table-cards td { display: block; width: auto; }

    .erp-table-cards thead { display: none; }

    .erp-table-cards tr {
        background: var(--bg-surface);
        border: 1px solid var(--border);
        border-radius: var(--radius);
        padding: .75rem 1rem;
        margin-bottom: .625rem;
    }

    .erp-table-cards td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 1rem;
        padding: .3rem 0;
        border: 0;
        text-align: right;
    }

    .erp-table-cards td::before {
        content: attr(data-label);
        flex: none;
        color: var(--text-secondary);
        font-size: var(--text-sm);
        text-align: left;
    }

    /* The first cell is the card's title: full width, no label, and it carries
       the link to the record. */
    .erp-table-cards td:first-child {
        display: block;
        text-align: left;
        font-weight: 600;
        padding-bottom: .5rem;
        margin-bottom: .35rem;
        border-bottom: 1px solid var(--border);
    }

    .erp-table-cards td:first-child::before { content: none; }

    /* A cell with no data-label is an actions cell — buttons, not a value. */
    .erp-table-cards td:not([data-label]) { justify-content: flex-end; }
    .erp-table-cards td:not([data-label])::before { content: none; }

    /* Totals rows stay a single line rather than becoming a card of one figure. */
    .erp-table-cards tfoot tr { display: flex; justify-content: space-between; }
    .erp-table-cards tfoot th { border: 0; padding: .25rem 0; }

    /* Page header (title + action buttons) stacks on phones. Without this the button row refuses
       to wrap: it squeezes the title/description to one word per line and pushes the last button
       off the right edge (e.g. "Receive goods" clipped on Purchases). This targets the standard
       raw header pattern used across the app; the erp-pageheader class already stacks on its own. */
    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 {
        flex-direction: column;
        align-items: stretch;
        gap: .75rem;
    }

    /* The actions group (the right-hand div of buttons) wraps onto as many rows as it needs
       instead of overflowing, and each button can shrink so none is pushed off the edge. */
    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 > .d-flex {
        flex-wrap: wrap;
        width: 100%;
        min-width: 0;
    }

    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 > .d-flex > .btn,
    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 > .d-flex > a.btn,
    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 > .d-flex > button.btn {
        flex: 0 1 auto;
        white-space: nowrap;
        text-align: center;
    }

    /* The title column must also be allowed to shrink, or a long word keeps the row wide and the
       buttons never get their own line. */
    .erp-main > .d-flex.justify-content-between.align-items-start.mb-3 > div:first-child {
        min-width: 0;
    }
}

/* ---------- 24. Filter bar: date ranges ------------------------------------
   Two date inputs read as one control, so they sit on a single line with a
   dash between rather than as two unrelated fields. */

.erp-filterbar__daterange {
    display: flex;
    align-items: center;
    gap: .35rem;
}

.erp-filterbar__daterange input { min-width: 8.5rem; }

.erp-filterbar__rangesep { color: var(--text-muted); }

@media (max-width: 575.98px) {
    /* Stacked on a phone: two date inputs side by side leave neither tappable. */
    .erp-filterbar__daterange { flex-direction: column; align-items: stretch; }
    .erp-filterbar__rangesep { display: none; }
}

/* ==========================================================================
   25. SIMPLE / CALM (2026-07-22) — plain, quiet, out of the way

   Replaces the 2026-07-21 "visual refresh", which piled on shadows, a
   saturated blue, hover-lifts and pill-rounding to look "modern" and instead
   read as busy. The brief now is the opposite and it is the right one: calm and
   plain, the way Zoho Books / Xero actually look — flat surfaces, thin borders,
   a muted accent, generous white space, and essentially no motion. Nothing
   competes for attention, so the data does.

   Principles:
     • Borders, not shadows. A card is a 1px outline on white, nothing floating.
     • Small, honest corners (4/6px), never pills on structural elements.
     • A muted grey-blue accent used sparingly — for the one primary action and
       links, not for decoration.
     • No hover-lifts, no transforms, no shadow transitions. Hover is at most a
       faint background tint.

   Last in the cascade so it wins; the §26 breathing-room spacing below is kept
   deliberately — calm needs the air. Colour *meaning* (success/danger/warning)
   is untouched, so nothing semantic has to be re-verified.
   ========================================================================== */

:root {
    /* Honest, small radii — an ERP, not a toy. */
    --radius: 4px;
    --radius-lg: 6px;

    /* A muted, slightly greyed blue. Calmer than the base #1c64d1 and far
       calmer than the refresh's #2563eb, still accessible on white (>4.5:1). */
    --accent: #3866b3;
    --accent-hover: #2c5192;
    --accent-subtle: #eef2f8;

    --bs-border-radius: var(--radius);
    --bs-border-radius-sm: var(--radius);
    --bs-border-radius-lg: var(--radius-lg);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --accent: #6f9bd8;
        --accent-hover: #89aee0;
        --accent-subtle: #1a2740;
    }
}
:root[data-theme="dark"] {
    --accent: #6f9bd8;
    --accent-hover: #89aee0;
    --accent-subtle: #1a2740;
}

/* ---- Cards: a flat outline on the surface, no shadow, no lift ---------- */
.card {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-surface);
    /* A soft shadow so a white card reads as a card lifted off the grey page, not a flat panel that
       blends into the background. Subtle enough to stay calm across a page full of them. */
    box-shadow: var(--shadow-sm);
}

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--border);
    font-weight: 600;
}

/* ---- Buttons: flat, quiet, no lift or shadow -------------------------- */
.btn {
    border-radius: var(--radius);
    font-weight: 500;
    padding: .5rem 1rem;
}

.btn-sm { padding: .3rem .7rem; border-radius: var(--radius); }

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    box-shadow: none;
}

.btn-primary:hover,
.btn-primary:focus {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    box-shadow: none;
}

.btn-outline-secondary {
    border-color: var(--border-strong);
    color: var(--text-secondary);
    box-shadow: none;
}

.btn-outline-secondary:hover {
    background: var(--bg-subtle);
    border-color: var(--text-muted);
    color: var(--text-primary);
}

/* ---- Inputs: plain, clear (not glowing) focus ------------------------- */
.form-control,
.form-select {
    border-radius: var(--radius);
    border-color: var(--border-strong);
    padding: .5rem .75rem;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-subtle);
}

.form-control-sm,
.form-select-sm { border-radius: var(--radius); }

/* ---- Tables: a plain bordered surface, quiet header, faint hover ------ */
/* Bootstrap defaults --bs-table-bg to the body background, which here is the grey app colour — so
   every table painted a grey fill on top of its white card. Make the table transparent so the
   card (or page) surface shows through, and rows stay white. */
.table {
    --bs-table-border-color: transparent;
    --bs-table-bg: transparent;
}

.table > thead > tr > th {
    border-bottom: 1px solid var(--border);
    color: var(--text-secondary);
    font-weight: 600;
    font-size: var(--text-xs);
    letter-spacing: .03em;
    text-transform: uppercase;
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.table > tbody > tr > td {
    border-bottom: 1px solid var(--bg-subtle);
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.table-hover > tbody > tr:hover > * {
    background: var(--bg-subtle);
    --bs-table-bg-state: transparent;
}

/* A STANDALONE list table sits on its own card surface — a white panel with a soft shadow, so a
   list page reads as a proper card rather than a bare table floating on the grey app background. */
.table-responsive {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-2) var(--space-4);
}

/* A table already INSIDE a .card must stay flush — the card is the surface, so the inner table is
   transparent (no box-in-a-box, no stray background). */
.card .table-responsive {
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}

/* A validation summary in the "valid" state has no errors to show — ASP.NET still renders the
   container, which read as an empty red alert on almost every form. Hide it until it actually holds
   errors (it gains .validation-summary-errors then). One rule, every form. */
.validation-summary-valid {
    display: none !important;
}

/* ---- Badges: small rounded rects, not pills, softer fills ------------- */
.badge {
    border-radius: var(--radius);
    font-weight: 600;
    padding: .3em .6em;
}

.text-bg-success { background: var(--success-subtle) !important; color: var(--success) !important; }
.text-bg-secondary { background: var(--slate-subtle) !important; color: var(--slate) !important; }
.text-bg-light { background: var(--bg-subtle) !important; color: var(--text-secondary) !important; }

/* ---- Alerts: flat tinted panel, a quiet left rule -------------------- */
.alert {
    border: 0;
    border-radius: var(--radius-lg);
    border-left: 3px solid transparent;
}

.alert-success { background: var(--success-subtle); border-left-color: var(--success); color: var(--success); }
.alert-danger  { background: var(--danger-subtle);  border-left-color: var(--danger);  color: var(--danger); }
.alert-warning { background: var(--warning-subtle); border-left-color: var(--warning); color: var(--warning); }
.alert-info    { background: var(--accent-subtle);  border-left-color: var(--accent);  color: var(--accent); }

/* ---- Dropdown menus: a plain bordered panel, minimal shadow ----------- */
.dropdown-menu {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-2);
}

.dropdown-item { border-radius: var(--radius); padding: .5rem .75rem; }

/* ---- Legibility: muted text on dark cards was too faint to read --------- */
/* Bootstrap's .text-muted maps to a dim grey that reads fine on a light card
   but nearly disappears on the dark surface (the "SOLD TODAY" / "of 10
   licensed" labels). Plain must still mean readable, so lift muted text one
   step in dark mode. Light mode is untouched. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .text-muted {
        color: var(--text-secondary) !important;
    }
}
:root[data-theme="dark"] .text-muted {
    color: var(--text-secondary) !important;
}

/* ==========================================================================
   26. BREATHING ROOM (2026-07-21) — the Zoho Books lesson

   The §25 refresh softened the surface but kept the density, and dense is what
   read as "old ERP". Modern business software — Zoho Books, Stripe, Xero — is
   not prettier so much as *calmer*: larger text, taller rows, more white space,
   fewer competing weights. This layer trades a little density for a lot of
   ease. It sits last, so it wins; nothing structural moves.

   Scoped to the app shell (.erp-content) so the chrome-free POS, which is
   deliberately dense and dark, is untouched.
   ========================================================================== */

.erp-content {
    /* Back to 14px — bumping the base made everything clumsy rather than clearer. The ease comes
       from spacing and hierarchy below, not from inflating every glyph. Line-height is the one
       type change kept: a little more leading reads calmer without enlarging anything. */
    line-height: 1.55;
    color: var(--text-primary);
}

/* ---- Page headings: larger, more air beneath -------------------------- */
.erp-content h1,
.erp-content .h4 {
    font-size: 1.35rem;
    font-weight: 650;
    letter-spacing: -.01em;
    margin-bottom: .5rem;
}

.erp-content .card-header,
.erp-content h2,
.erp-content .h6 {
    font-size: 1rem;
}

/* ---- Cards: more internal room ---------------------------------------- */
.erp-content .card { margin-bottom: 1.5rem; }
.erp-content .card-body { padding: 1.5rem; }
.erp-content .card-header { padding: 1.15rem 1.5rem; }

/* ---- Tables: this is where density hurt most -------------------------- */
.erp-content .table > tbody > tr > td,
.erp-content .table > thead > tr > th {
    padding-top: 1rem;
    padding-bottom: 1rem;
    vertical-align: middle;
}

.erp-content .table > tbody > tr > td {
    border-bottom-color: var(--border);
}

/* Give the list surface real margins so rows are not edge-to-edge. */
.erp-content .table-responsive {
    padding: .5rem 1.25rem;
}

/* ---- Filter bar: taller inputs, more gap ------------------------------ */
.erp-content .erp-filterbar { gap: .75rem; margin-bottom: 1.5rem; }
.erp-content .erp-filterbar .form-control,
.erp-content .erp-filterbar .form-select { height: 40px; }

/* ---- Forms: labels and fields breathe --------------------------------- */
.erp-content .form-label {
    font-weight: 500;
    margin-bottom: .35rem;
    color: var(--text-primary);
}

.erp-content .form-control,
.erp-content .form-select {
    min-height: 40px;
}

.erp-content .form-text {
    font-size: .8125rem;
    margin-top: .35rem;
}

/* Space between form rows, so fields are not stacked tight. */
.erp-content .row.g-3 { --bs-gutter-y: 1.25rem; }

/* ---- Buttons: a touch larger, matching the taller inputs -------------- */
.erp-content .btn { padding: .55rem 1.15rem; }
.erp-content .btn-sm { padding: .4rem .85rem; }

/* ---- Page intro text: quieter, roomier -------------------------------- */
.erp-content h1 + .text-muted,
.erp-content .h4 + .text-muted,
.erp-content h1 + .text-muted.small,
.erp-content .h4 + .text-muted.small {
    /* text-secondary, not text-muted: the intro line under a heading is meant to be read, and
       text-muted is too faint against the darker surface once the page is this roomy. */
    color: var(--text-secondary) !important;
    font-size: .9375rem;
    margin-bottom: 1.5rem !important;
}

/* ---- Empty state: centred and generous, not a bare sentence ----------- */
.erp-content td.text-center.text-muted.py-4 {
    padding-top: 3rem !important;
    padding-bottom: 3rem !important;
    font-size: 1rem;
}

/* ============================================================================
   30. DASHBOARD — interactive shop overview
   KPI tiles that lift on hover and link to their detail, a 7-day bar chart,
   and best-seller bars. Kept token-driven so it tracks the theme.
   ============================================================================ */

/* Rows inside a card (setup checklist, running-low, best-sellers) sit flush on the white card —
   no grey list-group background, no grey action-hover fill that would look like a band behind the
   text. The card is the surface; the rows are just its contents. */
.card .list-group-item,
.card .list-group-item-action {
    background: transparent;
    --bs-list-group-bg: transparent;
    --bs-list-group-action-hover-bg: transparent;
    --bs-list-group-action-active-bg: transparent;
}
.card .list-group-item-action:hover {
    background: var(--bg-app);   /* a gentle hover, only while pointing at it */
}

.dash-kpi {
    transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.dash-kpi:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md, 0 4px 12px rgba(16, 24, 40, .1));
    border-color: var(--accent);
}
.dash-kpi:hover .text-body { color: var(--accent) !important; }

.dash-ministat { border-top: 1px solid var(--border); }

/* 7-day bar chart — flex columns, animated bar grow on load. */
.dash-chart {
    display: flex;
    align-items: flex-end;
    gap: var(--space-2, .5rem);
    height: 180px;
    padding-top: 1.25rem;
}
.dash-chart__col {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100%;
    min-width: 0;
}
.dash-chart__bar-wrap {
    flex: 1 1 auto;
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    position: relative;
}
.dash-chart__bar {
    width: 100%;
    max-width: 46px;
    border-radius: var(--radius-sm, 4px) var(--radius-sm, 4px) 0 0;
    background: var(--accent-subtle);
    border: 1px solid var(--accent);
    border-bottom: 0;
    transition: height .5s cubic-bezier(.2, .8, .2, 1), background .12s ease;
    min-height: 2px;
}
.dash-chart__col:hover .dash-chart__bar { background: var(--accent); }
.dash-chart__bar--today {
    background: var(--accent);
    border-color: var(--accent-hover);
}
.dash-chart__val {
    font-size: .68rem;
    color: var(--text-muted, #667085);
    margin-bottom: 2px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.dash-chart__label {
    font-size: .7rem;
    color: var(--text-muted, #667085);
    margin-top: .35rem;
    text-transform: uppercase;
    letter-spacing: .02em;
}

/* A table dropped straight into a p-0 card body (the dashboard's Recent activity, and any list
   that does the same) spans edge to edge, so its cells touch the card border. Inset the outermost
   cells to line up with the card header (1.5rem); the row hover still runs full width, as it should.
   Targeted by structure — a .table that is a direct child of a .card-body.p-0 — so it needs no extra
   class on the markup and works without a rebuild. */
.card-body.p-0 > .table > :not(caption) > * > *:first-child { padding-left: 1.5rem; }
.card-body.p-0 > .table > :not(caption) > * > *:last-child { padding-right: 1.5rem; }
.card-body.p-0 > .table > thead > tr > * { padding-top: 1rem; padding-bottom: .5rem; }
.card-body.p-0 > .table > tbody > tr > * { padding-top: .6rem; padding-bottom: .6rem; }

/* Best-seller rows with a proportional quantity bar. */
.dash-top__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: .4rem;
}
.dash-top__track {
    height: 6px;
    border-radius: 3px;
    background: var(--bg-app, #f2f4f7);
    overflow: hidden;
}
.dash-top__fill {
    height: 100%;
    border-radius: 3px;
    background: var(--accent);
    transition: width .5s cubic-bezier(.2, .8, .2, 1);
}

@media (max-width: 575.98px) {
    .dash-chart { height: 150px; }
    .dash-chart__val { display: none; }
}

/* ---------- 30. ENABLER-S BRANDING ----------------------------------------
   Vendor identity: the mark and wordmark are Enabler-S, who supply the product.
   The tenant's own company name stays alongside them — it is whose books the
   user is in and what prints on their tax invoices.

   The supplied logo is white-on-transparent, so it is invisible on the light
   theme. Rather than alter the artwork, it sits on a dark tile in BOTH themes:
   one asset, one appearance, and the mark always has the contrast it was drawn
   for. Last in the cascade, so it wins over §25's surface layer.
   -------------------------------------------------------------------------- */

/* The dark tile. --brand-plate is deliberately a fixed near-black rather than a
   themed token: it must not follow the surface colour, or the white logo
   disappears the moment the light theme repaints it. */
:root {
    --brand-plate: #10161f;
}

.erp-brand__logo,
.erp-auth__logo {
    display: block;
    object-fit: contain;
    background: var(--brand-plate);
    border-radius: var(--radius);
    /* Optical padding: the glyph is drawn to the edge of its canvas and reads as
       cramped without it. */
    padding: 3px;
}

.erp-brand__logo {
    width: 26px;
    height: 26px;
    flex: 0 0 auto;
}

/* ---- Auth screens: sign-in, first-run setup, lockout, password reset ---- */

.erp-auth__logo {
    /* 72px, and no padding: this mark is a detailed circular badge rather than a simple
       glyph, and at 44px inside padding its wording was an unreadable smudge. The sign-in
       screen is the one place the shop's identity should be unmistakable. */
    width: 72px;
    height: 72px;
    border-radius: var(--radius-lg);
}

.erp-auth__wordmark {
    margin: var(--space-2) 0 0;
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: .08em;
    line-height: 1;
    color: var(--text-primary);
}

/* The "-S" is the one piece of colour in the lockup. */
.erp-auth__wordmark-suffix {
    color: var(--accent);
}

/* Demoted beneath the vendor lockup: at the sign-in screen the question is
   which installation this is, not who owns it. */
.erp-auth__company {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-muted);
}

.erp-auth__footer-sep {
    opacity: .5;
}

/* ---- Sidebar vendor credit ---------------------------------------------- */

/* Carries erp-nav__label in the markup, so the existing collapse and drawer
   rules hide and restore it with every other label — no new selectors needed. */
.erp-sidebar__copyright {
    margin: var(--space-1) 0 0;
    padding: 0 var(--space-4);
    font-size: var(--text-xs);
    color: var(--text-invert-muted);
    opacity: .75;
}

/* ---- Print --------------------------------------------------------------
   §21 hides the shell entirely, so neither the topbar nor the sidebar credit
   reaches paper. A tax invoice carries the tenant's identity and TRN, not the
   vendor's — printing "Enabler-S FZE LLC" onto an FTA document would be wrong.
   Nothing to add here; this note exists so it is not "fixed" later.
   ------------------------------------------------------------------------- */

/* ---- Printed letterhead and footer -------------------------------------------------------
   Hidden on screen: the topbar already names the company, and repeating it above every report
   would be clutter. Shown on paper, where there is no topbar and an unattributed report cannot
   be filed — a VAT summary with no TRN on it is not evidence of anything. */

.erp-letterhead,
.erp-printfoot { display: none; }

@media print {
    .erp-letterhead {
        display: flex;
        gap: 10px;
        align-items: center;
        border-bottom: 2px solid #1a237e;
        padding-bottom: 6px;
        margin-bottom: 10px;
    }

    /* The mark is a circular badge on a black field, so it keeps its own plate. Printed straight
       onto white it would be a black square. */
    .erp-letterhead__logo {
        width: 58px;
        height: 58px;
        object-fit: contain;
        background: #000;
        border-radius: 6px;
        padding: 3px;
    }

    .erp-letterhead__text { font-size: 9pt; line-height: 1.45; color: #000; }
    .erp-letterhead__name { font-size: 11pt; font-weight: 700; color: #1a237e; }
    .erp-letterhead__trn { font-weight: 700; color: #1a237e; }

    .erp-printfoot {
        display: block;
        margin-top: 12px;
        padding-top: 5px;
        border-top: 1px solid #999;
        text-align: center;
        font-size: 8pt;
        color: #444;
    }

    /* print-color-adjust keeps the plate and the rule from being dropped by the browser's
       "background graphics off" default, which would otherwise strip the letterhead's identity. */
    .erp-letterhead__logo,
    .erp-letterhead { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ---- Void receipt --------------------------------------------------------
   A <details> so the reason field is out of the way until the action is
   chosen: an always-visible "why are you voiding this" box on every purchase
   invites the question on documents nobody is voiding. The summary is styled
   as the button, and the panel is positioned so opening it does not stretch
   the page header it sits in.
   -------------------------------------------------------------------------- */

.erp-void { position: relative; }
.erp-void > summary { list-style: none; cursor: pointer; }
.erp-void > summary::-webkit-details-marker { display: none; }

.erp-void__form {
    position: absolute;
    right: 0;
    z-index: 5;
    width: min(22rem, 90vw);
    text-align: left;
    box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .15);
}

/* ---- Searchable dropdown (combobox) --------------------------------------
   The select itself becomes a text box you type into, with matching options
   beneath it. The original <select> stays in the DOM, hidden, and remains the
   element that posts and validates — so the form still works if the script
   never loads.
   -------------------------------------------------------------------------- */

/* A data-entry grid whose rows contain searchable dropdowns.
 *
 * .table-responsive sets overflow-x:auto, and an ancestor with overflow other than visible clips
 * absolutely-positioned descendants no matter what their z-index is. .erp-combo__list is exactly
 * that, so on every line-entry grid the dropdown rendered but was cut off at the table edge —
 * present in the DOM, invisible on screen, and reported as "the dropdown does not open".
 *
 * Both axes are released, not just the vertical one. Mixing them does not work: CSS computes a
 * `visible` paired with a non-visible value as `auto`, so `overflow-x:auto; overflow-y:visible`
 * silently becomes `auto auto` and clips exactly as before. Verified rather than assumed.
 *
 * The cost is horizontal scrolling on these grids at narrow widths. That is the right trade for a
 * line-entry form — the columns are few and mostly narrow, and a dropdown you cannot see makes the
 * page unusable, while a slightly wide table on a phone merely makes it awkward. Applied only to
 * grids whose rows contain a dropdown; report and list tables keep .table-responsive as-is. */
.erp-table-overflow-visible {
    overflow: visible;
}

.erp-combo { position: relative; }

/* Hidden, not display:none — a display:none control is skipped by some
   validation paths and cannot be focused when a message points at it. */
.erp-combo__native {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    height: 0;
    width: 0;
}

.erp-combo__input { background-image: none; cursor: text; }

.erp-combo__list {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1060;
    max-height: 60vh;
    overflow-y: auto;
    background: var(--surface, #fff);
    border: 1px solid var(--border, #d6dce5);
    border-radius: .375rem;
    box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .15);
}

.erp-combo__item {
    display: block;
    width: 100%;
    padding: .4rem .75rem;
    border: 0;
    background: none;
    text-align: left;
    font-size: .875rem;
    cursor: pointer;
}

.erp-combo__item:hover,
.erp-combo__item.is-active {
    background: var(--primary, #2f6df6);
    color: #fff;
}

.erp-combo__empty {
    padding: .5rem .75rem;
    font-size: .8125rem;
    color: var(--text-secondary, #5a6675);
}

/* ============================================================================
   MOBILE: report tables and page headers
   ========================================================================= */
@media (max-width: 991.98px) {

    /* Report cells carry `text-end font-monospace` for desktop column alignment.
       Inside a stacked card that right-alignment fights the flex layout and the
       value ends up pushed past the card's right edge — the label is visible and
       the number is not, which is worse than either. */
    .erp-table-cards td.text-end {
        text-align: right;
        min-width: 0;
        overflow-wrap: anywhere;
    }

    /* A page header is a title and a row of actions. Side by side they force the
       page wider than the screen; stacked, the buttons wrap under the title and
       stay reachable. */
    .erp-main > .d-flex.justify-content-between {
        flex-wrap: wrap;
        gap: .75rem;
    }

    .erp-main > .d-flex.justify-content-between > .d-flex {
        flex-wrap: wrap;
    }

    /* Nothing may push the document sideways: a single wide child otherwise
       scrolls the whole page and every screen feels broken. */
    .erp-content,
    .erp-content__inner {
        max-width: 100%;
        overflow-x: hidden;
    }
}

/* ============================================================================
   MOBILE: no cell may push the page sideways
   ============================================================================
   Card-stacking fixes table LAYOUT, but not content that cannot wrap. A long
   unbroken string — an audit log's comma-separated column list, a GUID, a JSON
   fragment — still measures its full width and drags the row with it. The audit
   log reached 2,067px on a 700px screen this way.

   `overflow-wrap: anywhere` lets such a string break mid-token when there is no
   other option. It does NOT hyphenate ordinary prose or affect desktop, which
   keeps the real table layout above this breakpoint.
   ========================================================================= */
@media (max-width: 991.98px) {
    .erp-table-cards td,
    .erp-table-cards th {
        overflow-wrap: anywhere;
        word-break: break-word;
        min-width: 0;
    }

    /* Code and badges are the usual offenders: an entity id or a permission
       string has no spaces at all. */
    .erp-table-cards code,
    .erp-table-cards .badge {
        overflow-wrap: anywhere;
        white-space: normal;
    }
}

/* A visually-hidden header label (position:absolute) inside a scrolling table escaped the scroll
   box — its containing block was the page — and widened the whole phone layout, topbar included.
   Making the scroll box the containing block keeps it, and anything like it, clipped inside. */
.table-responsive { position: relative; }
