/* ============================================================================
   StayMaster ONE — RESPONSIVE LAYER  (mobile + tablet)
   Link LAST on every ONE surface so it wins the cascade:
     <link rel="stylesheet" href="/static/rms/one-responsive.css?v=1">
   Pairs with one-responsive.js (drawer toggle + body flags).

   Breakpoints
     <=1024  tablet landscape   — soften fixed grids
     <=900   tablet portrait    — left sub-nav becomes an off-canvas drawer
     <=640   phone             — right rail becomes a bottom bar, 1-col, sheets
     <=380   small phone       — tighten type + padding

   Design intent: the app must stay usable one-handed on site. Chrome collapses
   first, data stays. Nothing is hidden that carries information — wide tables
   scroll inside their own container rather than being truncated.
   ========================================================================= */

/* ---------------------------------------------------------------- 0. safety */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
img, svg, video, canvas { max-width: 100%; }
/* flex/grid children refuse to shrink below content width without this —
   the single most common cause of horizontal overflow in this codebase */
.content, .view, .panel, .card, .stat, .row, .flex, [class*="flex"] { min-width: 0; }

@media (max-width: 1024px) {
  /* any hard 2+ column grid softens to auto-fit so it can reflow */
  .content .grid-2, .content .grid-3, .content .grid-4,
  .cards, .kpis, .stats, .statrow {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
  }
}

/* ------------------------------------------------- 1. left sub-nav → drawer */
@media (max-width: 900px) {
  /* !important on both states: several ONE surfaces animate or re-assign the
     sub-nav's transform/width at runtime (nav-collapsed toggling), which would
     otherwise strand the drawer half-open. The drawer state must win. */
  /* NOTE: no transform-transition here on purpose. app-nav.css puts
     `transition: width .16s` on .subnav; combined with a transform transition
     the drawer could be left with a CSSTransition stuck in `running`, so the
     panel never reached translateX(0) even with an inline !important end state
     (reproduced on /expense). The drawer therefore snaps, and the *scrim*
     carries the motion — a working drawer matters more than a slide. */
  .subnav {
    transform: translateX(-100%) !important;
    transition: none !important;
    width: 264px !important;
    box-shadow: 0 0 40px rgba(0,0,0,.5);
    z-index: 9600 !important;
  }
  body.nav-open .subnav { transform: translateX(0) !important; }
  /* collapsed-rail styling must not apply once it's a drawer */
  body.nav-collapsed .subnav { width: 264px !important; }
  body.nav-collapsed .sn-brand .tt,
  body.nav-collapsed .sn-link .lb,
  body.nav-collapsed .sn-link .ct,
  body.nav-collapsed .sn-cap,
  body.nav-collapsed .sn-foot .txt { display: revert !important; }
  body.nav-collapsed .sn-link { justify-content: flex-start !important; padding: 11px 12px !important; }
  body.nav-collapsed .sn-top { padding: 0 14px !important; justify-content: flex-start !important; }
  body.nav-collapsed .sn-foot { justify-content: flex-start !important; padding: 12px 14px !important; }
  body.nav-collapsed .sn-link .lb {
    position: static !important; opacity: 1 !important; background: none !important;
    border: none !important; box-shadow: none !important; padding: 0 !important; transform: none !important;
  }
  .sn-list { overflow-y: auto; }

  /* content reclaims the full width.
     NB: surfaces don't share one container class — RMS/mini-apps use .content,
     Diagnostics uses .wrap. Both must be reset or the page keeps a 230px
     phantom gutter and its panels overflow. */
  .content, .wrap { margin-left: 0 !important; }
  .wrap { padding-left: 14px !important; padding-right: 14px !important; }
  /* Diagnostics bleeds its header past the wrap padding with
     `.wrap > .chead{margin:-18px -24px}`. Once the padding changes to 14px
     that -24px overshoots and pushes the page 14px wide, so the negative
     margin has to track the padding. */
  .wrap > .chead { margin-left: -14px !important; margin-right: -14px !important; }

  /* scrim */
  /* no opacity transition, for the same reason the drawer has no transform
     transition — a stranded CSSTransition left the scrim invisible while the
     drawer was open, so the operator saw the nav floating over live content
     with no dimming and no obvious way to dismiss it. Deterministic beats
     pretty for a tool used on site. */
  #one-scrim {
    position: fixed; inset: 0; background: rgba(2,14,18,.55);
    backdrop-filter: blur(2px); z-index: 9500; opacity: 0; pointer-events: none;
    transition: none;
  }
  body.nav-open #one-scrim { opacity: 1; pointer-events: auto; }

  /* hamburger (injected by one-responsive.js) */
  .one-burger {
    display: inline-grid !important; place-items: center;
    width: 40px; height: 40px; min-width: 40px; flex: none;
    border-radius: 11px; border: 1px solid rgba(130,195,205,.18);
    background: rgba(6,26,26,.4); color: #cfe3df; cursor: pointer; margin-right: 2px;
  }
  .one-burger:active { background: rgba(43,167,160,.22); }
}
.one-burger { display: none; }   /* desktop */

/* ------------------------------------------------------- 2. content header */
@media (max-width: 900px) {
  .chead {
    height: auto !important; min-height: 56px !important;
    padding: 8px 12px !important; gap: 10px !important;
    flex-wrap: wrap !important;
  }
  .chead .ct-main { font-size: 16px !important; }
  .chead .ct-crumb { font-size: 10px !important; }
  .chead h1 { font-size: 17px !important; }
  /* search drops to its own full-width row so the title/actions stay on line 1 */
  .chead .csearch, .chead .gsearch {
    order: 10; flex: 1 0 100% !important; max-width: 100% !important; margin: 2px 0 0 !important;
  }
  .chead .homebtn span, .chead .homebtn .lbl { display: none; }
  .chead .homebtn { padding: 0 10px; }
  /* Keep row 1 = [burger][title][badges][bell]. Without letting the badges
     shrink, a wide chip (e.g. Owner Mgmt's RESTRICTED) pushes the bell onto
     its own line and wastes a whole row of vertical space. */
  .chead > *:not(.csearch):not(.gsearch) { flex-shrink: 1; min-width: 0; }
  .chead .ctitle { flex: 1 1 auto; }
  .chead .nbell { margin-left: auto; flex: none !important; }
  .chead .badge, .chead .pill, .chead .chip, .chead .restricted, .chead .lock {
    font-size: 9px !important; padding: 2px 7px !important;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    flex: 0 1 auto !important; min-width: 0;
  }
}
@media (max-width: 480px) {
  /* Below ~480px the title + a wide status chip + the bell can't share a row,
     and it was the BELL that wrapped — pushing an almost-empty second row into
     the header and stealing vertical space from the list. The chip is the
     least urgent element, so it loses its text and keeps just its lock icon;
     the bell (which carries a live count) stays put. */
  .chead .lock, .chead .restricted {
    font-size: 0 !important; padding: 4px !important; gap: 0 !important;
  }
  .chead .lock svg, .chead .lock i,
  .chead .restricted svg, .chead .restricted i { font-size: 11px !important; }
  body.rail-right .content { padding-right: 0 !important; }
  body.rail-right .content .chead { margin-right: 0 !important; padding-right: 12px !important; }
}
@media (max-width: 640px) {
  .chead .cs-tags, .chead .cs-tag { display: none !important; }
}

