@songsid/agend 2.3.0-beta.8 → 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 (736) 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 +9 -2
  8. package/dist/agent-cli.js +44 -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 +54 -11
  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 +43 -6
  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.d.ts +25 -0
  144. package/dist/decision-list.js +30 -0
  145. package/dist/decision-list.js.map +1 -0
  146. package/dist/delivery-consumed-watch.js.map +1 -1
  147. package/dist/delivery-outbox.js +5 -0
  148. package/dist/delivery-outbox.js.map +1 -1
  149. package/dist/delivery-outbox.test.js.map +1 -1
  150. package/dist/delivery-reconciliation.test.js.map +1 -1
  151. package/dist/diagnostic-redaction.d.ts +10 -0
  152. package/dist/diagnostic-redaction.js +167 -0
  153. package/dist/diagnostic-redaction.js.map +1 -0
  154. package/dist/doctor.d.ts +8 -0
  155. package/dist/doctor.js +52 -0
  156. package/dist/doctor.js.map +1 -1
  157. package/dist/e2e-isolation.js.map +1 -1
  158. package/dist/event-log.js.map +1 -1
  159. package/dist/export-import.js +7 -5
  160. package/dist/export-import.js.map +1 -1
  161. package/dist/fleet-control-audit.js.map +1 -1
  162. package/dist/fleet-label.js.map +1 -1
  163. package/dist/fleet-level-config.d.ts +1 -1
  164. package/dist/fleet-level-config.js +2 -0
  165. package/dist/fleet-level-config.js.map +1 -1
  166. package/dist/fleet-lock.js +3 -2
  167. package/dist/fleet-lock.js.map +1 -1
  168. package/dist/fleet-manager.d.ts +258 -15
  169. package/dist/fleet-manager.js +1605 -304
  170. package/dist/fleet-manager.js.map +1 -1
  171. package/dist/fleet-process-handlers.d.ts +18 -0
  172. package/dist/fleet-process-handlers.js +70 -0
  173. package/dist/fleet-process-handlers.js.map +1 -0
  174. package/dist/fleet-startup.d.ts +14 -0
  175. package/dist/fleet-startup.js +30 -0
  176. package/dist/fleet-startup.js.map +1 -0
  177. package/dist/fleet-traffic.d.ts +36 -0
  178. package/dist/fleet-traffic.js +100 -0
  179. package/dist/fleet-traffic.js.map +1 -1
  180. package/dist/forged-envelope-scan.d.ts +0 -20
  181. package/dist/forged-envelope-scan.js +3 -2
  182. package/dist/forged-envelope-scan.js.map +1 -1
  183. package/dist/full-restart.d.ts +5 -5
  184. package/dist/full-restart.js +5 -5
  185. package/dist/full-restart.js.map +1 -1
  186. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  187. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  188. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  189. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  190. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  191. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  192. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  193. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  194. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  195. package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
  196. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  197. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
  198. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  199. package/dist/general-knowledge/steering/core-rules.md +1 -1
  200. package/dist/host-memory.js.map +1 -1
  201. package/dist/idle-gate-log.d.ts +19 -0
  202. package/dist/idle-gate-log.js +15 -0
  203. package/dist/idle-gate-log.js.map +1 -0
  204. package/dist/instance-config-impact.js +25 -4
  205. package/dist/instance-config-impact.js.map +1 -1
  206. package/dist/instance-lifecycle.d.ts +10 -1
  207. package/dist/instance-lifecycle.js +86 -25
  208. package/dist/instance-lifecycle.js.map +1 -1
  209. package/dist/instructions.d.ts +12 -6
  210. package/dist/instructions.js +19 -10
  211. package/dist/instructions.js.map +1 -1
  212. package/dist/kiro-compact-pane.js.map +1 -1
  213. package/dist/kiro-db-reader.js.map +1 -1
  214. package/dist/kiro-engine-status.js.map +1 -1
  215. package/dist/kiro-log-gate.js.map +1 -1
  216. package/dist/kiro-transcript-lane.js.map +1 -1
  217. package/dist/locale.js +428 -20
  218. package/dist/locale.js.map +1 -1
  219. package/dist/log-service.js.map +1 -1
  220. package/dist/log-steps.d.ts +1 -0
  221. package/dist/log-steps.js +15 -0
  222. package/dist/log-steps.js.map +1 -1
  223. package/dist/logger.js +3 -2
  224. package/dist/logger.js.map +1 -1
  225. package/dist/login-controller.d.ts +45 -0
  226. package/dist/login-controller.js +101 -5
  227. package/dist/login-controller.js.map +1 -1
  228. package/dist/login-flows.js +1 -1
  229. package/dist/login-manager.js.map +1 -1
  230. package/dist/login-shell.js +3 -1
  231. package/dist/login-shell.js.map +1 -1
  232. package/dist/ls-attach-resolve.d.ts +96 -0
  233. package/dist/ls-attach-resolve.js +180 -0
  234. package/dist/ls-attach-resolve.js.map +1 -0
  235. package/dist/ls-rows.d.ts +12 -0
  236. package/dist/ls-rows.js +83 -4
  237. package/dist/ls-rows.js.map +1 -1
  238. package/dist/memory-pressure.js.map +1 -1
  239. package/dist/muse-usage-relay.js.map +1 -1
  240. package/dist/needs-you-hub.d.ts +98 -1
  241. package/dist/needs-you-hub.js +313 -44
  242. package/dist/needs-you-hub.js.map +1 -1
  243. package/dist/needs-you-live.d.ts +5 -2
  244. package/dist/needs-you-live.js +6 -3
  245. package/dist/needs-you-live.js.map +1 -1
  246. package/dist/needs-you.d.ts +68 -3
  247. package/dist/needs-you.js +38 -4
  248. package/dist/needs-you.js.map +1 -1
  249. package/dist/network-family.js.map +1 -1
  250. package/dist/operator-control-paths.js +3 -4
  251. package/dist/operator-control-paths.js.map +1 -1
  252. package/dist/outbound-handlers.d.ts +3 -0
  253. package/dist/outbound-handlers.js +76 -19
  254. package/dist/outbound-handlers.js.map +1 -1
  255. package/dist/outbound-schemas.d.ts +112 -64
  256. package/dist/outbound-schemas.js +39 -12
  257. package/dist/outbound-schemas.js.map +1 -1
  258. package/dist/outbox-open-error.js.map +1 -1
  259. package/dist/pane-context-cache.js.map +1 -1
  260. package/dist/paths.js.map +1 -1
  261. package/dist/private-dir.js.map +1 -1
  262. package/dist/probe-worker-pool.js.map +1 -1
  263. package/dist/profile-control.js.map +1 -1
  264. package/dist/prompt-file-ref.js.map +1 -1
  265. package/dist/provider-probe.js.map +1 -1
  266. package/dist/provider-secret-registry.d.ts +5 -3
  267. package/dist/provider-secret-registry.js +8 -2
  268. package/dist/provider-secret-registry.js.map +1 -1
  269. package/dist/public-link-auto-open.d.ts +32 -0
  270. package/dist/public-link-auto-open.js +86 -0
  271. package/dist/public-link-auto-open.js.map +1 -0
  272. package/dist/public-link-owner.d.ts +10 -0
  273. package/dist/public-link-owner.js +36 -0
  274. package/dist/public-link-owner.js.map +1 -0
  275. package/dist/public-link-progress.d.ts +12 -1
  276. package/dist/public-link-progress.js +5 -10
  277. package/dist/public-link-progress.js.map +1 -1
  278. package/dist/public-preview.js.map +1 -1
  279. package/dist/public-tunnel-config.d.ts +11 -0
  280. package/dist/public-tunnel-config.js +68 -0
  281. package/dist/public-tunnel-config.js.map +1 -0
  282. package/dist/public-web-gateway.d.ts +2 -0
  283. package/dist/public-web-gateway.js +19 -6
  284. package/dist/public-web-gateway.js.map +1 -1
  285. package/dist/public-web-link.d.ts +48 -3
  286. package/dist/public-web-link.js +177 -51
  287. package/dist/public-web-link.js.map +1 -1
  288. package/dist/quickstart-api.d.ts +9 -0
  289. package/dist/quickstart-api.js +82 -0
  290. package/dist/quickstart-api.js.map +1 -1
  291. package/dist/quickstart.d.ts +5 -0
  292. package/dist/quickstart.js +40 -25
  293. package/dist/quickstart.js.map +1 -1
  294. package/dist/reply-buttons-controller.js.map +1 -1
  295. package/dist/reply-dedup.js.map +1 -1
  296. package/dist/resource-report.js +1 -1
  297. package/dist/resource-report.js.map +1 -1
  298. package/dist/restart-guard.js.map +1 -1
  299. package/dist/restart-progress.d.ts +80 -1
  300. package/dist/restart-progress.js +306 -21
  301. package/dist/restart-progress.js.map +1 -1
  302. package/dist/rollout-index.js.map +1 -1
  303. package/dist/runtime-cpu-profile.js.map +1 -1
  304. package/dist/scheduler/db.d.ts +40 -13
  305. package/dist/scheduler/db.js +123 -89
  306. package/dist/scheduler/db.js.map +1 -1
  307. package/dist/scheduler/scheduler.js.map +1 -1
  308. package/dist/scheduler/task-board-text.d.ts +26 -0
  309. package/dist/scheduler/task-board-text.js +140 -0
  310. package/dist/scheduler/task-board-text.js.map +1 -0
  311. package/dist/scheduler/task-board.d.ts +730 -0
  312. package/dist/scheduler/task-board.js +2179 -0
  313. package/dist/scheduler/task-board.js.map +1 -0
  314. package/dist/scheduler/types.d.ts +6 -1
  315. package/dist/sd-notify.js +2 -1
  316. package/dist/sd-notify.js.map +1 -1
  317. package/dist/search/search-docs.d.ts +58 -0
  318. package/dist/search/search-docs.js +63 -0
  319. package/dist/search/search-docs.js.map +1 -0
  320. package/dist/search/search-index.d.ts +141 -0
  321. package/dist/search/search-index.js +440 -0
  322. package/dist/search/search-index.js.map +1 -0
  323. package/dist/search/search-store.d.ts +122 -0
  324. package/dist/search/search-store.js +236 -0
  325. package/dist/search/search-store.js.map +1 -0
  326. package/dist/search/search-worker.d.ts +1 -0
  327. package/dist/search/search-worker.js +163 -0
  328. package/dist/search/search-worker.js.map +1 -0
  329. package/dist/secret-file.js.map +1 -1
  330. package/dist/secret-store.d.ts +2 -0
  331. package/dist/secret-store.js +21 -0
  332. package/dist/secret-store.js.map +1 -1
  333. package/dist/service-installer.d.ts +75 -0
  334. package/dist/service-installer.js +206 -0
  335. package/dist/service-installer.js.map +1 -1
  336. package/dist/service-owner.d.ts +44 -0
  337. package/dist/service-owner.js +48 -0
  338. package/dist/service-owner.js.map +1 -0
  339. package/dist/service-plan.d.ts +39 -2
  340. package/dist/service-plan.js +188 -6
  341. package/dist/service-plan.js.map +1 -1
  342. package/dist/session-oom.d.ts +21 -0
  343. package/dist/session-oom.js +139 -0
  344. package/dist/session-oom.js.map +1 -0
  345. package/dist/settings-api.d.ts +13 -0
  346. package/dist/settings-api.js +73 -12
  347. package/dist/settings-api.js.map +1 -1
  348. package/dist/settings-baseline.js.map +1 -1
  349. package/dist/settings-change.d.ts +5 -0
  350. package/dist/settings-change.js +167 -6
  351. package/dist/settings-change.js.map +1 -1
  352. package/dist/settings-confirmation.d.ts +9 -1
  353. package/dist/settings-confirmation.js +18 -8
  354. package/dist/settings-confirmation.js.map +1 -1
  355. package/dist/settings-control.js +2 -1
  356. package/dist/settings-control.js.map +1 -1
  357. package/dist/settings-effect.js +29 -4
  358. package/dist/settings-effect.js.map +1 -1
  359. package/dist/settings-http-confirmation.d.ts +13 -0
  360. package/dist/settings-http-confirmation.js +15 -3
  361. package/dist/settings-http-confirmation.js.map +1 -1
  362. package/dist/settings-instance-patch.js +13 -1
  363. package/dist/settings-instance-patch.js.map +1 -1
  364. package/dist/settings-request-capability.d.ts +4 -1
  365. package/dist/settings-request-capability.js +11 -3
  366. package/dist/settings-request-capability.js.map +1 -1
  367. package/dist/settings-transaction.js.map +1 -1
  368. package/dist/setup-auth.d.ts +1 -0
  369. package/dist/setup-auth.js +2 -1
  370. package/dist/setup-auth.js.map +1 -1
  371. package/dist/setup-form.d.ts +1 -1
  372. package/dist/setup-form.js +23 -7
  373. package/dist/setup-form.js.map +1 -1
  374. package/dist/setup-host.d.ts +6 -1
  375. package/dist/setup-host.js +15 -4
  376. package/dist/setup-host.js.map +1 -1
  377. package/dist/setup-wizard.js +6 -3
  378. package/dist/setup-wizard.js.map +1 -1
  379. package/dist/spawn-gate.d.ts +5 -0
  380. package/dist/spawn-gate.js +28 -8
  381. package/dist/spawn-gate.js.map +1 -1
  382. package/dist/start-attempt.d.ts +1 -0
  383. package/dist/start-attempt.js +18 -0
  384. package/dist/start-attempt.js.map +1 -0
  385. package/dist/start-failure-notice.d.ts +4 -0
  386. package/dist/start-failure-notice.js +20 -0
  387. package/dist/start-failure-notice.js.map +1 -0
  388. package/dist/start-failure.d.ts +147 -0
  389. package/dist/start-failure.js +281 -0
  390. package/dist/start-failure.js.map +1 -0
  391. package/dist/startup-memory-deadline.d.ts +23 -0
  392. package/dist/startup-memory-deadline.js +55 -0
  393. package/dist/startup-memory-deadline.js.map +1 -0
  394. package/dist/statusline-watcher.js.map +1 -1
  395. package/dist/storm-window.js.map +1 -1
  396. package/dist/systemd-peer-bus.js.map +1 -1
  397. package/dist/target-queue-worker.js.map +1 -1
  398. package/dist/task-board-summary.d.ts +101 -0
  399. package/dist/task-board-summary.js +177 -0
  400. package/dist/task-board-summary.js.map +1 -0
  401. package/dist/task-board-tool.d.ts +25 -0
  402. package/dist/task-board-tool.js +155 -0
  403. package/dist/task-board-tool.js.map +1 -0
  404. package/dist/task-board-waker.d.ts +51 -0
  405. package/dist/task-board-waker.js +141 -0
  406. package/dist/task-board-waker.js.map +1 -0
  407. package/dist/tips.js.map +1 -1
  408. package/dist/tmux-control.js +1 -1
  409. package/dist/tmux-control.js.map +1 -1
  410. package/dist/tmux-exec-helper.d.ts +104 -0
  411. package/dist/tmux-exec-helper.js +412 -0
  412. package/dist/tmux-exec-helper.js.map +1 -0
  413. package/dist/tmux-manager.d.ts +1 -0
  414. package/dist/tmux-manager.js +29 -13
  415. package/dist/tmux-manager.js.map +1 -1
  416. package/dist/tmux-read.js +2 -2
  417. package/dist/tmux-read.js.map +1 -1
  418. package/dist/tool-permissions.js +9 -42
  419. package/dist/tool-permissions.js.map +1 -1
  420. package/dist/tool-progress.js.map +1 -1
  421. package/dist/topic-archiver.js.map +1 -1
  422. package/dist/topic-commands.d.ts +13 -0
  423. package/dist/topic-commands.js +56 -33
  424. package/dist/topic-commands.js.map +1 -1
  425. package/dist/topic-link.js.map +1 -1
  426. package/dist/transcript-delta-reader.js.map +1 -1
  427. package/dist/transcript-jsonl.js.map +1 -1
  428. package/dist/transcript-monitor.js +5 -0
  429. package/dist/transcript-monitor.js.map +1 -1
  430. package/dist/transcript-sources.d.ts +2 -0
  431. package/dist/transcript-sources.js +4 -0
  432. package/dist/transcript-sources.js.map +1 -1
  433. package/dist/tunnel/cloudflared-install.js +3 -1
  434. package/dist/tunnel/cloudflared-install.js.map +1 -1
  435. package/dist/tunnel/cloudflared.d.ts +7 -16
  436. package/dist/tunnel/cloudflared.js +100 -13
  437. package/dist/tunnel/cloudflared.js.map +1 -1
  438. package/dist/tunnel/lease.js +3 -2
  439. package/dist/tunnel/lease.js.map +1 -1
  440. package/dist/tunnel/manager.js.map +1 -1
  441. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  442. package/dist/tunnel/named-diagnostics.js +52 -0
  443. package/dist/tunnel/named-diagnostics.js.map +1 -0
  444. package/dist/tunnel/public-fetch.js.map +1 -1
  445. package/dist/tunnel/purpose-lane.js.map +1 -1
  446. package/dist/tunnel/types.d.ts +4 -1
  447. package/dist/tunnel/types.js.map +1 -1
  448. package/dist/types.d.ts +55 -2
  449. package/dist/ui/app-effects.js +27 -5
  450. package/dist/ui/app.html +2 -0
  451. package/dist/ui/backend-signin.js +297 -0
  452. package/dist/ui/chat-effects.js +15 -7
  453. package/dist/ui/chat-msg-actions.js +176 -0
  454. package/dist/ui/chat-render.js +67 -20
  455. package/dist/ui/chat-store.js +218 -48
  456. package/dist/ui/chat-strings.js +42 -10
  457. package/dist/ui/chat-thread.js +249 -23
  458. package/dist/ui/effect-trial-controller.js +13 -8
  459. package/dist/ui/effect-trial-offer.js +2 -31
  460. package/dist/ui/effects-waker.js +2 -0
  461. package/dist/ui/fleet-canvas-layout.js +13 -4
  462. package/dist/ui/fleet-canvas.js +120 -43
  463. package/dist/ui/fleet-office-editor.js +149 -0
  464. package/dist/ui/fleet-office-model.js +358 -0
  465. package/dist/ui/fleet-office-pack.js +199 -0
  466. package/dist/ui/fleet-office-skin.js +474 -0
  467. package/dist/ui/fleet-office-store.js +49 -0
  468. package/dist/ui/fleet-office-zones.js +177 -0
  469. package/dist/ui/fleet-office.js +434 -0
  470. package/dist/ui/fleet-org.js +21 -8
  471. package/dist/ui/fleet-route-scene.js +272 -0
  472. package/dist/ui/fleet-route-worker.js +21 -0
  473. package/dist/ui/fleet-route.js +88 -0
  474. package/dist/ui/fleet-task-card.js +436 -0
  475. package/dist/ui/fleet-task-common.js +482 -0
  476. package/dist/ui/fleet-task-work.js +107 -0
  477. package/dist/ui/fleet-tasks.js +569 -0
  478. package/dist/ui/fleet-traffic.js +227 -45
  479. package/dist/ui/fleet-usage.js +36 -2
  480. package/dist/ui/guest-refused.html +41 -0
  481. package/dist/ui/icons/icon-192.png +0 -0
  482. package/dist/ui/icons/icon-512.png +0 -0
  483. package/dist/ui/image-lightbox.js +45 -1
  484. package/dist/ui/image-zoom.js +242 -0
  485. package/dist/ui/panel-chat.js +282 -89
  486. package/dist/ui/panel-details.js +2 -0
  487. package/dist/ui/panel-fleet.js +32 -71
  488. package/dist/ui/panel-needs.js +23 -6
  489. package/dist/ui/panel-settings.js +158 -32
  490. package/dist/ui/preview-panel.js +2 -1
  491. package/dist/ui/search-dialog.js +350 -0
  492. package/dist/ui/settings-appearance.js +170 -10
  493. package/dist/ui/settings-apply.js +3 -3
  494. package/dist/ui/settings-confirm.js +7 -2
  495. package/dist/ui/settings-dialogs.js +46 -21
  496. package/dist/ui/settings-discord.js +6 -2
  497. package/dist/ui/settings-guests.js +2 -1
  498. package/dist/ui/settings-learn.js +1 -0
  499. package/dist/ui/settings-model.js +51 -18
  500. package/dist/ui/settings-mods.js +8 -3
  501. package/dist/ui/settings-owner-effects.js +6 -4
  502. package/dist/ui/settings-strings.js +180 -6
  503. package/dist/ui/settings-token.js +3 -1
  504. package/dist/ui/settings-web-authority.js +13 -5
  505. package/dist/ui/settings-wizard.js +13 -7
  506. package/dist/ui/shared/agend-auth.js +3 -1
  507. package/dist/ui/shared/app-i18n.js +12 -5
  508. package/dist/ui/shared/app-needs.js +2 -2
  509. package/dist/ui/shared/app-prefs.js +15 -0
  510. package/dist/ui/shared/app-route.js +18 -0
  511. package/dist/ui/shared/app-shell.js +172 -28
  512. package/dist/ui/shared/app-store.js +3 -2
  513. package/dist/ui/shared/app-stream.js +7 -2
  514. package/dist/ui/shared/app-themes.js +116 -1
  515. package/dist/ui/shared/app.css +681 -54
  516. package/dist/ui/shared/app.js +9 -1
  517. package/dist/ui/shared/card-strings.js +4 -0
  518. package/dist/ui/shared/effect-app-runtime.js +7 -5
  519. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  520. package/dist/ui/shared/effect-cursor.js +3 -2
  521. package/dist/ui/shared/effect-display-metadata.js +39 -0
  522. package/dist/ui/shared/effect-owner-source.js +8 -1
  523. package/dist/ui/shared/effect-policy.js +2 -2
  524. package/dist/ui/shared/effect-registry.js +30 -11
  525. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  526. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  527. package/dist/ui/shared/effect-stock-trust.js +40 -9
  528. package/dist/ui/shared/effect-trial-source.js +1 -1
  529. package/dist/ui/shared/effect-trial-stage.js +27 -21
  530. package/dist/ui/shared/effect-trial.css +1 -1
  531. package/dist/ui/shared/feature-flags.js +127 -0
  532. package/dist/ui/shared/guest-refused.js +35 -0
  533. package/dist/ui/shared/header-tools.js +2 -2
  534. package/dist/ui/shared/identity-card.js +26 -8
  535. package/dist/ui/shared/identity-color.js +17 -10
  536. package/dist/ui/shared/instance-nav.js +183 -28
  537. package/dist/ui/shared/owner-css.js +30 -1
  538. package/dist/ui/shared/panel-view.js +14 -29
  539. package/dist/ui/shared/text-undo.js +210 -0
  540. package/dist/ui/shared/tokens.css +13 -3
  541. package/dist/ui/shared/ui-dialog.js +5 -4
  542. package/dist/ui/shared/ui-icons.js +4 -0
  543. package/dist/ui/shared/ui-menu.js +20 -7
  544. package/dist/ui/shared/ui-toast.js +16 -3
  545. package/dist/ui/shared/usage-dialog.js +206 -16
  546. package/dist/ui/shared/view-strings.js +68 -4
  547. package/dist/ui/shared/web-authorize.js +50 -1
  548. package/dist/ui/signin.html +2 -0
  549. package/dist/ui/web-terminal/terminal.css +4 -4
  550. package/dist/ui/web-terminal/terminal.html +10 -10
  551. package/dist/ui/web-terminal/terminal.js +58 -12
  552. package/dist/update-check.js.map +1 -1
  553. package/dist/update-dispatch.js +1 -1
  554. package/dist/update-dispatch.js.map +1 -1
  555. package/dist/update-install.js.map +1 -1
  556. package/dist/update-launch.d.ts +10 -1
  557. package/dist/update-launch.js +39 -14
  558. package/dist/update-launch.js.map +1 -1
  559. package/dist/update-marker.js.map +1 -1
  560. package/dist/update-preflight.js +1 -1
  561. package/dist/update-preflight.js.map +1 -1
  562. package/dist/update-progress.d.ts +3 -1
  563. package/dist/update-progress.js +3 -1
  564. package/dist/update-progress.js.map +1 -1
  565. package/dist/usage/format-rich.js +6 -3
  566. package/dist/usage/format-rich.js.map +1 -1
  567. package/dist/usage/i18n-keys.d.ts +1 -1
  568. package/dist/usage/i18n-keys.js +2 -1
  569. package/dist/usage/i18n-keys.js.map +1 -1
  570. package/dist/usage/i18n.d.ts +13 -1
  571. package/dist/usage/i18n.js +29 -0
  572. package/dist/usage/i18n.js.map +1 -1
  573. package/dist/usage/providers.d.ts +89 -2
  574. package/dist/usage/providers.js +247 -41
  575. package/dist/usage/providers.js.map +1 -1
  576. package/dist/usage/statusline-usage.js.map +1 -1
  577. package/dist/usage/usage-api.d.ts +5 -1
  578. package/dist/usage/usage-api.js +185 -58
  579. package/dist/usage/usage-api.js.map +1 -1
  580. package/dist/usage-report.js.map +1 -1
  581. package/dist/usage-rollup.js +1 -1
  582. package/dist/usage-rollup.js.map +1 -1
  583. package/dist/user-systemd.d.ts +24 -0
  584. package/dist/user-systemd.js +75 -0
  585. package/dist/user-systemd.js.map +1 -0
  586. package/dist/view-api.d.ts +7 -0
  587. package/dist/view-api.js +16 -4
  588. package/dist/view-api.js.map +1 -1
  589. package/dist/wake-coordinator.js.map +1 -1
  590. package/dist/web-ambient.js +9 -2
  591. package/dist/web-ambient.js.map +1 -1
  592. package/dist/web-api.d.ts +58 -10
  593. package/dist/web-api.js +1104 -71
  594. package/dist/web-api.js.map +1 -1
  595. package/dist/web-app-icon-worker.d.ts +1 -0
  596. package/dist/web-app-icon-worker.js +16 -0
  597. package/dist/web-app-icon-worker.js.map +1 -0
  598. package/dist/web-app-icon.d.ts +109 -0
  599. package/dist/web-app-icon.js +257 -0
  600. package/dist/web-app-icon.js.map +1 -0
  601. package/dist/web-appearance-policy.js.map +1 -1
  602. package/dist/web-appearance-tools.d.ts +1 -0
  603. package/dist/web-appearance-tools.js +7 -3
  604. package/dist/web-appearance-tools.js.map +1 -1
  605. package/dist/web-appearance-view.js.map +1 -1
  606. package/dist/web-appearance.d.ts +4 -10
  607. package/dist/web-appearance.js +7 -4
  608. package/dist/web-appearance.js.map +1 -1
  609. package/dist/web-auth.d.ts +8 -4
  610. package/dist/web-auth.js +33 -21
  611. package/dist/web-auth.js.map +1 -1
  612. package/dist/web-backend-login.d.ts +130 -0
  613. package/dist/web-backend-login.js +225 -0
  614. package/dist/web-backend-login.js.map +1 -0
  615. package/dist/web-card.js.map +1 -1
  616. package/dist/web-channel-echo.js.map +1 -1
  617. package/dist/web-chat-history.d.ts +118 -8
  618. package/dist/web-chat-history.js +220 -25
  619. package/dist/web-chat-history.js.map +1 -1
  620. package/dist/web-commands.d.ts +5 -1
  621. package/dist/web-commands.js +1 -1
  622. package/dist/web-commands.js.map +1 -1
  623. package/dist/web-cookie-names.d.ts +5 -0
  624. package/dist/web-cookie-names.js +12 -0
  625. package/dist/web-cookie-names.js.map +1 -0
  626. package/dist/web-effect-bundle.d.ts +2 -2
  627. package/dist/web-effect-library.js.map +1 -1
  628. package/dist/web-effect-playback.js.map +1 -1
  629. package/dist/web-effect-profiles.d.ts +16 -16
  630. package/dist/web-effect-profiles.js +3 -2
  631. package/dist/web-effect-profiles.js.map +1 -1
  632. package/dist/web-effect-service.js.map +1 -1
  633. package/dist/web-effect-tools.js.map +1 -1
  634. package/dist/web-effect-trials.js.map +1 -1
  635. package/dist/web-effect-upload.js.map +1 -1
  636. package/dist/web-effect.d.ts +6 -6
  637. package/dist/web-effect.js.map +1 -1
  638. package/dist/web-experimental-http.d.ts +2 -0
  639. package/dist/web-experimental-http.js +12 -0
  640. package/dist/web-experimental-http.js.map +1 -0
  641. package/dist/web-experimental.d.ts +11 -0
  642. package/dist/web-experimental.js +49 -0
  643. package/dist/web-experimental.js.map +1 -0
  644. package/dist/web-guest-access.d.ts +4 -2
  645. package/dist/web-guest-access.js +22 -10
  646. package/dist/web-guest-access.js.map +1 -1
  647. package/dist/web-guest-rooms.js.map +1 -1
  648. package/dist/web-host-guard.d.ts +11 -0
  649. package/dist/web-host-guard.js +11 -0
  650. package/dist/web-host-guard.js.map +1 -1
  651. package/dist/web-icons.d.ts +33 -1
  652. package/dist/web-icons.js +83 -11
  653. package/dist/web-icons.js.map +1 -1
  654. package/dist/web-identity-color.js.map +1 -1
  655. package/dist/web-image-meta.d.ts +13 -0
  656. package/dist/web-image-meta.js +62 -0
  657. package/dist/web-image-meta.js.map +1 -1
  658. package/dist/web-images.js.map +1 -1
  659. package/dist/web-libavoid.d.ts +14 -0
  660. package/dist/web-libavoid.js +46 -0
  661. package/dist/web-libavoid.js.map +1 -0
  662. package/dist/web-login.js.map +1 -1
  663. package/dist/web-mentions.js.map +1 -1
  664. package/dist/web-mod-agent.js.map +1 -1
  665. package/dist/web-mod-store.d.ts +2 -0
  666. package/dist/web-mod-store.js +10 -0
  667. package/dist/web-mod-store.js.map +1 -1
  668. package/dist/web-office-store.d.ts +104 -0
  669. package/dist/web-office-store.js +236 -0
  670. package/dist/web-office-store.js.map +1 -0
  671. package/dist/web-owner-css-store.d.ts +44 -1
  672. package/dist/web-owner-css-store.js +70 -9
  673. package/dist/web-owner-css-store.js.map +1 -1
  674. package/dist/web-owner-css.js.map +1 -1
  675. package/dist/web-png.d.ts +33 -0
  676. package/dist/web-png.js +329 -0
  677. package/dist/web-png.js.map +1 -0
  678. package/dist/web-prefs.d.ts +6 -0
  679. package/dist/web-prefs.js +29 -3
  680. package/dist/web-prefs.js.map +1 -1
  681. package/dist/web-preview.d.ts +2 -0
  682. package/dist/web-preview.js +2 -0
  683. package/dist/web-preview.js.map +1 -1
  684. package/dist/web-profile.js.map +1 -1
  685. package/dist/web-reactions.d.ts +35 -0
  686. package/dist/web-reactions.js +47 -0
  687. package/dist/web-reactions.js.map +1 -0
  688. package/dist/web-request-context.d.ts +5 -0
  689. package/dist/web-request-context.js.map +1 -1
  690. package/dist/web-returning-device.d.ts +4 -2
  691. package/dist/web-returning-device.js +13 -6
  692. package/dist/web-returning-device.js.map +1 -1
  693. package/dist/web-schedules.js.map +1 -1
  694. package/dist/web-send-dedupe.d.ts +36 -0
  695. package/dist/web-send-dedupe.js +69 -0
  696. package/dist/web-send-dedupe.js.map +1 -0
  697. package/dist/web-session-authorization.js.map +1 -1
  698. package/dist/web-session.js +1 -1
  699. package/dist/web-session.js.map +1 -1
  700. package/dist/web-settings-patch.d.ts +3 -1
  701. package/dist/web-settings-patch.js +11 -5
  702. package/dist/web-settings-patch.js.map +1 -1
  703. package/dist/web-settings-tools.d.ts +6 -0
  704. package/dist/web-settings-tools.js +52 -17
  705. package/dist/web-settings-tools.js.map +1 -1
  706. package/dist/web-terminal-http.js +15 -2
  707. package/dist/web-terminal-http.js.map +1 -1
  708. package/dist/web-terminal.js +1 -1
  709. package/dist/web-terminal.js.map +1 -1
  710. package/dist/web-theme-store.d.ts +2 -2
  711. package/dist/web-theme-store.js +6 -3
  712. package/dist/web-theme-store.js.map +1 -1
  713. package/dist/web-theme.d.ts +29 -0
  714. package/dist/web-theme.js +89 -1
  715. package/dist/web-theme.js.map +1 -1
  716. package/dist/web-upload.d.ts +18 -1
  717. package/dist/web-upload.js +45 -7
  718. package/dist/web-upload.js.map +1 -1
  719. package/dist/web-widget.js.map +1 -1
  720. package/dist/webhook-emitter.js.map +1 -1
  721. package/dist/windows-shortcuts.d.ts +78 -0
  722. package/dist/windows-shortcuts.js +203 -0
  723. package/dist/windows-shortcuts.js.map +1 -0
  724. package/dist/workflow-templates/default.md +4 -1
  725. package/dist/ws-server.js.map +1 -1
  726. package/dist/yaml-shared-nodes.d.ts +25 -0
  727. package/dist/yaml-shared-nodes.js +185 -0
  728. package/dist/yaml-shared-nodes.js.map +1 -0
  729. package/launcher/agend-install.cjs +828 -0
  730. package/launcher/install-admission.cjs +4 -39
  731. package/launcher/postinstall.cjs +14 -12
  732. package/launcher/private-home.cjs +43 -0
  733. package/package.json +16 -13
  734. package/scripts/preinstall-guard.cjs +2 -5
  735. package/templates/windows-shortcuts.ps1 +181 -0
  736. 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; }
