@songsid/agend 2.3.0-beta.9 → 2.3.0

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.
Files changed (723) hide show
  1. package/README.md +16 -8
  2. package/README.zh-TW.md +16 -8
  3. package/dist/adapter-world.js.map +1 -1
  4. package/dist/agend-home.d.ts +5 -0
  5. package/dist/agend-home.js +7 -0
  6. package/dist/agend-home.js.map +1 -0
  7. package/dist/agent-cli-instructions.md +7 -1
  8. package/dist/agent-cli.js +41 -0
  9. package/dist/agent-cli.js.map +1 -1
  10. package/dist/agent-endpoint.d.ts +9 -0
  11. package/dist/agent-endpoint.js +23 -0
  12. package/dist/agent-endpoint.js.map +1 -1
  13. package/dist/agent-file-read.js +1 -1
  14. package/dist/agent-file-read.js.map +1 -1
  15. package/dist/agent-whats-new.d.ts +16 -0
  16. package/dist/agent-whats-new.js +53 -12
  17. package/dist/agent-whats-new.js.map +1 -1
  18. package/dist/apply-job.js.map +1 -1
  19. package/dist/atomic-write.js.map +1 -1
  20. package/dist/auth-api.d.ts +12 -0
  21. package/dist/auth-api.js +77 -22
  22. package/dist/auth-api.js.map +1 -1
  23. package/dist/authority/authority-state.d.ts +4 -0
  24. package/dist/authority/authority-state.js +17 -8
  25. package/dist/authority/authority-state.js.map +1 -1
  26. package/dist/authority/session-authorizations.js.map +1 -1
  27. package/dist/authority/web-authority.d.ts +16 -8
  28. package/dist/authority/web-authority.js +19 -5
  29. package/dist/authority/web-authority.js.map +1 -1
  30. package/dist/backend/antigravity.d.ts +2 -2
  31. package/dist/backend/antigravity.js +2 -1
  32. package/dist/backend/antigravity.js.map +1 -1
  33. package/dist/backend/claude-code.js +13 -4
  34. package/dist/backend/claude-code.js.map +1 -1
  35. package/dist/backend/codex-metadata.d.ts +8 -0
  36. package/dist/backend/codex-metadata.js +74 -17
  37. package/dist/backend/codex-metadata.js.map +1 -1
  38. package/dist/backend/codex-package.d.ts +30 -0
  39. package/dist/backend/codex-package.js +133 -0
  40. package/dist/backend/codex-package.js.map +1 -0
  41. package/dist/backend/codex-session-lookup.js.map +1 -1
  42. package/dist/backend/codex.d.ts +2 -0
  43. package/dist/backend/codex.js +25 -5
  44. package/dist/backend/codex.js.map +1 -1
  45. package/dist/backend/credential-profile.d.ts +2 -0
  46. package/dist/backend/credential-profile.js +2 -0
  47. package/dist/backend/credential-profile.js.map +1 -1
  48. package/dist/backend/effort-metadata.js.map +1 -1
  49. package/dist/backend/grok.js +58 -3
  50. package/dist/backend/grok.js.map +1 -1
  51. package/dist/backend/kiro-engine-ledger.js.map +1 -1
  52. package/dist/backend/kiro-kas-store.js.map +1 -1
  53. package/dist/backend/kiro-v2-store.js.map +1 -1
  54. package/dist/backend/kiro-v3-identity.js.map +1 -1
  55. package/dist/backend/kiro.d.ts +9 -1
  56. package/dist/backend/kiro.js +102 -1
  57. package/dist/backend/kiro.js.map +1 -1
  58. package/dist/backend/launch-effort.js.map +1 -1
  59. package/dist/backend/mock.js.map +1 -1
  60. package/dist/backend/muse.js.map +1 -1
  61. package/dist/backend/opencode-permission.js +1 -1
  62. package/dist/backend/opencode-permission.js.map +1 -1
  63. package/dist/backend/opencode.js +2 -1
  64. package/dist/backend/opencode.js.map +1 -1
  65. package/dist/backend/session-signals.js.map +1 -1
  66. package/dist/backend-availability.js.map +1 -1
  67. package/dist/backend-command.d.ts +2 -0
  68. package/dist/backend-command.js +3 -1
  69. package/dist/backend-command.js.map +1 -1
  70. package/dist/backend-outage.js.map +1 -1
  71. package/dist/binary-probe.js +1 -1
  72. package/dist/binary-probe.js.map +1 -1
  73. package/dist/bug-report-cli.d.ts +30 -0
  74. package/dist/bug-report-cli.js +139 -0
  75. package/dist/bug-report-cli.js.map +1 -0
  76. package/dist/bug-report.d.ts +47 -0
  77. package/dist/bug-report.js +137 -0
  78. package/dist/bug-report.js.map +1 -0
  79. package/dist/bundled-skills.d.ts +18 -0
  80. package/dist/bundled-skills.js +38 -0
  81. package/dist/bundled-skills.js.map +1 -0
  82. package/dist/cache-service.js +1 -1
  83. package/dist/cache-service.js.map +1 -1
  84. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  85. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  86. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  87. package/dist/channel/adapters/discord.d.ts +4 -0
  88. package/dist/channel/adapters/discord.js +57 -12
  89. package/dist/channel/adapters/discord.js.map +1 -1
  90. package/dist/channel/adapters/telegram.d.ts +6 -0
  91. package/dist/channel/adapters/telegram.js +54 -14
  92. package/dist/channel/adapters/telegram.js.map +1 -1
  93. package/dist/channel/mcp-server.js +21 -4
  94. package/dist/channel/mcp-server.js.map +1 -1
  95. package/dist/channel/mcp-tools.d.ts +3 -1
  96. package/dist/channel/mcp-tools.js +41 -4
  97. package/dist/channel/mcp-tools.js.map +1 -1
  98. package/dist/channel/message-queue.js.map +1 -1
  99. package/dist/channel/sticker-download.js.map +1 -1
  100. package/dist/channel/tool-router.js.map +1 -1
  101. package/dist/child-process.d.ts +21 -0
  102. package/dist/child-process.js +54 -0
  103. package/dist/child-process.js.map +1 -0
  104. package/dist/classic-channel-manager.js +3 -2
  105. package/dist/classic-channel-manager.js.map +1 -1
  106. package/dist/cli-entry.js.map +1 -1
  107. package/dist/cli-flags.js.map +1 -1
  108. package/dist/cli.d.ts +1 -0
  109. package/dist/cli.js +443 -311
  110. package/dist/cli.js.map +1 -1
  111. package/dist/command-table.d.ts +1 -1
  112. package/dist/command-table.js +1 -1
  113. package/dist/command-table.js.map +1 -1
  114. package/dist/compact-watch.js.map +1 -1
  115. package/dist/completion-install.js.map +1 -1
  116. package/dist/completion.js.map +1 -1
  117. package/dist/config-validator.d.ts +6 -0
  118. package/dist/config-validator.js +81 -8
  119. package/dist/config-validator.js.map +1 -1
  120. package/dist/config.d.ts +15 -3
  121. package/dist/config.js +41 -10
  122. package/dist/config.js.map +1 -1
  123. package/dist/connection-secrets.js.map +1 -1
  124. package/dist/context-guardian.js.map +1 -1
  125. package/dist/coredump-filter.js.map +1 -1
  126. package/dist/cpu-profile.js.map +1 -1
  127. package/dist/cross-instance-envelope.js.map +1 -1
  128. package/dist/cross-instance-notice.d.ts +7 -0
  129. package/dist/cross-instance-notice.js +10 -0
  130. package/dist/cross-instance-notice.js.map +1 -1
  131. package/dist/daemon.d.ts +39 -1
  132. package/dist/daemon.js +234 -15
  133. package/dist/daemon.js.map +1 -1
  134. package/dist/daily-summary.js.map +1 -1
  135. package/dist/darwin-memory.js +1 -1
  136. package/dist/darwin-memory.js.map +1 -1
  137. package/dist/dashboard-live.d.ts +8 -0
  138. package/dist/dashboard-live.js +35 -0
  139. package/dist/dashboard-live.js.map +1 -0
  140. package/dist/dashboard-permissions.d.ts +69 -0
  141. package/dist/dashboard-permissions.js +138 -0
  142. package/dist/dashboard-permissions.js.map +1 -0
  143. package/dist/decision-list.js.map +1 -1
  144. package/dist/delivery-consumed-watch.js.map +1 -1
  145. package/dist/delivery-outbox.js +5 -0
  146. package/dist/delivery-outbox.js.map +1 -1
  147. package/dist/delivery-outbox.test.js.map +1 -1
  148. package/dist/delivery-reconciliation.test.js.map +1 -1
  149. package/dist/diagnostic-redaction.d.ts +10 -0
  150. package/dist/diagnostic-redaction.js +167 -0
  151. package/dist/diagnostic-redaction.js.map +1 -0
  152. package/dist/doctor.d.ts +8 -0
  153. package/dist/doctor.js +52 -0
  154. package/dist/doctor.js.map +1 -1
  155. package/dist/e2e-isolation.js.map +1 -1
  156. package/dist/event-log.js.map +1 -1
  157. package/dist/export-import.js +7 -5
  158. package/dist/export-import.js.map +1 -1
  159. package/dist/fleet-control-audit.js.map +1 -1
  160. package/dist/fleet-label.js.map +1 -1
  161. package/dist/fleet-level-config.d.ts +1 -1
  162. package/dist/fleet-level-config.js +2 -0
  163. package/dist/fleet-level-config.js.map +1 -1
  164. package/dist/fleet-lock.js +3 -2
  165. package/dist/fleet-lock.js.map +1 -1
  166. package/dist/fleet-manager.d.ts +249 -13
  167. package/dist/fleet-manager.js +1561 -292
  168. package/dist/fleet-manager.js.map +1 -1
  169. package/dist/fleet-process-handlers.d.ts +18 -0
  170. package/dist/fleet-process-handlers.js +70 -0
  171. package/dist/fleet-process-handlers.js.map +1 -0
  172. package/dist/fleet-startup.d.ts +14 -0
  173. package/dist/fleet-startup.js +30 -0
  174. package/dist/fleet-startup.js.map +1 -0
  175. package/dist/fleet-traffic.js.map +1 -1
  176. package/dist/forged-envelope-scan.d.ts +0 -20
  177. package/dist/forged-envelope-scan.js +3 -2
  178. package/dist/forged-envelope-scan.js.map +1 -1
  179. package/dist/full-restart.d.ts +5 -5
  180. package/dist/full-restart.js +5 -5
  181. package/dist/full-restart.js.map +1 -1
  182. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  183. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  184. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  185. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  186. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  187. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  188. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  189. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  190. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  191. package/dist/general-knowledge/skills/web-appearance/SKILL.md +24 -4
  192. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  193. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +154 -31
  194. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  195. package/dist/general-knowledge/steering/core-rules.md +1 -1
  196. package/dist/host-memory.js.map +1 -1
  197. package/dist/idle-gate-log.d.ts +19 -0
  198. package/dist/idle-gate-log.js +15 -0
  199. package/dist/idle-gate-log.js.map +1 -0
  200. package/dist/instance-config-impact.js +25 -4
  201. package/dist/instance-config-impact.js.map +1 -1
  202. package/dist/instance-lifecycle.d.ts +10 -1
  203. package/dist/instance-lifecycle.js +86 -25
  204. package/dist/instance-lifecycle.js.map +1 -1
  205. package/dist/instructions.d.ts +12 -6
  206. package/dist/instructions.js +19 -10
  207. package/dist/instructions.js.map +1 -1
  208. package/dist/kiro-compact-pane.js.map +1 -1
  209. package/dist/kiro-db-reader.js.map +1 -1
  210. package/dist/kiro-engine-status.js.map +1 -1
  211. package/dist/kiro-log-gate.js.map +1 -1
  212. package/dist/kiro-transcript-lane.js.map +1 -1
  213. package/dist/locale.js +428 -20
  214. package/dist/locale.js.map +1 -1
  215. package/dist/log-service.js.map +1 -1
  216. package/dist/log-steps.d.ts +1 -0
  217. package/dist/log-steps.js +15 -0
  218. package/dist/log-steps.js.map +1 -1
  219. package/dist/logger.js +3 -2
  220. package/dist/logger.js.map +1 -1
  221. package/dist/login-controller.d.ts +45 -0
  222. package/dist/login-controller.js +101 -5
  223. package/dist/login-controller.js.map +1 -1
  224. package/dist/login-flows.js +1 -1
  225. package/dist/login-manager.js.map +1 -1
  226. package/dist/login-shell.js +3 -1
  227. package/dist/login-shell.js.map +1 -1
  228. package/dist/ls-attach-resolve.d.ts +96 -0
  229. package/dist/ls-attach-resolve.js +180 -0
  230. package/dist/ls-attach-resolve.js.map +1 -0
  231. package/dist/ls-rows.d.ts +12 -0
  232. package/dist/ls-rows.js +83 -4
  233. package/dist/ls-rows.js.map +1 -1
  234. package/dist/memory-pressure.js.map +1 -1
  235. package/dist/muse-usage-relay.js.map +1 -1
  236. package/dist/needs-you-hub.d.ts +98 -1
  237. package/dist/needs-you-hub.js +313 -44
  238. package/dist/needs-you-hub.js.map +1 -1
  239. package/dist/needs-you-live.d.ts +5 -2
  240. package/dist/needs-you-live.js +6 -3
  241. package/dist/needs-you-live.js.map +1 -1
  242. package/dist/needs-you.d.ts +68 -3
  243. package/dist/needs-you.js +38 -4
  244. package/dist/needs-you.js.map +1 -1
  245. package/dist/network-family.js.map +1 -1
  246. package/dist/operator-control-paths.js +3 -4
  247. package/dist/operator-control-paths.js.map +1 -1
  248. package/dist/outbound-handlers.d.ts +3 -0
  249. package/dist/outbound-handlers.js +76 -19
  250. package/dist/outbound-handlers.js.map +1 -1
  251. package/dist/outbound-schemas.d.ts +106 -60
  252. package/dist/outbound-schemas.js +33 -10
  253. package/dist/outbound-schemas.js.map +1 -1
  254. package/dist/outbox-open-error.js.map +1 -1
  255. package/dist/pane-context-cache.js.map +1 -1
  256. package/dist/paths.js.map +1 -1
  257. package/dist/private-dir.js.map +1 -1
  258. package/dist/probe-worker-pool.js.map +1 -1
  259. package/dist/profile-control.js.map +1 -1
  260. package/dist/prompt-file-ref.js.map +1 -1
  261. package/dist/provider-probe.js.map +1 -1
  262. package/dist/provider-secret-registry.d.ts +5 -3
  263. package/dist/provider-secret-registry.js +8 -2
  264. package/dist/provider-secret-registry.js.map +1 -1
  265. package/dist/public-link-auto-open.d.ts +32 -0
  266. package/dist/public-link-auto-open.js +86 -0
  267. package/dist/public-link-auto-open.js.map +1 -0
  268. package/dist/public-link-owner.d.ts +10 -0
  269. package/dist/public-link-owner.js +36 -0
  270. package/dist/public-link-owner.js.map +1 -0
  271. package/dist/public-link-progress.d.ts +12 -1
  272. package/dist/public-link-progress.js +5 -10
  273. package/dist/public-link-progress.js.map +1 -1
  274. package/dist/public-preview.js.map +1 -1
  275. package/dist/public-tunnel-config.d.ts +11 -0
  276. package/dist/public-tunnel-config.js +68 -0
  277. package/dist/public-tunnel-config.js.map +1 -0
  278. package/dist/public-web-gateway.d.ts +2 -0
  279. package/dist/public-web-gateway.js +19 -6
  280. package/dist/public-web-gateway.js.map +1 -1
  281. package/dist/public-web-link.d.ts +48 -3
  282. package/dist/public-web-link.js +177 -51
  283. package/dist/public-web-link.js.map +1 -1
  284. package/dist/quickstart-api.d.ts +9 -0
  285. package/dist/quickstart-api.js +82 -0
  286. package/dist/quickstart-api.js.map +1 -1
  287. package/dist/quickstart.d.ts +5 -0
  288. package/dist/quickstart.js +40 -25
  289. package/dist/quickstart.js.map +1 -1
  290. package/dist/reply-buttons-controller.js.map +1 -1
  291. package/dist/reply-dedup.js.map +1 -1
  292. package/dist/resource-report.js +1 -1
  293. package/dist/resource-report.js.map +1 -1
  294. package/dist/restart-guard.js.map +1 -1
  295. package/dist/restart-progress.d.ts +80 -1
  296. package/dist/restart-progress.js +306 -21
  297. package/dist/restart-progress.js.map +1 -1
  298. package/dist/rollout-index.js.map +1 -1
  299. package/dist/runtime-cpu-profile.js.map +1 -1
  300. package/dist/scheduler/db.d.ts +40 -13
  301. package/dist/scheduler/db.js +123 -89
  302. package/dist/scheduler/db.js.map +1 -1
  303. package/dist/scheduler/scheduler.js.map +1 -1
  304. package/dist/scheduler/task-board-text.d.ts +26 -0
  305. package/dist/scheduler/task-board-text.js +140 -0
  306. package/dist/scheduler/task-board-text.js.map +1 -0
  307. package/dist/scheduler/task-board.d.ts +730 -0
  308. package/dist/scheduler/task-board.js +2179 -0
  309. package/dist/scheduler/task-board.js.map +1 -0
  310. package/dist/scheduler/types.d.ts +6 -1
  311. package/dist/sd-notify.js +2 -1
  312. package/dist/sd-notify.js.map +1 -1
  313. package/dist/search/search-docs.d.ts +58 -0
  314. package/dist/search/search-docs.js +63 -0
  315. package/dist/search/search-docs.js.map +1 -0
  316. package/dist/search/search-index.d.ts +141 -0
  317. package/dist/search/search-index.js +440 -0
  318. package/dist/search/search-index.js.map +1 -0
  319. package/dist/search/search-store.d.ts +122 -0
  320. package/dist/search/search-store.js +236 -0
  321. package/dist/search/search-store.js.map +1 -0
  322. package/dist/search/search-worker.d.ts +1 -0
  323. package/dist/search/search-worker.js +163 -0
  324. package/dist/search/search-worker.js.map +1 -0
  325. package/dist/secret-file.js.map +1 -1
  326. package/dist/secret-store.d.ts +2 -0
  327. package/dist/secret-store.js +21 -0
  328. package/dist/secret-store.js.map +1 -1
  329. package/dist/service-installer.d.ts +75 -0
  330. package/dist/service-installer.js +206 -0
  331. package/dist/service-installer.js.map +1 -1
  332. package/dist/service-owner.d.ts +44 -0
  333. package/dist/service-owner.js +48 -0
  334. package/dist/service-owner.js.map +1 -0
  335. package/dist/service-plan.d.ts +39 -2
  336. package/dist/service-plan.js +188 -6
  337. package/dist/service-plan.js.map +1 -1
  338. package/dist/session-oom.d.ts +21 -0
  339. package/dist/session-oom.js +139 -0
  340. package/dist/session-oom.js.map +1 -0
  341. package/dist/settings-api.d.ts +13 -0
  342. package/dist/settings-api.js +73 -12
  343. package/dist/settings-api.js.map +1 -1
  344. package/dist/settings-baseline.js.map +1 -1
  345. package/dist/settings-change.d.ts +5 -0
  346. package/dist/settings-change.js +167 -6
  347. package/dist/settings-change.js.map +1 -1
  348. package/dist/settings-confirmation.d.ts +9 -1
  349. package/dist/settings-confirmation.js +18 -8
  350. package/dist/settings-confirmation.js.map +1 -1
  351. package/dist/settings-control.js +2 -1
  352. package/dist/settings-control.js.map +1 -1
  353. package/dist/settings-effect.js +29 -4
  354. package/dist/settings-effect.js.map +1 -1
  355. package/dist/settings-http-confirmation.d.ts +13 -0
  356. package/dist/settings-http-confirmation.js +15 -3
  357. package/dist/settings-http-confirmation.js.map +1 -1
  358. package/dist/settings-instance-patch.js +13 -1
  359. package/dist/settings-instance-patch.js.map +1 -1
  360. package/dist/settings-request-capability.d.ts +4 -1
  361. package/dist/settings-request-capability.js +11 -3
  362. package/dist/settings-request-capability.js.map +1 -1
  363. package/dist/settings-transaction.js.map +1 -1
  364. package/dist/setup-auth.d.ts +1 -0
  365. package/dist/setup-auth.js +2 -1
  366. package/dist/setup-auth.js.map +1 -1
  367. package/dist/setup-form.d.ts +1 -1
  368. package/dist/setup-form.js +23 -7
  369. package/dist/setup-form.js.map +1 -1
  370. package/dist/setup-host.d.ts +6 -1
  371. package/dist/setup-host.js +15 -4
  372. package/dist/setup-host.js.map +1 -1
  373. package/dist/setup-wizard.js +6 -3
  374. package/dist/setup-wizard.js.map +1 -1
  375. package/dist/spawn-gate.d.ts +5 -0
  376. package/dist/spawn-gate.js +28 -8
  377. package/dist/spawn-gate.js.map +1 -1
  378. package/dist/start-attempt.d.ts +1 -0
  379. package/dist/start-attempt.js +18 -0
  380. package/dist/start-attempt.js.map +1 -0
  381. package/dist/start-failure-notice.d.ts +4 -0
  382. package/dist/start-failure-notice.js +20 -0
  383. package/dist/start-failure-notice.js.map +1 -0
  384. package/dist/start-failure.d.ts +147 -0
  385. package/dist/start-failure.js +281 -0
  386. package/dist/start-failure.js.map +1 -0
  387. package/dist/startup-memory-deadline.d.ts +23 -0
  388. package/dist/startup-memory-deadline.js +55 -0
  389. package/dist/startup-memory-deadline.js.map +1 -0
  390. package/dist/statusline-watcher.js.map +1 -1
  391. package/dist/storm-window.js.map +1 -1
  392. package/dist/systemd-peer-bus.js.map +1 -1
  393. package/dist/target-queue-worker.js.map +1 -1
  394. package/dist/task-board-summary.d.ts +101 -0
  395. package/dist/task-board-summary.js +177 -0
  396. package/dist/task-board-summary.js.map +1 -0
  397. package/dist/task-board-tool.d.ts +25 -0
  398. package/dist/task-board-tool.js +155 -0
  399. package/dist/task-board-tool.js.map +1 -0
  400. package/dist/task-board-waker.d.ts +51 -0
  401. package/dist/task-board-waker.js +141 -0
  402. package/dist/task-board-waker.js.map +1 -0
  403. package/dist/tips.js.map +1 -1
  404. package/dist/tmux-control.js +1 -1
  405. package/dist/tmux-control.js.map +1 -1
  406. package/dist/tmux-exec-helper.d.ts +104 -0
  407. package/dist/tmux-exec-helper.js +412 -0
  408. package/dist/tmux-exec-helper.js.map +1 -0
  409. package/dist/tmux-manager.d.ts +1 -0
  410. package/dist/tmux-manager.js +29 -13
  411. package/dist/tmux-manager.js.map +1 -1
  412. package/dist/tmux-read.js +2 -2
  413. package/dist/tmux-read.js.map +1 -1
  414. package/dist/tool-permissions.js.map +1 -1
  415. package/dist/tool-progress.js.map +1 -1
  416. package/dist/topic-archiver.js.map +1 -1
  417. package/dist/topic-commands.d.ts +13 -0
  418. package/dist/topic-commands.js +56 -33
  419. package/dist/topic-commands.js.map +1 -1
  420. package/dist/topic-link.js.map +1 -1
  421. package/dist/transcript-delta-reader.js.map +1 -1
  422. package/dist/transcript-jsonl.js.map +1 -1
  423. package/dist/transcript-monitor.js +5 -0
  424. package/dist/transcript-monitor.js.map +1 -1
  425. package/dist/transcript-sources.d.ts +2 -0
  426. package/dist/transcript-sources.js +4 -0
  427. package/dist/transcript-sources.js.map +1 -1
  428. package/dist/tunnel/cloudflared-install.js +3 -1
  429. package/dist/tunnel/cloudflared-install.js.map +1 -1
  430. package/dist/tunnel/cloudflared.d.ts +7 -16
  431. package/dist/tunnel/cloudflared.js +100 -13
  432. package/dist/tunnel/cloudflared.js.map +1 -1
  433. package/dist/tunnel/lease.js +3 -2
  434. package/dist/tunnel/lease.js.map +1 -1
  435. package/dist/tunnel/manager.js.map +1 -1
  436. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  437. package/dist/tunnel/named-diagnostics.js +52 -0
  438. package/dist/tunnel/named-diagnostics.js.map +1 -0
  439. package/dist/tunnel/public-fetch.js.map +1 -1
  440. package/dist/tunnel/purpose-lane.js.map +1 -1
  441. package/dist/tunnel/types.d.ts +4 -1
  442. package/dist/tunnel/types.js.map +1 -1
  443. package/dist/types.d.ts +55 -2
  444. package/dist/ui/app-effects.js +23 -5
  445. package/dist/ui/app.html +2 -0
  446. package/dist/ui/backend-signin.js +297 -0
  447. package/dist/ui/chat-effects.js +10 -3
  448. package/dist/ui/chat-msg-actions.js +176 -0
  449. package/dist/ui/chat-render.js +62 -18
  450. package/dist/ui/chat-store.js +218 -48
  451. package/dist/ui/chat-strings.js +40 -8
  452. package/dist/ui/chat-thread.js +119 -10
  453. package/dist/ui/effect-trial-offer.js +2 -31
  454. package/dist/ui/effects-waker.js +2 -0
  455. package/dist/ui/fleet-canvas-layout.js +13 -4
  456. package/dist/ui/fleet-canvas.js +69 -28
  457. package/dist/ui/fleet-office-editor.js +149 -0
  458. package/dist/ui/fleet-office-model.js +358 -0
  459. package/dist/ui/fleet-office-pack.js +199 -0
  460. package/dist/ui/fleet-office-skin.js +474 -0
  461. package/dist/ui/fleet-office-store.js +49 -0
  462. package/dist/ui/fleet-office-zones.js +177 -0
  463. package/dist/ui/fleet-office.js +434 -0
  464. package/dist/ui/fleet-org.js +18 -5
  465. package/dist/ui/fleet-route-scene.js +272 -0
  466. package/dist/ui/fleet-route-worker.js +21 -0
  467. package/dist/ui/fleet-route.js +88 -0
  468. package/dist/ui/fleet-task-card.js +436 -0
  469. package/dist/ui/fleet-task-common.js +482 -0
  470. package/dist/ui/fleet-task-work.js +107 -0
  471. package/dist/ui/fleet-tasks.js +569 -0
  472. package/dist/ui/fleet-traffic.js +81 -18
  473. package/dist/ui/fleet-usage.js +36 -2
  474. package/dist/ui/guest-refused.html +41 -0
  475. package/dist/ui/icons/icon-192.png +0 -0
  476. package/dist/ui/icons/icon-512.png +0 -0
  477. package/dist/ui/image-lightbox.js +45 -1
  478. package/dist/ui/image-zoom.js +242 -0
  479. package/dist/ui/panel-chat.js +200 -56
  480. package/dist/ui/panel-details.js +2 -0
  481. package/dist/ui/panel-fleet.js +32 -71
  482. package/dist/ui/panel-needs.js +23 -6
  483. package/dist/ui/panel-settings.js +158 -32
  484. package/dist/ui/preview-panel.js +2 -1
  485. package/dist/ui/search-dialog.js +350 -0
  486. package/dist/ui/settings-appearance.js +170 -10
  487. package/dist/ui/settings-apply.js +3 -3
  488. package/dist/ui/settings-confirm.js +7 -2
  489. package/dist/ui/settings-dialogs.js +46 -21
  490. package/dist/ui/settings-discord.js +6 -2
  491. package/dist/ui/settings-guests.js +2 -1
  492. package/dist/ui/settings-learn.js +1 -0
  493. package/dist/ui/settings-model.js +51 -18
  494. package/dist/ui/settings-mods.js +8 -3
  495. package/dist/ui/settings-owner-effects.js +6 -4
  496. package/dist/ui/settings-strings.js +180 -6
  497. package/dist/ui/settings-token.js +3 -1
  498. package/dist/ui/settings-web-authority.js +13 -5
  499. package/dist/ui/settings-wizard.js +13 -7
  500. package/dist/ui/shared/agend-auth.js +2 -0
  501. package/dist/ui/shared/app-i18n.js +12 -5
  502. package/dist/ui/shared/app-needs.js +2 -2
  503. package/dist/ui/shared/app-prefs.js +15 -0
  504. package/dist/ui/shared/app-route.js +18 -0
  505. package/dist/ui/shared/app-shell.js +172 -28
  506. package/dist/ui/shared/app-store.js +3 -2
  507. package/dist/ui/shared/app-stream.js +5 -1
  508. package/dist/ui/shared/app-themes.js +116 -1
  509. package/dist/ui/shared/app.css +662 -48
  510. package/dist/ui/shared/app.js +9 -1
  511. package/dist/ui/shared/card-strings.js +4 -0
  512. package/dist/ui/shared/effect-app-runtime.js +7 -5
  513. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  514. package/dist/ui/shared/effect-cursor.js +3 -2
  515. package/dist/ui/shared/effect-display-metadata.js +39 -0
  516. package/dist/ui/shared/effect-owner-source.js +8 -1
  517. package/dist/ui/shared/effect-registry.js +14 -4
  518. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  519. package/dist/ui/shared/effect-stock-trust.js +5 -5
  520. package/dist/ui/shared/feature-flags.js +127 -0
  521. package/dist/ui/shared/guest-refused.js +35 -0
  522. package/dist/ui/shared/header-tools.js +2 -2
  523. package/dist/ui/shared/identity-card.js +26 -8
  524. package/dist/ui/shared/identity-color.js +17 -10
  525. package/dist/ui/shared/instance-nav.js +183 -28
  526. package/dist/ui/shared/owner-css.js +30 -1
  527. package/dist/ui/shared/panel-view.js +14 -29
  528. package/dist/ui/shared/text-undo.js +210 -0
  529. package/dist/ui/shared/tokens.css +4 -0
  530. package/dist/ui/shared/ui-dialog.js +5 -4
  531. package/dist/ui/shared/ui-icons.js +4 -0
  532. package/dist/ui/shared/ui-menu.js +20 -7
  533. package/dist/ui/shared/ui-toast.js +16 -3
  534. package/dist/ui/shared/usage-dialog.js +206 -16
  535. package/dist/ui/shared/view-strings.js +68 -4
  536. package/dist/ui/shared/web-authorize.js +50 -1
  537. package/dist/ui/signin.html +2 -0
  538. package/dist/ui/web-terminal/terminal.html +10 -10
  539. package/dist/ui/web-terminal/terminal.js +58 -12
  540. package/dist/update-check.js.map +1 -1
  541. package/dist/update-dispatch.js +1 -1
  542. package/dist/update-dispatch.js.map +1 -1
  543. package/dist/update-install.js.map +1 -1
  544. package/dist/update-launch.d.ts +10 -1
  545. package/dist/update-launch.js +39 -14
  546. package/dist/update-launch.js.map +1 -1
  547. package/dist/update-marker.js.map +1 -1
  548. package/dist/update-preflight.js +1 -1
  549. package/dist/update-preflight.js.map +1 -1
  550. package/dist/update-progress.d.ts +3 -1
  551. package/dist/update-progress.js +3 -1
  552. package/dist/update-progress.js.map +1 -1
  553. package/dist/usage/format-rich.js +6 -3
  554. package/dist/usage/format-rich.js.map +1 -1
  555. package/dist/usage/i18n-keys.d.ts +1 -1
  556. package/dist/usage/i18n-keys.js +2 -1
  557. package/dist/usage/i18n-keys.js.map +1 -1
  558. package/dist/usage/i18n.d.ts +13 -1
  559. package/dist/usage/i18n.js +29 -0
  560. package/dist/usage/i18n.js.map +1 -1
  561. package/dist/usage/providers.d.ts +89 -2
  562. package/dist/usage/providers.js +247 -41
  563. package/dist/usage/providers.js.map +1 -1
  564. package/dist/usage/statusline-usage.js.map +1 -1
  565. package/dist/usage/usage-api.d.ts +5 -1
  566. package/dist/usage/usage-api.js +185 -58
  567. package/dist/usage/usage-api.js.map +1 -1
  568. package/dist/usage-report.js.map +1 -1
  569. package/dist/usage-rollup.js +1 -1
  570. package/dist/usage-rollup.js.map +1 -1
  571. package/dist/user-systemd.d.ts +24 -0
  572. package/dist/user-systemd.js +75 -0
  573. package/dist/user-systemd.js.map +1 -0
  574. package/dist/view-api.d.ts +7 -0
  575. package/dist/view-api.js +16 -4
  576. package/dist/view-api.js.map +1 -1
  577. package/dist/wake-coordinator.js.map +1 -1
  578. package/dist/web-ambient.js.map +1 -1
  579. package/dist/web-api.d.ts +57 -10
  580. package/dist/web-api.js +1103 -70
  581. package/dist/web-api.js.map +1 -1
  582. package/dist/web-app-icon-worker.d.ts +1 -0
  583. package/dist/web-app-icon-worker.js +16 -0
  584. package/dist/web-app-icon-worker.js.map +1 -0
  585. package/dist/web-app-icon.d.ts +109 -0
  586. package/dist/web-app-icon.js +257 -0
  587. package/dist/web-app-icon.js.map +1 -0
  588. package/dist/web-appearance-policy.js.map +1 -1
  589. package/dist/web-appearance-tools.d.ts +1 -0
  590. package/dist/web-appearance-tools.js +7 -3
  591. package/dist/web-appearance-tools.js.map +1 -1
  592. package/dist/web-appearance-view.js.map +1 -1
  593. package/dist/web-appearance.d.ts +4 -10
  594. package/dist/web-appearance.js +7 -4
  595. package/dist/web-appearance.js.map +1 -1
  596. package/dist/web-auth.d.ts +8 -4
  597. package/dist/web-auth.js +33 -21
  598. package/dist/web-auth.js.map +1 -1
  599. package/dist/web-backend-login.d.ts +130 -0
  600. package/dist/web-backend-login.js +225 -0
  601. package/dist/web-backend-login.js.map +1 -0
  602. package/dist/web-card.js.map +1 -1
  603. package/dist/web-channel-echo.js.map +1 -1
  604. package/dist/web-chat-history.d.ts +118 -8
  605. package/dist/web-chat-history.js +220 -25
  606. package/dist/web-chat-history.js.map +1 -1
  607. package/dist/web-commands.d.ts +5 -1
  608. package/dist/web-commands.js +1 -1
  609. package/dist/web-commands.js.map +1 -1
  610. package/dist/web-cookie-names.d.ts +5 -0
  611. package/dist/web-cookie-names.js +12 -0
  612. package/dist/web-cookie-names.js.map +1 -0
  613. package/dist/web-effect-bundle.d.ts +2 -2
  614. package/dist/web-effect-library.js.map +1 -1
  615. package/dist/web-effect-playback.js.map +1 -1
  616. package/dist/web-effect-profiles.d.ts +16 -16
  617. package/dist/web-effect-profiles.js +3 -2
  618. package/dist/web-effect-profiles.js.map +1 -1
  619. package/dist/web-effect-service.js.map +1 -1
  620. package/dist/web-effect-tools.js.map +1 -1
  621. package/dist/web-effect-trials.js.map +1 -1
  622. package/dist/web-effect-upload.js.map +1 -1
  623. package/dist/web-effect.d.ts +6 -6
  624. package/dist/web-effect.js.map +1 -1
  625. package/dist/web-experimental-http.d.ts +2 -0
  626. package/dist/web-experimental-http.js +12 -0
  627. package/dist/web-experimental-http.js.map +1 -0
  628. package/dist/web-experimental.d.ts +11 -0
  629. package/dist/web-experimental.js +49 -0
  630. package/dist/web-experimental.js.map +1 -0
  631. package/dist/web-guest-access.d.ts +4 -2
  632. package/dist/web-guest-access.js +22 -10
  633. package/dist/web-guest-access.js.map +1 -1
  634. package/dist/web-guest-rooms.js.map +1 -1
  635. package/dist/web-host-guard.d.ts +11 -0
  636. package/dist/web-host-guard.js +11 -0
  637. package/dist/web-host-guard.js.map +1 -1
  638. package/dist/web-icons.d.ts +33 -1
  639. package/dist/web-icons.js +83 -11
  640. package/dist/web-icons.js.map +1 -1
  641. package/dist/web-identity-color.js.map +1 -1
  642. package/dist/web-image-meta.d.ts +13 -0
  643. package/dist/web-image-meta.js +62 -0
  644. package/dist/web-image-meta.js.map +1 -1
  645. package/dist/web-images.js.map +1 -1
  646. package/dist/web-libavoid.d.ts +14 -0
  647. package/dist/web-libavoid.js +46 -0
  648. package/dist/web-libavoid.js.map +1 -0
  649. package/dist/web-login.js.map +1 -1
  650. package/dist/web-mentions.js.map +1 -1
  651. package/dist/web-mod-agent.js.map +1 -1
  652. package/dist/web-mod-store.d.ts +2 -0
  653. package/dist/web-mod-store.js +10 -0
  654. package/dist/web-mod-store.js.map +1 -1
  655. package/dist/web-office-store.d.ts +104 -0
  656. package/dist/web-office-store.js +236 -0
  657. package/dist/web-office-store.js.map +1 -0
  658. package/dist/web-owner-css-store.d.ts +44 -1
  659. package/dist/web-owner-css-store.js +70 -9
  660. package/dist/web-owner-css-store.js.map +1 -1
  661. package/dist/web-owner-css.js.map +1 -1
  662. package/dist/web-png.d.ts +33 -0
  663. package/dist/web-png.js +329 -0
  664. package/dist/web-png.js.map +1 -0
  665. package/dist/web-prefs.d.ts +6 -0
  666. package/dist/web-prefs.js +29 -3
  667. package/dist/web-prefs.js.map +1 -1
  668. package/dist/web-preview.d.ts +2 -0
  669. package/dist/web-preview.js +2 -0
  670. package/dist/web-preview.js.map +1 -1
  671. package/dist/web-profile.js.map +1 -1
  672. package/dist/web-reactions.d.ts +35 -0
  673. package/dist/web-reactions.js +47 -0
  674. package/dist/web-reactions.js.map +1 -0
  675. package/dist/web-request-context.d.ts +5 -0
  676. package/dist/web-request-context.js.map +1 -1
  677. package/dist/web-returning-device.d.ts +4 -2
  678. package/dist/web-returning-device.js +13 -6
  679. package/dist/web-returning-device.js.map +1 -1
  680. package/dist/web-schedules.js.map +1 -1
  681. package/dist/web-send-dedupe.d.ts +36 -0
  682. package/dist/web-send-dedupe.js +69 -0
  683. package/dist/web-send-dedupe.js.map +1 -0
  684. package/dist/web-session-authorization.js.map +1 -1
  685. package/dist/web-session.js +1 -1
  686. package/dist/web-session.js.map +1 -1
  687. package/dist/web-settings-patch.d.ts +3 -1
  688. package/dist/web-settings-patch.js +11 -5
  689. package/dist/web-settings-patch.js.map +1 -1
  690. package/dist/web-settings-tools.d.ts +6 -0
  691. package/dist/web-settings-tools.js +52 -17
  692. package/dist/web-settings-tools.js.map +1 -1
  693. package/dist/web-terminal-http.js +15 -2
  694. package/dist/web-terminal-http.js.map +1 -1
  695. package/dist/web-terminal.js +1 -1
  696. package/dist/web-terminal.js.map +1 -1
  697. package/dist/web-theme-store.d.ts +2 -2
  698. package/dist/web-theme-store.js +6 -3
  699. package/dist/web-theme-store.js.map +1 -1
  700. package/dist/web-theme.d.ts +29 -0
  701. package/dist/web-theme.js +89 -1
  702. package/dist/web-theme.js.map +1 -1
  703. package/dist/web-upload.d.ts +18 -1
  704. package/dist/web-upload.js +45 -7
  705. package/dist/web-upload.js.map +1 -1
  706. package/dist/web-widget.js.map +1 -1
  707. package/dist/webhook-emitter.js.map +1 -1
  708. package/dist/windows-shortcuts.d.ts +78 -0
  709. package/dist/windows-shortcuts.js +203 -0
  710. package/dist/windows-shortcuts.js.map +1 -0
  711. package/dist/workflow-templates/default.md +3 -0
  712. package/dist/ws-server.js.map +1 -1
  713. package/dist/yaml-shared-nodes.d.ts +25 -0
  714. package/dist/yaml-shared-nodes.js +185 -0
  715. package/dist/yaml-shared-nodes.js.map +1 -0
  716. package/launcher/agend-install.cjs +828 -0
  717. package/launcher/install-admission.cjs +4 -39
  718. package/launcher/postinstall.cjs +14 -12
  719. package/launcher/private-home.cjs +43 -0
  720. package/package.json +16 -13
  721. package/scripts/preinstall-guard.cjs +2 -5
  722. package/templates/windows-shortcuts.ps1 +181 -0
  723. package/launcher/old-updater-note.cjs +0 -48
