/*
 * mobile-v2.css — Torus mobile overhaul framework (2026-07-06).
 *
 * Loaded LAST so its scoped overrides win cascade ties. EVERY rule here lives
 * inside a media query (or under body.is-mobile / body.mob-nav-on, which
 * src/shared/platform/mobile.js only sets at ≤768px) — desktop rendering is untouched.
 *
 * Layers:
 *   1. Global mobile hygiene (≤768): tap targets, 16px inputs, no dbl-tap zoom
 *   2. Top-nav compression
 *   3. Sidebar → bottom tab bar (body.mob-nav-on, chrome built by src/shared/platform/mobile.js)
 *   4. Generic modal → bottom-sheet base for core shared modals
 *   5. Simplification: decorative layers off on phones
 *   6. Small-phone (≤480 / ≤360), landscape-short, tablet (769–1024) bands
 *
 * Per-tab refinements live as appended @media blocks in each tab's own CSS
 * file (same date stamp) — this file is only the shared framework.
 */

/* ═══ 1. Global mobile hygiene ══════════════════════════════════════════════ */
@media (max-width: 768px) {
  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }
  body {
    -webkit-tap-highlight-color: transparent;
  }
  /* Kill the 300ms double-tap-zoom delay on everything interactive */
  button, [role="button"], a, .nav-tab, input, select, textarea, label {
    touch-action: manipulation;
  }
  /* iOS zooms the page when focusing any input under 16px — hard floor it. */
  input, select, textarea {
    font-size: 16px !important;
  }
  /* Momentum + no scroll-chaining out of internal scrollers */
  .tab-panel, .tab-content {
    overscroll-behavior: contain;
  }
}

