/* =========================================================================
   MAESTROX — Mobile (PWA-ready) primitives
   Vendored from the Mx2 Design System v1 (mobile.css).
   Scoped to < 768px; desktop layout is untouched.

   Components ported here:
     .m-page-hero      — eyebrow + 24px Cormorant title
     .m-rangebar       — sticky horizontal chip strip (date range)
     .m-chip           — pill chip used in m-rangebar
     .m-live           — pulsing "N active right now" pill
     .m-kpi-grid       — 2×2 KPI tiles
     .m-kpi            — KPI card with label + number
     .m-section        — preview card with head + body
     .m-row / m-bar-row — list rows inside sections
     .m-segctl         — segmented control (replaces some dropdowns)

   Also includes a few overrides on existing portal classes so the
   Client Reports show page picks up the mobile feel without a full
   markup rewrite (the existing .page-header, .realtime-strip,
   .date-toolbar, .mx2-kpi-grid all get tightened mobile styling).
   ========================================================================= */

:root {
  --m-tabbar-h: 64px;
  --m-tabbar-safe: env(safe-area-inset-bottom, 0);
  --m-report-topbar-h: 60px;
  --m-report-topbar-safe: env(safe-area-inset-top, 0);
}

/* =========================================================================
   GLOBAL MOBILE TOP BAR — black sticky bar with [client logo]
   [client name] [MaestroX]. Lives in every mobile page via the
   `mobile-topbar` partial included from layouts/{mx2,client}.ejs.
   Mirrors the fixed bottom tabbar so the MaestroX brand stays
   anchored across the entire mobile experience. Desktop hides this
   entirely; the sidebar carries branding there. (The class name is
   historical — first shipped on the Client Reports page.)
   ========================================================================= */
.m-report-topbar { display: none; }

/* =========================================================================
   COSIMO SPINNER — gold ring used in the AI-loading state on the
   Client Reports page. Sized to read inline next to body text.
   ========================================================================= */
