/* =====================================================================
 * TID Group OS — Responsive layer (MERGED, 2026-06-04)
 * Location (served): /static/_shared/responsive.css
 * Source file:       /home/jameslaptop/tid_group_os/vFinal/_shared/responsive.css
 *
 * PURELY ADDITIVE. Loads on EVERY portal page + the hub, AFTER tidos.css and
 * after any portal-local sheet. It renames NOTHING, redefines NO tidos token,
 * and changes NO page logic. It only re-flows the EXISTING primitives across
 * four breakpoints and widens the desktop track.
 *
 * GOALS
 *   (a) MOBILE  — every portal + the hub cleanly readable & usable on a phone:
 *                 collapsible drawer nav, dense finance tables that
 *                 horizontal-scroll inside their own box, tap targets >=44px,
 *                 zero fixed-width overflow.
 *   (b) DESKTOP — target 1920x1080 and MAXIMISE it: a wide (~1800px) CENTRED
 *                 track instead of a narrow column OR an edge-to-edge sprawl,
 *                 multi-column dashboards, denser tables/cards using the full
 *                 width, larger readable type.
 *
 * LOAD ORDER (must be honoured by whoever wires it):
 *   <link rel="stylesheet" href="/static/_shared/tidos.css">
 *   <link rel="stylesheet" href="/static/_shared/responsive.css">   <-- LAST
 * Plus (already present on 85/87 pages; injector adds the 2 missing):
 *   <meta name="viewport" content="width=device-width, initial-scale=1">
 *
 * SCOPING DISCIPLINE (the single most important safety decision)
 *   ~21 pages are BESPOKE and do NOT link tidos.css — widgets/*, airbnb_portal/*,
 *   timeline_portal/index, some driver_pwa & operational pages — and they define
 *   their OWN body / main / header / .card / .grid with their OWN colour tokens
 *   (e.g. widgets: --bg/--ink, main{max-width:1280px}, .card{minmax(420px)}).
 *   THEREFORE every LAYOUT rule below is SCOPED to the shared tidos shell
 *   (.app / .app__main / .app__side / …) or to a SPECIFIC named shell
 *   (.exec-shell, #topbar+main, .admin-grid, portal_home, driver.css PWA).
 *   Only genuinely universal, harmless rules are left global (overflow-x guard,
 *   media max-width, long-word break). Nothing here touches .drillable,
 *   data-cell-key, raw-JSON href rules, or any page JS hook — purely visual.
 *
 * GROUND-TRUTH ANCHORS (verified against the real /_shared/tidos.css, 1896 lines)
 *   tokens : --sidebar-w:240px --header-h:56px --drill-w:460px
 *            --s-1..--s-12 (4..48px) --fs-xs..--fs-num-hero --radius* --shadow-3
 *   shell  : .app (grid, height:100vh, cols var(--sidebar-w) 1fr; areas side/header/main)
 *   drawer : tidos.css §ALREADY collapses at @media(max-width:900px) — .app__side
 *            becomes position:fixed top:var(--header-h) translateX(-100%); the
 *            class .app__side.is-open (toggled by tidos.js bindMenuToggle on
 *            .menu-toggle click) slides it in. We REUSE .is-open verbatim and
 *            EXTEND the ceiling to 1023px (portrait tablets) + add backdrop,
 *            44px hamburger, safe-area. We invent no new toggle class.
 *   drill  : .drill + its own .drill-overlay (NOT clashed with the nav backdrop)
 *
 * Breakpoints (mobile-first):
 *   base            phone   < 640px    single column
 *   640 – 1023px    tablet             2-up grids; drawer nav still active
 *   >= 1024px       desktop            sidebar restored; 1800px centred track
 *   >= 1600px       wide   (1920x1080) full width, 3–4 col, bigger type
 *   >= 2200px       ultra              gentle cap bump, then symmetric gutters
 * =================================================================== */

/* =====================================================================
 * 0. NEW TOKENS (additive only — no tidos.css token is redefined here)
 * =================================================================== */