@@ -124,6 +124,23 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
124
124
  .idc.id-bar { position: relative; }
125
125
  .idc.id-bar::before { content: ""; position: absolute; left: 0; top: var(--s-2); bottom: var(--s-2); width: 3px; background: var(--id); pointer-events: none; }
126
126
  .idc.id-name .inst-name { color: var(--id-name); }
127
+ /* #2330: the same straight bar for every other coloured left edge (a 3px border-left curved into a rounded box's
128
+ corners). `.lbar` is the utility; the places below join its selector list instead of carrying a class. A place sets
129
+ --lbar-color (status variants too) and adds the 3px the border took to its own padding-left, so its text stays put.
130
+ A short box that clips to its corners (.msg-quote) moves the bar in (--lbar-left) and shortens it (--lbar-inset) so
131
+ the corner never cuts its ends round.
132
+ tests/web-left-bar-2330.test.ts keeps a coloured border-left off rounded boxes. */
133
+ .lbar, .reply-bar, .msg-quote, .p-log .log-item.k-error, .p-log .log-item.s-failed, .org-node, .us-basis, .us-partial, .cmd-card.bad, .tb-tile,
134
+ .search-row.on, .search-recent-item:hover, .search-recent-item:focus-visible, .search-ctx-line.here, .tw-line:hover, .tw-line:focus-visible,
135
+ .u-crow:focus-visible { position: relative; }
136
+ .lbar::before, .reply-bar::before, .msg-quote::before, .p-log .log-item.k-error::before, .p-log .log-item.s-failed::before, .org-node::before,
137
+ .us-basis::before, .us-partial::before, .cmd-card.bad::before, .tb-tile::before,
138
+ /* #2478 item 7 (the user's fixed template): a selected, hovered or keyboard-focused row is the straight bar and a flat
139
+ background at most — never a rounded fill, a curved inset edge or a rounded ring. */
140
+ .search-row.on::before, .search-recent-item:hover::before, .search-recent-item:focus-visible::before, .search-ctx-line.here::before,
141
+ .tw-line:hover::before, .tw-line:focus-visible::before, .u-crow:focus-visible::before {
142
+ content: ""; position: absolute; left: var(--lbar-left, 0); top: var(--lbar-inset, var(--s-2)); bottom: var(--lbar-inset, var(--s-2)); width: 3px;
143
+ background: var(--lbar-color, var(--accent)); pointer-events: none; }
127
144
  .idc-swatches, .idc-places { border: 0; padding: 0; margin: 0 0 var(--s-3); display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
128
145
  .idc-swatches legend, .idc-places legend { font-weight: var(--fw-semibold); margin-bottom: 6px; width: 100%; }
129
146
  .idc-swatch { --sw: var(--sw-dark); width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; background: var(--sw); cursor: pointer; padding: 0; }
@@ -139,6 +156,14 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
139
156
  .s-ap-group { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); margin: var(--s-4) 0 var(--s-2); }
