/* ============================================================
   KUMO — the portal's design tokens
   ------------------------------------------------------------
   Single source of truth for colour, type, radius, spacing and
   motion. Loaded LAST in <head> so these definitions win over the
   legacy :root block in includes/header.php, and every rule in the
   portal that already says var(--gray-200) or var(--radius-lg)
   picks the new value up without being touched.

   THE THREE RULES THIS SYSTEM IS BUILT ON
   1. Edges are box-shadow rings, not borders. A 1px spread shadow
      never affects layout and layers with a whisper of lift.
   2. Two greys, three surfaces: canvas #FBFBFB, base #FFFFFF,
      recessed #F3F3F3. Contrast comes from the ring, not shadows.
   3. Small type, tight tracking, generous line-height. Body is
      14px with -0.01em tracking; chrome drops to 13px/12px at 500.

   BRAND SUBSTITUTION
   The reference system is Cloudflare's, whose accent is #056DFF and
   whose orange is logo-only. This portal keeps its own royal blue
   (#0033a1) in every accent slot; no orange reaches a control. The
   house "light fill + dark ring" primary button is reproduced with
   the brand's own ramp: fill #1a4ec0 (7.25:1 with white text, AA
   clear at every size), ring #0033a1.
   ============================================================ */

:root {
    /* ---------- 1.1 surfaces & structure ---------- */
    --kumo-canvas:      #FBFBFB;   /* page ground, sidebar, table header row */
    --kumo-base:        #FFFFFF;   /* cards, table body cells, controls */
    --kumo-control:     #FFFFFF;   /* inputs, secondary buttons */
    --kumo-elevated:    #F8F8F8;   /* popovers, menus */
    --kumo-overlay:     #FBFBFB;   /* modal surface */
    --kumo-recessed:    #F3F3F3;   /* active nav item, inset wells */
    --kumo-tint:        #F5F5F5;   /* subtle zebra, muted block */
    --kumo-fill:        #E5E5E5;   /* switch track (off), bar track */
    --kumo-fill-hover:  #F3F3F3;
    --kumo-interact:    #D4D4D4;   /* ring on neutral filled controls */
    --kumo-contrast:    #060606;   /* inverted surface — tooltips */

    --kumo-line:        rgb(10 10 10 / 0.10);  /* the hairline ring */
    --kumo-hairline:    #E9E9E9;               /* opaque equivalent, nested rings */
    --kumo-focus:       #1a4ec0;               /* brand-derived focus ring */

    --kumo-shadow-drop: rgb(0 0 0 / 0.08);
    --kumo-shadow-edge: rgb(0 0 0 / 0.12);

    /* the two shadows this system allows */
    --kumo-ring:        0 0 0 1px var(--kumo-line);
    --kumo-raised:      0 0 0 1px var(--kumo-line), 0 1px 2px 0 rgb(0 0 0 / 0.05);
    --kumo-float:       0 0 0 1px var(--kumo-line), 0 8px 24px rgb(0 0 0 / 0.08);

    /* ---------- 1.2 text ---------- */
    --text-strong:      #0A0A0A;
    --text-default:     #171717;
    --text-subtle:      #737373;
    --text-placeholder: #A1A1A1;
    --text-inactive:    #D4D4D4;
    --text-inverse:     #F5F5F5;
    --text-link:        #193CB8;
    --text-danger:      #C10007;
    --text-success:     #006045;
    --text-warning:     #BD6500;
    --text-info:        #193CB8;

    /* ---------- 1.3 accent & status ---------- */
    --kumo-brand:        #0033a1;   /* the portal's royal blue, not Cloudflare's */
    --kumo-brand-hover:  #002c8e;
    --kumo-primary-fill: #1a4ec0;   /* light fill … */
    --kumo-primary-ring: #0033a1;   /* … held by a darker ring */

    --kumo-danger:   #FB2C36;  --kumo-danger-tint:  rgb(255 226 226 / 0.42);
    --kumo-success:  #009966;  --kumo-success-tint: rgb(220 252 231 / 0.57);
    --kumo-warning:  #FA8900;  --kumo-warning-tint: rgb(255 232 148 / 0.20);
    /* #FA8900 is a signal colour, not an ink: it carries white at 2.4:1 and
       sits on its own tint at 2.2:1. These two are the readable pairings —
       -ink for text/icons ON the warning tint, -fill for a solid warning
       surface that has to carry white. */
    --kumo-warning-ink:  #A85A00;   /* 4.5:1 on --kumo-banner-warning */
    --kumo-warning-fill: #B26A00;   /* 4.2:1 under white */
    --kumo-info:     #2B7FFF;  --kumo-info-tint:    rgb(219 234 254 / 0.45);
    --kumo-banner-info:    rgb(219 234 254 / 0.70);
    --kumo-banner-warning: #FEF9C2;

    --badge-blue:#155DFC; --badge-green:#009966; --badge-red:#E7000B; --badge-orange:#B26A00;
    --badge-purple:#9810FA; --badge-teal:#00897B; --badge-neutral:#737373; --badge-inverted:#0A0A0A;

    --delta-up:   #196535;
    --delta-down: #B20F03;

    /* ---------- 1.4 typography ---------- */
    --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

    --text-xs:   12px;  --text-xs-lh:   16px;    /* badges, axis labels */
    --text-sm:   13px;  --text-sm-lh:   19.5px;  /* nav, table headers, segmented */
    --text-base: 14px;  --text-base-lh: 21px;    /* body default */
    --text-lg:   16px;  --text-lg-lh:   24px;    /* h2 */
    --text-xl:   20px;  --text-xl-lh:   28px;    /* section figures */
    --text-2xl:  24px;  --text-2xl-lh:  32px;    /* stat values, legend totals */
    --text-3xl:  30px;  --text-3xl-lh:  36px;    /* h1 */

    /* ---------- 1.5 radius, spacing, motion ---------- */
    --radius-xs: .125rem; --radius-sm: .25rem; --radius-md: .375rem;
    --radius-lg: .5rem;                        /* 8px — the default for everything */
    --radius-xl: .75rem; --radius-2xl: 1rem; --radius-3xl: 1.5rem;
    --radius-pill: 9999px;                     /* badges only */

    /* ---------- 2. shell geometry ---------- */
    --sidebar: 221px;                          /* Kumo §2.2 */
    --header:  58px;                           /* Kumo §2.1 */
    --content-max: 1400px;                     /* Kumo §2.4 */
    --content-gutter: 40px;

    --space-unit: 4px;
    --ease: cubic-bezier(.4, 0, .2, 1);
    --dur: .1s;

    /* ---------- the one documented exception ----------
       Kumo says table headers sit on canvas and carry no colour
       (§9). The Reliant Register is the deliberate exception: its
       field-name row is a dark bar, asked for by name so the column
       names read clearly above 1,600 rows of dense data. It is kept
       on purpose — do not "correct" it back to canvas without asking.
       Every other table in the portal follows the brief.            */
    --rgh-bar:        #16255c;   /* the field-name row */
    --rgh-corner:     #101b45;   /* the select-all corner */
    --rgh-hover:      #1f3273;
    --rgh-sorted:     #24398a;
    --rgh-selected:   #2f4bab;
    --rgh-filtered:   #6b4410;
    --rgh-ink:        #eaf0fb;   /* the column names themselves */
    --rgh-ink-warm:   #ffe6b8;   /* on the filtered state */
    --rgh-accent:     #ffd77a;   /* sort arrow, pinned column */

    /* ---------- the second documented exception ----------
       Kumo puts the sidebar on canvas (§2.2). This portal keeps it
       in the brand blue — asked for by name. The rail is the one
       branded surface in the product; everything inside it still
       follows the system: 34px items, 8px radius, 13px/500, and an
       active state that is a fill and nothing else. Deliberate.   */
    --sb-bg:          var(--kumo-brand);
    --sb-line:        rgb(255 255 255 / 0.12);
    --sb-ink:         #ffffff;   /* nav labels */
    --sb-ink-strong:  #ffffff;
    --sb-ink-subtle:  rgb(255 255 255 / 0.65);   /* section titles, the role line */
    --sb-icon:        #ffffff;   /* every glyph in the rail */
    --sb-hover:       rgb(255 255 255 / 0.10);
    --sb-active:      rgb(255 255 255 / 0.16);
    --sb-surface:     rgb(255 255 255 / 0.08);

    /* ---------- 5. data visualisation ---------- */
    --chart-line:      #4693FF;
    --chart-area-from: rgb(62 142 255 / 0.80);
    --chart-area-to:   rgb(62 142 255 / 0.00);
    --chart-grid:      rgb(0 0 0 / 0.10);
    --chart-axis-text: var(--text-subtle);

    /* the categorical order, in CSS — same six steps, same sequence, as
       KUMO_PALETTE in kumo-charts.js. Anything past the sixth folds into
       --chart-other rather than cycling back to blue. */
    --chart-1: #155DFC;
    --chart-2: #009966;
    --chart-3: #9810FA;
    --chart-4: #B26A00;
    --chart-5: #00897B;
    --chart-6: #E7000B;
    --chart-other: #737373;
}