/* ═══ 2. Top nav compression (≤768) ═════════════════════════════════════════ */
@media (max-width: 768px) {
  .nav-top-row {
    padding: 6px 10px;
    gap: 8px;
    flex-wrap: nowrap;
  }
  /* Icon cluster scrolls horizontally instead of wrapping into a second row */
  .nav-controls {
    overflow-x: auto;
    flex-wrap: nowrap;
    scrollbar-width: none;
    -ms-overflow-style: none;
    gap: 6px;
    max-width: 100%;
  }
  .nav-controls::-webkit-scrollbar { display: none; }
  .nav-controls > * { flex: none; }

  /* Text labels → icon-only on phones */
  .nav-logout-btn span,
  .nav-help-btn .nav-help-label { display: none; }
  .nav-logout-btn { padding: 8px; }

  .nav-role-badge { max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
@media (max-width: 600px) {
  .nav-clock { display: none; }
}
@media (max-width: 480px) {
  .nav-logo-text { display: none; }        /* keep the mark + dept badge */
  .nav-top-row { padding: 6px 8px; }
}

/* ═══ 3. Sidebar → bottom tab bar ═══════════════════════════════════════════ */
/* Only when src/shared/platform/mobile.js confirmed activation (body.mob-nav-on). If that JS
   ever fails, none of this applies and the legacy slide-out sidebar remains. */
@media (max-width: 768px) {
  body.mob-nav-on #side-nav-v2,
  body.mob-nav-on .sidenav-edge-toggle { display: none !important; }

  /* Beat the GSAP inline styles that reserve sidebar space */
  body.mob-nav-on .dept-dashboard { padding-left: 0 !important; }
  body.mob-nav-on #main-nav {
    margin-left: 0 !important;
    padding-left: 0 !important;
  }

  /* Reserve space for the bar (+ home indicator) at the bottom of content */
  body.mob-nav-on .dept-dashboard {
    padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)) !important;
  }

  /* The bar */
  #mnav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    /* BELOW every modal/overlay (all >=1050) so open sheets cover the bar;
       above page content. Toasts/FABs that must clear the bar offset by 68px. */
    z-index: 999;
    display: flex;
    align-items: stretch;
    height: calc(60px + env(safe-area-inset-bottom, 0px));
    padding: 0 4px env(safe-area-inset-bottom, 0px);
    /* Opaque, not glass — see §14 at the foot of this file for the measurement
       and the reason the blur cannot be relied on. Kept in sync here so this
       block never states a value the page does not actually render. */
    background: #060915;
    border-top: 1px solid rgba(56, 189, 248, 0.18);
  }
  html[data-theme="light"] #mnav {
    background: #f6f9ff;
    border-top-color: rgba(10, 16, 32, 0.12);
  }
  .mnav-btn {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    background: none;
    border: 0;
    padding: 6px 2px;
    color: var(--text-muted, #66789e);
    font: 600 10px/1 Inter, system-ui, sans-serif;
    letter-spacing: 0.02em;
    cursor: pointer;
  }
  .mnav-btn span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .mnav-btn .nav-tab-icon { width: 21px; height: 21px; }
  .mnav-btn.active { color: var(--accent-cyan, #38bdf8); }
  .mnav-btn.active .nav-tab-icon { filter: drop-shadow(0 0 6px rgba(56, 189, 248, 0.55)); }
  .mnav-btn:active { opacity: 0.7; }

  /* Keyboard open → get the bar out of the way */
  body.kb-open #mnav { display: none; }

  /* "More" sheet */
  #mnav-scrim {
    position: fixed; inset: 0; z-index: 997;
    background: rgba(2, 4, 12, 0.6);
    opacity: 0; transition: opacity 0.2s ease;
  }
  #mnav-scrim.in { opacity: 1; }
  #mnav-sheet {
    position: fixed;
    left: 0; right: 0;
    bottom: calc(60px + env(safe-area-inset-bottom, 0px));
    z-index: 998;
    background: rgba(10, 15, 33, 0.97);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border-top: 1px solid rgba(56, 189, 248, 0.22);
    border-radius: 18px 18px 0 0;
    padding: 10px 14px 16px;
    max-height: min(60dvh, 420px);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateY(12px);
    opacity: 0;
    transition: transform 0.22s cubic-bezier(0.2, 0.9, 0.3, 1), opacity 0.18s ease;
  }
  html[data-theme="light"] #mnav-sheet { background: rgba(244, 247, 255, 0.98); }
  #mnav-sheet.in { transform: none; opacity: 1; }
  .mnav-sheet-grab {
    width: 36px; height: 4px; border-radius: 999px;
    background: rgba(125, 211, 252, 0.35);
    margin: 0 auto 12px;
  }
  .mnav-sheet-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
  }
  .mnav-sheet-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 6px;
    min-height: 68px;
    border-radius: 12px;
    border: 1px solid rgba(56, 189, 248, 0.14);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-primary, #e6edff);
    font: 600 11px/1.2 Inter, system-ui, sans-serif;
    text-align: center;
    cursor: pointer;
  }
  html[data-theme="light"] .mnav-sheet-btn {
    background: rgba(10, 16, 32, 0.04);
    color: #0b1020;
  }
  .mnav-sheet-btn .nav-tab-icon { width: 20px; height: 20px; }
  .mnav-sheet-btn.active {
    border-color: rgba(56, 189, 248, 0.55);
    color: var(--accent-cyan, #38bdf8);
  }
}

