/* ----------------------------------------------------------------------
 * Responsive: phones + tablets.
 *
 * Two breakpoints:
 *   - "phone"  ≤ 760px: collapse the sidebar into an off-canvas drawer,
 *                       header into a single compact row, panes into a
 *                       swipeable 1-up carousel, expose a virtual keybar
 *                       so users can type Ctrl/Esc/Tab/Arrows on a
 *                       soft keyboard.
 *   - "tablet" 761–1024px: keep the sidebar but slim it down, and let
 *                          pane grids scroll vertically if they overflow.
 *
 * In addition, `.is-touch` is applied to <body> by mobile.js whenever the
 * primary pointer is coarse (touchscreen). That class gates touch-only
 * behaviour (larger hit targets, long-press hint) on devices like iPads
 * in landscape that exceed the phone breakpoint but still lack a mouse.
 * ---------------------------------------------------------------------- */

:root {
  /* Height of the virtual key bar. Used in JS too via getComputedStyle for
     viewport-fit calculations when the soft keyboard opens. */
  --mobile-keybar-h: 44px;
  --mobile-drawer-w: 280px;
}

/* Avoid double-tap zoom on buttons that we treat as touch surfaces. Setting
   touch-action: manipulation everywhere would also kill xterm's drag-to-
   select on touch — so we scope it to interactive chrome only. */
.btn, .nav-item, .tab, .tab__close, .machines-panel__close,
.platform-tab, .toggle-btn, .layout-option, .claude-menu__btn,
.mobile-hamburger, .mobile-keybar__key, .pane-counter,
.machine-chip, .machine-row__btn, .swatch, .context-menu__item,
.settings-tab, .ssh-row__actions .btn {
  touch-action: manipulation;
}

/* Terminal touch scrolling. On a touchscreen the xterm host owns its own
   drag gestures (session.js _installTouchDragScroll): a vertical drag scrolls
   the scrollback, a horizontal drag pages the pane carousel. touch-action:none
   hands the browser's gesture to our capture-phase handler so it can cancel the
   native one — without it, a TUI in mouse-tracking mode eats the drag and the
   scrollback is unreachable on mobile. Taps (no drag) still pass through to
   xterm for focus / TUI clicks / the edge tap-to-bottom.

   The rule MUST reach the inner xterm elements the finger actually lands on
   (.xterm-viewport / .xterm-screen) — xterm.css leaves them touch-action:auto,
   so without this the browser claims the gesture before our handler sees it. */
body.is-touch .shell-cell__host,
body.is-touch .shell-cell__host .xterm,
body.is-touch .shell-cell__host .xterm-viewport,
body.is-touch .shell-cell__host .xterm-screen {
  touch-action: none !important;
}

/* Hide phone-only UI on desktop by default. */
.mobile-hamburger { display: none; }
.mobile-keybar    { display: none; }
.pane-counter     { display: none; }
.sidebar-backdrop { display: none; }

/* Touch devices that exceed the phone breakpoint (iPads in landscape,
   touch laptops) still need the helper keybar — soft keyboards rarely
   surface Ctrl/Esc reliably. Reveal it but keep the sidebar visible. */
body.is-touch .mobile-keybar { display: flex; }
body.is-touch .app           { padding-bottom: var(--mobile-keybar-h); box-sizing: border-box; }

/* ----- Virtual key bar (base styles — apply at all breakpoints) -----
   Visibility is gated above (display:none by default, display:flex when
   .is-touch or under @media phone). Layout / sizing here so a tablet in
   landscape gets the same chrome a phone does. */
.mobile-keybar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--mobile-keybar-h);
  z-index: 55;
  align-items: center;
  gap: 4px;
  padding: 4px 6px;
  background: linear-gradient(180deg, var(--surface-1), var(--bg-tint));
  border-top: 1px solid var(--border-strong);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.35);
  /* iOS pushes the soft keyboard via visualViewport; mobile.js writes
     --kb-offset so the bar floats just above it. */
  transform: translateY(calc(-1 * var(--kb-offset, 0px)));
}
.mobile-keybar::-webkit-scrollbar { display: none; }