/* ------------------------------------------------ 3. right rail → bottom bar */
@media (max-width: 640px) {
  /* Most ONE apps run the rail on the RIGHT (rail.js: RAIL_RIGHT for
     rms/supply/owner-management/users/monitor/chat/expense) and reserve a
     56px right gutter. Both variants must release their gutter, or the phone
     loses 56px of width to an empty column. */
  body.has-rail,
  body.has-rail.rail-right {
    padding-left: 0 !important; padding-right: 0 !important;
    padding-bottom: 58px !important;
  }
  .one-rail, body.rail-right .one-rail {
    left: 0 !important; right: 0 !important; top: auto !important; bottom: 0 !important;
    border-left: none !important;
    width: 100% !important; height: 58px !important;
    flex-direction: row !important; justify-content: space-around !important;
    align-items: center !important; padding: 0 6px !important;
    border-right: none !important; border-top: 1px solid rgba(120,200,190,.16) !important;
    z-index: 9400 !important;
  }
  .one-rail .r-emblem, .one-rail .r-toggle, .one-rail .r-spacer { display: none !important; }
  .one-rail .r-btn { width: 46px !important; height: 44px !important; margin: 0 !important; }
  .one-rail .r-btn .r-lbl, .one-rail .r-label, .one-rail .r-tip { display: none !important; }

  /* The app dock is a VERTICAL stack of per-app shortcuts. In a 58px horizontal
     bar it overflows upward and floats over the content. Flatten it, and drop
     the individual app shortcuts — every app is one tap away in the Launchpad,
     so the bar stays to five thumb-sized targets instead of a crowded strip. */
  .one-rail .r-dock {
    flex-direction: row !important; gap: 4px !important;
    padding: 0 !important; margin: 0 !important;
    background: none !important; border: none !important; border-radius: 0 !important;
  }
  .one-rail .r-dock .r-app { display: none !important; }
  .one-rail .r-dock .r-home, .one-rail .r-dock .r-apps {
    width: 40px !important; height: 40px !important; min-height: 40px !important;
  }
  body.rail-expanded { --r-w: 0px !important; }
  body.rail-expanded .one-rail { width: 100% !important; }
  body.rail-expanded .one-rail .r-btn { width: 46px !important; justify-content: center !important; }

  /* flyout panels become full-screen sheets sitting above the bar.
     rail.js slides these with translateX and anchors them to the rail side;
     on mobile they must cover the screen from either origin. */
  .one-chat, .one-todo, .one-cal, .one-notif,
  body.rail-right .one-chat, body.rail-right .one-todo, body.rail-right .one-cal {
    left: 0 !important; right: 0 !important; top: 0 !important; bottom: 58px !important;
    width: 100vw !important; max-width: 100vw !important; z-index: 9300 !important;
  }
  .one-chat.open, .one-todo.open, .one-cal.open,
  body.rail-right .one-chat.open, body.rail-right .one-todo.open, body.rail-right .one-cal.open {
    transform: translateX(0) !important;
  }
}

/* --------------------------------------------------------- 4. tables scroll */
/* Wide operational tables must scroll INSIDE their card, never push the page */
.one-tblwrap, .tblwrap, .table-wrap, .content .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 900px) {
  /* Give columns room to breathe. Squeezing a 7-column operational table into
     360px wraps every cell character-by-character ("Electri city Depart ment")
     which is unreadable. Instead the table keeps a comfortable width, each cell
     stays on ONE line with an ellipsis, and the operator swipes sideways —
     the standard mobile data-table pattern. No data is hidden or truncated
     away; it is all still there, just paged horizontally. */
  .content table, .one-tbl, .tbl, .vd-tbl, .vctbl { min-width: 720px; }
  .content th, .content td, .one-tbl th, .one-tbl td, .tbl th, .tbl td {
    white-space: nowrap !important;
    max-width: 200px; overflow: hidden; text-overflow: ellipsis;
  }
  /* cells that are genuinely multi-line by design keep wrapping */
  .content td.wrap, .content td .sub, .content td .stack { white-space: normal !important; }
}

/* ============== 4b. LABELLED TABLES → CARD LIST on phones ===================
   A horizontally-scrolling table is a compromise: it fits, but the operator
   has to swipe to read one record and can't compare fields. Where a table's
   cells carry `data-l` (their column label), we stack each ROW into a card and
   print the label beside each value — so one record reads top-to-bottom with
   no sideways scrolling at all.

   Opt-in by design: only tables whose cells have data-l transform, so tables
   that genuinely want the grid (rate calendars, nightly schedules) keep it. */
@media (max-width: 640px) {
  table:has(td[data-l]) { min-width: 0 !important; width: 100% !important; }
  table:has(td[data-l]) thead { display: none; }            /* labels move inline */
  table:has(td[data-l]),
  table:has(td[data-l]) tbody,
  table:has(td[data-l]) tr,
  table:has(td[data-l]) td { display: block; width: auto !important; }

  table:has(td[data-l]) tr {
    background: var(--canvas-surface, #fff);
    border: 1px solid var(--canvas-line, #e7ddd3);
    border-radius: 12px;
    padding: 10px 12px;
    margin: 0 0 10px;
    box-shadow: 0 1px 3px rgba(88,65,57,.06);
    /* The Audit rows carry an INLINE style="height:38px" to keep desktop rows
       uniform. Stacked as a card the content needs ~300px, so that inline
       height clipped every card to one line and the fields overflowed on top
       of the next card. Inline styles need !important to beat. */
    height: auto !important; min-height: 0 !important;
  }
  table:has(td[data-l]) td {
    border: 0 !important; padding: 3px 0 !important;
    display: flex !important; align-items: baseline; gap: 10px;
    white-space: normal !important; max-width: none !important;
    text-align: left !important;
  }
  table:has(td[data-l]) td::before {
    content: attr(data-l);
    flex: 0 0 92px;
    font-size: 10px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--canvas-faint, #9aa8a3);
  }
  /* The card's headline is marked EXPLICITLY with data-hd, not assumed to be
     the first cell — in the Audit table the first cell is a select checkbox,
     so a positional rule would have made the tick-box the title. It must be
     BLOCK, not flex: these cells hold a name plus a muted sub-line (code /
     phone / type), and as flex items those sit side-by-side instead of
     stacking. */
  table:has(td[data-l]) td[data-hd] {
    display: block !important;
    font-weight: 600; font-size: 14.5px;
    padding-bottom: 7px !important;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--canvas-line-2, #efe8df) !important;
  }
  table:has(td[data-l]) td[data-hd]::before { display: none; }
  table:has(td[data-l]) td[data-hd] .mut {
    display: block; font-weight: 400; font-size: 11.5px; margin-top: 2px;
  }
  /* Card mode must override the horizontal-scroll min-width from section 4,
     or the "cards" still sit on a 720px canvas and clip. */
  table:has(td[data-l]) { min-width: 0 !important; }

  /* Utility cells carry no label — a row-select checkbox or a row action.
     They stack like any other row; do NOT float them. Floating the checkbox
     took it out of flow and the cards collapsed on top of each other. */
  table:has(td[data-l]) td:not([data-l]) {
    display: flex !important; justify-content: flex-end;
    padding: 6px 0 0 !important;
  }
  table:has(td[data-l]) td:not([data-l])::before { display: none !important; }

  /* Bulk-select checkboxes are a desktop workflow (tick many, act once). On a
     phone the row itself is the target — you tap it to open the record — and a
     14px tick-box column just adds noise and mis-taps. Hidden here; bulk audit
     stays available on desktop where it belongs. */
  table:has(td[data-l]) td:not([data-l]):first-child:has(input[type="checkbox"]) {
    display: none !important;
  }
  /* money stays right-aligned against its label, and tabular */
  table:has(td[data-l]) td.num { justify-content: flex-start; font-variant-numeric: tabular-nums; }
  /* an empty-state row shouldn't look like a card */
  table:has(td[data-l]) td.empty::before { display: none; }
  table:has(td[data-l]) tr:has(td.empty) { border: 0; box-shadow: none; background: none; }
}

/* ----------------------------------------------------------- 5. grids → 1col */
/* CRITICAL: a `1fr` track is `minmax(auto,1fr)`, and `auto` floors at the item's
   MIN-CONTENT width. So a panel containing a wide table stays wider than the
   viewport even after the grid is collapsed to one column — which is exactly
   why Diagnostics kept an 88px overflow. `minmax(0,1fr)` lets tracks shrink,
   and `min-width:0` lets the items inside them shrink too. */
@media (max-width: 900px) {
  /* Two-PANE layouts (content + sidebar, form + preview) stack to one column —
     they're not comparable tiles, so side-by-side stops working early. */
  .cols, .form-grid, .fgrid, .frow {
    grid-template-columns: minmax(0, 1fr) !important;
  }
  /* TILE grids (KPIs, stat cards, gauges) should stay multi-column for as long
     as the tiles remain legible — collapsing these to 1-up at tablet width
     wastes most of the screen and pushes the real content below the fold. */
  .gauges, .grid-2, .grid-3, .grid-4,
  .content .grid, .cards, .kpis, .stats, .statrow {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)) !important;
  }
  .cols > *, .content .grid > *, .cards > *, .kpis > *, .stats > *,
  .panel, .card, .stat, .gauge, section, article { min-width: 0 !important; }
}
@media (max-width: 640px) {
  .content [style*="grid-template-columns"] { grid-template-columns: minmax(0,1fr) !important; }
  .content .row, .content .tools, .content .filters, .toolbar {
    flex-wrap: wrap !important; gap: 8px !important;
  }
  /* two-up KPI tiles read better than one-up on a phone */
  .kpis, .stats, .statrow { grid-template-columns: repeat(2, minmax(0,1fr)) !important; }
}
@media (max-width: 380px) {
  .kpis, .stats, .statrow { grid-template-columns: minmax(0,1fr) !important; }
}