:root {
    --app-max:        1800px;   /* wide-desktop content ceiling, centred */
    --sidebar-w-wide:  280px;   /* roomier rail on big monitors */
    --tap-min:          44px;   /* WCAG / Apple / Material touch target */
    --bar-h-mobile:     52px;   /* compact mobile top-bar height */
}

/* =====================================================================
 * 1. UNIVERSAL, HARMLESS GUARDS (global — cannot break bespoke layouts)
 * =================================================================== */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Never let a stray fixed width / long token push the viewport sideways. */
html, body { max-width: 100%; overflow-x: hidden; }
img, svg, video, canvas, iframe, embed, object, table { max-width: 100%; }
img, video { height: auto; }
/* Long unbroken tokens (atom ids, paths, hashes, regs) wrap, never overflow. */
.mono, code, pre, .chip-source, .chip-atom, .chip-event, .truck-card__reg {
    overflow-wrap: anywhere;
    word-break: break-word;
}
pre { overflow-x: auto; }

/* =====================================================================
 * 2. MOBILE BASE  (phone-first; widened by the min-width queries below)
 *    Applies up to the tablet ceiling unless a wider query overrides.
 * =================================================================== */

/* 2.1 — Readable base type on phones/tablets. 16px stops iOS form zoom. */
@media (max-width: 1023px) {
    body { font-size: 16px; }
}

/* 2.2 — App shell collapses to a single column for phone AND portrait
 *        tablet. tidos.css already does this at <=900; we extend the
 *        ceiling to 1023 and add the missing chrome (sticky bar sizing,
 *        safe-area insets). Header stays a TOP BAR; the drawer sits below
 *        it (because tidos pins .app__side at top:var(--header-h)). */
@media (max-width: 1023px) {
    .app {
        grid-template-columns: 1fr;
        grid-template-areas:
            "header"
            "main";
        height: auto;
        min-height: 100vh;
        min-height: 100dvh;
        overflow: visible;
    }

    .app__header {
        position: sticky;
        top: 0;
        z-index: 60;
        min-height: var(--bar-h-mobile);
        padding: 0 var(--s-3);
        padding-left: max(var(--s-3), env(safe-area-inset-left));
        padding-right: max(var(--s-3), env(safe-area-inset-right));
        gap: var(--s-2);
        overflow-x: auto;                 /* scope/asof/gate chips can scroll */
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .app__header::-webkit-scrollbar { display: none; }

    .app__main {
        overflow: visible;
        padding: var(--s-4);
        padding-left: max(var(--s-4), env(safe-area-inset-left));
        padding-right: max(var(--s-4), env(safe-area-inset-right));
        padding-bottom: max(var(--s-6), env(safe-area-inset-bottom));
    }

    /* Off-canvas drawer (extends tidos' <=900 rule up to 1023). The slide
     * is driven by tidos.js toggling .is-open on .menu-toggle click. */
    .app__side {
        position: fixed;
        top: var(--header-h);
        bottom: 0;
        left: 0;
        width: min(82vw, 340px);
        max-width: 340px;
        transform: translateX(-100%);
        transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1);
        z-index: 60;
        box-shadow: var(--shadow-3);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        padding-bottom: env(safe-area-inset-bottom);
    }
    .app__side.is-open { transform: translateX(0); }

    /* The hamburger is the primary nav affordance — reveal it whenever the
     * drawer layout is active and make it a real 44px target. */
    .menu-toggle {
        display: inline-grid;
        place-items: center;
        width: var(--tap-min);
        height: var(--tap-min);
    }

    /* CSS-only dimming scrim behind the OPEN drawer (no JS, no extra DOM).
     * It is pointer-events:none so taps still reach nav links; the visible
     * hamburger toggles the drawer closed. Painted by the drawer itself so
     * it never clashes with the drill panel's own .drill-overlay. */
    .app__side::after {
        content: "";
        position: fixed;
        top: var(--header-h); right: 0; bottom: 0; left: 0;
        background: rgba(15, 23, 42, 0.42);
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.2s ease, visibility 0.2s ease;
        z-index: -1;
        pointer-events: none;
    }
    .app__side.is-open::after { opacity: 1; visibility: visible; }
}