@@ -453,6 +523,9 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
453
523
  .msg.status-line .st-more { border: 0; background: none; color: var(--text-2); cursor: pointer; font-size: var(--fs-xs); padding: var(--s-1) 0 0 var(--s-3); }
454
524
  .msg.status-line .st-more:hover { color: var(--text); }
455
525
  .msg-tools { display: flex; gap: var(--s-1); margin-top: var(--s-1); opacity: 0; transition: opacity var(--t-fast); }
526
+ /* #2147: bounded stock toolbar paint, including fixed descendants. Padding preserves focus outlines. */
527
+ .shell .thread .msg-tools { contain: paint; overflow: clip; overflow-clip-margin: 0px; padding: 4px; margin: 0 -4px -4px; }
528
+ .shell .thread .codeblock > .cb-head { contain: paint; overflow: clip; overflow-clip-margin: 0px; }
456
529
  .msg:hover .msg-tools, .msg:focus-within .msg-tools { opacity: 1; }
457
530
  @media (hover: none) { .msg-tools { opacity: 1; } }
458
531
  /* Delivery ticks: always visible, in colour, with their label on hover and for screen readers (rough edge 10). */
@@ -488,8 +561,19 @@ html.lb-open .scroller { overflow: hidden; }
488
561
  .lb { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
489
562
  background: rgba(0, 0, 0, 0.95); color: #fff; overflow: hidden; overscroll-behavior: contain; }
490
563
  .lb::backdrop { background: rgba(0, 0, 0, 0.6); }
491
- .lb-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 56px 16px 16px; box-sizing: border-box; }
492
- .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); }
493
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);
494
578
  background: rgba(0, 0, 0, 0.75); }
