@songsid/agend 2.3.1 → 2.3.2-beta.10

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 (338) hide show
  1. package/THIRD_PARTY_NOTICES.md +40 -0
  2. package/dist/agent-cli.js +21 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +5 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/antigravity-usage-scan.d.ts +58 -0
  7. package/dist/antigravity-usage-scan.js +257 -0
  8. package/dist/antigravity-usage-scan.js.map +1 -0
  9. package/dist/antigravity-usage-worker.d.ts +1 -0
  10. package/dist/antigravity-usage-worker.js +10 -0
  11. package/dist/antigravity-usage-worker.js.map +1 -0
  12. package/dist/auth-api.js +4 -0
  13. package/dist/auth-api.js.map +1 -1
  14. package/dist/authority/authority-state.d.ts +4 -0
  15. package/dist/authority/authority-state.js +16 -10
  16. package/dist/authority/authority-state.js.map +1 -1
  17. package/dist/authority/session-authorizations.d.ts +7 -1
  18. package/dist/authority/session-authorizations.js +6 -4
  19. package/dist/authority/session-authorizations.js.map +1 -1
  20. package/dist/authority/web-authority.d.ts +19 -6
  21. package/dist/authority/web-authority.js +22 -8
  22. package/dist/authority/web-authority.js.map +1 -1
  23. package/dist/backend/kiro-identity.d.ts +64 -0
  24. package/dist/backend/kiro-identity.js +101 -0
  25. package/dist/backend/kiro-identity.js.map +1 -1
  26. package/dist/backend/kiro-retired-model.d.ts +62 -0
  27. package/dist/backend/kiro-retired-model.js +160 -0
  28. package/dist/backend/kiro-retired-model.js.map +1 -0
  29. package/dist/backend/kiro.d.ts +71 -2
  30. package/dist/backend/kiro.js +352 -11
  31. package/dist/backend/kiro.js.map +1 -1
  32. package/dist/backend/types.d.ts +59 -0
  33. package/dist/backend/types.js.map +1 -1
  34. package/dist/backend-signin-guide.d.ts +1 -0
  35. package/dist/backend-signin-guide.js +9 -0
  36. package/dist/backend-signin-guide.js.map +1 -0
  37. package/dist/backend-signin-pending.d.ts +10 -0
  38. package/dist/backend-signin-pending.js +44 -0
  39. package/dist/backend-signin-pending.js.map +1 -0
  40. package/dist/browser-backend-signins.d.ts +56 -0
  41. package/dist/browser-backend-signins.js +189 -0
  42. package/dist/browser-backend-signins.js.map +1 -0
  43. package/dist/cache-ledger.d.ts +38 -2
  44. package/dist/cache-ledger.js +133 -8
  45. package/dist/cache-ledger.js.map +1 -1
  46. package/dist/cache-prices.d.ts +2 -1
  47. package/dist/cache-prices.js +5 -2
  48. package/dist/cache-prices.js.map +1 -1
  49. package/dist/cache-service.d.ts +68 -0
  50. package/dist/cache-service.js +355 -13
  51. package/dist/cache-service.js.map +1 -1
  52. package/dist/channel/adapters/discord.d.ts +13 -0
  53. package/dist/channel/adapters/discord.js +103 -16
  54. package/dist/channel/adapters/discord.js.map +1 -1
  55. package/dist/channel/mcp-tools.js +34 -7
  56. package/dist/channel/mcp-tools.js.map +1 -1
  57. package/dist/channel/tool-router.js +2 -1
  58. package/dist/channel/tool-router.js.map +1 -1
  59. package/dist/channel/types.d.ts +11 -0
  60. package/dist/classic-channel-manager.d.ts +11 -0
  61. package/dist/classic-channel-manager.js +39 -1
  62. package/dist/classic-channel-manager.js.map +1 -1
  63. package/dist/cli.js +21 -2
  64. package/dist/cli.js.map +1 -1
  65. package/dist/config-validator.d.ts +7 -1
  66. package/dist/config-validator.js +92 -12
  67. package/dist/config-validator.js.map +1 -1
  68. package/dist/config.d.ts +19 -0
  69. package/dist/config.js +31 -1
  70. package/dist/config.js.map +1 -1
  71. package/dist/cpu-quota.d.ts +23 -0
  72. package/dist/cpu-quota.js +86 -0
  73. package/dist/cpu-quota.js.map +1 -0
  74. package/dist/daemon.d.ts +57 -3
  75. package/dist/daemon.js +330 -50
  76. package/dist/daemon.js.map +1 -1
  77. package/dist/dashboard-permissions.d.ts +20 -6
  78. package/dist/dashboard-permissions.js +58 -9
  79. package/dist/dashboard-permissions.js.map +1 -1
  80. package/dist/delivery-outbox.d.ts +12 -1
  81. package/dist/delivery-outbox.js +67 -15
  82. package/dist/delivery-outbox.js.map +1 -1
  83. package/dist/doctor.d.ts +3 -0
  84. package/dist/doctor.js +11 -1
  85. package/dist/doctor.js.map +1 -1
  86. package/dist/event-log.d.ts +5 -0
  87. package/dist/event-log.js +13 -0
  88. package/dist/event-log.js.map +1 -1
  89. package/dist/fleet-manager.d.ts +212 -0
  90. package/dist/fleet-manager.js +914 -111
  91. package/dist/fleet-manager.js.map +1 -1
  92. package/dist/fleet-process-handlers.d.ts +1 -0
  93. package/dist/fleet-process-handlers.js +9 -1
  94. package/dist/fleet-process-handlers.js.map +1 -1
  95. package/dist/forged-envelope-scan.d.ts +9 -0
  96. package/dist/forged-envelope-scan.js +30 -5
  97. package/dist/forged-envelope-scan.js.map +1 -1
  98. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
  99. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
  100. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +28 -5
  101. package/dist/general-knowledge/skills/web-appearance/SKILL.md +31 -8
  102. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +138 -59
  103. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +145 -61
  104. package/dist/guest-seen-people.d.ts +38 -0
  105. package/dist/guest-seen-people.js +78 -0
  106. package/dist/guest-seen-people.js.map +1 -0
  107. package/dist/instance-config-impact.js +14 -6
  108. package/dist/instance-config-impact.js.map +1 -1
  109. package/dist/instance-lifecycle.d.ts +20 -0
  110. package/dist/instance-lifecycle.js +71 -13
  111. package/dist/instance-lifecycle.js.map +1 -1
  112. package/dist/kiro-db-reader.d.ts +5 -0
  113. package/dist/kiro-db-reader.js +18 -0
  114. package/dist/kiro-db-reader.js.map +1 -1
  115. package/dist/kiro-engine-status.d.ts +2 -0
  116. package/dist/kiro-engine-status.js +9 -0
  117. package/dist/kiro-engine-status.js.map +1 -1
  118. package/dist/kiro-migrate.d.ts +49 -0
  119. package/dist/kiro-migrate.js +105 -0
  120. package/dist/kiro-migrate.js.map +1 -0
  121. package/dist/kiro-transcript-lane.d.ts +2 -0
  122. package/dist/kiro-transcript-lane.js.map +1 -1
  123. package/dist/kiro-transcript-worker.js +1 -0
  124. package/dist/kiro-transcript-worker.js.map +1 -1
  125. package/dist/kiro-tui-forensic.d.ts +7 -0
  126. package/dist/kiro-tui-forensic.js +110 -0
  127. package/dist/kiro-tui-forensic.js.map +1 -0
  128. package/dist/kiro-usage-run.d.ts +7 -0
  129. package/dist/kiro-usage-run.js +39 -0
  130. package/dist/kiro-usage-run.js.map +1 -0
  131. package/dist/kiro-usage-scan.d.ts +49 -0
  132. package/dist/kiro-usage-scan.js +223 -0
  133. package/dist/kiro-usage-scan.js.map +1 -0
  134. package/dist/kiro-usage-worker.d.ts +1 -0
  135. package/dist/kiro-usage-worker.js +10 -0
  136. package/dist/kiro-usage-worker.js.map +1 -0
  137. package/dist/kiro-usage.d.ts +58 -0
  138. package/dist/kiro-usage.js +310 -0
  139. package/dist/kiro-usage.js.map +1 -0
  140. package/dist/locale.js +120 -12
  141. package/dist/locale.js.map +1 -1
  142. package/dist/log-service.js +1 -1
  143. package/dist/log-service.js.map +1 -1
  144. package/dist/login-url.d.ts +4 -0
  145. package/dist/login-url.js +22 -0
  146. package/dist/login-url.js.map +1 -0
  147. package/dist/mac-auto-restore.d.ts +117 -0
  148. package/dist/mac-auto-restore.js +294 -0
  149. package/dist/mac-auto-restore.js.map +1 -0
  150. package/dist/needs-you-hub.d.ts +2 -1
  151. package/dist/needs-you-hub.js +1 -1
  152. package/dist/needs-you-hub.js.map +1 -1
  153. package/dist/needs-you.d.ts +8 -2
  154. package/dist/needs-you.js +6 -0
  155. package/dist/needs-you.js.map +1 -1
  156. package/dist/notice-delivery.d.ts +16 -0
  157. package/dist/notice-delivery.js +35 -0
  158. package/dist/notice-delivery.js.map +1 -0
  159. package/dist/office-share-page.d.ts +16 -0
  160. package/dist/office-share-page.js +85 -0
  161. package/dist/office-share-page.js.map +1 -0
  162. package/dist/office-share-service.d.ts +91 -0
  163. package/dist/office-share-service.js +176 -0
  164. package/dist/office-share-service.js.map +1 -0
  165. package/dist/office-share.d.ts +258 -0
  166. package/dist/office-share.js +549 -0
  167. package/dist/office-share.js.map +1 -0
  168. package/dist/opencode-usage-scan.d.ts +28 -0
  169. package/dist/opencode-usage-scan.js +92 -0
  170. package/dist/opencode-usage-scan.js.map +1 -0
  171. package/dist/opencode-usage-worker.d.ts +1 -0
  172. package/dist/opencode-usage-worker.js +10 -0
  173. package/dist/opencode-usage-worker.js.map +1 -0
  174. package/dist/outbound-handlers.js +22 -2
  175. package/dist/outbound-handlers.js.map +1 -1
  176. package/dist/outbound-schemas.d.ts +28 -2
  177. package/dist/outbound-schemas.js +29 -2
  178. package/dist/outbound-schemas.js.map +1 -1
  179. package/dist/public-web-gateway.js +16 -2
  180. package/dist/public-web-gateway.js.map +1 -1
  181. package/dist/quickstart-api.js +13 -2
  182. package/dist/quickstart-api.js.map +1 -1
  183. package/dist/quickstart.js +2 -1
  184. package/dist/quickstart.js.map +1 -1
  185. package/dist/remote-card-answer.d.ts +83 -0
  186. package/dist/remote-card-answer.js +208 -0
  187. package/dist/remote-card-answer.js.map +1 -0
  188. package/dist/reply-triggers.d.ts +2 -0
  189. package/dist/reply-triggers.js +3 -0
  190. package/dist/reply-triggers.js.map +1 -0
  191. package/dist/settings-api.d.ts +28 -0
  192. package/dist/settings-api.js +148 -17
  193. package/dist/settings-api.js.map +1 -1
  194. package/dist/settings-change.js +54 -17
  195. package/dist/settings-change.js.map +1 -1
  196. package/dist/settings-effect.js +12 -3
  197. package/dist/settings-effect.js.map +1 -1
  198. package/dist/settings-instance-patch.js +4 -1
  199. package/dist/settings-instance-patch.js.map +1 -1
  200. package/dist/setup-form.d.ts +1 -1
  201. package/dist/setup-form.js +55 -6
  202. package/dist/setup-form.js.map +1 -1
  203. package/dist/setup-host.d.ts +9 -0
  204. package/dist/setup-host.js +127 -6
  205. package/dist/setup-host.js.map +1 -1
  206. package/dist/setup-signin-assets.d.ts +2 -0
  207. package/dist/setup-signin-assets.js +6 -0
  208. package/dist/setup-signin-assets.js.map +1 -0
  209. package/dist/setup-wizard.js +2 -0
  210. package/dist/setup-wizard.js.map +1 -1
  211. package/dist/start-attempt.d.ts +9 -5
  212. package/dist/start-attempt.js +27 -8
  213. package/dist/start-attempt.js.map +1 -1
  214. package/dist/start-failure-chat.d.ts +4 -0
  215. package/dist/start-failure-chat.js +23 -6
  216. package/dist/start-failure-chat.js.map +1 -1
  217. package/dist/start-failure-notice.d.ts +4 -0
  218. package/dist/start-failure-notice.js +8 -0
  219. package/dist/start-failure-notice.js.map +1 -1
  220. package/dist/start-failure.d.ts +25 -0
  221. package/dist/start-failure.js +75 -2
  222. package/dist/start-failure.js.map +1 -1
  223. package/dist/structured-signin-transport.d.ts +8 -0
  224. package/dist/structured-signin-transport.js +79 -0
  225. package/dist/structured-signin-transport.js.map +1 -0
  226. package/dist/structured-signin.d.ts +131 -0
  227. package/dist/structured-signin.js +388 -0
  228. package/dist/structured-signin.js.map +1 -0
  229. package/dist/tool-permissions.js +12 -0
  230. package/dist/tool-permissions.js.map +1 -1
  231. package/dist/topic-commands.js +6 -2
  232. package/dist/topic-commands.js.map +1 -1
  233. package/dist/transcript-sources.d.ts +26 -2
  234. package/dist/transcript-sources.js +103 -40
  235. package/dist/transcript-sources.js.map +1 -1
  236. package/dist/turn-reply-guard.d.ts +25 -0
  237. package/dist/turn-reply-guard.js +111 -12
  238. package/dist/turn-reply-guard.js.map +1 -1
  239. package/dist/types.d.ts +46 -9
  240. package/dist/ui/backend-signin.js +68 -12
  241. package/dist/ui/chat-ambient.js +1 -1
  242. package/dist/ui/chat-effects.js +4 -4
  243. package/dist/ui/chat-render.js +5 -2
  244. package/dist/ui/chat-strings.js +4 -4
  245. package/dist/ui/chat-thread.js +2 -2
  246. package/dist/ui/first-run.js +2 -2
  247. package/dist/ui/fleet-canvas-view.js +114 -0
  248. package/dist/ui/fleet-canvas.js +15 -77
  249. package/dist/ui/fleet-office-editor.js +94 -14
  250. package/dist/ui/fleet-office-layout.js +235 -0
  251. package/dist/ui/fleet-office-model.js +12 -6
  252. package/dist/ui/fleet-office-overview.js +167 -0
  253. package/dist/ui/fleet-office-pack.d.ts +44 -0
  254. package/dist/ui/fleet-office-pack.js +352 -37
  255. package/dist/ui/fleet-office-skin.js +220 -36
  256. package/dist/ui/fleet-office-store.js +112 -7
  257. package/dist/ui/fleet-office-view.js +155 -0
  258. package/dist/ui/fleet-office-zones.js +264 -42
  259. package/dist/ui/fleet-office.js +957 -160
  260. package/dist/ui/fleet-usage.js +26 -21
  261. package/dist/ui/office-share-dialog.js +145 -0
  262. package/dist/ui/office-share-page.js +164 -0
  263. package/dist/ui/panel-chat.js +9 -2
  264. package/dist/ui/panel-details.js +2 -2
  265. package/dist/ui/panel-fleet.js +11 -77
  266. package/dist/ui/panel-log.js +4 -4
  267. package/dist/ui/panel-needs.js +4 -4
  268. package/dist/ui/panel-settings.js +608 -167
  269. package/dist/ui/search-dialog.js +26 -7
  270. package/dist/ui/settings-appearance.js +82 -29
  271. package/dist/ui/settings-apply.js +42 -7
  272. package/dist/ui/settings-dialogs.js +76 -23
  273. package/dist/ui/settings-draft.js +51 -0
  274. package/dist/ui/settings-guests.js +255 -79
  275. package/dist/ui/settings-learn.js +2 -2
  276. package/dist/ui/settings-model.js +16 -6
  277. package/dist/ui/settings-registry.js +146 -0
  278. package/dist/ui/settings-strings.js +116 -44
  279. package/dist/ui/settings-web-authority.js +34 -23
  280. package/dist/ui/shared/app-i18n.js +18 -2
  281. package/dist/ui/shared/app-nav.js +10 -5
  282. package/dist/ui/shared/app-prefs.js +80 -2
  283. package/dist/ui/shared/app-route.js +39 -5
  284. package/dist/ui/shared/app-shell.js +73 -10
  285. package/dist/ui/shared/app-stream.js +3 -1
  286. package/dist/ui/shared/app.css +307 -17
  287. package/dist/ui/shared/app.js +3 -0
  288. package/dist/ui/shared/effect-stock-trust.js +1 -1
  289. package/dist/ui/shared/identity-color.js +4 -4
  290. package/dist/ui/shared/office/cozy.png +0 -0
  291. package/dist/ui/shared/side-panel.js +95 -0
  292. package/dist/ui/shared/signin.js +2 -2
  293. package/dist/ui/shared/ui-dialog.js +6 -1
  294. package/dist/ui/shared/ui-icons.js +2 -0
  295. package/dist/ui/shared/web-authorize.js +13 -12
  296. package/dist/ui/structured-signin.js +115 -0
  297. package/dist/usage-report.d.ts +20 -0
  298. package/dist/usage-report.js +54 -17
  299. package/dist/usage-report.js.map +1 -1
  300. package/dist/usage-rollup.d.ts +9 -1
  301. package/dist/usage-rollup.js +20 -4
  302. package/dist/usage-rollup.js.map +1 -1
  303. package/dist/web-api.d.ts +26 -2
  304. package/dist/web-api.js +361 -5
  305. package/dist/web-api.js.map +1 -1
  306. package/dist/web-auth.js +8 -2
  307. package/dist/web-auth.js.map +1 -1
  308. package/dist/web-backend-login.d.ts +1 -7
  309. package/dist/web-backend-login.js +2 -24
  310. package/dist/web-backend-login.js.map +1 -1
  311. package/dist/web-experimental.d.ts +1 -1
  312. package/dist/web-experimental.js +1 -1
  313. package/dist/web-experimental.js.map +1 -1
  314. package/dist/web-mod-agent.js +2 -2
  315. package/dist/web-mod-agent.js.map +1 -1
  316. package/dist/web-office-acts.d.ts +173 -0
  317. package/dist/web-office-acts.js +285 -0
  318. package/dist/web-office-acts.js.map +1 -0
  319. package/dist/web-office-skins.d.ts +109 -0
  320. package/dist/web-office-skins.js +299 -0
  321. package/dist/web-office-skins.js.map +1 -0
  322. package/dist/web-office-store.d.ts +8 -2
  323. package/dist/web-office-store.js +77 -14
  324. package/dist/web-office-store.js.map +1 -1
  325. package/dist/web-settings-patch.d.ts +8 -1
  326. package/dist/web-settings-patch.js +65 -5
  327. package/dist/web-settings-patch.js.map +1 -1
  328. package/dist/web-shell-routes.d.ts +4 -2
  329. package/dist/web-shell-routes.js +17 -7
  330. package/dist/web-shell-routes.js.map +1 -1
  331. package/dist/working-recovery.d.ts +104 -0
  332. package/dist/working-recovery.js +298 -0
  333. package/dist/working-recovery.js.map +1 -0
  334. package/dist/working-state-journal.d.ts +5 -1
  335. package/dist/working-state-journal.js +31 -3
  336. package/dist/working-state-journal.js.map +1 -1
  337. package/package.json +3 -2
  338. package/templates/windows-shortcuts.ps1 +155 -140
