/* ============================================================================
   soj-mobile.css — SynergyAI MOBILE SHELL (additive, fully isolated)
   ----------------------------------------------------------------------------
   Every selector is scoped under html.soj-mobile — set only on phones /
   portrait tablets / narrow windows (<=1024px). On desktop the class is never
   present, so this whole file matches NOTHING; desktop is untouched.

   DESIGN LANGUAGE = THE PLATFORM'S OWN, re-laid-out for mobile:
   - The theme background (the .bg-stage video / CSS theme) stays visible; the
     shell is a TRANSPARENT layer on top so themes (My Garden, Hanley, Pop,
     L?D, Day…) drive the mobile background for free.
   - Surfaces use the platform liquid-glass tokens from universal.css
     (--lg-fill / --lg-stroke / --lg-blur / --lg-shadow / --glass-* / --text*),
     so it is the SAME glass as desktop — not a new palette.
   The --m-* names below are kept (panels reference them) but RE-POINTED to
   those platform tokens.
   ========================================================================= */

/* ============================ 1. GUARD ================================== */

html.soj-mobile #soj-mobile-root {
  display: block !important;
  position: fixed;
  inset: 0;
  z-index: 100000;
  overscroll-behavior: none;
  background: transparent;            /* the theme video shows through */
}

/* Hide the desktop tree but KEEP it in the DOM (chat el.* refs resolve) AND
   keep the theme background layers (.bg-stage video + .bg-playback) visible so
   the mobile shell sits on the real platform background. */
html.soj-mobile body > *:not(#soj-mobile-root):not(.bg-stage):not(.bg-playback):not([data-soj-keep]):not(.razorpay-container):not(.razorpay-backdrop) {
  display: none !important;
}

/* Theme background layers stay on (and behind the shell). */
html.soj-mobile body > .bg-stage,
html.soj-mobile body > .bg-playback { display: block !important; z-index: 0 !important; }

/* Razorpay payment overlays are EXEMPTED from the hide rule above (the
   :not(.razorpay-*) clauses), so they appear on their own — DO NOT force
   display:block !important here. Razorpay hides its backdrop via inline
   display:none on close; an !important override kept that invisible full-screen
   backdrop alive as a click-trap (screen frozen until refresh). Letting Razorpay
   own its visibility matches desktop, which has no such rule and no stuck bug. */

/* ============================ 2. TOKENS ================================= */