495
579
  .lb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); }
@@ -557,10 +641,18 @@ html.lb-open .scroller { overflow: hidden; }
557
641
  .chat-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
558
642
  /* #1629: an agent's theme on its own chat surface — custom properties set on .p-chat through the CSSOM, choices as
559
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); }
560
652
  .p-chat.th { background: var(--bg); color: var(--text); }
561
653
  .p-chat.th .msg.user .body { border-radius: var(--bubble-radius, var(--r-xl)); }
562
- .p-chat.th-font-system .thread, .p-chat.th-font-system .composer textarea { font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
563
- .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); }
564
656
  .p-chat.th-bubble-thin .msg.user .body { box-shadow: inset 0 0 0 1px var(--border); }
565
657
  .p-chat.th-bubble-accent .msg.user .body { box-shadow: inset 0 0 0 1px var(--accent); }
566
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); }
@@ -611,6 +703,24 @@ img.amb-p { object-fit: contain; }
611
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;
612
704
  background: var(--surface); border-radius: var(--r-sm); padding: var(--s-3); white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
613
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 */
614
724
  @media (max-width: 899px) {
615
725
  .only-wide { display: none; }
616
726
  .pv-divider { display: none; }
@@ -676,12 +786,40 @@ img.amb-p { object-fit: contain; }
676
786
  font-size: var(--fs-md); line-height: var(--lh-md); resize: none; min-height: 24px; max-height: 240px; overflow-y: auto;
677
787
  }
