/* ================================================================
   Automated Business — global.css
   Single source of truth for the design system. Loaded by:
     - usersc/templates/automated-business/header.php  (custom pages)
     - usersc/login.php, account.php, ...               (UserSpice overrides)
   Both contexts link this file directly so the visual system
   never drifts between them.

   All custom classes use the ab- prefix to avoid Bootstrap and
   UserSpice collisions. CSS custom properties drive the entire
   visual system; rebranding requires editing only :root.
   ================================================================ */

:root {
    /* --- Brand: deep navy primary + amber accent (industrial / contract feel) --- */
    --ab-primary:        #0F2A44;
    --ab-primary-600:    #14385C;
    --ab-primary-500:    #1B4A77;
    --ab-primary-400:    #305F8C;
    --ab-primary-100:    #DDE6F0;
    --ab-primary-50:     #EEF3F8;
    --ab-primary-glow:   rgba(15, 42, 68, 0.15);

    --ab-accent:         #C8722A;   /* burnt amber — primary CTA highlight */
    --ab-accent-600:     #B0631F;
    --ab-accent-500:     #D58A4A;
    --ab-accent-100:     #F8E6D2;
    --ab-accent-50:      #FBF1E4;

    --ab-bg:             #F7F4EF;   /* warm off-white page background */
    --ab-surface:        #FFFFFF;
    --ab-surface-alt:    #FBF8F3;

    /* --- Warm neutrals (slight brown undertone, fits furniture/lumber world) --- */
    --ab-gray-50:    #F7F5F2;
    --ab-gray-100:   #EFEBE5;
    --ab-gray-200:   #E2DCD3;
    --ab-gray-300:   #CAC2B6;
    --ab-gray-400:   #A89F92;
    --ab-gray-500:   #807868;
    --ab-gray-600:   #5C5648;
    --ab-gray-700:   #423E33;
    --ab-gray-800:   #2A2720;
    --ab-gray-900:   #1A1814;

    /* --- Semantic status colors (read on light backgrounds) --- */
    --ab-success:        #2F855A;
    --ab-success-bg:     #E6F4EC;
    --ab-warning:        #B7791F;
    --ab-warning-bg:     #FBF1DC;
    --ab-danger:         #B23A2C;
    --ab-danger-bg:      #FBE6E2;
    --ab-info:           #2C5282;
    --ab-info-bg:        #E3ECF6;

    /* --- Project-lifecycle status colors (used by ab_status_badge) --- */
    --ab-status-lead:           var(--ab-gray-500);
    --ab-status-surveyed:       #4A6B8A;
    --ab-status-quoted:         #2C5282;
    --ab-status-proposal:       #6B5B95;
    --ab-status-deposit:        #2F855A;
    --ab-status-production:     #B7791F;
    --ab-status-received:       #5B7B3F;
    --ab-status-scheduled:      #C8722A;
    --ab-status-installing:     #B0631F;
    --ab-status-punch:          #8E5A1F;
    --ab-status-complete:       #1F5C3D;
    --ab-status-cancelled:      #8A4540;

    /* --- Doc-type identity (chip + action-bar accent) ---
       Each transaction type has a foreground (text/border/icon) color
       and a tinted background for the .ab-doc-type-chip pill. Same
       foreground color drives the .ab-action-bar[data-doctype] top
       accent so the type stays visible after the user scrolls past
       the page header. */
    --ab-doctype-quote-fg:           #D97706;
    --ab-doctype-quote-bg:           #FDF2E1;
    --ab-doctype-sales_order-fg:     #15803D;
    --ab-doctype-sales_order-bg:     #E4F3EA;
    --ab-doctype-invoice-fg:         #4338CA;
    --ab-doctype-invoice-bg:         #E7E6F8;
    --ab-doctype-po-fg:              #7C3AED;
    --ab-doctype-po-bg:              #EDE5FB;
    --ab-doctype-project-fg:         var(--ab-primary);
    --ab-doctype-project-bg:         var(--ab-primary-50);
    --ab-doctype-delivery-fg:        #0E7490;
    --ab-doctype-delivery-bg:        #DEEEF2;
    --ab-doctype-task-fg:            #BE123C;
    --ab-doctype-task-bg:            #F8E1E7;
    --ab-doctype-punch-fg:           #C2410C;
    --ab-doctype-punch-bg:           #FAE5D8;
    --ab-doctype-survey-fg:          #475569;
    --ab-doctype-survey-bg:          #E5E8ED;
    --ab-doctype-customer-fg:        #047857;
    --ab-doctype-customer-bg:        #DCEEE6;
    --ab-doctype-contact-fg:         #059669;
    --ab-doctype-contact-bg:         #DCEFE6;
    --ab-doctype-supplier-fg:        #92400E;
    --ab-doctype-supplier-bg:        #F2E6D8;
    --ab-doctype-subcontractor-fg:   #A16207;
    --ab-doctype-subcontractor-bg:   #F4EAD3;
    --ab-doctype-typical-fg:         #334155;
    --ab-doctype-typical-bg:         #E2E5EA;
    --ab-doctype-tax_rate-fg:        #6B7280;
    --ab-doctype-tax_rate-bg:        #E8E9EB;
    --ab-doctype-change_order-fg:    #A21CAF;
    --ab-doctype-change_order-bg:    #F4DEF6;

    /* --- Elevation --- */
    --ab-shadow-sm:  0 1px 2px rgba(26, 24, 20, 0.06);
    --ab-shadow:     0 1px 3px rgba(26, 24, 20, 0.08), 0 1px 2px rgba(26, 24, 20, 0.04);
    --ab-shadow-md:  0 4px 8px rgba(26, 24, 20, 0.08), 0 2px 4px rgba(26, 24, 20, 0.04);
    --ab-shadow-lg:  0 10px 24px rgba(26, 24, 20, 0.10), 0 4px 8px rgba(26, 24, 20, 0.04);
    --ab-shadow-xl:  0 20px 40px rgba(26, 24, 20, 0.12);

    /* --- Shape & motion --- */
    --ab-radius-sm:  0.25rem;
    --ab-radius:     0.5rem;
    --ab-radius-lg:  0.75rem;
    --ab-radius-xl:  1rem;
    --ab-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);

    /* --- Typography --- */
    --ab-font:       'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --ab-font-mono:  ui-monospace, 'SFMono-Regular', 'Menlo', 'Cascadia Mono', 'Consolas', monospace;

    /* --- Layout --- */
    --ab-navbar-height: 68px;
    --ab-content-max:   1440px;
}

/* ------------------------------------------------------------
   Base + typography
   ------------------------------------------------------------ */
html, body {
    font-family: var(--ab-font);
    background-color: var(--ab-bg);
    color: var(--ab-gray-800);
    font-size: 15px;
    line-height: 1.55;
    letter-spacing: -0.005em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body.d-flex.flex-column.min-vh-100 { min-height: 100vh; }

h1, h2, h3, h4, h5, h6,
.ab-h1, .ab-h2, .ab-h3, .ab-h4, .ab-h5, .ab-h6 {
    font-family: var(--ab-font);
    color: var(--ab-gray-900);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.2;
    margin-top: 0;
}

h1, .ab-h1 { font-size: 2.25rem;  font-weight: 700; letter-spacing: -0.025em; margin-bottom: 0.75rem; }
h2, .ab-h2 { font-size: 1.75rem;  font-weight: 700; margin-bottom: 0.625rem; }
h3, .ab-h3 { font-size: 1.375rem; font-weight: 600; margin-bottom: 0.5rem; }
h4, .ab-h4 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; }
h5, .ab-h5 { font-size: 1rem;     font-weight: 600; margin-bottom: 0.5rem; }
h6, .ab-h6 { font-size: 0.875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ab-gray-600); margin-bottom: 0.5rem; }

p { margin-bottom: 1rem; }

.ab-text-body  { font-size: 0.9375rem; color: var(--ab-gray-800); }
.ab-text-small { font-size: 0.8125rem; color: var(--ab-gray-600); }
.ab-text-tiny  { font-size: 0.75rem;   color: var(--ab-gray-600); }
.ab-text-muted { color: var(--ab-gray-500); }
.ab-link-muted { color: var(--ab-gray-700); }
.ab-link-muted:hover { color: var(--ab-primary-500); text-decoration: underline; }
.ab-text-caption {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ab-gray-500);
    font-weight: 500;
}
.ab-text-mono { font-family: var(--ab-font-mono); font-size: 0.875rem; }

a { color: var(--ab-primary-500); text-decoration: none; transition: color var(--ab-transition); }
a:hover { color: var(--ab-accent-600); text-decoration: underline; }

hr { border-color: var(--ab-gray-200); opacity: 1; }

/* ------------------------------------------------------------
   Navbar
   ------------------------------------------------------------ */
.ab-navbar {
    background-color: var(--ab-primary);
    border-bottom: 3px solid var(--ab-accent);
    box-shadow: var(--ab-shadow);
    min-height: var(--ab-navbar-height);
    padding: 0.75rem 0;
}

.ab-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    color: #fff;
    font-weight: 700;
    font-size: 1.125rem;
    letter-spacing: -0.02em;
    text-decoration: none;
}
.ab-brand:hover { color: #fff; text-decoration: none; }

.ab-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--ab-radius-sm);
    background: linear-gradient(135deg, var(--ab-accent) 0%, var(--ab-accent-600) 100%);
    color: #fff;
    font-weight: 800;
    font-size: 0.95rem;
    letter-spacing: -0.04em;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}

.ab-brand-name { line-height: 1.1; }
.ab-brand-tag {
    display: block;
    font-size: 0.6875rem;
    font-weight: 400;
    color: var(--ab-gray-300);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-top: 1px;
}