.mobile-keybar__key {
  flex: 0 0 auto;
  min-width: 36px;
  /* Bumped from 34→38 so a thumb landing slightly low or high still
     hits the key — common on the bottom-row of a phone where reach is
     compromised. Stays under WCAG 2.5.5's 44px since the keybar is
     touch-only and runs full-width across the bottom. */
  height: 38px;
  padding: 0 9px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
}
.mobile-keybar__key:active,
.mobile-keybar__key.is-pressed {
  background: var(--surface-3);
  border-color: var(--accent-soft);
  transform: scale(0.95);
}
.mobile-keybar__key.is-sticky.is-armed {
  background: var(--accent-soft);
  border-color: var(--accent-strong);
  color: var(--accent-strong);
  box-shadow: 0 0 0 1px var(--accent-strong), 0 0 12px var(--accent-soft);
}
.mobile-keybar__key.is-wide { min-width: 56px; padding: 0 12px; }
.mobile-keybar__key.is-arrow { font-size: 16px; min-width: 40px; }

/* On a touch device, beef up tap targets even at desktop widths.
   tab__close: 36×36 hit area (WCAG 2.5.5) with the visible chip kept at
   28×28 via padding + background-clip; closing a tab is workspace-loss
   territory per the persistence invariant so the target has to be
   forgiving. */
body.is-touch .tab__close { width: 36px; height: 36px; padding: 4px; font-size: 14px; background-clip: content-box; }
body.is-touch .machine-row__btn { padding: 8px 12px; font-size: 13px; }
body.is-touch .nav-item { padding: 12px 12px; font-size: 14px; }
body.is-touch .btn { padding: 8px 12px; font-size: 13px; min-height: 36px; }
body.is-touch .btn--small { padding: 6px 12px; font-size: 12.5px; min-height: 32px; }
body.is-touch .swatch { width: 28px; height: 28px; }
body.is-touch .context-menu__item { padding: 10px 12px; font-size: 13.5px; }
/* The size-picker (and any future button-row) inside a context menu —
   22×22 is below comfortable touch; 32 lifts it without breaking the
   10-button row fit in a 240–280px menu. */
body.is-touch .context-menu__btn { min-width: 32px; height: 32px; padding: 0 8px; }
/* Claude-menu panel rows — compute to 22-28px on touch without overrides;
   lift them to a comfortable tap target. Number-row uses a slightly
   smaller input so the row height still fits in the panel. */
body.is-touch .claude-menu__panel .toggle-btn { min-height: 40px; padding: 10px 12px; font-size: 13.5px; }
body.is-touch .claude-menu__panel .number-row { padding: 10px 12px; font-size: 13.5px; }
body.is-touch .claude-menu__panel .number-row__input { height: 32px; padding: 4px 8px; font-size: 14px; }
body.is-touch .platform-tab { padding: 12px 10px; font-size: 14px; }
/* Touch lacks hover so the native iOS/Android grey-flash on tap is the
   only "did the button fire?" signal — but it clashes with our own
   :active styles and ruins the visual rhythm. Suppress globally on
   touch; we already provide our own :active/active-state feedback. */
body.is-touch button { -webkit-tap-highlight-color: transparent; }

/* Make sure scrollable rows are reachable with a finger on touch devices. */
body.is-touch .tabs { -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; }
body.is-touch .tabs::-webkit-scrollbar { display: none; }
body.is-touch .tab { scroll-snap-align: start; }

/* ----------------------------------------------------------------------
 * TABLET (≤ 1024px)
 * ---------------------------------------------------------------------- */
@media (max-width: 1024px) {
  :root { --sidebar-w: 200px; }
  .sidebar__brand { gap: 8px; }
  .sidebar__logo { width: 36px; height: 36px; }
  .sidebar__hint { display: none; }
}

/* ----------------------------------------------------------------------
 * PHONE (≤ 760px)
 * ---------------------------------------------------------------------- */