/* ═══ 4. Core shared modals → phone sheets ══════════════════════════════════ */
@media (max-width: 768px) {
  /* Submit-Data + Add Back forms (.ftest-*) — the most-used mobile flow.
     Full-screen sheet: full width, dynamic viewport height, internal scroll. */
  .ftest-overlay { align-items: flex-end !important; padding: 0 !important; }
  .ftest-modal {
    width: 100vw !important;
    max-width: 100vw !important;
    height: 100dvh !important;
    max-height: 100dvh !important;
    border-radius: 0 !important;
    margin: 0 !important;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    /* no bottom padding — .ftest-footer is sticky at the scrollport bottom and
       carries its own safe-area padding; a gap here would float it mid-air */
    padding-bottom: 0 !important;
  }

  /* Form-type selector: legacy src/styles/5-utilities/mobile.css ≤640 band stacks it into three
     tall full-width cards (~150px of header). Restore the designed compact
     horizontal chip row (form.css ≤768 block) — this file loads last. */
  .ftest-type-bar {
    flex-direction: row !important;
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 8px;
    padding: 8px 12px;
    scrollbar-width: none;
  }
  .ftest-type-bar::-webkit-scrollbar { display: none; }
  .ftest-type-btn { min-height: 44px; flex: none; padding: 8px 14px; }

  /* Live Status (Data Stream) modal */
  #ns-modal-overlay .ns-modal {
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: 100dvh !important;
    border-radius: 0 !important;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* ═══ 5. Simplify: decorative layers off on phones ══════════════════════════ */
@media (max-width: 768px) {
  /* Giant background watermark words — pure decoration, costs paint + space */
  .overview-bg-text,
  .room-bg-text,
  .wip-bg-text { display: none !important; }

  /* Desktop-only cursor chrome (belt & suspenders — polish gates on hover) */
  .cursor-glow, .cursor-follower { display: none !important; }
}

/* ═══ 6a. Small phones (≤480) + fold covers (≤360) ══════════════════════════ */
@media (max-width: 480px) {
  .dashboard-header .page-title { font-size: clamp(20px, 6vw, 28px); }
  .room-subtab { width: 40px; height: 40px; font-size: 15px; }
}
@media (max-width: 360px) {
  .mnav-btn span { font-size: 9px; }
  .mnav-sheet-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ═══ 6b. Landscape phones (short viewport) ═════════════════════════════════ */
/* (pointer:coarse) keeps a short desktop mouse window (769–900 × ≤480) out */
@media (max-width: 900px) and (max-height: 480px) and (pointer: coarse) {
  #mnav { height: calc(44px + env(safe-area-inset-bottom, 0px)); }
  .mnav-btn span { display: none; }
  body.mob-nav-on .dept-dashboard {
    padding-bottom: calc(52px + env(safe-area-inset-bottom, 0px)) !important;
  }
  /* 0, not 12px — the sticky .ftest-footer carries its own padding; any gap
     here floats the footer mid-air at end of scroll (§4 sets the same) */
  .ftest-modal { padding-bottom: 0 !important; }
}

/* ═══ 6c. Tablets (769–1024): desktop layout, touch-friendly fixes ══════════ */
@media (min-width: 769px) and (max-width: 1024px) {
  .ftest-modal { max-height: 92dvh; overflow-y: auto; }
  #ns-modal-overlay .ns-modal { max-height: 92dvh; overflow-y: auto; }
}

/* ═══ 7. Touch-input affordances (any touch device) ═════════════════════════ */
@media (pointer: coarse) {
  .mnav-btn, .mnav-sheet-btn { min-height: 44px; }
  .nav-bug-btn, .theme-toggle, .nav-help-btn,
  .nav-patchnotes-btn, .nav-review-queue-btn { min-width: 40px; min-height: 40px; }
}

/* Reduced motion: sheet appears without slide */
@media (prefers-reduced-motion: reduce) {
  #mnav-sheet { transition: opacity 0.15s ease; transform: none; }
}

/* ═══ 8. Shell-nav recon fixes (2026-07-06, from mobile audit) ══════════════ */
@media (max-width: 768px) {
  /* Fallback-only: if src/shared/platform/mobile.js ever fails (no mob-nav-on), the legacy
     drawer toggle was a ~14px sliver at mid-left. Make it a real FAB.
     Invisible whenever the bottom bar is active (sidebar chrome is hidden). */
  body:not(.mob-nav-on) .sidenav-edge-toggle,
  body:not(.mob-nav-on).sidebar-collapsed .sidenav-edge-toggle {
    left: 12px !important;
    top: auto !important;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px)) !important;
    transform: none !important;
    width: 48px;
    height: 48px;
    border-radius: 14px;
    z-index: 1200;
  }
  body:not(.mob-nav-on) .sidenav-edge-toggle:active { transform: none !important; }

  /* Data Stream modal internals: scrollable body + big close + safe area */
  #ns-modal-overlay .ns-modal { display: flex; flex-direction: column; }
  #ns-modal-overlay .ns-modal-body {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  }

  /* Account-switcher dropdown: pin to the viewport, not the badge */
  .nav-switch-dropdown {
    position: fixed !important;
    top: 56px !important;
    right: 8px !important;
    left: 8px !important;
    max-width: calc(100vw - 16px);
  }
  .nav-switch-scroll { max-height: 52dvh; }

  /* Heavy always-on backdrop blurs → solid fills on phones (big GPU win even
     outside lite tier). Light-theme mirrors below.

     ⚠ THE FILL HAS TO BE OPAQUE, NOT "NEARLY" OPAQUE (2026-08-02). This line
     used to read 0.96 / 0.97 alpha, which looks like a rounding detail and is
     not. The blur that was supposed to smear whatever passes underneath NEVER
     RUNS on a phone: this rule kills it explicitly, and src/shared/platform/perf/perf.css then
     strips it a second time from every element via
     `html[data-perf="lite"] * { backdrop-filter: none !important }` — measured
     computed value on a 375px phone is `none`, tier `lite`. With no blur, a
     3–4% alpha of near-white body copy over a near-black bar is a ~7-unit
     luminance step, and the eye resolves that as legible ghost text (seen in
     the bottom-bar screenshot: WATER TEMP / PH ALERTS / a large 0 all readable
     straight through the tab bar). Bars are chrome — content must pass BEHIND
     them, not through them. Opaque, with the existing border + a soft shadow
     doing the "distinct surface" job that the glass used to do. */
  #main-nav {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: #080d1e;
    box-shadow: 0 10px 24px -18px rgba(0, 0, 0, 0.85);
  }
  .nav-switch-dropdown, .nav-dept-dropdown, .ns-modal, .ns-tooltip {
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  html[data-theme="light"] #main-nav {
    background: #e8eeff;
    box-shadow: 0 10px 24px -20px rgba(10, 16, 32, 0.35);
  }
}

