/* ==========================================================================
   responsive.css — iPad / iPhone / touch-device adjustments.

   Loaded LAST so it overrides earlier shells (sidebar.css, chat.css, etc.).
   Breakpoints:
     <=1180px   tablet-landscape (iPad Pro 11" landscape; iPad Air 10.9"; etc.)
     <=1024px   tablet-portrait + small laptop (iPad Pro portrait, iPad 9.7")
     <=820px    iPad mini portrait, large phones landscape
     <=480px    phones portrait
   ========================================================================== */

/* ---------- iOS Safari 100vh fix + safe areas + smooth scroll ---------- */
:root {
  --vh: 1vh;
  /* Used by chrome height calcs; 0 on desktop / non-notch devices. */
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);
}
@supports (height: 100dvh) {
  /* Only the outermost shells get a min-height floor. .main-content and
     .content-wrapper deliberately use the topbar-aware height calc from
     sidebar.css; giving them min-height: 100dvh forced content-wrapper
     past the viewport (because its parent already has the 56px topbar
     above), which caused the body to scroll and dragged the docked chat
     panel header off-screen. */
  .app-layout,
  .sidebar { min-height: 100dvh; }
}

html, body {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

/* Edge-to-edge shell: paint the theme background into the status-bar and
   home-indicator regions. Chrome (top bar / composer) pads with env(safe-area-*).
   Capacitor uses contentInset:never so the WebView itself is full-bleed. */
html {
  background: var(--bg-base, #0f1419);
  height: 100%;
}
body {
  min-height: 100%;
  min-height: 100dvh;
  background: var(--bg-base, #0f1419);
  margin: 0;
}

/* Desktop / tablet-landscape: pin the chrome to the viewport.
   The page itself never scrolls — only internal regions
   (.content-left, .chat-log, .sidebar-nav) do. This guarantees the
   chat-drawer header (top) and input row (bottom) stay docked to the
   browser window edges no matter how long the left-pane content is.
   Below 820px the layout collapses to a single column and page-scroll
   is expected again, so this guard only applies on wider viewports. */
@media (min-width: 821px) {
  html, body {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
  }
}

.content-left,
.sidebar-nav,
.chat-log {
  -webkit-overflow-scrolling: touch;
}

/* Hamburger button — visible only on small screens (CSS-only toggle).
   The button itself lives in base.html. */
.sidebar-mobile-trigger {
  display: none;
  background: transparent;
  border: 1px solid var(--border-default, #30363d);
  color: var(--text-primary, #e6edf3);
  width: 36px;
  height: 36px;
  border-radius: var(--r-sm, 6px);
  font-size: 18px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}
.sidebar-mobile-trigger:active { background: var(--bg-elevated-2, #21262d); }

/* Backdrop that appears behind the off-canvas sidebar on small screens. */
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 998;
  opacity: 0;
  transition: opacity 180ms ease-out;
}
.sidebar-backdrop.visible {
  display: block;
  opacity: 1;
}

/* ============================================================
   Universal viewport-bounding for the chat panel.
   Applies at every breakpoint above the bottom-sheet handover (>820px).
   Solves the "panel extends beyond screen and gets cut off" bug when:
     - the user resized the panel wide on a big monitor, then narrowed
       the browser window (--chat-width-user > viewport),
     - mode-mini's hardcoded 380×480 is wider than a narrow laptop split,
     - a saved --chat-fx/--chat-fy positions the float off-screen.
   We never let the panel exceed viewport - 32px and we clamp its
   right/left offsets so it stays fully on-screen.
   ============================================================ */
.content-right.mode-dock {
  /* In-flow dock: cap width by viewport so it never overflows the
     flex row even if --chat-width-user is bigger than the screen. */
  max-width: calc(100vw - 64px);
}
.content-right.mode-float {
  /* Detached overlay: cap width AND height, and clamp the right + top
     offsets with BOTH a lower and an upper bound so the panel can never
     slide off any edge — even if a saved --chat-fx/--chat-fy came from a
     larger window. The upper bounds keep at least ~64px reachable from
     each edge; JS (clampFloatPosition) then refines to fully on-screen.
     overflow:hidden + flex column keep the top menu bar pinned; only
     #chat-log scrolls (see chat.css mode-float rules). */
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 48px);
  max-height: calc(100dvh - 48px);
  /* Upper bound keeps ≥280px of the panel on-screen (was 100vw-64px,
     which parked a restored window almost fully off the left edge). */
  right: clamp(
    8px,
    var(--chat-fx, calc((100vw - min(var(--chat-width-user, 50vw), 100vw - 32px)) / 2)),
    max(8px, calc(100vw - 288px))
  );
  top:   clamp(8px, var(--chat-fy, 80px), calc(100vh - 64px));
  top:   clamp(8px, var(--chat-fy, 80px), calc(100dvh - 64px));
  bottom: 16px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
}
.content-right.mode-mini {
  /* Compact picture-in-picture: shrink to viewport on narrow screens. */
  width: min(380px, calc(100vw - 24px));
  height: min(480px, calc(100vh - 80px));
  height: min(480px, calc(100dvh - 80px));
  right:  clamp(8px, var(--chat-fx, 16px), calc(100vw - 64px));
  bottom: clamp(8px, var(--chat-fy-bottom, 16px), calc(100vh - 64px));
  bottom: clamp(8px, var(--chat-fy-bottom, 16px), calc(100dvh - 64px));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
}
/* Constrain the resizer grip so it can't pull the panel wider than vw. */
.chat-resizer { max-width: 100vw; }

/* ============================================================
   Tablet landscape (iPad Pro 11" landscape ~1180px)
   Auto-collapse sidebar to icon rail; keep chat dock visible but
   slightly narrower. Touch-friendly tap targets.
   ============================================================ */
@media (max-width: 1180px) and (min-width: 821px) {
  .nav-item,
  .user-menu-item {
    min-height: 44px;       /* iOS HIG minimum */
  }
  .top-bar-actions { gap: var(--sp-2, 8px); }
  .content-right { width: clamp(320px, 32vw, 480px); }
}

/* ============================================================
   Tablet portrait + iPad mini (<=1024px down to 821px)
   Off-canvas sidebar; chat-drawer overlays content; topbar gets hamburger.
   ============================================================ */
@media (max-width: 1024px) {
  /* Sidebar slides off-screen by default; opens via hamburger. */
  .sidebar {
    transform: translateX(-100%);
    width: 280px;
    box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,0.4));
  }
  body.sidebar-open .sidebar {
    transform: translateX(0);
  }
  /* Disregard the "collapsed" rail mode at this size — full overlay is clearer. */
  .sidebar.collapsed {
    width: 280px;
    transform: translateX(-100%);
  }
  body.sidebar-open .sidebar.collapsed {
    transform: translateX(0);
  }
  .main-content,
  body.sidebar-collapsed .main-content { margin-left: 0; }

  body.sidebar-open .sidebar-backdrop { display: block; opacity: 1; }
  body.sidebar-open .sidebar { z-index: 1100; }
  .sidebar-backdrop { background: rgba(0, 0, 0, 0.18); }

  .sidebar-mobile-trigger { display: inline-flex; }
  /* Desktop rail toggle lives in the top bar; phones use the hamburger. */
  .top-bar-brand .sidebar-toggle { display: none; }

  /* Chat dock: keep behavior but slightly narrower in dock mode. */
  .content-right { width: min(420px, 60vw); }
}

/* ============================================================
   iPad mini portrait + large phones landscape (<=820px)
   Stack chat below content; chat-fab becomes the primary entry.
   ============================================================ */
@media (max-width: 820px) {
  .top-bar { padding: 0 var(--sp-3, 12px); }
  .top-bar-title {
    font-size: var(--fs-sm, 12px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1;
    max-width: none;
  }
  /* Hide the "current-theme" pill on phones to save space. */
  .theme-indicator { display: none; }

  /* Content padding shrinks. */
  .content-left { padding: var(--sp-3, 12px); }

  /* Chat drawer becomes a bottom sheet by default (mode-dock). */
  .content-wrapper {
    flex-direction: column;
    overflow: visible;
    height: auto;
    max-height: none;
    min-height: calc(100dvh - var(--topbar-height, 56px) - env(safe-area-inset-top, 0px));
  }
  .content-left {
    width: 100%;
    height: auto;
    max-height: none;
    padding-bottom: max(var(--sp-3, 12px), env(safe-area-inset-bottom, 0px));
  }

  .content-right.mode-dock {
    position: fixed;
    left: 0; right: 0; bottom: 0; top: auto;
    width: 100%;
    height: 65dvh;
    height: 65vh;
    max-height: 80vh;
    border-left: none;
    border-top: 1px solid var(--border-default, #30363d);
    border-top-left-radius: 14px;
    border-top-right-radius: 14px;
    box-shadow: 0 -12px 28px rgba(0,0,0,0.45);
    z-index: 950;
    transform: translate3d(0, 0, 0);
    transition: transform var(--dur-sheet, 400ms) var(--ease-sheet, cubic-bezier(0.32, 0.72, 0, 1));
    padding-bottom: env(safe-area-inset-bottom, 0);
    box-sizing: border-box;
    width: 100% !important;
    max-width: 100% !important;
  }
  .content-right.mode-dock.collapsed {
    transform: translate3d(0, 100%, 0);
  }
  #chat-drawer.chat-no-motion,
  .content-right.chat-no-motion {
    transition: none !important;
  }
  /* Phone close is a Y slide, not the desktop float genie. */
  .content-right.closing,
  .content-right.mode-float.closing,
  .content-right.mode-mini.closing,
  #chat-drawer.closing {
    animation: none !important;
  }
  /* Chat is a sheet, not a lightbox. A full-viewport dimmer here sat at
     z-index 28900 and greyed the whole app (including over float chat). */

  /* The .chat-resizer doesn't make sense on touch; hide it. */
  .chat-resizer { display: none; }

  /* Tap targets for chat header buttons. */
  .chat-panel-btn,
  .chat-win-btn {
    min-height: 44px;
    min-width: 44px;
    padding-left: 10px;
    padding-right: 10px;
  }
  .chat-window-controls { display: none; }

  /* The iridescent "Thinking…" activity bar must always be visible on
     mobile when the AI is processing. Belt-and-suspenders override —
     keeps display:flex + min-height locked in regardless of cascade. */
  #chat-activity-bar.chat-activity-bar.active,
  .chat-activity-bar.active {
    display: flex !important;
    flex-shrink: 0 !important;
    min-height: 36px !important;
    opacity: 1 !important;
  }

  /* Composer: single shell with in-box tools + send (no external +/send). */
  .chat-input-row {
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: stretch !important;
    gap: 0 !important;
    padding: 8px !important;
    position: relative;
  }
  .chat-input-wrap {
    flex: 1 1 auto !important;
    min-width: 0 !important;
    border-radius: 16px !important;
  }
  .chat-attach-toggle { display: none !important; }
  .chat-fmt-toggle,
  .chat-toolbar,
  #chat-toolbar { display: none !important; }
  #chat-input {
    font-size: 16px !important;          /* prevents iOS zoom-on-focus */
    --chat-input-fs: 16px;
    --chat-input-lh: 1.4;
    min-height: calc(16px * 1.4 * 1.5 + 6px) !important;
    padding: 10px 12px 4px !important;
    line-height: 1.4 !important;
  }
  .chat-composer-bar {
    display: flex !important;
    padding: 2px 6px 6px !important;
    min-height: 36px !important;
    border: none !important;
    border-top: none !important;
    background: transparent !important;
  }
  .chat-composer-bar .chat-action-buttons {
    display: flex !important;
    flex-direction: row !important;
    position: static !important;
    gap: 2px !important;
  }
  .chat-composer-bar .chat-action-btn {
    width: 34px !important;
    height: 34px !important;
  }
  /* Send: compact circle in lower-right of the box. */
  .chat-composer-bar > button#chat-send,
  .chat-input-wrap #chat-send,
  #chat-send {
    flex: 0 0 auto !important;
    align-self: center !important;
    width: 34px !important;
    height: 34px !important;
    min-width: 34px !important;
    min-height: 34px !important;
    max-width: 34px !important;
    max-height: 34px !important;
    padding: 0 !important;
    border-radius: 50% !important;
    gap: 0 !important;
  }
  #chat-send .send-label { display: none !important; }
  #chat-send .send-ico   { display: inline-flex !important; }
  #chat-send .send-ico svg { width: 16px !important; height: 16px !important; }

  /* Sessions popover spans the screen on phones. */
  .chat-sessions-pop {
    left: 4px !important;
    right: 4px !important;
    width: auto !important;
    max-width: none !important;
  }

  /* FAB sized for thumbs — sit above the home indicator. */
  .chat-toggle-fab,
  #chat-fab {
    bottom: max(12px, calc(env(safe-area-inset-bottom, 0px) + 8px));
    right: max(var(--sp-3, 12px), env(safe-area-inset-right, 0px));
    min-width: 56px;
    min-height: 56px;
    border-radius: 50%;
    box-shadow: var(--shadow-lg, 0 6px 18px rgba(0,0,0,0.35));
  }
}

/* ============================================================
   Phones portrait (<=480px)
   ============================================================ */
@media (max-width: 480px) {
  :root {
    --topbar-height: 52px;
  }
  .sidebar { width: 86vw; }
  body.sidebar-open .sidebar.collapsed,
  body.sidebar-open .sidebar { width: 86vw; }

  .lang-switcher { display: none; }   /* keep theme + ava dot only */
  .ava-status-dot { display: none; }
  .top-bar-actions { gap: 8px; }
  /* font-scale compact moved to touch-only block below */

  .content-left { padding: var(--sp-2, 8px); }

  /* Header keeps single row + horizontal-scroll behavior (defined in
   * chat.css). Just tighten typography for phone widths. */
  .chat-panel-title { font-size: var(--fs-md, 14px); }
  .chat-panel-actions { gap: 4px; }
  .chat-panel-btn { font-size: 12px; padding: 4px 8px; }

  /* ---- Phone fullscreen: any chat mode fills the entire viewport ----
   * Float/mini already become 70vh sheets at 768px; on phones we expand
   * every mode (dock/float/mini) to the full screen so the user always
   * gets a usable, full-width chat. The × button still closes it. */
  .content-right,
  .content-right.mode-dock,
  .content-right.mode-float,
  .content-right.mode-mini {
    position: fixed !important;
    inset: 0 !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    /* Defeat any ancestor `max-width` / `width: X%` constraints.
     * sidebar.css sets `.content-right { max-width: 100% }` which, when
     * the parent .content-wrapper is narrower than the viewport, would
     * pin the chat to that narrower box. Force the actual viewport size. */
    width: 100vw !important;
    min-width: 100vw !important;
    max-width: 100vw !important;
    height: 100vh !important;
    height: 100dvh !important;
    min-height: 100vh !important;
    min-height: 100dvh !important;
    max-height: 100vh !important;
    max-height: 100dvh !important;
    margin: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    border-radius: 0 !important;
    border: none !important;
    box-shadow: none !important;
    z-index: 9500 !important;
    /* Full-bleed panel; pad chrome via header/composer, not an outer gap. */
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0);
    box-sizing: border-box !important;
    /* Rest pose must NOT be !important — iOS will not interpolate or let
       WAAPI override an !important transform, so open snaps while close
       (adding .collapsed !important) still slides. */
    transform: translate3d(0, 0, 0);
    transition: transform var(--dur-sheet, 400ms) var(--ease-sheet, cubic-bezier(0.32, 0.72, 0, 1)) !important;
  }
  .content-right.closing,
  .content-right.mode-dock.closing,
  .content-right.mode-float.closing,
  .content-right.mode-mini.closing,
  #chat-drawer.closing {
    /* Close is a 240ms ease-in slide, not the 400ms open sheet curve. */
    animation: none !important;
    transition: transform 240ms cubic-bezier(0.4, 0, 1, 1) !important;
    width: 100vw !important;
    max-width: 100vw !important;
  }
  /* The chat-fab/close FAB sits on top — keep it tappable above chat. */
  .chat-toggle-fab, #chat-fab { z-index: 9600 !important; }
  /* Slide-down close when collapsed (preserve the dock animation). */
  .content-right.collapsed,
  .content-right.mode-dock.collapsed,
  .content-right.mode-float.collapsed,
  .content-right.mode-mini.collapsed {
    transform: translate3d(0, 100%, 0) !important;
  }
  /* Resizer/drag-grip make no sense at fullscreen. */
  .chat-resizer,
  .chat-drag-grip { display: none !important; }

  /* Research view sidebar collapses below */
  .research-shell,
  .research-layout {
    grid-template-columns: 1fr !important;
  }
  /* Board: 1 column at this size (research.css already does 1 col @640) — keep parity. */

  /* Tables in markets/portfolios — let them scroll horizontally instead of breaking layout. */
  .markets-table-wrap,
  .table-wrap,
  .scroll-x {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Forms (login/signup/settings) full-width inputs. */
  input, select, textarea, button {
    max-width: 100%;
  }
}