@@ -130,17 +130,22 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
130
130
  A short box that clips to its corners (.msg-quote) moves the bar in (--lbar-left) and shortens it (--lbar-inset) so
131
131
  the corner never cuts its ends round.
132
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,
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, .s-dirty,
134
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; }
135
+ .u-crow:focus-visible, .p-settings .s-nav .seg-item.active, .s-find-item.on { position: relative; }
136
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,
137
+ .us-basis::before, .us-partial::before, .cmd-card.bad::before, .tb-tile::before, .s-dirty::before,
138
138
  /* #2478 item 7 (the user's fixed template): a selected, hovered or keyboard-focused row is the straight bar and a flat
139
139
  background at most — never a rounded fill, a curved inset edge or a rounded ring. */
140
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 {
141
+ .tw-line:hover::before, .tw-line:focus-visible::before, .u-crow:focus-visible::before,
142
+ .p-settings .s-nav .seg-item.active::before, .s-find-item.on::before {
142
143
  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
144
  background: var(--lbar-color, var(--accent)); pointer-events: none; }
145
+ /* #2347: a Settings field edited and not saved yet — the shared straight bar (above), a light tint, and the 3px the bar
146
+ takes added to its padding (and taken back from its margin), so the field's text stays put. */
147
+ .s-dirty { --lbar-color: var(--accent); --lbar-inset: var(--s-1); background: color-mix(in srgb, var(--accent) 7%, transparent);
148
+ padding-left: calc(var(--s-2) + 3px); margin-left: calc(-1 * (var(--s-2) + 3px)); border-radius: 0; align-self: start; }
144
149
  .idc-swatches, .idc-places { border: 0; padding: 0; margin: 0 0 var(--s-3); display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
145
150
  .idc-swatches legend, .idc-places legend { font-weight: var(--fw-semibold); margin-bottom: 6px; width: 100%; }
146
151
  .idc-swatch { --sw: var(--sw-dark); width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; background: var(--sw); cursor: pointer; padding: 0; }
@@ -229,6 +234,9 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
229
234
  /* #1620: Settings → Web — the lead, and the read-only list of what is set in fleet.yaml. */
230
235
  .s-web .sub { margin: 0; color: var(--text-3); font-size: var(--fs-sm); }
231
236
  .s-web-fields:disabled select { opacity: 0.6; } /* over the public link: dimmed like the inputs (.field input:disabled) */
237
+ /* #2347: forms that write what an unsaved fleet.yaml edit writes — off, with the way to that edit above them. */
238
+ .s-yaml-lock:disabled select { opacity: 0.6; }
239
+ .s-yaml-lock-note { margin: 0 0 var(--s-3); }
232
240
  .s-web-ro { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s-1) var(--s-3); margin: 0; font-size: var(--fs-sm); }
233
241
  .s-web-ro > div { display: contents; }
234
242
  .s-web-ro dt { color: var(--text-3); }
@@ -385,6 +393,7 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
385
393
  .dlg-wide { width: min(640px, calc(100vw - 32px)); }
386
394
  .dlg::backdrop { background: var(--scrim); }
387
395
  .dlg-box { display: flex; flex-direction: column; max-height: 85vh; }
396
+ .dlg-box:focus { outline: none; } /* the open dialog's first stop (ui-dialog.js): no ring; Tab moves on with one */
388
397
  .dlg-head { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-4) var(--s-3) var(--s-2) var(--s-5); }