/* Stale legacy token: mobile.css's 641–1194 band still sets --nav-h:86px from
   the two-row-nav era; the nav is one 46px row now → 40px dead band on iPads.
   This file loads last, so this override wins. Same band, desktop unaffected. */
@media (min-width: 641px) and (max-width: 1194px) {
  :root { --nav-h: 46px; }
}

@media (pointer: coarse) {
  #ns-modal-overlay .ns-modal-close { width: 44px; height: 44px; }
  /* Nothing must be able to squeeze it back down: the close button is a flex
     item in .ns-modal-header, and a long title is enough to make a shrinkable
     item lose pixels. Lock the flex basis to the same 44px. */
  #ns-modal-overlay .ns-modal-close { flex: 0 0 44px; }

  /* ── WHY #ns-modal-close KEPT AUDITING AT 43x43 (2026-08-02) ──────────────
     Four separate audits reported this button 1px under the floor, and the
     rule directly above says 44px. It is not the rule that is wrong and it is
     not a border: computed box-sizing is border-box, offsetWidth/offsetHeight
     are 44/44, getComputedStyle width/height are 44px/44px. Asked the browser
     which rules match and measured both states:

         closed  →  getBoundingClientRect() 42.68 x 42.68   offsetWidth 44
         open    →  getBoundingClientRect() 44.00 x 44.00   offsetWidth 44

     The auditors call getBoundingClientRect(), which reports the VISUAL box
     after transforms. src/app/shell/nav/nav.css parks the dialog at
     `.ns-modal { transform: translateY(16px) scale(0.97) }` and only removes
     the scale on `.visible`. 44 x 0.97 = 42.68, which rounds to the 43 that
     every report quoted. So the target is genuinely sub-44 for the whole
     0.28s open transition, and permanently sub-44 to any tool that measures
     it before the modal is shown.

     The scale is also plain wrong on a phone: §4 above makes this modal a
     full-bleed 100vw/100dvh panel, so scale(0.97) inset the entire screen by
     ~5px a side while it animated in. Slide it instead of scaling it — a
     translate-only entrance is the native full-screen idiom, it leaves every
     touch target at its true layout size at every frame, and the motion still
     reads. ID-scoped (1,1,0) to outrank src/app/shell/nav/nav.css's `.ns-modal` (0,1,0) and
     `.ns-modal-overlay.visible .ns-modal` (0,2,1) — the latter needs the id or
     it keeps re-applying scale(1) from a losing position. */
  #ns-modal-overlay .ns-modal { transform: translateY(28px); }
  #ns-modal-overlay.visible .ns-modal { transform: translateY(0); }

  /* The LIVE status pill is the only touch path to the Data Stream modal —
     was ~30x26px. Pad the hit area without changing its look. */
  #nav-status { min-height: 40px; padding-top: 7px; padding-bottom: 7px; }
}