/* ------------------------------------------------------ 6. modals as sheets */
@media (max-width: 640px) {
  .modal, .modal-card, .dlg, .drawer, .sheet, .overlay-card, .detail-modal,
  .vmodal, .lightbox {
    width: 100vw !important; max-width: 100vw !important;
    height: 100dvh !important; max-height: 100dvh !important;
    border-radius: 0 !important; margin: 0 !important; inset: 0 !important;
  }
  /* The visible CARD inside the overlay is the thing the operator reads —
     e.g. `.drawer .panel{width:min(760px,94vw)}` leaves a dead 6vw strip and a
     rounded edge that reads as a half-open sheet on a phone. Fill the screen. */
  .drawer > .panel, .vmodal > .panel, .vmodal > .card,
  .modal > .panel, .modal > .card, .sheet > .panel {
    position: absolute !important; inset: 0 !important;
    width: 100% !important; max-width: 100% !important;
    height: 100% !important; max-height: 100% !important;
    border-radius: 0 !important; box-shadow: none !important;
    animation: none !important;            /* slide-in strands mid-animation */
  }
  .drawer .dbody, .modal-body, .dlg-body, .vmodal .dbody {
    flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  /* header + footer stay put, body scrolls between them */
  .drawer .dhead, .vmodal .dhead { position: sticky; top: 0; z-index: 2; }
  .drawer .dfoot, .vmodal .dfoot {
    position: sticky; bottom: 0; z-index: 2;
    padding-bottom: max(14px, env(safe-area-inset-bottom)) !important;
  }
}

/* ------------------------------------------------------- 7. touch ergonomics */
/* Both signals: `pointer:coarse` is the correct semantic test, but a narrow
   viewport is the one we can actually verify — and hybrid/desktop-mode phones
   report a fine pointer. Either qualifies. */
@media (pointer: coarse), (max-width: 640px) {
  button, .btn, .one-btn, .sn-link, .tab, [role="button"], select, a.act { min-height: 40px; }
  /* 16px is the threshold below which iOS Safari zooms the page on focus —
     that zoom then leaves the layout scrolled sideways, which is the single
     most common "the app is broken on my phone" report. */
  input, select, textarea { font-size: 16px !important; }
  .one-btn--sm, .btn-sm, .seg, .chip { min-height: 34px; }
  /* Text inputs are borderless children of a styled pill — the pill IS the tap
     target, so size the pill rather than the input (setting a min-height on the
     input itself would burst the pill). */
  .box, .tsearch, .c-search, .search, .csearch .box, .gsearch .box { min-height: 42px; }
}

/* ------------------------------- 8. horizontal strips: scroll, never overflow */
/* Segmented controls, tab rows and chip rows are nowrap by design. On a phone
   they must scroll sideways inside themselves rather than widening the page. */
@media (max-width: 900px) {
  .segs, .tabs, .tabrow, .chips, .seg-wrap, .filters-row, .subtabs, .kindtabs {
    display: flex !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    max-width: 100%;
    flex-wrap: nowrap !important;
  }
  .segs::-webkit-scrollbar, .tabs::-webkit-scrollbar, .chips::-webkit-scrollbar,
  .subtabs::-webkit-scrollbar { height: 0; display: none; }
  .seg, .tab, .chip { flex: 0 0 auto; }
}

/* ================= 8b. ANY horizontal scroller: children must not shrink =====
   A row marked `overflow-x-auto` with `whitespace-nowrap` children still
   COMPRESSES them, because flex items shrink by default. On the Bookings filter
   strip that pushed each count bubble on top of the next label, producing
   "Confirmed(19)ee Cancel" / "C(2)argeable Ca…(0)Blocks" — the tangled text.
   Pinning children to their content width makes the row scroll as intended. */
@media (max-width: 900px) {
  .overflow-x-auto > button,
  .overflow-x-auto > a,
  .overflow-x-auto > .tab,
  .overflow-x-auto > label { flex: 0 0 auto !important; }
  /* count bubbles keep their own width and never overlap the label */
  .overflow-x-auto > button > span,
  .overflow-x-auto > a > span { flex: none !important; }
  /* the strip itself scrolls silently */
  .overflow-x-auto { scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .overflow-x-auto::-webkit-scrollbar { height: 0; display: none; }
}

/* ============ 8c. THE RMS / LEDGER TAB ROW IS TWO THINGS IN ONE ==============
   .rz-tabs (RMS) and .btabs (owner ledger) are not plain tab strips: each
   carries the view tabs AND the toolbar, pushed apart by a flex spacer. That
   is why section 8 above never fixed them — the selectors were never listed,
   and listing them would not have been enough.

   On a phone the row cannot fit. .rz-tools wraps into a tall vertical stack,
   and because .rz-tabs sets align-items:flex-end the tabs drop to the BOTTOM
   of that now-tall row. The result is a band of empty ivory between the header
   and the tabs, with the Table/Cards control stranded off the right edge —
   roughly 280px of dead space on a 390px-wide screen.

   Two rows instead: the tabs on top, the tools beneath, each scrolling
   sideways inside itself and neither widening the page. */
@media (max-width: 900px) {
  .rz-tabs, .btabs {
    flex-wrap: wrap !important;
    align-items: center !important;
    padding: 6px 12px 0 !important;
    row-gap: 6px;
  }
  /* The spacer exists to shove the tools to the far right of a wide row. On
     two rows it has nothing to push apart and only adds height. */
  .rz-spacer { display: none !important; }
  .rz-tools {
    order: 2;
    width: 100%;
    display: flex !important;
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    gap: 6px;
    padding-bottom: 6px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .rz-tools::-webkit-scrollbar { height: 0; display: none; }
  .rz-tools > * { flex: 0 0 auto !important; }
  /* Tabs keep their own width and shrink their padding so the common case —
     four tabs — still lands on one line at 390px. */
  .rz-tab, .btab { flex: 0 0 auto !important; }
  .rz-tab { padding: 8px 13px 9px !important; font-size: 12.5px !important; }
}

/* ========== 8d. A minmax() FLOOR IS A MINIMUM, EVEN IN ONE COLUMN ===========
   Supply Monitor's detail layouts are
     grid-template-columns: minmax(420px,1.35fr) minmax(360px,1fr)
   and its own media queries stop at 900px. Collapsing to a single column does
   NOT rescue them: a minmax(420px, …) track still refuses to be narrower than
   420px, so on a 390px phone every one of these forced the page wider than the
   screen and the whole layout scrolled sideways — the map, the icon rail and
   the property list included.

   The floor has to go, not just the column count. `minmax(0,1fr)` is the
   single-column form that can actually shrink, and min-width:0 lets the
   children shrink with it (a grid item defaults to min-content, which is how a
   long property name reintroduces the same overflow one level down). */
@media (max-width: 900px) {
  .split, .cxsplit, .ov-split, .geosplit {
    grid-template-columns: minmax(0, 1fr) !important;
    gap: 12px;
  }
  .split > *, .cxsplit > *, .ov-split > *, .geosplit > * { min-width: 0 !important; }
}
@media (max-width: 640px) {
  /* Maps get a usable but not page-dominating height on a phone. */
  #geoMap, .cxmap { height: 300px !important; }
  /* Icon rails and chip rows scroll rather than wrap into a tall block. */
  .cx-actions, .p-actions, .icon-rail {
    display: flex; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .cx-actions::-webkit-scrollbar, .p-actions::-webkit-scrollbar,
  .icon-rail::-webkit-scrollbar { height: 0; display: none; }
  .cx-actions > *, .p-actions > *, .icon-rail > * { flex: 0 0 auto; }
}

/* --------------------------- 9. rail overlays (launchpad) must respect the box */
.one-launch, .one-launch * { box-sizing: border-box !important; }
@media (max-width: 640px) {
  .one-launch { padding: 14px 12px 12px !important; gap: 14px !important; overflow: hidden; }

  /* Close button and search share ONE top row.
     .lp-close is position:absolute (top:22px/right:26px) while .lp-search is
     the first in-flow child. Widening the search to 100% on a phone — which an
     earlier pass here did — slid it straight underneath the ×, so the two
     overlapped in both axes. Instead: pin the × to the top-right, reserve a
     lane for it with margin-right, and give both the same top edge and height
     so they read as a single row. */
  .one-launch .lp-close {
    top: 14px !important; right: 12px !important;
    width: 46px !important; height: 46px !important; border-radius: 13px !important;
  }
  .one-launch .lp-search {
    align-self: stretch !important;      /* beats the parent's align-items:center */
    width: auto !important; max-width: none !important;
    margin-right: 58px !important;       /* 46px button + 12px breathing room */
    height: 46px !important;
  }

  .one-launch .lp-grid {
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)) !important;
    gap: 16px 6px !important; padding: 8px 0 !important;
  }
  /* 74px icons don't fit a 96px cell — scale the tile down with the grid */
  .one-launch .lp-ico { width: 62px !important; height: 62px !important; border-radius: 17px !important; }
  .one-launch .lp-ico svg { width: 28px !important; height: 28px !important; }
  .one-launch .lp-app { gap: 8px !important; padding: 8px 2px !important; }
  .one-launch .lp-name { font-size: 11.5px !important; line-height: 1.25 !important; }
  .one-launch .lp-hint { display: none !important; }   /* no Esc key on a phone */
}

/* --------------------------------- 10. marquee ticker must clip on small screens */
.ticker { overflow: hidden !important; max-width: 100%; }
@media (max-width: 900px) {
  .ticker-track { max-width: none; }               /* keep scrolling, but the
                                                      parent clips it (above) */
  .ticker::before, .ticker::after { width: 24px !important; }
}

/* ============ 10b. FULL-SCREEN SHEETS — overlay dialogs on a phone =========
   Tagged by one-responsive.js (.one-fullsheet / .one-fullsheet-card).

   The bug: the RMS booking card is `h-[93vh]`. On iOS Safari `vh` is the LARGE
   viewport (toolbars retracted), so the card is taller than the visible area,
   the PAGE scrolls rather than the card body, and the sticky header — holding
   the only close button — scrolls out of reach. You couldn't exit a booking.

   Fix: pin to 100dvh (the DYNAMIC viewport, which tracks the toolbars), lock
   the background, and let ONLY the card's own body scroll. */
@media (max-width: 900px) {
  .one-fullsheet {
    padding: 0 !important;
    align-items: stretch !important; justify-content: stretch !important;
    height: 100dvh !important; max-height: 100dvh !important;
    overscroll-behavior: contain;
  }
  .one-fullsheet-card {
    width: 100vw !important; max-width: 100vw !important;
    height: 100dvh !important; max-height: 100dvh !important;
    margin: 0 !important; border-radius: 0 !important; border: 0 !important;
    display: flex !important; flex-direction: column !important;
    overflow: hidden !important;                 /* body scrolls, card doesn't */
    animation: none !important;                  /* slide-in can strand mid-way */
  }
  /* the card's own scroll region keeps momentum scrolling */
  .one-fullsheet-card .overflow-y-auto,
  .one-fullsheet-card .overflow-auto {
    -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  }
  /* background must not scroll behind the sheet */
  body.one-sheet-open { overflow: hidden !important; }
  /* the bottom tab bar would sit ON TOP of the sheet's own action bar and
     steal 58px — the sheet owns the screen while it's open */
  body.one-sheet-open .one-rail { display: none !important; }
  body.one-sheet-open.has-rail { padding-bottom: 0 !important; }

  /* Close button: the desktop `absolute top-3 right-3` lands against whichever
     ancestor happens to be positioned. Pin it to the sheet itself, give it a
     real 44px target and a background so it reads on any header colour. */
  .one-fullsheet-card > div > button.absolute,
  .one-fullsheet-card button.absolute.top-3.right-3 {
    position: fixed !important; top: 8px !important; right: 8px !important;
    width: 44px !important; height: 44px !important; z-index: 40 !important;
    background: rgba(255,255,255,.92) !important;
    border: 1px solid rgba(88,65,57,.16) !important;
    border-radius: 999px !important;
    box-shadow: 0 2px 10px rgba(0,0,0,.12) !important;
  }
  /* header stays put, never scrolls with the body */
  .one-fullsheet-card .sticky.top-0 {
    position: sticky !important; top: 0 !important; z-index: 30 !important;
    flex: none !important;
  }
  /* keep the header clear of the floating close button */
  .one-fullsheet-card .sticky.top-0 > div:first-child { padding-right: 58px !important; }

  /* Tab rail. The container already has overflow-x-auto and the buttons are
     whitespace-nowrap, but as flex children they still SHRINK — which is why
     the labels ran together ("PaymentsBilling") instead of scrolling. Pinning
     them to their content width makes the row scroll as intended. */
  .one-fullsheet-card .overflow-x-auto > button { flex: 0 0 auto !important; }
  .one-fullsheet-card > div > div.overflow-x-auto {
    gap: 4px !important; padding: 6px 8px !important;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    border-right: 0 !important;
    border-bottom: 1px solid var(--canvas-line, #e7ddd3) !important;
  }
  .one-fullsheet-card > div > div.overflow-x-auto::-webkit-scrollbar { height: 0; display: none; }
  .one-fullsheet-card .overflow-x-auto > button { padding: 8px 12px !important; min-height: 40px; }

  /* Stay/summary tiles: 2-up is too tight at 360px once labels and icons are
     in — one clear tile per row reads better and matches how the field team
     scans (arrival, then departure). */
  .one-fullsheet-card .grid.grid-cols-2 { grid-template-columns: minmax(0,1fr) !important; }

  /* The header meta is a wrapping flex row separated by bare "·" spans
     (span.text-warm-300). Designed for one desktop line; on a phone the row
     wraps and the dots strand at the start/end of lines, reading as stray
     punctuation. Hide them and let the row gap carry the separation. */
  .one-fullsheet-card .sticky.top-0 span.text-warm-300 { display: none !important; }
  .one-fullsheet-card .sticky.top-0 .flex-wrap,
  .one-fullsheet-card .sticky.top-0 .flex { gap: 4px 10px !important; }
  .one-fullsheet-card .sticky.top-0 { padding-bottom: 4px !important; }
}

/* ------------------------- 11. vw-sized blocks vs body padding (rail gutter) */
/* `width:min(720px,94vw)` measures against the VIEWPORT, not the content box,
   so any body padding (the rail gutter) pushes it past the right edge. On
   mobile these should simply fill the available width. */
@media (max-width: 900px) {
  .ask, .ceo-thread, .askbox, .hero, .centered, .narrow, .measure {
    width: auto !important; max-width: 100% !important;
    margin-left: 0 !important; margin-right: 0 !important;
  }
}

/* -------------------------------- 12. small-phone (<=380) specific tightening */
@media (max-width: 380px) {
  /* identity pill in the header: keep the avatar, drop the name */
  .who { padding: 4px 6px !important; gap: 6px !important; min-width: 0; }
  .who .nm, .who .cl { display: none !important; }
  /* type specimens on /design are intentionally large — let them wrap */
  .spec-display, .spec-mark, .spec-body, .spec-data {
    font-size: clamp(15px, 6vw, 26px) !important;
    letter-spacing: .06em !important;
    overflow-wrap: anywhere; white-space: normal !important;
  }
  .chead { padding: 6px 10px !important; }
  .wrap { padding-left: 10px !important; padding-right: 10px !important; }
  .wrap > .chead { margin-left: -10px !important; margin-right: -10px !important; }
}

/* ============ 12b. Expense (/expense) — form workspace + inline panels =======
   The New/Edit Expense page is a two-pane workspace (form | bill preview).
   Its media query stacks the panes at 1080px, but the flex container still
   refuses to shrink below its content's min width, so on a phone the whole
   page was 60px wider than the viewport. */
@media (max-width: 900px) {
  .view, .dpage, .exp-workspace, .exp-left, .exp-right, #expFormBody {
    max-width: 100% !important; min-width: 0 !important;
  }
  .exp-workspace { flex-direction: column !important; height: auto !important; overflow: visible !important; }
  .exp-left, .exp-right { width: 100% !important; flex: 0 0 auto !important; border-left: none !important; }
  .exp-right { min-height: 300px; border-top: 1px solid var(--line, rgba(88,65,57,.14)); }
  /* Form field rows AND field sections stack to one column.
     `.fsection` is a 2-col grid; left un-collapsed it split running prose into
     two ~127px columns ("No AI review yet — capture the bill and hit" |
     "Scan with Maestro" | "for verification…"), which is unreadable. */
  .dpage .frow, .dpage .fgrid, .dpage .fsection,
  .formcard .fsection, .formcard .fgrid,
  #expFormBody .row, #expFormBody .grid, #expFormBody .fsection {
    grid-template-columns: minmax(0,1fr) !important; display: grid !important;
  }
  /* identifier chips shouldn't break mid-token */
  .dpage .mut, .formcard .mut, .exp-id, .xid { white-space: nowrap; }

  /* Empty-state rows are flex containers holding an icon plus RAW TEXT with an
     inline <b>. In a flex row every text node becomes its own anonymous flex
     item, so one sentence renders as three narrow columns
     ("No AI review yet — capture the bill and hit" / "Scan with Maestro" /
     "for verification & compliance notes"). Switching to block lets the icon
     float and the sentence read as a sentence. */
  .ai-empty, .wo-empty, .empty-inline, .emptyrow, .rofield {
    display: block !important; text-align: left;
  }
  .ai-empty > svg, .ai-empty > img, .ai-empty > i,
  .wo-empty > svg, .wo-empty > img, .wo-empty > i,
  .rofield > svg, .rofield > img, .rofield > i {
    float: left; margin: 2px 8px 0 0;
  }
  .ai-empty::after, .wo-empty::after, .rofield::after { content: ""; display: block; clear: both; }
  /* the read-only field's trailing hint sits under the value, not jammed
     against it ("No work order linkedWork Orders — coming soon") */
  .rofield > em, .rofield > .hint, .rofield > small, .rofield > span {
    display: block; margin-top: 3px;
  }

  /* the expense-ID chip is a flex row [label][value][status] — keep the ID
     itself on one line so "XID-001309" can't break after the hyphen */
  .xidbar { flex-wrap: wrap !important; gap: 6px 10px !important; }
  .xidbar .xidv { white-space: nowrap !important; }
  /* the itemisation table keeps its own scroller */
  .dpage .itemgrid { min-width: 640px; }

  /* Form footer: [actions] + the Payable·Paid·Balance money strip. Side by side
     they need ~470px, so the strip hung off the right edge. Wrap it onto its
     own row and let it scroll if three figures still don't fit. */
  .formfoot { flex-wrap: wrap !important; gap: 10px !important; padding: 10px 12px !important; }
  .formfoot .foot-left { flex: 1 1 100%; }
  .foot-pay {
    flex: 1 1 100%; justify-content: space-between !important;
    gap: 10px !important; overflow-x: auto; scrollbar-width: none;
  }
  .foot-pay::-webkit-scrollbar { height: 0; display: none; }
  .foot-pay .fp { align-items: flex-start !important; flex: 0 0 auto; }
  .foot-pay .fp-v { font-size: 14px !important; }
}

/* ================= 13. RMS (/rms) — Tailwind shell, needs its own targets ====
   index.html is a Vue + Tailwind app and shares none of the .content/.subnav
   class names, so the generic rules above don't reach it. These selectors key
   off the Tailwind utility combinations that are stable in the markup. */
@media (max-width: 900px) {
  /* page gutters: px-6 is too generous on a phone */
  #app .px-6 { padding-left: 14px !important; padding-right: 14px !important; }
  #app .p-6 { padding: 14px !important; }

  /* Maestro header row (logo · agent pill · next-brief) — let it wrap instead
     of crushing the pill text to one word per line */
  #app .flex.items-center.gap-3 { flex-wrap: wrap !important; row-gap: 8px !important; }
  #app .flex.items-center.gap-3 > .ml-auto { margin-left: 0 !important; }
  #app img.h-9 { height: 30px !important; }

  /* Maestro section tabs (`flex items-end gap-1 mt-4 -mb-px`): six tabs cannot
     share 342px — they overlap. Scroll them instead, full label intact. */
  #app .flex.items-end.gap-1 {
    overflow-x: auto !important; flex-wrap: nowrap !important;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  #app .flex.items-end.gap-1::-webkit-scrollbar { height: 0; display: none; }
  #app .flex.items-end.gap-1 > button {
    flex: 0 0 auto !important; white-space: nowrap !important;
    padding-left: 12px !important; padding-right: 12px !important;
  }

}

