/* =============================================================================
   RealEstate CRM — application shell and component styles.

   Layered on top of Bootstrap 5.3 rather than replacing it. The important idea in
   this file is the bridge in section 3: our design tokens are mapped onto
   Bootstrap's own CSS variables, so every `.btn`, `.form-control`, `.table`,
   `.badge` and `.alert` already in the views picks up the theme without a single
   markup change — and follows it into dark mode.

   Colour is defined here and nowhere else. Nothing in the database describes how
   anything looks, so re-theming the product is an edit to this file.

   Sections
     1. Tokens (light)
     2. Tokens (dark)
     3. Bootstrap bridge
     4. Base, typography, focus
     5. Shell — sidebar, topbar, content, footer
     6. Components — page header, card, table, form, badge, pager, empty state
     7. Lead CRM — stat tiles, charts, kanban, timeline
     8. Inventory — status palette, grid, drawer, gallery, pricing
     9. Sign-in
    10. Responsive, motion, print
   ========================================================================== */

/* =============================================================================
   1. Tokens (light)

   Palette, type and proportions taken from the Legacy Buddy template: navy
   #020F59 as the one strong colour, gold #D4AF37 beside it, and everything else
   held back so those two carry the page.

   Only the values are shared. Every rule below this point is written for this
   codebase — none of the template's stylesheet is used, and none of its assets
   are shipped. Inter, Playfair Display and JetBrains Mono, which the look depends
   on, are open source (SIL OFL) and vendored under `lib/fonts/`.

   Three things carry most of the feel:

   **The sidebar is navy.** A deep, near-black blue rail against a cool paper
   canvas, with a gold marker on the active item. Navy and gold together are the
   template's whole brand signature, and the sidebar is where it reads loudest.

   **Shadows are navy, not grey, and very soft.** `0 2px 12px rgba(2,15,89,0.06)`
   is the template's one card shadow — barely there. Cards separate by sitting on
   a tinted canvas, not by being lifted off it.

   **Fields are tinted, not white.** An input is `#F8FAFC` against a white card,
   so the place you type is visible before you look for a border, and it turns
   white on focus — the field brightens as you arrive in it.
   ========================================================================== */

:root {
    color-scheme: light;

    /* -- layout -- */
    --crm-sidebar-width: 260px;
    --crm-content-max: 1560px;
    --crm-topbar-height: 62px;

    /* -- surfaces. The canvas is a cool off-white with blue in it (#F4F6FD), not
          a warm grey: it is what makes a plain white card read as raised. -- */
    --crm-canvas: #f4f6fd;
    --crm-surface: #ffffff;
    --crm-surface-2: #f6f8ff;
    --crm-surface-3: #edf1fb;
    --crm-overlay: rgba(2, 15, 89, 0.5);

    /* -- ink -- */
    --crm-ink: #0f172a;
    --crm-ink-2: #475569;
    --crm-muted: #94a3b8;
    --crm-faint: #a9b4c6;

    /* -- lines -- */
    --crm-border: #e8ebf4;
    --crm-border-strong: #d7dcef;
    --crm-border-soft: #eff2fa;

    /* -- action / accent. Navy does both jobs: it is the primary button and the
          accent, and nothing else on the page competes with it. -- */
    --crm-action: #020f59;
    --crm-action-hover: #01093b;
    --crm-action-ink: #ffffff;

    --crm-accent: #020f59;
    --crm-accent-hover: #01093b;
    --crm-accent-ink: #020f59;
    --crm-accent-soft: #eef0fd;
    --crm-accent-soft-2: #dfe4fa;
    --crm-accent-ring: #eef0fd;
    /* No glow. The previous palette cast violet from its buttons; this one does
       not cast anything — the template's restraint is the point of it. */
    --crm-accent-glow: 0 0.0625rem 0.1875rem 0 rgba(2, 15, 89, 0.18);

    /* -- gold. The second half of the brand. Reserved for the sidebar's active
          marker and the brand mark: used more widely it stops reading as special
          and starts reading as a warning colour. -- */
    --crm-gold: #d4af37;
    --crm-gold-hover: #b8912b;
    --crm-gold-soft: #fbf3dd;

    /* -- semantic -- */
    --crm-success: #2e7d32;
    --crm-success-soft: #dcfce7;
    --crm-warning: #d97706;
    --crm-warning-soft: #fef3c7;
    --crm-danger: #ef4444;
    --crm-danger-soft: #fee2e2;
    --crm-info: #0ea5e9;
    --crm-info-soft: #e0f2fe;
    --crm-neutral: #64748b;

    /* -- fields. Their own tokens rather than reusing the surface ramp: the
          template gives an input a background, a hover border and a focus border
          that belong to none of the other surfaces. -- */
    --crm-field-bg: #f8fafc;
    --crm-field-bg-focus: #ffffff;
    --crm-field-border: #e8ebf4;
    --crm-field-border-hover: #c7d0f8;
    --crm-field-border-focus: #020f59;
    --crm-field-ring: #eef0fd;

    /* -- sidebar: navy, with gold on the active item -- */
    --crm-sidebar-bg: #020f59;
    --crm-sidebar-bg-2: #020f59;
    --crm-sidebar-ink: rgba(255, 255, 255, 0.72);
    --crm-sidebar-ink-strong: #ffffff;
    --crm-sidebar-ink-faint: rgba(255, 255, 255, 0.45);
    --crm-sidebar-hover: rgba(255, 255, 255, 0.08);
    --crm-sidebar-active-bg: rgba(255, 255, 255, 0.13);
    --crm-sidebar-line: rgba(255, 255, 255, 0.12);
    --crm-sidebar-rail: var(--crm-gold);

    /* -- radii. The template's own ramp: 6 on small controls, 8 as the base, 12
          on cards, 16 on drawers and sheets. -- */
    --crm-radius-sm: 6px;
    --crm-radius: 8px;
    --crm-radius-lg: 12px;
    --crm-radius-xl: 16px;

    /* -- elevation, tinted navy. `--crm-shadow-sm` is the template's card shadow
          exactly; the rest of the ramp is built around it. -- */
    --crm-shadow-xs: 0 0.0625rem 0.1875rem 0 rgba(2, 15, 89, 0.05);
    --crm-shadow-sm: 0 0.125rem 0.75rem 0 rgba(2, 15, 89, 0.06);
    --crm-shadow: 0 0.375rem 1.25rem 0 rgba(2, 15, 89, 0.09);
    --crm-shadow-lg: 0 1.125rem 2.75rem 0 rgba(2, 15, 89, 0.14);

    /* -- type. All three families are vendored under lib/fonts, so nothing is
          fetched at render time. Inter carries the interface; Playfair Display is
          the display face and appears only on page and card headings; JetBrains
          Mono is for codes and reference numbers. -- */
    --crm-font-sans: "Inter", -apple-system, BlinkMacSystemFont,
        "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    --crm-font-display: "Playfair Display", Georgia, "Times New Roman", serif;

    --crm-font-mono: "JetBrains Mono", "Cascadia Mono", ui-monospace, SFMono-Regular,
        "SF Mono", Menlo, Consolas, monospace;

    /* -- motion -- */
    --crm-ease: cubic-bezier(0.16, 0.84, 0.44, 1);
    --crm-fast: 120ms;
    --crm-medium: 200ms;
}

/* =============================================================================
   2. Tokens (dark)

   Defined twice on purpose: once for the viewer whose system is dark and who has
   made no choice, and once for the viewer who explicitly picked dark. Only the
   tokens change — no component below knows which theme it is in.

   The template ships no dark palette, so this one is derived rather than copied.
   The ground is deep navy (#070b26 / #0e1440) rather than a neutral charcoal,
   which is the same reasoning the violet palette used: on charcoal the brand
   colour drifts, and navy on charcoal drifts furthest of all. The action colour
   lifts from #020f59 toward the template's own #1e2ede, because navy that dark
   is unreadable as a button on a dark ground.
   ========================================================================== */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --crm-canvas: #070b26;
        --crm-surface: #0e1440;
        --crm-surface-2: #151c4f;
        --crm-surface-3: #1d255f;
        --crm-overlay: rgba(2, 7, 30, 0.72);

        --crm-ink: #e2e6f5;
        --crm-ink-2: #b4bcd9;
        --crm-muted: #8792b5;
        --crm-faint: #6b769b;

        --crm-border: #232b60;
        --crm-border-strong: #333d78;
        --crm-border-soft: #1b2350;

        --crm-action: #4553e8;
        --crm-action-hover: #5c68f2;
        --crm-action-ink: #ffffff;

        --crm-accent: #8e99f5;
        --crm-accent-hover: #a3acf8;
        --crm-accent-ink: #b9c1fa;
        --crm-accent-soft: rgba(76, 91, 240, 0.18);
        --crm-accent-soft-2: rgba(76, 91, 240, 0.3);
        --crm-accent-ring: rgba(76, 91, 240, 0.45);
        --crm-accent-glow: 0 0.0625rem 0.25rem 0 rgba(2, 7, 30, 0.6);

        --crm-gold: #e0c15c;
        --crm-gold-hover: #eed488;
        --crm-gold-soft: rgba(212, 175, 55, 0.16);

        --crm-success: #4ade80;
        --crm-success-soft: rgba(34, 197, 94, 0.16);
        --crm-warning: #fbbf24;
        --crm-warning-soft: rgba(245, 158, 11, 0.16);
        --crm-danger: #f87171;
        --crm-danger-soft: rgba(239, 68, 68, 0.16);
        --crm-info: #38bdf8;
        --crm-info-soft: rgba(14, 165, 233, 0.16);
        --crm-neutral: #94a3b8;

        --crm-field-bg: #121a47;
        --crm-field-bg-focus: #0e1440;
        --crm-field-border: #232b60;
        --crm-field-border-hover: #3a4585;
        --crm-field-border-focus: #8e99f5;
        --crm-field-ring: rgba(76, 91, 240, 0.28);

        --crm-sidebar-bg: #070b26;
        --crm-sidebar-bg-2: #070b26;
        --crm-sidebar-ink: rgba(226, 230, 245, 0.72);
        --crm-sidebar-ink-strong: #ffffff;
        --crm-sidebar-ink-faint: rgba(226, 230, 245, 0.42);
        --crm-sidebar-hover: rgba(255, 255, 255, 0.07);
        --crm-sidebar-active-bg: rgba(255, 255, 255, 0.12);
        --crm-sidebar-line: rgba(255, 255, 255, 0.1);

        --crm-shadow-xs: 0 0.0625rem 0.1875rem 0 rgba(2, 7, 30, 0.4);
        --crm-shadow-sm: 0 0.125rem 0.75rem 0 rgba(2, 7, 30, 0.46);
        --crm-shadow: 0 0.375rem 1.25rem 0 rgba(2, 7, 30, 0.54);
        --crm-shadow-lg: 0 1.125rem 2.75rem 0 rgba(2, 7, 30, 0.62);
    }
}

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

    --crm-canvas: #070b26;
    --crm-surface: #0e1440;
    --crm-surface-2: #151c4f;
    --crm-surface-3: #1d255f;
    --crm-overlay: rgba(2, 7, 30, 0.72);

    --crm-ink: #e2e6f5;
    --crm-ink-2: #b4bcd9;
    --crm-muted: #8792b5;
    --crm-faint: #6b769b;

    --crm-border: #232b60;
    --crm-border-strong: #333d78;
    --crm-border-soft: #1b2350;

    --crm-action: #4553e8;
    --crm-action-hover: #5c68f2;
    --crm-action-ink: #ffffff;

    --crm-accent: #8e99f5;
    --crm-accent-hover: #a3acf8;
    --crm-accent-ink: #b9c1fa;
    --crm-accent-soft: rgba(76, 91, 240, 0.18);
    --crm-accent-soft-2: rgba(76, 91, 240, 0.3);
    --crm-accent-ring: rgba(76, 91, 240, 0.45);
    --crm-accent-glow: 0 0.0625rem 0.25rem 0 rgba(2, 7, 30, 0.6);

    --crm-gold: #e0c15c;
    --crm-gold-hover: #eed488;
    --crm-gold-soft: rgba(212, 175, 55, 0.16);

    --crm-success: #4ade80;
    --crm-success-soft: rgba(34, 197, 94, 0.16);
    --crm-warning: #fbbf24;
    --crm-warning-soft: rgba(245, 158, 11, 0.16);
    --crm-danger: #f87171;
    --crm-danger-soft: rgba(239, 68, 68, 0.16);
    --crm-info: #38bdf8;
    --crm-info-soft: rgba(14, 165, 233, 0.16);
    --crm-neutral: #94a3b8;

    --crm-field-bg: #121a47;
    --crm-field-bg-focus: #0e1440;
    --crm-field-border: #232b60;
    --crm-field-border-hover: #3a4585;
    --crm-field-border-focus: #8e99f5;
    --crm-field-ring: rgba(76, 91, 240, 0.28);

    --crm-sidebar-bg: #070b26;
    --crm-sidebar-bg-2: #070b26;
    --crm-sidebar-ink: rgba(226, 230, 245, 0.72);
    --crm-sidebar-ink-strong: #ffffff;
    --crm-sidebar-ink-faint: rgba(226, 230, 245, 0.42);
    --crm-sidebar-hover: rgba(255, 255, 255, 0.07);
    --crm-sidebar-active-bg: rgba(255, 255, 255, 0.12);
    --crm-sidebar-line: rgba(255, 255, 255, 0.1);

    --crm-shadow-xs: 0 0.0625rem 0.1875rem 0 rgba(2, 7, 30, 0.4);
    --crm-shadow-sm: 0 0.125rem 0.75rem 0 rgba(2, 7, 30, 0.46);
    --crm-shadow: 0 0.375rem 1.25rem 0 rgba(2, 7, 30, 0.54);
    --crm-shadow-lg: 0 1.125rem 2.75rem 0 rgba(2, 7, 30, 0.62);
}