@media (prefers-reduced-motion: reduce) {
  #ns-modal-overlay .ns-modal,
  #ns-modal-overlay.visible .ns-modal { transform: none; }
}

/* ═══ 9. Central placements from surface agents (2026-07-07) ════════════════ */
@media (max-width: 768px) {
  /* WIP placeholder tabs (Messages/Deliveries/Room Rotation/Calendar):
     100vh overshoots under mobile browser chrome; cards over-padded on phones */
  .wip-wrap { min-height: calc(100vh - var(--nav-h, 46px)); min-height: calc(100dvh - var(--nav-h, 46px)); }
  .wipx-card, .wip-card { padding: 28px 18px; }
}
/* iPad band: #tab-overview locked to stale 100vh — Safari toolbar eats ~20px */
@media (min-width: 769px) and (max-width: 1024px) {
  #tab-overview { min-height: 100dvh; }
}

/* ═══ 10. Fix batch 2026-07-07b — from real-device screenshots ═══════════════ */
@media (max-width: 768px) {
  /* ── Daily Logs CARDS: the table carries a dynamic min-width (e.g. 560px)
     that made cards pan off-screen. Zero every intrinsic size in card mode. */
  body.dl-cards #room-subpanel .table-wrapper { overflow-x: hidden; }
  body.dl-cards #room-subpanel .data-table {
    min-width: 0 !important;
    width: 100% !important;
    white-space: normal !important;
  }
  body.dl-cards #room-subpanel .data-table tbody tr {
    max-width: 100%;
    overflow: hidden;
    /* perf: skip layout/paint for offscreen cards (big win on 90-card lists) */
    content-visibility: auto;
    contain-intrinsic-size: 0 190px;
  }
  body.dl-cards #room-subpanel .data-table tbody td {
    min-width: 0 !important;
    max-width: 100%;
  }
  /* metric band + chips: strict caps so labels can never push card width */
  body.dl-cards #room-subpanel .data-table tbody td[data-label]::before {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }
  body.dl-cards #room-subpanel .data-table tbody td[data-key="ph"],
  body.dl-cards #room-subpanel .data-table tbody td[data-key="ppm"],
  body.dl-cards #room-subpanel .data-table tbody td[data-key="chiller"] {
    flex: 1 1 30%;
    min-width: 0 !important;
    max-width: 33%;
  }
  body.dl-cards #room-subpanel .cyc-cell-sel { max-width: 100%; }

  /* ── Toolbar: MOVED here from daily-logs.css — rooms-help.css loads after it
     and re-sets flex-wrap:wrap, undoing the compaction. mobile-v2 loads LAST. */
  .rooms-toolbar,
  .system-selector,
  #room-subpanel .filter-bar {
    display: flex;
    /* legacy mobile.css <=640 band stacks .filter-bar into a column - undo */
    flex-direction: row !important;
    /* WRAP, don't sideways-scroll — every control stays visible + tappable
       (user: "multiple features unusable unless I go sideways") */
    flex-wrap: wrap !important;
    justify-content: flex-start;
    align-items: center;
    gap: 8px;
    padding: 2px 0 6px;
  }
  .rooms-toolbar > *, .system-selector > *, #room-subpanel .filter-bar > * { flex: none; }
  #room-subpanel .filter-bar input { max-width: 132px; }
  /* redundant with the numbered room pills — reclaim a full row */
  .room-header .room-name-label, .room-header .room-sys-badge { display: none; }

  /* ── "Working…" busy pill: sat ON the nav icons. Pin it just below the nav,
     under every modal (z<1200). Beats the injected style tag (loads earlier). */
  .tbusy {
    top: 54px !important;
    z-index: 1150 !important;
    max-width: min(72vw, 330px);
  }

  /* ── Admin Permissions pane: inner grids clipped at the right edge — let the
     pane scroll sideways as a usable fallback (admin tooling bar). */
  #admin-perms-pane, #dv-pane-permissions { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* ═══ 11. De-clutter pass (2026-07-07c) — "super clean" mobile ══════════════ */