/* ============================================================
   THE BRIDGE
   The portal's legacy constants, re-pointed at the tokens above.
   Nothing bypasses the system: a rule that still says
   var(--gray-200) now draws a Kumo hairline. These aliases are the
   only place old names survive; Phase 6 sweeps the call sites.
   ============================================================ */
:root {
    /* neutral ladder -> three surfaces + two greys */
    --gray-25:  var(--kumo-base);
    --gray-50:  var(--kumo-canvas);
    --gray-100: var(--kumo-recessed);
    --gray-200: var(--kumo-fill);
    --gray-300: var(--kumo-interact);
    --gray-400: var(--text-placeholder);
    --gray-500: var(--text-subtle);
    --gray-600: var(--text-subtle);
    --gray-700: var(--text-default);
    --gray-800: var(--text-default);
    --gray-900: var(--text-strong);
    --gray-950: var(--text-strong);

    /* surfaces */
    --surface:        var(--kumo-base);
    --surface-muted:  var(--kumo-canvas);
    --surface-sunken: var(--kumo-recessed);
    --hairline:        var(--kumo-line);
    --hairline-strong: var(--kumo-line);
    --ring: 0 0 0 3px rgb(26 78 192 / 0.25);
    --brand: var(--kumo-brand);

    /* Kumo has no gradient surfaces: the brand ramps flatten to the brand */
    --brand-grad:     var(--kumo-brand);
    --brand-grad-btn: var(--kumo-primary-fill);
    --brand-glow:     rgb(0 51 161 / 0.18);

    /* status ramps keep their hue but adopt the Kumo steps */
    --green-500: var(--kumo-success); --green-600: var(--kumo-success); --green-700: var(--text-success);
    --blue-500:  var(--kumo-info);    --blue-600:  var(--kumo-brand);   --blue-700:  var(--kumo-brand-hover);
    --orange-500: var(--kumo-warning); --orange-600: var(--text-warning);
    --orange-700: var(--text-warning);
    /* the 50/100 tints and the 200-400 edges: pages reached for steps the
       ramp never had, and an undefined custom property voids the whole
       declaration — a border vanishes, and `color` silently inherits its
       parent, which is how text ends up painted on its own background. */
    --blue-50:   var(--kumo-info-tint);    --blue-100: var(--kumo-banner-info);
    --blue-200:  var(--kumo-line);         --blue-300: var(--kumo-line);
    --blue-400:  var(--kumo-primary-ring);
    --green-50:  var(--kumo-success-tint); --green-100: var(--kumo-success-tint);
    --green-200: var(--kumo-line);         --green-300: var(--kumo-line);
    --green-400: var(--kumo-success);
    --orange-200: var(--kumo-line);
    --red-500: var(--kumo-primary-fill);   /* the brand ramp is this portal's blue */
    --red-600: var(--kumo-brand);
    --red-700: var(--kumo-brand-hover);

    /* radius discipline: 8px on controls and cards, 12px only on large surfaces */
    --radius-sm:  8px;
    --radius-md:  8px;
    --radius-lg:  8px;
    --radius-xl:  12px;
    --radius-2xl: 12px;

    /* shadow discipline: a ring, a ring with lift, and one float for modals.
       Nothing in this UI carries a large or coloured drop shadow. */
    --shadow-sm:    var(--kumo-ring);
    --shadow-md:    var(--kumo-raised);
    --shadow-lg:    var(--kumo-raised);
    --shadow-xl:    var(--kumo-float);
    --shadow-2xl:   var(--kumo-float);
    --shadow-inner: inset 0 1px 2px 0 rgb(0 0 0 / 0.05);

    /* motion: nothing animates longer than 150ms */
    --transition-fast:   .1s cubic-bezier(.4, 0, .2, 1);
    --transition:        .1s cubic-bezier(.4, 0, .2, 1);
    --transition-slow:   .15s cubic-bezier(.4, 0, .2, 1);
    --transition-bounce: .15s cubic-bezier(.4, 0, .2, 1);
}