/* =============================================================================
   3. Bootstrap bridge

   Sixty Razor views were written against Bootstrap's own classes. Rather than
   rewrite them, the tokens above are mapped onto Bootstrap's variables here, so
   `btn-primary`, `form-control`, `table`, `badge` and the rest inherit the theme
   — including dark mode — with no markup change at all.
   ========================================================================== */

:root {
    --bs-body-bg: var(--crm-canvas);
    --bs-body-color: var(--crm-ink-2);
    --bs-emphasis-color: var(--crm-ink);
    --bs-secondary-color: var(--crm-muted);
    --bs-tertiary-color: var(--crm-faint);
    --bs-border-color: var(--crm-border);
    --bs-border-color-translucent: var(--crm-border);
    --bs-secondary-bg: var(--crm-surface-2);
    --bs-tertiary-bg: var(--crm-surface-3);

    --bs-primary: var(--crm-accent);
    --bs-link-color: var(--crm-accent);
    --bs-link-hover-color: var(--crm-accent-hover);
    --bs-link-color-rgb: 138, 100, 32;

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

    --bs-font-sans-serif: var(--crm-font-sans);
    --bs-font-monospace: var(--crm-font-mono);
}

/* Buttons. Bootstrap resolves these per component, so they are set per variant
   rather than globally. */
.btn {
    --bs-btn-font-weight: 500;
    --bs-btn-padding-y: 0.44rem;
    --bs-btn-padding-x: 0.9rem;
    --bs-btn-border-radius: var(--crm-radius-sm);
    transition: background-color var(--crm-fast) var(--crm-ease),
                border-color var(--crm-fast) var(--crm-ease),
                color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease),
                transform var(--crm-fast) var(--crm-ease);
}

.btn-sm {
    --bs-btn-padding-y: 0.28rem;
    --bs-btn-padding-x: 0.65rem;
    --bs-btn-font-size: 0.82rem;
}

.btn-lg {
    --bs-btn-padding-y: 0.62rem;
    --bs-btn-padding-x: 1.25rem;
    --bs-btn-font-size: 1rem;
}

/* The commit button is ink, not brand colour. There is usually exactly one of
   these on a screen — Save, Create, Sign in — and near-black makes it the most
   definite thing there without shouting, and without competing with the status
   colours that actually carry meaning. On a dark ground it inverts. */
.btn-primary {
    --bs-btn-bg: var(--crm-action);
    --bs-btn-border-color: var(--crm-action);
    --bs-btn-color: var(--crm-action-ink);
    --bs-btn-hover-bg: var(--crm-action-hover);
    --bs-btn-hover-border-color: var(--crm-action-hover);
    --bs-btn-hover-color: var(--crm-action-ink);
    --bs-btn-active-bg: var(--crm-action-hover);
    --bs-btn-active-border-color: var(--crm-action-hover);
    --bs-btn-active-color: var(--crm-action-ink);
    --bs-btn-disabled-bg: var(--crm-action);
    --bs-btn-disabled-border-color: var(--crm-action);
    --bs-btn-disabled-color: var(--crm-action-ink);
    box-shadow: var(--crm-shadow-xs);
}

/* Coloured buttons carry white text in light mode; in dark mode the fills are
   light enough that white text on them is unreadable, so the ink flips. */
:root[data-theme="dark"] .btn-danger,
:root[data-theme="dark"] .btn-success {
    --bs-btn-color: #14120e;
    --bs-btn-hover-color: #14120e;
    --bs-btn-active-color: #14120e;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .btn-danger,
    :root:not([data-theme="light"]) .btn-success {
        --bs-btn-color: #14120e;
        --bs-btn-hover-color: #14120e;
        --bs-btn-active-color: #14120e;
    }
}

.btn-outline-secondary {
    --bs-btn-color: var(--crm-ink-2);
    --bs-btn-border-color: var(--crm-border-strong);
    --bs-btn-bg: var(--crm-surface);
    --bs-btn-hover-color: var(--crm-ink);
    --bs-btn-hover-bg: var(--crm-surface-2);
    --bs-btn-hover-border-color: var(--crm-border-strong);
    --bs-btn-active-color: var(--crm-ink);
    --bs-btn-active-bg: var(--crm-surface-3);
    --bs-btn-active-border-color: var(--crm-border-strong);
}

.btn-outline-primary {
    --bs-btn-color: var(--crm-accent);
    --bs-btn-border-color: var(--crm-accent);
    --bs-btn-hover-bg: var(--crm-accent);
    --bs-btn-hover-border-color: var(--crm-accent);
    --bs-btn-active-bg: var(--crm-accent-hover);
    --bs-btn-active-border-color: var(--crm-accent-hover);
}

.btn-danger {
    --bs-btn-bg: var(--crm-danger);
    --bs-btn-border-color: var(--crm-danger);
    --bs-btn-hover-bg: #b91c1c;
    --bs-btn-hover-border-color: #b91c1c;
}

.btn-success {
    --bs-btn-bg: var(--crm-success);
    --bs-btn-border-color: var(--crm-success);
    --bs-btn-hover-bg: #15803d;
    --bs-btn-hover-border-color: #15803d;
}

.btn:not(.btn-link):not(:disabled):active {
    transform: translateY(1px);
}

/* Forms. */
/* A field is tinted rather than white, so on a white card the place you type is
   visible before you go looking for its border. Arriving in it turns it white and
   draws a navy edge: the field brightens under the cursor instead of merely
   gaining an outline. */
.form-control,
.form-select {
    --bs-body-bg: var(--crm-field-bg);
    background-color: var(--crm-field-bg);
    border-color: var(--crm-field-border);
    border-radius: var(--crm-radius);
    color: var(--crm-ink);
    padding: 0.45rem 0.7rem;
    transition: border-color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease),
                background-color var(--crm-fast) var(--crm-ease);
}

/* Hover only when the field is not already focused: otherwise moving the mouse
   across a field you are typing in would pull its border off navy. */
.form-control:hover:not(:focus):not(:disabled),
.form-select:hover:not(:focus):not(:disabled) {
    border-color: var(--crm-field-border-hover);
}

.form-control:focus,
.form-select:focus {
    background-color: var(--crm-field-bg-focus);
    border-color: var(--crm-field-border-focus);
    box-shadow: 0 0 0 3px var(--crm-field-ring);
    color: var(--crm-ink);
}

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

.form-control:disabled,
.form-select:disabled {
    background-color: var(--crm-surface-3);
    color: var(--crm-muted);
}

.form-control-sm,
.form-select-sm {
    padding: 0.28rem 0.55rem;
    font-size: 0.82rem;
}

.form-label {
    font-size: 0.82rem;
    font-weight: 550;
    color: var(--crm-ink-2);
    margin-bottom: 0.3rem;
}

.form-text {
    color: var(--crm-muted);
    font-size: 0.78rem;
}

.form-check-input {
    border-color: var(--crm-border-strong);
    background-color: var(--crm-surface);
}

.form-check-input:checked {
    background-color: var(--crm-accent);
    border-color: var(--crm-accent);
}

.form-check-input:focus {
    border-color: var(--crm-accent);
    box-shadow: 0 0 0 3px var(--crm-accent-ring);
}

.input-group-text {
    background-color: var(--crm-field-bg);
    border-color: var(--crm-field-border);
    color: var(--crm-muted);
}

/* Dark mode needs the browser's own widgets to match, or a date picker and a
   select arrow arrive as bright white rectangles. */
:root[data-theme="dark"] .form-control,
:root[data-theme="dark"] .form-select {
    color-scheme: dark;
}

/* Tables. */
.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--crm-ink-2);
    --bs-table-border-color: var(--crm-border-soft);
    --bs-table-hover-bg: var(--crm-surface-2);
    --bs-table-hover-color: var(--crm-ink);
    margin-bottom: 0;
}

.table > thead {
    --bs-table-color: var(--crm-muted);
}

.table > thead th {
    font-size: 0.74rem;
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--crm-muted);
    border-bottom: 1px solid var(--crm-border);
    padding: 0.6rem 0.75rem;
    white-space: nowrap;
    background: var(--crm-surface-2);
}

.table > tbody td,
.table > tbody th {
    padding: 0.7rem 0.75rem;
    vertical-align: middle;
    border-bottom-color: var(--crm-border-soft);
}

.table > tbody tr:last-child > * {
    border-bottom-width: 0;
}

/* Money and counts line up when the digits are the same width. */
.table td.text-end,
.table th.text-end {
    font-variant-numeric: tabular-nums;
}

/* Badges. Bootstrap's subtle variants are remapped so they survive dark mode. */
.badge {
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.01em;
    padding: 0.3em 0.6em;
    border-radius: 999px;
}

.text-bg-success-subtle { background-color: var(--crm-success-soft) !important; color: var(--crm-success) !important; }
.text-bg-warning-subtle { background-color: var(--crm-warning-soft) !important; color: var(--crm-warning) !important; }
.text-bg-danger-subtle { background-color: var(--crm-danger-soft) !important; color: var(--crm-danger) !important; }
.text-bg-info-subtle { background-color: var(--crm-info-soft) !important; color: var(--crm-info) !important; }
.text-bg-primary-subtle { background-color: var(--crm-accent-soft-2) !important; color: var(--crm-accent-ink) !important; }
.text-bg-secondary-subtle { background-color: var(--crm-surface-3) !important; color: var(--crm-muted) !important; }
.text-bg-light { background-color: var(--crm-surface-2) !important; color: var(--crm-ink-2) !important; }

.text-secondary { color: var(--crm-muted) !important; }
.text-body-secondary { color: var(--crm-muted) !important; }
.text-danger { color: var(--crm-danger) !important; }
.text-success { color: var(--crm-success) !important; }
.text-muted { color: var(--crm-muted) !important; }

/* Alerts. */
.alert {
    border-radius: var(--crm-radius);
    border-width: 1px;
    padding: 0.7rem 1rem;
    font-size: 0.9rem;
    box-shadow: var(--crm-shadow-xs);
}

.alert-success { background: var(--crm-success-soft); border-color: transparent; color: var(--crm-success); }
.alert-danger  { background: var(--crm-danger-soft);  border-color: transparent; color: var(--crm-danger); }
.alert-warning { background: var(--crm-warning-soft); border-color: transparent; color: var(--crm-warning); }
.alert-info    { background: var(--crm-info-soft);    border-color: transparent; color: var(--crm-info); }
.alert-light   { background: var(--crm-surface-2);    border-color: var(--crm-border); color: var(--crm-ink-2); }

/* Dropdowns, modals and other floating surfaces. */
.dropdown-menu {
    --bs-dropdown-bg: var(--crm-surface);
    --bs-dropdown-border-color: var(--crm-border);
    --bs-dropdown-link-color: var(--crm-ink-2);
    --bs-dropdown-link-hover-bg: var(--crm-surface-2);
    --bs-dropdown-link-hover-color: var(--crm-ink);
    --bs-dropdown-link-active-bg: var(--crm-accent-soft);
    --bs-dropdown-link-active-color: var(--crm-accent-ink);
    --bs-dropdown-header-color: var(--crm-muted);
    border-radius: var(--crm-radius);
    box-shadow: var(--crm-shadow-lg);
    padding: 0.35rem;
    font-size: 0.88rem;
}