@media (max-width: 768px) {
  /* Per-tab tutorial pill: Help Center stays one tap away in the top nav */
  #rooms-help-btn { display: none !important; }

  /* Filters hidden until the "⌕ Filters" chip is toggled (chip in toolbar) */
  #room-subpanel:not(.dl-filters-open) .filter-bar { display: none !important; }
  .dl-filter-toggle {
    padding: 8px 14px;
    min-height: 36px;
    border-radius: 999px;
    border: 1px solid rgba(125, 211, 252, 0.25);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text-secondary, #b6c2e2);
    font: 600 12px Inter, system-ui, sans-serif;
    cursor: pointer;
    flex: none;
  }
  .dl-filter-toggle.on {
    border-color: rgba(56, 189, 248, 0.55);
    background: rgba(56, 189, 248, 0.12);
    color: var(--accent-cyan, #38bdf8);
  }
  html[data-theme="light"] .dl-filter-toggle { background: rgba(10, 16, 32, 0.04); color: #3a4a6b; }
  html[data-theme="light"] .dl-filter-toggle.on { background: rgba(56, 130, 248, 0.10); color: #0369a1; }

  /* Card content: FULL chip set stays visible collapsed (deltas, trend, cycle,
     day, water — user asked for all info back); only the long tail of rarely
     used columns sits behind the tap, per the daily-logs.css card chain. */

  /* tighter, calmer card */
  body.dl-cards #room-subpanel .data-table tbody tr { padding: 12px 14px 26px; gap: 2px 8px; }
  /* header strip: SYS badge left, Recap/expand right — one row, not a stack */
  body.dl-cards #room-subpanel .cell-expand .cell-expand-stack {
    flex-direction: row !important;
    align-items: center;
    justify-content: space-between;
  }
  body.dl-cards #room-subpanel .cell-expand .cell-expand-btns {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  body.dl-cards #room-subpanel .data-table tbody tr::after { content: "⌄ details"; }
  body.dl-cards #room-subpanel .data-table tbody tr.dl-open::after { content: "⌃ close"; }
}
@media (max-width: 480px) {
  /* Easy View pill label → icon only at the smallest widths */
  .nav-easyview-btn span { display: none; }
}

/* ═══ 12. Top-bar "⋯" overflow menu (2026-07-07c) ═══════════════════════════
   src/shared/platform/mobile.js MOVES the secondary nav controls (patch notes, review queue,
   help, bugs, Easy View, theme, account, logout) into this labeled sheet so
   the top bar never needs sideways scrolling: logo · dept · LIVE · ⋯ */
@media (max-width: 768px) {
  /* with the cluster collapsed into ⋯ the bar fits — stop scrolling it */
  body.mtop-on .nav-controls { overflow: visible; flex-wrap: nowrap; }

  #mtop-more {
    width: 38px;
    height: 38px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 11px;
    border: 1px solid rgba(125, 211, 252, 0.22);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text-secondary, #b6c2e2);
    cursor: pointer;
  }
  #mtop-more:active { background: rgba(56, 189, 248, 0.14); color: var(--accent-cyan, #38bdf8); }

  #mtop-scrim {
    position: fixed;
    inset: 0;
    z-index: 2240;
    background: rgba(2, 4, 12, 0.55);
    opacity: 0;
    transition: opacity 0.16s ease;
  }
  #mtop-scrim.in { opacity: 1; }

  #mtop-sheet {
    position: fixed;
    top: calc(var(--nav-h, 52px) + 6px);
    right: 8px;
    z-index: 2241;
    width: min(300px, calc(100vw - 16px));
    max-height: calc(100dvh - var(--nav-h, 52px) - 90px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px;
    border-radius: 16px;
    border: 1px solid rgba(125, 211, 252, 0.18);
    background: rgba(10, 15, 32, 0.98);
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
    opacity: 0;
    transform: translateY(-6px) scale(0.97);
    transform-origin: top right;
    transition: opacity 0.16s ease, transform 0.16s ease;
  }
  #mtop-sheet.in { opacity: 1; transform: none; }
  #mtop-sheet[hidden], #mtop-scrim[hidden] { display: none; }

  .mts-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 46px;
    padding: 4px 10px;
    border-radius: 12px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .mts-row:active { background: rgba(255, 255, 255, 0.07); }
  .mts-row > *:first-child { flex: none; }
  .mts-label {
    flex: 1;
    font: 500 13.5px Inter, system-ui, sans-serif;
    color: var(--text-primary, #e7ecff);
    letter-spacing: 0.01em;
  }
  /* moved controls keep their compact icon look inside rows */
  .mts-row .nav-role-badge {
    /* legacy mobile.css ≤640 band hides the badge outright — restore in-sheet */
    display: inline-flex !important;
    max-width: 150px;
  }

  /* account dropdown opens from INSIDE the sheet — must layer above it */
  .nav-switch-dropdown { z-index: 2300 !important; }

  /* light theme */
  html[data-theme="light"] #mtop-more { background: rgba(10, 16, 32, 0.04); color: #3a4a6b; }
  html[data-theme="light"] #mtop-sheet {
    background: rgba(244, 247, 255, 0.99);
    border-color: rgba(30, 64, 120, 0.14);
    box-shadow: 0 18px 50px rgba(30, 40, 80, 0.22);
  }
  html[data-theme="light"] .mts-label { color: #1c2742; }
  html[data-theme="light"] .mts-row:active { background: rgba(10, 16, 32, 0.06); }
}
/* desktop: the menu never exists (JS restores controls); belt & braces */
@media (min-width: 769px) {
  #mtop-more, #mtop-sheet, #mtop-scrim { display: none !important; }
}

/* ═══ 13. Overview compare chart + sparklines: read-only on touch (07-07d) ══
   User request: the scrub readout chased the finger and cluttered/fought page
   scrolling. Charts are static pictures on phones — pointer-events:none also
   swallows the post-tap compatibility mousemove, so no tooltip ever sticks.
   !important because overview-fixed.js injects its styles at runtime (after
   this file in the cascade). Toggle chips + legend buttons live outside the
   svg/spark wraps and stay fully tappable. Desktop hover-scrub untouched. */
@media (max-width: 768px) {
  .ovf-bc svg,
  .ovf-spark { pointer-events: none !important; }
  /* pan-x too: the chart renders at min-width 560px inside the horizontally
     scrollable .ovf-bigchart-slot (overview-fixed.js injected mobile CSS) —
     pan-y alone would make the right half of the chart unreachable by touch */
  .ovf-bc { touch-action: pan-x pan-y !important; }
  .ovf-spark { touch-action: pan-y !important; }
  /* stale hints ("hover to scrub", "scrub to compare") — there is no hover */
  .ovf-hero-sub,
  .ovf-leg-hint { display: none !important; }
}

/* ═══ 14. Bottom tab bar must be a SURFACE, not a filter (2026-08-02) ═══════
   SEEN, then measured. Screenshot of the Overview tab at 375px scrolled to
   y=420: "WATER TEMP", "PH ALERTS", "avg chiller", "all in range" and a large
   numeral 0 are all plainly READABLE through #mnav, sitting behind the
   Overview / Messages / Personnel / Tasks / More labels. It reads as a
   rendering fault, not as an iOS-style translucent tab bar.

   src/styles/5-utilities/mobile-native.css §4 already diagnosed this correctly and moved the bar
   to rgba(6,9,21,0.97) with an upward shadow. That was a real improvement and
   it is still not enough: the tiles underneath are near-white type on
   near-black, so even 3% carries a visible luminance step, and there is no
   blur to smear it — computed backdrop-filter on a phone is `none` (perf tier
   `lite`, verified: src/shared/platform/perf/perf.css strips it from every element). An iOS tab bar
   gets away with translucency ONLY because the system blur is real; without
   it, translucency is just ghosting. Take the alpha to zero.

   ⚠ SPECIFICITY, NOT ORDER. src/styles/5-utilities/mobile-native.css is the LAST <link> and sets
   `#mnav` (1,0,0) / `html[data-theme="light"] #mnav` (1,1,0). This file loads
   BEFORE it, so an identical selector here would lose no matter where in the
   file it sits. `nav#mnav` is (1,0,1) and `html[data-theme="light"] nav#mnav`
   is (1,1,1) — both outrank their counterparts on specificity, which order
   cannot undo. The element qualifier is load-bearing; do not "tidy" it away.

   The blur declarations are deliberately NOT restated: against an opaque fill
   they are a no-op that only costs a compositor layer. */
@media (max-width: 768px) {
  nav#mnav {
    background: #060915;
    box-shadow: 0 -14px 30px -14px rgba(0, 0, 0, 0.9);
  }
  html[data-theme="light"] nav#mnav {
    background: #f6f9ff;
    box-shadow: 0 -14px 30px -18px rgba(10, 16, 32, 0.32);
  }
  /* The "More" sheet slides out of the same bar — it must not be see-through
     either, or the ghosting simply moves up one layer. */
  div#mnav-sheet { background: #080d1e; }
  html[data-theme="light"] div#mnav-sheet { background: #f4f7ff; }
}

/* ═══ 15. .torus-mark-badge at 7px — CHECKED, NOT A DEFECT (2026-08-02) ══════
   NO RULE FOLLOWS ON PURPOSE. This is a note, because the 7px wordmark inside
   the nav logo keeps being re-reported as sub-12px text and keeps being "fixed"
   badly. It has now been looked at rather than measured:

     measured   .nav-logo-icon.torus-mark-badge → 44 x 44 disc, font-size 7px,
                Press Start 2P, #fff on #000 inside a 2px white ring
     inspected  cropped at 375px and blown up nearest-neighbour so the real
                device pixels are visible, at BOTH dpr 2 and dpr 1

   At dpr 2 — what every current phone renders — the letterforms are crisp and
   fully legible; at dpr 1 they are chunky but still plainly read TORUS. It is
   a MARK, not copy, and it is doing its job at the size it is.

   So: do not raise the font-size (it will overflow the disc), do not set
   font-size:0 (the wordmark is real text — that turned the logo into a solid
   black dot once already), and do not add it to a text-size floor. The floor
   in src/styles/5-utilities/mobile-native.css §1 already carries an explicit opt-out for this
   class; keep it there. If a future audit genuinely finds it unreadable, grow
   the DISC, not the type. */
