/* Claude Code — Chat v2.  Shares v1 backend (session-manager + ttyd).
 * Design goal: big, calm, glanceable. Built for someone who is NOT a developer.
 * Few elements, lots of whitespace, large touch targets, plain language.
 * Developer controls live behind a "More" disclosure, never in the default view. */
:root{
  --bg:#1C1B19; --bg2:#211F1C; --panel:#262420; --panel2:#2F2C27;
  --border:#3A372F; --border2:#4A463D;
  --text:#F2EEE6; --muted:#A8A399; --faint:#8A8578;
  --orange:#D97757; --orange-soft:rgba(217,119,87,.16);
  --green:#9CCB5A; --green-soft:rgba(156,203,90,.16);
  --sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;
  --r:14px;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:var(--bg);color:var(--text);font-family:var(--sans);font-size:16px;line-height:1.55;overflow:hidden;-webkit-font-smoothing:antialiased}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit;-webkit-tap-highlight-color:transparent}
/* No blue tap-flash on touch and no focus box on the composer/sidebar buttons —
   they have their own hover/active styling, so the default outline just looks
   like a glitch when it flashes on tap. Text inputs keep their focus ring. */
button:focus,button:focus-visible{outline:none}
a{color:#8FB4EC}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:8px}
::-webkit-scrollbar-thumb:hover{background:var(--faint)}

/* Height is driven by js/viewport.js from window.visualViewport so the iOS
   keyboard shrinks the shell instead of sliding over the composer. --app-shift
   pins the header in place when iOS scrolls the layout viewport. On desktop and
   any non-keyboard state these vars equal the normal height / 0, so nothing
   visibly changes. */
/* Keyboard shift uses position:relative + top (NOT transform) on purpose: a
 * transform would make #shell a stacking context and trap #side (the sidebar)
 * below the body-level artifact panel (z-index 250), which is why the sidebar kept
 * sliding under the artifact. With relative+top (no z-index) #shell is NOT a
 * stacking context, so #side (z-index 300) sits above the artifact while the chat
 * (#main, auto) stays below it — i.e. the sidebar covers the artifact and the
 * artifact stays visible (dimmed) behind it. Towaiji 2026-06-14. */
#shell{display:grid;grid-template-columns:320px 1fr;height:100vh;height:100dvh;height:var(--app-vh,100dvh);position:relative;top:var(--app-shift,0px);transition:grid-template-columns .2s ease-out}
#shell.solo{grid-template-columns:1fr}
#shell.solo #side{display:none}
/* Collapsed (desktop only): hide the sidebar, main takes the full width.
 * Scoped to desktop so it never fights the mobile slide-over below. */
@media(min-width:761px){
  #shell.collapsed{grid-template-columns:1fr}
  #shell.collapsed #side{display:none}
}
/* Backdrop is for the mobile slide-over only; never a grid cell on desktop. */
#backdrop{display:none}

/* ============================ SIDEBAR ============================ */
#side{background:var(--bg2);border-right:1px solid var(--border);display:flex;flex-direction:column;min-height:0}
.side-top{padding:13px 14px 8px;display:flex;align-items:center;gap:9px}
.logo{flex:1;min-width:0;display:flex;align-items:center;gap:6px;font-weight:700;font-size:15px}
/* orange logo doubles as the "hide sidebar" button */
.logo-dot{width:28px;height:28px;border-radius:50%;background:var(--orange);display:grid;place-items:center;flex-shrink:0;transition:filter .12s,transform .12s}
.logo-dot:hover{filter:brightness(1.08);transform:scale(1.05)}
.logo-dot svg{width:15px;height:15px}
/* version pill — small & quiet beside the title, but a 44px finger target.
   The visual stays tiny; the tap area is grown with an invisible pseudo-element. */
.logo .v2{position:relative;font-size:10px;font-weight:700;color:var(--orange);
  border:1px solid var(--orange);border-radius:6px;padding:1px 6px;margin-left:1px;
  background:transparent;cursor:pointer;line-height:1.4;transition:background .12s,color .12s}
.logo .v2::after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:44px;height:44px}
.logo .v2:hover{background:var(--orange-soft)}
.logo .v2:active{background:var(--orange);color:#fff}
.newbtn{margin:2px 12px 9px;height:38px;border-radius:10px;background:var(--orange);color:#fff;font-weight:600;font-size:13.5px;display:flex;align-items:center;justify-content:center;gap:7px;transition:.15s;box-shadow:0 3px 12px rgba(217,119,87,.24)}
.newbtn:hover{filter:brightness(1.07);transform:translateY(-1px)}
.newbtn svg{width:15px;height:15px}
.searchwrap{padding:0 12px 8px}
.searchwrap input{width:100%;height:36px;background:var(--panel);border:1px solid var(--border);border-radius:10px;color:var(--text);padding:0 12px;font-size:13.5px;outline:none}
.searchwrap input::placeholder{color:var(--faint)}
.searchwrap input:focus{border-color:var(--orange)}
.chatlist{flex:1;overflow-y:auto;padding:0 12px 18px}

/* Usage — pinned at the bottom of the sidebar; one line split 5-hour | Weekly */
.side-usage{flex-shrink:0;margin-top:10px;border-top:1px solid var(--border);padding:14px 12px 13px;background:var(--bg2);display:flex;align-items:stretch}.su-half{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:4px;padding:0 12px}
.su-div{width:1px;background:var(--border2);flex-shrink:0}
.su-top{display:flex;align-items:baseline;justify-content:space-between;gap:6px}
.su-label{font-size:12px;letter-spacing:.05em;text-transform:uppercase;color:var(--faint);font-weight:700}
.su-pct{font-family:var(--mono);font-size:14px;font-weight:700;color:var(--green)}
.su-bar{height:4px;border-radius:999px;background:var(--panel2);overflow:hidden}
.su-bar span{display:block;height:100%;width:0;border-radius:999px;background:var(--green);transition:width .4s ease,background .2s}
.su-reset{font-size:12px;color:var(--faint);font-family:var(--mono);white-space:nowrap}

/* Fixed-height row, top-aligned: dot + 2-line title + always-visible actions.
 * Status = dot colour: green pulsing (working), orange (open/idle), grey (earlier). */
.chat-item{height:60px;padding:10px 8px 0 12px;border-radius:11px;cursor:pointer;display:flex;gap:10px;align-items:flex-start;border:1px solid transparent;margin-bottom:4px;transition:background .12s,border-color .12s}
.chat-item:hover{background:var(--panel)}
.chat-item.active{background:var(--panel);border-color:var(--border2)}
.ci-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0;background:var(--faint);margin-top:4px}
.chat-item.live .ci-dot{background:var(--orange)}                 /* open / idle */
.chat-item.working .ci-dot{background:var(--green);box-shadow:0 0 0 0 rgba(156,203,90,.6);animation:pulse 1.5s infinite}  /* working */
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(156,203,90,.5)}70%{box-shadow:0 0 0 8px rgba(156,203,90,0)}100%{box-shadow:0 0 0 0 rgba(156,203,90,0)}}
.ci-title{flex:1;min-width:0;font-size:14px;font-weight:600;line-height:1.32;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ci-actions{display:flex;gap:2px;flex-shrink:0}
.ci-open,.ci-x,.ci-pin{width:28px;height:28px;border-radius:7px;display:grid;place-items:center;color:var(--faint);background:none;border:none;transition:.12s}
.ci-open svg{width:15px;height:15px}
.ci-open:hover{background:var(--panel2);color:var(--orange)}
.ci-x{font-size:15px;line-height:1}
.ci-x:hover{background:rgba(224,108,117,.16);color:#E06C75}
/* Pin / flag toggle — outline when off, solid orange when pinned. */
.ci-pin svg{width:15px;height:15px}
.ci-pin:hover{background:var(--panel2);color:var(--orange)}
.ci-pin.on{color:var(--orange)}
.ci-pin.on svg path{fill:var(--orange);stroke:var(--orange)}
.ci-pin.on:hover{background:var(--orange-soft)}
/* Plain pinned style (Towaiji's pick): a pinned chat looks identical to a
   normal row — no left rail, no recoloured dot. It floats to the top and the
   only marker is its filled-orange pin icon (.ci-pin.on). */
.list-empty{padding:30px 20px;color:var(--faint);font-size:15px;text-align:center}
/* Collapsible "Pinned" group — tappable header folds the pinned rows away
   while the live/ended chats below stay visible. Same chat skin throughout. */
.pin-group{margin-bottom:4px}
.pin-group-head{width:100%;height:44px;display:flex;align-items:center;gap:8px;padding:0 10px;border-radius:11px;background:none;border:none;cursor:pointer;color:var(--faint);font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;transition:background .12s}
.pin-group-head:hover{background:var(--panel)}
.pin-group-head .pg-chev{width:16px;height:16px;flex-shrink:0;transform:rotate(90deg);transition:transform .15s}
.pin-group.collapsed .pin-group-head .pg-chev{transform:rotate(0deg)}
.pin-group-head .pg-label{flex:1;text-align:left;color:var(--orange)}
.pin-group-head .pg-count{min-width:20px;height:18px;padding:0 6px;border-radius:9px;display:grid;place-items:center;background:var(--panel2);color:var(--faint);font-size:11px;font-weight:700}
.pin-group.collapsed .pin-group-body{display:none}

/* ============================ MAIN ============================ */
#main{display:flex;flex-direction:column;min-width:0;background:var(--bg)}
.topbar{position:relative;height:66px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;padding:0 20px;flex-shrink:0}
/* Top-bar button = "show sidebar" (orange, round). Desktop: only when collapsed. */
#side-toggle{display:none;width:40px;height:40px;border-radius:50%;background:var(--orange);color:#fff;place-items:center;flex-shrink:0}
#side-toggle:hover{filter:brightness(1.08)}
#side-toggle svg{width:19px;height:19px}
@media(min-width:761px){ #shell.collapsed #side-toggle{display:grid} }
.tb-title{flex:1;min-width:0;font-weight:600;font-size:18px;display:flex;align-items:center;gap:10px;background:none;border:none;color:inherit;cursor:pointer;text-align:left;padding:6px 6px;border-radius:10px;font-family:inherit}
.tb-title:hover{background:var(--panel)}
.tb-title #tb-dot{width:11px;height:11px;border-radius:50%;flex-shrink:0}
.tb-title span#tb-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tb-caret{color:var(--faint);font-size:14px;flex-shrink:0;margin-left:-2px}
.title-pop{position:absolute;top:calc(100% - 6px);left:14px;right:14px;z-index:60;background:var(--panel);border:1px solid var(--border2);border-radius:12px;padding:13px 16px;font-size:15px;line-height:1.5;color:var(--text);box-shadow:0 18px 44px rgba(0,0,0,.55)}
.title-pop.hidden{display:none}
.tb-folder{font-family:var(--mono);font-size:12px;color:#8FB4EC;background:var(--panel);padding:5px 10px;border-radius:7px;white-space:nowrap;max-width:240px;overflow:hidden;text-overflow:ellipsis}
.ctxmini{font-family:var(--mono);font-size:12px;color:var(--muted);display:flex;align-items:center;gap:7px}
.ctxmini .track{display:block;width:50px;height:6px;border-radius:4px;background:var(--panel2);overflow:hidden}
.ctxmini .fill{display:block;height:100%;width:0;background:var(--green);transition:width .4s}
.viewtoggle{display:flex;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:4px}
.viewtoggle button{padding:9px 18px;border-radius:9px;font-size:14.5px;font-weight:600;color:var(--muted);transition:.12s;min-height:40px}
.viewtoggle button.on{background:var(--orange);color:#fff}

/* ============================ STAGE / PANES ============================ */
#stage{flex:1;position:relative;min-height:0}
.pane{position:absolute;inset:0;display:none;flex-direction:column;min-height:0}
.pane.active{display:flex}
.pane iframe{flex:1;border:0;width:100%;background:#161513}
.pane-readview{flex:1;overflow-y:auto;overflow-x:hidden;display:none}
/* Chat view: keep the terminal iframe RENDERED (NOT display:none) and overlay the
 * read-view on top of it. xterm.js silently DROPS a paste when its container has
 * zero layout (display:none) — so a message typed in chat view would fire the
 * paste into a non-rendered terminal and vanish, only landing once the user
 * switched to terminal view. Parking the iframe offscreen (kept laid-out, just
 * pushed out of sight) keeps xterm live so the paste lands while chat view is up.
 * The read-view sits above it (its own stacking context) so the look is unchanged. */
.pane.readmode iframe{position:absolute;left:-99999px;width:100%;height:100%;visibility:visible}
.pane.readmode .pane-readview{display:block;position:relative;z-index:2;background:#161513}
/* Reconnect cover (no-502): hides the bare nginx "502 Bad Gateway" page the
 * browser paints inside the iframe during a ttyd respawn gap. Sits ON the
 * terminal (z-index 1, above the iframe) but BELOW the read-view (z-index 2) so
 * chat view is unaffected. transport toggles [hidden] — shown only while the
 * attach layer is re-attaching, gone the instant the live terminal is back. */
.pane .term-cover{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:10px;background:#1C1B19;color:#9b958c;font-size:15px;font-weight:500}
.pane .term-cover[hidden]{display:none}
.pane .term-cover .tc-dot{width:9px;height:9px;border-radius:50%;background:#D97757;animation:tc-pulse 1s ease-in-out infinite}
@keyframes tc-pulse{0%,100%{opacity:.35;transform:scale(.8)}50%{opacity:1;transform:scale(1)}}
/* Error state: gap outlasted its window (engine genuinely down). Swap the quiet
 * pulse for a clear honest message so the user is never stuck on an endless
 * spinner; the watchdog keeps retrying in the background. */
.pane .term-cover .tc-err{display:none;max-width:80%;text-align:center;color:#c9c3ba}
.pane .term-cover.tc-error .tc-dot,.pane .term-cover.tc-error .tc-txt{display:none}
.pane .term-cover.tc-error .tc-err{display:block}

/* bubbles — You on the right, Claude on the left, each in its own bordered bubble */
.rv-inner{max-width:100%;margin:0;padding:30px 28px 44px;display:flex;flex-direction:column;gap:18px}
.msg{max-width:86%;min-width:0;display:flex;flex-direction:column}
.msg-user{align-self:flex-end;align-items:flex-end}
.msg-assistant{align-self:flex-start;align-items:flex-start}
/* Entry animation — render.js adds .msg-in to NEWLY inserted bubbles only, so
   existing bubbles never re-animate on a repaint. Subtle and quick, not bouncy. */
@keyframes msg-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.msg.msg-in{animation:msg-in .22s ease-out}
.msg-header{display:flex;align-items:center;gap:9px;margin:0 5px 5px}
.msg-role{font-size:12.5px;font-weight:700;color:var(--muted);letter-spacing:.01em;margin-right:auto}
.msg-assistant .msg-role{color:var(--orange)}
/* Always-visible one-tap Copy on every message — no hover, no selecting. */
.msg-copy,.msg-copy-code{font-size:12px;color:var(--muted);padding:4px 12px;border-radius:8px;transition:.12s;background:var(--panel);border:1px solid var(--border)}
.msg-copy:hover,.msg-copy-code:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.msg-copy:active,.msg-copy-code:active{transform:translateY(1px)}
/* On touch, extend the copy buttons to a ≥44px hit area without growing the
 * visible pill (.msg-copy-code is already positioned; give .msg-copy relative). */
@media (pointer:coarse){
  .msg-copy{position:relative}
  .msg-copy::after,.msg-copy-code::after{content:"";position:absolute;inset:-8px -4px}
}
.msg-queued{font-size:11.5px;font-weight:600;color:var(--green);background:rgba(156,203,90,.16);padding:2px 9px;border-radius:6px}
/* Failed send: same badge shape as Queued but clearly attention-coloured, plus a
   big tappable Retry inside the bubble (44px tall — phone-friendly). */
.msg-failed{font-size:11.5px;font-weight:600;color:#f87171;background:rgba(248,113,113,.14);padding:2px 9px;border-radius:6px}
.msg-retry{align-self:flex-end;margin-top:8px;min-height:44px;padding:0 20px;border-radius:11px;
  font-size:14px;font-weight:700;color:#f87171;background:rgba(248,113,113,.12);
  border:1px solid rgba(248,113,113,.45);transition:.12s}
.msg-retry:hover{background:#f87171;color:#fff;border-color:#f87171}
.msg-retry:active{transform:translateY(1px)}
.msg-body{font-size:16px;line-height:1.66;white-space:pre-wrap;overflow-wrap:anywhere;border:1px solid;border-radius:16px;padding:13px 16px;min-width:0;max-width:100%;overflow:hidden;-webkit-user-select:none;user-select:none}
/* Links stay tappable even though the surrounding text isn't selectable. */
.msg-body a{-webkit-user-select:none;user-select:none}
/* Desktop (mouse/trackpad): native drag-select works; touch keeps press-and-hold. */
@media(hover:hover){
  .msg-body{-webkit-user-select:text;user-select:text}
  .msg-body a{-webkit-user-select:text;user-select:text}
}
/* Press-and-hold swaps the message text into this field for reliable selection.
   Looks identical to the bubble text; selection here can't escape the message. */
.msg-ta{width:100%;background:transparent;border:none;outline:none;color:inherit;font:inherit;line-height:inherit;padding:0;margin:0;resize:none;display:block;overflow:hidden;-webkit-user-select:text;user-select:text}
/* Two clearly different tints, both lifted off the #1C1B19 background:
   You = warm orange-tinted (your messages), Claude = neutral raised grey. */
.msg-user .msg-body{background:#3A2A20;border-color:#5C4634;border-top-right-radius:6px}
.msg-assistant .msg-body{background:#2B2926;border-color:#46423B;border-top-left-radius:6px}
.msg-pending .msg-body{opacity:.6}
.msg-body code{font-family:var(--mono);background:var(--panel2);padding:2px 6px;border-radius:6px;font-size:14px;color:var(--orange)}
.msg-code{position:relative;max-width:100%;background:#1a1916;border:1px solid var(--border);border-radius:12px;font-family:var(--mono);font-size:13.5px;margin:12px 0;padding:14px 16px;overflow-x:auto;line-height:1.62;color:#cfe8b0}
.msg-copy-code{position:absolute;top:7px;right:7px;opacity:1;background:var(--panel2)}
.msg-empty{align-self:center;max-width:100%;color:var(--faint);text-align:center;padding:48px;font-size:15px}

/* ============================ COMPOSER ============================ */
.composer{border-top:1px solid var(--border);padding:16px 22px 20px;flex-shrink:0}
.composer-inner{max-width:100%;margin:0;position:relative}

/* ── STATUS PILL: "Jarvis is thinking…" (busy) vs "Ready" (idle) ───────────
 * Glanceable signal so Towaiji always knows if Claude is still working. Sits
 * just above the input, visible in both Chat and Terminal views. */
/* Thinking line — sits at the BOTTOM of the conversation (not in the input box),
   left-aligned like a chat line. Hidden entirely when idle. */
/* ── pill row (spinner line) ─────────────────────────────────────────────────
 * The thinking spinner now owns this WHOLE thin line (the Tray pill moved down
 * to the composer button row). The spinner truncates as needed (min-width:0).
 * When idle the spinner is display:none, so the line is essentially empty —
 * kept thin, just the row's padding. */
.pillrow{display:flex;align-items:center;gap:10px;margin:0;flex-shrink:0;
  padding:6px 22px 12px;min-width:0}
.status-pill{position:relative;display:flex;align-items:center;gap:9px;margin:0;
  min-width:0;flex:1 1 auto;padding:0;font-size:14px;font-weight:600;font-style:italic;
  color:var(--orange);background:transparent;-webkit-user-select:none;user-select:none}
.status-pill .sp-spinner{width:14px;height:14px;border-radius:50%;flex-shrink:0;
  border:2px solid rgba(217,119,87,.3);border-top-color:var(--orange);
  animation:sp-spin .7s linear infinite}
@keyframes sp-spin{to{transform:rotate(360deg)}}
/* Word swap ("Thinking…" → "Brewing…"): render.js re-adds .sp-fade to the text
   span when the word changes — a tiny fade instead of a hard cut. */
@keyframes sp-fade{from{opacity:0}to{opacity:1}}
.sp-fade{animation:sp-fade .16s ease-out}
/* Live token/time meta mirrored from the terminal spinner — grey, like the terminal. */
.status-pill .sp-meta{color:var(--faint);font-weight:500;font-style:normal;
  font-variant-numeric:tabular-nums;letter-spacing:.1px}
.status-pill .sp-meta:empty{display:none}
.status-pill .sp-meta{flex-shrink:0}
/* Spinner word truncates (with …) instead of pushing the Tray pill — the pill
 * keeps its slot at every width. */
#status-pill-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Idle: spinner removed from flow (no invisible spinner running), but the row +
 * Tray pill stay put — the Tray pill is pushed right by its own margin-left:auto. */
.status-pill.ready{display:none}
/* Busy: warm orange word + animated spinner. */
.status-pill.busy{display:flex}
/* Done: calm grey summary ("Worked for 4m 43s"), no spin, like the terminal's
   completion line. A small static dot replaces the animated spinner. */
.status-pill.done{display:flex;color:var(--faint);font-style:normal}
.status-pill.done .sp-spinner{border-color:var(--faint);border-top-color:var(--faint);animation:none;opacity:.6}
.status-pill.done .sp-meta{display:none}

/* ── live workflow / crew factory-line ──────────────────────────────────────
   Sits just above the thinking pill: a glanceable card of plain-English phase
   chips + small crew chips. The RUNNING phase is the biggest/brightest thing;
   done = green check, pending = dim. Reuses the agent-card accent language
   (orange / green pulse). Empty → fully collapsed (no #stage shift). */
/* Horizontal padding matches .rv-inner (the conversation column) so the strip
   lines up with the chat bubbles on desktop AND mobile instead of sitting flush
   against the screen edge. */
#workflow-strip{display:none;flex-shrink:0;padding:8px 28px 0;-webkit-user-select:none;user-select:none}
#workflow-strip.show{display:block}
.wf-card{display:flex;flex-direction:column;gap:9px;padding:11px 14px;
  background:var(--panel);border:1px solid var(--border2);border-radius:14px;
  border-left:3px solid var(--border2);max-width:760px}
.wf-card.running{border-left-color:var(--orange)}
.wf-head{display:flex;align-items:center;gap:9px}
.wf-title{font-size:13px;font-weight:700;letter-spacing:.03em;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wf-card.running .wf-title{color:var(--orange)}
/* Live dot (steady green pulse, same as agent rows) + done check. */
.wf-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0;background:var(--green);
  box-shadow:0 0 0 0 rgba(156,203,90,.5);animation:agentpulse 1.5s ease-out infinite}
.wf-chk{width:18px;height:18px;border-radius:50%;flex-shrink:0;display:inline-grid;place-items:center;
  font-size:11px;font-weight:700;color:var(--green);background:rgba(156,203,90,.16)}
/* Phase chips — one calm row, wraps on phone width. */
.wf-phases{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.wf-phase{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:10px;
  font-size:13px;font-weight:600;background:var(--panel2);border:1px solid var(--border);color:var(--faint)}
.wf-phase-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}
/* Done phase: settled, with a check. */
.wf-phase.wf-done{color:var(--muted)}
/* Pending phase: dim, recedes. */
.wf-phase.wf-pending{opacity:.55}
/* Running phase: the loudest thing on the strip — bigger, orange, raised. */
.wf-phase.wf-running{color:var(--orange);background:var(--orange-soft);border-color:var(--orange);
  font-size:14.5px;font-weight:700;padding:8px 14px}
.wf-phase.wf-running .wf-phase-t{max-width:240px}
/* Crew chips — smaller line under the phases. */
.wf-agents{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.wf-agent{display:inline-flex;align-items:center;gap:6px;padding:4px 9px;border-radius:9px;
  font-size:12px;font-weight:600;background:transparent;border:1px solid var(--border);color:var(--muted)}
.wf-agent .wf-dot{width:8px;height:8px}
.wf-agent .wf-chk{width:15px;height:15px;font-size:10px}
.wf-agent.wf-pending{opacity:.5}
.wf-agent-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:140px}

/* ── Tray pill (tray.js) ─────────────────────────────────────────────────────
 * ONE small quiet pill labelled "Tray" — "Tray · 2" while jobs run, just "Tray"
 * when idle. It is the door to Ongoing / Finished / Artifacts and STAYS VISIBLE.
 * It now lives in #jobs-tray at the FAR RIGHT of the composer button row, just
 * after the context bar (the spinner line is spinner-only again). flex-shrink:0
 * reserves its slot. Tapping opens the shared docked side panel — never reflows
 * the transcript. */
#jobs-tray{display:flex;flex-shrink:0;align-items:center;-webkit-user-select:none;user-select:none}

/* The Tray button — a SIBLING of CLR / Stop: same 44px height, same 12px square
 * radius, same 1px border + panel fill, same bold short label. NOT a pill.
 * State is shown ONLY by a static colour code (border + label + small dot),
 * never by animation (owner ban, 2026-06-11):
 *   idle    → quiet gray (neutral, like an idle button)
 *   .running→ green border + green dot ("Tray · 2")
 *   .waiting→ amber border + amber dot (work finished, tray not yet opened) */
.tray-count{display:inline-flex;align-items:center;gap:7px;height:44px;padding:0 14px;cursor:pointer;
  background:var(--panel);border:1px solid var(--border);border-radius:12px;
  font:inherit;transition:background .12s,border-color .12s}
.tray-count:hover{color:var(--text);background:var(--panel2)}
.tray-count:active{transform:translateY(1px)}
/* GREEN — one or more jobs running. */
.tray-count.running{border-color:var(--green)}
.tray-count.running .tray-summary,.tray-count.running .tray-n{color:var(--green)}
.tray-count.running .tray-dot{background:var(--green)}
/* AMBER — nothing running, but finished work he hasn't opened the tray to see. */
.tray-count.waiting{border-color:#E0A22E}
.tray-count.waiting .tray-summary{color:#E0A22E}
.tray-count.waiting .tray-dot{background:#E0A22E}
.tray-summary{min-width:0;font-size:13px;font-weight:700;letter-spacing:.2px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal}
.tray-n{font-weight:800}
/* Small STATIC status dot — colour set by the state class above. No animation. */
.tray-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--muted)}

/* The expanded view is the SHARED docked side panel (see .art-panel below). The
 * tray's job list is painted into that panel body (.trayp-* below). */
@media (max-width:760px){
  /* Phone: 44px+ touch target on the Tray pill. */
  .tray-count{min-height:44px;padding:0 16px}
}

/* ── JOBS TRAY LIST — painted into the shared docked panel body ────────────────
 * Two sections (Running / Finished), each job a big tappable row, with its
 * artifacts listed right under it. Glanceable: plain-English labels, big touch
 * targets, low density. Reuses the agent-card visual language (orange/green). */
.trayp-body{padding:0}
.trayp-section + .trayp-section{margin-top:6px}
.trayp-section-head{position:sticky;top:0;z-index:1;padding:13px 20px 9px;font-size:12px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted);background:var(--bg);
  border-bottom:1px solid var(--border)}
.trayp-job{display:flex;align-items:center;gap:12px;padding:15px 20px;border-bottom:1px solid var(--border)}
.trayp-job.tappable{cursor:pointer;transition:background .12s}
.trayp-job.tappable:hover{background:var(--panel2)}
.trayp-job.tappable:active{transform:translateY(1px)}
.trayp-jmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
/* The job/workflow name wraps onto as many lines as it needs — never cropped.
   The TYPE tag rides inline at the start of the first line; long descriptions
   (e.g. a verbose workflow name) stay fully readable on phone AND desktop. */
.trayp-label{font-size:16px;font-weight:700;color:var(--text);line-height:1.35;
  overflow-wrap:anywhere;word-break:break-word}
/* Small TYPE tag every job row carries: Agent (blue) or Workflow (purple). */
.trayp-tag{display:inline-block;vertical-align:middle;margin-right:8px;font-size:11px;font-weight:800;
  padding:2px 8px;border-radius:7px;letter-spacing:.03em;text-transform:uppercase}
.trayp-tag.ag{color:#5b8def;background:rgba(91,141,239,.15)}
.trayp-tag.wf{color:#a87ce6;background:rgba(168,124,230,.16)}
.trayp-sub{font-size:13px;font-weight:600;color:var(--faint)}
.trayp-chip{flex-shrink:0;font-size:12px;font-weight:700;padding:4px 11px;border-radius:9px;letter-spacing:.02em}
.trayp-chip.running{color:var(--orange);background:var(--orange-soft)}
.trayp-chip.done{color:var(--green);background:rgba(156,203,90,.16)}
.trayp-chip.stopped{color:var(--faint);background:var(--panel2);border:1px solid var(--border)}
.trayp-elapsed{flex-shrink:0;font-size:13px;font-weight:600;color:var(--faint);min-width:40px;text-align:right}
.trayp-go{flex-shrink:0;font-size:20px;line-height:1;color:var(--faint);font-weight:700}
/* Status markers (mirror the count-chip language). */
.trayp-dot{width:11px;height:11px;border-radius:50%;flex-shrink:0;background:var(--green);
  box-shadow:0 0 0 0 rgba(156,203,90,.5);animation:agentpulse 1.5s ease-out infinite}
.trayp-chk{width:20px;height:20px;border-radius:50%;flex-shrink:0;display:inline-grid;place-items:center;
  font-size:11px;font-weight:700;color:var(--green);background:rgba(156,203,90,.16)}
.trayp-stop{flex-shrink:0;width:18px;height:18px;font-size:10px;line-height:1;color:var(--faint);
  display:inline-grid;place-items:center}
/* Artifact sub-rows under a job — indented, lighter, still a big tap target. */
.trayp-art{display:flex;align-items:center;gap:11px;padding:12px 20px 12px 40px;
  border-bottom:1px solid var(--border);background:var(--bg2);cursor:pointer;transition:background .12s}
.trayp-art:hover{background:var(--panel2)}
.trayp-art:active{transform:translateY(1px)}
.trayp-art-ico{flex-shrink:0;font-size:16px;line-height:1}
.trayp-art-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.trayp-art-title{font-size:14.5px;font-weight:700;color:var(--text);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.trayp-art-kind{font-size:12px;font-weight:600;color:var(--orange);text-transform:uppercase;letter-spacing:.05em}
.trayp-empty{padding:40px 24px;text-align:center;font-size:15px;color:var(--muted);line-height:1.6}
.trayp-wf{padding:18px 18px}

.attach-row{display:flex;gap:9px;padding:0 4px 10px;flex-wrap:wrap}
.attach-row.hidden{display:none}
.chip{display:flex;align-items:center;gap:9px;background:var(--panel2);border:1px solid var(--border2);border-radius:11px;padding:7px 10px;font-size:13px;color:var(--text);max-width:220px}
.chip img{width:30px;height:30px;border-radius:7px;object-fit:cover}
.chip .ext{font-size:10px;font-weight:700;color:var(--orange);background:var(--orange-soft);border-radius:5px;padding:4px 6px}
.chip .nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chip.failed{border-color:#E06C75}
.chip .x{color:var(--faint);font-weight:700;cursor:pointer;padding:0 3px;font-size:15px}
.chip .x:hover{color:#E06C75}
/* Composer is a GRID, not nested flexboxes — the textarea + the three buttons
 * are direct cells, so switching between the two layouts is just swapping
 * grid-template-areas. The buttons slide between cells; they never regroup or
 * flash to the wrong side (the old flex+display:contents approach did, on
 * mobile Safari). Default = stacked: full-width textarea on top, controls row
 * beneath (attach + mic on the left, send pushed right by the empty `.` cell).
 * Only border/shadow transition — geometry snaps cleanly, never half-animates. */
.inputbox{position:relative;background:var(--panel);border:1px solid var(--border);border-radius:18px;padding:10px 14px;transition:border-color .15s,box-shadow .15s,padding .14s ease;
  display:grid;grid-template-columns:auto auto 1fr auto;grid-template-areas:"ta ta ta ta" "up mic . send";gap:6px 8px;align-items:center}
.inputbox #composer-input{grid-area:ta}
.inputbox #btn-upload{grid-area:up}
.inputbox #btn-mic{grid-area:mic}
.inputbox #btn-send{grid-area:send}
.inputbox.drag{border-color:var(--orange);background:var(--orange-soft)}
.inputbox:focus-within{border-color:var(--orange);box-shadow:0 0 0 4px var(--orange-soft)}
.inputbox textarea{width:100%;background:none;border:none;outline:none;color:var(--text);font-family:inherit;font-size:16.5px;resize:none;padding:6px 2px;max-height:200px;line-height:1.55;transition:height .14s ease,min-height .14s ease,padding .14s ease}
.inputbox textarea::placeholder{color:var(--faint)}
.tool-btn{position:relative;width:46px;height:46px;border-radius:13px;display:grid;place-items:center;color:var(--muted);transition:.12s;flex-shrink:0}
.tool-btn:hover{background:var(--panel2);color:var(--text)}

/* Mic states: bars dance while RECORDING, dots bounce while ANALYSING.
   The bars/dots replace the mic glyph; JS toggles .recording / .transcribing. */
.mic-eq,.mic-dots{display:none;align-items:flex-end;justify-content:center;gap:3px;height:22px}
.tool-btn.recording{background:rgba(224,108,117,.14)}
.tool-btn.recording .mic-icon{display:none}
.tool-btn.recording .mic-eq{display:flex}
.tool-btn.transcribing{background:var(--orange-soft)}
.tool-btn.transcribing .mic-icon{display:none}
.tool-btn.transcribing .mic-dots{display:flex;align-items:center}
.mic-eq i{width:3.5px;height:7px;background:#E06C75;border-radius:2px;animation:mic-eq 0.9s ease-in-out infinite}
.mic-eq i:nth-child(2){animation-delay:.12s}
.mic-eq i:nth-child(3){animation-delay:.24s}
.mic-eq i:nth-child(4){animation-delay:.36s}
.mic-eq i:nth-child(5){animation-delay:.48s}
@keyframes mic-eq{0%,100%{height:7px}50%{height:22px}}
.mic-dots i{width:6px;height:6px;border-radius:50%;background:var(--orange);animation:mic-bd 0.9s ease-in-out infinite}
.mic-dots i:nth-child(2){animation-delay:.15s}
.mic-dots i:nth-child(3){animation-delay:.3s}
@keyframes mic-bd{0%,100%{transform:translateY(0);opacity:.4}50%{transform:translateY(-5px);opacity:1}}
.tool-btn.uploading{color:var(--orange)}

/* MIC = a bigger, clearer bar than the other tool buttons (it's the dictation
 * control). Wider, soft orange-tinted, so it reads as "tap to talk". */
.inputbox #btn-mic{width:60px;border-radius:14px;background:var(--orange-soft);color:var(--orange)}
.inputbox #btn-mic:hover{background:var(--orange-soft);filter:brightness(1.06);color:var(--orange)}
.inputbox #btn-mic .mic-icon{width:22px;height:22px}
.inputbox #btn-mic::after{inset:-6px}   /* generous touch target */

/* WAVE BAR (Sample 1, "expand-from-mic") — on mic tap the strip does NOT take
 * over the row. It's a compact recording strip anchored at the left/mic side of
 * the inputbox that SMOOTHLY EXPANDS RIGHTWARD (a width transition) into:
 *   pulsing dot · live timer · animated equalizer · Show text · Send · ✕.
 * The textarea + controls keep their size underneath; the strip just overlays
 * the right end of the row while recording, then collapses back to the mic.
 * JS toggles .recording on .inputbox; the wave bar is appended once. */
.wavebar{
  /* Pinned to the bottom-left (the controls row, where the mic lives) so a tall
   * multi-line textarea stays fully visible above it. Grows rightward from here. */
  position:absolute;left:8px;bottom:8px;z-index:5;
  display:flex;align-items:center;gap:10px;
  background:var(--panel2);border:1px solid var(--border);border-radius:14px;
  height:48px;padding:0;
  /* collapsed = mic-sized; opens to the full strip on .recording */
  width:60px;max-width:60px;overflow:hidden;white-space:nowrap;
  opacity:0;pointer-events:none;
  box-shadow:0 6px 22px rgba(0,0,0,.28);
  transition:max-width .26s cubic-bezier(.22,.61,.36,1),
             width .26s cubic-bezier(.22,.61,.36,1),
             opacity .16s ease,padding .26s cubic-bezier(.22,.61,.36,1);
}
.inputbox.recording .wavebar{
  /* grows rightward to fill the row, anchored at the left/mic side */
  width:calc(100% - 16px);max-width:calc(100% - 16px);
  padding:0 10px;opacity:1;pointer-events:auto;
}
.wavebar .wb-dot{width:9px;height:9px;border-radius:50%;background:#E5564B;flex-shrink:0;margin-left:4px;animation:wb-pulse 1.1s ease-in-out infinite}
@keyframes wb-pulse{0%,100%{opacity:1}50%{opacity:.35}}
.wavebar .wb-time{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600;color:var(--text);flex-shrink:0;min-width:42px}
.wavebar .wb-cancel{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border-radius:50%;color:var(--muted);font-size:15px;cursor:pointer;transition:.12s}
.wavebar .wb-cancel:hover{background:var(--panel);color:var(--text)}
.wavebar .wb-wave{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:3px;height:24px;overflow:hidden}
.wavebar .wb-wave i{width:3px;border-radius:3px;background:var(--orange);opacity:.85;height:6px;animation:wb-eq 1s infinite ease-in-out}
@keyframes wb-eq{0%,100%{height:6px}50%{height:24px}}
.wavebar .wb-show,.wavebar .wb-send{flex-shrink:0;border-radius:11px;padding:9px 13px;font-weight:700;font-size:14px;cursor:pointer;transition:.12s;display:inline-flex;align-items:center;gap:6px}
.wavebar .wb-show{background:transparent;border:1.5px solid var(--border2);color:var(--text)}
.wavebar .wb-show:hover{border-color:var(--orange);color:var(--orange)}
.wavebar .wb-send{background:var(--orange);border:1.5px solid var(--orange);color:#fff}
.wavebar .wb-send:hover{filter:brightness(1.08)}
.wavebar .wb-send svg{width:16px;height:16px}
/* Reduced motion: no width animation, just appear/disappear. */
@media (prefers-reduced-motion:reduce){
  .wavebar{transition:opacity .12s ease}
}
/* Coarse pointer: pills must be a real ≥40px touch target; keep both visible. */
@media (pointer:coarse){
  .wavebar{height:52px}
  .wavebar .wb-show,.wavebar .wb-send{min-height:42px;padding:9px 14px}
  .wavebar .wb-cancel{width:34px;height:34px}
}
/* Phones: tighten gaps + shrink the wave (never the pills) so it stays one row. */
@media (max-width:560px){
  .inputbox.recording .wavebar{gap:7px;padding:0 8px}
  .wavebar .wb-show,.wavebar .wb-send{padding:9px 11px;font-size:13.5px}
  .wavebar .wb-time{min-width:38px}
  .wavebar .wb-wave{gap:2px}
}

.send{width:50px;height:50px;border-radius:15px;background:var(--orange);color:#fff;display:grid;place-items:center;flex-shrink:0;transition:.12s}
.send:hover{filter:brightness(1.1)}
.send svg{width:21px;height:21px}

/* control strip above the input (Option 1, full width): mode + arrows + context % */
.composer-toolbar{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:11px;padding:0 2px}
.adv-mode{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:14px;cursor:pointer;padding:0 14px;height:44px;border-radius:12px;background:var(--panel);border:1px solid var(--border)}
.adv-mode:hover{color:var(--text);border-color:var(--border2)}
.adv-mode b{color:var(--orange)}
.arrowpad{display:flex;gap:7px;align-items:center}
.arrowpad button{width:44px;height:44px;border-radius:12px;color:var(--muted);background:var(--panel);border:1px solid var(--border);font-size:15px;display:grid;place-items:center}
.arrowpad button:hover{color:var(--text);background:var(--panel2)}
/* CLR: wipe the composer — same square size as the arrow keys, smaller text so the word fits */
.arrowpad #btn-clear{font-size:11.5px;font-weight:700;letter-spacing:.3px}

/* NAV: one compact button that pops the three rarely-used arrow keys above it. */
.navpad{position:relative;display:flex}
#btn-nav{font-size:16px;line-height:1}
/* The popover floats ABOVE the button; tap-away / second click closes it. */
.navpop{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);
  display:flex;gap:7px;padding:7px;background:var(--panel);border:1px solid var(--border2);
  border-radius:14px;box-shadow:0 14px 34px rgba(0,0,0,.5);z-index:70}
.navpop.hidden{display:none}
/* a small pointer beneath the popover, centered on the NAV button */
.navpop::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);
  border:6px solid transparent;border-top-color:var(--panel)}
.navpop button{width:44px;height:44px;border-radius:11px;color:var(--muted);background:var(--panel2);
  border:1px solid var(--border);font-size:15px;display:grid;place-items:center}
.navpop button:hover{color:var(--text);background:var(--border)}

/* STOP: same size as CLR / the arrow keys, subtle red tint so it reads as "halt". */
#btn-stop{width:auto;min-width:44px;padding:0 13px;font-size:12.5px;font-weight:700;letter-spacing:.2px;
  color:#E8927B;background:rgba(208,92,68,.13);border-color:rgba(208,92,68,.5)}
#btn-stop:hover{color:#fff;background:rgba(208,92,68,.85);border-color:rgba(208,92,68,.9)}

/* CTX stretches to fill the leftover middle space in the toolbar */
.composer-toolbar .ctxmini{flex:1;min-width:140px;height:44px;padding:0 16px;background:var(--panel);border:1px solid var(--border);border-radius:12px}
.composer-toolbar .ctxmini .track{flex:1;width:auto}
/* TRAY sits at the far right of the button row (after the context bar). */
.composer-toolbar #jobs-tray{margin-left:0}

/* ── 44px tap targets ──────────────────────────────────────────────────────
   Floor every interactive control at ~44px of HIT AREA without bloating the
   visuals: an invisible ::after extends the tappable zone. Insets are tuned so
   no extension ever overlaps a neighbouring control (gaps are 2-8px; each side
   takes less than its half of the gap). .ci-x ends a chat, so it only grows
   vertically — never sideways toward the title or the open button. */
.send,.viewtoggle button,.arrowpad button,.ci-open,.ci-x,.ci-pin,.chip .x{position:relative}
.tool-btn::after,.send::after,.viewtoggle button::after,.arrowpad button::after,
.ci-open::after,.ci-x::after,.ci-pin::after,.chip .x::after{content:"";position:absolute}
.tool-btn::after{inset:-3px}                      /* 46→52 desktop, 38→44 mobile */
.send::after{inset:-2px}                          /* 50→54 desktop, 40→44 mobile */
.viewtoggle button::after{inset:-6px 0}           /* 32→44 tall on mobile */
.arrowpad button::after{inset:-2px 0}             /* 40→44 tall on mobile */
.ci-open::after{inset:-8px -7px -8px -1px}        /* 44 tall, grows toward the row edge */
.ci-x::after{inset:-8px 0}                        /* 44 tall only — destructive button */
.ci-pin::after{inset:-8px 0}                      /* 44 tall — thumb-friendly */
.chip .x::after{inset:-14px -8px -14px -6px}      /* ~44 tall inside the chip */

/* Floating scroll-to-top / scroll-to-bottom button. Lives in #stage (over both
 * the chat bubbles and the terminal iframe). Appears while scrolling: up-arrow
 * while scrolling up (jump to top), down-arrow while scrolling down (to bottom). */
.scrolljump{position:absolute;right:16px;bottom:18px;z-index:60;width:46px;height:46px;border-radius:50%;
  background:var(--panel2);border:1px solid var(--border2);color:var(--text);display:grid;place-items:center;
  box-shadow:0 8px 22px rgba(0,0,0,.45);opacity:0;transform:translateY(10px) scale(.92);
  transition:opacity .16s ease,transform .16s ease;pointer-events:none}
.scrolljump.show{opacity:.96;transform:none;pointer-events:auto}
.scrolljump:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.scrolljump:active{transform:scale(.94)}
.scrolljump svg{width:22px;height:22px;transition:transform .16s ease}
.scrolljump.down svg{transform:rotate(180deg)}

/* loading + toast */
/* Toast — small transient notice pill, centered above the composer. JS toggles
   .show and handles the auto-hide; it never blocks taps (pointer-events:none). */
.toast{position:fixed;left:50%;bottom:120px;z-index:260;max-width:86vw;
  padding:11px 20px;border-radius:999px;background:var(--panel2);border:1px solid var(--border2);
  color:var(--text);font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  box-shadow:0 10px 30px rgba(0,0,0,.45);opacity:0;transform:translate(-50%,8px);
  transition:opacity .18s ease,transform .18s ease;pointer-events:none}
.toast.show{opacity:1;transform:translate(-50%,0)}
#loading{position:fixed;inset:0;background:rgba(0,0,0,.45);display:none;place-items:center;z-index:200}
#loading.show{display:grid}
.spinner{width:46px;height:46px;border:3px solid var(--border2);border-top-color:var(--orange);border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

@media(max-width:760px){
  #shell{grid-template-columns:1fr}
  /* #side (z-index 300) now beats the artifact panel (z-index 250) because #shell
     is no longer a stacking context (see the #shell rule up top). So the sidebar
     covers the artifact, and the artifact stays visible (dimmed) behind it. */
  #side{position:fixed;z-index:300;width:86%;max-width:340px;height:100%;transform:translateX(-100%);transition:transform .22s ease-out}
  #shell.side-open #side{transform:translateX(0);display:flex}
  #side-toggle{display:grid;width:34px;height:34px;position:relative}
  #side-toggle::after{content:"";position:absolute;inset:-5px}   /* 34→44 hit area */
  #side-toggle svg{width:17px;height:17px}
  /* SLIM two-row header on mobile: row 1 = menu + chat name, row 2 = full-width
     Chat/Terminal toggle — both rows tightened to give the chat more height. */
  .topbar{height:auto;min-height:0;flex-wrap:wrap;align-items:center;gap:7px;padding:6px 12px 7px}
  .tb-title{flex:1 1 0;min-width:0;font-size:15px;gap:7px;padding:3px 4px}  /* basis 0 so it shares row 1 with the menu button */
  .tb-title #tb-dot{display:block}
  .viewtoggle{flex:1 1 100%;width:100%;padding:3px}   /* own full-width row, slimmer */
  .viewtoggle button{flex:1;text-align:center;padding:6px 0;font-size:13px;min-height:32px}
  .title-pop{font-size:14.5px}
  /* z-index 290 sits between the artifact panel (250) and #side (300): it dims the
     artifact behind the open sidebar instead of leaving it bright. */
  #backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:290;display:none}
  #shell.side-open #backdrop{display:block}
  .rv-inner{padding:22px 16px 36px}
  #workflow-strip{padding:6px 16px 0}   /* match .rv-inner side padding on phone */
  .agents-bar{padding:0}
  .agents-bar:not(:empty){padding:0 0 24px}
  .agent-steps-list{padding:16px}
  .msg{max-width:94%}                    /* bubbles nearly full width on phone */
  /* Wide code hints "more to the right": a soft right-edge shadow that only
     appears while there is overflow left to scroll (local-attachment cover
     slides over it at the end). No mask, so the Copy button never dims. */
  .msg-code{background:
    linear-gradient(270deg,#1a1916 12px,rgba(26,25,22,0) 44px) right/44px 100% no-repeat,
    linear-gradient(270deg,rgba(0,0,0,.5),rgba(0,0,0,0) 26px) right/26px 100% no-repeat,
    #1a1916;
    background-attachment:local,scroll,scroll}
  .composer{padding:10px 14px 12px;padding-bottom:calc(12px + env(safe-area-inset-bottom,0px))}
  /* Sidebar usage meter clears the iPhone home indicator too. */
  .side-usage{padding-bottom:calc(13px + env(safe-area-inset-bottom,0px))}
  /* Control strip = ONE row: CLR · NAV · Stop · CTX · Tray, shrunk to fit
     (nothing dropped). The CTX bar is the flexible part — it shrinks FIRST so
     the touch buttons + Tray keep their size. */
  .composer-toolbar{flex-wrap:nowrap;gap:6px;margin-bottom:9px}
  .adv-mode{height:44px;padding:0 11px;font-size:12.5px;gap:5px;flex-shrink:0}
  /* Buttons keep a real 44px touch target on phones; they don't grow/shrink. */
  .arrowpad{gap:5px;flex:0 0 auto}
  .arrowpad button{height:44px;width:44px;font-size:13px}
  .arrowpad #btn-stop{width:auto;min-width:44px;padding:0 11px}
  .navpad{flex:0 0 auto}
  /* CTX shrinks first to make room: just the % (bar hidden), can go narrow. */
  .composer-toolbar .ctxmini{flex:1 1 auto;min-width:0;width:auto;height:44px;padding:0 11px;gap:5px;overflow:hidden}
  .composer-toolbar .ctxmini .track{display:none}
  /* Tray pinned far right, never shrinks. */
  .composer-toolbar #jobs-tray{flex:0 0 auto}
  .tray-count{height:44px;min-height:44px;padding:0 13px}

  /* INPUT BOX — same grid as desktop, just a different grid-template-areas.
     EMPTY  → one row:  [attach][mic]  [ type here ]  [send]
     TYPING → two rows: full-width textarea on top, then [attach][mic] … [send]
     (the default areas from the base rule). JS adds .has-text the moment there
     is text (typed OR dictated). Because both states are the SAME 4-column grid,
     the buttons just slide between cells — no regrouping, no left↔right flash. */
  .inputbox{gap:6px 7px;padding:6px 8px}
  .inputbox #composer-input{font-size:16px;padding:4px 2px}
  .inputbox:not(.has-text){grid-template-areas:"up mic ta send";padding:6px 8px 6px 12px}
  .tool-btn{width:38px;height:38px;border-radius:11px}
  .inputbox #btn-mic{width:52px}   /* keep the mic a clear, wider bar on phones */
  .send{width:40px;height:40px;border-radius:12px}
  .send svg{width:18px;height:18px}
  .inputbox.has-text{padding:9px 12px}
}
/* ── In-chat question widgets ──────────────────────────────────────────────
   A Claude ```ask block renders as this card: the question, then big tappable
   choice buttons or an input + Send. Big targets, plain look, orange accent —
   built for tapping on a phone, not reading raw JSON. */
.ask-widget{margin:14px 0;padding:16px 16px 18px;background:var(--panel);
  border:1px solid var(--border2);border-radius:14px;display:flex;flex-direction:column;gap:14px}
.ask-q{font-size:17px;font-weight:600;line-height:1.45;color:var(--text)}
.ask-options{display:flex;flex-direction:column;gap:10px}
.ask-opt{min-height:52px;padding:13px 18px;border-radius:12px;font-size:16px;font-weight:600;
  text-align:left;color:var(--text);background:var(--panel2);border:1px solid var(--border2);
  transition:.12s;cursor:pointer}
.ask-opt:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.ask-opt:active{transform:translateY(1px)}
.ask-input-row{display:flex;gap:10px;align-items:stretch}
.ask-input{flex:1;min-height:52px;padding:13px 16px;border-radius:12px;font-size:16px;
  color:var(--text);background:var(--bg2);border:1px solid var(--border2);font-family:var(--sans)}
.ask-input:focus{border-color:var(--orange);box-shadow:0 0 0 4px var(--orange-soft);outline:none}
.ask-send{min-height:52px;padding:0 22px;border-radius:12px;font-size:16px;font-weight:700;
  color:#fff;background:var(--orange);border:none;flex-shrink:0;cursor:pointer;transition:.12s}
.ask-send:hover{filter:brightness(1.06)}
.ask-send:active{transform:translateY(1px)}
/* Multi-select: a ticked option (before Submit) shows the orange-soft state. */
.ask-opt.ask-chosen{background:var(--orange-soft);border-color:var(--orange);color:var(--orange)}
/* "Other → type your own": the inline input/Send stay hidden until the pill is tapped. */
.ask-input.hidden,.ask-send.hidden{display:none}
/* Answered state: dim the card, mark the chosen option, lock everything. */
.ask-locked{opacity:.85}
.ask-locked .ask-opt,.ask-locked .ask-input,.ask-locked .ask-send{cursor:default;opacity:.6}
.ask-locked .ask-opt.ask-chosen{opacity:1;background:var(--orange-soft);
  border-color:var(--orange);color:var(--orange)}
.ask-locked .ask-input{opacity:1}

/* ── Artifacts ──────────────────────────────────────────────────────────────
   A Claude ```artifact block renders as this tappable CARD inside the bubble
   (never the raw content). Tapping it opens the slide-over panel below. Big
   target, obviously clickable, calm — matches the ask-widget visual language. */
.artifact-card,.art-card-loading{margin:14px 0;display:flex;align-items:center;gap:14px;min-height:64px;
  padding:14px 16px;background:var(--panel);border:1px solid var(--border2);border-radius:14px;
  cursor:pointer;transition:background .12s,border-color .12s,transform .08s;-webkit-user-select:none;user-select:none}
.artifact-card:hover{background:var(--panel2);border-color:var(--orange)}
.artifact-card:active{transform:translateY(1px)}
.art-card-icon{width:42px;height:42px;border-radius:11px;flex-shrink:0;display:grid;place-items:center;
  background:var(--orange-soft);color:var(--orange)}
.art-card-icon svg{width:22px;height:22px}
.art-card-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.art-card-title{font-size:16px;font-weight:700;color:var(--text);line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.art-card-kind{font-size:12.5px;font-weight:600;color:var(--muted);letter-spacing:.02em}
.art-card-go{flex-shrink:0;font-size:13px;font-weight:700;color:var(--orange);
  background:var(--orange-soft);padding:8px 14px;border-radius:10px}
/* "Writing…" placeholder while an artifact is still streaming in — same card,
   slightly dimmed with a calm pulse, not clickable. */
.art-card-loading{cursor:default;animation:art-card-pulse 1.8s ease-in-out infinite}
.art-card-loading:hover{background:var(--panel);border-color:var(--border2)}
.art-card-loading:active{transform:none}
@keyframes art-card-pulse{0%,100%{opacity:.7}50%{opacity:.45}}

/* ── Cards block ─────────────────────────────────────────────────────────────
   A Claude ```cards block renders INLINE in the bubble (no slide-over) as one
   of three sub-types: links (stacked quick-links), snippet (preview cards),
   products (swipeable carousel). Uses :root tokens only — native to the chat. */
.cards-block{margin:14px 0;display:block}
.cards-block .cards-title{font-size:14px;font-weight:700;color:var(--text);
  margin:0 0 10px;letter-spacing:.01em}
.cards-note{font-size:13px;color:var(--faint);font-style:italic;padding:10px 2px}
/* streaming placeholder */
.cards-loading{min-height:60px;background:var(--panel);border:1px solid var(--border2);
  border-radius:var(--r);padding:16px;animation:art-card-pulse 1.8s ease-in-out infinite}
.cards-loading-bar{height:12px;width:60%;border-radius:6px;background:var(--panel2)}

/* links — stacked tappable rows */
.cards-links{display:flex;flex-direction:column;gap:8px}
.cards-link{display:flex;align-items:center;gap:12px;min-height:54px;padding:10px 14px;
  background:var(--panel);border:1px solid var(--border2);border-radius:var(--r);
  text-decoration:none;cursor:pointer;transition:background .12s,border-color .12s,transform .08s}
.cards-link:hover{background:var(--panel2);border-color:var(--orange)}
.cards-link:active{transform:translateY(1px)}
.cards-link-ic{width:34px;height:34px;flex-shrink:0;border-radius:9px;overflow:hidden;
  display:grid;place-items:center;background:var(--panel2);color:var(--muted)}
.cards-link-ic img{width:22px;height:22px;object-fit:contain;border-radius:5px}
.cards-link-ic svg{width:20px;height:20px}
.cards-link-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.cards-link-t{font-size:15px;font-weight:700;color:var(--text);line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cards-link-s{font-size:12.5px;color:var(--muted);line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cards-link-go{flex-shrink:0;font-size:22px;font-weight:400;color:var(--faint);line-height:1}

/* snippet — preview cards */
.cards-snippet{background:var(--panel);border:1px solid var(--border2);border-radius:var(--r);
  padding:14px 16px;margin-bottom:8px}
.cards-snippet:last-child{margin-bottom:0}
.cards-snip-t{font-size:15px;font-weight:700;color:var(--text);line-height:1.35;margin-bottom:6px}
.cards-snip-x{font-size:13.5px;color:var(--muted);line-height:1.5;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical}
.cards-snip-src{display:inline-block;margin-top:10px;font-size:12.5px;font-weight:700;
  color:var(--orange);background:var(--orange-soft);padding:6px 12px;border-radius:9px;
  text-decoration:none;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
a.cards-snip-src:hover{filter:brightness(1.12)}
.cards-snip-src-flat{cursor:default}

/* products — swipeable carousel */
.cards-carousel{display:flex;gap:12px;overflow-x:auto;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;padding:2px 40px 6px 2px;scrollbar-width:none}
.cards-carousel::-webkit-scrollbar{display:none}
.cards-product{flex:0 0 160px;width:160px;scroll-snap-align:start;
  background:var(--panel);border:1px solid var(--border2);border-radius:var(--r);
  overflow:hidden;display:flex;flex-direction:column}
.cards-prod-img{height:110px;width:100%;flex-shrink:0;background:var(--panel2);position:relative;overflow:hidden}
.cards-prod-img img{width:100%;height:100%;object-fit:cover;display:block}
.cards-prod-noimg{display:grid;place-items:center;color:var(--faint)}
.cards-prod-noimg svg{width:38px;height:38px}
.cards-prod-body{padding:10px 11px 6px;flex:1;display:flex;flex-direction:column;gap:4px}
.cards-prod-name{font-size:14px;font-weight:700;color:var(--text);line-height:1.3;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.cards-prod-price{font-size:15px;font-weight:800;color:var(--orange);line-height:1.2}
.cards-prod-note{font-size:12px;color:var(--muted);line-height:1.4;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.cards-prod-btn{display:block;margin:8px 10px 10px;height:40px;line-height:40px;text-align:center;
  font-size:13.5px;font-weight:700;color:var(--orange);background:var(--orange-soft);
  border-radius:10px;text-decoration:none;cursor:pointer;transition:filter .12s}
.cards-prod-btn:hover{filter:brightness(1.12)}
.cards-prod-btn-off{opacity:.5;cursor:default}

/* phone: slightly smaller carousel cards; links stay full-width */
@media (max-width:520px){
  .cards-product{flex-basis:148px;width:148px}
  .cards-prod-img{height:100px}
  .cards-carousel{padding-right:34px}
}

/* ============================================================================
 * Fight Mode — an in-chat ```fight widget: mode picker → battle → winner submit.
 * Skin/feel ported from temp/lite-feature-samples/fight-mode. Tokens only; green
 * = #9CCB5A (win). Big 44px+ targets, phone-first. Repaint-safe (state in JS). */
.fight-block{margin:14px 0;display:block}
.fight-note{font-size:13px;color:var(--faint);font-style:italic;padding:10px 2px}
.fight-done-note{padding:14px 16px;background:var(--panel);border:1px solid var(--border);
  border-radius:var(--r);color:var(--muted);font-style:normal;font-weight:600}
.fight-loading{min-height:60px;background:var(--panel);border:1px solid var(--border2);
  border-radius:var(--r);padding:16px;animation:art-card-pulse 1.8s ease-in-out infinite}

/* header */
.fight-head{display:flex;align-items:center;gap:10px;margin-bottom:14px}
.fight-bolt{width:34px;height:34px;border-radius:10px;flex:none;
  background:var(--orange-soft);display:flex;align-items:center;justify-content:center;font-size:18px}
.fight-titles{min-width:0}
.fight-title{font-size:18px;font-weight:800;letter-spacing:-.01em;line-height:1.2}
.fight-subj{font-size:13.5px;color:var(--muted);margin-top:1px;line-height:1.3}
.fight-sub{color:var(--muted);font-size:14px;margin:-6px 0 14px}

.fight-topbtn{background:var(--panel2);border:1px solid var(--border2);color:var(--text);
  font-family:inherit;font-weight:600;font-size:14px;border-radius:10px;padding:9px 13px;
  min-height:40px;cursor:pointer;transition:background .12s}
.fight-topbtn:hover{background:var(--border)}
.fight-topbtn:active{transform:translateY(1px)}

.fight-stage-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px}
.fight-stage-name{font-size:17px;font-weight:800;display:flex;align-items:center;gap:8px}

/* mode picker (hero) */
.fight-picker{display:flex;flex-direction:column;gap:11px}
.fight-tile{background:var(--panel);border:1px solid var(--border);border-radius:var(--r);
  padding:15px;cursor:pointer;text-align:left;display:flex;align-items:center;gap:14px;
  color:var(--text);font-family:inherit;width:100%;
  transition:transform .12s ease,border-color .12s ease,background .12s ease}
.fight-tile:hover{border-color:var(--border2);background:var(--panel2)}
.fight-tile:active{transform:scale(.985)}
.fight-tile-e{width:50px;height:50px;border-radius:13px;flex:none;background:var(--orange-soft);
  display:flex;align-items:center;justify-content:center;font-size:25px}
.fight-tile-tx{flex:1;min-width:0}
.fight-tile-n{font-size:17px;font-weight:800;letter-spacing:-.01em}
.fight-tile-d{font-size:13.5px;color:var(--muted);margin-top:3px;line-height:1.4}
.fight-tile-a{color:var(--faint);font-size:22px;flex:none}

/* progress pill */
.fight-prog-wrap{text-align:center;margin-bottom:12px}
.fight-prog{font-size:13px;color:var(--muted);font-weight:600;background:var(--panel2);
  border:1px solid var(--border);padding:6px 11px;border-radius:999px}
.fight-hint{text-align:center;color:var(--faint);font-size:13px;margin-top:14px}

/* generic option card */
.fight-opt{background:var(--panel);border:1px solid var(--border);border-radius:var(--r);
  padding:15px 14px;cursor:pointer;text-align:left;color:var(--text);font-family:inherit;width:100%;
  transition:transform .14s ease,border-color .14s ease,opacity .25s ease}
.fight-opt:hover{border-color:var(--border2)}
.fight-opt:active{transform:scale(.97)}
.fight-opt-tag{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--orange);margin-bottom:7px}
.fight-opt-big{font-size:17px;font-weight:700;line-height:1.3}
.fight-opt-note{font-size:13px;color:var(--muted);margin-top:6px;line-height:1.4}

/* 1 v 1 arena */
.fight-arena{display:flex;gap:12px;align-items:stretch}
.fight-arena .fight-opt{flex:1;display:flex;flex-direction:column;justify-content:center;min-height:140px}
.fight-vs{align-self:center;font-size:13px;font-weight:800;color:var(--faint);background:var(--panel2);
  border:1px solid var(--border);width:38px;height:38px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center}
.fight-opt.fight-win{border-color:#9CCB5A;animation:fight-pulse .5s ease}
.fight-opt.fight-slideout{opacity:0;transform:translateX(-30px) scale(.9)}
.fight-opt.fight-slidein{animation:fight-slidein .35s ease}

/* crown */
.fight-crown{margin-top:6px;background:linear-gradient(180deg,var(--panel2),var(--panel));
  border:1px solid #9CCB5A;border-radius:var(--r);padding:20px 16px;text-align:center;
  animation:fight-dropin .45s cubic-bezier(.2,.8,.3,1.2)}
.fight-crown.fight-frozen{animation:none}
.fight-crown-c{font-size:34px}
.fight-crown-lbl{font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#9CCB5A;margin-top:4px}
.fight-crown-val{font-size:21px;font-weight:800;margin-top:4px}

/* 3 ways lanes */
.fight-lanes{display:flex;gap:10px;align-items:stretch}
.fight-lane{flex:1;background:var(--panel);border:1px solid var(--border);border-radius:var(--r);
  padding:13px 11px;display:flex;flex-direction:column;
  transition:flex .3s ease,opacity .3s ease,transform .3s ease}
.fight-lane-tag{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--orange);margin-bottom:6px}
.fight-lane-take{font-size:14px;font-weight:600;line-height:1.35;flex:1}
.fight-lane-sub{font-size:12px;color:var(--muted);margin-top:5px;line-height:1.35}
.fight-lane-btns{display:flex;gap:7px;margin-top:11px}
.fight-mini{flex:1;border:none;border-radius:9px;font-family:inherit;font-weight:700;font-size:13px;
  min-height:40px;padding:9px 0;cursor:pointer;transition:transform .1s,filter .1s}
.fight-mini:active{transform:scale(.95)}
.fight-mini.fight-keep{background:var(--orange-soft);color:var(--orange);border:1px solid rgba(217,119,87,.4)}
.fight-mini.fight-kill{background:var(--panel2);color:var(--muted);border:1px solid var(--border2)}
.fight-lane.fight-killed{opacity:0;transform:scale(.85);flex:0;padding:0;margin:0;pointer-events:none;overflow:hidden}
.fight-lane.fight-chosen{border-color:#9CCB5A;flex:1;background:linear-gradient(180deg,var(--panel2),var(--panel))}
.fight-lane.fight-chosen .fight-lane-take{font-size:16px}
.fight-lane-flag{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:#9CCB5A;margin-bottom:8px;display:flex;align-items:center;gap:6px}

/* Give me 10 */
.fight-ten-grid{display:flex;flex-direction:column;gap:11px}
.fight-ten-extra{margin-top:11px}
.fight-opt.fight-fanin{animation:fight-fanin .45s cubic-bezier(.2,.8,.3,1.2) both}
.fight-ten-grid .fight-opt.fight-fanin:nth-child(1){animation-delay:.02s}
.fight-ten-grid .fight-opt.fight-fanin:nth-child(2){animation-delay:.10s}
.fight-ten-grid .fight-opt.fight-fanin:nth-child(3){animation-delay:.18s}
.fight-more{width:100%;background:var(--panel2);border:1px solid var(--border);border-radius:12px;
  padding:13px 14px;margin-top:11px;text-align:center;color:var(--muted);font-size:14px;font-weight:600;
  font-family:inherit;min-height:46px;cursor:pointer;transition:background .12s}
.fight-more:hover{background:var(--border)}
.fight-more:active{transform:translateY(1px)}

/* "Use this" submit bar */
.fight-use{margin-top:16px;width:100%;background:var(--orange);color:#fff;border:none;border-radius:12px;
  font-family:inherit;font-weight:700;font-size:16px;min-height:52px;padding:14px 16px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;gap:8px;
  box-shadow:0 3px 12px rgba(217,119,87,.24);transition:transform .12s,filter .12s}
.fight-use:hover{filter:brightness(1.04)}
.fight-use:active{transform:scale(.985)}

/* animations */
@keyframes fight-slidein{from{opacity:0;transform:translateX(40px) scale(.92)}to{opacity:1;transform:translateX(0) scale(1)}}
@keyframes fight-dropin{0%{opacity:0;transform:translateY(-24px) scale(.92)}100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes fight-fanin{0%{opacity:0;transform:translateY(26px) scale(.92)}100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes fight-pulse{0%{box-shadow:0 0 0 0 rgba(156,203,90,.45)}100%{box-shadow:0 0 0 14px rgba(156,203,90,0)}}

/* phone: tighter arena/lane text */
@media (max-width:520px){
  .fight-arena .fight-opt{min-height:128px}
  .fight-opt-big{font-size:16px}
  .fight-lane{padding:12px 9px}
}

/* ============================================================================
 * Spark Mode — an in-chat ```spark widget: three pieces of OUTSIDE fuel land on
 * the table (quote / out-of-industry example / visual reference) to break a
 * stuck idea. Each card has "Remix with this"; "Spark again" reshuffles. Tokens
 * only (NO purple). Big 44px+ targets, phone-first. Repaint-safe (state in JS). */
.spark-block{margin:14px 0;display:block}
.spark-note{font-size:13px;color:var(--faint);font-style:italic;padding:10px 2px}
.spark-done-note{padding:14px 16px;background:var(--panel);border:1px solid var(--border);
  border-radius:var(--r);color:var(--muted);font-style:normal;font-weight:600;margin-top:12px}
.spark-loading{min-height:60px;background:var(--panel);border:1px solid var(--border2);
  border-radius:var(--r);padding:16px;animation:art-card-pulse 1.8s ease-in-out infinite}

/* header */
.spark-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.spark-dot{width:34px;height:34px;border-radius:10px;flex:none;
  background:var(--orange-soft);display:flex;align-items:center;justify-content:center;
  font-size:18px;color:var(--orange)}
.spark-titles{min-width:0}
.spark-title{font-size:18px;font-weight:800;letter-spacing:-.01em;line-height:1.2}
.spark-subj{font-size:13.5px;color:var(--muted);margin-top:1px;line-height:1.3;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}

/* "Fuel on the table" divider */
.spark-lead{display:flex;align-items:center;gap:10px;margin:6px 2px 12px;
  font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.spark-line{flex:1;height:1px;background:var(--border)}

/* cards. Base state is fully visible so a FROZEN/used block (which never gets the
 * .spark-in class) paints calm and correct. Live cards are hidden by an inline
 * style set in JS the instant they're created, then .spark-in animates them in —
 * so the landing has somewhere to land FROM without leaving frozen cards blank. */
.spark-cards{display:flex;flex-direction:column;gap:12px}
.spark-card{background:var(--panel);border:1px solid var(--border);border-radius:var(--r);
  padding:15px;position:relative;overflow:hidden}
.spark-card.spark-in{animation:spark-landing .55s cubic-bezier(.18,.9,.28,1.2) forwards}
/* fuel flash as the card lands */
.spark-card::after{content:"";position:absolute;inset:0;border-radius:var(--r);pointer-events:none;
  background:radial-gradient(120% 80% at 50% 0%, var(--orange-soft), transparent 60%);opacity:0}
.spark-card.spark-in::after{animation:spark-flash .7s ease-out forwards}

.spark-tag{display:inline-flex;align-items:center;gap:6px;
  font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--orange);background:var(--orange-soft);padding:4px 10px;border-radius:20px;margin-bottom:11px}
.spark-body{font-size:16px;line-height:1.5;color:var(--text);margin-bottom:6px}
.spark-body-quote{font-style:italic;font-weight:500}
.spark-meta{font-size:13px;color:var(--muted);margin-bottom:13px}

/* visual reference — a tasteful CSS gradient placeholder with its label */
.spark-swatch{min-height:96px;border-radius:10px;margin-bottom:12px;
  display:flex;align-items:flex-end;padding:10px 12px;
  color:#fff;font-size:13px;font-weight:600;line-height:1.35;
  text-shadow:0 1px 4px rgba(0,0,0,.45);border:1px solid var(--border2)}

/* "Remix with this" — 46px target, orange outline (matches remix-btn in mockup) */
.spark-remix{width:100%;min-height:46px;cursor:pointer;
  background:transparent;color:var(--orange);border:1px solid var(--orange);border-radius:11px;
  font-family:inherit;font-size:15px;font-weight:700;
  display:flex;align-items:center;justify-content:center;gap:8px;
  transition:background .12s ease,transform .1s ease}
.spark-remix:active{background:var(--orange-soft);transform:translateY(1px)}
.spark-remix-off{opacity:.45;cursor:default;pointer-events:none}

/* "Spark again" — 48px ghost button */
.spark-again{margin-top:12px;width:100%;min-height:48px;cursor:pointer;
  background:var(--panel);color:var(--text);border:1px solid var(--border2);border-radius:12px;
  font-family:inherit;font-size:15px;font-weight:700;
  display:flex;align-items:center;justify-content:center;gap:8px;
  transition:background .12s ease,border-color .12s ease,transform .08s ease}
.spark-again:hover{background:var(--panel2);border-color:var(--orange)}
.spark-again:active{transform:translateY(1px)}

@keyframes spark-landing{0%{opacity:0;transform:translateY(22px) scale(.96)}
  60%{opacity:1;transform:translateY(-3px) scale(1.01)}100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes spark-flash{0%{opacity:1}100%{opacity:0}}

/* phone: slightly larger fuel text */
@media (max-width:520px){
  .spark-body{font-size:15.5px}
  .spark-swatch{min-height:88px}
}

/* Slide-over PANEL — from the right on desktop, full-screen on mobile.
   Created once in JS and appended to <body>. Premium, calm, lots of whitespace. */
.art-backdrop{position:fixed;inset:0;z-index:240;background:rgba(0,0,0,.5);
  opacity:0;pointer-events:none;transition:opacity .2s ease}
.art-backdrop.show{opacity:1;pointer-events:auto}
.art-panel{position:fixed;top:0;right:0;z-index:250;height:100vh;height:100dvh;
  width:min(640px,94vw);background:var(--panel);border-left:1px solid var(--border2);
  display:flex;flex-direction:column;transform:translateX(102%);transition:transform .24s ease-out;
  box-shadow:-18px 0 50px rgba(0,0,0,.5)}
.art-panel.show{transform:none}

/* ── MOBILE STAGE OVERLAY (<900px) — Towaiji 2026-06-14 ───────────────────────
 * The panel fills ONLY the message-bubble area (#stage). js/artifacts.js sets
 * top/left/width/height inline to mirror #stage and keeps them synced as it
 * resizes (typing grows the composer → #stage shrinks → panel shrinks). The top
 * bar stays above it and the composer stays below it, both usable — no backdrop,
 * no scroll-lock. */
body.art-stage .art-panel{
  border:1px solid var(--border2);
  border-radius:0;
  box-shadow:0 -8px 30px rgba(0,0,0,.35);
}
/* Bigger/smaller toggle (Towaiji 2026-06-14): the ⤢ button shows ONLY in mobile
 * stage mode, mirroring .art-close so it's a matching 40-44px tappable target.
 * BIG (art-stage-full) covers the whole screen, so kill the border radius +
 * shadow for an edge-to-edge reading surface. */
body.art-stage .art-max{width:44px;height:44px;border-radius:11px;flex-shrink:0;display:grid;place-items:center;
  font-size:18px;color:var(--muted);background:var(--panel2);border:1px solid var(--border2);transition:.12s}
body.art-stage .art-max:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
body.art-stage-full .art-max{color:var(--orange);border-color:var(--orange)}
body.art-stage-full .art-panel{border-radius:0;box-shadow:none}

/* ── DOCKED MODE (desktop/tablet, >=900px) ────────────────────────────────────
 * Opening an artifact docks it beside the chat instead of covering it. The
 * shell (sidebar + chat) is given a right margin equal to the panel width, so
 * the chat COLUMN physically shrinks — no overlay, no backdrop, no scroll-lock,
 * the conversation stays fully interactive (scroll, tap, type). The panel sits
 * fixed in the reserved gutter. Narrow phones never get this class, so today's
 * modal slide-over is untouched below 900px. */
:root{--art-dock-w:min(560px,42vw)}
/* CLOSE = the exact mirror of open. On close JS adds .art-closing and removes
 * .art-docked only AFTER the panel finishes sliding out (transitionend). While
 * closing we keep the docked panel WIDTH and the shell margin transition so the
 * chat column animates back to full width in sync with the panel sliding out,
 * using the same .24s ease-out curve in reverse — no end-of-close snap. */
body.art-docked #shell,body.art-closing #shell{transition:margin-right .24s ease-out}
body.art-docked #shell{margin-right:var(--art-dock-w)}
body.art-docked .art-panel,body.art-closing .art-panel{width:var(--art-dock-w);box-shadow:-1px 0 0 var(--border2)}
body.art-docked .art-backdrop{display:none}
/* The maximize button belongs to the mobile stage overlay only — hidden by
 * default (incl. desktop side-dock); the stage rules above opt it back in. */
.art-max{display:none}

.art-head{flex-shrink:0;display:flex;align-items:flex-start;gap:14px;padding:18px 20px;
  border-bottom:1px solid var(--border);background:var(--bg2)}
.art-titlewrap{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.art-kind{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--orange)}
.art-title{font-size:19px;font-weight:700;color:var(--text);line-height:1.35;overflow-wrap:anywhere}
.art-actions{display:flex;align-items:center;gap:8px;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end}
.art-btn{height:44px;padding:0 16px;border-radius:11px;font-size:14.5px;font-weight:600;
  color:var(--text);background:var(--panel2);border:1px solid var(--border2);transition:.12s}
.art-btn:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.art-btn:active{transform:translateY(1px)}
.art-close{width:44px;height:44px;border-radius:11px;flex-shrink:0;display:grid;place-items:center;
  font-size:18px;color:var(--muted);background:var(--panel2);border:1px solid var(--border2);transition:.12s}
.art-close:hover{background:rgba(224,108,117,.16);color:#E06C75;border-color:#E06C75}
/* Back arrow — top-left of the header, shown ONLY in a nested view (.has-back).
 * Back = up one level (detail → tray list); the X still closes the whole panel.
 * Big 44px target so it passes the non-tech-staff standard. */
.art-back{display:none;width:44px;height:44px;border-radius:11px;flex-shrink:0;place-items:center;
  font-size:30px;line-height:1;color:var(--text);background:var(--panel2);border:1px solid var(--border2);transition:.12s}
.art-back:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.art-back:active{transform:translateY(1px)}
.art-panel.has-back .art-back{display:grid}
/* Sign-in card — shown in the chat when the session is waiting at the OAuth prompt */
.login-card{margin:14px 12px;padding:16px 18px;border-radius:16px;background:var(--panel);
  border:1px solid var(--border);display:flex;flex-direction:column;gap:10px}
.login-title{font-size:16px;font-weight:700;color:var(--text)}
.login-sub{font-size:13.5px;color:var(--muted);line-height:1.45}
.login-connect{align-self:flex-start;height:44px;padding:0 20px;border-radius:11px;font-size:14.5px;
  font-weight:700;color:#fff;background:var(--orange);border:1px solid var(--orange);transition:.12s}
.login-connect:hover{filter:brightness(1.06)}
.login-connect:disabled{opacity:.5;cursor:not-allowed}
.login-hint{font-size:12.5px;color:var(--muted)}
.login-row{display:flex;gap:8px;align-items:center}
.login-input{flex:1;min-width:0;height:44px;padding:0 14px;border-radius:11px;font-size:15px;
  color:var(--text);background:var(--panel2);border:1px solid var(--border2)}
.login-done{height:44px;padding:0 18px;border-radius:11px;font-size:14.5px;font-weight:700;
  color:var(--text);background:var(--panel2);border:1px solid var(--border2);transition:.12s}
.login-done:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.login-done:disabled{opacity:.5;cursor:not-allowed}
.login-status{font-size:13px;color:var(--muted)}

/* ====================== SIDEBAR LOGIN TAKEOVER (2026-06-14) ====================== */
/* When sign-in is needed the sidebar morphs into the login card (top layer) instead
 * of a card floating over the chat/artifact. login-mode hides the chat list etc. */
/* The login FILLS the sidebar (his ask): #side-login becomes a flex column and the
 * card stretches to fill it, content vertically centered, flush (no card-on-card) —
 * so the whole sidebar reads as the sign-in screen, not a small box at the top. */
.side-login{display:none;flex:1;min-height:0;overflow-y:auto}
#shell.login-mode #side-login{display:flex;flex-direction:column}
#shell.login-mode .newbtn,
#shell.login-mode .searchwrap,
#shell.login-mode .chatlist,
#shell.login-mode .side-usage{display:none}
/* LOGIN-FREEZE FIX (2026-06-16): when sign-in is needed, the live terminal pane is
 * frozen but still mounted over the main column, and that dead iframe captures every
 * click — making the whole screen feel locked even with the card shown. Drop the
 * stage out of the layout entirely in login-mode so nothing in the main area can
 * swallow clicks; the sign-in takeover (and the topbar / sidebar toggle) stay
 * interactive. Reversible: removing .login-mode restores the pane on sign-in. */
#shell.login-mode #stage{display:none}
.side-login .login-card{flex:1;margin:0;border-radius:0;background:transparent;border:none;box-shadow:none;
  justify-content:center;gap:16px;padding:26px 20px}
.side-login .login-title{font-size:20px}
.side-login .login-sub{font-size:14.5px}
.side-login .login-connect{align-self:stretch;width:100%;height:50px;justify-content:center;display:flex;align-items:center;font-size:15.5px}
.side-login .login-done{width:auto}
.login-gen{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--muted)}
.login-gen-dot{width:14px;height:14px;flex-shrink:0;border-radius:50%;
  border:2px solid var(--border2);border-top-color:var(--orange);
  animation:login-gen-spin .8s linear infinite}
.login-gen-txt{line-height:1.4}
@keyframes login-gen-spin{to{transform:rotate(360deg)}}

/* Mobile avatar → account/login in the SIDEBAR (2026-06-14). Back control at the
 * top returns to the chat list; signed-in account rows match the sidebar skin. */
.side-acct-back{align-self:flex-start;display:inline-flex;align-items:center;gap:6px;
  height:40px;padding:0 14px 0 8px;margin-bottom:4px;border-radius:11px;
  font-size:14.5px;font-weight:600;color:var(--muted);
  background:transparent;border:1px solid transparent;cursor:pointer;transition:.12s}
.side-acct-back:hover{background:var(--panel2);color:var(--text)}
.side-acct-back svg{width:20px;height:20px}
/* The signed-in account card fills the sidebar like the sign-in takeover does. */
.side-login .side-acct{justify-content:flex-start;gap:12px;padding:18px 20px}
.side-acct-av{width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:26px;font-weight:700;color:#fff;background:var(--orange);margin-top:6px}
.side-acct-email{font-size:17px;font-weight:700;color:var(--text);word-break:break-all}
.side-acct-sub{font-size:13.5px;color:var(--muted);margin-top:-4px}
.side-acct-out{margin-top:auto;width:100%;height:50px;border-radius:11px;
  font-size:15px;font-weight:700;color:var(--text);
  background:var(--panel2);border:1px solid var(--border2);cursor:pointer;transition:.12s}
.side-acct-out:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.side-acct-danger{margin-top:0;color:#fff;background:#c2453a;border-color:#c2453a}
.side-acct-danger:hover{filter:brightness(1.06);background:#c2453a;border-color:#c2453a}
.side-login .side-acct .login-done{margin-top:8px;width:100%;height:46px}

.art-body{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:0;background:var(--bg)}
/* Dark load background (no white flash on the dark theme) + a quick CSS-only
   fade-in when the iframe is inserted; light artifacts paint over it smoothly. */
.art-iframe{width:100%;height:100%;border:0;background:var(--bg);display:block;animation:art-fade .25s ease-out}
@keyframes art-fade{from{opacity:0}to{opacity:1}}
/* Markdown render in the panel — readable, generous spacing. */
.art-md{padding:24px 26px;font-size:16px;line-height:1.7;color:var(--text)}
.art-md h1,.art-md h2,.art-md h3,.art-md h4,.art-md h5,.art-md h6{line-height:1.3;margin:22px 0 10px;font-weight:700}
.art-md h1{font-size:24px}.art-md h2{font-size:21px}.art-md h3{font-size:18px}
.art-md h4,.art-md h5,.art-md h6{font-size:16px}
.art-md p{margin:0 0 14px}
.art-md ul,.art-md ol{margin:0 0 14px;padding-left:26px}
.art-md li{margin:5px 0}
.art-md a{color:#8FB4EC}
.art-md code{font-family:var(--mono);background:var(--panel2);padding:2px 6px;border-radius:6px;font-size:14px;color:var(--orange)}
.art-md-code{font-family:var(--mono);font-size:13.5px;background:#1a1916;border:1px solid var(--border);
  border-radius:10px;padding:14px 16px;margin:0 0 14px;overflow-x:auto;line-height:1.6;color:#cfe8b0;white-space:pre}
.art-md strong{font-weight:700}.art-md em{font-style:italic}
.art-md :first-child{margin-top:0}
/* Code / text render — monospace, preserved whitespace, readable. */
.art-lang{padding:14px 26px 0;font-family:var(--mono);font-size:12px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
.art-code,.art-text{margin:0;padding:20px 26px;font-family:var(--mono);font-size:14px;line-height:1.7;
  color:#cfe8b0;white-space:pre;overflow-x:auto}
.art-text{color:var(--text);white-space:pre-wrap;overflow-wrap:anywhere;font-family:var(--mono)}
body.art-open-lock{overflow:hidden}

/* ── Sub-agents ────────────────────────────────────────────────────────────
   The "Agents working" strip lives under the latest reply (its own element,
   never inside the re-rendered transcript). Each row is a big tappable target:
   live pulsing dot + what the agent is doing + a specialist pill + steps and
   ticking time. Finished agents collapse below, faint with a check, still
   tappable to review. Calm, premium, low-density — matches the panel language. */
/* Agent containers that are direct children of .rv-inner align to the same
 * column as the assistant bubbles: left-aligned, capped at the bubble width,
 * starting at .rv-inner's content edge (no extra side padding). */
.agent-anchor,.agents-bar{align-self:flex-start;width:100%;max-width:86%}
.agents-bar{padding:0;display:flex;flex-direction:column}
.agents-bar:not(:empty){padding:2px 0 30px}
.agents-head{display:flex;align-items:center;gap:9px;margin:0 2px 12px}
.agents-title{font-size:13px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--orange)}
.agents-count{font-size:12.5px;font-weight:700;color:var(--orange);background:var(--orange-soft);
  min-width:22px;height:22px;border-radius:11px;display:grid;place-items:center;padding:0 7px}
.agent-row{display:flex;align-items:center;gap:13px;min-height:60px;padding:13px 16px;margin:0 0 10px;
  background:var(--panel);border:1px solid var(--border2);border-radius:14px;
  transition:background .12s,border-color .12s,transform .08s;-webkit-user-select:none;user-select:none}
.agent-row[role="button"]{cursor:pointer}
.agent-row[role="button"]:hover{background:var(--panel2);border-color:var(--orange)}
.agent-row[role="button"]:active{transform:translateY(1px)}
.agent-row.locked{opacity:.7;cursor:default}
/* A RUNNING card is never dimmed, even when it has no detail view to open (e.g. a
   workflow row carries no agentId so it's "locked"). Dimming a live job made it
   read as stopped/gray next to a tappable agent — the running card must stay
   full-strength until there is positive evidence it ended. */
.agent-row.locked.active{opacity:1;cursor:default}
.agent-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:5px}
.agent-desc{font-size:16px;font-weight:700;color:var(--text);line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.agent-meta{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.agent-pill{font-size:12px;font-weight:700;color:var(--orange);background:var(--orange-soft);
  padding:3px 11px;border-radius:8px;letter-spacing:.02em}
.agent-steps,.agent-time{font-size:13px;font-weight:600;color:var(--muted)}
.agent-time{color:var(--faint)}
.agent-go{flex-shrink:0;font-size:13px;font-weight:700;color:var(--orange);
  background:var(--orange-soft);padding:8px 14px;border-radius:10px}
/* The live dot must clearly read as "alive" — a steady green pulse. */
.agent-dot{width:11px;height:11px;border-radius:50%;flex-shrink:0;background:var(--green);
  box-shadow:0 0 0 0 rgba(156,203,90,.5);animation:agentpulse 1.5s ease-out infinite}
@keyframes agentpulse{0%{box-shadow:0 0 0 0 rgba(156,203,90,.5)}70%{box-shadow:0 0 0 9px rgba(156,203,90,0)}100%{box-shadow:0 0 0 0 rgba(156,203,90,0)}}
.agent-check{width:22px;height:22px;border-radius:50%;flex-shrink:0;display:grid;place-items:center;
  font-size:13px;font-weight:700;color:var(--green);background:rgba(156,203,90,.16)}
.agent-row.finished{margin-bottom:8px}
/* Stopped (killed/cancelled/failed) — terminal but NOT success: gray, calm, with
   a square stop glyph instead of a green check. Never reads as "done". */
.agent-stop{width:22px;height:22px;border-radius:50%;flex-shrink:0;display:grid;place-items:center;
  font-size:10px;font-weight:700;color:var(--faint);background:var(--panel2);border:1px solid var(--border)}
.agent-row.stopped{margin-bottom:8px;opacity:.82}
.agent-row.stopped .agent-time{color:var(--faint)}
.agents-done{margin:2px 0 0}
.agents-done summary{list-style:none;cursor:pointer;font-size:13px;font-weight:700;color:var(--muted);
  padding:8px 2px;letter-spacing:.02em}
.agents-done summary::-webkit-details-marker{display:none}
.agents-done summary:hover{color:var(--text)}
.agents-done[open] summary{margin-bottom:8px}

/* Inline agent clusters. Each sits in an anchor slot right under the reply that
 * spawned it. An empty slot is fully collapsed so it adds no gap to the
 * transcript; a filled one reads as a calm group belonging to the reply above. */
.agent-anchor:empty{display:none}
.agents-group{display:flex;flex-direction:column;margin:-2px 0 2px;
  padding-left:14px;border-left:3px solid var(--border2)}
.agents-group.has-active{border-left-color:var(--orange)}
.agents-group .agents-head{margin:0 2px 10px}
.agents-group .agents-title{color:var(--muted)}
.agents-group.has-active .agents-title{color:var(--orange)}
.agents-group .agent-row:last-child{margin-bottom:0}

/* LIGHT workflow detail: header (name + status chip + count·time) then the
 * workers as agent-rows (reused), grouped under their plain phase title. */
.wf-detail{padding:18px 20px 24px}
.wf-detail-head{margin:0 2px 20px}
.wf-detail-title{font-size:20px;font-weight:800;color:var(--text);line-height:1.3;overflow-wrap:anywhere}
.wf-detail-sub{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-top:10px}
.wf-detail-meta{font-size:14px;font-weight:600;color:var(--muted)}
.wf-detail-desc{margin-top:11px;font-size:14.5px;line-height:1.55;color:var(--muted);overflow-wrap:anywhere}
.wf-detail .agents-group{margin-bottom:18px}
.wf-detail .agents-group:last-child{margin-bottom:0}

/* Agent work in the slide-over: a readable step list that streams live. */
.agent-steps-list{padding:20px 26px;display:flex;flex-direction:column;gap:16px}
.agent-step{display:flex;flex-direction:column;gap:8px;padding:14px 16px;
  background:var(--panel2);border:1px solid var(--border);border-radius:12px}
.agent-step-text{font-size:15.5px;line-height:1.6;color:var(--text);white-space:pre-wrap;overflow-wrap:anywhere}
.agent-step-text code{font-family:var(--mono);background:var(--bg2);padding:2px 6px;border-radius:6px;font-size:13.5px;color:var(--orange)}
.agent-step-tool{font-size:13.5px;font-weight:600;color:var(--muted);display:flex;align-items:center;gap:8px}
.agent-step-tool::before{content:"›";color:var(--orange);font-weight:700}
.agent-step-empty{color:var(--faint);text-align:center;padding:30px;font-size:15px}
.agent-working{display:flex;align-items:center;gap:9px;font-size:13.5px;font-weight:600;color:var(--muted);padding:4px 2px}

@media(max-width:760px){
  .art-panel{width:100vw;border-left:none}
  .art-head{flex-wrap:wrap;padding:14px 14px}
  .art-title{font-size:17px}
  .art-actions{width:100%;justify-content:flex-start}
  .art-md{padding:18px 16px}
  .art-code,.art-text{padding:16px}
  .art-lang{padding:14px 16px 0}
  /* Phone: job/agent cards == message-bubble width. Two parts, BOTH placed here
     (after the base rules at ~684/737) so they actually win over the desktop
     defaults:
       1) the container matches the bubble cap (94%, not the desktop 86%);
       2) the reply-group's left inset (14px padding + 3px border) is dropped so
          the card edges line up flush with the bubbles, not 17px narrower.
     The grouping bar is a desktop-only luxury. */
  .agent-anchor,.agents-bar{max-width:94%}
  .agents-group{padding-left:0;border-left:none}
}

/* Reduced motion: decorative animations end instantly at their final state and
   looping spinners/pulses freeze (iteration-count:1), while ESSENTIAL moves —
   sidebar slide, artifact panel, composer growth — still complete near-instantly
   (.01ms) so panels always appear/disappear correctly, never break. */
@media(prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important}
}

/* ── "What's new" panel (opened from the header version pill, js/version.js) ── */
.ver-overlay{position:fixed;inset:0;z-index:260;display:grid;place-items:center;
  background:rgba(0,0,0,.5);opacity:0;pointer-events:none;transition:opacity .18s ease;padding:18px}
.ver-overlay.show{opacity:1;pointer-events:auto}
.ver-sheet{width:100%;max-width:420px;max-height:80vh;max-height:80dvh;display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--border2);border-radius:16px;overflow:hidden;
  box-shadow:0 22px 60px rgba(0,0,0,.6);transform:translateY(10px) scale(.98);transition:transform .18s ease}
.ver-overlay.show .ver-sheet{transform:none}
.ver-sheet-head{flex-shrink:0;display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 18px;border-bottom:1px solid var(--border)}
.ver-sheet-title{font-size:17px;font-weight:700;color:var(--text)}
.ver-close{width:40px;height:40px;border-radius:11px;flex-shrink:0;display:grid;place-items:center;
  color:var(--muted);background:var(--panel2);border:1px solid var(--border);font-size:15px;transition:.12s}
.ver-close:hover{background:rgba(224,108,117,.16);color:#E06C75;border-color:#E06C75}
.ver-sheet-body{flex:1;min-height:0;overflow-y:auto;padding:6px 18px 18px}
.ver-entry{padding:16px 0;border-bottom:1px solid var(--border)}
.ver-entry:last-child{border-bottom:none}
.ver-entry-head{display:flex;align-items:baseline;gap:10px;margin-bottom:9px}
.ver-num{font-family:var(--mono);font-size:15px;font-weight:700;color:var(--orange)}
.ver-date{font-size:12.5px;color:var(--faint);font-family:var(--mono)}
.ver-notes{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:7px}
.ver-notes li{font-size:14.5px;line-height:1.5;color:var(--text)}
.ver-notes li::marker{color:var(--muted)}
.ver-empty{padding:24px 4px;color:var(--muted);font-size:14px;text-align:center}

/* ── close-confirm (busy chat closed via the sidebar X) — in-skin two-button sheet ── */
.confirm-overlay{z-index:300}
.confirm-sheet{max-width:360px;padding:20px}
.confirm-body{font-size:16px;line-height:1.45;color:var(--text);font-weight:600}
.confirm-actions{display:flex;gap:10px;margin-top:18px}
.confirm-actions button{flex:1;height:46px;border-radius:11px;font-size:14.5px;font-weight:700;
  font-family:inherit;cursor:pointer;transition:.12s}
.confirm-cancel{color:var(--text);background:var(--panel2);border:1px solid var(--border2)}
.confirm-cancel:hover{background:var(--border)}
.confirm-go{color:#fff;background:var(--orange);border:1px solid var(--orange)}
.confirm-go:hover{filter:brightness(1.06)}

/* ── PROFILE / ACCOUNT chip (top-right of sidebar header, beside version pill) + panel ─────
   Compact round avatar with a status dot on its corner. Name/email live in the panel only.
   Visible circle is 28px; an invisible pseudo grows the tap target to 44px. */
.profile-chip{position:relative;flex-shrink:0;margin-left:auto;display:grid;place-items:center;
  width:28px;height:28px;padding:0;border:none;background:transparent;color:var(--text);
  cursor:pointer;font-family:inherit;transition:filter .12s}
.profile-chip::before{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:44px;height:44px}
.profile-chip:hover{filter:brightness(1.08)}
.profile-chip[hidden]{display:none}
.pc-avatar{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  background:var(--orange-soft);color:var(--orange);font-weight:700;font-size:13px}
.pc-avatar.pc-avatar-empty{background:var(--panel2);color:var(--muted)}
.pc-avatar.pc-avatar-empty::after{content:"";width:13px;height:13px;border-radius:50%;
  box-shadow:0 0 0 2px var(--muted) inset;display:block}
.pc-dot{position:absolute;right:-1px;bottom:-1px;width:9px;height:9px;border-radius:50%;
  background:var(--faint);box-shadow:0 0 0 2px var(--bg2)}
.pc-dot-green{background:#3FB950}
.pc-dot-amber{background:var(--orange)}
.pc-dot-gray{background:#6B6B6B}

/* profile panel body (painted into the shared docked side-panel) */
.profile-panel{display:flex;flex-direction:column;align-items:stretch;gap:14px;padding:22px 18px;max-width:440px;margin:0 auto}
.pp-avatar{width:64px;height:64px;border-radius:50%;align-self:center;display:grid;place-items:center;
  background:var(--orange-soft);color:var(--orange);font-weight:700;font-size:26px}
.pp-avatar.pp-avatar-empty{background:var(--panel2)}
.pp-email{text-align:center;font-size:17px;font-weight:600;word-break:break-all}
.pp-sub{text-align:center;font-size:14px;color:var(--muted);margin-top:-8px}
.pp-line{text-align:center;font-size:15px;color:var(--text)}
.pp-title{text-align:center;font-size:18px;font-weight:700}
.pp-note{font-size:14px;color:var(--orange);background:var(--orange-soft);border-radius:12px;padding:11px 13px;text-align:center}
.pp-step{font-size:15px;font-weight:600}
.pp-help{font-size:13.5px;color:var(--muted);line-height:1.5}
.pp-err{font-size:13.5px;color:#E06C75}
.pp-btn{min-height:48px;border-radius:14px;font-size:16px;font-weight:600;font-family:inherit;cursor:pointer;border:1px solid transparent;padding:0 18px;transition:filter .12s,background .12s}
.pp-btn-primary{background:var(--orange);color:#fff}
.pp-btn-primary:hover{filter:brightness(1.08)}
.pp-btn-outline{background:transparent;color:var(--text);border-color:var(--border2)}
.pp-btn-outline:hover{background:var(--panel)}
.pp-btn-danger{background:#3a2420;color:#F2C0B4;border-color:#5a322a}
.pp-btn-danger:hover{filter:brightness(1.1)}
.pp-row{display:flex;gap:10px}.pp-row .pp-btn{flex:1}
.pp-code{min-height:50px;border-radius:14px;border:1px solid var(--border2);background:var(--panel);
  color:var(--text);font-family:var(--mono,monospace);font-size:17px;padding:0 14px;width:100%}
.pp-code:focus{outline:none;border-color:var(--orange)}

/* ============================================================================
 * DASHBOARD HOME (cockpit) — js/home.js. Matches the approved decision-queue
 * mockup: greeting + Dubai date, one decision at a time, running now, to-dos.
 * Lives over the panes inside #stage; shown via .show, hidden otherwise.
 * ==========================================================================*/
#home-view{position:absolute;inset:0;display:none;overflow-y:auto;overflow-x:hidden;background:#161513;z-index:3}
#home-view.show{display:block}
.home-wrap{max-width:560px;margin:0 auto;padding:22px 16px 40px}

/* Sidebar Home row (pinned at top of the chat list) */
/* Full-width for now; future buttons split this row into side-by-side circles. */
.home-item{width:100%;margin:0 0 8px;height:42px;display:flex;align-items:center;justify-content:center;gap:10px;
  background:var(--panel);border:1px solid var(--border);border-radius:10px;color:var(--text);
  font-family:inherit;font-size:14px;font-weight:600;padding:0 12px;cursor:pointer;transition:.14s}
.home-item:hover{border-color:var(--border2)}
.home-item.active{background:var(--panel2);border-color:var(--orange)}
.home-item-ico{width:20px;height:20px;flex:0 0 auto;color:var(--orange)}
.home-item-ico svg{width:100%;height:100%}

/* Greeting + date */
.home-greet{font-size:23px;font-weight:900;line-height:1.2}
.home-greet b{color:var(--orange)}
.home-date{font-size:12.5px;color:var(--faint);font-weight:600;margin-top:3px}
.home-tag{font-size:13px;color:var(--muted);margin:8px 0 20px;line-height:1.45}

/* Section header + count chip */
.home-sec{font-size:11px;font-weight:800;color:var(--faint);text-transform:uppercase;letter-spacing:.08em;
  margin:0 0 11px;display:flex;align-items:center;gap:8px}
.home-count{background:var(--orange-soft);color:var(--orange);font-size:11px;font-weight:800;padding:2px 9px;border-radius:999px}
.home-block{margin-top:26px}

/* Decision hero — one card at a time */
.home-hero{background:var(--panel);border:1px solid var(--orange);border-radius:18px;padding:18px;
  box-shadow:0 8px 30px rgba(0,0,0,.25);transition:opacity .3s,transform .3s}
.home-hero.go{opacity:0;transform:translateY(-10px)}
.home-pick{display:inline-flex;align-items:center;gap:6px;background:var(--orange-soft);color:var(--orange);
  font-size:11px;font-weight:800;padding:5px 11px;border-radius:999px;margin-bottom:11px}
.home-q{font-size:18px;font-weight:800;line-height:1.3;margin-bottom:4px}
.home-qd{font-size:13px;color:var(--muted);line-height:1.45;margin-bottom:16px}
.home-opts{display:flex;gap:9px;flex-wrap:wrap}
.home-opt{flex:1;min-width:120px;min-height:50px;border:1px solid var(--border2);background:var(--panel2);
  color:var(--text);font-family:inherit;font-size:15px;font-weight:700;border-radius:12px;cursor:pointer;transition:.15s}
.home-opt.primary{background:var(--orange);border-color:var(--orange);color:#1C1B19}
.home-opt:hover{filter:brightness(1.08)}
.home-opt:active{transform:scale(.97)}

/* Decided / empty states */
.home-done{background:var(--green-soft);border:1px solid var(--green);border-radius:18px;padding:22px 18px;text-align:center}
.home-done .hd-big{font-size:18px;font-weight:900;color:var(--green);margin-bottom:3px}
.home-done .hd-d{font-size:13px;color:var(--muted)}
.home-empty{background:var(--panel);border:1px dashed var(--border2);border-radius:18px;padding:26px 18px;text-align:center}
.home-empty .he-big{font-size:18px;font-weight:900;margin-bottom:5px}
.home-empty .he-d{font-size:13px;color:var(--muted);line-height:1.45}

/* Running-now rows */
.home-row{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:12px 13px;
  display:flex;align-items:center;gap:11px;margin-bottom:8px}
.home-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
.home-dot.run{background:var(--orange);box-shadow:0 0 0 4px var(--orange-soft);animation:pulse 1.6s infinite}
.home-rmain{min-width:0}
.home-rt{font-size:13.5px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.home-rd{font-size:12px;color:var(--faint);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.home-rmeta{margin-left:auto;font-size:11px;color:var(--faint);font-weight:700;flex:0 0 auto}
.home-run-empty{font-size:13px;color:var(--faint);padding:6px 2px}

/* To-do rows + add bar */
.home-todo{display:flex;align-items:center;gap:11px;padding:11px 13px;background:var(--panel);
  border:1px solid var(--border);border-radius:12px;margin-bottom:8px;transition:opacity .3s}
.home-todo.done{opacity:.35}
.home-todo.done .home-tt{text-decoration:line-through}
.home-chk{width:24px;height:24px;border-radius:7px;border:2px solid var(--border2);background:transparent;
  flex:0 0 auto;cursor:pointer;transition:.14s;position:relative}
.home-chk:hover{border-color:var(--green)}
.home-todo.done .home-chk{background:var(--green);border-color:var(--green)}
.home-todo.done .home-chk::after{content:"✓";position:absolute;inset:0;display:grid;place-items:center;color:#1C1B19;font-size:14px;font-weight:900}
.home-tt{font-size:13.5px;font-weight:600;line-height:1.35;flex:1;min-width:0}
.home-prio{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;padding:2px 7px;
  border-radius:999px;flex:0 0 auto;background:var(--panel2);color:var(--muted)}
.home-prio.crit{background:rgba(248,113,113,.16);color:#f87171}
.home-prio.high{background:var(--orange-soft);color:var(--orange)}
.home-add{display:flex;gap:8px;margin-top:4px}
.home-add input{flex:1;min-width:0;height:48px;background:var(--panel);border:1px solid var(--border);
  border-radius:12px;color:var(--text);padding:0 14px;font-family:inherit;font-size:15px;outline:none}
.home-add input::placeholder{color:var(--faint)}
.home-add input:focus{border-color:var(--orange)}
.home-add-btn{width:48px;height:48px;flex:0 0 auto;border-radius:12px;background:var(--orange);color:#1C1B19;
  border:0;font-size:26px;font-weight:700;line-height:1;cursor:pointer;transition:.14s}
.home-add-btn:hover{filter:brightness(1.08)}
.home-add-btn:active{transform:scale(.95)}

/* Per-assistant-bubble speaker (tap to hear / replay) — matches .msg-copy */
.msg-speak{position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;min-width:30px;border-radius:8px;cursor:pointer;
  color:var(--muted);background:var(--panel);border:1px solid var(--border);
  padding:0;transition:.12s}
.msg-speak svg{width:17px;height:17px}
.msg-speak:hover{background:var(--orange);color:#fff;border-color:var(--orange)}
.msg-speak:active{transform:translateY(1px)}
/* On a touch screen the bubble button is comfortably tappable (≥44px hit area) */
@media (pointer:coarse){.msg-speak{width:34px;height:34px;min-width:34px}.msg-speak svg{width:18px;height:18px}
  .msg-speak::after{content:"";position:absolute;inset:-5px}}
