/**
 * PracBill Brand Design System — theme conformance layer
 *
 * Re-skins the Axelit (pracbill-26.1) theme to the PracBill brand guide:
 *   - PracBill Blue #1C75BC hero / PracBill Grey #58595B structure & text
 *   - Space Grotesk (display) · Inter (body/UI + tabular money) · Space Mono (data)
 *   - 4px grid, radii 6px inputs / 8px buttons / 12px cards / 16px modals
 *   - Flat-first elevation: 1px grey-200 borders over shadows
 *   - Billing states: paid #1A965A · pending #D68A0C · overdue #D24444
 *
 * MUST load after style.css AND pracbill-modern-forms.css — this file wins by order.
 * Source of truth: .claude/skills/pracbill-design (brand guide + tokens).
 *
 * Part of: PRACBILL-1224
 */

/* ========================================
   1. BRAND TOKENS
   ======================================== */
:root {
    /* primary — blue */
    --pb-blue-50: #EFF5FA;  --pb-blue-100: #DDEAF5; --pb-blue-200: #BBD6EB;
    --pb-blue-300: #8EBADE; --pb-blue-400: #5598CD; --pb-blue-500: #3383C3;
    --pb-blue-600: #1C75BC; --pb-blue-700: #165B94; --pb-blue-800: #114875;
    --pb-blue-900: #0D375B;

    /* neutral — grey (hue-matched to logo grey, a touch cool) */
    --pb-grey-50: #F7F7F8;  --pb-grey-100: #F0F0F1; --pb-grey-200: #E2E2E3;
    --pb-grey-300: #CECED0; --pb-grey-400: #A3A4A6; --pb-grey-500: #78797B;
    --pb-grey-600: #58595B; --pb-grey-700: #444546; --pb-grey-800: #2E2E2F;
    --pb-grey-900: #1C1C1D;

    /* billing states — purpose-built for invoice status */
    --pb-paid: #1A965A;    --pb-paid-bg: #DFF0E8;    --pb-paid-text: #12693F;
    --pb-pending: #D68A0C; --pb-pending-bg: #F9EFDD; --pb-pending-text: #966108;
    --pb-overdue: #D24444; --pb-overdue-bg: #F9E5E5; --pb-overdue-text: #933030;

    /* warm accent — optional seasoning, never a second brand colour */
    --pb-accent: #F26A50; --pb-accent-bg: #FDEAE6;

    /* type */
    --font-display: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
    --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
    --font-mono: "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;

    /* elevation — cool-tinted, subtle */
    --pb-shadow-xs: 0 1px 2px rgba(28, 28, 29, 0.06);
    --pb-shadow-sm: 0 1px 3px rgba(28, 28, 29, 0.08), 0 1px 2px rgba(28, 28, 29, 0.05);
    --pb-shadow-md: 0 4px 12px rgba(28, 28, 29, 0.08), 0 2px 4px rgba(28, 28, 29, 0.05);
    --pb-shadow-lg: 0 12px 28px rgba(28, 28, 29, 0.12), 0 4px 8px rgba(28, 28, 29, 0.06);

    /* focus */
    --focus-ring: 0 0 0 2px #fff, 0 0 0 4px var(--pb-blue-600);
}

/* ========================================
   2. AXELIT TOKEN REMAP — LIGHT MODE
   The whole theme reads these; remapping them does 80% of the work.
   ======================================== */
:root {
    /* semantic RGB triplets (Axelit pattern: rgba(var(--x), a)) */
    --primary: 28, 117, 188;        /* blue-600 */
    --primary-dark: 22, 91, 148;    /* blue-700 (hover) */
    --secondary: 88, 89, 91;        /* grey-600 */
    --secondary-dark: 68, 69, 70;   /* grey-700 */
    --success: 26, 150, 90;         /* paid */
    --success-dark: 18, 105, 63;    /* paid text */
    --danger: 210, 68, 68;          /* overdue */
    --danger-dark: 147, 48, 48;     /* overdue text */
    --warning: 214, 138, 12;        /* pending */
    --warning-dark: 150, 97, 8;     /* pending text */
    --info: 51, 131, 195;           /* blue-500 */
    --info-dark: 17, 72, 117;       /* blue-800 */
    --light: 240, 240, 241;         /* grey-100 */
    --dark: 68, 69, 70;             /* grey-700 — Axelit's foreground/link token */
    --dark-dark: 46, 46, 47;        /* grey-800 */
    --dark-light: 120, 121, 123;    /* grey-500 */

    /* text — PracBill Grey carries the text work; softened per user preference
       (grey-900 read too harsh on screen) */
    --font-color: #58595B;              /* grey-600 body text — the brand grey */
    --font-title-color: #444546;        /* grey-700 headings */
    --font-secondary-color: #444546;    /* grey-700 */
    --font-light-color: #78797B;        /* grey-500 muted */
    --theme-body-font-color: #58595B;
    --theme-body-sub-title-color: rgba(88, 89, 91, 0.8);
    --link-color: var(--pb-blue-600);

    /* surfaces — white does the work, grey-50 is the canvas */
    --body-color: #F7F7F8;
    --bodybg-color: #F7F7F8;            /* grey-50 */
    --border_color: #E2E2E3;            /* grey-200 hairline */
    --bs-border-color: #E2E2E3;
    --light-gray: #F0F0F1;              /* grey-100 */
    --light-gray-bg: #F7F7F8;
    --grid_color: rgba(28, 117, 188, 0.08);
    --bs-danger: #D24444;
    --bs-danger-rgb: 210, 68, 68;

    /* radii — each has a job: 6 inputs, 8 buttons, 12 cards, 16 modals */
    --app-border-radius: 12px;
    --bs-border-radius: 8px;
    --bs-accordion-inner-border-radius: 8px;

    /* flat-first elevation */
    --box-shadow: var(--pb-shadow-sm);
    --hover-shadow: var(--pb-shadow-md);
    --bottom-shadow: none;

    /* type — Axelit funnels every font through this one variable */
    --font-Montserrat: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;

    /* action colours follow the semantic remap */
    --pb-action-view: var(--info);
    --pb-action-edit: var(--primary);
    --pb-action-delete: var(--danger);
    --pb-action-add: var(--success);
}

