/* ==========================================================================
   oms-mobile.css — the responsive layer for the three portals
   ==========================================================================

   ⚠️ LOAD THIS LAST — as the final element before </body>, NOT in <head>.

   Media queries add ZERO specificity. admin-new.html has a tail <style> block
   (~27173–27308) that sits inside <body>, after every <link>, and hardcodes
   .vw-add-panel{width:680px}, .vw-expanded-body{grid-template-columns:420px 1fr},
   .po-unified-left{flex:0 0 620px} and more. A head-linked sheet loses to all of
   them at equal specificity and would need !important to win — which
   DESIGN-SYSTEM.md §7 forbids. Loading last wins cleanly.

   No FOUC risk: all three portals keep the app hidden until an async auth
   round-trip completes (admin-new.html:475 style="display:none";
   factory-new.html / customers.html .portal{display:none}), so nothing of the
   app paints during initial parse. This file does not touch .lp-* (login).

   BREAKPOINTS — CSS cannot use variables in @media, so they live here as prose.

     900px  TOPOLOGY. Nav drawer, sidebar width token → 0, table scrollers,
            side panels/drawers capped to viewport, 16px form controls.
            Chosen over 860 because customers.html already switches
            #dash-main-grid at 900 — at 860 there'd be a 40px band where the
            dashboard is single-column but the sidebar still eats 240px.

     600px  DENSITY. Type/spacing step-down, multi-column grids → 1 col,
            full-bleed modals. Sits above every phone PORTRAIT width (Pro Max
            430) and below every phone LANDSCAPE width (iPhone 14 = 844), so
            turning a phone sideways gives wide tables their room back.

     1100px Reserved. admin-new.html:236 (.settings-grid) already lives here.

   Phase 1 = the 900px layer + the table scroller. Phase 2 adds the 600px
   density layer. Desktop is byte-for-byte unaffected: every rule below is
   inside a max-width query except the two inert defaults immediately below.
   ========================================================================== */


/* --------------------------------------------------------------------------
   INERT DEFAULTS (desktop)
   The nav chrome is injected into the DOM by oms-mobile.js on every viewport,
   so it must be hidden above the breakpoint. The table wrapper is likewise
   present but transparent: overflow:visible means the table spills exactly as
   it does today and .table-container keeps clipping it, unchanged.
   -------------------------------------------------------------------------- */
.oms-navbtn,
.oms-scrim        { display: none; }
.oms-tscroll-bar  { display: none; }
.oms-tscroll-view { overflow: visible; }


/* ==========================================================================
   ≤ 900px — TOPOLOGY
   ========================================================================== */