/* 2.3 — Sidebar internals: comfortable 44px tap targets + readable text. */
@media (max-width: 1023px) {
    .side__nav { padding-top: var(--s-2); padding-bottom: var(--s-2); }
    .side__nav-link {
        min-height: var(--tap-min);
        display: flex;
        align-items: center;
        font-size: var(--fs-md);
        padding-top: 11px;
        padding-bottom: 11px;
        border-radius: var(--radius);
    }
    .side__nav-link .badge,
    .side__nav-link .nav-badge { flex: 0 0 auto; }
    .side__persona { padding: var(--s-3) var(--s-4); }
}

/* 2.4 — Header de-clutters on phones (visual only; nothing carrying an
 *        R-amount is removed). Keeps brand + hamburger + freshness + gate. */
@media (max-width: 640px) {
    .crumbs { display: none; }                      /* matches tidos intent */
    .scope-switch {
        max-width: 42vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .asof { font-size: var(--fs-xs); white-space: nowrap; }
    .user-chip span:not(.user-chip__avatar) { display: none; } /* avatar only */
    .gate-pill { white-space: nowrap; }
}

/* 2.5 — KPI / dashboard grids STACK on phones (scoped to the .app shell so
 *        bespoke widgets/airbnb .card grids are untouched). */
@media (max-width: 640px) {
    .app .strip-grid,
    .app .truck-grid,
    .app .hero__grid,
    .app .grid-2,
    .app .bank-section__grid,
    .app .stoplight-grid,
    .app .bucket-grid,
    .app .routing-matrix,
    .app .truck-card__metrics {
        grid-template-columns: 1fr !important;
        gap: var(--s-3);
    }
    .app .hero,
    .app .truck-hero {
        padding: var(--s-4) var(--s-4);
        border-radius: var(--radius-lg);
    }
    .app .truck-hero { grid-template-columns: 1fr; gap: var(--s-4); }
    .app .truck-hero__left h1 { font-size: 24px; }
    .app .hero__stat-value { font-size: 22px; }
    .app .strip__big { font-size: 24px; }
    .app .section-head { gap: var(--s-2); }
    .app .section-head h2 { font-size: var(--fs-xl); }
    .app h1 { font-size: var(--fs-xl); }
}

/* 2.6 — DENSE FINANCE TABLES on phones.
 *  The table becomes its OWN horizontal-scroll container so a wide finance
 *  grid never forces the whole page wider than the viewport (which would
 *  break the drawer + cause body x-scroll). Every column, every .drillable
 *  cell, and every click handler is preserved. Covers shared .table /
 *  .lb-table, page-local table.acc, and the portal tables
 *  (table.dense / .exec / .lite / .hmap). Where the author already wrapped
 *  a table in <div style="overflow-x:auto"> (tid_dashboard does), the inner
 *  table keeps display:table so we do NOT double-scroll. */
@media (max-width: 1023px) {
    .app__main,
    .app .card,
    .app .card__body,
    .app .panel { min-width: 0; max-width: 100%; }

    .app .table,
    .app table.acc,
    .app .lb-table,
    table.dense, table.exec, table.lite, table.hmap {
        display: block;
        width: 100%;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        white-space: nowrap;            /* keep rows intact while scrolling */
    }
    /* Re-assert table semantics INSIDE the scroll box so zebra/striping and
     * column alignment survive the display:block on the table element. */
    .app .table > thead, .app .table > tbody, .app .table > tfoot,
    .app table.acc > thead, .app table.acc > tbody, .app table.acc > tfoot,
    .app .lb-table > thead, .app .lb-table > tbody, .app .lb-table > tfoot,
    table.dense > thead, table.dense > tbody, table.dense > tfoot,
    table.exec  > thead, table.exec  > tbody, table.exec  > tfoot,
    table.lite  > thead, table.lite  > tbody, table.lite  > tfoot,
    table.hmap  > thead, table.hmap  > tbody, table.hmap  > tfoot {
        display: table;
        width: 100%;
        table-layout: auto;
    }
    /* Sticky header is dropped on mobile scroll-tables (it fights the
     * block/overflow box and the customer table's 60px sticky offset). */
    .app .table th { position: static; }
    table.dense th { top: 0; }

    /* Tighter cell padding keeps more columns on screen. */
    .app .table th, .app .table td { padding: 8px 8px; }
    .app table.acc th, .app table.acc td { padding: 7px 8px; }

    /* Numbers must never wrap (R 1 234 567.89 stays one token). */
    .app td.num, .app th.num,
    .app table.acc td.r, .app .num, .app .amount { white-space: nowrap; }

    /* If a table is ALREADY hand-wrapped in an author overflow box, keep it
     * a normal table and let the WRAPPER own the scroll (no double-scroll). */
    [style*="overflow-x"] > .table,
    [style*="overflow-x"] > table.acc,
    [style*="overflow-x"] > table.dense,
    [style*="overflow-x"] > .lb-table { display: table; white-space: normal; }
    .app__main div[style*="overflow-x"] { max-width: 100%; }
}

/* 2.7 — Kill fixed inline first-column / rail widths on phones.
 *        Inline width:NNNpx beats classes, so we target the attribute. */
@media (max-width: 640px) {
    .app td[style*="width:"], .app th[style*="width:"] { width: auto !important; }
    .app [style*="width: 200px"], .app [style*="width:200px"],
    .app [style*="width: 220px"], .app [style*="width:220px"],
    .app [style*="width: 240px"], .app [style*="width:240px"],
    .app [style*="width: 180px"], .app [style*="width:180px"] {
        width: auto !important;
        max-width: 100% !important;
    }
}

/* 2.8 — Touch targets for interactive chrome (>=44px) on phones. */
@media (max-width: 1023px) {
    .btn, .tab, .lb-tab,
    .truck-nav__btn, .sort-pill,
    .fetch-failure__retry, .orientation-banner__dismiss, .drill__close {
        min-height: var(--tap-min);
        display: inline-flex;
        align-items: center;
    }
    .tabs { gap: 4px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .tab { padding-left: var(--s-3); padding-right: var(--s-3); }

    /* Drillable cells: widen the tap/hit area WITHOUT changing layout/flow
     * or its inline-flex display (the drill click logic relies on it). */
    .drillable { padding-top: 6px; padding-bottom: 6px; min-height: 32px; }
    .drillable::after { width: 12px; height: 12px; }   /* bigger chevron */
}

/* 2.9 — Drill / evidence panel is full-width on phones (tidos sets 100% at
 *        <=600; extend to <=640 and pin to the viewport so no sliver shows
 *        on 360–414px). */
@media (max-width: 640px) {
    .drill { width: 100vw; max-width: 100vw; }
    .drill__body { padding: var(--s-4); }
}

/* 2.10 — Forms / inputs comfortable on phones (accounting + loadbook
 *         toolbars). 16px prevents iOS auto-zoom; fields stack full-width. */
@media (max-width: 640px) {
    input, select, textarea, button { font-size: 16px; }
    .acc-toolbar, .lb-toolbar { padding: var(--s-3); gap: var(--s-2); }
    .acc-toolbar label { width: 100%; }
    .acc-toolbar input, .acc-toolbar select,
    .lb-toolbar input, .lb-toolbar select { min-width: 0; width: 100%; }
    .acc-toolbar button, .lb-toolbar button { min-height: var(--tap-min); }
}

/* =====================================================================
 * 3. TABLET  (>= 640px and <= 1023px)
 *    Two-/three-column dashboards; drawer nav still active (section 2).
 * =================================================================== */
@media (min-width: 640px) and (max-width: 1023px) {
    .app__main { padding: var(--s-5) var(--s-6); }
    .app .strip-grid,
    .app .grid-2,
    .app .bank-section__grid,
    .app .bucket-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); }
    .app .truck-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); }
    .app .hero__grid { grid-template-columns: repeat(2, 1fr); gap: var(--s-4); }
    .app .stoplight-grid { grid-template-columns: repeat(3, 1fr); }
    .app .truck-card__metrics { grid-template-columns: 1fr 1fr; }
    .app .hero__stat-value { font-size: 24px; }
    .app .strip__big { font-size: 26px; }

    /* Mid-size screens can usually show the full finance table without a
     * scroll box; lay it out normally but still cap width + restore sticky. */
    .app .table, .app table.acc, .app .lb-table,
    table.dense, table.exec, table.lite, table.hmap {
        display: table;
        white-space: normal;
        width: 100%;
    }
    .app .table th { position: sticky; top: 0; }
}