.ab-navbar .navbar-nav .nav-link {
    color: rgba(255, 255, 255, 0.78);
    font-weight: 500;
    font-size: 0.9375rem;
    padding: 0.5rem 0.875rem;
    border-radius: var(--ab-radius-sm);
    transition: color var(--ab-transition), background-color var(--ab-transition);

    /* Icon + label inline */
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    white-space: nowrap;
}

.ab-navbar .navbar-nav .nav-link i {
    font-size: 1rem;
    width: 1.1rem;
    text-align: center;
    flex-shrink: 0;
}

.ab-navbar .navbar-nav .nav-link:hover,
.ab-navbar .navbar-nav .nav-link:focus { color: #fff; background-color: rgba(255, 255, 255, 0.06); }

.ab-navbar .navbar-nav .nav-link.active {
    color: #fff;
    background-color: rgba(255, 255, 255, 0.1);
}

/* Icon-only mode at the awkward mid-width before the hamburger kicks in.
   Bootstrap's navbar-expand-lg breakpoint is 992px (≥lg = expanded).
   Between 992 and 1300 we shrink each link to its icon (label hidden,
   tooltip from title="" attribute). Below 992 the whole nav collapses
   into the hamburger and labels reappear in the dropdown. */
@media (min-width: 992px) and (max-width: 1300px) {
    .ab-navbar .navbar-nav .nav-link .ab-nav-label {
        display: none;
    }
    .ab-navbar .navbar-nav .nav-link {
        padding: 0.5rem 0.625rem;
    }
    .ab-navbar .navbar-nav .nav-link i {
        font-size: 1.125rem;
    }
    /* Hide the dropdown caret in icon-only mode */
    .ab-navbar .navbar-nav .dropdown-toggle::after {
        display: none;
    }
}

/* In hamburger mode (below lg) labels are always visible inside the
   collapsed menu — no special rule needed; the @media block above
   doesn't apply. */

.ab-navbar .navbar-toggler {
    border-color: rgba(255, 255, 255, 0.3);
    color: #fff;
    padding: 0.375rem 0.625rem;
}
.ab-navbar .navbar-toggler:focus { box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.15); }
.ab-navbar .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255,255,255,0.85%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* Dropdowns inside the dark navbar */
.ab-navbar .dropdown-menu {
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius);
    box-shadow: var(--ab-shadow-lg);
    padding: 0.375rem;
    margin-top: 0.375rem;
    min-width: 220px;
}
.ab-navbar .dropdown-item {
    border-radius: var(--ab-radius-sm);
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
    color: var(--ab-gray-800);
    font-weight: 500;
}
.ab-navbar .dropdown-item:hover,
.ab-navbar .dropdown-item:focus { background-color: var(--ab-primary-50); color: var(--ab-primary); }
.ab-navbar .dropdown-item i { width: 18px; text-align: center; margin-right: 0.5rem; color: var(--ab-gray-500); }
.ab-navbar .dropdown-divider { border-color: var(--ab-gray-200); margin: 0.375rem 0; }

.ab-account-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.625rem 0.375rem 0.375rem;
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.08);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.12);
    font-size: 0.875rem;
    font-weight: 500;
    transition: background-color var(--ab-transition);
}
.ab-account-toggle:hover, .ab-account-toggle:focus { background-color: rgba(255, 255, 255, 0.15); color: #fff; }
.ab-account-toggle::after { display: none; }

/* Alert bell — admin nav. Goes amber on unacked alerts. */
.ab-alert-bell-wrapper { display: flex; align-items: center; }
.ab-alert-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 999px;
    color: rgba(255, 255, 255, 0.78) !important;
    transition: background-color var(--ab-transition), color var(--ab-transition);
}
.ab-alert-bell i { font-size: 1rem; }
.ab-alert-bell:hover, .ab-alert-bell:focus {
    background-color: rgba(255, 255, 255, 0.1);
    color: #fff !important;
}
.ab-alert-bell.has-alerts {
    color: var(--ab-warning) !important;
    animation: ab-bell-pulse 2s ease-in-out infinite;
}
.ab-alert-bell.has-alerts:hover { color: #fff !important; }
.ab-alert-bell-badge {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    background-color: var(--ab-danger);
    color: #fff;
    font-size: 0.625rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    border-radius: 999px;
    border: 2px solid var(--ab-primary-700, #1B4A77);
    box-sizing: content-box;
}
@keyframes ab-bell-pulse {
    0%, 100% { transform: rotate(0); }
    8%       { transform: rotate(-12deg); }
    16%      { transform: rotate(10deg); }
    24%      { transform: rotate(-6deg); }
    32%      { transform: rotate(0); }
}

.ab-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background-color: var(--ab-accent);
    color: #fff;
    font-weight: 600;
    font-size: 0.75rem;
    letter-spacing: 0;
}

.ab-login-btn {
    color: rgba(255, 255, 255, 0.85);
    font-weight: 500;
    padding: 0.5rem 0.875rem;
    text-decoration: none;
}
.ab-login-btn:hover { color: #fff; }

/* ------------------------------------------------------------
   Buttons
   ------------------------------------------------------------ */
.ab-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-family: var(--ab-font);
    font-weight: 600;
    font-size: 0.9375rem;
    line-height: 1.2;
    padding: 0.625rem 1.125rem;
    border-radius: var(--ab-radius);
    border: 1px solid transparent;
    background-color: transparent;
    color: var(--ab-gray-800);
    cursor: pointer;
    text-decoration: none;
    transition: all var(--ab-transition);
    user-select: none;
    white-space: nowrap;
}
.ab-btn:focus-visible {
    outline: 2px solid var(--ab-primary-400);
    outline-offset: 2px;
}
.ab-btn:disabled, .ab-btn.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.ab-btn-primary {
    background-color: var(--ab-accent);
    border-color: var(--ab-accent);
    color: #fff;
    box-shadow: var(--ab-shadow-sm);
}
.ab-btn-primary:hover { background-color: var(--ab-accent-600); border-color: var(--ab-accent-600); color: #fff; box-shadow: var(--ab-shadow-md); transform: translateY(-1px); }
.ab-btn-primary:active { transform: translateY(0); box-shadow: var(--ab-shadow-sm); }

.ab-btn-secondary {
    background-color: var(--ab-primary);
    border-color: var(--ab-primary);
    color: #fff;
}
.ab-btn-secondary:hover { background-color: var(--ab-primary-600); border-color: var(--ab-primary-600); color: #fff; }

.ab-btn-outline {
    background-color: transparent;
    border-color: var(--ab-gray-300);
    color: var(--ab-gray-800);
}
.ab-btn-outline:hover { border-color: var(--ab-primary); color: var(--ab-primary); background-color: var(--ab-primary-50); }

.ab-btn-ghost {
    background-color: transparent;
    border-color: transparent;
    color: var(--ab-gray-700);
}
.ab-btn-ghost:hover { background-color: var(--ab-gray-100); color: var(--ab-gray-900); }

.ab-btn-danger {
    background-color: var(--ab-danger);
    border-color: var(--ab-danger);
    color: #fff;
}
.ab-btn-danger:hover { background-color: #962F23; border-color: #962F23; color: #fff; }

.ab-btn-sm { padding: 0.4rem 0.75rem; font-size: 0.8125rem; border-radius: var(--ab-radius-sm); }
.ab-btn-lg { padding: 0.875rem 1.5rem; font-size: 1rem; }

/* ------------------------------------------------------------
   Forms
   ------------------------------------------------------------ */
.ab-label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ab-gray-700);
    margin-bottom: 0.375rem;
    letter-spacing: 0.005em;
}
.ab-label-required::after { content: ' *'; color: var(--ab-danger); }

.ab-input, .ab-select, .ab-textarea {
    display: block;
    width: 100%;
    font-family: var(--ab-font);
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ab-gray-900);
    background-color: var(--ab-surface);
    border: 1px solid var(--ab-gray-300);
    border-radius: var(--ab-radius);
    padding: 0.5625rem 0.75rem;
    transition: border-color var(--ab-transition), box-shadow var(--ab-transition);
}
.ab-input::placeholder, .ab-textarea::placeholder { color: var(--ab-gray-400); }

.ab-input:focus, .ab-select:focus, .ab-textarea:focus {
    outline: none;
    border-color: var(--ab-primary-500);
    box-shadow: 0 0 0 3px var(--ab-primary-glow);
}

.ab-textarea { min-height: 96px; resize: vertical; }

.ab-input.is-error, .ab-select.is-error, .ab-textarea.is-error {
    border-color: var(--ab-danger);
    box-shadow: 0 0 0 3px rgba(178, 58, 44, 0.1);
}
.ab-input-help { font-size: 0.8125rem; color: var(--ab-gray-500); margin-top: 0.375rem; }
.ab-input-error { font-size: 0.8125rem; color: var(--ab-danger); margin-top: 0.375rem; }

.ab-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%235C5648'%3e%3cpath d='M8 11L3 6h10z'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 14px;
    padding-right: 2.25rem;
}

/* Bootstrap .input-group compatibility — collapse natural width so the
   $ prefix and the input render inline. Mirrors what Bootstrap does
   automatically for its own .form-control class. */
.input-group > .ab-input,
.input-group > .ab-select {
    position: relative;
    flex: 1 1 auto;
    width: 1%;
    min-width: 0;
}
/* When an .ab-input follows an input-group prefix, flatten its left edge
   so the prefix and field merge visually. */