678
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; }
679
794
  .btn-send { width: 36px; padding: 0; }
680
795
  .btn-send .send-label { display: none; }
681
796
  /* A narrow phone: Stop reply beside Send leaves the message box no room — the label is for screen readers there. */
682
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; } }
683
798
  .btn-stop { background: var(--bg); }
684
- .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; }
685
823
  /* #1920 phase 3: Settings → Web → Guests. */
686
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;
687
825
  padding: var(--s-1) var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
@@ -698,11 +836,20 @@ img.amb-p { object-fit: contain; }
698
836
  /* #1939 S2a: Settings → Web → Web authority. */
699
837
  .s-web-authority .s-va-sessions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
700
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; }
701
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); }
702
842
  .s-web-authority .save-row { flex-wrap: wrap; }
703
843
  /* #1920: a guest's note under the composer — on a phone too, where the key hints are hidden. */
704
844
  .guest-note { margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
705
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; }
706
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; }
707
854
  .file-chip img { width: 28px; height: 28px; object-fit: cover; border-radius: 4px; }
708
855
  .file-chip .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
@@ -771,6 +918,9 @@ img.amb-p { object-fit: contain; }
771
918
  .oc-keep { left: var(--s-2); right: var(--s-2); transform: none; max-width: none; flex-wrap: nowrap; }