389
398
  .dlg-title { flex: 1; font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
390
399
  .dlg-body { padding: var(--s-2) var(--s-5) var(--s-4); overflow-y: auto; display: flex; flex-direction: column; gap: var(--s-3); }
@@ -440,6 +449,99 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
440
449
  .seg-item.active { background: var(--surface-2); color: var(--text); font-weight: var(--fw-semibold); }
441
450
  /* #1629: Settings has eight sections (Appearance added): they wrap to a second row rather than hide behind a scroll. */
442
451
  .p-settings .seg { flex-wrap: wrap; row-gap: var(--s-1); overflow-x: visible; }
452
+ /* #2347: the sections in two groups, "You" and "Fleet", each with its name; a column on the left on a wide screen. */
453
+ .s-nav { align-items: center; column-gap: var(--s-3); }
454
+ /* #2347, the fixed template (#2330): Settings' sections are square; the one shown is the shared straight bar and a flat
455
+ background (no rounded pill). `.seg` elsewhere (Fleet's tabs, the chat header) is not changed here. */
456
+ .p-settings .s-nav .seg-item { border-radius: 0; }
457
+ .p-settings .s-nav .seg-item.active { background: var(--surface-2); }
458
+ .s-nav-group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1); }
459
+ .s-nav-head { font-size: var(--fs-xs); color: var(--text-3, var(--text-2)); text-transform: uppercase; letter-spacing: 0.04em; padding: 0 var(--s-2); }
460
+ .s-anchor { scroll-margin-top: var(--s-4); }
461
+ /* #2347 §6: settings search — on top of the section nav; results grouped by section, the config key small; a setting
462
+ opened from it flashes for 2 s (a tint, no coloured edge). */
463
+ /* One column (`.p-settings .seg` wraps, which in a column would start a second one beside it). */
464
+ .p-settings > .s-nav { flex-direction: column; align-items: stretch; flex-wrap: nowrap; row-gap: var(--s-2); }
465
+ .s-nav-groups { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--s-3); row-gap: var(--s-1); }
466
+ /* The search never makes the nav wider than its column or row (a flex item's min-content would: a long config key). */
467
+ .s-find, .s-find-results, .s-find-group { min-width: 0; max-width: 100%; }
468
+ .s-find .s-search { width: 100%; box-sizing: border-box; min-width: 0; }
469
+ .s-find .s-search input { text-overflow: ellipsis; }
470
+ .s-find-results { max-height: min(60vh, 420px); overflow-y: auto; margin-top: var(--s-1);
471
+ background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: var(--s-1) 0; }
472
+ .s-find-head { padding: var(--s-2) var(--s-3) var(--s-1); font-size: var(--fs-xs); color: var(--text-2); }
473
+ .s-find-item { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: var(--s-2); padding: var(--s-2) var(--s-3); cursor: pointer; min-width: 0; }
474
+ .s-find-label { min-width: 0; overflow-wrap: anywhere; }
475
+ .s-find-item.on { background: var(--surface-2); }
476
+ .s-find-item mark { background: color-mix(in srgb, var(--accent) 22%, transparent); color: inherit; border-radius: 2px; }
477
+ .s-find-key { font-size: var(--fs-xs); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
478
+ .s-find-none, .s-find-foot { padding: var(--s-2) var(--s-3); margin: 0; font-size: var(--fs-xs); color: var(--text-2); }
479
+ .s-find-foot { border-top: 1px solid var(--border); }
480
+ /* #2382 review: "Fix N field(s) in <section> to save" goes there. */
481
+ .s-pending button.s-fix { border: 0; background: none; padding: 0; cursor: pointer; text-decoration: underline; font: inherit; }
482
+ @keyframes s-flash { from { background: color-mix(in srgb, var(--accent) 22%, transparent); } to { background: transparent; } }
483
+ .s-flash { animation: s-flash 2s ease-out; }
484
+ @media (prefers-reduced-motion: reduce) { .s-flash { animation: none; background: color-mix(in srgb, var(--accent) 12%, transparent); } }
485
+ /* #2347: on a phone the sections keep their names (bare icons could not be told apart), on one row that scrolls
486
+ sideways, each group after its name. */
487
+ @media (max-width: 479px) {
488
+ .p-settings > .s-nav .s-nav-groups { flex-wrap: nowrap; overflow-x: auto; }
489
+ .p-settings > .s-nav .s-nav-group { flex-wrap: nowrap; flex-shrink: 0; }
490
+ }
491
+ /* #2347 §7: on a phone (the app's narrow layout) Settings itself (/settings) is the list of sections — search on top,
492
+ the two groups as full-width rows — and a section opens on its own with "‹ Settings" back to the list. The strip
493
+ that scrolled sideways (and cut its ends) is gone there. Wider screens keep the list beside the section. */
494
+ .p-settings .s-back { display: none; }
495
+ @media (max-width: 899px) {
496
+ .p-settings[data-view="index"] > .panel-body { display: none; }
497
+ .p-settings[data-view="section"] > .s-nav { display: none; }
498
+ .p-settings > .panel-body .s-back { display: flex; align-items: center; gap: var(--s-2); min-height: var(--tap); margin: 0 0 var(--s-2);
499
+ color: var(--accent); font-size: var(--fs-sm); text-decoration: none; }
500
+ .p-settings .s-back .s-back-here { margin-left: auto; color: var(--text); font-weight: var(--fw-semibold); }
501
+ .p-settings[data-view="index"] > .s-nav { flex-direction: column; align-items: stretch; padding: 0 var(--s-4) var(--s-4); }
502
+ .p-settings[data-view="index"] > .s-nav .s-nav-groups { flex-direction: column; align-items: stretch; flex-wrap: nowrap; overflow: visible; gap: var(--s-4); }
503
+ .p-settings[data-view="index"] > .s-nav .s-nav-group { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 0; }
504
+ .p-settings[data-view="index"] > .s-nav .s-nav-head { padding: var(--s-2) var(--s-3) var(--s-1); }
505
+ .p-settings[data-view="index"] > .s-nav .seg-item { min-height: var(--tap); padding: 0 var(--s-3); font-size: var(--fs-md); white-space: normal;
506
+ border-bottom: 1px solid var(--border); }
507
+ /* In the list no section is open: none is marked as the one shown — every row alike. */
508
+ .p-settings[data-view="index"] > .s-nav .seg-item, .p-settings[data-view="index"] > .s-nav .seg-item.active { color: var(--text); }
509
+ .p-settings[data-view="index"] > .s-nav .seg-item.active { background: none; font-weight: inherit; }
510
+ /* The list fills the screen, so unsaved changes' bar stays at the bottom (above the tabs), not right under a short list;
511
+ on a short screen (a small phone, one turned) it takes the room there is and scrolls (#2501 review). */
512
+ .p-settings[data-view="index"] > .s-nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
513
+ /* The bar on a phone: the app's 16 px gutter, and Discard / Save a full tap target. */
514
+ .p-settings > .s-pending { padding-left: var(--s-4); padding-right: var(--s-4); }
515
+ .p-settings > .s-pending .btn { min-height: var(--tap); }
516
+ /* Settings' dialogs are full-screen sheets (§7): an agent's or a connection's fields get the whole screen, the title on
517
+ top and the actions at the bottom, inside it. The app's own questions (ask()) stay bottom sheets. */
518
+ .p-settings .dlg { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border-radius: 0; }
519
+ .p-settings .dlg-box { height: 100%; max-height: 100dvh; }
520
+ .p-settings .dlg-head { padding-top: max(var(--s-3), env(safe-area-inset-top)); border-bottom: 1px solid var(--border); }
521
+ .p-settings .dlg-body { flex: 1; padding-top: var(--s-4); }
522
+ .p-settings .dlg-actions { border-top: 1px solid var(--border); padding-top: var(--s-3); }
523
+ /* Effect tags wrap under the label (§7): whole, on their own line, where the label's text starts — beside a long label
524
+ on a narrow screen they were squeezed or broken mid-tag. */
525
+ .p-settings .field > label:not(.check) .impact, .p-settings .field > legend .impact { display: block; margin: 2px 0 0; white-space: nowrap; }
526
+ /* A checkbox row: the box, the text (and its "default" mark), then the tag on a line of its own under the text. */
527
+ .p-settings .check:has(> .impact) { flex-wrap: wrap; row-gap: 2px; }
528
+ .p-settings .check:has(> .impact) > input { flex: none; width: 16px; height: 16px; margin: 0; }
529
+ .p-settings .check > .impact { flex: 1 0 calc(100% - 16px - var(--s-2)); margin-left: calc(16px + var(--s-2)); white-space: nowrap; }
530
+ /* A tag inside a note (a dialog's status-emoji line) goes to the next line whole, never broken mid-tag. */
531
+ .p-settings .note > .impact { display: inline-block; white-space: nowrap; }
532
+ .p-settings[data-view="index"] > .s-nav .seg-item.active::before { display: none; }
533
+ }
534
+ @media (min-width: 1100px) {
535
+ .p-settings { display: grid; grid-template-columns: 220px minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto; }
536
+ .p-settings > :not(.s-nav):not(.panel-body) { grid-column: 1 / -1; }
537
+ .p-settings > .s-nav { grid-column: 1; grid-row: 2; margin: 0; max-width: none; min-width: 0; padding: var(--s-2) var(--s-2) var(--s-4) var(--s-4); overflow-x: hidden; overflow-y: auto; }
538
+ .p-settings > .s-nav .s-nav-groups { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: var(--s-3); }
539
+ .p-settings > .s-nav .s-nav-group { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
540
+ .p-settings > .s-nav .s-nav-head { padding: var(--s-1) var(--s-3); }
541
+ .p-settings > .s-nav .seg-item { border-radius: 0; }
542
+ .p-settings > .panel-body { grid-column: 2; grid-row: 2; }
543
+ .p-settings > .s-pending { grid-column: 1 / -1; grid-row: 3; }
544
+ }
443
545
  .list-head { display: flex; justify-content: space-between; align-items: center; gap: var(--s-3); margin: var(--s-2) 0 var(--s-3); color: var(--text-2); font-size: var(--fs-sm); }
444
546
  .rows { display: flex; flex-direction: column; gap: var(--s-1); }
445
547
  .row-item { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--surface); font-size: var(--fs-sm); }
@@ -471,6 +573,9 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
471
573
  the message's overflow-wrap: anywhere that is one character wide (the #1672 status line's time, one glyph per line). */