/* RMS sidebar drawer.
   BUG THIS FIXES: the aside is `hidden md:flex`, so under 768px it is
   display:none — while the `md:hidden` hamburger only flips `sidebarOpen`,
   which merely swaps w-[52px]/w-[216px]. Net effect: on a phone the hamburger
   did nothing and the entire RMS navigation was unreachable.
   We key off the Vue-applied width class (sidebarOpen === true) rather than
   adding state, so Vue stays the single source of truth. 767px matches
   Tailwind's `md` breakpoint exactly. */
@media (max-width: 767px) {
  #app > aside {
    position: fixed !important; top: 0; bottom: 0; left: 0;
    z-index: 9600 !important; transition: none !important;
    box-shadow: 0 0 40px rgba(0,0,0,.45);
  }
  #app > aside.w-\[216px\] {
    display: flex !important;
    width: min(276px, 84vw) !important;
    transform: translateX(0) !important;
  }
  #app > aside.w-\[52px\] { display: none !important; }
  /* the drawer is dark; keep the ivory wordmark at full strength on it */
  #app > aside .wmimg { opacity: 1 !important; filter: none !important; }
  /* comfortable tap targets in the drawer */
  #app > aside a, #app > aside button { min-height: 42px; }
}
@media (max-width: 640px) {
  /* KPI tiles: 2-up reads well; the auto-fit default would give 1-up */
  #app .grid.grid-cols-2, #app .grid.grid-cols-3, #app .grid.grid-cols-4 {
    grid-template-columns: repeat(2, minmax(0,1fr)) !important;
  }
  #app .grid.grid-cols-5, #app .grid.grid-cols-6 {
    grid-template-columns: repeat(2, minmax(0,1fr)) !important;
  }

  /* Footer metrics + pagination share one nowrap row; at 360px the GBV/ADR/
     Nights figures ran straight into "Previous/Next" ("Nights: 89ous Next").
     Stack them: numbers on top, pager beneath with real tap targets. */
  #app .border-t.bg-white.flex.justify-between,
  #app .px-6.py-3.border-t {
    flex-direction: column !important; align-items: stretch !important;
    gap: 8px !important; padding: 10px 12px !important;
  }
  #app .border-t .flex.gap-6 {
    gap: 12px !important; flex-wrap: wrap !important;
    justify-content: space-between !important;
  }
  #app .border-t .flex.gap-2 {
    justify-content: flex-end !important; gap: 6px !important;
  }
  #app .border-t .flex.gap-2 > button {
    min-height: 36px; padding: 0 14px; border-radius: 8px;
    border: 1px solid var(--canvas-line, #e7ddd3);
  }
}