.dropdown-item {
    border-radius: var(--crm-radius-sm);
    padding: 0.42rem 0.6rem;
}

.modal-content,
.offcanvas {
    background-color: var(--crm-surface);
    border-color: var(--crm-border);
    border-radius: var(--crm-radius-lg);
}

.nav-tabs {
    --bs-nav-tabs-border-color: var(--crm-border);
    --bs-nav-tabs-link-active-bg: var(--crm-surface);
    --bs-nav-tabs-link-active-color: var(--crm-accent);
    --bs-nav-tabs-link-active-border-color: var(--crm-border) var(--crm-border) var(--crm-surface);
    --bs-nav-link-color: var(--crm-muted);
    --bs-nav-link-hover-color: var(--crm-ink);
}

.breadcrumb {
    --bs-breadcrumb-divider-color: var(--crm-faint);
    --bs-breadcrumb-item-active-color: var(--crm-ink-2);
    margin-bottom: 0.75rem;
}

.breadcrumb a {
    color: var(--crm-muted);
    text-decoration: none;
}

.breadcrumb a:hover {
    color: var(--crm-accent);
}

.progress {
    background-color: var(--crm-surface-3);
    border-radius: 999px;
}

hr,
.dropdown-divider {
    border-color: var(--crm-border);
    opacity: 1;
}

.btn-close {
    --bs-btn-close-color: var(--crm-ink);
}

:root[data-theme="dark"] .btn-close {
    filter: invert(1) grayscale(1) brightness(2);
}

/* =============================================================================
   4. Base, typography, focus
   ========================================================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body.crm-app,
body.crm-plain {
    background-color: var(--crm-canvas);
    color: var(--crm-ink-2);
    font-family: var(--bs-font-sans-serif);
    font-size: 0.925rem;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}

/* Playfair against Inter is the template's entire typographic idea: headings
   read as considered, body copy reads as neutral. A serif needs less negative
   tracking than a grotesque and a little more line, so both are relaxed from what
   the previous single-family stack wanted. */
h1, h2, h3, h4, h5, h6 {
    color: var(--crm-ink);
    font-family: var(--crm-font-display);
    font-weight: 700;
    letter-spacing: -0.004em;
    line-height: 1.32;
}

/* Anything that is a heading by markup but a label by function stays on Inter:
   a serif on a 12px uppercase caption reads as a mistake, not as a flourish. */
.table th,
.form-label,
.badge,
.btn,
.nav-link,
.crm-stat-tile h3,
.crm-stat-tile h4 {
    font-family: var(--crm-font-sans);
}

a {
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

/* One focus treatment for the whole application. Keyboard users get a ring they
   cannot miss; mouse users never see it. */
:focus-visible {
    outline: 2px solid var(--crm-accent);
    outline-offset: 2px;
    border-radius: var(--crm-radius-sm);
}

.form-control:focus-visible,
.form-select:focus-visible,
.btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--crm-accent-ring);
}

::selection {
    background: var(--crm-accent-soft-2);
    color: var(--crm-accent-ink);
}

/* Scrollbars, so a long sidebar or a wide table does not interrupt the palette. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--crm-border-strong) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background: var(--crm-border-strong);
    border-radius: 999px;
    border: 3px solid transparent;
    background-clip: content-box;
}

*::-webkit-scrollbar-thumb:hover {
    background: var(--crm-faint);
    background-clip: content-box;
}

/* JetBrains Mono runs wider than the Consolas and Menlo this used to fall through
   to, so the size comes down a step to keep a reference number the same length on
   the page as it was before the face was actually vendored. */
.font-monospace {
    font-family: var(--crm-font-mono);
    font-size: 0.82em;
    letter-spacing: -0.015em;
}

/* An identifier in a table cell never wraps. LEAD-2026-000046 broken across three
   lines is unreadable and it drags the whole row taller; the table already scrolls
   sideways inside .table-responsive when a column needs the room. */
.table .font-monospace,
.table td > .font-monospace {
    white-space: nowrap;
}

/* =============================================================================
   5. Shell
   ========================================================================== */

.crm-shell {
    display: flex;
    min-height: 100vh;
    min-height: 100dvh;
}

.crm-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.crm-content {
    flex: 1 1 auto;
    width: 100%;
    max-width: var(--crm-content-max);
    margin: 0 auto;
    padding: 1.5rem 1.75rem 2.5rem;
}

/* ---------- sidebar ---------- */

.crm-sidebar {
    width: var(--crm-sidebar-width);
    flex: 0 0 var(--crm-sidebar-width);
    background: var(--crm-sidebar-bg);
    color: var(--crm-sidebar-ink);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    border-right: 1px solid var(--crm-sidebar-line);
}

.crm-brand {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 1.05rem 1.1rem;
    border-bottom: 1px solid var(--crm-sidebar-line);
    position: sticky;
    top: 0;
    background: inherit;
    backdrop-filter: blur(6px);
    z-index: 2;
}

.crm-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: var(--crm-radius);
    background: linear-gradient(140deg, #e6c65c 0%, var(--crm-gold) 55%, #b8912b 100%);
    color: #01072e;
    font-weight: 800;
    font-size: 0.86rem;
    letter-spacing: 0.04em;
    flex: 0 0 auto;
    box-shadow: 0 0.25rem 0.75rem -0.2rem rgba(1, 7, 46, 0.55);
}

.crm-brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    min-width: 0;
}

.crm-brand-text strong {
    color: var(--crm-sidebar-ink-strong);
    font-size: 0.98rem;
    font-weight: 640;
    letter-spacing: -0.01em;
}

.crm-brand-text span {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--crm-sidebar-ink-faint);
}

.crm-nav {
    padding: 0.6rem 0.55rem 2rem;
    flex: 1 1 auto;
}

.crm-nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Entries are pills rather than full-width rows: on a navy rail a row that runs
   edge to edge reads as a band of lighter navy, and the eye stops finding the
   label inside it. The active one is handled further down. */
.crm-nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.55rem 0.85rem;
    margin: 0.12rem 0;
    border-radius: 999px;
    color: var(--crm-sidebar-ink);
    text-decoration: none;
    font-size: 0.9375rem;
    font-weight: 400;
    transition: background-color var(--crm-fast) var(--crm-ease),
                color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease);
}

.crm-nav-link .crm-icon {
    color: var(--crm-sidebar-ink-faint);
    transition: color var(--crm-fast) var(--crm-ease);
}

.crm-nav-link:hover,
.crm-nav-link:focus-visible {
    background: var(--crm-sidebar-hover);
    color: var(--crm-sidebar-ink-strong);
}

.crm-nav-link:hover .crm-icon {
    color: var(--crm-sidebar-ink-strong);
}

/* The active entry: a translucent white pill on the navy rail, marked in gold.

   A solid brand pill is what a white sidebar wants, and it is what this file used
   to do. It cannot work here — the brand colour and the sidebar are both navy, so
   the pill would vanish into its own background. Lifting the surface instead is
   how the template marks position, and the gold bar is the one place the second
   brand colour appears in the shell. */
.crm-nav-link.active {
    position: relative;
    background: var(--crm-sidebar-active-bg);
    color: var(--crm-sidebar-ink-strong);
    font-weight: 550;
}

.crm-nav-link.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.35rem;
    bottom: 0.35rem;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--crm-sidebar-rail);
}

.crm-nav-link.active .crm-icon {
    color: var(--crm-sidebar-ink-strong);
}

.crm-nav-badge {
    margin-left: auto;
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    padding: 0.12rem 0.45rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.14);
    color: var(--crm-sidebar-ink-strong);
}

.crm-nav-link.active .crm-nav-badge {
    background: rgba(255, 255, 255, 0.9);
    color: var(--crm-accent);
}

.crm-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
}

/* Sidebar groups. A group heading is a label, not a link: every destination
   inside it is a child entry, and the group is dropped entirely when the
   signed-in user may open none of them. */
.crm-nav-group {
    margin-top: 1.1rem;
}

.crm-nav-group-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.3rem 0.7rem 0.4rem;
    font-size: 0.66rem;
    font-weight: 650;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--crm-sidebar-ink-faint);
}

.crm-nav-group-title .crm-icon {
    width: 14px;
    height: 14px;
    opacity: 0.7;
}

/* The section you are in. This stays deliberately quieter than the active pill:
   the pill answers "which page", the heading only answers "which section", and a
   second loud marker would compete with the one that matters. Colour alone is not
   the signal — the active link also carries aria-current for anyone not seeing it. */
.crm-nav-group.is-active > .crm-nav-group-title {
    color: var(--crm-accent-ink);
}

.crm-nav-group.is-active > .crm-nav-group-title .crm-icon {
    opacity: 1;
}

/* A rail down the children ties the heading to the pill sitting under it, which
   matters most in the long groups where the two are far apart. */
.crm-nav-group.is-active > ul {
    box-shadow: inset 2px 0 0 -1px var(--crm-accent-soft-2);
}

/* On the dark sidebar the accent ink is too dim to read as a heading. */
:root[data-theme="dark"] .crm-nav-group.is-active > .crm-nav-group-title {
    color: var(--crm-sidebar-ink-strong);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .crm-nav-group.is-active > .crm-nav-group-title {
        color: var(--crm-sidebar-ink-strong);
    }
}

.crm-nav-group > ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.crm-nav-sublink {
    padding-left: 1.65rem;
}

/* ---------- topbar ---------- */

.crm-topbar {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    min-height: var(--crm-topbar-height);
    padding: 0.6rem 1.75rem;
    background: color-mix(in srgb, var(--crm-surface) 82%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--crm-border);
    position: sticky;
    top: 0;
    z-index: 20;
}

/* Browsers without color-mix still need an opaque bar rather than a see-through
   one, so the fallback is declared first and overridden above. */
@supports not (background: color-mix(in srgb, red 50%, blue)) {
    .crm-topbar {
        background: var(--crm-surface);
    }
}

.crm-topbar-title {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
}

.crm-topbar-title h1 {
    font-size: 1.02rem;
    font-weight: 620;
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: -0.012em;
}

.crm-tenant-chip {
    font-size: 0.67rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    padding: 0.18rem 0.5rem;
    border-radius: 999px;
    background: var(--crm-accent-soft);
    color: var(--crm-accent-ink);
    border: 1px solid var(--crm-accent-soft-2);
    white-space: nowrap;
}

.crm-tenant-chip-platform {
    background: var(--crm-warning-soft);
    color: var(--crm-warning);
    border-color: transparent;
}

.crm-topbar-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.crm-topbar-user .btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.5rem 0.25rem 0.25rem;
    border-radius: 999px;
    color: var(--crm-ink-2);
    text-decoration: none;
    font-size: 0.86rem;
    font-weight: 520;
    transition: background-color var(--crm-fast) var(--crm-ease);
}

.crm-topbar-user .btn:hover {
    background: var(--crm-surface-2);
}

.crm-topbar-user .dropdown-toggle::after {
    margin-left: 0.1rem;
    color: var(--crm-faint);
}

.crm-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: linear-gradient(140deg, var(--crm-ink-2) 0%, var(--crm-ink) 100%);
    color: var(--crm-action-ink);
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    flex: 0 0 auto;
    /* A hairline of brass, so the avatar belongs to the same set as the brand
       mark rather than looking like a stray grey circle. */
    box-shadow: inset 0 0 0 1px rgba(180, 137, 60, 0.45);
}

/* An icon-only control in the topbar: the theme switch and anything joining it
   later. */
.crm-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-muted);
    transition: background-color var(--crm-fast) var(--crm-ease),
                color var(--crm-fast) var(--crm-ease),
                border-color var(--crm-fast) var(--crm-ease);
}

.crm-icon-btn:hover {
    background: var(--crm-surface-2);
    border-color: var(--crm-border);
    color: var(--crm-ink);
}

.crm-icon-btn .crm-icon {
    width: 17px;
    height: 17px;
}

/* Only one of the two glyphs is ever shown, and which one depends on the theme
   the viewer is actually in — including when that theme came from the operating
   system rather than from a click. */
.crm-theme-toggle [data-theme-dark] { display: none; }
.crm-theme-toggle [data-theme-light] { display: inline-flex; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .crm-theme-toggle [data-theme-light] { display: none; }
    :root:not([data-theme="light"]) .crm-theme-toggle [data-theme-dark] { display: inline-flex; }
}