.input-group > .input-group-text + .ab-input,
.input-group > .input-group-text + .ab-select {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}
.input-group > .ab-input:not(:last-child),
.input-group > .ab-select:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}
.input-group > .input-group-text {
    display: flex;
    align-items: center;
    padding: 0.5625rem 0.75rem;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--ab-gray-600);
    background-color: var(--ab-gray-50);
    border: 1px solid var(--ab-gray-300);
    border-radius: var(--ab-radius);
}
.input-group > .input-group-text:first-child {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right: 0;
}
.input-group > .input-group-text:last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    border-left: 0;
}

.ab-check {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
    color: var(--ab-gray-800);
    cursor: pointer;
    user-select: none;
}
.ab-check input[type="checkbox"], .ab-check input[type="radio"] {
    appearance: none;
    width: 18px;
    height: 18px;
    border: 1px solid var(--ab-gray-400);
    background-color: var(--ab-surface);
    cursor: pointer;
    transition: all var(--ab-transition);
    flex-shrink: 0;
    position: relative;
}
.ab-check input[type="checkbox"] { border-radius: var(--ab-radius-sm); }
.ab-check input[type="radio"] { border-radius: 50%; }
.ab-check input:checked { background-color: var(--ab-primary); border-color: var(--ab-primary); }
.ab-check input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3e%3cpath d='M13.485 4.515a1 1 0 0 1 0 1.414l-6 6a1 1 0 0 1-1.414 0l-3-3a1 1 0 1 1 1.414-1.414L6.778 9.808l5.293-5.293a1 1 0 0 1 1.414 0z'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 14px;
}
.ab-check input[type="radio"]:checked::after {
    content: '';
    position: absolute;
    inset: 4px;
    background-color: #fff;
    border-radius: 50%;
}
.ab-check input:focus-visible { outline: 2px solid var(--ab-primary-400); outline-offset: 2px; }

.ab-switch { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; }
.ab-switch input { opacity: 0; width: 0; height: 0; }
.ab-switch-track {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background-color: var(--ab-gray-300);
    border-radius: 999px;
    transition: background-color var(--ab-transition);
}
.ab-switch-track::before {
    content: '';
    position: absolute;
    width: 16px; height: 16px;
    left: 3px; top: 3px;
    background-color: #fff;
    border-radius: 50%;
    transition: transform var(--ab-transition);
    box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}
.ab-switch input:checked + .ab-switch-track { background-color: var(--ab-primary); }
.ab-switch input:checked + .ab-switch-track::before { transform: translateX(18px); }

/* ------------------------------------------------------------
   Action bar — sticky strip of buttons at the top of detail pages
   (status transitions + per-doc shortcuts on PO / quote / SO / invoice).
   Stays visible while scrolling so the user doesn't have to scroll
   to the bottom to advance a doc through its lifecycle.
   ------------------------------------------------------------ */
.ab-action-bar {
    position: sticky;
    top: 0;
    z-index: 90;          /* sits below the navbar (which is 100+) */
    background: var(--ab-surface);
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius);
    padding: 0.625rem 0.875rem;
    margin-bottom: 1rem;
    box-shadow: var(--ab-shadow-sm);
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: space-between;
    align-items: center;
}
.ab-action-bar > .ab-action-group {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

/* When the action bar fully wraps on narrow screens it shouldn't
   reserve so much top padding it pushes the page content down. */
@media (max-width: 575.98px) {
    .ab-action-bar { padding: 0.5rem 0.625rem; }
}

/* Action-bar doc-type accent — a 3px colored top-border that matches
   the .ab-doc-type-chip in the page header, so the document's type
   stays visually anchored once the user scrolls past the title. */
.ab-action-bar[data-doctype="quote"]         { border-top: 3px solid var(--ab-doctype-quote-fg); }
.ab-action-bar[data-doctype="sales_order"]   { border-top: 3px solid var(--ab-doctype-sales_order-fg); }
.ab-action-bar[data-doctype="invoice"]       { border-top: 3px solid var(--ab-doctype-invoice-fg); }
.ab-action-bar[data-doctype="po"]            { border-top: 3px solid var(--ab-doctype-po-fg); }
.ab-action-bar[data-doctype="project"]       { border-top: 3px solid var(--ab-doctype-project-fg); }
.ab-action-bar[data-doctype="delivery"]      { border-top: 3px solid var(--ab-doctype-delivery-fg); }
.ab-action-bar[data-doctype="task"]          { border-top: 3px solid var(--ab-doctype-task-fg); }
.ab-action-bar[data-doctype="punch"]         { border-top: 3px solid var(--ab-doctype-punch-fg); }
.ab-action-bar[data-doctype="survey"]        { border-top: 3px solid var(--ab-doctype-survey-fg); }
.ab-action-bar[data-doctype="customer"]      { border-top: 3px solid var(--ab-doctype-customer-fg); }
.ab-action-bar[data-doctype="contact"]       { border-top: 3px solid var(--ab-doctype-contact-fg); }
.ab-action-bar[data-doctype="supplier"]      { border-top: 3px solid var(--ab-doctype-supplier-fg); }
.ab-action-bar[data-doctype="subcontractor"] { border-top: 3px solid var(--ab-doctype-subcontractor-fg); }
.ab-action-bar[data-doctype="typical"]       { border-top: 3px solid var(--ab-doctype-typical-fg); }
.ab-action-bar[data-doctype="tax_rate"]      { border-top: 3px solid var(--ab-doctype-tax_rate-fg); }
.ab-action-bar[data-doctype="change_order"]  { border-top: 3px solid var(--ab-doctype-change_order-fg); }

/* ------------------------------------------------------------
   Doc-type chip — bold colored pill that sits at the top of every
   detail-page header announcing what kind of record this is
   (QUOTE, PURCHASE ORDER, INVOICE, ...). The biggest wayfinding
   signal on detail pages — pairs with the matching colored top
   border on .ab-action-bar so the type is recognizable both at
   the header and in the sticky scroll position.

   Visual treatment: tinted background + foreground-color text/icon.
   Reads cleanly on the warm off-white page bg without screaming.
   ------------------------------------------------------------ */
.ab-doc-type-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
    /* Fallback colors if data-type is missing or unknown */
    background: var(--ab-gray-100);
    color: var(--ab-gray-700);
    border: 1px solid transparent;
}
.ab-doc-type-chip i {
    font-size: 0.95em;
    line-height: 1;
}
.ab-doc-type-chip[data-type="quote"]         { background: var(--ab-doctype-quote-bg);         color: var(--ab-doctype-quote-fg); }
.ab-doc-type-chip[data-type="sales_order"]   { background: var(--ab-doctype-sales_order-bg);   color: var(--ab-doctype-sales_order-fg); }
.ab-doc-type-chip[data-type="invoice"]       { background: var(--ab-doctype-invoice-bg);       color: var(--ab-doctype-invoice-fg); }
.ab-doc-type-chip[data-type="po"]            { background: var(--ab-doctype-po-bg);            color: var(--ab-doctype-po-fg); }
.ab-doc-type-chip[data-type="project"]       { background: var(--ab-doctype-project-bg);       color: var(--ab-doctype-project-fg); }
.ab-doc-type-chip[data-type="delivery"]      { background: var(--ab-doctype-delivery-bg);      color: var(--ab-doctype-delivery-fg); }
.ab-doc-type-chip[data-type="task"]          { background: var(--ab-doctype-task-bg);          color: var(--ab-doctype-task-fg); }
.ab-doc-type-chip[data-type="punch"]         { background: var(--ab-doctype-punch-bg);         color: var(--ab-doctype-punch-fg); }
.ab-doc-type-chip[data-type="survey"]        { background: var(--ab-doctype-survey-bg);        color: var(--ab-doctype-survey-fg); }
.ab-doc-type-chip[data-type="customer"]      { background: var(--ab-doctype-customer-bg);      color: var(--ab-doctype-customer-fg); }
.ab-doc-type-chip[data-type="contact"]       { background: var(--ab-doctype-contact-bg);       color: var(--ab-doctype-contact-fg); }
.ab-doc-type-chip[data-type="supplier"]      { background: var(--ab-doctype-supplier-bg);      color: var(--ab-doctype-supplier-fg); }
.ab-doc-type-chip[data-type="subcontractor"] { background: var(--ab-doctype-subcontractor-bg); color: var(--ab-doctype-subcontractor-fg); }
.ab-doc-type-chip[data-type="typical"]       { background: var(--ab-doctype-typical-bg);       color: var(--ab-doctype-typical-fg); }
.ab-doc-type-chip[data-type="tax_rate"]      { background: var(--ab-doctype-tax_rate-bg);      color: var(--ab-doctype-tax_rate-fg); }
.ab-doc-type-chip[data-type="change_order"]  { background: var(--ab-doctype-change_order-bg);  color: var(--ab-doctype-change_order-fg); }

/* On phones the existing flex header gets cramped — let the chip
   wrap to its own line above the title rather than fighting for
   horizontal space with the h1. */
@media (max-width: 575.98px) {
    .ab-doc-type-chip {
        font-size: 0.72rem;
        padding: 0.32rem 0.7rem;
    }
}

/* ------------------------------------------------------------
   Count pill — sits next to a list-page <h1> title showing the
   total record count. Replaces the tiny mono inline number that
   used to be hidden in the header.
   ------------------------------------------------------------ */
.ab-count-pill {
    display: inline-flex;
    align-items: center;
    margin-left: 0.6rem;
    padding: 0.18rem 0.7rem;
    background: var(--ab-primary-50);
    color: var(--ab-primary-700, var(--ab-primary));
    font-size: 0.95rem;
    font-weight: 600;
    border-radius: 999px;
    line-height: 1.35;
    vertical-align: 0.18em;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}

/* ------------------------------------------------------------
   Cards
   ------------------------------------------------------------ */