/* --------------------------------------------- 14. long strings must not blow out */
@media (max-width: 640px) {
  .content .nm, .content .guest, .content .title, .content .ct-main,
  .content td, .content .cell { overflow-wrap: anywhere; }
  .content .ct-main, .chead h1 { white-space: normal !important; }
}

/* ============ 14. RMS · PROPERTY CALENDAR — stack the split screen =========
   Desktop is two panes: a flex-1 month grid and a fixed `w-[340px]` aside
   holding a vertical 12-month year strip.

   THE BUG: 340px is not a proportion, it is a wall. On a 390px phone the
   aside claimed 340px and left the month pane ~50px — "Pick a property."
   was sliced in half and the month grid rendered on top of the year strip.

   THE FIX is a genuine re-layout, not a squeeze. On <=900px the view becomes
   a single column and the aside turns into a compact horizontal MONTH PICKER
   pinned above the grid: year nav on the left, month chips scrolling beside
   it. The 12 day-thumbnail heatmaps are dropped — at ~28px wide they were
   unreadable anyway, and they cost the vertical space the actual calendar
   needs. Month + year navigation stays complete: the chips select a month,
   the year arrows move the year, and the grid's own < > roll across year
   boundaries (propCalPrev/propCalNext).
   ========================================================================= */
@media (max-width: 900px) {
  .sm-propcal { flex-direction: column !important; }

  .sm-propcal-main { border-right: 0 !important; min-height: 0; }

  /* HEADER BUDGET. This view stacked four bands of chrome above the calendar
     — app bar, month strip, property select, month nav — roughly 240px of an
     844px screen before a single date was visible. The month-nav band is the
     one that goes: the month chips already select the month AND highlight the
     active one, and the year sits in the strip, so "< September 2026 >" was
     restating what the row above it already showed. Today stays (it is the
     one action neither chips nor arrows perform). */
  .sm-propcal-head { padding: 7px 10px !important; gap: 8px !important; }
  .sm-propcal-monthnav { display: none !important; }
  /* select and Today share the row now that the nav cluster is gone */
  .sm-propcal-prop { max-width: none !important; flex: 1 1 auto; min-width: 0; }
  .sm-propcal-scroll { padding: 0 10px 12px !important; }

  /* Weekday labels scrolled away under the header the moment you moved down
     the month, which read as the row being clipped. Pin them. */
  .sm-propcal-dow { position: sticky; top: 0; z-index: 5; }
  /* reclaim cell width: 7 columns on a 390px screen is ~53px each */
  .sm-propcal-week > div { padding: 3px !important; }
  /* At ~47px of content the date number and the nightly rate met with no gap
     and read as one token ("21₹11,000"). Both carry information, so neither
     is dropped — the rate just gives up a point of size and takes a hard gap.
     Stacking them onto separate lines is not an option: the third line would
     run under the lane-0 booking banner at top:28px. */
  .sm-propcal-daytop { gap: 2px !important; }
  .sm-propcal-rate { font-size: 8.5px !important; letter-spacing: -0.2px; }
  /* decorative — it was claiming a whole header row next to the full-width
     property select, which is the control that actually matters here */
  .sm-propcal-ico { display: none !important; }

  /* aside → month-picker strip above the grid */
  .sm-propcal-side {
    order: -1;                                   /* above the month grid */
    width: 100% !important;                      /* beats w-[340px] */
    flex: 0 0 auto !important;
    flex-direction: row !important;              /* beats flex-col */
    align-items: stretch !important;
    border-bottom: 1px solid #ece7dd;
  }
  .sm-propcal-year {
    flex: 0 0 auto; gap: 2px;
    padding: 4px 8px !important;
    border-bottom: 0 !important; border-right: 1px solid #ece7dd;
  }
  .sm-propcal-year > div { font-size: 15px !important; padding: 0 2px; }
  /* the year buttons are chevron-up/down for a vertical strip; the strip is
     horizontal now, so point them left/right */
  .sm-propcal-year .fa-chevron-up,
  .sm-propcal-year .fa-chevron-down { transform: rotate(-90deg); }

  .sm-cal-strip {
    /* NB: the strip is a BLOCK element on desktop (`flex-1 overflow-y-auto
       space-y-2` — "flex-1" is a flex-item utility, not a container one), so
       flex-direction alone does nothing here. It has to become a flex
       container first or the month chips just stack vertically. */
    display: flex !important;
    flex-wrap: nowrap !important;
    flex-direction: row !important;
    overflow-x: auto !important; overflow-y: hidden !important;
    padding: 6px !important; gap: 6px;
    align-items: center;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .sm-cal-strip::-webkit-scrollbar { height: 0; display: none; }
  /* Tailwind space-y-2 puts margin-top on every child but the first — that is
     vertical stacking logic and it breaks a horizontal strip */
  .sm-cal-strip > * + * { margin-top: 0 !important; }
  .sm-cal-strip > button {
    width: auto !important; flex: 0 0 auto;
    padding: 7px 13px !important; text-align: center !important;
  }
  .sm-cal-strip > button > .grid { display: none !important; }   /* drop heatmaps */
  .sm-cal-strip > button > div:first-child {
    margin-bottom: 0 !important; white-space: nowrap; font-size: 12.5px !important;
  }
}

/* ============ 15. RMS · RATES & INVENTORY grid — reclaim the date columns ===
   `.ari-lbl` (the Room/Unit name column) is a hard `flex:0 0 240px`. On a
   390px phone that is 61% of the screen for a label, leaving room for barely
   three date columns — the grid the operator actually came for was a sliver.

   Safe to fix in CSS here (unlike the portfolio Gantt, whose bars are
   percentages of a pixel-sized container): `.ari-col` is `flex:1 1 0`, so the
   date area is simply "whatever is left" and the overlaid booking bars — also
   percentage-based — stay aligned no matter how the split moves.
   ========================================================================= */
@media (max-width: 640px) {
  .ari-lbl { width: 112px !important; flex: 0 0 112px !important; }
  .ari-col { min-width: 40px !important; }                 /* ~6.5 days visible */
  /* the child (unit) rows indent by pl-8; at 112px that left ~64px for a name */
  .ari-lbl.pl-8 { padding-left: 14px !important; padding-right: 6px !important; }
  .ari-lbl.px-4 { padding-left: 8px !important; padding-right: 6px !important; }
}

/* portfolio Gantt: mx-5 spent 40px of a 390px screen on margin — that is a
   whole extra day column on the timeline */
@media (max-width: 640px) {
  .sm-pcal-grid { margin-left: 6px !important; margin-right: 6px !important; margin-bottom: 8px !important; }
}

/* ---- Property Calendar · ANNUAL VIEW (phone) -------------------------------
   The 12-month heatmap strip is a permanent 340px column on desktop. On a
   phone it collapses to a row of month chips (see above), which would have
   silently removed the year-at-a-glance overview — so the chevron beside the
   year re-expands it, here, over the month grid. Same markup, same data; only
   the shape changes. Picking a month closes it (cal.annualOpen = false).
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .sm-propcal-side.annual-open {
    position: absolute; inset: 0; z-index: 40;
    flex-direction: column !important;
    border-bottom: 0;
  }
  .sm-propcal-side.annual-open .sm-propcal-year {
    border-right: 0; border-bottom: 1px solid #ece7dd;
    padding: 8px 12px !important;
  }
  .sm-propcal-side.annual-open .sm-cal-strip {
    flex-direction: row !important; flex-wrap: wrap !important;
    overflow-x: hidden !important; overflow-y: auto !important;
    align-items: start; align-content: start;
    padding: 10px !important; gap: 10px;
  }
  /* three months per row, heatmaps back on — this is the whole point of the view */
  .sm-propcal-side.annual-open .sm-cal-strip > button {
    flex: 0 0 calc((100% - 20px) / 3);
    padding: 8px 6px !important; text-align: left !important;
  }
  .sm-propcal-side.annual-open .sm-cal-strip > button > .grid { display: grid !important; }
  .sm-propcal-side.annual-open .sm-cal-strip > button > div:first-child {
    margin-bottom: 6px !important; font-size: 11px !important;
  }
  /* the day thumbnails have a hard 18px height for the desktop column; at a
     third of a phone's width they must shrink or they overflow their month */
  .sm-propcal-side.annual-open .sm-cal-strip > button > .grid > div {
    height: 13px !important; font-size: 7.5px !important; line-height: 13px !important;
  }
}
/* desktop keeps the strip permanently open — the toggle is phone-only chrome */
@media (min-width: 901px) { .sm-propcal-annual { display: none !important; } }