140
157
  .s-ap-group:first-child { margin-top: 0; }
141
158
  .s-ap-title { display: flex; align-items: center; gap: var(--s-2); }
159
+ /* #2308: the app icon card — the icon now (home-screen size, and tab size) beside the one chosen, before it is used. */
160
+ .s-app-icon-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s-4); margin: var(--s-2) 0; }
161
+ .s-app-icon-row figure { margin: 0; display: grid; justify-items: center; gap: var(--s-1); }
162
+ .s-app-icon-row figure.s-app-icon-now { grid-template-columns: auto auto; align-items: end; column-gap: var(--s-3); }
163
+ .s-app-icon-row figure.s-app-icon-now figcaption { grid-column: 1 / -1; }
164
+ .s-app-icon-row figcaption { font-size: var(--fs-sm); color: var(--text-2); }
165
+ .s-app-icon-big { width: 96px; height: 96px; border-radius: 22%; border: 1px solid var(--border); background: var(--surface-2); object-fit: cover; }
166
+ .s-app-icon-small { width: 32px; height: 32px; border-radius: 6px; object-fit: cover; }
142
167
  /* The fields' placeholders show the defaults: readable, not the browser's faint grey (dark mode). */
143
168
  .s-appearance input::placeholder { color: var(--text-3); opacity: 1; }
144
169
  /* A card title in Chinese is never upper-cased ("AGENT 的主題"): the small caps are a Latin convention. */
@@ -284,7 +309,7 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
284
309
  .p-log .log-item.turn-start { margin-top: var(--s-4); }
285
310
  .p-log .log-item.k-user { background: var(--user-bubble); }
286
311
  .p-log .log-item.k-turn_end, .p-log .log-item.k-state, .p-log .log-item.k-event { background: transparent; color: var(--text-3); padding-block: 2px; font-size: var(--fs-sm); }
287
- .p-log .log-item.k-error, .p-log .log-item.s-failed { border-left: 3px solid var(--danger); }
312
+ .p-log .log-item.k-error, .p-log .log-item.s-failed { --lbar-color: var(--danger); padding-left: calc(var(--s-3) + 3px); }
288
313
  .p-log .log-head { display: flex; align-items: baseline; gap: var(--s-2); min-width: 0; }
289
314
  .p-log .log-icon { flex: none; }
290
315
  .p-log .log-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -350,6 +375,10 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
350
375
  .menu-item:hover:not(:disabled), .menu-item:focus-visible { background: var(--surface-2); outline: none; }
351
376
  .menu-item.danger { color: var(--danger); }
352
377
  .menu-item:disabled { opacity: 0.45; }
378
+ /* #2196: a group's heading in a menu (Page colours) and its radio items (the chosen one ticked). */
379
+ .menu-heading { padding: var(--s-2) var(--s-3) var(--s-1); font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); border-top: 1px solid var(--border); margin-top: var(--s-1); }
380
+ .menu-heading:first-child { border-top: 0; margin-top: 0; }
381
+ .menu-radio .menu-tick { width: 16px; display: inline-flex; color: var(--accent); }
353
382
 
354
383
  /* ── Dialog: centred on a desktop, a bottom sheet on a phone ── */
355
384
  .dlg { border: 0; padding: 0; border-radius: var(--r-lg); background: var(--bg); color: var(--text); box-shadow: var(--shadow-2); width: min(480px, calc(100vw - 32px)); max-height: 85vh; }
@@ -360,6 +389,17 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
360
389
  .dlg-title { flex: 1; font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
361
390
  .dlg-body { padding: var(--s-2) var(--s-5) var(--s-4); overflow-y: auto; display: flex; flex-direction: column; gap: var(--s-3); }
362
391
  .dlg-actions { display: flex; justify-content: flex-end; gap: var(--s-2); padding: var(--s-3) var(--s-5) var(--s-5); }
392
+ /* A drawer (ui-dialog.js `drawer`): on a desk, the right edge at full height, the page in view beside it. A phone keeps
393
+ the bottom sheet (the rules below are for 900 px and up only). */
394
+ @media (min-width: 900px) {
395
+ .dlg.dlg-drawer { width: min(620px, 100vw); max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0 0 0 auto; border-radius: 0;
396
+ background: var(--bg); box-shadow: var(--shadow-2); animation: dlg-drawer-in 0.18s var(--ease); }
397
+ .dlg-drawer .dlg-box { height: 100%; max-height: 100dvh; }
398
+ .dlg-drawer .dlg-head { padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5); border-bottom: 1px solid var(--border); }
399
+ .dlg-drawer .dlg-body { flex: 1; padding-top: var(--s-4); padding-bottom: var(--s-8); }
400
+ }
401
+ @keyframes dlg-drawer-in { from { transform: translateX(28px); opacity: 0.6; } }
402
+ @media (prefers-reduced-motion: reduce) { .dlg.dlg-drawer { animation: none; } }
363
403
 
364
404
  /* ── Forms ── */
365
405
  .form { display: flex; flex-direction: column; gap: var(--s-3); }
@@ -423,7 +463,7 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
423
463
 
424
464
  /* ── Chat ── */
425
465
  .p-chat .scroller { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; position: relative; }
426
- .thread { max-width: var(--col); margin: 0 auto; padding: var(--s-4) var(--s-5) var(--s-3); display: flex; flex-direction: column; gap: var(--s-6); }
466
+ .thread { max-width: var(--col); margin: var(--thread-snap, 0px) auto 0; padding: var(--s-4) var(--s-5) var(--s-3); display: flex; flex-direction: column; gap: var(--s-6); }
427
467
  .msg { font-size: var(--fs-md); line-height: var(--lh-md); overflow-wrap: anywhere; min-width: 0; }
428
468
  .msg .meta { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-3); margin-bottom: var(--s-1); }
429
469
  .msg .sender { font-weight: var(--fw-semibold); color: var(--text-2); }
@@ -436,6 +476,36 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
436
476
  such as 「昨天 下午03:58」, ticks) — and a block body would stretch to it; fit-content keeps a short message short, on
437
477
  the right under its meta, and a long one still wraps at the message's max-width. */
438
478
  .msg.user .body { background: var(--user-bubble); border-radius: var(--r-xl); padding: 10px var(--s-4); width: fit-content; max-width: 100%; margin-left: auto; }