/* ========================================
   3. AXELIT TOKEN REMAP — DARK MODE
   Cool grey-900/800, hue-matched to the brand grey (no Axelit navy).
   ======================================== */
body.dark,
body[class*="dark"],
nav.dark-sidebar {
    --white: 46, 46, 47;                /* grey-800 surfaces */
    --black: #F0F0F1;
    --body-color: #1C1C1D;
    --bodybg-color: #1C1C1D;            /* grey-900 canvas */
    --bs-body-bg: #1C1C1D;
    --font-color: #F0F0F1;
    --font-title-color: #F7F7F8;
    --font-secondary-color: #CECED0;
    --font-light-color: #A3A4A6;
    --link-color: #8EBADE;              /* blue-300 */
    --border_color: #444546;            /* grey-700 hairline */
    --bs-border-color: #444546;
    --bs-card-border-color: #444546;
    --bs-form-control-bg: #242425;
    --bs-body-color: #F0F0F1;
    --bs-secondary-color: #CECED0;
    --bs-list-group-color: #F0F0F1;
    --bs-body-color-rgb: 240, 240, 241;
    --bs-tertiary-bg: #242425;
    --bs-card-color: #F0F0F1;
    --light-gray: #2E2E2F;
    --light: 68, 69, 70;                /* grey-700 */
    --dark: 226, 226, 227;              /* grey-200 — foreground token flips */
    --dark-dark: 240, 240, 241;
    --dark-light: 163, 164, 166;
    --box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    --hover-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);

    /* semantic colours — lifted for dark surfaces */
    --primary: 85, 152, 205;            /* blue-400 */
    --primary-dark: 142, 186, 222;      /* blue-300 */
    --secondary: 163, 164, 166;         /* grey-400 */
    --secondary-dark: 206, 206, 208;    /* grey-300 */
    --success: 47, 179, 116;
    --success-dark: 120, 208, 166;
    --danger: 224, 102, 102;
    --danger-dark: 235, 153, 153;
    --warning: 232, 162, 61;
    --warning-dark: 240, 193, 128;
    --info: 85, 152, 205;
    --info-dark: 142, 186, 222;
    --bs-danger: rgb(224, 102, 102);
    --bs-danger-rgb: 224, 102, 102;

    --focus-ring: 0 0 0 2px #1C1C1D, 0 0 0 4px var(--pb-blue-400);
}

/* Re-anchor the hardcoded Axelit-navy dark rules from pracbill-modern-forms.css */
body.dark .header-main,
body[class*="dark"] .header-main {
    background: rgba(var(--white), 1);
    border-bottom: 1px solid var(--border_color);
}
body.dark .header-main::before,
body[class*="dark"] .header-main::before {
    background: rgba(var(--white), 1);
}
body.dark .header-main .form-control,
body[class*="dark"] .header-main .form-control {
    background: var(--bs-form-control-bg);
    color: var(--font-color);
    border-color: var(--border_color);
}
body.dark nav,
body[class*="dark"] nav {
    background-color: rgba(var(--white), 1);
    border-right: 1px solid var(--border_color);
}
body.dark .disabled > .page-link,
body.dark .page-link.disabled,
body[class*="dark"] .disabled > .page-link,
body[class*="dark"] .page-link.disabled {
    color: var(--font-light-color);
    background-color: #242425;
    border-color: var(--border_color);
}

/* ========================================
   4. TYPOGRAPHY
   Space Grotesk for headings; Inter everywhere you read;
   Space Mono for data/code; tabular numerals for money.
   Sentence case — no auto-capitalisation.
   ======================================== */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6,
.main-title {
    font-family: var(--font-display);
    color: var(--font-title-color);
}

/* Guide weights: display/headings 700/600, tracking tight on large sizes */
h1, .h1 { font-weight: 700; letter-spacing: -0.02em; }
h2, .h2 { font-weight: 700; letter-spacing: -0.02em; }
h3, .h3 { font-weight: 600; letter-spacing: -0.01em; }

.main-title {
    font-weight: 600;
    text-transform: none; /* sentence case, not Capitalised Case */
    letter-spacing: -0.01em;
}

code, pre, kbd, samp, .font-monospace {
    font-family: var(--font-mono);
}
code {
    color: var(--pb-blue-700);
    background-color: var(--pb-blue-50);
}
body.dark code,
body[class*="dark"] code {
    color: var(--pb-blue-300);
    background-color: rgba(85, 152, 205, 0.12);
}

/* Money & metrics read in columns — tabular numerals everywhere data lives */
.tabular { font-variant-numeric: tabular-nums; }
.table, table.dataTable {
    font-variant-numeric: tabular-nums;
}

/* Overline-style section labels (sidebar menu title) */
nav .app-nav .main-nav > li.menu-title span {
    font-family: var(--font-sans);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--font-light-color);
}