@media (max-width: 760px) {
  /* ----- App-shell lock -----
     Pin the document to the viewport so the PAGE itself never scrolls or
     rubber-bands. Everything reachable on a phone is reached through the
     intended inner scrollers (the horizontal tab strip, the swipeable pane
     carousel, the sidebar drawer, full-screen modals) — each of which keeps
     its own overflow — so locking the page doesn't strand any of them. This
     is what makes the workspace feel like a native app instead of a web page
     you can drag around. Pairs with the no-zoom viewport meta + the
     gesturestart guard in mobile.js. */
  html, body {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    /* Kill the elastic bounce at the top/bottom edges (iOS) and any
       scroll-chaining out of inner scrollers into the page. */
    overscroll-behavior: none;
  }

  /* Use the dynamic viewport height so iOS Safari's collapsing chrome
     doesn't leave a 50px sliver of the previous page peeking through. */
  .app {
    grid-template-columns: 1fr;
    height: 100dvh;
    /* Reserve room at the bottom for the virtual key bar so terminal
       output isn't permanently hidden behind it. */
    padding-bottom: var(--mobile-keybar-h);
    box-sizing: border-box;
  }

  /* ----- Sidebar as off-canvas drawer ----- */
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--mobile-drawer-w);
    max-width: 88vw;
    z-index: 65;
    transform: translateX(-100%);
    transition: transform 240ms cubic-bezier(0.16, 1, 0.3, 1);
    padding: 18px 14px 16px;
    overflow-y: auto;
    box-shadow: 8px 0 32px rgba(0, 0, 0, 0.45);
    border-right: 1px solid var(--border-strong);
  }
  body.is-drawer-open .sidebar { transform: translateX(0); }
  body.is-drawer-open .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(5, 7, 11, 0.6);
    backdrop-filter: blur(4px);
    z-index: 64;
    animation: fade-in var(--t-fast) var(--ease);
  }

  .sidebar__hint { display: block; }

  /* The sidebar also hosts the actions we hide from the workspace header
     on phone (Layout, Reconnect, Voice toggle). They're injected by
     mobile.js into #sidebar-mobile-actions when present. */

  /* ----- Workspace header on phone ----- */
  .workspace__header {
    padding: 0 8px;
    gap: 6px;
    height: 52px;
  }
  :root { --header-h: 52px; }

  /* Hamburger: appears as the leftmost item, swaps the sidebar in. */
  .mobile-hamburger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--fg);
    font-size: 18px;
    flex: 0 0 auto;
  }
  .mobile-hamburger:active { background: var(--surface-3); }

  /* Machine chip on phone shrinks to icon + dot. */
  .machine-chip {
    margin-right: 0;
    padding: 4px 8px;
    font-size: 12px;
    max-width: 110px;
  }
  .machine-chip__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 72px;
  }

  /* Reconnect moved into the machines-panel header (visible at all
     sizes when the panel is open). +New is redundant with the
     tab-strip "+" on phones — hide entirely to free space for the
     account chip. */
  #new-tab-btn { display: none !important; }

  .workspace__actions { gap: 4px; margin-left: 4px; flex: 0 0 auto; }

  /* Claude menu collapses to a pill on phone. */
  .claude-menu__btn {
    padding: 4px 8px;
    font-size: 11px;
  }
  .claude-menu__panel {
    right: -4px;
    min-width: 180px;
  }

  /* ----- Tabs: bigger touch targets, sticky bottom border. ----- */
  .tabs-host { min-width: 0; }
  .tab {
    height: calc(var(--header-h) - 10px);
    padding: 0 8px 0 10px;
    font-size: 13px;
    max-width: 180px;
    flex: 0 0 auto;
  }
  /* Hit area 36×36; visible chip stays 28×28 via padding + content-box
     background clipping. Matches the .is-touch override above. */
  .tab__close {
    width: 36px; height: 36px; padding: 4px;
    font-size: 14px; background-clip: content-box;
  }
  .tab__title { max-width: 110px; }

  /* ----- Panes: 1-up swipeable carousel. ----- */
  .pane {
    padding: 6px 6px 6px;
  }
  .pane__inner {
    padding: 4px;
  }
  /* Override the inline grid-template-{columns,rows} that tabs.js writes,
     so any 2/4/6/9-shell tab becomes a horizontal carousel. !important is
     required to win over the inline style. */
  .pane__grid {
    grid-template-columns: none !important;
    grid-template-rows: none !important;
    display: flex;
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    gap: 0;
    scrollbar-width: none;
  }
  .pane__grid::-webkit-scrollbar { display: none; }
  .shell-cell {
    flex: 0 0 100%;
    width: 100%;
    height: 100%;
    scroll-snap-align: center;
    /* Vertical swipes scroll the pane carousel, horizontal stays free
       for xterm text-selection. Without this, xterm's pointerdown can
       eat the swipe and the carousel stops responding. */
    touch-action: pan-y;
    scroll-snap-stop: always;
  }

  /* Pane counter "2/4" floating bottom-center when carouseling. */
  .pane[data-shell-count]:not([data-shell-count="1"]) .pane-counter {
    display: inline-flex;
  }
  .pane-counter {
    position: absolute;
    left: 50%;
    bottom: 10px;
    transform: translateX(-50%);
    z-index: 4;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: rgba(7, 9, 13, 0.85);
    color: var(--fg-muted);
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    font-size: 11.5px;
    font-family: var(--font-mono);
    letter-spacing: 0.04em;
    pointer-events: none;
    backdrop-filter: blur(4px);
  }
  .pane-counter__dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--fg-dim);
    transition: background var(--t-fast) var(--ease);
  }
  .pane-counter__dot.is-active {
    background: var(--accent-strong);
    box-shadow: 0 0 6px var(--accent-soft);
  }

  /* Shell cell name label stays at top, but a touch larger so it's actually
     readable on a 5"-class display. */
  .shell-cell__name {
    font-size: 12px;
    opacity: 0.6;
  }

  /* ----- Modals: full-screen on phone. ----- */
  .modal {
    width: 100vw;
    max-width: 100vw;
    max-height: 100dvh;
    height: 100dvh;
    border-radius: 0;
    padding: 18px 16px 24px;
    overflow-y: auto;
  }
  .modal__header h1 { font-size: 18px; }
  .modal__sub { font-size: 12.5px; }
  .steps { gap: 10px; }
  .steps li { padding: 10px; }
  .modal__footer { font-size: 11.5px; }
  .platform-tabs { grid-template-columns: 1fr 1fr; }

  /* Machines drawer fills the screen. */
  .machines-panel { grid-template-columns: 0 1fr; }
  .machines-panel__sheet { padding: 14px; }
  .machines-panel__header h2 { font-size: 16px; }
  .machine-row { grid-template-columns: auto 1fr; row-gap: 6px; }
  .machine-row__actions {
    grid-column: 1 / -1;
    justify-content: flex-end;
    border-top: 1px dashed var(--border);
    padding-top: 8px;
  }

  /* Settings drawer fills the screen. */
  .settings-drawer { width: 100vw; }
  .settings-drawer__body { padding: 14px; }
  .ssh-form__grid { grid-template-columns: 1fr; }

  /* Context menu wider for easier finger taps. */
  .context-menu { min-width: 240px; }

  /* Toasts dodge the keybar so they don't get clipped. */
  .toasts {
    bottom: calc(var(--mobile-keybar-h) + 12px);
    right: 12px;
    left: 12px;
    max-width: none;
  }
  .toast { font-size: 12.5px; }

  /* Virtual key bar shows on every phone-width view (base styles live
     above the @media block so .is-touch tablets pick them up too). */
  .mobile-keybar { display: flex; }

  /* Empty states should still be visible on tiny screens. */
  .empty-state h2 { font-size: 16px; }
  .empty-state p { font-size: 12.5px; padding: 0 18px; }
  .empty-state__icon { font-size: 40px; }

  /* Hide the experimental top-right voice/agent UI labels to save room.
     The pulse dot still tells the user it's live. */
  .voice-indicator__label { display: none; }
  .voice-indicator { padding: 4px 6px; max-width: 60px; }

  /* Agent-network legend collapses vertically. */
  .agent-network__chrome {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .agent-network__status { margin-left: 0; }
}

/* ----------------------------------------------------------------------
 * NARROW PHONE (≤ 380px) — final aggressive collapse.
 * ---------------------------------------------------------------------- */
@media (max-width: 380px) {
  .workspace__header { padding: 0 4px; gap: 4px; }
  .machine-chip { max-width: 80px; padding: 4px 6px; }
  .machine-chip__name { max-width: 48px; }
  .tab { max-width: 130px; padding: 0 6px 0 8px; }
  .tab__title { max-width: 70px; }
  #new-tab-btn { padding: 6px 10px; }
  .mobile-keybar__key { min-width: 34px; padding: 0 7px; font-size: 12.5px; }
}

/* Reduced motion — kill the keep-alive transform animation so the page is
   readable for users who can't tolerate motion. The CSS comment above the
   keep-alive rule notes this is the workaround for Chromium throttling; on
   touch devices the user is interacting frequently enough that rAF stays
   awake without it. */
@media (prefers-reduced-motion: reduce) {
  .xterm { animation: none; }
  .machines-panel__sheet,
  .settings-drawer,
  .sidebar { transition: none; }
}