html.soj-mobile {
  /* — palette: re-pointed to the platform liquid-glass system (universal.css).
       Theme video shows through a transparent shell; surfaces are the SAME
       liquid glass as desktop, so it stays one design language. — */
  --m-bg: transparent;
  --m-bg-2: transparent;
  --m-ink: var(--text, #fff);
  --m-ink-dim: var(--text-muted, rgba(255, 255, 255, 0.72));
  --m-ink-faint: var(--text-faint, rgba(255, 255, 255, 0.55));
  --m-ink-ghost: rgba(255, 255, 255, 0.16);

  /* — liquid glass surfaces (platform --lg-* with fallbacks) — */
  --m-surface: var(--lg-fill, rgba(255, 255, 255, 0.06));
  --m-surface-2: var(--lg-fill-hover, rgba(255, 255, 255, 0.10));
  --m-surface-3: var(--lg-fill-active, rgba(255, 255, 255, 0.16));
  --m-surface-4: rgba(255, 255, 255, 0.26);   /* stronger 'selected' fill (active tab/chip/option) */
  --m-line: var(--lg-stroke, rgba(255, 255, 255, 0.22));
  --m-line-2: var(--lg-stroke-hi, rgba(255, 255, 255, 0.45));
  --m-blur: var(--lg-blur, saturate(1.3) blur(22px));

  /* — accent = white liquid-glass CTA (matches desktop), not a colour — */
  --m-accent: var(--glass-bg-cta, rgba(255, 255, 255, 0.32));
  --m-accent-ink: #ffffff;
  --m-accent-soft: rgba(255, 255, 255, 0.14);
  --m-gold: #ffc24b;
  --m-danger: #ff6b6b;
  --m-ok: var(--switch-2, #2fd084);
  /* DQ-4: semantic tints DERIVED from the source token, so every success/danger
     surface provably matches its own solid (replaces drifting rgba literals). */
  --m-ok-soft: color-mix(in srgb, var(--m-ok) 16%, transparent);
  --m-ok-line: color-mix(in srgb, var(--m-ok) 55%, transparent);
  --m-danger-soft: color-mix(in srgb, var(--m-danger) 14%, transparent);
  --m-danger-line: color-mix(in srgb, var(--m-danger) 55%, transparent);
  --m-danger-strong: color-mix(in srgb, var(--m-danger) 85%, transparent);
  --m-danger-ink: #1a0606;
  /* DQ-4: one hairline weight for the whole system */
  --m-bw: 1.5px;

  /* — type — */
  --m-font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --m-display: "Space Grotesk", var(--m-font);
  --m-t-micro: clamp(0.56rem, 0.53rem + 0.12vw, 0.6rem);
  --m-t-2xs: clamp(0.62rem, 0.59rem + 0.14vw, 0.66rem);
  --m-t-xs: clamp(0.69rem, 0.66rem + 0.15vw, 0.75rem);
  --m-t-sm: clamp(0.8rem, 0.77rem + 0.18vw, 0.875rem);
  --m-t-base: clamp(0.94rem, 0.9rem + 0.2vw, 1rem);
  --m-t-lg: clamp(1.1rem, 1rem + 0.5vw, 1.3rem);
  --m-t-xl: clamp(1.45rem, 1.2rem + 1.2vw, 2rem);
  --m-t-2xl: clamp(2rem, 1.5rem + 2.4vw, 3rem);

  /* — geometry (matches platform radii: pills 999, cards 22, buttons 16) — */
  --m-r-xs: 10px;
  --m-r-sm: 14px;
  --m-r: 16px;
  --m-r-lg: 22px;
  --m-r-xl: 28px;
  --m-pill: 999px;
  --m-gap: clamp(12px, 3vw, 18px);
  --m-pad: clamp(14px, 4vw, 22px);

  /* — chrome heights — */
  --m-topbar-h: 56px;
  --m-tabbar-h: 60px;
  --m-safe-t: env(safe-area-inset-top, 0px);
  --m-safe-b: env(safe-area-inset-bottom, 0px);

  /* — depth — */
  --m-shadow: var(--lg-shadow, 0 2px 8px rgba(0, 0, 0, 0.3), 0 12px 32px rgba(0, 0, 0, 0.34));
  --m-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4), 0 24px 64px rgba(0, 0, 0, 0.5);
  --m-dock-scrim: rgba(8, 10, 16, 0.55);   /* DQ-4: real composer-dock fade (was a no-op transparent gradient) */
  --m-ring: 0 0 0 1px var(--m-line) inset, 0 1px 0 rgba(255, 255, 255, 0.06) inset;

  /* — motion — */
  --m-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --m-ease-in: cubic-bezier(0.5, 0, 0.75, 0);
  --m-fast: 160ms;
  --m-mid: 280ms;
  --m-slow: 480ms;
}

/* ============================ 3. BASE ================================== */

/* Solid theme-matched backdrop (NOT transparent). The shell + #soj-mobile-root
   stay transparent so the .bg-stage theme video shows through; this opaque layer
   sits BEHIND .bg-stage and only ever shows in the iOS safe-area strips (status
   bar / home-indicator) that a fixed inset:0 .bg-stage can leave uncovered.
   Transparent here exposed the browser's default WHITE canvas there → the white
   bars top & bottom on real phones. var(--bg-deep) is dark on every theme; the
   light "boring" theme overrides html/body to #f4f4f2 !important, so it follows
   suit. Net: the page reads edge-to-edge immersive instead of white-barred. */
html.soj-mobile,
html.soj-mobile body { margin: 0; overflow: hidden; height: 100%; background: var(--bg-deep, #050a06); }

html.soj-mobile #soj-mobile-root,
html.soj-mobile #soj-mobile-root *,
html.soj-mobile #soj-mobile-root *::before,
html.soj-mobile #soj-mobile-root *::after {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html.soj-mobile #soj-mobile-root {
  font-family: var(--m-font);
  color: var(--m-ink);
  font-size: var(--m-t-base);
  line-height: 1.5;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* background intentionally transparent — the platform theme video (.bg-stage)
     renders behind this layer. */
}

html.soj-mobile #soj-mobile-root ::selection { background: rgba(255, 255, 255, 0.22); }

html.soj-mobile .m-scroll {
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain; scrollbar-width: none;
}
html.soj-mobile .m-scroll::-webkit-scrollbar { width: 0; height: 0; }

/* "boring" is the platform's one LIGHT theme (#f4f4f2 flat bg, no video — see
   _overrides.css). Every other theme is a dark scrimmed-video bg where white ink
   reads fine. Here we flip mobile text dark + give the glass CTA an opaque fill so
   primary buttons/bubbles clear WCAG AA on the bright background. (Was keyed on the
   legacy "day" id, which universal-boot.js maps to my-garden — so it never matched.) */
html.soj-mobile[data-theme="boring"] #soj-mobile-root {
  --m-ink: #0a0a0a;
  --m-ink-dim: rgba(0, 0, 0, 0.66);
  --m-ink-faint: rgba(0, 0, 0, 0.48);
  --m-accent-ink: #0a0a0a;
  /* Day theme: the glass CTA fill must be opaque enough that #0a0a0a text on it
     clears WCAG AA, otherwise primary buttons/bubbles render dark-on-translucent. */
  --m-accent: rgba(255, 255, 255, 0.92);
  --m-accent-soft: rgba(0, 0, 0, 0.08);
  --m-surface-4: rgba(0, 0, 0, 0.12);   /* selected fill reads on the bright bg */
  --m-dock-scrim: rgba(245, 246, 248, 0.62);
}

/* Keyboard / switch focus ring — one rule for every control (buttons, tabs,
   chips, fields, sheet options, links). Uses --m-ink so it's high-contrast in
   BOTH themes (white on dark, near-black on day). Mouse/touch presses use
   :active scales and never trigger :focus-visible, so this stays keyboard-only. */
html.soj-mobile #soj-mobile-root :focus-visible {
  outline: 2px solid var(--m-ink);
  outline-offset: 2px;
}
html.soj-mobile #soj-mobile-root :focus:not(:focus-visible) { outline: none; }

/* ============================ 4. SHELL ================================= */

html.soj-mobile .m-app {
  position: absolute; inset: 0; z-index: 1;
  display: grid; grid-template-rows: auto 1fr auto; grid-template-columns: minmax(0, 1fr); height: 100dvh;
}