:root[data-theme="dark"] .crm-theme-toggle [data-theme-light] { display: none; }
:root[data-theme="dark"] .crm-theme-toggle [data-theme-dark] { display: inline-flex; }
:root[data-theme="light"] .crm-theme-toggle [data-theme-light] { display: inline-flex; }
:root[data-theme="light"] .crm-theme-toggle [data-theme-dark] { display: none; }

.crm-sidebar-toggle {
    display: none;
    flex-direction: column;
    gap: 4px;
    padding: 0.45rem;
    border-radius: var(--crm-radius-sm);
}

.crm-sidebar-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--crm-ink);
    border-radius: 2px;
}

.crm-sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--crm-overlay);
    backdrop-filter: blur(2px);
    z-index: 25;
}

/* ---------- footer ---------- */

.crm-footer {
    padding: 0.9rem 1.75rem;
    border-top: 1px solid var(--crm-border);
    background: var(--crm-surface);
    font-size: 0.82rem;
    color: var(--crm-muted);
}

/* =============================================================================
   6. Components
   ========================================================================== */

/* ---------- page header ---------- */

.crm-page-intro {
    margin-bottom: 1.35rem;
}

.crm-page-intro h2 {
    font-size: 1.42rem;
    font-weight: 640;
    letter-spacing: -0.018em;
    margin-bottom: 0.28rem;
}

.crm-page-intro p {
    color: var(--crm-muted);
    max-width: 72ch;
    margin-bottom: 0;
    font-size: 0.9rem;
}

/* ---------- card ---------- */

/* The workhorse. Padding and a surface live here rather than in each view, so a
   card is a card everywhere and nobody has to remember `p-3`. */
.crm-card {
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
    padding: 1.15rem 1.25rem;
}

/* A card that is only a frame around a table gives the table its edges back. */
.crm-card > .table-responsive:first-child,
.crm-card > .table-responsive:only-child {
    margin: -1.15rem -1.25rem;
    width: auto;
    border-radius: inherit;
}

.crm-card > .table-responsive > .table > thead th:first-child { padding-left: 1.25rem; }
.crm-card > .table-responsive > .table > thead th:last-child { padding-right: 1.25rem; }
.crm-card > .table-responsive > .table > tbody td:first-child,
.crm-card > .table-responsive > .table > tbody th:first-child { padding-left: 1.25rem; }
.crm-card > .table-responsive > .table > tbody td:last-child { padding-right: 1.25rem; }

.crm-card > .table-responsive:first-child + .crm-pager {
    margin: 0 -1.25rem -1.15rem;
    padding: 0.85rem 1.25rem;
    border-top: 1px solid var(--crm-border);
}

/* A card that links somewhere lifts on hover; one that does not, does not. */
a.crm-card {
    transition: border-color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease),
                transform var(--crm-fast) var(--crm-ease);
}

a.crm-card:hover {
    border-color: var(--crm-border-strong);
    box-shadow: var(--crm-shadow);
    transform: translateY(-1px);
}

.crm-card-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.94rem;
    font-weight: 640;
    color: var(--crm-ink);
    letter-spacing: -0.008em;
    margin-bottom: 0.9rem;
}

/* ---------- description list ---------- */

.crm-dl {
    display: grid;
    grid-template-columns: minmax(130px, 34%) 1fr;
    gap: 0.55rem 1.25rem;
    margin: 0;
    font-size: 0.885rem;
}

.crm-dl dt {
    color: var(--crm-muted);
    font-weight: 500;
}

.crm-dl dd {
    margin: 0;
    color: var(--crm-ink);
    word-break: break-word;
}

/* ---------- pager ---------- */

.crm-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1rem;
    font-size: 0.84rem;
    color: var(--crm-muted);
}

.pagination {
    --bs-pagination-color: var(--crm-ink-2);
    --bs-pagination-bg: var(--crm-surface);
    --bs-pagination-border-color: var(--crm-border);
    --bs-pagination-hover-bg: var(--crm-surface-2);
    --bs-pagination-hover-color: var(--crm-ink);
    --bs-pagination-hover-border-color: var(--crm-border-strong);
    --bs-pagination-active-bg: var(--crm-accent);
    --bs-pagination-active-border-color: var(--crm-accent);
    --bs-pagination-disabled-bg: var(--crm-surface-2);
    --bs-pagination-disabled-color: var(--crm-faint);
    --bs-pagination-disabled-border-color: var(--crm-border);
    --bs-pagination-border-radius: var(--crm-radius-sm);
    margin-bottom: 0;
}

/* ---------- empty state ---------- */

.crm-empty-state {
    max-width: 520px;
    margin: 2.5rem auto;
    text-align: center;
    padding: 1rem;
}

.crm-empty-state .crm-icon {
    width: 40px;
    height: 40px;
    color: var(--crm-accent);
    margin-bottom: 0.75rem;
    opacity: 0.85;
}

.crm-empty-state h2 {
    font-size: 1.1rem;
    font-weight: 620;
    margin-bottom: 0.4rem;
}

.crm-empty-state p {
    color: var(--crm-muted);
    font-size: 0.9rem;
    margin-bottom: 1.1rem;
}

/* Keeps a wide permission matrix readable: the module column stays put while the
   verb columns scroll horizontally inside the table container. */
.table-responsive th[scope="row"] {
    position: sticky;
    left: 0;
    background: var(--crm-surface);
    z-index: 1;
}

.table-responsive {
    border-radius: inherit;
}

/* =============================================================================
   7. Lead CRM (Phase 4)
   ========================================================================== */

/* ---------- stat tiles ---------- */

.crm-stat-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    height: 100%;
    padding: 0.95rem 1.05rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
    overflow: hidden;
    transition: border-color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease),
                transform var(--crm-fast) var(--crm-ease);
}

/* The accent is a hairline down the left edge, painted as a pseudo-element so it
   sits inside the rounded corner instead of squaring it off. */
.crm-stat-tile::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--crm-stat-accent, var(--crm-accent));
}

.crm-stat-value {
    font-size: 1.65rem;
    font-weight: 660;
    line-height: 1.1;
    color: var(--crm-ink);
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
}

.crm-stat-label {
    font-size: 0.78rem;
    color: var(--crm-muted);
}

.crm-stat-primary   { --crm-stat-accent: var(--crm-accent); }
.crm-stat-secondary { --crm-stat-accent: var(--crm-faint); }
.crm-stat-info      { --crm-stat-accent: var(--crm-info); }
.crm-stat-success   { --crm-stat-accent: var(--crm-success); }
.crm-stat-warning   { --crm-stat-accent: var(--crm-warning); }
.crm-stat-danger    { --crm-stat-accent: var(--crm-danger); }

/* A tile that links somewhere should say so on hover. */
.crm-stat-tile:has(.stretched-link):hover {
    border-color: var(--crm-border-strong);
    box-shadow: var(--crm-shadow);
    transform: translateY(-1px);
}

/* ---------- charts ---------- */

/* Chart.js sizes to its container, so the container needs an explicit height —
   without one the canvas grows on every resize event. */
.crm-chart {
    position: relative;
    height: 300px;
}

.crm-chart-sm {
    height: 220px;
}

/* ---------- kanban ---------- */

.crm-kanban {
    display: flex;
    gap: 0.8rem;
    /* The board scrolls sideways rather than squeezing ten columns into the
       viewport; a 90px-wide column is not a column. */
    overflow-x: auto;
    padding-bottom: 0.85rem;
    align-items: flex-start;
}

.crm-kanban-column {
    flex: 0 0 17.5rem;
    max-width: 17.5rem;
    background: var(--crm-surface-2);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 16rem);
    transition: background-color var(--crm-fast) var(--crm-ease),
                outline-color var(--crm-fast) var(--crm-ease);
}

.crm-kanban-column.is-won {
    background: var(--crm-success-soft);
    border-color: transparent;
}

.crm-kanban-column.is-lost {
    background: var(--crm-danger-soft);
    border-color: transparent;
}

.crm-kanban-column.is-drop-target {
    outline: 2px dashed var(--crm-accent);
    outline-offset: -3px;
    background: var(--crm-accent-soft);
}

.crm-kanban-header {
    padding: 0.7rem 0.85rem 0.55rem;
    border-bottom: 1px solid var(--crm-border);
    position: sticky;
    top: 0;
    background: inherit;
    border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0;
    z-index: 1;
}

.crm-kanban-title {
    font-size: 0.83rem;
    font-weight: 660;
    color: var(--crm-ink);
    letter-spacing: -0.005em;
}

.crm-kanban-count {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0 0.45rem;
    border-radius: 999px;
    background: var(--crm-surface-3);
    color: var(--crm-muted);
    font-size: 0.7rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}

.crm-kanban-value {
    font-size: 0.72rem;
    color: var(--crm-muted);
    margin-top: 0.12rem;
    font-variant-numeric: tabular-nums;
}

.crm-kanban-body {
    padding: 0.6rem;
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 6rem;
}

.crm-kanban-empty {
    color: var(--crm-faint);
    font-size: 0.78rem;
    text-align: center;
    margin: 1.6rem 0;
}

.crm-kanban-card {
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    padding: 0.62rem 0.72rem;
    margin-bottom: 0.55rem;
    box-shadow: var(--crm-shadow-xs);
    transition: box-shadow var(--crm-fast) var(--crm-ease),
                border-color var(--crm-fast) var(--crm-ease),
                opacity var(--crm-fast) var(--crm-ease),
                transform var(--crm-fast) var(--crm-ease);
}

.crm-kanban-card[draggable="true"] {
    cursor: grab;
}

.crm-kanban-card:hover {
    box-shadow: var(--crm-shadow);
    border-color: var(--crm-border-strong);
    transform: translateY(-1px);
}

.crm-kanban-card.is-dragging {
    opacity: 0.45;
    transform: rotate(1.5deg);
    cursor: grabbing;
}

/* While the server decides, the card is visibly not yet settled. */
.crm-kanban-card.is-saving {
    opacity: 0.6;
    pointer-events: none;
}

.crm-kanban-name {
    font-weight: 600;
    font-size: 0.86rem;
    color: var(--crm-ink);
}

.crm-kanban-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    font-size: 0.74rem;
    color: var(--crm-muted);
    margin-top: 0.2rem;
}

.crm-kanban-project {
    font-size: 0.74rem;
    color: var(--crm-accent);
    margin-top: 0.15rem;
}

.crm-kanban-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 0.5rem;
    padding-top: 0.45rem;
    border-top: 1px dashed var(--crm-border);
}

.crm-kanban-owner {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--crm-accent-soft-2);
    color: var(--crm-accent-ink);
    font-size: 0.64rem;
    font-weight: 700;
    flex: 0 0 auto;
}

.crm-kanban-more {
    display: block;
    text-align: center;
    font-size: 0.75rem;
    padding: 0.4rem;
    color: var(--crm-accent);
    text-decoration: none;
    border-radius: var(--crm-radius-sm);
}

.crm-kanban-more:hover {
    background: var(--crm-surface-3);
}

/* ---------- activity timeline ---------- */

.crm-timeline-day {
    font-size: 0.7rem;
    font-weight: 680;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--crm-faint);
    margin: 1.25rem 0 0.6rem;
}

.crm-timeline-day:first-child {
    margin-top: 0;
}

.crm-timeline {
    list-style: none;
    margin: 0;
    padding: 0 0 0 1.6rem;
    position: relative;
}

/* The spine. Drawn on the list rather than per item so it does not break between
   entries. */
.crm-timeline::before {
    content: "";
    position: absolute;
    left: 0.65rem;
    top: 0.4rem;
    bottom: 0.4rem;
    width: 2px;
    background: var(--crm-border);
    border-radius: 2px;
}

.crm-timeline-item {
    position: relative;
    padding: 0 0 0.95rem 0.9rem;
}

.crm-timeline-dot {
    position: absolute;
    left: -1.6rem;
    top: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.55rem;
    height: 1.55rem;
    border-radius: 50%;
    background: var(--crm-surface);
    border: 2px solid var(--crm-border);
    color: var(--crm-muted);
    box-shadow: 0 0 0 3px var(--crm-canvas);
}

.crm-timeline-dot .crm-icon {
    width: 12px;
    height: 12px;
}