.ab-card {
    background-color: var(--ab-surface);
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius-lg);
    box-shadow: var(--ab-shadow-sm);
    overflow: hidden;
    transition: box-shadow var(--ab-transition), transform var(--ab-transition);
}
.ab-card-hover:hover { box-shadow: var(--ab-shadow-md); }

.ab-card-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--ab-gray-200);
    background-color: var(--ab-surface-alt);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}
.ab-card-title { font-size: 1rem; font-weight: 600; margin: 0; color: var(--ab-gray-900); }
.ab-card-body { padding: 1.25rem; }
.ab-card-footer {
    padding: 0.875rem 1.25rem;
    border-top: 1px solid var(--ab-gray-200);
    background-color: var(--ab-surface-alt);
}
.ab-card-image {
    width: 100%;
    height: 180px;
    object-fit: cover;
    display: block;
    background-color: var(--ab-gray-100);
}

/* ------------------------------------------------------------
   Badges (status)
   ------------------------------------------------------------ */
.ab-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.625rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.01em;
    text-transform: capitalize;
    background-color: var(--ab-gray-100);
    color: var(--ab-gray-700);
    border: 1px solid var(--ab-gray-200);
    white-space: nowrap;
}
.ab-badge::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background-color: currentColor;
    flex-shrink: 0;
}