472
574
  .msg .time { font-family: var(--font-mono); white-space: nowrap; flex: none; }
473
575
  .msg.user { align-self: flex-end; max-width: min(80%, 620px); }
576
+ /* Full width (the header's ⋯ menu, this browser's choice): the thread and the composer take the panel, less their own
577
+ padding, for wide tables and code; a person's bubble keeps its cap (above). A phone's column is the screen already. */
578
+ @media (min-width: 900px) { .p-chat[data-width="full"] .thread, .p-chat[data-width="full"] .dock-col { max-width: none; } }
474
579
  .msg.user .meta { justify-content: flex-end; }
475
580
  /* #1773: the bubble hugs its text. The message is as wide as its widest child — usually the meta row (sender, a time
476
581
  such as 「昨天 下午03:58」, ticks) — and a block body would stretch to it; fit-content keeps a short message short, on
@@ -821,15 +926,47 @@ img.amb-p { object-fit: contain; }
821
926
  padding: var(--s-1) var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); color: var(--text);
822
927
  box-shadow: var(--shadow-2); }
823
928
  .webauth-tip[hidden] { display: none; }
824
- /* #1920 phase 3: Settings → Web → Guests. */
929
+ /* #1920 phase 3 / #2348: Settings → Access & security → Guests. The fixed template (#2330): flat rows split by a rule,
930
+ no rounded box or fill; an edited row is .s-dirty (the shared straight bar + tint, square). A state is coloured text. */
825
931
  .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;
