/* ════════════════════════════════════════════════════════════════════════
   08 · Mobile app-shell  (Sunwave OS)
   ------------------------------------------------------------------------
   Turns the desktop /admin shell into a real phone app at ≤600px WITHOUT
   touching the desktop layout. Everything here is gated behind the phone
   breakpoint (or hides a phone-only element on desktop), so >600px is byte-
   identical to before. Loads LAST (after 06-horizon-shell / 07-dock-schedule)
   so its rules win on equal specificity.

   What the phone layer does:
     • Bottom dock collapses from 7 tabs to 5: Booking · Schedule · Inbox ·
       Customers · More. KPI / Settings / Price Book drop OFF the bar (Price
       Book + every settings screen live under the new "More" tab).
     • The desktop sidebar and the top command-search are hidden (the dock +
       per-section search + "More" replace them).
     • The Booking iframe fills the screen above the dock.
   The breakpoint is 600px: ≤860px (tablet) keeps its existing strip layout.
   ════════════════════════════════════════════════════════════════════════ */

/* The "More" tab is phone-only — hidden on desktop/tablet by default.
   `.admin-body`-scoped so it matches the base `.admin-body .horizon-tab`
   specificity and wins by load order (this sheet loads last). */
.admin-body .horizon-tab--more { display: none; }
.admin-body .sw-app-loader {
  display: none;
}

/* Location-leaders phone header — phone-only (shown in the ≤600 block below);
   desktop keeps the KPI rail + the board's own period header. */
.ldf-head { display: none; }

/* ── "More" hub visuals (width-agnostic so /admin/more reads well anywhere) ── */
.more-wrap { max-width: 640px; margin-inline: auto; padding: 0 4px 24px; }
.more-section-title {
  margin: 18px 4px 8px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--sw-muted, #7B8190);
}
.more-grid { display: flex; flex-direction: column; gap: 8px; }

/* Global search pill at the top of "More" — looks like a search field, but is a
   button that opens the shared command palette (wired in admin-dashboard.js). */