/* ============================================================
   GLOBAL BASE
   ============================================================ */
html, body {
    font-family: var(--font-sans);
    font-size: var(--text-base);       /* 14px, not 16 — density is the point */
    line-height: 1.5;
    letter-spacing: -0.01em;
    color: var(--text-default);
    background: var(--kumo-canvas);
}

/* 700+ is not used anywhere in this system */
:where(h1, h2, h3, h4, h5, h6, b, strong, th) { font-weight: 600; }

/* every number that sits in a column, a card or an axis aligns */
:where(td, th, .tabular, [data-numeric]) { font-variant-numeric: tabular-nums; }

/* machine values read as machine values */
:where(code, kbd, samp, pre, .mono) { font-family: var(--font-mono); }

/* one visible focus treatment, everywhere */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--kumo-focus);
    outline-offset: 1px;
}

::selection { background: rgb(26 78 192 / 0.16); }

/* ============================================================
   DARK MODE
   The surface ladder inverts, the ring technique and every accent
   hue stay. Gated on an explicit choice and on the OS setting.
   ============================================================ */
:root[data-theme="dark"] {
    --kumo-canvas:#0B0B0B; --kumo-base:#0F0F0F; --kumo-control:#0F0F0F;
    --kumo-elevated:#171717; --kumo-overlay:#0F0F0F; --kumo-recessed:#1F1F1F;
    --kumo-tint:#171717; --kumo-fill:#262626; --kumo-fill-hover:#1F1F1F;
    --kumo-interact:#404040; --kumo-line: rgb(255 255 255 / 0.10); --kumo-hairline:#262626;
    --text-default:#EDEDED; --text-strong:#FAFAFA; --text-subtle:#A1A1A1;
    --text-placeholder:#737373; --text-inactive:#404040; --text-link:#82B6FF;
}
/* Not gated on prefers-color-scheme yet, deliberately: the portal's
   surfaces are still hardcoded #fff in 52 files, so honouring the OS
   setting today would produce white cards with light text. Wire the
   media query up at the end of the sweep, when the surfaces come from
   tokens and the inversion is real. */