/* ============================================================
   Touch-only: kill hover effects that get "stuck" on tap.
   ============================================================ */
@media (hover: none) and (pointer: coarse) {
  .nav-item:hover,
  .card:hover,
  .board-card:hover {
    background: inherit;
  }
  .theme-toggle-btn:hover {
    transform: none;
  }
}

/* ============================================================
   Modal sizing on phones — make any dialog full-screen.
   ============================================================ */
@media (max-width: 640px) {
  .chat-modal-box,
  .mem-box {
    width: 100% !important;
    max-width: 100% !important;
    height: 100%;
    max-height: 100dvh;
    border-radius: 0 !important;
  }
}

/* ============================================================
   MOBILE-FIRST CHAT REDESIGN (phones / touch devices only)
   Header primary toolbar is owned by chat.css (≤768):
     sessions · tier · model · reset · ··· · ✕
   Do NOT iconify / restyle those buttons here — it fights the
   compact single-row layout. Sheet + composer tweaks only.
   ============================================================ */
@media (max-width: 480px) {

  /* Hide window-mode cluster (fullscreen chat on phones). */
  .chat-window-controls { display: none !important; }

  /* --- Composer: in-box tools + send; single-line floor, grows on type. */
  .chat-composer,
  .chat-input-row {
    padding: 10px !important;
    gap: 0 !important;
  }
  .chat-composer textarea,
  #chat-input,
  textarea.chat-input {
    font-size: 16px !important;   /* prevents iOS auto-zoom */
    min-height: calc(16px * 1.4 * 1.5 + 6px) !important;
    padding: 10px 12px 4px !important;
    line-height: 1.4 !important;
  }
  .chat-attach-toggle { display: none !important; }
  .chat-composer-bar .chat-action-btn {
    width: 36px !important;
    height: 36px !important;
  }
  #chat-send,
  button.chat-send,
  .chat-composer button[type="submit"] {
    width: 36px !important;
    min-width: 36px !important;
    max-width: 36px !important;
    height: 36px !important;
    min-height: 36px !important;
    max-height: 36px !important;
    font-size: 0 !important;
    border-radius: 50% !important;
    padding: 0 !important;
  }
  #chat-send .send-ico svg { width: 17px !important; height: 17px !important; }
}

/* ============================================================
   Profile / user-menu — phone + tablet bottom sheet
   Desktop keeps the sidebar popover. On narrow / touch we portal
   #user-menu to body (see base.html) and present a scrollable
   sheet so long admin lists are not clipped above the footer.
   Breakpoint matches _userMenuIsMobile() in base.html.
   ============================================================ */