/* =====================================================================
 * 4. DESKTOP  (>= 1024px)
 *    Restore the fixed sidebar grid. CENTRE the whole app shell inside a
 *    wide 1800px track so 1080p/1440p reads as a deliberate wide dashboard
 *    — never a narrow ribbon, never edge-to-edge sprawl.
 * =================================================================== */
@media (min-width: 1024px) {
    /* Roomier rail + slightly bigger base type so a 1920px screen is USED. */
    :root { --sidebar-w: 256px; }

    .app {
        display: grid;
        grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
        grid-template-rows: var(--header-h) 1fr;
        grid-template-areas:
            "side  header"
            "side  main";
        height: 100vh;
        overflow: hidden;
        /* Centre the entire shell at the wide track on big monitors. */
        max-width: var(--app-max);
        margin-inline: auto;
    }
    .app__side {
        position: static;
        transform: none;
        width: auto;
        height: auto;
        box-shadow: none;
    }
    .app__side::after { content: none; }     /* no mobile scrim on desktop */
    .menu-toggle { display: none; }           /* hamburger hidden */

    .app__header { position: static; overflow: visible; }
    .app__main {
        grid-area: main;
        overflow-y: auto;
        padding: var(--s-6) var(--s-8);
    }

    /* Dashboard grids fill the wide column with deliberate auto-fit floors so
     * 1080p shows 3–4 cards across rather than 1–2 oversized ones. */
    .app .strip-grid       { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--s-5); }
    .app .truck-grid       { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--s-5); }
    .app .hero__grid       { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
    .app .bank-section__grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .app .stoplight-grid   { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
    .app .bucket-grid      { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

    /* Tables use the full width of the (capped) column and stay dense. */
    .app .table, .app table.acc, .app .lb-table {
        display: table;
        width: 100%;
        white-space: normal;
    }
    .app .table th { position: sticky; top: 0; }
}

/* =====================================================================
 * 5. WIDE  (>= 1600px — the 1920x1080 target)
 *    MAXIMISE: wider rail, denser+larger type, more columns, roomier table.
 * =================================================================== */
@media (min-width: 1600px) {
    :root { --sidebar-w: var(--sidebar-w-wide); --drill-w: 540px; }

    .app__main { padding: var(--s-8) var(--s-10); font-size: var(--fs-md); }

    .app .strip-grid       { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s-6); }
    .app .truck-grid       { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--s-6); }
    .app .hero__grid       { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-6); }
    .app .bank-section__grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
    .app .grid-2           { gap: var(--s-6); }

    /* Bigger, more readable headline + numeric type on big monitors. */
    .app h1 { font-size: 32px; }
    .app .section-head h2 { font-size: 24px; }
    .app .hero__stat-value { font-size: 28px; }
    .app .strip__big { font-size: 32px; }
    .app .kpi .val { font-size: 1.4em; }

    /* Denser-but-roomier finance tables; full-width 1800px table stays comfy. */
    .app .table { font-size: var(--fs-sm); }
    .app .table th, .app .table td { padding: 10px 14px; }
    .app table.acc { font-size: .95em; }
    .app table.acc th, .app table.acc td { padding: 9px 14px; }
    .app .amount { font-size: var(--fs-md); }
}