/* — top bar: transparent container, glass elements (platform pattern) — */
html.soj-mobile .m-top {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  height: calc(var(--m-topbar-h) + var(--m-safe-t));
  padding: var(--m-safe-t) clamp(10px, 3vw, 16px) 0;
  position: relative; z-index: 5;
}
html.soj-mobile .m-brand {
  display: flex; align-items: center; gap: 8px; min-width: 0; flex-shrink: 1;
  font-family: var(--m-display); font-weight: 700; font-size: 0.98rem; letter-spacing: -0.02em;
  white-space: nowrap; text-shadow: 0 1px 10px rgba(0, 0, 0, 0.35);
}
html.soj-mobile .m-brand span:last-child { overflow: hidden; text-overflow: ellipsis; }
html.soj-mobile[data-theme="boring"] .m-brand { text-shadow: none; }
html.soj-mobile .m-brand-dot {
  width: 22px; height: 22px; border-radius: 7px;
  background: var(--m-surface-2); box-shadow: var(--m-ring);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
}
html.soj-mobile .m-top-tools { display: flex; align-items: center; gap: 8px; flex: none; }

/* glass utility circle in the top bar (Mind / Agent / Theme / Sound) */
html.soj-mobile .m-util {
  position: relative;
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border: 1.5px solid var(--m-line); border-radius: 50%;
  background: var(--m-surface); color: var(--m-ink);
  box-shadow: var(--m-shadow);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  cursor: pointer; transition: transform var(--m-fast) var(--m-ease), background var(--m-fast);
}
/* invisible hit-slop → ~48px tap target while the glyph stays compact (WCAG 2.5.8). */
html.soj-mobile .m-util::after { content: ""; position: absolute; inset: -4px; }
html.soj-mobile .m-util:active { transform: scale(0.92); background: var(--m-surface-2); }
html.soj-mobile .m-util svg { width: 20px; height: 20px; }
html.soj-mobile .m-util.is-on { background: var(--m-surface-4); border-color: var(--m-line-2); box-shadow: var(--m-shadow), inset 0 0 0 1px var(--m-line-2); }

/* — Top-bar icon parity with desktop. The Mind (sonar/neural), Agent (mic) and
     Sound (speaker/waves) glyphs are ported verbatim from desktop
     (#mindStateBtn / #agentBtn / #soundBtn in index.html); these self-contained
     keyframe copies (m-* prefix, no collision with the desktop stylesheets)
     drive them at the mobile 20px size without depending on desktop CSS scoping. */
html.soj-mobile .m-util .msb-svg,
html.soj-mobile .m-util .agent-svg,
html.soj-mobile .m-util .snd-svg { overflow: visible; }
/* State of Mind — standard sonar ripples + breathing core */
html.soj-mobile .m-util .msb-ring { transform-box: fill-box; transform-origin: center; animation: m-msbRipple 3s ease-out infinite; }
html.soj-mobile .m-util .msb-core { transform-box: fill-box; transform-origin: center; animation: m-msbCore 3s ease-in-out infinite; }
/* State of Mind — neural net rings + twinkling nodes (signals self-animate via SMIL) */
html.soj-mobile .m-util .msb-nring { transform-box: fill-box; transform-origin: center; animation: m-msbNRing 2.8s ease-out infinite; }
html.soj-mobile .m-util .msb-node { transform-box: fill-box; transform-origin: center; animation: m-msbTwinkle 2.6s ease-in-out infinite; }
/* State of Mind — Burn: spinning orange disc + flickering flame bed. Verbatim
   parity with desktop #mindStateBtn .msb-burn (mind.css) + the .msb-lick flame
   bed built in universal.js buildFire(). The disc fills the .m-util circle; the
   per-flame animation-duration/-delay come inline from buildBurnGlyph(). */