479
+ /* A message this page is sending (chat-thread.js outgoingHtml): shown at once, its text dimmed with "Sending…" until the
480
+ server takes it; failed, a straight red bar with Retry and Delete. Each file: a picture as itself (or a document mark),
481
+ its name, a square-ended bar and its percentage, moved in place. */
482
+ .msg.user.out .meta { align-items: center; gap: var(--s-2); }
483
+ .msg.out.out-queued .body, .msg.out.out-sending .body { color: var(--text-3); }
484
+ .msg.out.out-queued .body .md, .msg.out.out-sending .body .md { opacity: .72; }
485
+ .out-state { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--text-3); }
486
+ .out-spin { width: 10px; height: 10px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: out-spin .8s linear infinite; }
487
+ @keyframes out-spin { to { transform: rotate(360deg); } }
488
+ .out-files { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-2); }
489
+ .msg.out .body .out-files:first-child { margin-top: 0; }
490
+ .out-file { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
491
+ .out-pic { width: 72px; height: 72px; object-fit: cover; border-radius: var(--r-md); flex: none; background: var(--surface-2); }
492
+ .msg.out.out-queued .out-pic, .msg.out.out-sending .out-pic { opacity: .7; }
493
+ .out-doc { width: 32px; height: 40px; flex: none; border: 1px solid var(--border); border-radius: 4px; background: var(--surface-2); }
494
+ .out-file-info { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px var(--s-2); min-width: 0; flex: 1; min-width: 140px; }
495
+ .out-name { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
496
+ .out-pct { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
497
+ .out-bar { grid-column: 1 / -1; height: 3px; background: var(--border); overflow: hidden; }
498
+ .out-fill { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform .2s linear; }
499
+ .out-file[data-state="done"] .out-bar, .out-file[data-state="done"] .out-pct { visibility: hidden; }
500
+ .out-file[data-state="failed"] .out-fill { background: var(--danger); }
501
+ .out-file[data-state="failed"] .out-pct { color: var(--danger); }
502
+ .msg.out.out-sent .out-file .out-bar, .msg.out.out-sent .out-file .out-pct { visibility: hidden; }
503
+ /* Hugs its words under the bubble's right edge, as the bubble does: the bar stays beside them, never across the row. */
504
+ .out-note { --lbar-color: var(--danger); display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); width: fit-content; max-width: 100%;
505
+ margin: var(--s-2) 0 0 auto; padding: var(--s-1) 0 var(--s-1) calc(var(--s-2) + 3px); font-size: var(--fs-xs); color: var(--danger); }
506
+ .out-error { overflow-wrap: anywhere; }
507
+ .out-actions { display: inline-flex; gap: var(--s-1); }
508
+ @media (prefers-reduced-motion: reduce) { .out-spin { animation: none; border-right-color: currentColor; opacity: .6; } .out-fill { transition: none; } }
439
509
  /* A person's click on a reply button: the bubble shows 🔘 and the button's label (never the value the agent was given);
440
510
  live, the label is a button that shows the reply its buttons were on. */
441
511
  .click-chip { display: flex; }
@@ -491,8 +561,19 @@ html.lb-open .scroller { overflow: hidden; }
491
561
  .lb { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
492
562
  background: rgba(0, 0, 0, 0.95); color: #fff; overflow: hidden; overscroll-behavior: contain; }
493
563
  .lb::backdrop { background: rgba(0, 0, 0, 0.6); }
494
- .lb-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 56px 16px 16px; box-sizing: border-box; }
495
- .lb-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
564
+ .lb-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 56px 16px 16px; box-sizing: border-box;
565
+ overflow: hidden; touch-action: none; }
566
+ /* #2333: the picture at its own size, placed and scaled by a CSSOM transform from its top-left corner (image-zoom.js);
567
+ hidden until it has loaded and been fitted. One that fails to load is shown where the browser puts a broken one. */
568
+ .lb-img { position: absolute; left: 0; top: 0; max-width: none; max-height: none; display: block; transform-origin: 0 0; will-change: transform;
569
+ visibility: hidden; cursor: zoom-in; user-select: none; -webkit-user-select: none; -webkit-user-drag: none; -webkit-touch-callout: none; }
570
+ .lb-img.lb-ready { visibility: visible; }
571
+ .lb-img.lb-err { position: static; max-width: 100%; max-height: 100%; visibility: visible; transform: none; cursor: default; }
572
+ .lb-stage.lb-zoomed .lb-img { cursor: grab; }
573
+ .lb-stage.lb-zoomed .lb-img:active { cursor: grabbing; }
574
+ .lb-zoom { display: inline-flex; align-items: center; gap: 2px; }
575
+ .lb .lb-level { min-width: 4.5em; justify-content: center; color: #fff; background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.3); font-variant-numeric: tabular-nums; }
576
+ .lb .lb-fit-width.on { background: rgba(255, 255, 255, 0.22); }
496
577
  .lb-bar { position: absolute; top: 0; left: 0; right: 0; z-index: 1; display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3);
497
578
  background: rgba(0, 0, 0, 0.75); }
498
579
  .lb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); }
@@ -560,10 +641,18 @@ html.lb-open .scroller { overflow: hidden; }
560
641
  .chat-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
561
642
  /* #1629: an agent's theme on its own chat surface — custom properties set on .p-chat through the CSSOM, choices as
562
643
  these tokens. The surface paints its own background (the page's body is not its). */
644
+ /*
645
+ * #2196: an agent's colours on the whole page (app-themes.js applyPageTheme, on .shell): the shell paints its own
646
+ * background then, under the sidebar, the header, the usage rail and a phone's tabs. The header follows the page, not
647
+ * the chat: it takes the shell's colours back (--chrome-*: resolved on .shell, so the page's theme or the page's own).
648
+ */
649
+ .shell.th-page { background: var(--bg); color: var(--text); }
650
+ .shell { --chrome-bg: var(--bg); --chrome-surface: var(--surface); --chrome-text: var(--text); --chrome-text-2: var(--text-2); --chrome-accent: var(--accent); }
651
+ .p-chat > .panel-head { --bg: var(--chrome-bg); --surface: var(--chrome-surface); --text: var(--chrome-text); --text-2: var(--chrome-text-2); --accent: var(--chrome-accent); background: var(--bg); color: var(--text); }
563
652
  .p-chat.th { background: var(--bg); color: var(--text); }
564
653
  .p-chat.th .msg.user .body { border-radius: var(--bubble-radius, var(--r-xl)); }
565
- .p-chat.th-font-system .thread, .p-chat.th-font-system .composer textarea { font-family: system-ui, -apple-system, "Segoe UI", sans-serif, var(--font-emoji); }
566
- .p-chat.th-font-mono .thread, .p-chat.th-font-mono .composer textarea { font-family: var(--font-mono); }
654
+ .p-chat.th-font-system .thread, .p-chat.th-font-system .composer textarea, .p-chat.th-font-system .composer-ph { font-family: system-ui, -apple-system, "Segoe UI", sans-serif, var(--font-emoji); }
655
+ .p-chat.th-font-mono .thread, .p-chat.th-font-mono .composer textarea, .p-chat.th-font-mono .composer-ph { font-family: var(--font-mono); }
567
656
  .p-chat.th-bubble-thin .msg.user .body { box-shadow: inset 0 0 0 1px var(--border); }
568
657
  .p-chat.th-bubble-accent .msg.user .body { box-shadow: inset 0 0 0 1px var(--accent); }
569
658
  .p-chat.th-agent-bubble .msg.agent .body { background: var(--agent-bubble); border-radius: var(--bubble-radius, var(--r-xl)); padding: 10px var(--s-4); }
@@ -614,6 +703,24 @@ img.amb-p { object-fit: contain; }
614
703
  .pv-code { flex: 1; min-height: 0; margin: 0; overflow: auto; font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.5;
615
704
  background: var(--surface); border-radius: var(--r-sm); padding: var(--s-3); white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
616
705
  .msg.flash { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--r-sm); transition: outline-color var(--t-med); }
706
+ /* #2272: a message's reply action (top right, on hover or focus), the quote a reply shows, the message menu, a swipe. */
707
+ .msg[data-key] { position: relative; }
708
+ .msg[data-key]:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--r-sm); }
709
+ .msg-actions { position: absolute; top: -6px; right: 0; z-index: 2; display: flex; gap: var(--s-1); padding: 2px; border-radius: var(--r-sm);
710
+ background: var(--surface); box-shadow: var(--shadow-1); opacity: 0; pointer-events: none; transition: opacity var(--t-fast); }
711
+ .msg:hover > .msg-actions, .msg:focus-within > .msg-actions { opacity: 1; pointer-events: auto; }
712
+ @media (hover: none) { .msg-actions { display: none; } }
713
+ .msg-quote { display: flex; align-items: center; gap: 4px; max-width: 100%; margin: 0 0 4px; padding: 2px var(--s-2) 2px calc(var(--s-2) + 3px); border: 0;
714
+ --lbar-color: var(--border-strong, var(--border)); --lbar-inset: 4px; --lbar-left: 2px; border-radius: var(--r-sm); background: transparent; color: var(--text-3);
715
+ font: inherit; font-size: var(--fs-sm); text-align: left; cursor: pointer; overflow: hidden; }
716
+ .msg.user .msg-quote { margin-left: auto; }
717
+ .msg-quote:hover, .msg-quote:focus-visible { color: var(--text-2); background: var(--surface-2); outline: none; }
718
+ .msg-quote .quote-sender { font-weight: var(--fw-semibold); white-space: nowrap; }
719
+ .msg-quote .quote-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
720
+ .msg-menu { position: fixed; z-index: 60; min-width: 180px; padding: var(--s-1); border-radius: var(--r-md); background: var(--surface);
721
+ box-shadow: var(--shadow-2); display: flex; flex-direction: column; }
722
+ .msg[data-key] { transition: transform var(--t-fast); }
723
+ .msg.swipe-ready { box-shadow: 3px 0 0 var(--accent); border-radius: var(--r-sm); } /* let go now: a reply */
617
724
  @media (max-width: 899px) {
618
725
  .only-wide { display: none; }
619
726
  .pv-divider { display: none; }
@@ -679,12 +786,40 @@ img.amb-p { object-fit: contain; }
679
786
  font-size: var(--fs-md); line-height: var(--lh-md); resize: none; min-height: 24px; max-height: 240px; overflow-y: auto;
680
787
  }
681
788
  .composer textarea::placeholder { color: var(--text-3); }
789
+ /* #2478: the placeholder, drawn over the empty box at its text's place: one line ending in "…" (a textarea's own is
790
+ clipped, never ellipsized). The same size and line as the box's text; it never takes a tap. */
791
+ .composer-field { position: relative; flex: 1; min-width: 0; display: flex; }
792
+ .composer-ph { position: absolute; left: var(--s-1); right: var(--s-1); top: 7px; pointer-events: none; color: var(--text-3);
793
+ font-size: var(--fs-md); line-height: var(--lh-md); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
682
794
  .btn-send { width: 36px; padding: 0; }
683
795
  .btn-send .send-label { display: none; }
684
796
  /* A narrow phone: Stop reply beside Send leaves the message box no room — the label is for screen readers there. */
685
797
  @media (max-width: 479px) { .btn-stop .stop-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } }
686
798
  .btn-stop { background: var(--bg); }
687
- .hint { font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
799
+ .hint { font-size: var(--fs-xs); color: var(--text-3); }
800
+ /* #2215 (the user's request, 2026-10-19): one row under the composer, at the bottom left — this browser's web authority, then
801
+ the key hint. Its height is kept even before the authority is read (#2184: switching chats never moves the composer). */
802
+ .composer-row { position: relative; display: flex; align-items: center; gap: var(--s-2); min-height: 20px; margin-top: calc(-1 * var(--s-1));
803
+ font-size: var(--fs-xs); line-height: 1.4; color: var(--text-3); white-space: nowrap; }
804
+ .composer-row > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
805
+ .composer-row > .hint { flex-shrink: 1000; }
806
+ .composer-row > :not(.hint) + .hint::before { content: "·"; margin-right: var(--s-2); }
807
+ /* A guest's note and the public link's sentence are kept whole: on a narrow screen they wrap rather than lose words. */
808
+ .composer-row .guest-note, .composer-row .webauth-row[data-state="public"] { margin: 0; text-align: left; white-space: normal; flex-shrink: 1; }
809
+ .webauth-row { display: inline-flex; align-items: center; gap: var(--s-1); }
810
+ .webauth-row .webauth-ok, .webauth-row .webauth-ask { font: inherit; padding: 0 2px; border: 0; background: none; cursor: pointer; border-radius: var(--r-sm); }
811
+ .webauth-row .webauth-ok { color: var(--ok); }
812
+ .webauth-row .webauth-ask { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
813
+ .webauth-row .webauth-ok:focus-visible, .webauth-row .webauth-ask:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
814
+ /* What pressing Authorize answered is said in the row, in the hint's place: nothing is laid over the composer. */
815
+ .webauth-row .webauth-notice { white-space: normal; color: var(--text-2); }
816
+ .webauth-row .webauth-notice::before { content: "·"; margin-right: var(--s-2); color: var(--text-3); }
817
+ .composer-row:has(.webauth-notice) > .hint { display: none; }
818
+ /* When "✓ Verified" ends, on a tap (touch has no hover): a bubble above the row while it has focus. */
819
+ .webauth-tip { position: absolute; left: 0; bottom: calc(100% + 4px); z-index: 5; max-width: min(420px, calc(100vw - 32px)); white-space: normal;
820
+ padding: var(--s-1) var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); color: var(--text);
821
+ box-shadow: var(--shadow-2); }
822
+ .webauth-tip[hidden] { display: none; }
688
823
  /* #1920 phase 3: Settings → Web → Guests. */
689
824
  .s-guests .guest-names { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 2px var(--s-3); max-height: 220px; overflow: auto;
690
825
  padding: var(--s-1) var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
@@ -701,11 +836,20 @@ img.amb-p { object-fit: contain; }
701
836
  /* #1939 S2a: Settings → Web → Web authority. */
702
837
  .s-web-authority .s-va-sessions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
703
838
  .s-web-authority .s-va-sessions li { padding: var(--s-2) var(--s-3); border: 1px solid var(--border); border-radius: var(--r-sm); overflow-wrap: anywhere; }
839
+ /* #2453: "over your named link" stays one phrase (the list item may break anywhere, CJK included). */
840
+ .s-web-authority .s-va-named { white-space: nowrap; }
704
841
  .s-web-authority .s-va-warn { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn-line); border-radius: var(--r-sm); padding: var(--s-1) var(--s-2); }
705
842
  .s-web-authority .save-row { flex-wrap: wrap; }
706
843
  /* #1920: a guest's note under the composer — on a phone too, where the key hints are hidden. */
707
844
  .guest-note { margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
708
845
  .pending-files { display: flex; flex-wrap: wrap; gap: var(--s-2); padding: var(--s-2) var(--s-2) 0; }
846
+ /* #2272: replying — the bar above the composer (who and what is answered; ✕ / Esc cancels). */
847
+ .reply-bar { display: flex; align-items: center; gap: var(--s-2); min-width: 0; margin: var(--s-2) var(--s-2) 0; padding: 4px var(--s-2) 4px calc(var(--s-3) + 3px);
848
+ --lbar-color: var(--accent); border-radius: var(--r-sm); background: var(--surface-2); font-size: var(--fs-sm); }
849
+ .reply-bar .reply-mark { color: var(--accent); }
850
+ .reply-bar .reply-label { font-weight: var(--fw-semibold); white-space: nowrap; }
851
+ .reply-bar .reply-text { flex: 1; min-width: 0; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
852
+ .reply-bar .reply-cancel { flex: none; width: 28px; height: 28px; }
709
853
  .file-chip { display: flex; align-items: center; gap: 6px; font-size: var(--fs-xs); padding: 4px var(--s-2); border-radius: var(--r-md); background: var(--bg); max-width: 320px; }
710
854
  .file-chip img { width: 28px; height: 28px; object-fit: cover; border-radius: 4px; }
711
855
  .file-chip .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
@@ -774,6 +918,9 @@ img.amb-p { object-fit: contain; }
774
918
  .oc-keep { left: var(--s-2); right: var(--s-2); transform: none; max-width: none; flex-wrap: nowrap; }
775
919
  .oc-keep-text { flex: 1; flex-direction: column; align-items: flex-start; gap: 0; }
776
920
  }
921
+ /* #2299: the toasts are a manual popover (ui-toast.js), so they stand in the top layer above an open dialog's backdrop;
922
+ the popover's own box (inset 0, margin, border, background) is undone here, before any placement below. */
923
+ :where(.toasts) { inset: auto; margin: 0; padding: 0; border: 0; background: none; color: inherit; overflow: visible; width: auto; height: auto; }
777
924
  .toasts { position: fixed; bottom: var(--s-6); right: var(--s-6); z-index: 100; display: flex; flex-direction: column; align-items: flex-end; gap: var(--s-2); pointer-events: none; }
778
925
  .toast { padding: 10px var(--s-4); max-width: min(420px, calc(100vw - 32px)); border-radius: var(--r-md); font-size: var(--fs-sm); font-weight: var(--fw-medium); box-shadow: var(--shadow-2); background: var(--accent-fill); color: var(--on-accent); animation: toast-in var(--t-med) var(--ease); }
779
926
  .toast.err { background: var(--danger-fill); color: var(--on-danger); }
@@ -800,7 +947,12 @@ img.amb-p { object-fit: contain; }
800
947
  .panel-head .sb-new { display: none; }
801
948
  .only-narrow { display: inline-flex; }
802
949
  .thread { padding: var(--s-3) var(--s-3) var(--s-2); gap: var(--s-5); }
803
- .col { padding: var(--s-3) var(--s-3) var(--s-8); }
950
+ /* #2299: a phone's side gutter is 16 px — the content column, the header and the toasts alike. */
951
+ .col { padding: var(--s-3) var(--s-4) var(--s-8); }
952
+ .panel-head { padding: max(var(--s-1), env(safe-area-inset-top)) max(var(--s-4), env(safe-area-inset-right)) var(--s-1) max(var(--s-4), env(safe-area-inset-left)); }
953
+ /* #2299: the header's controls are a full touch target (its row is 52 px: 44 px plus its padding). */
954
+ .panel-head .icon-btn { min-width: var(--tap); min-height: var(--tap); }
955
+ .panel-head .btn, .panel-head .seg-item, .panel-head select { min-height: var(--tap); }
804
956
  .dock { padding: 0 max(var(--s-2), env(safe-area-inset-right)) var(--s-2) max(var(--s-2), env(safe-area-inset-left)); }
805
957
  .hint { display: none; }
806
958
  .msg.user { max-width: 88%; }
@@ -811,12 +963,14 @@ img.amb-p { object-fit: contain; }
811
963
  padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
812
964
  }
813
965
  .kb-open .tabs { display: none; }
966
+ /* #2478: with the keyboard up the line under the composer goes too — the box sits on the keyboard; back on blur. */
967
+ .kb-open .composer-row { display: none; }
814
968
  .tab { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 56px; justify-content: center; font-size: 11px; color: var(--text-2); position: relative; }
815
969
  .tab.active { color: var(--text); font-weight: var(--fw-semibold); }
816
970
  .tab-badge { position: absolute; top: 6px; left: calc(50% + 6px); min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--r-full); background: var(--danger-fill); color: var(--on-danger); font-size: 10px; line-height: 16px; text-align: center; }