.crm-timeline-dot-primary   { border-color: var(--crm-accent);  color: var(--crm-accent); }
.crm-timeline-dot-success   { border-color: var(--crm-success); color: var(--crm-success); }
.crm-timeline-dot-danger    { border-color: var(--crm-danger);  color: var(--crm-danger); }
.crm-timeline-dot-warning   { border-color: var(--crm-warning); color: var(--crm-warning); }
.crm-timeline-dot-info      { border-color: var(--crm-info);    color: var(--crm-info); }
.crm-timeline-dot-secondary { border-color: var(--crm-faint);   color: var(--crm-faint); }

.crm-timeline-body {
    font-size: 0.86rem;
    line-height: 1.45;
}

/* =============================================================================
   8. Inventory (Phase 3)
   ========================================================================== */

/* The single source of truth for what each unit status looks like. The database
   stores the status; the colour lives here and nowhere else, so re-theming is a
   CSS edit rather than a data migration. Each status gets a fill, a line and an
   ink colour, so the same class works on a tile, a dot and a bar segment. */

/* The six map onto the palette's semantic set, so a held unit is the same amber
   as a warning alert and a sold one the same navy as the brand. Nothing here
   invents a colour the rest of the application does not already use.

   Each row is a tint, the full-strength colour, and a darkened ink. The fill is
   too light to carry text at full strength, so the ink is a deeper step of the
   same hue — every one of the six clears the 4.5:1 floor on its own fill. */
.status-available { --crm-status-fill: #dcfce7; --crm-status-line: #2e7d32; --crm-status-ink: #166534; }
.status-hold      { --crm-status-fill: #fef3c7; --crm-status-line: #f59e0b; --crm-status-ink: #92590b; }
.status-blocked   { --crm-status-fill: #eef1f7; --crm-status-line: #64748b; --crm-status-ink: #44506a; }
.status-booked    { --crm-status-fill: #e0f2fe; --crm-status-line: #0ea5e9; --crm-status-ink: #06617f; }
.status-sold      { --crm-status-fill: #eef0fd; --crm-status-line: #020f59; --crm-status-ink: #020f59; }
.status-cancelled { --crm-status-fill: #fee2e2; --crm-status-line: #ef4444; --crm-status-ink: #a51d1d; }

/* On a dark canvas all three roles have to move. The pale fills above turn into
   glare, so the fill becomes a tint. And the deepened lines — which are what make
   these tones calm in light mode — go nearly invisible against a dark ground, so
   they lift to the same hue at a lighter value. Hue is what carries the meaning
   and hue is what stays fixed; value follows the theme. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .status-available { --crm-status-fill: rgba(46, 125, 50, 0.2); --crm-status-line: #4ade80; --crm-status-ink: #86efac; }
    :root:not([data-theme="light"]) .status-hold      { --crm-status-fill: rgba(245, 158, 11, 0.18); --crm-status-line: #fbbf24; --crm-status-ink: #fcd77f; }
    :root:not([data-theme="light"]) .status-blocked   { --crm-status-fill: rgba(100, 116, 139, 0.26); --crm-status-line: #94a3b8; --crm-status-ink: #cbd5e1; }
    :root:not([data-theme="light"]) .status-booked    { --crm-status-fill: rgba(14, 165, 233, 0.18); --crm-status-line: #38bdf8; --crm-status-ink: #8ed7fb; }
    :root:not([data-theme="light"]) .status-sold      { --crm-status-fill: rgba(76, 91, 240, 0.24); --crm-status-line: #8e99f5; --crm-status-ink: #bcc3fa; }
    :root:not([data-theme="light"]) .status-cancelled { --crm-status-fill: rgba(239, 68, 68, 0.18); --crm-status-line: #f87171; --crm-status-ink: #fca5a5; }
}

:root[data-theme="dark"] .status-available { --crm-status-fill: rgba(46, 125, 50, 0.2); --crm-status-line: #4ade80; --crm-status-ink: #86efac; }
:root[data-theme="dark"] .status-hold      { --crm-status-fill: rgba(245, 158, 11, 0.18); --crm-status-line: #fbbf24; --crm-status-ink: #fcd77f; }
:root[data-theme="dark"] .status-blocked   { --crm-status-fill: rgba(100, 116, 139, 0.26); --crm-status-line: #94a3b8; --crm-status-ink: #cbd5e1; }
:root[data-theme="dark"] .status-booked    { --crm-status-fill: rgba(14, 165, 233, 0.18); --crm-status-line: #38bdf8; --crm-status-ink: #8ed7fb; }
:root[data-theme="dark"] .status-sold      { --crm-status-fill: rgba(76, 91, 240, 0.24); --crm-status-line: #8e99f5; --crm-status-ink: #bcc3fa; }
:root[data-theme="dark"] .status-cancelled { --crm-status-fill: rgba(239, 68, 68, 0.18); --crm-status-line: #f87171; --crm-status-ink: #fca5a5; }

.crm-status-dot {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 50%;
    background-color: var(--crm-status-fill, var(--crm-surface-3));
    border: 1px solid var(--crm-status-line, var(--crm-border));
    flex: 0 0 auto;
}

.crm-status-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1rem;
}

.crm-status-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    white-space: nowrap;
}

.crm-status-legend-label {
    color: var(--crm-muted);
}

.crm-status-legend-count {
    font-variant-numeric: tabular-nums;
    font-weight: 650;
    color: var(--crm-ink);
}

/* ---------- summary bar ---------- */

.crm-inventory-summary {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
}

/* A proportional bar rather than six loose numbers: the mix of a project is what
   a sales head reads at a glance, and proportions read faster than counts. */
.crm-status-bar {
    display: flex;
    width: 100%;
    height: 0.8rem;
    border-radius: 999px;
    overflow: hidden;
    background-color: var(--crm-surface-3);
    border: 1px solid var(--crm-border);
}

.crm-status-bar-segment {
    background-color: var(--crm-status-line, var(--crm-border-strong));
    min-width: 2px;
    transition: flex-basis var(--crm-medium) var(--crm-ease);
}

.crm-status-bar-segment:not(:last-child) {
    border-right: 1px solid var(--crm-surface);
}

/* ---------- visual grid ---------- */

.crm-floor-row {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--crm-border-soft);
}

.crm-floor-row:last-child {
    border-bottom: 0;
}

.crm-floor-label {
    flex: 0 0 8.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding-top: 0.5rem;
    font-size: 0.8rem;
    font-weight: 620;
    color: var(--crm-muted);
}

.crm-floor-count {
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    color: var(--crm-faint);
}

.crm-floor-units {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* Tiles are buttons, not divs: keyboard users reach the drawer for free, and the
   focus ring lands where it should. */
.crm-unit-tile {
    flex: 0 0 auto;
    width: 6.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.08rem;
    padding: 0.42rem 0.55rem;
    text-align: left;
    border: 1px solid var(--crm-status-line, var(--crm-border));
    border-left-width: 3px;
    border-radius: var(--crm-radius-sm);
    background-color: var(--crm-status-fill, var(--crm-surface));
    color: var(--crm-status-ink, var(--crm-ink));
    line-height: 1.2;
    cursor: pointer;
    transition: transform var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease);
}

.crm-unit-tile:hover {
    transform: translateY(-2px);
    box-shadow: var(--crm-shadow);
}

.crm-unit-tile:focus-visible {
    outline: 2px solid var(--crm-accent);
    outline-offset: 2px;
}

.crm-unit-number {
    font-weight: 650;
    font-size: 0.8rem;
    letter-spacing: -0.005em;
}

.crm-unit-bhk {
    font-size: 0.68rem;
    opacity: 0.9;
}

.crm-unit-price {
    font-size: 0.68rem;
    font-variant-numeric: tabular-nums;
    opacity: 0.9;
}

/* ---------- unit drawer ---------- */

.crm-drawer {
    position: fixed;
    inset: 0;
    z-index: 1050;
    pointer-events: none;
    visibility: hidden;
}

.crm-drawer.is-open {
    pointer-events: auto;
    visibility: visible;
}

/* Transparent is not the same as absent. An element at opacity 0 still takes every
   click that lands on it, so the backdrop states its own pointer-events rather than
   relying on the drawer above it to switch them off — the nesting is correct now, and
   this makes the rule hold even if the markup is moved again. */
.crm-drawer-backdrop {
    position: absolute;
    inset: 0;
    background-color: var(--crm-overlay);
    backdrop-filter: blur(2px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--crm-medium) var(--crm-ease);
}

.crm-drawer-backdrop.is-visible {
    opacity: 1;
    pointer-events: auto;
}

.crm-drawer-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(31rem, 100%);
    display: flex;
    flex-direction: column;
    background-color: var(--crm-surface);
    border-left: 1px solid var(--crm-border);
    box-shadow: var(--crm-shadow-lg);
    transform: translateX(100%);
    transition: transform var(--crm-medium) var(--crm-ease);
}

.crm-drawer.is-open .crm-drawer-panel {
    transform: translateX(0);
}

.crm-drawer-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.crm-drawer-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.1rem 1.35rem;
    border-bottom: 1px solid var(--crm-border);
}

.crm-drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 1.1rem 1.35rem;
}

.crm-drawer-footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0.8rem 1.35rem;
    border-top: 1px solid var(--crm-border);
    background-color: var(--crm-surface-2);
}

.crm-drawer-section {
    font-size: 0.7rem;
    font-weight: 680;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--crm-faint);
    margin: 1.4rem 0 0.6rem;
}

.crm-drawer-loading {
    padding: 2.5rem 1.35rem;
    text-align: center;
    color: var(--crm-muted);
}

body.crm-drawer-open {
    overflow: hidden;
}

/* The full unit page reuses the same card partial, so the drawer chrome has to
   stop behaving like a slide-over when it is simply sitting inside a card. */
.crm-unit-page .crm-drawer-header,
.crm-unit-page .crm-drawer-footer {
    padding-left: 0;
    padding-right: 0;
    background-color: transparent;
}

.crm-unit-page .crm-drawer-body {
    overflow: visible;
    padding-left: 0;
    padding-right: 0;
}

.crm-unit-page [data-drawer-close] {
    display: none;
}

/* ---------- price break-up ---------- */

.crm-price-table td {
    padding: 0.32rem 0;
    border-color: var(--crm-border-soft);
    font-size: 0.87rem;
}

.crm-price-table td:last-child {
    font-variant-numeric: tabular-nums;
}

.crm-price-total td {
    border-top: 2px solid var(--crm-border);
    font-weight: 700;
    font-size: 1rem;
    color: var(--crm-ink);
    padding-top: 0.5rem;
}

/* ---------- project media gallery ---------- */

.crm-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 0.75rem;
}

.crm-gallery-item {
    position: relative;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    overflow: hidden;
    background-color: var(--crm-surface-2);
    transition: border-color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease);
}

.crm-gallery-item:hover {
    border-color: var(--crm-border-strong);
    box-shadow: var(--crm-shadow-sm);
}

.crm-gallery-item img {
    display: block;
    width: 100%;
    height: 8rem;
    object-fit: cover;
}

.crm-gallery-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.35rem;
    padding: 0.45rem 0.55rem;
    font-size: 0.78rem;
}

/* =============================================================================
   9. Sign-in

   A two-panel page: the form on the left, and on the right a brand panel that
   says what this product is. The panel is decoration and is dropped on small
   screens rather than stacked, because nobody scrolls past a gradient to reach a
   password field.
   ========================================================================== */

.crm-auth {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    background: var(--crm-surface);
}

.crm-auth-main {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1.5rem;
    min-width: 0;
}

.crm-auth-card {
    width: 100%;
    max-width: 400px;
}

.crm-auth-brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 2rem;
}