826
- padding: var(--s-1) var(--s-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
932
+ padding: var(--s-1) 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
827
933
  .s-guests .guest-name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
828
- .s-guests .guest-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
829
- .s-guests .guest-row { padding: var(--s-2) var(--s-3); border: 1px solid var(--border); border-radius: var(--r-sm); }
830
- .s-guests .guest-actions { display: flex; flex-wrap: wrap; gap: var(--s-1); margin-top: var(--s-1); }
934
+ /* #2667: the ClassicBot rooms follow the fleet's instances under their own heading, across the grid. */
935
+ .s-guests .guest-names-group { grid-column: 1 / -1; margin-top: var(--s-2); }
936
+ .s-guests .guest-list, .s-guests .g-pick { list-style: none; margin: 0 0 var(--s-3); padding: 0; display: flex; flex-direction: column; border-top: 1px solid var(--border); }
937
+ .s-guests .guest-row, .s-guests .g-cand { padding: var(--s-3) 0; border-bottom: 1px solid var(--border); min-width: 0; }
938
+ .s-guests .guest-row.s-dirty { border-radius: 0; margin-left: 0; align-self: stretch; padding-left: calc(var(--s-2) + 3px); padding-right: var(--s-2); }
939
+ .s-guests .guest-row.g-removed .g-id strong { text-decoration: line-through; color: var(--text-3); }
940
+ .s-guests .g-head { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; min-width: 0; }
941
+ .s-guests .g-av { flex: none; width: 28px; height: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
942
+ background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--text); font-weight: 600; font-size: var(--fs-sm); }
943
+ .s-guests .g-id { flex: 1 1 220px; min-width: 0; overflow-wrap: anywhere; }
944
+ .s-guests .g-id .note { white-space: normal; }
945
+ .s-guests .g-state { flex: 0 1 auto; max-width: 100%; margin-left: auto; font-size: var(--fs-sm); color: var(--text-3); text-align: right; }
946
+ .s-guests .g-state.on { color: var(--ok); }
947
+ .s-guests .g-state.sent { color: var(--accent); }
948
+ .s-guests .g-state.warn { color: var(--danger); text-align: left; flex-basis: 100%; margin-left: calc(28px + var(--s-2)); }
949
+ .s-guests .g-chips { display: flex; flex-wrap: wrap; gap: var(--s-1); margin: var(--s-2) 0 0 calc(28px + var(--s-2)); }
950
+ .s-guests .g-chip { padding: 1px var(--s-2); border: 1px solid color-mix(in srgb, var(--text-3) 55%, transparent); border-radius: 0; font-size: var(--fs-sm); color: var(--text-2); white-space: nowrap; }
951
+ .s-guests .g-edit { margin: var(--s-2) 0 0 calc(28px + var(--s-2)); }
952
+ .s-guests .guest-actions { display: flex; flex-wrap: wrap; gap: var(--s-1); margin: var(--s-2) 0 0 calc(28px + var(--s-2)); }
953
+ .s-guests .g-error { color: var(--danger); margin-left: calc(28px + var(--s-2)); }
954
+ .s-guests .g-search { width: 100%; max-width: 360px; margin: var(--s-1) 0 var(--s-2); }
955
+ .s-guests .g-cand { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; align-items: center; gap: var(--s-2); }
956
+ .s-guests .g-legacy { margin: var(--s-2) 0; }
957
+ .s-guests .g-audit { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); font-size: var(--fs-sm); }
958
+ .s-guests .g-audit-row { padding: var(--s-1) 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
959
+ .s-guests .g-audit-row .g-when { color: var(--text-3); }
960
+ .s-guests .g-add { color: var(--ok); }
961
+ .s-guests .g-del { color: var(--danger); }
962
+ .s-guests .g-when, .s-guests .g-wrote { white-space: nowrap; }
831
963
  .s-guests .guest-narrow-edit { margin-top: var(--s-2); }
832
964
  .s-guests .guest-away { color: var(--text-3); }
965
+ @media (max-width: 560px) {
966
+ .s-guests .g-state { flex-basis: 100%; margin-left: calc(28px + var(--s-2)); text-align: left; }
967
+ .s-guests .g-cand { grid-template-columns: 28px minmax(0, 1fr); }
968
+ .s-guests .g-cand > .btn { grid-column: 2; justify-self: start; }
969
+ }
833
970
  /* #1939 S2b: this browser's authorization, under the composer and in the session menu (one compact line). */
834
971
  .webauth-chip { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-2); margin: var(--s-1) 0 0; font-size: var(--fs-xs); }
835
972
  .webauth-chip .webauth-ok { color: var(--ok); }
@@ -1213,6 +1350,18 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
1213
1350
  @media (prefers-reduced-motion: no-preference) { .u-crow { transition: background-color 0.15s var(--ease); } }
1214
1351
  .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); }
1215
1352
  @media (max-width: 1199px) { .u-rail { display: none; } }
1353
+ /* #2585: the docked side panel (side-panel.js), in the usage rail's place beside the page — a non-modal dialog, so the
1354
+ shared dialog's head, body and actions, laid out as a full-height column. Below the rail's width it is never drawn
1355
+ (the editor is the centred Dialog there). */
1356
+ .dlg.side-panel { position: static; inset: auto; margin: 0; width: 400px; max-width: 400px; height: auto; max-height: none; flex-shrink: 0;
1357
+ display: flex; flex-direction: column; min-height: 0; border-radius: 0; box-shadow: none; border-left: 1px solid var(--border); background: var(--bg); color: var(--text); }
1358
+ .side-panel .dlg-box { flex: 1; min-height: 0; max-height: none; }
1359
+ .side-panel .dlg-head { padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5); border-bottom: 1px solid var(--border); }
1360
+ .side-panel .dlg-body { flex: 1; min-height: 0; padding-top: var(--s-4); }
1361
+ .side-panel .dlg-actions { padding: var(--s-3) var(--s-5); border-top: 1px solid var(--border); }
1362
+ @media (max-width: 1199px) { .dlg.side-panel { display: none; } }
1363
+ /* A toast (Offices saved.) beside a docked panel, not over its Cancel and Save. */
1364
+ @media (min-width: 1200px) { .shell:has(> .side-panel) .toasts { right: calc(400px + var(--s-6)); } }
1216
1365
  @media (max-width: 899px) {
1217
1366
  .hide-narrow { display: none; }
1218
1367
  .v-id { padding-left: var(--s-3); padding-right: var(--s-3); }
@@ -1224,7 +1373,7 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
1224
1373
  .s-toolbar { display: flex; gap: var(--s-2); margin: var(--s-2) 0; }
1225
1374
  .s-search { flex: 1; display: flex; align-items: center; gap: var(--s-2); padding: 0 var(--s-3); border-radius: var(--r-sm); background: var(--surface); color: var(--text-3); }
1226
1375
  .s-search:focus-within { box-shadow: 0 0 0 2px var(--focus); }
1227
- .s-search input { flex: 1; min-width: 0; height: 36px; border: 0; background: transparent; color: var(--text); outline: none; font-size: var(--fs-sm); }
1376
+ .s-search input { flex: 1; min-width: 0; height: 36px; border: 0; background: transparent; color: var(--text); outline: none; font-size: var(--fs-sm); text-overflow: ellipsis; }
1228
1377
  .s-list { display: flex; flex-direction: column; gap: 2px; margin-bottom: var(--s-4); }
1229
1378
  .s-group { margin-bottom: var(--s-2); }
1230
1379
  .s-group-head { display: flex; align-items: center; gap: var(--s-2); width: 100%; padding: var(--s-2) var(--s-2); border: 0; background: transparent; color: var(--text-3);
@@ -1259,6 +1408,10 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
1259
1408
  .grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3) var(--s-4); }
1260
1409
  .override { display: flex; flex-direction: column; gap: var(--s-1); }
1261
1410
  .inherit-row { font-size: var(--fs-xs); color: var(--text-3); }