/* Project lifecycle status badges */
.ab-badge-lead          { color: var(--ab-status-lead);       background-color: var(--ab-gray-100);    border-color: var(--ab-gray-200); }
.ab-badge-surveyed      { color: var(--ab-status-surveyed);   background-color: #E5EBF2;               border-color: #C8D4E2; }
.ab-badge-quoted        { color: var(--ab-status-quoted);     background-color: var(--ab-info-bg);     border-color: #C8D7E8; }
.ab-badge-proposal_sent { color: var(--ab-status-proposal);   background-color: #ECE7F1;               border-color: #D6CDE0; }
.ab-badge-deposit_paid  { color: var(--ab-status-deposit);    background-color: var(--ab-success-bg);  border-color: #BBE0C9; }
.ab-badge-in_production { color: var(--ab-status-production); background-color: var(--ab-warning-bg);  border-color: #EBD5A4; }
.ab-badge-received      { color: var(--ab-status-received);   background-color: #EAF0E1;               border-color: #C7D5B0; }
.ab-badge-scheduled     { color: var(--ab-status-scheduled);  background-color: var(--ab-accent-50);   border-color: var(--ab-accent-100); }
.ab-badge-installing    { color: var(--ab-status-installing); background-color: var(--ab-accent-50);   border-color: var(--ab-accent-100); }
.ab-badge-punch         { color: var(--ab-status-punch);      background-color: #F4E8D6;               border-color: #DBC59B; }
.ab-badge-complete      { color: var(--ab-status-complete);   background-color: var(--ab-success-bg);  border-color: #A6CFB6; }
.ab-badge-cancelled     { color: var(--ab-status-cancelled);  background-color: var(--ab-danger-bg);   border-color: #E2BAB3; }

.ab-badge-success { color: var(--ab-success); background-color: var(--ab-success-bg); border-color: #BBE0C9; }
.ab-badge-warning { color: var(--ab-warning); background-color: var(--ab-warning-bg); border-color: #EBD5A4; }
.ab-badge-danger  { color: var(--ab-danger);  background-color: var(--ab-danger-bg);  border-color: #E2BAB3; }
.ab-badge-info    { color: var(--ab-info);    background-color: var(--ab-info-bg);    border-color: #C8D7E8; }
.ab-badge-secondary { color: var(--ab-gray-700); background-color: var(--ab-gray-100); border-color: var(--ab-gray-200); }

/* ------------------------------------------------------------
   Tables
   ------------------------------------------------------------ */
.ab-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background-color: var(--ab-surface);
    border-radius: var(--ab-radius-lg);
    overflow: hidden;
    box-shadow: var(--ab-shadow-sm);
    border: 1px solid var(--ab-gray-200);
}
.ab-table thead th {
    background-color: var(--ab-surface-alt);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ab-gray-600);
    padding: 0.75rem 1rem;
    text-align: left;
    border-bottom: 1px solid var(--ab-gray-200);
}
.ab-table tbody td {
    padding: 0.875rem 1rem;
    font-size: 0.9375rem;
    color: var(--ab-gray-800);
    border-bottom: 1px solid var(--ab-gray-100);
    vertical-align: middle;
}
.ab-table tbody tr:last-child td { border-bottom: none; }
.ab-table tbody tr:hover { background-color: var(--ab-surface-alt); }
.ab-table-num { font-family: var(--ab-font-mono); font-variant-numeric: tabular-nums; text-align: right; }

/* ------------------------------------------------------------
   Alerts (tied to usSuccess / usError / usMessage)
   ------------------------------------------------------------ */
.ab-alert {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    padding: 0.875rem 1rem;
    border-radius: var(--ab-radius);
    border: 1px solid transparent;
    border-left-width: 4px;
    background-color: var(--ab-gray-50);
    font-size: 0.9375rem;
    line-height: 1.5;
    margin-bottom: 1rem;
}
.ab-alert-icon {
    flex-shrink: 0;
    width: 20px; height: 20px;
    display: inline-flex; align-items: center; justify-content: center;
    margin-top: 1px;
}
.ab-alert-success { background-color: var(--ab-success-bg); border-color: #BBE0C9; border-left-color: var(--ab-success); color: #1F5C3D; }
.ab-alert-warning { background-color: var(--ab-warning-bg); border-color: #EBD5A4; border-left-color: var(--ab-warning); color: #7A5212; }
.ab-alert-danger  { background-color: var(--ab-danger-bg);  border-color: #E2BAB3; border-left-color: var(--ab-danger);  color: #7A2820; }
.ab-alert-info    { background-color: var(--ab-info-bg);    border-color: #C8D7E8; border-left-color: var(--ab-info);    color: #1F3D5C; }

/* Toast width — core CSS sets min-width:30vw / max-width:85vw which is
   massive on desktop. Pin to a tidy fixed range so notifications don't
   span half the screen. */
.us-toast {
    min-width: 280px !important;
    max-width: 420px !important;
}
.us-toast .toast-body { font-size: 0.9375rem; line-height: 1.45; }

/* ------------------------------------------------------------
   Milestone progress (50/40/10)
   ------------------------------------------------------------ */
.ab-progress {
    display: flex;
    height: 10px;
    background-color: var(--ab-gray-100);
    border-radius: 999px;
    overflow: hidden;
    border: 1px solid var(--ab-gray-200);
}
.ab-progress-segment {
    height: 100%;
    border-right: 2px solid var(--ab-surface);
}
.ab-progress-segment:last-child { border-right: none; }
.ab-progress-paid { background-color: var(--ab-success); }
.ab-progress-due  { background-color: var(--ab-accent); }
.ab-progress-pending { background-color: var(--ab-gray-200); }

.ab-milestone-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.625rem 0;
    border-bottom: 1px solid var(--ab-gray-100);
    font-size: 0.875rem;
}
.ab-milestone-row:last-child { border-bottom: none; }
.ab-milestone-label { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--ab-gray-700); }
.ab-milestone-amount { font-family: var(--ab-font-mono); font-weight: 600; color: var(--ab-gray-900); }
.ab-milestone-dot { width: 10px; height: 10px; border-radius: 50%; background-color: var(--ab-gray-300); }
.ab-milestone-dot.paid { background-color: var(--ab-success); }
.ab-milestone-dot.due  { background-color: var(--ab-accent); }

/* ------------------------------------------------------------
   Pagination
   ------------------------------------------------------------ */
.ab-pagination {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    list-style: none;
    padding: 0;
    margin: 0;
}
.ab-pagination li a, .ab-pagination li span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 0.625rem;
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius-sm);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ab-gray-700);
    background-color: var(--ab-surface);
    text-decoration: none;
    transition: all var(--ab-transition);
}
.ab-pagination li a:hover { border-color: var(--ab-primary-400); color: var(--ab-primary); background-color: var(--ab-primary-50); }
.ab-pagination li.active a, .ab-pagination li.active span {
    background-color: var(--ab-primary);
    border-color: var(--ab-primary);
    color: #fff;
}
.ab-pagination li.disabled span { color: var(--ab-gray-400); background-color: var(--ab-gray-50); cursor: not-allowed; }

/* ------------------------------------------------------------
   Empty state
   ------------------------------------------------------------ */
.ab-empty {
    text-align: center;
    padding: 3rem 1.5rem;
    background-color: var(--ab-surface);
    border: 1px dashed var(--ab-gray-300);
    border-radius: var(--ab-radius-lg);
}
.ab-empty-icon {
    width: 64px; height: 64px;
    margin: 0 auto 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--ab-gray-100);
    border-radius: 50%;
    color: var(--ab-gray-500);
    font-size: 1.5rem;
}
.ab-empty-title { font-size: 1.125rem; font-weight: 600; color: var(--ab-gray-900); margin-bottom: 0.5rem; }
.ab-empty-text  { color: var(--ab-gray-600); margin-bottom: 1.25rem; max-width: 440px; margin-left: auto; margin-right: auto; }

/* ------------------------------------------------------------
   Modals (themed Bootstrap modal)
   ------------------------------------------------------------ */
.modal-content {
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius-lg);
    box-shadow: var(--ab-shadow-xl);
}
.modal-header {
    border-bottom-color: var(--ab-gray-200);
    background-color: var(--ab-surface-alt);
    border-top-left-radius: var(--ab-radius-lg);
    border-top-right-radius: var(--ab-radius-lg);
    padding: 1rem 1.25rem;
}
.modal-title { font-weight: 600; color: var(--ab-gray-900); font-size: 1.0625rem; }
.modal-body  { padding: 1.25rem; color: var(--ab-gray-800); }
.modal-footer {
    border-top-color: var(--ab-gray-200);
    background-color: var(--ab-surface-alt);
    padding: 0.875rem 1.25rem;
    border-bottom-left-radius: var(--ab-radius-lg);
    border-bottom-right-radius: var(--ab-radius-lg);
}

/* ------------------------------------------------------------
   Color swatches (style guide)
   ------------------------------------------------------------ */
.ab-swatch {
    display: flex;
    flex-direction: column;
    border-radius: var(--ab-radius);
    overflow: hidden;
    border: 1px solid var(--ab-gray-200);
    background-color: var(--ab-surface);
}
.ab-swatch-color { height: 80px; }
.ab-swatch-info  { padding: 0.625rem 0.75rem; }
.ab-swatch-name  { font-size: 0.8125rem; font-weight: 600; color: var(--ab-gray-900); }
.ab-swatch-hex   { font-family: var(--ab-font-mono); font-size: 0.75rem; color: var(--ab-gray-500); }

/* ------------------------------------------------------------
   Typeahead (catalog item picker — replaces big <select>s)
   Used by quote/SO/PO/quick-sale add-line forms via ab_typeahead.js.
   ------------------------------------------------------------ */
.ab-typeahead-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1050;
    background: var(--ab-surface);
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius);
    box-shadow: var(--ab-shadow-lg);
    max-height: 380px;
    overflow-y: auto;
    margin-top: 4px;
}
.ab-typeahead-item {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    border-bottom: 1px solid var(--ab-gray-100);
}
.ab-typeahead-item:last-child { border-bottom: 0; }
.ab-typeahead-item.active,
.ab-typeahead-item:hover { background: var(--ab-primary-50); }
.ab-typeahead-thumb {
    width: 36px;
    height: 36px;
    object-fit: cover;
    border-radius: var(--ab-radius-sm);
    border: 1px solid var(--ab-gray-200);
    background: var(--ab-surface);
    flex-shrink: 0;
}
.ab-typeahead-thumb-blank {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ab-gray-400);
    background: var(--ab-gray-100);
    border-style: dashed;
}
.ab-typeahead-body {
    flex: 1;
    min-width: 0;
}
.ab-typeahead-meta {
    font-size: 0.75rem;
    color: var(--ab-gray-500);
    margin-bottom: 1px;
}
.ab-typeahead-name {
    font-weight: 500;
    color: var(--ab-gray-900);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ab-typeahead-price {
    flex-shrink: 0;
    font-family: var(--ab-font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--ab-gray-900);
    text-align: right;
    line-height: 1.15;
}
.ab-typeahead-unit {
    font-family: var(--ab-font);
    font-size: 0.6875rem;
    font-weight: 400;
    color: var(--ab-gray-500);
}
.ab-typeahead-empty,
.ab-typeahead-more {
    padding: 0.75rem;
    text-align: center;
    color: var(--ab-gray-500);
    font-size: 0.8125rem;
}
.ab-typeahead-more {
    border-top: 1px solid var(--ab-gray-100);
    background: var(--ab-surface-alt);
}

/* "Browse all" button + modal — added by ab_typeahead.js.
   Wraps the input + button in a flex row so the icon button aligns with
   the input's right edge. */
.ab-typeahead-wrap {
    display: flex;
    align-items: stretch;
    gap: 0.375rem;
    width: 100%;
}
.ab-typeahead-wrap > .ab-input,
.ab-typeahead-wrap > input { flex: 1 1 auto; min-width: 0; }
.ab-browse-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    border: 1px solid var(--ab-gray-300);
    background: var(--ab-surface);
    color: var(--ab-gray-700);
    border-radius: var(--ab-radius);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.ab-browse-btn:hover {
    background: var(--ab-primary-50);
    border-color: var(--ab-primary-300, var(--ab-primary));
    color: var(--ab-primary);
}
.ab-browse-btn:focus-visible {
    outline: 2px solid var(--ab-primary);
    outline-offset: 2px;
}

/* Catalog browse modal — populated by ABTypeahead._openBrowseModal(). */
.ab-browse-supplier-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    background: var(--ab-doctype-supplier-bg, var(--ab-gray-100));
    color: var(--ab-doctype-supplier-fg, var(--ab-gray-700));
}
.ab-browse-search { width: 100%; }
.ab-browse-modal-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8125rem;
}
.ab-browse-modal-table thead th {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ab-gray-600);
    font-weight: 600;
    padding: 0.5rem 0.625rem;
    border-bottom: 2px solid var(--ab-gray-200);
    background: var(--ab-surface-alt);
    position: sticky;
    top: 0;
    z-index: 1;
}
.ab-browse-modal-table tbody td {
    padding: 0.5rem 0.625rem;
    border-bottom: 1px solid var(--ab-gray-100);
    vertical-align: middle;
}
.ab-browse-modal-table tbody tr {
    cursor: pointer;
    transition: background 0.1s;
}
.ab-browse-modal-table tbody tr:hover {
    background: var(--ab-primary-50);
}
.ab-browse-modal-table tbody tr.ab-browse-current {
    background: var(--ab-primary-50);
    box-shadow: inset 3px 0 0 var(--ab-primary);
}
.ab-browse-thumb {
    width: 36px;
    height: 36px;
    object-fit: cover;
    border-radius: 4px;
    background: var(--ab-gray-100);
    display: block;
}
.ab-browse-thumb-blank {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ab-gray-400);
    font-size: 0.875rem;
}

/* Entity typeahead (customers/suppliers — no thumbnail, no price column).
   Used by ab_entity_typeahead.js on project/quick_sale/typical/po pages. */
.ab-typeahead-item-entity .ab-typeahead-name {
    font-weight: 600;
}
.ab-typeahead-clear {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    width: 1.5rem;
    height: 1.5rem;
    line-height: 1;
    border: 0;
    background: var(--ab-gray-200);
    color: var(--ab-gray-700);
    border-radius: 50%;
    cursor: pointer;
    font-size: 1rem;
    padding: 0;
    z-index: 2;
}
.ab-typeahead-clear:hover { background: var(--ab-gray-300); color: var(--ab-gray-900); }

/* Helper text shown next to the typeahead after a pick */
.ab-typeahead-preview {
    margin-top: 0.375rem;
    padding: 0.5rem 0.625rem;
    background: var(--ab-success-bg);
    border: 1px solid #BBE0C9;
    border-radius: var(--ab-radius-sm);
    font-size: 0.8125rem;
    color: var(--ab-gray-800);
}
.ab-typeahead-preview strong { color: var(--ab-gray-900); }

/* ------------------------------------------------------------
   Auth screens (login, join, forgot, etc. — usersc/ overrides)
   Standalone pages without the navbar/footer chrome.
   ------------------------------------------------------------ */
.ab-auth-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    background:
        radial-gradient(circle at 20% 10%, rgba(200, 114, 42, 0.08), transparent 45%),
        radial-gradient(circle at 80% 90%, rgba(15, 42, 68, 0.10),  transparent 50%),
        var(--ab-bg);
}
.ab-auth-card {
    width: 100%;
    max-width: 440px;
    background-color: var(--ab-surface);
    border: 1px solid var(--ab-gray-200);
    border-radius: var(--ab-radius-lg);
    box-shadow: var(--ab-shadow-xl);
    overflow: hidden;
}
.ab-auth-header {
    padding: 1.75rem 1.75rem 0.5rem;
    text-align: center;
}
.ab-auth-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    margin-bottom: 1.25rem;
    text-decoration: none;
}
.ab-auth-brand .ab-brand-mark { width: 40px; height: 40px; font-size: 1rem; }
.ab-auth-brand-text {
    font-weight: 700;
    font-size: 1.0625rem;
    color: var(--ab-gray-900);
    letter-spacing: -0.02em;
}
.ab-auth-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.375rem; color: var(--ab-gray-900); }
.ab-auth-sub   { font-size: 0.9375rem; color: var(--ab-gray-600); margin-bottom: 0; }
.ab-auth-body  { padding: 1.5rem 1.75rem 1.75rem; }
.ab-auth-footer {
    border-top: 1px solid var(--ab-gray-200);
    padding: 1rem 1.75rem;
    background-color: var(--ab-surface-alt);
    text-align: center;
    font-size: 0.875rem;
    color: var(--ab-gray-600);
}
.ab-auth-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 1.25rem 0;
    color: var(--ab-gray-500);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.ab-auth-divider::before, .ab-auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background-color: var(--ab-gray-200);
}
.ab-auth-input-group {
    position: relative;
    display: flex;
}
.ab-auth-input-group .ab-input { padding-right: 2.75rem; }
.ab-auth-toggle-pw {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    color: var(--ab-gray-500);
    background: transparent;
    border: 0;
    cursor: pointer;
    border-radius: var(--ab-radius-sm);
}
.ab-auth-toggle-pw:hover { color: var(--ab-gray-800); background-color: var(--ab-gray-100); }
.ab-auth-totp-input {
    text-align: center;
    letter-spacing: 0.5em;
    font-size: 1.25rem;
    font-family: var(--ab-font-mono);
    padding: 0.875rem;
}

/* ------------------------------------------------------------
   Footer
   ------------------------------------------------------------ */
