agentus 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@
3
3
  import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
4
4
  import type { Duplex } from "node:stream";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
+ import { execFileSync } from "node:child_process";
6
7
  import { homedir } from "node:os";
7
8
  import { fileURLToPath } from "node:url";
8
9
  import path from "node:path";
@@ -17,7 +18,7 @@ import { classifyError, checkedHealth, coerceRow, inspectRow, planFor, rowWarnin
17
18
  import { ChangedOnDiskError, FsError, listDirs, readTextFile, statFile, writeTextFile } from "./fs.js";
18
19
  import { terms } from "./term.js";
19
20
  import { VoiceError, listVoiceModels, setHotwordSource, synthesize, transcribe, voiceCapabilities } from "./voice.js";
20
- import { hotwordsFor, vocabularyOf } from "./hotwords.js";
21
+ import { dictationContext, hotwordsFor, vocabularyOf } from "./hotwords.js";
21
22
  import { openDashscopeStream } from "./dashscope.js";
22
23
  import {
23
24
  agentSettings, getSettings, initSettings, observerSettings, planHintSettings, publicSettings,
@@ -71,6 +72,23 @@ const DATA_DIR_SOURCE = ENV_DATA_DIR
71
72
  : DATA_DIR === REPO_DATA_DIR
72
73
  ? "in-repo packages/server/.data"
73
74
  : hasData(DEFAULT_DATA_DIR) ? "existing ~/.agentus" : "default ~/.agentus (created on this boot)";
75
+ // WHICH CODE THIS PROCESS IS RUNNING — resolved once, at boot, on purpose.
76
+ //
77
+ // The live server has no watcher, so the only thing that decides "is this release live?" is what
78
+ // this process loaded. A promote used to compare the live tree's previous checkout with the new
79
+ // tip, which stops being true the moment anything moves the tree first (an earlier promote that
80
+ // died after checkout, a manual `git checkout`, a re-run): every later promote then saw a zero
81
+ // diff, printed "no server-side change" and left the old process serving — the release looked
82
+ // green while the code was a commit behind. This is that fact, from the process itself: promote
83
+ // asks the server what it booted, and restarts because the answer is not the target commit.
84
+ const BOOT_COMMIT = (() => {
85
+ try {
86
+ const out = execFileSync("git", ["rev-parse", "--short", "HEAD"], {
87
+ cwd: path.resolve(HERE, "../.."), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"],
88
+ }).trim();
89
+ return out || null;
90
+ } catch { return null; } // a published install has no .git — nothing to name
91
+ })();
74
92
  const WEB_DIST = process.env.AGENTUS_WEB_DIST ?? path.resolve(HERE, "../../web/dist");
75
93
  // The Android companion artifact (/notify links to it, /agentus-companion.apk streams it).
76
94
  // First candidate is relative to THIS FILE (src → packages/server → packages → repo root,
@@ -191,6 +209,9 @@ const sessionsEvent = (): ServerEvent => ({
191
209
  cold: mgr.cold(),
192
210
  archived: mgr.archived(),
193
211
  pending: mgr.pendingPermissions(),
212
+ // Background snapshots (issue #22) ride this frame for the same reason pending approvals do: they are
213
+ // STATE, and a page that connects or refreshes after the agent last spoke still has to be current.
214
+ background: mgr.backgroundSnapshots(),
194
215
  });
195
216
 
196
217
  // 工作播报 (issue #16): one long-lived observer per watched session, in its own scratch home under
@@ -365,6 +386,10 @@ setHotwordSource((sessionId) => hotwordsFor(store, sessionId).map((h) => h.word)
365
386
  // The plan-tool hint: read per prompt, so the 设置 switch applies to the next turn with nothing
366
387
  // to restart (the session's own plan card is what it fills).
367
388
  mgr.setPlanHintSource(planHintSettings);
389
+ // Issue #22: a finished background process may open a turn by itself. Default on (the CLI/gateway
390
+ // behaviour); the switch exists because a synthetic turn spends tokens the operator may not want
391
+ // spent at 3am — and it is read live, so flipping it applies to the next completion.
392
+ mgr.setCompletionWakeSource(() => agentSettings().completionWake);
368
393
  mgr.startIdleReaper({
369
394
  idleMs: () => envIdleMs ?? agentSettings().idleKillMin * 60_000,
370
395
  warmSlots: () => envWarm ?? agentSettings().warmSlots,
@@ -374,19 +399,6 @@ setHotwordSource((sessionId) => hotwordsFor(store, sessionId).map((h) => h.word)
374
399
  });
375
400
  }
376
401
 
377
- /** The tail of the session being dictated into, for DashScope's context enhancement
378
- * ("根据上下文"): user/assistant turns only, capped at 5 by the API. */
379
- function dictationContext(sessionId?: string): { role: "user" | "assistant"; text: string }[] {
380
- if (!sessionId) return [];
381
- const out: { role: "user" | "assistant"; text: string }[] = [];
382
- for (const row of store.messagesTail(sessionId, 8).messages) {
383
- if (row.kind !== "user" && row.kind !== "agent") continue;
384
- const text = String((row.payload as { text?: string })?.text ?? "").trim().slice(0, 200);
385
- if (text) out.push({ role: row.kind === "user" ? "user" : "assistant", text });
386
- }
387
- return out.slice(-5);
388
- }
389
-
390
402
  /**
391
403
  * Single prompt entry point (REST + WS both use it).
392
404
  * A failed turn must never be silent: the UI used to show a bare
@@ -1199,10 +1211,16 @@ async function post(path){const r=await fetch(path,{method:'POST'});alert(r.ok?'
1199
1211
  if (url.pathname === "/api/voice/hotwords" && req.method === "GET") {
1200
1212
  const sid = url.searchParams.get("sessionId") || undefined;
1201
1213
  const words = hotwordsFor(store, sid);
1214
+ // contextTurns is the half of the request the settings page could not see: it is the
1215
+ // count of natural-language turns the next recognition would carry, and it used to be
1216
+ // 0 forever because the window was applied before the kind filter (issue #21).
1217
+ const context = dictationContext(store, sid);
1202
1218
  return send(res, 200, {
1203
1219
  words: words.map((h) => ({ word: h.word, weight: h.weight, origin: h.origin })),
1204
1220
  fixed: words.filter((h) => h.origin === "fixed").length,
1205
1221
  dynamic: words.filter((h) => h.origin === "dynamic").length,
1222
+ contextTurns: context.length,
1223
+ context: context.map((c) => ({ role: c.role, text: c.text.slice(0, 80) })),
1206
1224
  });
1207
1225
  }
1208
1226
  // What the browser should offer: it can always speak/read text itself, and the
@@ -1536,7 +1554,9 @@ async function post(path){const r=await fetch(path,{method:'POST'});alert(r.ok?'
1536
1554
  // launcher sets neither, so live answers false. An instance-level fact, so it rides the
1537
1555
  // endpoint that already describes the instance rather than every backend row.
1538
1556
  const dev = Boolean(process.env.DEV_TREE) || process.env.AGENTUS_DEV === "1";
1539
- return send(res, 200, { asset, dev });
1557
+ // `commit`: the code THIS process booted from (see BOOT_COMMIT). It is the only honest answer
1558
+ // to "did the release actually land", because the tree can be moved under a running server.
1559
+ return send(res, 200, { asset, dev, commit: BOOT_COMMIT });
1540
1560
  }
1541
1561
  if (url.pathname.startsWith("/api/")) return send(res, 404, { error: "not_found" });
1542
1562
  return serveStatic(req, res);
@@ -1790,7 +1810,7 @@ asrWss.on("connection", (ws: WebSocket, _req: IncomingMessage, url: URL) => {
1790
1810
  try {
1791
1811
  live = openDashscopeStream({
1792
1812
  vocabulary: vocabularyOf(words),
1793
- context: dictationContext(sessionId),
1813
+ context: dictationContext(store, sessionId),
1794
1814
  onPartial: (text) => reply({ t: "asr-partial", text }),
1795
1815
  onFinal: (text) => reply({ t: "asr-final", text }),
1796
1816
  onError: (error) => reply({ t: "asr-error", error }),
@@ -185,9 +185,15 @@ export interface AgentSettings {
185
185
  * (`context`/`messages`/`plan`) is NOT gated: it cannot change anything, and it is what the
186
186
  * 工作播报 observer runs on. */
187
187
  cockpitSend: boolean;
188
+ /** Let a finished background process wake the agent with its own result (issue #22). ON by default:
189
+ * this is what the CLI and the gateway already do, and the failure it prevents is the silent one —
190
+ * a session that looks finished while a build is still running, whose result nobody ever reads. */
191
+ completionWake: boolean;
188
192
  }
189
193
 
190
- export const AGENT_DEFAULT: AgentSettings = { idleKillMin: 5, warmSlots: 5, warmTtlHours: 24, cockpitSend: false };
194
+ export const AGENT_DEFAULT: AgentSettings = {
195
+ idleKillMin: 5, warmSlots: 5, warmTtlHours: 24, cockpitSend: false, completionWake: true,
196
+ };
191
197
 
192
198
  /** The numeric half of `AgentSettings` — the keys the range-checked helpers may write. */
193
199
  type AgentNumberKey = "idleKillMin" | "warmSlots" | "warmTtlHours";
@@ -419,6 +425,7 @@ function pickAgent(raw: unknown): AgentSettings {
419
425
  take("warmSlots", AGENT_WARM_RANGE);
420
426
  take("warmTtlHours", AGENT_WARM_TTL_RANGE);
421
427
  if (typeof r.cockpitSend === "boolean") out.cockpitSend = r.cockpitSend;
428
+ if (typeof r.completionWake === "boolean") out.completionWake = r.completionWake;
422
429
  }
423
430
  return out;
424
431
  }
@@ -718,6 +725,10 @@ export function saveAgent(patch: Record<string, unknown>): Settings {
718
725
  if (typeof patch.cockpitSend !== "boolean") throw new Error("invalid cockpitSend: expected true or false");
719
726
  a.cockpitSend = patch.cockpitSend;
720
727
  }
728
+ if ("completionWake" in patch) {
729
+ if (typeof patch.completionWake !== "boolean") throw new Error("invalid completionWake: expected true or false");
730
+ a.completionWake = patch.completionWake;
731
+ }
721
732
  cache = { ...cache, agent: a, updatedAt: Date.now() };
722
733
  persist();
723
734
  return cache;
@@ -62,6 +62,11 @@ function reemissionTarget(blockText: string, incoming: string): "same" | "grew"
62
62
  /** A page also stops on bytes, so one 30 KB message cannot overflow a phone-sized fetch. */
63
63
  const PAGE_BYTES = 256 * 1024;
64
64
 
65
+ /** Provenance of a session's name, ranked: a name may only be overwritten by a BETTER source
66
+ * (or by the operator asking for a new one). See `setAutoTitle`. */
67
+ export type TitleSrc = "derived" | "agent" | "operator";
68
+ const TITLE_RANK: Record<TitleSrc, number> = { derived: 1, agent: 2, operator: 3 };
69
+
65
70
  export interface SessionRow {
66
71
  id: string;
67
72
  backend: BackendId;
@@ -73,6 +78,9 @@ export interface SessionRow {
73
78
  autoTitle?: string | null;
74
79
  /** session id of whoever renamed it through the cockpit CLI; null = the operator's own name */
75
80
  titleBy?: string | null;
81
+ /** Where the CURRENT name came from — see the `title_src` migration below. Not part of SessionInfo:
82
+ * it is bookkeeping that decides who may overwrite the row, not something the page draws. */
83
+ titleSrc?: TitleSrc | null;
76
84
  status: SessionStatus;
77
85
  pid: number | null;
78
86
  createdAt: number;
@@ -113,7 +121,8 @@ export interface SessionRow {
113
121
 
114
122
  interface RawSessionRow {
115
123
  id: string; backend: BackendId; acp_session_id: string | null; cwd: string;
116
- title: string; auto_title?: string | null; title_by?: string | null; status: SessionStatus; pid: number | null;
124
+ title: string; auto_title?: string | null; title_by?: string | null; title_src?: string | null;
125
+ status: SessionStatus; pid: number | null;
117
126
  created_at: number; closed_at: number | null; archived_at?: number | null;
118
127
  modes?: string | null; config_options?: string | null;
119
128
  usage?: string | null; commands?: string | null;
@@ -178,7 +187,8 @@ function blockKeyOf(kind: string, payload: unknown): string | null {
178
187
  function rowToSession(r: RawSessionRow): SessionRow {
179
188
  return {
180
189
  id: r.id, backend: r.backend, acpSessionId: r.acp_session_id, cwd: r.cwd,
181
- title: r.title, autoTitle: r.auto_title ?? null, titleBy: r.title_by ?? null, status: r.status, pid: r.pid,
190
+ title: r.title, autoTitle: r.auto_title ?? null, titleBy: r.title_by ?? null,
191
+ titleSrc: (r.title_src as TitleSrc | null) ?? null, status: r.status, pid: r.pid,
182
192
  createdAt: r.created_at, closedAt: r.closed_at, archivedAt: r.archived_at ?? null,
183
193
  modes: parseJson(r.modes), configOptions: parseJson(r.config_options) ?? [],
184
194
  usage: parseJson(r.usage), commands: parseJson(r.commands) ?? [],
@@ -376,6 +386,19 @@ export class Store {
376
386
  // rail would show it as fact. NULL = the operator (every existing row), a session id = that
377
387
  // session's agent renamed it through the cockpit CLI.
378
388
  if (!cols.has("title_by")) this.#db.exec("alter table sessions add column title_by text");
389
+ // WHERE THE CURRENT NAME CAME FROM, which `title_by` cannot answer: a generated name has no author
390
+ // (title_by is NULL) — exactly like a name the operator typed. Without this column the store cannot
391
+ // tell 「the operator named this」 from 「we generated this」, so every later generated name looked
392
+ // like the first one and moved the display title. Measured 2026-10-17: Hermes regenerates a title
393
+ // on EVERY turn (auxiliary `title_generation`), so a running conversation was renamed each time.
394
+ // 'derived' — truncated from the operator's first prompt (no model, instant)
395
+ // 'agent' — the agent announced a name (session_info_update / the 重新生成 fork)
396
+ // 'operator' — the operator typed it; nothing generated may move it
397
+ // NULL on existing rows = generated before this column existed; treated as 'agent'.
398
+ if (!cols.has("title_src")) this.#db.exec("alter table sessions add column title_src text");
399
+ // Existing rows get NULL here, i.e. "no generated name was ever recorded" — harmless: a legacy row
400
+ // that already wears a generated name is protected by `#autoTitleFrom`'s placeholder test, which
401
+ // only ever re-derives a name for a row still showing "Hermes @ tmp".
379
402
  // The session's own ACTIVITY clock — when the operator or the agent last really said something
380
403
  // in it. A COLUMN, not a derived `max(messages.created_at)` (AionUi's model: `modified_at` on
381
404
  // the conversation row, indexed, which is what its sidebar sorts by): every ingestion path
@@ -1069,6 +1092,23 @@ export class Store {
1069
1092
  return { hasMore: hasMore || page.length < capped.length, messages: page.reverse().map(rowToMessage) };
1070
1093
  }
1071
1094
 
1095
+ /** The newest rows of the given KINDS, ignoring whatever sits in between.
1096
+ *
1097
+ * A row window is the wrong unit when the question is "what did the humans say": one agentic
1098
+ * turn emits hundreds of `tool`/`thought` rows between two sentences, so `messagesTail(200)`
1099
+ * legitimately contains zero natural-language rows (measured on a live session: 275 rows, 153
1100
+ * tool + 106 thought, and every user/agent row older than the window). Filtering by kind in
1101
+ * SQL is the only way to ask for "the last 5 sentences" and actually get them.
1102
+ */
1103
+ messagesLastKinds(sessionId: string, kinds: string[], limit = 5): StoredMessage[] {
1104
+ if (!kinds.length || limit <= 0) return [];
1105
+ const marks = kinds.map(() => "?").join(",");
1106
+ const rows = this.#db
1107
+ .prepare(`select * from messages where session_id = ? and kind in (${marks}) order by seq desc limit ?`)
1108
+ .all(sessionId, ...kinds, limit) as unknown as RawMessageRow[];
1109
+ return rows.reverse().map(rowToMessage);
1110
+ }
1111
+
1072
1112
  messagesAfter(sessionId: string, afterSeq: number, limit = 500): StoredMessage[] {
1073
1113
  const rows = this.#db
1074
1114
  .prepare(
@@ -1099,10 +1139,15 @@ export class Store {
1099
1139
  | { title: string; auto_title: string | null }
1100
1140
  | undefined;
1101
1141
  if (!row) return false;
1102
- const next = title == null || !title.length ? (row.auto_title ?? row.title) : title;
1142
+ const named = title != null && title.length > 0;
1143
+ const next = named ? title : (row.auto_title ?? row.title);
1103
1144
  // `by` rides along on every write, including a reset: after `--auto` the name is generated again,
1104
1145
  // and the note that an agent once renamed it would be a lie about the CURRENT name.
1105
- const info = this.#db.prepare("update sessions set title = ?, title_by = ? where id = ?").run(next, by, id);
1146
+ // `title_src` is what PINS the row: a hand-written name must survive every later generated one,
1147
+ // while a reset hands the name back to whichever generator wrote `auto_title`.
1148
+ const src = named ? "operator" : (row.auto_title ? "agent" : null);
1149
+ const info = this.#db.prepare("update sessions set title = ?, title_by = ?, title_src = ? where id = ?")
1150
+ .run(next, by, src, id);
1106
1151
  return Number(info.changes ?? 0) > 0;
1107
1152
  }
1108
1153
 
@@ -1115,18 +1160,30 @@ export class Store {
1115
1160
  * the fallback and leaves the visible row alone. `force` is for the operator asking for a
1116
1161
  * new name on purpose (the rail's 重新生成), where the new title is the point.
1117
1162
  * Returns the row it ended up with, so callers can broadcast exactly what changed. */
1118
- setAutoTitle(id: string, title: string, { force = false }: { force?: boolean } = {}): SessionRow | null {
1119
- const row = this.#db.prepare("select title, auto_title from sessions where id = ?").get(id) as
1120
- | { title: string; auto_title: string | null }
1163
+ setAutoTitle(
1164
+ id: string, title: string, { force = false, src = "agent" }: { force?: boolean; src?: TitleSrc } = {},
1165
+ ): SessionRow | null {
1166
+ const row = this.#db.prepare("select title, auto_title, title_src from sessions where id = ?").get(id) as
1167
+ | { title: string; auto_title: string | null; title_src: string | null }
1121
1168
  | undefined;
1122
1169
  if (!row) return null;
1123
1170
  const clean = title.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 120).trim();
1124
1171
  if (!clean) return null;
1125
- const wasAuto = row.auto_title == null || row.auto_title === "" || row.title === row.auto_title;
1126
- const nextTitle = force || wasAuto ? clean : row.title;
1172
+ // WHO WINS, by rank — derived < agent < operator. A name only moves the row when it comes from a
1173
+ // BETTER source than the one already on it (or when there is nothing yet, or the operator asked
1174
+ // for a new one). This is what stops 「跑着跑着标题就变了」: Hermes regenerates a title every turn,
1175
+ // and every one of those is an `agent` name arriving over an `agent` name — the same generator
1176
+ // saying the same thing again, not news. A `derived` guess still yields to the first real one.
1177
+ // `null` = nothing has NAMED this row yet. That is not the same as "the operator named it": every
1178
+ // row is INSERTED with `auto_title = title` (the placeholder "Hermes @ tmp"), so the column alone
1179
+ // cannot say whether a name was ever generated — only `title_src` can.
1180
+ const current = row.title_src as TitleSrc | null;
1181
+ const named = current != null && row.auto_title != null && row.auto_title !== "";
1182
+ const wins = force || !named || TITLE_RANK[src] > TITLE_RANK[current];
1183
+ if (!wins) return this.getSession(id) ?? null;
1127
1184
  this.#db
1128
- .prepare("update sessions set auto_title = ?, title = ? where id = ?")
1129
- .run(clean, nextTitle, id);
1185
+ .prepare("update sessions set auto_title = ?, title = ?, title_src = ? where id = ?")
1186
+ .run(clean, clean, src, id);
1130
1187
  return this.getSession(id) ?? null;
1131
1188
  }
1132
1189
 
@@ -169,7 +169,7 @@ export interface PermissionDiff {
169
169
  // ---- WS envelope (server -> browser) ----
170
170
  export type ServerEvent =
171
171
  | { t: "hello"; clientId: string; resumed: boolean }
172
- | { t: "sessions"; sessions: SessionInfo[]; /** rows on disk with NO process and no archive flag — they belong in 工作空间 beside the live ones (a crashed slot must not look archived, and must not vanish from the rail either) */ cold?: SessionInfo[]; /** rows the operator explicitly archived (archivedAt set) — the 已归档 section, whatever their process state */ archived?: SessionInfo[]; /** requests already waiting for an answer, so a page that connects or refreshes learns about them (they are STATE; the events happened before it existed) */ pending?: PermissionRequestView[] }
172
+ | { t: "sessions"; sessions: SessionInfo[]; /** current background snapshots, for a page that connects AFTER the frame that carried them */ background?: { sessionId: string; tasks: BackgroundTask[] }[]; /** rows on disk with NO process and no archive flag — they belong in 工作空间 beside the live ones (a crashed slot must not look archived, and must not vanish from the rail either) */ cold?: SessionInfo[]; /** rows the operator explicitly archived (archivedAt set) — the 已归档 section, whatever their process state */ archived?: SessionInfo[]; /** requests already waiting for an answer, so a page that connects or refreshes learns about them (they are STATE; the events happened before it existed) */ pending?: PermissionRequestView[] }
173
173
  | { t: "session"; session: SessionInfo }
174
174
  | { t: "messages"; sessionId: string; messages: StoredMessage[]; hasMore: boolean; partial?: boolean }
175
175
  | { t: "message"; message: StoredMessage; /** text to APPEND for a streamed block that grew (absent
@@ -214,6 +214,15 @@ export type ServerEvent =
214
214
  * conversation from last week). Carrier on the ACP side: an empty thought chunk tagged
215
215
  * `_meta.hermes.kind = "status"`. */
216
216
  | { t: "status"; sessionId: string; text: string; statusKind?: string }
217
+ /** Background processes this session still has (issue #22) — the ACP equivalent of the desktop's
218
+ * status stack, and the reason a turn can end while work goes on.
219
+ *
220
+ * SNAPSHOT, replaced wholesale, never stored: the agent re-sends the whole list whenever it changes,
221
+ * and the last one wins. A row is 「running」 or 「exited」 (with `exitCode`) — the exit is reported
222
+ * once, because a process without `notify_on_complete` publishes no event and this frame is the only
223
+ * witness it ever ended. Empty `tasks` = nothing runs; the page shows nothing.
224
+ * Carrier on the ACP side: an empty thought chunk tagged `_meta.hermes.kind = "background"`. */
225
+ | { t: "background"; sessionId: string; tasks: BackgroundTask[] }
217
226
  /** The session's plan object — the TRUTH the card renders, not the transcript's frames. Sent on
218
227
  * every change, and the same object is available over GET /api/sessions/:id/plan, so a page that
219
228
  * loads after the agent process died still renders the real plan instead of nothing. */
@@ -241,6 +250,18 @@ export type ServerEvent =
241
250
  * this tab in the background (`document.hidden` — the page's own answer to 「我正在看就不弹」, made
242
251
  * where the fact lives), (3) draw it with `noticeId` as the notification `tag`. Everything about WHAT
243
252
  * happened and WHEN to say it is decided server-side. */
253
+ /** One background process as the agent reports it (issue #22). Field names are the wire's, not the
254
+ * registry's: `uptimeSeconds`/`exitCode` are normalised server-side so the page never has to know
255
+ * whether it is reading `list_sessions()` or a completion event. */
256
+ export interface BackgroundTask {
257
+ id: string;
258
+ command: string;
259
+ pid?: number | null;
260
+ status: "running" | "exited";
261
+ uptimeSeconds?: number;
262
+ exitCode?: number | null;
263
+ }
264
+
244
265
  export interface WebNotice {
245
266
  /** `upsert` = show (or replace) the card for `noticeId`; `dismiss` = take it away. */
246
267
  op: "upsert" | "dismiss";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}:root{--bg: #0c1116;--bg-panel: #121a22;--bg-raised: #182430;--line: #223140;--text: #e3ecf3;--text-dim: #b6bec3;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #295f7b;--ok: #4ec9a0;--err: #e57373;--err-rgb: 229, 115, 115;--thought: #8f7bd7;--tool: #5ba8d4;--code-bg: #0a0f14;--code-fg: #d7e2ea;--code-bar: rgba(255, 255, 255, .06);--code-line: rgba(255, 255, 255, .1);--chip-bg: #1e2b38;--on-accent: #101820;--accent-text: #4aacdf;--scrim: rgba(0, 0, 0, .55);--shadow: 0 18px 40px rgba(0, 0, 0, .45);--scroll-thumb: rgba(255, 255, 255, .18);--scroll-thumb-hover: rgba(255, 255, 255, .34);--mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace}:root[data-theme=light]{--bg: #f4f6f9;--bg-panel: #ffffff;--bg-raised: #eaeef4;--line: #d7dde6;--text: #1c2735;--text-dim: #3f4750;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #9bd1ed;--ok: #1f9d75;--err: #c2453f;--err-rgb: 194, 69, 63;--thought: #6d5bc4;--tool: #2f7fb5;--code-bg: #10171f;--code-fg: #cfd8e3;--code-bar: rgba(255, 255, 255, .07);--code-line: rgba(255, 255, 255, .12);--chip-bg: #e8ecf2;--accent-text: #16659b;--on-accent: #101820;--scrim: rgba(12, 17, 22, .42);--shadow: 0 18px 40px rgba(23, 36, 48, .18);--scroll-thumb: rgba(12, 17, 22, .22);--scroll-thumb-hover: rgba(12, 17, 22, .38)}@media (prefers-color-scheme: light){:root[data-theme=system]{--bg: #f4f6f9;--bg-panel: #ffffff;--bg-raised: #eaeef4;--line: #d7dde6;--text: #1c2735;--text-dim: #3f4750;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #9bd1ed;--ok: #1f9d75;--err: #c2453f;--err-rgb: 194, 69, 63;--thought: #6d5bc4;--tool: #2f7fb5;--code-bg: #10171f;--code-fg: #cfd8e3;--code-bar: rgba(255, 255, 255, .07);--code-line: rgba(255, 255, 255, .12);--chip-bg: #e8ecf2;--accent-text: #16659b;--on-accent: #101820;--scrim: rgba(12, 17, 22, .42);--shadow: 0 18px 40px rgba(23, 36, 48, .18);--scroll-thumb: rgba(12, 17, 22, .22);--scroll-thumb-hover: rgba(12, 17, 22, .38)}}*{box-sizing:border-box}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-corner{background:transparent}*::-webkit-scrollbar-thumb{background-color:transparent;border:2px solid transparent;border-radius:999px;background-clip:padding-box}*:hover::-webkit-scrollbar-thumb{background-color:var(--scroll-thumb)}*::-webkit-scrollbar-thumb:hover{background-color:var(--scroll-thumb-hover)}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--text);font:15px/1.5 -apple-system,Segoe UI,PingFang SC,Noto Sans SC,sans-serif;-webkit-font-smoothing:antialiased}button{font:inherit}.app{display:flex;height:100%;overflow:hidden}.sidebar{width:var(--rail-w, 268px);flex:0 0 var(--rail-w, 268px);background:var(--bg-panel);border-right:1px solid var(--line);display:flex;flex-direction:column;position:relative}.sidebar header{padding:14px 16px 10px;display:flex;align-items:baseline;gap:8px}.sidebar header .logo{color:var(--accent-text);font-weight:700;letter-spacing:.5px;display:inline-flex;align-items:center;gap:7px}.brand-mark{display:block;flex:0 0 auto}.sidebar header .tagline{font-size:11px;color:var(--text-dim)}.new-btn{margin:0 12px 10px;padding:9px;border-radius:8px;cursor:pointer;border:1px dashed var(--accent-dim);background:transparent;color:var(--accent-text)}.new-btn:hover{background:rgba(var(--accent-rgb),.08)}.rail-search{margin:0 8px 6px;padding:7px 9px;border-radius:8px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);font-size:12.5px;font-family:var(--mono)}.rail-search:focus{outline:none;border-color:var(--accent-dim)}.rail-search::placeholder{color:var(--text-dim);opacity:1}.load-earlier{display:flex;justify-content:center;margin-bottom:10px}.load-earlier-busy,.load-earlier-end{font-size:11px;color:var(--text-dim);line-height:1.6}.cold-purge{margin-left:auto;background:transparent;border:1px solid transparent;color:var(--text-dim);font-size:11px;line-height:1;padding:2px 5px;border-radius:5px;cursor:pointer}.session-item.cold:hover .cold-purge{border-color:var(--line);color:var(--err)}.session-list{flex:1;overflow-y:auto;padding:0 8px 8px}.session-item{padding:10px;border-radius:8px;cursor:pointer;margin-bottom:4px;border:1px solid transparent}.session-item:hover{background:var(--bg-raised)}.session-item.active{background:var(--bg-raised);border-color:var(--line)}.session-item .title{font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.session-item .meta{font-size:11.5px;color:var(--text-dim);display:flex;gap:8px;margin-top:3px;align-items:center}.dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}.dot.ready{background:var(--ok)}.dot.running{background:var(--accent);animation:pulse 1s infinite}.dot.starting{background:var(--text-dim)}.dot.error,.dot.closed{background:var(--err)}.rail-sep{display:flex;justify-content:space-between;align-items:baseline;padding:12px 10px 6px;font-size:11px;letter-spacing:.4px;text-transform:uppercase;color:var(--text-dim);border-top:1px solid var(--line);margin:8px 4px 0}.session-item.cold:hover{background:rgba(var(--accent-rgb),.06)}.dot.cold{background:transparent;border:1px solid var(--text-dim)}.hint{color:var(--text-dim)}@keyframes pulse{50%{opacity:.35}}.badge{font-size:10.5px;border:1px solid var(--line);border-radius:5px;padding:0 5px;color:var(--text-dim)}.badge.perm{border-color:var(--accent-dim);color:var(--accent-text)}.badge.bg{border-color:var(--accent-dim);color:var(--accent-text);font-variant-numeric:tabular-nums}.bg-row{border:1px solid var(--line);border-left:3px solid var(--accent-dim);border-radius:8px;margin-bottom:6px;background:var(--bg-panel)}.bg-head{display:flex;align-items:center;gap:7px;width:100%;padding:3px 8px;background:none;border:0;color:var(--text-dim);font:inherit;text-align:left;cursor:pointer}.bg-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--accent)}.bg-dot[data-state=exited]{background:var(--text-dim)}.bg-text{flex:0 0 auto;white-space:nowrap;font-size:12.5px;color:var(--text)}.bg-hint{flex:1 1 auto;min-width:0;font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bg-caret{flex:0 0 auto;font-size:10px;opacity:.7}.bg-list{list-style:none;margin:0;padding:2px 8px 6px;border-top:1px solid var(--line);max-height:40vh;overflow:auto}.bg-item{display:block;padding:4px 0;border-top:1px dashed var(--line)}.bg-item:first-child{border-top:0}.bg-cmd-full{margin:0;max-height:132px;overflow:auto;font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px;line-height:1.45;white-space:pre-wrap;word-break:break-word;color:var(--text)}.bg-item-foot{display:flex;align-items:center;gap:10px;margin-top:2px}.bg-cmd{flex:1 1 auto;min-width:0;font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bg-meta{flex:0 0 auto;color:var(--text-dim);font-variant-numeric:tabular-nums}.bg-item[data-state=exited] .bg-meta{color:var(--accent-text)}.bg-notice{border:1px solid var(--line);border-left:3px solid var(--accent-dim);border-radius:7px;background:var(--bg-panel);max-width:100%}.bg-notice[data-ok=fail]{border-left-color:var(--err)}.bg-notice-head{display:flex;align-items:center;gap:7px;width:100%;padding:4px 8px;background:none;border:0;color:var(--text-dim);font:inherit;text-align:left;cursor:pointer}.bg-notice-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--accent)}.bg-notice[data-ok=fail] .bg-notice-dot{background:var(--err)}.bg-notice-title{flex:0 0 auto;font-size:12.5px;color:var(--text)}.bg-notice-cmd{flex:1 1 auto;min-width:0;font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bg-notice-code{flex:0 0 auto;font-size:11.5px;color:var(--text-dim);font-variant-numeric:tabular-nums}.bg-notice-caret{flex:0 0 auto;font-size:10px;opacity:.7}.bg-notice-body{border-top:1px solid var(--line);padding:4px 8px 7px}.bg-notice-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--text-dim);margin-top:3px}.bg-notice-pre{margin:2px 0 0;padding:5px 7px;border-radius:5px;background:var(--bg-code, rgba(127, 127, 127, .07));font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px;line-height:1.45;white-space:pre-wrap;word-break:break-word;max-height:260px;overflow:auto}@media (max-width: 720px){.bg-notice-cmd{font-size:11px}}@media (max-width: 720px){.bg-hint{display:none}.bg-text{font-size:12px}}.sidebar footer{padding:10px 14px;font-size:11.5px;color:var(--text-dim);border-top:1px solid var(--line)}.sidebar footer .conn.off{color:var(--err)}.main{flex:1;display:flex;flex-direction:column;min-width:0}.chat-head{padding:7px 10px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:6px;flex-wrap:nowrap;background:var(--bg-panel);min-height:46px}.chat-head .title{font-weight:600;font-size:14px;flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-btn .spin,.sess-menu-item .spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.icon-btn .spin,.sess-menu-item .spin{animation:none}}.head-spacer{flex:1 1 auto;min-width:4px}.speak-wrap{position:relative;display:inline-flex}.speak-dot{position:absolute;top:4px;right:4px;width:5px;height:5px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 1.5px var(--bg-panel)}.speak-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:40;min-width:240px;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;box-shadow:0 10px 30px #00000052;padding:3px;display:flex;flex-direction:column}.speak-menu-item{display:flex;align-items:center;gap:7px;text-align:left;width:100%;background:none;border:1px solid transparent;border-radius:7px;color:var(--text);font:inherit;font-size:12.5px;padding:7px 8px;cursor:pointer}.speak-menu-item:hover{background:var(--bg-panel);border-color:var(--line)}.speak-menu-item.on{color:var(--text);font-weight:600}.speak-check{width:10px;flex:0 0 10px;color:var(--accent);font-size:11px}.speak-hint{margin:2px 4px 4px;padding-top:6px;border-top:1px solid var(--line);font-size:11px;line-height:1.5;color:var(--text-dim)}.turn-pulse{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--ok);animation:pulse 1.4s infinite}.turn-pulse.quiet{background:var(--accent);animation-duration:2.6s}@media (prefers-reduced-motion: reduce){.turn-pulse{animation:none}}.head-actions{display:inline-flex;align-items:center;gap:0;flex:0 0 auto}.head-actions .icon-btn{width:28px;height:28px}.chat-head .icon-btn svg{width:18px;height:18px}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;flex:0 0 auto;padding:0;background:transparent;border:1px solid transparent;border-radius:8px;color:var(--text-dim);cursor:pointer}.icon-btn:hover{background:var(--bg-raised);border-color:var(--line);color:var(--text)}.icon-btn.danger:hover{color:var(--err);border-color:var(--err)}.chip{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;font-size:11px;padding:2px 7px;border-radius:999px}.perm-chip{border:1px solid var(--accent-dim);color:var(--accent-text)}.perm-pulse{width:6px;height:6px;border-radius:50%;background:var(--accent);animation:pulse 1.2s infinite}.ghost-btn{background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12.5px}.ghost-btn:hover{color:var(--text);border-color:var(--text-dim)}.ghost-btn.danger:hover{color:var(--err);border-color:var(--err)}.stream-wrap{flex:1;min-height:0;position:relative;display:flex}.stream{flex:1;overflow-y:auto;padding:18px 0;overscroll-behavior:contain}.stream:focus{outline:none}.stream-hint{display:flex;gap:7px;padding:2px 0;color:var(--text-dim);font-size:12.5px;align-items:baseline;flex-wrap:nowrap;min-width:0}.stream-hint>span:not(.turn-status){flex:0 0 auto;white-space:nowrap}.stream-hint .elapsed{opacity:.75;font-variant-numeric:tabular-nums}.stream-hint .turn-status{flex:1 1 auto;min-width:0;white-space:normal;overflow-wrap:anywhere;line-height:1.3;font-size:11.5px;padding-left:7px;border-left:1px solid var(--line)}@media (max-width: 720px){.stream-hint{gap:5px;flex-wrap:wrap;row-gap:2px}.stream-hint .turn-status{flex:1 0 100%;padding-left:0;border-left:none;font-size:11px;line-height:1.35}}.stream-spin{flex:0 0 auto;align-self:flex-start;margin-top:4px;width:11px;height:11px;border-radius:50%;border:1.5px solid var(--line);border-top-color:var(--accent);animation:spin .8s linear infinite}@media (prefers-reduced-motion: reduce){.stream-spin{animation:none}}.jump-latest{position:absolute;left:50%;bottom:14px;transform:translate(-50%);width:34px;height:34px;border-radius:50%;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);box-shadow:0 6px 18px #0006}.jump-latest:hover{color:var(--text);border-color:var(--text-dim)}.jump-latest.has-new{color:var(--accent-text);border-color:var(--accent-dim)}.jump-dot{position:absolute;top:3px;right:3px;width:7px;height:7px;border-radius:50%;background:var(--accent);animation:pulse 1.2s infinite}.rail-search-wrap{position:relative;margin:0 8px 6px;display:flex;align-items:center}.rail-search-wrap>svg{position:absolute;left:9px;color:var(--text-dim);pointer-events:none}.rail-search-wrap .rail-search{margin:0;padding-left:27px;width:100%}.cold-resume{background:transparent;border:1px solid transparent;color:var(--text-dim);padding:2px 4px;border-radius:5px;cursor:pointer;line-height:1;display:inline-flex;align-items:center}.session-item.cold:hover .cold-resume{border-color:var(--line);color:var(--ok)}.stream-inner{margin:0;padding:0 20px}.msg{margin-bottom:14px;display:flex;flex-direction:column;align-items:flex-start;min-width:0}.msg>*{max-width:100%}.msg.user{align-items:flex-end}.msg.user.from-agent .role{color:var(--accent, #6ea8fe);letter-spacing:.2px}.msg.user.from-agent .bubble{border-style:dashed;border-color:var(--accent, #6ea8fe)}.msg.plan,.msg.meta{align-items:stretch}.msg .role{font-size:11px;color:var(--text-dim);margin-bottom:3px;letter-spacing:.4px}.msg .role.with-mark{display:flex;align-items:center;gap:5px}.agent-mark{flex:0 0 auto;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;font-size:9.5px}.agent-mark img{display:block;width:16px;height:16px;border-radius:4px;object-fit:contain}.msg .bubble{border-radius:10px;padding:10px 14px;white-space:pre-wrap;overflow-wrap:anywhere}.msg .bubble:has(.md),.msg .bubble>.md{white-space:normal}.msg.user .bubble{background:var(--bg-raised);border:1px solid var(--line)}.msg.agent .bubble{background:transparent}.msg.thought .bubble{background:#8f7bd712;border-left:3px solid var(--thought);color:var(--text-dim);font-size:13.5px;white-space:pre-wrap}.thought-head{display:flex;align-items:center;gap:5px;background:none;border:none;padding:2px 4px;border-radius:6px;cursor:pointer;color:var(--text-dim);font:inherit;font-size:11px;letter-spacing:.4px}.thought-head:hover{background:var(--bg-raised);color:var(--text)}.thought-chev,.tool-chev{flex:0 0 auto;color:var(--text-dim);transition:transform .15s ease}.thought-chev.open,.tool-chev.open{transform:rotate(90deg)}.thought-meta{color:var(--text-dim);opacity:.75;font-variant-numeric:tabular-nums}.msg.thought.live .thought-head{color:var(--thought)}.msg.thought .bubble.live{max-height:6.6em;overflow-y:auto}.thought-stick{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;margin:2px 0 0;padding:2px 8px;border-radius:999px;cursor:pointer;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);font:inherit;font-size:11px;letter-spacing:.3px}.thought-stick:hover{color:var(--text);border-color:var(--text-dim)}.work-run-head{display:flex;align-items:center;gap:6px;width:fit-content;max-width:100%;min-height:30px;padding:4px 8px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text-dim);font:inherit;font-size:11.5px;text-align:left;cursor:pointer}.work-run.active{align-self:stretch}.work-run-head:hover,.work-run-head:focus-visible{outline:none;border-color:var(--accent-dim);background:rgba(var(--accent-rgb),.055)}.work-run.active .work-run-head{border-color:var(--accent-dim)}.work-chev{flex:0 0 auto;color:var(--text-dim);transition:transform .15s ease}.work-chev.open{transform:rotate(90deg)}.work-run-icon{flex:0 0 auto;color:var(--accent-text)}.work-run-count{flex:0 0 auto;font-weight:600;color:var(--text)}.work-run-names,.work-run-chars{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.work-run-state{flex:0 0 auto}.work-run-state.ok{color:var(--ok)}.work-run-state.err{color:var(--err)}.work-run-state.run{color:var(--accent-text)}.work-run-items{display:flex;flex-direction:column;gap:2px;margin:4px 0 0 11px;padding:3px 4px 3px 12px;border-left:1px solid var(--line);max-height:42vh;overflow-y:auto}.work-run-items .msg{margin-bottom:4px}.work-run-items .bubble{max-height:none}@media (max-width: 700px){.work-run-head{min-height:34px}.work-run-items{max-height:38vh}.msg.thought .bubble.live{max-height:7.4em}}.msg.meta .bubble{color:var(--err);font-size:13px;background:#e5737314}.usage-note{color:var(--text-dim);font-size:11.5px;line-height:1.5;max-width:46ch}.msg.plan .bubble{border-left:3px solid var(--ok);background:#4ec9a00f;font-size:13.5px}.plan-card{border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:8px;padding:3px 8px;background:var(--bg-panel)}.plan-card.completed{border-left-color:var(--ok)}.plan-head{display:flex;align-items:center;gap:8px;width:100%;padding:3px 0;border:0;background:none;color:var(--text);font:inherit;font-size:13px;cursor:pointer;text-align:start}.plan-head:hover{color:var(--accent-text)}.plan-title{font-weight:600;flex:0 0 auto}.plan-count{font-size:12px;color:var(--text-dim);font-variant-numeric:tabular-nums}.plan-state{font-size:11.5px;padding:0 6px;border-radius:999px;line-height:18px}.plan-state.running{color:var(--accent-text);background:rgba(var(--accent-rgb, 90, 140, 255),.12)}.plan-state.done{color:var(--ok);background:#4ec9a01f}.plan-state.terminal{color:var(--err);background:rgba(var(--err-rgb),.1)}.plan-head .tool-chev{margin-inline-start:auto}.plan-body{list-style:none;margin:2px 0 4px;padding:4px 0 0;border-top:1px dashed var(--line)}.plan-name{padding:1px 0 6px;margin-bottom:2px;border-bottom:1px dotted var(--line);font-weight:600;font-size:13px;overflow-wrap:anywhere}.plan-step{display:flex;align-items:baseline;gap:8px;padding:2.5px 0;font-size:13px}@media (max-width: 720px){.plan-step{font-size:12px;gap:6px}.plan-step .step-icon{flex-basis:12px}.plan-name{font-size:12.5px}}.plan-step .step-icon{flex:0 0 14px;text-align:center;color:var(--text-dim)}.plan-step.completed .step-icon{color:var(--ok)}.plan-step.completed .step-title{color:var(--text-dim)}.plan-step.in_progress .step-icon{color:var(--accent);animation:pulse 1.2s infinite}.plan-step.cancelled .step-icon{color:var(--err)}.plan-step.cancelled .step-title{color:var(--text-dim);text-decoration:line-through}.plan-step .step-title{flex:1;min-width:0;overflow-wrap:anywhere}.plan-explanation{margin:6px 0 2px;padding-top:4px;border-top:1px dashed var(--line);font-size:12px;opacity:.7;overflow-wrap:anywhere}.plan-bar{border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:8px;padding:1px 8px;margin-bottom:6px;background:var(--bg-panel)}.plan-bar.completed{border-left-color:var(--ok)}.plan-bar .plan-body{max-height:40vh;overflow-y:auto}.plan-dots{display:inline-flex;align-items:center;gap:2.5px;margin-inline-start:2px}.plan-dots .dot{width:5px;height:5px;border-radius:50%;background:var(--line);border:1px solid var(--text-dim);box-sizing:border-box}.plan-dots .dot.completed{background:var(--ok);border-color:var(--ok)}.plan-dots .dot.in_progress{background:var(--accent);border-color:var(--accent);animation:pulse 1.2s infinite}.plan-dots .dot.cancelled{background:var(--err);border-color:var(--err)}@media (max-width: 700px){.plan-step{font-size:12px;padding:2px 0;gap:6px}.plan-step .step-icon{flex-basis:12px}.plan-name{font-size:12.5px;padding-bottom:5px}.plan-explanation{font-size:11.5px}.plan-head{font-size:12.5px}}pre.code{background:var(--code-bg);color:var(--code-fg);border:1px solid var(--line);border-radius:8px;padding:10px 12px;overflow-x:auto;font-family:var(--mono);font-size:12.8px}code.inline{font-family:var(--mono);background:var(--chip-bg);color:var(--text);border:1px solid var(--line);padding:1px 5px;border-radius:4px;font-size:.92em}.bubble-actions{display:flex;align-items:center;gap:4px;margin-top:4px;opacity:0;transition:opacity .12s}.msg:hover .bubble-actions{opacity:1}@media (hover: none){.bubble-actions{opacity:.75}}.msg-at{font-size:10.5px;color:var(--text-dim);opacity:.9;font-variant-numeric:tabular-nums;white-space:nowrap;flex:0 0 auto}.bubble-actions .msg-at{flex:1 1 auto;text-align:left}.bubble-note{font-size:10.5px;color:var(--text-dim)}.bubble-files{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:6px}.bubble-file{display:inline-flex;align-items:center;gap:4px;font-size:11px;border:1px solid var(--line);border-radius:6px;padding:1px 6px;color:var(--text-dim)}.tool-card{border:1px solid var(--line);border-left:3px solid var(--tool);border-radius:8px;padding:3px 8px;background:var(--bg-panel)}.tool-head{display:flex;align-items:center;gap:6px;width:100%;min-width:0;background:transparent;border:none;padding:2px 0;cursor:pointer;color:var(--text);font-family:var(--mono);font-size:11.5px;text-align:left}.tool-head:hover{color:var(--accent-text)}.tool-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool-chev{flex:0 0 auto;opacity:.5;transition:transform .12s ease}.tool-chev.open{transform:rotate(90deg)}.tool-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--text-dim)}.tool-dot.running{background:var(--accent);animation:pulse 1.2s infinite}.tool-dot.ok{background:var(--ok)}.tool-dot.err{background:var(--err)}.tool-card.completed{border-left-color:var(--ok)}.tool-card.failed{border-left-color:var(--err)}.tool-card .tool-body{margin-top:8px;border-top:1px dashed var(--line);padding-top:6px}.tool-card .tool-body .lbl{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--text-dim)}.tool-card .tool-body pre{margin:4px 0 8px;padding:6px 9px;max-height:260px;overflow:auto;background:var(--bg);border:1px solid var(--line);border-radius:6px;font-family:var(--mono);font-size:11px;line-height:1.45;white-space:pre-wrap;word-break:break-word}.tool-card .tool-body pre.tool-meta{color:var(--text-dim);margin-bottom:6px}.ctx{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;color:var(--ok)}.ctx.warn{color:#d9a03a}.ctx.hot{color:var(--err)}.ctx .ctx-text{font-size:11px;font-family:var(--mono);color:var(--text-dim)}.slash-palette{position:absolute;bottom:calc(100% + 6px);left:0;right:0;max-height:260px;overflow:auto;background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;padding:4px;box-shadow:0 10px 26px #00000059;z-index:5}.slash-item{display:flex;align-items:baseline;gap:8px;padding:6px 9px;border-radius:6px;cursor:pointer}.slash-item.sel{background:#ffffff0f}.slash-item .cmd{font-family:var(--mono);font-size:12.5px;color:var(--accent-text)}.slash-item .desc{font-size:11.5px;color:var(--text-dim);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slash-item .src{font-size:10px;color:var(--text-dim);border:1px solid var(--line);border-radius:4px;padding:0 4px}.slash-item.empty{color:var(--text-dim);font-size:12px;cursor:default}.perm-card{border:1px solid var(--accent-dim);border-radius:10px;padding:12px 14px;background:rgba(var(--accent-rgb),.05)}.perm-card .q{font-size:13.5px;margin-bottom:4px}.perm-card .tc{font-family:var(--mono);font-size:12.5px;color:var(--text-dim);margin-bottom:10px;overflow-wrap:anywhere}.perm-card .opts{display:flex;gap:8px;flex-wrap:wrap}.perm-card .opts button{border-radius:7px;padding:6px 12px;cursor:pointer;font-size:13px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text)}.perm-card .opts button.allow{border-color:var(--ok);color:var(--ok)}.perm-card .opts button.reject{border-color:var(--err);color:var(--err)}.perm-card.resolved{opacity:.55}.perm-card.resolved .picked{font-size:12px;color:var(--accent-text);margin-top:8px}.perm-dialog{max-width:560px;max-height:92vh;overflow-y:auto}.perm-ask{font-size:13px;line-height:1.5;color:var(--text)}.perm-file{display:flex;align-items:center;gap:6px;margin-top:10px;padding:6px 8px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised)}.perm-file code{font-family:var(--mono);font-size:12px;word-break:break-all;color:var(--accent-text)}.perm-changes{margin-top:10px}.perm-change-row{display:flex;align-items:center;gap:7px;width:100%;text-align:left;cursor:pointer;padding:7px 9px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text);font:inherit}.perm-change-row:hover{border-color:var(--accent-dim)}.perm-change-row code{font-family:var(--mono);font-size:12px;color:var(--accent-text);flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.perm-counts{display:flex;gap:6px;font-family:var(--mono);font-size:11.5px;flex:0 0 auto}.perm-counts .add{color:var(--ok)}.perm-counts .del{color:var(--err)}.perm-caret{color:var(--text-dim);font-size:11px;flex:0 0 auto}.perm-diff{margin-top:6px;border:1px solid var(--line);border-radius:8px;background:var(--bg);max-height:34vh;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.5}.perm-diff-line{display:grid;grid-template-columns:3.2em 3.2em 1.2em 1fr;white-space:pre-wrap;overflow-wrap:anywhere;padding:0 6px}.perm-diff-line .no{color:var(--text-dim);text-align:right;padding-right:6px;user-select:none}.perm-diff-line .sig{text-align:center}.perm-diff-line.add{background:#30a46c1f}.perm-diff-line.add .sig{color:var(--ok)}.perm-diff-line.del{background:#e25a501f}.perm-diff-line.del .sig{color:var(--err)}.perm-diff-line.ctx{color:var(--text-dim)}.perm-diff-gap{color:var(--text-dim);font-size:10.5px;text-align:center;padding:3px 0;background:#7f7f7f0f}.perm-cut{font-size:11px;color:var(--text-dim);margin-top:4px}.stale-banner{position:fixed;left:50%;transform:translate(-50%);bottom:calc(10px + env(safe-area-inset-bottom,0px));z-index:80;cursor:pointer;border:1px solid var(--accent-dim);border-radius:999px;background:var(--accent);color:var(--on-accent);font-weight:700;font-size:12.5px;padding:9px 16px;box-shadow:0 6px 18px #00000059}.stale-banner:hover{filter:brightness(1.06)}.perm-opts{margin-top:14px}.perm-note{font-size:11.5px;color:var(--text-dim);margin-top:10px;line-height:1.5}.perm-answered{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ok);border:1px solid var(--ok);border-radius:7px;padding:6px 11px;background:#4ec9a014}.perm-answered-tick{font-weight:700}.perm-queue{margin-top:10px;font-size:12px;color:var(--accent-text);line-height:1.5}.perm-unconfirmed{margin-top:10px;font-size:12.5px;color:var(--warn, #d08a2a);border:1px solid var(--warn, #d08a2a);border-radius:7px;padding:6px 10px;line-height:1.5}.ns-fixed-dir{display:flex;align-items:center;gap:6px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text-dim)}.ns-fixed-dir code{font-family:var(--mono);font-size:12px;word-break:break-all;color:var(--accent-text)}.composer{border-top:1px solid var(--line);background:var(--bg-panel);padding:8px 20px calc(10px + env(safe-area-inset-bottom))}.composer.drop-active .composer-box{border-color:var(--accent-text);background:rgba(var(--accent-rgb),.06)}.composer-inner{position:relative;display:flex;flex-direction:column;gap:6px}.composer-box{display:flex;flex-direction:column;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px}.composer-box:focus-within{border-color:var(--accent-dim)}.composer textarea{flex:0 0 auto;resize:none;background:transparent;color:var(--text);border:none;padding:10px 12px 4px;font:inherit;min-height:42px;max-height:40vh;overflow-y:auto}.composer textarea:focus{outline:none}.composer-bar{display:flex;align-items:center;gap:6px;padding:2px 6px 6px}.icon-btn.on{background:var(--bg-panel);border-color:var(--accent-dim);color:var(--accent-text)}.icon-btn.rec{color:var(--err);border-color:var(--err);animation:pulse 1.4s infinite}.icon-btn.tiny{width:22px;height:22px;border-radius:6px}.send-btn{border:none;background:var(--accent);color:var(--on-accent);font-weight:700;border-radius:9px;padding:0;cursor:pointer;width:40px;height:34px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}.send-btn.stop{background:var(--err);color:#180e0e}.send-btn:disabled{opacity:.4;cursor:default}.usage-row{display:flex;align-items:center;gap:8px;padding:0 2px;position:relative}.usage-text{background:transparent;border:none;padding:0;cursor:pointer;font-size:11px;color:var(--text-dim);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left;display:inline-flex;align-items:center;gap:5px}.usage-text:hover{color:var(--text)}.usage-row.warn .usage-text{color:var(--accent-text)}.usage-row.hot .usage-text{color:var(--err)}.usage-icon{flex:none;opacity:.75}.usage-bar{flex:1 1 auto;max-width:220px;height:5px;border-radius:3px;background:var(--line);overflow:hidden}.usage-bar>i{display:block;height:100%;background:var(--ok);transition:width .22s ease}.usage-row.warn .usage-bar>i{background:var(--accent)}.usage-row.hot .usage-bar>i{background:var(--err)}.usage-set{margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--line)}.usage-set-head{display:flex;align-items:center;gap:5px;color:var(--text);margin-bottom:6px}.usage-set-scope{margin-left:auto;font-size:10px;color:var(--text-dim);border:1px solid var(--line);border-radius:999px;padding:0 6px}.usage-set-chips{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:6px}.usage-chip{background:var(--chip-bg);border:1px solid var(--line);border-radius:6px;color:var(--text-dim);font-family:inherit;font-size:11px;padding:4px 8px;cursor:pointer}.usage-chip:hover{color:var(--text);border-color:var(--accent-dim)}.usage-chip.sel{color:var(--bg);background:var(--accent);border-color:var(--accent)}.settings-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--effort, var(--text-dim));margin-right:6px}.usage-detail{position:absolute;left:0;right:auto;width:min(560px,100%);bottom:calc(100% + 8px);z-index:12;max-height:min(60vh,420px);overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:11.5px;color:var(--text-dim);font-family:var(--mono);box-shadow:0 12px 30px #00000059}.draft-row{display:flex;flex-wrap:wrap;align-items:center;gap:5px}.draft{display:inline-flex;align-items:center;gap:5px;max-width:220px;border:1px solid var(--line);border-radius:8px;padding:2px 4px 2px 5px;background:var(--bg-raised);font-size:11.5px;color:var(--text-dim)}.draft img{width:20px;height:20px;object-fit:cover;border-radius:4px}.draft-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.draft-x{background:transparent;border:none;color:var(--text-dim);cursor:pointer;display:inline-flex;padding:0 2px}.draft-x:hover{color:var(--err)}.draft-clear{background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:11px;text-decoration:underline}.draft-clear:hover{color:var(--text)}.queue-list{display:flex;flex-direction:column;gap:4px}.queue-head{display:flex;align-items:baseline;gap:8px;font-size:11px;color:var(--text-dim)}.queue-title{font-weight:600;letter-spacing:.3px;text-transform:uppercase}.queue-hint{opacity:.85}.queue-row{display:flex;align-items:flex-start;gap:7px;padding:5px 6px 5px 8px;border:1px solid var(--line);border-left:3px solid var(--accent-dim);border-radius:8px;background:var(--bg-raised);font-size:12.5px;color:var(--text)}.queue-row.inflight{border-left-color:var(--accent);opacity:.75}.queue-idx{flex:0 0 auto;min-width:14px;text-align:right;font-size:10.5px;color:var(--text-dim);font-variant-numeric:tabular-nums;padding-top:2px}.queue-text{flex:1 1 auto;min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;max-height:5.6em;overflow:hidden}.queue-edit{flex:1 1 auto;min-width:0;font:inherit;font-size:12.5px;color:var(--text);background:var(--bg-panel);border:1px solid var(--accent-dim);border-radius:6px;padding:2px 6px;resize:vertical}.queue-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px}.queue-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border:1px solid var(--line);border-radius:6px;background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.queue-btn:hover{color:var(--text);border-color:var(--accent-dim);background:rgba(var(--accent-rgb),.08)}.queue-btn.danger:hover{color:var(--err);border-color:var(--err);background:#e5737314}@media (max-width: 720px){.queue-btn{width:28px;height:28px}.queue-text{max-height:3.6em}}.composer-note{font-size:11.5px;color:var(--text-dim)}.composer-note.err{color:var(--err)}.dict-chip{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--accent-text);border:1px dashed var(--accent-dim);border-radius:8px;padding:4px 8px}.dict-chip.err{color:var(--err);border-color:var(--err)}.dict-chip .interim{color:var(--text-dim)}.dict-stop{margin-left:auto;background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:1px 8px;cursor:pointer;font-size:11px}.dict-stop:hover{color:var(--err);border-color:var(--err)}.settings-pop{position:absolute;left:0;bottom:calc(100% + 8px);z-index:14;width:min(340px,92vw);max-height:70vh;overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:12px;padding:8px 10px 10px;box-shadow:0 16px 40px #00000073}.settings-head{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px}.settings-group{border-top:1px solid var(--line);padding:7px 0 4px}.settings-group:first-of-type{border-top:none}.settings-label{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-dim);margin-bottom:5px}.settings-opt{display:block;width:100%;text-align:left;margin:2px 0;cursor:pointer;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font-size:12.5px;padding:5px 8px;font-family:inherit}.settings-opt:hover{background:var(--bg-panel);border-color:var(--line)}.settings-opt.sel{background:rgba(var(--accent-rgb),.1);border-color:var(--accent-dim);color:var(--accent-text)}.settings-toggle{display:flex;align-items:center;gap:7px;font-size:12.5px;margin:5px 0;cursor:pointer}.settings-select,.settings-input{width:100%;margin:3px 0;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:7px;padding:5px 7px;font-size:12px;font-family:inherit}.settings-select:focus,.settings-input:focus{outline:none;border-color:var(--accent-dim)}.settings-freeform{display:flex;gap:6px;align-items:center;margin-top:6px}.settings-freeform .settings-input{flex:1 1 auto;min-width:0}.settings-note{font-size:10.5px;color:var(--text-dim);margin-top:4px}.settings-range{display:block;font-size:11.5px;color:var(--text-dim);margin:5px 0}.settings-range input{width:100%}.empty{margin:auto;text-align:center;color:var(--text-dim)}.empty .big{font-size:42px;display:flex;justify-content:center;margin-bottom:4px}.modal-bg{position:fixed;inset:0;background:#0000008c;display:flex;align-items:center;justify-content:center;z-index:35;padding:16px;overflow-y:auto;overscroll-behavior:contain}.modal{background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;padding:20px;width:100%;max-width:420px;max-height:calc(100dvh - 32px);overflow-y:auto}.modal.start-page{max-width:560px}.start-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}.start-head h3{margin:0;flex:1;min-width:0}.ws-pill{display:inline-flex;align-items:center;gap:6px;max-width:58%;flex:0 1 auto;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:999px;padding:5px 10px;font:inherit;font-size:12.5px;cursor:pointer}.ws-pill:hover{border-color:var(--accent-dim)}.ws-pill.empty{color:var(--text-dim);border-style:dashed}.ws-pill.locked{cursor:default;color:var(--text-dim);background:transparent}.ws-pill.locked:hover{border-color:var(--line)}.ws-pill-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ws-modal-bg{z-index:60}.ws-modal{max-width:520px}.composer.start-composer{border-top:none;background:transparent;padding:0}.start-page .backend-pick{margin-top:14px}.start-input{width:100%;box-sizing:border-box;resize:vertical;min-height:86px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:10px;padding:11px 12px;font:inherit;line-height:1.5}.start-input:focus{outline:none;border-color:var(--accent-dim)}.start-hold{display:flex;align-items:center;justify-content:center;gap:8px;color:var(--text-dim);font-size:12.5px;padding:22px 8px}.start-fail{border:1px solid var(--err);border-radius:10px;padding:12px 14px;margin:8px 0 12px;background:color-mix(in srgb,var(--err) 10%,transparent)}.start-fail-why{color:var(--err);font-size:12.5px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}.start-fail-act{display:flex;gap:8px;margin-top:10px}.modal h3{margin:0 0 14px;font-size:16px}.modal label{display:block;font-size:12.5px;color:var(--text-dim);margin:10px 0 4px}.modal input,.modal select{width:100%;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:8px;padding:9px 10px;font:inherit}.modal .row{display:flex;gap:10px;margin-top:18px}.modal .row button{flex:1;padding:9px;border-radius:8px;cursor:pointer}.modal .row .cancel{background:transparent;border:1px solid var(--line);color:var(--text-dim)}.modal .row .go{background:var(--accent);border:none;color:var(--on-accent);font-weight:700}.modal .row .go.danger{background:var(--err);color:#fff}.modal .err{color:var(--err);font-size:12.5px;margin-top:10px}@media (max-width: 520px){.modal-bg{align-items:flex-start;padding:10px}.modal{padding:14px;border-radius:12px}.modal h3{margin:0 0 8px;font-size:15px}.modal label{margin:8px 0 3px}.modal input,.modal select{padding:8px 9px}.modal .row{margin-top:12px}.backend-pick .be-card{width:68px;min-height:58px}}.blocked-homes{margin-top:12px;display:flex;flex-direction:column;gap:6px}.blocked-homes div{display:flex;gap:8px;align-items:baseline;font-size:12px}.blocked-homes span{color:var(--text-dim);min-width:104px;flex:none}.blocked-homes code{font-family:var(--mono);word-break:break-all}.backend-pick{display:flex;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;padding-bottom:2px}.backend-pick .be-card{flex:0 0 auto;width:74px;min-height:62px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:8px 6px;border-radius:10px;cursor:pointer;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);font:inherit}.backend-pick .be-card.sel{border-color:var(--accent-text);color:var(--accent-text);background:rgba(var(--accent-rgb),.1)}.be-card-mark{flex:0 0 auto;width:26px;height:26px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:var(--be-tone, var(--text-dim));background:color-mix(in srgb,var(--be-tone, var(--text-dim)) 16%,transparent);border:1px solid color-mix(in srgb,var(--be-tone, var(--text-dim)) 40%,transparent)}.be-card-mark img{width:100%;height:100%;object-fit:cover;border-radius:inherit;display:block}.be-card-label{max-width:100%;font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.backend-pick .be-card.reload{width:42px;font-size:15px}.be-detail{margin-top:6px}.be-detail-head{display:inline-flex;align-items:center;gap:4px;background:transparent;border:none;padding:2px 0;cursor:pointer;color:var(--text-dim);font-size:11.5px}.be-detail-head:hover{color:var(--accent-text)}.be-detail-arrow{transition:transform .12s}.be-detail.open .be-detail-arrow{transform:rotate(90deg)}.dim{color:var(--text-dim);font-size:12.5px;align-self:center}.hint{color:var(--text-dim);font-size:11.5px;margin-top:8px;font-family:ui-monospace,monospace;word-break:break-all}.net-banner{margin:8px 12px 0;padding:8px 10px;border-radius:8px;font-size:12.5px;background:rgba(var(--err-rgb),.12);border:1px solid rgba(var(--err-rgb),.45);color:var(--err);display:flex;gap:8px;align-items:center;justify-content:space-between}.net-banner button{background:transparent;border:1px solid rgba(var(--err-rgb),.55);color:var(--err);border-radius:6px;padding:3px 9px;cursor:pointer;font-size:12px}.menu-btn{display:none;background:none;border:none;color:var(--text);font-size:20px;padding:2px 8px;cursor:pointer}@media (max-width: 720px){.sidebar{position:fixed;inset:0 auto 0 0;z-index:30;width:min(82vw,320px);transform:translate(-105%);transition:transform .22s ease}.sidebar.open{transform:translate(0);box-shadow:0 0 40px #0009}.menu-btn{display:block}.scrim{position:fixed;inset:0;background:#00000073;z-index:25}.chip{padding:2px 6px}.perm-card button{min-height:44px;padding:10px 14px;font-size:14px}.perm-dialog{max-width:none;max-height:100%}.perm-dialog .perm-opts button{min-height:44px;padding:10px 14px;font-size:14px}.perm-diff{max-height:42vh}.perm-change-row{min-height:44px}.rail-group .group-add{width:32px;height:30px}.rail-section{min-height:34px;margin-top:6px}.slash-palette{max-height:40vh}.slash-item{min-height:44px}.msg{max-width:100%}.empty .big{font-size:42px}}.sidebar footer{display:flex;align-items:center;gap:6px}.sidebar footer .logout-btn{margin-left:auto;background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:2px 8px;cursor:pointer;line-height:1.4}.sidebar footer .logout-btn:hover{color:var(--err);border-color:var(--err)}.auth-wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:24px;background:radial-gradient(1000px 500px at 50% -10%,rgba(var(--accent-rgb),.07),transparent 60%),var(--bg)}.auth-card{width:100%;max-width:360px;background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;padding:26px 24px 20px;display:flex;flex-direction:column;gap:12px;box-shadow:0 18px 50px #00000073}.auth-logo{color:var(--accent-text);font-weight:700;font-size:20px;letter-spacing:.5px;display:flex;align-items:center;justify-content:center;gap:9px}.auth-sub{font-size:11.5px;color:var(--text-dim);margin-top:-8px}.auth-note{font-size:12.5px;color:var(--text-dim);padding:6px 0}.auth-field{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--text-dim)}.auth-field input{font:inherit;font-size:16px;padding:10px 11px;border-radius:8px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text)}.auth-field input:focus{outline:none;border-color:var(--accent-dim)}.auth-btn{margin-top:4px;padding:11px;min-height:44px;border-radius:8px;cursor:pointer;border:1px solid var(--accent-dim);background:rgba(var(--accent-rgb),.12);color:var(--accent-text);font-weight:600}.auth-btn:disabled{opacity:.6;cursor:default}.auth-err{color:var(--err);font-size:12.5px;border-left:2px solid var(--err);padding-left:8px}.auth-warn{color:var(--accent-text);font-size:11.5px;line-height:1.5;opacity:.9}.auth-foot{color:var(--text-dim);font-size:11px;line-height:1.5;border-top:1px solid var(--line);padding-top:10px}.auth-card code{font-family:var(--mono);font-size:11px;color:var(--text)}@media (max-width: 480px){.auth-card{padding:20px 16px 16px}.sidebar footer .logout-btn{min-height:44px;padding:2px 12px}}.wp{display:flex;flex-direction:column;gap:5px}.wp-bar{display:flex;align-items:center;gap:6px}.wp-bar>svg{color:var(--text-dim);flex:0 0 auto}.wp-path{flex:1;min-width:0;padding:8px 10px;border-radius:8px;font-size:13px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);font-family:var(--mono)}.wp-path:focus{outline:none;border-color:var(--accent-dim)}.wp-list{max-height:210px;overflow-y:auto;border:1px solid var(--line);border-radius:8px;background:#0000002e;padding:3px}.wp-row{display:flex;align-items:center;gap:6px;padding:4px 7px;border-radius:6px;cursor:pointer;font-size:12.5px;color:var(--text)}.wp-row>svg{color:var(--text-dim);flex:0 0 auto}.wp-row:hover{background:var(--bg-raised)}.wp-row.sel{background:rgba(var(--accent-rgb),.1);outline:1px solid var(--accent-dim)}.wp-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wp-enter{background:transparent;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;padding:1px 3px;display:inline-flex}.wp-enter:hover{color:var(--accent-text);border-color:var(--line)}.wp-note{padding:10px;font-size:12px;color:var(--text-dim);text-align:center}.wp-note.err{color:var(--err)}.wp-recent{display:flex;flex-wrap:nowrap;align-items:center;gap:4px;overflow-x:auto;overscroll-behavior-x:contain;padding-bottom:1px}.wp-recent-label{font-size:11px;color:var(--text-dim)}.wp-chip{flex:0 0 auto;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim);border-radius:999px;padding:1px 8px;font-size:10.5px;line-height:1.5;cursor:pointer;font-family:var(--mono);max-width:116px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wp-chip:hover{color:var(--text);border-color:var(--text-dim)}.wp-chip.sel{color:var(--accent-text);border-color:var(--accent-dim)}.wp-use{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;border:1px solid var(--line);background:transparent;color:var(--text-dim);border-radius:7px;padding:5px 9px;font-size:12px;cursor:pointer}.wp-use:hover:not(:disabled){color:var(--accent-text);border-color:var(--accent-dim)}.wp-use:disabled{opacity:.5;cursor:default}@media (max-width: 480px){.wp-row{min-height:40px}.wp-chip{min-height:26px}.wp-path{font-size:16px}.wp-list{max-height:150px}}.main-body{flex:1;display:flex;min-height:0}.chat-col{flex:1;display:flex;flex-direction:column;min-width:0;container-type:inline-size}.tool-panel{width:var(--panel-w, 430px);flex:0 0 auto;display:flex;flex-direction:column;min-height:0;border-left:1px solid var(--line);background:var(--bg-panel);position:relative}.panel-split{flex:1;display:flex;min-height:0;position:relative}.preview-col{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}.explorer-col{position:relative;flex:0 0 auto;width:var(--explorer-w, 300px);display:flex;flex-direction:column;min-height:0}.panel-split:not(.has-preview) .explorer-col{width:100%}.panel-split.tree-folded .explorer-col,.panel-split.preview-folded .preview-col{display:none}.panel-split.preview-folded .explorer-col{width:100%}.pane-handle{position:absolute;top:0;bottom:0;width:12px;z-index:12;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.sidebar>.pane-handle{right:-6px}.tool-panel>.pane-handle{left:-6px}.explorer-col>.pane-handle{left:-6px}.pane-handle-line{width:2px;height:100%;background:transparent;transition:background .15s ease}.pane-handle:hover .pane-handle-line,.pane-handle:active .pane-handle-line{background:var(--accent-dim)}body.pane-dragging{cursor:col-resize;user-select:none}body.pane-dragging *{cursor:col-resize!important}@media (max-width: 720px){.pane-handle{display:none}}@media (hover: none){.pane-handle{display:none}}.tool-tabs{display:flex;align-items:center;gap:3px;padding:4px 6px;border-bottom:1px solid var(--line)}.tool-tab{display:inline-flex;align-items:center;gap:5px;cursor:pointer;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text-dim);font-size:12px;padding:3px 8px;font-family:inherit}.tool-tab:hover{background:var(--bg-raised);color:var(--text)}.tool-tab.active{background:var(--bg-raised);border-color:var(--line);color:var(--accent-text)}.tool-body{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.ws-root{display:flex;align-items:center;gap:5px;padding:6px 9px 0;font-size:11px;color:var(--text-dim);font-family:var(--mono)}.ws-root-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-bar{display:flex;align-items:center;gap:2px;padding:3px 6px;border-bottom:1px solid var(--line)}.file-bar-path{flex:1;min-width:0;font-size:10.5px;color:var(--text-dim);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-list{flex:1;overflow-y:auto;padding:4px}.file-row{display:flex;align-items:center;gap:7px;width:100%;text-align:left;background:transparent;border:none;border-radius:6px;color:var(--text);font-size:12.5px;padding:4px 7px;cursor:pointer;font-family:inherit}.file-row:hover{background:var(--bg-raised)}.file-row.sel{background:rgba(var(--accent-rgb),.1)}.file-row>svg:first-child{color:var(--text-dim);flex:0 0 auto}.file-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:10.5px;color:var(--text-dim);font-family:var(--mono)}.file-enter{opacity:.45}.file-preview{flex:1;min-height:0;display:flex;flex-direction:column}.file-preview-head{display:flex;align-items:center;gap:6px;padding:4px 8px;font-size:11.5px;border-bottom:1px solid var(--line)}.file-preview-body{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column}.file-preview-body>*{min-height:0}.file-text{margin:0;padding:4px 9px 10px;overflow:auto;white-space:pre;font-family:var(--mono);font-size:11.5px;line-height:1.45;color:var(--text)}.file-image-wrap{display:flex;padding:8px;align-items:flex-start}.file-image{max-width:100%;border-radius:6px;border:1px solid var(--line)}.file-frame{flex:1;min-height:260px;width:100%;border:0;background:var(--bg-raised)}.file-audio{width:calc(100% - 16px);margin:8px}.file-video{max-width:100%;max-height:100%;margin:8px}.file-fallback{padding-top:6px}.file-view-toggle{display:flex;gap:6px;padding:4px 8px 0}.file-source{font-family:var(--mono);font-size:11.5px;line-height:1.45;padding:4px 0 10px;overflow-x:auto}.file-line{display:flex;gap:8px;padding:0 9px;white-space:pre}.file-line.hit{background:rgba(var(--accent-rgb),.14);box-shadow:inset 2px 0 0 var(--accent-text)}.file-ln{flex:0 0 34px;text-align:right;color:var(--text-dim);opacity:.6;user-select:none}.file-lt{flex:1}.file-edit{flex:1;min-height:220px;border:0;outline:0;resize:none;padding:8px 10px;background:var(--code-bg);color:var(--code-fg);white-space:pre;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.5}.file-dirty{color:var(--accent-text)}.file-conflict{display:flex;align-items:center;gap:6px;padding:5px 8px;font-size:11.5px;color:var(--text);background:rgba(var(--accent-rgb),.12);border-bottom:1px solid var(--line)}.file-md{padding:6px 10px 12px}.tool-note{padding:8px;font-size:11.5px;color:var(--text-dim)}.tool-error{padding:6px 9px;font-size:11.5px;color:var(--err)}.term-bar{display:flex;align-items:center;gap:6px;padding:4px 8px;border-bottom:1px solid var(--line);font-size:11.5px;color:var(--text-dim)}.term-dot{width:8px;height:8px;border-radius:50%;background:var(--text-dim)}.term-dot.ready{background:var(--ok)}.term-dot.error{background:var(--err)}.term-dot.closed{background:var(--accent)}.term-cwd{font-family:var(--mono);color:var(--text)}.term-body{display:flex;flex-direction:column;min-height:0;padding:0}.term-host{flex:1;min-height:0;min-width:0;overflow:hidden;padding:4px 0 0 6px;background:var(--bg-panel)}.term-host .xterm{height:100%}.term-host .xterm-viewport{background:transparent!important}.term-note{padding:4px 9px 7px;font-size:10.5px;color:var(--text-dim)}@media (max-width: 720px){.chat-head{padding:5px 8px;min-height:44px}.chat-head .title{font-size:14px}.chat-head .menu-btn,.chat-head .icon-btn{width:40px;height:40px}.chat-head .head-actions .icon-btn{width:28px;height:28px}.chat-head .head-actions .icon-btn svg{width:18px;height:18px}.composer{padding:6px 8px calc(8px + env(safe-area-inset-bottom,0px))}.composer textarea{font-size:16px;min-height:44px}.composer-bar .icon-btn{width:38px;height:38px}.send-btn{width:46px;height:38px}.usage-row .usage-bar{max-width:90px}.tb-list,.tb-list.wide{position:fixed;left:8px;right:8px;width:auto;max-width:none;bottom:calc(76px + env(safe-area-inset-bottom,0px));max-height:52vh}.settings-pop{width:min(340px,94vw);bottom:calc(100% + 6px)}.tool-panel{position:fixed;inset:44px 0 0;z-index:22;width:auto;max-width:none;border-left:none}.panel-split.has-preview .explorer-col{display:none}.file-row{min-height:42px}.term-host{min-height:30vh}}.md{font-size:13.5px;line-height:1.55;overflow-wrap:anywhere;white-space:normal}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md h1,.md h2,.md h3,.md h4{margin:12px 0 6px;line-height:1.3;font-weight:650}.md h1{font-size:18px}.md h2{font-size:16px}.md h3{font-size:14.5px}.md h4{font-size:13.5px}.md p{margin:6px 0}.md ul,.md ol{margin:6px 0;padding-left:20px}.md li{margin:2px 0}.md li>ul,.md li>ol{margin:2px 0}.md blockquote{margin:6px 0;padding:2px 10px;color:var(--text-dim);border-left:3px solid var(--line)}.md a{color:var(--accent-text);text-decoration:none;border-bottom:1px solid var(--accent-dim)}.md a:hover{border-bottom-color:var(--accent-text)}.md a.md-file-link{font-family:var(--mono);font-size:.94em;padding:0 3px;border-bottom-color:transparent;border-radius:4px;background:rgba(var(--accent-rgb),.1)}.md a.md-file-link:hover{background:rgba(var(--accent-rgb),.2)}.md-file-line{color:var(--text-dim)}.md a.md-img-link{border-bottom:none;display:inline-block;max-width:100%}.md img.md-img{max-width:100%;border-radius:6px;border:1px solid var(--line);display:block;margin:6px 0}.md hr{border:none;border-top:1px solid var(--line);margin:10px 0}.md code{font-family:var(--mono);font-size:12px;padding:1px 4px;border-radius:4px;background:var(--chip-bg);color:var(--text);border:1px solid var(--line)}.md pre{margin:0;padding:8px 10px;overflow-x:auto;background:var(--code-bg);color:var(--code-fg)}.md pre code{padding:0;background:transparent;border:none;color:inherit;font-size:12px;line-height:1.5}.md table{border-collapse:collapse;margin:8px 0;font-size:12.5px;display:block;overflow-x:auto;max-width:100%}.md-table-bar{display:flex;align-items:center;gap:6px;margin:8px 0 -2px}.md-table-filter{flex:1;min-width:0;max-width:240px;font-size:11.5px;padding:3px 7px;background:var(--bg-input, var(--bg-raised));color:var(--text);border:1px solid var(--line);border-radius:5px}.md-table-btn{font-size:11px;line-height:1;padding:3px 7px;cursor:pointer;background:var(--bg-raised);color:var(--text-dim);border:1px solid var(--line);border-radius:5px}.md-table-btn:hover{color:var(--text);border-color:var(--accent-dim)}.md-table-sort{display:inline-flex;align-items:center;gap:4px;width:100%;font:inherit;font-weight:inherit;text-align:left;cursor:pointer;background:none;border:0;padding:0;color:inherit}.md-table-sort:hover{color:var(--accent-text)}.md-table-sort-indicator{font-size:9px;opacity:.55}.md th[aria-sort=ascending] .md-table-sort-indicator,.md th[aria-sort=descending] .md-table-sort-indicator{opacity:1;color:var(--accent-text)}.md-table-overlay{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;background:#0000009e;backdrop-filter:blur(1.5px)}.md-table-overlay .md-table-bar{margin:8px}.md-table-overlay .md-table-btn{background:var(--bg-panel);font-size:12px;padding:5px 10px}.md-table-stage{flex:1;min-height:0;position:relative;overflow:hidden}.md-table-zoom{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:96vw;max-height:96vh;overflow:auto;background:var(--bg-panel);border:1px solid var(--line);border-radius:8px;padding:8px}.md-table-zoom.rot{width:96vh;height:96vw;max-width:none;max-height:none;transform:translate(-50%,-50%) rotate(90deg);transform-origin:center}.md-table-zoom table{display:table;max-width:none;margin:0}.md th,.md td{border:1px solid var(--line);padding:4px 8px;text-align:left}.md th{background:var(--bg-raised);font-weight:600}.md-code{margin:8px 0;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--code-bg);color:var(--code-fg)}.md-code-bar{display:flex;align-items:center;gap:6px;padding:3px 8px;background:var(--code-bar);border-bottom:1px solid var(--code-line)}.md-lang{font-family:var(--mono);font-size:10.5px;color:#9fb0c0;text-transform:lowercase}.md-copy{margin-left:auto;background:transparent;border:1px solid transparent;border-radius:5px;color:#9fb0c0;font-size:10.5px;padding:0 5px;cursor:pointer;font-family:inherit}.md-copy:hover{color:#e3ebf4;border-color:var(--code-line)}.md .hljs-comment,.md .hljs-quote{color:#7f8c98;font-style:italic}.md .hljs-keyword,.md .hljs-selector-tag,.md .hljs-literal,.md .hljs-section,.md .hljs-doctag,.md .hljs-name{color:#c792ea}.md .hljs-string,.md .hljs-regexp,.md .hljs-addition,.md .hljs-attribute,.md .hljs-meta .hljs-string{color:#a5d6a7}.md .hljs-number,.md .hljs-symbol,.md .hljs-bullet,.md .hljs-variable,.md .hljs-template-variable{color:#f0a35e}.md .hljs-title,.md .hljs-title.class_,.md .hljs-title.function_{color:#82b1ff}.md .hljs-built_in,.md .hljs-type,.md .hljs-class .hljs-title{color:#ffd479}.md .hljs-attr,.md .hljs-property,.md .hljs-params{color:#ffcb6b}.md .hljs-deletion{color:#ff6b6b}.md .hljs-emphasis{font-style:italic}.md .hljs-strong{font-weight:700}.tb-wrap{position:relative;flex:0 0 auto}.tb-btn{display:inline-flex;align-items:center;gap:5px;max-width:190px;height:30px;padding:0 7px;background:transparent;border:1px solid transparent;border-radius:8px;color:var(--text-dim);font-size:12px;font-family:inherit;cursor:pointer}.tb-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--text)}.tb-btn.on{background:var(--bg-panel);border-color:var(--accent-dim);color:var(--accent-text)}.tb-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-chev{opacity:.55}.tb-list{position:fixed;z-index:15;min-width:180px;max-width:min(420px,78vw);max-height:46vh;overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:4px;box-shadow:0 14px 34px #00000073}.tb-list.wide{min-width:320px}.tb-list.stacked{display:flex;flex-direction:column;overflow:hidden}.tb-list.stacked .tb-err,.tb-list.stacked .tb-search{flex:0 0 auto}.tb-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain}.tb-list.stacked .tb-group{border-top:1px solid var(--line)}.tb-list.stacked .tb-group:first-child{border-top:none}.tb-list.stacked .tb-group-head{position:sticky;top:0;z-index:1;background:var(--bg-raised)}.tb-search{width:100%;margin-bottom:3px;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:4px 6px;font-size:12px}.tb-search:focus{outline:none;border-color:var(--accent-dim)}.tb-opt{display:flex;flex-direction:column;gap:1px;width:100%;text-align:left;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font-size:12.5px;padding:4px 7px;cursor:pointer;font-family:inherit}.tb-opt:hover{background:var(--bg-panel);border-color:var(--line)}.tb-opt.sel{background:rgba(var(--accent-rgb),.1);border-color:var(--accent-dim);color:var(--accent-text)}.tb-opt.bad{border-color:var(--err);color:var(--err)}.tb-opt.bad:hover{background:rgba(var(--err-rgb),.08)}.tb-err{display:flex;flex-direction:column;gap:2px;margin:6px 4px;padding:6px 8px;border:1px solid var(--err);border-radius:7px;background:rgba(var(--err-rgb),.08);color:var(--err);font-size:11.5px;line-height:1.4;white-space:pre-wrap;word-break:break-word}.tb-err-id{font-family:var(--mono, monospace);font-size:11px;opacity:.85}.tb-err-text{color:var(--text)}.tb-opt-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-opt-hint{font-size:10.5px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-empty{padding:8px;font-size:11.5px;color:var(--text-dim);text-align:center}.usage-edit{display:flex;align-items:center;gap:5px;margin:6px 0 2px}.usage-edit input{flex:1;min-width:0;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:3px 6px;font-family:var(--mono);font-size:12px}.usage-edit input:focus{outline:none;border-color:var(--accent-dim)}.usage-edit-btn{background:transparent;border:1px solid var(--line);border-radius:6px;color:var(--text-dim);font-size:11px;padding:2px 8px;cursor:pointer;font-family:inherit}.usage-edit-btn:hover:not(:disabled){color:var(--accent-text);border-color:var(--accent-dim)}.usage-edit-btn:disabled{opacity:.45;cursor:default}.usage-edit-err{color:var(--err);font-size:11px;margin-top:3px}.usage-note{margin-top:6px;color:var(--text-dim);font-size:10.5px;line-height:1.4}@media (max-width: 720px){.tb-list,.tb-list.wide{min-width:0;width:min(86vw,420px)}.tb-btn{max-width:34vw}.md{font-size:14px}}.tb-wrap{flex:0 1 auto;min-width:0}.tb-btn,.tb-label{min-width:0}.tb-wrap>.tb-btn{max-width:100%}.tb-effort{padding:0 5px;gap:4px}.tb-pips{display:inline-flex;align-items:flex-end;gap:2px;height:12px}.tb-pips i{display:block;width:3px;border-radius:1px;background:var(--line)}.tb-pips i:nth-child(1){height:4px}.tb-pips i:nth-child(2){height:5px}.tb-pips i:nth-child(3){height:6px}.tb-pips i:nth-child(4){height:7px}.tb-pips i:nth-child(5){height:9px}.tb-pips i:nth-child(6){height:11px}.tb-pips i:nth-child(7){height:13px}.tb-dot{width:7px;height:7px;border-radius:50%;display:inline-block;margin-right:6px;vertical-align:middle}.tb-group{border-top:1px solid var(--line)}.tb-group:first-of-type{border-top:none}.tb-group-head{display:flex;align-items:center;gap:5px;width:100%;text-align:left;background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-family:inherit;font-size:11px;letter-spacing:.03em;text-transform:uppercase;padding:5px 6px;border-radius:6px}.tb-group-head:hover{background:var(--bg-panel);color:var(--text)}.tb-group-chev{transition:transform .12s ease}.tb-group-chev.open{transform:rotate(90deg)}.tb-group-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-group-count{font-size:10px;color:var(--text-dim)}.tb-group-body{padding:0 0 4px 8px}@media (max-width: 720px){.tb-btn{max-width:34vw;padding:0 4px;gap:3px}.tb-btn .tb-chev{display:none}.tb-effort{max-width:none}.composer-bar{gap:6px;padding:2px 5px 5px}.composer-bar .icon-btn{width:32px;height:32px}.send-btn{width:40px;height:36px}.composer-bar .tb-wrap:has([data-testid=start-model]),.composer-bar .tb-wrap:has([data-testid=tb-model]){flex-shrink:6}.composer-bar .tb-wrap:has([data-testid=start-mode]){flex-shrink:0;max-width:42vw}}@media (max-width: 420px){.tb-pips{gap:1px}.tb-pips i{width:2px}}@media (max-width: 340px){.composer-bar .tb-wrap:has([data-testid=start-model]),.composer-bar .tb-wrap:has([data-testid=tb-model]){flex-shrink:1}.composer-bar .tb-wrap:has([data-testid=start-model]) .tb-label,.composer-bar .tb-wrap:has([data-testid=tb-model]) .tb-label{display:none}.composer-bar .tb-wrap:has([data-testid=start-model]) .tb-btn,.composer-bar .tb-wrap:has([data-testid=tb-model]) .tb-btn{min-width:0}.composer-bar{gap:4px;padding:2px 4px 4px}.composer-bar .icon-btn{width:30px;height:30px}.composer-bar .send-btn{width:36px}}.rail-section{display:flex;align-items:center;gap:4px;width:calc(100% - 10px);margin:9px 10px 3px 0;background:transparent;border:none;font-family:inherit;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-dim);padding:3px 2px;border-radius:6px;cursor:pointer}.rail-section:hover{color:var(--text)}.rail-section-chev{flex:0 0 auto;transition:transform .12s ease}.rail-section-chev.open{transform:rotate(90deg)}.rail-section-count{margin-left:auto;letter-spacing:0;font-variant-numeric:tabular-nums}.rail-section:first-child{margin-top:3px}.rail-placeholder{display:flex;align-items:center;gap:6px;margin:0 10px 2px;padding:5px 7px;border-radius:6px;border:1px dashed var(--line);color:var(--text-dim);font-size:11px;cursor:default}.rail-placeholder-name{color:var(--text);opacity:.75}.rail-placeholder-note{margin-left:auto;font-size:11px}.rail-group{margin-bottom:2px}.rail-group-row{display:flex;align-items:center;gap:2px}.rail-group-head{display:flex;align-items:center;gap:6px;flex:1 1 auto;min-width:0;text-align:left;background:transparent;border:none;cursor:pointer;color:var(--text);font-family:inherit;font-size:12px;padding:5px 6px;border-radius:6px;margin-left:0}.rail-group-head:hover{background:var(--bg-raised)}.group-add{flex:0 0 auto;opacity:0;transition:opacity .12s}.rail-group:hover .group-add,.rail-group:focus-within .group-add{opacity:1}@media (hover: none){.group-add{opacity:.7}}.rail-group-folder{flex:0 0 auto;color:var(--text-dim)}.rail-group-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rail-group-count{font-size:11px;color:var(--text-dim)}.rail-group-body{padding-left:28px}.rail-more{display:flex;align-items:center;gap:5px;width:calc(100% - 28px);margin:1px 0 4px 28px;padding:3px 6px;background:transparent;border:none;border-radius:6px;cursor:pointer;color:var(--text-dim);font-family:inherit;font-size:11px;text-align:left}.rail-more:hover{background:var(--bg-raised);color:var(--text)}.rail-more-chev{transition:transform .12s ease;opacity:.7}.rail-more-chev.open{transform:rotate(90deg)}.item-actions{display:inline-flex;align-items:center;gap:2px;margin-left:auto}.item-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:20px;padding:0;background:transparent;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;font-family:inherit;font-size:11px}.item-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--accent-text)}.item-btn.danger:hover{color:var(--err);border-color:var(--err)}.item-btn:disabled{opacity:.5;cursor:default}.rail-error{margin:4px 8px;padding:5px 7px;border:1px solid var(--err);border-radius:6px;color:var(--err);font-size:11px;display:flex;align-items:center;gap:6px}.rail-error .draft-x{margin-left:auto}.rail-empty{padding:14px 10px;color:var(--text-dim);font-size:12.5px}.rail-gear{margin-left:auto;width:26px;height:26px;border-radius:7px}.set-head .title{display:inline-flex;align-items:center;gap:6px}.set-save{padding:6px 14px;border-radius:8px;cursor:pointer;font-weight:600;font-size:12.5px;background:var(--accent);color:var(--on-accent);border:1px solid var(--accent)}.set-save:disabled{background:transparent;color:var(--text-dim);border-color:var(--line);cursor:default}.set-toast{font-size:12px;color:var(--ok)}.set-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:14px}.set-main{flex:1;display:flex;min-height:0}.set-nav{width:196px;flex:0 0 auto;overflow-y:auto;padding:14px 10px 18px;border-right:1px solid var(--line);display:flex;flex-direction:column}.set-nav-group{display:flex;flex-direction:column;margin-bottom:10px}.set-nav-cat{text-align:left;font-size:11px;font-weight:600;color:var(--text-dim);background:none;border:0;cursor:pointer;padding:4px 8px 3px;border-radius:6px}.set-nav-cat:hover{color:var(--text);background:var(--chip-bg)}.set-nav-cat.on{color:var(--text);background:var(--chip-bg);box-shadow:inset 2px 0 0 var(--accent)}.set-nav-item{text-align:left;font-size:12.5px;color:var(--text-dim);background:none;border:0;border-left:2px solid transparent;cursor:pointer;padding:5px 8px;border-radius:0 6px 6px 0;line-height:1.4}.set-nav-item:hover{color:var(--text);background:var(--chip-bg)}.set-nav-item.on{color:var(--text);font-weight:600;border-left-color:var(--accent);background:var(--chip-bg)}.set-group{margin:4px 0 -6px;font-size:11.5px;font-weight:600;letter-spacing:.06em;color:var(--text-dim);max-width:900px;width:100%;align-self:center}.set-body[data-cat=account]>[data-setgroup]:not([data-setgroup=account]),.set-body[data-cat=agent]>[data-setgroup]:not([data-setgroup=agent]),.set-body[data-cat=notify]>[data-setgroup]:not([data-setgroup=notify]),.set-body[data-cat=look]>[data-setgroup]:not([data-setgroup=look]),.set-body[data-cat=voice]>[data-setgroup]:not([data-setgroup=voice]){display:none}.set-card{background:var(--bg-panel);border:1px solid var(--line);border-radius:12px;padding:14px 16px 16px;max-width:900px;width:100%;align-self:center}.set-card h3{margin:0 0 6px;font-size:13.5px}.set-hint{margin:6px 0 0;font-size:12px;color:var(--text-dim);line-height:1.6;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.set-hint code{font-family:var(--mono);background:var(--chip-bg);color:var(--text);border:1px solid var(--line);padding:1px 5px;border-radius:4px;font-size:11.5px}.set-row{display:flex;gap:12px;align-items:flex-start;margin-top:12px}.set-row>label{flex:0 0 84px;font-size:12.5px;color:var(--text-dim);padding-top:7px}.set-input,.set-select,.set-textarea,.set-num{background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:8px;padding:7px 9px;font-size:12.5px;font-family:var(--mono);min-width:0;flex:1 1 auto}.set-textarea{width:100%;margin-top:10px;resize:vertical;line-height:1.6}.set-builtin{margin-top:10px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised)}.set-builtin>summary{padding:8px 10px;font-size:12.5px;color:var(--text-dim);cursor:pointer}.set-builtin[open]>summary{border-bottom:1px solid var(--line)}.set-builtin>.set-hint{padding:8px 10px 0;margin:0}.set-builtin-item{padding:8px 10px 0}.set-builtin-item:last-child{padding-bottom:10px}.set-builtin-when{font-size:12px;color:var(--text-dim);margin-bottom:5px}.set-builtin-text{margin:0;padding:8px 10px;border-radius:6px;background:var(--bg-panel);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.set-num{flex:0 0 70px}.set-input:focus,.set-select:focus,.set-textarea:focus{outline:none;border-color:var(--accent-dim)}.set-pair{display:flex;gap:10px;flex-wrap:wrap;flex:1 1 320px;align-items:center;min-width:0}.set-check{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-dim);white-space:nowrap}.set-seg{display:inline-flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}.set-seg button{padding:6px 12px;background:transparent;color:var(--text-dim);border:none;border-right:1px solid var(--line);cursor:pointer;font-size:12.5px}.set-seg button:last-child{border-right:none}.set-seg button.on{background:var(--accent);color:var(--on-accent);font-weight:600}.set-swatches{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.set-swatch{width:22px;height:22px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0}.set-swatch.on{border-color:var(--text)}.set-color{width:26px;height:24px;padding:0;border:1px solid var(--line);border-radius:6px;background:var(--bg-raised)}.set-mini{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;padding:5px 9px;border-radius:7px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim);cursor:pointer}.set-mini:hover:not(:disabled){color:var(--text);border-color:var(--accent-dim)}.set-mini:disabled{opacity:.55;cursor:default}.set-hot{margin-top:12px;border-top:1px dashed var(--line);padding-top:10px}.set-hot-title{font-size:12px;color:var(--text-dim)}.set-hot-list{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}.set-chip{font-size:11.5px;font-family:var(--mono);padding:2px 7px;border-radius:6px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim)}.set-chip.fixed{border-color:var(--accent-dim);color:var(--text)}.set-chip.dynamic{border-style:dashed}.set-chip b{color:var(--accent-text);margin-left:4px;font-size:10.5px}.set-err{max-width:900px;width:100%;align-self:center;display:flex;gap:8px;align-items:center;font-size:12.5px;color:var(--err);background:var(--bg-panel);border:1px solid var(--err);border-radius:10px;padding:9px 12px}.set-inline-err{color:var(--err);font-size:12px}.set-actions{display:flex;gap:10px;align-items:center;max-width:900px;width:100%;align-self:center;padding-bottom:8px}@media (max-width: 720px){.set-row{flex-direction:column;gap:6px}.set-row>label{padding-top:0}.set-body{padding:10px}.set-main{flex-direction:column}.set-nav{width:auto;flex-direction:row;align-items:center;gap:6px;overflow-x:auto;overflow-y:hidden;padding:8px 10px;border-right:0;border-bottom:1px solid var(--line)}.set-nav-group{flex-direction:row;align-items:center;gap:6px;margin-bottom:0}.set-nav-cat{white-space:nowrap;font-size:12px;padding:4px 10px;border-radius:999px;border:1px solid var(--line);background:var(--chip-bg)}.set-nav-item{display:none}}.usage-row .usage-act{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;font-size:10.5px;padding:2px 7px;border-radius:6px;cursor:pointer;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim)}.usage-row.hot .usage-act{border-color:rgba(var(--err-rgb),.5);color:var(--err)}.usage-row .usage-act:hover{color:var(--text);border-color:var(--accent-dim)}.usage-actions{display:flex;gap:6px;margin:6px 0 2px;flex-wrap:wrap}.usage-check{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--text-dim)}.usage-note code{background:var(--chip-bg);border:1px solid var(--line);border-radius:4px;padding:0 4px}@media (max-width: 720px){.usage-text{padding:9px 2px;margin:-9px -2px}.tb-btn,.tb-effort{min-width:40px}.item-btn{min-width:34px;min-height:32px}.set-swatch{width:32px;height:32px}.set-color{width:36px;height:32px}.set-seg button{padding:8px 12px}.usage-act{padding:5px 9px}}.acct-list{display:flex;flex-direction:column;gap:6px;margin-top:10px}.acct-row{display:flex;align-items:center;gap:10px;padding:8px 10px;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px}.acct-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.acct-name{font-size:12.5px;color:var(--text);display:inline-flex;align-items:center;gap:6px}.acct-sub{font-size:11px;color:var(--text-dim);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.acct-badge{font-size:10px;padding:1px 5px;border-radius:999px;color:var(--ok);border:1px solid rgba(var(--accent-rgb),.4);background:rgba(var(--accent-rgb),.12)}.acct-badge.danger{color:var(--err);border-color:rgba(var(--err-rgb),.45);background:rgba(var(--err-rgb),.12)}.acct-when{font-size:11px;color:var(--text-dim);font-family:var(--mono)}.acct-empty{font-size:12px;color:var(--text-dim);padding:6px 2px}.set-mini.danger{color:var(--err);border-color:rgba(var(--err-rgb),.35)}.set-mini.danger:hover:not(:disabled){color:var(--err);border-color:var(--err)}.pw-wrap{position:relative;display:flex;align-items:center}.pw-wrap input{padding-right:34px}.pw-eye{position:absolute;right:4px;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-dim);cursor:pointer;border-radius:6px}.pw-eye:hover{color:var(--text);background:var(--bg-raised)}.modal-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}.modal-head h3{margin:0;flex:1}@media (max-width: 720px){.pw-eye{width:34px;height:34px}.acct-row{padding:10px}.acct-row .set-mini{min-height:34px}.set-row .set-pair{flex:0 0 auto}.set-row>label{flex:0 0 auto}}.session-item{display:flex;align-items:center;gap:8px;padding:4px 6px;min-height:30px}.session-item .title{flex:1 1 auto;min-width:0}.session-item .badge.perm{flex:0 0 auto}.rail-at{flex:0 0 auto;font-size:11px;color:var(--text-dim);font-variant-numeric:tabular-nums;white-space:nowrap}.session-item.active .rail-at{color:var(--text-dim)}.unread-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px rgba(var(--accent-rgb),.18)}.be-avatar{position:relative;flex:0 0 auto;width:20px;height:20px;border-radius:6px;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;letter-spacing:.2px;color:var(--be-tone, var(--text-dim));background:color-mix(in srgb,var(--be-tone, var(--text-dim)) 16%,transparent);border:1px solid color-mix(in srgb,var(--be-tone, var(--text-dim)) 40%,transparent)}.be-avatar.be-hermes,.be-card-mark[data-backend=hermes]{--be-tone: #a98bff}.be-avatar.be-qoder,.be-card-mark[data-backend=qoder]{--be-tone: #4f9bf5}.be-avatar.be-mock,.be-card-mark[data-backend=mock]{--be-tone: #94a3b8}.be-avatar img{width:100%;height:100%;object-fit:cover;border-radius:inherit;display:block}.be-avatar .be-dot{position:absolute;right:-2px;bottom:-2px;width:7px;height:7px;border-radius:50%;border:1px solid var(--bg);background:var(--text-dim)}.be-avatar .be-dot.running{background:var(--ok)}.be-avatar.live{animation:rail-live 1.8s ease-in-out infinite}@keyframes rail-live{0%,to{box-shadow:0 0 0 1.5px color-mix(in srgb,var(--ok) 55%,transparent)}50%{box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 10%,transparent)}}@media (prefers-reduced-motion: reduce){.be-avatar.live{animation:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--ok) 55%,transparent)}}.title-input{flex:1 1 auto;min-width:0;font:inherit;font-size:13.5px;color:var(--text);background:var(--bg-panel);border:1px solid var(--accent-dim);border-radius:6px;padding:2px 6px}.title-input:focus{outline:none;border-color:var(--accent)}.row-menu{flex:0 0 auto;opacity:0;transition:opacity .12s}.session-item:hover .row-menu,.session-item.active .row-menu,.session-item:focus-within .row-menu{opacity:1}@media (hover: none){.row-menu{opacity:.7}}.sess-menu{position:fixed;z-index:40;width:max-content;max-width:min(320px,calc(100vw - 12px));background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:5px;display:flex;flex-direction:column;gap:1px}.sess-menu-head{display:flex;align-items:center;gap:8px;padding:6px 7px 8px;margin-bottom:3px;border-bottom:1px solid var(--line)}.sess-menu-title{font-size:12.5px;color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sess-menu-item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 8px;text-align:left;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font:inherit;font-size:13px;cursor:pointer}.sess-menu-item:hover{background:var(--bg-raised);border-color:var(--line)}.sess-menu-item.danger{color:var(--err)}.sess-menu-item.danger:hover{border-color:var(--err);background:rgba(var(--err-rgb),.08)}.sess-menu-item svg{flex:0 0 auto;color:var(--text-dim)}.sess-menu-item.danger svg{color:var(--err)}.bubble-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;background:transparent;border:1px solid transparent;border-radius:6px;color:var(--text-dim);font:inherit;cursor:pointer}.bubble-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--text)}.bubble-btn.copy.ok{color:var(--ok);border-color:var(--ok)}.bubble-btn.copy.no{color:var(--err);border-color:var(--err)}.bubble-btn.speak.on,.bubble-btn.fork:hover{color:var(--accent-text);border-color:var(--accent-dim)}.bubble-btn.fork.failed{color:var(--err);border-color:var(--err)}.bubble-btn.fork.working{opacity:.55}.bubble-btn:disabled{opacity:.55;cursor:default}@media (max-width: 720px){.sess-menu{left:8px!important;right:8px;top:auto!important;bottom:calc(10px + env(safe-area-inset-bottom,0px));width:auto!important;max-width:none;min-width:0}.sess-menu-item{padding:11px 10px;font-size:14px}.session-item{min-height:36px}.bubble-btn{width:34px;height:30px}}.call-mode{position:fixed;inset:0;z-index:60;--bg-panel: rgba(255,255,255,.07);--bg-raised: rgba(255,255,255,.14);--line: rgba(255,255,255,.16);--text: #eef2f7;--text-dim: rgba(238,242,247,.6);--err: #f2555a;--on-accent: #0b1220;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:max(20px,env(safe-area-inset-top)) 18px calc(20px + env(safe-area-inset-bottom));background:radial-gradient(120% 90% at 50% 33%,#111827,#080a12 60%,#05060b);color:var(--text);overflow:hidden;animation:call-in .24s ease-out}@keyframes call-in{0%{opacity:0;transform:scale(1.015)}to{opacity:1;transform:none}}.call-mode[data-phase=connecting]{--call-tone: #7d91c8}.call-mode[data-phase=listening]{--call-tone: #38bdf8}.call-mode[data-phase=thinking]{--call-tone: #a78bfa}.call-mode[data-phase=speaking]{--call-tone: #fbbf24}.call-mode[data-phase=error]{--call-tone: #f87171}.call-mode:before{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(26% 19% at 50% 37%,color-mix(in srgb,var(--call-tone, #38bdf8) 26%,transparent) 0%,transparent 100%),radial-gradient(62% 44% at 50% 37%,color-mix(in srgb,var(--call-tone, #38bdf8) 15%,transparent) 0%,transparent 74%);transition:background .5s ease}.call-head,.call-orb,.call-lines,.call-wave,.call-controls{position:relative}.call-head{display:flex;flex-direction:column;align-items:center;gap:4px}.call-title{font-size:17px;font-weight:600;letter-spacing:.03em;color:var(--call-tone, var(--text));text-shadow:0 0 18px color-mix(in srgb,var(--call-tone, #38bdf8) 45%,transparent)}.call-sub{font-size:11.5px;color:var(--text-dim);letter-spacing:.04em}.call-orb{height:min(46vh,76vw,380px);aspect-ratio:1;flex:0 1 auto;padding:0;border:none;background:transparent;cursor:pointer;-webkit-tap-highlight-color:transparent}.call-orb-canvas{display:block;width:100%;height:100%}.call-orb:focus-visible{outline:2px solid var(--call-tone, var(--accent));outline-offset:6px;border-radius:50%}.call-lines{display:flex;flex-direction:column;align-items:center;gap:6px;width:min(560px,92vw);min-height:60px;flex:0 1 auto;overflow:hidden}.call-heard{margin:0;font-size:15px;line-height:1.45;text-align:center}.call-reply{margin:0;font-size:13.5px;line-height:1.5;color:var(--text-dim);text-align:center;max-height:24vh;overflow-y:auto;white-space:pre-wrap}.call-hint{margin:0;font-size:12.5px;color:var(--text-dim)}.call-err{margin:0;font-size:12.5px;color:var(--err)}.call-note{margin:0;font-size:12.5px;color:var(--warn, #d08a2a)}.call-wave{width:min(420px,80vw);height:46px;display:block;flex:0 1 auto;min-height:34px;border-radius:12px;background:linear-gradient(to bottom,#ffffff03,#ffffff09)}.call-hist{width:min(560px,92vw);flex:0 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--line);border-radius:14px;background:#ffffff0a}.call-hist-bar{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:0 12px;border:0;background:transparent;color:var(--text-dim);cursor:pointer;text-align:left}.call-hist-bar:hover{color:var(--text)}.call-hist-title{font-size:12.5px;color:var(--text)}.call-hist-n{font-size:11.5px;color:var(--text-dim)}.call-hist-peek{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.call-hist-chev{margin-left:auto;display:inline-flex;transition:transform .18s ease}.call-hist[data-open=true] .call-hist-chev{transform:rotate(180deg)}.call-hist-list{flex:1 1 auto;min-height:0;max-height:min(38vh,300px);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:10px 12px 12px;display:flex;flex-direction:column;gap:9px;border-top:1px solid var(--line)}.call-hm{font-size:12.5px;line-height:1.5;color:var(--text)}.call-hm-who{display:block;margin-bottom:2px;font-size:10.5px;letter-spacing:.08em;color:var(--text-dim);opacity:.7}.call-hm.meta,.call-hm.tool{font-size:11.5px;font-style:italic;color:var(--text-dim)}.call-hm.current{border-left:2px solid var(--call-tone, #38bdf8);margin-left:-12px;padding-left:10px}.call-hm .code{margin:4px 0;padding:6px 8px;font-size:11.5px;color:var(--text)}.call-hist-back{align-self:center;margin:0 0 10px;min-height:32px;padding:0 12px;border-radius:999px;border:1px solid var(--line);background:#ffffff0f;color:var(--text);font-size:12px;cursor:pointer}.call-hist-back:hover{background:var(--bg-raised)}.call-modes{display:inline-flex;align-items:center;gap:2px;margin-top:6px;padding:2px;border:1px solid var(--line);border-radius:999px;background:#ffffff0a}.call-mode-btn{min-height:28px;padding:0 11px;border:0;border-radius:999px;cursor:pointer;background:transparent;color:var(--text-dim);font-size:12px;letter-spacing:.02em}.call-mode-btn:hover{color:var(--text)}.call-mode-btn.on{background:var(--call-tone, #38bdf8);color:#0b1220;font-weight:600;box-shadow:0 0 12px color-mix(in srgb,var(--call-tone, #38bdf8) 40%,transparent)}.call-controls{display:flex;align-items:center;gap:16px;margin-top:2px}.call-btn{width:52px;height:52px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text);cursor:pointer}.call-btn:hover{background:var(--bg-raised);border-color:var(--text-dim)}.call-btn.on{background:var(--accent);color:var(--on-accent);border-color:transparent}.call-btn.hangup{width:60px;height:60px;background:var(--err);border-color:transparent;color:#fff}.call-btn.hangup:hover{background:var(--err);filter:brightness(1.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.call-gear{position:absolute;z-index:2;top:max(14px,env(safe-area-inset-top));right:14px;width:38px;height:38px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.call-gear:hover{color:var(--text);background:var(--bg-raised)}.call-cc-btn{position:absolute;z-index:3;top:max(14px,env(safe-area-inset-top));right:60px;width:38px;height:38px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.call-cc-btn:hover{color:var(--text);background:var(--bg-raised)}.call-cc-btn.on{color:#0b1220;background:var(--call-tone, #38bdf8);border-color:transparent}.call-mode[data-caption=true]{gap:10px;padding-top:calc(max(14px,env(safe-area-inset-top)) + 44px)}.call-mode[data-caption=true] .call-gear{z-index:3}.call-mode[data-caption=true] .call-orb{position:absolute;inset:0;z-index:0;width:auto;height:auto;aspect-ratio:auto;pointer-events:none;cursor:default}.call-mode[data-caption=true] .call-orb-canvas{width:100%;height:100%;filter:blur(34px) saturate(1.3) brightness(1.35);transform:scale(1.08)}.call-mode[data-caption=true]:before{z-index:1}.call-mode[data-caption=true] .call-wave{display:none}.call-cc{position:relative;z-index:2;width:min(560px,94vw);flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid rgba(255,255,255,.14);border-radius:18px;background:linear-gradient(180deg,#1218264d,#090c1494);-webkit-backdrop-filter:blur(22px) saturate(1.35);backdrop-filter:blur(22px) saturate(1.35);box-shadow:inset 0 1px #ffffff12,0 20px 60px #0000006b}.call-cc-head{display:flex;align-items:center;gap:10px;padding:7px 12px;border-bottom:1px solid rgba(255,255,255,.07)}.call-cc-head .call-modes{margin-top:0}.call-cc-state{display:inline-flex;align-items:center;gap:7px;min-height:30px;padding:0 4px;border:0;background:transparent;cursor:pointer;color:var(--call-tone, #38bdf8);font-size:12.5px;font-weight:600;letter-spacing:.02em}.call-cc-dot{width:7px;height:7px;border-radius:50%;background:currentColor;box-shadow:0 0 10px currentColor;animation:cc-pulse 2.4s ease-in-out infinite}@keyframes cc-pulse{0%,to{opacity:.5;transform:scale(.8)}50%{opacity:1;transform:scale(1.2)}}.call-cc-n{margin-left:auto;font-size:11.5px;font-variant-numeric:tabular-nums;color:var(--text-dim)}.call-cc-latest{position:absolute;left:50%;bottom:58px;transform:translate(-50%);z-index:3;min-height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--line);background:#141a28d1;color:var(--text);font-size:11.5px;cursor:pointer;backdrop-filter:blur(8px)}.call-cc-latest:hover{background:var(--bg-raised)}.call-cc-list{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:12px 14px 16px;display:flex;flex-direction:column;gap:12px}.call-cc-inner{display:flex;flex-direction:column}.call-cc-inner .msg{margin-bottom:13px}.call-cc-inner .msg:last-child{margin-bottom:2px}.call-cc-inner .msg .role{color:#ffffff85}.call-cc-inner .msg .bubble{color:#fffffff2}.call-cc-inner .msg.user .bubble{background:#ffffff12;border:1px solid rgba(255,255,255,.09)}.call-cc-inner .msg.agent .bubble{background:transparent;border:0}.call-cc-inner .msg.meta .bubble{color:#fca5a5;background:#f871711a}.call-cc-inner .tool-card,.call-cc-inner .plan-card,.call-cc-inner .thought .bubble{background:#ffffff0b;border-color:#ffffff17}.call-floor-row{flex:0 0 auto;display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:8px 10px;border-top:1px solid rgba(255,255,255,.09)}.call-floor-row.single{grid-template-columns:1fr}.call-floor{flex:0 0 auto;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:46px;margin:0;padding:0 12px;border:0;border-radius:12px;background:#ffffff0d;color:var(--text);font-size:14px;font-weight:650;letter-spacing:.01em;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation;user-select:none;-webkit-user-select:none}.call-floor:hover:not(:disabled){background:#ffffff17}.call-floor.is-take{background:color-mix(in srgb,var(--call-tone, #fbbf24) 88%,#000);color:#0b1220}.call-floor.is-take:hover{background:var(--call-tone, #fbbf24)}.call-floor.is-send{background:color-mix(in srgb,var(--call-tone, #38bdf8) 88%,#000);color:#0b1220}.call-floor.is-send:hover{background:var(--call-tone, #38bdf8)}.call-floor.is-retry{background:#ffffff1a}.call-floor:disabled{color:var(--text-dim);background:#ffffff08;cursor:default}.call-floor.is-done{background:color-mix(in srgb,var(--call-tone, #38bdf8) 80%,#000);color:#0b1220}.call-floor.is-done:hover{background:var(--call-tone, #38bdf8)}.call-floor.is-ptt{background:#ffffff17}.call-floor.is-ptt.on{background:color-mix(in srgb,var(--call-tone, #38bdf8) 82%,#000);color:#0b1220;box-shadow:0 0 0 2px color-mix(in srgb,var(--call-tone, #38bdf8) 45%,transparent)}.call-cc-list .call-hm{font-size:13.5px;line-height:1.62}.call-cc-list .call-hm.meta,.call-cc-list .call-hm.tool{font-size:12px}.call-cc-list .call-hint,.call-cc-list .call-err,.call-cc-list .call-note{margin:0}.call-hm.live .call-hm-who:after{content:" · 在说";color:var(--call-tone, #38bdf8)}.call-sheet{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;padding:16px;background:#04060cbd;animation:call-in .16s ease-out}.call-sheet-card{width:min(460px,100%);max-height:88%;overflow-y:auto;display:flex;flex-direction:column;gap:14px;padding:16px;border:1px solid var(--line);border-radius:18px;background:#0d1220;box-shadow:0 24px 60px #0000008c}.call-sheet-head{display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600}.call-sheet-x{width:30px;height:30px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:transparent;color:var(--text-dim);cursor:pointer}.call-sheet-note{margin:0;font-size:11.5px;line-height:1.5;color:var(--text-dim)}.call-knob{display:flex;flex-direction:column;gap:4px}.call-knob-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.call-knob-name{font-size:13.5px}.call-knob-val{font-size:13px;font-variant-numeric:tabular-nums;color:var(--call-tone, #38bdf8)}.call-knob input[type=range]{width:100%;height:30px;accent-color:var(--call-tone, #38bdf8);background:transparent;cursor:pointer}.call-knob-ends{display:flex;justify-content:space-between;font-size:10.5px;color:var(--text-dim)}.call-knob-hint{font-size:11px;line-height:1.45;color:var(--text-dim)}.call-knob.off{opacity:.45}.call-knob.off input[type=range]{cursor:not-allowed}.call-sheet-warn{margin:0;padding:9px 11px;border-radius:10px;font-size:11.5px;line-height:1.5;border:1px solid color-mix(in srgb,var(--call-tone, #38bdf8) 35%,transparent);background:color-mix(in srgb,var(--call-tone, #38bdf8) 12%,transparent);color:var(--text)}.call-sheet-echo{margin:0;font-size:11.5px;line-height:1.5;color:var(--text-dim)}.call-sheet-echo.bad{color:#fbbf24}.call-sheet-foot{display:flex;gap:10px;justify-content:flex-end;margin-top:2px}.call-sheet-btn{min-height:40px;padding:0 14px;border-radius:10px;font-size:13px;border:1px solid var(--line);background:transparent;color:var(--text);cursor:pointer}.call-sheet-btn:hover{background:var(--bg-raised)}.call-sheet-btn.primary{background:var(--call-tone, #38bdf8);border-color:transparent;color:#0b1220;font-weight:600}@media (max-width: 720px){.call-mode{gap:8px}.call-sheet{align-items:flex-end;padding:0}.call-sheet-card{width:100%;max-height:84%;border-radius:20px 20px 0 0;padding-bottom:calc(16px + env(safe-area-inset-bottom))}.call-gear{width:42px;height:42px}.call-cc-btn{width:42px;height:42px;right:64px}.call-mode[data-caption=true]{padding-top:calc(max(14px,env(safe-area-inset-top)) + 48px)}.call-cc-head .call-mode-btn{min-height:26px;padding:0 9px;font-size:11.5px}.call-cc-head .call-cc-state{font-size:12px;gap:6px}.call-cc{width:94vw;border-radius:16px}.call-cc-head{padding:5px 10px;gap:8px}.call-cc-list{padding:10px 12px 14px;gap:11px}.call-cc-list .call-hm{font-size:13px}.call-floor{min-height:48px;font-size:14px}.call-floor span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.call-cc-inner .msg .bubble{font-size:13.5px;padding:9px 12px}.call-knob input[type=range]{height:34px}.call-orb{height:min(42vh,72vw,300px)}.call-lines{min-height:88px}.call-reply{max-height:20vh}.call-hist-list{max-height:min(30vh,240px)}.call-hist-peek{display:none}.call-btn{width:56px;height:56px}.call-btn.hangup{width:64px;height:64px}}@media (prefers-reduced-motion: reduce){.call-mode,.call-cc-dot{animation:none}}.be-list{display:flex;flex-direction:column;gap:8px;margin-top:12px}.be-row{display:flex;gap:12px;align-items:flex-start;justify-content:space-between;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:10px 12px}.be-row-main{min-width:0;display:flex;flex-direction:column;gap:3px}.be-row-title{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:13px}.be-row-sub{font-size:11.5px;color:var(--text-dim);font-family:var(--mono);word-break:break-all}.be-row-note{font-size:11.5px;color:var(--text-dim)}.be-kind-help{display:block;margin:6px 0 0;padding:8px 10px;border-left:2px solid var(--accent-dim);background:var(--chip-bg);border-radius:0 8px 8px 0;line-height:1.75}.be-kind-help b{color:var(--text)}.be-kind-help code{font-size:11px}.be-row-actions{display:flex;gap:6px;flex-shrink:0;flex-wrap:wrap}.be-badge{font-size:10.5px;padding:1px 6px;border-radius:999px;border:1px solid var(--line);color:var(--text-dim);background:var(--chip-bg)}.be-badge.be-warn{color:var(--accent);border-color:var(--accent-dim)}.be-badge.be-danger,.be-danger{color:var(--err)}.be-badge.be-dim{opacity:.75}.be-badge.be-ok{color:var(--ok, #3fb950);border-color:var(--ok, #3fb950)}.be-health{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:5px;font-size:11.5px}.be-code{font-family:var(--mono);font-size:10.5px;padding:0 4px;border:1px solid var(--line);border-radius:4px;color:var(--text-dim)}.be-guidance{flex-basis:100%;color:var(--text-dim);font-size:11.5px}.be-handshake{margin-top:4px;font-size:11.5px;color:var(--text-dim)}.be-handshake code{font-family:var(--mono)}.be-dim{color:var(--text-dim);font-size:11.5px}.hint-warn{color:var(--accent);font-size:11.5px;margin-top:4px}.be-hint{display:block}.be-hint code,.be-inspect code,.be-inspect-out{font-family:var(--mono)}.be-hint code{word-break:break-all}.be-inspect{margin-top:12px;border:1px dashed var(--line);border-radius:10px;padding:10px 12px;font-size:12px;background:var(--bg-raised)}.be-inspect-head{display:flex;justify-content:space-between;align-items:center;gap:8px}.be-inspect ul{margin:8px 0 0;padding-left:18px;display:flex;flex-direction:column;gap:4px}.be-inspect-out{margin-top:4px;font-size:11px;color:var(--text-dim);white-space:pre-wrap;word-break:break-all}.be-backdrop{position:fixed;inset:0;z-index:60;background:#00000073;display:flex;align-items:center;justify-content:center;padding:20px}.be-modal{background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;width:min(560px,100%);max-height:min(86vh,780px);display:flex;flex-direction:column;box-shadow:0 18px 48px #00000080}.be-modal-head{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--line);font-size:13.5px}.be-modal-head b{font-size:13.5px}.be-modal-head code{font-family:var(--mono);font-size:11.5px;color:var(--text-dim)}.be-modal-x{margin-left:auto}.be-modal-body{overflow:auto;overscroll-behavior:contain;padding:2px 16px 14px}.be-modal-foot{display:flex;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--line)}.be-modal-foot button{flex:0 0 auto;white-space:nowrap}.be-modal-foot .set-mini{margin-left:auto}.be-modal-err{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--err);border:none;padding:0;background:none}@media (max-width: 720px){.be-backdrop{padding:0;align-items:flex-end}.be-modal{width:100%;max-height:92vh;border-radius:14px 14px 0 0}}@media (max-width: 720px){.be-row{flex-direction:column}}