1411
+ /* #2347 §10: the value in effect (an empty field's, an inherited one's) in plain text; "default" marks what nobody set. */
1412
+ .s-effect, .s-inherited { margin: 0; font-size: var(--fs-xs); color: var(--text-2); }
1413
+ .s-inherited a { color: var(--accent); }
1414
+ .tag.s-default { font-weight: var(--fw-regular); }
1262
1415
  .impact { font-size: 11px; font-weight: var(--fw-regular); color: var(--text-3); margin-left: var(--s-1); }
1263
1416
  .check .impact { margin-left: auto; }
1264
1417
  .feedback { font-size: var(--fs-xs); color: var(--text-2); }
@@ -1283,6 +1436,12 @@ body.side-resizing, body.side-resizing * { cursor: col-resize !important; user-s
1283
1436
  .btn.on { background: var(--surface-2); color: var(--text); font-weight: var(--fw-semibold); }
1284
1437
  .card h4 { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-2); }
1285
1438
  .pill.ver { text-transform: none; letter-spacing: 0; }
1439
+ /* #2347 §7: Settings' title stays whole on a narrow phone (at 320 px it was cut to "S…"): the version beside it takes the
1440
+ room that is left — shortened, or not shown when too little is. */
1441
+ .p-settings .panel-title h1 { flex: none; }
1442
+ .p-settings .panel-sub { flex: 1 1 0; min-width: 0; container: settings-ver / inline-size; }
1443
+ .p-settings .panel-sub .pill.ver { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }
1444
+ @container settings-ver (max-width: 56px) { .p-settings .panel-sub .pill.ver { display: none; } }
1286
1445
  .s-key { display: flex; flex-direction: column; gap: var(--s-1); padding: var(--s-2) 0; border-top: 1px solid var(--border); }
1287
1446
  .s-key:first-of-type { border-top: 0; }
1288
1447
  .s-key-row { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
@@ -1316,6 +1475,7 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1316
1475
  .s-pending { position: sticky; bottom: 0; display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; padding: var(--s-3) var(--s-5);
1317
1476
  background: var(--bg); border-top: 1px solid var(--border); box-shadow: var(--shadow-2); }
1318
1477
  .s-pending .grow { flex: 1; }
1478
+ .s-pending-actions { display: flex; align-items: center; gap: var(--s-3); margin-left: auto; }
1319
1479
  .s-op { border: 1px solid var(--border); }
1320
1480
  .s-op.failed { border-color: var(--danger-line); }
1321
1481
  .s-op-head { display: flex; align-items: center; gap: var(--s-2); }
@@ -1357,6 +1517,10 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1357
1517
  .op-line { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
1358
1518
  .op-line.ok { color: var(--ok); }
1359
1519
  .op-line.bad { color: var(--danger); }
1520
+ /* #2347: saved changes waiting for an AgEnD restart — one line, the shared straight bar on its left. */
1521
+ .restart-line { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--s-2); color: var(--text);
1522
+ --lbar-color: var(--warn); }
1523
+ .restart-line .restart-keys { font-family: var(--font-mono); }
1360
1524
  /* #2233: the backend sign-in dialog and Settings' list */
1361
1525
  .signin-field { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin: var(--s-2) 0; }
1362
1526
  .signin-label { color: var(--text-2); font-size: var(--fs-xs); min-width: 6em; }
@@ -1379,6 +1543,7 @@ textarea.s-yaml { white-space: pre; overflow-x: auto; }
1379
1543
  .shell:has(.s-pending) .pending-stack { bottom: calc(64px + 64px + var(--s-3)); }
1380
1544
  .shell:has(.s-pending) .toasts { bottom: auto; }
1381
1545
  .s-pending { padding: var(--s-2) var(--s-3); }
1546
+ .s-pending-actions { flex-basis: 100%; justify-content: flex-end; }
1382
1547
  }
1383
1548
 
1384
1549
  /* ── Needs you (#1408 step 4 = #1386 part b) ── */
@@ -1569,8 +1734,18 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1569
1734
  .oc-mini { display: none; }
1570
1735
  }
1571
1736
  /* ── Fleet → Org chart → Office (fleet-office.js): the fleet as a pixel office on one <canvas>. Its size is set through
1572
- the CSSOM (never a style attribute, #1300); the stage scrolls, the page around it too. ── */
1573
- .oo { display: flex; flex-direction: column; gap: var(--s-2); }
1737
+ the CSSOM (never a style attribute, #1300). #2540: it fills the Fleet panel — no frame or margins around the canvas,
1738
+ the bars above it keep the column's padding; the stage pans and zooms (touch gestures are its own, touch-action:
1739
+ none on it only) and the page around it no longer scrolls sideways. The column's `margin: 0 auto` must go too: in
1740
+ the panel's flex column an auto margin shrinks the column to its content (the bars: the canvas is absolutely placed
1741
+ and adds no width) and centres it — the Office was as wide as its toolbar, not the panel. ── */
1742
+ .p-fleet .panel-body:has(> .col > .oc-office) { display: flex; flex-direction: column; }
1743
+ .p-fleet .panel-body > .col:has(> .oc-office) { flex: 1 0 auto; display: flex; flex-direction: column; max-width: none; padding: 0; margin: 0; width: 100%; align-self: stretch; }
1744
+ .oc-office { flex: 1 0 auto; display: flex; flex-direction: column; min-width: 0; width: 100%; }
1745
+ .oc-office > .oc-bar { margin: 0; padding: var(--s-3) var(--s-5) var(--s-2); }
1746
+ .oc-office > .oc-legend { margin: 0 var(--s-5) var(--s-2); }
1747
+ .oo { flex: 1 0 auto; display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; width: 100%; }
1748
+ .oo > :not(.oo-stage):not(dialog) { margin-left: var(--s-5); margin-right: var(--s-5); } /* not the editors' dialogs: they centre themselves (#2585) */
1574
1749
  .oo-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
1575
1750
  .oo-pick { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--text-2); }
1576
1751
  .oo-pick .tb-select { max-width: 200px; }
@@ -1586,6 +1761,13 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1586
1761
  .oe-label { font-size: var(--fs-xs); color: var(--text-2); }
1587
1762
  .oe-name { min-width: 0; width: 16em; max-width: 100%; }
1588
1763
  .oe-remove { margin-left: auto; }
1764
+ /* #2513: the skin packs the host keeps — a row each with its delete, then the upload buttons (a hidden file input each). */
1765
+ .oe-packs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-3); }
1766
+ .oe-packs > legend, .oe-packs > .note { flex-basis: 100%; }
1767
+ .oe-pack-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; flex-basis: 100%; }
1768
+ .oe-pack { display: flex; align-items: center; gap: var(--s-2); overflow-wrap: anywhere; }
1769
+ .oe-pack-remove { margin-left: auto; }
1770
+ .oe-upload { position: relative; cursor: pointer; }
1589
1771
  .oe-members { display: flex; flex-wrap: wrap; gap: var(--s-3); }
1590
1772
  .oe-group { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; min-width: 12em; max-height: 240px; overflow-y: auto; }
1591
1773
  .oe-group legend { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-2); padding: 0; margin-bottom: 4px; }
@@ -1596,24 +1778,103 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1596
1778
  .oo-people-list { list-style: none; margin: 0; padding: 0; }
1597
1779
  .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; }
1598
1780
  .oo-note { font-size: var(--fs-xs); }
1599
- .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); }
1600
- .oo-canvas { display: block; margin: 0 auto; image-rendering: pixelated; }
1781
+ .oo-stage { position: relative; flex: 1 1 auto; min-height: 340px; overflow: hidden; background: var(--bg); touch-action: none; user-select: none; -webkit-user-select: none; }
1782
+ /* #2554: clip, not a scroll container — nothing past the edge (a tile's label) can scroll the stage and its controls. */
1783
+ .oo-stage { overflow: clip; }
1784
+ .oo-canvas { position: absolute; left: 0; top: 0; display: block; image-rendering: pixelated; cursor: grab; touch-action: none; }
1785
+ .oo-canvas:active { cursor: grabbing; }
1786
+ .oo-canvas:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
1601
1787
  .oo-canvas.hot { cursor: pointer; }