/* Ultra-wide: bump the cap slightly then let symmetric gutters form, which
 * keeps line lengths + table density readable on 2200px+ panels. */
@media (min-width: 2200px) { :root { --app-max: 2000px; } }
@media (min-width: 2400px) {
    .app__main { padding-left: var(--s-12); padding-right: var(--s-12); }
}

/* =====================================================================
 * 6. iOS DYNAMIC VIEWPORT — replace the 100vh trap progressively.
 *    (.app uses height:100vh which overflows under the iOS URL bar.)
 * =================================================================== */
@supports (height: 100svh) {
    @media (min-width: 1024px) { .app { height: 100svh; } }
}

/* =====================================================================
 * 7. exec_dashboard (.exec-shell — centred 1400px column in exec.css)
 *    Widen on desktop; stack + scroll on phone.
 * =================================================================== */
@media (min-width: 1024px) {
    .exec-shell { max-width: var(--app-max); padding: 1.5rem 2rem 4rem; }
}
@media (min-width: 1600px) {
    #kpi-strip     { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    #customer-grid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
    .ekpi__value   { font-size: 1.7rem; }
    .trend-wrap    { height: 380px; }
}
@media (max-width: 640px) {
    .exec-shell { padding: 1rem 0.9rem 3rem; }
    .exec-head { flex-direction: column; align-items: flex-start; }
    .exec-head__meta { text-align: left; }
    .ai-cols, .ai-row { grid-template-columns: 1fr; }
    .ai-row__time { margin-bottom: 2px; }
    .trunc { max-width: 60vw; }
    /* exec tables share the global table scroll-box rule via .app? No — exec
     * is NOT an .app shell, so cover its tables explicitly here. */
    table.exec, table.lite, table.hmap {
        display: block; width: 100%; overflow-x: auto;
        -webkit-overflow-scrolling: touch; white-space: nowrap;
    }
    table.exec > thead, table.exec > tbody,
    table.lite > thead, table.lite > tbody,
    table.hmap > thead, table.hmap > tbody { display: table; width: 100%; }
}

