/* ============================================================================
   D9Commerce — responsive layer
   ----------------------------------------------------------------------------
   ONE authoritative stylesheet for how the product behaves across screen
   sizes. Loaded LAST in every shell (inc/layout.php, public/templates/
   header.php, inc/pages/home.php|legal.php|help.php) so it always wins the
   cascade against the layered sheets underneath it.

   Why it exists: before this file, responsive rules were scattered across
   style.css (768), cr-design.css (992/640), d9-unify.css (1100/980/768/640/
   480/400), landing.css (1050/900/640/520), inventory-pro.css (768) and ~30
   ad-hoc @media blocks inside PHP <style> tags at 460/520/680/700/760/860/
   920/940/1250/1280. Nothing agreed on a breakpoint, so bands of widths fell
   between the rules and pages panned sideways on a phone.

   THE BREAKPOINT SCALE — every new rule must use one of these:

     ≤ 480px   phone            single column, everything stacks
     ≤ 640px   large phone      compact chrome, search collapses, sheets
     ≤ 768px   tablet portrait  two-up grids collapse, tables become cards
     ≤ 992px   tablet landscape sidebar becomes an overlay drawer
                                (matches cr-design.css AND the _sbAuto()
                                threshold in the two shells' inline JS —
                                do not change one without the others)
     ≥ 1280px  desktop          full chrome, comfortable gutters
     ≥ 1600px  wide desktop     content capped and centred, denser grids

   Ordering inside the file: foundations → app chrome → content → components
   → forms → tables → modals → landing site → desktop/wide → a11y & print.

   !important is used deliberately and only where a rule must beat an inline
   style="" attribute or a page-level <style> block (both of which are emitted
   *after* this file in the document). Every such use is commented.
   ========================================================================== */

:root {
    /* Widest the reading/working column ever gets. Without this the app
       stretched to the full width of a 4K monitor — a KPI tile measured
       576px and a textarea 1125px, which reads as broken, not spacious. */
    --d9-content-max: 1560px;

    /* Gutters, per band. Consumed by .content-wrapper below. */
    --d9-gutter: 24px;

    /* Notch / home-indicator insets. 0 on hardware without them. */
    --d9-safe-t: env(safe-area-inset-top, 0px);
    --d9-safe-r: env(safe-area-inset-right, 0px);
    --d9-safe-b: env(safe-area-inset-bottom, 0px);
    --d9-safe-l: env(safe-area-inset-left, 0px);

    /* Minimum comfortable touch target (WCAG 2.5.5 / iOS HIG / Material). */
    --d9-tap: 44px;
}

/* ============================================================================
   1. FOUNDATIONS
   ========================================================================== */

/* Nothing may ever cause the *page* to scroll sideways. Individual regions
   (tables, tab strips, stat bands) scroll inside themselves instead — see §7.
   overflow-x on <html> rather than <body> so position:sticky keeps working. */