@media (max-width: 1024px), (hover: none) and (pointer: coarse) {
  body.user-menu-open {
    overflow: hidden !important;
  }

  .user-menu-backdrop.visible,
  body > .user-menu-backdrop.visible {
    display: block !important;
    position: fixed;
    inset: 0;
    background: var(--overlay, rgba(0, 0, 0, 0.5));
    /* Above sidebar (1000) and open chat/tray; sheet sits one step higher. */
    z-index: 32000;
    opacity: 1;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
    animation: oc-fade-in var(--dur-ui, 200ms) var(--ease-out, ease);
  }

  /* Keep sheet geometry while .show is off so the close slide can play. */
  body > .user-menu.user-menu--sheet,
  .user-menu.user-menu--sheet {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    top: auto !important;
    width: 100vw !important;
    max-width: 100vw !important;
    min-width: 0 !important;
    height: auto !important;
    max-height: min(85dvh, 640px) !important;
    border-radius: 16px 16px 0 0 !important;
    border: 1px solid var(--border-default) !important;
    border-bottom: none !important;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.45) !important;
    background: var(--bg-elevated, #161b22) !important;
    color: var(--text-primary) !important;
    z-index: 32100 !important;
    margin: 0 !important;
    padding: 0 0 calc(10px + env(safe-area-inset-bottom, 0px)) 0 !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    transform: translateY(100%) !important;
    opacity: 1 !important;
    visibility: visible !important;
    pointer-events: none !important;
    transition: transform var(--dur-sheet, 320ms) var(--ease-out, ease) !important;
  }
  body > .user-menu.user-menu--sheet.show,
  .user-menu.user-menu--sheet.show {
    transform: translateY(0) !important;
    pointer-events: auto !important;
  }

  .user-menu.user-menu--sheet .user-menu-sheet-chrome {
    display: block !important;
    flex: 0 0 auto;
    padding: 0 4px 4px;
    border-bottom: 1px solid var(--border-default, #30363d);
  }
  .user-menu.user-menu--sheet .user-menu-handle {
    width: 36px;
    height: 4px;
    border-radius: 999px;
    background: var(--border-default, #30363d);
    margin: 10px auto 8px;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 12px 12px;
    min-width: 0;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-avatar {
    width: 40px;
    height: 40px;
    border-radius: 999px;
    background: var(--accent, #58a6ff);
    color: var(--text-inverse, #fff);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 16px;
    flex-shrink: 0;
    overflow: hidden;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-avatar .avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-meta {
    flex: 1 1 auto;
    min-width: 0;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-role {
    font-size: 12px;
    color: var(--text-muted);
    text-transform: capitalize;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-close {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 18px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    -webkit-tap-highlight-color: transparent;
  }
  .user-menu.user-menu--sheet .user-menu-sheet-close:active {
    background: var(--bg-elevated-2, #21262d);
  }

  .user-menu.user-menu--sheet .user-menu-body {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-x: hidden !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 6px 0 4px;
    /* Solid plate so list text never collides with page behind */
    background: var(--bg-elevated, #161b22);
  }

  .user-menu.user-menu--sheet .user-menu-item {
    min-height: 48px;
    padding: 12px 18px;
    font-size: 16px;
    gap: 14px;
    color: var(--text-primary) !important;
  }
  .user-menu.user-menu--sheet .user-menu-item:active {
    background: var(--bg-elevated-2, #21262d);
  }
  .user-menu.user-menu--sheet .user-menu-item .menu-icon {
    width: 24px;
    font-size: 18px;
  }
  /* Keyboard hint is secondary on phone sheets (pull-to-refresh is primary). */
  .user-menu.user-menu--sheet .user-menu-item .menu-kbd {
    font-size: 11px;
    opacity: 0.55;
  }
  .user-menu.user-menu--sheet .user-menu-divider {
    margin: 8px 16px;
  }
  .user-menu.user-menu--sheet .user-menu-item.logout {
    color: var(--danger) !important;
  }

  /* Sidebar profile row: clearer tap target on phones */
  .user-profile {
    min-height: 48px;
    padding: 8px 10px;
  }
  .user-profile:active {
    background: var(--bg-elevated-2, #21262d);
  }
}

/* ============================================================
   Chat bottom sheets (sessions / model / tier) — mobile friendly
   Matches JS portal breakpoint (max-width: 768). Loads after
   chat.css so these rules win over the older full-scroll sheets.
   Layout: sticky chrome · scrollable list · compact rows · no wall of help text.
   ============================================================ */
@media (max-width: 768px) {
  body.chat-sheet-open {
    overflow: hidden !important;
  }
  /* JS toggles .chat-sheet-open. Do not also key off :has(.open) — iOS
     kept that dimmer after the chat closed (page gray, taps dead). */
  body.chat-sheet-open::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    /* Above open chat (27000), command tray (28000), tools dimmer (29500),
       tools tray (30000). Sheets themselves sit one step higher. */
    z-index: 30500;
    pointer-events: auto;
    animation: chatBackdropIn var(--dur-ui, 280ms) var(--ease-out, ease);
  }
  @keyframes chatBackdropIn {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  @keyframes chatSheetUp {
    from { transform: translateY(110%); }
    to   { transform: translateY(0); }
  }
  @keyframes chatSheetDown {
    from { transform: translateY(0); }
    to   { transform: translateY(110%); }
  }

  /* Portaled (body >) or in-tree: compact bottom sheet */
  body > .chat-model-pop.open,
  body > .chat-tier-pop.open,
  body > .chat-sessions-pop.open,
  .chat-model-pop.open,
  .chat-tier-pop.open,
  .chat-sessions-pop.open {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    top: auto !important;
    width: 100vw !important;
    max-width: 100vw !important;
    min-width: 0 !important;
    height: auto !important;
    /* Cap height so chrome + list stay usable; list scrolls inside. */
    max-height: min(72dvh, 560px) !important;
    border-radius: 16px 16px 0 0 !important;
    border: 1px solid var(--border-default) !important;
    border-bottom: none !important;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.4) !important;
    background: var(--bg-elevated) !important;
    color: var(--text-primary) !important;
    z-index: 31000 !important;
    margin: 0 !important;
    list-style: none !important;
    display: flex !important;
    flex-direction: column !important;
    /* Outer sheet does NOT scroll — list body does. */
    overflow: hidden !important;
    padding: 0 0 calc(10px + env(safe-area-inset-bottom, 0px)) 0 !important;
    visibility: visible !important;
    pointer-events: auto !important;
    opacity: 1 !important;
    animation: chatSheetUp var(--dur-sheet, 440ms) var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1));
  }
  body > .chat-model-pop.open.is-leaving,
  body > .chat-tier-pop.open.is-leaving,
  body > .chat-sessions-pop.open.is-leaving,
  .chat-model-pop.open.is-leaving,
  .chat-tier-pop.open.is-leaving,
  .chat-sessions-pop.open.is-leaving {
    animation: chatSheetDown var(--dur-sheet, 440ms) var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1)) forwards !important;
    pointer-events: none !important;
  }

  body > .chat-model-pop.open::before,
  body > .chat-tier-pop.open::before,
  body > .chat-sessions-pop.open::before,
  .chat-model-pop.open::before,
  .chat-tier-pop.open::before,
  .chat-sessions-pop.open::before {
    content: "";
    display: block;
    flex: 0 0 auto;
    width: 36px;
    height: 4px;
    background: var(--border-default);
    border-radius: 999px;
    margin: 8px auto 6px auto;
  }
  .chat-model-pop:not(.open)::before,
  .chat-tier-pop:not(.open)::before,
  .chat-sessions-pop:not(.open)::before {
    display: none !important;
  }

  /* ── Sessions sheet ─────────────────────────────────────────── */
  .chat-sessions-pop.open .sess-chrome {
    flex: 0 0 auto !important;
    position: relative !important;
    top: auto !important;
    z-index: 2;
    background: var(--bg-elevated) !important;
    border-bottom: 1px solid var(--border-default);
  }
  .chat-sessions-pop.open .sess-head {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 8px !important;
    padding: 8px 14px 6px !important;
    font-size: 12px !important;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary) !important;
    background: var(--bg-elevated) !important;
    border-bottom: none !important;
  }
  .chat-sessions-pop.open .sess-head .sess-new {
    min-height: 36px !important;
    padding: 0 12px !important;
    font-size: 14px !important;
    border-radius: 8px !important;
  }
  /* Search + prev/next: keep flip controls always visible */
  .chat-sessions-pop.open .sess-toolbar {
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
    padding: 6px 12px 10px !important;
    background: var(--bg-elevated) !important;
    border-bottom: none !important;
  }
  .chat-sessions-pop.open .sess-search {
    min-height: 40px !important;
    font-size: 16px !important; /* no iOS zoom */
    padding: 8px 32px 8px 28px !important;
    border-radius: 10px !important;
  }
  .chat-sessions-pop.open .sess-nav {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 10px !important;
    width: 100%;
  }
  .chat-sessions-pop.open .sess-nav-btn {
    flex: 1 1 0 !important;
    width: auto !important;
    min-width: 0 !important;
    height: 44px !important;
    min-height: 44px !important;
    font-size: 28px !important;
    line-height: 1 !important;
    border-radius: 10px !important;
    border: 1px solid var(--border-default) !important;
    background: var(--bg-elevated-2, var(--bg-base)) !important;
    color: var(--text-primary) !important;
  }
  .chat-sessions-pop.open .sess-nav-btn:disabled {
    opacity: 0.35 !important;
  }
  .chat-sessions-pop.open .sess-nav-pos {
    flex: 0 0 auto !important;
    min-width: 4.5em !important;
    font-size: 13px !important;
    font-weight: 600;
    color: var(--text-secondary) !important;
  }

  /* Scrollable session list only */
  .chat-sessions-pop.open .sess-list,
  .chat-sessions-pop.open > ul.sess-list {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow-x: hidden !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    margin: 0 !important;
    padding: 0 !important;
    list-style: none !important;
  }
  /* Empty / loading state between chrome and foot */
  .chat-sessions-pop.open > .empty {
    flex: 1 1 auto !important;
    min-height: 80px;
    overflow-y: auto;
    padding: 16px !important;
  }
  .chat-sessions-pop.open .sess-more-wrap {
    flex: 0 0 auto !important;
    padding: 8px 12px !important;
    border-top: 1px solid var(--border-muted);
    background: var(--bg-elevated);
  }
  .chat-sessions-pop.open .sess-more {
    min-height: 44px !important;
    font-size: 14px !important;
    border-radius: 10px !important;
  }

  /* Kill the long help wall — it was eating the whole sheet on phones. */
  .chat-sessions-pop.open .sess-foot {
    display: none !important;
  }

  /* Compact session rows — single-line title + meta, no wrap explosion */
  .chat-sessions-pop.open li {
    min-height: 0 !important;
    max-height: none !important;
  }
  .chat-sessions-pop.open li.sess {
    display: flex !important;
    flex-direction: row !important;
    align-items: center !important;
    gap: 8px !important;
    padding: 10px 12px !important;
    min-height: 52px !important;
    border-bottom: 1px solid var(--border-soft, var(--border-muted)) !important;
    box-sizing: border-box;
  }
  .chat-sessions-pop.open li.sess-group {
    min-height: 0 !important;
    padding: 10px 12px 6px !important;
    font-size: 11px !important;
    border-bottom: none !important;
  }
  .chat-sessions-pop.open .s-main {
    flex: 1 1 auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 2px !important;
    overflow: hidden !important;
  }
  .chat-sessions-pop.open .s-label {
    display: block !important;
    flex: 0 1 auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    line-height: 1.25 !important;
    color: var(--text-primary) !important;
  }
  .chat-sessions-pop.open .s-meta {
    display: flex !important;
    gap: 8px !important;
    min-width: 0 !important;
    overflow: hidden !important;
    font-size: 11px !important;
    color: var(--text-muted) !important;
  }
  .chat-sessions-pop.open .s-when,
  .chat-sessions-pop.open .s-rel {
    flex: 0 1 auto !important;
    min-width: 0 !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
    font-size: 11px !important;
  }
  /* Local simpler layout (date left of label, no .s-main) */
  .chat-sessions-pop.open li.sess > .s-when {
    flex: 0 0 52px !important;
    min-width: 52px !important;
    font-size: 11px !important;
  }
  .chat-sessions-pop.open li.sess > .s-label {
    flex: 1 1 auto !important;
  }
  .chat-sessions-pop.open .s-rename,
  .chat-sessions-pop.open .s-del {
    flex: 0 0 auto !important;
    opacity: 1 !important;
    min-width: 40px !important;
    min-height: 40px !important;
    width: 40px !important;
    height: 40px !important;
    font-size: 18px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    border-radius: 8px !important;
  }
  .chat-sessions-pop.open li.sess.active {
    background: color-mix(in srgb, var(--accent) 14%, var(--bg-elevated)) !important;
  }
  .chat-sessions-pop.open .s-rename-input {
    font-size: 16px !important;
    min-height: 36px !important;
  }

  /* ── Model / tier sheets — <ul> is the scroll container ──────────
     iOS needs overflow-y:scroll, no residual transform, pan-y. */
  body > .chat-model-pop.open,
  body > .chat-tier-pop.open,
  .chat-model-pop.open,
  .chat-tier-pop.open {
    display: block !important;
    overflow-x: hidden !important;
    overflow-y: scroll !important;
    -webkit-overflow-scrolling: touch !important;
    overscroll-behavior: contain !important;
    touch-action: pan-y !important;
    max-height: min(70dvh, 560px) !important;
    animation: none !important;
    transform: none !important;
  }
  .chat-model-pop.open li,
  .chat-tier-pop.open li {
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    flex-shrink: 0 !important;
    min-height: 48px !important;
    padding: 10px 16px !important;
    font-size: 15px !important;
    line-height: 1.3 !important;
    border-bottom: 1px solid var(--border-soft, var(--border-muted)) !important;
    color: var(--text-primary) !important;
    box-sizing: border-box;
  }
  .chat-model-pop.open li.grp,
  .chat-tier-pop.open li.grp {
    min-height: 0 !important;
    padding: 10px 16px 4px !important;
    font-size: 11px !important;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted) !important;
    border-bottom: none !important;
    pointer-events: none;
  }
  .chat-model-pop.open li.mdl .m-label,
  .chat-tier-pop.open li.mdl .m-label {
    display: block !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    color: var(--text-primary) !important;
  }
  .chat-model-pop.open li.mdl .m-id,
  .chat-tier-pop.open li.mdl .m-id {
    display: block !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
    font-size: 11px !important;
    color: var(--text-muted) !important;
  }
  .chat-model-pop.open li.mdl.active,
  .chat-tier-pop.open li.mdl.active {
    background: color-mix(in srgb, var(--accent) 12%, var(--bg-elevated)) !important;
    border-left: 3px solid var(--accent);
  }
  .chat-model-pop.open li.mdl.active .m-label,
  .chat-tier-pop.open li.mdl.active .m-label {
    color: var(--accent) !important;
  }
  .chat-model-pop.open li.mdl-foot,
  .chat-tier-pop.open li.mdl-foot {
    min-height: 0 !important;
    font-size: 12px !important;
    line-height: 1.35 !important;
    color: var(--text-muted) !important;
    border-bottom: none !important;
    background: var(--bg-elevated) !important;
    position: sticky !important;
    bottom: 0 !important;
  }
  /* Long model-foot help: clamp so it can't dominate the sheet */
  .chat-model-pop.open li.mdl-foot,
  .chat-tier-pop.open li.mdl-foot {
    max-height: 4.2em !important;
    overflow: hidden !important;
    display: -webkit-box !important;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
  }
}

/* ============================================================
   iOS Safari bottom cutoff fix — covers iPhone + iPad Safari.
   - Use dynamic viewport height (100dvh) so retracting URL bar
     does not push content off-screen.
   - Honor safe-area-inset-bottom so the user-profile / composer
     clear the home-indicator and bottom toolbar.
   ============================================================ */
@media (max-width: 1024px) {
  /* Outer shell: use dvh where available so layout shrinks with
     iOS Safari toolbar. Fall back to vh. */
  .app-layout {
    min-height: 100vh;
    min-height: 100dvh;
  }
  .sidebar {
    height: 100vh;
    height: 100dvh;
  }
  /* Pad sidebar footer so the user-profile row clears the home
     indicator / Safari bottom toolbar on iOS. */
  .sidebar-footer {
    padding-bottom: calc(var(--sp-3, 12px) + env(safe-area-inset-bottom, 0)) !important;
  }
  /* Ensure the sidebar nav itself can scroll if content + footer
     exceed the visible viewport. */
  .sidebar-nav {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* Phone fullscreen chat: composer needs safe-area padding so the
   input row & send button are not hidden behind the iOS toolbar. */
@media (max-width: 480px) {
  .content-right .chat-panel,
  .content-right > .chat-panel,
  .chat-panel {
    /* If the chat panel is the root flex column inside content-right,
       reserve space at the bottom for the home indicator. */
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  /* The composer is the bottom-most child; lift it above the
     home-indicator strip. */
  .chat-composer,
  .chat-input-row {
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0)) !important;
  }
}

/* iPad portrait / landscape Safari: sidebar is hidden behind the
   hamburger drawer at narrow widths, but at 768–1024 it may still
   render — give its footer the same safe-area treatment. */
@media (min-width: 481px) and (max-width: 1024px) {
  .content-right.mode-float,
  .content-right.mode-dock {
    /* Don't let docked/floating chat overflow off the bottom on iPad. */
    max-height: calc(100dvh - var(--topbar-height, 56px));
  }
  .content-right .chat-composer,
  .content-right .chat-input-row {
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0)) !important;
  }
}

/* ============================================================
   iOS Safari / iPadOS Chrome bottom cutoff — universal fix
   Applies to ALL touch devices regardless of viewport width.
   iPadOS landscape can be 1366px+ so width queries miss them.
   ============================================================ */
@media (hover: none) and (pointer: coarse) {
  /* Force every viewport-height-relative chat surface to use the
     *dynamic* viewport height (shrinks with browser toolbar). */
  .content-right.mode-dock {
    height: calc(100dvh - var(--topbar-height, 56px)) !important;
    max-height: calc(100dvh - var(--topbar-height, 56px)) !important;
  }
  .content-right.mode-float {
    /* Float panel: keep top offset, but constrain bottom to visible
       viewport accounting for safe-area inset. Clip chrome so only
       the log scrolls (header must not leave the panel). */
    max-height: calc(100dvh - 104px - env(safe-area-inset-bottom, 0)) !important;
    bottom: calc(24px + env(safe-area-inset-bottom, 0)) !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    min-height: 0 !important;
  }
  .content-right.mode-mini {
    max-height: calc(100dvh - 80px - env(safe-area-inset-bottom, 0)) !important;
    bottom: calc(16px + env(safe-area-inset-bottom, 0)) !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    min-height: 0 !important;
  }

  /* Make .content-right a proper flex column so the input row stays
     pinned to the bottom of the visible area, and #chat-log scrolls. */
  .content-right {
    display: flex !important;
    flex-direction: column !important;
    overflow: hidden !important;
    min-height: 0 !important;
  }
  .content-right > .chat-panel-header,
  #chat-drawer > .chat-panel-header {
    flex: 0 0 auto !important;
    flex-shrink: 0 !important;
    position: relative !important;
    top: auto !important;
    z-index: 200 !important;
    background: var(--bg-elevated, #161b22) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none !important;
    opacity: 1 !important;
    transform: none !important;
    will-change: auto !important;
  }
  #chat-log,
  .chat-log,
  .content-right > #chat-log,
  .content-right > .chat-log {
    flex: 1 1 0 !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    position: relative;
    z-index: 1;
  }
  /* Pin input row at bottom with safe-area padding (home indicator). */
  .content-right > .chat-input-row,
  .chat-input-row {
    flex-shrink: 0 !important;
    padding-bottom: calc(8px + env(safe-area-inset-bottom, 0)) !important;
    background: var(--bg-elevated);
  }

  /* Outer shell: use dvh so the entire page doesn't extend behind
     the browser toolbar (which would also push the sidebar footer
     off-screen). */
  .app-layout {
    min-height: 100dvh !important;
  }
  .sidebar {
    height: 100dvh !important;
  }
  .sidebar-footer {
    padding-bottom: calc(var(--sp-3, 12px) + env(safe-area-inset-bottom, 0)) !important;
  }
}

/* Phone-specific fullscreen chat already uses 100dvh — also force
   its inner column structure for input pinning. */
@media (max-width: 480px) {
  .content-right,
  .content-right.mode-dock,
  .content-right.mode-float,
  .content-right.mode-mini {
    display: flex !important;
    flex-direction: column !important;
    overflow: hidden !important;
    min-height: 0 !important;
  }
  .content-right > .chat-panel-header,
  #chat-drawer > .chat-panel-header {
    flex: 0 0 auto !important;
    flex-shrink: 0 !important;
    position: relative !important;
    top: auto !important;
    z-index: 200 !important;
    background: var(--bg-elevated, #161b22) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none !important;
    opacity: 1 !important;
    transform: none !important;
    will-change: auto !important;
  }
  .content-right > #chat-log,
  .content-right > .chat-log {
    flex: 1 1 0 !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    position: relative;
    z-index: 1;
  }
  .content-right > .chat-input-row {
    flex-shrink: 0 !important;
  }
}

/* ============================================================
   Lock the page itself on touch devices — no body rubber-band /
   no whitespace strip appearing when the iOS toolbar retracts.
   The page is now a fixed frame; only inner panes scroll.
   ============================================================ */
@media (hover: none) and (pointer: coarse) {
  html, body {
    height: 100vh;
    height: 100dvh;
    max-height: 100vh;
    max-height: 100dvh;
    overflow: hidden !important;
    overscroll-behavior: none;
    position: fixed;
    width: 100%;
    top: 0;
    left: 0;
  }
  /* The main app shell must fit exactly within the viewport. */
  .app-layout {
    height: 100vh;
    height: 100dvh;
    max-height: 100vh;
    max-height: 100dvh;
    overflow: hidden;
  }
  /* The main content area scrolls internally instead. */
  .main-content,
  .content-wrapper {
    height: 100%;
    max-height: 100%;
    overflow: hidden;
  }
  .content-left {
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
}

/* ==========================================================================
   Phase 2 — forms / shell / admin mobile hardening (ADDITIVE).
   Scoped to touch devices and small widths only, so the gated desktop /
   tablet-landscape viewports are never affected.
   ========================================================================== */

/* iOS Safari zooms the whole page when a focused input has font-size < 16px.
   Apply 16px to every form field on small / touch viewports — never on the
   gated desktop + tablet-landscape (>=1180px) widths. The width clause makes
   it verifiable in emulation; the touch clause also covers landscape phones
   (>820px wide but still touch). Extends the chat composer's existing fix to
   login / signup / settings / account / admin / search and every other form. */
@media (max-width: 820px), (hover: none) and (pointer: coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea {
    /* !important: many components (.cal-select, .tr-select, .an-input,
       .research-select, #th-chat-input, #im-input, …) set their own smaller
       font-size with higher specificity, which would still trigger iOS zoom.
       The override is mobile-scoped so desktop is unaffected. */
    font-size: 16px !important;
  }
}

/* Comfortable tap targets (Apple HIG >= 44px) for the shared shell controls
   (sidebar nav + top bar) that were undersized. Width-scoped so it's
   verifiable and desktop-safe. */
@media (max-width: 820px) {
  .sidebar-mobile-trigger {
    width: 44px;
    height: 44px;
  }
  /* Primary navigation: each nav row a full 44px tap target. */
  .sidebar .nav-item {
    min-height: 44px;
  }
  /* Shell icon/text controls (top bar + sidebar footer menu): 44px hit area.
     These classes exist only in the shell, so bare selectors are safe and the
     whole block is mobile-scoped. */
  .theme-toggle-btn,
  .tb-fs-btn,
  .user-menu-toggle,
  .lang-pop-btn,
  .feedback-btn-minimal {
    min-height: 44px;
    min-width: 44px;
  }
  .font-scale-ctrl {
    height: 44px;
  }
  .font-scale-btn {
    min-width: 40px;
    min-height: 44px;
  }
  .font-scale-pct {
    min-height: 44px;
    min-width: 44px;
  }
  /* Brand/home link in the sidebar header — a real nav target. */
  .sidebar-brand {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
}

/* Admin tables are dense and wide; on phones let each one scroll horizontally
   inside its own box instead of pushing the page sideways. (Admins normally
   work on desktop, so this is a safety net; verify on-device when an admin
   account is available.) */
@media (max-width: 640px) {
  table.ab-tbl, table.ac-tbl, table.ao-tbl, table.ar-tbl,
  table.au-tbl, table.fb-tbl, table.hb-tbl {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
  }
  /* Admin "new team" inline form: stack its inputs/button so the row doesn't
     overflow the phone width. */
  .admin-new-team {
    flex-wrap: wrap;
  }
  .admin-new-team input,
  .admin-new-team select {
    flex: 1 1 100%;
    min-width: 0;
    max-width: 100%;
  }
}

/* ============================================================
   iPhone / Capacitor shell polish (Dynamic Island + bottom composer)
   ============================================================ */

/* Top chrome: prefer --sat-fix (JS polyfill) so controls clear the island
   even when env(safe-area-inset-top) is 0 inside WKWebView. */
.top-bar {
  padding-top: var(--sat-fix, env(safe-area-inset-top, 0px)) !important;
  min-height: calc(var(--topbar-height, 56px) + var(--sat-fix, env(safe-area-inset-top, 0px))) !important;
  height: auto !important;
  max-height: none !important;
  box-sizing: border-box !important;
}
.sidebar-header {
  padding-top: var(--sat-fix, env(safe-area-inset-top, 0px)) !important;
  min-height: calc(var(--topbar-height, 56px) + var(--sat-fix, env(safe-area-inset-top, 0px))) !important;
  height: auto !important;
  box-sizing: border-box !important;
}

/* Phone / touch: pin chat composer to the physical bottom. Empty-session
   mode otherwise uses margin-bottom:auto which floats the input mid-panel. */
@media (max-width: 820px), (hover: none) and (pointer: coarse) {
  .content-right.is-empty-session .chat-empty-welcome {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
    flex: 1 1 auto !important;
    justify-content: center !important;
  }
  .content-right.is-empty-session .chat-input-row {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
  }

  /* Fullscreen chat: no outer bottom gap — safe-area lives on the input row. */
  .content-right,
  .content-right.mode-dock,
  .content-right.mode-float,
  .content-right.mode-mini {
    padding-bottom: 0 !important;
  }

  .content-right > .chat-input-row,
  .chat-input-row {
    margin-bottom: 0 !important;
    flex-shrink: 0 !important;
    padding-bottom: max(10px, var(--sab-fix, env(safe-area-inset-bottom, 0px))) !important;
    padding-left: max(8px, env(safe-area-inset-left, 0px)) !important;
    padding-right: max(8px, env(safe-area-inset-right, 0px)) !important;
    background: var(--bg-elevated) !important;
  }

  /* FAB sits just above the home indicator, not floating mid-air. */
  .chat-toggle-fab,
  #chat-fab {
    bottom: max(12px, calc(var(--sab-fix, env(safe-area-inset-bottom, 0px)) + 8px)) !important;
  }

  /* Fullscreen phone chat: top pad uses polyfill too. */
  @media (max-width: 480px) {
    .content-right,
    .content-right.mode-dock,
    .content-right.mode-float,
    .content-right.mode-mini {
      padding-top: var(--sat-fix, env(safe-area-inset-top, 0px)) !important;
    }
  }
}

/* ============================================================
   Touch / mobile app — slightly larger hit targets on the same
   minimal icon language used on desktop (32px circles).
   ============================================================ */
@media (hover: none) and (pointer: coarse) {
  .top-bar .font-scale-ctrl,
  .top-bar .lang-pop-btn,
  .top-bar .theme-toggle-btn,
  .top-bar .tb-fs-btn,
  .top-bar .feedback-btn-minimal,
  .top-bar .oc-cmdp-trigger,
  .top-bar .ask-oceanus-btn {
    width: 36px;
    height: 36px;
    min-width: 36px;
  }
  .top-bar .lang-pop-flag {
    font-size: 18px;
    line-height: 1;
  }
  .top-bar-actions {
    gap: 6px !important;
  }
}

/* ============================================================
   Touch / mobile app — sliding top tools tray (collapsed by default)
   Desktop browser keeps a normal inline top-bar-actions row.
   ============================================================ */
.top-bar-tools-toggle,
.top-bar-tools-close {
  display: none;
}

@media (max-width: 820px), (hover: none) and (pointer: coarse) {
  .top-bar {
    gap: 8px;
    /* Base chrome above page content. When tools open we raise this so the
       fixed tray escapes the body dimmer stacking trap (see below). */
    z-index: 1200;
  }
  body.topbar-tools-open .top-bar {
    /* Must beat body.topbar-tools-open::after (dimmer). The tray is a
       position:fixed child of .top-bar, so it lives in this stacking
       context — if .top-bar stays at 1200 and dimmer is 1250, clicks hit
       the dimmer and tray buttons appear dead. */
    z-index: 1400;
  }
  /* Slim page title — same metrics as Dashboard greeting */
  .top-bar-title-wrap {
    flex: 1 1 auto;
    min-width: 0;
    flex-direction: row;
    align-items: center;
    overflow: hidden;
  }
  .top-bar-title {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--fs-sm, 12px) !important;
    line-height: 1 !important;
    font-weight: var(--fw-medium, 500);
  }
  .top-bar-title-wrap .top-bar-subtitle,
  .top-bar .page-subtitle {
    display: none !important;
  }

  .top-bar-tools-toggle {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    min-width: 36px;
    padding: 0;
    margin: 0;
    border: 1px solid var(--border-default, #30363d);
    border-radius: 999px;
    background: var(--bg-elevated, #161b22);
    color: var(--text-primary, #e6edf3);
    cursor: pointer;
    flex-shrink: 0;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  .top-bar-tools-toggle__icon {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1;
    transform: translateY(-2px);
  }
  .top-bar.tools-open .top-bar-tools-toggle {
    border-color: var(--accent, #58a6ff);
    color: var(--accent, #58a6ff);
  }

  /* Tray: off-canvas to the right by default */
  .top-bar-actions {
    position: fixed !important;
    top: calc(var(--sat-fix, env(safe-area-inset-top, 0px)) + 6px);
    left: auto;
    bottom: auto;
    z-index: 1410;
    display: flex !important;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    padding-right: max(10px, env(safe-area-inset-right, 0px));
    max-width: calc(100vw - 24px);
    /* visible so .lang-pop-menu is not clipped; no capture of child clicks */
    overflow: visible !important;
    -webkit-overflow-scrolling: touch;
    background: var(--chrome-fill, color-mix(in srgb, var(--bg-elevated, #161b22) 96%, transparent));
    border: 0.5px solid var(--chrome-edge, var(--border-default, #30363d));
    border-radius: 999px;
    box-shadow: var(--chrome-shadow, 0 10px 28px rgba(0, 0, 0, 0.35));
    backdrop-filter: var(--chrome-filter, blur(16px) saturate(1.2));
    -webkit-backdrop-filter: var(--chrome-filter, blur(16px) saturate(1.2));
    /* Slide with `right`, not transform: WebKit clips overflow:visible
       descendants (lang/theme menus) inside a transformed rounded pill. */
    right: calc(-100% - 24px);
    opacity: 0;
    pointer-events: none;
    transition: right 220ms cubic-bezier(0.2, 0.8, 0.2, 1),
                opacity 180ms ease;
  }
  .top-bar.tools-open .top-bar-actions {
    right: 8px;
    opacity: 1;
    pointer-events: auto;
  }
  /* Ensure every control in the tray is tappable */
  .top-bar.tools-open .top-bar-actions button,
  .top-bar.tools-open .top-bar-actions a,
  .top-bar.tools-open .top-bar-actions .lang-pop,
  .top-bar.tools-open .top-bar-actions .theme-pop,
  .top-bar.tools-open .top-bar-actions .font-scale-ctrl {
    pointer-events: auto !important;
    position: relative;
    z-index: 1;
  }
  .top-bar.tools-open .top-bar-actions .lang-pop,
  .top-bar.tools-open .top-bar-actions .theme-pop {
    position: relative;
    z-index: 2;
  }
  /* Language / theme menus must paint above the pill tray + dimmer.
     Scope to the tray: the same menus now live in the sidebar strip. */
  .top-bar.tools-open .top-bar-actions .lang-pop-menu,
  .top-bar.tools-open .top-bar-actions .theme-pop-menu {
    z-index: 1600 !important;
    position: absolute !important;
    top: calc(100% + 8px) !important;
    right: 0 !important;
    min-width: 200px !important;
  }

  .top-bar-tools-close {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    min-width: 28px;
    border: 0;
    border-radius: 999px;
    background: var(--bg-elevated-2, #21262d);
    color: var(--text-secondary, #9ba3af);
    font-size: 12px;
    cursor: pointer;
    flex-shrink: 0;
    order: 99;
    touch-action: manipulation;
  }

  /* No full-page blackout. Outside taps still close the tray. */
  body.topbar-tools-open::after {
    content: none;
    background: transparent;
    pointer-events: none;
  }

  /* Command palette / Ask Oceanus: icon-only in the tray */
  .top-bar .oc-cmdp-trigger__label,
  .top-bar .oc-cmdp-trigger__kbd,
  .top-bar .ask-oceanus-btn__label {
    display: none !important;
  }
  .top-bar .oc-cmdp-trigger,
  .top-bar .ask-oceanus-btn {
    width: 36px !important;
    min-width: 36px !important;
    height: 36px !important;
    padding: 0 !important;
    justify-content: center !important;
    border-radius: 999px !important;
    gap: 0 !important;
  }
}


/* ============================================================
   Chat tools tray — same style as main top-bar (lang/font) tray.
   Open = #chat-panel-actions.is-open OR body.chat-tools-open.
   Applied for touch devices AND narrow widths (not only hover:none).
   ============================================================ */
@media (hover: none) and (pointer: coarse), (max-width: 820px) {
  #chat-drawer .chat-panel-header,
  .content-right .chat-panel-header {
    gap: 8px;
    z-index: 1200;
    overflow: visible !important;
  }
  body.chat-tools-open #chat-drawer .chat-panel-header,
  #chat-panel-header.tools-open {
    z-index: 1400;
  }
  #chat-drawer .chat-panel-title,
  .content-right .chat-panel-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 15px !important;
  }

  /* ··· toggle — clone of top-bar-tools-toggle */
  #chat-actions-toggle,
  .chat-actions-toggle {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 36px !important;
    height: 36px !important;
    min-width: 36px !important;
    padding: 0 !important;
    margin: 0 !important;
    border: 1px solid var(--border-default, #30363d) !important;
    border-radius: 999px !important;
    background: var(--bg-elevated, #161b22) !important;
    color: var(--text-primary, #e6edf3) !important;
    cursor: pointer;
    flex-shrink: 0;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    font-size: inherit !important;
    line-height: 1 !important;
  }
  .chat-actions-toggle__icon {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1;
    transform: translateY(-2px);
    pointer-events: none; /* clicks hit the button, not the span */
  }
  body.chat-tools-open .chat-actions-toggle,
  #chat-panel-header.tools-open .chat-actions-toggle {
    border-color: var(--accent, #58a6ff) !important;
    color: var(--accent, #58a6ff) !important;
    /* Above dimmer (29500) so ··· still closes the tray */
    position: relative;
    z-index: 30100 !important;
  }

  .chat-panel-header > #chat-close {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 36px !important;
    height: 36px !important;
    min-width: 36px !important;
    padding: 0 !important;
    border-radius: 999px !important;
    font-size: 15px !important;
    flex-shrink: 0;
    z-index: 2;
  }

  /* Collapsed: tray off-canvas to the right (fixed pill).
     z must sit ABOVE open chat sheet (27000) and command tray (28000),
     otherwise the ··· menu paints under the fullscreen chat and looks dead. */
  #chat-panel-actions {
    position: fixed !important;
    top: calc(var(--sat-fix, env(safe-area-inset-top, 0px)) + 6px) !important;
    right: 8px !important;
    left: auto !important;
    bottom: auto !important;
    z-index: 30000 !important;
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    gap: 8px !important;
    padding: 8px 10px !important;
    padding-right: max(10px, env(safe-area-inset-right, 0px)) !important;
    max-width: calc(100vw - 24px) !important;
    width: max-content !important;
    min-width: 0 !important;
    margin: 0 !important;
    overflow-x: auto !important;
    overflow-y: visible !important;
    -webkit-overflow-scrolling: touch;
    background: var(--chrome-fill, color-mix(in srgb, var(--bg-elevated, #161b22) 96%, transparent)) !important;
    border: 0.5px solid var(--chrome-edge, var(--border-default, #30363d)) !important;
    border-radius: 999px !important;
    box-shadow: var(--chrome-shadow, 0 10px 28px rgba(0, 0, 0, 0.35)) !important;
    backdrop-filter: var(--chrome-filter, blur(16px) saturate(1.2));
    -webkit-backdrop-filter: var(--chrome-filter, blur(16px) saturate(1.2));
    transform: translateX(calc(100% + 32px)) !important;
    opacity: 0 !important;
    pointer-events: none !important;
    visibility: visible !important;
    transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1),
                opacity 180ms ease !important;
    flex: 0 0 auto !important;
  }

  /* OPEN — class on the tray itself (works after portal to body) */
  #chat-panel-actions.is-open,
  body.chat-tools-open #chat-panel-actions {
    transform: translateX(0) !important;
    opacity: 1 !important;
    pointer-events: auto !important;
    visibility: visible !important;
  }

  #chat-panel-actions.is-open > *,
  body.chat-tools-open #chat-panel-actions > * {
    display: inline-flex !important;
    pointer-events: auto !important;
    position: relative !important;
    flex: 0 0 auto !important;
    opacity: 1 !important;
    visibility: visible !important;
  }
  #chat-panel-actions.is-open > .chat-tier-wrap,
  #chat-panel-actions.is-open > .chat-model-wrap,
  body.chat-tools-open #chat-panel-actions > .chat-tier-wrap,
  body.chat-tools-open #chat-panel-actions > .chat-model-wrap {
    display: inline-flex !important;
  }
  #chat-panel-actions.is-open .chat-panel-btn,
  #chat-panel-actions.is-open .chat-tier-btn,
  #chat-panel-actions.is-open .chat-model-btn,
  body.chat-tools-open #chat-panel-actions .chat-panel-btn,
  body.chat-tools-open #chat-panel-actions .chat-tier-btn,
  body.chat-tools-open #chat-panel-actions .chat-model-btn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    height: 32px !important;
    min-height: 32px !important;
    padding: 0 10px !important;
    border-radius: 999px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    white-space: nowrap !important;
    max-width: 120px !important;
    color: var(--text-primary) !important;
    background: var(--bg-elevated-2, var(--bg-base)) !important;
    border: 1px solid var(--border-default) !important;
    opacity: 1 !important;
  }
  #chat-panel-actions.is-open #chat-tier-label,
  #chat-panel-actions.is-open #chat-model-label,
  body.chat-tools-open #chat-panel-actions #chat-tier-label,
  body.chat-tools-open #chat-panel-actions #chat-model-label {
    max-width: 72px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .chat-actions-close { display: none !important; }
  #chat-panel-actions.is-open .chat-actions-close,
  body.chat-tools-open .chat-actions-close {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 28px !important;
    height: 28px !important;
    min-width: 28px !important;
    border: 0 !important;
    border-radius: 999px !important;
    background: var(--bg-elevated-2, #21262d) !important;
    color: var(--text-secondary, #9ba3af) !important;
    font-size: 12px !important;
    padding: 0 !important;
    order: 99;
    touch-action: manipulation;
  }

  /* Mobile tray: sessions / tier / model / more only (plus tray close).
     Layout (dock/float/…) is desktop-only — window modes don't apply on phone. */
  #chat-panel-actions.is-open > .chat-layout-wrap,
  #chat-panel-actions.is-open > .chat-more-wrap,
  body.chat-tools-open #chat-panel-actions > .chat-layout-wrap,
  body.chat-tools-open #chat-panel-actions > .chat-more-wrap {
    display: none !important;
  }
  /* On mobile, surface reset/memory/plan/export as direct tray buttons
     (they live inside .chat-more-pop on desktop). */
  #chat-panel-actions.is-open .chat-more-pop,
  body.chat-tools-open #chat-panel-actions .chat-more-pop {
    display: contents !important;
    position: static !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    min-width: 0 !important;
    background: transparent !important;
  }
  #chat-panel-actions.is-open .chat-more-pop .chat-menu-item,
  body.chat-tools-open #chat-panel-actions .chat-more-pop .chat-menu-item {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    height: 32px !important;
    min-height: 32px !important;
    padding: 0 10px !important;
    border-radius: 999px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    white-space: nowrap !important;
    max-width: 120px !important;
    color: var(--text-primary) !important;
    background: var(--bg-elevated-2, var(--bg-base)) !important;
    border: 1px solid var(--border-default) !important;
    grid-template-columns: none !important;
    width: auto !important;
  }
  #chat-panel-actions.is-open .chat-more-pop .chat-menu-hint,
  #chat-panel-actions.is-open .chat-more-pop .chat-menu-ico,
  body.chat-tools-open #chat-panel-actions .chat-more-pop .chat-menu-hint,
  body.chat-tools-open #chat-panel-actions .chat-more-pop .chat-menu-ico {
    display: none !important;
  }
  #chat-panel-actions.is-open .chat-more-btn,
  body.chat-tools-open #chat-panel-actions .chat-more-btn {
    display: none !important;
  }
  #chat-panel-actions > #chat-cancel { display: none !important; }
  #chat-panel-actions.is-open > #chat-cancel.show,
  body.chat-tools-open #chat-panel-actions > #chat-cancel.show {
    display: inline-flex !important;
  }

  /* No full-page blackout under the chat tools tray. */
  body.chat-tools-open::after {
    content: none;
    background: transparent;
    pointer-events: none;
  }
}





/* ==========================================================================
   M2 — bottom command tray (phone / narrow tablet)
   Desktop ≥1024: hidden.

   Order: AI Analyst | Markets | Chat (center) | Home | Research Notes
   Icons only · solid bar · fixed to bottom.

   iOS keyboard: fixed layers always ride the visual viewport. There is no
   reliable way to keep a fixed bar painted at the physical bottom *above*
   the keys. Product rule: hide the entire tray while typing
   (body.tray-kb-hide). Restore when keyboard is gone.
   ========================================================================== */
.app-command-tray,
.app-command-tray-shell {
  display: none;
}

@media (max-width: 1023px) {
  :root {
    --command-tray-height: 52px;
    --command-tray-pad: calc(
      var(--command-tray-height) + var(--sab-fix, env(safe-area-inset-bottom, 0px))
    );
  }
  /* Tray chrome is display:none while typing. Do NOT snap
     --command-tray-pad to 0 here — JS interpolates pad against
     visualViewport keyboard height so the sheet doesn't jump. */

  /* Collapsed chat must not steal taps. Keep it painted while it slides
     off-screen — visibility:hidden / z-index:1 here made close() snap. */
  .content-right.collapsed,
  .content-right.mode-dock.collapsed,
  .content-right.mode-float.collapsed,
  .content-right.mode-mini.collapsed,
  #chat-drawer.collapsed {
    pointer-events: none !important;
  }
  .content-right.collapsed *,
  .content-right.mode-dock.collapsed *,
  .content-right.mode-float.collapsed *,
  .content-right.mode-mini.collapsed *,
  #chat-drawer.collapsed * {
    pointer-events: none !important;
  }
  .content-right:not(.collapsed),
  #chat-drawer:not(.collapsed) {
    visibility: visible !important;
  }

  /* Shell is a simple portal wrapper — not a viewport frame */
  .app-command-tray-shell,
  body > .app-command-tray-shell {
    display: contents; /* children participate as if shell weren't there */
  }
  /* Fallback when display:contents is flaky: shell as transparent fixed host */
  @supports not (display: contents) {
    .app-command-tray-shell,
    body > .app-command-tray-shell {
      display: block !important;
      position: fixed !important;
      left: 0 !important;
      right: 0 !important;
      bottom: 0 !important;
      top: auto !important;
      width: 100% !important;
      height: auto !important;
      margin: 0 !important;
      padding: 0 !important;
      pointer-events: none !important;
      z-index: 28000 !important;
      background: transparent !important;
      border: 0 !important;
    }
  }

  /* More sheet is an .oc-sheet (motion.css). Keep a-rows tappable here
     because this file loads last among layout sheets. */
  .act-more-sheet.oc-sheet { z-index: 29000; }
  .act-more-sheet[hidden] { display: none !important; }
  .act-more-sheet .oc-sheet__body a,
  .act-more-sheet .act-more-sheet__nav a {
    min-height: 44px;
  }

  .app-command-tray,
  body > .app-command-tray,
  .app-command-tray-shell > .app-command-tray,
  body > .app-command-tray-shell > .app-command-tray {
    display: flex !important;
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    top: auto !important;
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
    transform: none !important;
    -webkit-transform: none !important;
    z-index: 28000 !important;
    align-items: center;
    justify-content: space-around;
    gap: 0;
    height: var(--command-tray-pad);
    min-height: var(--command-tray-pad);
    max-height: var(--command-tray-pad);
    padding: 0 4px var(--sab-fix, env(safe-area-inset-bottom, 0px)) 4px;
    box-sizing: border-box;
    background: var(--bg-elevated, #161b22) !important;
    border: 0 !important;
    border-top: 1px solid var(--border-default, #30363d) !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    overflow: hidden;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    pointer-events: auto !important;
    user-select: none;
    -webkit-user-select: none;
    transition: none !important;
  }

  [data-theme="light"] .app-command-tray,
  [data-theme="light"] body > .app-command-tray,
  [data-theme="light"] .app-command-tray-shell > .app-command-tray {
    background: var(--bg-elevated, #ffffff) !important;
    border-top-color: var(--border-default, #d0d7de) !important;
  }

  .content-left,
  .main-content .content-wrapper {
    padding-bottom: calc(var(--command-tray-pad) + 8px) !important;
  }

  #chat-fab,
  .chat-toggle-fab {
    display: none !important;
    pointer-events: none !important;
  }

  /*
   * HARD HIDE while typing / keyboard up.
   * display:none removes the layer entirely so iOS cannot animate it upward.
   * visibility alone still leaves a fixed layer that rides the visual viewport.
   *
   * Also collapse every layout reservation that assumed the tray was visible
   * (content padding-bottom, chat sheet bottom offset). Otherwise iOS leaves
   * a large empty band between the keyboard and the content.
   */
  body.tray-kb-hide .app-command-tray,
  body.tray-kb-hide .app-command-tray-shell,
  body.tray-kb-hide > .app-command-tray,
  body.tray-kb-hide > .app-command-tray-shell,
  body.keyboard-open .app-command-tray,
  body.keyboard-open .app-command-tray-shell,
  body.keyboard-open > .app-command-tray,
  body.keyboard-open > .app-command-tray-shell {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
    opacity: 0 !important;
    height: 0 !important;
    min-height: 0 !important;
    max-height: 0 !important;
    overflow: hidden !important;
    bottom: -200px !important;
  }

  /* While the keyboard is up: do not tween transform/height — iOS is
     already sliding position:fixed with the visual viewport. Fighting
     that 400ms sheet ease is what felt jumpy. */
  html.oc-kb-open #chat-drawer,
  html.oc-kb-open .content-right,
  html.oc-kb-open .an-root,
  html.oc-kb-open .an-workspace,
  html.oc-kb-open .an-composer,
  html.oc-kb-open .im-root,
  html.oc-kb-open #th-chat-panel {
    transition: none !important;
  }
  html.oc-kb-open .chat-log,
  body.keyboard-open .chat-log {
    scroll-behavior: auto !important;
  }
  /* Lift composers by --oc-kb (visualViewport / Capacitor). No CSS
     transition — the var already tracks the keyboard each frame. */
  html.oc-kb-overlay #chat-drawer:not(.collapsed),
  html.oc-kb-overlay .content-right:not(.collapsed),
  html.oc-kb-overlay #th-chat-panel.is-maximized,
  html.oc-kb-overlay body > #th-chat-panel.is-maximized {
    bottom: var(--oc-kb, 0px) !important;
  }
  html.oc-kb-overlay .an-root,
  html.oc-kb-overlay .an-root--desk {
    padding-bottom: var(--oc-kb, 0px) !important;
    box-sizing: border-box !important;
  }
  html.oc-kb-overlay .an-composer {
    padding-bottom: calc(8px + var(--oc-kb, 0px)) !important;
  }
  html.oc-kb-overlay .im-composer,
  html.oc-kb-overlay html.page-messages .im-composer {
    padding-bottom: calc(8px + var(--oc-kb, 0px)) !important;
  }
  html.oc-kb-overlay .main-content {
    padding-bottom: var(--oc-kb, 0px) !important;
  }

  .app-command-tray .act-tab {
    position: relative;
    z-index: 1;
    flex: 1 1 0;
    min-width: 0;
    height: var(--command-tray-height);
    min-height: var(--command-tray-height);
    max-height: var(--command-tray-height);
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 0;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent !important;
    color: var(--text-muted, #8b949e);
    text-decoration: none !important;
    font: inherit;
    cursor: pointer;
    pointer-events: auto !important;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
    box-shadow: none !important;
    opacity: 1;
    transition: color 0.12s ease, opacity 0.12s ease;
  }
  [data-theme="light"] .app-command-tray .act-tab {
    color: var(--text-muted, #656d76);
  }
  .app-command-tray .act-ico {
    pointer-events: none !important;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    opacity: 1;
  }
  .app-command-tray .act-label {
    display: none !important;
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }
  .app-command-tray .act-tab:active { opacity: 0.55; }
  .app-command-tray .act-tab.is-active {
    color: var(--accent, #6cb6ff);
    background: transparent !important;
    box-shadow: none !important;
  }
  [data-theme="light"] .app-command-tray .act-tab.is-active {
    color: var(--accent, #0969da);
  }
  .app-command-tray .act-tab.is-active .act-ico {
    stroke: currentColor;
    opacity: 1;
  }
  .app-command-tray .act-tab[data-nav="chat"].is-active {
    color: var(--accent-ai, #a371f7);
  }
  .app-command-tray .act-tab[data-nav="chat"].is-active .act-ico {
    stroke: currentColor;
  }
}

/* Open chat sheet sits above the fixed tray (Model A).
   Keyboard: --command-tray-pad is interpolated from visualViewport. */
@media (max-width: 820px) {
  .content-right.mode-dock:not(.collapsed),
  #chat-drawer.mode-dock:not(.collapsed) {
    bottom: var(--command-tray-pad) !important;
    height: calc(65dvh - 4px) !important;
    max-height: calc(80dvh - var(--command-tray-pad)) !important;
    padding-bottom: 0 !important;
    /* Above command tray (28000) so composer is tappable — Model A */
    z-index: 29000 !important;
    pointer-events: auto !important;
    visibility: visible !important;
    /* Solid sheet — no live blur of the page behind (illegible + GPU jank) */
    background: var(--bg-elevated, #161b22) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none !important;
    opacity: 1 !important;
  }
}

@media (max-width: 480px) {
  .content-right:not(.collapsed),
  .content-right.mode-dock:not(.collapsed),
  .content-right.mode-float:not(.collapsed),
  .content-right.mode-mini:not(.collapsed),
  #chat-drawer:not(.collapsed) {
    top: 0 !important;
    bottom: var(--command-tray-pad) !important;
    /* top+bottom pin a definite height; keep overflow clipped so the
       header never scrolls away with the transcript. */
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    z-index: 29000 !important;
    padding-bottom: 0 !important;
    padding-top: var(--sat-fix, env(safe-area-inset-top, 0px)) !important;
    pointer-events: auto !important;
    visibility: visible !important;
    background: var(--bg-elevated, #161b22) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none !important;
    opacity: 1 !important;
  }
}

@media (max-width: 1023px) {
  body.chat-tools-open > .app-command-tray,
  body.chat-tools-open .app-command-tray,
  body.chat-tools-open > .app-command-tray-shell {
    z-index: 26000 !important;
  }
}









/* Fixed page-color paint behind the whole UI. When iOS shrinks the visual
   viewport for the keyboard, the region below the WebView content would
   otherwise show as black; this layer always covers the layout viewport. */
#oc-kb-paint {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
  height: 100dvh;
  min-height: 100%;
  min-height: 100dvh;
  min-height: -webkit-fill-available;
  /* Always under the app — never create a stacking context over chat */
  z-index: -1;
  pointer-events: none !important;
  background: var(--bg-base, #0d1117);
}
.app-layout {
  position: relative;
  z-index: auto;
}
html.oc-kb-open #oc-kb-paint,
body.keyboard-open #oc-kb-paint,
body.tray-kb-hide #oc-kb-paint {
  background: var(--bg-base, #0d1117) !important;
}

/* ===== keyboard chrome: match page background =====
   iOS Safari / WKWebView paint the region above the soft keyboard and
   overscroll gutters from document + theme-color. Force those to --bg-base
   so they never fall back to pure black. */
html {
  color-scheme: dark;
  background-color: var(--bg-base, #0d1117);
  background: var(--bg-base, #0d1117);
}
html[data-theme="light"] {
  color-scheme: light;
}
html, body {
  background-color: var(--bg-base, #0d1117);
  background: var(--bg-base, #0d1117);
}
/* While keyboard is up, reaffirm paint on root shells (some WebViews
   expose a black letterbox under the visual viewport). */
html.oc-kb-open,
html.oc-kb-open body,
body.keyboard-open,
body.tray-kb-hide {
  background-color: var(--bg-base, #0d1117) !important;
  background: var(--bg-base, #0d1117) !important;
}
html.oc-kb-open .app-layout,
body.keyboard-open .app-layout,
body.tray-kb-hide .app-layout {
  background-color: var(--bg-base, #0d1117);
  background: var(--bg-base, #0d1117);
}
/* Composer strip stays elevated (panel) but sits on the same page base. */
@media (max-width: 1023px) {
  body.keyboard-open .chat-input-row,
  body.tray-kb-hide .chat-input-row,
  body.keyboard-open .content-right > .chat-input-row,
  body.tray-kb-hide .content-right > .chat-input-row {
    background: var(--bg-elevated, var(--bg-base)) !important;
  }
}


/* ===== Chat operable sheet (phone / tray layout) =====
   Command tray is z-index 28000. Open Oceanus chat MUST sit above it
   or the tray steals taps and the frosted tray makes the sheet look
   "blurry and dead". Also force solid fill — no backdrop blur of the
   page behind the drawer (illegible transcript on iOS). */
@media (max-width: 1023px) {
  body.chat-open .content-right:not(.collapsed):not(.closing),
  body.chat-open #chat-drawer:not(.collapsed):not(.closing),
  .content-right:not(.collapsed):not(.closing),
  #chat-drawer:not(.collapsed):not(.closing) {
    z-index: 29000 !important;
    pointer-events: auto !important;
    visibility: visible !important;
    opacity: 1 !important;
    filter: none !important;
  }
  body.chat-open .content-right.closing,
  body.chat-open #chat-drawer.closing,
  .content-right.closing,
  #chat-drawer.closing {
    z-index: 29000 !important;
    pointer-events: none !important;
    visibility: visible !important;
  }
  body.chat-open .content-right:not(.collapsed),
  body.chat-open #chat-drawer:not(.collapsed),
  body.chat-open .content-right:not(.collapsed) *,
  body.chat-open #chat-drawer:not(.collapsed) * {
    /* Never inherit a stuck pointer-events:none from collapsed rules */
    pointer-events: auto;
  }
  /* Collapsed drawer stays inert but remains painted above the tray
     so the close slide is visible (z 29000 > tray 28000). */
  body.chat-open .content-right.collapsed,
  body.chat-open #chat-drawer.collapsed {
    z-index: 29000 !important;
    visibility: visible !important;
    opacity: 1 !important;
    pointer-events: none !important;
  }
  body.chat-open .content-right.collapsed *,
  body.chat-open #chat-drawer.collapsed * {
    pointer-events: none !important;
  }
  .content-right:not(.collapsed),
  #chat-drawer:not(.collapsed),
  .content-right:not(.collapsed) .chat-panel,
  #chat-drawer:not(.collapsed) .chat-panel {
    background: var(--bg-elevated, #161b22) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  .content-right:not(.collapsed) .chat-log,
  #chat-drawer:not(.collapsed) .chat-log,
  .content-right:not(.collapsed) #chat-log,
  #chat-drawer:not(.collapsed) #chat-log {
    filter: none !important;
    opacity: 1 !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  /* Composer: solid, sharp — no 26px live blur plate on phone */
  .content-right:not(.collapsed) .chat-input-wrap,
  #chat-drawer:not(.collapsed) .chat-input-wrap {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: var(--bg-elevated-2, #21262d) !important;
    filter: none !important;
  }
  .content-right:not(.collapsed) .chat-input-wrap::before,
  .content-right:not(.collapsed) .chat-input-wrap::after,
  #chat-drawer:not(.collapsed) .chat-input-wrap::before,
  #chat-drawer:not(.collapsed) .chat-input-wrap::after {
    display: none !important;
    content: none !important;
    filter: none !important;
    backdrop-filter: none !important;
  }
  /* Cover the tray; do not display:none or zero --command-tray-pad — that
     reflows page content while the sheet is sliding (reads as a lump). */
  body.th-copilot-overlay-open .app-command-tray,
  body.th-copilot-overlay-open .app-command-tray-shell,
  body.th-copilot-overlay-open > .app-command-tray,
  body.th-copilot-overlay-open > .app-command-tray-shell,
  body.chat-open .app-command-tray,
  body.chat-open .app-command-tray-shell,
  body.chat-open > .app-command-tray,
  body.chat-open > .app-command-tray-shell {
    pointer-events: none !important;
    opacity: 0 !important;
  }
  body.chat-open .content-right:not(.collapsed),
  body.chat-open #chat-drawer:not(.collapsed) {
    bottom: 0 !important;
  }
  html.oc-kb-overlay body.chat-open #chat-drawer:not(.collapsed),
  html.oc-kb-overlay body.chat-open .content-right:not(.collapsed),
  html.oc-kb-overlay #chat-drawer:not(.collapsed),
  html.oc-kb-overlay .content-right:not(.collapsed),
  html.oc-kb-overlay #th-chat-panel.is-maximized,
  html.oc-kb-overlay body > #th-chat-panel.is-maximized {
    bottom: var(--oc-kb, 0px) !important;
    height: auto !important;
    max-height: none !important;
  }
}

/* ===== shell-nav persistent shell swap ===== */
html.shell-nav-busy,
html.shell-nav-busy body {
  cursor: progress;
}
html.shell-nav-busy #content-left {
  pointer-events: none;
}
@media (max-width: 1023px) {
  #content-left.shell-swap-enter {
    animation: ocPageEnter var(--dur-ui, 200ms) var(--ease-out, ease) both;
  }
}
@media (prefers-reduced-motion: reduce) {
  #content-left.shell-swap-enter {
    animation: none !important;
  }
}

/* ===== nav-smooth mobile page transitions =====
   Soften multi-page reloads on phone (PWA / Capacitor WebView).
   Desktop ≥1024: no leave fade; optional VT if browser supports. */
@view-transition {
  navigation: auto;
}

/* Keep transitions short — app chrome, not a cinematic wipe */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
}

@media (max-width: 1023px) {
  /* Disable slow theme morph on every paint — reads as a "wash" on nav */
  html, body {
    transition: none !important;
  }

  /* Outgoing page: quick dim before unload */
  html.page-leave,
  html.page-leave body,
  body.page-leave {
    opacity: 0.72 !important;
    transition: opacity var(--dur-ui, 200ms) var(--ease-out, ease) !important;
  }

  /* Incoming page: content fades/slides in; shell stays put */
  html.page-enter .content-left,
  body.page-enter .content-left,
  html.page-enter .main-content .content-wrapper,
  body.page-enter .main-content .content-wrapper {
    animation: ocPageEnter var(--dur-ui, 200ms) var(--ease-out, ease) both;
  }

  @keyframes ocPageEnter {
    from {
      opacity: 0.55;
      transform: translateY(6px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  /* Stable chrome names help VT keep tray/topbar from morphing oddly */
  .app-command-tray,
  body > .app-command-tray,
  body > .app-command-tray-shell {
    view-transition-name: oc-tray;
  }
  .top-bar {
    view-transition-name: oc-topbar;
  }
}

@media (max-width: 1023px) and (prefers-reduced-motion: reduce) {
  html.page-leave,
  html.page-leave body,
  body.page-leave {
    opacity: 1 !important;
    transition: none !important;
  }
  html.page-enter .content-left,
  body.page-enter .content-left,
  html.page-enter .main-content .content-wrapper,
  body.page-enter .main-content .content-wrapper {
    animation: none !important;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}

/* ==========================================================================
   Mobile gestures — edge-back affordance + pull-to-refresh indicator
   Phone / tablet only (≤1023). Desktop unchanged.
   ========================================================================== */

@media (max-width: 1023px) {
  /* Invisible left-edge catcher — wins first touch at the rim. */
  .oc-edge-back {
    position: fixed;
    left: 0;
    top: calc(var(--topbar-height, 56px) + var(--sat-fix, env(safe-area-inset-top, 0px)));
    bottom: 0;
    width: 56px; /* match EDGE_PX_NATIVE; JS also sets inline width */
    z-index: 900;
    background: transparent;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    pointer-events: auto;
  }
  body.sidebar-open .oc-edge-back,
  body.chat-open .oc-edge-back,
  body.user-menu-open .oc-edge-back,
  body.topbar-tools-open .oc-edge-back {
    pointer-events: none;
  }

  /* Previous-page underlay (parallax sheet + dim) — iOS UINavigation style */
  .oc-back-underlay {
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    display: none;
    overflow: hidden;
    background: var(--bg-base, #0f1419);
  }
  .oc-back-underlay.is-on { display: block; }
  .oc-back-underlay__sheet {
    position: absolute;
    inset: 0;
    background:
      linear-gradient(180deg,
        color-mix(in srgb, var(--bg-elevated, #161b22) 92%, transparent) 0%,
        var(--bg-base, #0f1419) 48%,
        var(--bg-base, #0f1419) 100%);
    /* Faint “previous screen” texture so the reveal isn’t a flat void */
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-default, #30363d) 40%, transparent);
    will-change: transform;
  }
  .oc-back-underlay__dim {
    position: absolute;
    inset: 0;
    background: #000;
    opacity: 0.45;
    will-change: opacity;
  }

  /* Soft left edge shadow that rides with the sliding page */
  .oc-back-shade {
    position: fixed;
    left: -18px;
    top: 0;
    bottom: 0;
    width: 18px;
    z-index: 850;
    pointer-events: none;
    opacity: 0;
    background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.35));
    will-change: transform, opacity;
  }
  .oc-back-shade.is-on { opacity: 1; }

  /* Interactive drag: lock horizontal overflow; elevate sliding column */
  html.oc-back-gesture,
  html.oc-back-interactive {
    touch-action: pan-y;
  }
  html.oc-back-interactive,
  html.oc-back-interactive body {
    overflow: hidden !important;
    overscroll-behavior-x: none;
  }
  html.oc-back-interactive .main-content {
    position: relative;
    z-index: 800;
    background: var(--bg-base, #0f1419);
    box-shadow: -8px 0 28px rgba(0, 0, 0, 0.35);
    border-radius: 0;
    /* transform driven by JS (translate3d) */
  }
  /* Keep fixed chrome that shouldn’t slide with the page above the underlay
     but the whole .main-content slides intentionally (native-like). */

  .oc-ptr {
    position: fixed;
    left: 50%;
    top: calc(env(safe-area-inset-top, 0px) + 8px);
    transform: translate(-50%, calc(-110% + var(--oc-ptr-pull, 0px)));
    z-index: 11900;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 120px;
    padding: 10px 14px 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg-elevated, #1a1f26) 92%, transparent);
    border: 1px solid var(--border-default, rgba(255, 255, 255, 0.08));
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
    color: var(--text-secondary, #9aa6b2);
    font-family: var(--font-sans, system-ui, sans-serif);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease, transform 0.15s ease;
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }

  .oc-ptr.is-visible {
    opacity: 1;
  }

  .oc-ptr.is-ready {
    color: var(--text-primary, #e6edf3);
    border-color: color-mix(in srgb, var(--accent, #58a6ff) 45%, var(--border-default, #30363d));
  }

  .oc-ptr.is-refreshing {
    opacity: 1;
    transform: translate(-50%, 0);
  }

  .oc-ptr__spinner {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2px solid var(--border-default, rgba(255, 255, 255, 0.15));
    border-top-color: var(--accent, #58a6ff);
    box-sizing: border-box;
  }

  .oc-ptr.is-refreshing .oc-ptr__spinner {
    animation: oc-ptr-spin 0.7s linear infinite;
  }

  .oc-ptr.is-armed .oc-ptr__spinner,
  .oc-ptr.is-ready .oc-ptr__spinner {
    /* Static tilt while armed; full spin only when refreshing */
    transform: rotate(40deg);
  }
  .oc-ptr.is-ready .oc-ptr__spinner {
    transform: rotate(180deg);
    border-top-color: var(--accent, #58a6ff);
  }

  .oc-ptr__label {
    line-height: 1.2;
    white-space: nowrap;
  }

  html.oc-ptr-busy,
  html.oc-ptr-busy body {
    cursor: wait;
  }
}

@keyframes oc-ptr-spin {
  to { transform: rotate(360deg); }
}

@media (max-width: 1023px) and (prefers-reduced-motion: reduce) {
  .oc-ptr {
    transition: none;
  }
  .oc-ptr.is-refreshing .oc-ptr__spinner {
    animation: none;
  }
}

/* Phase 9 cockpit: stack 4 lenses at ≤900px (company_dossier.css also sets this). */
@media (max-width: 900px) {
  .dd-cockpit-lenses { grid-template-columns: 1fr; }
  .dd-cockpit-tabs { display: flex; flex-wrap: wrap; }
  .dd-cockpit-lens { display: none; }
  .dd-cockpit-lens.is-active { display: block; }
}

/* Hide edge-back chrome on desktop widths */
@media (min-width: 1024px) {
  .oc-edge-back,
  .oc-back-underlay,
  .oc-back-shade { display: none !important; }
}

/* Top-bar refresh button removed — use pull-to-refresh (app shell),
   ⌘/Ctrl+R (soft) / ⌘/Ctrl+Shift+R (hard), user menu, or ⌘K → Refresh. */