.crm-auth-brand div {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

.crm-auth-brand strong {
    color: var(--crm-ink);
    font-size: 1rem;
    font-weight: 640;
}

.crm-auth-brand div span {
    font-size: 0.78rem;
    color: var(--crm-muted);
}

.crm-auth-title {
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -0.004em;
    margin-bottom: 0.35rem;
}

.crm-auth-subtitle {
    color: var(--crm-muted);
    font-size: 0.9rem;
    margin-bottom: 1.6rem;
}

.crm-auth-footer {
    margin-top: 2rem;
    color: var(--crm-faint);
    font-size: 0.78rem;
}

/* The brand panel. */
.crm-auth-aside {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.5rem;
    padding: 3rem;
    overflow: hidden;
    background: linear-gradient(150deg, #1e2ede 0%, #020f59 55%, #01072e 100%);
    color: #dfe4fa;
}

/* Two soft lights behind the copy, so the panel has depth without an image file
   to ship, cache and keep in sync with the palette. */
.crm-auth-aside::before,
.crm-auth-aside::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    filter: blur(80px);
    pointer-events: none;
}

.crm-auth-aside::before {
    width: 26rem;
    height: 26rem;
    top: -8rem;
    right: -6rem;
    background: rgba(255, 255, 255, 0.28);
}

.crm-auth-aside::after {
    width: 22rem;
    height: 22rem;
    bottom: -7rem;
    left: -5rem;
    background: rgba(0, 186, 209, 0.34);
}

.crm-auth-aside > * {
    position: relative;
    z-index: 1;
    max-width: 34rem;
}

.crm-auth-aside h2 {
    color: #fff;
    font-size: 2rem;
    font-weight: 660;
    letter-spacing: -0.03em;
    line-height: 1.2;
}

.crm-auth-aside p {
    color: rgba(236, 233, 254, 0.8);
    font-size: 1rem;
    margin-bottom: 0;
}

.crm-auth-points {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
}

.crm-auth-points li {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    font-size: 0.92rem;
    color: rgba(236, 233, 254, 0.9);
}

.crm-auth-points .crm-icon {
    width: 18px;
    height: 18px;
    margin-top: 0.15rem;
    color: #b3aaf8;
    flex: 0 0 auto;
}

/* =============================================================================
   10. Responsive, motion, print
   ========================================================================== */

@media (max-width: 1199.98px) {
    .crm-auth {
        grid-template-columns: 1fr;
    }

    /* Decoration, not content: on a narrow screen it is dropped rather than
       stacked above the form. */
    .crm-auth-aside {
        display: none;
    }
}

@media (max-width: 991.98px) {
    .crm-sidebar {
        position: fixed;
        left: 0;
        top: 0;
        z-index: 30;
        transform: translateX(-100%);
        transition: transform var(--crm-medium) var(--crm-ease);
        box-shadow: var(--crm-shadow-lg);
    }

    .crm-sidebar.is-open {
        transform: translateX(0);
    }

    .crm-sidebar-toggle {
        display: flex;
    }

    .crm-sidebar-backdrop.is-visible {
        display: block;
    }

    .crm-topbar {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    .crm-content {
        padding: 1.1rem 1rem 2rem;
    }

    .crm-footer {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    .crm-dl {
        grid-template-columns: 1fr;
        gap: 0.1rem;
    }

    .crm-dl dt {
        font-size: 0.78rem;
    }

    .crm-dl dd {
        margin-bottom: 0.65rem;
    }
}

@media (max-width: 767.98px) {
    .crm-card {
        padding: 1rem;
    }

    .crm-card > .table-responsive:first-child,
    .crm-card > .table-responsive:only-child {
        margin: -1rem;
    }

    .crm-card > .table-responsive > .table > thead th:first-child,
    .crm-card > .table-responsive > .table > tbody td:first-child,
    .crm-card > .table-responsive > .table > tbody th:first-child { padding-left: 1rem; }

    .crm-card > .table-responsive > .table > thead th:last-child,
    .crm-card > .table-responsive > .table > tbody td:last-child { padding-right: 1rem; }

    .crm-page-intro h2 {
        font-size: 1.25rem;
    }

    .crm-kanban-column {
        flex-basis: 15rem;
        max-width: 15rem;
    }

    .crm-chart {
        height: 240px;
    }

    .crm-floor-row {
        flex-direction: column;
        gap: 0.35rem;
    }

    .crm-floor-label {
        flex: 1 1 auto;
        width: 100%;
        padding-top: 0;
    }

    .crm-unit-tile {
        width: calc(50% - 0.2rem);
    }

    .crm-drawer-panel {
        width: 100%;
    }

    .crm-stat-value {
        font-size: 1.4rem;
    }
}

/* Someone who has asked their system to stop animating things means it. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .crm-card:hover,
    .crm-stat-tile:hover,
    .crm-unit-tile:hover,
    .crm-kanban-card:hover {
        transform: none;
    }
}

@media print {
    .crm-sidebar,
    .crm-topbar,
    .crm-footer,
    .crm-drawer,
    .crm-sidebar-backdrop,
    .btn {
        display: none !important;
    }

    body.crm-app {
        background: #fff;
    }

    .crm-content {
        padding: 0;
        max-width: none;
    }

    .crm-card {
        border-color: #d4cdc2;
        box-shadow: none;
        break-inside: avoid;
    }
}

/* =============================================================================
   11. Shell odds and ends
   ========================================================================== */

/* A keyboard user should not have to tab through the whole sidebar on every page
   to reach the thing they came for. Off-screen until focused. */
.crm-skip-link {
    position: absolute;
    left: 0.75rem;
    top: -3rem;
    z-index: 60;
    padding: 0.5rem 0.9rem;
    border-radius: var(--crm-radius-sm);
    background: var(--crm-accent);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    transition: top var(--crm-fast) var(--crm-ease);
}

.crm-skip-link:focus {
    top: 0.75rem;
    color: #fff;
}

/* Who is signed in, at the head of the account menu. The email used to be a
   dropdown-header, which truncated it and read as a section label rather than as
   the answer to "which account am I in?" */
.crm-menu-identity {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.6rem 0.6rem;
}

.crm-menu-identity div {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.crm-menu-identity strong {
    font-size: 0.86rem;
    font-weight: 620;
    color: var(--crm-ink);
}

.crm-menu-identity span {
    font-size: 0.76rem;
    color: var(--crm-muted);
    overflow: hidden;
    text-overflow: ellipsis;
}

.crm-topbar-user .dropdown-menu {
    min-width: 15rem;
}

.crm-topbar-user .dropdown-menu form {
    margin: 0;
}

/* A card that is the whole page — an error, a refusal, a module that does not
   exist yet — rather than one panel among several. */
.crm-card-centered {
    max-width: 640px;
    margin: 2rem auto;
}

.crm-error-code {
    font-size: 3.4rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.04em;
    color: var(--crm-ink);
    margin-bottom: 0.5rem;
    font-variant-numeric: tabular-nums;
}

code {
    background: var(--crm-surface-3);
    color: var(--crm-ink-2);
    padding: 0.1rem 0.35rem;
    border-radius: var(--crm-radius-sm);
    font-size: 0.85em;
}

/* The brand is a link now, so it needs to stop looking like body text and start
   showing that it responds. */
a.crm-brand {
    text-decoration: none;
    transition: background-color var(--crm-fast) var(--crm-ease);
}

a.crm-brand:hover {
    background: var(--crm-sidebar-hover);
}

/* =============================================================================
   12. Filter bars

   Every list screen opens with a GET form of dropdowns. Left on the same white
   as the data below it, that strip reads as content; recessed slightly, it reads
   as controls — which is what it is. Matched on shape rather than on a new class
   so the twelve views that already have one need no edit.
   ========================================================================== */

.crm-card:has(> form[method="get"]) {
    background: var(--crm-surface-2);
    box-shadow: none;
    padding: 0.9rem 1rem;
}

.crm-card:has(> form[method="get"]) .form-label {
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--crm-muted);
    margin-bottom: 0.25rem;
}

.crm-card:has(> form[method="get"]) .form-control,
.crm-card:has(> form[method="get"]) .form-select {
    background-color: var(--crm-surface);
}

/* Browsers without :has() get the plain card. It is a shade of grey, not a
   feature, and nothing is unusable without it. */

/* =============================================================================
   13. Small refinements that apply everywhere
   ========================================================================== */

/* A sortable column header should look like something you can click. */
.table thead a {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    border-radius: var(--crm-radius-sm);
}

.table thead a:hover {
    color: var(--crm-accent);
}

/* Row actions stay put while the eye scans, and stop competing with the data. */
.table .btn-group-sm > .btn,
.table .btn-sm {
    --bs-btn-padding-y: 0.2rem;
    --bs-btn-padding-x: 0.55rem;
    --bs-btn-font-size: 0.78rem;
}

/* Ids and codes are read character by character, so they get a face built for it
   and a tone that keeps them out of the way of the name beside them. */
.font-monospace,
code {
    color: var(--crm-muted);
}

.table .font-monospace {
    font-size: 0.78rem;
}

/* Bootstrap's `.small` inside a muted context was landing at two different greys
   depending on the parent. One grey. */
.small,
small {
    font-size: 0.82rem;
}

/* Forms: a section of a long form reads better with a rule under its heading than
   with more whitespace, which a dense form has none of to spare. */
form .crm-card-title {
    padding-bottom: 0.55rem;
    border-bottom: 1px solid var(--crm-border-soft);
}

/* The validation summary is an error list, and an empty one should not reserve a
   red box's worth of space at the top of every form. */
.validation-summary-valid {
    display: none;
}

.field-validation-error,
.text-danger.small {
    display: inline-block;
    margin-top: 0.25rem;
    font-size: 0.78rem;
}

.form-control.input-validation-error,
.form-select.input-validation-error {
    border-color: var(--crm-danger);
}

.form-control.input-validation-error:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--crm-danger) 25%, transparent);
}

/* Anything the user can drag or select-drag inside the boards. */
[draggable="true"] {
    -webkit-user-drag: element;
    user-select: none;
}

/* =============================================================================
   14. Display type

   Two families, and the split is by role rather than by size: Playfair Display
   wherever a heading is meant to be read as a heading, Inter everywhere the text
   is doing a job — labels, buttons, table columns, badges. The template draws the
   same line, and it is what keeps the serif from turning into decoration.

   The rules below are the places where the display face needs its own size and
   tracking rather than inheriting the global heading rule.
   ========================================================================== */

.crm-auth-aside h2 {
    font-family: var(--crm-font-display);
    font-weight: 700;
    font-size: 2.1rem;
    line-height: 1.24;
    letter-spacing: -0.008em;
}

.crm-error-code {
    font-family: var(--crm-font-display);
    font-weight: 800;
    letter-spacing: -0.02em;
}

.crm-brand-text strong {
    font-family: var(--crm-font-sans);
    font-weight: 650;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
}

/* A hairline under the sign-in headline. One rule, and the panel stops looking
   like a gradient with words on it. */
.crm-auth-aside h2::after {
    content: "";
    display: block;
    width: 3.5rem;
    height: 2px;
    margin-top: 1.1rem;
    background: rgba(255, 255, 255, 0.55);
    border-radius: 2px;
}

/* =============================================================================
   15. Weight and spacing

   The palette above is most of the premium feel; the rest is restraint. Cards
   sit on lighter borders and softer shadows, and headings get a little more room
   than a dense admin template usually allows.
   ========================================================================== */

.crm-page-intro {
    margin-bottom: 1.5rem;
}

.crm-page-intro h2 {
    font-weight: 600;
    letter-spacing: -0.021em;
}

.crm-card {
    padding: 1.25rem 1.35rem;
}

.crm-card > .table-responsive:first-child,
.crm-card > .table-responsive:only-child {
    margin: -1.25rem -1.35rem;
}

.crm-card > .table-responsive > .table > thead th:first-child,
.crm-card > .table-responsive > .table > tbody td:first-child,
.crm-card > .table-responsive > .table > tbody th:first-child { padding-left: 1.35rem; }

.crm-card > .table-responsive > .table > thead th:last-child,
.crm-card > .table-responsive > .table > tbody td:last-child { padding-right: 1.35rem; }

.crm-card > .table-responsive:first-child + .crm-pager {
    margin: 0 -1.35rem -1.25rem;
    padding: 0.9rem 1.35rem;
}

/* Column headers were shouting in full uppercase at 650 weight. Same idea,
   quieter. */
.table > thead th {
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    background: transparent;
    border-bottom-color: var(--crm-border-strong);
}

.crm-stat-value {
    font-weight: 600;
    letter-spacing: -0.028em;
}

/* A stat tile with no semantic colour of its own carries the brand colour. */
.crm-stat-primary { --crm-stat-accent: var(--crm-accent); }

/* =============================================================================
   16. Component weight

   The palette does most of the work; the rest is proportion. Cards are rounder
   and float rather than sit inside a border, and body copy runs at 15px with a
   tight 1.375 line-height.

   The primary button no longer glows. Under the violet palette it cast its own
   colour, which was that style's signature; navy casting navy would only look
   like a smudge, and the template it now follows puts nothing under its buttons
   at all.
   ========================================================================== */

body.crm-app,
body.crm-plain {
    font-size: 0.9375rem;
    line-height: 1.375;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--crm-ink);
    font-weight: 700;
    letter-spacing: -0.004em;
}