.ab-footer {
    background-color: var(--ab-surface);
    border-top: 1px solid var(--ab-gray-200);
    padding: 1.5rem 0;
    margin-top: 3rem;
    color: var(--ab-gray-500);
    font-size: 0.8125rem;
}
.ab-footer-name { font-weight: 600; color: var(--ab-gray-700); }
.ab-footer-tag {
    display: inline-block;
    margin-left: 0.5rem;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    background-color: var(--ab-gray-100);
    color: var(--ab-gray-600);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* ------------------------------------------------------------
   Container override (warmer, slightly wider)
   ------------------------------------------------------------ */
.container, .container-fluid { padding-left: 1.25rem; padding-right: 1.25rem; }
@media (min-width: 1200px) {
    .container { max-width: var(--ab-content-max); }
}

/* ------------------------------------------------------------
   Utilities
   ------------------------------------------------------------ */
.ab-stack > * + * { margin-top: 1rem; }
.ab-stack-sm > * + * { margin-top: 0.5rem; }
.ab-stack-lg > * + * { margin-top: 1.5rem; }
.ab-divider { height: 1px; background-color: var(--ab-gray-200); margin: 1.5rem 0; border: none; }
.ab-mono { font-family: var(--ab-font-mono); font-variant-numeric: tabular-nums; }
.ab-num  { font-variant-numeric: tabular-nums; }

/* Visually hidden — screen-reader-only labels */
.ab-sr-only {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    white-space: nowrap; border: 0;
}

/* Reduced motion preference */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

/* ============================================================
   Mobile / narrow-viewport adjustments
   ============================================================
   Everything below applies only at narrow widths. The desktop
   layout above is unchanged — these rules are purely additive.
   Two breakpoints in use:
     <= 768px  — phones + small tablets (most adjustments)
     <= 575px  — phone-only, tightest layout
   We never change `:root` tokens here, so the design system stays
   stable across viewports. */

/* ------------------------------------------------------------
   Tables — horizontal scroll wrapper for narrow viewports.
   Most list pages render `<div class="ab-card"><table class="ab-table">`
   directly. With 6–10 columns, the table can't fit on a phone, so
   between 576–768px we let the table scroll horizontally inside its
   card. Below 576px, list-page tables (those tagged .ab-list-table)
   morph into stacked card rows — see the next block. Detail-page
   line-item tables (no .ab-list-table) keep horizontal scroll all
   the way down because their cells need to stay aligned (price/qty
   columns mean nothing without context).
   ------------------------------------------------------------ */
@media (max-width: 768px) {
    /* Cards become horizontally scrollable on narrow viewports so
       the contained table can overflow without squashing columns.
       We override the base `overflow: hidden` here. Cards that don't
       contain a wide child see no visual change — there's simply
       nothing to scroll. Vertical overflow stays hidden so card
       borders still clip correctly. */
    .ab-card {
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
    }
    /* Force the table to size to its content rather than fit the
       parent. Combined with `nowrap` cells below, this triggers
       overflow on the ancestor card when the table is wider than
       the viewport. Selector covers both layouts:
         - .ab-card > .ab-table (most list pages)
         - .ab-card .ab-card-body .ab-table (PO receipt subform) */
    .ab-card .ab-table {
        width: max-content;
        min-width: 100%;
    }
    /* Cells should not wrap mid-text on narrow widths — readability
       beats vertical compression when horizontal scroll is available.
       Tightening padding gains a few px of useful width. */
    .ab-card .ab-table thead th,
    .ab-card .ab-table tbody td {
        white-space: nowrap;
        padding: 0.625rem 0.75rem;
    }
    /* Page-level inline styles in catalog.php / quote.php / projects.php
       use `text-overflow: ellipsis; white-space: nowrap; max-width: 320px`
       on description cells. Those keep working because their explicit
       max-width caps the cell content. No override needed. */
}

/* ------------------------------------------------------------
   List-page tables — phone-only card mode (≤575.98px).
   Tables marked with .ab-list-table morph into stacked per-row
   cards on phones. Each <td> needs a data-label="Column name"
   attribute that the CSS surfaces via ::before.
   - Detail-page line tables (no .ab-list-table class) keep their
     horizontal-scroll behaviour from the block above, because in
     a quote line table the columns (qty, unit price, line total)
     only make sense aligned.
   - The .ab-card wrapper drops its scroll on this breakpoint so
     each row card is full width with no horizontal overflow.
   ------------------------------------------------------------ */
@media (max-width: 575.98px) {
    /* The wrapping card no longer needs horizontal scroll — the
       table becomes a vertical stack. Removing scroll also lets
       focus rings on row links sit above the card border. */
    .ab-card:has(> .ab-list-table) {
        overflow: visible;
    }

    /* Hide the column header row entirely; labels move inline. */
    .ab-list-table thead {
        display: none;
    }

    /* Each row becomes its own card-styled block. */
    .ab-list-table,
    .ab-list-table tbody,
    .ab-list-table tr,
    .ab-list-table td {
        display: block;
        width: auto;
        max-width: none;
    }

    .ab-list-table {
        background: transparent;
        border: 0;
        box-shadow: none;
        border-radius: 0;
        min-width: 0;
    }

    .ab-list-table tbody tr {
        background: var(--ab-surface);
        border: 1px solid var(--ab-gray-200);
        border-radius: var(--ab-radius);
        box-shadow: var(--ab-shadow-sm);
        margin-bottom: 0.625rem;
        padding: 0.25rem 0;
        overflow: hidden;
    }
    .ab-list-table tbody tr:last-child { margin-bottom: 0; }
    .ab-list-table tbody tr:hover { background: var(--ab-surface); }

    /* Each cell becomes a row inside the card with the column
       name on the left and the value on the right. */
    .ab-list-table tbody td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        padding: 0.5rem 0.875rem;
        border-bottom: 1px solid var(--ab-gray-100);
        white-space: normal;
        text-align: right;
        min-height: 2rem;
    }
    .ab-list-table tbody tr td:last-child {
        border-bottom: 0;
    }

    /* Surface the column name from data-label as a leading caption.
       Cells without a data-label (action button cells, image cells)
       simply render full-width with no caption. */
    .ab-list-table tbody td[data-label]::before {
        content: attr(data-label);
        flex: 0 0 40%;
        text-align: left;
        font-size: 0.75rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--ab-gray-500);
    }

    /* Cells flagged as "primary" (the row's main link, e.g. code or
       title) get pulled to the top with no caption and centered text
       so they read like a card title. */
    .ab-list-table tbody td.ab-list-primary {
        justify-content: flex-start;
        text-align: left;
        font-weight: 600;
        background: var(--ab-surface-alt);
        padding: 0.625rem 0.875rem;
    }
    .ab-list-table tbody td.ab-list-primary::before {
        display: none;
    }

    /* Cells with no data-label and no .ab-list-primary (typically the
       trailing "edit" button column) align to the right edge. */
    .ab-list-table tbody td:not([data-label]):not(.ab-list-primary) {
        justify-content: flex-end;
    }

    /* Numeric/right-aligned cells should still right-align their value
       beside the label. The caption stays left, the value right. */
    .ab-list-table tbody td.ab-table-num {
        text-align: right;
        font-family: var(--ab-font-mono);
    }

    /* Inner truncation containers (max-width: 240px ellipsis on project
       name divs in pos.php / quotes.php / projects.php / etc.) are
       useless on a stacked card — let them wrap normally. */
    .ab-list-table tbody td > div[style*="max-width"] {
        max-width: none !important;
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }
}

/* ------------------------------------------------------------
   Filter bars — collapse into a single "Filters" toggle on phones.
   Filter forms are tagged with .ab-filter-bar so the JS in
   ab_filter_collapse.js can find them. At ≤575.98px the inner
   .row of fields is hidden by default and a toggle button is
   injected. If the form has any active (non-default) filter, the
   JS opens the bar on load so the user sees current state.
   ------------------------------------------------------------ */
.ab-filter-bar-toggle {
    display: none; /* desktop: hidden, JS only reveals on phones */
}

@media (max-width: 575.98px) {
    /* The toggle button is rendered by the JS into the card body;
       this just makes it visible at this breakpoint. */
    .ab-filter-bar .ab-filter-bar-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        gap: 0.5rem;
    }
    .ab-filter-bar .ab-filter-bar-toggle .ab-filter-bar-count {
        display: inline-flex;
        align-items: center;
        padding: 0.125rem 0.5rem;
        background: var(--ab-accent-50);
        color: var(--ab-accent-600);
        border-radius: 999px;
        font-size: 0.75rem;
        font-weight: 600;
        margin-left: 0.5rem;
    }

    /* When collapsed, hide the filter row + the active-filter chip
       row underneath. JS toggles `is-open` on the form element. */
    .ab-filter-bar:not(.is-open) .ab-card-body > .row,
    .ab-filter-bar:not(.is-open) .ab-card-body > .mt-2 {
        display: none;
    }

    /* Open state: the toggle button sits above the form fields with
       a small gap. */
    .ab-filter-bar.is-open .ab-filter-bar-toggle {
        margin-bottom: 0.625rem;
    }
}

/* ------------------------------------------------------------
   Long mono codes — Q-202604-0001, PO-202604-0042, INV-DEMO-001.
   At narrow widths, allow them to break inside flex rows so they
   don't push their parent off-screen. Inside .ab-table cells they
   stay nowrap (handled above) since the table itself scrolls.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    /* Outside of tables, mono codes can wrap. Common case: sidebar
       list items in detail pages with code + badge in a flex row. */
    .ab-card-body .ab-mono,
    .ab-milestone-amount {
        overflow-wrap: anywhere;
        word-break: break-word;
    }
    /* Reset for table cells / inline numerics where wrapping would
       be ugly — the table scroll wrapper already handles overflow. */
    .ab-table .ab-mono,
    .ab-table-num,
    .ab-table-num .ab-mono {
        overflow-wrap: normal;
        word-break: normal;
    }
}