html.soj-mobile .m-util--mind .msb-burn { position: absolute; inset: 0; border-radius: 50%; overflow: hidden; background: #D8430C; animation: m-msbSpin 1.1s linear infinite; transform-origin: 50% 50%; will-change: transform; }
html.soj-mobile .m-util--mind .msb-burn svg { position: absolute; inset: 0; width: 100%; height: 100%; }
html.soj-mobile .m-util .msb-lick { transform-box: fill-box; transform-origin: 50% 100%; animation: m-msbLick .4s ease-in-out infinite; }
/* Agent — idle mic breathe; listening ripple + mic pulse; active-mission orbit.
   Verbatim parity with desktop #agentBtn (styles/agent-bar.css). data-state is
   set on .m-util--agent by soj-mobile-agent.js (listening=voice, active=running). */
html.soj-mobile .m-util .ag-ring { opacity: 0; transform-box: fill-box; transform-origin: center; }
html.soj-mobile .m-util .ag-orbit { opacity: 0; transform-box: fill-box; transform-origin: 20px 20px; }
html.soj-mobile .m-util .ag-mic { transform-box: fill-box; transform-origin: center; animation: m-agMicBreathe 3.2s ease-in-out infinite; }
html.soj-mobile .m-util--agent[data-state="listening"] .ag-ring { opacity: 1; animation: m-agRipple 2.2s ease-out infinite; }
html.soj-mobile .m-util--agent[data-state="listening"] .ag-mic { animation: m-agMicPulse .9s ease-in-out infinite; }
html.soj-mobile .m-util--agent[data-state="active"] .ag-orbit { opacity: 1; animation: m-agOrbit 2.4s linear infinite; }
/* Agent running-mission count badge (desktop #agentBadge parity). */
html.soj-mobile .m-util--agent .m-util-badge { position: absolute; top: -2px; right: -2px; min-width: 15px; height: 15px; padding: 0 3px; border-radius: 8px; background: #7FE9C3; color: #06231a; font-size: 10px; font-weight: 700; line-height: 15px; text-align: center; box-shadow: var(--m-shadow); pointer-events: none; }
html.soj-mobile .m-util--agent .m-util-badge[hidden] { display: none; }
/* Sound — ON state: 3 rings expand outward + fade (classic sound wave) */
html.soj-mobile .m-util .sw { transform-box: fill-box; transform-origin: center; }
html.soj-mobile .m-util .sw-1 { animation: m-soundWave 1.8s ease-out infinite; animation-delay: 0s; }
html.soj-mobile .m-util .sw-2 { animation: m-soundWave 1.8s ease-out infinite; animation-delay: .6s; }
html.soj-mobile .m-util .sw-3 { animation: m-soundWave 1.8s ease-out infinite; animation-delay: 1.2s; }

@keyframes m-msbRipple { 0% { transform: scale(.08); opacity: .95; } 70% { opacity: .2; } 100% { transform: scale(1); opacity: 0; } }
@keyframes m-msbCore { 0%, 100% { transform: scale(.8); opacity: .6; } 50% { transform: scale(1.18); opacity: 1; } }
@keyframes m-msbNRing { 0% { transform: scale(.12); opacity: .6; } 100% { transform: scale(1); opacity: 0; } }
@keyframes m-msbTwinkle { 0%, 100% { transform: scale(.6); opacity: .45; } 50% { transform: scale(1.25); opacity: 1; } }
@keyframes m-msbLick { 0%, 100% { transform: scaleY(.72) scaleX(1.08); opacity: .78; } 45% { transform: scaleY(1.34) scaleX(.82); opacity: 1; } 75% { transform: scaleY(1) scaleX(1); opacity: .95; } }
@keyframes m-agMicBreathe { 0%, 100% { transform: scale(1); opacity: .92; } 50% { transform: scale(1.06); opacity: 1; } }
@keyframes m-soundWave { 0% { transform: scale(1); opacity: .9; } 80% { opacity: .15; } 100% { transform: scale(3.4); opacity: 0; } }
/* Burn disc spin (desktop msbtnSpin) + agent listening/active (desktop agRipple/agMicPulse/agOrbit). */
@keyframes m-msbSpin { to { transform: rotate(360deg); } }
@keyframes m-agMicPulse { 0%, 100% { transform: scale(.96); } 50% { transform: scale(1.12); } }
@keyframes m-agRipple { 0% { transform: scale(.18); opacity: .85; } 70% { opacity: .15; } 100% { transform: scale(1); opacity: 0; } }
@keyframes m-agOrbit { to { transform: rotate(360deg); } }

/* — touch/hover tooltip on the top-bar utility circles (desktop hover-tooltip parity).
     Long-press peeks the label (JS adds .m-tip-show); a quick tap still acts. Sits
     BELOW the circle (it's at the top edge of the screen) with an upward caret. — */
html.soj-mobile .m-tip {
  position: absolute; top: calc(100% + 9px); left: 50%;
  transform: translateX(-50%) translateY(-4px);
  padding: 5px 10px; border-radius: 9px; white-space: nowrap;
  background: var(--m-surface-3); color: var(--m-ink); border: 1.5px solid var(--m-line-2);
  font-family: var(--m-font); font-size: var(--m-t-2xs); font-weight: 700; letter-spacing: 0.01em; line-height: 1;
  box-shadow: var(--m-shadow-lg); backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  opacity: 0; pointer-events: none; z-index: 40;
  transition: opacity var(--m-fast) var(--m-ease), transform var(--m-fast) var(--m-ease);
}
html.soj-mobile .m-tip::after {
  content: ""; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-bottom-color: var(--m-surface-3);
}
html.soj-mobile .m-tip-show .m-tip { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) { html.soj-mobile .m-tip { transition: opacity var(--m-fast); } }

/* Narrow phones: stop the top bar overflowing when the coin balance is 4+ digits
   — tighten the utility row + wallet pill so the chrome never clips. Mobile-only;
   utils keep a 44px tap target via the ::after hit-slop. */
@media (max-width: 400px) {
  html.soj-mobile .m-top { gap: 6px; }
  html.soj-mobile .m-top-tools { gap: 6px; }
  html.soj-mobile .m-util { width: 36px; height: 36px; }
  html.soj-mobile .m-util::after { inset: -6px; }
  html.soj-mobile .m-util svg { width: 18px; height: 18px; }
  html.soj-mobile .m-wallet { padding: 6px 6px 6px 10px; gap: 5px; font-size: 0.82rem; }
}

/* Very small phones (<360px: iPhone SE 1st-gen, Galaxy Fold cover): the four
   utility circles + wallet pill claim the whole row, leaving the wordmark only
   ~40px — enough to clip "Synergy AI" to a broken "Syner…". Drop the wordmark
   entirely below this width so the header reads as an intentional, clean
   control cluster instead of a truncated brand. 360px+ keeps the wordmark. */
@media (max-width: 359px) {
  html.soj-mobile .m-brand { display: none; }
}

/* — wallet pill — */
html.soj-mobile .m-wallet {
  display: inline-flex; align-items: center; gap: 7px; min-height: 44px;
  padding: 7px 7px 7px 12px; border-radius: var(--m-pill);
  border: 1.5px solid var(--m-line); background: var(--m-surface);
  box-shadow: var(--m-shadow);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  font-weight: 700; font-size: 0.86rem; font-variant-numeric: tabular-nums;
  cursor: pointer; transition: transform var(--m-fast) var(--m-ease);
}
html.soj-mobile .m-wallet:active { transform: scale(0.96); }
html.soj-mobile .m-wallet b { color: var(--m-gold); }
html.soj-mobile .m-wallet .m-coin { width: 15px; height: 15px; filter: drop-shadow(0 0 5px rgba(255, 194, 75, 0.5)); }
html.soj-mobile .m-wallet-add {
  width: 24px; height: 24px; display: grid; place-items: center; border-radius: var(--m-pill);
  background: var(--m-surface-3); color: var(--m-ink); font-weight: 800; font-size: 1rem;
}
html.soj-mobile .m-wallet.is-pulse { animation: m-walletpulse var(--m-slow) var(--m-ease); }
@keyframes m-walletpulse { 0% { transform: scale(1); } 35% { transform: scale(1.12); } 100% { transform: scale(1); } }

/* — Vortex Coins sheet — */
html.soj-mobile .m-coins-head {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; margin-bottom: 12px;
  border-radius: var(--m-r-lg); border: 1.5px solid var(--m-line);
  background: var(--m-surface-2); box-shadow: var(--m-ring);
}
html.soj-mobile .m-coins-coin {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center;
  color: var(--m-gold); filter: drop-shadow(0 0 8px rgba(255, 194, 75, 0.45));
}
html.soj-mobile .m-coins-coin svg { width: 34px; height: 34px; }
html.soj-mobile .m-coins-bal { font-family: var(--m-display); font-size: var(--m-t-2xl); font-weight: 700; letter-spacing: -0.03em; line-height: 1; color: var(--m-gold); font-variant-numeric: tabular-nums; }
html.soj-mobile .m-coins-brk { display: flex; flex-direction: column; gap: 2px; margin-bottom: 14px; }
html.soj-mobile .m-coins-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 4px; border-bottom: 1px solid var(--m-line);
  font-size: var(--m-t-sm); font-variant-numeric: tabular-nums;
}
html.soj-mobile .m-coins-row:last-child { border-bottom: 0; }
html.soj-mobile .m-coins-row b { color: var(--m-ink); }

/* — theme-aware coin art (per-theme PNG, mirrors desktop) — */
html.soj-mobile .m-coin-img { display: inline-block; vertical-align: middle; object-fit: contain; filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.35)); animation: m-coin-spin 3s linear infinite; transform-origin: center center; }
/* Mirror desktop's vortex-coin-spin — the coin rotates flat, 3s linear loop. */
@keyframes m-coin-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
html.soj-mobile .m-wallet .m-coin { display: inline-flex; align-items: center; }
html.soj-mobile .m-coins-coin { animation: none; }
html.soj-mobile .m-coins-coin .m-coin-img { width: 38px; height: 38px; }