/* ============================================================
   DENSITY — one set of metrics for the whole portal

   Pages grew their own sizes over time: page titles landed at 20,
   24 and 30px; stat values at 20 and 30; table cells anywhere from
   8px to 14px of padding; filter controls from 28px to 44px tall.
   Read one after another the portal felt like several products.

   This block states the one answer for each. It lives here rather
   than in the pages because kumo.css is linked AFTER every page's
   own <style> — so these win on equal specificity, and a page that
   wants a genuine exception raises its specificity and says so.
   ============================================================ */

/* ---------- tables: 10px rows, not 14 ---------- */
.mab-table th, .mal-table th, .pa-table th, .rl-table th, .vb-table th { padding: 9px 12px; }
.mab-table td, .mal-table td, .pa-table td, .rl-table td, .vb-table td { padding: 10px 12px; }

/* ---------- filter controls: the system's 34px, not 40-44 ----------
   padding-block only: these selects carry a chevron positioned off
   their right padding, so the horizontal values stay as the page set
   them and just the vertical comes back to the scale. */
.mab-filters select, .mab-filters input,
.mal-filters select, .mal-filters input,
.rl-filters select,
.vb-search input, .vb-filter-select,
.status-control select,
.status-select, .assign-select {
    padding-block: 7px;
    line-height: 18px;
}