/* ============ 16. RMS · Today / Tomorrow time chips on phones =============
   These were `hidden md:flex` — the quick time filters simply did not exist
   below 768px, so a phone user had no way to scope Bookings to Today or
   Tomorrow at all. They are the most-used filter on the floor, so they now
   render on their own full-width row above the view/filter cluster and
   scroll sideways rather than being dropped.
   ========================================================================= */
@media (max-width: 767px) {
  .sm-timechips {
    order: -1;                       /* above Individual/Group · Table/Cards · Filters */
    flex: 1 0 100% !important;
    justify-content: flex-start !important;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  .sm-timechips::-webkit-scrollbar { height: 0; display: none; }
  .sm-timechips > button { flex: 0 0 auto; }   /* chips keep their width, never squash */
}

/* ============ 17. EXPENSE — mobile shell ==================================
   Three separate complaints, one section.
   ========================================================================= */
@media (max-width: 640px) {
  /* (a) WHITE ON WHITE. The list tables live inside a `.card` (white, bordered,
     rounded). Once each row becomes its own white card, that outer shell just
     framed white with white — no separation between records. On phones the
     shell steps back and the row-cards float on the ivory canvas instead. */
  /* NB: `:has()` cannot be nested inside `:has()` — `.card:has(table:has(td))`
     is an invalid selector and the browser drops the entire rule. The labelled
     cell is a descendant of the card regardless, so match it directly. */
  .content .card:has(td[data-l]) {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    overflow: visible !important;
  }
  /* give the floating cards a little more presence than the flat 1px shadow */
  table:has(td[data-l]) tr { box-shadow: 0 1px 4px rgba(88,65,57,.09) !important; }

  /* (b) THE FILTER SEARCH SPILLED OFF-SCREEN, and it duplicates the global
     search in the app bar. `.tsearch` is `flex:1; min-width:160px` and its
     input is `flex:1` with no min-width — a flex item defaults to
     `min-width:auto`, so the input refused to shrink below its intrinsic
     ~193px and painted straight off the right edge of a 390px screen.
     It is hidden on phones (the app-bar search covers it); the min-width:0
     stays as a guard for anywhere else a .tsearch is shown. */
  .tsearch { display: none !important; }
  .tsearch input, .tsearch select { min-width: 0 !important; }

  /* (c) the toolbar is now [segments] + [primary action] */
  .tbar { gap: 8px !important; margin-bottom: 10px !important; }
  .tbar .segs {
    flex: 1 0 100%; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tbar .segs::-webkit-scrollbar { height: 0; display: none; }
  .tbar .segs .seg { flex: 0 0 auto; }
  .tbar .sp { display: none !important; }          /* the flex:1 spacer */
  .tbar .btn.primary { flex: 1 0 100%; justify-content: center; height: 44px; }
}

/* ============ 18. EXPENSE — Maestro scan header ============================
   `.vision-hd` is a nowrap flex row: a 48px-tall Maestro lockup plus a
   "Scan with Maestro" button pushed right with margin-left:auto. Together
   they need ~430px; at 390px the button ran off the screen edge with its
   label cut mid-word. The row wraps on phones and the scan button — the
   primary action of this whole screen — takes the full width beneath the
   lockup, where it is also a comfortable thumb target.
   ========================================================================= */
@media (max-width: 640px) {
  .vision-hd { flex-wrap: wrap !important; gap: 8px !important; margin-bottom: 10px !important; }
  .mstr-logo { height: 38px !important; }
  .vai-scan.hd {
    width: 100% !important; margin-left: 0 !important;
    height: 44px !important; font-size: 14px !important;
  }
  .vision { padding: 12px !important; }
}

/* ============ 19. EXPENSE — scanner first, sections collapsible ============
   SCANNER FIRST. `.exp-workspace` is form-left + bill-right; below 1080px it
   stacks into a column with the bill panel SECOND, so on a phone the Maestro
   drop zone sat under the entire form. That inverts the actual workflow —
   you photograph the bill, then Maestro fills the form — and buried the
   screen's primary action. `order:-1` puts it back on top.

   COLLAPSIBLE SECTIONS. Seven full sections in one scroll is a long way to
   thumb. Headings become accordion toggles (wired in one-responsive.js);
   the first is open, the rest fold. Phone-only: above 640px nothing here
   applies and the desktop form is untouched.
   ========================================================================= */
@media (max-width: 640px) {
  .exp-workspace { height: auto !important; }
  .exp-right {
    order: -1;                        /* the bill/scan panel leads */
    border-top: 0 !important;
    border-bottom: 1px solid var(--line, rgba(88,65,57,.12));
    min-height: 0 !important;
  }
  .exp-scroll { overflow: visible !important; }

  /* --- accordion affordance: expense form (.fsection > .sec-title) --- */
  .fsection { padding: 12px 14px 14px !important; }
  .fsection > .sec-title {
    cursor: pointer; position: relative; padding-right: 24px !important;
    user-select: none; -webkit-user-select: none;
  }
  .fsection > .sec-title::after {
    content: ""; position: absolute; right: 4px; top: 50%;
    width: 8px; height: 8px; margin-top: -6px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); transition: transform .15s;
  }
  .fsection.sec-collapsed > .sec-title::after { transform: rotate(-45deg); margin-top: -3px; }
  .fsection.sec-collapsed > .sec-title { border-bottom: 0 !important; padding-bottom: 0 !important; }
  .fsection.sec-collapsed > *:not(.sec-title) { display: none !important; }
  .fsection.sec-collapsed { padding-bottom: 12px !important; }

  /* --- accordion affordance: vendor drawer (.fgrid > .fsec + .fsec-body) --- */
  .fgrid > .fsec {
    cursor: pointer; position: relative; padding-right: 24px !important;
    user-select: none; -webkit-user-select: none;
  }
  .fgrid > .fsec::after {
    content: ""; position: absolute; right: 4px; top: 50%;
    width: 8px; height: 8px; margin-top: -6px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); transition: transform .15s;
  }
  .fgrid > .fsec.fsec-collapsed::after { transform: rotate(-45deg); margin-top: -3px; }
}
/* The wrapper one-responsive.js inserts must be INVISIBLE to layout when
   open — display:contents keeps the fields as direct grid items of .fgrid,
   so neither the phone nor the desktop grid changes shape. */