772
919
  .oc-keep-text { flex: 1; flex-direction: column; align-items: flex-start; gap: 0; }
773
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; }
774
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; }
775
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); }
776
926
  .toast.err { background: var(--danger-fill); color: var(--on-danger); }
@@ -797,7 +947,12 @@ img.amb-p { object-fit: contain; }
797
947
  .panel-head .sb-new { display: none; }
798
948
  .only-narrow { display: inline-flex; }
799
949
  .thread { padding: var(--s-3) var(--s-3) var(--s-2); gap: var(--s-5); }
800
- .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); }
801
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)); }
802
957
  .hint { display: none; }
803
958
  .msg.user { max-width: 88%; }
@@ -808,12 +963,14 @@ img.amb-p { object-fit: contain; }
808
963
  padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
809
964
  }
810
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; }
811
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; }
812
969
  .tab.active { color: var(--text); font-weight: var(--fw-semibold); }
813
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; }
814
971
  .main { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
815
972
  .kb-open .main { padding-bottom: 0; }
816
- .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; }
817
974
  .tour { left: var(--s-4); right: var(--s-4); width: auto; top: calc(64px + env(safe-area-inset-top)); }
818
975
  .dlg { width: 100vw; max-width: 100vw; margin: auto 0 0; border-radius: var(--r-lg) var(--r-lg) 0 0; max-height: 90vh; }