.cosimo-spinner {
  display: inline-block;
  width: 22px;
  height: 22px;
  border: 2.5px solid var(--gold-faint, rgba(200, 169, 94, 0.22));
  border-top-color: var(--gold, #c8a95e);
  border-radius: 50%;
  animation: cosimo-spin 0.9s linear infinite;
  flex-shrink: 0;
}
@keyframes cosimo-spin {
  to { transform: rotate(360deg); }
}

/* Cosimo avatar shown while his insight is loading. Same circular
   portrait used elsewhere (campaigns, composer), with a gentle pulse
   so the user can tell something is in flight. */
.cosimo-loading-avatar {
  display: inline-block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  background: var(--ink, #0a0805);
  box-shadow: 0 0 0 2px var(--gold-faint, rgba(200, 169, 94, 0.22));
  animation: cosimo-think 1.6s ease-in-out infinite;
}
@keyframes cosimo-think {
  0%, 100% { box-shadow: 0 0 0 2px var(--gold-faint, rgba(200, 169, 94, 0.22)); }
  50%      { box-shadow: 0 0 0 4px rgba(200, 169, 94, 0.55); }
}

/* Cosimo loading shell — wraps the avatar, text, and indeterminate
   progress bar shown while the AI narrative is in flight. The bar
   uses a gold pip that slides left → right inside a faint track;
   no percentage to track (the Anthropic call has no progress
   events), but the motion signals work is happening. */
.cosimo-loading {
  background: var(--bg-card, #FFFFFF);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 18px 20px;
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.cosimo-loading__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cosimo-loading__msg {
  color: var(--ink-mid, #4a4138);
  font-size: 14px;
  line-height: 1.4;
}
.cosimo-loading__bar {
  position: relative;
  height: 4px;
  background: rgba(200, 169, 94, 0.14);
  border-radius: 2px;
  overflow: hidden;
}
.cosimo-loading__bar-fill {
  position: absolute;
  top: 0; bottom: 0;
  left: -40%;
  width: 40%;
  background: linear-gradient(
    90deg,
    rgba(200, 169, 94, 0) 0%,
    rgba(200, 169, 94, 0.85) 50%,
    rgba(200, 169, 94, 0) 100%
  );
  animation: cosimo-bar-slide 1.6s ease-in-out infinite;
  will-change: left;
}
@keyframes cosimo-bar-slide {
  0%   { left: -40%; }
  100% { left: 100%; }
}

/* =========================================================================
   Mobile-only nav elements — hidden on desktop by default. All three
   are rendered unconditionally in the layout for mx2 users; the
   mobile @media block re-displays them. Without this hide rule:
     - .m-tabbar would render as raw stacked nav (the icons you saw)
     - .m-more-sheet would render as an inline <aside> taking up a
       large gap at the bottom of the page (~7 menu items tall)
     - .m-more-backdrop would render as an empty block element
   Mobile rules below explicitly set `display: flex` / `display: block`
   to override this default at <= 767px.
   ========================================================================= */
.m-tabbar,
.m-more-sheet,
.m-more-backdrop { display: none; }

/* =========================================================================
   PWA install pill — small bottom-of-screen prompt for browsers that
   support beforeinstallprompt (Chrome/Edge/Android) or for iOS Safari
   (with the "Tap Share → Add to Home Screen" tip). Sits ABOVE the
   bottom tabbar so it doesn't overlap nav.
   ========================================================================= */
.m-install-pill {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(var(--m-tabbar-h) + var(--m-tabbar-safe) + 12px);
  z-index: 950;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--ink, #1a1410);
  color: var(--fg-on-dark, #f3ead4);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(8, 6, 4, 0.25);
  font-size: 13px;
  line-height: 1.35;
}
.m-install-pill__msg { flex: 1; min-width: 0; }
.m-install-pill__msg strong { color: var(--gold, #c8a95e); }
.m-install-pill__msg em { font-style: italic; color: var(--gold, #c8a95e); }
.m-install-pill__action {
  flex-shrink: 0;
  padding: 6px 12px;
  background: var(--gold, #c8a95e);
  color: var(--ink, #1a1410);
  border: 0;
  border-radius: 6px;
  font: inherit;
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
}
.m-install-pill__close {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--fg-on-dark, #f3ead4);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
.m-install-pill__close:hover { opacity: 1; }
.m-install-pill--ios .m-install-pill__action { display: none; }
/* The install pill is mobile-only — pwa-install-prompt.js gates on
   viewport width before showing it. No desktop styles needed. */

/* =========================================================================
   BROAD MOBILE SWEEP — applies across every portal page on <768px.
   These rules tighten form inputs (44px tap targets, 16px font to
   block iOS Safari's auto-zoom on focus), button sizing, section
   gutters, and grids that need more density on phones.
   ========================================================================= */

@media (max-width: 767px) {
  /* Form controls: 44px tap target minimum per WCAG / Apple HIG.
     16px font on iOS prevents the page from zooming when the input
     gains focus — anything smaller triggers Safari's auto-zoom. */
  body.mx2-side input[type="text"],
  body.mx2-side input[type="email"],
  body.mx2-side input[type="password"],
  body.mx2-side input[type="tel"],
  body.mx2-side input[type="url"],
  body.mx2-side input[type="number"],
  body.mx2-side input[type="search"],
  body.mx2-side input[type="date"],
  body.mx2-side input[type="datetime-local"],
  body.mx2-side textarea,
  body.mx2-side select,
  body.client-side input[type="text"],
  body.client-side input[type="email"],
  body.client-side input[type="password"],
  body.client-side input[type="tel"],
  body.client-side input[type="url"],
  body.client-side input[type="number"],
  body.client-side input[type="search"],
  body.client-side input[type="date"],
  body.client-side input[type="datetime-local"],
  body.client-side textarea,
  body.client-side select {
    min-height: 44px;
    font-size: 16px;
  }
  /* Textareas: 44px min on a single-line is fine but multi-line
     textareas should stay tall as authored — only enforce a min,
     don't fight existing height. */
  body.mx2-side textarea,
  body.client-side textarea { min-height: 88px; }

  /* Button tap targets — exclude tabbar/icon buttons (their padding
     already extends their hit zone) and any opt-out. */
  body.mx2-side button:not(.m-tab):not(.m-iconbtn):not(.btn-sm):not([data-no-mobile-min]),
  body.mx2-side a.btn:not(.btn-sm),
  body.mx2-side a.btn-ghost-dark:not(.btn-sm),
  body.client-side button:not(.m-tab):not(.m-iconbtn):not(.btn-sm):not([data-no-mobile-min]),
  body.client-side a.btn:not(.btn-sm),
  body.client-side a.btn-ghost-dark:not(.btn-sm) {
    min-height: 40px;
  }

  /* Consistent 16px gutters on every .mx2-section. The earlier
     desktop padding was the gutter token (24-32px); on phones we
     want edge-to-edge content with a tighter inset. */
  body.mx2-side .mx2-section,
  body.client-side .mx2-section {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Tables: long unbroken values (emails, GA4 URLs) must wrap, never push the
     page wider than the viewport. And any table still on the horizontal-scroll
     variant scrolls INSIDE its own box, contained to the gutter — it never
     clips content off the right edge of the screen. */
  body.mx2-side .mx2-table td,
  body.client-side .mx2-table td { overflow-wrap: anywhere; word-break: break-word; }
  body.mx2-side .mx2-table--scroll,
  body.client-side .mx2-table--scroll {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
  }

  /* .mx2-toolbar — the title-bar + action-button block. Wrap onto
     two rows on phones; gap tightens. */
  .mx2-toolbar { gap: 8px; flex-wrap: wrap; }

  /* Asset library grid: 140px min tile width on mobile so two or
     three tiles fit per row depending on phone size. */
  body.mx2-side .asset-grid,
  body.client-side .asset-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
  }

  /* Modal / asset-panel: contained inside the viewport with a sane
     inset and bottom padding to clear the tabbar. */
  body.mx2-side .asset-panel,
  body.client-side .asset-panel {
    max-height: calc(100vh - var(--m-tabbar-h) - var(--m-tabbar-safe) - 60px);
    overflow-y: auto;
  }

  /* mx2-card-form on mobile: tighten internal padding, drop the
     huge top spacing some forms got from desktop padding. */
  body.mx2-side .mx2-card-form,
  body.client-side .mx2-card-form {
    padding: 16px;
  }

  /* Hide the desktop-only "back" or "view" links that overlap a tap
     target — opt-out via [data-show-on-mobile]. */
  body.mx2-side .hide-on-mobile,
  body.client-side .hide-on-mobile { display: none !important; }

  /* Form row groupings — desktop laid these out as 2- or 3-up grids.
     On phones they stack single-column without exception. */
  body.mx2-side .form-row-2,
  body.mx2-side .form-row-3,
  body.mx2-side .form-row-4,
  body.client-side .form-row-2,
  body.client-side .form-row-3,
  body.client-side .form-row-4 {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }

  /* ── Mobile dashboard (Drew 2026-09-27) ──────────────────────────────
     Designed for the phone app: the bottom tab bar handles navigation, so
     the big "drop into a section" cards are redundant. Drop the product-
     tile carousel and the "Jump in" shortcut column; keep the info feeds
     (recent activity, latest client activity). The KPI cards stay — they
     carry live counts — but go 2-up and compact instead of huge + stacked. */
  body.mx2-side .hub-kpis,
  body.client-side .hub-kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin: 16px 0;
  }
  body.mx2-side .hub-kpi-card,
  body.client-side .hub-kpi-card {
    min-height: 0;
    padding: 12px 14px;
    gap: 3px;
    border-radius: 12px;
  }
  body.mx2-side .hub-kpi-card__value,
  body.client-side .hub-kpi-card__value { font-size: 30px; }
  body.mx2-side .hub-kpi-card__label,
  body.client-side .hub-kpi-card__label { font-size: 9px; letter-spacing: 0.1em; }
  body.mx2-side .hub-kpi-card__meta,
  body.client-side .hub-kpi-card__meta { font-size: 11px; }
  /* Redundant section-navigation surfaces — the bottom tab bar covers these. */
  body.mx2-side .hub,
  body.client-side .hub,
  body.mx2-side .hub-bottom__right,
  body.client-side .hub-bottom__right { display: none; }
  /* Recent-activity card — keep the header on one tidy line on narrow screens */
  body.mx2-side .hub-bottom .mx2-dash-card__head,
  body.client-side .hub-bottom .mx2-dash-card__head { flex-wrap: wrap; row-gap: 4px; }
  body.mx2-side .hub-bottom .section-kicker,
  body.mx2-side .hub-bottom .mx2-dash-card__action,
  body.client-side .hub-bottom .section-kicker,
  body.client-side .hub-bottom .mx2-dash-card__action { white-space: nowrap; font-size: 10px; letter-spacing: 0.06em; }

  /* Workspace switcher chip — small button on desktop becomes a
     proper tap target on mobile. */
  body.client-side .nav-workspace-chip {
    min-height: 44px;
    padding: 10px 14px;
  }
  body.client-side .nav-workspace-option {
    min-height: 44px;
    padding: 10px 14px;
  }

  /* Banner / flash messages — full-width on mobile, slimmer padding. */
  body.mx2-side .banner,
  body.client-side .banner {
    padding: 12px 14px;
    font-size: 13px;
    border-radius: 0;
    margin-left: -16px;
    margin-right: -16px;
  }

  /* Breadcrumbs — already collapse to "‹ parent" on phones via the
     existing base.css mobile rule. Ensure they don't take double-
     gutter padding inside our 16px section gutter. */
  body.mx2-side .breadcrumbs,
  body.client-side .breadcrumbs {
    padding-left: 0;
    padding-right: 0;
  }

  /* ── Collapsible sections (Client Reports on mobile). Each
     .tab-panel's h2 becomes the toggle for its content. First panel
     is open by default; rest get .is-collapsed initially via JS. */
  .tab-panel[data-collapsible] h2 {
    cursor: pointer;
    user-select: none;
    position: relative;
    padding-right: 28px;
  }
  .tab-panel[data-collapsible] h2::after {
    content: '';
    position: absolute;
    right: 4px;
    top: 50%;
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--ink-soft, #7c7264);
    border-bottom: 2px solid var(--ink-soft, #7c7264);
    transform: translateY(-70%) rotate(45deg);
    transition: transform 200ms ease;
  }
  .tab-panel[data-collapsible].is-collapsed h2::after {
    transform: translateY(-30%) rotate(-135deg);
  }
  /* Hide everything inside a collapsed panel EXCEPT the kicker and
     the h2 itself. */
  .tab-panel[data-collapsible].is-collapsed > :not(.section-kicker):not(h2) {
    display: none !important;
  }
}

@media (max-width: 767px) {

  /* ── Replace hamburger + sidebar with bottom tabbar nav.
     Per design brief: "No hamburger menu on mobile. Bottom tabbar
     is the spine of navigation." Classes scoped to authenticated
     layouts only (these elements don't exist on auth pages). ───── */
  body.mx2-side .mx2-sidebar-toggle,
  body.client-side .mx2-sidebar-toggle,
  body.mx2-side .mx2-sidebar,
  body.client-side .mx2-sidebar,
  body.mx2-side .mx2-sidebar-backdrop,
  body.client-side .mx2-sidebar-backdrop,
  body.mx2-side .app-brand-corner,
  body.client-side .app-brand-corner { display: none !important; }

  /* Collapse the desktop 2-column shell (sidebar | main) to a single column.
     The sidebar is only display:none'd above, but its GRID TRACK
     (grid-template-columns: var(--sidebar-w) 1fr) persists — so .mx2-main is
     squeezed into `viewport − sidebar-w`, and any auto-placed body banner (the
     revision-request alert, impersonation/trial banners) fills the leftover
     sidebar column. Forcing one column makes main full-width and stacks the
     banners full-width on top, as intended. */
  body.mx2-side,
  body.client-side {
    grid-template-columns: 1fr !important;
    grid-template-areas: none !important;
  }
  /* Drop main out of the named "main" cell so it auto-flows in DOM order —
     i.e. AFTER the alert/impersonation/trial banners, which are earlier in the
     body. Keeps a full-width alert bar at the TOP on mobile, content below. */
  body.mx2-side .mx2-main,
  body.client-side .client-main { grid-area: auto !important; }

  /* Main content needs padding-bottom so the last row isn't hidden
     behind the fixed tabbar. Add safe-area-inset for home-indicator
     iPhones. Both layouts use a different main-class name. */
  body.mx2-side .mx2-main,
  body.client-side .client-main {
    padding-bottom: calc(var(--m-tabbar-h) + var(--m-tabbar-safe) + 16px);
  }
  /* Cancel the side gutter the desktop layout reserved for the
     sidebar — content goes edge-to-edge on mobile. */
  body.mx2-side,
  body.client-side {
    padding-left: 0 !important;
  }

  /* Collapse the desktop 2-column shell grid to a single column on mobile.
     The sidebar is display:none'd above, but display:none on a grid ITEM
     leaves its 280px TRACK — which squeezes content into a sliver (per-char
     wrapping). Force one column + a top "alerts" row (the .mx2-alerts wrapper
     with the sticky bars) above full-width content. The desktop grid sets
     grid-template-rows/areas for the alert row, which must be reset here too
     or they mismatch the single column. (Drew 2026-09-21) */
  body.mx2-side,
  body.client-side.app {
    grid-template-columns: 1fr !important;
    grid-template-rows: auto 1fr !important;
    grid-template-areas: "alerts" "main" !important;
  }
  body.mx2-side .mx2-main,
  body.client-side.app .client-main { grid-area: main !important; }
  body.mx2-side .mx2-alerts,
  body.client-side.app .mx2-alerts { grid-area: alerts !important; }

  /* The earlier 60px padding-left on .page-header was for the
     hamburger. Hamburger's gone, so reclaim that space. */
  body.mx2-side .page-header,
  body.client-side .page-header {
    padding: 20px 16px 12px !important;
  }

  /* ── Client Report sticky top bar (mobile only). Fixed black bar
     showing org logo + client name. The page-header below it hides
     its own logo/name row + property-label sub-line so the client
     name doesn't repeat. Pages that include this bar get a top
     spacer (added on body) so content starts below it. ─────────── */
  .m-report-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    position: fixed;
    top: 0; left: 0; right: 0;
    height: calc(var(--m-report-topbar-h) + var(--m-report-topbar-safe));
    padding: var(--m-report-topbar-safe) 12px 0;
    background: var(--ink, #0a0805);
    color: #ffffff;
    z-index: 990;
    box-shadow: 0 1px 0 rgba(200, 169, 94, 0.18);
  }
  /* Client logo (LEFT) — transparent background so the logo itself
     renders against the black bar without a white card. Sits above
     the absolutely-positioned name in case of overlap. */
  .m-report-topbar .org-logo {
    width: 32px;
    height: 32px;
    background: transparent;
    position: relative;
    z-index: 1;
  }
  .m-report-topbar .org-logo img { padding: 0; }
  .m-report-topbar .org-logo .avatar-fallback {
    font-size: 14px;
    color: var(--gold, #c8a95e);
  }
  /* Client name (LEFT, right after the logo) — a flex item that fills the
     space between the logo and the MaestroX brand and TRUNCATES, so a long
     client name can never run under / collide with the brand on the right.
     (Was absolute-centered, which overlapped the brand — Drew 2026-09-30.) */
  .m-report-topbar__name {
    flex: 1 1 auto;
    min-width: 0;
    color: #ffffff;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.005em;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: none;
  }
  /* Empty-state spacer (LEFT) — placeholder so the right brand stays
     pinned to the right edge even when no org context is available. */
  .m-report-topbar__spacer {
    display: inline-block;
    width: 32px;
    height: 32px;
  }
  /* MaestroX Studio wordmark (RIGHT) — horizontal "MaestroX Studio"
     lockup in cream, sits cleanly on the black bar. Width-constrained
     (the lockup is ~5:1) so it stays compact and doesn't crowd the
     centered org name. */
  .m-report-topbar__brand {
    width: 118px;
    height: auto;
    display: block;
    position: relative;
    z-index: 1;
  }
  /* Impersonation edge case — the rust banner is sticky at top: 0
     too. When impersonating on mobile, hide the topbar so the
     "Return to my account" button stays reachable. (Admins rarely
     impersonate from a phone; brand visibility is the lesser loss.) */
  body.is-impersonating .m-report-topbar { display: none; }
  body.is-impersonating:has(.m-report-topbar) .mx2-main,
  body.is-impersonating:has(.m-report-topbar) .client-main {
    padding-top: 0;
  }
  body.is-impersonating:has(.m-report-topbar) .date-toolbar {
    top: 0;
  }
  /* When the topbar is present (any page that includes it), push the layout
     down so it isn't hidden underneath. Applied to the GRID CONTAINER (body),
     not .mx2-main, because top-of-flow body banners — the revision-request
     alert + trial banner — now sit ABOVE main (see the shell-grid collapse
     above) and must clear the fixed bar too. Padding on the grid container
     offsets the whole single column. */
  body.mx2-side:has(.m-report-topbar),
  body.client-side:has(.m-report-topbar) {
    padding-top: calc(var(--m-report-topbar-h) + var(--m-report-topbar-safe));
  }
  /* Impersonating hides the topbar (rule above), so reclaim that space. */
  body.is-impersonating:has(.m-report-topbar) { padding-top: 0; }
  /* And sit the sticky date-toolbar right below the fixed top bar
     instead of at top: 0 (where it would overlap). */
  body:has(.m-report-topbar) .date-toolbar {
    top: calc(var(--m-report-topbar-h) + var(--m-report-topbar-safe));
  }
  /* Revision-request alert: STICKY so it stays pinned (just under the fixed
     topbar) on every page instead of scrolling away with the content. Below
     the topbar (z:990) and tabbar (z:1000), above page content. */
  body.mx2-side .revision-alert-bar,
  body.client-side .revision-alert-bar {
    position: sticky;
    top: env(safe-area-inset-top, 0);
    z-index: 980;
  }
  /* Slim, single-line alert bars on mobile — the verbose multi-line banners ate
     ~40% of the screen and shoved the header down (Drew 2026-09-30). One line:
     icon · truncating message · CTA pinned right. */
  body.mx2-side .revision-alert-bar,
  body.client-side .revision-alert-bar {
    padding: 7px 14px;
    font-size: 12.5px;
    gap: 8px;
    justify-content: flex-start;
    line-height: 1.25;
  }
  body.mx2-side .revision-alert-bar > span:not(.revision-alert-bar__cta),
  body.client-side .revision-alert-bar > span:not(.revision-alert-bar__cta) {
    flex: 1 1 auto; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  body.mx2-side .revision-alert-bar__cta,
  body.client-side .revision-alert-bar__cta { flex: 0 0 auto; margin-left: auto; }
  body.mx2-side .revision-alert-bar svg,
  body.client-side .revision-alert-bar svg { flex: 0 0 auto; }
  body.mx2-side:has(.m-report-topbar) .revision-alert-bar,
  body.client-side:has(.m-report-topbar) .revision-alert-bar {
    top: calc(var(--m-report-topbar-h) + var(--m-report-topbar-safe));
  }
  /* Impersonating hides the topbar → pin the alert to the very top instead. */
  body.is-impersonating:has(.m-report-topbar) .revision-alert-bar {
    top: env(safe-area-inset-top, 0);
  }
  /* Elements explicitly marked as duplicated by the sticky top bar.
     Used on the show page (org logo + name + property label) so they
     don't repeat below the top bar. Drill page uses the same class
     on its sub-line but keeps the section-name h1 visible. */
  .is-topbar-dupe { display: none !important; }

  /* ── Tab strips WRAP on screen — no horizontal scroll ──────────────────────
     .ph-tabs (client detail, shoots, settings, etc.) can hold more tabs than
     fit one phone row. WRAP them onto multiple rows so every tab stays on
     screen; nothing scrolls sideways (everything on screen width — Drew,
     2026-09-30, superseding the earlier scroll approach). The "folder" rising
     style is flattened to self-contained pills so wrapped rows read cleanly. */
  .ph-tabs {
    flex-wrap: wrap;
    row-gap: 6px;
  }
  .ph-tabs .ph-tab { flex: 0 0 auto; white-space: nowrap; }
  .ph-tabs.folder { margin-bottom: 0; }
  .ph-tabs.folder .ph-tab {
    padding: 9px 15px;
    margin-right: 6px;
    border: 1px solid rgba(200, 169, 94, 0.28);
    border-radius: 9px;
  }
  .ph-tabs.folder .ph-tab.is-active { border-color: rgba(200, 169, 94, 0.6); }
  .ph-tabs.folder .ph-tab.is-active::before { display: none; }

  /* ── Horizontal-overflow guard: action button rows ─────────────────────────
     Rows of inline action buttons (composer DELETE / DUPLICATE / REGENERATE,
     form action rows) ran off-screen and overlapped. Let them wrap. */
  .form-actions,
  .mx2-card-actions,
  .composer-actions,
  .post-actions { flex-wrap: wrap; }

  /* ── Member management + permissions editor (client detail → Users) ─────────
     Was badly clipped on mobile: the role summary truncated, the action buttons
     ran off-screen, and the permission dropdowns overflowed. Make the whole
     section stack full-width so it's fully usable on a phone. (Drew 2026-09-30) */
  /* Role summary wraps instead of truncating ("… Soci…"). */
  .users-table .member-perm-summary,
  .users-table .member-perm-summary .dim.micro { white-space: normal; }
  /* Per-member action buttons: two-up grid that wraps, full-width taps. */
  .users-table .row-actions {
    display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-start; opacity: 1;
  }
  .users-table .row-actions > *,
  .users-table .row-actions > form { flex: 1 1 calc(50% - 4px); min-width: 0; margin: 0; }
  .users-table .row-actions .btn-ghost-dark { width: 100%; text-align: center; }
  /* Permissions editor: single column, full-width controls, comfortable padding. */
  .member-perms-row > td { padding: 14px 14px; }
  .member-perms-grid .form-row-3 { grid-template-columns: 1fr; }
  .member-perms-form .field { min-width: 0; }
  .member-perms-form select,
  .member-perms-form input,
  .member-perms-form textarea { width: 100%; }
  .member-perms-admin { width: 100%; }
  .member-perms-actions { flex-direction: column-reverse; align-items: stretch; }
  .member-perms-actions > .btn,
  .member-perms-actions > .btn-ghost-dark { width: 100%; }

  /* ── Bottom tabbar — 5 tabs, fixed to bottom of viewport,
     pulses gold under the active icon. ─────────────────────────── */
  .m-tabbar {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    height: var(--m-tabbar-h);
    padding-bottom: var(--m-tabbar-safe);
    background: var(--bg-card, #FFFFFF);
    border-top: 1px solid var(--rule);
    display: flex;
    z-index: 1000;
  }
  .m-tabbar > .m-tab { flex: 1; min-width: 0; }
  .m-tabbar::before {
    content: '';
    position: absolute;
    top: -1px; left: 16px; right: 16px;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(200, 169, 94, 0.55), transparent);
    opacity: 0.5;
  }
  .m-tab {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 3px;
    border: 0; background: transparent;
    color: var(--ink-soft, #7c7264);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.04em;
    cursor: pointer;
    padding: 8px 4px 6px;
    text-decoration: none;
    text-align: center;
    -webkit-tap-highlight-color: transparent;
    min-height: 44px;
  }
  .m-tab svg {
    width: 22px; height: 22px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
  }
  .m-tab.is-active {
    color: var(--gold, #c8a95e);
    position: relative;
  }
  .m-tab.is-active svg { stroke-width: 1.9; }
  .m-tab.is-active::after {
    content: '';
    position: absolute;
    bottom: 4px;
    left: 50%;
    transform: translateX(-50%);
    width: 4px; height: 4px;
    background: var(--gold, #c8a95e);
    border-radius: 50%;
  }

  /* ── Bottom sheet primitives — reusable slide-up surface for the
     More tab, Share, Date range, Filters, etc. The .m-more-sheet
     and .m-more-backdrop selectors below are legacy aliases that
     keep the existing More-tab markup working unchanged. ─────── */
  .m-sheet,
  .m-more-sheet {
    /* display: block here to override the default-hide rule above
       (which is needed to keep these from rendering as inline blocks
       on desktop where the @media doesn't apply). */
    display: block;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    background: var(--bg-card, #FFFFFF);
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
    padding: 14px 0 calc(var(--m-tabbar-safe) + var(--m-tabbar-h) + 12px);
    max-height: 75vh;
    overflow-y: auto;
    box-shadow: 0 -8px 24px rgba(8, 6, 4, 0.18);
    z-index: 999;
    transform: translateY(100%);
    transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
    visibility: hidden;
  }
  .m-sheet-backdrop,
  .m-more-backdrop {
    /* display: block to override the default-hide rule above. */
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(10, 8, 5, 0.5);
    z-index: 998;
    opacity: 0;
    pointer-events: none;
    transition: opacity 220ms ease, visibility 220ms ease;
    visibility: hidden;
  }
  /* Open state: body class .has-sheet-<name> pins the matching sheet
     open. .has-more-sheet is the legacy alias for the More tab. */
  body.has-more-sheet .m-more-sheet,
  body[class*="has-sheet-"] .m-sheet.is-open {
    transform: translateY(0);
    visibility: visible;
  }
  body.has-more-sheet .m-more-backdrop,
  body[class*="has-sheet-"] .m-sheet-backdrop.is-open {
    opacity: 1; pointer-events: auto; visibility: visible;
  }
  .m-sheet-handle,
  .m-more-handle {
    width: 40px; height: 4px;
    background: var(--ink-soft, #c8b894);
    border-radius: 2px;
    margin: 0 auto 12px;
    opacity: 0.4;
  }
  .m-sheet-head {
    padding: 4px 20px 12px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 8px;
  }
  .m-sheet-head .kicker {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft, #7c7264);
  }
  .m-sheet-head h2 {
    font-size: 17px;
    font-weight: 600;
    margin: 2px 0 0;
    color: var(--ink, #1a1410);
  }
  .m-sheet-head .sub {
    font-size: 12px;
    color: var(--ink-soft, #7c7264);
    margin-top: 2px;
  }
  .m-action-list,
  .m-more-list {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .m-action-list li,
  .m-action-list a,
  .m-action-list button,
  .m-more-list a,
  .m-more-list button {
    display: flex; align-items: center; gap: 14px;
    padding: 14px 20px;
    width: 100%;
    color: var(--ink, #1a1410);
    background: transparent;
    border: 0;
    border-top: 1px solid var(--rule);
    font: inherit;
    font-size: 15px;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
  }
  .m-action-list li:first-child,
  .m-action-list a:first-child,
  .m-action-list button:first-child,
  .m-more-list a:first-child,
  .m-more-list button:first-child,
  .m-more-list li:first-child a,
  .m-more-list li:first-child button { border-top: 0; }
  .m-action-list svg,
  .m-more-list svg {
    width: 20px; height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    color: var(--ink-mid, #4a4138);
    flex-shrink: 0;
  }
  .m-action-list .meta,
  .m-more-list .meta {
    margin-left: auto;
    color: var(--ink-soft, #7c7264);
    font-size: 12px;
  }
  .m-more-list .danger { color: var(--red, #b8341c); }
  .m-more-list .danger svg { color: var(--red, #b8341c); }
  /* Section dividers inside the More sheet (Workspaces / Inbox / Admin).
     Plain <li>, not a link — no border-top rule, muted uppercase label. */
  .m-more-list .m-more-section {
    padding: 16px 20px 6px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-soft, #7c7264);
  }
  .m-more-list .m-more-section:first-child { padding-top: 4px; }
  /* The link/button directly under a section label starts a fresh block,
     so drop the top rule that would otherwise double the divider. */
  .m-more-list .m-more-section + li a,
  .m-more-list .m-more-section + li button { border-top: 0; }
  .m-action-list .coming-soon {
    margin-left: auto;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft, #7c7264);
  }

  /* ── Page hero typography — collapses .page-header content to the
     mobile visual described in the design system brief: eyebrow +
     24px title + tiny subtitle. The page-header padding itself is
     reset higher up in this media query (no hamburger to clear). ── */
  body.mx2-side .page-header .page-title.lg,
  body.client-side .page-header .page-title.lg,
  body.mx2-side .page-header .report-title.lg,
  body.client-side .page-header .report-title.lg {
    font-size: 24px !important;
    line-height: 1.15;
    margin: 0;
    font-weight: 500;
    letter-spacing: -0.005em;
  }
  body.mx2-side .page-header .page-description,
  body.client-side .page-header .page-description {
    font-size: 12px;
    color: var(--ink-soft, #7c7264);
    margin-top: 4px;
  }
  body.mx2-side .page-header .section-kicker,
  body.client-side .page-header .section-kicker,
  body.mx2-side .m-eyebrow,
  body.client-side .m-eyebrow {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gold, #c8a95e);
    margin-bottom: 6px;
  }

  /* ── Date toolbar (two rows). Row 1 (.date-toolbar__presets) is a
     sticky horizontal chip strip; row 2 is the "Custom time period"
     button. Pill-styled chips per the design system. ─────────────── */
  .date-toolbar {
    position: sticky;
    top: 0;
    background: var(--cream, #F4EFE6);
    z-index: 5;
    padding: 12px 16px;
    margin: 0 -16px;
  }
  .date-toolbar__presets {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    flex-wrap: nowrap;
    padding-bottom: 2px;
  }
  .date-toolbar__presets::-webkit-scrollbar { display: none; }
  .date-toolbar__presets > a {
    flex: 0 0 auto;
    padding: 8px 14px;
    background: var(--bg-card, #FFFFFF);
    border: 1px solid var(--rule);
    color: var(--ink-mid, #4a4138);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
    text-decoration: none;
  }
  .date-toolbar__presets > a.is-active {
    background: var(--ink, #1a1410);
    color: var(--cream, #f6efe3);
    border-color: var(--ink, #1a1410);
  }
  .date-toolbar__custom-btn {
    width: 100%;
    margin-top: 8px;
    padding: 10px 14px !important;
    border-radius: 8px !important;
    background: var(--bg-card, #FFFFFF);
    border: 1px solid var(--rule);
    color: var(--ink, #1a1410);
    font-size: 13px;
    font-weight: 500;
    justify-content: center;
  }
  .date-toolbar__custom-btn.is-active {
    background: var(--ink, #1a1410);
    color: var(--cream, #f6efe3);
    border-color: var(--ink, #1a1410);
  }

  /* ── Realtime users (.realtime-strip) → m-live pill ─────────── */
  .realtime-strip {
    padding: 5px 10px 5px 8px !important;
    background: var(--bg-card, #FFFFFF);
    border: 1px solid #a8d5bf !important;
    border-radius: 999px !important;
    font-size: 12px;
  }
  .realtime-strip__dot {
    background: #1f8a5b !important;
    box-shadow: 0 0 0 4px rgba(31, 138, 91, 0.18) !important;
    animation: m-pulse-dot 1.8s ease-in-out infinite !important;
  }
  @keyframes m-pulse-dot {
    0%, 100% { box-shadow: 0 0 0 4px rgba(31, 138, 91, 0.18); }
    50%      { box-shadow: 0 0 0 7px rgba(31, 138, 91, 0.05); }
  }
  .realtime-strip__num { font-size: 14px !important; }

  /* ── KPI hero (.mx2-kpi-grid on report page) → m-kpi-grid 2×2 ── */
  .tab-panel .mx2-kpi-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    padding: 0;
    margin-bottom: 16px;
  }
  .tab-panel .mx2-kpi {
    background: var(--bg-card, #FFFFFF);
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 12px 16px;
    min-height: 76px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
  .tab-panel .mx2-kpi label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft, #7c7264);
    margin-bottom: 4px;
  }
  .tab-panel .mx2-kpi .value {
    font-size: 24px;
    font-weight: 500;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.005em;
    color: var(--ink, #1a1410);
  }
}

/* =========================================================================
   M-COMPONENT CLASSES — opt-in primitives the report view uses
   directly. Available at all viewports but the layouts (grids, spacing)
   are tuned for narrow screens.
   ========================================================================= */

.m-eyebrow {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold, #c8a95e);
  margin-bottom: 6px;
  display: block;
}

/* m-section — collapsed preview card */
.m-section {
  background: var(--bg-card, #FFFFFF);
  margin: 0 0 12px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
}
.m-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 12px 16px 6px;
  gap: 12px;
}
.m-section-head .title {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink, #1a1410);
  letter-spacing: -0.005em;
  margin: 0;
}
.m-section-head .more {
  font-size: 12px;
  font-weight: 600;
  color: var(--gold, #c8a95e);
  cursor: pointer;
  text-decoration: none;
}
.m-section-body { padding: 0 16px 12px; }

/* m-row — single-row list item inside a section card */
.m-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  border-top: 1px solid var(--rule);
}
.m-row:first-child { border-top: 0; }
.m-row .name {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink, #1a1410);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.m-row .name .path {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12.5px;
  color: var(--ink-mid, #4a4138);
}
.m-row .meta {
  font-size: 11px;
  color: var(--ink-soft, #7c7264);
  margin-top: 2px;
  font-weight: 500;
}
.m-row .stat {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.m-row .stat .big {
  font-size: 18px;
  font-weight: 500;
  color: var(--ink, #1a1410);
  line-height: 1;
}
.m-row .stat .small {
  font-size: 10px;
  color: var(--ink-soft, #7c7264);
  margin-top: 3px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* m-bar-row — name + value with a horizontal bar fill below */
.m-bar-row {
  padding: 10px 0;
  border-top: 1px solid var(--rule);
}
.m-bar-row:first-child { border-top: 0; }
.m-bar-row-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.m-bar-row-head .name {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink, #1a1410);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 65%;
}
.m-bar-row-head .val {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink, #1a1410);
}
.m-bar-track {
  height: 6px;
  background: var(--cream-lt, #f1e8d6);
  border-radius: 3px;
  overflow: hidden;
}
.m-bar-fill {
  height: 100%;
  background: var(--gold, #c8a95e);
  border-radius: 3px;
}

/* =========================================================================
   DESKTOP — bottom-sheet primitives become a centered modal.
   The .m-sheet / .m-sheet-backdrop markup was designed for mobile
   (slides up from the bottom). On desktop the same JS open/close
   needs to do SOMETHING visible, so we restyle the elements as a
   centered modal: backdrop dims the page, sheet floats centered
   with a max width / height. Same .is-open + body[has-sheet-*]
   classes drive both forms.
   ========================================================================= */
@media (min-width: 768px) {
  .m-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 8, 5, 0.5);
    z-index: 998;
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease;
  }
  .m-sheet-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
  }
  .m-sheet {
    display: block;
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%) scale(0.96);
    width: min(440px, calc(100vw - 32px));
    max-height: 80vh;
    overflow-y: auto;
    background: #FFFFFF;
    border-radius: 12px;
    box-shadow: 0 16px 48px rgba(8, 6, 4, 0.32);
    z-index: 999;
    opacity: 0;
    pointer-events: none;
    visibility: hidden;
    transition: opacity 180ms ease, transform 180ms ease, visibility 180ms ease;
    padding: 8px 0 12px;
  }
  body[class*="has-sheet-"] .m-sheet.is-open {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
    pointer-events: auto;
    visibility: visible;
  }
  /* The drag handle is meaningless on desktop — hide it. */
  .m-sheet .m-sheet-handle { display: none; }
  .m-sheet .m-sheet-head {
    padding: 16px 22px 14px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 6px;
  }
  .m-sheet .m-sheet-head .kicker {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft, #7c7264);
    margin-bottom: 4px;
  }
  .m-sheet .m-sheet-head h2 {
    font-size: 17px;
    font-weight: 600;
    margin: 0;
    color: var(--ink, #1a1410);
  }
  .m-sheet .m-sheet-head .sub {
    font-size: 12px;
    color: var(--ink-soft, #7c7264);
    margin-top: 4px;
  }
  /* Action list inside the sheet — vertical list of buttons. Same
     visual as the mobile sheet so the layout doesn't change between
     viewports, just the container. */
  .m-sheet .m-action-list {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .m-sheet .m-action-list li { margin: 0; }
  .m-sheet .m-action-list a,
  .m-sheet .m-action-list button {
    display: flex; align-items: center; gap: 14px;
    padding: 13px 22px;
    width: 100%;
    color: var(--ink, #1a1410);
    background: transparent;
    border: 0;
    border-top: 1px solid var(--rule);
    font: inherit;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
  }
  .m-sheet .m-action-list li:first-child a,
  .m-sheet .m-action-list li:first-child button { border-top: 0; }
  .m-sheet .m-action-list button:hover { background: var(--cream, #f4efe6); }
  .m-sheet .m-action-list button:disabled {
    cursor: not-allowed;
    color: var(--ink-soft, #7c7264);
    background: transparent;
  }
  .m-sheet .m-action-list svg {
    width: 18px; height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    color: var(--ink-mid, #4a4138);
    flex-shrink: 0;
  }
  .m-sheet .m-action-list .meta {
    margin-left: auto;
    color: var(--ink-soft, #7c7264);
    font-size: 12px;
  }
  .m-sheet .m-action-list .coming-soon {
    margin-left: auto;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--gold, #c8a95e);
    background: var(--cream, #f4efe6);
    padding: 3px 8px;
    border-radius: 999px;
  }
}

/* ── Auto-card tables: monospace values must WRAP (no page overflow) ─────────
   A .mx2-table WITHOUT --scroll stacks each row into a card at <=959px. A
   .mono value inside a card cell defaults to white-space:nowrap, so a long
   monospace string — e.g. "currently storing 2854 assets across N collections"
   on the client-detail Products card, or a GA4 property / LinkedIn URN / email
   — forces the card wider than the viewport and the whole page clips sideways.
   Force those .mono values to wrap so every card fits the screen. Scrollable
   tables (--scroll) keep their nowrap columns. (Drew 2026-09-30) */
@media (max-width: 959px) {
  .mx2-table:not(.mx2-table--scroll) td.mono,
  .mx2-table:not(.mx2-table--scroll) td .mono {
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
  }
}

/* ── "Customize nav" picker ─────────────────────────────────────────────────
   The in-app modal (views/partials/mobile-nav-customize-modal.ejs) that edits
   which tabs appear in the mobile bottom bar. Rendered inside the mobile-gated
   layout block but only ever OPENED on a phone (the "Customize nav" row lives
   in the More sheet), so these rules are viewport-agnostic and ride the glass
   .modal-card surface. Light tokens only — no dark fills inside the cream card
   (see no-black-inside-content-cards). (Drew 2026-10-02) */
.mnav-card { max-height: 85vh; overflow-y: auto; }
.mnav-sub { font-size: 13px; line-height: 1.4; margin: 0 0 12px; }
.mnav-count {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold, #c8a95e);
  margin: 0 0 10px;
}
.mnav-group { margin: 0 0 16px; }
.mnav-group-head {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft, #7c7264);
  margin: 0 0 6px;
}
.mnav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--rule, #d9d2c0);
  border-radius: 12px;
  overflow: hidden;
}
.mnav-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-top: 1px solid var(--rule, #d9d2c0);
  background: transparent;
}
.mnav-list .mnav-row:first-child { border-top: 0; }
.mnav-row--locked { opacity: 0.6; }
.mnav-ic {
  width: 18px; height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  color: var(--ink-mid, #4a4138);
  flex-shrink: 0;
}
.mnav-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  color: var(--ink, #1a1410);
}
.mnav-tag {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft, #7c7264);
}
/* Reorder arrows — only meaningful in the pinned list; hidden (but
   keeping their width for alignment) in the available list. */
.mnav-grip {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  width: 24px;
  flex-shrink: 0;
}
.mnav-list[data-mnav-list="available"] .mnav-grip { visibility: hidden; }
.mnav-move {
  border: 0;
  background: transparent;
  color: var(--ink-mid, #4a4138);
  font-size: 12px;
  line-height: 1;
  padding: 3px 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.mnav-move:disabled { opacity: 0.25; cursor: default; }
.mnav-toggle {
  flex-shrink: 0;
  border: 1px solid var(--rule, #d9d2c0);
  border-radius: 999px;
  padding: 5px 14px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  background: transparent;
  -webkit-tap-highlight-color: transparent;
}
.mnav-toggle--add {
  color: var(--gold-ink, #6b5a2e);
  border-color: var(--gold, #c8a95e);
  background: rgba(200, 169, 94, 0.1);
}
.mnav-toggle--remove {
  color: var(--ink-soft, #7c7264);
}
.mnav-toggle.is-disabled,
.mnav-toggle:disabled { opacity: 0.4; cursor: default; }
.mnav-empty {
  font-size: 13px;
  color: var(--ink-soft, #7c7264);
  margin: 8px 2px 0;
}
.mnav-error {
  color: var(--red, #b8341c);
  font-size: 13px;
  margin: 0 0 10px;
}
.mnav-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--rule, #d9d2c0);
  padding-bottom: calc(2px + env(safe-area-inset-bottom, 0px));
}
.mnav-actions-right { display: flex; gap: 8px; }

/* The Customize-nav modal is a bottom sheet on phones; the fixed bottom
   tab bar (z-index:1000) would otherwise paint over its Save button. Hide
   the bar while this modal is open — same approach as the Pocket Library
   overlays. (Drew 2026-10-02) */
body:has(.modal-overlay[data-modal="mobile-nav-customize"]:not([hidden])) .m-tabbar {
  display: none !important;
}

/* Keep two-line bar labels (e.g. "Content Planner") tight within the bar. */
.m-tab span { line-height: 1.15; }