.fsec-body { display: contents; }
@media (max-width: 640px) {
  .fgrid > .fsec.fsec-collapsed + .fsec-body { display: none; }
}

/* ============ 20. RMS · icon-only buttons need real tap targets ===========
   Audited every RMS view at 390px for controls under ~30px in either axis.
   Three offenders, all icon-only buttons that inherit their size from the
   glyph because they have no padding of their own:

     • the sidebar hamburger  — 18px wide. This is THE control for reaching
       navigation on a phone and it was a sliver.
     • an error-banner dismiss × — 11px wide.
     • the Individual/Group segmented toggle — 26px per half.

   Apple's guidance is 44px, Material's 48dp; these get 40px, which is what
   fits the existing 40px-tall header rows without reflowing them. The glyphs
   are unchanged — only the hit area grows.
   ========================================================================= */
@media (max-width: 767px) {
  #app button.md\:hidden {
    min-width: 40px; min-height: 40px;
    display: inline-grid !important; place-items: center;
    margin-left: -6px;                  /* keep the icon optically on the grid */
  }
  /* icon-only dismiss buttons (no text node of their own) */
  #app button:has(> i.fa-times):not(:has(span)),
  #app button:has(> i.fa-xmark):not(:has(span)) {
    min-width: 38px; min-height: 38px;
    display: inline-grid !important; place-items: center;
  }
  /* segmented toggles: Individual/Group, Table/Cards */
  #app .inline-flex.rounded-lg > button { min-width: 40px; min-height: 36px; }
}