.more-search {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin: 2px 0 14px;
  padding: 13px 15px;
  border: 1px solid var(--sw-border, #E5DED3);
  border-radius: 14px;
  background: var(--sw-card, #FCFAF6);
  color: var(--sw-muted, #7B8190);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 4px 14px rgba(55, 59, 77, 0.05);
  transition: background .16s ease, transform .12s ease;
}
.more-search:hover { background: var(--sw-card-lift, #FFFDF9); }
.more-search:active { transform: scale(0.99); }
.more-search-ico { flex: none; color: var(--sw-orange, #F38A3F); }
.more-search-text {
  flex: 1; min-width: 0;
  font-size: 14.5px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.more-profile {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 6px;
  padding: 14px;
  border: 1px solid var(--sw-border, #E5DED3);
  border-radius: 18px;
  background: var(--sw-card, #FCFAF6);
  box-shadow: 0 8px 24px rgba(55, 59, 77, 0.06);
  color: var(--sw-ink-deep, #373B4D);
  text-decoration: none;
}
.more-profile-avatar {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--sw-orange, #F38A3F);
  color: #fff; font-weight: 800; font-size: 18px;
}
.more-profile-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.more-profile-text strong { font-size: 15px; }
.more-profile-text small {
  color: var(--sw-muted, #7B8190); font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.more-profile-role {
  flex: none;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(55, 59, 77, 0.06);
  color: var(--sw-muted, #7B8190);
  font-size: 11px; text-transform: capitalize;
}

.more-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 14px;
  border: 1px solid var(--sw-border, #E5DED3);
  border-radius: 14px;
  background: var(--sw-card, #FCFAF6);
  color: var(--sw-ink-deep, #373B4D);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease, transform .12s ease;
}
.more-row:hover { background: var(--sw-card-lift, #FFFDF9); }
.more-row:active { transform: scale(0.99); }
.more-row-ico {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: 10px;
  background: rgba(243, 138, 63, 0.10);
  color: var(--sw-orange, #F38A3F);
}
.more-row-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.more-row-label { font-size: 14.5px; font-weight: 600; }
.more-row-sub {
  font-size: 12px; color: var(--sw-muted, #7B8190);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.more-row-chev { flex: none; color: var(--sw-muted, #7B8190); }
.more-row--danger { color: var(--sw-coral, #D65F4F); }
.more-row--danger .more-row-ico {
  background: rgba(214, 95, 79, 0.10);
  color: var(--sw-coral, #D65F4F);
}

@media (max-width: 600px) {
  /* Kill the iOS white bar at the screen bottom. The shell pins html/body to
     height:100% (06-horizon-shell.css), which on an iPhone can stop short of
     the full dynamic viewport (collapsed Safari toolbar / home-indicator
     region) — the strip below the document paints the browser's own white,
     not our frost. Stretch the document to the full dynamic viewport, exactly
     how /tech does it (body.tech-appshell { min-height:100dvh }). No layout
     effect: overflow stays hidden and .app-scroll owns the only scrollbar. */
  html:has(body.app-framed),
  body.app-framed {
    min-height: 100vh;
    min-height: 100dvh;
  }
  .admin-body.admin-app-loading {
    overflow: hidden;
  }
  .admin-body .sw-app-loader {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: grid;
    place-items: center;
    padding: max(22px, env(safe-area-inset-top, 0px)) 22px max(22px, env(safe-area-inset-bottom, 0px));
    background:
      radial-gradient(130% 105% at 100% -8%, rgba(191, 224, 243, 0.26) 0%, rgba(191, 224, 243, 0) 58%),
      radial-gradient(120% 95% at -8% 108%, rgba(243, 138, 63, 0.16) 0%, rgba(243, 138, 63, 0) 62%),
      var(--sw-frost-base, #FBF8F3);
    color: var(--sw-ink, #373B4D);
    opacity: 1;
    visibility: visible;
    transition: opacity 260ms cubic-bezier(0.22, 1, 0.36, 1), visibility 260ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .admin-body.admin-app-loaded .sw-app-loader,
  .admin-body:not(.admin-app-loading) .sw-app-loader {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  .admin-body .sw-app-loader-card {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 22px;
    width: min(280px, calc(100vw - 44px));
    padding: 12px;
    text-align: center;
    animation: swAdminLoaderCardIn 460ms cubic-bezier(0.22, 1, 0.36, 1) both;
  }
  /* The brandmark art already carries its own dark rounded-rectangle border,
     so we draw NO tile/card behind it — just the logo, with a single orange
     light tracing its own edge. */
  .admin-body .sw-app-loader-mark {
    position: relative;
    display: grid;
    place-items: center;
  }
  .admin-body .sw-app-loader-mark img {
    display: block;
    width: auto;
    height: 96px;
  }
  .admin-body .sw-app-loader-trace {
    position: absolute;
    inset: -7px;
    width: calc(100% + 14px);
    height: calc(100% + 14px);
    overflow: visible;
    pointer-events: none;
  }
  .admin-body .sw-app-loader-trace rect {
    fill: none;
    stroke: var(--sw-orange, #F38A3F);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 14 86;
    animation: swAdminLoaderTrace 2100ms linear infinite;
  }
  .admin-body .sw-app-loader-copy {
    display: grid;
    gap: 6px;
  }
  /* Wordmark only — the "Preparing the mobile workspace" subtext was
     removed 2026-07-03; the animation + "Sunwave" carry the moment. */
  .admin-body .sw-app-loader-copy strong {
    color: var(--sw-ink, #373B4D);
    font-size: 20px;
    line-height: 1.2;
    font-weight: 800;
    letter-spacing: -0.4px;
  }
  /* Light travels the full edge exactly once per cycle (pathLength=100,
     dash pattern sums to 100), so the loop is seamless. */
  @keyframes swAdminLoaderTrace {
    to { stroke-dashoffset: -100; }
  }
  @keyframes swAdminLoaderCardIn {
    from { opacity: 0; transform: translateY(10px) scale(0.98); }
    to   { opacity: 1; transform: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .admin-body .sw-app-loader-card,
    .admin-body .sw-app-loader-trace rect {
      animation: none;
    }
  }

  /* ── Bottom dock → 5-tab phone bar ───────────────────────────────────
     Show the four keepers + More; drop the three that move under "More".
     In Super Admin (org) scope Booking/Customers are already absent
     server-side, leaving Feedback · Inbox · More — space-around keeps a
     short bar looking intentional. */
  .admin-body .horizon-tab[data-nav="finances"],
  .admin-body .horizon-tab[data-nav="pricebook"],
  .admin-body .horizon-tab[data-nav="performance-hub"],
  .admin-body .horizon-tab[data-nav="settings-hub"] {
    display: none;
  }
  .admin-body .horizon-tab--more { display: inline-grid; }

  .horizon-dock {
    /* Phone dock matches /tech: wide frosted pill, low to the safe area, with
       56px thumb targets inside. */
    left: 12px;
    right: 12px;
    bottom: max(8px, calc(env(safe-area-inset-bottom, 0px) + 6px));
    width: auto;
    max-width: none;
    transform: none;
    gap: 4px;
    padding: 9px 10px;
    border-radius: 30px;
  }
  .horizon-dock-center {
    justify-content: space-around;
    gap: 2px;
  }
  .horizon-tab,
  .admin-body .horizon-tab {
    /* Icon-only tap targets on phone. Labels stay in aria-label/title only. */
    box-sizing: border-box;
    grid-template-columns: auto !important;
    justify-content: center;
    justify-items: center;
    width: 56px;
    height: 56px;
    min-width: 56px;
    padding: 0;
    min-height: 56px;
    font-size: 14px;
    appearance: none;
    -webkit-appearance: none;
    transition: grid-template-columns 0.22s cubic-bezier(0.22, 1, 0.36, 1),
                background 0.18s cubic-bezier(0.22, 1, 0.36, 1),
                color 0.14s ease,
                box-shadow 0.18s ease;
  }
  .horizon-tab.is-active,
  .admin-body .horizon-tab.is-active {
    grid-template-columns: auto !important;
  }
  .horizon-tab-label,
  .admin-body .horizon-tab-label {
    display: none !important;
  }
  .horizon-dock-pill {
    transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
                width 0.2s cubic-bezier(0.22, 1, 0.36, 1),
                height 0.2s cubic-bezier(0.22, 1, 0.36, 1),
                background 0.16s ease,
                box-shadow 0.16s ease,
                opacity 0.16s ease;
  }
  /* The orange active-glide keeps the phone bar's quicker pace (tabs are
     fixed 56px squares here, so the slide is a pure horizontal hop). */
  .horizon-dock-glide {
    transition: transform 0.26s cubic-bezier(0.22, 1, 0.36, 1),
                width 0.26s cubic-bezier(0.22, 1, 0.36, 1),
                height 0.26s cubic-bezier(0.22, 1, 0.36, 1),
                opacity 0.16s ease;
  }
  .admin-body .section-page > *,
  .admin-body .section-page .horizon-hub-layout > .horizon-hub-main {
    animation-duration: 0.18s;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  }
  /* Drop BOTH dock wings on phone. The profile wing duplicates what "More"
     surfaces (account + sign out), and the "+" quick-create wing is redundant
     with the Booking tab (it opens the same new-job flow) — so the five tabs
     get the full width and there's no stray "+" in the corner. */
  .horizon-dock > .horizon-dock-wing {
    display: none;
  }

  /* ── Native iOS shell (SWNativeTabs UA) ──────────────────────────────
     The admin app now draws its OWN native bottom tab bar (AdminShellView),
     so the web dock disappears entirely inside it. Content clearances stay —
     the native bar occupies the same band the dock did. Old app builds carry
     the plain "SunwaveApp" UA and keep this dock. */
  .admin-body.native-tabs .horizon-dock {
    display: none !important;
  }

  /* ── Hide desktop chrome ─────────────────────────────────────────────
     The sidebar (a clumsy horizontal strip on phone) and the top command-
     search both go away; "More" + per-section search cover their jobs. With
     the search gone, reclaim the top room the ≤860 block reserved for the
     stacked pill+search row (104px → just under the location pill). */
  /* DO NOT CHANGE WITHOUT ASKING LEVI FIRST.
     The installed app lets the page background continue behind the iOS status
     icons. Content still needs safe-area clearance because the floating
     location pill sits close to the physical top edge. max() keeps a fixed
     floor where there is no inset and expands to clear the notch. */
  :root { --chrome-top: max(64px, calc(env(safe-area-inset-top, 0px) + 20px)); }
  .admin-nav,
  .admin-nav-v3,
  .horizon-searchbar {
    display: none !important;
  }

  /* ── Booking tab fills the phone ─────────────────────────────────────
     One column, no left rail (the booking menu + recent-bookings dock are
     desktop-only). The iframe spans full width; its HEIGHT is owned by the
     parent's embed-autosize (it sets f.style.height inline to the content
     height, which beats any stylesheet height), so the page scrolls as one —
     no nested scrollbar. min-height covers the moment before autosize fires. */
  .section-page[data-section="booking-portal"] .horizon-hub-layout,
  .section-page[data-section="booking-portal"] .horizon-context-layout--wide {
    grid-template-columns: 1fr;
  }
  /* The wizard card should touch the physical screen edges. Cancel the
     .admin-shell side gutter (clamp() floors at 16px on phone widths) with
     matching negative margins. width:auto + max-width:none are required:
     the flex-column stretch then sizes the box to container + 32px, whereas
     the inherited width:100% / max-width:min(1480px,100%) would clamp it
     back and shove the section off-center. The heavy selector out-weighs
     both of those inherited rules. */
  .admin-body .admin-content > .section-page[data-section="booking-portal"] {
    width: auto;
    max-width: none;
    margin-inline: calc(-1 * clamp(16px, 2.5vw, 36px));
  }
  .scheduler-rail-col {
    display: none;
  }
  #admin-scheduler-frame {
    width: 100%;
    min-height: 480px;
  }

  /* Roomier tap targets for the "More" rows on a phone. */
  .more-row { min-height: 52px; }
  .more-row-label { font-size: 15px; }
  /* (iOS focus-zoom guard for phone fields is app-wide now — see tokens.css.) */

  /* ── Settings destinations from More ───────────────────────────────
     Most More links still render the desktop admin partials. On a phone the
     rail becomes a compact horizontal chip strip, while the content below
     behaves like a single-column app screen. */
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) {
    padding-inline: 0;
  }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-layout,
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-context-layout--wide,
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-context-layout--kpi {
    display: block;
  }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-main {
    width: 100%;
    min-width: 0;
  }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-rail {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    margin: 0 0 12px;
    padding: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    border: 1px solid var(--sw-border, #E5DED3);
    border-radius: 18px;
    background: color-mix(in srgb, var(--sw-card, #FCFAF6) 82%, transparent);
    box-shadow: 0 10px 24px var(--sw-shadow, rgba(55,59,77,0.08));
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-rail::-webkit-scrollbar { display: none; }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-rail > .rail-list,
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .horizon-hub-rail .rail-group-panel .rail-list {
    display: flex;
    flex-direction: row;
    gap: 6px;
    min-width: max-content;
    margin: 0;
    padding: 0;
    border-left: 0;
  }

  .section-page.booking-settings-page .booking-page-rail .rail-group--booking-settings,
  .section-page.booking-settings-page .booking-page-rail .rail-group-panel {
    display: flex;
    opacity: 1;
  }
  .section-page.booking-settings-page .booking-page-rail .rail-group-trigger { display: none; }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .page-rail .rail-list,
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .page-rail .rail-group {
    min-width: max-content;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .page-rail-link {
    width: auto;
    min-width: 0;
    min-height: 42px;
    padding: 8px 12px;
    border-radius: var(--sw-radius-pill, 999px);
    white-space: nowrap;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .page-rail-link .rail-label {
    max-width: 148px;
    font-size: 12.5px;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .rail-icon {
    width: 28px;
    height: 28px;
    border-radius: 10px;
  }

  /* ── Location Leaders: real page header instead of the chip strip ────
     The generic rail-as-chip-strip breaks on this section (the rail's nested
     desk sub-groups are forced open at ≤860 and wrap into a tall cluster that
     slides UNDER the floating top chips — the "‹ More" chip in the native app
     and the centered location pill). Replace it: hide the rail + the board's
     in-content period header, and show the .ldf-head band (title row + period
     pill + dashboard switcher) with enough top margin that nothing sits under
     the chips row. The margin formula: the chips row bottoms out around
     safe-area-top + 44px (cornerbar top = max(8px, safe-top), height 36px);
     content already starts at --chrome-top, so only the shortfall is added —
     in a plain browser tab (no notch) it resolves to 0. */
  /* !important: the generic chip-strip rule above carries three :not()
     attribute selectors and would out-weigh this section-scoped hide. */
  .section-page[data-section="leader-dashboard-frame"] .horizon-hub-rail,
  .section-page[data-section="leader-dashboard-frame"] .fin-month-header {
    display: none !important;
  }
  .section-page[data-section="leader-dashboard-frame"] .ldf-head {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: max(0px, calc(env(safe-area-inset-top, 0px) + 56px - var(--chrome-top, 64px))) 0 16px;
    padding-inline: 4px;
  }
  .ldf-head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  .ldf-head-titles {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }
  .ldf-head-eyebrow {
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--sw-muted, #7B8190);
  }
  .ldf-head-title {
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--sw-ink-deep, #373B4D);
  }
  .ldf-period {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    flex: none;
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid var(--sw-orange, #F38A3F);
    border-radius: var(--sw-radius-pill, 999px);
    background: var(--sw-orange-soft, #FFEEDC);
    color: var(--sw-orange-dark, #C66518);
    font: inherit;
    font-size: 13.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    padding: 8px 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform 140ms ease, box-shadow 140ms ease;
  }
  .ldf-period:active { transform: scale(0.97); }
  .ldf-period:focus-visible {
    outline: none;
    box-shadow: var(--sw-focus-shadow, 0 0 0 1px #F38A3F, 0 6px 13px rgba(243, 138, 63, 0.30));
  }
  .ldf-tabs {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .ldf-tabs::-webkit-scrollbar { display: none; }
  .ldf-tab {
    flex: none;
    white-space: nowrap;
    border: 1px solid var(--sw-border, #E5DED3);
    border-radius: var(--sw-radius-pill, 999px);
    background: var(--sw-card-lift, #FFFDF9);
    color: var(--sw-muted, #7B8190);
    font-size: 12.5px;
    font-weight: 700;
    padding: 8px 13px;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: transform 140ms ease, background 140ms ease;
  }
  .ldf-tab:active { transform: scale(0.97); }
  .ldf-tab.is-active {
    border-color: var(--sw-orange, #F38A3F);
    background: var(--sw-orange, #F38A3F);
    color: #FFFDF9;
  }
  /* Inside the native app the dashboard switcher is redundant — the "‹ Back"
     chip returns to More, where Technician Performance is its own row — so
     the tabs row disappears and the header tightens up. Web phone keeps it. */
  .admin-body.native-tabs .ldf-tabs {
    display: none !important;
  }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .hub-mini-head {
    align-items: flex-start;
    min-height: 0;
    margin-bottom: 12px;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .hub-mini-chip {
    margin-left: 0;
    max-width: 100%;
  }

  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) .bento-grid { gap: 12px; }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) :is(.bento-card, .card2) { border-radius: 20px; }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) :is(.bento-card-head, .card2-header) { gap: 12px; }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) :is(input, select, textarea) {
    max-width: 100%;
    min-width: 0 !important;
    font-size: 16px;
  }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) :is(.bento-actions-row, .gkey-actions, .card2-actions) { align-items: stretch; }
  .section-page:not([data-section="booking-portal"]):not([data-section="schedule-agenda"]):not([data-section="communications-inbox"]) :is(.bento-actions-row, .gkey-actions, .card2-actions) > :is(.bento-btn, .btn, a.btn, button) {
    justify-content: center;
  }

  .gkey-acc-summary {
    align-items: flex-start;
    flex-wrap: wrap;
    padding-block: 12px;
  }
  .gkey-acc-summary .gkey-name {
    flex: 1 1 calc(100% - 36px);
  }
  .gkey-acc-status {
    margin-left: 25px;
  }
  .gkey-acc-body {
    padding-right: 0;
  }
  .svc-login-grid {
    grid-template-columns: 1fr;
  }
  .svc-login-link {
    align-items: stretch;
    flex-direction: column;
  }
  .svc-login-open {
    align-self: flex-start;
  }

  .account-identity {
    align-items: flex-start;
  }
  .account-identity-meta {
    width: 100%;
    margin-left: 0;
  }
  .account-field-grid {
    grid-template-columns: 1fr;
  }

  .user-search-wrap,
  .user-add-form,
  .user-add-field {
    width: 100%;
  }
  .user-add-form {
    align-items: stretch;
    flex-direction: column;
  }
  .user-add-field input,
  .user-add-field select,
  .user-add-form .btn {
    width: 100%;
    min-width: 0;
  }

  .all-locations-row {
    padding: 14px;
    background: var(--sw-card-lift, #FFFDF9);
    border: 1px solid var(--sw-border, #E5DED3);
  }
  .all-locations-row--head {
    display: none;
  }
  .all-locations-action-group,
  .all-locations-cell--action,
  .all-locations-cell--action .bento-btn {
    width: 100%;
  }
  .all-locations-action-group {
    display: flex;
    align-items: stretch;
    gap: 8px;
  }

  .pw-wrap {
    width: 100%;
  }
  .pw-head,
  .pw-head-tools,
  .pw-search,
  .pw-add-btn {
    width: 100%;
  }
  .pw-add-btn {
    justify-content: center;
  }
  .pw-filters {
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: 2px;
    -webkit-overflow-scrolling: touch;
  }
  .pw-filter {
    flex: none;
  }
  .pw-modal {
    width: min(100vw - 20px, 480px);
    max-height: calc(100dvh - var(--chrome-top, 64px) - var(--chrome-bottom, 112px));
  }
  .pw-modal-foot {
    align-items: stretch;
    flex-wrap: wrap;
  }
  .pw-modal-foot .bento-btn {
    flex: 1 1 auto;
    justify-content: center;
  }

  .booking-settings-page .booking-settings-layout,
  .booking-settings-page .booking-settings-layout--single {
    margin-top: 0;
  }
  .booking-settings-page .bento-card {
    padding: 16px 14px;
  }
  .day-row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .bento-mini-grid {
    grid-template-columns: 1fr;
  }
  .booking-settings-save-card--footer,
  .settings-save-strip--footer {
    border-radius: 18px;
  }
}

/* ── Phone tech-view embeds (Schedule · Inbox · Passwords) ────────────────
   These three phone tabs reuse the heavily mobile-optimized TECHNICIAN views
   in iframes (src loaded lazily by admin-dashboard.js). Hidden on desktop; on a
   phone each fills the area between the location pill and the dock, and the
   desktop section content is hidden so only the iframe shows. The desktop
   /admin sections are otherwise untouched. */
.mobile-embed { display: none; width: 100%; border: 0; background: transparent; }
@media (max-width: 600px) {
  .mobile-embed {
    display: block;
    height: calc(100dvh - var(--chrome-top, 56px) - var(--chrome-bottom, 112px));
    min-height: 420px;
  }
  .section-page.mobile-embed-loading::before {
    content: "Loading workspace";
    position: fixed;
    inset: 0;
    z-index: 2;
    display: grid;
    place-items: center;
    padding: var(--chrome-top, 56px) 22px var(--chrome-bottom, 112px);
    background:
      radial-gradient(130% 105% at 100% -8%, rgba(191, 224, 243, 0.18) 0%, rgba(191, 224, 243, 0) 58%),
      radial-gradient(120% 95% at -8% 108%, rgba(243, 138, 63, 0.12) 0%, rgba(243, 138, 63, 0) 62%),
      var(--sw-frost-base, #FBF8F3);
    color: var(--sw-muted, #7B8190);
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0;
    pointer-events: none;
  }
  /* Schedule + Inbox: show ONLY the iframe; hide the desktop board / two-pane.
     (The Passwords embed lives in its own iframe-only section, nothing to hide.) */
  .section-page[data-section="schedule-agenda"] > *:not(.mobile-embed),
  .section-page[data-section="communications-inbox"] > *:not(.mobile-embed) {
    display: none !important;
  }

  /* Schedule should read as the page background, not as an iframe-shaped panel.
     Pin it edge-to-edge behind the floating location pill and bottom dock; the
     embed adds its own chrome clearance in admin-mobile-embed.ejs. */
  .section-page[data-section="schedule-agenda"] .mobile-embed {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100dvh;
    min-height: 0;
    z-index: 1;
  }

  /* ── Inbox list fills the whole phone ────────────────────────────────
     The inbox iframe used to sit in the middle band (between the pill and the
     dock) and inset by the shell's side gutter, so it read as a smaller card on
     a second background. Pin it edge-to-edge / top-to-bottom instead, BELOW the
     floating location pill + dock (z 90) so they rest ON TOP of it — the box is
     now the page, with no seam. The iframe's own content carries the top/bottom
     clearance (admin-mobile-embed.ejs `body.ame-inbox-full`). The immersive rule
     below (a single open thread) still wins via higher specificity. */
  .section-page[data-section="communications-inbox"] .mobile-embed {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100dvh;
    min-height: 0;
    z-index: 1;
  }

  /* Messaging/Templates folded into the inbox: on a phone the inbox is the iframe, but
     the studio is still reachable (More → Messaging → body.inbox-templates-open). When
     it's open, hide the iframe and surface ONLY the studio pane — no desktop rail / list
     / thread on a phone; the studio carries its own phone nav (.comm-phone-nav). */
  body.inbox-templates-open .section-page[data-section="communications-inbox"] .mobile-embed { display: none !important; }
  body.inbox-templates-open .section-page[data-section="communications-inbox"] > #inboxApp { display: block !important; }
  body.inbox-templates-open #inboxApp > *:not(#inboxTemplates) { display: none !important; }
  body.inbox-templates-open #inboxTemplates {
    display: block !important;
    /* Clear the floating top pills + the bottom dock (both z-90, position:fixed). */
    padding-top: calc(var(--chrome-top, 56px) + 8px);
    padding-bottom: calc(var(--chrome-bottom, 112px) + 16px);
  }

  /* ── Immersive conversation ──────────────────────────────────────────
     When the Inbox iframe reports that a single conversation (or the new-
     message composer) is open, it posts up to admin-dashboard.js, which flags
     body.inbox-immersive. We then drop the floating location pill + the bottom
     dock and let the inbox iframe cover the WHOLE phone, so a chat reads full-
     screen and edge-to-edge — iMessage-style (the thread carries its own
     "‹ Inbox" back button to return, which clears the flag). No transformed/
     filtered ancestor sits above .mobile-embed, so position:fixed anchors to
     the viewport. */
  body.inbox-immersive .horizon-cornerbar,
  body.inbox-immersive .horizon-dock {
    display: none !important;
  }
  body.inbox-immersive .section-page[data-section="communications-inbox"] .mobile-embed {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100dvh;
    min-height: 0;
    z-index: 200;
  }
  body.inbox-immersive .section-page.mobile-embed-loading::before {
    z-index: 201;
    padding: 22px;
  }

  /* ── Full-screen detail views drop the location pill ─────────────────
     The location switcher belongs to the main tab views only. While a
     full-screen detail is open — a job modal / appointment sheet / composer
     inside the Schedule iframe (it posts up sw:detail-immersive →
     body.detail-immersive), or a customer profile on the Customers tab
     (pure :has(), no JS needed) — hide the floating pill so it can't paint
     over the detail's header. The dock stays: tabs remain reachable. */
  body.detail-immersive .horizon-cornerbar {
    display: none !important;
  }
  /* The appointment sheet / composer put Build + Back actions at the very
     bottom of the screen — the floating dock (z-90, above the iframe) would
     cover them, so FULL immersive drops the dock too. The read-only job modal
     stays dock-visible (its content is top-anchored). */
  body.detail-immersive-full .horizon-dock {
    display: none !important;
  }
  /* Kept as a SEPARATE rule on purpose: a browser without :has() support
     drops the whole rule it appears in, and grouping it above would take the
     body.detail-immersive selector down with it. */
  body.admin-body:has(.section-page[data-section="customers"].is-visible [data-cust-view="profile"]:not([hidden])) .horizon-cornerbar {
    display: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .admin-body .sw-app-loader {
    transition: none;
  }
  .admin-body .sw-app-loader-ring {
    animation: none;
  }
}