817
971
  .main { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
818
972
  .kb-open .main { padding-bottom: 0; }
819
- .toasts { top: calc(60px + env(safe-area-inset-top)); bottom: auto; left: var(--s-3); right: var(--s-3); align-items: stretch; }
973
+ .toasts { top: calc(60px + env(safe-area-inset-top)); bottom: auto; left: var(--s-4); right: var(--s-4); align-items: stretch; }
820
974
  .tour { left: var(--s-4); right: var(--s-4); width: auto; top: calc(64px + env(safe-area-inset-top)); }
821
975
  .dlg { width: 100vw; max-width: 100vw; margin: auto 0 0; border-radius: var(--r-lg) var(--r-lg) 0 0; max-height: 90vh; }
822
976
  .dlg-box { max-height: 90vh; }
@@ -840,6 +994,9 @@ img.amb-p { object-fit: contain; }
840
994
  color: var(--text-3); font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: 0.04em; cursor: pointer; text-align: left;
841
995
  }
842
996
  .v-group-head:hover { color: var(--text); }
997
+ /* #2172: what a group is — a team's icon, or "#" before a tag — muted, before its name (sidebar and Settings). */
998
+ .v-group-kind { display: inline-flex; align-items: center; flex: none; color: var(--text-3); font-weight: var(--fw-medium); }
999
+ .v-group-kind.tag { min-width: 0.7em; justify-content: center; }
843
1000
  .v-group-head .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
844
1001
  .v-group-head .count { font-weight: var(--fw-medium); letter-spacing: 0; text-transform: none; padding: 0 var(--s-2); border-radius: var(--r-full); background: var(--surface-2); }
845
1002
  .caret { transition: transform var(--t-fast) var(--ease); }
@@ -869,6 +1026,35 @@ img.amb-p { object-fit: contain; }
869
1026
  @media (max-width: 899px) { .fav-editing .inst-star, .fav-editing .inst-move { width: 36px; height: 36px; } }
870
1027
  .v-inst .dot { margin-top: 0; }