/* checkboxes and radios in RMS forms render at the Tailwind w-3/h-3 (12–13px)
   the desktop design uses. That is a fine mouse target and a poor thumb one —
   the admin screens (auto-assign rules, property mapping) are full of them.
   20px keeps the row heights intact while roughly tripling the hit area.
   Bulk-select checkboxes in card mode are hidden elsewhere and unaffected. */
@media (max-width: 767px) {
  #app input[type="checkbox"],
  #app input[type="radio"] {
    width: 20px !important; height: 20px !important;
    flex: none; accent-color: #0e7d78;
  }
}

/* Expense ID bar: "EXPENSE ID · XID-001312 · NOT SUBMITTED" needs ~300px of
   text at desktop sizes, so on a phone the status chip wrapped to its own
   line and left the bar looking broken-open. Tightened so all three sit on
   one row, with the chip allowed to shrink last. */
@media (max-width: 640px) {
  .xidbar { gap: 7px !important; padding: 6px 10px !important; flex-wrap: nowrap; }
  .xidbar .xidk { font-size: 8.5px !important; flex: none; }
  .xidbar .xidv { font-size: 14px !important; flex: 0 1 auto; min-width: 0;
                  overflow: hidden; text-overflow: ellipsis; }
  .xidbar .xstatus { font-size: 8.5px !important; padding: 3px 8px !important; flex: none; }
  .xidbar .xidnote { display: none; }        /* the italic hint is desktop-only nicety */
}