/* ---------- page titles: 20px, one size ---------- */
.vb-hero h1, .dash-hero-banner h1, .hero-inner .hero-left h1 {
    font-size: var(--text-xl);
    line-height: var(--text-xl-lh);
}

/* ---------- stat values: 20px, one size ----------
   30px numbers next to 13px labels read as a slide, not a dashboard. */
.stat-value,
.vb-stat-card .stat-value {          /* the page states this at 0,2,0 — match it */
    font-size: var(--text-xl);
    line-height: var(--text-xl-lh);
}

/* ---------- stat cards: less air around the number ---------- */
.vb-stat-card .stat-foot { margin-top: 10px; padding-top: 10px; }

/* ---------- table rows: one line a cell ----------
   Rows had grown into stacked mini-cards — a date over a time, a name over a
   company, a phone over an email, an address wrapping to two lines and a
   location chip wrapping under it. That is ~110px a row, so twenty records
   became a page of scrolling. Every cell now holds its line and truncates;
   the full value stays available on hover and on the record's own page. */
.vb-table td, .rl-table td, .mab-table td, .mal-table td, .leads-table td {
    max-width: 260px;
}
.vb-table td .lead-name, .vb-table td .lead-sub,
.vb-table td .lead-email, .vb-table td .lead-phone,
.rl-table td .lead-name, .rl-table td .lead-sub,
.rl-table td .lead-email, .rl-table td .lead-phone {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    max-width: 100%;
}
/* the address was explicitly clamped to two lines — one is enough in a row */
.address-cell .addr-text {
    -webkit-line-clamp: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* company and other single-value text cells: one line, ellipsis, and a
   width they can actually use */
.rl-table td .company-cell, .rl-table td .lead-company,
.leads-table td .company-cell, .leads-table td .lead-company,
.vb-table td .company-cell {
    display: block;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* chips sat below their cell text and pushed the row taller still */
.lead-chip, .address-cell .lead-chip {
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ============================================================
   MOBILE — the same product, at arm's length
   Below 768px the rail is a drawer and the content column is the
   whole screen. Wide surfaces scroll on their own axis so the page
   body never does, and targets stay at 40px+ where a thumb lands.
   ============================================================ */
@media (max-width: 768px) {
    /* nothing but a deliberately scrollable strip may exceed the viewport */
    body { overflow-x: hidden; }
    .content { padding: 12px; }

    /* every table gets its own scroll axis rather than stretching the page */
    .table-wrapper, .table-wrap, .vb-table-wrap, .rl-table-wrap,
    .mab-table-wrap, .mal-table-wrap {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }
    .vb-table, .rl-table, .mab-table, .mal-table, .leads-table, .pa-table {
        min-width: 720px;                 /* keeps columns legible while scrolling */
    }

    /* stat grids: two up, not six squeezed */
    .kpi-grid { --kpi-cols: 2 !important; gap: 10px; }
    .kpi-card { padding: 12px; }

    /* filter rows stack instead of overflowing sideways */
    .vb-filters, .rl-filters, .mab-filters, .mal-filters, .premium-filters {
        flex-wrap: wrap;
        gap: 8px;
    }
    .vb-search, .vb-search input { width: 100%; min-width: 0; }
    .vb-filter-select, .rl-filters select,
    .mab-filters select, .mab-filters input,
    .mal-filters select, .mal-filters input {
        flex: 1 1 46%;
        min-width: 0;
    }

    /* WCAG 2.1 target size and the audit's own gate is 44px; the desktop
       32px control is not reachable with a thumb */
    .btn, .pa-btn, .vb-tool-btn, .rg-chip-btn,
    .pv-btn, .lx-pg, .dash-tab, .filter-select, .filter-date,
    .vb-filter-select, .status-select, .assign-select,
    .btn-icon, .file-action, .topbar-btn { min-height: 44px; }
    /* icon-only controls need the width too, not just the height */
    .btn-icon, .file-action, .topbar-btn, .menu-toggle, .header-btn { min-width: 44px; }
    .pa-action-row { width: 100%; }
    .pa-action-row .pa-btn { flex: 1 1 auto; justify-content: center; }

    /* the credit bar centres rather than splitting across a narrow column */
    .app-footer { justify-content: center; text-align: center; gap: 10px; padding: 12px 16px; }
}

@media (max-width: 480px) {
    .kpi-grid { --kpi-cols: 1 !important; }
    .content { padding: 10px; }
    .vb-filter-select, .rl-filters select,
    .mab-filters select, .mab-filters input,
    .mal-filters select, .mal-filters input { flex: 1 1 100%; }
}

/* ============================================================
   GLASS — translucency on the chrome that floats, and nowhere else

   Kumo is a flat system by choice, so this is applied narrowly: the
   surfaces that sit ON TOP of scrolling content (the sticky header,
   sticky table heads, modal backdrops, the footer bar) take a blur
   and a translucent ground, which gives depth as the page moves.
   Cards and text surfaces stay opaque — glass under body copy costs
   contrast and buys nothing.

   Everything is inside @supports: where backdrop-filter is missing
   the opaque values above still stand, so nothing turns transparent
   over content it cannot be read against.
   ============================================================ */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {

    /* the app header — the one surface every page scrolls beneath */
    .header {
        background: rgb(255 255 255 / .72);
        -webkit-backdrop-filter: saturate(180%) blur(16px);
        backdrop-filter: saturate(180%) blur(16px);
        border-bottom-color: rgb(10 10 10 / .08);
    }

    /* sticky column heads ride over their own rows */
    .vb-table thead, .leads-table thead {
        background: rgb(250 250 250 / .82);
        -webkit-backdrop-filter: saturate(180%) blur(12px);
        backdrop-filter: saturate(180%) blur(12px);
    }

    /* modal grounds: dim and defocus what is behind rather than hiding it */
    .modal-bg, .vs-modal-bg, .vr-modal-bg, .rm-overlay,
    .rl-overlay, .rg-modal-bg, .pdf-modal-overlay, .pa-modal-bg {
        background: rgb(15 18 26 / .40);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
    }

    /* the drawer's backdrop on a phone */
    .sidebar-overlay {
        -webkit-backdrop-filter: blur(4px);
        backdrop-filter: blur(4px);
    }

    /* the credit bar closes the page on the same material as the header */
    .app-footer {
        background: rgb(255 255 255 / .70);
        -webkit-backdrop-filter: saturate(180%) blur(14px);
        backdrop-filter: saturate(180%) blur(14px);
    }

    :root[data-theme="dark"] .header,
    :root[data-theme="dark"] .app-footer { background: rgb(15 15 15 / .72); }
    :root[data-theme="dark"] .vb-table thead,
    :root[data-theme="dark"] .leads-table thead { background: rgb(23 23 23 / .82); }
}

/* a blur under a moving page is expensive on low-power devices, and the
   effect is motion-derived anyway — drop it when motion is unwelcome */
@media (prefers-reduced-motion: reduce) {
    .header, .app-footer,
    .vb-table thead, .leads-table thead {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* ============================================================
   MOTION — things that open, arrive

   A panel that appears fully formed reads as a repaint; the same
   panel scaled up over 140ms reads as an object that came from the
   control you pressed. Entrances only — nothing loops, nothing
   animates on exit (a dismissal should feel instant), and the whole
   layer is off under prefers-reduced-motion.
   ============================================================ */
@keyframes kumoFade  { from { opacity: 0 } to { opacity: 1 } }
@keyframes kumoPanel {
    from { opacity: 0; transform: translateY(8px) scale(.97) }
    to   { opacity: 1; transform: none }
}
@keyframes kumoPop {
    from { opacity: 0; transform: translateY(-4px) scale(.98) }
    to   { opacity: 1; transform: none }
}
@keyframes kumoRise {
    from { opacity: 0; transform: translateY(6px) }
    to   { opacity: 1; transform: none }
}

/* the ground fades, the panel on top of it comes forward */
.modal-bg.open, .pa-modal-bg.show, .vs-modal-bg.show, .vr-modal-bg.show,
.rm-overlay.open, .pdf-modal-overlay.active, .rg-modal-bg:not([hidden]) {
    animation: kumoFade .14s var(--ease) both;
}
.modal-bg.open .modal, .pa-modal-bg.show .pa-modal,
.vs-modal-bg.show .vs-modal, .vr-modal-bg.show .vr-modal,
.rm-overlay.open .rm-modal, .rg-modal-bg:not([hidden]) .rg-modal {
    animation: kumoPanel .16s var(--ease) both;
}

/* menus and popovers pop from their trigger */
.header-user.open .header-user-menu,
.notif-panel.open, .rg-pop:not([hidden]), .rg-menu:not([hidden]) {
    animation: kumoPop .12s var(--ease) both;
}

/* the phone drawer and its backdrop */
.sidebar-overlay.open { animation: kumoFade .16s var(--ease) both; }

/* a page's own cards settle in, briefly and once */
.kpi-card, .dash-card, .premium-table-card, .vb-stat-card {
    animation: kumoRise .18s var(--ease) both;
}
.kpi-grid .kpi-card:nth-child(2) { animation-delay: .02s }
.kpi-grid .kpi-card:nth-child(3) { animation-delay: .04s }
.kpi-grid .kpi-card:nth-child(4) { animation-delay: .06s }
.kpi-grid .kpi-card:nth-child(5) { animation-delay: .08s }
.kpi-grid .kpi-card:nth-child(6) { animation-delay: .10s }
.kpi-grid .kpi-card:nth-child(7) { animation-delay: .12s }
.kpi-grid .kpi-card:nth-child(8) { animation-delay: .14s }

@media (prefers-reduced-motion: reduce) {
    .modal-bg.open, .pa-modal-bg.show, .vs-modal-bg.show, .vr-modal-bg.show,
    .rm-overlay.open, .pdf-modal-overlay.active, .rg-modal-bg:not([hidden]),
    .modal-bg.open .modal, .pa-modal-bg.show .pa-modal,
    .vs-modal-bg.show .vs-modal, .vr-modal-bg.show .vr-modal,
    .rm-overlay.open .rm-modal, .rg-modal-bg:not([hidden]) .rg-modal,
    .header-user.open .header-user-menu, .notif-panel.open,
    .rg-pop:not([hidden]), .rg-menu:not([hidden]), .sidebar-overlay.open,
    .kpi-card, .dash-card, .premium-table-card, .vb-stat-card {
        animation: none !important;
    }
}

/* ============================================================
   ACCESSIBILITY — one focus treatment, everywhere

   The base sheet has a :where() focus rule, which carries zero
   specificity and loses to every page-level `outline: none`. These
   are stated at real specificity so a focus ring actually survives.
   ============================================================ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="tab"]:focus-visible {
    outline: 2px solid var(--kumo-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}
/* pages that kill the outline must still show focus */
.btn:focus-visible, .rg-chip-btn:focus-visible, .dash-tab:focus-visible,
.pa-btn:focus-visible, .lx-pg:focus-visible, .nav-item:focus-visible {
    outline: 2px solid var(--kumo-focus);
    outline-offset: 2px;
}
.nav-item:focus-visible { outline-color: #fff; }

/* Skip link — the first tab stop on every page, invisible until focused */
.skip-link {
    position: absolute;
    left: 8px; top: -60px;
    z-index: 200;
    display: inline-flex; align-items: center;
    height: 36px; padding: 0 14px;
    border-radius: var(--radius-lg);
    background: var(--kumo-brand); color: #fff;
    font-size: var(--text-sm); font-weight: 600; text-decoration: none;
    transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: 8px; }

/* a target for it, and for "back to top" */
.main:focus { outline: none; }

/* ============================================================
   OVERFLOW — the page never scrolls sideways; wide things do

   Body-level horizontal scroll came from text children of flex and
   grid containers refusing to shrink below their content width.
   min-width:0 is the fix, and it has to be stated because the
   initial value for a flex item is auto.
   ============================================================ */
.card, .card-head, .card-body,
.dash-card, .dash-card-head, .dash-card-body,
.section-card, .sidebar-section,
.premium-table-card, .stat-card, .kpi-card {
    min-width: 0;
}
.chart-grid > *, .dash-grid > *, .detail-grid > *,
.kpi-grid > *, .premium-stats-grid > * { min-width: 0; }

/* ============================================================
   TABLES — identifiers and dates never break across lines
   ============================================================ */
/* break-word, NOT anywhere: `anywhere` also lets a column contribute its
   narrowest possible intrinsic width, which collapsed the Company column to
   one character and stacked "Move homes Real Estate Brokers LLC" down eleven
   lines. break-word wraps without touching intrinsic sizing. */
.pa-table td, .vb-table td, .rl-table td, .leads-table td,
.mab-table td, .mal-table td, .premium-table td {
    overflow-wrap: break-word;
    min-width: 96px;                  /* no column may collapse to a sliver */
}
/* … but a lead number, an agent code, a date or a figure may not */
.lead-number, .lead-no, .lead-date, .pa-lead-no, .font-mono,
[class*="-ref"], [class*="-number"], [class*="-code"],
td .amount, td .money, .tabular {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ============================================================
   PRINT — a record or a list should print as a document
   ============================================================ */
@media print {
    .sidebar, .header, .sidebar-overlay, .menu-toggle,
    .dash-tabs, .lx-pager, .date-filter-section,
    .btn, .pa-action-row, .quick-actions, .notif-panel { display: none !important; }

    .main { margin-left: 0 !important; width: 100% !important; max-width: 100% !important; }
    .content { padding: 0 !important; max-width: none !important; }
    .app-footer { display: block; border-top: 1px solid #ddd; }

    /* every panel prints, whichever tab happened to be open */
    .dash-panel[hidden] { display: block !important; }

    .lead-topbar { position: static !important; }
    .section-card, .sidebar-section, .dash-card, .premium-table-card {
        break-inside: avoid;
        box-shadow: none !important;
        border: 1px solid #ddd !important;
    }
    a[href]::after { content: ""; }        /* no URL noise in a client document */
    body { background: #fff !important; }
}