819
976
  .dlg-box { max-height: 90vh; }
@@ -837,6 +994,9 @@ img.amb-p { object-fit: contain; }
837
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;
838
995
  }
839
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; }
840
1000
  .v-group-head .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
841
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); }
842
1002
  .caret { transition: transform var(--t-fast) var(--ease); }
@@ -866,6 +1026,35 @@ img.amb-p { object-fit: contain; }
866
1026
  @media (max-width: 899px) { .fav-editing .inst-star, .fav-editing .inst-move { width: 36px; height: 36px; } }
867
1027
  .v-inst .dot { margin-top: 0; }
868
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; }
869
1058
  /* #1722: the sidebar's width — a separator on its right edge (drag, arrows, Home/End, double-click resets); not on a phone */
870
1059
  .side-resize { position: absolute; top: 0; right: -3px; width: 6px; height: 100%; z-index: 5; cursor: col-resize; touch-action: none; }
871
1060
  .side-resize:hover, .side-resize:focus-visible, .side-resize.dragging { background: var(--accent-dim, var(--border-strong)); }
@@ -888,7 +1077,21 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
888
1077
  down, never the count; the count is as tall as a header, so the row does not grow. */
889
1078
  .nav-facets { display: flex; align-items: flex-start; gap: var(--s-2); padding: var(--s-2) var(--s-1) 0; }
890
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; }
891
- .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; }
892
1095
  .nav-facet { font-size: var(--fs-xs); color: var(--text-2); min-width: 0; max-width: 100%; }
893
1096
  /* #1700: a facet group's header — the whole row toggles its list; folded with a filter set, a short summary. */
894
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);
@@ -897,10 +1100,15 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
897
1100
  .nav-facet-head:focus-visible { outline: 2px solid var(--accent); }
898
1101
  .nav-facet-head .caret { color: var(--text-3); flex: none; }
899
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); }
900
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; }
901
1109
  .nav-facet-list { display: flex; flex-direction: column; gap: 2px; padding: var(--s-1) var(--s-2); }
902
1110
  .nav-chip { display: flex; align-items: center; gap: var(--s-2); cursor: pointer; color: var(--text); }
903
- .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); }
904
1112
 
905
1113
  /* One gap on every page (View's, #1448): the header's controls are the same size on every tab. */
906
1114
  .panel-actions .btn { gap: var(--s-1); }
@@ -918,26 +1126,17 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
918
1126
  .v-pre .ansi[data-dim] { opacity: .5; }
919
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); }
920
1128
  .v-probe { position: absolute; visibility: hidden; white-space: pre; left: -9999px; top: 0; font-size: 100px; }