/* — top-bar state icons — */
html.soj-mobile .m-util--theme .m-theme-glyph { font-size: 17px; line-height: 1; }
html.soj-mobile .m-util--mind.is-neural { color: var(--m-ok); }
html.soj-mobile .m-util--mind.is-burn { color: var(--m-gold); }

/* — currency segmented toggle (INR / USD) — */
html.soj-mobile .m-curtoggle { display: inline-flex; border: 1.5px solid var(--m-line); border-radius: var(--m-pill); overflow: hidden; background: var(--m-surface); }
html.soj-mobile .m-curopt { appearance: none; border: 0; background: transparent; color: var(--m-ink-dim); font-family: var(--m-font); font-weight: 700; font-size: var(--m-t-xs); min-height: 44px; display: inline-flex; align-items: center; padding: 6px 14px; cursor: pointer; transition: background var(--m-fast), color var(--m-fast), transform var(--m-fast); }
html.soj-mobile .m-curopt.is-on { background: var(--m-surface-4); color: var(--m-ink); box-shadow: inset 0 0 0 1px var(--m-line-2); }
html.soj-mobile .m-curopt:active { transform: scale(0.96); }

/* — auto-hiding bottom nav + floating pull-handle — */
html.soj-mobile .m-tabs { transition: transform var(--m-mid) var(--m-ease); }
html.soj-mobile .m-app.tabs-hidden { grid-template-rows: auto 1fr 0; }
html.soj-mobile .m-app.tabs-hidden .m-tabs { transform: translateY(120%); pointer-events: none; }
html.soj-mobile .m-tabhandle {
  position: fixed; left: 50%; bottom: calc(var(--m-safe-b) + 5px); transform: translateX(-50%);
  width: 46px; height: 5px; padding: 0; border: 0; border-radius: 3px;
  background: var(--m-ink-faint); box-shadow: var(--m-shadow);
  opacity: 0; pointer-events: none; z-index: 6; cursor: pointer;
  transition: opacity var(--m-mid) var(--m-ease);
}
html.soj-mobile .m-app.tabs-hidden .m-tabhandle { opacity: 0.85; pointer-events: auto; }
html.soj-mobile .m-tabhandle::before { content: ""; position: absolute; left: -16px; right: -16px; top: -16px; bottom: -16px; }

/* — panel host — */
html.soj-mobile .m-panels { position: relative; overflow: hidden; z-index: 1; }
html.soj-mobile .m-panel {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  opacity: 0; visibility: hidden; transform: translateY(8px) scale(0.992);
  transition: opacity var(--m-mid) var(--m-ease), transform var(--m-mid) var(--m-ease), visibility var(--m-mid);
}
html.soj-mobile .m-panel.is-active { opacity: 1; visibility: visible; transform: none; }

