/* =====================================================================
   Claude Dev Portal — v13 design system
   Dark-only, mobile-first, IDE-grade. Cursor / Linear / Vercel / GitHub.
   Selector names are PRESERVED from v12: app.js holds ~94 live #id refs and
   toggles these exact classes. Repaint, don't rename.
   ===================================================================== */

@font-face {
  font-family: 'InterVar';
  src: url('/vendor/InterVariable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ---- surfaces ---- */
  --bg: #09090B;          /* app background */
  --bg-2: #111218;        /* cards / panels / header  (alias: --surface) */
  --bg-3: #17181F;        /* raised: inputs, chips, hover (alias: --surface-2) */
  --bg-4: #1E1F28;        /* pressed / active raised */
  --border: #24262F;
  --border-soft: #1B1D25; /* hairline inside a card */
  --code-bg: #0C0D12;
  --user-bubble: #17181F;

  /* ---- text ---- */
  --fg: #FFFFFF;
  --muted: #A1A1AA;
  --faint: #6B6B78;

  /* ---- accents ---- */
  --accent: #7C5CFF;      /* primary */
  --accent-2: #9F87FF;    /* primary hover / links */
  --accent-dim: rgba(124, 92, 255, .14);
  --accent-ring: rgba(124, 92, 255, .22);
  --ok: #22C55E;
  --warn: #F59E0B;
  --danger: #EF4444;
  --info: #3B82F6;
  --ok-dim: rgba(34, 197, 94, .13);
  --warn-dim: rgba(245, 158, 11, .13);
  --danger-dim: rgba(239, 68, 68, .13);
  --info-dim: rgba(59, 130, 246, .13);

  /* ---- shape ---- */
  --radius: 16px;         /* cards */
  --r-md: 12px;           /* panels, popovers */
  --r-sm: 10px;           /* buttons, inputs */
  --r-xs: 8px;            /* chips, tight rows */

  /* ---- elevation: soft, never harsh ---- */
  --sh-1: 0 1px 2px rgba(0, 0, 0, .45);
  --sh-2: 0 6px 20px -6px rgba(0, 0, 0, .65);
  --sh-3: 0 18px 44px -14px rgba(0, 0, 0, .78);
  --sh-fab: 0 8px 24px -6px rgba(124, 92, 255, .5), 0 2px 8px rgba(0, 0, 0, .5);

  /* subtle gradient wash for card tops — reads as light, not as glass */
  --wash: linear-gradient(180deg, rgba(255, 255, 255, .028), rgba(255, 255, 255, 0) 62%);

  /* ---- motion: fast, smooth, professional ---- */
  --ease: cubic-bezier(.22, .72, .28, 1);
  --t-fast: .12s;
  --t-med: .2s;

  /* ---- chrome metrics ---- */
  --topnav-h: 52px;
  --bottomnav-h: 56px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  /* index.html sets viewport-fit=cover, so in LANDSCAPE the display cutout eats
     one edge and anything flush to it is drawn underneath. Only the bottom
     inset was ever handled; these two are why the topbar looked shifted and
     clipped on a phone held sideways. Both resolve to 0px on hardware without
     a cutout, so they cost nothing anywhere else. */
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  --mono: 'SFMono-Regular', ui-monospace, 'JetBrains Mono', Menlo, Consolas, monospace;

  font-size: 15px;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--bg);
  color: var(--fg);
  font-family: 'InterVar', Inter, -apple-system, BlinkMacSystemFont, 'SF Pro Display',
               'Segoe UI', Roboto, sans-serif;
  font-feature-settings: 'cv05' 1, 'ss03' 1, 'tnum' 0;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  letter-spacing: -0.01em;
}
.hidden { display: none !important; }
.muted { color: var(--muted); }
.view { height: 100vh; height: 100dvh; }
.center { display: flex; align-items: center; justify-content: center; padding: 20px; }

/* ---------- cards / auth ---------- */
.card {
  background: var(--bg-2);
  background-image: var(--wash);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: var(--sh-2);
}
.auth-card { width: 100%; max-width: 380px; text-align: center; }
.brand { font-weight: 650; font-size: 1.02rem; display: flex; align-items: center; gap: 9px; justify-content: center; letter-spacing: -.02em; }
.brand.small { font-size: .94rem; justify-content: flex-start; }
.dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.hint { font-size: .78rem; color: var(--muted); margin: 10px 0 0; line-height: 1.5; }
.lbl { display: block; text-align: left; font-size: .72rem; font-weight: 550; color: var(--muted); margin: 14px 0 5px; letter-spacing: .01em; }