/* =====================================================================
 * 8. customer_portal / portal.css — widen the centred 1200px column on
 *    desktop; turn the horizontal #topbar nav into a mobile drawer-strip.
 * =================================================================== */
@media (min-width: 1024px) {
    #topbar + main { max-width: var(--app-max); }
}
@media (max-width: 760px) {
    #topbar { flex-wrap: wrap; gap: 8px; padding: 10px 14px; }
    #topbar nav.nav {
        order: 3;
        width: 100%;
        gap: 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        border-top: 1px solid rgba(255, 255, 255, 0.18);
        padding-top: 6px;
        flex-wrap: nowrap;
    }
    #topbar nav.nav a {
        flex: 0 0 auto;
        padding: 8px 12px;
        min-height: var(--tap-min);
        white-space: nowrap;
    }
    /* portal.css pins sticky th at top:60px assuming a fixed bar; the bar now
     * wraps, so reset the offset and let dense tables scroll. */
    table.dense {
        display: block; width: 100%; overflow-x: auto;
        -webkit-overflow-scrolling: touch; white-space: nowrap;
    }
    table.dense > thead, table.dense > tbody { display: table; width: 100%; }
    table.dense th { top: 0; position: static; }
    .kpis { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 420px) { .kpis { grid-template-columns: 1fr; } }

/* =====================================================================
 * 9. agent_portal (agent_portal.css — its own topbar variant)
 * =================================================================== */
@media (min-width: 1024px) {
    #topbar + main.agent, .agent-shell { max-width: var(--app-max); }
}
@media (max-width: 760px) {
    table.dense, table.lite {
        display: block; width: 100%; overflow-x: auto;
        -webkit-overflow-scrolling: touch; white-space: nowrap;
    }
    table.dense > thead, table.dense > tbody,
    table.lite  > thead, table.lite  > tbody { display: table; width: 100%; }
}