/* Cards float on the canvas instead of being outlined on it. The border is kept
   at hairline weight for the one case a shadow cannot carry — a card sitting
   directly on another card. */
.crm-card,
.crm-stat-tile {
    border-color: transparent;
    box-shadow: var(--crm-shadow-xs);
    border-radius: var(--crm-radius-lg);
}

.crm-card:hover,
a.crm-card:hover,
.crm-stat-tile:has(.stretched-link):hover {
    border-color: transparent;
    box-shadow: var(--crm-shadow-sm);
}

/* Filter strips stay outlined rather than floating — two stacked shadows read as
   one blurred edge, and the strip is chrome, not content. */
.crm-card:has(> form[method="get"]) {
    background: var(--crm-surface);
    border-color: var(--crm-border);
    box-shadow: none;
}

/* The primary button casts its own colour. This is the single most recognisable
   thing about the style and it is worth exactly one line. */
.btn-primary {
    box-shadow: var(--crm-accent-glow);
}

.btn-primary:hover {
    box-shadow: var(--crm-accent-glow);
}

.btn-primary:disabled {
    box-shadow: none;
}

/* Bootstrap's outline buttons pick the brand colour up automatically; the
   secondary one is remapped so it reads as neutral rather than as a second
   brand. */
.btn-outline-secondary {
    --bs-btn-color: var(--crm-ink-2);
    --bs-btn-border-color: var(--crm-border-strong);
}

/* Badges are pills of tinted colour, matching the status treatment. */
.badge {
    font-weight: 500;
    letter-spacing: 0;
    padding: 0.32em 0.7em;
}

/* Column headers: small, spaced, and the same soft grey as body copy. */
.table > thead th {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--crm-muted);
    border-bottom-color: var(--crm-border);
}

.table > tbody td,
.table > tbody th {
    padding: 0.78rem 0.75rem;
}

/* Inputs sit slightly taller than Bootstrap's default, which is what makes a form
   in this style feel unhurried. */
.form-control,
.form-select {
    padding: 0.53rem 0.85rem;
    border-radius: var(--crm-radius-sm);
}

.form-control:focus,
.form-select:focus {
    box-shadow: var(--crm-accent-glow);
}

.form-label {
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--crm-ink);
    text-transform: none;
    letter-spacing: 0;
}

.crm-card:has(> form[method="get"]) .form-label {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--crm-ink);
}

/* The topbar loses its border and floats over the canvas, so the sidebar and the
   content area read as one surface with a header sitting on it. */
.crm-topbar {
    border-bottom: 1px solid var(--crm-border);
}

.crm-footer {
    background: transparent;
    border-top-color: var(--crm-border);
}

/* The avatar carries the brand gradient, unlike the sidebar mark beside it: the
   avatar sits in the topbar on paper, where navy is the colour that stands out,
   and the mark sits on navy, where gold is. Same brand, opposite grounds. */
.crm-avatar {
    background: linear-gradient(140deg, #1e2ede 0%, var(--crm-accent) 100%);
    color: #fff;
    box-shadow: none;
}

/* Kanban columns on a light canvas want a tint, not a border. */
.crm-kanban-column {
    background: var(--crm-surface-3);
    border-color: transparent;
}

.crm-kanban-card {
    border-color: transparent;
    box-shadow: var(--crm-shadow-xs);
    border-radius: var(--crm-radius);
}

.crm-kanban-card:hover {
    border-color: transparent;
    box-shadow: var(--crm-shadow-sm);
}

.crm-kanban-owner {
    background: var(--crm-accent-soft);
    color: var(--crm-accent-ink);
}

/* Drawer and dropdown corners follow the card radius. */
.crm-drawer-panel,
.dropdown-menu,
.modal-content {
    border-radius: var(--crm-radius-lg);
}

.crm-drawer-panel {
    border-left: 0;
}

/* Unit tiles keep their status border but pick up the softer corner. */
.crm-unit-tile {
    border-radius: var(--crm-radius-sm);
}

/* ==========================================================================
   Live updates
   ==========================================================================
   The toast host and the connection indicator. Both are quiet by design: a
   realtime feature that draws attention to itself is a realtime feature people
   turn off.
   -------------------------------------------------------------------------- */

.crm-toast-host {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1090;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: min(22rem, calc(100vw - 2rem));
}

.crm-toast-host .toast {
    background: var(--crm-surface);
    color: var(--crm-ink);
    border: 1px solid var(--crm-border);
    box-shadow: var(--crm-shadow-md);
}

/* A dot, not a banner. Grey when nothing is connected, which is the honest
   default rather than an optimistic green. */
.crm-live-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--crm-border);
    vertical-align: middle;
}

.crm-live-dot[data-state="live"] {
    background: var(--crm-success);
}

.crm-live-dot[data-state="connecting"] {
    background: var(--crm-warning);
}

.crm-live-dot[data-state="offline"] {
    background: var(--crm-ink-2);
    opacity: 0.4;
}

/* ==========================================================================
   Sales CRM dashboard
   ==========================================================================
   The dashboard is the first screen of the working day, so the hierarchy is
   deliberate: four numbers large enough to read without stopping, a rank of
   smaller ones below them, and then the panels that need actual attention.
   -------------------------------------------------------------------------- */

.crm-kpi {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    height: 100%;
    padding: 1.15rem 1.25rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
    transition: border-color var(--crm-fast) var(--crm-ease),
                box-shadow var(--crm-fast) var(--crm-ease);
}

.crm-kpi:hover {
    box-shadow: var(--crm-shadow-md);
}

.crm-kpi-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--crm-muted);
}

.crm-kpi-value {
    font-size: 2rem;
    font-weight: 680;
    line-height: 1.05;
    letter-spacing: -0.03em;
    color: var(--crm-ink);
    font-variant-numeric: tabular-nums;
}

.crm-kpi-foot {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.78rem;
    color: var(--crm-muted);
}

/* Direction is carried by the arrow as well as the colour, so the meaning
   survives a monochrome print and a red-green colour deficiency. */
.crm-delta {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.crm-delta-up {
    color: var(--crm-success);
    background: color-mix(in srgb, var(--crm-success) 12%, transparent);
}

.crm-delta-down {
    color: var(--crm-danger);
    background: color-mix(in srgb, var(--crm-danger) 12%, transparent);
}

/* The icon sits above the number in the small tiles, muted, so it labels the
   tile without competing with the figure. */
.crm-stat-icon {
    font-size: 0.95rem;
    line-height: 1;
    color: var(--crm-stat-accent, var(--crm-accent));
    opacity: 0.75;
}

/* ---------------------------------------------------------------- funnel */

.crm-funnel {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.crm-funnel-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.3rem;
}

.crm-funnel-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--crm-ink);
}

.crm-funnel-count {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--crm-ink);
    font-variant-numeric: tabular-nums;
}

/* The step-to-step rate, not the share of the total: "40% of qualified leads
   were won" is the question a sales head actually asks. */
.crm-funnel-rate {
    margin-left: 0.4rem;
    font-weight: 500;
    color: var(--crm-muted);
}

.crm-funnel-bar {
    height: 0.6rem;
    border-radius: 999px;
    background: var(--crm-canvas);
    overflow: hidden;
}

.crm-funnel-bar > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg,
        var(--crm-accent) 0%,
        color-mix(in srgb, var(--crm-accent) 65%, var(--crm-info)) 100%);
    transition: width 400ms var(--crm-ease);
}

.crm-funnel-step:last-child .crm-funnel-bar > span {
    background: linear-gradient(90deg,
        var(--crm-success) 0%,
        color-mix(in srgb, var(--crm-success) 70%, var(--crm-accent)) 100%);
}

/* ---------------------------------------------------------------- agenda */

.crm-agenda {
    list-style: none;
    margin: 0;
    padding: 0;
}

.crm-agenda-item {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--crm-border);
}

.crm-agenda-item:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

.crm-agenda-when {
    flex: 0 0 2.75rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--crm-muted);
    font-variant-numeric: tabular-nums;
    padding-top: 0.05rem;
}

.crm-agenda-item.is-overdue .crm-agenda-when {
    color: var(--crm-danger);
}

.crm-agenda-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.crm-agenda-lead {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--crm-ink);
    text-decoration: none;
}

.crm-agenda-lead:hover {
    color: var(--crm-accent);
}

/* One line, clipped. A follow-up subject can be a paragraph, and a panel that
   grows to fit the longest one stops being scannable. */
.crm-agenda-subject {
    font-size: 0.78rem;
    color: var(--crm-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-agenda-flag {
    flex: 0 0 auto;
    font-size: 0.7rem;
}

/* ------------------------------------------------------------ mini stats */

.crm-mini-stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    padding: 0.7rem 0.4rem;
    background: var(--crm-canvas);
    border-radius: var(--crm-radius);
}

.crm-mini-value {
    font-size: 1.4rem;
    font-weight: 660;
    line-height: 1.1;
    color: var(--crm-ink);
    font-variant-numeric: tabular-nums;
}

.crm-mini-label {
    font-size: 0.72rem;
    color: var(--crm-muted);
}

/* ----------------------------------------------------------- owner rows */

.crm-owner-row {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--crm-border);
}

.crm-owner-row:last-child {
    border-bottom: 0;
}

.crm-owner-name {
    flex: 0 0 auto;
    max-width: 8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Takes the leftover width, so the bars line up regardless of name length. */
.crm-owner-bar {
    flex: 1 1 auto;
    height: 0.35rem;
    border-radius: 999px;
    background: var(--crm-canvas);
    overflow: hidden;
}

.crm-owner-bar > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--crm-accent);
    opacity: 0.75;
}

@media (max-width: 575.98px) {
    .crm-kpi-value {
        font-size: 1.7rem;
    }

    .crm-owner-name {
        max-width: 6rem;
    }
}

/* ==========================================================================
   Notifications
   ==========================================================================
   The bell, its dropdown, and the full list. One set of row styles serves both
   surfaces, because they render the same partial shapes and two sets would
   drift the moment a new notification type appeared.
   -------------------------------------------------------------------------- */

.crm-notify {
    position: relative;
}

.crm-notify-toggle {
    position: relative;
}

/* A count, not a dot: "3" tells somebody whether to look now or later. Hidden
   entirely at zero, so a quiet bell looks quiet. */
.crm-notify-badge {
    position: absolute;
    top: 0.15rem;
    right: 0.1rem;
    min-width: 1rem;
    padding: 0 0.25rem;
    border-radius: 999px;
    background: var(--crm-danger);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    line-height: 1rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 0 0 2px var(--crm-surface);
}

.crm-note-menu {
    width: min(24rem, calc(100vw - 2rem));
    max-height: min(28rem, 70vh);
    overflow-y: auto;
    padding: 0;
}

.crm-note-menu-head,
.crm-note-menu-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--crm-muted);
}

/* Sticky so "mark all read" stays reachable in a long list without scrolling
   back up for it. */
.crm-note-menu-head {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--crm-surface);
    border-bottom: 1px solid var(--crm-border);
}

.crm-note-menu-foot {
    justify-content: center;
    border-top: 1px solid var(--crm-border);
}

.crm-note-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 1.5rem 1rem;
    margin: 0;
    font-size: 0.83rem;
    color: var(--crm-muted);
}

.crm-note-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.crm-note {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.7rem 0.9rem;
    border-bottom: 1px solid var(--crm-border);
}

.crm-note:last-child {
    border-bottom: 0;
}

/* Unread is a tinted row plus a bar on the leading edge. Two signals, because
   a tint alone disappears on a low-contrast screen. */
.crm-note.is-unread {
    background: var(--crm-accent-soft);
    box-shadow: inset 3px 0 0 0 var(--crm-accent);
}

.crm-note-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    border-radius: 50%;
    background: var(--crm-canvas);
    color: var(--crm-muted);
}

.crm-note-danger { color: var(--crm-danger); background: color-mix(in srgb, var(--crm-danger) 12%, transparent); }
.crm-note-warning { color: var(--crm-warning); background: color-mix(in srgb, var(--crm-warning) 14%, transparent); }
.crm-note-accent { color: var(--crm-accent); background: var(--crm-accent-soft-2); }
.crm-note-muted { color: var(--crm-muted); }

.crm-note-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.crm-note-title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--crm-ink);
    text-decoration: none;
    line-height: 1.3;
}

.crm-note-title:hover {
    color: var(--crm-accent);
}

/* Two lines then clipped. A notification body can be a paragraph, and a
   dropdown that grows to fit the longest one stops being scannable. */