/* — bottom tab bar: liquid glass strip — */
html.soj-mobile .m-tabs {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; align-items: stretch;
  height: calc(var(--m-tabbar-h) + var(--m-safe-b)); padding-bottom: var(--m-safe-b);
  background: var(--m-surface); border-top: 1.5px solid var(--m-line);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.28);
  position: relative; z-index: 5;
}
html.soj-mobile .m-tab {
  appearance: none; border: 0; background: transparent; color: var(--m-ink-faint);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  font-family: var(--m-font); font-size: 0.66rem; font-weight: 600; letter-spacing: 0.02em;
  cursor: pointer; position: relative; transition: color var(--m-fast) var(--m-ease);
  padding: 0 2px;
}
html.soj-mobile .m-tab svg { width: 23px; height: 23px; transition: transform var(--m-mid) var(--m-ease); }
html.soj-mobile .m-tab.is-active { color: var(--m-ink); font-weight: 800; }
html.soj-mobile .m-tab.is-active svg { transform: translateY(-1px) scale(1.06); }
html.soj-mobile .m-tab.is-active::before {
  content: ""; position: absolute; top: 6px; width: 40px; height: 30px;
  border-radius: var(--m-pill); background: var(--m-surface-4); z-index: -1;
  box-shadow: inset 0 0 0 1px var(--m-line-2), 0 4px 12px rgba(0, 0, 0, 0.25);
}
html.soj-mobile .m-tab:active svg { transform: scale(0.9); }
html.soj-mobile .m-tab-label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* panel scaffolding */
html.soj-mobile .m-panel-scroll {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain; scrollbar-width: none;
  padding: clamp(14px, 4vw, 20px); display: flex; flex-direction: column; gap: var(--m-gap);
}
html.soj-mobile .m-panel-scroll::-webkit-scrollbar { width: 0; }
html.soj-mobile .m-panel-head { padding: 4px 2px 2px; }
html.soj-mobile .m-panel-head h2 {
  margin: 0; font-family: var(--m-display); font-size: var(--m-t-xl); font-weight: 700;
  letter-spacing: -0.03em; line-height: 1.05; text-shadow: 0 1px 12px rgba(0, 0, 0, 0.3);
}
html.soj-mobile[data-theme="boring"] .m-panel-head h2 { text-shadow: none; }
/* The panel-head subtitle sits surface-less over the scrimmed video just like its
   h2 sibling, but at dimmer --m-ink-dim — give it the same soft shadow so it stays
   legible over bright frames; removed on the flat "boring" light theme. */
html.soj-mobile .m-panel-head p { margin: 6px 0 0; color: var(--m-ink-dim); font-size: var(--m-t-sm); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.28); }
html.soj-mobile[data-theme="boring"] .m-panel-head p { text-shadow: none; }

/* ========================== 5. PRIMITIVES ============================== */

html.soj-mobile .m-btn {
  appearance: none; -webkit-appearance: none; border: 1.5px solid var(--m-line-2);
  font-family: var(--m-font); font-weight: 700; font-size: var(--m-t-base); letter-spacing: -0.01em;
  border-radius: var(--m-pill); padding: 14px 22px; min-height: 48px;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  cursor: pointer; color: var(--m-accent-ink); background: var(--m-accent);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  box-shadow: var(--m-shadow), inset 0 1px 0 rgba(255, 255, 255, 0.28);
  transition: transform var(--m-fast) var(--m-ease), filter var(--m-fast), opacity var(--m-fast);
}
html.soj-mobile .m-btn:active { transform: scale(0.97); filter: brightness(1.08); }
html.soj-mobile .m-btn[disabled] { opacity: 0.45; pointer-events: none; }
html.soj-mobile .m-btn svg { width: 19px; height: 19px; }
html.soj-mobile .m-btn--ghost { background: var(--m-surface); color: var(--m-ink); border-color: var(--m-line); box-shadow: var(--m-shadow); }
html.soj-mobile .m-btn--line { background: transparent; color: var(--m-ink); border-color: var(--m-line-2); box-shadow: none; }
html.soj-mobile .m-btn--danger { background: var(--m-danger-strong); color: var(--m-danger-ink); border-color: var(--m-danger-line); }
html.soj-mobile .m-btn--block { width: 100%; }
html.soj-mobile .m-btn--sm { min-height: 44px; padding: 11px 18px; font-size: var(--m-t-sm); }
html.soj-mobile .m-iconbtn {
  appearance: none; border: 1.5px solid var(--m-line); width: 44px; height: 44px; border-radius: var(--m-pill);
  display: grid; place-items: center; background: var(--m-surface); color: var(--m-ink); box-shadow: var(--m-shadow);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  cursor: pointer; transition: transform var(--m-fast) var(--m-ease), background var(--m-fast);
}
html.soj-mobile .m-iconbtn:active { transform: scale(0.92); }
html.soj-mobile .m-iconbtn svg { width: 21px; height: 21px; }

html.soj-mobile .m-field {
  width: 100%; font-family: var(--m-font); font-size: 1rem; color: var(--m-ink);
  background: var(--m-surface); border: 1.5px solid var(--m-line); border-radius: var(--m-r);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  padding: 14px 16px; resize: none;
  transition: border-color var(--m-fast), background var(--m-fast), box-shadow var(--m-fast);
}
html.soj-mobile .m-field::placeholder { color: var(--m-ink-faint); }
html.soj-mobile .m-field:focus {
  outline: none; border-color: var(--m-line-2); background: var(--m-surface-2);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.12);
}
html.soj-mobile .m-label { font-size: var(--m-t-sm); font-weight: 700; color: var(--m-ink-dim); margin: 0 0 8px 2px; }
/* DQ-4: shared micro eyebrow/caption — replaces the 9px uppercase block copy-pasted across panels */
html.soj-mobile .m-eyebrow { font-size: var(--m-t-2xs); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--m-ink-faint); }