871
1028
  .v-meta { color: var(--text-3); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
1029
+ .v-meta { flex: none; }
1030
+ /* #2179 (B5, the user's pick): the name and its % on the first line; the other name and the last reply's time on the
1031
+ second, the time at its end — one column of times down the list. The ★ beside a two-line row sits on the first line. */
1032
+ .inst-line { display: flex; align-items: baseline; gap: var(--s-2); min-width: 0; }
1033
+ .inst-line > .inst-name, .inst-line2 > .inst-alt { flex: 1; min-width: 0; }
1034
+ .inst-when { flex: none; font-size: var(--fs-xs); line-height: var(--lh-xs); color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
1035
+ .inst-when.fresh { color: var(--accent); font-weight: var(--fw-semibold); }
1036
+ .v-li.two-line > .inst-star, .v-li.two-line > .inst-move { align-self: flex-start; margin-top: 6px; }
1037
+ /* A fresh reply: an accent tint that fades with --reply-a (1 → 0 over ten minutes, set on the row), never over the open
1038
+ or a hovered row; one under a minute old pulses once — not under reduced motion. Nothing to click or clear. */
1039
+ .inst.replied:not(.active):not(:hover) { background: color-mix(in srgb, var(--accent) calc(var(--reply-a, 0) * 22%), transparent); }
1040
+ .inst.just:not(.active) { animation: inst-just 2.4s ease-out 1; }
1041
+ @keyframes inst-just { from { box-shadow: inset 0 0 0 1.5px var(--accent); } to { box-shadow: inset 0 0 0 1.5px transparent; } }
1042
+ @media (prefers-reduced-motion: reduce) { .inst.just:not(.active) { animation: none; } } /* as specific as the rule it stops */
1043
+ /* #2179: how the list sorts — the button says it (the accent while "Recent replies" is on); its menu under it. */
1044
+ .inst-head { position: relative; }
1045
+ .nav-sort { position: static; flex: none; } /* the menu spans the header's width, under it — never past the sidebar's edge */
1046
+ .nav-sort-btn { display: inline-flex; align-items: center; gap: 4px; }
1047
+ .nav-sort-btn.on { color: var(--accent); }
1048
+ .nav-sort-static { cursor: default; }
1049
+ .nav-sort-menu { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 30; padding: var(--s-3);
1050
+ border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
1051
+ display: flex; flex-direction: column; gap: var(--s-3); }
1052
+ .nav-sort-menu fieldset { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
1053
+ .nav-sort-menu legend { padding: 0 0 4px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); }
1054
+ .nav-sort-opt { display: flex; align-items: flex-start; gap: var(--s-2); min-height: 36px; padding: 4px 2px; font-size: var(--fs-sm); cursor: pointer; }
1055
+ .nav-sort-opt input { margin-top: 3px; flex: none; }
1056
+ .nav-sort-hint { display: block; font-size: var(--fs-xs); color: var(--text-3); }
1057
+ .recent-head { cursor: default; }
872
1058
  /* #1722: the sidebar's width — a separator on its right edge (drag, arrows, Home/End, double-click resets); not on a phone */
873
1059
  .side-resize { position: absolute; top: 0; right: -3px; width: 6px; height: 100%; z-index: 5; cursor: col-resize; touch-action: none; }
874
1060
  .side-resize:hover, .side-resize:focus-visible, .side-resize.dragging { background: var(--accent-dim, var(--border-strong)); }
@@ -891,7 +1077,21 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
891
1077
  down, never the count; the count is as tall as a header, so the row does not grow. */
892
1078
  .nav-facets { display: flex; align-items: flex-start; gap: var(--s-2); padding: var(--s-2) var(--s-1) 0; }
893
1079
  .nav-facet-groups { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--s-1) var(--s-2); flex: 1 1 auto; min-width: 0; }
894
- .nav-facets .nav-shown { flex: none; margin: 0 0 0 auto; padding: 2px 0; white-space: nowrap; }
1080
+ /* #2401: the count, "shown" under it and Clear under that. The word's width is held by ::before (its text from
1081
+ data-reserve) and idle Clear's by the button itself, both at no height, unseen and out of reach (visibility): the column —
1082
+ and the headers' box beside it — is as wide with a facet set as without. */
1083
+ .nav-facet-end { flex: none; margin: 0 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; }
1084
+ .nav-facets .nav-shown { margin: 0; padding: 2px 0; white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
1085
+ .nav-shown-word { display: block; }
1086
+ .nav-facet-end::before { content: attr(data-reserve); display: block; height: 0; overflow: hidden; visibility: hidden; font-size: var(--fs-xs); white-space: nowrap; }
1087
+ .nav-facet-end .is-idle { visibility: hidden; height: 0; min-height: 0; margin: 0; padding-top: 0; padding-bottom: 0; border-top-width: 0; border-bottom-width: 0; overflow: hidden; }
1088
+ /* No open list beside it (.compact): one cell of one line, as wide as the count or Clear; a facet set, Clear in the count's
1089
+ place (the count transparent, still read; the word for a screen reader only, so its width is not held here). */
1090
+ .nav-facets.compact .nav-facet-end { display: grid; justify-items: end; align-items: center; }
1091
+ .nav-facets.compact .nav-facet-end > * { grid-area: 1 / 1; margin: 0; }
1092
+ .nav-facets.compact .nav-facet-end::before { display: none; }
1093
+ .nav-facets.compact .nav-shown.is-set { opacity: 0; pointer-events: none; }
1094
+ .nav-facets.compact .nav-shown-word { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
895
1095
  .nav-facet { font-size: var(--fs-xs); color: var(--text-2); min-width: 0; max-width: 100%; }
896
1096
  /* #1700: a facet group's header — the whole row toggles its list; folded with a filter set, a short summary. */
897
1097
  .nav-facet-head { display: inline-flex; align-items: center; gap: var(--s-1); max-width: 100%; padding: 2px var(--s-2); border: 0; border-radius: var(--r-sm);
@@ -900,10 +1100,15 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
900
1100
  .nav-facet-head:focus-visible { outline: 2px solid var(--accent); }
901
1101
  .nav-facet-head .caret { color: var(--text-3); flex: none; }
902
1102
  .nav-facet-sum { min-width: 0; max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--accent); }
1103
+ /* #2401: the summary takes only the room its line has left — never counted when the headers wrap (contain: inline-size,
1104
+ its gap taken back), so a facet set never sends a header to a line of its own; the header holding it grows into the rest. */
1105
+ .nav-facet.has-sum { flex-grow: 1; }
1106
+ .nav-facet.has-sum .nav-facet-head { width: 100%; }
1107
+ .nav-facet-sum { contain: inline-size; flex: 1 1 0; margin-left: calc(-1 * var(--s-1)); padding-left: var(--s-1); }
903
1108
  .nav-facet-n { display: inline-block; min-width: 16px; padding: 0 4px; border-radius: 8px; background: var(--accent); color: var(--on-accent, #fff); text-align: center; font-variant-numeric: tabular-nums; }
904
1109
  .nav-facet-list { display: flex; flex-direction: column; gap: 2px; padding: var(--s-1) var(--s-2); }
905
1110
  .nav-chip { display: flex; align-items: center; gap: var(--s-2); cursor: pointer; color: var(--text); }
906
- .nav-facet-reset { font-size: var(--fs-xs); }
1111
+ .nav-facet-reset { font-size: var(--fs-xs); flex: none; white-space: nowrap; margin-top: 2px; padding: 2px var(--s-1); }
907
1112
 
908
1113
  /* One gap on every page (View's, #1448): the header's controls are the same size on every tab. */
909
1114
  .panel-actions .btn { gap: var(--s-1); }
@@ -921,26 +1126,17 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
921
1126
  .v-pre .ansi[data-dim] { opacity: .5; }
922
1127
  .v-term-note { position: absolute; left: var(--s-3); right: var(--s-3); top: var(--s-3); padding: var(--s-2) var(--s-3); border-radius: var(--r-sm); background: var(--warn-bg); border: 1px solid var(--warn-line); color: #f0f0f0; font-size: var(--fs-sm); }
923
1128
  .v-probe { position: absolute; visibility: hidden; white-space: pre; left: -9999px; top: 0; font-size: 100px; }
924
- .v-card { flex-shrink: 0; display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) var(--s-4); background: var(--bg); padding-bottom: max(var(--s-2), env(safe-area-inset-bottom)); }
925
- .v-card.open { align-items: flex-start; padding-top: var(--s-3); padding-bottom: var(--s-3); }
926
- .v-avatar { width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%; overflow: hidden; background: var(--surface-2); display: flex; align-items: center; justify-content: center; }
927
- .v-card.open .v-avatar { width: 48px; height: 48px; }
928
- .v-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
929
- .v-initial { color: var(--text-2); font-weight: var(--fw-semibold); text-transform: uppercase; }
930
- .v-card-body { flex: 1; min-width: 0; }
931
- .v-card-line { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--fs-sm); min-width: 0; }
932
- .v-card-line strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
933
- .v-role { color: var(--accent); font-size: var(--fs-xs); white-space: nowrap; }
934
- .v-card-meta { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
935
- .v-card.open .v-card-meta { white-space: normal; }
936
- .v-card-desc { margin-top: var(--s-2); color: var(--text-2); font-size: var(--fs-sm); white-space: pre-wrap; }
937
1129
  .help-list { list-style: disc; padding-left: var(--s-5); display: flex; flex-direction: column; gap: var(--s-2); font-size: var(--fs-sm); }
938
1130
  .err { color: var(--danger); font-size: var(--fs-sm); }
939
1131
  .u-provider { padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--surface); display: flex; flex-direction: column; gap: var(--s-2); }
940
1132
  .u-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
941
- /* #1749: one line beside ↑↓ — the name gives way first, then the plan badge (each with an ellipsis); ↑↓ never wrap. */
942
- .u-head strong { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
943
- .u-plan { min-width: 0; flex: none; max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1133
+ /* #1749 / #2412: one line beside ↑↓, by flexing alone (no widths assumed: ↑↓ are larger on a phone). The plan badge
1134
+ starts at its minimum (40 px) and grows up to its own width into the room the name and ↑↓ leave, so a long badge ends
1135
+ in an ellipsis (the full name its tooltip) while the name keeps every pixel (#2415 review: a shared shrink, however
1136
+ weighted, still took a fraction of one and painted "Meta Muse Co…"). Only when the name, that minimum badge and ↑↓
1137
+ cannot all fit (a 320 px phone) does the name shrink and end in an ellipsis — nothing leaves the card. */
1138
+ .u-head strong { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1139
+ .u-plan { flex: 1 0 40px; max-width: max-content; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
944
1140
  /* #2014: a credential profile's row — the provider name beside the plan badge, and the profile on its own full-width
945
1141
  muted line under the head (one line in the rail, whole in the dialog). */
946
1142
  .u-profile { margin-top: calc(-1 * var(--s-2) + 2px); color: var(--text-3); font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -959,19 +1155,62 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
959
1155
  .u-meter { height: 10px; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
960
1156
  .u-fill { height: 100%; width: 0; min-width: 3px; border-radius: var(--r-full); background: var(--accent); transition: width 0.3s var(--ease); }
961
1157
  .u-fill.warn { background: var(--warn); } .u-fill.crit { background: var(--danger); }
1158
+ /* Last known numbers (the live read failed): greyed, so they never read as live; the mark says when they were read. */
1159
+ .u-provider.is-stale .u-pct, .u-provider.is-stale .u-val, .u-provider.is-stale .u-status { color: var(--text-3); }
1160
+ .u-provider.is-stale .u-fill { background: var(--text-3); }
1161
+ .u-stale { font-weight: var(--fw-semibold); }
1162
+ .u-stale-detail { color: var(--text-3); font-size: var(--fs-xs); }
962
1163
  .u-sub { color: var(--text-3); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
963
1164
  .u-err { color: var(--warn); font-size: var(--fs-sm); }
964
1165
  .u-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
965
1166
  /* #1673: the usage rail beside the page on a wide screen (header-tools.js UsageRail; shown only at min-width 1200px). */
966
1167
  .u-rail { width: 320px; flex-shrink: 0; display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--border); background: var(--bg); }
967
1168
  .u-rail-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); padding: var(--s-3) var(--s-3) var(--s-2) var(--s-4); }
968
- .u-rail-head h2 { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); }
1169
+ .u-rail-head h2 { margin: 0; flex: 1; min-width: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); }
1170
+ /* The usage view's compact mode (usage-dialog.js CompactGroup / CompactRow), the user's pick (2026-10-22): the logins
1171
+ grouped by provider (its name once, in small capitals), each in three short lines — its name and plan with the
1172
+ soonest reset on the right, then each window as a labelled full-width bar and the percent. */
1173
+ .dlg-tools { display: inline-flex; align-items: center; flex: none; }
1174
+ .u-compact-toggle { flex: none; }
1175
+ /* flex: none — a group never shrinks to fit the rail (it would clip its accounts): the rail scrolls instead. */
1176
+ .u-cgroup { flex: none; display: flex; flex-direction: column; border-radius: var(--r-md); background: var(--surface); overflow: hidden; }
1177
+ .u-cg-head { display: flex; align-items: baseline; gap: 4px; padding: 7px var(--s-3) 3px; font-size: 11px; font-weight: var(--fw-semibold);
1178
+ letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-3); }
1179
+ .u-cg-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1180
+ .u-cg-count { flex: none; }
1181
+ .u-crow { display: flex; flex-direction: column; gap: 3px; width: 100%; min-width: 0; padding: 6px var(--s-3); border: 0; border-top: 1px solid var(--border);
1182
+ background: transparent; color: inherit; font: inherit; line-height: 1.3; text-align: left; cursor: pointer; }
1183
+ .u-cg-head + .u-crow { border-top: 0; }
1184
+ .u-crow:hover { background: var(--surface-2); }
1185
+ /* #2478 (Prism r1): the compact rows sit in .u-cgroup, rounded and clipping (overflow: hidden) — the bar keeps clear of
1186
+ its 12 px corners (4 px in, 6 px off the row's ends) and there is no full-width underline to be rounded at the ends:
1187
+ the bar is the focus mark (hover has none). */
1188
+ .u-crow:focus-visible { outline: none; background: var(--surface-2); --lbar-left: var(--s-1); --lbar-inset: 6px; }
1189
+ /* The name never gives way to the plan (#2415); the reset keeps its room on the right. */
1190
+ .u-crow-head { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--fs-sm); }
1191
+ .u-crow-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--fw-semibold); color: var(--text); }
1192
+ .u-crow .u-plan { flex: 0 100 auto; min-width: 22px; max-width: max-content; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1193
+ padding-block: 0; line-height: 16px; font-size: 10.5px; }
1194
+ .u-crow-reset { margin-left: auto; flex: none; padding-left: 6px; font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
1195
+ .u-cm { display: grid; grid-template-columns: 2.6em minmax(0, 1fr) 3.4em; align-items: center; gap: 7px; min-width: 0; }
1196
+ .u-cm-tag { font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1197
+ /* #2240: an account of several pools (agy) names each pool's line: a wider label, ending in an ellipsis if it must. */
1198
+ .u-crow.is-pooled .u-cm { grid-template-columns: minmax(0, 7.5em) minmax(0, 1fr) 3.4em; }
1199
+ .u-cm-bar { height: 6px; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
1200
+ .u-cm-fill { display: block; height: 100%; width: 0; min-width: 2px; border-radius: var(--r-full); background: var(--accent); }
1201
+ .u-cm-fill.warn { background: var(--warn); } .u-cm-fill.crit { background: var(--danger); }
1202
+ .u-cm-pct { text-align: right; font-size: 13px; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--text); }
1203
+ .u-cm-pct.warn { color: var(--warn); } .u-cm-pct.crit { color: var(--danger); }
1204
+ .u-crow-note { font-size: var(--fs-xs); color: var(--text-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1205
+ .u-crow-note.is-alert::before { content: "●"; margin-right: 5px; color: var(--danger); }
1206
+ .u-crow.is-stale .u-crow-note.is-alert::before { color: var(--warn); }
1207
+ @media (prefers-reduced-motion: no-preference) { .u-crow { transition: background-color 0.15s var(--ease); } }
969
1208
  .u-rail-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 var(--s-3) var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
970
1209
  @media (max-width: 1199px) { .u-rail { display: none; } }
971
1210
  @media (max-width: 899px) {
972
1211
  .hide-narrow { display: none; }
973
- .v-card { padding-left: var(--s-3); padding-right: var(--s-3); }
974
- .v-card .btn { min-height: var(--tap); }
1212
+ .v-id { padding-left: var(--s-3); padding-right: var(--s-3); }
1213
+ .v-id-actions .btn { min-height: var(--tap); }
975
1214
  }
976
1215
 
977
1216
  /* ── Settings (#1408 step 3): lists, forms, the pending bar, the Apply in hand ── */
@@ -1063,8 +1302,6 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1063
1302
  .s-dev-bar .lbl { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
1064
1303
  /* An agent's row: name and model on the first line, its tags and buttons from the second, on every row alike. */
1065
1304
  .s-br { display: block; flex-basis: 100%; height: 0; }
1066
- /* View: the profile line wraps to two lines instead of hiding the model and context. */
1067
- .v-card-meta { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
1068
1305
  /* A text button in Needs you lines up with the text above it, first in its row or wrapped onto a line of its own;
1069
1306
  a row's trailing Delete sits at the right. */
1070
1307
  .n-actions > .btn-ghost { padding-left: 0; padding-right: 0; margin-left: -1px; }
@@ -1114,6 +1351,18 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1114
1351
  .op-line { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
1115
1352
  .op-line.ok { color: var(--ok); }
1116
1353
  .op-line.bad { color: var(--danger); }
1354
+ /* #2233: the backend sign-in dialog and Settings' list */
1355
+ .signin-field { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin: var(--s-2) 0; }
1356
+ .signin-label { color: var(--text-2); font-size: var(--fs-xs); min-width: 6em; }
1357
+ .signin-value { font-size: var(--fs-md); letter-spacing: 0.04em; user-select: all; word-break: break-all; }
1358
+ .signin-url { color: var(--text-2); font-size: var(--fs-xs); word-break: break-all; }
1359
+ .signin-note { color: var(--text-2); font-size: var(--fs-xs); }
1360
+ .signin-ok { color: var(--ok); }
1361
+ .signin-message { white-space: pre-wrap; }
1362
+ .signin-lines { margin: var(--s-2) 0 0; padding-left: 1.2em; color: var(--text-2); font-size: var(--fs-xs); white-space: pre-wrap; }
1363
+ .signin-list { margin-top: var(--s-4); }
1364
+ .signin-list code { font-size: var(--fs-xs); word-break: break-all; }
1365
+ .signin-list .s-meta { white-space: normal; max-width: none; overflow: visible; }
1117
1366
  @media (max-width: 899px) {
1118
1367
  .grid2 { grid-template-columns: minmax(0, 1fr); }
1119
1368
  .se-row { grid-template-columns: minmax(0, 1fr) auto auto; }
@@ -1164,10 +1413,10 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1164
1413
  .org-team-head h3 { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-md); font-weight: var(--fw-semibold); overflow-wrap: anywhere; }
1165
1414
  .org-team-desc { color: var(--text-2); font-size: var(--fs-sm); overflow-wrap: anywhere; }
1166
1415
  .org-team-sub { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-3); font-size: var(--fs-xs); }
1167
- .org-node { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; padding: var(--s-3); border-radius: var(--r-md); background: var(--surface); border-left: 3px solid transparent; }
1168
- .org-node.st-needs, .org-node.st-stuck { border-left-color: var(--warn); }
1169
- .org-node.st-crashed { border-left-color: var(--danger); }
1170
- .org-node.st-working { border-left-color: var(--ok); }
1416
+ .org-node { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; padding: var(--s-3) var(--s-3) var(--s-3) calc(var(--s-3) + 3px); border-radius: var(--r-md); background: var(--surface); --lbar-color: transparent; }
1417
+ .org-node.st-needs, .org-node.st-stuck { --lbar-color: var(--warn); }
1418
+ .org-node.st-crashed { --lbar-color: var(--danger); }
1419
+ .org-node.st-working { --lbar-color: var(--ok); }
1171
1420
  .org-node.st-missing { opacity: 0.7; }
1172
1421
  .org-node-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
1173
1422
  .org-names { flex: 1; min-width: 0; display: flex; flex-direction: column; }
@@ -1260,16 +1509,17 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1260
1509
  .oc { --fx-task: #b794f6; --fx-send: #2dd4bf; --fx-report: #f472b6; --fx-broadcast: #fb923c; --fx-team: #cbd5e1; }
1261
1510
  @media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .oc { --fx-task: #7c3aed; --fx-send: #0f766e; --fx-report: #be185d; --fx-broadcast: #c2410c; --fx-team: #475569; } }
1262
1511
  :root[data-theme="light"] .oc { --fx-task: #7c3aed; --fx-send: #0f766e; --fx-report: #be185d; --fx-broadcast: #c2410c; --fx-team: #475569; }
1263
- .oc-flow { fill: none; stroke-width: 2.5; stroke-linecap: round; }
1512
+ /* #2329: a line's stroke width is its own attribute (fleet-traffic.js strokeOf): its head and its trimmed ends are sized from it. */
1513
+ .oc-flow { fill: none; stroke-linecap: round; }
1264
1514
  .oc-flow-halo { fill: none; stroke: var(--bg); stroke-width: 6; stroke-linecap: round; opacity: 0.85; }
1265
1515
  .oc-flow.h-task { stroke: var(--fx-task); } .oc-flow.h-send { stroke: var(--fx-send); } .oc-flow.h-report { stroke: var(--fx-report); }
1266
- .oc-flow.h-broadcast { stroke: var(--fx-broadcast); } .oc-flow.h-team { stroke: var(--fx-team); stroke-width: 3.5; }
1516
+ .oc-flow.h-broadcast { stroke: var(--fx-broadcast); } .oc-flow.h-team { stroke: var(--fx-team); }
1267
1517
  .oc-flow.ph-live { stroke-dasharray: 7 6; animation: oc-dash 0.9s linear infinite; }
1268
1518
  .oc-flow.ph-queued { stroke-dasharray: 2 5; opacity: 0.8; }
1269
1519
  .oc-flow.ph-fading { stroke: var(--text-3); animation: oc-fade 12s ease-out forwards; }
1270
1520
  /* #1918 review: the work — a delegation in progress (a slow dash, kept until its report), its report coming back, none. */
1271
- .oc-flow.ph-work { stroke-dasharray: 10 7; stroke-width: 3; animation: oc-dash 2.4s linear infinite; }
1272
- .oc-flow.ph-return { stroke-width: 3; animation: oc-fade 2.4s ease-out forwards; }
1521
+ .oc-flow.ph-work { stroke-dasharray: 10 7; animation: oc-dash 2.4s linear infinite; }
1522
+ .oc-flow.ph-return { animation: oc-fade 2.4s ease-out forwards; }
1273
1523
  .oc-flow.ph-stale { stroke: var(--text-3); stroke-dasharray: 3 6; animation: oc-fade 12s ease-out forwards; }
1274
1524
  .oc-ah.h-task { fill: var(--fx-task); } .oc-ah.h-send { fill: var(--fx-send); } .oc-ah.h-report { fill: var(--fx-report); }
1275
1525
  .oc-ah.h-broadcast { fill: var(--fx-broadcast); } .oc-ah.h-team { fill: var(--fx-team); } .oc-ah.h-fading { fill: var(--text-3); }
@@ -1312,6 +1562,49 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1312
1562
  .oc-tools { margin-left: 0; width: 100%; flex-wrap: wrap; row-gap: var(--s-2); }
1313
1563
  .oc-mini { display: none; }
1314
1564
  }
1565
+ /* ── Fleet → Org chart → Office (fleet-office.js): the fleet as a pixel office on one <canvas>. Its size is set through
1566
+ the CSSOM (never a style attribute, #1300); the stage scrolls, the page around it too. ── */
1567
+ .oo { display: flex; flex-direction: column; gap: var(--s-2); }
1568
+ .oo-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
1569
+ .oo-pick { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--text-2); }
1570
+ .oo-pick .tb-select { max-width: 200px; }
1571
+ .oo-people { position: relative; }
1572
+ /* #2399: the offices' minimal editor (fleet-office-editor.js) — one row per office, its members unfolded under it. */
1573
+ .oe-form { border: 0; margin: 0; padding: 0; min-width: 0; }
1574
+ /* #2431: after a 409, the two ways on (keep my edits, load theirs), side by side; they wrap on a phone. */
1575
+ .oe-conflict { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
1576
+ .oe-list { list-style: none; margin: var(--s-3) 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-3); }
1577
+ .oe-row { padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); display: flex; flex-direction: column; gap: var(--s-2); }
1578
+ .oe-head { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s-2); }
1579
+ .oe-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
1580
+ .oe-label { font-size: var(--fs-xs); color: var(--text-2); }
1581
+ .oe-name { min-width: 0; width: 16em; max-width: 100%; }
1582
+ .oe-remove { margin-left: auto; }
1583
+ .oe-members { display: flex; flex-wrap: wrap; gap: var(--s-3); }
1584
+ .oe-group { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; min-width: 12em; max-height: 240px; overflow-y: auto; }
1585
+ .oe-group legend { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); padding: 0; margin-bottom: 4px; }
1586
+ .oo-people > .btn.on { border-color: var(--accent); }
1587
+ .oo-people-pop { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; width: min(280px, calc(100vw - 32px)); max-height: 340px; overflow-y: auto;
1588
+ display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-2); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-2); }
1589
+ .oo-people-pop input[type="search"] { width: 100%; height: 32px; }
1590
+ .oo-people-list { list-style: none; margin: 0; padding: 0; }
1591
+ .oo-people-list label { display: flex; align-items: center; gap: 8px; padding: 3px 2px; font-size: var(--fs-xs); color: var(--text); cursor: pointer; overflow-wrap: anywhere; }
1592
+ .oo-note { font-size: var(--fs-xs); }
1593
+ .oo-stage { position: relative; height: clamp(420px, calc(100dvh - 280px), 960px); overflow: auto; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg); }
1594
+ .oo-canvas { display: block; margin: 0 auto; image-rendering: pixelated; }
1595
+ .oo-canvas.hot { cursor: pointer; }
1596
+ .oo-tip { position: absolute; left: 0; top: 0; z-index: 5; max-width: 240px; pointer-events: none; padding: 6px 10px; font-size: var(--fs-xs); line-height: 1.4;
1597
+ color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-2); overflow-wrap: anywhere; }
1598
+ /* The desks as a list: for a screen reader, and shown (over the stage's corner) while the keyboard is in it. */
1599
+ .oo-desks { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; list-style: none; }
1600
+ .oo-desks:focus-within { position: sticky; left: var(--s-2); bottom: var(--s-2); width: auto; height: auto; max-height: 40%; margin: 0; padding: var(--s-1); clip: auto; overflow-y: auto;
1601
+ display: inline-flex; flex-wrap: wrap; gap: 4px; max-width: calc(100% - 2 * var(--s-2)); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); white-space: normal; }
1602
+ .oo-desk { font-size: var(--fs-xs); padding: 2px 6px; border-radius: var(--r-sm); background: var(--bg); color: var(--text); border: 1px solid var(--border); }
1603
+ .oo-desk:focus-visible { outline: none; border-color: var(--focus); box-shadow: inset 0 -2px 0 var(--focus); }
1604
+ @media (max-width: 640px) {
1605
+ .oo-stage { height: calc(100dvh - 300px); min-height: 340px; }
1606
+ .oo-pick .tb-select { max-width: 150px; }
1607
+ }
1315
1608
  /* A phone: Fleet's five tabs fit when only the open one shows its label (the others keep theirs for screen readers). */
1316
1609
  @media (max-width: 479px) {
1317
1610
  .p-fleet .seg-item:not(.active) > span, .p-settings .seg-item:not(.active) > span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
@@ -1366,9 +1659,9 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1366
1659
  .us-csv { margin-left: auto; }
1367
1660
  .us-custom { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s-2) var(--s-3); font-size: var(--fs-sm); }
1368
1661
  .us-custom label { display: inline-flex; flex-direction: column; gap: 2px; color: var(--text-2); }
1369
- .us-basis { font-size: var(--fs-sm); color: var(--text); padding: var(--s-2) var(--s-3); border-left: 3px solid var(--accent); background: var(--surface-2); border-radius: var(--r-sm); }
1662
+ .us-basis { font-size: var(--fs-sm); color: var(--text); padding: var(--s-2) var(--s-3) var(--s-2) calc(var(--s-3) + 3px); --lbar-color: var(--accent); background: var(--surface-2); border-radius: var(--r-sm); }
1370
1663
  .us-fresh { font-size: var(--fs-xs); }
1371
- .us-partial { font-size: var(--fs-sm); padding: var(--s-2) var(--s-3); border-left: 3px solid var(--warn); background: var(--warn-bg); border-radius: var(--r-sm); }
1664
+ .us-partial { font-size: var(--fs-sm); padding: var(--s-2) var(--s-3) var(--s-2) calc(var(--s-3) + 3px); --lbar-color: var(--warn); background: var(--warn-bg); border-radius: var(--r-sm); }
1372
1665
  .us-unpriced { font-size: var(--fs-xs); }
1373
1666
  .us-scan { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
1374
1667
  .us-totals { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-3); margin: 0; }
@@ -1434,7 +1727,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1434
1727
  .cmd-palette .cmd-arg { color: var(--text-3); }
1435
1728
  .cmd-palette .cmd-none { color: var(--text-3); cursor: default; }
1436
1729
  .cmd-card { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-2); padding: var(--s-2) var(--s-3); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); }
1437
- .cmd-card.bad { border-left: 3px solid var(--danger); }
1730
+ .cmd-card.bad { --lbar-color: var(--danger); padding-left: calc(var(--s-3) + 3px); }
1438
1731
  .cmd-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
1439
1732
  .cmd-name { font-weight: var(--fw-semibold); }
1440
1733
  .cmd-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--font-ui); color: var(--text-2); }
@@ -1549,8 +1842,8 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1549
1842
  .side-widget { padding: 0 var(--s-3) var(--s-2); }
1550
1843
  .aw-sidebar { max-height: 240px; overflow: auto; }
1551
1844
 