/* ========================================
   5. BUTTONS — 8px radius, brand hover, visible focus
   ======================================== */
.btn {
    border-radius: 8px;
    font-weight: 600;
    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.btn:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}
/* Axelit rounds modal buttons up to the card radius — keep them buttons */
.modal-content .btn {
    border-radius: 8px;
}
.btn.rounded-pill { border-radius: 999px; }

/* Secondary buttons per guide: white, grey-300 hairline; hover grey-50 fill */
.btn-secondary,
.btn-default {
    background-color: #fff;
    border: 1px solid var(--pb-grey-300);
    color: var(--pb-grey-700);
}
.btn-secondary:hover, .btn-secondary:focus, .btn-secondary.active,
.btn-default:hover, .btn-default:focus, .btn-default.active {
    background-color: var(--pb-grey-50);
    border-color: var(--pb-grey-300);
    color: var(--pb-grey-800);
}
body.dark .btn-secondary, body.dark .btn-default,
body[class*="dark"] .btn-secondary, body[class*="dark"] .btn-default {
    background-color: rgba(var(--white), 1);
    border: 1px solid var(--border_color);
    color: var(--font-secondary-color);
}
body.dark .btn-secondary:hover, body.dark .btn-secondary:focus,
body.dark .btn-default:hover, body.dark .btn-default:focus,
body[class*="dark"] .btn-secondary:hover, body[class*="dark"] .btn-secondary:focus,
body[class*="dark"] .btn-default:hover, body[class*="dark"] .btn-default:focus {
    background-color: #3A3A3C;
    border-color: var(--border_color);
    color: var(--font-color);
}

/* Timeline note-bar actions — quiet ghost buttons so the note header
   doesn't shout; colour only carries state (public/private) and danger */
.timeline-content .navbar-nav > li > .btn {
    padding: 4px 10px;
    font-size: 12px;
    border-radius: 6px;
    background: transparent;
    border: 1px solid transparent;
    color: var(--pb-grey-600);
    box-shadow: none;
}
.timeline-content .navbar-nav > li > .btn:hover,
.timeline-content .navbar-nav > li > .btn:focus {
    background: var(--pb-grey-100);
    border-color: transparent;
    color: var(--pb-grey-800);
}
.timeline-content .navbar-nav > li > .btn.btn-danger {
    background: transparent;
    color: var(--pb-overdue-text);
}
.timeline-content .navbar-nav > li > .btn.btn-danger:hover,
.timeline-content .navbar-nav > li > .btn.btn-danger:focus {
    background: var(--pb-overdue-bg);
    color: var(--pb-overdue-text);
}
.timeline-content .navbar-nav > li > .btn.btn-success {
    background: var(--pb-paid-bg);
    color: var(--pb-paid-text);
}
.timeline-content .navbar-nav > li > .btn.btn-success:hover,
.timeline-content .navbar-nav > li > .btn.btn-success:focus {
    background: var(--pb-paid-bg);
    color: var(--pb-paid-text);
}
body.dark .timeline-content .navbar-nav > li > .btn,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn {
    color: var(--font-secondary-color);
}
body.dark .timeline-content .navbar-nav > li > .btn:hover,
body.dark .timeline-content .navbar-nav > li > .btn:focus,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn:hover,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn:focus {
    background: #3A3A3C;
    color: var(--font-color);
}
body.dark .timeline-content .navbar-nav > li > .btn.btn-danger,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn.btn-danger {
    background: transparent;
    color: #EB9999;
}
body.dark .timeline-content .navbar-nav > li > .btn.btn-danger:hover,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn.btn-danger:hover {
    background: rgba(224, 102, 102, 0.18);
    color: #EB9999;
}
body.dark .timeline-content .navbar-nav > li > .btn.btn-success,
body[class*="dark"] .timeline-content .navbar-nav > li > .btn.btn-success {
    background: rgba(47, 179, 116, 0.18);
    color: #78D0A6;
}

/* ========================================
   6. CARDS & SURFACES — flat-first: hairline border, no resting shadow
   ======================================== */
.card {
    background: rgba(var(--white), 1);
    border: 1px solid var(--border_color);
    border-radius: 12px;
    box-shadow: none;
}
.card:hover {
    box-shadow: none; /* resting cards stay flat */
}
.card.hover-effect:hover {
    box-shadow: var(--hover-shadow); /* things that float may float */
}
.card .card-header {
    border-bottom: 1px solid var(--border_color);
    border-radius: 12px 12px 0 0;
}
.card .card-footer {
    border-top: 1px solid var(--border_color);
}

/* ========================================
   7. FORMS — 6px radius, grey-300 rest / grey-400 hover /
   blue-600 focus + 3px blue-100 ring
   ======================================== */