html { overflow-x: hidden; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { overflow-x: clip; }
/* `clip` does the same job without turning the element into a scroll
   container, so position:sticky in the chrome can never be affected by it.
   Chrome 90+/Firefox 81+/Safari 16+; older engines keep `hidden` above. */
@supports (overflow-x: clip) {
    html { overflow-x: clip; }
}

/* Media never overflows its column. */
img, svg, video, canvas, iframe, embed, object { max-width: 100%; }
img, video, canvas { height: auto; }

/* Long SKUs, order ids, tracking numbers and URLs are the single most common
   cause of a blown-out mobile layout in this app. Let them break. */
code, kbd, samp, pre, .mono, [class*="sku"], [class*="serial"], [class*="track"] {
    overflow-wrap: anywhere;
    word-break: break-word;
}
a { overflow-wrap: break-word; }

/* Flex/grid children default to min-width:auto, which refuses to shrink below
   their content and is what pushed cards off-screen. Opt every layout child
   in the app content area into shrinking instead. */
.content-wrapper :where(.card, section.card, .grid-2, .form-grid, .mp-panel) > * { min-width: 0; }

/* ============================================================================
   2. APP CHROME — sidebar drawer, top bar, content wrapper
   ========================================================================== */

/* --- 2a. The overlay drawer (≤992px) ------------------------------------ */
@media (max-width: 992px) {

    /* cr-design.css already slides the sidebar off-canvas here; these rules
       make it behave like a real drawer rather than a hidden panel. */
    .sidebar {
        width: min(320px, 88vw);
        max-width: 88vw;
        transition: transform .26s cubic-bezier(.32, .72, 0, 1);
        padding-top: var(--d9-safe-t);
        padding-bottom: var(--d9-safe-b);
        padding-left: var(--d9-safe-l);
        z-index: 1200;                       /* above the sticky top bar (90) */
        overflow-y: auto;                    /* short phones in landscape */
        overscroll-behavior: contain;        /* no scroll chaining to the page */
    }
    .sidebar.collapsed { width: min(320px, 88vw); }

    /* Backdrop. body.menu-open is toggled by both shells' toggleMobileMenu(). */
    body.menu-open::before {
        content: '';
        position: fixed;
        inset: 0;
        background: rgba(9, 14, 30, .5);
        -webkit-backdrop-filter: blur(2px);
        backdrop-filter: blur(2px);
        z-index: 1100;
        animation: d9FadeIn .2s ease-out;
    }

    /* The drawer's own controls need to be thumb-sized. */
    .sidebar-menu a {
        min-height: var(--d9-tap);
        display: flex;
        align-items: center;
    }
    .mobile-close-btn,
    .mobile-menu-btn {
        min-width: var(--d9-tap);
        min-height: var(--d9-tap);
    }

    /* The collapse toggle is meaningless while the sidebar is a drawer. */
    .sidebar-collapse-btn { display: none !important; }

    /* Content is full-bleed once the sidebar is out of flow. */
    .main-content,
    .sidebar.collapsed ~ .main-content { margin-left: 0; }
}

@keyframes d9FadeIn { from { opacity: 0; } }

/* --- 2b. Top bar -------------------------------------------------------- */
@media (max-width: 992px) {
    .top-header {
        padding-left: max(14px, var(--d9-safe-l));
        padding-right: max(14px, var(--d9-safe-r));
        gap: 10px;
    }
    /* Page titles must truncate, never wrap the bar onto two lines. */
    .top-header .header-title { min-width: 0; flex: 0 1 auto; }
    .top-header .header-title h1 {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 17px;
    }
}

/* Global search collapses to a tappable magnifier on phones and expands to
   fill the bar on focus. Keeps Ctrl+K search one tap away without stealing
   the title's space. Pure CSS — :focus-within, no JS in either shell. */
@media (max-width: 700px) {
    .global-search-wrap {
        flex: 0 0 40px;
        width: 40px;
        max-width: 40px;
        margin: 0 !important;               /* beats cr-design's margin !important */
        transition: none;
    }
    .global-search-wrap > input,
    .global-search-wrap > div > input,
    #global-search,
    #globalSearchInput {
        width: 40px !important;             /* beats cr-design's width !important */
        height: 40px;
        padding: 0 !important;              /* beats cr-design's padding !important */
        cursor: pointer;
        color: transparent;
        /* beats the `background:` shorthand !important in cr-design.css */
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") !important;
        background-repeat: no-repeat !important;
        background-position: center !important;
    }
    .global-search-wrap > input::placeholder,
    #global-search::placeholder,
    #globalSearchInput::placeholder { color: transparent; }

    .global-search-wrap:focus-within {
        position: absolute;
        left: max(10px, var(--d9-safe-l));
        right: max(10px, var(--d9-safe-r));
        width: auto;
        max-width: none;
        flex: none;
        z-index: 30;
    }
    .global-search-wrap:focus-within > input,
    .global-search-wrap:focus-within > div > input,
    .global-search-wrap:focus-within #global-search,
    .global-search-wrap:focus-within #globalSearchInput {
        width: 100% !important;
        color: inherit;
        padding: 0 14px 0 38px !important;
        background-position: 12px center !important;
        font-size: 16px !important;         /* ≥16px or iOS zooms the page in */
    }
    .global-search-wrap:focus-within > input::placeholder { color: var(--cr-muted, #64748B); }

    /* The keyboard-shortcut chip is noise on a device with no keyboard. */
    #globalSearchKbd { display: none !important; }
}

/* --- 2c. Content wrapper gutters ---------------------------------------- */
.content-wrapper {
    /* !important: d9-unify.css collapses this to `padding: 10px !important`
       below 480px, which would drop the safe-area padding with it. */
    padding-left: max(var(--d9-gutter), var(--d9-safe-l)) !important;
    padding-right: max(var(--d9-gutter), var(--d9-safe-r)) !important;
    padding-bottom: max(var(--d9-gutter), var(--d9-safe-b)) !important;
}
@media (max-width: 768px) { :root { --d9-gutter: 16px; } }
@media (max-width: 480px) { :root { --d9-gutter: 12px; } }

/* ============================================================================
   3. LAYOUT GRIDS
   ----------------------------------------------------------------------------
   ~17 places in inc/pages/*.php and public/_marketplaces_core.php set rigid
   track lists (`1fr 1fr`, `2fr 1fr`, `1fr 2fr 70px 90px`, `230px 1fr`, …) via
   an inline style="" attribute, which no stylesheet can override without
   !important. Rather than editing markup in a 12k-line legacy file, collapse
   them here: match the inline attribute, skip the ones that are already fluid
   (auto-fit / auto-fill / a single 1fr), and flatten the rest.

   Measured effect: a two-up .grid-2 on a 375px phone gave each column ~165px,
   which clipped 112px off every text input inside it.
   ========================================================================== */

@media (max-width: 700px) {
    .content-wrapper [style*="grid-template-columns"]:not([style*="auto-fit"]):not([style*="auto-fill"]),
    .d9-modal [style*="grid-template-columns"]:not([style*="auto-fit"]):not([style*="auto-fill"]),
    .modal [style*="grid-template-columns"]:not([style*="auto-fit"]):not([style*="auto-fill"]) {
        grid-template-columns: minmax(0, 1fr) !important;
    }
    /* Anything that spanned two columns now spans the only column. */
    .content-wrapper .span2,
    .d9-modal .span2,
    .modal .span2 { grid-column: auto !important; }
}

/* Named two-up grids collapse a little earlier — they hold cards, not fields. */
@media (max-width: 900px) {
    .content-wrapper .grid-2,
    .content-wrapper .dsh-grid,
    .content-wrapper .pf-grid,
    .d9-modal .grid-2 {
        grid-template-columns: minmax(0, 1fr) !important;
    }
}

/* Fluid grids keep their auto-fit behaviour but must be allowed to go
   narrower than their minmax() floor once the viewport is smaller than it. */
.content-wrapper [style*="minmax"],
.content-wrapper .inv-kpis,
.content-wrapper .mp-stats,
.content-wrapper .credit-packs { min-width: 0; }

@media (max-width: 480px) {
    /* Two-up KPI tiles read better than one enormous one. */
    .content-wrapper .inv-kpis,
    .content-wrapper .mp-stats {
        grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
        display: grid !important;           /* beats d9-unify's flex scroll strip */
        overflow: visible !important;
    }
    .content-wrapper .mp-stats .mp-stat { min-width: 0; }
}

/* ============================================================================
   4. PAGE FURNITURE — heroes, tab strips, toolbars, quick-nav
   ========================================================================== */

/* --- Hero banners (.mp-header) ------------------------------------------
   These carry overflow:hidden for their gradient wash, so anything wider
   than the banner is silently cut off. On a 375px phone the pill row was
   377px inside a 355px banner: 22px of it simply disappeared. */
.mp-header { flex-wrap: wrap; }
.mp-header > * { min-width: 0; }
.mp-header h2 { overflow-wrap: anywhere; }

@media (max-width: 768px) {
    .mp-header {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
        /* cr-modernize.css sets `padding: 22px 26px !important` on the shared
           gradient-banner mixin, so this has to match its weight. */
        padding: 16px !important;
        border-radius: 14px;
    }
    .mp-header h2 { font-size: 18px; line-height: 1.3; }
    .mp-header small { font-size: 12.5px; }
    /* The pill row scrolls as a strip instead of being clipped. */
    .mp-header > div:last-child {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
    }
    .hero-pill { font-size: 11.5px; }
}
@media (max-width: 480px) {
    .mp-header { padding: 14px; }
    .mp-header h2 { font-size: 16.5px; }
}

/* --- Tab strips (.mp-tabs) ----------------------------------------------
   Already overflow-x:auto, but with no affordance the extra tabs are
   invisible. Add edge fades, hide the scrollbar, and snap. */
.mp-tabs {
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
}
.mp-tabs::-webkit-scrollbar { display: none; }
.mp-tabs .mp-tab { scroll-snap-align: start; }

@media (max-width: 768px) {
    .mp-tabs {
        /* Lea Verou scroll shadows: the two `local` cover layers sit on the
           content and hide the fixed shadow gradients when you are at that
           end. The cover colour must match what is BEHIND the strip — the
           page background, since a tab strip is not inside a card. Both stops
           of a cover gradient are the same colour so it never hazes. */
        background:
            linear-gradient(90deg, #F8FAFC 30%, rgba(248,250,252,0)) left center / 28px 100% no-repeat local,
            linear-gradient(90deg, rgba(248,250,252,0), #F8FAFC 70%) right center / 28px 100% no-repeat local,
            linear-gradient(90deg, rgba(15,23,42,.10), rgba(15,23,42,0)) left center / 16px 100% no-repeat scroll,
            linear-gradient(90deg, rgba(15,23,42,0), rgba(15,23,42,.10)) right center / 16px 100% no-repeat scroll;
    }
    .mp-tab {
        padding: 12px 14px;
        min-height: var(--d9-tap);
        display: inline-flex;
        align-items: center;
        gap: 6px;
        font-size: 13px;
    }
}
@media (max-width: 768px) {
    body.dark-mode .mp-tabs {
        background:
            linear-gradient(90deg, #0B111F 30%, rgba(11,17,31,0)) left center / 28px 100% no-repeat local,
            linear-gradient(90deg, rgba(11,17,31,0), #0B111F 70%) right center / 28px 100% no-repeat local,
            linear-gradient(90deg, rgba(0,0,0,.45), rgba(0,0,0,0)) left center / 16px 100% no-repeat scroll,
            linear-gradient(90deg, rgba(0,0,0,0), rgba(0,0,0,.45)) right center / 16px 100% no-repeat scroll;
    }
}

/* --- Toolbars / action rows ---------------------------------------------
   Most are inline `display:flex` with an auto-margin search form. On a phone
   the form must own its own line and fill it. */
@media (max-width: 768px) {
    .content-wrapper .actions,
    .content-wrapper .mp-toolbar,
    .content-wrapper .mp-cmdbar,
    .content-wrapper .filter-bar,
    .content-wrapper .form-row {
        flex-wrap: wrap !important;
    }
    /* Search/filter forms pushed right with margin-left:auto go full width. */
    .content-wrapper .actions form[style*="margin-left:auto"],
    .content-wrapper .actions > form {
        margin-left: 0 !important;
        width: 100%;
    }
    .content-wrapper .actions > form > input[type="search"],
    .content-wrapper .actions > form > input[type="text"] {
        flex: 1 1 160px;
        min-width: 0 !important;            /* beats inline min-width:170px */
    }
    /* Buttons in a toolbar share the row evenly rather than orphaning one. */
    .content-wrapper .actions > .btn-primary,
    .content-wrapper .actions > .btn-outline,
    .content-wrapper .actions > .btn {
        flex: 1 1 auto;
        justify-content: center;
        text-align: center;
    }
}

/* --- Quick-nav tiles (.st-nav, emitted inline by settings_quicknav()) ---- */
@media (max-width: 768px) {
    /* !important: settings_quicknav() in inc/layout.php emits its own <style>
       block into the body, i.e. after this file in the document. */
    .st-nav { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 8px; }
    .st-tile { min-height: var(--d9-tap); padding: 10px; }
}
@media (max-width: 420px) {
    .st-nav { grid-template-columns: minmax(0, 1fr) !important; }
}

/* --- Filter sidebar as a disclosure (.inv2-side) -------------------------
   The Inventory / Orders / Messages filter panel stacks above the listings on
   a phone. At ~550px tall that pushed the first product card 1250px down the
   page. responsive.js wraps the panel body and injects .inv2-fold-btn; these
   rules are the visual half of that. The page's own stylesheet inside
   public/_marketplaces_core.php owns everything else about .inv2-*.

   920px, not one of the scale values at the top of this file: it is the width
   at which _marketplaces_core.php switches .inv2-layout to a column, and the
   fold is only meaningful once the panel is stacked above the content. Keep
   this in sync with that rule AND with PHONE in responsive.js. */

.inv2-fold-btn,
.inv2-fold-ct { display: none; }        /* both are injected by responsive.js */

@media (max-width: 920px) {
    .inv2-side .inv2-fhead {
        cursor: pointer;
        gap: 10px;
        min-height: var(--d9-tap);
        margin-bottom: 0;
    }
    /* "N applied" badge, so a collapsed panel never hides an active filter. */
    .inv2-side .inv2-fold-ct {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 20px;
        height: 20px;
        margin-right: auto;
        padding: 0 6px;
        border-radius: 999px;
        background: var(--mk-primary-soft, #eef2ff);
        color: var(--mk-primary, #4338ca);
        font-size: 11px;
        font-weight: 800;
    }
    .inv2-side .inv2-fhead .t { margin-right: 8px; }
    .inv2-side .inv2-fhead:not(:has(.inv2-fold-ct)) .t { margin-right: auto; }
    /* Reset is a bare 17px-tall text link — give it a real hit area. */
    .inv2-side .inv2-fhead > a {
        display: inline-flex;
        align-items: center;
        min-height: 36px;
        padding: 0 8px;
        border-radius: 8px;
    }
    .inv2-side .inv2-fold-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        flex: 0 0 auto;
        border: 1px solid var(--cr-border, #E2E8F0);
        border-radius: 9px;
        background: transparent;
        color: var(--cr-muted, #64748B);
        cursor: pointer;
        font-size: 12px;
    }
    .inv2-side .inv2-fold-btn i { transition: transform .18s ease; }
    .inv2-side:not(.is-folded) .inv2-fold-btn i { transform: rotate(180deg); }

    .inv2-side .inv2-side-body { padding-top: 12px; }
    .inv2-side.is-folded .inv2-side-body { display: none; }
    .inv2-side.is-folded { padding: 8px 12px; }

    /* Filter rows are links in a tight list — give them a real hit area. */
    .inv2-qf a,
    .inv2-sec-body a { min-height: var(--d9-tap); }
    .inv2-sec summary { min-height: var(--d9-tap); }

    body.dark-mode .inv2-side .inv2-fold-btn {
        border-color: var(--mk-border, #374151);
        color: #cbd5e1;
    }
}

/* --- Inventory page: mobile information architecture ---------------------
   Visual half of invSetup() in responsive.js. The bands are re-ordered with
   flex `order` on .page rather than by moving them, so the DOM (and every
   inline onclick in _marketplaces_core.php) stays as the server wrote it.
   Reading order below the breakpoint:

       insights → search → channels → [Filters | Sort | View | ⋯] → grid

   .inv2-mobile is added by the script, so none of this can fire on a page
   the script did not restructure. */

.inv2-mbar,
.inv2-mpanel { display: none; }

@media (max-width: 920px) {
    .page.inv2-mobile { display: flex; flex-direction: column; }
    .page.inv2-mobile > *              { order: 7; }
    .page.inv2-mobile > .inv-insights  { order: 1; }
    .page.inv2-mobile > .inv2-cmd      { order: 2; }
    .page.inv2-mobile > .inv2-tabsrow  { order: 3; }
    .page.inv2-mobile > .inv2-mbar     { order: 4; }
    .page.inv2-mobile > .inv2-mpanel   { order: 5; }
    .page.inv2-mobile > .inv2-layout   { order: 6; }
    /* The <h1> repeats the app bar's title and the subtitle is desktop
       marketing copy; the controls have moved into .inv2-mpanel. */
    .page.inv2-mobile > .inv2-head     { display: none; }

    /* Insights: one scrollable line instead of a two-line wrap. */
    .inv2-mobile .inv-insights-bar {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }
    .inv2-mobile .inv-insights-bar::-webkit-scrollbar { display: none; }

    /* Search owns its own full-width band. */
    .inv2-mobile .inv2-cmd { margin: 0 0 10px; gap: 8px; }
    .inv2-mobile .inv2-cmd .mp-search { flex: 1 1 100%; min-width: 0; }

    /* One control bar. */
    .inv2-mbar {
        display: flex;
        gap: 8px;
        align-items: stretch;
        margin: 0 0 12px;
    }
    .inv2-mbar .inv2-mbtn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 7px;
        min-height: var(--d9-tap);
        padding: 0 14px;
        background: var(--mk-surface, #fff);
        border: 1px solid var(--cr-border, #e3e6f0);
        border-radius: 11px;
        font-family: inherit;
        font-size: 12.5px;
        font-weight: 700;
        color: #3a4157;
        cursor: pointer;
        white-space: nowrap;
    }
    .inv2-mbar .inv2-mbtn.is-on {
        border-color: var(--mk-primary, #4338ca);
        background: var(--mk-primary-soft, #eef2ff);
        color: var(--mk-primary, #4338ca);
    }
    .inv2-mbar .inv2-mct {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 18px;
        height: 18px;
        padding: 0 5px;
        border-radius: 999px;
        background: var(--mk-primary, #4338ca);
        color: #fff;
        font-size: 10.5px;
        font-weight: 800;
    }
    .inv2-mbar .inv2-mbtn-filters { flex: 1 1 auto; min-width: 0; }
    .inv2-mbar .inv2-mbtn-more    { flex: 0 0 var(--d9-tap); padding: 0; font-size: 15px; }
    .inv2-mbar .inv2-sort {
        flex: 1 1 auto;
        min-width: 0;
        min-height: var(--d9-tap);
        margin: 0;
        /* No vertical padding: §5 already gives the select a 44px min-height,
           and the wrapper's own 8px padding stacked on top of it made every
           control in the bar 62px tall. */
        padding: 0 0 0 10px;
    }
    .inv2-mbar .inv2-sort select {
        flex: 1 1 auto;
        min-width: 0;
        width: 100%;
        align-self: stretch;        /* the select IS the tap target, not the label */
        padding-right: 10px;
    }

    /* ⋯ panel — the rare page actions, laid out two-up. */
    .inv2-mpanel {
        display: block;
        margin: 0 0 12px;
        padding: 12px;
        background: var(--mk-surface, #fff);
        border: 1px solid var(--cr-border, #e3e6f0);
        border-radius: 12px;
    }
    .inv2-mpanel[hidden] { display: none; }
    .inv2-mpanel .inv2-head-r {
        width: 100%;
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
        align-items: stretch;
    }
    .inv2-mpanel .inv2-head-r > * { min-width: 0; margin: 0; }
    .inv2-mpanel .inv2-views,
    .inv2-mpanel .mp-selall-lbl,
    .inv2-mpanel .cg { grid-column: 1 / -1; }
    .inv2-mpanel .inv2-btn,
    .inv2-mpanel .inv2-acct-sel {
        width: 100%;
        min-height: var(--d9-tap);
        justify-content: center;
        max-width: none;
    }
    .inv2-mpanel .inv2-btn.icon-only { padding: 0; }
    .inv2-mpanel .mp-selall-lbl,
    .inv2-mpanel .cg { display: flex; align-items: center; gap: 8px; min-height: var(--d9-tap); }
    .inv2-mpanel .cg .mp-pp-sel { flex: 1 1 auto; min-width: 0; }
    /* grid-column, not width:100% — in a two-track grid a lone button would
       otherwise fill one track and leave the row half empty. */
    .inv2-mpanel .mp-dens-btn {
        grid-column: 1 / -1;
        width: 100%;
        justify-content: center;
        min-height: var(--d9-tap);
    }
    /* View toggle spans the panel and splits evenly — it reads as a segmented
       control rather than a stray pair of buttons. */
    .inv2-mpanel .mp-vtoggle {
        grid-column: 1 / -1;
        display: flex;
        width: 100%;
    }
    .inv2-mpanel .mp-vtoggle button { flex: 1 1 0; justify-content: center; min-height: 40px; }

    /* The bar owns the filter toggle here, so the panel's own header chrome
       is redundant and the collapsed panel takes no vertical space at all. */
    .inv2-mobile .inv2-side.is-folded { display: none; }
    .inv2-mobile .inv2-fold-btn,
    .inv2-mobile .inv2-fold-ct { display: none; }

    /* Add Item floats over the grid — always reachable, costs no page height.
       Two classes so it outranks the page's own `.inv2-btn-primary
       { min-height:44px }`, which _marketplaces_core.php emits from a <style>
       block further down the document. */
    .inv2-btn-primary.inv2-fab,
    .inv2-fab {
        display: inline-flex !important;
        position: fixed;
        right: max(14px, var(--d9-safe-r));
        bottom: calc(14px + var(--d9-safe-b));
        z-index: 8000;                  /* under .mp-bulkbar, which is 9000 */
        min-height: 52px;
        padding: 0 20px;
        border-radius: 999px;
        box-shadow: 0 10px 28px rgba(67, 56, 202, .42);
    }
    /* The bulk-action bar owns the bottom of the screen while rows are picked. */
    body:has(.mp-bulkbar.show) .inv2-fab { opacity: 0; pointer-events: none; }
    /* Keep the last card clear of the floating button. */
    .inv2-mobile .mp-grid,
    .inv2-mobile #mpInvTableWrap { padding-bottom: 76px; }

    body.dark-mode .inv2-mbar .inv2-mbtn,
    body.dark-mode .inv2-mpanel {
        background: #1f2937;
        border-color: #374151;
        color: #cbd5e1;
    }
}

/* --- Breadcrumbs --------------------------------------------------------- */
@media (max-width: 768px) {
    .breadcrumbs {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 4px 6px;
        font-size: 12.5px;
    }
    .breadcrumbs a { padding: 6px 0; }      /* 18px tall links were unhittable */
}

/* --- Pagination ---------------------------------------------------------- */
@media (max-width: 768px) {
    .pager {
        flex-wrap: wrap;
        gap: 10px;
        justify-content: space-between;
    }
    .pager a {
        min-height: var(--d9-tap);
        display: inline-flex;
        align-items: center;
        padding: 0 14px;
        border: 1px solid var(--cr-border, #E2E8F0);
        border-radius: 10px;
    }
    .pager span { order: 3; width: 100%; text-align: center; font-size: 12px; }
}

/* --- Cards --------------------------------------------------------------- */
@media (max-width: 768px) {
    .content-wrapper section.card,
    .content-wrapper .card { padding: 14px; border-radius: 12px; margin-bottom: 12px; }
}
@media (max-width: 480px) {
    .content-wrapper section.card,
    .content-wrapper .card { padding: 12px; }
}

/* ============================================================================
   5. TOUCH TARGETS
   ----------------------------------------------------------------------------
   Gated on (pointer: coarse) as well as width so a narrow desktop window
   keeps its compact density — the sizing is for fingers, not for small
   viewports. Baseline before this: buttons 36–40px, breadcrumb links 18px,
   row checkboxes 13px.
   ========================================================================== */

@media (max-width: 768px), (pointer: coarse) {
    .content-wrapper .btn,
    .content-wrapper .btn-primary,
    .content-wrapper .btn-outline,
    .content-wrapper .btn-secondary,
    .content-wrapper button:not(.btn-ghost):not(.d9-modal-close),
    .content-wrapper select,
    .content-wrapper input[type="submit"],
    .content-wrapper input[type="button"] {
        min-height: var(--d9-tap);
    }
    .content-wrapper .btn-ghost,
    .content-wrapper .btn-icon {
        min-width: var(--d9-tap);
        min-height: var(--d9-tap);
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    /* Row-select and settings checkboxes/radios. 24px is the WCAG 2.5.8 (AA)
       floor; they measured 13px before. */
    .content-wrapper input[type="checkbox"],
    .content-wrapper input[type="radio"] {
        width: 24px;
        height: 24px;
        flex: 0 0 auto;
        accent-color: var(--mk-primary, #4338ca);
    }
    /* Table cells that only hold a checkbox get a real hit area around it. */
    .content-wrapper td:has(> input[type="checkbox"]) { padding: 10px; }
    .header-user button,
    .header-user #darkModeToggle { min-width: var(--d9-tap); min-height: var(--d9-tap); }
}

/* Kill the 300ms tap delay and the grey flash on iOS/Android. */
@media (pointer: coarse) {
    a, button, [role="button"], input, select, textarea, label, summary {
        touch-action: manipulation;
        -webkit-tap-highlight-color: rgba(67, 56, 202, .12);
    }
    /* Hover lifts read as stuck state on touch — drop them. */
    .content-wrapper .card:hover,
    .content-wrapper .mp-stat:hover,
    .content-wrapper .inv-kpi:hover,
    .content-wrapper .credit-pack:hover,
    .st-tile:hover,
    .content-wrapper .mp-gcard:hover { transform: none; }
}

/* ============================================================================
   6. FORMS
   ----------------------------------------------------------------------------
   The app's controls run 12.5–15px. Safari on iOS zooms the whole page in
   whenever a focused control is under 16px and there is no way to zoom back
   out with one hand. Every control goes to 16px on small screens.
   ========================================================================== */

@media (max-width: 768px) {
    /* Deliberately global — the marketing pages, the login card and the scan
       screens all have their own shells, and every one of them shipped 13–15px
       controls. Toggles and sliders are excluded; they are sized in §5. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
    select,
    textarea,
    .form-control {
        font-size: 16px !important;         /* beats per-page <style> blocks */
        max-width: 100%;
        min-width: 0;
    }
    /* cr-design.css pins the global search to 13px through an #id selector,
       which outranks the rule above. Below 700px it is collapsed (§2b) so the
       size is moot, but 701–768px shows it expanded. */
    #global-search,
    #globalSearchInput { font-size: 16px !important; }
    /* Field grids are always one column on a phone. */
    .content-wrapper .form-grid,
    .content-wrapper .form-row,
    .d9-modal .form-grid {
        grid-template-columns: minmax(0, 1fr) !important;
    }
    .content-wrapper label { font-size: 13.5px; }

    /* Sticky form footers: the primary action stays reachable in a long form. */
    .content-wrapper .form-actions,
    .content-wrapper .card > .btn-primary:last-child { width: 100%; }
    .content-wrapper .card > .btn-primary:last-child { justify-content: center; }
}

/* Native pickers and steppers behave better when the browser knows the type. */
@media (max-width: 768px) {
    .content-wrapper input[type="number"] { -moz-appearance: textfield; }
}

/* ============================================================================
   7. TABLES
   ----------------------------------------------------------------------------
   Two strategies, chosen by how much a table can lose:

   (a) ≤ 768px  — every table scrolls horizontally inside its own wrapper
                  with edge shadows and a sticky header, never the page.
   (b) ≤ 600px  — data tables that responsive.js could label collapse into
                  stacked record cards (`data-stack`). A 9-column orders grid
                  is unreadable at 375px however you scroll it.

   responsive.js wraps naked tables and copies each column's <th> text onto
   its cells as data-label. With JS off you still get (a).
   ========================================================================== */

.d9-table-wrap,
.mp-table-wrap,
.table-responsive {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}

@media (max-width: 768px) {
    .d9-table-wrap,
    .mp-table-wrap,
    .table-responsive {
        background:
            /* A wrapped table sits inside a card, so the cover colour is the
               card surface. Dark mode is handled at the end of this block. */
            linear-gradient(90deg, #FFFFFF 30%, rgba(255,255,255,0)) left center / 24px 100% no-repeat local,
            linear-gradient(90deg, rgba(255,255,255,0), #FFFFFF 70%) right center / 24px 100% no-repeat local,
            linear-gradient(90deg, rgba(15,23,42,.09), rgba(15,23,42,0)) left center / 14px 100% no-repeat scroll,
            linear-gradient(90deg, rgba(15,23,42,0), rgba(15,23,42,.09)) right center / 14px 100% no-repeat scroll;
    }
    body.dark-mode .d9-table-wrap,
    body.dark-mode .mp-table-wrap,
    body.dark-mode .table-responsive {
        background:
            linear-gradient(90deg, #1E1E1E 30%, rgba(30,30,30,0)) left center / 24px 100% no-repeat local,
            linear-gradient(90deg, rgba(30,30,30,0), #1E1E1E 70%) right center / 24px 100% no-repeat local,
            linear-gradient(90deg, rgba(0,0,0,.5), rgba(0,0,0,0)) left center / 14px 100% no-repeat scroll,
            linear-gradient(90deg, rgba(0,0,0,0), rgba(0,0,0,.5)) right center / 14px 100% no-repeat scroll;
    }
    /* d9-unify turned the table itself into a scroll box at this width, which
       breaks sticky headers and the wrapper's shadows. The wrapper owns it.
       Stacked tables (below) are the exception — they must stay display:block. */
    .content-wrapper .card .d9-table-wrap table,
    .content-wrapper .card > table {
        display: table !important;
        overflow: visible !important;
    }
    /* The stray negative margin on .d9-table-wrap matched an 18px card pad
       that is 14px on phones — re-match it so the fades sit on the edge. */
    .d9-table-wrap { margin: 0 -14px; padding: 0 14px; }
}

/* --- (b) Stacked record cards ------------------------------------------- */
@media (max-width: 600px) {
    .d9-table-wrap[data-stack] {
        overflow: visible;
        margin: 0;
        padding: 0;
        background: none;
    }
    /* The long selector matches the weight of the ≤768px "wrapper owns the
       scroll" rule above (0,3,1); the short one covers wraps outside a card. */
    .content-wrapper .card .d9-table-wrap[data-stack] table,
    .d9-table-wrap[data-stack] table {
        display: block !important;          /* beats d9-unify's display:block→table dance */
        min-width: 0 !important;            /* beats d9-unify's min-width:640px */
        overflow: visible !important;
        border-collapse: separate;
        border-spacing: 0;
    }
    .d9-table-wrap[data-stack] thead {
        /* Visually hidden, still announced to screen readers. */
        display: block;                     /* width:1px is ignored on a table-header-group */
        position: absolute;
        width: 1px; height: 1px;
        margin: -1px; padding: 0;
        overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
        white-space: nowrap;
    }
    .d9-table-wrap[data-stack] tbody { display: block; }
    .d9-table-wrap[data-stack] tbody tr {
        display: block;
        border: 1px solid var(--cr-border, #E2E8F0);
        border-radius: 12px;
        padding: 4px 12px;
        margin-bottom: 10px;
        background: var(--cr-surface, #fff);
        box-shadow: var(--cr-shadow-sm, 0 1px 2px rgba(15,23,42,.06));
    }
    .d9-table-wrap[data-stack] tbody td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 14px;
        width: auto !important;
        padding: 8px 0 !important;
        border: 0;
        border-bottom: 1px solid var(--cr-border-soft, #F1F5F9);
        text-align: right;
        font-size: 13.5px;
    }
    .d9-table-wrap[data-stack] tbody td:last-child { border-bottom: 0; }
    /* The column name, carried over by responsive.js. */
    .d9-table-wrap[data-stack] tbody td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        text-align: left;
        font-size: 11px;
        font-weight: 700;
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--cr-muted, #64748B);
        white-space: nowrap;
    }
    /* Cells with no header (row-select, action columns) skip the label and
       sit full width — they read as the card's own controls. */
    .d9-table-wrap[data-stack] tbody td[data-label=""]::before,
    .d9-table-wrap[data-stack] tbody td:not([data-label])::before { content: none; }
    .d9-table-wrap[data-stack] tbody td[data-label=""] { justify-content: flex-start; }
    /* Numbers stay tabular and right-aligned, which is the point of .num. */
    .d9-table-wrap[data-stack] tbody td.num { font-variant-numeric: tabular-nums; }
    .d9-table-wrap[data-stack] tbody td > * { min-width: 0; }
    /* In a stacked card the row's link is the primary tap target. */
    .d9-table-wrap[data-stack] tbody td a {
        display: inline-flex;
        align-items: center;
        min-height: 28px;
    }

    /* A translucent lift rather than a fixed colour: the card underneath is
       #1E1E1E in dark-mode.css but #15142E where the d9 variables win, and a
       tint reads correctly on either. */
    body.dark-mode .d9-table-wrap[data-stack] tbody tr {
        background: rgba(255, 255, 255, .045);
        border-color: rgba(255, 255, 255, .11);
    }
    body.dark-mode .d9-table-wrap[data-stack] tbody td { border-bottom-color: rgba(255, 255, 255, .08); }
}

/* Sticky header for the scrolling variant (tall tables on a tablet). */
@media (min-width: 601px) and (max-width: 992px) {
    .d9-table-wrap thead th {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--cr-surface, #fff);
    }
    body.dark-mode .d9-table-wrap thead th { background: var(--mk-surface, #15142e); }
}

/* ============================================================================
   8. MODALS → bottom sheets on phones
   ========================================================================== */

@media (max-width: 640px) {
    .d9-modal-backdrop {
        /* d9-unify.css centres and pads every backdrop with !important so the
           dialog clears the fixed sidebar; on a phone there is no sidebar to
           clear and the sheet should own the bottom edge. */
        padding: 0 !important;
        align-items: flex-end !important;   /* sheet rises from the bottom */
    }
    .d9-modal,
    .d9-modal.order-modal {
        width: 100% !important;
        max-width: 100% !important;
        max-height: 92dvh;
        border-radius: 18px 18px 0 0;
        padding-bottom: var(--d9-safe-b);
        animation: d9SheetUp .24s cubic-bezier(.32, .72, 0, 1);
    }
    .d9-modal-head {
        position: sticky;
        top: 0;
        z-index: 2;
        padding: 14px 16px;
        background: inherit;
        /* Grab handle, so it reads as a sheet you can dismiss. */
        padding-top: 20px;
    }
    .d9-modal-head::before {
        content: '';
        position: absolute;
        top: 8px; left: 50%;
        transform: translateX(-50%);
        width: 36px; height: 4px;
        border-radius: 99px;
        background: var(--cr-border, #E2E8F0);
    }
    .d9-modal-close { min-width: var(--d9-tap); min-height: var(--d9-tap); font-size: 24px; }
    .d9-modal-body {
        padding: 16px;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }
    /* Nested cards inside a sheet lose their own chrome — one frame is enough. */
    .d9-modal-body section.card,
    .d9-modal-body .card { border: 0; box-shadow: none; padding: 0 0 12px; }

    /* The module's older .modal component gets the same treatment. */
    .modal .modal-dialog,
    .modal [class*="dialog"] {
        width: 100% !important;
        max-width: 100% !important;
        margin: 0 !important;
        border-radius: 18px 18px 0 0;
    }
}

@keyframes d9SheetUp { from { transform: translateY(14px); opacity: 0; } }

/* On any touch device a modal must not let the page behind it scroll. */
.d9-modal-backdrop { overscroll-behavior: contain; }

/* ============================================================================
   9. PUBLIC SITE — help (landing.css)
   NOTE: the front page, /contact, /terms and /privacy no longer load
   landing.css or this file — they share inc/public_chrome.php and the
   self-contained /assets/css/home.css (mobile-first breakpoints baked in).
   Section 9 now only serves /help.
   ========================================================================== */

/* --- 9a. The hero product mock -----------------------------------------
   .mock's min-content width is 369px. Inside .hero .wrap (331px of content
   box on a 375px phone) it overflowed by 38px and .hero{overflow:hidden}
   cut it off. Let its rows wrap instead. */
.hero .wrap > * { min-width: 0; }
.mock { min-width: 0; max-width: 100%; }

@media (max-width: 700px) {
    .mock-row { flex-wrap: wrap; row-gap: 6px; }
    .mock-row .nm { flex: 1 1 100%; order: 1; white-space: normal; }
    .mock-row .ph { order: 0; }
    .mock-row .pr { order: 2; margin-left: auto; }
    .mock-row .st { order: 3; }
    .mock-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .mock-kpi { padding: 9px 8px; }
    .mock-kpi b { font-size: 15px; }
    .mock-toast { flex-wrap: wrap; }
}

/* --- 9b. Fluid type so the marketing pages scale instead of jumping ----- */
.hero .lead { font-size: clamp(15.5px, 1.1vw + 12px, 18px); }
.block h2 { font-size: clamp(24px, 2.4vw + 12px, 38px); }
.block .sub { font-size: clamp(14.5px, .6vw + 12px, 16.5px); }

/* --- 9c. Mobile navigation ---------------------------------------------
   landing.css hid every nav link below 900px and the Login button below
   520px, so a phone visitor had no navigation at all — just a bare CTA.
   home.php / legal.php / help.php now emit a checkbox + label ahead of the
   <nav>, and the trial CTA moved out of the <nav> so it can stay in the bar.
   These pages are zero-JS and nginx-cached, so the menu is CSS-only. */

/* Visually hidden, NOT display:none — it must stay focusable so the menu is
   reachable by keyboard, and label-activation stays reliable. */
.nav-toggle {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
    white-space: nowrap;
}
.nav-toggle-label { display: none; }

/* Screen-reader-only text (the menu button's accessible name). */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
    white-space: nowrap;
}

@media (max-width: 900px) {
    .site-head .wrap { position: relative; gap: 10px; }

    .nav-toggle-label {
        order: 3;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: var(--d9-tap);
        height: var(--d9-tap);
        flex: 0 0 auto;
        border: 1px solid var(--border, #E2E8F0);
        border-radius: 10px;
        color: var(--ink, #0F172A);
        cursor: pointer;
        font-size: 17px;
        background: var(--surface, #fff);
    }
    .nav-toggle-label .fa-xmark { display: none; }
    .nav-toggle:checked ~ .nav-toggle-label .fa-xmark { display: block; }
    .nav-toggle:checked ~ .nav-toggle-label .fa-bars { display: none; }
    .nav-toggle:focus-visible ~ .nav-toggle-label {
        outline: 2px solid var(--primary, #4338CA);
        outline-offset: 2px;
    }

    /* The trial CTA stays in the bar — it is the page's whole purpose. */
    .site-head .head-cta { order: 2; margin-left: auto; }

    /* The panel. landing.css's display:none is scoped to `.site-head nav > a`,
       so the links have to be re-shown explicitly inside it. */
    .site-head nav {
        order: 4;
        display: none;
        position: absolute;
        top: calc(100% + 10px);
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 2px;
        margin-left: 0;
        padding: 10px;
        background: var(--surface, #fff);
        border: 1px solid var(--border, #E2E8F0);
        border-radius: 14px;
        box-shadow: 0 24px 48px -20px rgba(15, 23, 42, .28);
        z-index: 60;
    }
    .nav-toggle:checked ~ nav { display: flex; animation: d9NavIn .18s ease-out; }
    .site-head nav > a:not(.btn-primary):not(.btn-outline) {
        display: flex !important;           /* beats landing.css's display:none */
        align-items: center;
        min-height: var(--d9-tap);
        padding: 0 12px;
        border-radius: 9px;
        font-size: 15px;
    }
    .site-head nav > a:not(.btn-primary):not(.btn-outline):hover { background: var(--soft, #F1F5F9); }
    .site-head nav > .btn-outline,
    .site-head nav > .btn-primary {
        display: flex !important;           /* the ≤520px rule hid Login too */
        align-items: center;
        justify-content: center;
        min-height: var(--d9-tap);
        margin-top: 6px;
    }
}

@media (max-width: 400px) {
    .site-head .head-cta { padding: 9px 12px; font-size: 13px; }
    .brand { font-size: 16px; }
    .brand img { width: 26px; height: 26px; }
}

@keyframes d9NavIn { from { opacity: 0; transform: translateY(-6px); } }

/* --- 9d. Everything else on the marketing pages -------------------------- */
@media (max-width: 640px) {
    .wrap { padding-left: max(18px, var(--d9-safe-l)); padding-right: max(18px, var(--d9-safe-r)); }
    .hero .cta { flex-direction: column; align-items: stretch; }
    .hero .cta .btn-primary,
    .hero .cta .btn-outline { justify-content: center; min-height: 48px; display: inline-flex; align-items: center; }
    .trust { gap: 6px; }
    /* The rotated "popular" ribbon on the pricing cards escaped its card. */
    .plan-card { overflow: hidden; }
    /* Full-width primary actions on the pricing and contact forms. */
    .cform button[type="submit"],
    .plan .btn-primary,
    .plan .btn-outline,
    .cta-inner .btn-primary { width: 100%; justify-content: center; min-height: 48px; }
}
@media (max-width: 480px) {
    .flow { grid-template-columns: minmax(0, 1fr); }
    .numbers .wrap { grid-template-columns: minmax(0, 1fr); }
    .mock-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
}

/* Footer links were 22px tall — under the 24px WCAG 2.5.8 floor. The panel
   rule above does not reach them (that <nav> is inside .site-foot). */
@media (max-width: 900px) {
    .site-foot .wrap { padding: 24px 22px; }
    .site-foot nav { flex-wrap: wrap; gap: 4px 18px; }
    .site-foot nav a { display: inline-flex; align-items: center; min-height: 32px; }
}

/* ============================================================================
   10. DESKTOP & WIDE
   ----------------------------------------------------------------------------
   The counterpart problem to mobile: with .page {max-width:none} a 2400px
   monitor stretched a card to 2342px, one KPI tile to 576px and a textarea
   to 1125px. Cap the working column and let grids gain columns instead.
   ========================================================================== */

@media (min-width: 1400px) {
    .content-wrapper > .page,
    .content-wrapper > .container,
    .content-wrapper > .mp-wrap {
        max-width: var(--d9-content-max);
        margin-inline: auto;
    }
}

@media (min-width: 1600px) {
    :root { --d9-gutter: 32px; }
    /* Denser stat bands rather than four enormous tiles. */
    .content-wrapper .inv-kpis { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .content-wrapper .mp-stats { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
    /* Long-form text stays readable instead of running the full width. */
    .content-wrapper .card > p,
    .content-wrapper .empty,
    .content-wrapper .hint { max-width: 78ch; }
    .content-wrapper textarea { max-width: 900px; }
}

@media (min-width: 1920px) {
    :root { --d9-content-max: 1720px; }
    .top-header .header-title h1 { font-size: 20px; }
}

/* Short laptop screens: give content the vertical room back. */
@media (min-width: 993px) and (max-height: 800px) {
    .content-wrapper { padding-top: 16px; }
    .sidebar-foot { display: none; }
}

/* ============================================================================
   11. ORIENTATION & SMALL VIEWPORTS
   ========================================================================== */

/* Phone in landscape: the chrome eats most of the screen. Trim it. */
@media (max-width: 926px) and (max-height: 460px) and (orientation: landscape) {
    .top-header { height: 48px; position: static; }
    .content-wrapper { padding-top: 12px; }
    .mp-header { padding: 12px 14px; }
    .d9-modal { max-height: 96dvh; }
    .sidebar-foot { display: none; }
}

/* Very narrow (320px) hardware still has to work. */
@media (max-width: 360px) {
    .content-wrapper section.card,
    .content-wrapper .card { padding: 10px; }
    .mp-header h2 { font-size: 15.5px; }
    .content-wrapper .btn-primary,
    .content-wrapper .btn-outline { padding-inline: 12px; font-size: 13px; }
    .st-nav { grid-template-columns: minmax(0, 1fr) !important; }
    /* Two KPI tiles do not fit at 320px once padding is counted. */
    .content-wrapper .inv-kpis,
    .content-wrapper .mp-stats { grid-template-columns: minmax(0, 1fr) !important; }
}

/* Where supported, use the dynamic viewport unit so mobile browser chrome
   collapsing does not leave a gap or a scroll. */
@supports (height: 100dvh) {
    .dashboard { min-height: 100dvh; }
    .main-content { min-height: 100dvh; }
}

/* ============================================================================
   12. ACCESSIBILITY & PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    .sidebar,
    .main-content,
    .content-wrapper,
    .d9-modal,
    .d9-modal-backdrop,
    .site-head nav { animation: none !important; transition: none !important; }
    html { scroll-behavior: auto; }
}

/* Anything sticky must clear a notch. */
.top-header { top: var(--d9-safe-t); }

@media print {
    .sidebar,
    .top-header,
    .mobile-menu-btn,
    .mobile-close-btn,
    .st-nav,
    .mp-tabs,
    .pager,
    .actions,
    .d9-modal-backdrop { display: none !important; }
    .main-content { margin-left: 0 !important; }
    .content-wrapper { padding: 0 !important; animation: none !important; }
    .content-wrapper > .page { max-width: none !important; }
    .content-wrapper section.card,
    .content-wrapper .card {
        break-inside: avoid;
        box-shadow: none !important;
        border-color: #ccc !important;
    }
    .d9-table-wrap { overflow: visible !important; background: none !important; }
    .d9-table-wrap table { min-width: 0 !important; }
    thead { display: table-header-group; }
    tr { break-inside: avoid; }
}