1552
- .chat-card-toggle { display: flex; align-items: center; gap: var(--s-2); width: 100%; min-height: 32px; padding: 0 var(--s-4); border: 0; background: none; color: var(--text-2); font: inherit; font-size: var(--fs-xs); text-align: left; cursor: pointer; }
1553
- .chat-card-peek { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-3); }
1845
+ /* The chat header's card menu button (the user, 2026-10-20: no control on the card): pressed-looking while the card shows. */
1846
+ .chat-card-menu > .icon-btn.active { background: var(--accent-dim); color: var(--accent); }
1554
1847
  /* A phone: the portrait stays on the text's row, smaller (the user's ask: never a portrait alone on a line with the text
1555
1848
  under it); the S / M / L control takes the line below. The chat header's card is trimmed further: a smaller portrait
1556
1849
  and banner, and its tagline and bio cut to a few lines (Details and View show them whole). */
@@ -1567,9 +1860,10 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1567
1860
  .id-card.card-c .id-tagline { -webkit-line-clamp: 2; line-clamp: 2; }
1568
1861
  .id-card.card-c .id-bio { -webkit-line-clamp: 3; line-clamp: 3; }
1569
1862
  }
1570
- /* #1629 r4 §1: the card in View (above the profile row) and its part of Edit profile. */
1571
- .v-id { flex-shrink: 0; padding: var(--s-2) var(--s-4) 0; background: var(--bg); }
1863
+ /* #1629 r4 §1: the identity card in View, with Edit profile under it. */
1864
+ .v-id { flex-shrink: 0; padding: var(--s-2) var(--s-4); background: var(--bg); padding-bottom: max(var(--s-2), env(safe-area-inset-bottom)); }
1572
1865
  .v-id .id-card { margin: 0; }
1866
+ .v-id-actions { display: flex; justify-content: flex-end; padding-top: var(--s-2); }
1573
1867
  .form-sub { margin: var(--s-2) 0 0; font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
1574
1868
  /* #1629 r4.1 Q3 (b): Settings → Appearance, the card's upload limits (three to a row; one on a phone). */
1575
1869
  .grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3) var(--s-4); margin-bottom: var(--s-3); }
@@ -1613,7 +1907,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1613
1907
  .p-fleet > .seg, .p-settings > .seg,
1614
1908
  .p-fleet > .panel-body, .p-needs > .panel-body, .p-settings > .panel-body,
1615
1909
  .p-log > .panel-body, .p-details > .panel-body, .p-view > .panel-body,
1616
- .p-log > .log-bar, .p-view > .v-term, .p-view > .v-id, .p-view > .v-card { position: relative; z-index: 1; }
1910
+ .p-log > .log-bar, .p-view > .v-term, .p-view > .v-id { position: relative; z-index: 1; }
1617
1911
  /* Keep the existing Apply bar's sticky behavior, in its own bounded stock band. */
1618
1912
  .p-settings > .s-pending { z-index: 1; }
1619
1913
 
@@ -1628,3 +1922,323 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1628
1922
  .panel-head:has(> .chat-fx-notice) { flex-wrap: wrap; }
1629
1923
  .chat-fx-notice { order: 10; flex: 1 1 100%; min-width: 0; max-width: 100%; font-size: var(--fs-sm); overflow-wrap: anywhere; }
1630
1924
  .chat-fx-notice > span { display: block; }
