/* ============================================================================
   Risper CRM — Global Mobile / PWA adaptation layer
   Loaded in every portal. Desktop is untouched; everything here is inside
   mobile media queries. Goal: native-app feel on phones.
   Breakpoint: phones ≤ 768px.
   ============================================================================ */

:root {
    --crm-safe-bottom: env(safe-area-inset-bottom, 0px);
    --crm-safe-top: env(safe-area-inset-top, 0px);
    --crm-bottom-nav-h: 58px;
}

/* ── Bottom tab navigation (native-style) ─────────────────────────────────── */
.crm-bottom-nav { display: none; }

@media (max-width: 768px) {
    .crm-bottom-nav {
        display: flex;
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 1030;
        background: #fff;
        border-top: 1px solid var(--crm-border, #e8eaef);
        box-shadow: 0 -2px 14px rgba(0, 0, 0, .08);
        padding-bottom: var(--crm-safe-bottom);
        height: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom));
    }
    .crm-bottom-nav__item {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        border: none;
        background: none;
        color: #8a8a9a;
        font-size: .62rem;
        font-weight: 600;
        text-decoration: none;
        cursor: pointer;
        position: relative;
        padding: 6px 0;
        transition: color .15s;
        -webkit-tap-highlight-color: transparent;
    }
    .crm-bottom-nav__item i { font-size: 1.32rem; line-height: 1; }
    .crm-bottom-nav__item.active,
    .crm-bottom-nav__item:active { color: var(--crm-primary, #530383); }
    .crm-bottom-nav__badge {
        position: absolute; top: 3px; left: 54%;
        min-width: 15px; height: 15px; padding: 0 4px;
        background: #dc3545; color: #fff; font-size: .58rem; font-weight: 800;
        border-radius: 9px; display: none; align-items: center; justify-content: center;
        border: 1.5px solid #fff;
    }

    /* Make room above the bar for page content + floating UI. */
    body.crm-has-bottom-nav .main-wrapper,
    body.crm-has-bottom-nav .sp-main,
    body.crm-has-bottom-nav .page-content {
        padding-bottom: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom) + 12px) !important;
    }
    /* Lift the floating buttons (help, chat, bug, install banner) above the bar
       so they never cover a nav tab. */
    body.crm-has-bottom-nav #crmHelpFab { bottom: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom) + 12px); top: auto; transform: none; }
    body.crm-has-bottom-nav #crmChatFab { bottom: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom) + 14px); }
    body.crm-has-bottom-nav #pwaInstallBanner { bottom: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom) + 12px); }
}

/* ── Slide-in drawer for portals whose sidebar has no native mobile mode ──────
   (agent .ap-sidebar, subcontractor .sp-sidebar). The admin + super-admin
   layouts already ship their own drawer + overlay, so they are NOT targeted
   here. Toggled by crm-mobile.js via body.crm-mobile-open. ─────────────────── */
@media (max-width: 768px) {
    .ap-sidebar, .sp-sidebar {
        display: flex !important;
        left: -320px !important;
        z-index: 1050;
        transition: left .24s cubic-bezier(.4, 0, .2, 1);
    }
    body.crm-mobile-open .ap-sidebar,
    body.crm-mobile-open .sp-sidebar { left: 12px !important; }
    .ap-main, .sp-main { margin-left: 0 !important; }

    .crm-drawer-overlay {
        position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
        z-index: 1045; display: none;
    }
    body.crm-mobile-open .crm-drawer-overlay { display: block; }
}

/* ── General phone ergonomics ─────────────────────────────────────────────── */
@media (max-width: 768px) {
    /* Honour the notch / status bar. */
    .topbar { padding-left: 14px; padding-right: 14px; }

    /* Larger touch targets for form controls + buttons. */
    .form-control, .form-select { min-height: 42px; font-size: 16px; } /* 16px stops iOS zoom-on-focus */
    .btn { min-height: 40px; }
    .btn-sm, .crm-icon-btn, .btn-icon-sq.btn-sm { min-height: 36px; }

    /* Cards stretch to fill the screen (small uniform gutter, no right gap). */
    .main-wrapper { margin: 0 !important; padding: 0 !important; }
    .page-content { padding: 8px !important; }
    .card, .leads-header, .ap-card, .sp-card, .sa-card {
        width: 100% !important; max-width: 100% !important;
        margin-left: 0 !important; margin-right: 0 !important;
        border-radius: 14px;
    }
    /* Leads page renders content directly in the wrapper — give it a gutter. */
    .main-wrapper > section, .main-wrapper > .container-fluid { padding: 8px !important; }

    /* Stat cards: 2-up grid instead of cramped rows. */
    .stat-card { padding: 14px; }

    /* Kanban scrolls horizontally already; tighten columns. */
    .kanban-col { min-width: 78vw; max-width: 80vw; }

    /* Prevent accidental horizontal page scroll. */
    body { overflow-x: hidden; }
}