.form-control,
.form-select {
    border-radius: 6px;
    border-color: var(--pb-grey-300);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-control:hover:not(:focus):not(:disabled),
.form-select:hover:not(:focus):not(:disabled) {
    border-color: var(--pb-grey-400);
}
.form-control:focus,
.form-select:focus {
    border-color: rgba(var(--primary), 1);
    box-shadow: 0 0 0 3px var(--pb-blue-100);
}
body.dark .form-control,
body.dark .form-select,
body[class*="dark"] .form-control,
body[class*="dark"] .form-select {
    border-color: var(--border_color);
}
body.dark .form-control:focus,
body.dark .form-select:focus,
body[class*="dark"] .form-control:focus,
body[class*="dark"] .form-select:focus {
    border-color: rgba(var(--primary), 1);
    box-shadow: 0 0 0 3px rgba(85, 152, 205, 0.25);
}

/* .app-form scope (login + app forms) out-ranks the generic rules above */
.app-form .form-control,
.app-form .form-select,
.app-form.rounded-control .form-control,
.app-form.rounded-control .form-select {
    border-radius: 6px;
    border: 1px solid var(--pb-grey-300);
}
.app-form .form-control:hover:not(:focus):not(:disabled),
.app-form .form-select:hover:not(:focus):not(:disabled) {
    border-color: var(--pb-grey-400);
}
.app-form .form-control:focus,
.app-form .form-select:focus {
    border: 1px solid rgba(var(--primary), 1);
    box-shadow: 0 0 0 3px var(--pb-blue-100);
    padding-left: 0.75rem; /* no focus padding jump — motion stays restrained */
}
.app-form.rounded-control .btn {
    border-radius: 8px;
}
.app-form .input-group-text {
    border-radius: 6px;
}
body.dark .app-form .form-control,
body.dark .app-form .form-select,
body[class*="dark"] .app-form .form-control,
body[class*="dark"] .app-form .form-select {
    border-color: var(--border_color);
}
body.dark .app-form .form-control:focus,
body.dark .app-form .form-select:focus,
body[class*="dark"] .app-form .form-control:focus,
body[class*="dark"] .app-form .form-select:focus {
    border-color: rgba(var(--primary), 1);
    box-shadow: 0 0 0 3px rgba(85, 152, 205, 0.25);
}

/* Checkboxes, radios, switches — checked = brand blue */
.form-check-input:checked {
    background-color: rgba(var(--primary), 1);
    border-color: rgba(var(--primary), 1);
}
.form-check-input:focus {
    border-color: rgba(var(--primary), 1);
    box-shadow: 0 0 0 3px var(--pb-blue-100);
}
body.dark .form-check-input:focus,
body[class*="dark"] .form-check-input:focus {
    box-shadow: 0 0 0 3px rgba(85, 152, 205, 0.25);
}

/* ========================================
   8. BADGES — status chips: soft background + accessible text
   ======================================== */
.badge {
    border-radius: 999px;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.badge.text-bg-success, .badge.bg-success {
    background-color: var(--pb-paid-bg) !important;
    color: var(--pb-paid-text) !important;
}
.badge.text-bg-warning, .badge.bg-warning {
    background-color: var(--pb-pending-bg) !important;
    color: var(--pb-pending-text) !important;
}
.badge.text-bg-danger, .badge.bg-danger {
    background-color: var(--pb-overdue-bg) !important;
    color: var(--pb-overdue-text) !important;
}
body.dark .badge.text-bg-success, body.dark .badge.bg-success,
body[class*="dark"] .badge.text-bg-success, body[class*="dark"] .badge.bg-success {
    background-color: rgba(47, 179, 116, 0.18) !important;
    color: #78D0A6 !important;
}
body.dark .badge.text-bg-warning, body.dark .badge.bg-warning,
body[class*="dark"] .badge.text-bg-warning, body[class*="dark"] .badge.bg-warning {
    background-color: rgba(232, 162, 61, 0.18) !important;
    color: #F0C180 !important;
}
body.dark .badge.text-bg-danger, body.dark .badge.bg-danger,
body[class*="dark"] .badge.text-bg-danger, body[class*="dark"] .badge.bg-danger {
    background-color: rgba(224, 102, 102, 0.18) !important;
    color: #EB9999 !important;
}

/* Legacy Bootstrap-3 .label chips (bridged in pracbill-modern-forms.css) */
.label {
    border-radius: 999px;
    font-weight: 600;
    padding: 0.3em 0.75em;
}
.label-success {
    background-color: var(--pb-paid-bg);
    color: var(--pb-paid-text);
}
.label-warning {
    background-color: var(--pb-pending-bg);
    color: var(--pb-pending-text);
}
.label-danger {
    background-color: var(--pb-overdue-bg);
    color: var(--pb-overdue-text);
}
.label-info, .label-primary {
    background-color: var(--pb-blue-100);
    color: var(--pb-blue-800);
}
body.dark .label-success, body[class*="dark"] .label-success {
    background-color: rgba(47, 179, 116, 0.18);
    color: #78D0A6;
}
body.dark .label-warning, body[class*="dark"] .label-warning {
    background-color: rgba(232, 162, 61, 0.18);
    color: #F0C180;
}
body.dark .label-danger, body[class*="dark"] .label-danger {
    background-color: rgba(224, 102, 102, 0.18);
    color: #EB9999;
}
body.dark .label-info, body.dark .label-primary,
body[class*="dark"] .label-info, body[class*="dark"] .label-primary {
    background-color: rgba(85, 152, 205, 0.18);
    color: #8EBADE;
}

/* ========================================
   9. ALERTS — soft state background, hairline border, 12px radius
   ======================================== */
.alert {
    border-radius: 12px;
    border: 1px solid transparent;
}
.alert-success {
    background-color: var(--pb-paid-bg);
    color: var(--pb-paid-text);
    border-color: rgba(26, 150, 90, 0.3);
}
.alert-warning {
    background-color: var(--pb-pending-bg);
    color: var(--pb-pending-text);
    border-color: rgba(214, 138, 12, 0.3);
}
.alert-danger {
    background-color: var(--pb-overdue-bg);
    color: var(--pb-overdue-text);
    border-color: rgba(210, 68, 68, 0.3);
}
.alert-primary, .alert-info {
    background-color: var(--pb-blue-50);
    color: var(--pb-blue-800);
    border-color: var(--pb-blue-200);
}
body.dark .alert-success, body[class*="dark"] .alert-success {
    background-color: rgba(47, 179, 116, 0.12);
    color: #78D0A6;
    border-color: rgba(47, 179, 116, 0.35);
}
body.dark .alert-warning, body[class*="dark"] .alert-warning {
    background-color: rgba(232, 162, 61, 0.12);
    color: #F0C180;
    border-color: rgba(232, 162, 61, 0.35);
}
body.dark .alert-danger, body[class*="dark"] .alert-danger {
    background-color: rgba(224, 102, 102, 0.12);
    color: #EB9999;
    border-color: rgba(224, 102, 102, 0.35);
}
body.dark .alert-primary, body.dark .alert-info,
body[class*="dark"] .alert-primary, body[class*="dark"] .alert-info {
    background-color: rgba(85, 152, 205, 0.12);
    color: #8EBADE;
    border-color: rgba(85, 152, 205, 0.35);
}

/* ========================================
   10. TABLES — grey-50 header band, hairline rows, blue-50 hover
   ======================================== */
.table thead tr th {
    background-color: var(--pb-grey-50);
    color: var(--pb-grey-600);
    font-weight: 600;
    border-bottom: 1px solid var(--border_color);
}
.table tbody tr td {
    border-bottom: 1px solid var(--border_color);
}
.table-hover > tbody > tr:hover > *,
table.dataTable tbody tr:hover {
    background-color: var(--pb-blue-50);
    --bs-table-bg-state: var(--pb-blue-50);
}
body.dark .table thead tr th,
body[class*="dark"] .table thead tr th {
    background-color: #242425;
    color: var(--font-secondary-color);
}
body.dark .table-hover > tbody > tr:hover > *,
body.dark table.dataTable tbody tr:hover,
body[class*="dark"] .table-hover > tbody > tr:hover > *,
body[class*="dark"] table.dataTable tbody tr:hover {
    background-color: rgba(85, 152, 205, 0.08);
    --bs-table-bg-state: rgba(85, 152, 205, 0.08);
}

/* ========================================
   11. MODALS — 16px radius, lg shadow (modals genuinely float)
   ======================================== */
.modal-content {
    border-radius: 16px;
    border: 1px solid var(--border_color);
    box-shadow: var(--pb-shadow-lg);
}
.modal-backdrop {
    background-color: var(--pb-grey-900);
}
.modal-backdrop.show {
    opacity: 0.45;
}

/* Legacy Bootstrap-3 modals (class="close" data-dismiss) — many modules still
   ship this markup; render their × like the BS5 btn-close: quiet ghost,
   pinned top-right of the header */
.modal .modal-header {
    position: relative;
}
.modal .modal-header .close {
    position: absolute;
    top: 14px;
    right: 16px;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 6px;
    font-size: 22px;
    font-weight: 400;
    line-height: 1;
    color: var(--pb-grey-500);
    opacity: 1;
    text-shadow: none;
    float: none;
}
.modal .modal-header .close:hover,
.modal .modal-header .close:focus {
    background: var(--pb-grey-100);
    color: var(--pb-grey-700);
    outline: none;
}
/* Legacy headers wrap oversized headings in .modal-title — normalise to the
   guide's modal title size */
.modal .modal-title h1,
.modal .modal-title h2,
.modal .modal-title h3,
.modal .modal-title h4 {
    font-size: 1.25rem;
    font-weight: 600;
    margin: 0;
    line-height: 1.3;
}
body.dark .modal .modal-header .close,
body[class*="dark"] .modal .modal-header .close {
    color: var(--font-light-color);
}
body.dark .modal .modal-header .close:hover,
body.dark .modal .modal-header .close:focus,
body[class*="dark"] .modal .modal-header .close:hover,
body[class*="dark"] .modal .modal-header .close:focus {
    background: #3A3A3C;
    color: var(--font-color);
}

/* ========================================
   12. BREADCRUMBS — muted grey, active grey-900, hover blue
   ======================================== */
.app-line-breadcrumbs li a {
    color: var(--font-light-color);
}
.app-line-breadcrumbs li a:hover {
    color: rgba(var(--primary), 1);
}
.app-line-breadcrumbs li.active a {
    color: var(--font-title-color);
}

/* ========================================
   13. SIDEBAR — white surface, hairline edge, calm active states
   ======================================== */
nav {
    border-right: 1px solid var(--border_color);
}
nav .app-nav .main-nav > li:not(.menu-title) > a {
    border-radius: 8px;
    text-transform: none; /* sentence case */
    font-size: 15px;
}
nav .app-nav .main-nav > li:not(.menu-title) > a[aria-expanded=true] {
    background: rgba(var(--primary), 0.1);
    color: var(--pb-blue-700);
}
body.dark nav .app-nav .main-nav > li:not(.menu-title) > a[aria-expanded=true],
body[class*="dark"] nav .app-nav .main-nav > li:not(.menu-title) > a[aria-expanded=true] {
    color: var(--pb-blue-300);
}

/* ========================================
   14. HEADER — canvas-coloured with a hairline bottom edge
   ======================================== */
header.header-main {
    border-bottom: 1px solid var(--border_color);
}
header.header-main .form-control {
    background-color: rgba(var(--white), 1);
}

/* ========================================
   15. FOCUS VISIBILITY — 2px surface + 4px blue ring
   ======================================== */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: 4px;
}

/* ========================================
   16. LOGIN — soft blue-50→white backdrop, flat card, solid blue primary
   ======================================== */
.sign-in-bg {
    background: linear-gradient(180deg, var(--pb-blue-50) 0%, #fff 100%);
}
.sign-in-bg .sign-in-content-bg {
    border: 1px solid var(--border_color);
    border-radius: 16px;
    box-shadow: var(--pb-shadow-md);
}
.sign-in-bg .image-contentbox {
    background-color: var(--pb-blue-50);
}
/* Primary action = solid brand blue (guide: hover darkens to blue-700) */
.sign-in-bg .btn-light-primary {
    background-color: rgba(var(--primary), 1);
    color: #fff;
    border-color: transparent;
}
.sign-in-bg .btn-light-primary:hover,
.sign-in-bg .btn-light-primary:focus,
.sign-in-bg .btn-light-primary:focus-visible,
.sign-in-bg .btn-light-primary.active {
    background-color: rgba(var(--primary-dark), 1);
    color: #fff;
    border-color: transparent;
}
.sign-in-bg .form-contentbox h2 {
    color: var(--pb-blue-700);
}

/* ========================================
   17. CONTACT CARDS — helpdesk ticket contacts (PRACBILL-1224)
   Flat-first row cards: name in medium weight, contact details muted
   beneath, quiet action on the right.
   ======================================== */
.pb-contact-block {
    margin-top: var(--space-4, 16px);
}
.pb-contact-heading {
    font-family: var(--font-sans);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--font-light-color);
    margin-bottom: 8px;
}
.pb-contact-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.pb-contact-card {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 12px 12px 16px;
    background: rgba(var(--white), 1);
    border: 1px solid var(--border_color);
    border-radius: 8px;
    transition: border-color 0.15s ease, opacity 0.15s ease;
}
.pb-contact-card:hover {
    border-color: var(--pb-grey-300);
}
.pb-contact-main {
    flex: 1;
    min-width: 0;
}
.pb-contact-name {
    font-weight: 600;
    color: var(--font-title-color);
    line-height: 1.35;
    overflow-wrap: break-word;
}
.pb-contact-meta {
    margin-top: 2px;
    font-size: 0.875rem;
    color: var(--font-light-color);
    line-height: 1.45;
    overflow-wrap: break-word;
}
.pb-contact-sep {
    margin: 0 6px;
    color: var(--pb-grey-300);
}
.pb-contact-empty {
    margin: 0;
    padding: 16px;
    text-align: center;
    font-size: 0.875rem;
    color: var(--font-light-color);
    background: var(--color-surface-alt, var(--pb-grey-50));
    border: 1px solid var(--border_color);
    border-radius: 8px;
}

/* Quiet ghost action — matches the timeline note-bar buttons */
.pb-contact-action {
    flex: none;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 18px;
    line-height: 1;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    color: var(--pb-grey-500);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.pb-contact-action:hover,
.pb-contact-action:focus {
    background: var(--pb-overdue-bg);
    color: var(--pb-overdue-text);
    outline: none;
}
.pb-contact-action--add {
    font-size: 13px;
}
.pb-contact-action--add:hover,
.pb-contact-action--add:focus {
    background: var(--pb-blue-50);
    color: var(--pb-blue-700);
}

/* Marked for removal — applies on save, undoable until then */
.pb-contact-card--removed {
    opacity: 0.55;
    border-style: dashed;
}
.pb-contact-card--removed .pb-contact-name {
    text-decoration: line-through;
}
.pb-contact-card--removed .pb-contact-action {
    color: var(--pb-grey-500);
}
/* The delete flag is driven by the x button, never shown directly */
.pb-contact-remove-flag {
    display: none;
}

/* Customer-contact picker rows in the Add Contact modal */
.pb-contact-pick {
    cursor: pointer;
}

body.dark .pb-contact-card,
body[class*="dark"] .pb-contact-card {
    background: rgba(var(--white), 1);
}
body.dark .pb-contact-card:hover,
body[class*="dark"] .pb-contact-card:hover {
    border-color: var(--pb-grey-500);
}
body.dark .pb-contact-empty,
body[class*="dark"] .pb-contact-empty {
    background: #242425;
}
body.dark .pb-contact-action:hover,
body.dark .pb-contact-action:focus,
body[class*="dark"] .pb-contact-action:hover,
body[class*="dark"] .pb-contact-action:focus {
    background: rgba(224, 102, 102, 0.18);
    color: #EB9999;
}
body.dark .pb-contact-action--add:hover,
body.dark .pb-contact-action--add:focus,
body[class*="dark"] .pb-contact-action--add:hover,
body[class*="dark"] .pb-contact-action--add:focus {
    background: rgba(85, 152, 205, 0.18);
    color: #8EBADE;
}

/* ========================================
   18. LOADING / PROGRESS (PRACBILL-1224)

   Legacy markup puts the message *inside* .progress-bar, but the theme
   pins .progress to 11px so that text overflows and clips. Bootstrap 3's
   animated stripe (.progress-bar-striped.active) was also renamed to
   .progress-bar-animated in BS5, so those bars sat frozen.

   .pb-loading is the replacement for indeterminate "please wait" states:
   a slim indeterminate track with the label alongside, never inside.
   ======================================== */
.pb-loading {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 0;
}
.pb-loading-track {
    position: relative;
    flex: 1;
    height: 8px;
    min-width: 80px;
    background: var(--pb-grey-100);
    border-radius: 999px;
    overflow: hidden;
}
.pb-loading-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 40%;
    background: rgba(var(--primary), 1);
    border-radius: 999px;
    animation: pb-loading-slide 1.1s ease-in-out infinite;
}
.pb-loading-text {
    flex: none;
    font-size: 0.875rem;
    color: var(--font-light-color);
    white-space: nowrap;
}
@keyframes pb-loading-slide {
    0%   { left: -40%; }
    100% { left: 100%; }
}
body.dark .pb-loading-track,
body[class*="dark"] .pb-loading-track {
    background: var(--pb-grey-700);
}
.pb-search-empty {
    margin: 0;
    padding: 12px 0;
    font-size: 0.875rem;
    color: var(--font-light-color);
}

/* Legacy .progress bars — brand the track and fill, and restore the
   animated stripe for the Bootstrap 3 .active markup still in the app */
.progress {
    background-color: var(--pb-grey-100) !important;
    border-radius: 999px;
    overflow: hidden;
}
.progress .progress-bar,
.progress-bar {
    background-color: rgba(var(--primary), 1);
    border-radius: 999px;
}
/* The theme pins .progress to 11px; any inline label would clip, and every
   remaining caller repeats the message in its modal title */
.progress .progress-bar {
    font-size: 0;
    text-indent: -9999px;
}
.progress-bar-striped,
.progress-bar-striped.active {
    background-image: linear-gradient(45deg,
        rgba(255, 255, 255, 0.15) 25%, transparent 25%,
        transparent 50%, rgba(255, 255, 255, 0.15) 50%,
        rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
    background-size: 1rem 1rem;
}
/* BS3 compatibility: .active was renamed .progress-bar-animated in BS5 */
.progress-bar-striped.active,
.progress-bar-striped.progress-bar-animated {
    animation: progress-bar-stripes 1s linear infinite;
}
body.dark .progress,
body[class*="dark"] .progress {
    background-color: var(--pb-grey-700) !important;
}
@media (prefers-reduced-motion: reduce) {
    .pb-loading-fill,
    .progress-bar-striped.active,
    .progress-bar-striped.progress-bar-animated {
        animation: none;
    }
    .pb-loading-fill { width: 100%; left: 0; }
}

/* ========================================
   19. OAUTH CONNECTION STATUS (PRACBILL-353)
   Integration status + connect/disconnect, replacing the Bootstrap 3
   panel markup the legacy department page used (which no longer renders).
   ======================================== */
.pb-oauth {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 16px;
    border: 1px solid var(--border_color);
    border-left-width: 3px;
    border-radius: 8px;
    background: rgba(var(--white), 1);
}
.pb-oauth-main {
    flex: 1;
    min-width: 0;
}
.pb-oauth-title {
    font-weight: 600;
    color: var(--font-title-color);
    line-height: 1.35;
}
.pb-oauth-detail {
    margin-top: 2px;
    font-size: 0.875rem;
    color: var(--font-light-color);
    overflow-wrap: break-word;
}
.pb-oauth-action {
    flex: none;
}
.pb-oauth--success { border-left-color: var(--pb-paid); }
.pb-oauth--warning { border-left-color: var(--pb-pending); }
.pb-oauth--danger  { border-left-color: var(--pb-overdue); }
.pb-oauth--success .pb-oauth-title { color: var(--pb-paid-text); }
.pb-oauth--danger .pb-oauth-title  { color: var(--pb-overdue-text); }
body.dark .pb-oauth--success .pb-oauth-title,
body[class*="dark"] .pb-oauth--success .pb-oauth-title { color: #78D0A6; }
body.dark .pb-oauth--danger .pb-oauth-title,
body[class*="dark"] .pb-oauth--danger .pb-oauth-title { color: #EB9999; }

/* ========================================
   20. SEARCH RESULT ROWS (PRACBILL-353)
   Shared by the quick-select pickers and the large search modal.
   ======================================== */
.pb-result {
    display: block;
    padding: 10px 14px;
    margin-bottom: 6px;
    text-align: left;
    background: rgba(var(--white), 1);
    border: 1px solid var(--border_color);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.pb-result:hover,
.pb-result:focus {
    background: var(--pb-blue-50);
    border-color: var(--pb-blue-200);
}
body.dark .pb-result:hover,
body[class*="dark"] .pb-result:hover {
    background: rgba(85, 152, 205, 0.12);
    border-color: var(--pb-grey-500);
}

/* Primary line and secondary detail — also used inside .list-group results */
.pb-result-primary {
    display: block;
    font-weight: 600;
    color: var(--font-title-color);
    line-height: 1.35;
}
.pb-result-secondary {
    display: block;
    margin-top: 1px;
    font-size: 0.875rem;
    color: var(--font-light-color);
    line-height: 1.4;
    overflow-wrap: break-word;
}
.list-group-item .pb-result-primary,
.list-group-item .pb-result-secondary {
    text-align: left;
}

/* ========================================
   21. ACTION CHOOSER GRID (PRACBILL-1224)
   Modal choosers such as the customer view's Advanced Options: an even
   grid of equal-width, left-aligned actions rather than a ragged stack.
   ======================================== */
.pb-action-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}
.pb-action-grid > div {
    display: flex;
}
.pb-action-grid .btn {
    flex: 1;
    text-align: left;
    justify-content: flex-start;
    white-space: normal;
    overflow-wrap: break-word;
}
@media (max-width: 575.98px) {
    .pb-action-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ========================================
   22. MOTION — restrained; respect reduced motion
   ======================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ========================================
   23. MOBILE COMPAT — PRACBILL-1259
   Theme-level fixes for two phone-width regressions. Both live here rather
   than in the shared files they correct, so only this theme is affected.
   ======================================== */

/* --- Stacked tables: keep the column label off the value ---------------
   standard.css collapses .table-mobile-stack rows (sdJobTable, e.g. the
   customer statement) into label/value pairs at phone widths: the column name
   is drawn by `td::before` absolutely positioned in the left 38%, and the cell
   reserves room for it with `padding-left: 42%`.

   `.table-mobile-stack td` is only (0,1,1) specific, so this theme's own
   `.table tbody tr td { padding: 0.8rem 0.75rem }` in style.css — (0,1,3) —
   wins and drops the reserve to 12px. The label is still positioned over the
   left of the cell, so it lands directly on top of the value.

   Re-assert the stacked padding with a selector the theme rules cannot
   outrank; scoped to .table-mobile-stack so ordinary tables are untouched. */
@media only screen and (max-width: 575.98px) {
    .table.table-mobile-stack tbody tr td {
        padding: 0.6em 0.75em 0.6em 42%;
        white-space: normal;
        word-break: break-word;
        overflow-wrap: anywhere;
        text-align: left;
    }
}

/* --- Timeline note headers are <nav>, and this theme styles <nav> as THE
       sidebar -------------------------------------------------------------
   Every note in libs/timeline/timeline.tpl (helpdesk notes, log entries,
   emails, payments — the whole timeline, on every module that renders one)
   wraps its title bar and action buttons in `<nav class="navbar">`. That is
   also the element this theme uses for the app sidebar, and style.css styles
   the bare tag:

       nav { width: var(--sidebar-width); height: 100vh; position: fixed; }
       @media (max-width: 991px) {
           .app-wrapper nav:not(.horizontal-sidebar) {
               transform: translateX(-100%);
               width: var(--sidebar-width) !important;
           }
       }

   The tag-only rules lose on specificity to `.timeline-content .navbar`
   (0,2,0) in pracbill-modern-forms.css, so the note header survives them. The
   off-canvas rule does not: nothing re-asserts `transform`, and its width
   carries `!important`. Below 992px every note header is therefore given the
   sidebar's width and slid one full width off the left edge of the viewport
   (measured at 390px: x = -156px). The header carries the
   `onclick="toggleAccordian()"` expand target and the Edit / Delete / Resend /
   Internal / View-HTML buttons, so all of it lands off-screen and untappable —
   the note reads as an empty box.

   Scoped to the same breakpoint as the rule it counters. The selector is
   (0,3,1) so it outranks `.app-wrapper nav:not(.horizontal-sidebar)` (0,2,1);
   width still needs !important to beat theirs. */
@media (max-width: 991px) {
    .app-wrapper .timeline-content nav.navbar {
        transform: none;
        width: 100% !important;
    }
}

/* --- Timeline date gutter collapses to zero width ----------------------
   style.css and pracbill-modern-forms.css each carry a `max-width: 768px`
   timeline block, and they disagree about the layout. style.css re-flows the
   date out of the absolute left gutter and into the document flow:

       .timeline-time-container { position: relative; width: 100%;
                                  padding: 0 0 5px 55px; }

   pracbill-modern-forms.css loads later and narrows it for the gutter layout
   it still assumes is in force:

       .timeline-time-container { width: 45px; padding-right: 5px; }

   The width lands on the in-flow box while `padding-left: 55px` survives, and
   under `box-sizing: border-box` the padding exceeds the width — content width
   resolves to 0, so "5 days ago" renders one character per line as an 86px
   tall vertical strip, and because the box is now in flow it pushes the note
   itself that far down the page.

   Take the layout the phone actually wants instead of restoring the gutter:
   below 576px the rail keeps only the dot and its line, the date becomes a
   plain label above the note, and the note gets the width the gutter was
   holding (measured at 390px: 235px -> 284px). 576–768px keeps the gutter
   layout and only repairs it. */
@media (max-width: 768px) {
    /* Put the date back in its absolute gutter — the modern-forms width and
       padding-right above are written for exactly this. */
    .timeline-time-container {
        position: absolute;
        left: 0;
        top: 4px;
        padding-left: 0;
    }
}

@media (max-width: 575.98px) {
    .timeline-list {
        padding-left: 0;
    }
    /* Rail carries the dot only: icon 14px at left:1px, centre 8px. */
    .timeline-list:after {
        left: 7px;
    }
    .timeline-list .timeline-icon {
        left: 1px;
        top: 6px;
    }
    /* Back into the flow as a one-line label above the note. Full width and
       left-aligned, so there is no narrow box for the text to shred itself in. */
    .timeline-time-container {
        position: static;
        width: auto;
        padding: 0 0 4px 28px;
        text-align: left;
    }
    /* The theme stacks the number over the unit for the narrow gutter; inline
       reads as ordinary prose now there is a whole line for it. */
    .timeline-relative-time .time-num,
    .timeline-relative-time .time-text {
        display: inline;
        font-size: 11px;
    }
    /* The two spans are emitted back to back with no whitespace between them
       (see the regex_replace in timeline.tpl), which only read correctly while
       they were block-level. Put the word space back. */
    .timeline-relative-time .time-num {
        margin-right: 0.25em;
    }
    .timeline-list .timeline-content {
        margin-left: 28px;
    }
    /* Title on its own row above the buttons, which the navbar-header already
       claims full width for; keeps long titles off the action row. */
    .timeline-content .navbar-brand {
        white-space: normal;
        overflow-wrap: anywhere;
    }
    /* Comfortable touch targets for the note actions. */
    .timeline-content .navbar-nav > li > button {
        min-height: 2.5rem;
        min-width: 2.5rem;
    }
}