1788
+ /* The canvas controls, as the org chart canvas's (.oc-zoom, .oc-mini): over the stage's corners. */
1789
+ .oo-zoom { z-index: 6; }
1790
+ .oo-zoom .icon-btn { color: var(--text); }
1791
+ /* The overview's box (left, top, width, height) is set by the page, inside the stage and scaled to it (miniBox). */
1792
+ .oo-mini { z-index: 6; right: auto; bottom: auto; overflow: hidden; }
1793
+ .oo-zoom-pct { display: block; padding: 3px 0; font-size: 11px; line-height: 14px; text-align: center; color: var(--text-2); font-variant-numeric: tabular-nums;
1794
+ border-bottom: 1px solid var(--border); user-select: none; }
1795
+ .oo-zoom .oo-fill { font-size: 11px; font-weight: var(--fw-semibold); }
1796
+ .oo-zoom .oo-fill.on { background: var(--accent-dim); color: var(--text); }
1797
+ .oo-stage.editing .oo-mini { display: none; }
1798
+ .oo-mini-scene { fill: var(--bg); }
1799
+ .oo-mini-room { fill: var(--surface); stroke: var(--border-strong); stroke-width: 6; }
1800
+ .oo-mini-dot { fill: var(--text-3); }
1801
+ .oo-mini-dot.st-working { fill: var(--ok); }
1802
+ .oo-mini-dot.st-needs, .oo-mini-dot.st-stuck { fill: var(--warn); }
1803
+ .oo-mini-dot.st-crashed { fill: var(--danger); }
1804
+ .oo-mini-dot.match { fill: var(--focus); }
1602
1805
  .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;
1603
1806
  color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-2); overflow-wrap: anywhere; }
1807
+ /* #2554: All offices — each tile's label (office name and head count) just above the tile, placed by the page (left, top,
1808
+ max-width through the CSSOM); a button that opens the office, the lobby's a plain chip. */
1809
+ .oo-tile-label { position: absolute; left: 0; top: 0; z-index: 3; transform: translateY(calc(-100% - 4px)); max-width: 240px; overflow: hidden; text-overflow: ellipsis;
1810
+ white-space: nowrap; padding: 2px 8px; font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-semibold); line-height: 18px; color: var(--text);
1811
+ background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); }
1812
+ button.oo-tile-label { cursor: pointer; }
1813
+ button.oo-tile-label:hover { border-color: var(--accent); }
1814
+ button.oo-tile-label:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
1815
+ .oo-tile-label.lobby { color: var(--text-2); }
1816
+ .oo-lobby-tile { font-size: var(--fs-xs); color: var(--text-2); }
1604
1817
  /* The desks as a list: for a screen reader, and shown (over the stage's corner) while the keyboard is in it. */
1605
1818
  .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; }
1606
- .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;
1819
+ .oo-desks:focus-within { position: absolute; z-index: 7; 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;
1607
1820
  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; }
1608
1821
  .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); }
1609
1822
  .oo-desk:focus-visible { outline: none; border-color: var(--focus); box-shadow: inset 0 -2px 0 var(--focus); }
1823
+ /* #2513: Edit layout (fleet-office-layout.js) — an SVG over the canvas (placed and sized through the CSSOM), its 1280×720
1824
+ grid, the areas, corridors and a handle for each seat, item, the door and waypoint; its bar sticks to the stage's foot. */
1825
+ .oo-hide-asleep { font-size: var(--fs-xs); color: var(--text-2); }
1826
+ /* #2540: fullscreen. The container is the page's fullscreen element (the Fullscreen API: the top layer), or, where the page
1827
+ cannot take one (an iPhone) or the browser refused, "immersive": it covers the window. Only the stage shows (the bars,
1828
+ notes and Edit offices are left out), the safe areas kept clear; floating over it the zoom controls, the overview
1829
+ (not on a phone) and a compact office switcher. Immersive lifts the Fleet panel's band (stock content, level 1) over
1830
+ the header (2), the phone's nav (35) and the drawer and Needs-you stack (40); menus (60) and toasts (100) stay above. */
1831
+ .oo.fs { gap: 0; margin: 0; background: var(--bg); box-sizing: border-box;
1832
+ padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
1833
+ .oo.fs > :not(.oo-stage) { display: none; }
1834
+ .oo.fs > .oo-stage { flex: 1 1 auto; min-height: 0; }
1835
+ .oo.fs.immersive { position: fixed; inset: 0; z-index: 50; width: 100vw; height: 100vh; width: 100dvw; height: 100dvh; }
1836
+ html.oo-immersive, html.oo-immersive body { overflow: hidden; }
1837
+ html.oo-immersive .p-fleet > .panel-body { z-index: 50; }
1838
+ .oo-fs-bar { position: absolute; left: var(--s-3); top: var(--s-3); z-index: 6; display: flex; align-items: center; gap: var(--s-2); }
1839
+ .oo-fs-bar .tb-select { max-width: 180px; }
1840
+ .ol-overlay { position: absolute; left: 0; top: 0; z-index: 4; }
1841
+ .ol-svg { display: block; overflow: visible; touch-action: none; }
1842
+ .ol-grid { stroke: var(--text-3); stroke-opacity: 0.25; stroke-width: 1; }
1843
+ .ol-label, .ol-coord { fill: var(--text); font-size: 12px; font-family: var(--font-mono, monospace); paint-order: stroke; stroke: var(--bg); stroke-width: 3px; }
1844
+ .ol-area { fill: none; stroke: var(--text-2); stroke-dasharray: 6 4; stroke-width: 1.5; }
1845
+ .ol-edge { stroke: var(--focus); stroke-width: 3; stroke-opacity: 0.7; }
1846
+ .ol-handle { cursor: grab; outline: none; }
1847
+ .ol-handle > circle, .ol-handle > rect { fill: var(--surface); stroke: var(--text); stroke-width: 2; }
1848
+ .ol-seat > circle { fill: var(--ok); }
1849
+ .ol-furniture > rect { fill: var(--warn); }
1850
+ .ol-door > rect { fill: var(--danger); }
1851
+ /* #2665: an item's night place — a moon on a faint disc, a thin dashed line to its day place. */
1852
+ .ol-night > circle { fill: var(--surface); fill-opacity: 0.85; }
1853
+ .ol-night > .ol-moon { fill: var(--warn); stroke: none; pointer-events: none; }
1854
+ .ol-night-line { stroke: var(--warn); stroke-width: 1.5; stroke-dasharray: 4 3; stroke-opacity: 0.8; pointer-events: none; }
1855
+ .ol-waypoint > circle { fill: var(--focus); }
1856
+ .ol-handle.on > circle, .ol-handle.on > rect, .ol-handle:focus-visible > circle, .ol-handle:focus-visible > rect { stroke: var(--focus); stroke-width: 4; }
1857
+ .ol-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 8; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-2);
1858
+ background: var(--surface); border-top: 1px solid var(--border); }
1859
+ .ol-actions { display: inline-flex; gap: var(--s-2); margin-left: auto; }
1860
+ /* #2585: Edit layout's controls docked in the side panel (a wide desk): one column, the waypoint's own row wrapping. */
1861
+ .ol-side { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-3); }
1862
+ .ol-side .ol-corridors { display: flex; flex-wrap: wrap; gap: var(--s-2); }
1863
+ .ol-corridors { display: inline-flex; flex-wrap: wrap; gap: 4px; }
1864
+ .ol-msg { flex-basis: 100%; margin: 0; }
1610
1865
  @media (max-width: 640px) {
1611
- .oo-stage { height: calc(100dvh - 300px); min-height: 340px; }
1866
+ /* A phone: the bars at the column's narrower padding; the stage at least most of a screen; no overview (as the canvas). */
1867
+ .oc-office > .oc-bar { padding: var(--s-2) var(--s-3); }
1868
+ .oc-office > .oc-legend { margin: 0 var(--s-3) var(--s-2); }
1869
+ .oo > :not(.oo-stage):not(dialog) { margin-left: var(--s-3); margin-right: var(--s-3); }
1870
+ .oo-stage { min-height: max(300px, calc(100dvh - 300px)); }
1612
1871
  .oo-pick .tb-select { max-width: 150px; }
1872
+ .oo-mini { display: none; }
1873
+ .oo-zoom .icon-btn { width: 40px; height: 40px; }
1613
1874
  }
1614
1875
  /* A phone: Fleet's five tabs fit when only the open one shows its label (the others keep theirs for screen readers). */
1615
1876
  @media (max-width: 479px) {
1616
- .p-fleet .seg-item:not(.active) > span, .p-settings .seg-item:not(.active) > span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
1877
+ .p-fleet .seg-item:not(.active) > span { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
1617
1878
  }
1618
1879
 
1619
1880
  /* ── Cache analysis (#1468): Fleet → Cache. Bars are SVG attributes; nothing here is an inline style. ── */
@@ -1681,6 +1942,7 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
1681
1942
  .us-bar { display: block; width: 100%; height: 6px; margin: 4px 0; }
1682
1943
  .us-bar-bg { fill: var(--surface-2); } .us-bar-fg { fill: var(--us-0); }
1683
1944
  .us-meta { display: block; font-size: var(--fs-xs); color: var(--text-3); overflow-wrap: anywhere; }
1945
+ .us-est { display: block; font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--text-3); }
1684
1946
  .us-flags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