/* ── Adaptive tables: rows become cards on phones ─────────────────────────────
   crm-table.js stamps each <td> with data-label="<column header>". On phones we
   stack each row into a card with label/value pairs. Opt-out: table.crm-no-cards
   ============================================================================ */
@media (max-width: 768px) {
    table.dataTable.crm-cards,
    table.dataTable.crm-cards thead,
    table.dataTable.crm-cards tbody,
    table.dataTable.crm-cards tr,
    table.dataTable.crm-cards td { display: block; width: 100% !important; }

    table.dataTable.crm-cards thead { display: none; }

    table.dataTable.crm-cards tr {
        margin: 0 0 12px;
        border: 1px solid var(--crm-border, #e8eaef);
        border-radius: 14px;
        background: #fff;
        box-shadow: 0 1px 6px rgba(0, 0, 0, .05);
        padding: 6px 4px;
        overflow: hidden;
    }

    table.dataTable.crm-cards td {
        display: flex !important;
        align-items: center;
        justify-content: space-between;
        gap: 14px;
        padding: 9px 14px !important;
        border: none !important;
        border-bottom: 1px solid #f3f4f8 !important;
        text-align: right;
        white-space: normal !important;
        max-width: none !important;
        overflow: visible !important;
    }
    table.dataTable.crm-cards td:last-child { border-bottom: none !important; }

    table.dataTable.crm-cards td::before {
        content: attr(data-label);
        font-weight: 700;
        font-size: .72rem;
        color: #8a8a9a;
        text-transform: uppercase;
        letter-spacing: .03em;
        text-align: left;
        flex-shrink: 0;
    }
    /* Hide the label for the row-select checkbox + the actions cell. */
    table.dataTable.crm-cards td[data-label=""]::before,
    table.dataTable.crm-cards td.crm-cards-nolabel::before { content: none; }
    table.dataTable.crm-cards td.crm-cards-nolabel { justify-content: flex-end; }

    /* DataTables top/bottom controls: stack + full width. */
    /* Filter bar WRAPS so the fields are visible when the funnel reveals them
       (was nowrap-scroll, which pushed the fields off-screen → "filter not working"). */
    .dataTables_wrapper .crm-filter-bar, .crm-filter-bar { flex-wrap: wrap !important; overflow-x: visible !important; row-gap: 6px; }
    .crm-filter-bar .crm-filter-left { flex-wrap: wrap !important; width: 100%; }
    .crm-filter-bar .crm-filter-left:not(.crm-filter-left--hidden) { display: flex !important; }
    .crm-filter-bar .crm-filter-left .form-select,
    .crm-filter-bar .crm-filter-left .form-control { width: auto; max-width: 100%; }
    .dataTables_wrapper .crm-dt-bottom { flex-direction: column; gap: 8px; align-items: stretch !important; }
}

/* ============================================================================
   Native-feel layer (CLAUDE-PWA.md §2 §4 §8 §10) — "Web Tell" removal.
   ============================================================================ */

/* Kill the grey tap flash everywhere (harmless on desktop). */
* { -webkit-tap-highlight-color: transparent; }

/* Cross-document page transitions (View Transitions API, progressive). Gives a
   native stack-style cross-fade between full-page navigations in Chromium. */
@view-transition { navigation: auto; }

@media (max-width: 768px) {
    html { -webkit-text-size-adjust: 100%; }
    body {
        overscroll-behavior-y: none;          /* no browser bounce / pull-to-refresh */
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        overflow-x: hidden;                    /* no horizontal rubber-band */
    }

    /* Remove the 300ms tap delay + double-tap zoom on interactive elements. */
    a, button, .btn, [role="button"], .crm-bottom-nav__item,
    .s-nav-item, .crm-tab, .nav-link, input, select, textarea { touch-action: manipulation; }

    /* Chrome (bars/buttons/labels) is not selectable; real content still is. */
    .topbar, .sidebar, .ap-sidebar, .sp-sidebar, .sa-sidebar, .sa-topbar,
    .crm-bottom-nav, .nav-tabs, .crm-page-tabs, .card-header,
    .btn, .s-nav-item, .s-nav-group-hdr, .crm-tab, .stat-card .stat-label,
    .topbar-bell, .topbar-user {
        -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
    }

    /* Press feedback (§4.66). */
    .btn:active, a.btn:active, .crm-bottom-nav__item:active,
    .s-nav-item:active, .list-group-item:active, .lead-card:active,
    .kanban-card:active, .stat-card:active { transform: scale(.97); }

    /* No focus ring on touch; keep it for real keyboard users (§10). */
    :focus { outline: none; }
    :focus-visible { outline: 2px solid var(--crm-primary, #530383); outline-offset: 1px; }

    /* Active bottom-tab gets the accent + a filled-icon feel (§3.54). */
    .crm-bottom-nav__item.active i { transform: scale(1.1); }

    /* Hide scrollbars visually, keep scroll (§2.22). */
    * { scrollbar-width: none; }
    *::-webkit-scrollbar { width: 0; height: 0; display: none; }

    /* No browser tooltips leaking on long-press is handled by touch-callout above. */
}

/* Honour reduced-motion (§4.70). */
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
    *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ── Pull-to-refresh (§5.75) — driven by crm-mobile.js, phones only ────────── */
.crm-ptr {
    position: fixed; top: 0; left: 50%; margin-left: -19px;
    width: 38px; height: 38px; z-index: 1900;
    transform: translateY(-120%);
    display: flex; align-items: center; justify-content: center;
    background: #fff; border-radius: 50%; box-shadow: 0 3px 14px rgba(0, 0, 0, .2);
}
.crm-ptr__spinner {
    width: 19px; height: 19px; border: 2.5px solid var(--crm-border, #e8eaef);
    border-top-color: var(--crm-primary, #530383); border-radius: 50%;
    transition: transform .2s ease;
}
.crm-ptr.ready .crm-ptr__spinner { transform: rotate(180deg); }
.crm-ptr.spinning { transition: transform .2s ease; }
.crm-ptr.spinning .crm-ptr__spinner { animation: crm-ptr-spin .7s linear infinite; }
@keyframes crm-ptr-spin { to { transform: rotate(360deg); } }

/* ── Skeleton loaders (§5.19 / §8.99) ─────────────────────────────────────── */
.crm-skeleton {
    position: relative; overflow: hidden;
    background: #e9ebf1; border-radius: 8px; min-height: 14px;
}
.crm-skeleton::after {
    content: ''; position: absolute; inset: 0; transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .7), transparent);
    animation: crm-shimmer 1.3s infinite;
}
@keyframes crm-shimmer { 100% { transform: translateX(100%); } }
.crm-skeleton-row { display: flex; gap: 12px; align-items: center; padding: 10px 4px; }
.crm-skeleton-row .crm-skeleton.avatar { width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0; }
.crm-skeleton-row .crm-skeleton.line { height: 12px; flex: 1; }
.crm-skeleton-row .crm-skeleton.line.short { max-width: 90px; }

/* Themed DataTables "processing" — a slim top progress shimmer, no boxed text. */
div.dataTables_processing {
    background: transparent !important; border: none !important; box-shadow: none !important;
    color: transparent !important; height: 3px !important; padding: 0 !important;
    top: 0 !important; overflow: hidden;
}
div.dataTables_processing > div { display: none !important; }
div.dataTables_processing::after {
    content: ''; position: absolute; left: 0; top: 0; height: 3px; width: 40%;
    background: var(--crm-primary, #530383); border-radius: 3px;
    animation: crm-dt-progress 1.1s ease-in-out infinite;
}
@keyframes crm-dt-progress { 0% { left: -40%; } 100% { left: 100%; } }

/* ── Empty states (§5.78) ─────────────────────────────────────────────────── */
.crm-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center; padding: 44px 22px; gap: 4px;
}
.crm-empty__icon {
    width: 64px; height: 64px; border-radius: 18px; margin-bottom: 8px;
    background: var(--crm-primary-soft, #f5f3ff); color: var(--crm-primary, #530383);
    display: flex; align-items: center; justify-content: center; font-size: 1.8rem;
}
.crm-empty__title { font-size: .95rem; font-weight: 700; color: #374151; }
.crm-empty__text { font-size: .82rem; color: #9097a6; max-width: 320px; }
.crm-empty__cta { margin-top: 12px; }

/* Make DataTables' bare "No data" row look intentional, not like a broken table. */
table.dataTable td.dataTables_empty {
    padding: 40px 16px !important; text-align: center !important;
    color: #9097a6; font-size: .85rem; font-weight: 500;
}

/* ── Sticky bottom form actions (§6.86) — add class to a button row ────────── */
@media (max-width: 768px) {
    .crm-form-actions--sticky {
        position: sticky; bottom: 0; z-index: 20;
        background: #fff; border-top: 1px solid var(--crm-border, #e8eaef);
        padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
        margin: 16px -14px -14px;
        display: flex; gap: 10px;
    }
    body.crm-has-bottom-nav .crm-form-actions--sticky {
        bottom: calc(var(--crm-bottom-nav-h) + var(--crm-safe-bottom));
    }
    .crm-form-actions--sticky .btn { flex: 1; min-height: 46px; }
}

/* Offline banner (§7.27) — toggled by crm-mobile.js. */
.crm-offline-banner {
    position: fixed; left: 0; right: 0; top: 0; z-index: 2000;
    transform: translateY(-100%); transition: transform .25s cubic-bezier(.4, 0, .2, 1);
    background: #1f2937; color: #fff; text-align: center;
    font-size: .8rem; font-weight: 600; padding: calc(7px + env(safe-area-inset-top, 0px)) 12px 7px;
    display: flex; align-items: center; justify-content: center; gap: 7px;
}
.crm-offline-banner.show { transform: translateY(0); }
.crm-offline-banner::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; }

/* ============================================================================
   Advanced native feel (CLAUDE-PWA.md §11, 101–150) — global + safe subset.
   ============================================================================ */

/* §103/§104 Active bottom-tab: indicator pill behind the icon + scale-bounce. */
.crm-bottom-nav__item::before {
    content: ''; position: absolute; top: 5px; left: 50%;
    width: 46px; height: 26px; border-radius: 13px;
    background: var(--crm-primary-soft, #f5f3ff);
    transform: translateX(-50%) scaleX(.35); opacity: 0; z-index: 0;
    transition: opacity .2s ease, transform .2s cubic-bezier(.2, 0, 0, 1);
}
.crm-bottom-nav__item.active::before { opacity: 1; transform: translateX(-50%) scaleX(1); }
.crm-bottom-nav__item i, .crm-bottom-nav__item span { position: relative; z-index: 1; }
.crm-bottom-nav__item.active i { animation: crm-tab-bounce .26s ease; }
@keyframes crm-tab-bounce { 0% { transform: scale(1); } 55% { transform: scale(1.2); } 100% { transform: scale(1.1); } }

/* Portable dark-mode toggle button (used across portals). */
.crm-theme-toggle {
    width: 36px; height: 36px; border-radius: 9px; flex-shrink: 0;
    border: 1px solid var(--crm-border, #e8eaef); background: transparent; color: #666;
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
    font-size: .95rem; transition: color .15s, border-color .15s, background .15s;
}
.crm-theme-toggle:hover { color: var(--crm-primary, #530383); border-color: var(--crm-primary, #530383); }

/* §107 Unread badge spring pop-in when it appears. */
.notif-count, .crm-bottom-nav__badge { animation: crm-badge-pop .26s cubic-bezier(.2, .8, .2, 1.3); }
@keyframes crm-badge-pop { 0% { transform: scale(0); } 70% { transform: scale(1.25); } 100% { transform: scale(1); } }

/* §134/§63 Modals slide up from the bottom on phones (native sheet). */
@media (max-width: 768px) {
    .modal.fade .modal-dialog { transform: translateY(100%); transition: transform .3s cubic-bezier(.2, 0, 0, 1); }
    .modal.show .modal-dialog { transform: none; }
}

/* §126 Horizontal scrollers snap into place (kanban, card rails). */
.kanban-board { scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; }
.kanban-col { scroll-snap-align: start; }

/* §136 App bar gains elevation once content scrolls under it (class set by JS). */
.topbar, .sa-topbar { transition: box-shadow .2s ease; }
.topbar.crm-scrolled, .sa-topbar.crm-scrolled { box-shadow: 0 6px 20px rgba(0, 0, 0, .14); }

/* ── Fit card content strictly inside the viewport — NO horizontal drag ──────
   (real-device feedback: long values were clipping off the right edge). ─────── */
@media (max-width: 768px) {
    /* clip (not hidden) so <html> does NOT become a scroll container that
       blocks vertical scrolling on mobile. */
    html, body { max-width: 100vw; overflow-x: hidden; overflow-x: clip; }
    .main-wrapper, .page-content, .card, .crm-table-container,
    .dataTables_wrapper, .crm-table-inner, .crm-table-wrap, .table-responsive,
    .dataTables_scroll, .dataTables_scrollHead, .dataTables_scrollBody {
        max-width: 100% !important;
        overflow-x: hidden !important;
    }

    table.dataTable.crm-cards { table-layout: fixed; width: 100% !important; }
    table.dataTable.crm-cards tr { width: auto !important; max-width: 100%; }

    table.dataTable.crm-cards td {
        align-items: flex-start;          /* multi-line values align cleanly */
        word-break: break-word;
        overflow-wrap: anywhere;
        overflow: hidden !important;
        /* Neutralise per-page sticky/frozen/min-width columns (e.g. leads' pinned
           Status/Value) that otherwise force the card wider than the screen. */
        position: static !important;
        right: auto !important; left: auto !important;
        min-width: 0 !important;
        width: auto !important;
        box-shadow: none !important;
    }
    /* The VALUE (everything after the label) must shrink + wrap, never push width. */
    table.dataTable.crm-cards td > * {
        min-width: 0 !important;
        max-width: 100% !important;
        white-space: normal !important;
        overflow-wrap: anywhere;
        word-break: break-word;
        text-overflow: clip !important;
        overflow: visible !important;
    }
    table.dataTable.crm-cards td::before { max-width: 42%; flex-shrink: 0; }
}

/* ── Pop-up forms on phones: compact CENTERED dialog, NOT full-screen ────────
   (user feedback: full-screen add-lead/project/task felt congested). ───────── */
@media (max-width: 768px) {
    .modal-dialog:not(.modal-sm):not(.modal-fullscreen):not(.modal-fullscreen-keep) {
        margin: 14px auto !important;
        max-width: calc(100vw - 24px) !important;
        width: calc(100vw - 24px) !important;
        min-height: auto !important;
    }
    .modal-dialog:not(.modal-sm):not(.modal-fullscreen):not(.modal-fullscreen-keep) .modal-content {
        min-height: auto !important;
        border-radius: 16px !important;
        max-height: calc(100dvh - 28px);
    }
    /* Body scrolls inside the dialog so the popup never grows past the screen. */
    .modal-body { overflow-y: auto; -webkit-overflow-scrolling: touch; }
    .modal-footer { padding-bottom: calc(12px + var(--crm-safe-bottom)); }
}

/* ── Bigger, more legible text on phones (real-device feedback) ─────────────── */
@media (max-width: 768px) {
    body { font-size: 15px; }
    .s-nav-item, .s-nav-group-hdr, .ap-nav-item, .sp-nav-item, .sa-nav-item,
    .s-nav-sub-link, .sa-nav-label { font-size: .96rem !important; }
    .topbar .page-title, .ap-topbar-title, .sp-page-title, .sa-topbar-title { font-size: 1.02rem; }
    .card-header { font-size: 1rem; }
    .stat-card .stat-value, .ap-kpi-val { font-size: 1.7rem; }
    .stat-card .stat-label, .ap-kpi-lbl { font-size: .85rem; }
    .btn, .btn-sm, .form-label { font-size: .9rem; }
    .badge { font-size: .76rem; }
    /* Card-table cells: bigger value + label so rows read like a native list. */
    table.dataTable.crm-cards td { font-size: .95rem !important; }
    table.dataTable.crm-cards td::before { font-size: .8rem !important; }
    /* Bottom-nav labels + icons a touch larger. */
    .crm-bottom-nav__item { font-size: .66rem; }
    .crm-bottom-nav__item i { font-size: 1.42rem; }
}

/* ── Keep ALL toolbar icons inside the card — never off the right edge ───────
   (real-device feedback: header icon rows + view toggles + export/import were
   overflowing, which also stretched the cards below.) ─────────────────────── */
@media (max-width: 768px) {
    .leads-header, .header-right, .header-left,
    .card-header, .card-header > .d-flex,
    .btn-group, .btn-toolbar, .view-toggle,
    .dt-buttons, .dataTables_wrapper .dt-buttons,
    [class$="-header"] {
        flex-wrap: wrap !important;
        max-width: 100% !important;
    }
    .header-right, .header-left { justify-content: flex-start !important; row-gap: 6px; }

    /* Declutter the topbar: Search / Alerts / Menu already live in the bottom bar,
       and the spotlight/clear-cache are admin tools — hide them on phones. */
    .topbar-right .gsearch-trigger,
    .topbar-right button[onclick*="enterSpotlightMode"],
    .topbar-right #btn-clear-cache { display: none !important; }
    .topbar { padding: 0 10px !important; }
    .topbar-right { gap: 5px !important; flex-wrap: nowrap; }
    .topbar-bell { width: 33px !important; height: 33px !important; }
    /* Clock-in/out shows icon only on phones to save width. */
    #topbar-clock-in-btn, #topbar-clock-out-btn { font-size: 0 !important; padding: 6px 9px !important; }
    #topbar-clock-in-btn i, #topbar-clock-out-btn i { font-size: 1.05rem !important; margin: 0 !important; }
}

/* ── Reports & dashboards accommodate the phone screen ─────────────────────── */
@media (max-width: 768px) {
    /* Dashboard widget grid + report cards stack full-width. */
    .dash-row, .dashboard-grid { display: block !important; }
    .dash-col-slot, .slot-widget, .slot-widget-inner, .widget-tile,
    .dashboard-grid > *, [class*="dash-col"] { width: 100% !important; max-width: 100% !important; }
    /* Charts never overflow horizontally. */
    canvas { max-width: 100% !important; }
    .apexcharts-canvas, .chartjs-render-monitor { max-width: 100% !important; }
    .chart-container, .report-chart, .widget-chart { max-width: 100% !important; overflow: hidden; }
    /* Genuinely wide tables that can't card-ize scroll inside themselves,
       not the whole page. */
    .table-responsive { overflow-x: auto !important; -webkit-overflow-scrolling: touch; max-width: 100%; }
}

/* ── Open menu drawer must scroll (long menus) + lock the page behind ────────
   (bug: after opening the menu, lower items were unreachable / no scroll). ─── */
@media (max-width: 768px) {
    /* While the drawer is open, freeze the page so ONLY the drawer scrolls. */
    body.crm-mobile-open { overflow: hidden !important; }

    body.crm-mobile-open .sidebar,
    body.crm-mobile-open .ap-sidebar,
    body.crm-mobile-open .sp-sidebar {
        top: 0 !important;
        height: 100vh !important;
        height: 100dvh !important;            /* dynamic viewport — survives the address bar */
        max-height: 100dvh !important;
        overflow-y: auto !important;
        -webkit-overflow-scrolling: touch;    /* momentum scroll on iOS */
        overscroll-behavior: contain;         /* don't chain to the page */
        touch-action: pan-y !important;       /* allow vertical drag inside the drawer */
        border-radius: 0 18px 18px 0 !important;
        padding-bottom: calc(28px + env(safe-area-inset-bottom, 0px)) !important;
    }
    /* The inner nav must be allowed to grow tall enough to scroll. */
    body.crm-mobile-open .sidebar-nav,
    body.crm-mobile-open .ap-nav,
    body.crm-mobile-open .sp-nav { flex: 0 0 auto; min-height: auto; }
}