1925
+
1926
+ /* ── #2293: global search — the sidebar row's shortcut, the header's button (collapsed sidebar, phone), the dialog ── */
1927
+ /* #2478: a touch screen has no Ctrl/⌘ K — the shortcut's hint is not shown there (the row is). */
1928
+ @media (pointer: coarse) { .side-search .kbd-hint { display: none; } }
1929
+ .kbd-hint { font: inherit; font-size: var(--fs-xs); color: var(--text-3); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 0 var(--s-1); line-height: 18px; white-space: nowrap; }
1930
+ .panel-head .sb-search { display: none; }
1931
+ .sb-collapsed .panel-head .sb-search { display: inline-flex; }
1932
+ .chip-btn.on { color: var(--text); background: var(--surface-2); font-weight: var(--fw-semibold); }
1933
+ .dlg.search-dlg { width: min(680px, calc(100vw - 32px)); margin: 10vh auto auto; max-height: 76vh; }
1934
+ .search-box { display: flex; flex-direction: column; max-height: 76vh; }
1935
+ .search-head { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-2) var(--s-2) var(--s-4); border-bottom: 1px solid var(--border); color: var(--text-2); }
1936
+ .search-input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text); font-size: max(16px, var(--fs-lg)); padding: var(--s-2) 0; }
1937
+ .search-input:focus { outline: none; }
1938
+ .search-filters-toggle { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
1939
+ .search-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-4); padding: var(--s-2) var(--s-4); border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
1940
+ .search-field { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--text-2); }
1941
+ .search-field select { max-width: 260px; }
1942
+ /* The filter chips' "on" state in the accent, so it reads apart from the hover and from the folded toggle. */
1943
+ .search-chips .chip-btn.on { background: var(--accent-dim); color: var(--accent); }
1944
+ .search-chips { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px; }
1945
+ .search-mine { display: inline-flex; align-items: center; gap: 6px; margin-left: var(--s-2); color: var(--text-2); cursor: pointer; }
1946
+ .search-mine input { margin: 0; accent-color: var(--accent); }
1947
+ .search-body { flex: 1; min-height: 140px; overflow-y: auto; padding: var(--s-2); }
1948
+ .search-foot { padding: var(--s-2) var(--s-4); border-top: 1px solid var(--border); color: var(--text-3); font-size: var(--fs-xs); }
1949
+ .search-hint, .search-status, .search-note { margin: 0; padding: var(--s-2) var(--s-3); color: var(--text-2); font-size: var(--fs-sm); }
1950
+ .search-status.bad { color: var(--danger); }
1951
+ .search-note { color: var(--warn); }
1952
+ .search-recent-head { display: flex; align-items: center; justify-content: space-between; padding: var(--s-2) var(--s-3) 0; color: var(--text-3); font-size: var(--fs-xs); }
1953
+ .search-recent ul { list-style: none; margin: 0; padding: 0; }
1954
+ .search-recent-item { display: flex; align-items: center; gap: var(--s-2); width: 100%; border: 0; border-radius: 0; --lbar-inset: 4px; background: transparent; color: var(--text); padding: var(--s-2) var(--s-3); font-size: var(--fs-sm); text-align: left; cursor: pointer; }
1955
+ .search-recent-item:hover, .search-recent-item:focus-visible { background: var(--surface-2); }
1956
+ /* Keyboard focus: the bar and a straight underline (no rounded ring). */
1957
+ .search-recent-item:focus-visible { outline: none; box-shadow: inset 0 -2px 0 var(--focus); }
1958
+ .search-recent-item svg { color: var(--text-3); flex: none; }
1959
+ .search-results.stale { opacity: 0.6; }
1960
+ .search-group + .search-group { margin-top: var(--s-2); }
1961
+ .search-group-head { display: flex; justify-content: space-between; gap: var(--s-2); padding: var(--s-2) var(--s-3) var(--s-1); font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); }
1962
+ .search-count { color: var(--text-3); font-weight: var(--fw-regular); }
1963
+ .search-row { padding: var(--s-2) var(--s-3); border-radius: 0; cursor: pointer; }
1964
+ .search-row.on { background: var(--surface-2); }
1965
+ .search-row-top { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-2); }
1966
+ .search-who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1967
+ .search-kind { color: var(--text-3); }
1968
+ .search-time { color: var(--text-3); white-space: nowrap; }
1969
+ .search-badge { flex: none; font-size: 10px; line-height: 16px; font-weight: var(--fw-semibold); padding: 0 6px; border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); }
1970
+ .search-badge.chat { background: var(--accent-dim); color: var(--accent); }
1971
+ .search-badge.xmsg { background: var(--warn-bg); color: var(--warn); }
1972
+ .search-badge.task { background: var(--ok-bg); color: var(--ok); }
1973
+ .search-snippet { margin-top: 2px; font-size: var(--fs-sm); color: var(--text); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
1974
+ .search-snippet mark, .search-ctx-text mark { background: var(--accent-dim); color: inherit; border-radius: 2px; padding: 0 1px; }
1975
+ .search-detail-head { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-1) var(--s-1) var(--s-2); font-size: var(--fs-sm); }
1976
+ .search-detail-head .chip-btn { display: inline-flex; align-items: center; gap: 4px; }
1977
+ .search-ctx { list-style: none; margin: 0; padding: 0 var(--s-1); display: flex; flex-direction: column; gap: var(--s-1); }
1978
+ .search-ctx-line { padding: var(--s-2) var(--s-3); border-radius: 0; }
1979
+ .search-ctx-line.here { background: var(--surface-2); }
1980
+ .search-ctx-text { margin-top: 2px; font-size: var(--fs-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
1981
+ .search-detail-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s-2); padding: var(--s-3) var(--s-1) var(--s-1); }
1982
+ @media (max-width: 899px) {
1983
+ .panel-head .sb-search { display: inline-flex; }
1984
+ .dlg.search-dlg { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border-radius: 0; }
1985
+ .search-box { height: 100%; max-height: 100dvh; padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom); box-sizing: border-box; }
1986
+ .search-foot { display: none; }
1987
+ .search-row { padding: var(--s-3); }
1988
+ .search-filters-toggle, .search-chips .chip-btn { min-height: var(--tap); }
1989
+ }
1990
+ /* The task board (Fleet › Tasks: fleet-tasks.js, fleet-task-card.js). Status colours: to do neutral, in progress the
1991
+ accent, blocked danger, waiting for you warn, done ok. Bars are SVG rects (no style attribute: the CSP). */
1992
+ .tb { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
1993
+ .tb-grow { flex: 1; }
1994
+ .tb-head { flex-wrap: wrap; }
1995
+ .tb-code { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; }
1996
+ .tb-who { font-size: var(--fs-xs); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14em; }
1997
+ .tb-link { color: var(--accent); font-size: var(--fs-xs); background: none; border: 0; padding: 0; cursor: pointer; text-align: left; }
1998
+ .tb-link:hover { text-decoration: underline; }
1999
+ .tb-select { min-height: 30px; padding: 0 var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg); color: var(--text); font-size: var(--fs-xs); max-width: 100%; }
2000
+ .tb-select:disabled, .tb-check input:disabled { opacity: 0.6; cursor: default; }
2001
+ .tb-check { display: inline-flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); color: var(--text-2); cursor: pointer; }
2002
+ .tb-check input { width: auto; min-height: 0; margin: 0; }
2003
+ .tb-form-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }
2004
+ .tb-chev { transition: transform var(--t-fast) var(--ease); transform: rotate(-90deg); }
2005
+ .tb-chev.open { transform: rotate(0deg); }
2006
+
2007
+ .tb-pill, .tb-tag, .tb-flag { display: inline-flex; align-items: center; gap: 2px; font-size: 11px; font-weight: var(--fw-semibold); padding: 1px var(--s-2); border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); white-space: nowrap; }
2008
+ .tb-pill.st-claimed, .tb-tag.st-claimed { background: var(--accent-dim); color: var(--accent); }
2009
+ .tb-pill.st-blocked, .tb-tag.st-blocked, .tb-flag.st-blocked, .tb-tag.p-urgent { background: var(--danger-bg); color: var(--danger); }
2010
+ .tb-pill.st-review, .tb-tag.st-review, .tb-flag.st-review, .tb-tag.p-high { background: var(--warn-bg); color: var(--warn); }
2011
+ .tb-pill.st-done, .tb-tag.st-done { background: var(--ok-bg); color: var(--ok); }
2012
+ .tb-pill.st-cancelled { color: var(--text-3); text-decoration: line-through; }
2013
+ .tb-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); flex-shrink: 0; }
2014
+ .tb-col.st-claimed > .tb-col-head > .tb-dot, .tb-dot.st-claimed { background: var(--accent); }
2015
+ .tb-col.st-blocked > .tb-col-head > .tb-dot, .tb-dot.st-blocked { background: var(--danger); }
2016
+ .tb-col.st-review > .tb-col-head > .tb-dot, .tb-dot.st-review { background: var(--warn); }
2017
+ .tb-col.st-done > .tb-col-head > .tb-dot, .tb-dot.st-done { background: var(--ok); }
2018
+
2019
+ .tb-bar { width: 96px; height: 6px; border-radius: var(--r-full); overflow: hidden; flex-shrink: 0; }
2020
+ .tb-bar.wide { width: 100%; flex-shrink: 1; }
2021
+ .tb-bar-track { fill: var(--surface-2); }
2022
+ .tb-seg.st-done { fill: var(--ok); }
2023
+ .tb-seg.st-review { fill: var(--warn); }
2024
+ .tb-seg.st-claimed { fill: var(--accent); }
2025
+ .tb-seg.st-blocked { fill: var(--danger); }
2026
+ .tb-pct { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
2027
+
2028
+ /* Home: what waits for the person, then the projects. */
2029
+ .tb-home { display: flex; flex-direction: column; gap: var(--s-4); }
2030
+ /* The public link: the board is shown, not changed. */
2031
+ .tb-readonly { display: flex; align-items: center; gap: var(--s-2); margin: 0 0 var(--s-3); padding: var(--s-2) var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); color: var(--text-2); font-size: var(--fs-sm); }
2032
+ .tb-home > .list-head { margin: 0; }
2033
+ .tb-section-title { display: flex; align-items: center; gap: var(--s-2); margin: 0 0 var(--s-2); font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-2); }
2034
+ .tb-waiting { padding: var(--s-3); border: 1px solid var(--warn-line); border-radius: var(--r-lg); }
2035
+ .tb-wait-row { flex-wrap: wrap; align-items: flex-start; }
2036
+ /* #2299: the pill sits on the title's first line (one baseline); the reason, under the title; the actions after. */
2037
+ .tb-wait-main { flex: 1 1 320px; min-width: 0; display: flex; align-items: baseline; gap: var(--s-2) var(--s-3); }
2038
+ .tb-wait-main > .tb-pill { flex-shrink: 0; min-width: 112px; justify-content: center; }
2039
+ .tb-wait-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-left: auto; }
2040
+ .tb-wait-actions .btn { min-width: 88px; padding: 0 var(--s-4); }
2041
+ .tb-wait-title { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2); background: none; border: 0; padding: 0; color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); }
2042
+ .tb-wait-title:hover { text-decoration: underline; }
2043
+ .tb-wait-reason { flex-basis: 100%; margin-top: 2px; color: var(--danger); font-size: var(--fs-xs); line-height: var(--lh-xs); overflow-wrap: anywhere; }
2044
+ .tb-projects { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--s-3); }
2045
+ .tb-project { position: relative; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); min-width: 0; }
2046
+ .tb-project:hover { border-color: var(--border-strong); }
2047
+ .tb-project.is-archived { opacity: 0.7; }
2048
+ .tb-project-open { display: flex; flex-direction: column; gap: var(--s-2); width: 100%; padding: var(--s-4); padding-right: calc(var(--s-4) + 32px); background: none; border: 0; color: inherit; text-align: left; cursor: pointer; border-radius: inherit; }
2049
+ .tb-project-name { font-weight: var(--fw-bold); font-size: var(--fs-md); overflow-wrap: anywhere; }
2050
+ .tb-project-desc { color: var(--text-2); font-size: var(--fs-xs); overflow-wrap: anywhere; }
2051
+ .tb-project-pct { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); }
2052
+ .tb-project-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-3); font-size: var(--fs-xs); color: var(--text-2); }
2053
+ .tb-project-menu { position: absolute; top: var(--s-2); right: var(--s-2); }
2054
+ .tb-archived { display: flex; flex-direction: column; gap: var(--s-2); align-items: flex-start; }
2055
+ .tb-archived > .tb-projects { align-self: stretch; }
2056
+
2057
+ .tb-search { position: relative; min-width: 180px; flex: 0 1 280px; }
2058
+ .tb-search input { width: 100%; min-height: 34px; padding: 0 var(--s-3) 0 30px; border: 1px solid var(--border); border-radius: var(--r-full); background: var(--bg); color: var(--text); font-size: var(--fs-sm); }
2059
+ .tb-search input:focus { border-color: var(--focus); outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
2060
+ .tb-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; }
2061
+ .tb-search-results { position: absolute; z-index: 5; top: calc(100% + 4px); right: 0; width: min(440px, calc(100vw - 32px)); max-height: 60vh; overflow-y: auto; margin: 0; padding: var(--s-1); list-style: none; background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--r-md); box-shadow: var(--shadow-2); }
2062
+ .tb-search-results button { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); width: 100%; padding: var(--s-2); background: none; border: 0; border-radius: var(--r-sm); color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); }
2063
+ .tb-search-results li.active button, .tb-search-results button:hover { background: var(--surface-2); }
2064
+ .tb-search-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
2065
+ .tb-search-where { flex-basis: 100%; font-size: var(--fs-xs); overflow-wrap: anywhere; }
2066
+ .tb-search-none { padding: var(--s-2); font-size: var(--fs-sm); }
2067
+
2068
+ /* A project: its header, then one column per status. */
2069
+ .tb-bar-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
2070
+ .tb-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2); min-width: 0; }
2071
+ .tb-title h2 { margin: 0; font-size: var(--fs-lg); overflow-wrap: anywhere; }
2072
+ .tb-stats { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); }
2073
+ .tb-scroll { overflow-x: auto; margin: 0 calc(-1 * var(--s-2)); padding: 0 var(--s-2) var(--s-2); }
2074
+ /* #2299: 176 px a column fits all five beside the sidebar from 1280 px wide (220 px cut Done off at 1366). */
2075
+ .tb-columns { display: grid; grid-template-columns: repeat(5, minmax(176px, 1fr)); gap: var(--s-3); align-items: start; min-width: min-content; }
2076
+ .tb-col { display: flex; flex-direction: column; gap: var(--s-2); min-height: 120px; padding: var(--s-2); border-radius: var(--r-lg); background: var(--surface); border: 1px dashed transparent; }
2077
+ .tb-col.can-drop { border-color: var(--border); }
2078
+ .tb-col.over { border-color: var(--accent); background: var(--accent-dim); }
2079
+ .tb-col-head { display: flex; align-items: center; gap: var(--s-2); margin: 0; padding: var(--s-1) var(--s-1) 0; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); text-transform: uppercase; letter-spacing: 0.04em; }
2080
+ .tb-col-head .tb-link { text-transform: none; letter-spacing: 0; font-weight: var(--fw-regular); }
2081
+ .tb-count { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-3); }
2082
+ .tb-drop-line { height: 3px; border-radius: 2px; background: var(--accent); }
2083
+
2084
+ .tb-tile { display: flex; flex-direction: column; gap: var(--s-2); padding: var(--s-3) var(--s-3) var(--s-3) calc(var(--s-3) + 2px); border-radius: var(--r-md); background: var(--bg); border: 1px solid var(--border); box-shadow: var(--shadow-1); --lbar-color: transparent; cursor: pointer; font-size: var(--fs-sm); min-width: 0; }
2085
+ .tb-tile:hover { border-color: var(--border-strong); box-shadow: var(--shadow-2); }
2086
+ /* As taskhall: the shared straight bar (#2330) only while the card is under way (in progress, blocked, waiting for
2087
+ you); none on to do or done, and a done tile is dimmed. */
2088
+ .tb-tile.st-claimed { --lbar-color: var(--accent); }
2089
+ .tb-tile.st-blocked { --lbar-color: var(--danger); }
2090
+ .tb-tile.st-review { --lbar-color: var(--warn); }
2091
+ .tb-tile.st-done { background: color-mix(in srgb, var(--bg) 60%, var(--surface)); box-shadow: none; }
2092
+ .tb-tile.st-done .tb-tile-title { color: var(--text-2); }
2093
+ .tb-tile.dragging { opacity: 0.4; }
2094
+ .tb-tile.flash { animation: tb-flash 1.6s var(--ease); }
2095
+ @keyframes tb-flash { from { box-shadow: 0 0 0 3px var(--accent-dim); background: var(--accent-dim); } to { box-shadow: none; } }
2096
+ .tb-tile-top { display: flex; align-items: center; gap: var(--s-2); }
2097
+ .tb-size { padding: 0 5px; border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 11px; font-weight: var(--fw-bold); line-height: 16px; color: var(--text-3); }
2098
+ /* The tile's control: its title, a plain-looking button (Enter opens the card, Alt+arrows move it). */
2099
+ .tb-tile-title { display: block; width: 100%; padding: 0; background: none; border: 0; border-radius: var(--r-sm); color: var(--text); font: inherit; font-weight: var(--fw-semibold); line-height: 1.4; text-align: left; cursor: pointer; overflow-wrap: anywhere; }
2100
+ .tb-tile-title:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
2101
+ .tb-tile:has(.tb-tile-title:focus-visible) { border-color: var(--focus); }
2102
+ .tb-tile-note { display: flex; gap: var(--s-1); align-items: flex-start; font-size: var(--fs-xs); color: var(--text-2); overflow-wrap: anywhere; }
2103
+ /* A main task's sub task at work now (its worker in the foot), and what a card waiting for you still lacks. */
2104
+ .tb-tile-now { display: flex; align-items: baseline; gap: var(--s-1); min-width: 0; font-size: var(--fs-xs); color: var(--text-2); }
2105
+ .tb-now-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2106
+ .tb-now-label { flex-shrink: 0; font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-2); }
2107
+ .tb-now-label.st-claimed { color: var(--accent); }
2108
+ .tb-now-label.st-blocked { color: var(--danger); }
2109
+ .tb-now-label.st-review { color: var(--warn); }
2110
+ .tb-tag.wrapup { background: var(--warn-bg); color: var(--warn); }
2111
+ .tb-wait-reason.wrapup, .tc-hint.wrapup { color: var(--warn); }
2112
+ .tb-wait-asked { flex-basis: 100%; font-size: var(--fs-xs); }
2113
+ .tc-now { display: flex; align-items: baseline; gap: var(--s-2); width: 100%; padding: 0; background: none; border: 0; color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); }
2114
+ .tc-now:hover .tc-child-title { text-decoration: underline; }
2115
+ .tb-tile-note.st-blocked { color: var(--danger); }
2116
+ .tb-tile-progress { display: flex; align-items: center; gap: var(--s-2); width: 100%; padding: 0; background: none; border: 0; color: var(--text-2); font-size: var(--fs-xs); cursor: pointer; }
2117
+ .tb-tile-progress > span { white-space: nowrap; }
2118
+ .tb-tile-progress > .tb-bar { flex: 1; min-width: 40px; }
2119
+ .tb-subs { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--border); padding-top: var(--s-2); }
2120
+ .tb-subs button { display: flex; align-items: center; gap: var(--s-2); width: 100%; padding: 2px var(--s-1); background: none; border: 0; border-radius: var(--r-sm); color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-xs); }
2121
+ .tb-subs button:hover { background: var(--surface-2); }
2122
+ .tb-sub-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2123
+ .tb-sub-blocked { padding-left: 22px; font-size: var(--fs-xs); color: var(--danger); overflow-wrap: anywhere; }
2124
+ .tb-sub-more { font-size: var(--fs-xs); padding-left: var(--s-1); }
2125
+ .tb-tile-foot { display: flex; align-items: center; gap: var(--s-2); }
2126
+ .tb-tile-foot > .tb-who, .tb-tile-foot > .tb-person, .tb-tile-foot > .tb-people { flex: 1; min-width: 0; max-width: none; }
2127
+ .tb-people { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-3); }
2128
+ /* Who (fleet-task-common.js): a round initial — the instance's identity colour when it has one — then the name. */
2129
+ .tb-person { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
2130
+ .tb-person > .tb-who { min-width: 0; }
2131
+ .tb-person.none > .tb-who { color: var(--text-3); }
2132
+ .tb-av { display: inline-grid; place-items: center; width: 20px; height: 20px; flex: none; border-radius: 50%; font-size: 11px; font-weight: var(--fw-bold); line-height: 1;
2133
+ background: color-mix(in srgb, var(--id, var(--text-3)) 16%, var(--bg)); color: var(--id-name, var(--text-2)); }
2134
+ .tb-tile-stats { display: inline-flex; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-3); }
2135
+ .tb-tile-stats > span { display: inline-flex; align-items: center; gap: 2px; }
2136
+ .tb-tile-stats > .all { color: var(--ok); }
2137
+ .tb-tile-stats > .reply { color: var(--accent); }
2138
+
2139
+ /* #2246 step 3: who works on what (fleet-task-work.js) — the board's Instance drawer and the Details page's block. */
2140
+ .tw { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
2141
+ .tw-head { margin: 0; font-size: var(--fs-sm); }
2142
+ .tw-error { margin: 0; color: var(--danger); font-size: var(--fs-sm); }
2143
+ .tw-group { display: flex; flex-direction: column; gap: var(--s-2); }
2144
+ .tw-group-head { display: flex; align-items: center; gap: var(--s-2); margin: 0; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); }
2145
+ .tw-inst { display: flex; flex-direction: column; gap: var(--s-1); padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg); min-width: 0; }
2146
+ .tw-inst-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
2147
+ .tw-inst-head .av { width: 24px; height: 24px; font-size: 11px; }
2148
+ .tw-inst-head .av .av-dot { box-shadow: 0 0 0 2px var(--bg); }
2149
+ .tw-name { font-weight: var(--fw-semibold); font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
2150
+ .tw-state { font-size: var(--fs-xs); white-space: nowrap; }
2151
+ .tw-alt { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
2152
+ .tw-desc { margin: 0; font-size: var(--fs-xs); overflow-wrap: anywhere; }
2153
+ .tw-none { margin: 0; font-size: var(--fs-xs); }
2154
+ .tw-lines { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
2155
+ .tw-line { display: flex; align-items: baseline; gap: var(--s-2); width: 100%; padding: 2px var(--s-1); background: none; border: 0; border-radius: 0; --lbar-inset: 2px; color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); min-width: 0; }
2156
+ .tw-line:hover { background: var(--surface-2); }
2157
+ .tw-line:focus-visible { outline: none; background: var(--surface-2); box-shadow: inset 0 -2px 0 var(--focus); }
2158
+ .tw-kind { flex-shrink: 0; min-width: 4.5em; font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-2); }
2159
+ .tw-kind.k-doing { color: var(--accent); }
2160
+ .tw-kind.k-blocked, .tw-kind.k-back { color: var(--danger); }
2161
+ .tw-kind.k-review { color: var(--warn); }
2162
+ .tw-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2163
+ .tw-note { flex-shrink: 0; font-size: var(--fs-xs); white-space: nowrap; }
2164
+ .tw-unread { flex-shrink: 0; display: inline-flex; color: var(--accent); }
2165
+ .d-board .tw-lines { margin-top: var(--s-1); }
2166
+
2167
+ /* One card, in the app's dialog. */
2168
+ .tc { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; }
2169
+ .tc-head { display: flex; align-items: center; gap: var(--s-2); }
2170
+ .tc-title { flex: 1; min-width: 0; padding: var(--s-1) var(--s-2); margin-left: calc(-1 * var(--s-2)); background: none; border: 1px solid transparent; border-radius: var(--r-sm); color: var(--text); font: inherit; font-size: var(--fs-lg); font-weight: var(--fw-semibold); text-align: left; cursor: text; overflow-wrap: anywhere; }
2171
+ .tc-title:hover { border-color: var(--border); }
2172
+ .tc-title-input { flex: 1; min-width: 0; padding: var(--s-1) var(--s-2); border: 1px solid var(--focus); border-radius: var(--r-sm); background: var(--bg); color: var(--text); font-size: max(16px, var(--fs-lg)); font-weight: var(--fw-semibold); }
2173
+ .tc-ver { font-size: var(--fs-xs); }
2174
+ .tc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding-bottom: var(--s-3); border-bottom: 1px solid var(--border); }
2175
+ .tc-hint { font-size: var(--fs-xs); }
2176
+ .tc-meta { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s-2) var(--s-4); margin: 0; padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); align-items: center; }
2177
+ .tc-meta dt { color: var(--text-2); }
2178
+ .tc-meta dd { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin: 0; min-width: 0; }
2179
+ .tc-value { color: var(--text); overflow-wrap: anywhere; }
2180
+ .tc-dep { padding: 1px var(--s-2); border: 1px solid var(--ok); border-radius: var(--r-full); background: none; color: var(--ok); font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer; }
2181
+ .tc-dep.waiting { border-color: var(--warn); color: var(--warn); }
2182
+ .tc-field h3 { margin: 0 0 var(--s-1); font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); text-transform: uppercase; letter-spacing: 0.04em; }
2183
+ .tc-field.tone-blocked h3 { color: var(--danger); }
2184
+ .tc-text { display: block; width: 100%; padding: var(--s-2); background: none; border: 1px solid transparent; border-radius: var(--r-sm); color: var(--text); font: inherit; font-size: var(--fs-sm); text-align: left; white-space: pre-wrap; overflow-wrap: anywhere; cursor: text; }
2185
+ .tc-text:hover { border-color: var(--border); background: var(--surface); }
2186
+ .tc-text.empty { color: var(--text-3); }
2187
+ .tc-edit textarea, .tc-composer textarea, .tc-quick-add { width: 100%; padding: var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg); color: var(--text); font-size: var(--fs-sm); resize: vertical; }
2188
+ .tc-edit textarea:focus, .tc-composer textarea:focus, .tc-quick-add:focus { border-color: var(--focus); outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
2189
+ .tc-edit-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-1); font-size: var(--fs-xs); }
2190
+ .tc-counter { font-variant-numeric: tabular-nums; color: var(--text-3); }
2191
+ .tc-counter.over { color: var(--danger); font-weight: var(--fw-semibold); }
2192
+ .tc-checklist { display: flex; flex-direction: column; gap: var(--s-1); margin: 0 0 var(--s-1); padding: 0; list-style: none; }
2193
+ .tc-checklist .done { color: var(--text-3); text-decoration: line-through; }
2194
+ .tc-children { display: flex; flex-direction: column; gap: 2px; margin: 0 0 var(--s-2); padding: 0; list-style: none; }
2195
+ .tc-children button { display: flex; align-items: center; gap: var(--s-2); width: 100%; padding: var(--s-1) var(--s-2); background: none; border: 0; border-radius: var(--r-sm); color: var(--text); text-align: left; cursor: pointer; font-size: var(--fs-sm); }
2196
+ .tc-children button:hover { background: var(--surface); }
2197
+ .tc-child-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
2198
+ .tc-tabs { padding: 0; margin: var(--s-2) 0 0; max-width: none; }
2199
+ .tc-feed { display: flex; flex-direction: column; gap: var(--s-1); margin: 0; padding: 0; list-style: none; font-size: var(--fs-sm); overflow-wrap: anywhere; }
2200
+ .tc-comments { display: flex; flex-direction: column; gap: var(--s-2); }
2201
+ .tc-comment { padding: var(--s-2) var(--s-3); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); }
2202
+ .tc-comment.person { background: var(--accent-dim); }
2203
+ .tc-comment-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-bottom: 2px; font-size: var(--fs-xs); }
2204
+ .tc-comment-body { white-space: pre-wrap; overflow-wrap: anywhere; }
2205
+ .tc-composer { display: flex; gap: var(--s-2); align-items: flex-end; }
2206
+
2207
+ @media (max-width: 899px) {
2208
+ /* A phone stacks the columns: no sideways scrolling, and a card moves through its dialog's "Move to…". */
2209
+ .tb-scroll { overflow-x: visible; margin: 0; padding: 0; }
2210
+ .tb-columns { grid-template-columns: minmax(0, 1fr); min-width: 0; }
2211
+ .tb-col { min-height: 0; }
2212
+ .tb-form-row { grid-template-columns: minmax(0, 1fr); }
2213
+ .tb-search { flex: 1 1 100%; }
2214
+ /* The card's sheet keeps its fields full width (the grey block is the desk drawer's). */
2215
+ .tc-meta { padding: 0; background: none; }
2216
+ /* #2299: a phone's waiting row: pill and title on one line, the actions under them (assignee left, buttons right). */
2217
+ .tb-wait-main > .tb-pill { min-width: 0; }
2218
+ .tb-wait-actions { flex-basis: 100%; margin-left: 0; }
2219
+ .tb-wait-actions > .muted { margin-right: auto; }
2220
+ /* #2299: on the board its toasts come in above the tabs, not over its title, search and progress — unless a card's
2221
+ sheet is open (its buttons are at the bottom). */
2222
+ .shell:has(.tb-home, .tb-board-page):not(:has(dialog[open])) .toasts { top: auto; bottom: calc(56px + env(safe-area-inset-bottom) + var(--s-3)); }
2223
+ /* …and they do not pile down the board: an older confirmation gives way to two newer toasts; an error never does. */
2224
+ .shell:has(.tb-home, .tb-board-page) .toasts > .toast.ok:nth-last-child(n+3) { display: none; }
2225
+ }
2226
+ /* On a desk a project's columns reach the bottom of the page, as taskhall's: a card drops anywhere down a column, and
2227
+ an empty column still reads as one. The page's column, the board and its scroller pass the height down as flex. */
2228
+ @media (min-width: 900px) {
2229
+ .col:has(> .tb > .tb-board-page) { display: flex; flex-direction: column; min-height: 100%; }
2230
+ .tb:has(> .tb-board-page) { flex: 1; }
2231
+ .tb-board-page { display: flex; flex-direction: column; flex: 1; }
2232
+ .tb-board-page > .tb-scroll { display: flex; flex-direction: column; flex: 1; }
2233
+ .tb-board-page .tb-columns { flex: 1; align-items: stretch; }
2234
+ }
2235
+ @media (prefers-reduced-motion: reduce) {
2236
+ .tb-tile.flash { animation: none; }
2237
+ .tb-chev { transition: none; }
2238
+ }
2239
+
2240
+ /* #2305: the agent's reactions to a message (its minimal reply), under the bubble — on the person's side for theirs. */
2241
+ .msg-reactions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
2242
+ .msg.user .msg-reactions { justify-content: flex-end; }
2243
+ .msg-reactions .reaction { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 24px; padding: 0 6px;
2244
+ border: 1px solid var(--border); border-radius: var(--r-full); background: var(--surface-2); font-family: var(--font-emoji); font-size: 15px; line-height: 1; }