.crm-note-text {
    font-size: 0.78rem;
    color: var(--crm-muted);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.crm-note-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
    font-size: 0.72rem;
    color: var(--crm-muted);
}

.crm-note-time {
    flex: 0 0 auto;
    font-size: 0.72rem;
    color: var(--crm-faint);
    white-space: nowrap;
    padding-top: 0.1rem;
}

.crm-note-actions {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.2rem;
}

/* The full-page list gets more room than the dropdown. */
.crm-note-list-page .crm-note {
    padding: 0.9rem 0.4rem;
}

.crm-note-list-page .crm-note.is-unread {
    border-radius: var(--crm-radius-sm);
    padding-left: 0.75rem;
}

/* ==========================================================================
   Conversion: site visit calendar, quotation panel, approval timeline
   ========================================================================== */

.crm-calendar {
    --crm-calendar-gap: 1px;
}

.crm-calendar-head,
.crm-calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--crm-calendar-gap);
}

.crm-calendar-weekday {
    padding: 0.4rem 0.5rem;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--crm-muted);
}

.crm-calendar-grid {
    background: var(--crm-border);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm);
    overflow: hidden;
}

/* Six fixed rows. A month whose visits all land in one week should not make
   that week three times as tall as the others. */
.crm-calendar-day {
    background: var(--crm-surface);
    min-height: 6.5rem;
    padding: 0.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.crm-calendar-day--muted {
    background: var(--crm-surface-muted, rgba(0, 0, 0, 0.02));
}

.crm-calendar-day--muted .crm-calendar-date {
    color: var(--crm-faint);
}

.crm-calendar-day--today {
    box-shadow: inset 0 0 0 2px var(--crm-accent);
}

.crm-calendar-date {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--crm-muted);
}

.crm-calendar-visit {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    padding: 0.15rem 0.35rem;
    border-radius: var(--crm-radius-sm);
    font-size: 0.72rem;
    text-decoration: none;
    color: inherit;
    overflow: hidden;
}

.crm-calendar-visit:hover {
    filter: brightness(0.96);
}

.crm-calendar-time {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.crm-calendar-lead {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-calendar-more {
    font-size: 0.7rem;
    color: var(--crm-muted);
    text-decoration: none;
}

@media (max-width: 767.98px) {
    .crm-calendar-day {
        min-height: 4.5rem;
    }

    .crm-calendar-lead {
        display: none;
    }
}

/* The pricing panel follows the form down a long page, so the total is always
   in view while the components are being typed. */
@media (min-width: 992px) {
    .crm-quote-summary {
        position: sticky;
        top: 1rem;
    }
}

.crm-quote-table td,
.crm-quote-table th {
    padding: 0.4rem 0.5rem;
}

.crm-quote-table td:last-child,
.crm-quote-table th:last-child {
    font-variant-numeric: tabular-nums;
}

/* One row per approval level, with the connecting line drawn between the
   markers rather than around them. */
.crm-approval-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
}

.crm-approval-step {
    position: relative;
    display: flex;
    gap: 0.75rem;
    padding-bottom: 1rem;
}

.crm-approval-step:last-child {
    padding-bottom: 0;
}

.crm-approval-step::before {
    content: "";
    position: absolute;
    left: 0.85rem;
    top: 1.75rem;
    bottom: 0;
    width: 2px;
    background: var(--crm-border);
}

.crm-approval-step:last-child::before {
    display: none;
}

.crm-approval-marker {
    flex: 0 0 auto;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.78rem;
    font-weight: 600;
    background: var(--crm-surface);
    border: 2px solid var(--crm-border);
    color: var(--crm-muted);
    z-index: 1;
}

.crm-approval-body {
    flex: 1 1 auto;
    min-width: 0;
}

.crm-approval-step--done .crm-approval-marker {
    border-color: var(--bs-success, #198754);
    color: var(--bs-success, #198754);
}

.crm-approval-step--pending .crm-approval-marker {
    border-color: var(--bs-warning, #ffc107);
    color: var(--bs-warning, #ffc107);
}

.crm-approval-step--rejected .crm-approval-marker {
    border-color: var(--bs-danger, #dc3545);
    color: var(--bs-danger, #dc3545);
}

.crm-approval-step--moot {
    opacity: 0.6;
}

/* ==========================================================================
   AI: the lead panel, the assistant modals, the provider cards
   ========================================================================== */

/* A tinted edge rather than a heavier border. The panel sits above the lead's
   own facts and should read as commentary on them, not as another record. */
.crm-ai-panel {
    border-left: 3px solid color-mix(in srgb, var(--crm-accent) 55%, transparent);
}

.crm-ai-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 1.5rem 1rem;
    text-align: center;
    color: var(--crm-muted);
}

.crm-ai-empty p {
    max-width: 44ch;
    font-size: 0.85rem;
    margin: 0;
}

.crm-ai-stat {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    height: 100%;
    padding: 0.65rem 0.75rem;
    background: var(--crm-canvas);
    border-radius: var(--crm-radius-sm);
}

.crm-ai-stat-value {
    font-size: 1.5rem;
    font-weight: 660;
    line-height: 1.1;
    color: var(--crm-ink);
    font-variant-numeric: tabular-nums;
}

.crm-ai-stat-value small {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--crm-muted);
}

.crm-ai-stat-label {
    font-size: 0.72rem;
    color: var(--crm-muted);
}

/* Bands, not a gradient: a salesperson reads hot / warm / cold, and a continuous
   ramp makes 61 and 64 look meaningfully different when they are not. */
.crm-ai-score--hot {
    box-shadow: inset 3px 0 0 var(--crm-danger);
}

.crm-ai-score--warm {
    box-shadow: inset 3px 0 0 var(--crm-warning, #f0a020);
}

.crm-ai-score--cool {
    box-shadow: inset 3px 0 0 var(--crm-info, #3b9edb);
}

.crm-ai-score--cold {
    box-shadow: inset 3px 0 0 var(--crm-border);
}

/* rule + AI = final, shown as arithmetic. The point is that a salesperson can
   see which half moved. */
.crm-ai-scores {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 0.75rem;
    background: var(--crm-canvas);
    border-radius: var(--crm-radius-sm);
    font-size: 0.82rem;
    color: var(--crm-muted);
}

.crm-ai-scores strong {
    color: var(--crm-ink);
    font-variant-numeric: tabular-nums;
}

.crm-ai-scores-sep {
    color: var(--crm-faint);
}

.crm-ai-action {
    padding: 0.65rem 0.85rem;
    background: color-mix(in srgb, var(--crm-accent) 7%, transparent);
    border-radius: var(--crm-radius-sm);
}

.crm-ai-action-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--crm-muted);
}

.crm-ai-list-label {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--crm-muted);
}

.crm-ai-list {
    list-style: none;
    margin: 0.35rem 0 0;
    padding: 0;
    font-size: 0.85rem;
}

.crm-ai-list li {
    position: relative;
    padding-left: 1.15rem;
    margin-bottom: 0.2rem;
}

/* The mark carries the meaning as well as the colour, so it survives a
   monochrome print and a red-green colour deficiency. */
.crm-ai-list--good li::before {
    content: "\2713";
    position: absolute;
    left: 0;
    color: var(--crm-success);
}

.crm-ai-list--bad li::before {
    content: "\26A0";
    position: absolute;
    left: 0;
    color: var(--crm-warning, #f0a020);
}

.crm-ai-objection {
    padding: 0.55rem 0.7rem;
    background: var(--crm-canvas);
    border-radius: var(--crm-radius-sm);
}

.crm-ai-busy {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
    font-size: 0.85rem;
    color: var(--crm-muted);
}

.crm-ai-draft {
    padding-top: 0.75rem;
    border-top: 1px solid var(--crm-border);
}

.crm-ai-provider-card {
    display: flex;
    flex-direction: column;
}

.crm-ai-provider-row {
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--crm-border);
}

.crm-ai-provider-row:last-child {
    border-bottom: none;
}

/* =============================================================================
   17. Permission tree (role rights)
   ========================================================================== */

/* Depth is carried by an indent and a rule down the left of each body, so the
   nesting stays readable when a branch is collapsed and the caret is all there is
   to go on. Everything below is token-driven, so dark mode needs no second block. */

.perm-tree__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    padding-bottom: 0.9rem;
    margin-bottom: 0.35rem;
    border-bottom: 1px solid var(--crm-border);
}

.perm-tree__search {
    flex: 1 1 16rem;
    min-width: 12rem;
}

.perm-tree__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

.perm-tree__summary {
    color: var(--crm-muted);
    font-size: 0.82rem;
    white-space: nowrap;
    margin-left: auto;
}

.perm-tree__bulk {
    min-width: 15rem;
    padding: 0.35rem;
}

.perm-tree__bulk-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.1rem 0.5rem;
}

.perm-tree__bulk-verb {
    font-size: 0.85rem;
    font-weight: 560;
}

.perm-tree__bulk-buttons .btn-link {
    padding: 0.1rem 0.3rem;
    font-size: 0.78rem;
    text-decoration: none;
}

.perm-tree__empty {
    color: var(--crm-muted);
    font-size: 0.88rem;
    padding: 1.25rem 0.25rem;
    margin: 0;
}

/* ---------- nodes ---------- */

.perm-node--group {
    border-top: 1px solid var(--crm-border-soft);
    padding-top: 0.15rem;
}

.perm-node--group:first-of-type {
    border-top: none;
}

.perm-node__head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.35rem;
    border-radius: var(--crm-radius-sm);
}

.perm-node__head:hover {
    background: var(--crm-surface-3);
}

.perm-node__toggle {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    border: none;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-faint);
    cursor: pointer;
}

.perm-node__toggle:hover {
    color: var(--crm-ink);
    background: var(--crm-surface-2);
}

/* A CSS caret rather than an icon font: one less asset, and it rotates cleanly. */
.perm-node__caret {
    width: 0;
    height: 0;
    border-left: 5px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transform: rotate(90deg);
    transition: transform 0.14s ease;
}

.perm-node.is-collapsed > .perm-node__head .perm-node__caret {
    transform: rotate(0deg);
}

.perm-node__check {
    margin: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

.perm-node__check .form-check-input {
    margin: 0;
    float: none;
}

.perm-node__label {
    cursor: pointer;
    line-height: 1.2;
}

.perm-node--group > .perm-node__head .perm-node__label {
    font-size: 0.95rem;
    font-weight: 640;
    letter-spacing: -0.01em;
}

.perm-node--module > .perm-node__head .perm-node__label {
    font-size: 0.875rem;
    font-weight: 560;
}

/* The count is the whole point of a collapsed branch: it says how much is granted
   without making anyone expand it to find out. */
.perm-node__count {
    margin-left: auto;
    font-size: 0.74rem;
    font-variant-numeric: tabular-nums;
    color: var(--crm-muted);
    background: var(--crm-surface-3);
    border-radius: 999px;
    padding: 0.08rem 0.5rem;
}

.perm-node__head.is-partial .perm-node__count {
    color: var(--crm-warning);
    background: var(--crm-warning-soft);
}

.perm-node__head.is-full .perm-node__count {
    color: var(--crm-success);
    background: var(--crm-success-soft);
}

.perm-node__body {
    padding-left: 1.55rem;
    margin-left: 0.35rem;
    border-left: 1px solid var(--crm-border-soft);
}

.perm-node--module {
    padding: 0.05rem 0;
}

/* ---------- leaves ---------- */

.perm-node__leaves {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.1rem 1rem;
    padding-top: 0.15rem;
    padding-bottom: 0.4rem;
}

.perm-leaf {
    margin: 0;
    padding: 0.28rem 0.4rem;
    border-radius: var(--crm-radius-sm);
    min-height: 0;
}

.perm-leaf:hover {
    background: var(--crm-surface-3);
}

.perm-leaf .form-check-input {
    margin-top: 0.2rem;
}

.perm-leaf .form-check-label {
    cursor: pointer;
    display: block;
}

.perm-leaf__name {
    display: block;
    font-size: 0.845rem;
    line-height: 1.3;
}

.perm-leaf__hint {
    display: block;
    font-size: 0.745rem;
    line-height: 1.35;
    color: var(--crm-muted);
}

@media (max-width: 575.98px) {
    .perm-tree__summary {
        margin-left: 0;
        width: 100%;
    }

    .perm-node__body {
        padding-left: 0.9rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .perm-node__caret {
        transition: none;
    }
}