921
- .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)); }
922
- .v-card.open { align-items: flex-start; padding-top: var(--s-3); padding-bottom: var(--s-3); }
923
- .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; }
924
- .v-card.open .v-avatar { width: 48px; height: 48px; }
925
- .v-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
926
- .v-initial { color: var(--text-2); font-weight: var(--fw-semibold); text-transform: uppercase; }
927
- .v-card-body { flex: 1; min-width: 0; }
928
- .v-card-line { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--fs-sm); min-width: 0; }
929
- .v-card-line strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
930
- .v-role { color: var(--accent); font-size: var(--fs-xs); white-space: nowrap; }
931
- .v-card-meta { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
932
- .v-card.open .v-card-meta { white-space: normal; }
933
- .v-card-desc { margin-top: var(--s-2); color: var(--text-2); font-size: var(--fs-sm); white-space: pre-wrap; }
934
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); }
935
1130
  .err { color: var(--danger); font-size: var(--fs-sm); }
936
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); }
937
1132
  .u-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
938
- /* #1749: one line beside ↑↓ — the name gives way first, then the plan badge (each with an ellipsis); ↑↓ never wrap. */
939
- .u-head strong { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
940
- .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; }
941
1140
  /* #2014: a credential profile's row — the provider name beside the plan badge, and the profile on its own full-width
942
1141
  muted line under the head (one line in the rail, whole in the dialog). */
943
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; }
@@ -956,19 +1155,62 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
956
1155
  .u-meter { height: 10px; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
957
1156
  .u-fill { height: 100%; width: 0; min-width: 3px; border-radius: var(--r-full); background: var(--accent); transition: width 0.3s var(--ease); }
958
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); }
959
1163
  .u-sub { color: var(--text-3); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
960
1164
  .u-err { color: var(--warn); font-size: var(--fs-sm); }
961
1165
  .u-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
962
1166
  /* #1673: the usage rail beside the page on a wide screen (header-tools.js UsageRail; shown only at min-width 1200px). */
963
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); }
964
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); }
965
- .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); } }
966
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); }
967
1209
  @media (max-width: 1199px) { .u-rail { display: none; } }
968
1210
  @media (max-width: 899px) {
969
1211
  .hide-narrow { display: none; }
970
- .v-card { padding-left: var(--s-3); padding-right: var(--s-3); }
971
- .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); }
972
1214
  }
973
1215
 
974
1216
  /* ── Settings (#1408 step 3): lists, forms, the pending bar, the Apply in hand ── */
@@ -1060,8 +1302,6 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1060
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; }
1061
1303
  /* An agent's row: name and model on the first line, its tags and buttons from the second, on every row alike. */
1062
1304
  .s-br { display: block; flex-basis: 100%; height: 0; }
1063
- /* View: the profile line wraps to two lines instead of hiding the model and context. */
1064
- .v-card-meta { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
1065
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;
1066
1306
  a row's trailing Delete sits at the right. */
1067
1307
  .n-actions > .btn-ghost { padding-left: 0; padding-right: 0; margin-left: -1px; }
@@ -1111,6 +1351,18 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1111
1351
  .op-line { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
1112
1352
  .op-line.ok { color: var(--ok); }
1113
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; }
1114
1366
  @media (max-width: 899px) {
1115
1367
  .grid2 { grid-template-columns: minmax(0, 1fr); }
1116
1368
  .se-row { grid-template-columns: minmax(0, 1fr) auto auto; }
@@ -1161,10 +1413,10 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1161
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; }
1162
1414
  .org-team-desc { color: var(--text-2); font-size: var(--fs-sm); overflow-wrap: anywhere; }
1163
1415
  .org-team-sub { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-3); font-size: var(--fs-xs); }
1164
- .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; }
1165
- .org-node.st-needs, .org-node.st-stuck { border-left-color: var(--warn); }
1166
- .org-node.st-crashed { border-left-color: var(--danger); }
1167
- .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); }
1168
1420
  .org-node.st-missing { opacity: 0.7; }
1169
1421
  .org-node-head { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
1170
1422
  .org-names { flex: 1; min-width: 0; display: flex; flex-direction: column; }
@@ -1217,7 +1469,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1217
1469
  .oc-team-name { fill: var(--text); font-size: 13px; font-weight: 600; }
1218
1470
  .oc-team-meta { fill: var(--text-3); font-size: 11px; }
1219
1471
  .oc-team-sum { fill: var(--text-2); font-size: 11.5px; }
1220
- .oc-team.dim { opacity: 0.55; }
1472
+ .oc-team.dim, .oc-team-head.dim { opacity: 0.55; }
1221
1473
  .oc-node.dim { opacity: 0.4; }
1222
1474
  .oc-node { cursor: pointer; }
1223
1475
  .oc-node[role="img"] { cursor: default; }
@@ -1257,13 +1509,18 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1257
1509
  .oc { --fx-task: #b794f6; --fx-send: #2dd4bf; --fx-report: #f472b6; --fx-broadcast: #fb923c; --fx-team: #cbd5e1; }
1258
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; } }
1259
1511
  :root[data-theme="light"] .oc { --fx-task: #7c3aed; --fx-send: #0f766e; --fx-report: #be185d; --fx-broadcast: #c2410c; --fx-team: #475569; }
1260
- .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; }
1261
1514
  .oc-flow-halo { fill: none; stroke: var(--bg); stroke-width: 6; stroke-linecap: round; opacity: 0.85; }
1262
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); }
1263
- .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); }
1264
1517
  .oc-flow.ph-live { stroke-dasharray: 7 6; animation: oc-dash 0.9s linear infinite; }
1265
1518
  .oc-flow.ph-queued { stroke-dasharray: 2 5; opacity: 0.8; }
1266
- .oc-flow.ph-fading { stroke: var(--text-3); animation: oc-fade 3s ease-out forwards; }
1519
+ .oc-flow.ph-fading { stroke: var(--text-3); animation: oc-fade 12s ease-out forwards; }
1520
+ /* #1918 review: the work — a delegation in progress (a slow dash, kept until its report), its report coming back, none. */
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; }
1523
+ .oc-flow.ph-stale { stroke: var(--text-3); stroke-dasharray: 3 6; animation: oc-fade 12s ease-out forwards; }
1267
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); }
1268
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); }
1269
1526
  .oc-pulse.h-task { fill: var(--fx-task); } .oc-pulse.h-send { fill: var(--fx-send); } .oc-pulse.h-report { fill: var(--fx-report); }
@@ -1272,16 +1529,19 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1272
1529
  .oc-badge rect { fill: var(--surface-2); stroke: var(--border); } .oc-badge text { fill: var(--text-2); font-size: 10.5px; }
1273
1530
  @keyframes oc-dash { to { stroke-dashoffset: -26; } }
1274
1531
  @keyframes oc-fade { from { opacity: 0.8; } to { opacity: 0.15; } }
1275
- .oc-legend { position: absolute; left: var(--s-3); bottom: var(--s-3); max-width: calc(100% - 220px);
1276
- font-size: var(--fs-xs); color: var(--text-2); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); padding: 6px 10px; }
1277
- .oc-legend summary { cursor: pointer; font-weight: var(--fw-semibold); color: var(--text); }
1278
- .oc-legend[open] summary { margin-bottom: 4px; }
1532
+ /* #2052: the key is a strip under the toolbar (its toggle is in the toolbar), never over the canvas. */
1533
+ .oc-legend { margin: 0 0 var(--s-2); font-size: var(--fs-xs); color: var(--text-2); background: var(--surface); border: 1px solid var(--border);
1534
+ border-radius: var(--r-md); padding: 6px 10px; }
1535
+ .oc-key.on { border-color: var(--accent); }
1279
1536
  .oc-lg-rows { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-3); }