/* ------------------------------------------------------------
   Touch targets — icon-only `.ab-btn-sm` buttons in tables.
   Per-line action columns (move up/down/delete) use ghost+sm
   buttons that render around 28x28px — too small to tap reliably.
   On coarse pointers (touch devices), bump them to 36px min.
   We keep the small *visual* size on mouse devices; only touch
   gets the larger hit area.
   ------------------------------------------------------------ */
@media (pointer: coarse) {
    /* `.ab-btn-sm` defaults to ~28px tall — too small for touch.
       Default `.ab-btn` is already ~38px, so no change there.
       Pagination items + password-toggle eye are already 36px. */
    .ab-btn-sm {
        min-height: 36px;
        min-width: 36px;
    }
}

/* ------------------------------------------------------------
   Forms — prevent iOS auto-zoom on focus.
   iOS zooms the viewport when an input has font-size < 16px and
   the user taps it. We bump inputs to 16px on phones to suppress
   that behaviour. Visual size adjusted via line-height / padding
   so layout doesn't shift much.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    .ab-input,
    .ab-select,
    .ab-textarea {
        font-size: 16px;
    }
    /* The `+ Apply` filter button on list pages already takes
       `w-100` at xl-1, but on phones the column wraps and the
       button becomes the only thing on its row. Cap its height
       so it visually matches the other filter selects above it. */
    .ab-card-body form .row.g-2 > .col-12 > .ab-btn {
        margin-top: 0.25rem;
    }
}

/* ------------------------------------------------------------
   Per-line action button columns in quote/PO/SO/invoice tables.
   These render 2–3 ghost+sm icon buttons in a single cell. With
   the table-scroll wrapper above, this works fine — but we still
   want the buttons to stay on one line inside their cell rather
   than stacking, since the cell already has `white-space: nowrap`.
   This rule keeps the buttons visually grouped at any width.
   ------------------------------------------------------------ */
.ab-table tbody td > .ab-btn + .ab-btn { margin-left: 0.125rem; }

/* (Detail-page action bars already stack cleanly via Bootstrap's
   `flex-wrap gap-2` — the gap utility handles both row + column
   spacing, so no extra rules needed here.) */

/* ------------------------------------------------------------
   Card headers — the right-side actions (e.g. "+ New" link in
   sidebar card headers) shouldn't collapse onto the title text.
   Bootstrap's flex-wrap is fine, but the title needs to be allowed
   to wrap when long.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    .ab-card-header {
        flex-wrap: wrap;
        gap: 0.5rem;
    }
    .ab-card-title {
        min-width: 0;
        flex: 1 1 auto;
    }
}

/* ------------------------------------------------------------
   Page header rows — title left + status badges / "+ New" CTA
   right. Most pages already use `d-flex flex-wrap`, but tighten
   the gap and allow the badge cluster to drop below the title
   without leaving an awkward sliver of whitespace.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    /* Page-level <header> with mb-4 wrapping flex content */
    header.d-flex.flex-wrap {
        gap: 0.75rem !important;
    }
    /* Make the page H1 a touch smaller on the narrowest phones so
       it doesn't dominate the screen. */
    h1, .ab-h1 { font-size: 1.75rem; }
}

/* ------------------------------------------------------------
   Container padding — Bootstrap's default 12px + our 20px override
   eats horizontal space on phones. Tighten to 16px at narrow widths.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    .container,
    .container-fluid {
        padding-left: 1rem;
        padding-right: 1rem;
    }
}

/* ------------------------------------------------------------
   Project page pipeline timeline — uses a fixed-width 200px date
   slot in a flex row. On narrow widths the label gets squashed.
   Allow the row to wrap so label and date stack.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    .ab-card-body .d-flex.align-items-center.gap-3 > div[style*="flex: 0 0 200px"] {
        flex: 1 1 100% !important;
    }
}

/* ------------------------------------------------------------
   Print pages — fixed-position "Back / Print" action bar at top
   right is positioned with `top: 16px; right: 16px`. On phones
   that sits over the document header. Reposition + ensure each
   button hits 36px tap target. Browser print-preview is the
   primary use, so this is mainly for someone who opens the link
   on a phone to forward.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    /* Scoped to .actions.no-print — only the print-page Back/Print
       cluster uses this combination. */
    .actions.no-print {
        top: 8px !important;
        right: 8px !important;
        left: 8px;
        justify-content: flex-end;
    }
    .actions.no-print a,
    .actions.no-print button {
        min-height: 36px;
        min-width: 36px;
        display: inline-flex;
        align-items: center;
    }
}

/* ------------------------------------------------------------
   Auth screens — the auth shell (.ab-auth-shell) already pads
   `2rem 1rem` and the card max-widths to 440px, so it works on
   phones already. Just shrink the inner padding a bit so more
   content shows above the fold.
   ------------------------------------------------------------ */
@media (max-width: 575px) {
    .ab-auth-header { padding: 1.25rem 1.25rem 0.5rem; }
    .ab-auth-body   { padding: 1.25rem; }
    .ab-auth-footer { padding: 0.875rem 1.25rem; }
}

/* ------------------------------------------------------------
   Pipeline timeline (project.php) — compact mode for phones.
   Past/empty milestones (no date set, stage already passed) are
   hidden by default at <=575.98px and revealed by an expander
   button. Desktop view is unaffected.
   ------------------------------------------------------------ */