1685
1947
  .us-trend, .us-heat { display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; }
1686
1948
  .us-trend h3, .us-heat h3, .us-rest h3 { font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
@@ -2248,3 +2510,31 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
2248
2510
  .msg.user .msg-reactions { justify-content: flex-end; }
2249
2511
  .msg-reactions .reaction { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 24px; padding: 0 6px;
2250
2512
  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; }
2513
+
2514
+ /* #2636: an Office share link's page (office-share-page.js) — the Office alone, filling the window under a one-line head. */
2515
+ .share-page { display: flex; flex-direction: column; min-height: 100dvh; background: var(--bg); color: var(--text); }
2516
+ .share-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-1) var(--s-3); padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--border); }
2517
+ .share-head .share-note { margin-left: auto; }
2518
+ .share-stage { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; padding: var(--s-2); }
2519
+ .share-loading, .share-page > .note { padding: var(--s-4); }
2520
+ .share-ended { align-items: center; justify-content: center; padding: var(--s-6); text-align: center; }
2521
+ @media (max-width: 640px) { .share-head .share-note { margin-left: 0; flex-basis: 100%; } }
2522
+
2523
+ /* #2636: Office share links — the Share… dialog and the open links (office-share-dialog.js; Settings → Access & security). */
2524
+ .os { display: flex; flex-direction: column; gap: var(--s-3); }
2525
+ .os > p { margin: 0; }
2526
+ .os-form { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3); align-items: end; }
2527
+ .os-form .check, .os-form .note { grid-column: 1 / -1; margin: 0; }
2528
+ .os-made { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
2529
+ .os-url { flex: 1 1 260px; min-width: 0; min-height: 40px; padding: var(--s-2) var(--s-3); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
2530
+ background: var(--bg); color: var(--text); font-size: var(--fs-sm); outline: none; }
2531
+ .os-url:focus { border-color: var(--focus); box-shadow: 0 0 0 3px var(--accent-dim); }
2532
+ .os-made .note { flex-basis: 100%; margin: 0; }
2533
+ .os-head { margin: var(--s-2) 0 0; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-2); }
2534
+ .os-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
2535
+ .os-row { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) var(--s-3); border: 1px solid var(--border); border-radius: var(--r-sm); }
2536
+ .os-what { flex: 1; min-width: 0; overflow-wrap: anywhere; font-size: var(--fs-sm); }
2537
+ .os-all { margin-top: var(--s-2); }
2538
+ .os-none { margin: 0; }
2539
+ .os-form .os-err { grid-column: 1 / -1; margin: 0; padding: var(--s-2) var(--s-3); border: 1px solid var(--danger); border-radius: var(--r-sm); }
2540
+ @media (max-width: 480px) { .os-form { grid-template-columns: 1fr; } }
@@ -87,6 +87,9 @@ if (mode === "full") {
87
87
  if (!guest) {
88
88
  panels.set("fleet", { load: () => loadFleet().then((m) => m.FleetPanel) });
89
89
  panels.set("settings", { load: () => loadSettings().then((m) => m.SettingsPanel) });
90
+ // #2347: the restart banner's Restart now, in any panel — the Settings runner (behind the session) does it.
91
+ const loadApply = retryable((a) => import(retryUrl("/ui/js/settings-apply.js", a)));
92
+ appStore.set({ restartRunner: (jobId) => loadApply().then((m) => m.restartPendingChanges(jobId)) });
90
93
  panels.set("needs", { load: () => loadNeeds().then((m) => m.NeedsPanel) });
91
94
  // #1523 N2: one instance's Details (/ui/fleet/agent/<name>).
92
95
  panels.set("details", { load: () => loadDetails().then((m) => m.DetailsPanel) });
@@ -212,6 +212,6 @@ export function stockEffectTrust(host, { frameRoot = null, ownerCss = "unknown"
212
212
  if (doc.fullscreenElement || doc.pictureInPictureElement) barrier = true;
213
213
  // Focus alone does not change protected paint bounds. Composer/controls stay clipped; editable focus
214
214
  // separately suppresses pointer delivery in the registry, and keyboard events never enter a Worker.
215
- return { ok: true, rects, front: !barrier, reason: barrier ? "stock_overlay" : "stock", agentFront: !barrier && ownerCss === "off", agentReason: barrier ? "stock_overlay" : ownerCss === "off" ? "stock" : "owner_css", settingsHref: "/settings/appearance" };
215
+ return { ok: true, rects, front: !barrier, reason: barrier ? "stock_overlay" : "stock", agentFront: !barrier && ownerCss === "off", agentReason: barrier ? "stock_overlay" : ownerCss === "off" ? "stock" : "owner_css", settingsHref: "/settings/look" };
216
216
  } catch { return fail("stock_trust_unknown"); }
217
217
  }
@@ -4,7 +4,7 @@
4
4
  // paints the sidebar row through the CSSOM (no style attribute, #1300), and holds the Color dialog.
5
5
  // colour: a person's pick > the agent's (themes shown) > its own bot's role colour > automatic (a few soft colours)
6
6
  // places: a person's choice > the agent's (themes shown) > this host's default (color.show) > all three (#2056)
7
- // Settings → Web appearance can turn colours off for the host (color.off): nothing is painted, every pick is kept.
7
+ // Settings → Look can turn colours off for the host (color.off): nothing is painted, every pick is kept.
8
8
  import { html, useEffect, useState } from "./app-html.js";
9
9
  import { createStore, useStore } from "./app-store.js";
10
10
  import { onPrefsChanged, prefInForce, savePref } from "./app-prefs.js";
@@ -108,7 +108,7 @@ export const colorPrefsStore = createStore({ n: 0 });
108
108
  const bump = () => colorPrefsStore.set((s) => ({ n: s.n + 1 }));
109
109
  onPrefsChanged((changed) => { if (changed.has("color.show") || changed.has("color.off")) bump(); });
110
110
  const readLocal = (k) => { try { return localStorage.getItem(k); } catch { return null; } };
111
- /** Where colours show by default on this host (Settings → Web appearance). */
111
+ /** Where colours show by default on this host (Settings → Look). */
112
112
  export function defaultPlaces() {
113
113
  const f = prefInForce("color.show");
114
114
  let v = f ? f.value : undefined;
@@ -251,7 +251,7 @@ register("color", {
251
251
  src_person: "Shown now: picked by a person.", src_agent: "Shown now: the agent's own colour.", src_role: "Shown now: the colour of its bot's Discord role.",
252
252
  src_auto: "Shown now: an automatic colour.", save: "Save", cancel: "Cancel", reset: "Reset",
253
253
  saved: "Colour saved for {0}", failed: "Couldn't save the colour: {0}",
254
- offNote: "Colours are turned off on this host (Settings → Web appearance). What you pick here is kept for when they're on.",
254
+ offNote: "Colours are turned off on this host (Settings → Look). What you pick here is kept for when they're on.",
255
255
  p_red: "Red", p_orange: "Orange", p_amber: "Amber", p_lime: "Lime", p_green: "Green", p_teal: "Teal", p_cyan: "Cyan", p_blue: "Blue",
256
256
  p_indigo: "Indigo", p_violet: "Violet", p_pink: "Pink", p_slate: "Slate",
257
257
  },
@@ -261,7 +261,7 @@ register("color", {
261
261
  src_person: "目前顯示:有人挑選的顏色。", src_agent: "目前顯示:agent 自己的顏色。", src_role: "目前顯示:它的 bot 在 Discord 身分組的顏色。",
262
262
  src_auto: "目前顯示:自動配色。", save: "儲存", cancel: "取消", reset: "重設",
263
263
  saved: "已儲存 {0} 的顏色", failed: "無法儲存顏色:{0}",
264
- offNote: "這台主機已關閉顏色(設定 → 網頁外觀)。在這裡挑的顏色會保留,重新開啟後就會出現。",
264
+ offNote: "這台主機已關閉顏色(設定 → 外觀)。在這裡挑的顏色會保留,重新開啟後就會出現。",
265
265
  p_red: "紅", p_orange: "橙", p_amber: "琥珀", p_lime: "萊姆", p_green: "綠", p_teal: "青綠", p_cyan: "青", p_blue: "藍",
266
266
  p_indigo: "靛", p_violet: "紫", p_pink: "粉紅", p_slate: "石板灰",
267
267
  },
Binary file