@media (max-width: 900px) {

/* ---------- Shell ------------------------------------------------------- */
/* ONE token clears the content offset everywhere at once. --sidebar-width is
   a live alias of --sez-sidebar-width (oms-design-system.css:153), so this
   also zeroes:
     .main-content margin-left  — oms-design-system.css:259 AND the inline
                                  duplicates at admin:29, factory:37,
                                  customers:31
     #quote-item-modal left     — admin-new.html:157/159
   The .sidebar width is re-declared explicitly below, so the drawer keeps a
   real width even though the token is 0. */
:root {
    --sez-sidebar-width: 0px;
    /* The open drawer's width. A plain px length so the off-canvas offset
       below can be a simple calc(-1 * this); the narrow-screen cap is a
       separate max-width on .sidebar rather than a min() in here. */
    --oms-drawer-w: 300px;
}

/* min-width:0 matters: factory-new.html:20 pins .app-container to
   min-width:900px (admin and customers do not). Left alone, the factory
   portal renders a 900px-wide body on a 390px phone — every page slides
   sideways by 520px and nothing else here can rescue it. */
.app-container { display: block; min-width: 0; }

/* ---------- Nav drawer -------------------------------------------------- */
/* Off-canvas rail + scrim + floating toggle. Ported from the pattern already
   shipping in OMS-Hub/public/kb.html:187-201.

   Z-BAND 99 / 100 / 101 — deliberately BELOW every existing overlay so an open
   modal covers the drawer chrome rather than fighting it:
     99  .oms-scrim        (verified unused elsewhere)
     100 .sidebar          (unchanged, oms-design-system.css:224)
     101 .oms-navbtn       (verified unused elsewhere) — above the open drawer
                            on purpose, so it doubles as the close button
     999  .overlay (admin:250)      1000 .overlay (customers:126) / .modal-overlay
     1001 .side-panel      1002 #quote-item-modal   1501 .cart-drawer
     9200 .msg-drawer      100000 .oms-dlg-overlay (ui-dialogs.js)

   ⚠️ THE DRAWER SLIDES ON `left`, NOT `transform` — DO NOT "OPTIMISE" THIS.
   A transform on .sidebar makes it a CONTAINING BLOCK for every
   position:fixed descendant, and .sidebar HAS two of them:
       #msgTriggerWrap  (.msg-trigger-wrap, z 996)  — the Messages launcher
       #msgHoverPreview (.msg-hover-preview, z 9000)
   Both are declared position:fixed in the portals' own <style> blocks
   (admin-new.html:318, factory-new.html:233), not inline on the element, so
   they are easy to miss. Under a transform they get captured by the drawer:
   the Messages tab rides off-screen whenever the drawer is closed — i.e.
   permanently — and lands on the drawer's right edge when it opens.
   Animating `left` creates no containing block, so both keep positioning
   against the viewport exactly as they do on desktop. */
.sidebar {
    width: var(--oms-drawer-w);
    max-width: 84vw;                    /* narrow phones keep a peek of page */
    left: calc(-1 * var(--oms-drawer-w));
    height: 100vh;
    height: 100dvh;                     /* no gap under the mobile URL bar */
    transition: left 220ms cubic-bezier(.2, 0, 0, 1);
    box-shadow: none;
}
body.oms-nav-open .sidebar {
    left: 0;
    box-shadow: 0 0 44px rgba(20, 22, 43, .30);
}

/* Right-edge floating launchers sit at z 995/996 — above the scrim (99) — so
   while the drawer is open they'd hover over the dimmed page and stay
   tappable. Fade them out rather than display:none: .msg-trigger-wrap's
   `display` is driven by an inline style the page's JS writes, which no
   stylesheet rule can beat. */
body.oms-nav-open .msg-trigger-wrap,
body.oms-nav-open .cart-fab { opacity: 0; pointer-events: none; }

.oms-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 99;
    background: rgba(20, 22, 43, .5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 200ms ease;
}
body.oms-nav-open .oms-scrim { opacity: 1; pointer-events: auto; }

.oms-navbtn {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    left: 12px;
    bottom: 12px;
    z-index: 101;
    width: 48px;
    height: 48px;
    padding: 0;
    border: none;
    border-radius: 14px;
    background: var(--of-accent-grad, var(--primary, #3D4EE8));
    box-shadow: 0 10px 26px -8px rgba(61, 78, 232, .75);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.oms-navbtn:active { transform: scale(.94); }
.oms-navbtn-i {
    width: 22px;
    height: 22px;
    stroke: #fff;
    fill: none;
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.oms-navbtn .oms-navbtn-x                        { display: none; }
body.oms-nav-open .oms-navbtn .oms-navbtn-bars   { display: none; }
body.oms-nav-open .oms-navbtn .oms-navbtn-x      { display: block; }

body.oms-nav-open { overflow: hidden; }          /* scroll lock behind drawer */

/* Keep pagination / the last table row clear of the floating button. */
.main-content { padding: 16px; padding-bottom: 76px; }

/* ---------- Form controls ----------------------------------------------- */
/* NON-NEGOTIABLE. iOS Safari force-zooms the whole page on focus for any form
   control under 16px, and --sez-text-md (14px, → 12px at ≤600) feeds every
   input in the design system. Consequence: fields read slightly larger than
   the text around them on a phone. That is deliberate — the alternative
   (maximum-scale=1 on the viewport meta) kills pinch-zoom and is not
   acceptable.

   Specificity here is fiddly, so it is spelled out rather than guessed:
   - The portals declare their own `.form-input { font-size: 14px }`
     (customers.html:43 and the equivalents in the other two). The `body`
     prefix takes ours to (0,1,1) so it wins outright rather than tying at
     (0,1,0) and depending on source order.
   - A BARE input needs more than that. oms-design-system.css:628 reaches
     those through `input[type="text"]` and friends — attribute selectors,
     so (0,1,1) — while `body input` is only (0,0,2) and loses. The `:not()`
     chain below carries its argument's specificity, lifting ours to (0,2,1).
     It also deliberately skips checkbox/radio/file, which are not text fields
     and never trigger the zoom. */
body input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
body select, body textarea,
body .form-input, body .form-select, body .edit-input,
body .table-toolbar .search-input,
body .table-toolbar input.search-input,
body .table-toolbar input[type="text"].search-input,
body .table-toolbar .filter-select,
body .table-toolbar select.filter-select { font-size: 16px; }

/* ---------- Components that are nowrap by construction ------------------ */
/* .page-header is flex + space-between (oms-design-system.css:269) — the title
   and its action buttons collide on a narrow screen. */
.page-header  { flex-wrap: wrap; }
.page-actions { flex-wrap: wrap; }

/* .table-toolbar is flex-wrap:nowrap (:476) and the search box is pinned to
   min-width:180px / max-width:360px (:485-490). Release both. */
.table-toolbar { flex-wrap: wrap; }
.table-toolbar .search-input,
.table-toolbar input.search-input,
.table-toolbar input[type="text"].search-input {
    flex: 1 1 100%;
    min-width: 0;
    max-width: none;
}
.table-toolbar .filter-select,
.table-toolbar select.filter-select { flex: 1 1 auto; min-width: 0; }
.table-toolbar .toolbar-spacer { flex-basis: 100%; height: 0; }

/* .tabs is flex + overflow:hidden with .tab-btn{flex:1} (:697-708), which
   crushes 5+ tabs into unreadable slivers. Scroll them instead. */
.tabs, .modal-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar,
.modal-tabs::-webkit-scrollbar { display: none; }
.tab-btn, .modal-tab {
    flex: 0 0 auto;
    white-space: nowrap;
    padding-left: 14px;
    padding-right: 14px;
}

/* `1fr` is shorthand for minmax(auto, 1fr), and that `auto` minimum is
   min-content — so a grid item holding a wide card pushes the column past its
   container instead of shrinking. customers.html guards against this on
   desktop (`minmax(0,1.8fr) minmax(0,1fr)`, line 439) but its own ≤900
   override drops the guard (`grid-template-columns:1fr`, line 447), which
   blows the dashboard ~15px wider than the viewport. Restore the guard. */
#dash-main-grid { grid-template-columns: minmax(0, 1fr); }

/* ---------- Side panels, drawers, modals -------------------------------- */
/* .side-panel is 882px in oms-design-system.css:826-840 and re-declared inline
   at admin:177 (882), factory:144 (700, NO cap at all) and customers:128
   (720/94vw). `right` has to be reset too — leaving right:-882px on a 390px
   screen still works but the panel flies in from 882px away and reads broken. */
.side-panel,
.side-panel.order-view {
    width: 100%;
    max-width: 100%;
    right: -100%;
}
.side-panel.open { right: 0; }
.side-panel.beside-cart { right: 0 !important; }   /* customers:234 pins it to --cart-w */
.panel-header { padding: var(--sez-space-4); }
.side-panel.order-view .panel-body { padding: 16px; }

.msg-drawer  { width: 100%; max-width: 100%; }     /* admin:334 is 480px uncapped */
.cart-drawer { width: 100%; max-width: 100%; right: -100%; }
.cart-drawer.open { right: 0; }

/* admin:157-158 reserves 882px on the right for the panel and offsets left by
   the sidebar. The token above already zeroed `left`; clear the reservation. */
#quote-item-modal { left: 0; right: 0; }
#quote-item-modal .modal { width: 100%; min-width: 0; max-width: 100%; margin: 0; }
body.no-quote-panel #quote-item-modal .modal { max-width: 100%; }

/* ---------- Visual Workspace (admin tail <style>, ~27173-27308) ---------- */
/* Reachable only because this file loads after that block — see the header. */
.vw-shell     { max-width: 100%; }
.vw-add-panel { width: 100%; }
.vw-body      { padding: 16px; }
.vw-header    { padding: 0 12px; }
.vw-info-grid,
.vw-upload-grid,
.vw-expanded-body,
.vw-logo-block-body { grid-template-columns: 1fr; }
.vw-body.po-unified-body { flex-direction: column; overflow-y: auto; }
.po-unified-left {
    flex: 0 0 auto;
    border-right: none;
    border-bottom: 1px solid var(--border);
}
.po-unified-left,
.po-unified-right { padding: 16px; overflow: visible; }

/* ---------- Table horizontal scroller ----------------------------------- */
/* Wrapper structure, built at runtime by oms-mobile.js:
       .oms-tscroll                     position:relative
         .oms-tscroll-bar               the "shifter" track
           .oms-tscroll-thumb           draggable, JS sets width/left
         .oms-tscroll-view              overflow-x:auto
           <table>

   WHY THIS DEFEATS .table-container{overflow:hidden} WITHOUT EDITING IT
   (oms-design-system.css:469, re-declared inline at admin:87 / customers:58):
   the scroll is consumed INSIDE .oms-tscroll-view, which is exactly the
   container's width. The container never sees an overflowing child, so its
   overflow:hidden clips nothing. Three edit sites avoided.

   WHY THE BAR IS A SIBLING, NOT position:sticky INSIDE THE SCROLLER: sticky
   inside a horizontal scroller drifts with the content, and sticky-to-page is
   defeated by that same enclosing overflow:hidden.

   WHY WE DRAW THE BAR INSTEAD OF STYLING A NATIVE SCROLLBAR: iOS uses overlay
   scrollbars that stay invisible until you touch, and ::-webkit-scrollbar
   cannot force them visible — so on the actual target device a styled native
   bar gives no affordance at all, which is the whole problem being solved. */
.oms-tscroll { position: relative; }

.oms-tscroll-view {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;      /* no accidental browser back-swipe */
    scrollbar-width: none;               /* we draw our own */
}
.oms-tscroll-view::-webkit-scrollbar { display: none; }

/* .is-scrollable is set by JS only when the table actually overflows, so a
   narrow table shows no bar at all. */
.oms-tscroll.is-scrollable > .oms-tscroll-bar {
    display: block;
    position: relative;
    height: 6px;
    margin: 8px 12px;
    border-radius: 999px;
    background: var(--of-line-strong, var(--border, #E5E7F0));
    touch-action: none;                  /* we own the drag gesture */
    cursor: grab;
}
.oms-tscroll.is-dragging > .oms-tscroll-bar { cursor: grabbing; }

.oms-tscroll-thumb {
    position: absolute;
    top: -4px;                           /* 14px tall over a 6px track */
    height: 14px;
    min-width: 34px;
    border-radius: 999px;
    background: var(--of-accent, var(--primary, #3D4EE8));
    box-shadow: 0 2px 6px -1px rgba(61, 78, 232, .5);
}

/* Right-edge fade — "there is more over there". Removed at the end of travel.
   top offset clears the bar; the gradient uses the card surface so it reads as
   the table dissolving rather than a grey box. */
.oms-tscroll.is-scrollable::after {
    content: "";
    position: absolute;
    top: 22px;
    right: 0;
    bottom: 0;
    width: 28px;
    pointer-events: none;
    opacity: 1;
    transition: opacity 150ms ease;
    background: linear-gradient(to right,
                rgba(255, 255, 255, 0), var(--surface, #fff));
}
.oms-tscroll.at-end::after { opacity: 0; }

} /* end ≤900 */


/* ==========================================================================
   ≤ 600px — DENSITY
   ========================================================================== */
@media (max-width: 600px) {

/* ---------- Stat cards / page filter tiles ------------------------------ */
/* `.stats-grid` is repeat(auto-fit, minmax(180px, 1fr)) (oms-design-system.css:394,
   re-declared at admin-new.html:56 and factory-new.html:96). On a 360px phone the
   content box is ~328px, so auto-fit resolves to a SINGLE column and the tiles
   stack one per line — five of them push the actual page content off the first
   screen. Pin them to three across instead.

   This grid is used for two different things and both want the same treatment:
   the dashboard counters, and the filter tiles that head the list pages
   (admin-new.html:829-834 All Orders / Draft / Visuals / Production / Shipping /
   Closed, and the equivalents on Products, POs and Customers).

   minmax(0, 1fr), never a bare 1fr: `1fr` means minmax(auto, 1fr) and that auto
   floor is min-content, so a long unbroken label like "B2B CUSTOMERS" would push
   the column past its share and blow the grid out sideways — the same trap
   #dash-main-grid hits above. */
.stats-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}
.stat-card {
    padding: 10px 8px;
    min-width: 0;
}
.stat-value { font-size: 20px; }
.stat-label {
    font-size: 9px;
    letter-spacing: 0.02em;
    margin-top: 2px;
    overflow-wrap: anywhere;      /* wrap rather than overflow the 3-up column */
}

} /* end ≤600 */


/* ==========================================================================
   PRINT — the injected chrome must never appear on paper, and a table has to
   print in full rather than clipped to its scroll window.
   ========================================================================== */
@media print {
    .oms-navbtn,
    .oms-scrim,
    .oms-tscroll-bar  { display: none !important; }
    .oms-tscroll-view { overflow: visible !important; }
    .oms-tscroll::after { display: none !important; }
}