/* ---------- inputs / buttons ---------- */
.input {
  width: 100%; padding: 10px 12px; background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: var(--r-sm); font-size: .9rem;
  font-family: inherit;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.input::placeholder { color: var(--faint); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }

.btn {
  cursor: pointer; border: 1px solid var(--border); background: var(--bg-3); color: var(--fg);
  padding: 8px 14px; border-radius: var(--r-sm); font-size: .85rem; font-weight: 550;
  font-family: inherit; letter-spacing: -.005em;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.btn:hover { background: var(--bg-4); border-color: #2E313C; }
.btn:active { transform: scale(.975); }
.btn:disabled { opacity: .42; cursor: not-allowed; transform: none; }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600;
  box-shadow: 0 1px 2px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.14);
}
.btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn.primary:disabled { box-shadow: none; }
.btn.big { width: 100%; padding: 12px; margin-top: 10px; font-size: .95rem; border-radius: var(--r-md); }
.btn.small { padding: 6px 10px; font-size: .78rem; border-radius: var(--r-xs); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn.ghost:hover { background: var(--bg-3); color: var(--fg); border-color: var(--border); }
.btn.link { background: none; border: none; color: var(--accent-2); padding: 8px; font-weight: 550; }
.btn.link:hover { background: none; color: var(--accent); }
.btn.danger { border-color: var(--danger); color: var(--danger); background: var(--danger-dim); }
.btn.danger:hover { background: rgba(239, 68, 68, .2); }

.icon-btn {
  cursor: pointer; background: transparent; border: 1px solid transparent; color: var(--muted);
  font-size: .95rem; border-radius: var(--r-xs); width: 32px; height: 32px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
/* Icon buttons may carry an inline SVG instead of a glyph. The download control
   used U+2B73 (⭳), which simply does not exist in the stock Android/iOS fonts —
   it rendered as nothing at all on a phone, so the button looked missing. Glyphs
   outside the common ranges are not safe here; SVG always draws. */
.icon-btn svg { width: 15px; height: 15px; display: block; flex: none; }
.icon-btn:hover { background: var(--bg-3); color: var(--fg); }
.icon-btn:active { transform: scale(.94); }
.icon-btn:disabled { opacity: .35; cursor: not-allowed; }

/* ===================== THE ICON SET (v15) =====================
   Every pictograph in the UI is now an inline <svg class="ico"> drawn from
   ICONS in app.js — see the block there for why (emoji are a lottery on
   mobile; U+2B73 had no glyph at all).

   Sizing is the whole job of this section. The default is `em`-based so the
   container's existing font-size keeps driving it — that is what let the tab
   strip and bottom nav switch to SVG without touching their rules. Containers
   whose font-size was tuned for a 2-3 character TEXT glyph (.qa-ico at .95rem,
   .sr-ico at .66rem) would render a comically small icon, so those get an
   explicit px size below. Colour always comes from `currentColor`, which is
   why the tone classes (.qa-tile.p .qa-ico, .act-ico.err, …) still work. */
svg.ico {
  width: 1.15em; height: 1.15em; display: block; flex: none;
  stroke: currentColor; fill: none;
}
/* icon + label in one control: "[svg] Settings". Kept as inline-block +
   vertical-align rather than flex/gap so it drops into .btn, .key and the
   pills unchanged — several of those are not flex containers. */
.btn > svg.ico, .key > svg.ico, .usage-pill > svg.ico {
  display: inline-block; vertical-align: -.19em; width: 1.05em; height: 1.05em;
}
.btn > svg.ico + .ico-lbl, .usage-pill > svg.ico + .ico-lbl,
.btn > svg.ico + span, .usage-pill > svg.ico + span { margin-left: 6px; }
.ico-lbl { display: inline-block; }
svg.ico.ico-inline { display: inline-block; vertical-align: -.16em; width: 1em; height: 1em; opacity: .75; }

/* containers whose font-size was set for text glyphs, not icons */
/* .icon-btn svg is 15px above; svg.ico has equal specificity and comes later,
   so re-assert it or every icon button silently grows. */
.icon-btn > svg.ico { width: 15px; height: 15px; }
.qa-ico svg.ico { width: 19px; height: 19px; }
.sa-ico svg.ico { width: 17px; height: 17px; }
.act-ico svg.ico { width: 14px; height: 14px; }
.sr-ico svg.ico { width: 14px; height: 14px; }
.search-ico svg.ico { width: 16px; height: 16px; opacity: .75; }
.tree-name svg.ico { display: inline-block; vertical-align: -.17em; width: 1.05em; height: 1.05em; opacity: .8; margin-right: 5px; }
.copy-btn svg.ico { width: 13px; height: 13px; }
.ci-pin svg.ico, .quick-manage svg.ico { width: 13px; height: 13px; }
.msg-who svg.ico { display: inline-block; vertical-align: -.16em; width: 1em; height: 1em; margin-right: 4px; }
.attach-chip svg.ico { display: inline-block; vertical-align: -.16em; width: 1em; height: 1em; margin-right: 4px; }
.ctx-pill svg.ico { display: inline-block; vertical-align: -.16em; width: .95em; height: .95em; margin-right: 4px; }

.msg { min-height: 20px; font-size: .82rem; margin-top: 12px; }
.msg.err { color: var(--danger); }
.msg.ok { color: var(--ok); }

/* status badge — one primitive, five tones */
.badge {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  padding: 2px 8px; border-radius: 999px; font-size: .68rem; font-weight: 600;
  letter-spacing: .01em; border: 1px solid var(--border);
  background: var(--bg-3); color: var(--muted); white-space: nowrap;
}
.badge.ok { color: var(--ok); background: var(--ok-dim); border-color: rgba(34,197,94,.28); }
.badge.warn { color: var(--warn); background: var(--warn-dim); border-color: rgba(245,158,11,.28); }
.badge.danger { color: var(--danger); background: var(--danger-dim); border-color: rgba(239,68,68,.28); }
.badge.info { color: var(--info); background: var(--info-dim); border-color: rgba(59,130,246,.28); }
.badge.primary { color: var(--accent-2); background: var(--accent-dim); border-color: rgba(124,92,255,.3); }
.badge .bdot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.mono { font-family: var(--mono); }

/* ---------- app layout ---------- */
#view-app { display: flex; }
/* The left drawer + icon rail are gone (v14). The project switcher is a single
   dropdown hanging off the workspace chip, identical on phone and desktop. */
.ws-menu {
  position: absolute; top: calc(100% - 4px); left: 10px; z-index: 60;
  width: min(300px, calc(100vw - 20px)); max-height: min(70vh, 520px);
  display: flex; flex-direction: column; padding: 8px;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: 0 18px 44px rgba(0,0,0,.55);
  animation: mm-in var(--t-fast) var(--ease);
}
.ws-menu.hidden { display: none; }
.ws-menu-head {
  display: flex; justify-content: space-between; align-items: center; padding: 2px 4px 8px;
  font-size: .68rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 650; color: var(--faint);
}
.ws-menu-foot { display: flex; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border-soft); }
.ws-menu-foot .btn { flex: 1; }
@keyframes mm-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.project-list { list-style: none; margin: 0; padding: 0; flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.project-list li {
  padding: 8px 10px; border-radius: var(--r-xs); cursor: pointer; font-size: .86rem;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  color: var(--muted); font-weight: 500;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.project-list li:hover { background: var(--bg-3); color: var(--fg); }
.project-list li.active {
  background: var(--accent-dim); color: var(--fg); font-weight: 600;
  box-shadow: inset 2px 0 0 var(--accent);
}
/* Touch has no hover, so the remove affordance can never be hover-only here. */
.project-list li .pj-del { opacity: .4; font-size: .82rem; padding: 0 4px; }
.project-list li:hover .pj-del { opacity: .75; }
.project-list li .missing { color: var(--danger); font-size: .68rem; }

.workspace { flex: 1; display: flex; flex-direction: column; min-width: 0; }

/* ---------- sticky top navigation ---------- */
.topbar {
  display: flex; align-items: center; gap: 8px;
  height: var(--topnav-h); flex: none;
  padding: 0 calc(10px + var(--safe-r)) 0 calc(6px + var(--safe-l));
  border-bottom: 1px solid var(--border);
  background: rgba(9, 9, 11, .82);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  position: sticky; top: 0; z-index: 35;
}
.current-project {
  font-weight: 600; font-size: .88rem; letter-spacing: -.015em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* workspace selector chip: project name + caret, tap = project drawer */
.ws-chip {
  display: flex; align-items: center; gap: 7px; min-width: 0; max-width: 46vw;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 11px 5px 7px; cursor: pointer; color: var(--fg); font: inherit;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.ws-chip:hover { background: var(--bg-3); border-color: #2E313C; }
.ws-chip .ws-sq {
  width: 20px; height: 20px; border-radius: 6px; flex: none;
  background: var(--accent-dim); color: var(--accent-2);
  display: grid; place-items: center; font-size: .6rem; font-weight: 750; letter-spacing: .02em;
}
.ws-chip .ws-nm { font-size: .82rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-chip .ws-caret { color: var(--faint); font-size: .6rem; flex: none; }

.tn-spacer { flex: 1 1 auto; min-width: 0; }
.tn-actions { display: flex; align-items: center; gap: 2px; flex: none; }

/* live connection indicator */
.conn {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 4px 9px; border-radius: 999px; font-size: .68rem; font-weight: 600;
  background: var(--bg-2); border: 1px solid var(--border); color: var(--muted);
}
.conn .cdot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); flex: none; }
.conn.online { color: var(--ok); border-color: rgba(34,197,94,.28); background: var(--ok-dim); }
.conn.online .cdot { background: var(--ok); box-shadow: 0 0 0 3px rgba(34,197,94,.18); animation: breathe 2.6s var(--ease) infinite; }
.conn.syncing { color: var(--warn); border-color: rgba(245,158,11,.28); background: var(--warn-dim); }
.conn.syncing .cdot { background: var(--warn); animation: breathe 1s var(--ease) infinite; }
.conn.offline { color: var(--danger); border-color: rgba(239,68,68,.28); background: var(--danger-dim); }
.conn.offline .cdot { background: var(--danger); }
@keyframes breathe { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

/* notification bell + unread pip */
.notif-btn { position: relative; }
.notif-btn .pip {
  position: absolute; top: 4px; right: 4px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--bg); display: none;
}
.notif-btn.has-unread .pip { display: block; }

/* user avatar */
.avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: none; cursor: pointer;
  background: linear-gradient(140deg, var(--accent), #4F3BCC);
  color: #fff; font-size: .68rem; font-weight: 700; letter-spacing: .02em;
  display: grid; place-items: center; border: 1px solid rgba(255,255,255,.14);
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.avatar:hover { transform: scale(1.06); box-shadow: 0 0 0 3px var(--accent-ring); }

/* desktop segmented tab control (mobile uses the bottom nav) */
.tabs { display: flex; gap: 2px; flex: none; background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px; }
.tab {
  background: transparent; border: none; color: var(--muted); padding: 6px 12px;
  border-radius: 7px; cursor: pointer; font-size: .8rem; font-weight: 550; font-family: inherit;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tab:hover { color: var(--fg); }
.tab.active { background: var(--bg-4); color: var(--fg); box-shadow: var(--sh-1); }

.tabpane { flex: 1; display: none; min-height: 0; }
.tabpane.active { display: flex; flex-direction: column; }

/* ---------- bottom navigation (mobile) ---------- */
.bottomnav {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  height: calc(var(--bottomnav-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  background: rgba(9, 9, 11, .9);
  backdrop-filter: saturate(160%) blur(16px);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
  border-top: 1px solid var(--border);
}
.bn-item {
  flex: 1 1 0; min-width: 0; background: none; border: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--faint); font-family: inherit; padding: 0;
  position: relative; transition: color var(--t-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.bn-ico { font-size: 1.12rem; line-height: 1; transition: transform var(--t-med) var(--ease); }
.bn-ico.ico-text { font-size: .8rem; font-weight: 750; letter-spacing: .03em; }
.bn-label { font-size: .62rem; font-weight: 600; letter-spacing: .01em; }
.bn-item.active { color: var(--accent-2); }
.bn-item.active .bn-ico { transform: translateY(-1px) scale(1.06); }
.bn-item.active::before {
  content: ''; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 22px; height: 2px; border-radius: 0 0 3px 3px; background: var(--accent);
}
.bn-item:active .bn-ico { transform: scale(.9); }
/* unread / attention pip on a nav item (e.g. AI awaiting permission) */
.bn-item .bn-pip {
  position: absolute; top: 7px; left: calc(50% + 8px); width: 7px; height: 7px;
  border-radius: 50%; background: var(--warn); border: 2px solid var(--bg); display: none;
}
.bn-item.attn .bn-pip { display: block; }

/* ---------- floating AI action button ---------- */
.fab {
  position: fixed; right: 16px; z-index: 42;
  bottom: calc(20px + var(--safe-b));
  width: 54px; height: 54px; border-radius: 18px; cursor: pointer;
  background: linear-gradient(145deg, #8E71FF, #6A47F5);
  border: 1px solid rgba(255,255,255,.16); color: #fff;
  font-size: 1.35rem; line-height: 1;
  display: grid; place-items: center;
  box-shadow: var(--sh-fab);
  transition: transform var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease);
}
.fab:hover { transform: translateY(-2px); }
.fab:active { transform: scale(.92); }
.fab.open { transform: rotate(45deg); }

/* ---------- bottom sheet (AI actions) ---------- */
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 55; background: rgba(0,0,0,.62);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  opacity: 0; transition: opacity var(--t-med) var(--ease);
}
.sheet-backdrop.show { opacity: 1; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 56;
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-bottom: none;
  border-radius: 22px 22px 0 0;
  box-shadow: var(--sh-3);
  padding: 8px 14px calc(18px + var(--safe-b));
  max-height: 82vh; overflow-y: auto;
  transform: translateY(101%);
  transition: transform .26s var(--ease);
}
.sheet.show { transform: translateY(0); }
.sheet-grip { width: 38px; height: 4px; border-radius: 999px; background: var(--border); margin: 6px auto 12px; }
.sheet-head { display: flex; align-items: center; gap: 8px; margin: 0 2px 12px; }
.sheet-title { font-size: .95rem; font-weight: 650; letter-spacing: -.02em; }
.sheet-sub { font-size: .72rem; color: var(--muted); margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sheet-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.sheet-action {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 11px 12px; cursor: pointer; color: var(--fg); font-family: inherit;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.sheet-action:hover { background: var(--bg-4); border-color: var(--accent); }
.sheet-action:active { transform: scale(.97); }
.sa-ico {
  width: 30px; height: 30px; border-radius: 9px; flex: none; display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent-2); font-size: .9rem;
}
.sa-ico.ok { background: var(--ok-dim); color: var(--ok); }
.sa-ico.warn { background: var(--warn-dim); color: var(--warn); }
.sa-ico.danger { background: var(--danger-dim); color: var(--danger); }
.sa-ico.info { background: var(--info-dim); color: var(--info); }
.sa-main { min-width: 0; }
.sa-title { font-size: .8rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sa-sub { font-size: .66rem; color: var(--faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ===================================================================
   DASHBOARD
   =================================================================== */
.dash {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior-y: contain;
  padding: 12px calc(12px + var(--safe-r)) 22px calc(12px + var(--safe-l));
  display: flex; flex-direction: column; gap: 16px;
  max-width: 1180px; width: 100%; margin-inline: auto;
}
.dash-sec { display: flex; flex-direction: column; gap: 8px; }
.sec-head { display: flex; align-items: baseline; gap: 8px; padding: 0 2px; }
.sec-title { font-size: .74rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--faint); }
.sec-link { margin-left: auto; font-size: .72rem; font-weight: 550; color: var(--accent-2); background: none; border: none; cursor: pointer; font-family: inherit; padding: 2px 4px; border-radius: 6px; }
.sec-link:hover { background: var(--accent-dim); }

/* pull-to-refresh indicator */
.ptr {
  height: 0; overflow: hidden; display: grid; place-items: center;
  color: var(--muted); font-size: .72rem; font-weight: 550;
  transition: height var(--t-med) var(--ease);
}
.ptr.armed { color: var(--accent-2); }
.ptr .ptr-spin { display: inline-block; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- current workspace card ---- */
.ws-card {
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--sh-2); overflow: hidden;
}
.wsc-top { display: flex; align-items: center; gap: 10px; padding: 13px 14px 11px; }
.wsc-sq {
  width: 38px; height: 38px; border-radius: 11px; flex: none; display: grid; place-items: center;
  background: linear-gradient(145deg, var(--accent), #4F3BCC); color: #fff;
  font-size: .82rem; font-weight: 750; letter-spacing: .01em;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.18);
}
.wsc-id { min-width: 0; flex: 1; }
.wsc-name { font-size: .98rem; font-weight: 650; letter-spacing: -.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wsc-path {
  font-family: var(--mono); font-size: .68rem; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left;
}
.wsc-path span { direction: ltr; unicode-bidi: bidi-override; }
.wsc-meta {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--border-soft);
}
.wsc-cell {
  padding: 9px 14px; min-width: 0;
  border-top: 1px solid var(--border-soft);
}
.wsc-cell:nth-child(-n+2) { border-top: none; }
.wsc-cell:nth-child(odd) { border-right: 1px solid var(--border-soft); }
.wsc-k { font-size: .62rem; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); margin-bottom: 3px; }
.wsc-v { font-size: .8rem; font-weight: 550; display: flex; align-items: center; gap: 6px; min-width: 0; }
.wsc-v .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wsc-v .mono { font-size: .76rem; }

/* ---- quick actions grid ---- */
.qa-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.qa-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px;
  aspect-ratio: 1 / .92; padding: 8px 4px;
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--r-md);
  color: var(--fg); font-family: inherit; cursor: pointer; box-shadow: var(--sh-1);
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.qa-tile:hover { border-color: #2E313C; background-color: var(--bg-3); }
.qa-tile:active { transform: scale(.95); }
.qa-ico {
  width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center;
  font-size: .95rem; background: var(--bg-3); color: var(--muted);
}
.qa-ico.ico-text { font-size: .68rem; font-weight: 750; letter-spacing: .03em; }
.qa-tile.p .qa-ico { background: var(--accent-dim); color: var(--accent-2); }
.qa-tile.g .qa-ico { background: var(--ok-dim); color: var(--ok); }
.qa-tile.w .qa-ico { background: var(--warn-dim); color: var(--warn); }
.qa-tile.d .qa-ico { background: var(--danger-dim); color: var(--danger); }
.qa-tile.i .qa-ico { background: var(--info-dim); color: var(--info); }
.qa-label { font-size: .66rem; font-weight: 600; color: var(--muted); text-align: center; line-height: 1.2; }
.qa-tile:hover .qa-label { color: var(--fg); }

/* ---- workspace health ---- */
.health-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
/* One card that owns the whole last row, at every breakpoint (4 cols, 2 cols).
   `1 / -1` rather than a span per media query: the column count changes twice
   and a hardcoded span would leave the hole back at one of them. */
.health-grid .hcard.hc-wide { grid-column: 1 / -1; }
.hcard {
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 10px 11px; box-shadow: var(--sh-1); min-width: 0;
}
.hc-top { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.hc-k { font-size: .62rem; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); }
.hc-tag { margin-left: auto; font-size: .6rem; font-weight: 650; color: var(--faint); font-family: var(--mono); }
.hc-v { font-size: 1.12rem; font-weight: 680; letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.hc-v .u { font-size: .68rem; font-weight: 550; color: var(--faint); margin-left: 2px; letter-spacing: 0; }
.hc-sub { font-size: .64rem; color: var(--faint); margin-top: 2px; font-family: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hc-bar { height: 4px; border-radius: 999px; background: var(--bg-4); overflow: hidden; margin-top: 7px; }
.hc-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width .45s var(--ease); min-width: 3px; }
.hc-fill.ok { background: var(--ok); }
.hc-fill.warn { background: var(--warn); }
.hc-fill.crit { background: var(--danger); }
/* service rows (docker / db / nginx / uptime) */
.svc-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.svc-row {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 8px 10px;
}
.svc-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--faint); }
.svc-dot.ok { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-dim); }
.svc-dot.warn { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-dim); }
.svc-dot.danger { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-dim); }
.svc-k { font-size: .74rem; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-v { margin-left: auto; font-size: .68rem; color: var(--muted); font-family: var(--mono); flex: none; }

/* ---- recent activity ---- */
.act-list {
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--sh-1);
}
.act-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border-top: 1px solid var(--border-soft); min-width: 0; cursor: default;
}
.act-row:first-child { border-top: none; }
.act-row.tap { cursor: pointer; transition: background var(--t-fast) var(--ease); }
.act-row.tap:hover { background: var(--bg-3); }
.act-ico {
  width: 26px; height: 26px; border-radius: 8px; flex: none; display: grid; place-items: center;
  font-size: .72rem; background: var(--bg-3); color: var(--muted);
}
.act-ico.ai { background: var(--accent-dim); color: var(--accent-2); }
.act-ico.git { background: var(--ok-dim); color: var(--ok); }
.act-ico.deploy { background: var(--info-dim); color: var(--info); }
.act-ico.term { background: var(--bg-4); color: var(--muted); }
.act-ico.warn { background: var(--warn-dim); color: var(--warn); }
.act-ico.err { background: var(--danger-dim); color: var(--danger); }
.act-main { min-width: 0; flex: 1; }
.act-title { font-size: .78rem; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-sub { font-size: .66rem; color: var(--faint); font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-when { font-size: .66rem; color: var(--faint); flex: none; font-variant-numeric: tabular-nums; }
.act-empty { padding: 20px 14px; text-align: center; font-size: .78rem; color: var(--faint); }

/* ---- pinned projects / favourite commands (horizontal chip rails) ---- */
.chip-rail { display: flex; gap: 7px; overflow-x: auto; padding: 1px 2px 4px; scrollbar-width: none; }
.chip-rail::-webkit-scrollbar { display: none; }
.pin-chip {
  flex: none; display: flex; align-items: center; gap: 8px; max-width: 62vw;
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px 12px 8px 9px; cursor: pointer; color: var(--fg); font-family: inherit;
  transition: border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.pin-chip:hover { border-color: var(--accent); }
.pin-chip:active { transform: scale(.97); }
.pin-sq {
  width: 26px; height: 26px; border-radius: 8px; flex: none; display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent-2); font-size: .62rem; font-weight: 750;
}
.pin-main { min-width: 0; text-align: left; }
.pin-name { font-size: .78rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pin-sub { font-size: .63rem; color: var(--faint); font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmd-chip {
  flex: none; background: var(--bg-3); border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 13px; font-family: var(--mono); font-size: .72rem; color: var(--muted);
  cursor: pointer; white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.cmd-chip:hover { color: var(--accent-2); border-color: var(--accent); }
.cmd-chip:active { transform: scale(.96); }

/* ---------- terminal ---------- */
.term-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--bg-2); flex: none; }
.term-status { margin-left: auto; font-size: .7rem; color: var(--faint); font-weight: 550; display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.term-status::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.term-status.on { color: var(--ok); }
.term-status.on::before { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-dim); }
/* "Claude is ready" is a binary fact — a green dot says it without eating the
   header width that the chat title and tabs need. The wording lives in title/
   aria-label so it is still available to a screen reader and on hover. */
.term-status.dot-only { gap: 0; }
.term-status.dot-only::before { width: 8px; height: 8px; }
.terminal-host { flex: 1; min-height: 0; padding: 8px 10px 4px 10px; background: #000; overflow: clip; }

/* THE ACTUAL FIX, after `overflow-x: hidden` failed to stop it.
   `hidden` REMOVES THE SCROLLBAR BUT KEEPS THE SCROLL CONTAINER — the browser
   can still scroll it programmatically, and that is precisely what "reveal the
   focused element" does. xterm parks its hidden input textarea AT THE CURSOR,
   so every keystroke near an edge slid the pane a few pixels and a character
   went behind the padding. Which letter vanished depended on where the cursor
   was, which is why it alternated between the first and the last.
   `clip` creates NO scroll container at all — there is nothing left to scroll.
   overflow-y stays `scroll`: the scrollback still needs it. */
/* NOTHING INSIDE THE TERMINAL CLIPS. The device reported 45 cols x 7.80px =
   351px painted into 362px available — 11px to spare, a full character — with
   scrollLeft 0, and the last glyph was STILL sliced in half. So the cut is not
   the container: it is a glyph overhanging its own cell box and meeting a clip
   edge. I had added two of those edges here (`overflow: clip` on .xterm-screen
   and .xterm-viewport) while chasing the scroll. They can only ever cut ink.
   The host still clips, 19px further out, so an overhang paints harmlessly
   into the padding instead of being trimmed.
   Sideways shifting stays prevented by the pinned helper textarea (below) and
   pinTermHorizontally() in app.js — neither of which clips anything. */

/* And remove the REASON to scroll: pin xterm's cursor-tracking textarea to the
   top-left so revealing it never demands a sideways shift. It is 0x0,
   opacity:0, z-index:-5 — invisible wherever it sits. */
.terminal-host .xterm-helper-textarea { left: 0 !important; top: 0 !important; }

/* MEASURED ON THE DEVICE: the prompt renders at 7.98px per character while
   xterm reports its cell as 7.80px — 2.3% wider than its own model. Over 45
   columns that drift is a whole cell, so the last character starts exactly
   where xterm's drawing box ends and only its left sliver survives. That is
   the "hidden letter", and it is why every container fix failed.
   The inflation is `body { letter-spacing: -0.01em }` being INHERITED here.
   xterm measures its cell with a DOM element — which gets the -0.13px per
   character — and then paints glyphs to a CANVAS, which ignores CSS
   letter-spacing entirely. It measures narrow and draws wide. A terminal is a
   grid; it must never inherit typographic spacing. */
.terminal-host, .terminal-host .xterm, .terminal-host .xterm * {
  letter-spacing: normal;
  word-spacing: normal;
  font-kerning: none;
  font-variant-ligatures: none;
}

/* runtime badges strip above the terminal */
.rt-badges { display: flex; gap: 6px; overflow-x: auto; padding: 6px 10px; border-bottom: 1px solid var(--border); background: var(--bg); scrollbar-width: none; flex: none; }
.rt-badges::-webkit-scrollbar { display: none; }
.rt-badges:empty { display: none; }

/* ---------- Claude chat ---------- */
.chat-layout { flex: 1; display: flex; min-height: 0; }
.chat-new { white-space: nowrap; }
.chat-list { list-style: none; margin: 0; padding: 0; }
.chat-item { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border-radius: var(--r-xs); cursor: pointer; transition: background var(--t-fast) var(--ease); }
.chat-item:hover { background: var(--bg-3); }
.chat-item.active { background: var(--accent-dim); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
.chat-item.active .ci-sub { color: var(--muted); }
.ci-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ci-title { font-size: .83rem; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ci-sub { font-size: .66rem; color: var(--faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ci-close { opacity: 0; font-size: .78rem; }
.chat-item:hover .ci-close { opacity: .55; }
.hist-empty { padding: 8px; font-size: .76rem; list-style: none; }

.ci-dot { width: 8px; height: 8px; min-width: 8px; border-radius: 50%; background: var(--faint); flex: 0 0 auto; }
.ci-dot.off { background: var(--faint); }
.ci-dot.ready { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-dim); }
.ci-dot.busy { background: var(--accent); animation: ci-dot-pulse 1.2s ease-in-out infinite; }
.ci-dot.perm { background: var(--warn); animation: ci-dot-pulse 1.2s ease-in-out infinite; }
@keyframes ci-dot-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.72); } }

.chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.chat-header { position: relative; display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-bottom: 1px solid var(--border); background: var(--bg-2); flex: none; }
.chat-title { font-weight: 600; font-size: .82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-usage { margin-left: auto; font-size: .68rem; font-family: var(--mono); color: var(--faint); }
.chat-header .term-status { margin-left: 8px; }
/* Smoothness in the chat pane, in the three places it was actually janky:
   - momentum scrolling + no scroll-chaining into the page behind it
   - streaming appends do not repaint messages already above the fold
   - a rubber-band at the ends instead of a hard stop
   `contain: content` is deliberately NOT used: the log holds sticky headers. */
.chat-log {
  flex: 1; overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
}
/* NB: no content-visibility here. The log has exactly ONE child (the active
   chat's container), so `content-visibility:auto` collapsed the whole
   transcript to its contain-intrinsic-size placeholder and scrollHeight went
   with it — every "am I at the bottom?" measurement then read as yes. */
@media (prefers-reduced-motion: reduce) { .chat-log { scroll-behavior: auto; } }

.chat-menu-btn {
  display: flex; align-items: center; gap: 6px; min-width: 0; max-width: 46%;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-xs);
  color: var(--fg); cursor: pointer; padding: 5px 8px; font: inherit;
}
.chat-menu-btn:hover { background: var(--bg-3); }
.cm-caret { color: var(--faint); font-size: .62rem; flex: 0 0 auto; }

.chat-menu {
  position: absolute; top: calc(100% + 6px); left: 8px; z-index: 45;
  width: 350px; max-width: calc(100vw - 16px); max-height: min(65vh, 480px); overflow-y: auto;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px; box-shadow: var(--sh-3);
}
.cm-group { font-size: .62rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 650; color: var(--faint); margin: 10px 6px 4px; }
.cm-group:first-child { margin-top: 2px; }
/* Claude Code setup: the MCP/plugin/slash inventory used to live in Settings
   only, so the tab the operator asked about looked untouched. */
.cm-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; margin-top: 8px; padding: 9px 10px; border: none; border-top: 1px solid var(--border-soft);
  background: none; color: var(--fg); font: inherit; font-size: .78rem; text-align: left; cursor: pointer;
  border-radius: 0 0 var(--r-sm) var(--r-sm); }
.cm-foot:hover { background: var(--bg-3); }
.cm-foot-v { font-size: .68rem; color: var(--faint); flex: none; }
.cm-foot-v.warn { color: var(--warn); }
.ci-main.row { flex-direction: row; align-items: baseline; gap: 8px; }
.ci-when { color: var(--faint); font-size: .68rem; font-family: var(--mono); margin-left: auto; flex: 0 0 auto; }
.hist-item .ci-title { flex: 1; min-width: 0; }

.chat-messages {
  display: flex; flex-direction: column; gap: 5px;
  padding: 14px 14px 16px;
  max-width: min(860px, 100%); margin-inline: auto; width: 100%;
  min-height: 100%; box-sizing: border-box;
}
.chat-empty { max-width: 560px; margin: 24px auto; text-align: center; line-height: 1.65; font-size: .85rem; }
.msg.user { margin-top: 16px; }
.msg.user:first-child { margin-top: 0; }
.msg.claude { margin-top: 8px; }
.chat-divider { text-align: center; color: var(--faint); font-size: .7rem; margin: 6px 0; position: relative; }
.chat-divider span { background: var(--bg); padding: 0 10px; }
.chat-divider::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; border-top: 1px dashed var(--border); z-index: -1; }

.msg { max-width: min(860px, 100%); width: fit-content; box-sizing: border-box; overflow-wrap: break-word; position: relative; }
.msg.claude {
  align-self: stretch; width: 100%; max-width: 100%;
  background: var(--bg-2); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); padding: 10px 13px 12px;
}
/* the three-dot placeholder is not a message — it gets no card */
.msg.claude.typing { background: none; border: none; padding: 0 0 0 2px; }
.msg.claude .msg-who { color: var(--accent-2); }
.msg.user {
  align-self: flex-end; max-width: 85%; width: fit-content;
  background: var(--user-bubble); color: var(--fg); padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 14px 14px 4px 14px;
}
.msg.user .msg-who { display: none; }
.msg.error { align-self: flex-start; color: var(--danger); border: 1px solid rgba(239,68,68,.4); background: var(--danger-dim); padding: 8px 11px; border-radius: var(--r-sm); }
.msg-who { font-size: .62rem; color: var(--muted); margin-bottom: 3px; font-weight: 700; font-family: var(--mono); text-transform: uppercase; letter-spacing: .07em; }
.md { font-size: .87rem; line-height: 1.58; }
.md-text { white-space: pre-wrap; word-break: break-word; }
.md code { background: var(--bg-3); border: 1px solid var(--border-soft); padding: 1px 5px; border-radius: 5px; font-family: var(--mono); font-size: .84em; }
.md pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 10px 12px; overflow-x: auto; font-size: .76rem; margin: 8px 0; line-height: 1.55; }
.msg pre { overflow-x: auto; max-width: 100%; }
.msg :not(pre) > code { overflow-wrap: anywhere; }
.chat-log, .chat-messages { overflow-x: hidden; }
html, body { overflow-x: hidden; }

/* collapsible tool row */
.msg.tool-row { align-self: stretch; width: 100%; max-width: 100%; background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-sm); font-size: .75rem; overflow: hidden; }
.tool-head { display: flex; align-items: center; gap: 8px; padding: 5px 9px; cursor: pointer; user-select: none; min-width: 0; }
.tool-head:hover { background: var(--bg-3); }
.tool-caret { color: var(--faint); font-size: .6rem; flex: 0 0 12px; text-align: center; transition: transform var(--t-fast) var(--ease); }
.tool-name { color: var(--accent-2); font-weight: 650; font-family: var(--mono); white-space: nowrap; flex: 0 0 auto; }
.tool-arg { color: var(--faint); font-family: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; }
.msg.tool-row.err .tool-name { color: var(--danger); }
.tool-body { border-top: 1px solid var(--border-soft); padding: 8px 9px; }
.tool-body pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 7px 9px; margin: 0; overflow: auto; font-size: .73rem; max-height: 240px; font-family: var(--mono); }
.tool-input { white-space: pre; }
.tool-res { margin-top: 7px; }
.tool-res-label { color: var(--faint); font-size: .62rem; text-transform: uppercase; letter-spacing: .07em; font-weight: 650; margin-bottom: 4px; font-family: var(--mono); }
.tool-res.err .tool-res-label { color: var(--danger); }

/* diff card */
.diff-card { font-family: var(--mono); font-size: .73rem; }
.diff-path { color: var(--faint); font-size: .69rem; margin-bottom: 5px; overflow-wrap: anywhere; }
.diff-block { border: 1px solid var(--border); border-radius: var(--r-xs); overflow: hidden; background: var(--code-bg); margin-bottom: 6px; }
.diff-block:last-child { margin-bottom: 0; }
.diff-line { padding: 1px 9px; white-space: pre-wrap; overflow-wrap: anywhere; min-height: 1.25em; line-height: 1.5; }
.diff-line.del { background: rgba(239, 68, 68, .11); border-left: 2px solid var(--danger); color: #F5B5B5; }
.diff-line.add { background: rgba(34, 197, 94, .11); border-left: 2px solid var(--ok); color: #A9E5C0; }
.diff-line.more { color: var(--faint); font-style: italic; }

.msg.tool-row.thinking-row .tool-name { color: var(--muted); font-weight: 550; }
.thinking-row .tool-body .md { font-size: .79rem; line-height: 1.55; color: var(--muted); }
.msg.typing .dots { color: var(--accent-2); letter-spacing: 2px; animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: .3; } 50% { opacity: 1; } }

/* ---------- composer ---------- */
.chat-input { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px 10px; border-top: 1px solid var(--border); background: var(--bg); position: sticky; bottom: 0; flex: none; }
.chat-attachments { display: flex; flex-wrap: wrap; gap: 6px; }
.chat-attachments:empty { display: none; }
.attach-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 4px 9px; font-size: .74rem; }
.attach-x { cursor: pointer; opacity: .55; }
.attach-x:hover { opacity: 1; }

.composer-box {
  display: flex; flex-direction: column; gap: 5px;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 6px 8px 6px 11px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.composer-box:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.chat-input textarea { resize: none; background: transparent; color: var(--fg); border: none; padding: 6px 2px; font-family: inherit; font-size: .89rem; line-height: 1.5; max-height: 160px; }
.chat-input textarea::placeholder { color: var(--faint); }
.chat-input textarea:focus { outline: none; }
/* wrap, always: this row grows by one control the moment Claude starts (■ Stop),
   and on a 360px phone that pushed Send clean outside the composer box. */
.composer-actions { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; row-gap: 6px; position: relative; }
.composer-actions > .btn { flex: none; }
.mm-native { display: none; }   /* the selects stay in the DOM as state, not UI */

/* ---- merged model + mode chip ---- */
.mm-chip {
  display: inline-flex; align-items: center; gap: 5px; flex: none; max-width: 62vw;
  background: var(--bg-3); border: 1px solid var(--border); border-radius: 999px;
  color: var(--muted); font-family: inherit; font-size: .72rem; font-weight: 550;
  padding: 4px 10px; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.mm-chip:hover, .mm-chip[aria-expanded="true"] { color: var(--fg); border-color: var(--accent); background: var(--bg-4); }
.mm-chip .mm-model { color: var(--accent-2); font-weight: 650; }
.mm-chip .mm-sep { color: var(--faint); }
/* Effort only appears when it is NOT the default, so it can afford to shout. */
.mm-chip .mm-effort { color: var(--warn); font-weight: 650; }
.mm-chip .mm-effort.hidden, .mm-chip .mm-sep.hidden { display: none; }
.mm-chip .mm-caret { color: var(--faint); font-size: .58rem; }
/* Plan mode is a promise that nothing will be written — make it loud. */
.mm-chip.plan { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.mm-chip.plan .mm-perm { color: var(--warn); font-weight: 650; }
.mm-chip.manual .mm-perm { color: var(--ok); font-weight: 650; }

.mm-menu {
  position: absolute; bottom: calc(100% + 8px); left: 0; z-index: 55;
  width: min(280px, calc(100vw - 32px)); padding: 8px;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: 0 18px 44px rgba(0,0,0,.55);
  animation: mm-in var(--t-fast) var(--ease);
}
.mm-menu.hidden { display: none; }
.mm-group {
  font-size: .62rem; text-transform: uppercase; letter-spacing: .09em; font-weight: 700;
  color: var(--faint); padding: 6px 6px 4px;
}
.mm-opts { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 2px 4px; }
.mm-opt {
  flex: 1 1 auto; min-width: 78px; text-align: left;
  background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-xs);
  color: var(--muted); font-family: inherit; font-size: .75rem; padding: 7px 9px; cursor: pointer;
  transition: all var(--t-fast) var(--ease);
}
.mm-opt:hover { color: var(--fg); border-color: #2E313C; background: var(--bg-4); }
.mm-opt.active { background: var(--accent-dim); border-color: rgba(124,92,255,.45); color: var(--fg); font-weight: 650; }
.mm-opt .mm-sub { display: block; font-size: .63rem; color: var(--faint); font-weight: 400; margin-top: 2px; }
.composer-select { background: var(--bg-3); color: var(--muted); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 4px 7px; font-size: .73rem; font-family: inherit; max-width: 130px; cursor: pointer; }
.composer-select:focus { outline: none; border-color: var(--accent); }
.composer-spacer { flex: 1; }

.composer-pop {
  position: absolute; left: 10px; right: 10px; bottom: 100%; margin-bottom: 7px; z-index: 46;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--sh-3); padding: 5px;
  max-height: min(46vh, 320px); overflow-y: auto; animation: pop .12s var(--ease);
}
.cp-head { font-size: .62rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 650; color: var(--faint); margin: 5px 7px 4px; }
.cp-item { display: flex; align-items: baseline; gap: 10px; padding: 7px 9px; border-radius: var(--r-xs); cursor: pointer; min-width: 0; }
.cp-item.active { background: var(--accent-dim); box-shadow: inset 2px 0 0 var(--accent); }
.cp-name { font-family: var(--mono); font-size: .8rem; flex: 0 0 auto; max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-hint { color: var(--faint); font-size: .71rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-foot { color: var(--faint); font-size: .66rem; margin: 4px 7px 2px; border-top: 1px solid var(--border-soft); padding-top: 5px; }
#btn-mic.rec { color: var(--danger); border-color: var(--danger); background: var(--danger-dim); animation: pulse 1.2s infinite; }

/* ---------- usage limits ---------- */
.usage-pill {
  background: var(--bg-2); border: 1px solid var(--border); color: var(--muted); border-radius: 999px;
  padding: 4px 11px; font-size: .72rem; font-weight: 600; cursor: pointer; white-space: nowrap;
  font-family: inherit; flex: none;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.usage-pill:hover { background: var(--bg-3); color: var(--fg); }
.usage-pill.warn { border-color: rgba(245,158,11,.4); color: var(--warn); background: var(--warn-dim); }
.usage-pill.crit { border-color: rgba(239,68,68,.4); color: var(--danger); background: var(--danger-dim); }
.usage-popover {
  position: absolute; top: calc(var(--topnav-h) + 4px); right: 12px; z-index: 40; width: 310px; max-width: 92vw;
  background: var(--bg-2); background-image: var(--wash); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px; box-shadow: var(--sh-3); animation: pop .14s var(--ease);
}
.up-title { font-weight: 650; font-size: .85rem; margin-bottom: 12px; letter-spacing: -.01em; }
.up-note { font-size: .78rem; }
.up-refresh { margin-top: 6px; }
.ubar { margin-bottom: 13px; }
.ubar-head { display: flex; justify-content: space-between; font-size: .75rem; margin-bottom: 5px; }
.ubar-label { color: var(--muted); font-weight: 550; }
.ubar-pct { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.ubar-track { height: 6px; background: var(--bg-4); border-radius: 999px; overflow: hidden; }
.ubar-fill { height: 100%; background: var(--ok); border-radius: 999px; transition: width .45s var(--ease); min-width: 3px; }
.ubar-fill.warn { background: var(--warn); }
.ubar-fill.crit { background: var(--danger); }
.ubar-reset { font-size: .66rem; color: var(--faint); margin-top: 4px; }

/* ---------- terminal key bar ---------- */
.key-bar { display: flex; gap: 6px; overflow-x: auto; padding: 7px 8px; border-top: 1px solid var(--border); background: var(--bg-2); -webkit-overflow-scrolling: touch; scrollbar-width: none; flex: none; }
.key-bar::-webkit-scrollbar { display: none; }
.key-bar .key {
  flex: 0 0 auto; min-width: 42px; height: 34px; background: var(--bg-3); border: 1px solid var(--border);
  color: var(--muted); border-radius: var(--r-xs); font-size: .8rem; cursor: pointer; font-family: var(--mono);
  transition: all var(--t-fast) var(--ease);
}
.key-bar .key:active { background: var(--accent); border-color: var(--accent); color: #fff; transform: scale(.94); }

/* ---------- tab icons ---------- */
.tab-ico { font-size: .95rem; }
.tab-ico.ico-text { font-size: .74rem; font-weight: 750; letter-spacing: .04em; text-transform: lowercase; }
.term-drawer-btn { margin-left: 2px; }

/* ---------- bottom terminal drawer ---------- */
.term-container { flex: 1; display: flex; flex-direction: column; min-height: 0; }
#tab-terminal.tabpane.active > .term-container { flex: 1; }
.term-drawer {
  /* DOCKED: a flex child of .workspace after the tab panes, so the active
     screen (flex:1; min-height:0) shrinks to what is left and nothing is
     covered. On phones .workspace's bottom padding keeps it above the nav. */
  position: relative; flex: none; height: 35dvh; z-index: 1;
  background: var(--bg); border-top: 1px solid var(--accent);
  display: flex; flex-direction: column; overflow: hidden;
}
.term-drawer.tall { height: 60dvh; }
.term-drawer.hidden { display: none; }
.term-drawer-head .icon-btn#btn-term-drawer-size { margin-left: auto; }
.term-drawer-head .icon-btn#btn-term-drawer-close { margin-left: 0; }
.peer-warn {
  flex: none; display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; background: var(--warn-dim); color: var(--warn);
  font-size: .74rem; line-height: 1.35; border-bottom: 1px solid var(--border);
}
.peer-warn.hidden { display: none; }
.peer-warn svg.ico { width: 15px; height: 15px; flex: none; }
.peer-warn > span { flex: 1; min-width: 0; }
.peer-warn .icon-btn { margin-left: auto; flex: none; }
.term-drawer-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg-2); border-bottom: 1px solid var(--border); font-size: .8rem; flex: none; }
.tdh-title { font-weight: 650; }
.tdh-project { color: var(--faint); font-size: .7rem; font-family: var(--mono); }
.term-drawer-head .icon-btn { margin-left: auto; }
.term-drawer-mount { flex: 1; min-height: 0; display: flex; }
.term-drawer-mount > .term-container { flex: 1; }

/* ---------- mobile drawer affordances ---------- */
.file-tree-open { display: none; }

/* ---------- scrollbars + motion ---------- */
* { scrollbar-width: thin; scrollbar-color: var(--bg-4) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: var(--bg-4); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: #33353F; background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }
.tabpane.active { animation: fadein .16s var(--ease); }
@keyframes fadein { from { opacity: .4; transform: translateY(2px); } to { opacity: 1; transform: none; } }
.msg { animation: msgin .16s var(--ease); }
@keyframes msgin { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.modal { animation: pop .16s var(--ease); }
@keyframes pop { from { opacity: 0; transform: scale(.97) translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------- files ---------- */
.files-layout { flex: 1; display: flex; min-height: 0; }
.file-tree-col { width: 300px; min-width: 220px; border-right: 1px solid var(--border); display: flex; flex-direction: column; background: var(--bg-2); }
.tree-toolbar { display: flex; gap: 2px; padding: 7px 8px; border-bottom: 1px solid var(--border-soft); flex: none; }
.file-tree { flex: 1; overflow: auto; padding: 6px 8px 12px; font-size: .82rem; }
.tree-node {
  padding: 4px 7px; border-radius: var(--r-xs); cursor: pointer; white-space: nowrap;
  display: flex; align-items: center; gap: 6px; color: var(--muted);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tree-node:hover { background: var(--bg-3); color: var(--fg); }
.tree-node.sel { background: var(--accent-dim); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
.tree-children { margin-left: 13px; border-left: 1px solid var(--border-soft); padding-left: 5px; }
.tree-node .caret { width: 10px; display: inline-block; color: var(--faint); font-size: .65rem; }
.tree-node .heavy { color: var(--faint); font-style: italic; }
/* git status badge on a tree row */
.tree-git { margin-left: auto; font-family: var(--mono); font-size: .64rem; font-weight: 700; flex: none; padding-left: 6px; }
.tree-git.m { color: var(--warn); }
.tree-git.a { color: var(--ok); }
.tree-git.d { color: var(--danger); }
.tree-git.u { color: var(--info); }

.file-edit-col { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.editor-head { display: flex; align-items: center; gap: 10px; padding: 7px 12px; border-bottom: 1px solid var(--border); background: var(--bg-2); flex: none; }
.editor-path { font-size: .78rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; font-family: var(--mono); }
.editor-actions { display: flex; align-items: center; gap: 8px; flex: none; }
.editor {
  flex: 1; width: 100%; resize: none; border: none; padding: 14px 16px;
  background: var(--bg); color: var(--fg); font-family: var(--mono);
  font-size: .83rem; line-height: 1.6; tab-size: 2;
}
.editor:focus { outline: none; }
.editor.hidden { display: none; }

/* ---------- modal / toast / settings ---------- */
.modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.66); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px; }
.modal { width: 100%; max-width: 430px; max-height: 86vh; overflow-y: auto; }
.modal h3 { margin: 0 0 14px; font-size: 1.02rem; font-weight: 650; letter-spacing: -.02em; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
.toast {
  position: fixed; bottom: calc(24px + var(--safe-b)); left: 50%; transform: translateX(-50%);
  background: var(--bg-3); border: 1px solid var(--border); padding: 11px 18px; border-radius: var(--r-md);
  font-size: .83rem; font-weight: 550; z-index: 60; box-shadow: var(--sh-3);
  animation: toastin .2s var(--ease); max-width: calc(100vw - 32px);
  /* A toast has nothing to click, and it sits exactly over the composer's
     button row on a phone: for the 3.2s it is up it was swallowing taps on
     Attach / paste / mic. Found by a hit test, never by looking at it. */
  pointer-events: none;
}
@keyframes toastin { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
.toast.err { border-color: rgba(239,68,68,.45); color: #FCA5A5; background: #1A1114; }
.settings-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border-soft); font-size: .83rem; gap: 8px; }

/* ---- Settings › Claude Code (v17 item 6b) ---- */
.set-sub { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 12px 0 5px; }
.mono-btn { font-family: var(--mono); font-weight: 700; }

/* ---- scheduled runs (v18) ---- */
.job-row { border: 1px solid var(--border); border-radius: var(--r-sm); padding: 9px 10px; margin-bottom: 8px; background: var(--bg-2); }
.job-row.off { opacity: .6; }
.job-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.job-at { font-family: var(--mono); font-weight: 700; color: var(--accent-2); }
.job-proj { font-size: .78rem; }
.job-mode { font-size: .64rem; padding: 1px 7px; border-radius: 999px; background: var(--bg-3); color: var(--muted); }
.job-prompt { font-size: .78rem; margin: 4px 0 2px; overflow-wrap: anywhere; }
.job-meta { font-size: .67rem; color: var(--faint); }
.job-out { margin: 6px 0 0; padding: 7px 8px; background: var(--code-bg); border-radius: var(--r-xs);
  font-family: var(--mono); font-size: .68rem; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 9em; overflow: auto; }
.job-acts { display: flex; gap: 6px; margin-top: 7px; flex-wrap: wrap; }
.job-form { margin-top: 10px; }
.job-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin: 6px 0; }
@media (max-width: 720px) { .job-grid { grid-template-columns: 1fr; } }

/* ---- terminal: native-selection sheet + the quiet watcher (v18) ---- */
/* In the FLOW, not position:fixed. A fixed overlay here is what covered the
   nav and made four unrelated suites time out on clicks. */
.term-select-sheet { flex: 1; min-height: 0; display: flex; flex-direction: column;
  background: var(--bg-2); border-top: 1px solid var(--border); }
.term-select-sheet.hidden { display: none; }
.term-container.selecting .terminal-host,
.term-container.selecting .term-toolbar .btn:not(#btn-select-term) { display: none; }
.tss-head { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 12px; font-size: .72rem; color: var(--muted); border-bottom: 1px solid var(--border); }
.tss-text { margin: 0; padding: 10px 12px; overflow: auto; flex: 1; min-height: 0;
  font-family: var(--mono); font-size: .72rem; line-height: 1.5; white-space: pre-wrap;
  overflow-wrap: anywhere; color: var(--fg);
  /* the entire point: the OS's own selection, which xterm cannot offer */
  user-select: text; -webkit-user-select: text; }
#btn-watch-term.on { color: var(--warn); border-color: var(--warn); background: rgba(245,158,11,.12); }
.slash-wrap { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.slash-chip { cursor: pointer; }
.slash-chip:hover { border-color: var(--accent); color: var(--accent-2); }
.slash-chip { font-family: var(--mono); font-size: .72rem; padding: 2px 7px; border: 1px solid var(--border); border-radius: 999px; color: var(--fg); background: var(--bg-2); }
.settings-row:last-child { border-bottom: none; }
.settings-row .meta { color: var(--faint); font-size: .72rem; }
.token-box { word-break: break-all; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 11px; font-family: var(--mono); font-size: .78rem; margin: 10px 0; }

/* ---------- copy buttons ---------- */
.copy-btn { background: var(--bg-3); color: var(--faint); border: 1px solid var(--border); border-radius: var(--r-xs); font-size: .76rem; line-height: 1; padding: 4px 7px; cursor: pointer; transition: color var(--t-fast) var(--ease); }
.copy-btn:hover { color: var(--fg); }
.msg-copy { position: absolute; top: 4px; right: 4px; opacity: 0; transition: opacity var(--t-fast); }
.msg:hover .msg-copy, .msg:focus-within .msg-copy { opacity: .85; }
.code-box { position: relative; }
.code-box pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r-sm); }
.code-copy { position: absolute; top: 8px; right: 8px; opacity: 0; transition: opacity var(--t-fast); }
.code-box:hover .code-copy { opacity: .85; }
.chat-export { font-size: 15px; }
.wake-btn { font-size: 15px; opacity: .55; }
.wake-btn.on { opacity: 1; color: var(--warn); }

/* ---------- permission card ---------- */
.msg.perm-req {
  align-self: flex-start; border: 1px solid rgba(245,158,11,.45); background: var(--bg-2);
  padding: 12px 13px; border-radius: var(--r-md); max-width: min(560px, 100%); box-sizing: border-box;
  box-shadow: var(--sh-2);
}
.msg.perm-req .msg-who { color: var(--warn); }
.perm-tool { font-weight: 650; margin-top: 3px; font-size: .85rem; }
.perm-arg { background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 7px 9px; margin: 8px 0; font-size: .76rem; font-family: var(--mono); overflow-x: auto; max-width: 100%; }
.perm-actions { display: flex; gap: 8px; margin-top: 10px; align-items: center; }
.perm-done { font-size: .82rem; }

/* ---------- chat editor tabs ---------- */
.chat-tabs { flex: 1 1 auto; min-width: 0; display: flex; align-items: stretch; overflow-x: auto; scrollbar-width: none; gap: 1px; align-self: stretch; }
.chat-tabs::-webkit-scrollbar { display: none; }
.ctab {
  display: flex; align-items: center; gap: 6px; padding: 5px 8px 5px 10px; cursor: pointer;
  border-right: 1px solid var(--border-soft); color: var(--faint); font-size: .78rem;
  white-space: nowrap; max-width: 180px; flex: 0 0 auto; border-top: 2px solid transparent;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.ctab:hover { background: var(--bg-3); color: var(--muted); }
.ctab.active { background: var(--bg); color: var(--fg); border-top-color: var(--accent); }
.ctab-title { overflow: hidden; text-overflow: ellipsis; max-width: 130px; font-weight: 550; }
.ctab-proj {
  flex: none; max-width: 76px; overflow: hidden; text-overflow: ellipsis;
  font-size: .64rem; letter-spacing: .02em; color: var(--faint);
  background: var(--bg-3); border: 1px solid var(--border-soft); border-radius: 5px;
  padding: 1px 5px; line-height: 1.55;
}
.ctab.active .ctab-proj { color: var(--muted); }
.ctab-proj.away { color: var(--accent-2); border-color: rgba(124,92,255,.4); background: var(--accent-dim); }
.ctab-close { opacity: 0; font-size: .74rem; padding: 1px 3px; border-radius: 4px; }
.ctab:hover .ctab-close, .ctab.active .ctab-close { opacity: .6; }
.ctab-close:hover { background: var(--bg-4); opacity: 1; }
.ctab .ci-dot { width: 7px; height: 7px; flex: none; box-shadow: none; }
.chat-menu-btn .chat-title { display: none; }

/* ---------- context pill ---------- */
.ctx-pill {
  margin-left: 8px; padding: 2px 8px; border-radius: 999px; font-size: .68rem; font-weight: 600;
  background: var(--bg-3); border: 1px solid var(--border); color: var(--muted); font-family: inherit;
}
.ctx-pill.warn { color: var(--warn); border-color: rgba(245,158,11,.4); background: var(--warn-dim); }
.ctx-pill.crit { color: var(--danger); border-color: rgba(239,68,68,.4); background: var(--danger-dim); }
button.ctx-pill { cursor: pointer; }
button.ctx-pill:hover { background: var(--bg-4); }

/* ---------- markdown ---------- */
.md-text { white-space: pre-wrap; overflow-wrap: break-word; line-height: 1.7; margin: 0 0 .85em; }
.md > *:first-child { margin-top: 0; }
.md > *:last-child { margin-bottom: 0; }
.md-h { font-weight: 700; margin: 17px 0 7px; line-height: 1.3; letter-spacing: -.02em; }
.md-h1 { font-size: 1.12rem; } .md-h2 { font-size: 1.02rem; }
.md-h3 { font-size: .93rem; } .md-h4 { font-size: .86rem; color: var(--muted); }
.md-list { margin: 0 0 .85em; padding-left: 21px; line-height: 1.7; }
.md-list li { margin: 4px 0; padding-left: 2px; }
.md-list li::marker { color: var(--faint); }
.md a {
  color: var(--accent-2); text-decoration: underline;
  text-decoration-color: rgba(159,135,255,.42); text-underline-offset: 2px;
  overflow-wrap: anywhere;   /* a bare URL is one unbreakable "word" */
}
.md a:hover { text-decoration-color: var(--accent-2); }
.md a:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; border-radius: 3px; }
.md-quote { border-left: 2px solid var(--accent); padding: 3px 13px; margin: 8px 0; color: var(--muted); background: rgba(124,92,255,.05); border-radius: 0 var(--r-xs) var(--r-xs) 0; }
.md-hr { border: none; border-top: 1px solid var(--border); margin: 14px 0; }
.md-table-wrap { overflow-x: auto; max-width: 100%; margin: 10px 0; border: 1px solid var(--border); border-radius: var(--r-sm); }
.md-table { border-collapse: collapse; font-size: .8rem; min-width: 100%; }
.md-table th, .md-table td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border-soft); }
.md-table th { background: var(--bg-3); font-weight: 650; white-space: nowrap; position: sticky; top: 0; }
.md-table tr:last-child td { border-bottom: none; }
.md-table tbody tr:nth-child(even) { background: rgba(255,255,255,.018); }
.md-table td { vertical-align: top; }
.queued-note { align-self: flex-end; font-size: .69rem; margin-top: -8px; color: var(--faint); }

/* ---------- images in a message ---------- */
.md-img { max-width: 100%; height: auto; border-radius: var(--r-sm); border: 1px solid var(--border); display: block; margin: 8px 0; }
.msg-images { display: flex; flex-wrap: wrap; gap: 7px; margin: 2px 0 7px; }
.msg-images:last-child { margin-bottom: 0; }
.msg-img {
  padding: 0; border: 1px solid var(--border); background: var(--code-bg);
  border-radius: var(--r-sm); overflow: hidden; cursor: zoom-in; line-height: 0;
  transition: border-color var(--t-fast) var(--ease);
}
.msg-img:hover { border-color: var(--accent); }
.msg-img img { display: block; max-width: 190px; max-height: 190px; width: auto; height: auto; object-fit: contain; }
.msg-files { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 7px; }
.attach-chip.static { background: var(--bg-2); color: var(--muted); max-width: 100%; }
.attach-chip { max-width: 240px; }
.attach-chip .ico-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* composer: the picked image, not its filename */
.attach-thumb {
  position: relative; width: 60px; height: 60px; border-radius: var(--r-xs);
  overflow: hidden; border: 1px solid var(--border); background: var(--code-bg);
}
.attach-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; cursor: zoom-in; }
.attach-x.thumb-x {
  position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; padding: 0;
  display: grid; place-items: center; border: none; border-radius: 50%;
  background: rgba(0,0,0,.66); color: #fff; font-size: .62rem; line-height: 1; opacity: .85;
}
.attach-x.thumb-x:hover { opacity: 1; background: var(--danger); }

/* ---------- image lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 59; background: rgba(0,0,0,.88);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 14px; cursor: zoom-out;
  animation: fadein .14s var(--ease);
}
.lightbox-bar { display: flex; align-items: center; gap: 10px; max-width: 100%; }
.lightbox-name { color: var(--muted); font-size: .76rem; font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lightbox-img { max-width: 100%; max-height: calc(100% - 52px); object-fit: contain; border-radius: var(--r-sm); cursor: default; }
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }

/* ---------- directory picker (add a project) ---------- */
.pick-row { display: flex; align-items: flex-start; gap: 10px; padding: 9px 4px; cursor: pointer; }
.pick-row input { margin-top: 3px; accent-color: var(--accent); width: 17px; height: 17px; flex: 0 0 auto; }
.pick-main { min-width: 0; }
.pick-title { font-size: .84rem; font-weight: 600; }
.pick-sub { font-size: .74rem; color: var(--muted); margin-top: 2px; line-height: 1.45; }
.pick-where {
  font-family: var(--mono); font-size: .72rem; color: var(--accent-2);
  padding: 6px 8px; background: var(--bg-3); border-radius: var(--r-xs);
  margin-bottom: 7px; overflow-wrap: anywhere;
}
.pick-list {
  max-height: 46vh; overflow-y: auto; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--bg-2);
}
.pick-item {
  display: flex; align-items: center; gap: 8px; padding: 9px 10px; cursor: pointer;
  border-bottom: 1px solid var(--border-soft); font-size: .8rem;
}
.pick-item:last-child { border-bottom: none; }
.pick-item:hover { background: var(--bg-3); }
.pick-item.up { color: var(--muted); font-family: var(--mono); font-size: .75rem; }
.pick-item.dim { opacity: .6; }
.pick-ico { display: inline-flex; color: var(--faint); flex: 0 0 auto; }
.pick-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-tag {
  margin-left: auto; font-size: .6rem; font-family: var(--mono); text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint); border: 1px solid var(--border);
  border-radius: 4px; padding: 0 4px; flex: 0 0 auto;
}
.pick-tag.added { color: var(--ok); border-color: rgba(34,197,94,.35); }
.pick-tag.ro { color: var(--warn); border-color: rgba(245,158,11,.35); }
.pick-warn {
  margin-top: 6px; padding: 7px 9px; font-size: .72rem; line-height: 1.5;
  color: var(--fg); background: var(--warn-dim);
  border: 1px solid rgba(245,158,11,.4); border-radius: var(--r-xs);
  font-family: var(--sans, inherit); white-space: normal;
}
.pick-empty { padding: 14px; text-align: center; font-size: .78rem; }
.pick-or { text-align: center; font-size: .7rem; margin: 8px 0 6px; }
.pick-manual { font-family: var(--mono); font-size: .76rem; }

/* ---------- process task manager ---------- */
.proc-sort { display: flex; gap: 4px; margin-left: auto; }
.proc-sort .sec-link { padding: 2px 8px; border-radius: var(--r-xs); }
.proc-sort .sec-link.on { background: var(--accent-dim); color: var(--accent-2); }

.proc-actions {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 7px 9px; margin-bottom: 7px;
  background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-sm);
  position: sticky; top: 0; z-index: 2;
}
.proc-actions.hidden { display: none; }
.proc-count { font-size: .76rem; color: var(--accent-2); font-weight: 650; margin-right: auto; }
.btn.danger-out { color: var(--danger); border-color: rgba(239,68,68,.4); }
.btn.danger-out:hover { background: var(--danger-dim); }

.proc-list { display: flex; flex-direction: column; gap: 2px; }
.proc-row {
  display: flex; align-items: flex-start; gap: 9px; padding: 7px 8px;
  border: 1px solid transparent; border-radius: var(--r-xs); cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}
.proc-row:hover { background: var(--bg-2); }
.proc-row.sel { background: var(--accent-dim); border-color: var(--accent-ring); }
/* Not ours to signal: readable, obviously inert, and it says why on hover. */
.proc-row.locked { cursor: default; opacity: .62; }
.proc-row.locked:hover { background: none; }
.proc-check { flex: 0 0 auto; margin-top: 3px; accent-color: var(--accent); width: 16px; height: 16px; }
.proc-check:disabled { cursor: not-allowed; }
.proc-main { flex: 1 1 auto; min-width: 0; }
.proc-title { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.proc-name { font-size: .81rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proc-user {
  font-size: .62rem; font-family: var(--mono); color: var(--faint);
  border: 1px solid var(--border); border-radius: 4px; padding: 0 4px; flex: 0 0 auto;
}
.proc-user.mine { color: var(--ok); border-color: rgba(34,197,94,.35); }
/* Reachable, but only by asking root — visually distinct from "ours", because
   it is not the same act and the confirm step says so too. */
.proc-user.viaroot { color: var(--warn); border-color: rgba(245,158,11,.38); }
.kill-warn {
  margin: 9px 0 4px; padding: 9px 11px; font-size: .78rem; line-height: 1.55;
  border: 1px solid rgba(245,158,11,.4); background: var(--warn-dim);
  border-radius: var(--r-sm); color: var(--fg);
}
.kill-warn strong { display: block; margin-bottom: 3px; color: var(--warn); }
.proc-sub { font-size: .69rem; color: var(--faint); font-family: var(--mono); margin-top: 2px; }
.proc-cmd {
  font-size: .67rem; color: var(--faint); font-family: var(--mono); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .8;
}
.proc-nums { flex: 0 0 auto; text-align: right; font-family: var(--mono); }
.proc-n { font-size: .76rem; }
.proc-n.dim { font-size: .66rem; color: var(--faint); margin-top: 2px; }
.proc-n.hot { color: var(--warn); font-weight: 650; }

.modal-list { margin: 8px 0; padding-left: 20px; font-size: .78rem; font-family: var(--mono); line-height: 1.6; }
.modal-list li { margin: 2px 0; overflow-wrap: anywhere; }

@media (max-width: 720px) {
  .proc-cmd { display: none; }   /* argv is desktop-only detail */
  .proc-row { padding: 8px 6px; }
  .proc-check { width: 20px; height: 20px; }   /* thumb target */
}

/* ---------- file preview ---------- */
.file-preview { flex: 1; min-height: 0; overflow: auto; background: var(--code-bg); display: flex; flex-direction: column; gap: 10px; padding: 14px; }
.file-preview.hidden { display: none; }
.preview-wrap {
  position: relative; flex: 1; min-height: 220px; width: 100%; overflow: hidden;
  touch-action: none; overscroll-behavior: contain;
  cursor: grab; user-select: none; -webkit-user-select: none;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background-image: linear-gradient(45deg, #17181F 25%, transparent 25%), linear-gradient(-45deg, #17181F 25%, transparent 25%),
                    linear-gradient(45deg, transparent 75%, #17181F 75%), linear-gradient(-45deg, transparent 75%, #17181F 75%);
  background-size: 16px 16px; background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}
.preview-wrap.zoomed { cursor: move; }
.preview-wrap:active { cursor: grabbing; }
.preview-img { position: absolute; top: 0; left: 0; transform-origin: 0 0; max-width: none; max-height: none; -webkit-user-drag: none; user-select: none; image-orientation: from-image; }
.preview-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: none; }
.zoom-btn { min-width: 38px; font-variant-numeric: tabular-nums; }
.preview-pct { font-size: .74rem; color: var(--muted); min-width: 42px; text-align: center; font-variant-numeric: tabular-nums; }
.preview-dim { font-size: .71rem; margin-right: 4px; }
.preview-frame { width: 100%; flex: 1; min-height: 320px; border: 1px solid var(--border); border-radius: var(--r-sm); background: #fff; }
.preview-note { color: var(--faint); font-size: .74rem; }

/* ---------- project search ---------- */
.tree-search { display: flex; gap: 4px; align-items: center; padding: 0 8px 8px; flex: none; }
.tree-search .input { flex: 1; min-width: 0; }
.input.tiny { padding: 6px 9px; font-size: .78rem; }
.find-results { flex: 1; overflow: auto; padding: 4px 7px 12px; font-size: .79rem; }
.find-results.hidden, .file-tree.hidden { display: none; }
.find-meta { color: var(--faint); font-size: .71rem; padding: 4px 4px 8px; }
.find-file { color: var(--accent-2); font-family: var(--mono); font-size: .73rem; margin: 9px 0 3px; overflow-wrap: anywhere; font-weight: 550; }
.find-hit { display: flex; gap: 8px; padding: 4px 6px; border-radius: 6px; cursor: pointer; align-items: baseline; }
.find-hit:hover { background: var(--bg-3); }
.find-line { color: var(--faint); font-size: .69rem; min-width: 30px; text-align: right; flex: none; font-variant-numeric: tabular-nums; }
.find-text { font-family: var(--mono); font-size: .73rem; white-space: pre-wrap; overflow-wrap: anywhere; min-width: 0; }
.find-mark { background: rgba(124,92,255,.3); color: #fff; border-radius: 3px; padding: 0 1px; }

/* ---------- git panel ---------- */
.git-layout { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.git-head { display: flex; align-items: center; gap: 9px; padding: 9px 12px; border-bottom: 1px solid var(--border); background: var(--bg-2); flex: none; }
.git-branch { font-weight: 650; font-size: .85rem; display: inline-flex; align-items: center; gap: 6px; }
.git-head .muted { font-size: .72rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono); }
/* PR strip: one line when there is nothing to say, a small list when there is. */
.git-pr { flex: none; padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--bg-2); font-size: .75rem; display: flex; flex-direction: column; gap: 6px; }
.git-pr-note { color: var(--faint); line-height: 1.45; }
.git-pr-note code { font-family: var(--mono); font-size: .95em; color: var(--muted); }
.git-pr-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.git-pr-num { font-family: var(--mono); color: var(--accent-2); font-weight: 600; flex: none; text-decoration: none; }
.git-pr-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg); }
.git-pr-meta { margin-left: auto; flex: none; display: flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: .68rem; color: var(--faint); }
.git-pr-chip { padding: 1px 6px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-3); }
.git-pr-chip.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
.git-pr-chip.bad { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.git-pr-chip.wait { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, var(--border)); }
.git-pr-chip.draft { color: var(--faint); }
.git-pr-mine { background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 7px 9px; }
.git-pr-more { background: none; border: none; color: var(--accent-2); font-family: inherit; font-size: .72rem; cursor: pointer; padding: 0; align-self: flex-start; }

/* ONE scroll region, not three. The old layout capped the file list at a
   percentage of the pane and let the diff take the rest, which on a phone left
   a dead half-screen under the commit box and a nested scroller inside a
   scrolling page. Changes and history now share a single column. */
.git-scroll { flex: 1; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch; }
.git-files { padding: 6px 8px; }
.git-sec-head { display: flex; align-items: center; justify-content: space-between;
  padding: 12px 12px 4px; border-top: 1px solid var(--border-soft); margin-top: 8px;
  font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.git-log { padding: 2px 8px 10px; }
.gl-row { padding: 7px 7px; border-radius: var(--r-xs); }
.gl-row:nth-child(odd) { background: var(--bg-2); }
.gl-top { display: flex; gap: 8px; align-items: baseline; }
.gl-sha { font-family: var(--mono); font-size: .68rem; color: var(--accent-2); flex: none; }
.gl-subject { font-size: .79rem; overflow-wrap: anywhere; }
.gl-meta { font-size: .67rem; color: var(--faint); margin-top: 2px; }
.gl-ref { margin-left: 6px; padding: 1px 6px; border-radius: 999px; font-size: .62rem;
  background: var(--accent-dim); color: var(--accent-2); }
.git-empty { padding: 18px 14px; font-size: .82rem; text-align: center; color: var(--faint); }
.git-row { display: flex; align-items: center; gap: 9px; padding: 6px 7px; border-radius: var(--r-xs); cursor: pointer; transition: background var(--t-fast) var(--ease); }
.git-row:hover { background: var(--bg-3); }
.git-cb { flex: none; width: 16px; height: 16px; accent-color: var(--accent); }
/* v17 item 3: a WORD, not a porcelain code. Fixed width so the filenames still
   line up into a column you can scan. */
.git-st { font-size: .66rem; font-weight: 700; flex: none; width: 74px; text-align: center;
          border-radius: 999px; padding: 2px 0; text-transform: lowercase; letter-spacing: .02em; }
.git-st.staged { color: var(--ok); background: rgba(34,197,94,.12); }
.git-st.unstaged { color: var(--warn); background: rgba(245,158,11,.12); }
.git-st.untracked { color: var(--info); background: rgba(56,189,248,.12); }
.git-st.conflict { color: var(--danger); background: rgba(239,68,68,.14); font-weight: 800; }
.git-path { font-size: .78rem; font-family: var(--mono); overflow-wrap: anywhere; min-width: 0; }
.gp-dir { color: var(--faint); }
.gp-name { color: var(--fg); }
.git-note { font-size: .66rem; color: var(--faint); flex: none; }
.git-group { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
             margin: 10px 0 3px; padding: 0 7px; }
.git-group:first-child { margin-top: 2px; }
.git-summary { font-size: .74rem; }
.git-diff { border: 1px solid var(--border); border-radius: var(--r-sm); margin: 6px 8px 2px;
  background: var(--code-bg); overflow: auto; max-height: 60vh; }
.git-diff.hidden { display: none; }
.git-diff-head { position: sticky; top: 0; background: var(--bg-2); padding: 7px 12px; font-size: .74rem; font-family: var(--mono); border-bottom: 1px solid var(--border);
                 display: flex; align-items: center; gap: 8px; z-index: 1; }
.gd-path { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.gd-close { flex: none; }
.git-diff-body { margin: 0; padding: 8px 0; font-family: var(--mono); font-size: .71rem; line-height: 1.5; overflow-x: auto; }
.git-diff-body > div { padding: 0 12px; white-space: pre; }
.dl-add { background: rgba(34,197,94,.12); color: #A9E5C0; }
.dl-del { background: rgba(239,68,68,.12); color: #F5B5B5; }
.dl-hunk { color: var(--accent-2); background: rgba(124,92,255,.08); }
.dl-ctx { color: var(--muted); }
.git-commit { border-top: 1px solid var(--border); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; flex: none; background: var(--bg-2); }
@supports (padding: max(0px)) { .git-commit { padding-bottom: max(10px, var(--safe-b)); } }
.git-message { width: 100%; resize: vertical; background: var(--bg); color: var(--fg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 9px 11px; font-size: .83rem; font-family: inherit; transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.git-message::placeholder { color: var(--faint); }
.git-message:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.git-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.git-all { font-size: .73rem; color: var(--muted); display: flex; align-items: center; gap: 6px; cursor: pointer; }
.git-out { font-size: .71rem; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 4.5em; overflow: auto; font-family: var(--mono); }

/* ---------- quick-prompt chips ---------- */
.quick-prompts { display: flex; gap: 6px; overflow-x: auto; padding: 0 2px 5px; scrollbar-width: none; }
.quick-prompts::-webkit-scrollbar { display: none; }
.quick-chip {
  flex: none; background: var(--bg-3); color: var(--muted); border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 12px; font-size: .74rem; font-family: inherit; font-weight: 550;
  cursor: pointer; white-space: nowrap; max-width: 42vw; overflow: hidden; text-overflow: ellipsis;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.quick-chip:hover { border-color: var(--accent); color: var(--accent-2); }
.quick-manage { color: var(--faint); padding: 5px 11px; }
.quick-rows { max-height: 34vh; overflow: auto; margin-bottom: 10px; }
.check-row { font-size: .79rem; color: var(--muted); display: flex; align-items: center; gap: 7px; margin: 10px 0 4px; cursor: pointer; }
.check-row input { accent-color: var(--accent); width: 16px; height: 16px; }

/* ===================================================================
   RESPONSIVE — phone is the primary target
   =================================================================== */
@media (max-width: 900px) {
  .qa-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .health-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  /* --- chrome --- */
  .tabs { display: none; }                 /* bottom nav owns navigation */
  .bottomnav { display: flex; }
  .workspace { padding-bottom: calc(var(--bottomnav-h) + var(--safe-b)); }
  .fab { bottom: calc(var(--bottomnav-h) + var(--safe-b) + 16px); }
  .toast { bottom: calc(var(--bottomnav-h) + var(--safe-b) + 16px); }
  .topbar { padding: 0 8px 0 4px; gap: 4px; }
  .current-project { display: none; }      /* the workspace chip carries it */
  /* The bottom nav already has a Terminal destination; a second entry point
     here just squeezed the workspace chip down to three letters. */
  .term-drawer-btn { display: none; }
  .ws-chip { max-width: 52vw; }
  .usage-pill { padding: 4px 9px; font-size: .69rem; }
  .conn .conn-label { display: none; }
  .conn { padding: 5px 7px; }

  .brand.small { display: flex; align-items: center; }

  /* --- dashboard density --- */
  /* Bottom padding clears the FAB: it is fixed, so without this the last card
     in the scroll can never be fully read. */
  .dash { padding: 10px 10px 86px; gap: 14px; }
  .qa-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; }
  .qa-tile { aspect-ratio: 1 / 1; gap: 6px; }
  .qa-ico { width: 30px; height: 30px; }
  .qa-label { font-size: .6rem; }
  .health-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
  .wsc-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* --- git: thumb-sized rows, and room to actually read the list --- */
  .git-row { padding: 10px 7px; gap: 10px; }
  .git-cb { width: 20px; height: 20px; }
  /* No inner cap on a phone: the whole column scrolls as one. */
  .git-files { max-height: none; }
  /* The diff sits IN the column, under the file it belongs to. It was briefly
     an overlay sheet; that covered the list, so after reading a diff you could
     not tick the file it described — the one flow this screen exists for.
     Four QA suites found it as a 30s click timeout, which reads like anything
     except a CSS bug. */
  .git-diff-head { padding: 12px; font-size: .8rem; }
  .gd-close { width: 34px; height: 34px; font-size: 1rem; }
  .git-st { width: 66px; }

  /* --- chat --- */
  .chat-main { position: relative; }
  .chat-menu { left: 6px; right: 6px; width: auto; }
  .chat-header { gap: 6px; padding: 4px 7px; }
  .chat-header .term-status { white-space: nowrap; margin-left: 4px; }
  .chat-usage { display: none; }
  .chat-new { padding: 5px 8px; }
  .cp-foot { display: none; }
  .composer-pop { left: 6px; right: 6px; }
  .chat-messages { padding: 12px 10px 14px; gap: 5px; }
  .msg.claude { padding: 9px 11px 11px; }
  .msg-img img { max-width: 132px; max-height: 132px; }
  .msg-copy { opacity: .5; }
  .code-copy { opacity: .5; }
  .ctab { max-width: 175px; }
  .ctab-title { max-width: 84px; }
  .ctab-proj { max-width: 56px; }
  .ctab-close { opacity: .6; }

  /* --- files --- */
  .files-layout { position: relative; }
  .file-tree-col {
    position: absolute; z-index: 15; height: 100%; width: 84%; max-width: 320px;
    background: var(--bg-2); transform: translateX(-100%); transition: transform .22s var(--ease);
    border-right: 1px solid var(--border);
  }
  #files-layout.tree-open .file-tree-col { transform: translateX(0); box-shadow: var(--sh-3); }
  .file-tree-open { display: inline-flex; margin-right: 4px; }

  /* --- git --- */
  /* No max-height here either. There were TWO mobile rules capping this list
     (46% and 40%); removing one left the other in charge and the pane still
     scrolled inside a scroll. */
  .git-files { max-height: none; }
  .git-head { padding: 8px 10px; }

  /* --- terminal --- */
  /* The toolbar carries four buttons on a phone and "connected · devspace" was
     the first thing to get clipped — and the least informative, since the dot
     already says it. Text is hidden, not removed: title + aria-label keep it. */
  .term-toolbar .term-status { font-size: 0; gap: 0; }
  .term-toolbar .term-status::before { width: 9px; height: 9px; }
  /* It is a tap target now (geometry diagnostic), so give it a thumb-sized
     hit area without making the dot itself bigger. */
  .term-toolbar .term-status { padding: 10px 8px; margin-right: -4px; }
  /* Symmetric padding: the 10px/4px asymmetry ate into the width the fit addon
     measures, which is half of why the last column was clipped. */
  /* Modest, symmetric. The oversized gutter here was compensating for the
     horizontal scroll fixed above, not for a real sizing problem. */
  /* A wider LEFT gutter too, while the first-column report is outstanding: if
     anything still shifts the pane by a fraction of a cell, the first glyph
     lands in padding instead of under it. */
  .terminal-host { padding: 6px 8px 4px 14px; }

  /* --- misc --- */
  .usage-popover { right: 6px; top: calc(var(--topnav-h) + 2px); }
  .sheet-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pin-chip { max-width: 72vw; }
}

/* narrow phones */
@media (max-width: 400px) {
  .topbar { gap: 4px; padding: 0 6px 0 2px; }
  .ws-chip { max-width: 40vw; padding: 5px 9px 5px 6px; }
  .usage-pill { padding: 4px 7px; font-size: .66rem; }
  .composer-actions { gap: 5px; }
  .composer-select { max-width: 100px; padding: 4px 5px; font-size: .71rem; }
  #btn-attach { padding: 5px 7px; }
  #chat-send { padding: 6px 11px; }
  .qa-grid { gap: 6px; }
  .qa-label { font-size: .57rem; }
  .bn-label { font-size: .58rem; }
  .fab { width: 50px; height: 50px; font-size: 1.25rem; right: 13px; }
}

/* wide desktop: give the dashboard real estate */
@media (min-width: 1100px) {
  .qa-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); }
  .health-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .svc-list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* 6 facts: 3 columns gives two full rows. 4 columns left a ragged half-empty
     second row, which read as missing data rather than as layout. */
  .wsc-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .wsc-cell:nth-child(-n+3) { border-top: none; }
  .wsc-cell:nth-child(odd) { border-right: none; }
  .wsc-cell:not(:nth-child(3n)) { border-right: 1px solid var(--border-soft); }
  .sheet { left: 50%; transform: translate(-50%, 101%); max-width: 560px; border-radius: 22px 22px 0 0; }
  .sheet.show { transform: translate(-50%, 0); }
  .sheet-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ===================================================================
   v13.1 / phase 2 — universal search, sparklines, deploy, logs
   =================================================================== */

/* ---------------------- universal search palette ------------------- */
.search-backdrop {
  position: fixed; inset: 0; z-index: 58;
  background: rgba(0, 0, 0, .66);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 8vh 14px 14px;
  animation: fadein .12s var(--ease);
}
.search-panel {
  width: 100%; max-width: 660px; max-height: 78vh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--sh-3); animation: pop .14s var(--ease);
}
.search-bar { display: flex; align-items: center; gap: 9px; padding: 11px 12px; border-bottom: 1px solid var(--border); flex: none; }
.search-ico { font-size: .9rem; opacity: .6; flex: none; }
.search-input {
  flex: 1; min-width: 0; background: transparent; border: none; color: var(--fg);
  font-family: inherit; font-size: .96rem; letter-spacing: -.01em;
}
.search-input:focus { outline: none; }
.search-input::placeholder { color: var(--faint); }

.search-scopes { display: flex; gap: 6px; overflow-x: auto; padding: 8px 12px; border-bottom: 1px solid var(--border-soft); flex: none; scrollbar-width: none; }
.search-scopes::-webkit-scrollbar { display: none; }
.scope-chip {
  flex: none; background: var(--bg-3); border: 1px solid var(--border); color: var(--muted);
  border-radius: 999px; padding: 4px 11px; font-size: .71rem; font-weight: 600;
  font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.scope-chip:hover { color: var(--fg); }
.scope-chip.on { background: var(--accent-dim); border-color: rgba(124,92,255,.45); color: var(--accent-2); }

.search-results { flex: 1; min-height: 0; overflow-y: auto; padding: 6px; }
.sr-group { font-size: .62rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 700; color: var(--faint); margin: 10px 8px 4px; display: flex; gap: 8px; align-items: baseline; }
.sr-group:first-child { margin-top: 3px; }
.sr-group .sr-n { color: var(--border); font-weight: 600; }
.sr-item {
  display: flex; align-items: center; gap: 10px; padding: 7px 9px; border-radius: var(--r-xs);
  cursor: pointer; min-width: 0; border: 1px solid transparent;
}
.sr-item:hover { background: var(--bg-3); }
.sr-item.active { background: var(--accent-dim); border-color: rgba(124,92,255,.35); }
.sr-ico { width: 24px; height: 24px; border-radius: 7px; flex: none; display: grid; place-items: center; font-size: .66rem; background: var(--bg-3); color: var(--muted); }
.sr-ico.file { background: var(--bg-4); }
.sr-ico.code { background: var(--warn-dim); color: var(--warn); }
.sr-ico.commit { background: var(--ok-dim); color: var(--ok); }
.sr-ico.chat { background: var(--accent-dim); color: var(--accent-2); }
.sr-ico.log { background: var(--info-dim); color: var(--info); }
.sr-ico.project { background: var(--accent-dim); color: var(--accent-2); }
.sr-ico.cmd { background: var(--bg-4); color: var(--muted); }
.sr-main { min-width: 0; flex: 1; }
.sr-title { font-size: .82rem; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sr-sub { font-size: .67rem; color: var(--faint); font-family: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sr-tag { font-size: .62rem; color: var(--faint); flex: none; font-family: var(--mono); }
.sr-hit { background: rgba(124,92,255,.28); color: #fff; border-radius: 3px; padding: 0 1px; }
.search-empty { padding: 26px 14px; text-align: center; color: var(--faint); font-size: .8rem; line-height: 1.6; }
.search-foot { display: flex; align-items: center; gap: 10px; padding: 7px 12px; border-top: 1px solid var(--border-soft); flex: none; }
.sf-keys { font-size: .66rem; color: var(--faint); }
.sf-keys kbd {
  font-family: var(--mono); font-size: .62rem; background: var(--bg-3);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 4px; margin-right: 2px;
}
.sf-count { margin-left: auto; font-size: .66rem; color: var(--faint); font-family: var(--mono); }
@media (max-width: 720px) {
  .search-backdrop { padding: 0; }
  .search-panel { max-width: none; max-height: 100dvh; height: 100dvh; border-radius: 0; border: none; }
  .sf-keys { display: none; }     /* no physical keyboard to hint at */
  .search-bar { padding: 12px 12px calc(12px); }
}

/* ------------------------------ sparklines ------------------------- */
.hc-spark { display: block; width: 100%; height: 26px; margin-top: 6px; overflow: visible; }
.hc-spark .sp-line { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.hc-spark .sp-area { fill: url(#spark-fade); opacity: .5; }
.hc-spark.ok .sp-line { stroke: var(--ok); }
.hc-spark.warn .sp-line { stroke: var(--warn); }
.hc-spark.crit .sp-line { stroke: var(--danger); }
.hc-spark .sp-dot { fill: currentColor; }

/* --------------------------- deploy screen ------------------------- */
.env-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
@media (max-width: 720px) { .env-list { grid-template-columns: minmax(0, 1fr); } }
.env-card {
  background: var(--bg-2); background-image: var(--wash);
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 12px; box-shadow: var(--sh-1); min-width: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.env-card.live { border-color: rgba(124,92,255,.4); }
.env-top { display: flex; align-items: center; gap: 8px; }
.env-name { font-size: .86rem; font-weight: 650; letter-spacing: -.01em; }
.env-host { font-size: .67rem; color: var(--faint); font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.env-meta { display: flex; flex-wrap: wrap; gap: 5px 12px; font-size: .68rem; color: var(--muted); }
.env-meta b { color: var(--fg); font-weight: 600; }
.env-actions { display: flex; gap: 6px; margin-top: 2px; flex-wrap: wrap; }
.env-note { font-size: .67rem; color: var(--faint); line-height: 1.5; }
.dep-log {
  margin: 0; max-height: 320px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere;
  background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 11px 13px; font-family: var(--mono); font-size: .72rem; line-height: 1.55; color: var(--muted);
}

/* ----------------------------- logs viewer ------------------------- */
.log-head { flex-wrap: wrap; gap: 6px; }
.log-head .input.tiny { max-width: 190px; flex: 1 1 120px; min-width: 90px; }
.log-head .composer-select { max-width: 165px; }
#btn-log-live.on { color: var(--ok); border-color: rgba(34,197,94,.4); background: var(--ok-dim); }
#btn-log-errors.on { color: var(--warn); border-color: rgba(245,158,11,.4); background: var(--warn-dim); }
.log-body { font-family: var(--mono); font-size: .72rem; line-height: 1.55; padding: 8px 0 14px; }
.log-row { display: flex; gap: 10px; padding: 1px 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
.log-row:hover { background: rgba(255,255,255,.025); }
.log-ts { color: var(--faint); flex: none; font-variant-numeric: tabular-nums; }
.log-msg { min-width: 0; color: var(--muted); }
.log-row.error .log-msg { color: #FCA5A5; }
.log-row.error { background: rgba(239,68,68,.07); box-shadow: inset 2px 0 0 var(--danger); }
.log-row.warn .log-msg { color: #FCD9A0; }
.log-row.warn { background: rgba(245,158,11,.06); box-shadow: inset 2px 0 0 var(--warn); }
.log-hit { background: rgba(124,92,255,.32); color: #fff; border-radius: 2px; }
.log-note { padding: 18px 14px; text-align: center; color: var(--faint); font-size: .78rem; font-family: inherit; }

/* ------------------- file tree: git status badges ------------------ */
.tree-node.gm { color: var(--warn); }
.tree-node.ga { color: var(--ok); }
.tree-node.gu { color: var(--info); }
.tree-node.gc { color: var(--danger); }

/* ------------------------- markdown preview ------------------------ */
.md-preview {
  flex: 1; min-height: 0; overflow: auto; padding: 18px 20px 40px;
  background: var(--bg); max-width: 820px; width: 100%; margin-inline: auto;
}
.md-preview.hidden { display: none; }
#btn-md-preview.on { color: var(--accent-2); border-color: var(--accent); background: var(--accent-dim); }

/* ------------------------ pinned conversations --------------------- */
.ci-pin, .ci-rename { opacity: 0; font-size: .72rem; flex: none; padding: 2px 4px; border-radius: 4px; cursor: pointer; }
.chat-item:hover .ci-pin { opacity: .5; }
.ci-pin:hover, .ci-rename:hover { opacity: 1 !important; background: var(--bg-4); }
.ci-pin.on { opacity: 1; color: var(--accent-2); }
.ctab.pinned { border-top-color: var(--accent-2); }

/* Rename (v17 item 1) reuses the pin's hit box so the row keeps one rhythm —
   but NOT its hover-to-reveal: an option you cannot see is not an option, and
   the ask was for a discoverable one. */
.ci-rename { opacity: .5; }
.chat-item:hover .ci-rename { opacity: 1; }
.ci-rename svg.ico { width: 13px; height: 13px; }
/* Deliberately NOT class="ci-pin ci-rename": sharing the pin's class made
   every existing `.ci-pin` selector — including a QA suite's — resolve to the
   rename button instead. */
/* ...but hover-to-reveal hides a control completely on a touch screen, which is
   the device this portal is mostly used from. Pin, rename and close are all
   permanently visible there. */
@media (hover: none) {
  .ci-pin, .ci-rename, .ci-close { opacity: .55; }
  .hist-item .ci-rename { opacity: .55; }
}

/* ------------------ drag an image onto the chat (v17) --------------- */
/* Outline the drop target rather than overlaying it: an overlay div would sit
   between the pointer and the textarea and swallow the drop it is advertising. */
#tab-claude.dropping { outline: 2px dashed var(--accent); outline-offset: -6px; }

/* ---------- monitor: storage + temperatures ---------- */
.disk-row { align-items: flex-start; gap: 10px; }
.disk-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.disk-top { display: flex; align-items: center; gap: 7px; min-width: 0; flex-wrap: wrap; }
.disk-badge {
  font-size: .6rem; font-family: var(--mono); letter-spacing: .02em;
  padding: 1px 6px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--bg-3); color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.disk-badge.hdd { color: #A9C7FF; border-color: rgba(169,199,255,.32); }
.disk-badge.ssd { color: #9FE8C4; border-color: rgba(159,232,196,.32); }
.disk-bar { height: 5px; border-radius: 999px; background: var(--bg-4); overflow: hidden; }
.disk-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width var(--t-mid, .25s) var(--ease); }
.disk-fill.warn { background: var(--warn); }
.disk-fill.danger { background: var(--danger); }
.disk-sub { font-size: .68rem; color: var(--faint); font-family: var(--mono); }
.temp-v { font-family: var(--mono); }

/* ---------- temperature headline (v15 item 3a) ----------
   One number leads; the eleven raw sensors collapse behind the disclosure in
   the section head. The tone comes from the CPU package reading, not from the
   hottest sensor — see renderTempHead(). */
.temp-card {
  display: flex; align-items: center; gap: 14px; padding: 14px 15px;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--radius);
}
.temp-left { flex: none; display: grid; gap: 2px; }
.temp-big { font-size: 1.9rem; font-weight: 650; letter-spacing: -.02em; line-height: 1.05; font-variant-numeric: tabular-nums; }
.temp-lbl { font-size: .66rem; color: var(--faint); text-transform: uppercase; letter-spacing: .06em; font-weight: 650; }
.temp-right { min-width: 0; display: grid; gap: 3px; }
.temp-state { font-size: .78rem; font-weight: 600; }
.temp-sub { font-size: .66rem; color: var(--faint); font-family: var(--mono); line-height: 1.35; }
.temp-card.ok .temp-big, .temp-card.ok .temp-state { color: var(--ok); }
.temp-card.warn .temp-big, .temp-card.warn .temp-state { color: var(--warn); }
.temp-card.danger .temp-big, .temp-card.danger .temp-state { color: var(--danger); }
.temp-card.warn { border-color: rgba(245, 158, 11, .35); }
.temp-card.danger { border-color: rgba(239, 68, 68, .4); }
.svc-row.temp-primary .svc-k { font-weight: 700; color: var(--fg); }

/* ---------- 30-day averages (v15 item 3b) ---------- */
.avg-note {
  font-size: .7rem; color: var(--faint); line-height: 1.45; margin-bottom: 8px;
}
.avg-partial { color: var(--warn); font-weight: 600; }
.avg-row { align-items: center; }
.avg-main { min-width: 0; display: grid; gap: 1px; }
.avg-sub { font-size: .64rem; color: var(--faint); font-family: var(--mono); }
.avg-v { font-size: .82rem; font-weight: 650; color: var(--fg); font-variant-numeric: tabular-nums; }

@media (max-width: 480px) {
  .temp-card { gap: 12px; padding: 12px; }
  .temp-big { font-size: 1.6rem; }
  .temp-sub { font-size: .62rem; }
}

/* ===================================================================
   PHONE IN LANDSCAPE  (v15 item 2a)
   ===================================================================
   MEASURED, not guessed: at 851x393 the topbar wanted 1090px of the 851 it
   had. `.tabs` (702px, flex:none) + `.tn-actions` (330px, flex:none) left
   `#ws-chip` as the only shrinkable child, so it was crushed from 132px to
   20px — a bare avatar square with the caret sliced off — and every action
   button was pushed past the right edge, where `html,body{overflow-x:hidden}`
   silently clipped it. That is the whole bug in the operator's screenshot.

   The backlog guessed this was `100vh` versus the dynamic viewport. It was
   not: `.workspace` measured exactly 393px and `#dash` scrolled internally.
   The real cause is that 720px is a PORTRAIT breakpoint, so a landscape phone
   at 844-926px keeps the DESKTOP chrome, which does not fit.

   Why not just switch to the bottom nav here: at 393px tall it would eat 14%
   of the viewport, and in landscape your thumbs rest at the left and right
   edges, not the bottom — a bottom bar is worse for reach, not better. So the
   tab strip stays and is made to fit: icons only, except the ACTIVE tab, which
   keeps its label so you still know where you are.

   `(pointer: coarse)` is what keeps a narrow DESKTOP window out of this block —
   it has a fine pointer and plenty of height, so it keeps the full tab strip. */
@media (pointer: coarse) and (max-height: 520px) and (min-width: 721px) {
  /* reclaim vertical space — it is the scarce axis here, not horizontal */
  :root { --topnav-h: 46px; }

  /* Nothing in the bar may overflow it. `.tabs` becomes shrinkable with a
     scroll fallback so a ninth tab degrades to a scroll, never to a clip. */
  .topbar { gap: 6px; }
  .tabs { flex: 0 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { padding: 6px 9px; gap: 0; }
  .tab .tab-label { display: none; }
  .tab.active .tab-label { display: inline; margin-left: 6px; }

  /* Give the chip a floor. Without `flex: none` it is the only elastic item in
     the row and absorbs every pixel of overflow down to its 20px icon. */
  .ws-chip { flex: none; max-width: 30vw; padding: 4px 9px 4px 5px; }
  .current-project { display: none; }        /* the chip already carries it */

  /* Same reasoning as the portrait block: the tab strip already has a Terminal
     destination, so a second entry point here only steals width. */
  .term-drawer-btn { display: none; }
  .conn .conn-label { display: none; }
  .conn { padding: 4px 6px; }
  .usage-pill { padding: 3px 8px; font-size: .68rem; }
  .tn-actions { flex: none; }

  /* The FAB is fixed and the bottom nav is absent here, so the scroller needs
     its own clearance or the last card can never be read. */
  .dash { padding-top: 10px; padding-bottom: 84px; gap: 12px; }
  .qa-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 7px; }
  .qa-tile { aspect-ratio: 1 / 1; gap: 5px; }
  .qa-ico { width: 28px; height: 28px; }
  .qa-label { font-size: .58rem; }
  .health-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; }

  /* Panes that sit flush to the screen edge need the cutout inset too. */
  .git-layout, .files-layout, .chat-main, .term-container {
    padding-left: var(--safe-l); padding-right: var(--safe-r);
  }
  .fab { right: calc(13px + var(--safe-r)); bottom: calc(14px + var(--safe-b)); width: 46px; height: 46px; }
  .key-bar { padding-left: calc(8px + var(--safe-l)); padding-right: calc(8px + var(--safe-r)); }
}

/* ---------- wrong-hostname banner ----------
   Shown when location.origin != the origin the server calls canonical. The
   portal answers on any hostname that reaches it and never used to say so,
   which is how a stale notification could land the operator on a dead host. */
.host-warn {
  position: relative; z-index: 60;
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 9px calc(12px + var(--safe-r)) 9px calc(12px + var(--safe-l));
  background: var(--warn-dim); color: var(--warn);
  border-bottom: 1px solid rgba(245, 158, 11, .35);
  font-size: .74rem; line-height: 1.4;
}
.host-warn svg.ico { width: 15px; height: 15px; flex: none; }
.host-warn-go { color: var(--fg); font-weight: 650; text-decoration: underline; white-space: nowrap; }

/* ---------- app icon colourways (Settings → This install) ---------- */
.icon-swatches { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.icon-swatch {
  width: 44px; height: 44px; padding: 3px;
  background: transparent; border: 2px solid transparent; border-radius: 12px;
  cursor: pointer; line-height: 0;
}
.icon-swatch img { width: 100%; height: 100%; border-radius: 9px; display: block; }
.icon-swatch:hover { border-color: var(--border); }
.icon-swatch.sel { border-color: var(--accent); }

/* ---------- locked gocryptfs vault ---------- */
.vault-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 8px; padding: 10px 11px;
  background: var(--warn-dim); border: 1px solid rgba(245, 158, 11, .3);
  border-radius: var(--r-sm); font-size: .72rem; line-height: 1.45; color: var(--warn);
}
.vault-bar svg.ico { width: 14px; height: 14px; flex: none; }
.vault-msg { flex: 1; min-width: 140px; color: var(--fg); }

/* ---------- stale push subscriptions ---------- */
.push-warn {
  display: flex; align-items: flex-start; gap: 8px; flex-wrap: wrap;
  margin: 8px 0 4px; padding: 10px 11px;
  background: var(--warn-dim); border: 1px solid rgba(245, 158, 11, .3);
  border-radius: var(--r-sm); font-size: .72rem; line-height: 1.45; color: var(--warn);
}
.push-warn svg.ico { width: 14px; height: 14px; flex: none; margin-top: 2px; }
.push-warn span { flex: 1; min-width: 0; color: var(--fg); }

/* =====================================================================
   v20 — review queue, host watchdog, token ledger, replace, more shells
   ===================================================================== */

/* ---------- headline + subtitle for a "one number" section ----------
   Used by the Temperature section (which had no styling at all) and now by the
   Host watchdog, so the two read as the same kind of statement. */
.temp-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 2px 0 8px; }
.th-val { font-size: 1.35rem; font-weight: 650; letter-spacing: -.02em; color: var(--fg); }
.th-val.warn { color: var(--warn); }
.th-val.crit { color: var(--danger); }
.th-sub { font-size: .7rem; color: var(--muted); }

/* ---------- host alarms ---------- */
.alarm-wrap { border-bottom: 1px solid var(--border-soft); }
.alarm-wrap:last-child { border-bottom: 0; }
.alarm-detail {
  padding: 0 0 8px 18px; font-size: .68rem; line-height: 1.45;
  color: var(--muted); word-break: break-word;
}

/* ---------- unattended-run review ---------- */
.rv-row { cursor: pointer; }
.rv-meta { margin: 0 0 8px; }
.rv-prompt, .rv-summary {
  margin: 4px 0 10px; padding: 9px 10px; max-height: 150px; overflow: auto;
  background: var(--code-bg); border: 1px solid var(--border-soft);
  border-radius: var(--r-sm); font-size: .7rem; line-height: 1.5;
  white-space: pre-wrap; word-break: break-word; color: var(--muted);
}
.rv-warn {
  margin: 8px 0; padding: 9px 10px;
  background: var(--warn-dim); border: 1px solid rgba(245, 158, 11, .3);
  border-radius: var(--r-sm); font-size: .7rem; line-height: 1.5; color: var(--warn);
}
.rv-note { margin: 6px 0 2px; }
.rv-files { margin: 4px 0 10px; }
.rv-file { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border-soft); }
.rv-file input { flex: none; }
.rv-path {
  flex: 1; min-width: 0; text-align: left; background: none; border: 0; padding: 0;
  color: var(--accent-2); font-family: var(--mono, ui-monospace, monospace);
  font-size: .7rem; cursor: pointer; overflow-wrap: anywhere;
}
.rv-code {
  flex: none; padding: 1px 6px; border-radius: 999px;
  background: var(--bg-3); color: var(--muted); font-size: .62rem;
}
.rv-diff { max-height: 220px; margin: 2px 0 6px; }
.rv-push { display: flex; align-items: center; gap: 7px; margin: 8px 0 2px; font-size: .72rem; color: var(--muted); }
.rv-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.btn.danger { color: var(--danger); border-color: rgba(239, 68, 68, .35); }
.btn.danger:hover { background: var(--danger-dim); }
.job-runs { margin-top: 14px; }

/* ---------- token ledger ---------- */
.ledger-card { padding: 2px 0; }
.lg-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.lg-big { font-size: 1.35rem; font-weight: 650; letter-spacing: -.02em; }
.lg-sub { font-size: .7rem; color: var(--muted); }
.lg-row { margin-bottom: 9px; cursor: pointer; }
.lg-head { display: flex; justify-content: space-between; gap: 8px; margin-bottom: 4px; font-size: .7rem; }
.lg-name { color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lg-val { color: var(--muted); flex: none; }
.lg-track { height: 5px; background: var(--bg-3); border-radius: 999px; overflow: hidden; }
.lg-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.lg-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 14px; margin: 8px 0 10px; }
.lg-fact { display: flex; justify-content: space-between; gap: 8px; font-size: .7rem; color: var(--muted); }
.lg-fact b { color: var(--fg); font-weight: 600; }

/* ---------- replace preview ---------- */
.rp-out { margin: 10px 0 2px; max-height: 260px; overflow: auto; }
.rp-sum { margin-bottom: 6px; font-size: .72rem; color: var(--fg); }

/* ---------- more than one shell per project ---------- */
.term-tabs { display: flex; gap: 4px; align-items: center; padding: 6px 8px 0; flex-wrap: wrap; }
.term-tabs.lonely { padding-bottom: 0; }
.tt-btn {
  min-width: 26px; height: 24px; padding: 0 7px;
  background: var(--bg-3); border: 1px solid var(--border); border-radius: var(--r-sm);
  color: var(--muted); font-size: .68rem; line-height: 1; cursor: pointer;
}
.tt-btn.on { background: var(--accent-dim); border-color: var(--accent-ring); color: var(--fg); }
.tt-btn.tt-add, .tt-btn.tt-kill { color: var(--faint); }
.tt-btn:hover { color: var(--fg); }

/* ---------- quick-prompt scopes ---------- */
.qp-scopes { display: flex; gap: 6px; margin-bottom: 8px; flex-wrap: wrap; }
.btn.ghost.on { background: var(--accent-dim); border-color: var(--accent-ring); color: var(--fg); }
.quick-chip.proj { border-color: var(--accent-ring); }

/* =====================================================================
   v21 — the desktop tab (XFCE over RFB, bridged by the portal)
   ===================================================================== */
.desk-wrap { display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--bg); }
.desk-toolbar { flex: none; }

/* noVNC injects its own canvas here and sizes it itself, so this element only
   ever supplies the box and the centring. Giving it a background that is not
   the desktop's own makes the letterboxing round a scaled 16:9 session read as
   deliberate rather than as a rendering fault. */
.desk-host {
  position: relative; flex: 1; min-height: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--code-bg);
}
.desk-host canvas { display: block; }

.desk-msg {
  position: absolute; inset: 0; margin: auto; height: fit-content;
  max-width: 420px; padding: 18px 20px; text-align: center;
}
.desk-msg.hidden { display: none; }
.dm-title { font-size: .9rem; font-weight: 550; color: var(--fg); margin-bottom: 8px; }
.dm-hint {
  font-size: .72rem; line-height: 1.6; color: var(--muted);
  white-space: pre-wrap; font-family: var(--mono, ui-monospace, monospace);
}

/* Off-screen rather than display:none — a field that is not rendered cannot be
   focused, and focusing it is the only way to raise a phone's keyboard. */
.desk-input {
  position: absolute; left: -9999px; top: 0;
  width: 1px; height: 1px; opacity: 0; border: 0; padding: 0; resize: none;
}
.desk-keys { flex: none; }
.desk-keys.hidden { display: none; }
.desk-keys .key.on { background: var(--accent-dim); border-color: var(--accent-ring); color: var(--fg); }