1280
1537
  .oc-lg { display: inline-flex; align-items: center; gap: 6px; }
1281
1538
  .oc-sw { width: 18px; height: 3px; border-radius: 2px; display: inline-block; background: var(--text-3); }
1282
1539
  .oc-sw.h-task { background: var(--fx-task); } .oc-sw.h-send { background: var(--fx-send); } .oc-sw.h-report { background: var(--fx-report); } .oc-sw.h-broadcast { background: var(--fx-broadcast); }
1283
1540
  .oc-sw.ph-queued { background: repeating-linear-gradient(90deg, var(--text-2) 0 3px, transparent 3px 7px); }
1284
1541
  .oc-sw.ph-fading { opacity: 0.5; }
1542
+ .oc-sw.ph-work { background: repeating-linear-gradient(90deg, var(--fx-task) 0 6px, transparent 6px 9px); height: 4px; }
1543
+ .oc-sw.ph-return { height: 4px; }
1544
+ .oc-sw.ph-stale { background: repeating-linear-gradient(90deg, var(--text-3) 0 2px, transparent 2px 6px); }
1285
1545
  .oc-live { gap: 6px; }
1286
1546
  .oc-live-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); }
1287
1547
  .oc-live.on .oc-live-dot { background: var(--ok); }
@@ -1291,14 +1551,59 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1291
1551
  @media (prefers-reduced-motion: reduce) {
1292
1552
  .oc-flow.ph-live { animation: none; stroke-dasharray: none; }
1293
1553
  .oc-flow.ph-fading { animation: none; opacity: 0.4; }
1554
+ .oc-flow.ph-work { animation: none; }
1555
+ .oc-flow.ph-return, .oc-flow.ph-stale { animation: none; opacity: 0.5; }
1294
1556
  .oc-pulse { display: none; }
1295
1557
  }
1296
1558
  @media (max-width: 640px) {
1297
1559
  .oc-stage { height: calc(100dvh - 248px); min-height: 340px; }
1298
1560
  .oc-find { flex: 1 1 150px; }
1299
- .oc-tools { margin-left: 0; width: 100%; flex-wrap: nowrap; }
1561
+ /* #2052: Find, Key, Live and Canvas/List are wider than a phone together: the row wraps (nothing is cut off). */
1562
+ .oc-tools { margin-left: 0; width: 100%; flex-wrap: wrap; row-gap: var(--s-2); }
1300
1563
  .oc-mini { display: none; }
1301
- .oc-legend { max-width: calc(100% - 24px); gap: 2px var(--s-2); }
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; }
1302
1607
  }
1303
1608
  /* A phone: Fleet's five tabs fit when only the open one shows its label (the others keep theirs for screen readers). */
1304
1609
  @media (max-width: 479px) {
@@ -1354,9 +1659,9 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1354
1659
  .us-csv { margin-left: auto; }
1355
1660
  .us-custom { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s-2) var(--s-3); font-size: var(--fs-sm); }
1356
1661
  .us-custom label { display: inline-flex; flex-direction: column; gap: 2px; color: var(--text-2); }
1357
- .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); }
1358
1663
  .us-fresh { font-size: var(--fs-xs); }
1359
- .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); }
1360
1665
  .us-unpriced { font-size: var(--fs-xs); }
1361
1666
  .us-scan { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
1362
1667
  .us-totals { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-3); margin: 0; }
@@ -1422,7 +1727,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1422
1727
  .cmd-palette .cmd-arg { color: var(--text-3); }
1423
1728
  .cmd-palette .cmd-none { color: var(--text-3); cursor: default; }
1424
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); }
1425
- .cmd-card.bad { border-left: 3px solid var(--danger); }
1730
+ .cmd-card.bad { --lbar-color: var(--danger); padding-left: calc(var(--s-3) + 3px); }
1426
1731
  .cmd-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
1427
1732
  .cmd-name { font-weight: var(--fw-semibold); }
1428
1733
  .cmd-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--font-ui); color: var(--text-2); }
@@ -1440,6 +1745,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1440
1745
  }
1441
1746
  /* #1630: a Discord server emoji in a chat message, the size of the text around it. */
1442
1747
  .md img.emoji { display: inline-block; width: 1.375em; height: 1.375em; object-fit: contain; vertical-align: -0.3em; margin: 0 0.05em; }
1748
+ .md .emoji-text { color: var(--text-2); }
1443
1749
  /* #1682: a mention, as Discord draws one — accent text on a tint of it; the id (or the Telegram handle) on hover. */
1444
1750
  .md .mention { display: inline; padding: 0 0.2em; border-radius: var(--r-sm); color: var(--accent); background: var(--accent-dim);
1445
1751
  font-weight: var(--fw-medium); white-space: nowrap; }
@@ -1536,8 +1842,8 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1536
1842
  .side-widget { padding: 0 var(--s-3) var(--s-2); }
1537
1843
  .aw-sidebar { max-height: 240px; overflow: auto; }
1538
1844
 
1539
- .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; }
1540
- .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); }
1541
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
1542
1848
  under it); the S / M / L control takes the line below. The chat header's card is trimmed further: a smaller portrait
1543
1849
  and banner, and its tagline and bio cut to a few lines (Details and View show them whole). */
@@ -1554,9 +1860,10 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1554
1860
  .id-card.card-c .id-tagline { -webkit-line-clamp: 2; line-clamp: 2; }
1555
1861
  .id-card.card-c .id-bio { -webkit-line-clamp: 3; line-clamp: 3; }
1556
1862
  }
1557
- /* #1629 r4 §1: the card in View (above the profile row) and its part of Edit profile. */
1558
- .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)); }
1559
1865
  .v-id .id-card { margin: 0; }
1866
+ .v-id-actions { display: flex; justify-content: flex-end; padding-top: var(--s-2); }
1560
1867
  .form-sub { margin: var(--s-2) 0 0; font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
1561
1868
  /* #1629 r4.1 Q3 (b): Settings → Appearance, the card's upload limits (three to a row; one on a phone). */
1562
1869
  .grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3) var(--s-4); margin-bottom: var(--s-3); }
@@ -1600,7 +1907,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1600
1907
  .p-fleet > .seg, .p-settings > .seg,
1601
1908
  .p-fleet > .panel-body, .p-needs > .panel-body, .p-settings > .panel-body,
1602
1909
  .p-log > .panel-body, .p-details > .panel-body, .p-view > .panel-body,
1603
- .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; }
1604
1911
  /* Keep the existing Apply bar's sticky behavior, in its own bounded stock band. */
1605
1912
  .p-settings > .s-pending { z-index: 1; }
1606
1913
 
@@ -1615,3 +1922,323 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1615
1922
  .panel-head:has(> .chat-fx-notice) { flex-wrap: wrap; }
1616
1923
  .chat-fx-notice { order: 10; flex: 1 1 100%; min-width: 0; max-width: 100%; font-size: var(--fs-sm); overflow-wrap: anywhere; }
1617
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; }