html.soj-mobile .m-chiprow { display: flex; gap: 8px; flex-wrap: wrap; }
html.soj-mobile .m-chip {
  appearance: none; border: 1.5px solid var(--m-line); font-family: var(--m-font); font-size: var(--m-t-sm); font-weight: 700;
  color: var(--m-ink-dim); background: var(--m-surface); backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  border-radius: var(--m-pill); padding: 10px 16px; min-height: 44px; cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color var(--m-fast), background var(--m-fast), border-color var(--m-fast), box-shadow var(--m-fast), transform var(--m-fast) var(--m-ease);
}
html.soj-mobile .m-chip.is-on { color: var(--m-ink); background: var(--m-surface-4); border-color: var(--m-line-2); box-shadow: inset 0 0 0 1px var(--m-line-2); }
html.soj-mobile .m-chip:active { transform: scale(0.95); }

html.soj-mobile .m-card {
  background: var(--m-surface); border: 1.5px solid var(--m-line); border-radius: var(--m-r-lg);
  padding: var(--m-pad); box-shadow: var(--m-shadow);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
}

/* — bottom sheet — */
html.soj-mobile .m-scrim {
  position: fixed; inset: 0; z-index: 100010; background: rgba(3, 4, 9, 0.5);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; transition: opacity var(--m-mid) var(--m-ease);
}
html.soj-mobile .m-scrim.is-open { opacity: 1; }
/* A closing scrim/sheet must stop intercepting taps during its ~320ms fade-out,
   so a fast double-tap can't land on a dismissing layer or stack two sheets. */
html.soj-mobile .m-scrim:not(.is-open) { pointer-events: none; }
html.soj-mobile .m-sheet:not(.is-open) { pointer-events: none; }
html.soj-mobile .m-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 100011; max-height: 90dvh;
  display: flex; flex-direction: column;
  background: var(--m-surface-2); border-top: 1.5px solid var(--m-line-2);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  border-radius: var(--m-r-xl) var(--m-r-xl) 0 0; box-shadow: var(--m-shadow-lg);
  padding: 10px clamp(16px, 5vw, 24px) calc(20px + var(--m-safe-b));
  transform: translateY(100%); transition: transform var(--m-slow) var(--m-ease);
}
html.soj-mobile .m-sheet.is-open { transform: none; }
html.soj-mobile .m-sheet-grip { width: 38px; height: 4px; border-radius: 4px; background: var(--m-ink-ghost); margin: 6px auto 12px; flex: none; }
html.soj-mobile .m-sheet h3 { margin: 0 0 4px; font-family: var(--m-display); font-size: var(--m-t-lg); font-weight: 700; letter-spacing: -0.02em; }
html.soj-mobile .m-sheet-body { overflow-y: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; display: flex; flex-direction: column; gap: 10px; }
html.soj-mobile .m-sheet-body::-webkit-scrollbar { width: 0; }

html.soj-mobile .m-opt {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  appearance: none; border: 1.5px solid var(--m-line); background: var(--m-surface); color: var(--m-ink);
  border-radius: var(--m-r); padding: 14px 16px; cursor: pointer; font-family: var(--m-font); font-size: var(--m-t-base);
  transition: background var(--m-fast), transform var(--m-fast) var(--m-ease);
}
html.soj-mobile .m-opt:active { transform: scale(0.985); }
html.soj-mobile .m-opt.is-on { border-color: var(--m-line-2); background: var(--m-surface-4); box-shadow: inset 0 0 0 1px var(--m-line-2); }
html.soj-mobile .m-opt-main { flex: 1; min-width: 0; }
html.soj-mobile .m-opt-main b { display: block; font-weight: 700; }
html.soj-mobile .m-opt-main span { display: block; color: var(--m-ink-faint); font-size: var(--m-t-xs); margin-top: 2px; }
html.soj-mobile .m-opt-cost { color: var(--m-gold); font-weight: 700; font-size: var(--m-t-sm); font-variant-numeric: tabular-nums; }

/* — over-cap grace banner (storage warning, shell-wide fixed strip; semantic danger) — */
html.soj-mobile .m-grace {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100001;
  display: flex; align-items: center; gap: 10px;
  padding: calc(var(--m-safe-t) + 9px) 14px 9px;
  background: var(--m-danger-strong); color: var(--m-danger-ink);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
  font-size: var(--m-t-xs); line-height: 1.35;
  animation: m-grace-in var(--m-mid, 0.3s) var(--m-ease, ease);
}
html.soj-mobile .m-grace-msg { flex: 1; min-width: 0; font-weight: 600; }
html.soj-mobile .m-grace-btn {
  flex: none; min-height: 44px; padding: 7px 15px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.16); color: inherit; font-weight: 800; font-size: var(--m-t-xs);
  border: 1px solid rgba(0, 0, 0, 0.2);
}
html.soj-mobile .m-grace-btn:active { transform: scale(0.96); background: rgba(0, 0, 0, 0.26); }
html.soj-mobile .m-grace-x {
  position: relative; flex: none; width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; color: inherit; background: transparent; opacity: 0.8;
}
/* hit-slop: lift the 34px dismiss glyph to a 46px tap target */
html.soj-mobile .m-grace-x::after { content: ""; position: absolute; inset: -6px; }
html.soj-mobile .m-grace-x:active { opacity: 1; background: rgba(0, 0, 0, 0.14); }
@keyframes m-grace-in { from { transform: translateY(-100%); } to { transform: translateY(0); } }