/* =====================================================================
 * 10. admin_portal inline .admin-grid (max-width:1100px, body{padding:24px})
 * =================================================================== */
@media (min-width: 1024px) { .admin-grid { max-width: var(--app-max) !important; } }
@media (max-width: 640px) {
    .admin-grid { grid-template-columns: 1fr; }
}

/* =====================================================================
 * 11. portal_home HUB (own inline CSS; it DOES link tidos.css so these
 *     reach it). It is NOT an .app shell — selectors below match its inline
 *     classes: main / main.wide / .role-grid / .role-btn / #truck-map .map-wrap.
 *     Treat it as the de-facto landing page (no separate marketing site
 *     exists anywhere under vFinal/).
 * =================================================================== */
@media (min-width: 1024px) {
    body > main#main { max-width: 720px; }            /* sign-in column a touch wider */
    body > main#main.wide { max-width: 1500px; }      /* with live map: use the screen */
    #truck-map .map-wrap { height: 60vh; }            /* taller map on desktop */
    .role-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1600px) {
    body > main#main.wide { max-width: var(--app-max); }
    #truck-map .map-wrap { height: 68vh; }
    .role-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 640px) {
    .role-grid { grid-template-columns: 1fr 1fr; gap: var(--s-3); }
    .role-btn { min-height: 96px; }
    .role-btn.wide { grid-column: span 2; }
    #truck-map .map-wrap { height: 300px; }
}
@media (max-width: 380px) {
    .role-grid { grid-template-columns: 1fr; }
    .role-btn.wide { grid-column: span 1; }
}

/* =====================================================================
 * 12. DRIVER PWA — explicitly DO NOT widen. driver.css is already phone-first
 *     (body{max-width:520px}, bottom .dnav, safe-area insets, .dbtn 76px tap
 *     targets). On large screens, FRAME it nicely instead of stretching it.
 *     Recommended (optional): add class="pwa" to its <html>; the body
 *     max-width guard below works either way.
 * =================================================================== */
@media (min-width: 700px) {
    html.pwa body,
    body:has(> .dnav) {
        box-shadow: var(--shadow-3);
        border-left: 1px solid var(--c-border);
        border-right: 1px solid var(--c-border);
    }
}

/* =====================================================================
 * 13. TOUCH-DEVICE HINT (coarse pointer) — generous targets on any
 *     touch-driven screen (tablets / kiosks) regardless of width.
 * =================================================================== */
@media (hover: none) and (pointer: coarse) {
    .side__nav-link, .btn, .dbtn, .tab, .lb-tab,
    .truck-nav__btn, #topbar nav.nav a, .role-btn, .dnav-item {
        min-height: 42px;
    }
    .side__nav-link { padding-top: 11px; padding-bottom: 11px; }
    .drillable { padding-block: 2px; }
}

/* =====================================================================
 * 14. SAFE-AREA INSETS (notched phones) — keep chrome clear of the notch.
 * =================================================================== */
@supports (padding: max(0px)) {
    @media (max-width: 1023px) {
        .app__header {
            padding-left: max(var(--s-3), env(safe-area-inset-left));
            padding-right: max(var(--s-3), env(safe-area-inset-right));
        }
        .app__side { padding-bottom: env(safe-area-inset-bottom); }
    }
}

/* =====================================================================
 * 15. REDUCED MOTION — honour the user preference for the drawer + pulses.
 * =================================================================== */
@media (prefers-reduced-motion: reduce) {
    .app__side, .app__side::after,
    .drill, .drill-overlay { transition: none !important; }
    .asof__pulse,
    .truck-card__status .dot,
    .skel, .skeleton, .skel-bar { animation: none !important; }
}

/* Print: defer entirely to tidos.css print rules (they already hide chrome). */