.ab-pipeline-expand {
    display: none;
    width: 100%;
    margin: 0 0 0.75rem;
    padding: 0.55rem 0.75rem;
    background: var(--ab-gray-50, #f9fafb);
    border: 1px dashed var(--ab-gray-300, #d1d5db);
    border-radius: var(--ab-radius, 0.5rem);
    color: var(--ab-gray-700, #4b5563);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
}
.ab-pipeline-expand:hover { background: var(--ab-gray-100, #f3f4f6); }
.ab-pipeline-expand i { margin-right: 0.4rem; }

@media (max-width: 575.98px) {
    .ab-pipeline-timeline .ab-pipeline-expand { display: block; }
    .ab-pipeline-timeline .ab-pipeline-row--past-empty { display: none; }
    .ab-pipeline-timeline.ab-pipeline-timeline--expanded
        .ab-pipeline-row--past-empty { display: flex; }
}

/* ------------------------------------------------------------
   Print styles — hide chrome, ensure clean output
   ------------------------------------------------------------ */
@media print {
    .ab-navbar,
    .ab-footer,
    .navbar,
    nav,
    .no-print,
    .ab-no-print { display: none !important; }

    body {
        background: #fff !important;
        color: #000 !important;
        font-size: 11pt;
    }

    a { color: #000; text-decoration: none; }
    a[href]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }

    .ab-card,
    .ab-table {
        box-shadow: none !important;
        border: 1px solid #999 !important;
        page-break-inside: avoid;
    }

    h1, h2, h3 { page-break-after: avoid; }
}

/* ============================================================
   Dark mode — applies when:
     1. User has explicitly chosen dark theme (data-bs-theme="dark"
        set on <html> via the head_tags.php bootstrap script), OR
     2. Their preference is 'system' AND OS is in dark mode AND no
        explicit data-bs-theme attribute is set on <html>.

   Strategy: override the SAME custom properties from :root with
   dark-tuned values. Any rule that uses var(--ab-*) inherits the
   override automatically — no per-component dark rules needed for
   the most part. A handful of components with hard-coded hex
   colors get explicit overrides at the bottom.

   Print views are unaffected because they hard-code
   data-bs-theme="light" on <html>.
   ============================================================ */

/* Explicit user pref → dark */
[data-bs-theme="dark"] {
    /* Brand — keep primary recognizable but lighten for contrast on dark */
    --ab-primary:        #6E9DD2;
    --ab-primary-600:    #5A88BD;
    --ab-primary-500:    #4A78AD;
    --ab-primary-400:    #3D689B;
    --ab-primary-100:    #2C4761;
    --ab-primary-50:     #1F3245;
    --ab-primary-glow:   rgba(110, 157, 210, 0.25);

    --ab-accent:         #E89A5C;
    --ab-accent-600:     #D58A4A;
    --ab-accent-500:     #BD7438;
    --ab-accent-100:     #4A3520;
    --ab-accent-50:      #33251A;

    /* Surfaces — flip the warm-paper palette to a warm-charcoal palette */
    --ab-bg:             #14130F;
    --ab-surface:        #1E1C18;
    --ab-surface-alt:    #25221C;

    /* Grays — invert the scale */
    --ab-gray-50:    #25221C;
    --ab-gray-100:   #2D2A23;
    --ab-gray-200:   #3A372E;
    --ab-gray-300:   #524E42;
    --ab-gray-400:   #807868;
    --ab-gray-500:   #A89F92;
    --ab-gray-600:   #C0B6A6;
    --ab-gray-700:   #D8CFC0;
    --ab-gray-800:   #EAE4D9;
    --ab-gray-900:   #F4F1EB;

    /* Status colors — kept saturated but with darker backgrounds */
    --ab-success:        #4FAD7B;
    --ab-success-bg:     #1F3326;
    --ab-warning:        #D9A14A;
    --ab-warning-bg:     #3A2F19;
    --ab-danger:         #D86560;
    --ab-danger-bg:      #3A1F1D;
    --ab-info:           #5A8FC8;
    --ab-info-bg:        #1E2D3F;

    /* Project status — same hue family, slightly lighter for legibility */
    --ab-status-lead:           #A89F92;
    --ab-status-surveyed:       #7895B5;
    --ab-status-quoted:         #5A8FC8;
    --ab-status-proposal:       #9885BC;
    --ab-status-deposit:        #4FAD7B;
    --ab-status-production:     #D9A14A;
    --ab-status-received:       #8AB066;
    --ab-status-scheduled:      #E89A5C;
    --ab-status-installing:     #D58A4A;
    --ab-status-punch:          #C0884A;
    --ab-status-complete:       #4FAD7B;
    --ab-status-cancelled:      #B07570;

    /* Doc-type chips — flip light backgrounds to dark, keep fg readable */
    --ab-doctype-quote-fg:           #F2B45C;
    --ab-doctype-quote-bg:           #3A2F19;
    --ab-doctype-sales_order-fg:     #6FCB8E;
    --ab-doctype-sales_order-bg:     #1F3326;
    --ab-doctype-invoice-fg:         #8E8FE8;
    --ab-doctype-invoice-bg:         #25234A;
    --ab-doctype-po-fg:              #B89AF2;
    --ab-doctype-po-bg:              #2D2347;
    --ab-doctype-project-fg:         var(--ab-primary);
    --ab-doctype-project-bg:         var(--ab-primary-50);
    --ab-doctype-delivery-fg:        #5BC0D6;
    --ab-doctype-delivery-bg:        #143038;
    --ab-doctype-task-fg:            #E66F8E;
    --ab-doctype-task-bg:            #381E27;
    --ab-doctype-punch-fg:           #E89469;
    --ab-doctype-punch-bg:           #38241A;
    --ab-doctype-survey-fg:          #B0BACA;
    --ab-doctype-survey-bg:          #2A2D34;
    --ab-doctype-customer-fg:        #5BC295;
    --ab-doctype-customer-bg:        #1A332A;
    --ab-doctype-contact-fg:         #5BC295;
    --ab-doctype-contact-bg:         #1A332A;
    --ab-doctype-supplier-fg:        #D6A05C;
    --ab-doctype-supplier-bg:        #382E1F;
    --ab-doctype-subcontractor-fg:   #D9B85C;
    --ab-doctype-subcontractor-bg:   #38301F;
    --ab-doctype-typical-fg:         #A8B5C9;
    --ab-doctype-typical-bg:         #25282E;
    --ab-doctype-tax_rate-fg:        #B0B7C0;
    --ab-doctype-tax_rate-bg:        #292B2E;
    --ab-doctype-change_order-fg:    #D976DD;
    --ab-doctype-change_order-bg:    #3A1F3D;

    /* Shadows — barely visible on dark surfaces; darken slightly */
    --ab-shadow-sm:  0 1px 2px rgba(0, 0, 0, 0.4);
    --ab-shadow:     0 2px 4px rgba(0, 0, 0, 0.4);
    --ab-shadow-md:  0 4px 8px rgba(0, 0, 0, 0.45);
    --ab-shadow-lg:  0 8px 18px rgba(0, 0, 0, 0.5);
    --ab-shadow-xl:  0 16px 32px rgba(0, 0, 0, 0.55);

    /* Body bg + text — anchor the page */
    color-scheme: dark;
}

[data-bs-theme="dark"] body {
    background: var(--ab-bg);
    color: var(--ab-gray-900);
}

/* Flash toasts (UserSpice usSuccess/usError/usMessage).
   Core CSS in users/includes/system_messages_header.php hard-codes
   .us-toast { background: white !important } and the .toast-body has
   no explicit color — so in dark mode the toast keeps its white bg
   while inheriting the light body text color. Override with !important
   to beat the core rule, and pin readable text + close button. */
[data-bs-theme="dark"] .us-toast {
    background: var(--ab-surface) !important;
    color: var(--ab-gray-900) !important;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5) !important;
    border: 1px solid var(--ab-gray-200) !important;
}
[data-bs-theme="dark"] .us-toast .toast-body { color: var(--ab-gray-900); }
[data-bs-theme="dark"] .us-toast .btn-close {
    filter: invert(1) grayscale(100%) brightness(1.6);
}

/* Bootstrap .alert-* dark variants — same problem: light backgrounds
   inherited from Bootstrap defaults, but text now reads near-white. */
[data-bs-theme="dark"] .alert-success {
    background-color: var(--ab-success-bg);
    border-color: rgba(79, 173, 123, 0.35);
    color: var(--ab-success);
}
[data-bs-theme="dark"] .alert-danger {
    background-color: var(--ab-danger-bg);
    border-color: rgba(216, 101, 96, 0.35);
    color: var(--ab-danger);
}
[data-bs-theme="dark"] .alert-warning {
    background-color: var(--ab-warning-bg);
    border-color: rgba(217, 161, 74, 0.35);
    color: var(--ab-warning);
}
[data-bs-theme="dark"] .alert-info {
    background-color: var(--ab-info-bg);
    border-color: rgba(90, 143, 200, 0.35);
    color: var(--ab-info);
}
[data-bs-theme="dark"] .alert-primary {
    background-color: var(--ab-primary-50);
    border-color: rgba(110, 157, 210, 0.35);
    color: var(--ab-primary);
}
[data-bs-theme="dark"] .alert-secondary,
[data-bs-theme="dark"] .alert-dark {
    background-color: var(--ab-gray-100);
    border-color: var(--ab-gray-300);
    color: var(--ab-gray-800);
}
[data-bs-theme="dark"] .alert .alert-link { color: inherit; text-decoration: underline; }
[data-bs-theme="dark"] .alert .btn-close {
    filter: invert(1) grayscale(100%) brightness(1.6);
}

/* System dark mode — apply same overrides ONLY when no explicit pref
   has been set on <html>. The bootstrap script sets data-bs-theme=""
   for 'system' so this attribute selector matches that AND a totally
   absent attribute. */
@media (prefers-color-scheme: dark) {
    :root:not([data-bs-theme="light"]) {
        --ab-primary:        #6E9DD2;
        --ab-primary-600:    #5A88BD;
        --ab-primary-500:    #4A78AD;
        --ab-primary-400:    #3D689B;
        --ab-primary-100:    #2C4761;
        --ab-primary-50:     #1F3245;
        --ab-primary-glow:   rgba(110, 157, 210, 0.25);

        --ab-accent:         #E89A5C;
        --ab-accent-600:     #D58A4A;
        --ab-accent-500:     #BD7438;
        --ab-accent-100:     #4A3520;
        --ab-accent-50:      #33251A;

        --ab-bg:             #14130F;
        --ab-surface:        #1E1C18;
        --ab-surface-alt:    #25221C;

        --ab-gray-50:    #25221C;
        --ab-gray-100:   #2D2A23;
        --ab-gray-200:   #3A372E;
        --ab-gray-300:   #524E42;
        --ab-gray-400:   #807868;
        --ab-gray-500:   #A89F92;
        --ab-gray-600:   #C0B6A6;
        --ab-gray-700:   #D8CFC0;
        --ab-gray-800:   #EAE4D9;
        --ab-gray-900:   #F4F1EB;

        --ab-success:        #4FAD7B;
        --ab-success-bg:     #1F3326;
        --ab-warning:        #D9A14A;
        --ab-warning-bg:     #3A2F19;
        --ab-danger:         #D86560;
        --ab-danger-bg:      #3A1F1D;
        --ab-info:           #5A8FC8;
        --ab-info-bg:        #1E2D3F;

        --ab-shadow-sm:  0 1px 2px rgba(0, 0, 0, 0.4);
        --ab-shadow:     0 2px 4px rgba(0, 0, 0, 0.4);
        --ab-shadow-md:  0 4px 8px rgba(0, 0, 0, 0.45);
        --ab-shadow-lg:  0 8px 18px rgba(0, 0, 0, 0.5);
        --ab-shadow-xl:  0 16px 32px rgba(0, 0, 0, 0.55);

        color-scheme: dark;
    }

    :root:not([data-bs-theme="light"]) body {
        background: var(--ab-bg);
        color: var(--ab-gray-900);
    }

    /* Flash toasts + Bootstrap alerts — mirror the explicit-dark overrides
       so system-theme users get the same fix. See the [data-bs-theme="dark"]
       block above for the rationale. */
    :root:not([data-bs-theme="light"]) .us-toast {
        background: var(--ab-surface) !important;
        color: var(--ab-gray-900) !important;
        box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5) !important;
        border: 1px solid var(--ab-gray-200) !important;
    }
    :root:not([data-bs-theme="light"]) .us-toast .toast-body { color: var(--ab-gray-900); }
    :root:not([data-bs-theme="light"]) .us-toast .btn-close,
    :root:not([data-bs-theme="light"]) .alert .btn-close {
        filter: invert(1) grayscale(100%) brightness(1.6);
    }

    :root:not([data-bs-theme="light"]) .alert-success {
        background-color: var(--ab-success-bg);
        border-color: rgba(79, 173, 123, 0.35);
        color: var(--ab-success);
    }
    :root:not([data-bs-theme="light"]) .alert-danger {
        background-color: var(--ab-danger-bg);
        border-color: rgba(216, 101, 96, 0.35);
        color: var(--ab-danger);
    }
    :root:not([data-bs-theme="light"]) .alert-warning {
        background-color: var(--ab-warning-bg);
        border-color: rgba(217, 161, 74, 0.35);
        color: var(--ab-warning);
    }
    :root:not([data-bs-theme="light"]) .alert-info {
        background-color: var(--ab-info-bg);
        border-color: rgba(90, 143, 200, 0.35);
        color: var(--ab-info);
    }
    :root:not([data-bs-theme="light"]) .alert-primary {
        background-color: var(--ab-primary-50);
        border-color: rgba(110, 157, 210, 0.35);
        color: var(--ab-primary);
    }
    :root:not([data-bs-theme="light"]) .alert-secondary,
    :root:not([data-bs-theme="light"]) .alert-dark {
        background-color: var(--ab-gray-100);
        border-color: var(--ab-gray-300);
        color: var(--ab-gray-800);
    }
    :root:not([data-bs-theme="light"]) .alert .alert-link { color: inherit; text-decoration: underline; }
}
