/* Console - dark, Claude-Code/desktop-app feel. System font, calm accent, hairline dividers.
   No em dashes anywhere in copy. Mobile-first: sidebar becomes a drawer under 800px. */
:root {
  --bg: #0b0b0c; --panel: #141416; --panel2: #1c1c1f; --line: #2a2a2e;
  --text: #ececf0; --muted: #8a8a93; --accent: #4c8dff;
  --accent-dim: #28324a; --user: #2a3a5c; --danger: #ff5c5c; --good: #4ad07a;
  --radius: 14px; --side-w: 280px;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* thin, dark scrollbars everywhere: the stock white bar glares on the dark theme */
* { scrollbar-width: thin; scrollbar-color: #3a3a40 transparent; }
*::-webkit-scrollbar { width: 7px; height: 7px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: #2f2f34; border-radius: 8px; }
*::-webkit-scrollbar-thumb:hover { background: #45454c; }
*::-webkit-scrollbar-corner { background: transparent; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg); color: var(--text); overflow: hidden;
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
}

/* ---- login ---- */
.login-body { display: flex; align-items: center; justify-content: center; height: 100vh; overflow: auto; }
.login-wrap { width: 100%; max-width: 360px; padding: 24px; }
.login-card { background: var(--panel); border: 0.5px solid var(--line); border-radius: 20px; padding: 28px; text-align: center; }
.brand, .logo { font-weight: 700; letter-spacing: -0.02em; }
.brand { font-size: 26px; margin-bottom: 6px; }
.muted { color: var(--muted); }
.err { color: var(--danger); font-size: 13px; }
.login-card form { display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }
.login-card input { padding: 13px 14px; border-radius: 12px; border: 0.5px solid var(--line); background: var(--panel2); color: var(--text); font-size: 16px; }
.login-card button { padding: 13px; border: none; border-radius: 12px; background: var(--accent); color: #fff; font-size: 16px; font-weight: 600; }
.pk-btn { width: 100%; margin-top: 18px; padding: 13px; border: 0.5px solid var(--accent); border-radius: 12px; background: var(--accent-dim); color: var(--accent); font-size: 16px; font-weight: 600; cursor: pointer; }
.pk-btn:disabled { opacity: 0.5; }
.pk-or { color: var(--muted); font-size: 12px; margin: 10px 0 0; }
/* the enroll button inside Console (sidebar); only shown in a secure context */
.pk-setup { margin: 6px 8px 2px; padding: 8px 12px; border: 0.5px solid var(--line); border-radius: 9px; background: var(--panel2); color: var(--muted); font-size: 12.5px; font-weight: 600; cursor: pointer; text-align: left; }
.pk-setup:hover { color: var(--text); }
.pk-setup.done { color: var(--good); border-color: var(--accent-dim); }

/* ---- layout ---- */
/* Height tracks the VISUAL viewport (set by JS from visualViewport.height) so the composer sits
   flush above the iOS keyboard with no dead band; falls back to 100dvh where the var is unset. */
.layout { display: flex; height: 100vh; height: 100dvh; height: var(--app-h, 100dvh); }
.sidebar {
  width: var(--side-w); flex: 0 0 var(--side-w); background: var(--panel); border-right: 0.5px solid var(--line);
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
}
.side-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; padding: 14px 16px calc(14px + env(safe-area-inset-top)) 16px; padding-top: max(14px, env(safe-area-inset-top)); border-bottom: 0.5px solid var(--line); }
.side-head .logo { font-size: 17px; }
.new-btn { background: var(--accent); color: #fff; border: none; border-radius: 9px; padding: 7px 14px; font-size: 14px; font-weight: 600; }
.session-list { flex: 1; min-height: 0; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 2px; }
.session-row { border-radius: 10px; display: flex; align-items: center; gap: 2px; }
.session-row:hover { background: var(--panel2); }
.session-row.active { background: var(--accent-dim); }
.srow-main { flex: 1; min-width: 0; text-align: left; background: transparent; border: none; color: var(--text); padding: 10px 6px 10px 12px; display: flex; flex-direction: column; gap: 4px; cursor: pointer; }
.srow-pin, .srow-edit { background: none; border: none; color: var(--muted); font-size: 15px; padding: 8px 7px; cursor: pointer; opacity: 0.55; }
.srow-pin:hover, .srow-edit:hover { opacity: 1; }
.srow-edit { font-size: 13px; }
.session-row.pinned .srow-pin { color: var(--accent); opacity: 1; }
#chat-title { cursor: pointer; }

/* attachments: staged strip, composer button, in-bubble previews, clickable file links */
.attach-strip { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 14px 0; max-height: 34vh; overflow-y: auto; }
.attach-staged { display: flex; align-items: center; gap: 6px; background: var(--panel2); border: 0.5px solid var(--line); border-radius: 8px; padding: 5px 8px; font-size: 12.5px; max-width: 220px; }
.attach-staged .as-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-staged .as-thumb { width: 34px; height: 34px; object-fit: cover; border-radius: 6px; border: 0.5px solid var(--line); flex: 0 0 auto; }
/* while the bytes are going up, the strip is visibly busy and its remove buttons are inert */
.attach-strip.busy .attach-staged { opacity: 0.55; }
.attach-strip.busy .attach-x { pointer-events: none; visibility: hidden; }
.attach-progress { flex: 1 0 100%; display: flex; align-items: center; gap: 9px; padding: 3px 1px 1px; color: var(--muted); font-size: 11.5px; }
.attach-progress-track { flex: 1; height: 3px; overflow: hidden; border-radius: 3px; background: var(--line); }
.attach-progress-fill { display: block; height: 100%; border-radius: inherit; background: var(--accent); transition: width 0.12s linear; }
.attach-progress-label { min-width: 112px; text-align: right; }
.attach-x { background: none; border: none; color: var(--muted); font-size: 16px; line-height: 1; padding: 0 2px; cursor: pointer; }
/* a send that failed says so above the composer, next to the still-staged photo */
.composer-note { padding: 8px 14px 0; font-size: 12.5px; color: var(--muted); }
.composer-note.err { color: var(--danger); }
.send-btn.busy, .send-btn:disabled { opacity: 0.5; }
.attach-btn { background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 12px; width: 40px; height: 40px; font-size: 22px; line-height: 1; flex: 0 0 auto; cursor: pointer; }
.attach-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; justify-content: flex-end; max-width: 100%; }
.attach-thumb { display: block; width: 96px; height: 96px; padding: 0; border: 0; border-radius: 10px; background: var(--panel2); cursor: zoom-in; overflow: hidden; }
.attach-thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; border: 0.5px solid var(--line); display: block; background: var(--panel2); }
.image-viewer-open { overflow: hidden; }
.image-viewer { position: fixed; inset: 0; z-index: 100; display: flex; flex-direction: column; background: rgba(0,0,0,0.96); color: #fff; }
.image-viewer-bar { flex: 0 0 auto; min-height: 54px; display: flex; align-items: center; gap: 12px; padding: max(10px, env(safe-area-inset-top)) 14px 10px; background: rgba(20,20,22,0.94); }
.image-viewer-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.image-viewer-status { color: var(--muted); font-size: 11px; white-space: nowrap; }
.image-viewer-original, .image-viewer-close { min-height: 36px; display: inline-flex; align-items: center; color: #fff; background: var(--panel2); border: 0.5px solid var(--line); border-radius: 9px; padding: 0 11px; font-size: 12px; text-decoration: none; }
.image-viewer-close { font-family: inherit; cursor: pointer; }
.image-viewer-stage { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: auto; padding: 14px 14px max(14px, env(safe-area-inset-bottom)); -webkit-overflow-scrolling: touch; }
.image-viewer-stage img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; touch-action: pinch-zoom; }
.attach-file { display: inline-block; background: var(--panel2); border: 0.5px solid var(--line); border-radius: 8px; padding: 6px 10px; font-size: 12.5px; color: var(--accent); text-decoration: none; }
.path-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; word-break: break-all; overflow-wrap: anywhere; }
.srow-title { font-size: 14px; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srow-meta { display: flex; gap: 6px; }
.chip { font-size: 11px; color: var(--accent); background: rgba(76,141,255,0.12); padding: 1px 8px; border-radius: 20px; }
.chip.subtle { color: var(--muted); background: var(--panel2); }

/* tier badge: prod renders no badge at all (template gate), staging amber, dev green, anything
   else (e.g. e2e) gray. Tiny on purpose so it never crowds the mobile topbar. */
.env-badge { display: inline-block; flex: 0 0 auto; margin-left: 7px; padding: 2px 7px;
  border-radius: 20px; font-size: 10px; font-weight: 600; line-height: 1.3;
  letter-spacing: 0.05em; text-transform: uppercase; vertical-align: 2px;
  color: var(--muted); background: var(--panel2); }
.env-badge.env-dev { color: var(--good); background: rgba(74,208,122,0.14); }
.env-badge.env-staging { color: #ffb454; background: rgba(255,180,84,0.14); }
.brand .env-badge { vertical-align: 6px; }
.topbar-title .env-badge { margin-left: 0; }  /* the flex gap already spaces it */

/* ---- main / chat ---- */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; position: relative; }
.topbar { display: flex; align-items: center; gap: 10px; padding: 10px 14px; padding-top: max(10px, env(safe-area-inset-top)); border-bottom: 0.5px solid var(--line); background: rgba(11,11,12,0.8); backdrop-filter: blur(12px); }
.icon-btn { display: none; background: none; border: none; color: var(--text); font-size: 20px; padding: 4px 8px; }
.topbar-title { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; }
#chat-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.model-pick { display: flex; gap: 6px; }
.model-pick select { background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 8px; padding: 5px 8px; font-size: 13px; }

/* Vertical scroll only. overflow-x:hidden clips any horizontal spill (a wide table, an unbreakable
   path) INSIDE the scroller so it can never widen the layout or drift the page sideways on mobile.
   min-width:0 lets this flex child actually shrink to the column instead of growing to its content. */
.thread { flex: 1; min-width: 0; overflow-y: auto; overflow-x: hidden; padding: 20px 16px 8px; display: flex; flex-direction: column; gap: 14px; }
/* A transcript scrolls, it never vertically compresses. Every thread child keeps its natural height.
   Without this, once the transcript overflows the viewport, flexbox shrinks the shrinkable children
   to fit; a tool card (overflow:hidden -> automatic min-height 0) collapses toward zero and its header
   clips into a sliver (a running card becomes a thin bar, an errored card a red rule). flex-shrink:0
   makes every card render at full height and simply scroll. */
.thread > * { flex-shrink: 0; }
/* scroll-up history paging: the thread's first child; quiet until it becomes "Beginning of session" */
.history-sentinel { align-self: center; color: var(--muted); font-size: 12px; font-style: italic; padding: 6px 0 2px; opacity: 0.8; }
.history-sentinel.done { opacity: 0.5; }
.empty-state { margin: auto; text-align: center; padding: 40px 20px; }
.empty-state h2 { font-weight: 600; letter-spacing: -0.02em; }

.msg { max-width: min(760px, 100%); width: 100%; min-width: 0; align-self: center; }
.msg .bubble { padding: 12px 14px; border-radius: var(--radius); white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }
.msg.user { align-self: flex-end; max-width: 86%; }
.msg.user .bubble { background: var(--user); border-bottom-right-radius: 5px; }
.msg.assistant .bubble { background: var(--panel); border: 0.5px solid var(--line); }
.msg.assistant .bubble.streaming::after { content: "\2588"; opacity: 0.5; animation: blink 1s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* expandable tool card (collapsed by default, like Claude Code) */
.toolcard { align-self: center; max-width: min(760px, 100%); width: 100%; min-width: 0; background: var(--panel); border: 0.5px solid var(--line); border-radius: 10px; overflow: hidden; }
.toolcard-head { width: 100%; text-align: left; background: transparent; border: none; color: var(--text); display: flex; align-items: center; gap: 8px; padding: 9px 12px; font-size: 13px; cursor: pointer; }
.toolcard-head .chev { color: var(--muted); transition: transform 0.15s; display: inline-block; }
.toolcard.open .toolcard-head .chev { transform: rotate(90deg); }
.toolcard-head .tname { color: var(--accent); font-weight: 600; }
.toolcard-head .targ { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; flex: 1; min-width: 0; }
.toolcard-head .tspin { color: var(--muted); font-size: 11px; opacity: 0.7; }
.toolcard-body { display: none; padding: 0 12px 12px; }
.toolcard.open .toolcard-body { display: block; }
.toolcard pre { margin: 8px 0 0; padding: 10px; background: var(--bg); border: 0.5px solid var(--line); border-radius: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; max-height: 360px; overflow: auto; }
/* Pretty per-tool input: real newlines + code styling, no raw escaped JSON. Code blocks keep hard
   newlines and scroll (both axes) inside the card so long lines never drag the column sideways. */
.toolcard pre.tool-code { color: var(--text); white-space: pre; word-break: normal; -webkit-overflow-scrolling: touch; }
.toolcard .tool-input { min-width: 0; }
.toolcard .tool-sub { margin: 8px 0 0; font-size: 12px; color: var(--muted); word-break: break-word; }
.toolcard .tool-sub.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.toolcard .tool-sub .path-link { color: var(--accent); text-decoration: none; }
.toolcard .tool-block { margin-top: 8px; }
.toolcard .tlabel { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 2px; }
.toolcard .tool-block pre.tool-code { margin-top: 0; }
.toolcard .tool-kv { display: flex; gap: 8px; margin-top: 6px; font-size: 12px; min-width: 0; }
.toolcard .tool-kv .tk { color: var(--accent); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; flex: none; }
.toolcard .tool-kv .tv { color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-word; min-width: 0; }
.toolcard pre.tool-json .tk { color: var(--accent); }
.toolcard .tool-raw-toggle { margin-top: 8px; background: transparent; border: 0.5px solid var(--line); border-radius: 6px; color: var(--muted); font-size: 11px; padding: 3px 8px; cursor: pointer; }
.toolcard .tool-raw-toggle:hover { color: var(--text); }
.toolcard.tool-error { border-color: var(--danger); }
.toolcard.tool-error pre.tool-result { color: var(--danger); }

/* collapsible thinking block: a finalized "Thought for Ns" affordance left inline in the transcript.
   The CLI redacts the reasoning text, so the body is an honest note, not an empty box. */
.thinking { align-self: center; max-width: min(760px, 100%); width: 100%; min-width: 0; border-left: 2px solid var(--line); }
.thinking-head { background: transparent; border: none; color: var(--muted); display: flex; align-items: center; gap: 6px; padding: 3px 0 3px 10px; font-size: 13px; font-style: italic; cursor: pointer; }
.thinking-head .chev { transition: transform 0.15s; display: inline-block; }
.thinking.open .thinking-head .chev { transform: rotate(90deg); }
.thinking-body { display: none; padding: 4px 0 4px 12px; font-size: 13px; color: var(--muted); font-style: italic; white-space: pre-wrap; overflow-wrap: anywhere; }
.thinking-body.think-note { white-space: normal; opacity: 0.8; }
.thinking.open .thinking-body { display: block; }

/* Detailed live activity, pinned visually last in the thread. The first line names the current
   phase, the second carries the real tool argument or latest explicit agent update, and the final
   line keeps elapsed time + event counts visible across long turns. */
.working { align-self: center; max-width: min(760px, 100%); width: 100%; min-width: 0; order: 8; display: flex; align-items: flex-start; gap: 9px; padding: 5px 0 7px 2px; color: var(--muted); font-size: 13px; }
.working .work-copy { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 3px; }
.working .work-label { color: var(--text); font-weight: 600; }
.working .work-detail { color: var(--muted); line-height: 1.38; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 9.7em; overflow-y: auto; scrollbar-width: thin; }
.working .work-meta { color: var(--muted); font-size: 11px; opacity: 0.82; }
/* While a tool is running the whole status line is a tap target that jumps to the running card. */
.working.tappable { cursor: pointer; }
.working.tappable .work-label { color: var(--accent); }
.working.tappable:hover .work-label { text-decoration: underline; text-underline-offset: 2px; }
.working.thinking .work-label {
  background: linear-gradient(90deg, var(--muted) 30%, var(--text) 50%, var(--muted) 70%);
  background-size: 200% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: work-shimmer 1.6s linear infinite;
}
@keyframes work-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.work-dots { display: inline-flex; gap: 4px; flex: 0 0 auto; padding-top: 5px; }
.work-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); opacity: 0.35; animation: work-pulse 1.2s ease-in-out infinite; }
.work-dots i:nth-child(2) { animation-delay: 0.2s; }
.work-dots i:nth-child(3) { animation-delay: 0.4s; }
@keyframes work-pulse { 0%, 100% { opacity: 0.25; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-2px); } }

.status-line { align-self: center; max-width: min(760px, 100%); width: 100%; min-width: 0; font-size: 12px; color: var(--muted); text-align: center; }

/* Queued inputs are normal user messages at the bottom of the transcript, not a second card tray. */
.msg.user.queued { order: 9; opacity: 0.78; }
.msg.user.queued .bubble { border: 1px dashed rgba(76,141,255,0.55); }
.msg.user.queued.errored .bubble { border-color: var(--danger); }
.msg.user.queued.plumbing { opacity: 0.52; }
.queued-footer { display: flex; justify-content: flex-end; align-items: center; gap: 9px; padding: 5px 5px 0 0; font-size: 11.5px; color: var(--muted); }
.queued-status { margin-right: 2px; }
.queued-status::before { content: "\23F3"; margin-right: 5px; font-size: 10px; }
.msg.user.queued.errored .queued-status { color: var(--danger); }
.queued-action { background: transparent; border: none; padding: 1px 0; color: var(--muted); font: inherit; cursor: pointer; }
.queued-action:hover { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.queued-remove:hover { color: var(--danger); }

/* ---- composer ---- */
.composer { position: relative; display: flex; gap: 8px; align-items: flex-end; padding: 12px 14px calc(12px + env(safe-area-inset-bottom)); border-top: 0.5px solid var(--line); background: var(--panel); }

/* Live Wall keeps the real composer and all of its behavior, but scales only that row to 80%.
   The wider layout box compensates for the transform so the visual result still spans the pane;
   a negative top margin removes the space the unscaled box would otherwise reserve. */
body.wall-embed .composer { width: 125%; margin-top: -14px; transform: scale(.8); transform-origin: left bottom; }
body.wall-embed .jump-latest { bottom: 64px; }
body.wall-embed .thread { padding: 10px 12px 5px; gap: 10px; }

/* skill picker: a dropdown anchored above the composer, opened by a leading `/` */
.skill-menu { position: absolute; left: 14px; right: 14px; bottom: calc(100% + 6px); max-height: 320px; overflow-y: auto; background: var(--panel2); border: 0.5px solid var(--line); border-radius: 12px; box-shadow: 0 -6px 24px rgba(0,0,0,0.45); z-index: 30; padding: 4px; -webkit-overflow-scrolling: touch; }
.skill-item { display: flex; flex-direction: column; gap: 2px; padding: 8px 11px; border-radius: 8px; cursor: pointer; }
.skill-item.active, .skill-item:hover { background: var(--accent-dim); }
.skill-name { font-size: 14px; font-weight: 600; color: var(--accent); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.skill-desc { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Auto-growing textarea: min one full line (never clips the placeholder or typed text), grows to
   ~6 lines then scrolls. JS (autoGrow) sets the exact height; min/max-height are the guard rails.
   min-width:0 lets it actually shrink/grow inside the flex row instead of overflowing. */
.composer textarea { flex: 1; min-width: 0; resize: none; min-height: 46px; max-height: 160px; overflow-y: auto; background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 14px; padding: 11px 14px; font-size: 16px; font-family: inherit; line-height: 1.4; }
.composer textarea:focus { outline: none; border-color: var(--accent); }
.send-btn { flex: 0 0 auto; background: var(--accent); color: #fff; border: none; border-radius: 12px; padding: 11px 18px; font-size: 15px; font-weight: 600; }
.send-btn:disabled { opacity: 0.4; }
/* floating quote affordance over a transcript selection */
.quote-btn { position: fixed; z-index: 60; background: var(--panel2); color: var(--fg);
  border: 0.5px solid var(--line); border-radius: 8px; padding: 5px 12px; font-size: 13px;
  font-weight: 600; cursor: pointer; box-shadow: 0 4px 16px rgba(0,0,0,0.45); }
.quote-btn:hover { border-color: var(--accent); color: var(--accent); }
/* new-messages pill: shown when content lands below while Sam reads up; never auto-scroll him */
.jump-latest { position: absolute; bottom: 86px; left: 50%; transform: translateX(-50%); z-index: 25;
  background: var(--accent); color: #fff; border: none; border-radius: 20px; padding: 7px 15px;
  font-size: 13px; font-weight: 600; cursor: pointer; box-shadow: 0 4px 16px rgba(0,0,0,0.45); }
.stop-btn { flex: 0 0 auto; background: var(--panel2); color: var(--danger); border: 0.5px solid var(--line); border-radius: 12px; padding: 11px 16px; font-size: 15px; font-weight: 600; }

/* project-pick prompt (ambiguous routing) */
.routepick { align-self: center; max-width: min(760px, 100%); width: 100%; min-width: 0; background: var(--panel); border: 0.5px solid var(--line); border-radius: var(--radius); padding: 14px; }
.routepick p { margin: 0 0 10px; }
.routepick .rp-reply { display: flex; gap: 8px; margin-bottom: 10px; }
.routepick .rp-input { flex: 1; background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 9px; padding: 9px 12px; font-size: 15px; }
.routepick .rp-input:focus { outline: none; border-color: var(--accent); }
.routepick .rp-reply button { background: var(--accent); color: #fff; border: none; border-radius: 9px; padding: 9px 16px; font-weight: 600; }
.routepick .opts { display: flex; flex-wrap: wrap; gap: 8px; }
.routepick .opts button { background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 9px; padding: 7px 12px; font-size: 13px; }

.scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 20; }

/* ---- mobile drawer ---- */
@media (max-width: 800px) {
  .icon-btn { display: block; }
  .sidebar { position: fixed; z-index: 30; left: 0; top: 0; bottom: 0; transform: translateX(-100%); transition: transform 0.22s ease; box-shadow: 2px 0 24px rgba(0,0,0,0.5); }
  .sidebar.open { transform: translateX(0); }
  .msg { max-width: 760px; }
  .msg.user { max-width: 90%; }
  .msg.user.has-attachments { max-width: 100%; }
  .image-viewer-bar { gap: 7px; }
  .image-viewer-status { display: none; }
  .image-viewer-original, .image-viewer-close { min-height: 44px; padding: 0 10px; }

  /* Composer: give the textarea the width, compact 44px tap targets, tighter safe-area padding
     (no dead band). Stop is hidden by JS unless a turn is running, so idle = just [+] input [Send]. */
  .composer { gap: 6px; align-items: flex-end; padding: 8px 10px calc(8px + env(safe-area-inset-bottom)); }
  body.wall-embed .composer { margin-top: -12px; }
  .attach-btn { width: 44px; height: 44px; min-width: 44px; font-size: 24px; }
  .composer textarea { min-height: 44px; padding: 10px 13px; }
  .send-btn { min-width: 44px; height: 44px; padding: 0 15px; }
  .stop-btn { min-width: 44px; height: 44px; padding: 0 13px; }
  /* Tap targets for the tool affordances: the card header and the tappable status line are >=44px. */
  .toolcard-head { min-height: 44px; }
  .working.tappable { min-height: 44px; padding-top: 6px; padding-bottom: 6px; }
  .toolcard .tool-raw-toggle { min-height: 44px; padding: 3px 14px; }
}

/* ---- command center: one screen, all sessions ---- */
.side-actions { flex: 1 0 100%; min-width: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(48px, 1fr)); gap: 6px; }
.side-actions > * { min-width: 0; justify-content: center; padding-left: 6px; padding-right: 6px; }
.center-btn { display: inline-flex; align-items: center; background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 9px; padding: 7px 12px; font-size: 13px; font-weight: 600; text-decoration: none; cursor: pointer; }
body.center-mode .center-btn { background: var(--accent-dim); color: var(--accent); border-color: var(--accent-dim); }

.center { flex: 1; min-width: 0; min-height: 0; display: none; flex-direction: column; }
body.center-mode .center { display: flex; }
body.center-mode .main { display: none; }
.center-title { font-weight: 600; }
.center-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 14px 16px calc(20px + env(safe-area-inset-bottom)); }

/* ---- The Stream: one narrated feed, bottom-anchored; grid is a toggle away ---- */
.view-toggle { display: flex; gap: 2px; background: var(--panel2); border-radius: 9px; padding: 2px; margin-right: 8px; }
.vt-btn { background: transparent; border: none; color: var(--muted); padding: 5px 12px; border-radius: 7px; font-size: 12.5px; font-weight: 600; cursor: pointer; }
.vt-btn.active { background: var(--accent-dim); color: var(--accent); }
.center .center-scroll { display: none; }
.center.grid-mode .center-scroll { display: block; }
.stream-view { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; }
.stream-jump { position: absolute; bottom: 14px; }

/* older beats are dots joined by a connector line; the head (newest) expands to show its text */
.stream-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 14px 16px 10px; }
.stream-scroll:has(.stream-list.lanes) { overflow-x: auto; padding-top: 0; }   /* columns scroll sideways; the sticky column heads carry the top padding */
.stream-list { max-width: 940px; margin: 0 auto; display: flex; flex-direction: column; gap: 13px; }
.stream-list:empty::after { content: "Quiet so far. Beats appear here as your sessions work."; color: var(--muted); font-size: 17px; font-style: italic; }
/* left rail = the session's stable color (set inline in beatNode), so one thread is trackable
   down the interleaved stream. Narration (the woven voice) has no single session, so no rail. */
.beat { display: flex; gap: 12px; align-items: baseline; font-size: 18px; line-height: 1.6; cursor: pointer; border-radius: 8px; padding: 4px 7px 4px 11px; border-left: 3px solid transparent; }
.beat:hover { background: var(--panel); }
.beat.b-narration { border-left-color: transparent !important; }
.beat-time { color: var(--muted); font-size: 13px; flex: 0 0 46px; font-variant-numeric: tabular-nums; }
.beat .chip { flex: 0 0 auto; max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.beat-text { min-width: 0; overflow-wrap: anywhere; }
.beat.b-you .beat-text { color: #b9cdf3; }
.beat.b-gist .beat-text { color: var(--muted); font-style: italic; }
.beat.b-question .beat-text { color: #ffb454; }
.beat.b-blocked .beat-text, .beat.b-error .beat-text { color: var(--danger); }
.beat.b-done .beat-text { color: var(--good); }
.beat.b-waiting .beat-text { color: #8ca3c7; }
.beat.b-watcher .beat-text { color: #ffb454; font-weight: 600; }
.beat.b-session .beat-text { color: var(--text); }

/* v2 narrator: the narration line is the voice; raw beats are the dim backbone beneath it. In
   Narrated view raw beats recede (small, muted) and narration stands out; Raw view shows only
   raw beats at full weight and hides narration. */
.beat.b-narration { font-size: 20px; line-height: 1.62; padding: 8px 8px; }
.beat.b-narration .beat-time { color: var(--accent); opacity: 0.8; }
.beat.b-narration .chip { display: none; }
.beat.b-narration .beat-text { color: var(--text); }
.center.narrated-mode .beat:not(.b-narration) { font-size: 13.5px; opacity: 0.5; padding: 0 7px; }
.center.narrated-mode .beat:not(.b-narration) .beat-text { color: var(--muted); }
.center.raw-mode .beat.b-narration { display: none; }

/* the waiting shelf: unanswered questions never scroll away */
.stream-shelf { border-top: 0.5px solid var(--line); background: var(--panel); padding: 8px 16px calc(10px + env(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: 8px; max-height: 42vh; overflow-y: auto; }
.shelf-item { display: flex; flex-direction: column; gap: 6px; background: var(--panel2); border-left: 3px solid #ffb454; border-radius: 10px; padding: 8px 11px; cursor: pointer; }
.shelf-item.k-blocked, .shelf-item.k-error { border-left-color: var(--danger); }
.shelf-head { display: flex; gap: 8px; align-items: center; font-size: 12.5px; }
.shelf-sum { font-size: 13px; color: var(--text); line-height: 1.45; }

.zone-head { font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); margin: 14px 2px 8px; display: flex; align-items: center; gap: 8px; }
.zone-head:first-child { margin-top: 2px; }
.zcount { background: var(--panel2); border-radius: 20px; padding: 0 8px; font-size: 11px; }
.zone { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 10px; }
.zone:empty::after { content: attr(data-empty); color: var(--muted); font-size: 13px; font-style: italic; padding: 2px 2px 6px; }

/* session card. Left accent = state: amber a question, red blocked/error, green done, blue working. */
.ccard { background: var(--panel); border: 0.5px solid var(--line); border-left: 3px solid var(--line); border-radius: 12px; padding: 11px 13px; display: flex; flex-direction: column; gap: 7px; cursor: pointer; min-width: 0; }
.ccard:hover { background: var(--panel2); }
.ccard.st-needs_you { border-left-color: #ffb454; }
.ccard.st-needs_you.k-blocked, .ccard.st-error { border-left-color: var(--danger); }
.ccard.st-done { border-left-color: var(--good); }
.ccard.st-working { border-left-color: var(--accent); }
.ccard.st-waiting { border-left-color: #6b7d99; }
/* header row doubles as the drag handle for Sam's manual ordering */
.ccard-head { display: flex; align-items: center; gap: 8px; min-width: 0; cursor: grab; }
.ccard.dragging { opacity: 0.45; }
body.center-mode .ccard-head:active { cursor: grabbing; }
.ccard-title { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.ccard-state { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; flex: 0 0 auto; }
.ccard.st-needs_you .ccard-state { color: #ffb454; }
.ccard.st-needs_you.k-blocked .ccard-state, .ccard.st-error .ccard-state { color: var(--danger); }
.ccard.st-done .ccard-state { color: var(--good); }
.ccard.st-working .ccard-state { color: var(--accent); }
.ccard.st-idle .ccard-state { color: var(--muted); }
.ccard.st-waiting .ccard-state { color: #8ca3c7; }
/* the session's actual last message: the thing Sam reads to answer without opening the session */
.ccard-last { font-size: 13px; line-height: 1.45; color: var(--text); background: var(--bg); border: 0.5px solid var(--line); border-radius: 9px; padding: 9px 11px; white-space: pre-wrap; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
/* summaries wrap to a few real lines (Sam: a few truncated words is not enough to steer from) */
.ccard-sum { font-size: 12.5px; color: var(--muted); line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.ccard.st-working .ccard-sum { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; -webkit-line-clamp: 2; }
.ccard-meta { font-size: 11.5px; color: var(--muted); display: flex; gap: 10px; align-items: center; }
.ccard-reply { display: flex; gap: 6px; align-items: flex-end; }
.ccard-reply textarea { flex: 1; min-width: 0; resize: none; min-height: 38px; max-height: 120px; background: var(--panel2); color: var(--text); border: 0.5px solid var(--line); border-radius: 10px; padding: 8px 11px; font-size: 14px; font-family: inherit; line-height: 1.4; }
.ccard-reply textarea:focus { outline: none; border-color: var(--accent); }
.ccard-reply button { flex: 0 0 auto; background: var(--accent); color: #fff; border: none; border-radius: 10px; padding: 9px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
.ccard-reply .btn-dismiss { background: var(--panel2); color: var(--muted); border: 0.5px solid var(--line); }
.ccard-reply .btn-dismiss:hover { color: var(--fg); border-color: var(--muted); }
/* the display rules above would beat the [hidden] attribute in the cascade; keep hidden meaning hidden */
.ccard [hidden] { display: none !important; }

/* center-mode sidebar: hidden by default (Sam: it steals the one screen), slides over on demand
   via the center header's hamburger, at EVERY width (the mobile drawer pattern promoted). */
/* z-index 46 (+ scrim 45) so the drawer sits ABOVE the docked peek pane (z-index 40). Without this,
   tapping the docked pane's hamburger opened the session list BEHIND the pane: invisible and
   unclickable, so switching sessions from inside a docked chat was a dead end (Sam: "stuck, can't
   switch sessions in command center"). Now the drawer is a real in-session session switcher. */
body.center-mode .sidebar { position: fixed; z-index: 46; left: 0; top: 0; bottom: 0; transform: translateX(-100%); transition: transform 0.22s ease; box-shadow: 2px 0 24px rgba(0,0,0,0.5); }
body.center-mode .sidebar.open { transform: translateX(0); }
body.center-mode #scrim { z-index: 45; }
body.center-mode .center-top .icon-btn { display: block; }

/* detail pane: on desktop a card click DOCKS the normal chat pane on the right, next to the grid
   (no popup; the cards keep streaming in view, Sam's stream of thought uninterrupted). The live
   summary card on the left stays highlighted. Mobile keeps the full-screen overlay: a split there
   would be unusably cramped. */
.peek-close { display: none; }
body.center-mode.peeking .peek-close { display: block; }
/* grid LEFT, detail RIGHT (flex order beats DOM order: .main precedes #center in the markup),
   with a draggable divider between them (width persists via --peek-w / localStorage) */
body.center-mode .center { order: 1; }
body.center-mode.peeking .main { display: flex; order: 3; flex: 0 0 var(--peek-w, min(46%, 720px)); min-width: 340px; max-width: 78vw; }
#pane-resizer { display: none; }
body.center-mode.peeking #pane-resizer { display: block; order: 2; flex: 0 0 7px; cursor: col-resize; position: relative; z-index: 5; touch-action: none; }
#pane-resizer::after { content: ""; position: absolute; left: 3px; top: 0; bottom: 0; width: 1px; background: var(--line); }
#pane-resizer:hover::after, body.resizing #pane-resizer::after { left: 2px; width: 3px; background: var(--accent); border-radius: 2px; }
body.resizing { cursor: col-resize; user-select: none; -webkit-user-select: none; }
.ccard.selected { border-color: var(--accent); background: var(--panel2); }

@media (max-width: 800px) {
  .center-scroll { padding: 10px 10px calc(16px + env(safe-area-inset-bottom)); }
  .zone { grid-template-columns: 1fr; }
  /* Stream on mobile: the beat must STACK (time+chip row, then text FULL WIDTH below). As a flex
     row the text was trapped in a sliver and wrapped 2 words at a time (Sam, IMG_9612). */
  .stream-scroll { padding: 10px 12px calc(16px + env(safe-area-inset-bottom)); }
  .beat { flex-wrap: wrap; font-size: 16px; gap: 4px 10px; padding: 7px 9px 7px 11px; }
  .beat-time { flex: 0 0 auto; }
  .beat-text { flex: 1 1 100%; }
  .beat.b-narration { font-size: 17px; }
  .beat .chip { max-width: 60vw; }
  /* header: hide the redundant title, shrink the toggle, let it scroll if still tight, so it never
     overlaps (Sam, IMG_9612 showed the toggle on top of the title) */
  .center-top { gap: 6px; }
  .center-top .center-title { display: none; }
  .center-top .topbar-title { flex: 0 1 auto; }
  #center-counts { white-space: nowrap; }
  .view-toggle { margin-right: 0; padding: 2px; overflow-x: auto; max-width: 70vw; -webkit-overflow-scrolling: touch; }
  .vt-btn { padding: 6px 8px; font-size: 12px; white-space: nowrap; }
  .watchers-btn { padding: 6px 8px; font-size: 11px; }
  /* the counts pill is the least essential thing in a tight header: drop it, keep the toggle whole */
  .center-top #center-counts { display: none; }
  /* background is load-bearing: the desktop docked pane needs none (it sits BESIDE the grid), but
     this fixed overlay sits ON TOP of it; without an opaque bg the grid bleeds through the chat
     (Sam's 2026-07-03 mobile regression, IMG_9607) */
  /* height must track the VISUAL viewport (--app-h), NOT inset:0. With inset:0 the pane is the full
     layout viewport, so its bottom composer sits UNDER the iOS keyboard (Sam, IMG_9616: only the
     keyboard accessory bar showed, the composer was hidden). top:0 + height:var(--app-h) shrinks the
     pane with the keyboard so the composer stays flush above it, like the non-peek layout does. */
  body.center-mode.peeking .main { position: fixed; top: 0; left: 0; bottom: auto; z-index: 40; width: 100vw; height: var(--app-h, 100dvh); max-width: none; border: none; background: var(--bg); }
  body.center-mode.peeking #pane-resizer { display: none; }
  body.center-mode.peeking::after { content: ""; position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 35; }
  .ccard-reply textarea { min-height: 44px; }
  .ccard-reply button { min-height: 44px; }
}

/* live gist: the haiku gist of what a running session is doing right now (wraps, 3 lines max) */
.ccard-live { font-size: 13px; color: var(--text); font-style: italic; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }

/* markdown-rendered assistant bubbles (class added after streaming completes) */
.bubble.md { white-space: normal; }
.bubble.md > *:first-child { margin-top: 0; }
.bubble.md > *:last-child { margin-bottom: 0; }
.bubble.md p { margin: 0 0 10px; }
.bubble.md h1, .bubble.md h2, .bubble.md h3, .bubble.md h4 { margin: 14px 0 8px; line-height: 1.3; }
.bubble.md h1 { font-size: 1.35em; } .bubble.md h2 { font-size: 1.2em; } .bubble.md h3 { font-size: 1.08em; } .bubble.md h4 { font-size: 1em; }
.bubble.md ul, .bubble.md ol { margin: 0 0 10px; padding-left: 22px; }
.bubble.md li { margin: 2px 0; }
.bubble.md li > ul, .bubble.md li > ol { margin: 2px 0; }
.bubble.md code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.88em; background: var(--bg); border: 0.5px solid var(--line); border-radius: 5px; padding: 1px 5px; overflow-wrap: anywhere; word-break: break-word; }
/* Fenced code scrolls horizontally WITHIN the bubble (never widens the column): max-width caps it to
   the bubble, overflow-x:auto keeps a long line as an internal scroll, min-width:0 lets it shrink. */
.bubble.md pre { margin: 0 0 10px; padding: 12px; background: var(--bg); border: 0.5px solid var(--line); border-radius: 8px; max-width: 100%; min-width: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.bubble.md pre code { background: none; border: 0; padding: 0; font-size: 12.5px; line-height: 1.5; white-space: pre; }
.bubble.md blockquote { margin: 0 0 10px; padding: 2px 0 2px 12px; border-left: 3px solid var(--line); color: var(--muted); }
.bubble.md a { color: var(--accent); }
/* Wide tables scroll horizontally within their own container (added by wrapScrollables in app.js),
   so the table can be as wide as it needs while the column stays strictly viewport width. The box
   caps at the bubble and scrolls internally; the table keeps native table layout inside it. */
.bubble.md .md-scroll { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 0 10px; }
.bubble.md .md-scroll > table { margin: 0; }
.bubble.md table { border-collapse: collapse; margin: 0 0 10px; font-size: 0.92em; }
.bubble.md th, .bubble.md td { border: 0.5px solid var(--line); padding: 5px 9px; text-align: left; }
.bubble.md hr { border: 0; border-top: 0.5px solid var(--line); margin: 12px 0; }

/* ---- watchers: fired-watcher badge on a card + the active-watchers panel ---- */
.ccard-watch { font-size: 11px; font-weight: 600; color: #ffb454; background: rgba(255,180,84,0.14);
  border: 0.5px solid rgba(255,180,84,0.4); padding: 1px 8px; border-radius: 20px; cursor: pointer;
  flex: 0 0 auto; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ccard-watch:hover { background: rgba(255,180,84,0.24); }
/* drag-and-drop attach cue: the whole chat pane is a drop target */
.main.dropping { outline: 2px dashed var(--accent); outline-offset: -8px; }
.main.dropping .composer { background: var(--accent-dim); }
/* Raw columns: one vertical lane per session, side by side, horizontally scrollable,
   chronological within. THE OVERLAP BUG (Sam's screenshot, 2026-07-04): .stream-list sets
   flex-direction: column and this block only set display: flex, so the lanes STACKED vertically
   instead of sitting side by side; worse, each .scol's flex-basis (300px) then acted as a fixed
   HEIGHT (the explicit min-height had replaced the content-based automatic minimum), so every
   column was squashed to 300px and its overflowing beats painted straight over the next column.
   Row direction + content-sized columns is the fix; never give .scol a flex-basis or a
   min-height again. */
/* flex-end, not flex-start: the stream is bottom-anchored (newest beats at the bottom, streamStick),
   so every column's LIVE EDGE must line up at the bottom of the list; top-aligned columns left the
   whole bottom view to the single tallest column and everything else blank. */
.stream-list.lanes { flex-direction: row; align-items: flex-end; gap: 16px;
  max-width: none; width: max-content; min-width: 100%; }
.stream-list.lanes > .beat { display: none; }   /* a cid-less beat has no lane (narration only, and the narrator is paused) */
.scol { flex: 0 0 320px; display: flex; flex-direction: column; gap: 10px;
  border-left: 2px solid var(--line); padding-left: 10px; }
/* sticky per-column session name: stays readable however deep Sam scrolls; also the drag handle */
.scol-head { position: sticky; top: 0; z-index: 2; background: var(--bg); padding: 14px 0 6px;
  font-weight: 700; font-size: 13px; letter-spacing: 0.02em; cursor: grab;
  display: flex; align-items: center; gap: 7px; border-radius: 6px; }
.scol-head:hover { background: var(--panel); }   /* hover cue: the header is grabbable */
.scol-head:active { cursor: grabbing; }
.scol.dragging { opacity: 0.45; }
.scol.dragging .scol-head { cursor: grabbing; }
/* grip glyph: the visible "grab me" affordance, brightens on header hover */
.scol-grip { flex: 0 0 auto; color: var(--muted); font-size: 15px; line-height: 1; opacity: 0.55;
  letter-spacing: -2px; cursor: grab; }
.scol-head:hover .scol-grip { opacity: 1; color: var(--text); }
.scol-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* per-column pin: hollow star by default, filled + accent when pinned to the front */
.scol-pin { flex: 0 0 auto; cursor: pointer; color: var(--muted); font-size: 13px; line-height: 1;
  opacity: 0.5; padding: 2px 3px; border-radius: 5px; }
.scol-head:hover .scol-pin { opacity: 0.9; }
.scol.pinned .scol-pin { color: var(--accent); opacity: 1; }
.scol.pinned .scol-head { background: var(--accent-dim); }   /* pinned columns read as "held to the front" */
/* the drop indicator: a bright vertical insertion line marking exactly where the column will land */
.scol-dropline { flex: 0 0 3px; align-self: stretch; min-height: 60px; border-radius: 2px;
  background: var(--accent); box-shadow: 0 0 8px var(--accent); }
.stream-list.lanes .beat .chip { display: none; }   /* the column head already names the session */
.stream-list.lanes .beat { border-left: none; padding-left: 4px; }
/* dismiss X for a parked verdict, on cards and shelf items; generous hit area for mobile */
.ccard-dismiss, .shelf-dismiss { flex: 0 0 auto; margin-left: auto; cursor: pointer;
  color: var(--muted); font-size: 13px; line-height: 1; padding: 3px 7px; border-radius: 6px; }
.ccard-dismiss:hover, .shelf-dismiss:hover { color: var(--fg); background: rgba(255,255,255,0.08); }
/* Pulse staleness: the moment activity shifts, the standing summary dims until the fresh one
   lands (never read a stale line as current) */
.ccard-live.stale, .beat.stale { opacity: 0.5; }
.ccard-live.stale::after, .beat.stale .beat-text::after { content: ' shifting...'; font-style: italic; color: var(--muted); }
.watchers-btn { cursor: pointer; border: 0; }
.watchers-panel { position: absolute; top: 46px; right: 12px; z-index: 40; width: min(360px, 86vw);
  max-height: 60vh; overflow-y: auto; background: var(--panel2); border: 0.5px solid var(--line);
  border-radius: 10px; padding: 6px; box-shadow: 0 8px 30px rgba(0,0,0,0.4); }
.watchers-empty { color: var(--muted); font-size: 13px; padding: 8px; }
.watch-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 7px; }
.watch-row:hover { background: var(--panel); }
.watch-row.fired { opacity: 0.55; }
.watch-desc { flex: 1 1 auto; min-width: 0; font-size: 12.5px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.watch-x { flex: 0 0 auto; background: none; border: 0; color: var(--muted); font-size: 18px;
  line-height: 1; cursor: pointer; padding: 0 4px; }
.watch-x:hover { color: var(--danger); }

/* Multi-user gateway and account administration. */
.identity-note { font-size: 12px; color: #7dd3fc; overflow-wrap: anywhere; }
.setup-title { margin: 8px 0; font-size: 22px; }
.accounts-body { margin: 0; min-height: 100vh; background: #050505; color: #f4f4f5; }
.accounts-wrap { width: min(920px, calc(100% - 32px)); margin: 0 auto; padding: 28px 0 60px; }
.accounts-head { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 20px; }
.accounts-head h1 { margin: 8px 0 0; font-size: 28px; }
.accounts-back { color: #a1a1aa; text-decoration: none; font-size: 13px; }
.account-card, .account-row, .invite-result {
  border: 1px solid #27272a; background: #0c0c0d; border-radius: 14px; padding: 18px;
}
.current-account { margin-bottom: 18px; }
.current-account strong, .account-person strong { margin-right: 8px; }
.current-account span, .account-person span { color: #a1a1aa; }
.account-meta { margin-top: 6px; color: #71717a; font-size: 12px; overflow-wrap: anywhere; }
.account-card h2 { margin: 0 0 8px; font-size: 18px; }
.account-form { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.account-form input, .account-form select, .invite-result input {
  box-sizing: border-box; width: 100%; border: 1px solid #303036; border-radius: 9px;
  background: #151517; color: #fafafa; padding: 11px 12px;
}
.account-form label { display: flex; align-items: center; gap: 10px; color: #a1a1aa; font-size: 12px; }
.account-form label select { flex: 1; }
.account-form button { grid-column: 1 / -1; }
.account-form button, .account-actions button, .invite-result button, .account-secondary {
  border: 1px solid #3f3f46; border-radius: 9px; background: #27272a; color: #fafafa;
  padding: 10px 13px; cursor: pointer;
}
.account-secondary { background: transparent; }
.account-link { display: inline-block; text-decoration: none; }
.account-head-actions { display: flex; align-items: center; gap: 8px; }
.invite-result { margin: 0 0 18px; border-color: #166534; background: #07140b; }
.invite-result p { color: #a1a1aa; font-size: 13px; }
.invite-result input { margin: 8px 0; }
.account-error { border: 1px solid #7f1d1d; background: #1f0909; color: #fecaca; border-radius: 10px; padding: 12px; }
.account-list { display: grid; gap: 9px; margin-top: 18px; }
.account-row { display: grid; grid-template-columns: minmax(190px, 1fr) auto auto auto; align-items: center; gap: 15px; }
.account-person { display: flex; flex-wrap: wrap; align-items: baseline; }
.account-person small { flex-basis: 100%; margin-top: 5px; color: #71717a; }
.account-status { border-radius: 999px; padding: 4px 8px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }
.account-status.active { background: #052e16; color: #86efac; }
.account-status.pending { background: #422006; color: #fdba74; }
.account-status.suspended { background: #3f0a0a; color: #fca5a5; }
.account-limit { color: #71717a; font-size: 12px; }
.account-actions { display: flex; gap: 7px; }
.account-actions form { margin: 0; }
.account-actions button { padding: 7px 9px; font-size: 12px; }
.account-actions button.danger { color: #fca5a5; border-color: #7f1d1d; }
.memory-wrap { max-width: 820px; }
.memory-message { border: 1px solid #166534; background: #07140b; color: #bbf7d0; border-radius: 10px; padding: 12px; }
.memory-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 18px; }
.memory-summary div { border: 1px solid #27272a; border-radius: 12px; padding: 15px; background: #0c0c0d; }
.memory-summary strong { display: block; font-size: 24px; }
.memory-summary span { color: #71717a; font-size: 12px; }
.memory-section { margin-bottom: 14px; }
.memory-section-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.memory-section-head form { flex: 0 0 auto; }
.memory-section button, .memory-actions button { border: 1px solid #3f3f46; border-radius: 9px; background: #27272a; color: #fafafa; padding: 9px 12px; cursor: pointer; }
.memory-item, .memory-proposal { border-top: 1px solid #27272a; padding: 13px 0; }
.memory-item summary { cursor: pointer; }
.memory-item summary span, .memory-proposal span { color: #71717a; font-size: 11px; margin-left: 7px; }
.memory-item p, .memory-proposal p { color: #d4d4d8; font-size: 13px; }
.memory-item pre, .memory-proposal pre { white-space: pre-wrap; overflow-wrap: anywhere; color: #a1a1aa; font: 12px/1.5 ui-monospace, monospace; }
.memory-proposal details summary { cursor: pointer; color: #a1a1aa; font-size: 12px; }
.memory-actions { display: flex; gap: 8px; margin-top: 10px; }
.memory-actions form { margin: 0; }
.memory-actions button.danger { color: #fca5a5; border-color: #7f1d1d; }
.memory-empty { color: #71717a; font-size: 13px; }
@media (max-width: 700px) {
  .account-form { grid-template-columns: 1fr; }
  .account-form button { grid-column: auto; }
  .account-row { grid-template-columns: 1fr auto; }
  .account-limit { grid-column: 1; }
  .account-actions { grid-column: 2; grid-row: 1 / span 2; flex-direction: column; }
  .memory-summary { grid-template-columns: 1fr; }
  .memory-section-head { align-items: flex-start; flex-direction: column; }
}