/* — toast — */
html.soj-mobile .m-toasts {
  position: fixed; left: 50%; bottom: calc(var(--m-tabbar-h) + var(--m-safe-b) + 14px); transform: translateX(-50%);
  z-index: 100020; display: flex; flex-direction: column; gap: 8px; width: min(92vw, 460px); pointer-events: none;
}
html.soj-mobile .m-toast {
  pointer-events: auto; background: var(--m-surface-3); color: var(--m-ink);
  border: 1.5px solid var(--m-line-2); border-radius: var(--m-r); padding: 13px 16px;
  font-size: var(--m-t-sm); font-weight: 600; box-shadow: var(--m-shadow-lg);
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
  display: flex; align-items: center; gap: 10px; animation: m-toastin var(--m-mid) var(--m-ease);
}
html.soj-mobile .m-toast.is-out { animation: m-toastout var(--m-fast) var(--m-ease-in) forwards; }
html.soj-mobile .m-toast--err { border-color: var(--m-danger-line); }
html.soj-mobile .m-toast--ok { border-color: var(--m-ok-line); }
html.soj-mobile .m-toast .m-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--m-ink); flex: none; }
html.soj-mobile .m-toast--err .m-dot { background: var(--m-danger); }
html.soj-mobile .m-toast--ok .m-dot { background: var(--m-ok); }
@keyframes m-toastin { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes m-toastout { to { opacity: 0; transform: translateY(8px); } }

/* — spinner — */
html.soj-mobile .m-spin {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2.5px solid var(--m-ink-ghost); border-top-color: var(--m-ink);
  animation: m-spin 0.7s linear infinite; flex: none;
}
@keyframes m-spin { to { transform: rotate(360deg); } }
html.soj-mobile .m-loading { display: inline-flex; align-items: center; gap: 10px; color: var(--m-ink-dim); font-size: var(--m-t-sm); font-weight: 600; }

/* — skeleton — */
html.soj-mobile .m-sk {
  background: linear-gradient(100deg, var(--m-surface) 30%, var(--m-surface-2) 50%, var(--m-surface) 70%);
  background-size: 200% 100%; animation: m-sk 1.3s var(--m-ease) infinite; border-radius: var(--m-r-sm);
}
@keyframes m-sk { to { background-position: -200% 0; } }

/* — empty / gate — */
html.soj-mobile .m-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: 12px; padding: 40px 24px; color: var(--m-ink-dim);
}
html.soj-mobile .m-empty-emoji {
  width: 64px; height: 64px; display: grid; place-items: center; border-radius: var(--m-r-lg);
  background: var(--m-surface-2); border: 1.5px solid var(--m-line); font-size: 30px;
  backdrop-filter: var(--m-blur); -webkit-backdrop-filter: var(--m-blur);
}
html.soj-mobile .m-empty h3 { margin: 0; color: var(--m-ink); font-family: var(--m-display); font-weight: 700; font-size: var(--m-t-lg); text-shadow: 0 1px 12px rgba(0, 0, 0, 0.3); }
html.soj-mobile .m-empty p { margin: 0; max-width: 30ch; font-size: var(--m-t-sm); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.28); }
/* Full-panel empty states sit on the transparent panel (over the scrimmed
   video), so shadow the text for legibility — matching .m-panel-head h2; the
   flat "boring" light theme needs no shadow. */
html.soj-mobile[data-theme="boring"] .m-empty h3, html.soj-mobile[data-theme="boring"] .m-empty p { text-shadow: none; }

html.soj-mobile .m-gate {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: 16px; padding: 40px 28px;
}
html.soj-mobile .m-gate h2 { margin: 0; font-family: var(--m-display); font-size: var(--m-t-2xl); font-weight: 700; letter-spacing: -0.03em; line-height: 1.02; text-shadow: 0 1px 14px rgba(0, 0, 0, 0.3); }
html.soj-mobile[data-theme="boring"] .m-gate h2 { text-shadow: none; }
html.soj-mobile .m-gate p { margin: 0; color: var(--m-ink-dim); max-width: 34ch; }

/* — utility — */
html.soj-mobile .m-row { display: flex; align-items: center; gap: 10px; }
html.soj-mobile .m-spread { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
html.soj-mobile .m-grow { flex: 1; min-width: 0; }
html.soj-mobile .m-hide { display: none !important; }
html.soj-mobile .m-muted { color: var(--m-ink-faint); }
/* text-overflow:ellipsis is ignored on inline elements, so .m-truncate silently
   failed on the many <b>/<span> labels it's applied to (song titles, account +
   persona + chip names) — they overran their flex container and overlapped
   sibling controls. min-width:0 + display:block make it truncate whether it's a
   flex item or a normal inline element. */
html.soj-mobile .m-truncate { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  html.soj-mobile #soj-mobile-root *,
  html.soj-mobile #soj-mobile-root *::before,
  html.soj-mobile #soj-mobile-root *::after,
  html.soj-mobile .m-sheet, html.soj-mobile .m-scrim, html.soj-mobile .m-toast, html.soj-mobile .m-coin-img {
    animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
  }
}
