@vendoai/ui 0.4.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 (525) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +7 -0
  3. package/dist/chrome/activity-ledger.d.ts +14 -0
  4. package/dist/chrome/activity-ledger.d.ts.map +1 -0
  5. package/dist/chrome/activity-ledger.js +40 -0
  6. package/dist/chrome/activity-ledger.js.map +1 -0
  7. package/dist/chrome/activity-panel.d.ts +7 -0
  8. package/dist/chrome/activity-panel.d.ts.map +1 -0
  9. package/dist/chrome/activity-panel.js +27 -0
  10. package/dist/chrome/activity-panel.js.map +1 -0
  11. package/dist/chrome/activity-semantics.d.ts +42 -0
  12. package/dist/chrome/activity-semantics.d.ts.map +1 -0
  13. package/dist/chrome/activity-semantics.js +119 -0
  14. package/dist/chrome/activity-semantics.js.map +1 -0
  15. package/dist/chrome/approval-card.d.ts +22 -0
  16. package/dist/chrome/approval-card.d.ts.map +1 -0
  17. package/dist/chrome/approval-card.js +95 -0
  18. package/dist/chrome/approval-card.js.map +1 -0
  19. package/dist/chrome/approval-sheet.d.ts +23 -0
  20. package/dist/chrome/approval-sheet.d.ts.map +1 -0
  21. package/dist/chrome/approval-sheet.js +72 -0
  22. package/dist/chrome/approval-sheet.js.map +1 -0
  23. package/dist/chrome/automations-panel.d.ts +3 -0
  24. package/dist/chrome/automations-panel.d.ts.map +1 -0
  25. package/dist/chrome/automations-panel.js +305 -0
  26. package/dist/chrome/automations-panel.js.map +1 -0
  27. package/dist/chrome/build-beat.d.ts +70 -0
  28. package/dist/chrome/build-beat.d.ts.map +1 -0
  29. package/dist/chrome/build-beat.js +101 -0
  30. package/dist/chrome/build-beat.js.map +1 -0
  31. package/dist/chrome/chrome-css.d.ts +7 -0
  32. package/dist/chrome/chrome-css.d.ts.map +1 -0
  33. package/dist/chrome/chrome-css.js +2042 -0
  34. package/dist/chrome/chrome-css.js.map +1 -0
  35. package/dist/chrome/chrome-root.d.ts +13 -0
  36. package/dist/chrome/chrome-root.d.ts.map +1 -0
  37. package/dist/chrome/chrome-root.js +39 -0
  38. package/dist/chrome/chrome-root.js.map +1 -0
  39. package/dist/chrome/clipboard.d.ts +4 -0
  40. package/dist/chrome/clipboard.d.ts.map +1 -0
  41. package/dist/chrome/clipboard.js +49 -0
  42. package/dist/chrome/clipboard.js.map +1 -0
  43. package/dist/chrome/connect-card.d.ts +19 -0
  44. package/dist/chrome/connect-card.d.ts.map +1 -0
  45. package/dist/chrome/connect-card.js +57 -0
  46. package/dist/chrome/connect-card.js.map +1 -0
  47. package/dist/chrome/connect-dock.d.ts +25 -0
  48. package/dist/chrome/connect-dock.d.ts.map +1 -0
  49. package/dist/chrome/connect-dock.js +192 -0
  50. package/dist/chrome/connect-dock.js.map +1 -0
  51. package/dist/chrome/connected-accounts-panel.d.ts +14 -0
  52. package/dist/chrome/connected-accounts-panel.d.ts.map +1 -0
  53. package/dist/chrome/connected-accounts-panel.js +157 -0
  54. package/dist/chrome/connected-accounts-panel.js.map +1 -0
  55. package/dist/chrome/dev-mode.d.ts +5 -0
  56. package/dist/chrome/dev-mode.d.ts.map +1 -0
  57. package/dist/chrome/dev-mode.js +7 -0
  58. package/dist/chrome/dev-mode.js.map +1 -0
  59. package/dist/chrome/discoverability.d.ts +33 -0
  60. package/dist/chrome/discoverability.d.ts.map +1 -0
  61. package/dist/chrome/discoverability.js +63 -0
  62. package/dist/chrome/discoverability.js.map +1 -0
  63. package/dist/chrome/embeds.d.ts +21 -0
  64. package/dist/chrome/embeds.d.ts.map +1 -0
  65. package/dist/chrome/embeds.js +181 -0
  66. package/dist/chrome/embeds.js.map +1 -0
  67. package/dist/chrome/fluid-thinking.d.ts +15 -0
  68. package/dist/chrome/fluid-thinking.d.ts.map +1 -0
  69. package/dist/chrome/fluid-thinking.js +37 -0
  70. package/dist/chrome/fluid-thinking.js.map +1 -0
  71. package/dist/chrome/humanize.d.ts +46 -0
  72. package/dist/chrome/humanize.d.ts.map +1 -0
  73. package/dist/chrome/humanize.js +104 -0
  74. package/dist/chrome/humanize.js.map +1 -0
  75. package/dist/chrome/index.d.ts +39 -0
  76. package/dist/chrome/index.d.ts.map +1 -0
  77. package/dist/chrome/index.js +38 -0
  78. package/dist/chrome/index.js.map +1 -0
  79. package/dist/chrome/markdown.d.ts +23 -0
  80. package/dist/chrome/markdown.d.ts.map +1 -0
  81. package/dist/chrome/markdown.js +149 -0
  82. package/dist/chrome/markdown.js.map +1 -0
  83. package/dist/chrome/morph-toast.d.ts +43 -0
  84. package/dist/chrome/morph-toast.d.ts.map +1 -0
  85. package/dist/chrome/morph-toast.js +89 -0
  86. package/dist/chrome/morph-toast.js.map +1 -0
  87. package/dist/chrome/no-policy-notice.d.ts +8 -0
  88. package/dist/chrome/no-policy-notice.d.ts.map +1 -0
  89. package/dist/chrome/no-policy-notice.js +18 -0
  90. package/dist/chrome/no-policy-notice.js.map +1 -0
  91. package/dist/chrome/onest-font.gen.d.ts +10 -0
  92. package/dist/chrome/onest-font.gen.d.ts.map +1 -0
  93. package/dist/chrome/onest-font.gen.js +10 -0
  94. package/dist/chrome/onest-font.gen.js.map +1 -0
  95. package/dist/chrome/overlay-registry.d.ts +66 -0
  96. package/dist/chrome/overlay-registry.d.ts.map +1 -0
  97. package/dist/chrome/overlay-registry.js +103 -0
  98. package/dist/chrome/overlay-registry.js.map +1 -0
  99. package/dist/chrome/palette-hotkey.d.ts +42 -0
  100. package/dist/chrome/palette-hotkey.d.ts.map +1 -0
  101. package/dist/chrome/palette-hotkey.js +91 -0
  102. package/dist/chrome/palette-hotkey.js.map +1 -0
  103. package/dist/chrome/policy-notice-body.d.ts +3 -0
  104. package/dist/chrome/policy-notice-body.d.ts.map +1 -0
  105. package/dist/chrome/policy-notice-body.js +6 -0
  106. package/dist/chrome/policy-notice-body.js.map +1 -0
  107. package/dist/chrome/takeover-portal.d.ts +16 -0
  108. package/dist/chrome/takeover-portal.d.ts.map +1 -0
  109. package/dist/chrome/takeover-portal.js +21 -0
  110. package/dist/chrome/takeover-portal.js.map +1 -0
  111. package/dist/chrome/thread/attachments.d.ts +24 -0
  112. package/dist/chrome/thread/attachments.d.ts.map +1 -0
  113. package/dist/chrome/thread/attachments.js +50 -0
  114. package/dist/chrome/thread/attachments.js.map +1 -0
  115. package/dist/chrome/thread/composer.d.ts +63 -0
  116. package/dist/chrome/thread/composer.d.ts.map +1 -0
  117. package/dist/chrome/thread/composer.js +259 -0
  118. package/dist/chrome/thread/composer.js.map +1 -0
  119. package/dist/chrome/thread/index.d.ts +41 -0
  120. package/dist/chrome/thread/index.d.ts.map +1 -0
  121. package/dist/chrome/thread/index.js +258 -0
  122. package/dist/chrome/thread/index.js.map +1 -0
  123. package/dist/chrome/thread/message-data.d.ts +35 -0
  124. package/dist/chrome/thread/message-data.d.ts.map +1 -0
  125. package/dist/chrome/thread/message-data.js +127 -0
  126. package/dist/chrome/thread/message-data.js.map +1 -0
  127. package/dist/chrome/thread/message-list.d.ts +30 -0
  128. package/dist/chrome/thread/message-list.d.ts.map +1 -0
  129. package/dist/chrome/thread/message-list.js +11 -0
  130. package/dist/chrome/thread/message-list.js.map +1 -0
  131. package/dist/chrome/thread/message.d.ts +18 -0
  132. package/dist/chrome/thread/message.d.ts.map +1 -0
  133. package/dist/chrome/thread/message.js +57 -0
  134. package/dist/chrome/thread/message.js.map +1 -0
  135. package/dist/chrome/thread/parts.d.ts +53 -0
  136. package/dist/chrome/thread/parts.d.ts.map +1 -0
  137. package/dist/chrome/thread/parts.js +184 -0
  138. package/dist/chrome/thread/parts.js.map +1 -0
  139. package/dist/chrome/thread/scrolling.d.ts +26 -0
  140. package/dist/chrome/thread/scrolling.d.ts.map +1 -0
  141. package/dist/chrome/thread/scrolling.js +214 -0
  142. package/dist/chrome/thread/scrolling.js.map +1 -0
  143. package/dist/chrome/truncate.d.ts +12 -0
  144. package/dist/chrome/truncate.d.ts.map +1 -0
  145. package/dist/chrome/truncate.js +18 -0
  146. package/dist/chrome/truncate.js.map +1 -0
  147. package/dist/chrome/vendo-activities.d.ts +24 -0
  148. package/dist/chrome/vendo-activities.d.ts.map +1 -0
  149. package/dist/chrome/vendo-activities.js +38 -0
  150. package/dist/chrome/vendo-activities.js.map +1 -0
  151. package/dist/chrome/vendo-overlay.d.ts +63 -0
  152. package/dist/chrome/vendo-overlay.d.ts.map +1 -0
  153. package/dist/chrome/vendo-overlay.js +256 -0
  154. package/dist/chrome/vendo-overlay.js.map +1 -0
  155. package/dist/chrome/vendo-page.d.ts +3 -0
  156. package/dist/chrome/vendo-page.d.ts.map +1 -0
  157. package/dist/chrome/vendo-page.js +162 -0
  158. package/dist/chrome/vendo-page.js.map +1 -0
  159. package/dist/chrome/vendo-palette.d.ts +29 -0
  160. package/dist/chrome/vendo-palette.d.ts.map +1 -0
  161. package/dist/chrome/vendo-palette.js +95 -0
  162. package/dist/chrome/vendo-palette.js.map +1 -0
  163. package/dist/chrome/vendo-slot.d.ts +79 -0
  164. package/dist/chrome/vendo-slot.d.ts.map +1 -0
  165. package/dist/chrome/vendo-slot.js +153 -0
  166. package/dist/chrome/vendo-slot.js.map +1 -0
  167. package/dist/chrome/vendo-toasts.d.ts +40 -0
  168. package/dist/chrome/vendo-toasts.d.ts.map +1 -0
  169. package/dist/chrome/vendo-toasts.js +135 -0
  170. package/dist/chrome/vendo-toasts.js.map +1 -0
  171. package/dist/chrome/vendo-trigger.d.ts +24 -0
  172. package/dist/chrome/vendo-trigger.d.ts.map +1 -0
  173. package/dist/chrome/vendo-trigger.js +30 -0
  174. package/dist/chrome/vendo-trigger.js.map +1 -0
  175. package/dist/chrome/waiting-queue.d.ts +8 -0
  176. package/dist/chrome/waiting-queue.d.ts.map +1 -0
  177. package/dist/chrome/waiting-queue.js +21 -0
  178. package/dist/chrome/waiting-queue.js.map +1 -0
  179. package/dist/client-impl.d.ts +4 -0
  180. package/dist/client-impl.d.ts.map +1 -0
  181. package/dist/client-impl.js +160 -0
  182. package/dist/client-impl.js.map +1 -0
  183. package/dist/client.d.ts +136 -0
  184. package/dist/client.d.ts.map +1 -0
  185. package/dist/client.js +2 -0
  186. package/dist/client.js.map +1 -0
  187. package/dist/context.d.ts +97 -0
  188. package/dist/context.d.ts.map +1 -0
  189. package/dist/context.js +71 -0
  190. package/dist/context.js.map +1 -0
  191. package/dist/eject-templates/activities/index.tsx +113 -0
  192. package/dist/eject-templates/templates.json +29 -0
  193. package/dist/eject-templates/thread/attachments.tsx +69 -0
  194. package/dist/eject-templates/thread/composer.tsx +409 -0
  195. package/dist/eject-templates/thread/index.tsx +422 -0
  196. package/dist/eject-templates/thread/message-data.ts +151 -0
  197. package/dist/eject-templates/thread/message-list.tsx +123 -0
  198. package/dist/eject-templates/thread/message.tsx +149 -0
  199. package/dist/eject-templates/thread/parts.tsx +293 -0
  200. package/dist/eject-templates/thread/scrolling.ts +223 -0
  201. package/dist/embeds.d.ts +28 -0
  202. package/dist/embeds.d.ts.map +1 -0
  203. package/dist/embeds.js +2 -0
  204. package/dist/embeds.js.map +1 -0
  205. package/dist/hooks/index.d.ts +18 -0
  206. package/dist/hooks/index.d.ts.map +1 -0
  207. package/dist/hooks/index.js +19 -0
  208. package/dist/hooks/index.js.map +1 -0
  209. package/dist/hooks/scripted-transport.d.ts +44 -0
  210. package/dist/hooks/scripted-transport.d.ts.map +1 -0
  211. package/dist/hooks/scripted-transport.js +58 -0
  212. package/dist/hooks/scripted-transport.js.map +1 -0
  213. package/dist/hooks/use-activity.d.ts +17 -0
  214. package/dist/hooks/use-activity.d.ts.map +1 -0
  215. package/dist/hooks/use-activity.js +50 -0
  216. package/dist/hooks/use-activity.js.map +1 -0
  217. package/dist/hooks/use-app.d.ts +19 -0
  218. package/dist/hooks/use-app.d.ts.map +1 -0
  219. package/dist/hooks/use-app.js +66 -0
  220. package/dist/hooks/use-app.js.map +1 -0
  221. package/dist/hooks/use-approvals.d.ts +13 -0
  222. package/dist/hooks/use-approvals.d.ts.map +1 -0
  223. package/dist/hooks/use-approvals.js +14 -0
  224. package/dist/hooks/use-approvals.js.map +1 -0
  225. package/dist/hooks/use-apps.d.ts +17 -0
  226. package/dist/hooks/use-apps.d.ts.map +1 -0
  227. package/dist/hooks/use-apps.js +30 -0
  228. package/dist/hooks/use-apps.js.map +1 -0
  229. package/dist/hooks/use-automations.d.ts +25 -0
  230. package/dist/hooks/use-automations.d.ts.map +1 -0
  231. package/dist/hooks/use-automations.js +30 -0
  232. package/dist/hooks/use-automations.js.map +1 -0
  233. package/dist/hooks/use-connections.d.ts +12 -0
  234. package/dist/hooks/use-connections.d.ts.map +1 -0
  235. package/dist/hooks/use-connections.js +15 -0
  236. package/dist/hooks/use-connections.js.map +1 -0
  237. package/dist/hooks/use-connector-catalog.d.ts +8 -0
  238. package/dist/hooks/use-connector-catalog.d.ts.map +1 -0
  239. package/dist/hooks/use-connector-catalog.js +52 -0
  240. package/dist/hooks/use-connector-catalog.js.map +1 -0
  241. package/dist/hooks/use-grants.d.ts +13 -0
  242. package/dist/hooks/use-grants.d.ts.map +1 -0
  243. package/dist/hooks/use-grants.js +14 -0
  244. package/dist/hooks/use-grants.js.map +1 -0
  245. package/dist/hooks/use-mobile-takeover.d.ts +22 -0
  246. package/dist/hooks/use-mobile-takeover.d.ts.map +1 -0
  247. package/dist/hooks/use-mobile-takeover.js +66 -0
  248. package/dist/hooks/use-mobile-takeover.js.map +1 -0
  249. package/dist/hooks/use-resource.d.ts +21 -0
  250. package/dist/hooks/use-resource.d.ts.map +1 -0
  251. package/dist/hooks/use-resource.js +79 -0
  252. package/dist/hooks/use-resource.js.map +1 -0
  253. package/dist/hooks/use-slot-app.d.ts +19 -0
  254. package/dist/hooks/use-slot-app.d.ts.map +1 -0
  255. package/dist/hooks/use-slot-app.js +18 -0
  256. package/dist/hooks/use-slot-app.js.map +1 -0
  257. package/dist/hooks/use-threads.d.ts +16 -0
  258. package/dist/hooks/use-threads.d.ts.map +1 -0
  259. package/dist/hooks/use-threads.js +15 -0
  260. package/dist/hooks/use-threads.js.map +1 -0
  261. package/dist/hooks/use-vendo-overlay.d.ts +31 -0
  262. package/dist/hooks/use-vendo-overlay.d.ts.map +1 -0
  263. package/dist/hooks/use-vendo-overlay.js +23 -0
  264. package/dist/hooks/use-vendo-overlay.js.map +1 -0
  265. package/dist/hooks/use-vendo-status.d.ts +6 -0
  266. package/dist/hooks/use-vendo-status.d.ts.map +1 -0
  267. package/dist/hooks/use-vendo-status.js +28 -0
  268. package/dist/hooks/use-vendo-status.js.map +1 -0
  269. package/dist/hooks/use-vendo-thread.d.ts +39 -0
  270. package/dist/hooks/use-vendo-thread.d.ts.map +1 -0
  271. package/dist/hooks/use-vendo-thread.js +185 -0
  272. package/dist/hooks/use-vendo-thread.js.map +1 -0
  273. package/dist/index.d.ts +12 -0
  274. package/dist/index.d.ts.map +1 -0
  275. package/dist/index.js +12 -0
  276. package/dist/index.js.map +1 -0
  277. package/dist/kit/charts/bar.d.ts +16 -0
  278. package/dist/kit/charts/bar.d.ts.map +1 -0
  279. package/dist/kit/charts/bar.js +21 -0
  280. package/dist/kit/charts/bar.js.map +1 -0
  281. package/dist/kit/charts/donut.d.ts +16 -0
  282. package/dist/kit/charts/donut.d.ts.map +1 -0
  283. package/dist/kit/charts/donut.js +17 -0
  284. package/dist/kit/charts/donut.js.map +1 -0
  285. package/dist/kit/charts/line.d.ts +19 -0
  286. package/dist/kit/charts/line.d.ts.map +1 -0
  287. package/dist/kit/charts/line.js +21 -0
  288. package/dist/kit/charts/line.js.map +1 -0
  289. package/dist/kit/charts/progress.d.ts +12 -0
  290. package/dist/kit/charts/progress.d.ts.map +1 -0
  291. package/dist/kit/charts/progress.js +25 -0
  292. package/dist/kit/charts/progress.js.map +1 -0
  293. package/dist/kit/charts/sanitize.d.ts +24 -0
  294. package/dist/kit/charts/sanitize.d.ts.map +1 -0
  295. package/dist/kit/charts/sanitize.js +50 -0
  296. package/dist/kit/charts/sanitize.js.map +1 -0
  297. package/dist/kit/charts/sparkline.d.ts +11 -0
  298. package/dist/kit/charts/sparkline.d.ts.map +1 -0
  299. package/dist/kit/charts/sparkline.js +17 -0
  300. package/dist/kit/charts/sparkline.js.map +1 -0
  301. package/dist/kit/data/badge.d.ts +13 -0
  302. package/dist/kit/data/badge.d.ts.map +1 -0
  303. package/dist/kit/data/badge.js +12 -0
  304. package/dist/kit/data/badge.js.map +1 -0
  305. package/dist/kit/data/card-list.d.ts +23 -0
  306. package/dist/kit/data/card-list.d.ts.map +1 -0
  307. package/dist/kit/data/card-list.js +43 -0
  308. package/dist/kit/data/card-list.js.map +1 -0
  309. package/dist/kit/data/data-table.d.ts +32 -0
  310. package/dist/kit/data/data-table.d.ts.map +1 -0
  311. package/dist/kit/data/data-table.js +153 -0
  312. package/dist/kit/data/data-table.js.map +1 -0
  313. package/dist/kit/data/stat.d.ts +15 -0
  314. package/dist/kit/data/stat.d.ts.map +1 -0
  315. package/dist/kit/data/stat.js +28 -0
  316. package/dist/kit/data/stat.js.map +1 -0
  317. package/dist/kit/feedback/accordion.d.ts +15 -0
  318. package/dist/kit/feedback/accordion.d.ts.map +1 -0
  319. package/dist/kit/feedback/accordion.js +33 -0
  320. package/dist/kit/feedback/accordion.js.map +1 -0
  321. package/dist/kit/feedback/callout.d.ts +13 -0
  322. package/dist/kit/feedback/callout.d.ts.map +1 -0
  323. package/dist/kit/feedback/callout.js +24 -0
  324. package/dist/kit/feedback/callout.js.map +1 -0
  325. package/dist/kit/feedback/tabs.d.ts +14 -0
  326. package/dist/kit/feedback/tabs.d.ts.map +1 -0
  327. package/dist/kit/feedback/tabs.js +37 -0
  328. package/dist/kit/feedback/tabs.js.map +1 -0
  329. package/dist/kit/format.d.ts +60 -0
  330. package/dist/kit/format.d.ts.map +1 -0
  331. package/dist/kit/format.js +123 -0
  332. package/dist/kit/format.js.map +1 -0
  333. package/dist/kit/forms/button.d.ts +17 -0
  334. package/dist/kit/forms/button.d.ts.map +1 -0
  335. package/dist/kit/forms/button.js +33 -0
  336. package/dist/kit/forms/button.js.map +1 -0
  337. package/dist/kit/forms/checkbox.d.ts +9 -0
  338. package/dist/kit/forms/checkbox.d.ts.map +1 -0
  339. package/dist/kit/forms/checkbox.js +9 -0
  340. package/dist/kit/forms/checkbox.js.map +1 -0
  341. package/dist/kit/forms/date-picker.d.ts +13 -0
  342. package/dist/kit/forms/date-picker.d.ts.map +1 -0
  343. package/dist/kit/forms/date-picker.js +9 -0
  344. package/dist/kit/forms/date-picker.js.map +1 -0
  345. package/dist/kit/forms/disclaimer.d.ts +8 -0
  346. package/dist/kit/forms/disclaimer.d.ts.map +1 -0
  347. package/dist/kit/forms/disclaimer.js +20 -0
  348. package/dist/kit/forms/disclaimer.js.map +1 -0
  349. package/dist/kit/forms/field.d.ts +18 -0
  350. package/dist/kit/forms/field.d.ts.map +1 -0
  351. package/dist/kit/forms/field.js +19 -0
  352. package/dist/kit/forms/field.js.map +1 -0
  353. package/dist/kit/forms/form.d.ts +10 -0
  354. package/dist/kit/forms/form.d.ts.map +1 -0
  355. package/dist/kit/forms/form.js +9 -0
  356. package/dist/kit/forms/form.js.map +1 -0
  357. package/dist/kit/forms/input.d.ts +14 -0
  358. package/dist/kit/forms/input.d.ts.map +1 -0
  359. package/dist/kit/forms/input.js +9 -0
  360. package/dist/kit/forms/input.js.map +1 -0
  361. package/dist/kit/forms/select.d.ts +21 -0
  362. package/dist/kit/forms/select.d.ts.map +1 -0
  363. package/dist/kit/forms/select.js +35 -0
  364. package/dist/kit/forms/select.js.map +1 -0
  365. package/dist/kit/forms/textarea.d.ts +12 -0
  366. package/dist/kit/forms/textarea.d.ts.map +1 -0
  367. package/dist/kit/forms/textarea.js +9 -0
  368. package/dist/kit/forms/textarea.js.map +1 -0
  369. package/dist/kit/index.d.ts +42 -0
  370. package/dist/kit/index.d.ts.map +1 -0
  371. package/dist/kit/index.js +45 -0
  372. package/dist/kit/index.js.map +1 -0
  373. package/dist/kit/kit-prompt.d.ts +7 -0
  374. package/dist/kit/kit-prompt.d.ts.map +1 -0
  375. package/dist/kit/kit-prompt.js +7 -0
  376. package/dist/kit/kit-prompt.js.map +1 -0
  377. package/dist/kit/layout.d.ts +29 -0
  378. package/dist/kit/layout.d.ts.map +1 -0
  379. package/dist/kit/layout.js +64 -0
  380. package/dist/kit/layout.js.map +1 -0
  381. package/dist/kit/registry.d.ts +11 -0
  382. package/dist/kit/registry.d.ts.map +1 -0
  383. package/dist/kit/registry.js +34 -0
  384. package/dist/kit/registry.js.map +1 -0
  385. package/dist/kit/schema.d.ts +9 -0
  386. package/dist/kit/schema.d.ts.map +1 -0
  387. package/dist/kit/schema.js +9 -0
  388. package/dist/kit/schema.js.map +1 -0
  389. package/dist/kit/tokens.d.ts +33 -0
  390. package/dist/kit/tokens.d.ts.map +1 -0
  391. package/dist/kit/tokens.js +48 -0
  392. package/dist/kit/tokens.js.map +1 -0
  393. package/dist/kit/values.d.ts +55 -0
  394. package/dist/kit/values.d.ts.map +1 -0
  395. package/dist/kit/values.js +108 -0
  396. package/dist/kit/values.js.map +1 -0
  397. package/dist/theme.d.ts +25 -0
  398. package/dist/theme.d.ts.map +1 -0
  399. package/dist/theme.js +100 -0
  400. package/dist/theme.js.map +1 -0
  401. package/dist/tree/bindings.d.ts +4 -0
  402. package/dist/tree/bindings.d.ts.map +1 -0
  403. package/dist/tree/bindings.js +20 -0
  404. package/dist/tree/bindings.js.map +1 -0
  405. package/dist/tree/branded.d.ts +124 -0
  406. package/dist/tree/branded.d.ts.map +1 -0
  407. package/dist/tree/branded.js +319 -0
  408. package/dist/tree/branded.js.map +1 -0
  409. package/dist/tree/error-boundary.d.ts +22 -0
  410. package/dist/tree/error-boundary.d.ts.map +1 -0
  411. package/dist/tree/error-boundary.js +25 -0
  412. package/dist/tree/error-boundary.js.map +1 -0
  413. package/dist/tree/fluid-reveal.d.ts +22 -0
  414. package/dist/tree/fluid-reveal.d.ts.map +1 -0
  415. package/dist/tree/fluid-reveal.js +28 -0
  416. package/dist/tree/fluid-reveal.js.map +1 -0
  417. package/dist/tree/forming-skeleton.d.ts +14 -0
  418. package/dist/tree/forming-skeleton.d.ts.map +1 -0
  419. package/dist/tree/forming-skeleton.js +36 -0
  420. package/dist/tree/forming-skeleton.js.map +1 -0
  421. package/dist/tree/frames.d.ts +52 -0
  422. package/dist/tree/frames.d.ts.map +1 -0
  423. package/dist/tree/frames.js +143 -0
  424. package/dist/tree/frames.js.map +1 -0
  425. package/dist/tree/host-mount.d.ts +24 -0
  426. package/dist/tree/host-mount.d.ts.map +1 -0
  427. package/dist/tree/host-mount.js +0 -0
  428. package/dist/tree/host-mount.js.map +1 -0
  429. package/dist/tree/index.d.ts +9 -0
  430. package/dist/tree/index.d.ts.map +1 -0
  431. package/dist/tree/index.js +9 -0
  432. package/dist/tree/index.js.map +1 -0
  433. package/dist/tree/jail/JailedComponent.d.ts +41 -0
  434. package/dist/tree/jail/JailedComponent.d.ts.map +1 -0
  435. package/dist/tree/jail/JailedComponent.js +269 -0
  436. package/dist/tree/jail/JailedComponent.js.map +1 -0
  437. package/dist/tree/jail/runtime-bundle.gen.d.ts +3 -0
  438. package/dist/tree/jail/runtime-bundle.gen.d.ts.map +1 -0
  439. package/dist/tree/jail/runtime-bundle.gen.js +3 -0
  440. package/dist/tree/jail/runtime-bundle.gen.js.map +1 -0
  441. package/dist/tree/jail/runtime-entry.d.ts +18 -0
  442. package/dist/tree/jail/runtime-entry.d.ts.map +1 -0
  443. package/dist/tree/jail/runtime-entry.js +440 -0
  444. package/dist/tree/jail/runtime-entry.js.map +1 -0
  445. package/dist/tree/jail/viewport-css.d.ts +17 -0
  446. package/dist/tree/jail/viewport-css.d.ts.map +1 -0
  447. package/dist/tree/jail/viewport-css.js +32 -0
  448. package/dist/tree/jail/viewport-css.js.map +1 -0
  449. package/dist/tree/mcp-shim/entry.d.ts +2 -0
  450. package/dist/tree/mcp-shim/entry.d.ts.map +1 -0
  451. package/dist/tree/mcp-shim/entry.js +45 -0
  452. package/dist/tree/mcp-shim/entry.js.map +1 -0
  453. package/dist/tree/mcp-shim/http-open-card.d.ts +5 -0
  454. package/dist/tree/mcp-shim/http-open-card.d.ts.map +1 -0
  455. package/dist/tree/mcp-shim/http-open-card.js +61 -0
  456. package/dist/tree/mcp-shim/http-open-card.js.map +1 -0
  457. package/dist/tree/mcp-shim/shim-core.d.ts +58 -0
  458. package/dist/tree/mcp-shim/shim-core.d.ts.map +1 -0
  459. package/dist/tree/mcp-shim/shim-core.js +176 -0
  460. package/dist/tree/mcp-shim/shim-core.js.map +1 -0
  461. package/dist/tree/mcp-shim/theme.d.ts +8 -0
  462. package/dist/tree/mcp-shim/theme.d.ts.map +1 -0
  463. package/dist/tree/mcp-shim/theme.js +36 -0
  464. package/dist/tree/mcp-shim/theme.js.map +1 -0
  465. package/dist/tree/notice.d.ts +8 -0
  466. package/dist/tree/notice.d.ts.map +1 -0
  467. package/dist/tree/notice.js +30 -0
  468. package/dist/tree/notice.js.map +1 -0
  469. package/dist/tree/primitives.d.ts +30 -0
  470. package/dist/tree/primitives.d.ts.map +1 -0
  471. package/dist/tree/primitives.js +105 -0
  472. package/dist/tree/primitives.js.map +1 -0
  473. package/dist/tree/renderer-v2.d.ts +15 -0
  474. package/dist/tree/renderer-v2.d.ts.map +1 -0
  475. package/dist/tree/renderer-v2.js +71 -0
  476. package/dist/tree/renderer-v2.js.map +1 -0
  477. package/dist/tree/renderer.d.ts +77 -0
  478. package/dist/tree/renderer.d.ts.map +1 -0
  479. package/dist/tree/renderer.js +376 -0
  480. package/dist/tree/renderer.js.map +1 -0
  481. package/dist/voice/driver.d.ts +94 -0
  482. package/dist/voice/driver.d.ts.map +1 -0
  483. package/dist/voice/driver.js +2 -0
  484. package/dist/voice/driver.js.map +1 -0
  485. package/dist/voice/index.d.ts +7 -0
  486. package/dist/voice/index.d.ts.map +1 -0
  487. package/dist/voice/index.js +5 -0
  488. package/dist/voice/index.js.map +1 -0
  489. package/dist/voice/realtime-driver.d.ts +57 -0
  490. package/dist/voice/realtime-driver.d.ts.map +1 -0
  491. package/dist/voice/realtime-driver.js +592 -0
  492. package/dist/voice/realtime-driver.js.map +1 -0
  493. package/dist/voice/stage.d.ts +12 -0
  494. package/dist/voice/stage.d.ts.map +1 -0
  495. package/dist/voice/stage.js +259 -0
  496. package/dist/voice/stage.js.map +1 -0
  497. package/dist/voice/use-voice-approvals.d.ts +16 -0
  498. package/dist/voice/use-voice-approvals.d.ts.map +1 -0
  499. package/dist/voice/use-voice-approvals.js +77 -0
  500. package/dist/voice/use-voice-approvals.js.map +1 -0
  501. package/dist/voice/use-voice.d.ts +26 -0
  502. package/dist/voice/use-voice.d.ts.map +1 -0
  503. package/dist/voice/use-voice.js +201 -0
  504. package/dist/voice/use-voice.js.map +1 -0
  505. package/dist/voice/voice-act.d.ts +13 -0
  506. package/dist/voice/voice-act.d.ts.map +1 -0
  507. package/dist/voice/voice-act.js +301 -0
  508. package/dist/voice/voice-act.js.map +1 -0
  509. package/dist/voice/voice-blob.d.ts +17 -0
  510. package/dist/voice/voice-blob.d.ts.map +1 -0
  511. package/dist/voice/voice-blob.js +67 -0
  512. package/dist/voice/voice-blob.js.map +1 -0
  513. package/dist/voice/voice-consent.d.ts +17 -0
  514. package/dist/voice/voice-consent.d.ts.map +1 -0
  515. package/dist/voice/voice-consent.js +45 -0
  516. package/dist/voice/voice-consent.js.map +1 -0
  517. package/dist/voice/voice-drawer.d.ts +10 -0
  518. package/dist/voice/voice-drawer.d.ts.map +1 -0
  519. package/dist/voice/voice-drawer.js +22 -0
  520. package/dist/voice/voice-drawer.js.map +1 -0
  521. package/dist/wire-types.d.ts +238 -0
  522. package/dist/wire-types.d.ts.map +1 -0
  523. package/dist/wire-types.js +2 -0
  524. package/dist/wire-types.js.map +1 -0
  525. package/package.json +106 -0
@@ -0,0 +1,2042 @@
1
+ import { ONEST_FONT_CSS } from "./onest-font.gen.js";
2
+ /** The ported Vendo shell stylesheet (design system). Generated from the
3
+ * wave-2 shell; tokens bridged to the VendoTheme contract. Onest (the brand
4
+ * font, defaultVendoTheme's first family) rides along as inlined @font-face
5
+ * data so the unthemed default look renders it with zero host setup — hosts
6
+ * that set their own fontFamily simply never reference it. */
7
+ export const CHROME_CSS = ONEST_FONT_CSS + `/* @vendoai/ui chrome — the wave-2 Vendo shell design, ported onto the frozen
8
+ VendoTheme contract. Every aesthetic token below is DERIVED from the contract
9
+ brand tokens (--vendo-color-*, --vendo-radius-*, --vendo-font-*) that
10
+ themeCssVariables() emits, so the host's brand still drives everything while
11
+ the frosted-glass design system rides on top. */
12
+ .vendo-root {
13
+ /* ENG-226: scheme derived from the luminance of the theme's colors.background
14
+ (themeCssVariables emits --vendo-color-scheme) — a dark-brand host flips
15
+ every light-dark() branch below to its designed dark value. */
16
+ color-scheme: var(--vendo-color-scheme, light);
17
+ /* brand → shell token bridge */
18
+ --vendo-fg: var(--vendo-color-text, #14151a);
19
+ /* Muted is pulled ~40% toward the text color so small muted labels
20
+ (.fl-picker-group, .fl-voice-status, captions) clear WCAG AA 4.5:1 on the
21
+ glass surfaces — in BOTH schemes, since text always contrasts the bg. */
22
+ --vendo-fg-muted: color-mix(in srgb, var(--vendo-color-muted, #8a8b92) 45%, var(--vendo-color-text, #14151a));
23
+ --vendo-bg: var(--vendo-color-background, #f3ede2);
24
+ --vendo-surface: var(--vendo-color-surface, #fffdf9);
25
+ --vendo-accent: var(--vendo-color-accent, #1b1c22);
26
+ --vendo-accent-fg: var(--vendo-color-accent-text, #ffffff);
27
+ --vendo-border: var(--vendo-color-border, rgba(20,21,26,.09));
28
+ --vendo-radius: var(--vendo-radius-medium, 12px);
29
+ /* radius.small / radius.large were emitted by the theme but never read — only
30
+ medium drove the whole sheet. Bridge them so small chrome (chips, badges,
31
+ inline code, icon buttons) picks up radius.small and large surfaces
32
+ (panels, sheets, pickers, connect card) pick up radius.large. */
33
+ --vendo-radius-sm: var(--vendo-radius-small, 7px);
34
+ --vendo-radius-lg: var(--vendo-radius-large, 16px);
35
+ --vendo-font: var(--vendo-font-family, inherit);
36
+ /* headingFamily was contract-listed but unread by the chrome; falls back to
37
+ the body font when the host doesn't set a distinct heading face. */
38
+ --vendo-heading-font: var(--vendo-heading-family, var(--vendo-font));
39
+ /* Type scale anchored on the theme baseSize (08 §2) so a host's baseSize
40
+ scales the primary reading text (turns, composer, hero), not only the root
41
+ font-size. The .933 ratio preserves the historical 14px-on-15px-base size. */
42
+ --vendo-base-size: var(--vendo-font-size, 15px);
43
+ --vendo-text-body: calc(var(--vendo-base-size) * 0.933);
44
+ /* System mono stack (no unshipped brand font): the chrome has no contract
45
+ mono token, so this is the single themeable source referenced everywhere. */
46
+ --vendo-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
47
+ /* derived aesthetics */
48
+ --vendo-accent-soft: color-mix(in srgb, var(--vendo-accent) 8%, transparent);
49
+ --vendo-border-strong: color-mix(in srgb, var(--vendo-fg) 16%, transparent);
50
+ --vendo-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-fg) 5%, transparent),
51
+ 0 6px 18px color-mix(in srgb, var(--vendo-fg) 6%, transparent);
52
+ --vendo-glass: color-mix(in srgb, var(--vendo-surface) 58%, transparent);
53
+ --vendo-glass-strong: color-mix(in srgb, var(--vendo-surface) 82%, transparent);
54
+ --vendo-blur: saturate(1.4) blur(40px);
55
+ --vendo-ok: #2e9e6b;
56
+ --vendo-danger: var(--vendo-color-danger, #b0392b);
57
+ --vendo-danger-bg: color-mix(in srgb, var(--vendo-danger) 8%, var(--vendo-surface));
58
+ --vendo-danger-border: color-mix(in srgb, var(--vendo-danger) 32%, var(--vendo-border));
59
+ /* Warn / ceremony amber family — single source. The amber was scattered as
60
+ raw literals across ceremony buttons, voice consent and the a11y hardening
61
+ block; collapsed here so it is themeable from one place. Every dark-side
62
+ value and the AA-safe on-fill text (ENG-226) are preserved exactly. */
63
+ --vendo-warn: light-dark(#7a5000, #d9a94e);
64
+ --vendo-warn-text: light-dark(#8a6a2e, #d9a94e);
65
+ --vendo-warn-edge: #b3822f;
66
+ --vendo-warn-fill-critical: light-dark(#a97e2f, #b3822f);
67
+ --vendo-warn-on-fill: light-dark(#fff, #14151a);
68
+ --vendo-warn-tint: #f0b429;
69
+ --vendo-warn-bg: color-mix(in srgb, var(--vendo-warn-tint) 12%, var(--vendo-surface));
70
+ --vendo-warn-border: color-mix(in srgb, var(--vendo-warn-tint) 32%, var(--vendo-border));
71
+ /* Neutral user bubble (ENG-227): raw accent painting the whole user turn read
72
+ as iMessage-blue on a mostly-white host. A subtle fg-tinted surface reads
73
+ as "mine" in both schemes (fg + surface both flip with the scheme) and
74
+ reserves accent for the send button, focus rings and true accents. */
75
+ --vendo-user-bubble: color-mix(in srgb, var(--vendo-fg) 7%, var(--vendo-surface));
76
+ --vendo-user-bubble-fg: var(--vendo-fg);
77
+ color: var(--vendo-fg);
78
+ background: var(--vendo-bg);
79
+ font-family: var(--vendo-font);
80
+ font-size: var(--vendo-font-size, 15px);
81
+ letter-spacing: -.011em;
82
+ line-height: 1.5;
83
+ }
84
+ .vendo-root *, .vendo-root *::before, .vendo-root *::after { box-sizing: border-box; }
85
+ .vendo-root[data-vendo-motion="reduced"] * { animation: none !important; transition: none !important; }
86
+ /* The root joins the host's height chain (ENG-212). When it directly hosts a
87
+ height-filling surface (thread or page — each declares height:100%;
88
+ min-height:0), the root must forward the host's bounded height instead of
89
+ sitting as an unconstrained block between the host's pane and the surface —
90
+ otherwise .fl-msglist never gets a bounded height, nothing scrolls, and
91
+ under an overflow:hidden host the composer and approval actions clip below
92
+ the fold. Flex (not a bare height) so the automatic policy notice, when
93
+ present above the surface, shares the space instead of pushing the surface
94
+ past it. In an unbounded host the percentage resolves against an auto-height
95
+ parent and everything sizes to content exactly as before. Overlay, slot and
96
+ palette roots mount fixed/inline children and are deliberately NOT matched;
97
+ the voice stage is left to the voice-v1 stage-layout work (it commonly
98
+ mounts as a sibling of a thread — see Maple /vendo — where claiming 100%
99
+ would carve the pane in half). */
100
+ .vendo-root:has(> .fl-thread), .vendo-root:has(> .fl-page) {
101
+ display: flex; flex-direction: column; height: 100%; min-height: 0; }
102
+
103
+ /* ---------- thread shell ---------- */
104
+ /* min-width floor (ENG-228): squeezed host columns (Cadence at 375px) were
105
+ collapsing the thread to one character per line — hold a readable floor and
106
+ let the host column scroll instead. Capped at 100vw so viewports narrower
107
+ than the floor never get horizontal overflow from us. */
108
+ .fl-thread { display: flex; flex-direction: column; height: 100%; min-height: 0;
109
+ min-width: min(280px, 100vw); }
110
+ /* Positioned wrapper so the "jump to latest" button stays fixed to the viewport
111
+ of the list instead of scrolling away with the content. */
112
+ .fl-msglist-wrap { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column;
113
+ animation: fl-fade-in .18s ease; }
114
+ .fl-msglist { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain;
115
+ display: flex; flex-direction: column; gap: 14px; padding: 18px 16px 10px; scrollbar-width: none;
116
+ /* Faint top fade hints at scrollable history above (the scrollbar is hidden). */
117
+ -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 14px);
118
+ mask-image: linear-gradient(180deg, transparent 0, #000 14px); }
119
+ /* A single short turn rests just above the composer (auto collapses to 0 once the
120
+ thread overflows, so long threads scroll normally) — no dead gap at the bottom. */
121
+ .fl-msglist > :first-child { margin-top: auto; }
122
+ /* The list scrolls; its children must never compress. Without this, any child
123
+ with overflow:hidden (activity panels, rendered view cards) has a zero flex
124
+ minimum and gets crushed to its borders the moment the thread overflows. */
125
+ .fl-msglist > * { flex-shrink: 0; }
126
+ .fl-msglist::-webkit-scrollbar { display: none; }
127
+ /* Every thread item enters fluidly (fade + rise + un-blur) instead of popping —
128
+ tool panels, approvals, connect cards, turns alike. Render-view slots are
129
+ excluded: FluidReveal already morphs those. */
130
+ @media (prefers-reduced-motion: no-preference) {
131
+ /* ENG-218 — entrance-animation gating on restore: turns present when a long
132
+ thread is reopened carry .fl-no-entrance (set in chrome/thread), so only
133
+ turns that ARRIVE after restore (streamed replies, sends) run the rise.
134
+ A reopened 200-turn thread no longer fires 200 animations on first paint. */
135
+ .fl-msglist > :not(.fl-reveal):not(.fl-no-entrance) { animation: fl-item-in .32s cubic-bezier(.22, 1, .36, 1) both; }
136
+ }
137
+ /* Opacity+transform only — blur would force per-element rasterization, and a
138
+ reopened 200-item thread runs every entrance at once on first paint. */
139
+ @keyframes fl-item-in {
140
+ from { opacity: 0; transform: translateY(10px); }
141
+ to { opacity: 1; transform: none; } }
142
+ @keyframes fl-fade-in { from { opacity: 0; } to { opacity: 1; } }
143
+ /* ENG-218 — "show N earlier messages": reveals the deferred head of a windowed
144
+ long thread. Sits at the top of the list, centered, quiet until hovered. */
145
+ .fl-load-older { align-self: center; margin: 2px auto 4px; padding: 5px 12px; cursor: pointer;
146
+ font: inherit; font-size: .82em; color: var(--vendo-fg-muted); background: var(--vendo-glass);
147
+ border: 1px solid var(--vendo-border); border-radius: 999px; transition: color .12s, border-color .12s; }
148
+ .fl-load-older:hover { color: var(--vendo-fg); border-color: var(--vendo-border-strong); }
149
+ /* ENG-218 — expand/collapse control for a huge single message (assistant or
150
+ user). Reads as a quiet inline text button under the truncated body. */
151
+ .fl-more { display: inline-block; margin-top: 6px; padding: 0; cursor: pointer; font: inherit;
152
+ font-size: .88em; font-weight: 550; color: var(--vendo-accent); background: none; border: 0;
153
+ text-decoration: underline; text-underline-offset: 2px; }
154
+ .fl-turn-user .fl-more { color: inherit; opacity: .8; }
155
+ /* Visually-hidden live region — announces only the settled assistant turn. */
156
+ .fl-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
157
+ clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
158
+ /* Jump to latest — appears only when scrolled up from the bottom. */
159
+ .fl-jump { position: absolute; right: 14px; bottom: 12px; width: 34px; height: 34px; border-radius: 50%;
160
+ display: grid; place-items: center; cursor: pointer; color: var(--vendo-fg);
161
+ border: 1px solid var(--vendo-border-strong); background: var(--vendo-glass-strong);
162
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
163
+ box-shadow: var(--vendo-shadow); animation: fl-fade-in .15s ease; transition: border-color .12s; }
164
+ .fl-jump:hover { border-color: var(--vendo-accent); }
165
+ .fl-jump:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
166
+ /* Connect dock (ENG-205): the in-bar connect-tools entry. The .fl-dock
167
+ wrapper hosts the ripple; the anchor positions the liquid tray over the bar. */
168
+ .fl-dock { position: relative; display: inline-flex; }
169
+ /* The ripple wrapper is the clip box (button rounding); the badge overhangs
170
+ it, so it lives on the outer .fl-dock instead. */
171
+ .fl-dock-ripple { display: inline-flex; border-radius: 10px; }
172
+ .fl-dock-btn { position: relative; gap: 3px; }
173
+ .fl-dock-badge { position: absolute; top: -3px; right: -3px; min-width: 15px; height: 15px;
174
+ border-radius: 999px; background: var(--vendo-ok); color: #fff; font-size: 10px;
175
+ font-weight: 700; line-height: 15px; text-align: center; padding: 0 3px;
176
+ z-index: 1; pointer-events: none;
177
+ box-shadow: 0 0 0 2px var(--vendo-surface); }
178
+ /* Flex column so the composer's top margin never collapses out of the anchor:
179
+ the anchor's top is then always exactly 10px above the bar's border edge,
180
+ on every surface (page, overlay, slot), and the tray can dock flush. */
181
+ .fl-dock-anchor { position: relative; display: flex; flex-direction: column; }
182
+ /* Bottom-justified so the panel grows out of the bar edge while the entrance
183
+ spring clamps its height. --fl-tray-max is set at open time to the room
184
+ actually above the bar within this surface (page, overlay, or slot panel),
185
+ so the tray never runs off the top — the picker scrolls internally instead.
186
+ Docked flush onto the composer (one interface): the tray's bottom edge sits
187
+ on the bar's top border, top corners match the bar's 14px, bottom corners
188
+ square into the seam. */
189
+ .fl-tray { position: absolute; bottom: calc(100% - 10px); left: 16px; right: 16px;
190
+ z-index: 30; transform-origin: bottom center; overflow: hidden; border-radius: 14px 14px 0 0;
191
+ display: flex; flex-direction: column; justify-content: flex-end; }
192
+ /* While the tray is up (incl. its exit animation) the bar squares its top
193
+ corners so the two read as one card; the bar's top border is the seam. */
194
+ .fl-dock-anchor:has(.fl-tray) .fl-composer { border-top-left-radius: 0; border-top-right-radius: 0; }
195
+ /* Opaque elevated sheet: the tray floats over display text (the hero greet,
196
+ thread turns), and even a few percent of translucency reads big dark glyphs
197
+ straight through. Depth comes from the border + shadow, not glass. */
198
+ .fl-tray .fl-picker { max-height: min(420px, 48vh, var(--fl-tray-max, 9999px));
199
+ background: var(--vendo-surface);
200
+ border-radius: 14px 14px 0 0; border-bottom: 0;
201
+ /* Fill the tray exactly: the standalone picker's 560px cap + flex-start
202
+ would leave a dead strip beside the bar whenever the bar is wider. */
203
+ max-width: none; align-self: stretch;
204
+ -webkit-backdrop-filter: none; backdrop-filter: none; }
205
+ /* No bottom scrim: the row clipped at the seam is the scroll cue. */
206
+
207
+ /* Host-component thread items (Connect card): same geometry as the render slot
208
+ but no morph machinery — the shared item entrance is their only motion. */
209
+ .fl-uihost { align-self: stretch; width: 100%; }
210
+ /* A turn carrying a generated view must fill the column, not shrink-to-fit:
211
+ the assistant bubble is normally align-self:flex-start (sized to its text),
212
+ which makes a child view's width:100% resolve circularly to content width —
213
+ collapsing streaming skeletons to a sliver. Stretch the turn so the view
214
+ (and its forming skeletons) occupy the full width from the first frame. */
215
+ .fl-turn-assistant:has(.fl-uihost) { align-self: stretch; max-width: 100%; width: 100%; }
216
+
217
+ /* App boundary: the generated view sits inside a titled frame so it reads as a
218
+ discrete piece of software, cleanly separated from the surrounding chat. */
219
+ .fl-appcard { border: 1px solid var(--vendo-border); border-radius: 14px; overflow: hidden;
220
+ background: var(--vendo-surface); box-shadow: var(--vendo-shadow); }
221
+ .fl-appcard-bar { display: flex; align-items: center; gap: 8px; padding: 9px 13px;
222
+ border-bottom: 1px solid var(--vendo-border);
223
+ background: color-mix(in srgb, var(--vendo-surface) 92%, var(--vendo-fg) 8%); }
224
+ .fl-appcard-dot { width: 8px; height: 8px; border-radius: 999px; flex: none;
225
+ background: var(--vendo-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-accent) 16%, transparent); }
226
+ .fl-appcard-name { font: 600 12.5px/1 var(--vendo-font); color: var(--vendo-fg);
227
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
228
+ .fl-appcard-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
229
+ .fl-appcard-foot { display: flex; align-items: center; justify-content: flex-end; padding: 12px 16px;
230
+ border-top: 1px solid var(--vendo-border);
231
+ background: color-mix(in srgb, var(--vendo-surface) 94%, var(--vendo-fg) 6%); }
232
+ .fl-appcard-pin { display: inline-flex; align-items: center; gap: 6px; }
233
+
234
+ /* Approval→notification morph: a solid-glass card (same material as the
235
+ overlay) that travels to the top-right on a GPU transform.
236
+ The layer must stay transparent — it carries .vendo-root (which paints a
237
+ surface bg) and is full-viewport, so a background here whites out the page. */
238
+ .fl-morph-layer { position: fixed; inset: 0; z-index: 2147483003; pointer-events: none; background: none; }
239
+ .fl-morph-card { display: flex; align-items: center; gap: 11px; box-sizing: border-box;
240
+ padding: 11px 15px; overflow: hidden; transform-origin: top left; will-change: transform, width, height, opacity;
241
+ border: 1px solid var(--vendo-border-strong); border-radius: 15px;
242
+ background: var(--vendo-glass-strong);
243
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
244
+ box-shadow: 0 20px 48px color-mix(in srgb, var(--vendo-fg) 22%, transparent),
245
+ inset 0 1px 0 color-mix(in srgb, #fff 55%, transparent); }
246
+ .fl-morph-live { position: relative; width: 9px; height: 9px; flex: 0 0 9px; border-radius: 999px;
247
+ background: var(--vendo-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--vendo-accent) 15%, transparent); }
248
+ .fl-morph-copy { min-width: 0; flex: 1; }
249
+ .fl-morph-title { overflow: hidden; color: var(--vendo-fg); font: 720 13px/1.2 var(--vendo-font);
250
+ text-overflow: ellipsis; white-space: nowrap; }
251
+ .fl-morph-sub { overflow: hidden; margin-top: 3px; color: var(--vendo-fg-muted); font: 400 12px/1.2 var(--vendo-font);
252
+ text-overflow: ellipsis; white-space: nowrap; }
253
+ .fl-morph-logo { display: inline-grid; width: 32px; height: 32px; flex: none; place-items: center;
254
+ border: 1px solid var(--vendo-border); border-radius: 10px; background: var(--vendo-surface); }
255
+
256
+ /* Render slot (ENG-205): the persistent wrapper a skeleton and its replacing
257
+ view share, so the reveal can morph. The column layout + 14px gap mirror the
258
+ message list so wrapping changes nothing about spacing; the exiting overlay
259
+ repeats it so the fading skeleton sits exactly where it was. */
260
+ .fl-reveal { position: relative; align-self: flex-start; width: 100%;
261
+ display: flex; flex-direction: column; gap: 14px; }
262
+ .fl-reveal-enter { display: flex; flex-direction: column; width: 100%; }
263
+ .fl-reveal-exit { position: absolute; top: 0; left: 0; right: 0; pointer-events: none;
264
+ display: flex; flex-direction: column; gap: 14px; }
265
+ @media (prefers-reduced-motion: no-preference) {
266
+ /* Animate only genuine morphs (an exit layer is present) — first paint of a
267
+ slot's ordinary content must not perform an entrance. Transform + opacity
268
+ only (GPU-composited, smooth at any frame rate); the incoming component
269
+ rises with a soft spring while the placeholder settles out beneath it. */
270
+ .fl-reveal:has(.fl-reveal-exit) .fl-reveal-enter { animation: fl-reveal-in .55s cubic-bezier(.22, 1.15, .36, 1) both; }
271
+ .fl-reveal-exit { animation: fl-reveal-out .4s cubic-bezier(.4, 0, .5, 1) both; }
272
+ }
273
+ @keyframes fl-reveal-in {
274
+ 0% { opacity: 0; transform: translateY(8px) scale(.965); }
275
+ 55% { opacity: 1; }
276
+ 100% { opacity: 1; transform: none; } }
277
+ @keyframes fl-reveal-out {
278
+ 0% { opacity: 1; transform: none; }
279
+ 100% { opacity: 0; transform: scale(1.015); } }
280
+
281
+ /* Fill reveal (pick A, ui-lane-renderer 2026-07-19): a shape-derived
282
+ silhouette already holds the incoming view's approximate geometry, so its
283
+ arrival crossfades in place — no rise, no settle. Placed AFTER the .fl-reveal
284
+ rules so the equal-specificity override wins by order. */
285
+ @media (prefers-reduced-motion: no-preference) {
286
+ .fl-reveal-fill:has(.fl-reveal-exit) .fl-reveal-enter { animation: fl-fill-in .45s ease both; }
287
+ .fl-reveal-fill .fl-reveal-exit { animation: fl-fill-out .45s ease both; }
288
+ }
289
+ @keyframes fl-fill-in { from { opacity: 0; } to { opacity: 1; } }
290
+ @keyframes fl-fill-out { from { opacity: 1; } to { opacity: 0; } }
291
+
292
+ /* App boot bar (pick C, V2 indeterminate sweep): while a generated view is
293
+ still forming, the appcard bar narrates — the dot pulses (fl-beat-orb), the
294
+ label reads "Building your view…", and a short accent segment sweeps along
295
+ the bar's bottom edge. On ready the label pair crossfades to the app name
296
+ and the sweep fades. Honest by design: no fake percentage, no completion
297
+ jump. The label pair shares one grid cell so the swap never remounts. */
298
+ .fl-appcard-bar { position: relative; }
299
+ .fl-boot-labels { position: relative; display: grid; min-width: 0; flex: 1; }
300
+ .fl-boot-labels > span { grid-area: 1 / 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
301
+ transition: opacity .3s ease; }
302
+ .fl-appcard-bar[data-state="building"] .fl-boot-ready { opacity: 0; }
303
+ .fl-appcard-bar[data-state="ready"] .fl-boot-building { opacity: 0; }
304
+ .fl-boot-building { color: var(--vendo-fg-muted); font-weight: 500; }
305
+ .fl-boot-hairline { position: absolute; left: 0; bottom: -1px; z-index: 1; width: 26%; height: 2px;
306
+ border-radius: 2px; background: var(--vendo-accent); opacity: 0; transition: opacity .5s ease; }
307
+ .fl-appcard-bar[data-state="building"] .fl-boot-hairline { opacity: 1; }
308
+ @media (prefers-reduced-motion: no-preference) {
309
+ .fl-appcard-bar[data-state="building"] .fl-appcard-dot { animation: fl-beat-orb 1.6s ease-in-out infinite; }
310
+ .fl-appcard-bar[data-state="building"] .fl-boot-hairline { animation: fl-boot-sweep 1.5s cubic-bezier(.45, .05, .55, .95) infinite; }
311
+ }
312
+ @keyframes fl-boot-sweep { from { transform: translateX(-110%); } to { transform: translateX(495%); } }
313
+
314
+ /* Working indicator — fluidkit metaball droplets (ENG-205); inherits the muted
315
+ foreground as the flat-material fill. The .fl-typing dots below are its
316
+ first-paint and no-fluidkit fallback. */
317
+ .fl-thinking { align-self: flex-start; color: var(--vendo-fg-muted); padding: 4px 2px; }
318
+ /* Typing indicator — three pulsing dots while the agent is working. */
319
+ .fl-typing { align-self: flex-start; display: flex; align-items: center; gap: 5px; padding: 4px 2px; }
320
+ .fl-typing span { width: 7px; height: 7px; border-radius: 50%; background: var(--vendo-fg-muted);
321
+ animation: fl-typing 1.1s ease-in-out infinite; }
322
+ .fl-typing span:nth-child(2) { animation-delay: .18s; }
323
+ .fl-typing span:nth-child(3) { animation-delay: .36s; }
324
+ @keyframes fl-typing { 0%, 60%, 100% { opacity: .25; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }
325
+
326
+ .fl-turn-user { align-self: flex-end; background: var(--vendo-user-bubble); color: var(--vendo-user-bubble-fg);
327
+ padding: 9px 14px; border-radius: var(--vendo-radius-lg) var(--vendo-radius-lg) var(--vendo-radius-sm) var(--vendo-radius-lg);
328
+ max-width: 82%; font-size: var(--vendo-text-body); line-height: 1.5;
329
+ letter-spacing: -.006em; border: 1px solid var(--vendo-border);
330
+ box-shadow: 0 1px 2px light-dark(rgba(20,21,26,.06), rgba(0,0,0,.28)); }
331
+ .fl-usertext { white-space: pre-wrap; word-break: break-word; }
332
+ .fl-turn-assistant { align-self: flex-start; max-width: 92%; line-height: 1.65; font-size: var(--vendo-text-body); letter-spacing: -.006em; }
333
+ /* Space a turn's parts (beats, the app card, text) so the app boundary reads
334
+ as its own block instead of butting against the beat above and the line
335
+ below. Beats hug (their own 3px padding); the app card gets real air. */
336
+ .fl-turn-assistant > .fl-appcard { margin: 10px 0; }
337
+ /* Lone caret while a streamed turn is still empty (stable line box, no jitter). */
338
+ .fl-caret { display: inline-block; width: 7px; min-height: 1.05em; height: 1.05em; background: var(--vendo-accent);
339
+ vertical-align: -2px; margin-left: 2px; border-radius: 1px; animation: fl-blink 1s steps(1) infinite; }
340
+ /* Once text is flowing, the caret trails the last block as a pseudo-element so it
341
+ stays inline instead of dropping onto its own line below the final paragraph. */
342
+ .fl-md--streaming > :last-child::after { content: ""; display: inline-block; width: .5em; height: 1.05em;
343
+ margin-left: 2px; vertical-align: -2px; background: var(--vendo-accent); border-radius: 1px;
344
+ animation: fl-blink 1s steps(1) infinite; }
345
+ @keyframes fl-blink { 50% { opacity: 0; } }
346
+
347
+ /* ---------- markdown ---------- */
348
+ .fl-md > :first-child { margin-top: 0; }
349
+ .fl-md > :last-child { margin-bottom: 0; }
350
+ .fl-md p { margin: 0 0 8px; }
351
+ .fl-md ul, .fl-md ol { margin: 0 0 8px; padding-left: 20px; }
352
+ .fl-md li { margin: 2px 0; }
353
+ .fl-md li > p { margin: 0; }
354
+ .fl-md h1, .fl-md h2, .fl-md h3, .fl-md h4 { margin: 10px 0 6px; font-weight: 650; line-height: 1.3;
355
+ font-family: var(--vendo-heading-font); }
356
+ .fl-md h1 { font-size: 1.15em; } .fl-md h2 { font-size: 1.08em; } .fl-md h3 { font-size: 1em; }
357
+ .fl-md a { color: var(--vendo-accent); text-decoration: underline; text-underline-offset: 2px; }
358
+ .fl-md strong { font-weight: 650; }
359
+ .fl-md code { font-family: var(--vendo-font-mono); font-size: .9em; background: var(--vendo-accent-soft);
360
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius-sm); padding: 1px 5px; }
361
+ .fl-md pre { background: var(--vendo-accent-soft); border: 1px solid var(--vendo-border); border-radius: 11px;
362
+ padding: 11px 13px; overflow-x: auto; margin: 0 0 8px; }
363
+ .fl-md pre code { background: none; border: 0; padding: 0; font-size: .85em; }
364
+ /* Code block with a hover Copy button. */
365
+ .fl-codeblock { position: relative; margin: 0 0 8px; }
366
+ .fl-codeblock pre { margin: 0; }
367
+ .fl-copy { position: absolute; top: 7px; right: 7px; font: 500 11px/1 var(--vendo-font); padding: 4px 8px;
368
+ border-radius: 7px; border: 1px solid var(--vendo-border); color: var(--vendo-fg-muted);
369
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
370
+ cursor: pointer; opacity: 0; transition: opacity .12s, color .12s; }
371
+ .fl-codeblock:hover .fl-copy, .fl-copy:focus-visible { opacity: 1; }
372
+ .fl-copy:hover { color: var(--vendo-fg); }
373
+ .fl-md blockquote { margin: 0 0 8px; padding-left: 10px;
374
+ border-left: 2px solid var(--vendo-border-strong); color: var(--vendo-fg-muted); }
375
+ .fl-md table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; font-size: .92em; margin: 0 0 8px; }
376
+ .fl-md th, .fl-md td { border: 1px solid var(--vendo-border); padding: var(--vendo-density-table-padding); text-align: left; }
377
+ .fl-md img { max-width: 100%; height: auto; border-radius: 8px; }
378
+ .fl-md hr { border: 0; border-top: 1px solid var(--vendo-border); margin: 10px 0; }
379
+ .fl-turn-user .fl-md a, .fl-turn-user .fl-md code { color: inherit; border-color: var(--vendo-border); }
380
+
381
+ /* ---------- generating: quiet status + skeleton (tool chips are hidden) ---------- */
382
+ .fl-generating { align-self: flex-start; display: flex; align-items: center; gap: 8px;
383
+ font-size: 12.5px; color: var(--vendo-fg-muted); }
384
+ .fl-generating .fl-pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--vendo-accent);
385
+ animation: fl-pulse 1.2s ease infinite; }
386
+ @keyframes fl-pulse { 0%,100% { opacity: .28; transform: scale(.8); } 50% { opacity: 1; transform: scale(1); } }
387
+ .fl-skeleton { align-self: flex-start; width: 100%; border-radius: var(--vendo-radius);
388
+ border: 1px solid var(--vendo-border); background: var(--vendo-glass-strong);
389
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
390
+ padding: var(--vendo-density-card-padding); box-shadow: var(--vendo-shadow); }
391
+ .fl-skeleton-bar { background: linear-gradient(90deg,
392
+ color-mix(in srgb, var(--vendo-fg) 5%, transparent) 25%,
393
+ color-mix(in srgb, var(--vendo-fg) 10%, transparent) 37%,
394
+ color-mix(in srgb, var(--vendo-fg) 5%, transparent) 63%);
395
+ background-size: 400% 100%; animation: fl-shimmer 1.5s ease infinite; border-radius: 6px; }
396
+ /* An answer taking shape: three shortening lines of "text". */
397
+ .fl-skeleton-bar { height: 10px; }
398
+ .fl-skeleton-bar + .fl-skeleton-bar { margin-top: 9px; }
399
+ .fl-skeleton-bar:nth-child(1) { width: 91%; }
400
+ .fl-skeleton-bar:nth-child(2) { width: 76%; }
401
+ .fl-skeleton-bar:nth-child(3) { width: 58%; }
402
+ @keyframes fl-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
403
+
404
+ /* ---------- glass skeleton (2026-07-05 recipe): a view taking shape ---------- */
405
+ /* The glass ground: translucent fill + hairline white border + inset highlight,
406
+ frosted for real in shell chrome (inside the sandbox iframe backdrop-filter
407
+ can't see the host page — the translucent fill IS the fallback there). Both
408
+ grounds flip with the host scheme; tint and radius come from the existing
409
+ theme tokens — no new theme keys. */
410
+ .fl-glass { border-radius: var(--vendo-radius); padding: var(--vendo-density-card-padding);
411
+ background: light-dark(rgba(255,255,255,.42), rgba(22,24,30,.55));
412
+ border: 1px solid light-dark(rgba(255,255,255,.65), rgba(255,255,255,.14));
413
+ box-shadow: 0 4px 24px light-dark(rgba(23,23,26,.06), rgba(0,0,0,.35)),
414
+ inset 0 1px 0 light-dark(rgba(255,255,255,.8), rgba(255,255,255,.08));
415
+ -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%); }
416
+ .fl-glass-skeleton { align-self: flex-start; width: 100%; }
417
+ .fl-glass-line { display: flex; align-items: center; gap: 9px;
418
+ font: 500 13.5px/1.4 var(--vendo-font); color: var(--vendo-fg); }
419
+ .fl-glass-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--vendo-accent);
420
+ flex-shrink: 0; animation: fl-glass-pulse 1.6s ease-in-out infinite; }
421
+ @keyframes fl-glass-pulse { 50% { transform: scale(1.25); opacity: 1; } }
422
+ /* Shimmer blocks: the HOST ACCENT at .10→.22→.10 (light) / .16→.32→.16 (dark),
423
+ sweeping 1.8s — the recipe's exact tint ramp via color-mix instead of a
424
+ precomputed rgb triplet. */
425
+ .fl-glass-shimmer { border-radius: 10px;
426
+ background: linear-gradient(100deg,
427
+ light-dark(color-mix(in srgb, var(--vendo-accent) 10%, transparent), color-mix(in srgb, var(--vendo-accent) 16%, transparent)) 30%,
428
+ light-dark(color-mix(in srgb, var(--vendo-accent) 22%, transparent), color-mix(in srgb, var(--vendo-accent) 32%, transparent)) 50%,
429
+ light-dark(color-mix(in srgb, var(--vendo-accent) 10%, transparent), color-mix(in srgb, var(--vendo-accent) 16%, transparent)) 70%);
430
+ background-size: 200% 100%; animation: fl-glass-shimmer 1.8s linear infinite; }
431
+ @keyframes fl-glass-shimmer { from { background-position: 120% 0; } to { background-position: -80% 0; } }
432
+ /* The approved grid: a view forming — 3 stat tiles, a wide chart, two rows. */
433
+ .fl-glass-grid { display: grid; gap: 8px; margin-top: 12px; grid-template-columns: repeat(3, 1fr); }
434
+ .fl-glass-tile { height: 44px; }
435
+ .fl-glass-chart { grid-column: span 3; height: 96px; }
436
+ .fl-glass-row { grid-column: span 3; height: 18px; }
437
+ .fl-glass-row.is-short { width: 72%; }
438
+ /* Repaint veil: shimmer over an updating view instead of a flash —
439
+ pointer-transparent, content stays readable. */
440
+ .fl-glass-veil { position: absolute; inset: 0; z-index: 4; pointer-events: none;
441
+ border-radius: var(--vendo-radius); }
442
+ /* Integrations tray placeholder rows. */
443
+ .fl-picker-loading .fl-glass-shimmer { height: 46px; border-radius: 11px; }
444
+
445
+ /* ---------- build beats (the thread's human progress voice) ----------
446
+ One quiet line per tool call: pulsing orb while working, tick when done,
447
+ loud only on error. Completed beats yield the line to the newest one
448
+ (.fl-beat-superseded collapses) so a build narrates as one voice. The
449
+ mechanical record lives in the Activity panel. */
450
+ /* Beats stack as one connected checklist: tight, even rhythm, no per-item
451
+ collapse. Consecutive beats hug (2px) so the group reads as a single block;
452
+ completed lines quiet to muted, the active one carries the pulsing orb. */
453
+ .fl-beat { align-self: flex-start; display: flex; align-items: center; gap: 9px;
454
+ font: 500 13px/1.35 var(--vendo-font); color: var(--vendo-fg-muted); padding: 3px 2px; }
455
+ @media (prefers-reduced-motion: no-preference) {
456
+ .fl-beat { animation: fl-fade-in .24s ease both; }
457
+ }
458
+ .fl-beat-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
459
+ .fl-beat-orb { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
460
+ background: radial-gradient(circle at 35% 35%,
461
+ color-mix(in srgb, var(--vendo-accent) 55%, var(--vendo-surface) 45%), var(--vendo-accent)); }
462
+ @media (prefers-reduced-motion: no-preference) {
463
+ .fl-beat-orb { animation: fl-beat-orb 1.6s ease-in-out infinite; }
464
+ }
465
+ @keyframes fl-beat-orb { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }
466
+ .fl-beat-ic { display: grid; place-items: center; width: 12px; height: 12px; flex-shrink: 0; }
467
+ .fl-beat-done { color: var(--vendo-fg-muted); }
468
+ .fl-beat-tick { color: var(--vendo-ok); }
469
+ .fl-beat-error { color: var(--vendo-danger); }
470
+ .fl-beat-x { color: var(--vendo-danger); }
471
+ .fl-beat-count { margin-left: 2px; padding: 1px 6px; border-radius: 999px; flex-shrink: 0;
472
+ font: 600 10.5px/1.4 var(--vendo-font); color: var(--vendo-fg-muted);
473
+ border: 1px solid var(--vendo-border); background: var(--vendo-glass-strong); }
474
+
475
+ /* ---------- tool chip (kept quiet; most are hidden in the thread) ---------- */
476
+ .fl-tool { align-self: flex-start; display: flex; align-items: center; gap: 8px;
477
+ font: 500 12px/1 var(--vendo-font); color: var(--vendo-fg-muted);
478
+ border: 1px solid var(--vendo-border); border-radius: 10px; padding: 7px 11px;
479
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur); }
480
+ .fl-tool-label { color: var(--vendo-fg); }
481
+ .fl-tool-detail { color: var(--vendo-fg-muted); font-weight: 400;
482
+ max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
483
+ .fl-tool-count { margin-left: 2px; padding: 1px 6px; border-radius: 999px; flex-shrink: 0;
484
+ font: 600 10.5px/1.5 var(--vendo-font); color: var(--vendo-fg-muted);
485
+ background: var(--vendo-glass); border: 1px solid var(--vendo-border); }
486
+ .fl-tool-icon { display: grid; place-items: center; width: 14px; height: 14px; font-size: 11px; flex-shrink: 0; }
487
+ .fl-tool-done .fl-tool-icon { color: var(--vendo-ok); }
488
+ .fl-tool-error { color: var(--vendo-danger); border-color: var(--vendo-danger-border); }
489
+ .fl-tool-error .fl-tool-icon, .fl-tool-err { color: var(--vendo-danger); }
490
+ /* Working spinner. */
491
+ .fl-tool-spinner { width: 13px; height: 13px; border-radius: 50%; flex-shrink: 0;
492
+ border: 2px solid var(--vendo-border-strong); border-top-color: var(--vendo-fg-muted);
493
+ animation: fl-spin .8s linear infinite; }
494
+ @keyframes fl-spin { to { transform: rotate(360deg); } }
495
+
496
+ /* ---------- approval / buttons ---------- */
497
+ .fl-approval { align-self: flex-start; border: 1px solid var(--vendo-border);
498
+ border-radius: var(--vendo-radius); padding: 14px; box-shadow: var(--vendo-shadow);
499
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
500
+ max-width: 88%; min-width: min(360px, 88%); }
501
+ .fl-automation-approval-slot { align-self: flex-start; width: 100%; display: flex; }
502
+ .fl-approval-head { display: flex; align-items: flex-start; gap: 10px; }
503
+ .fl-approval-ic { display: grid; place-items: center; width: 28px; height: 28px; flex-shrink: 0;
504
+ border-radius: 9px; color: var(--vendo-accent); background: var(--vendo-accent-soft); }
505
+ .fl-approval-eyebrow { font: 600 10.5px/1 var(--vendo-font); letter-spacing: .05em;
506
+ text-transform: uppercase; color: var(--vendo-fg-muted); }
507
+ .fl-approval-title { margin-top: 4px; font: 600 13.5px/1.3 var(--vendo-heading-font); color: var(--vendo-fg);
508
+ letter-spacing: -.01em; }
509
+ .fl-approval-desc { margin-top: 3px; font: 400 12px/1.4 var(--vendo-font); color: var(--vendo-fg-muted); }
510
+ .fl-approval-fields { margin: 12px 0 0; padding: 10px 0 2px; border-top: 1px solid var(--vendo-border);
511
+ display: flex; flex-direction: column; gap: 7px; }
512
+ .fl-approval-field { display: grid; grid-template-columns: minmax(88px, auto) 1fr; gap: 12px;
513
+ font-size: 12.5px; line-height: 1.45; }
514
+ .fl-approval-field dt { color: var(--vendo-fg-muted); }
515
+ /* pre-line: object/array inputs render as compact \`Key: value\` lines
516
+ (field-rows.ts), one per line, instead of raw JSON. */
517
+ .fl-approval-field dd { margin: 0; color: var(--vendo-fg); overflow-wrap: anywhere; white-space: pre-line; }
518
+ .fl-approval-more { font-size: 11.5px; color: var(--vendo-fg-muted); }
519
+ .fl-approval-desc { margin: 10px 0 0; font: 400 12.5px/1.5 var(--vendo-font); color: var(--vendo-fg-soft, var(--vendo-fg-muted)); }
520
+ .fl-approval-actions { display: flex; gap: 8px; margin-top: 12px; }
521
+ .fl-automation-approval { padding: 14px; }
522
+ .fl-auto-approval-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
523
+ .fl-auto-approval-heading { min-width: 0; }
524
+ .fl-auto-approval-title { margin-top: 5px; font: 650 15px/1.25 var(--vendo-heading-font); color: var(--vendo-fg);
525
+ letter-spacing: -.01em; overflow-wrap: anywhere; }
526
+ .fl-auto-logo-stack { display: flex; align-items: center; flex-shrink: 0; padding-top: 1px; }
527
+ .fl-auto-logo { display: grid; place-items: center; width: 31px; height: 31px; border: 1px solid var(--vendo-border);
528
+ border-radius: 10px; background: var(--vendo-surface); box-shadow: inset 0 1px 0 light-dark(rgba(255,255,255,.58), rgba(255,255,255,.08)); }
529
+ .fl-auto-logo + .fl-auto-logo { margin-left: -7px; }
530
+ .fl-auto-summary { display: flex; flex-direction: column; gap: 9px; margin-top: 14px; padding-top: 12px;
531
+ border-top: 1px solid var(--vendo-border); }
532
+ .fl-auto-summary-row { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 10px; align-items: start; }
533
+ .fl-auto-summary-k { padding-top: 1px; color: var(--vendo-fg-muted); font-size: 11.5px; font-weight: 650; }
534
+ .fl-auto-summary-v { min-width: 0; display: flex; flex-direction: column; gap: 2px; color: var(--vendo-fg);
535
+ font-size: 12.5px; line-height: 1.35; }
536
+ .fl-auto-summary-v strong { font: 600 12.8px/1.35 var(--vendo-font); overflow-wrap: anywhere; }
537
+ .fl-auto-summary-v span { color: var(--vendo-fg-muted); overflow-wrap: anywhere; }
538
+ .fl-auto-access { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
539
+ .fl-auto-access-label { color: var(--vendo-fg-muted); font-size: 11.5px; font-weight: 650; }
540
+ .fl-auto-access-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 10px; align-items: center;
541
+ min-width: 0; padding: 9px 0; border-top: 1px solid color-mix(in srgb, var(--vendo-border) 68%, transparent); }
542
+ .fl-auto-access-row:first-of-type { border-top: 0; }
543
+ .fl-auto-access-logo { display: grid; place-items: center; width: 32px; height: 32px; border: 1px solid var(--vendo-border);
544
+ border-radius: 10px; background: var(--vendo-surface); box-shadow: inset 0 1px 0 light-dark(rgba(255,255,255,.58), rgba(255,255,255,.08)); }
545
+ .fl-auto-access-copy { min-width: 0; }
546
+ .fl-auto-access-title { color: var(--vendo-fg); font-size: 12.5px; font-weight: 650; line-height: 1.2; }
547
+ .fl-auto-access-sub { margin-top: 2px; color: var(--vendo-fg-muted); font-size: 11.5px; line-height: 1.25;
548
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
549
+ .fl-auto-access-badge[data-auto] { background: var(--vendo-accent); color: var(--vendo-accent-fg); border-color: var(--vendo-accent); }
550
+ .fl-auto-access-badge { justify-self: end; max-width: 112px; padding: 4px 7px; border-radius: 999px;
551
+ background: var(--vendo-accent-soft); color: var(--vendo-fg); font-size: 10.5px; font-weight: 650;
552
+ line-height: 1.15; text-align: center; overflow-wrap: normal; }
553
+ .fl-auto-details { margin-top: 8px; }
554
+ .fl-auto-details summary { color: var(--vendo-fg-muted); font-size: 11px; cursor: pointer; }
555
+ .fl-auto-details pre { margin: 7px 0 0; max-height: 180px; overflow: auto; white-space: pre-wrap;
556
+ font: 11px/1.35 var(--vendo-font-mono); color: var(--vendo-fg-muted); }
557
+ .fl-auto-created-layer { position: fixed; inset: 0; z-index: 2147483002; pointer-events: none; overflow: visible; background: none; }
558
+ .fl-auto-created-panel { position: absolute; box-sizing: border-box; transform-origin: 100% 0%;
559
+ will-change: top, left, width, height, opacity, transform; }
560
+ .fl-auto-created-panel--morph .fl-auto-created-toast { position: absolute; inset: 0; opacity: 0; }
561
+ .fl-auto-created-proposal { width: 100%; }
562
+ .fl-auto-created-proposal .fl-approval { width: 100%; max-width: none; min-width: 0; box-sizing: border-box; }
563
+ .fl-auto-created-toast { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 58px;
564
+ box-shadow: 0 14px 40px rgba(0,0,0,.20);
565
+ box-sizing: border-box; padding: 11px 12px; border: 1px solid color-mix(in srgb, var(--vendo-border) 72%, var(--vendo-accent) 28%);
566
+ border-radius: 14px; color: var(--vendo-fg);
567
+ background:
568
+ linear-gradient(180deg, color-mix(in srgb, var(--vendo-surface) 94%, var(--vendo-accent) 6%), var(--vendo-surface)),
569
+ var(--vendo-surface);
570
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
571
+ box-shadow: 0 18px 44px light-dark(rgba(20,21,26,.14), rgba(0,0,0,.42)), inset 0 1px 0 light-dark(rgba(255,255,255,.58), rgba(255,255,255,.08)); }
572
+ .fl-auto-created-live { position: relative; width: 9px; height: 9px; flex: 0 0 9px; border-radius: 999px;
573
+ background: var(--vendo-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--vendo-accent) 15%, transparent); }
574
+ .fl-auto-created-live::after { position: absolute; inset: -4px; border: 1px solid color-mix(in srgb, var(--vendo-accent) 24%, transparent);
575
+ border-radius: inherit; content: ""; animation: fl-auto-created-pulse 1.7s ease-out infinite; }
576
+ .fl-auto-created-copy { min-width: 0; flex: 1; }
577
+ .fl-auto-created-title { overflow: hidden; color: var(--vendo-fg); font-size: 13px; font-weight: 720;
578
+ line-height: 1.18; text-overflow: ellipsis; white-space: nowrap; }
579
+ .fl-auto-created-sub { overflow: hidden; margin-top: 3px; color: var(--vendo-fg-muted); font-size: 12px;
580
+ line-height: 1.2; text-overflow: ellipsis; white-space: nowrap; }
581
+ .fl-auto-created-logos { display: flex; align-items: center; justify-content: flex-end; min-width: 38px; flex: 0 0 auto; }
582
+ .fl-auto-created-logo { position: relative; display: inline-grid; width: 32px; height: 32px; place-items: center;
583
+ border: 1px solid var(--vendo-border); border-radius: 10px; background: var(--vendo-surface);
584
+ box-shadow: inset 0 1px 0 light-dark(rgba(255,255,255,.58), rgba(255,255,255,.08)); }
585
+ .fl-auto-created-logo + .fl-auto-created-logo { margin-left: -7px; }
586
+ .fl-auto-created-count { position: absolute; right: -5px; bottom: -5px; min-width: 16px; height: 16px; padding: 0 4px;
587
+ border: 1px solid var(--vendo-surface); border-radius: 999px; background: var(--vendo-accent);
588
+ color: var(--vendo-accent-fg); font-size: 10px; font-weight: 750; line-height: 14px; text-align: center; }
589
+ @keyframes fl-auto-created-pulse {
590
+ 0% { opacity: .52; transform: scale(.7); }
591
+ 100% { opacity: 0; transform: scale(1.9); }
592
+ }
593
+ .fl-approval-batch-list { list-style: none; margin: 12px 0 0; padding: 10px 0 2px;
594
+ border-top: 1px solid var(--vendo-border); display: flex; flex-direction: column; gap: 7px; }
595
+ .fl-approval-batch-row label { display: flex; align-items: center; gap: 9px;
596
+ font-size: 12.5px; line-height: 1.45; color: var(--vendo-fg); cursor: pointer; }
597
+ .fl-approval-batch-row input[type="checkbox"] { appearance: none; margin: 0; width: 15px; height: 15px;
598
+ flex-shrink: 0; border: 1px solid var(--vendo-border-strong); border-radius: 4.5px;
599
+ background: var(--vendo-surface); cursor: pointer; display: grid; place-items: center;
600
+ transition: background .13s, border-color .13s; }
601
+ .fl-approval-batch-row input[type="checkbox"]:hover { border-color: var(--vendo-accent); }
602
+ .fl-approval-batch-row input[type="checkbox"]:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
603
+ .fl-approval-batch-row input[type="checkbox"]:checked { background: var(--vendo-accent); border-color: var(--vendo-accent); }
604
+ .fl-approval-batch-row input[type="checkbox"]:checked::after { content: ""; width: 8.5px; height: 8.5px;
605
+ background: var(--vendo-accent-fg);
606
+ clip-path: polygon(14% 44%, 0 62%, 40% 100%, 100% 18%, 84% 4%, 39% 68%); }
607
+ .fl-btn { border: 1px solid var(--vendo-border); border-radius: 9px; padding: 8px 15px;
608
+ font: 550 12.5px/1 var(--vendo-font); letter-spacing: -.006em;
609
+ background: var(--vendo-surface); color: var(--vendo-fg); cursor: pointer;
610
+ box-shadow: 0 1px 1.5px color-mix(in srgb, var(--vendo-fg) 5%, transparent);
611
+ transition: background .13s, border-color .13s, transform .05s, box-shadow .13s; }
612
+ .fl-btn:hover { background: var(--vendo-accent-soft); border-color: var(--vendo-border-strong); }
613
+ .fl-btn:active { transform: translateY(.5px); box-shadow: none; }
614
+ .fl-btn-primary { background: var(--vendo-accent); color: var(--vendo-accent-fg); border-color: transparent;
615
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-fg) 22%, transparent), inset 0 1px 0 rgba(255,255,255,.16); }
616
+ .fl-btn-primary:hover { opacity: .92; background: var(--vendo-accent); border-color: transparent; }
617
+ .fl-approval--ceremony { border-color: var(--vendo-warn-border); background: var(--vendo-warn-bg); }
618
+ .fl-approval--ceremony .fl-approval-ic { color: var(--vendo-warn); background: color-mix(in srgb, var(--vendo-warn) 16%, transparent); }
619
+ .fl-approval--ceremony .fl-approval-eyebrow { color: var(--vendo-warn); }
620
+ .fl-approval-unverified { margin-left: 8px; padding: 1px 6px; border-radius: 999px; font-size: 9.5px;
621
+ font-weight: 700; text-transform: none; letter-spacing: 0; color: var(--vendo-fg-muted);
622
+ background: color-mix(in srgb, var(--vendo-fg-muted) 12%, transparent); }
623
+ .fl-approval-consequence { margin-top: 10px; font: 600 12px/1.4 var(--vendo-font); color: var(--vendo-warn); }
624
+ .fl-btn-ceremony { background: var(--vendo-warn); color: var(--vendo-warn-on-fill); border-color: transparent;
625
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-warn) 40%, transparent); }
626
+ .fl-btn-ceremony:hover { opacity: .92; background: var(--vendo-warn); border-color: transparent; }
627
+ .fl-approval--escalation { border-color: var(--vendo-warn-border); background: var(--vendo-warn-bg); }
628
+ .fl-approval--escalation .fl-approval-ic { color: var(--vendo-warn); background: color-mix(in srgb, var(--vendo-warn) 16%, transparent); }
629
+ .fl-approval--escalation .fl-approval-eyebrow { color: var(--vendo-warn); }
630
+ .fl-approval-reason { margin: 10px 0 0; font: 400 12.5px/1.4 var(--vendo-font); color: var(--vendo-fg);
631
+ /* Defensive: the reason is model-authored text — capped at 200 chars at the
632
+ stamp site (runtime escalation.ts), but never let a runaway value blow
633
+ the card up regardless. */
634
+ max-height: 7em; overflow-y: auto; overflow-wrap: break-word; }
635
+ .fl-uinode { align-self: flex-start; width: 100%; }
636
+
637
+ /* ---------- fade proposal (ENG-193 §3 Moment 5/§4.4) ---------- */
638
+ .fl-fade { display: flex; flex-direction: column; gap: 10px; margin: 6px 0; padding: 12px 14px;
639
+ border: 1px dashed var(--vendo-border); border-radius: 12px; background: var(--vendo-accent-soft); }
640
+ .fl-fade-text { font-size: 13px; line-height: 1.4; color: var(--vendo-fg); }
641
+ .fl-fade-actions { display: flex; gap: 8px; }
642
+
643
+ /* ---------- waiting list ("waiting on you", ENG-193 §4.6) ---------- */
644
+ /* Height-capped with internal scroll: an unbounded inbox (verified live with
645
+ 9 parked rows) starves the host page's flex column, compressing the thread
646
+ until the last card's buttons sit UNDER the docked composer — whose form
647
+ then intercepts their clicks. The strip must never take more than its
648
+ share of the surface; overflow scrolls inside. */
649
+ .fl-waiting { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px;
650
+ max-height: min(40vh, 360px); overflow-y: auto; overscroll-behavior: contain;
651
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius);
652
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur); }
653
+ /* The scroller's children must never compress (same rule as .fl-msglist). */
654
+ .fl-waiting > * { flex-shrink: 0; }
655
+ .fl-waiting-head { font: 600 11px/1 var(--vendo-font); letter-spacing: .04em;
656
+ text-transform: uppercase; color: var(--vendo-fg-muted); }
657
+ .fl-waiting-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
658
+ padding: 9px 0; border-top: 1px solid var(--vendo-border); }
659
+ .fl-waiting-row:first-of-type { border-top: none; }
660
+ .fl-waiting-row-main { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
661
+ .fl-waiting-ic { flex-shrink: 0; line-height: 1.3; }
662
+ .fl-waiting-row-title { font: 600 13px/1.3 var(--vendo-font); color: var(--vendo-fg); }
663
+ .fl-waiting-row-preview { margin-top: 2px; font-size: 12px; color: var(--vendo-fg-muted);
664
+ overflow-wrap: anywhere; white-space: pre-line; }
665
+ .fl-waiting-row-meta { margin-top: 4px; font-size: 11px; color: var(--vendo-fg-muted); }
666
+ .fl-waiting-stale { color: var(--vendo-fg-muted); }
667
+ .fl-waiting-actions { display: flex; gap: 6px; flex-shrink: 0; }
668
+ .fl-waiting-row--ceremony { background: var(--vendo-warn-bg); border-radius: 9px; padding: 9px; margin: 0 -9px; }
669
+ .fl-waiting-row--ceremony .fl-waiting-row-title { color: var(--vendo-warn); }
670
+
671
+ /* ---------- composer ---------- */
672
+ /* Column so attachment chips / drop zone stack above the input row. */
673
+ .fl-composer { position: relative; display: flex; flex-direction: column; gap: 8px; margin: 10px 16px 16px;
674
+ padding: 7px 8px 7px 14px;
675
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
676
+ border: 1px solid var(--vendo-border); border-radius: 14px;
677
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-fg) 5%, transparent),
678
+ 0 10px 28px color-mix(in srgb, var(--vendo-fg) 7%, transparent);
679
+ transition: border-color .14s, box-shadow .14s, border-radius .2s ease; }
680
+ /* No focus ring on pointer focus (Apple/OpenAI-quiet): the caret is the
681
+ signal. KEYBOARD focus still gets a visible ring via :focus-visible —
682
+ the textarea keeps outline:0, so without this rule Tab-focus would be
683
+ invisible on the product's primary input. */
684
+ .fl-composer:has(:focus-visible) { border-color: var(--vendo-border-strong);
685
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-fg) 5%, transparent),
686
+ 0 10px 28px color-mix(in srgb, var(--vendo-fg) 7%, transparent),
687
+ 0 0 0 3px var(--vendo-accent-soft); }
688
+ .fl-composer-drag { border-color: var(--vendo-accent); }
689
+ /* align-items:flex-end so the buttons sit at the bottom as the field grows. */
690
+ .fl-composer-row { display: flex; align-items: flex-end; gap: 10px; }
691
+ .fl-composer textarea { flex: 1; border: 0; outline: 0; background: transparent; color: var(--vendo-fg);
692
+ font-family: var(--vendo-font); font-size: var(--vendo-base-size); line-height: 1.5; resize: none; max-height: 200px;
693
+ padding: 6px 0; overflow-y: auto; scrollbar-width: none; }
694
+ .fl-composer textarea::-webkit-scrollbar { display: none; }
695
+ .fl-composer textarea::placeholder { color: var(--vendo-fg-muted); }
696
+ .fl-icon-btn { flex-shrink: 0; width: 34px; height: 34px; border-radius: 10px; border: 1px solid transparent;
697
+ background: transparent; display: flex; align-items: center; justify-content: center; cursor: pointer;
698
+ color: var(--vendo-fg-muted); transition: background .12s, color .12s, opacity .12s; }
699
+ .fl-icon-btn:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
700
+ .fl-attach { color: var(--vendo-fg-muted); }
701
+
702
+ /* drag-over overlay */
703
+ .fl-drop { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; border-radius: 16px;
704
+ border: 1.5px dashed var(--vendo-accent); background: color-mix(in srgb, var(--vendo-accent) 7%, var(--vendo-surface));
705
+ font-size: 12.5px; font-weight: 550; color: var(--vendo-fg); }
706
+
707
+ /* attachment preview chips (in composer) */
708
+ .fl-att-chips { display: flex; flex-wrap: wrap; gap: 8px; }
709
+ .fl-att-img { position: relative; width: 46px; height: 46px; border-radius: var(--vendo-radius-sm); overflow: hidden;
710
+ border: 1px solid var(--vendo-border); }
711
+ .fl-att-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
712
+ .fl-att-file { display: inline-flex; align-items: center; gap: 8px; height: 46px; padding: 0 30px 0 10px; position: relative;
713
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius-sm); background: var(--vendo-surface); font-size: 12px; max-width: 220px; }
714
+ .fl-att-ext { display: grid; place-items: center; width: 26px; height: 32px; border-radius: 4px; flex-shrink: 0;
715
+ background: var(--vendo-danger); color: #fff; font: 700 8px/1 var(--vendo-font); letter-spacing: .02em; }
716
+ .fl-att-meta { display: flex; flex-direction: column; min-width: 0; }
717
+ .fl-att-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
718
+ .fl-att-meta small { color: var(--vendo-fg-muted); font-size: 10.5px; }
719
+ .fl-att-rm { position: absolute; top: 2px; right: 2px; width: 16px; height: 16px; border-radius: 50%; border: 0;
720
+ background: rgba(0,0,0,.6); color: #fff; font-size: 11px; line-height: 1; display: grid; place-items: center; cursor: pointer; }
721
+ .fl-att-rm-file { top: 50%; transform: translateY(-50%); background: var(--vendo-accent-soft); color: var(--vendo-fg); }
722
+ .fl-att-error { font-size: 11.5px; color: var(--vendo-danger); padding: 0 2px; }
723
+
724
+ /* queued-send pill (ENG-215): a message typed mid-turn parks here and auto-sends
725
+ when the turn completes. Reads as a pending chip, not a sent bubble. */
726
+ .fl-queued { position: relative; display: flex; align-items: center; gap: 8px; padding: 7px 34px 7px 10px;
727
+ border: 1px dashed var(--vendo-border-strong); border-radius: var(--vendo-radius-sm);
728
+ background: var(--vendo-accent-soft); font-size: 12.5px; color: var(--vendo-fg); }
729
+ .fl-queued-tag { flex-shrink: 0; font: 600 10px/1 var(--vendo-font); text-transform: uppercase; letter-spacing: .04em;
730
+ color: var(--vendo-accent); border: 1px solid color-mix(in srgb, var(--vendo-accent) 40%, transparent);
731
+ border-radius: 5px; padding: 3px 5px; }
732
+ .fl-queued-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
733
+ .fl-queued-hint { margin-left: auto; flex-shrink: 0; color: var(--vendo-fg-muted); font-size: 11px; }
734
+ .fl-queued-rm { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
735
+
736
+ /* sent attachments (in transcript) */
737
+ .fl-turn-user-att { align-self: flex-end; max-width: 82%; display: flex; flex-wrap: wrap; gap: 6px;
738
+ align-items: flex-start; justify-content: flex-end; }
739
+ .fl-msg-img { display: block; max-width: 160px; border-radius: 12px; overflow: hidden; border: 1px solid var(--vendo-border); }
740
+ .fl-msg-img img { display: block; max-width: 100%; height: auto; }
741
+ .fl-msg-file { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 12px; align-self: flex-start;
742
+ border: 1px solid var(--vendo-border); background: var(--vendo-surface); font-size: 12.5px; color: var(--vendo-fg);
743
+ text-decoration: none; max-width: 200px; }
744
+ .fl-msg-file .fl-att-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
745
+
746
+ /* ---------- activity panel ---------- */
747
+ .fl-act { align-self: flex-start; width: 100%; max-width: 92%; border: 1px solid var(--vendo-border);
748
+ border-radius: 13px; background: var(--vendo-glass-strong); box-shadow: 0 1px 2px light-dark(rgba(20,21,26,.04), rgba(0,0,0,.35));
749
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur); overflow: hidden; }
750
+ .fl-act-head { display: flex; align-items: center; gap: 9px; width: 100%; padding: 9px 13px; cursor: pointer;
751
+ border: 0; background: transparent; font: 600 12.5px/1.2 var(--vendo-font); color: var(--vendo-fg); text-align: left; }
752
+ .fl-act-head:hover { background: var(--vendo-accent-soft); }
753
+ .fl-act-head-lbl { font-weight: 600; }
754
+ .fl-act-head-err { color: var(--vendo-danger); }
755
+ .fl-act-now { color: var(--vendo-fg-muted); font-weight: 500; }
756
+ .fl-act-chev { margin-left: auto; color: var(--vendo-fg-muted); font-size: 13px; transition: transform .15s; }
757
+ .fl-act-chev-open { transform: rotate(90deg); }
758
+ .fl-act-pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--vendo-accent); flex-shrink: 0;
759
+ animation: fl-pulse 1.2s ease infinite; }
760
+ .fl-act-body { border-top: 1px solid var(--vendo-border); padding: 3px 0; }
761
+ .fl-act-row { display: flex; align-items: center; gap: 9px; padding: 8px 13px; font-size: 12.5px; }
762
+ .fl-act-lbl { font-weight: 550; }
763
+ .fl-act-sub { margin-left: auto; color: var(--vendo-fg-muted); font-size: 11.5px;
764
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 55%; }
765
+ .fl-act-err { color: var(--vendo-danger); }
766
+ .fl-act-ic { display: grid; place-items: center; width: 14px; height: 14px; font-size: 11px; flex-shrink: 0; }
767
+ .fl-act-tick { color: var(--vendo-ok); }
768
+ .fl-act-x { color: var(--vendo-danger); }
769
+ .fl-act-denied { color: var(--vendo-fg-muted); }
770
+ .fl-act-spin { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;
771
+ border: 2px solid var(--vendo-border-strong); border-top-color: var(--vendo-fg-muted); animation: fl-spin .8s linear infinite; }
772
+ .fl-act-table { border-collapse: collapse; display: block; width: 100%; }
773
+ .fl-act-cap { display: block; width: 100%; padding: 9px 13px 3px; text-align: left;
774
+ color: var(--vendo-fg-muted); font-weight: 500; font-size: 11.5px; }
775
+ .fl-act-thead, .fl-act-tbody { display: block; }
776
+ .fl-act-grid { display: grid; grid-template-columns: 1.5fr 1.4fr 1fr 1.05fr; gap: 10px;
777
+ align-items: start; padding: 9px 13px; border-bottom: 1px solid var(--vendo-border); }
778
+ .fl-act-tbody .fl-act-grid:last-child { border-bottom: 0; }
779
+ .fl-act-th { text-align: left; font-weight: 600; font-size: 10.5px; letter-spacing: .05em;
780
+ text-transform: uppercase; color: var(--vendo-fg-muted); }
781
+ .fl-act-cell { min-width: 0; font-size: 12.5px; }
782
+ .fl-act-kind { display: inline-block; margin-right: 7px; padding: 1px 7px; border-radius: 999px;
783
+ background: var(--vendo-accent-soft); border: 1px solid var(--vendo-border); color: var(--vendo-fg-muted);
784
+ font-size: 10px; font-weight: 600; letter-spacing: .02em; vertical-align: 1px; }
785
+ .fl-act-action { font-weight: 550; }
786
+ .fl-act-detail { color: var(--vendo-fg-muted); font-size: 11.5px;
787
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
788
+ .fl-act-when { color: var(--vendo-fg-muted); font-size: 11.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
789
+ .fl-act-outcome { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
790
+ .fl-act-by { margin-top: 2px; color: var(--vendo-fg-muted); font-size: 10.5px; }
791
+ .fl-act-foot { display: flex; align-items: center; padding: 10px 13px; }
792
+ .fl-act-end { margin: 0; color: var(--vendo-fg-muted); font-size: 11.5px; }
793
+ .fl-act-peek { margin: -2px 13px 9px 36px; border: 1px solid var(--vendo-border); border-radius: 9px; overflow: hidden; }
794
+ .fl-act-peek-row { display: flex; justify-content: space-between; gap: 10px; padding: 6px 10px; font-size: 11.5px;
795
+ border-bottom: 1px solid var(--vendo-border); }
796
+ .fl-act-peek-row:last-child { border-bottom: 0; }
797
+ .fl-act-peek-k { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
798
+ .fl-act-peek-v { color: var(--vendo-fg-muted); font-variant-numeric: tabular-nums; flex-shrink: 0; }
799
+ .fl-receipt { margin-left: 6px; padding: 0; border: none; background: none; cursor: pointer;
800
+ font: 500 10.5px/1 var(--vendo-font); color: var(--vendo-fg-muted); text-decoration: underline;
801
+ text-decoration-color: color-mix(in srgb, var(--vendo-fg-muted) 45%, transparent); }
802
+ .fl-receipt-fields { margin-top: 6px; padding-left: 26px; }
803
+
804
+ /* ---------- turn actions ---------- */
805
+ .fl-turn-actions { display: flex; align-items: center; gap: 2px; margin-top: 6px;
806
+ opacity: 0; transition: opacity .14s; }
807
+ .fl-turn-assistant:hover .fl-turn-actions,
808
+ .fl-turn-assistant:focus-within .fl-turn-actions,
809
+ .fl-turn-assistant:last-child .fl-turn-actions { opacity: 1; }
810
+ /* ENG-215 — the last user turn carries an Edit action; reveal on hover/focus so
811
+ keyboard users reach it too (the button stays tabbable while faint). */
812
+ .fl-turn-user .fl-turn-actions { justify-content: flex-end; }
813
+ .fl-turn-user:hover .fl-turn-actions,
814
+ .fl-turn-user:focus-within .fl-turn-actions { opacity: 1; }
815
+ .fl-turn-btn { display: inline-flex; align-items: center; gap: 5px; height: 27px; min-width: 27px; padding: 0 6px;
816
+ border: 0; border-radius: 7px; background: transparent; color: var(--vendo-fg-muted); cursor: pointer;
817
+ font: 550 12px/1 var(--vendo-font); transition: background .12s, color .12s; }
818
+ .fl-turn-btn:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
819
+ .fl-turn-btn:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 1px; }
820
+ .fl-turn-up { color: var(--vendo-ok); }
821
+ .fl-turn-down { color: var(--vendo-danger); }
822
+ .fl-turn-ts { margin-left: 8px; font-size: 11px; color: var(--vendo-fg-muted); opacity: .7; }
823
+
824
+ /* ---------- markdown: tables + math ---------- */
825
+ .fl-md table { border-collapse: collapse; width: 100%; font-size: 13px; margin: 8px 0; }
826
+ .fl-md th, .fl-md td { text-align: left; padding: var(--vendo-density-table-padding); border-bottom: 1px solid var(--vendo-border); }
827
+ .fl-md thead th { color: var(--vendo-fg-muted); font: 600 11px/1.3 var(--vendo-font);
828
+ text-transform: uppercase; letter-spacing: .03em; }
829
+ .fl-md tbody tr:nth-child(even) { background: var(--vendo-accent-soft); }
830
+ .fl-md .katex-display { margin: 10px 0; overflow-x: auto; overflow-y: hidden; }
831
+
832
+ /* streaming: new blocks fade in as they arrive (subtle, per-block) */
833
+ .fl-md--streaming > * { animation: fl-fade-in .28s ease both; }
834
+ .fl-icon-btn:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
835
+ .fl-icon-btn:disabled { opacity: .4; cursor: default; }
836
+ .fl-icon-btn:disabled:hover { background: transparent; }
837
+ .fl-send { border-radius: 50%; background: var(--vendo-accent); color: var(--vendo-accent-fg); border-color: transparent;
838
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--vendo-fg) 22%, transparent), inset 0 1px 0 rgba(255,255,255,.16); }
839
+ .fl-send:hover { opacity: .92; background: var(--vendo-accent); color: var(--vendo-accent-fg); }
840
+ .fl-send:disabled:hover { opacity: .4; background: var(--vendo-accent); }
841
+
842
+ /* ---------- landing ---------- */
843
+ .fl-landing { display: flex; flex-direction: column; align-items: center; justify-content: center;
844
+ gap: 16px; flex: 1; padding: 30px; text-align: center; }
845
+ .fl-greet { margin: 0; font-family: var(--vendo-heading-font); font-size: calc(var(--vendo-base-size) * 1.533); font-weight: 600; letter-spacing: -.022em; }
846
+ /* Greeting-as-tutorial (ui-usage-dx §6): the one-time first message reads as
847
+ the agent speaking — left-aligned assistant typography with its prompt chips
848
+ beneath — inside the otherwise-centered landing. */
849
+ .fl-greeting { display: flex; flex-direction: column; gap: 14px; align-self: stretch;
850
+ max-width: 560px; margin: 0 auto; text-align: left; }
851
+ .fl-greeting-intro { margin: 0; line-height: 1.65; font-size: var(--vendo-text-body); letter-spacing: -.006em; }
852
+ .fl-greeting .fl-chips { justify-content: flex-start; }
853
+ .fl-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
854
+ .fl-chip { border: 1px solid var(--vendo-border); background: var(--vendo-glass-strong);
855
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
856
+ border-radius: 999px; padding: 8px 14px; font-size: 12.5px; color: var(--vendo-fg); cursor: pointer;
857
+ transition: border-color .14s, background .14s, transform .18s cubic-bezier(.22,1,.36,1), box-shadow .18s; }
858
+ .fl-chip:hover { border-color: var(--vendo-border-strong); background: var(--vendo-surface);
859
+ transform: translateY(-1px); box-shadow: 0 2px 10px color-mix(in srgb, var(--vendo-fg) 8%, transparent); }
860
+ .fl-chip:active { transform: translateY(0); box-shadow: none; }
861
+ /* Brand focus ring — the UA default blue halo is off-brand in every host. */
862
+ .fl-chip:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
863
+ .fl-landing-composer { width: 100%; max-width: 560px; }
864
+ /* No padding override here: the hero composer keeps the standard bar
865
+ geometry, so the send circle stays inset and concentric with the bar's
866
+ rounded end instead of colliding with the border arc. */
867
+
868
+ /* ---------- connection selector (denser, brand-forward) ---------- */
869
+ .fl-picker { border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius-lg);
870
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
871
+ box-shadow: var(--vendo-shadow); overflow: auto; padding: 18px 18px 20px; max-width: 560px;
872
+ max-height: min(560px, 70vh); align-self: flex-start; width: 100%;
873
+ scrollbar-width: none; }
874
+ .fl-picker::-webkit-scrollbar { display: none; }
875
+ .fl-picker-toprow { display: flex; align-items: center; gap: 8px; }
876
+ .fl-picker-toprow .fl-picker-search { flex: 1; width: auto; margin-bottom: 0; }
877
+ .fl-picker-close { margin-left: auto; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center;
878
+ border: 0; background: transparent; color: var(--vendo-fg-muted); cursor: pointer; transition: background .12s, color .12s; }
879
+ .fl-picker-close:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
880
+ .fl-picker-search { width: 100%; box-sizing: border-box; border: 1px solid var(--vendo-border); border-radius: 10px;
881
+ outline: 0; background: var(--vendo-surface); font-family: var(--vendo-font); font-size: 13px;
882
+ color: var(--vendo-fg); padding: 9px 11px; margin-bottom: 4px; }
883
+ .fl-picker-search::placeholder { color: var(--vendo-fg-muted); }
884
+ .fl-picker-group { font: 600 10.5px/1 var(--vendo-font); letter-spacing: .05em; text-transform: uppercase;
885
+ color: var(--vendo-fg-muted); margin: 16px 2px 9px; }
886
+ .fl-picker-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; padding: 0; }
887
+ .fl-picker-item { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border-radius: 11px;
888
+ border: 1px solid var(--vendo-border); background: var(--vendo-surface); transition: transform .12s, border-color .12s, box-shadow .12s; }
889
+ .fl-picker-item:hover { transform: translateY(-1px); border-color: var(--vendo-border-strong); box-shadow: var(--vendo-shadow); }
890
+ .fl-picker-item.is-connected { background: color-mix(in srgb, var(--vendo-ok) 9%, var(--vendo-surface));
891
+ border-color: color-mix(in srgb, var(--vendo-ok) 26%, var(--vendo-border));
892
+ transition: transform .12s, border-color .35s cubic-bezier(.22,1,.36,1), box-shadow .12s, background .35s cubic-bezier(.22,1,.36,1); }
893
+ /* OAuth in flight: the + hands the status slot to a mini metaball loader. */
894
+ .fl-picker-connecting { display: inline-flex; align-items: center; color: var(--vendo-fg-muted);
895
+ min-width: 19px; justify-content: center; }
896
+ .fl-picker-connecting .fl-typing span { width: 4px; height: 4px; }
897
+ /* Observed connect: the green wash blooms in and the dot lands with a soft
898
+ ripple ring — a one-shot celebration; reopens render is-connected plain. */
899
+ .fl-picker-item.is-just-connected { animation: fl-connect-bloom .5s cubic-bezier(.22,1,.36,1) both; }
900
+ .fl-picker-item.is-just-connected .fl-picker-on { animation: fl-connect-pop .55s cubic-bezier(.22,1,.36,1) both; }
901
+ @keyframes fl-connect-bloom {
902
+ from { background: var(--vendo-surface); border-color: var(--vendo-border); }
903
+ to { background: color-mix(in srgb, var(--vendo-ok) 9%, var(--vendo-surface));
904
+ border-color: color-mix(in srgb, var(--vendo-ok) 26%, var(--vendo-border)); } }
905
+ @keyframes fl-connect-pop {
906
+ 0% { transform: scale(0); box-shadow: 0 0 0 0 color-mix(in srgb, var(--vendo-ok) 45%, transparent); }
907
+ 55% { transform: scale(1.35); }
908
+ 80% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--vendo-ok) 0%, transparent); }
909
+ 100% { transform: scale(1); box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-ok) 16%, transparent); } }
910
+ .fl-picker-ic { width: 24px; height: 24px; border-radius: 7px; display: grid; place-items: center; flex-shrink: 0;
911
+ background: var(--vendo-surface); border: 1px solid var(--vendo-border); font-size: 11px; font-weight: 700; }
912
+ .fl-picker-nm { font-size: 12.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
913
+ .fl-picker-status { margin-left: auto; flex-shrink: 0; }
914
+ .fl-picker-on { width: 7px; height: 7px; border-radius: 50%; background: var(--vendo-ok);
915
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-ok) 16%, transparent); }
916
+ .fl-picker-add { width: 19px; height: 19px; border-radius: 50%; border: 1px solid var(--vendo-border-strong);
917
+ display: grid; place-items: center; font-size: 13px; line-height: 1; color: var(--vendo-fg-muted); background: transparent; cursor: pointer; }
918
+ .fl-picker-item:hover .fl-picker-add { background: var(--vendo-accent); color: var(--vendo-accent-fg); border-color: var(--vendo-accent); }
919
+
920
+ /* ---------- in-conversation connect prompt ---------- */
921
+ /* Compact post-connect confirmation: a quiet status pill, not a display card. */
922
+ .fl-connect-done { display: inline-flex; align-items: center; gap: 9px; align-self: flex-start;
923
+ border: 1px solid var(--vendo-border); border-radius: 999px; padding: 7px 14px 7px 9px;
924
+ background: var(--vendo-surface); font-size: 12.5px; font-weight: 550; }
925
+ .fl-connect-done-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--vendo-ok);
926
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-ok) 18%, transparent); }
927
+ .fl-connect { border: 1px solid var(--vendo-border-strong); border-radius: var(--vendo-radius-lg);
928
+ padding: var(--vendo-density-card-padding); background: var(--vendo-glass-strong);
929
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
930
+ box-shadow: var(--vendo-shadow); max-width: 100%; align-self: flex-start; width: 100%; }
931
+ .fl-connect-head { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 13.5px; }
932
+ .fl-connect-ic { width: 30px; height: 30px; border-radius: 8px; background: var(--vendo-surface);
933
+ border: 1px solid var(--vendo-border); display: grid; place-items: center; }
934
+
935
+ /* ---------- automation card ---------- */
936
+ .fl-automation { align-self: flex-start; width: 100%; border-radius: var(--vendo-radius); overflow: hidden;
937
+ border: 1px solid var(--vendo-border); background: var(--vendo-glass-strong);
938
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur); box-shadow: var(--vendo-shadow); }
939
+ .fl-auto-head { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
940
+ .fl-auto-ic { width: 34px; height: 34px; border-radius: 10px; background: var(--vendo-accent);
941
+ color: var(--vendo-accent-fg); display: grid; place-items: center; flex-shrink: 0; }
942
+ .fl-auto-title { font-weight: 600; font-size: 14px; letter-spacing: -.01em; }
943
+ .fl-auto-sub { font-size: 11.5px; color: var(--vendo-fg-muted); margin-top: 2px; display: flex; align-items: center; gap: 6px; }
944
+ .fl-auto-live { width: 6px; height: 6px; border-radius: 50%; background: var(--vendo-ok);
945
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-ok) 16%, transparent); }
946
+ .fl-auto-toggle { margin-left: auto; width: 40px; height: 23px; border-radius: 999px; background: var(--vendo-accent);
947
+ position: relative; flex-shrink: 0; border: 0; cursor: pointer; }
948
+ .fl-auto-toggle::after { content: ""; position: absolute; top: 2.5px; right: 2.5px; width: 18px; height: 18px;
949
+ border-radius: 50%; background: var(--vendo-accent-fg); box-shadow: 0 1px 3px rgba(0,0,0,.22); }
950
+ .fl-auto-flow { display: flex; align-items: center; padding: 14px 16px 16px; border-top: 1px solid var(--vendo-border); }
951
+ .fl-auto-node { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 12px;
952
+ background: var(--vendo-bg); border: 1px solid var(--vendo-border); }
953
+ .fl-auto-node-ic { width: 24px; height: 24px; border-radius: 7px; display: grid; place-items: center;
954
+ background: var(--vendo-surface); border: 1px solid var(--vendo-border); }
955
+ .fl-auto-node-t { font-size: 12.5px; font-weight: 600; line-height: 1.2; }
956
+ .fl-auto-node-s { font-size: 11px; color: var(--vendo-fg-muted); margin-top: 1px; }
957
+ .fl-auto-arrow { flex: 1; min-width: 20px; height: 0; border-top: 1.5px dashed var(--vendo-border-strong);
958
+ margin: 0 8px; position: relative; }
959
+ .fl-auto-arrow::after { content: ""; position: absolute; right: -1px; top: -4px; width: 7px; height: 7px;
960
+ border-top: 1.5px solid var(--vendo-border-strong); border-right: 1.5px solid var(--vendo-border-strong); transform: rotate(45deg); }
961
+
962
+ /* ---------- overlay (clipping fixed: bounded height, scrolls) ---------- */
963
+ /* Portal wrapper: provides theme vars to the modal without generating a box. */
964
+ .fl-overlay-portal { display: contents; }
965
+ .fl-overlay-scrim { position: fixed; inset: 0; background: color-mix(in srgb, var(--vendo-fg) 22%, transparent);
966
+ -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); z-index: 2147483000;
967
+ animation: fl-scrim-in .2s ease both; }
968
+ .fl-overlay-panel { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 2147483001;
969
+ width: min(620px, 94vw); height: min(680px, 86vh); display: flex; flex-direction: column;
970
+ background: var(--vendo-glass); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
971
+ border: 1px solid var(--vendo-border-strong); border-radius: var(--vendo-radius-lg); overflow: hidden;
972
+ box-shadow: 0 30px 80px color-mix(in srgb, var(--vendo-fg) 28%, transparent);
973
+ /* open animation — the "squeeze": a horizontal stretch out from a sliver, with a
974
+ springy overshoot. transform-origin stays centered so it grows symmetrically. */
975
+ transform-origin: center; animation: fl-overlay-stretch .5s cubic-bezier(.22, 1.2, .36, 1) both; }
976
+ .fl-overlay-close { position: absolute; top: 12px; right: 12px; z-index: 5; width: 28px; height: 28px;
977
+ border-radius: 9px; display: grid; place-items: center; border: 0; background: transparent;
978
+ color: var(--vendo-fg-muted); cursor: pointer; transition: background .12s, color .12s; }
979
+ .fl-overlay-close:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
980
+ /* ENG-221: new-conversation sits just left of the close X — same quiet header
981
+ treatment (it shares .fl-overlay-close), only the horizontal offset differs.
982
+ Offsets = close's right + close's width + a 6px gap, per pointer density. */
983
+ .fl-overlay-new { right: 46px; }
984
+ /* Compact when empty (ui-lane-entry pick P-C): while the thread shows its
985
+ landing (no conversation yet), the panel is a small box — greeting, command
986
+ chips, composer, no dead glass — and animates to full height the moment the
987
+ first turn lands (the landing swaps to the message list, :has stops
988
+ matching). Browsers without :has() simply keep the full-size panel. */
989
+ .fl-overlay-panel { transition: height .45s cubic-bezier(.22, 1, .36, 1); }
990
+ .fl-overlay-panel:has(.fl-landing) { height: min(360px, 80vh); }
991
+ .fl-overlay-panel:has(.fl-landing) .fl-landing { padding-top: 34px; }
992
+ @keyframes fl-scrim-in { from { opacity: 0; } to { opacity: 1; } }
993
+ @keyframes fl-overlay-stretch {
994
+ from { transform: translate(-50%, -50%) scaleX(.06) scaleY(.7); opacity: .4; }
995
+ 60% { opacity: 1; }
996
+ to { transform: translate(-50%, -50%) scaleX(1) scaleY(1); opacity: 1; } }
997
+ @media (prefers-reduced-motion: reduce) {
998
+ .fl-overlay-panel { animation: fl-overlay-fade .18s ease both; }
999
+ @keyframes fl-overlay-fade { from { opacity: 0; } to { opacity: 1; } }
1000
+ /* Silence every looping loader for vestibular-sensitive users. */
1001
+ .fl-caret, .fl-md--streaming > :last-child::after { animation: none; opacity: 1; }
1002
+ .fl-typing span, .fl-generating .fl-pulse, .fl-skeleton-bar,
1003
+ .fl-tool-spin, .fl-tool-spinner, .fl-act-pulse, .fl-act-spin,
1004
+ .fl-auto-created-live::after { animation: none; }
1005
+ /* Glass skeleton: the sweep and pulse freeze; the blocks stay tinted. */
1006
+ .fl-glass-shimmer, .fl-glass-dot { animation: none; }
1007
+ .fl-picker-item.is-just-connected, .fl-picker-item.is-just-connected .fl-picker-on { animation: none; }
1008
+ .fl-msglist-wrap, .fl-jump, .fl-md--streaming > * { animation: none; opacity: 1; }
1009
+ /* The launcher blob rests as a plain circle; the panel resize snaps. */
1010
+ .fl-launcher-blob { animation: none; border-radius: 50%; }
1011
+ .fl-overlay-panel { transition: none; }
1012
+ }
1013
+
1014
+ /* ---------- full-screen mobile takeover (<768px, Intercom pattern) ---------- */
1015
+ /* The \`fl-takeover\` class is stamped by useMobileTakeover (matchMedia) on the
1016
+ surface containers — the overlay panel (the Cmd+K overlay AND the slot's
1017
+ design overlay share OverlayPanel) and the page element. Full bleed, its own
1018
+ stacking context, internal scrolling (only .fl-msglist scrolls), the
1019
+ composer pinned at the bottom inside the safe area, the close X reachable
1020
+ under the notch. Host layout below the breakpoint is covered, not fixed. */
1021
+ .fl-overlay-panel.fl-takeover { left: 0; top: 0; transform: none;
1022
+ width: 100%; height: 100%; max-width: none; max-height: none;
1023
+ border: 0; border-radius: 0; isolation: isolate;
1024
+ padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px)
1025
+ env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
1026
+ /* --fl-kb-inset is stamped by useMobileTakeover from visualViewport: the
1027
+ bottom edge (the composer) lifts above the virtual keyboard. */
1028
+ padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--fl-kb-inset, 0px));
1029
+ /* The centered "squeeze" keyframes carry translate(-50%,-50%) — full bleed
1030
+ fades in instead of flying in from mid-screen. */
1031
+ animation: fl-takeover-fade .18s ease both; }
1032
+ @keyframes fl-takeover-fade { from { opacity: 0; } to { opacity: 1; } }
1033
+ .fl-overlay-panel.fl-takeover .fl-overlay-close {
1034
+ top: calc(12px + env(safe-area-inset-top, 0px));
1035
+ right: calc(12px + env(safe-area-inset-right, 0px)); }
1036
+ .fl-overlay-panel.fl-takeover .fl-overlay-new {
1037
+ right: calc(46px + env(safe-area-inset-right, 0px)); }
1038
+ /* Mobile mirror of compact-when-empty: the takeover starts as a bottom sheet
1039
+ (host page visible behind the scrim) and becomes the full-bleed takeover
1040
+ once a conversation is running. */
1041
+ .fl-overlay-panel.fl-takeover:has(.fl-landing) { top: auto; bottom: 0; height: auto; max-height: 62%;
1042
+ border-top: 1px solid var(--vendo-border-strong);
1043
+ border-radius: var(--vendo-radius-lg) var(--vendo-radius-lg) 0 0; }
1044
+ .fl-overlay-panel.fl-takeover:has(.fl-landing) .fl-landing { padding-top: 18px; }
1045
+ .fl-page.fl-takeover { position: fixed; inset: 0; z-index: 2147483001; isolation: isolate;
1046
+ background: var(--vendo-bg);
1047
+ padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px)
1048
+ env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
1049
+ padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--fl-kb-inset, 0px)); }
1050
+ /* The palette is a modal over EVERY takeover surface: its scrim (2147483000)
1051
+ would otherwise sit under a takeover page/overlay panel (2147483001). */
1052
+ .fl-overlay-scrim.fl-takeover { z-index: 2147483002; }
1053
+
1054
+ /* ---------- mobile input + touch ergonomics (ENG-228) ---------- */
1055
+ /* iOS Safari auto-zooms any focused text input under 16px, and 44px is the
1056
+ HIG touch-target floor. Keyed to small viewports OR coarse pointers so
1057
+ tablets in wide orientations still get honest targets; desktop keeps the
1058
+ quieter 15px/34px design. */
1059
+ @media (max-width: 767px), (pointer: coarse) {
1060
+ .fl-composer textarea { font-size: 16px; }
1061
+ .fl-picker-search { font-size: 16px; }
1062
+ .fl-icon-btn { width: 44px; height: 44px; }
1063
+ .fl-jump { width: 44px; height: 44px; }
1064
+ .fl-overlay-close { width: 44px; height: 44px; }
1065
+ .fl-overlay-new { right: 62px; }
1066
+ .fl-cmd-chip { min-height: 38px; }
1067
+ .fl-invite-chip { width: 100%; min-height: 44px; justify-content: center; display: inline-flex; align-items: center; }
1068
+ .fl-invite-chips { align-self: stretch; align-items: stretch; max-width: none; padding: 0 8px; }
1069
+ /* The grown close button keeps its visual position under the notch. */
1070
+ .fl-overlay-panel.fl-takeover .fl-overlay-close {
1071
+ top: calc(4px + env(safe-area-inset-top, 0px));
1072
+ right: calc(4px + env(safe-area-inset-right, 0px)); }
1073
+ .fl-overlay-panel.fl-takeover .fl-overlay-new {
1074
+ right: calc(54px + env(safe-area-inset-right, 0px)); }
1075
+ }
1076
+
1077
+ /* ---------- conversation command strip (one-surface \u2318K, pick P-C) ---------- */
1078
+ /* The palette's commands, rendered by the overlay as chips pinned above the
1079
+ composer. Anything typed that matches no chip is simply the message. */
1080
+ .fl-cmdstrip { display: flex; gap: 7px; padding: 0 14px 9px; overflow-x: auto;
1081
+ scrollbar-width: none; flex-shrink: 0; }
1082
+ .fl-cmdstrip::-webkit-scrollbar { display: none; }
1083
+ .fl-landing .fl-cmdstrip { padding: 0 0 4px; flex-wrap: wrap; justify-content: center; overflow: visible; }
1084
+ .fl-cmd-chip { display: inline-flex; align-items: center; gap: 6px; flex: none;
1085
+ border: 1px solid var(--vendo-border); border-radius: 999px; padding: 7px 12px;
1086
+ background: var(--vendo-surface); font: 500 12px/1 var(--vendo-font); color: var(--vendo-fg-muted);
1087
+ cursor: pointer; transition: color .12s, border-color .12s, transform .12s; }
1088
+ .fl-cmd-chip:hover { color: var(--vendo-fg); border-color: var(--vendo-border-strong); transform: translateY(-1px); }
1089
+ .fl-cmd-chip:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1090
+ .fl-cmd-chip svg { flex: none; }
1091
+
1092
+ .fl-launcher { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--vendo-border);
1093
+ border-radius: 999px; padding: 10px 15px; font-size: 13px; font-weight: 600; color: var(--vendo-fg);
1094
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1095
+ box-shadow: var(--vendo-shadow); cursor: pointer; }
1096
+ /* ENG-220: the supported overlay entry — VendoOverlay's default launcher is a
1097
+ fixed brand pill pinned to a viewport corner (safe-area aware). z-index sits
1098
+ one below the scrim so the open overlay covers it. Placement variants keyed
1099
+ off data-vendo-launcher so bare .fl-launcher keeps its in-flow behavior. */
1100
+ .fl-launcher[data-vendo-launcher="bottom-right"], .fl-launcher[data-vendo-launcher="bottom-left"] {
1101
+ position: fixed; bottom: calc(20px + env(safe-area-inset-bottom, 0px)); z-index: 2147482999; }
1102
+ .fl-launcher[data-vendo-launcher="bottom-right"] { right: calc(20px + env(safe-area-inset-right, 0px)); }
1103
+ .fl-launcher[data-vendo-launcher="bottom-left"] { left: calc(20px + env(safe-area-inset-left, 0px)); }
1104
+
1105
+ /* The launcher mark (ui-lane-entry pick L-B): an accent-colored blob that
1106
+ continuously morphs shape — the recognition cue, in place of any glyph or
1107
+ product name. Quickens on hover; a static circle under reduced motion. */
1108
+ .fl-launcher-blob { width: 20px; height: 20px; flex: none; background: var(--vendo-accent);
1109
+ animation: fl-blob-morph 7s ease-in-out infinite; }
1110
+ .fl-launcher:hover .fl-launcher-blob { animation-duration: 2.4s; }
1111
+ @keyframes fl-blob-morph {
1112
+ 0%, 100% { border-radius: 58% 42% 55% 45% / 48% 55% 45% 52%; transform: rotate(0deg) scale(1); }
1113
+ 25% { border-radius: 45% 55% 48% 52% / 58% 42% 58% 42%; transform: rotate(12deg) scale(1.05); }
1114
+ 50% { border-radius: 52% 48% 42% 58% / 45% 52% 48% 55%; transform: rotate(-8deg) scale(.96); }
1115
+ 75% { border-radius: 42% 58% 55% 45% / 52% 48% 55% 45%; transform: rotate(6deg) scale(1.03); } }
1116
+ /* Blob-only orb: the host cleared the label (launcher.label: null). */
1117
+ .fl-launcher[data-vendo-launcher-bare] { padding: 11px; gap: 0; border-radius: 50%; }
1118
+
1119
+ /* The whisper (ui-usage-dx §6): first eligible visit only — one gentle pulse
1120
+ on the pill plus a small ~6s caption. The pulse is motion-gated (reduced
1121
+ motion keeps the caption, drops the pulse); fire-once is enforced in JS. */
1122
+ @media (prefers-reduced-motion: no-preference) {
1123
+ .fl-launcher[data-vendo-whisper] { animation: fl-whisper-pulse 1.8s ease-out .5s 1 both; }
1124
+ .fl-whisper { animation: fl-whisper-in .4s ease-out both; }
1125
+ }
1126
+ @keyframes fl-whisper-pulse {
1127
+ 0% { box-shadow: var(--vendo-shadow), 0 0 0 0 color-mix(in srgb, var(--vendo-accent) 45%, transparent); }
1128
+ 70% { box-shadow: var(--vendo-shadow), 0 0 0 14px color-mix(in srgb, var(--vendo-accent) 0%, transparent); }
1129
+ 100% { box-shadow: var(--vendo-shadow), 0 0 0 0 transparent; }
1130
+ }
1131
+ @keyframes fl-whisper-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
1132
+ .fl-whisper { display: flex; flex-direction: column; gap: 3px; max-width: 250px; padding: 11px 14px;
1133
+ border: 1px solid var(--vendo-border); border-radius: 14px; background: var(--vendo-glass-strong);
1134
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1135
+ box-shadow: var(--vendo-shadow); font-size: 12.5px; line-height: 1.45; }
1136
+ .fl-whisper strong { font-weight: 600; font-size: 13px; color: var(--vendo-fg); }
1137
+ .fl-whisper span { color: var(--vendo-fg-muted); }
1138
+ /* Fixed variants sit just above the pill, matching its corner. */
1139
+ .fl-whisper[data-vendo-launcher="bottom-right"], .fl-whisper[data-vendo-launcher="bottom-left"] {
1140
+ position: fixed; bottom: calc(72px + env(safe-area-inset-bottom, 0px)); z-index: 2147482999; }
1141
+ .fl-whisper[data-vendo-launcher="bottom-right"] { right: calc(20px + env(safe-area-inset-right, 0px)); }
1142
+ .fl-whisper[data-vendo-launcher="bottom-left"] { left: calc(20px + env(safe-area-inset-left, 0px)); }
1143
+
1144
+ /* ---------- page + tabs + slot ---------- */
1145
+ /* The Page surface is ingrained: the chat IS the page (no card-in-card). Tabs are
1146
+ a quiet underline row, the body fills the height, only the message list scrolls. */
1147
+ .fl-page { display: flex; flex-direction: column; height: 100%; min-height: 0; }
1148
+ .fl-page > [hidden] { display: none; }
1149
+ .fl-tabbar { display: flex; align-items: center; gap: 2px; padding: 0 0 0 2px;
1150
+ border-bottom: 1px solid var(--vendo-border); flex-shrink: 0; overflow-x: auto; scrollbar-width: none; }
1151
+ .fl-tabbar::-webkit-scrollbar { display: none; }
1152
+ .fl-tab { display: flex; align-items: center; gap: 7px; padding: 10px 13px; font-size: 12.5px; font-weight: 500;
1153
+ color: var(--vendo-fg-muted); border: 0; border-bottom: 2px solid transparent; background: transparent;
1154
+ cursor: pointer; white-space: nowrap; margin-bottom: -1px; transition: color .12s; }
1155
+ .fl-tab:hover { color: var(--vendo-fg); }
1156
+ .fl-tab[aria-selected="true"] { color: var(--vendo-fg); border-bottom-color: var(--vendo-accent); }
1157
+ .fl-tab-new { color: var(--vendo-fg-muted); font-size: 16px; line-height: 1; padding: 8px 11px; }
1158
+ /* Body region below the tabs — the only thing that scrolls is the inner message list. */
1159
+ .fl-page-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
1160
+ .fl-page-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; }
1161
+ .fl-page-pane[hidden] { display: none; }
1162
+ .fl-slot-empty { border: 1.5px dashed var(--vendo-border-strong); border-radius: var(--vendo-radius-lg);
1163
+ display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px;
1164
+ padding: 24px; cursor: pointer; background: var(--vendo-glass-strong); color: var(--vendo-fg-muted);
1165
+ width: 100%; transition: border-color .12s, color .12s; }
1166
+ .fl-slot-empty:hover { border-color: var(--vendo-accent); color: var(--vendo-fg); }
1167
+ /* Trust screen mounted as a docked side panel beside the page chrome (ENG-193
1168
+ §3 Moment 12) — the accounting demo's own overlay, not a portal (unlike
1169
+ VendoOverlay's Cmd+K palette, which escapes the host's stacking context
1170
+ entirely and so needs the near-max z-index above); this only needs to sit
1171
+ above the page it's mounted inside. */
1172
+ .fl-trust-overlay { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, .28);
1173
+ display: flex; justify-content: flex-end; }
1174
+ .fl-trust-overlay > div { width: min(420px, 92vw); height: 100%; background: var(--vendo-bg);
1175
+ box-shadow: -8px 0 24px rgba(0, 0, 0, .12); }
1176
+
1177
+ /* ---------- generative dashboard slot (vendo-slot) ---------- */
1178
+ .fl-slot { position: relative; width: 100%; min-height: var(--fl-slot-min-h, 370px);
1179
+ display: flex; flex-direction: column; }
1180
+
1181
+ /* ---- ghost (empty) state: faint skeleton behind a CTA ---- */
1182
+ .fl-slot-ghost { position: relative; width: 100%; flex: 1; display: flex; flex-direction: column;
1183
+ cursor: pointer; overflow: hidden;
1184
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius); padding: 14px;
1185
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1186
+ color: var(--vendo-fg-muted); text-align: left; transition: border-color .14s, box-shadow .14s; }
1187
+ .fl-slot-ghost:hover { border-color: var(--vendo-border-strong); box-shadow: var(--vendo-shadow); }
1188
+ /* The empty-state ghost is a real button (ENG-223): strip the UA button chrome
1189
+ so it reads exactly like the div variant, and give the CTA a visible focus ring. */
1190
+ .fl-slot-ghost-cta { font: inherit; appearance: none; -webkit-appearance: none; }
1191
+ .fl-slot-ghost-cta:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1192
+ .fl-slot-skel { flex: 1; display: flex; flex-direction: column; gap: 8px; min-height: 118px;
1193
+ opacity: .5; filter: blur(.3px); -webkit-mask-image: linear-gradient(180deg, #000 30%, transparent);
1194
+ mask-image: linear-gradient(180deg, #000 30%, transparent); }
1195
+ .fl-skel-line { height: 9px; border-radius: 5px;
1196
+ background: color-mix(in srgb, var(--vendo-fg) 9%, transparent); }
1197
+ .fl-skel-bars { display: flex; align-items: flex-end; gap: 6px; height: 52px; margin-top: auto; }
1198
+ .fl-skel-bars span { flex: 1; border-radius: 3px;
1199
+ background: color-mix(in srgb, var(--vendo-fg) 12%, transparent); }
1200
+ .fl-slot-cta { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
1201
+ justify-content: center; gap: 4px; font-size: 13px; font-weight: 600; color: var(--vendo-fg);
1202
+ background: color-mix(in srgb, var(--vendo-bg) 30%, transparent); transition: background .14s; }
1203
+ .fl-slot-ghost:hover .fl-slot-cta { background: color-mix(in srgb, var(--vendo-bg) 16%, transparent); }
1204
+ .fl-slot-cta svg { margin-bottom: 2px; opacity: .85; }
1205
+ .fl-slot-cta small { font-weight: 400; font-size: 11.5px; color: var(--vendo-fg-muted); }
1206
+
1207
+ /* ---- empty-state invitation (ui-lane-entry pick S-A\u00d7S-D) ----
1208
+ Accent-washed surface carrying real copy, up to three concrete suggestion
1209
+ chips, and a primary CTA. The skeleton stays faintly behind (a view goes
1210
+ here); no icon by default. */
1211
+ .fl-slot-invite { cursor: default;
1212
+ border-color: color-mix(in srgb, var(--vendo-accent) 22%, var(--vendo-border));
1213
+ background: linear-gradient(155deg, color-mix(in srgb, var(--vendo-accent) 7%, var(--vendo-surface)),
1214
+ color-mix(in srgb, var(--vendo-accent) 2%, var(--vendo-surface)) 55%); }
1215
+ .fl-slot-invite:hover { border-color: color-mix(in srgb, var(--vendo-accent) 40%, var(--vendo-border)); }
1216
+ .fl-slot-invite .fl-slot-skel { opacity: .35; }
1217
+ .fl-slot-invite .fl-slot-cta { gap: 8px; background: none; cursor: default; }
1218
+ .fl-invite-mark { width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center;
1219
+ color: var(--vendo-fg); opacity: .85; }
1220
+ .fl-invite-mark-tile { background: var(--vendo-accent); color: var(--vendo-accent-fg);
1221
+ opacity: 1; box-shadow: var(--vendo-shadow); }
1222
+ .fl-invite-title { font: 600 14px/1 var(--vendo-font); color: var(--vendo-fg); }
1223
+ .fl-invite-sub { font-weight: 400; font-size: 11.5px; color: var(--vendo-fg-muted); text-align: center;
1224
+ max-width: 82%; line-height: 1.4; }
1225
+ .fl-invite-try { font: 600 10.5px/1 var(--vendo-font); letter-spacing: .05em; text-transform: uppercase;
1226
+ color: var(--vendo-fg-muted); margin-top: 2px; }
1227
+ .fl-invite-chips { display: flex; flex-direction: column; gap: 7px; align-items: center; max-width: 92%; }
1228
+ .fl-invite-chip { border: 1px solid var(--vendo-border); border-radius: 999px; padding: 8px 14px;
1229
+ background: var(--vendo-surface); font: 500 12px/1.2 var(--vendo-font); color: var(--vendo-fg);
1230
+ cursor: pointer; box-shadow: var(--vendo-shadow); transition: border-color .12s, transform .12s; }
1231
+ .fl-invite-chip:hover { border-color: color-mix(in srgb, var(--vendo-accent) 40%, var(--vendo-border));
1232
+ transform: translateY(-1px); }
1233
+ .fl-invite-chip:focus-visible, .fl-invite-btn:focus-visible, .fl-invite-own:focus-visible {
1234
+ outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1235
+ .fl-invite-btn { margin-top: 6px; display: inline-flex; align-items: center; gap: 7px; border: 0;
1236
+ border-radius: 9px; padding: 9px 16px; background: var(--vendo-accent); color: var(--vendo-accent-fg);
1237
+ font: 600 12.5px/1 var(--vendo-font); cursor: pointer; box-shadow: var(--vendo-shadow);
1238
+ transition: opacity .14s, transform .14s; }
1239
+ .fl-invite-btn:hover { opacity: .9; transform: translateY(-1px); }
1240
+ .fl-invite-own { margin-top: 4px; border: 0; background: transparent; cursor: pointer;
1241
+ font: 500 11.5px/1 var(--vendo-font); color: var(--vendo-fg-muted);
1242
+ text-decoration: underline; text-underline-offset: 3px; }
1243
+ .fl-invite-own:hover { color: var(--vendo-fg); }
1244
+
1245
+ /* ---- remix affordance (ui-usage-dx §2 — remix folds into Slot as a flag) ----
1246
+ Hover-revealed over the slot's content: the filled state (.fl-slot) and the
1247
+ host-original state (the [data-vendo-slot] inline wrapper) share one rule.
1248
+ Focus reveals it too, so it stays keyboard-reachable. */
1249
+ .fl-slot-remix { position: absolute; top: 10px; right: 10px; z-index: 6;
1250
+ display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px;
1251
+ border: 1px solid var(--vendo-border); border-radius: 9px;
1252
+ background: color-mix(in srgb, var(--vendo-surface) 92%, transparent);
1253
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1254
+ color: var(--vendo-fg-muted); font: 600 11.5px/1 var(--vendo-font-family);
1255
+ box-shadow: var(--vendo-shadow); cursor: pointer;
1256
+ opacity: 0; pointer-events: none; transition: opacity .15s, color .15s; }
1257
+ [data-vendo-slot]:hover .fl-slot-remix, .fl-slot-remix:focus-visible { opacity: 1; pointer-events: auto; }
1258
+ .fl-slot-remix:hover { color: var(--vendo-fg); }
1259
+ .fl-slot-remix:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1260
+
1261
+ /* ---- filled state + overflow menu ---- */
1262
+ .fl-slot-filled { position: relative; flex: 1; }
1263
+ .fl-slot-filled > .fl-uinode { height: 100%; }
1264
+ .fl-slot-menu-wrap { position: absolute; top: 8px; right: 8px; }
1265
+ .fl-slot-menu-btn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
1266
+ border-radius: 8px; border: 1px solid transparent; background: transparent; color: var(--vendo-fg-muted);
1267
+ cursor: pointer; opacity: 0; transition: opacity .14s, background .14s, color .14s; }
1268
+ .fl-slot-filled:hover .fl-slot-menu-btn, .fl-slot-menu-btn[aria-expanded="true"] { opacity: 1; }
1269
+ .fl-slot-menu-btn:hover, .fl-slot-menu-btn[aria-expanded="true"] {
1270
+ background: var(--vendo-glass-strong); border-color: var(--vendo-border); color: var(--vendo-fg); }
1271
+ .fl-slot-menu { position: absolute; top: 34px; right: 0; z-index: 5; min-width: 132px; padding: 5px;
1272
+ display: flex; flex-direction: column; border: 1px solid var(--vendo-border-strong); border-radius: 12px;
1273
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1274
+ box-shadow: var(--vendo-shadow); }
1275
+ .fl-slot-menu button { text-align: left; font-size: 12.5px; padding: 7px 9px; border: 0; border-radius: 8px;
1276
+ background: transparent; color: var(--vendo-fg); cursor: pointer; }
1277
+ .fl-slot-menu button:hover { background: var(--vendo-accent-soft); }
1278
+ .fl-slot-menu button.is-danger { color: var(--vendo-danger); }
1279
+
1280
+ /* ---- pin-to-card footer (slot overlay only) ---- */
1281
+ .fl-pinbar { display: flex; align-items: center; gap: 10px; padding: 8px 14px 0; }
1282
+ .fl-pin-btn { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600;
1283
+ padding: 8px 13px; border-radius: 10px; border: 1px solid transparent; cursor: pointer;
1284
+ background: var(--vendo-accent); color: var(--vendo-accent-fg); transition: opacity .14s; }
1285
+ .fl-pin-btn:not(:disabled):hover { opacity: .88; }
1286
+ .fl-pin-btn:disabled { cursor: default; background: var(--vendo-surface);
1287
+ color: var(--vendo-fg-muted); border-color: var(--vendo-border); }
1288
+ .fl-pinbar-hint { font-size: 11.5px; color: var(--vendo-fg-muted); }
1289
+
1290
+ /* ---------- error ---------- */
1291
+ .fl-error { margin: 8px 16px; padding: 10px 13px; border-radius: 12px;
1292
+ border: 1px solid var(--vendo-danger-border); background: var(--vendo-danger-bg);
1293
+ color: var(--vendo-danger); font-size: 12.5px;
1294
+ display: flex; align-items: center; gap: 10px; }
1295
+ .fl-error-retry { margin-left: auto; flex-shrink: 0; padding: 4px 11px; border-radius: 8px;
1296
+ border: 1px solid var(--vendo-danger-border); background: transparent;
1297
+ color: var(--vendo-danger); font: 600 12px/1.2 var(--vendo-font); cursor: pointer; }
1298
+ /* Hover fill: page-bg text reads on the danger fill in light; on a dark theme
1299
+ the page bg is near-black on red, so the dark branch pins white (ENG-226). */
1300
+ .fl-error-retry:hover { background: var(--vendo-danger); color: light-dark(var(--vendo-bg, #fff), #fff); }
1301
+
1302
+ /* ---------- Trust screen (ENG-193 §3 Moment 12) ---------- */
1303
+ .fl-trust { display: flex; flex-direction: column; gap: 16px; padding: 16px; overflow-y: auto;
1304
+ background: var(--vendo-bg); color: var(--vendo-fg); font-family: var(--vendo-font); }
1305
+ .fl-trust-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
1306
+ .fl-trust-title { font-size: 14px; font-weight: 600; line-height: 1.4; }
1307
+ .fl-trust-close { border: none; background: transparent; font-size: 20px; line-height: 1; cursor: pointer;
1308
+ color: var(--vendo-fg-muted); }
1309
+ .fl-trust-section { display: flex; flex-direction: column; gap: 8px; }
1310
+ .fl-trust-section-head { font: 600 11px/1 var(--vendo-font); letter-spacing: .04em; text-transform: uppercase;
1311
+ color: var(--vendo-fg-muted); margin: 0; }
1312
+ .fl-trust-empty { font-size: 12.5px; color: var(--vendo-fg-muted); }
1313
+ .fl-trust-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
1314
+ padding: 8px 0; border-top: 1px solid var(--vendo-border); }
1315
+ .fl-trust-row:first-of-type { border-top: none; }
1316
+ .fl-trust-row-title { font: 600 13px/1.3 var(--vendo-font); }
1317
+ .fl-trust-row-meta { margin-top: 2px; font-size: 11px; color: var(--vendo-fg-muted); }
1318
+ .fl-trust-critical { font-size: 12.5px; color: var(--vendo-fg-muted); }
1319
+ .fl-trust-diary { font-size: 13px; line-height: 1.5; padding: 10px 12px; border-radius: 10px;
1320
+ background: var(--vendo-accent-soft); }
1321
+ .fl-trust-activity { display: flex; flex-direction: column; gap: 4px; max-height: 220px; overflow-y: auto; }
1322
+ .fl-trust-activity-row { display: flex; gap: 8px; font-size: 12px; color: var(--vendo-fg-muted); }
1323
+ .fl-trust-activity-time { flex-shrink: 0; width: 48px; }
1324
+
1325
+ /* ---------- VendoToasts (2026-07-04): automation delivery surface ---------- */
1326
+ .fl-toasts { position: fixed; z-index: 2147483100; display: flex; flex-direction: column; gap: 10px;
1327
+ width: min(340px, calc(100vw - 32px)); font-family: var(--vendo-font); }
1328
+ .fl-toasts[data-placement="bottom-right"] { right: 18px; bottom: 18px; }
1329
+ .fl-toasts[data-placement="bottom-left"] { left: 18px; bottom: 18px; }
1330
+ .fl-toasts[data-placement="top-right"] { right: 18px; top: 18px; }
1331
+ .fl-toasts-card { display: flex; gap: 9px; align-items: flex-start; padding: 11px 13px;
1332
+ border-radius: 13px; border: 1px solid var(--vendo-border); background: var(--vendo-surface);
1333
+ color: var(--vendo-fg); box-shadow: 0 10px 30px rgba(0,0,0,.16);
1334
+ animation: fl-toast-in .18s ease-out; }
1335
+ .fl-toasts-card[data-kind="approval-required"] { border-color: var(--vendo-warn-border); }
1336
+ .fl-toasts-card[data-state="error"] { border-color: var(--vendo-danger-border); }
1337
+ .fl-toasts-icon { color: var(--vendo-accent); font-size: 13px; line-height: 1.5; }
1338
+ .fl-toasts-card[data-kind="approval-required"] .fl-toasts-icon { color: var(--vendo-warn); }
1339
+ .fl-toasts-body { display: flex; flex-direction: column; gap: 7px; min-width: 0; flex: 1; }
1340
+ .fl-toasts-text { font-size: 12.5px; line-height: 1.45; }
1341
+ .fl-toasts-actions { display: flex; align-items: center; gap: 10px; }
1342
+ .fl-toasts-approve { border: 0; border-radius: 8px; padding: 5px 12px; cursor: pointer;
1343
+ background: var(--vendo-accent); color: var(--vendo-accent-fg);
1344
+ font: 600 12px/1.2 var(--vendo-font); }
1345
+ .fl-toasts-approve:hover { opacity: .88; }
1346
+ .fl-toasts-view { border: 0; background: none; padding: 0; cursor: pointer;
1347
+ color: var(--vendo-accent); font: 600 12px/1.2 var(--vendo-font); }
1348
+ .fl-toasts-view:hover { text-decoration: underline; }
1349
+ .fl-toasts-hint { font-size: 11.5px; color: var(--vendo-fg-muted); }
1350
+ .fl-toasts-dismiss { margin-left: auto; border: 0; background: none; padding: 0 2px; cursor: pointer;
1351
+ color: var(--vendo-fg-muted); font: 600 12px/1 var(--vendo-font); }
1352
+ .fl-toasts-dismiss:hover { color: var(--vendo-fg); }
1353
+ @keyframes fl-toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
1354
+ /* ---------- realtime voice stage (ENG-185) ---------- */
1355
+ /* The stage fills the surface that launched it. The blob head is pinned; the
1356
+ feed scrolls beneath it; the caption + footer stay anchored at the bottom. */
1357
+ .fl-voice-root { display: flex; flex-direction: column; height: 100%; min-height: 0; }
1358
+ .fl-voice-root > .fl-voice-stage { flex: 1; }
1359
+ .fl-voice-stage { position: relative; display: flex; flex-direction: column; height: 100%; min-height: 0;
1360
+ animation: fl-voice-rise .42s cubic-bezier(.22, 1, .36, 1) both; }
1361
+ @keyframes fl-voice-rise { from { opacity: 0; transform: translateY(18px) scale(.985); }
1362
+ to { opacity: 1; transform: none; } }
1363
+ .fl-voice-stage.is-leaving { animation: fl-voice-settle .5s ease both; }
1364
+ @keyframes fl-voice-settle { from { opacity: 1; transform: none; }
1365
+ to { opacity: 0; transform: translateY(14px) scale(.99); } }
1366
+
1367
+ /* Presence rests centered until the first view lands, then rises to the top.
1368
+ Grid rows [lift · head · feed]: the lift spacer animates 1fr → 0fr, carrying
1369
+ the head from vertical center up to the top as the feed opens beneath it. */
1370
+ .fl-voice-canvas { flex: 1; min-height: 0; display: grid;
1371
+ grid-template-rows: 1fr auto 1fr;
1372
+ transition: grid-template-rows .55s cubic-bezier(.22, 1, .36, 1); }
1373
+ .fl-voice-canvas.has-views { grid-template-rows: 0fr auto 1fr; }
1374
+ .fl-voice-lift { min-height: 0; }
1375
+ .fl-voice-head { display: flex; flex-direction: column; align-items: center; gap: 8px;
1376
+ padding: 18px 0 10px; flex-shrink: 0; }
1377
+ .fl-voice-blob { position: relative; display: grid; place-items: center; border-radius: 50%;
1378
+ color: var(--vendo-accent); transition: transform .12s ease; }
1379
+ .fl-voice-blob .fl-voice-disc { width: 46%; height: 46%; border-radius: 50%;
1380
+ background: var(--vendo-accent); transition: background .2s, opacity .2s; }
1381
+ .fl-voice-blob.is-muted .fl-voice-disc, .fl-voice-blob.is-error .fl-voice-disc { opacity: .38; }
1382
+ .fl-voice-blob.is-error .fl-voice-disc { background: var(--vendo-fg-muted); }
1383
+ .fl-voice-glyph { position: absolute; display: grid; place-items: center; color: var(--vendo-fg);
1384
+ opacity: .85; }
1385
+ .fl-voice-status { font: 500 12px/1 var(--vendo-font); color: var(--vendo-fg-muted);
1386
+ letter-spacing: .01em; min-height: 12px; }
1387
+ .fl-voice-stage.is-speaking .fl-voice-status { color: var(--vendo-fg); }
1388
+
1389
+ /* The scroll edges blur out: content dissolves under the blob and above the
1390
+ caption. A soft alpha mask on the scroller + frosted strips (backdrop blur,
1391
+ themselves mask-faded so the blur tapers instead of ending on a hard line). */
1392
+ .fl-voice-feedwrap { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
1393
+ .fl-voice-feedwrap::before, .fl-voice-feedwrap::after { content: ""; position: absolute; left: 0; right: 0;
1394
+ height: 40px; z-index: 1; pointer-events: none;
1395
+ -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
1396
+ .fl-voice-feedwrap::before { top: 0;
1397
+ -webkit-mask-image: linear-gradient(180deg, #000 30%, transparent);
1398
+ mask-image: linear-gradient(180deg, #000 30%, transparent); }
1399
+ .fl-voice-feedwrap::after { bottom: 0;
1400
+ -webkit-mask-image: linear-gradient(0deg, #000 30%, transparent);
1401
+ mask-image: linear-gradient(0deg, #000 30%, transparent); }
1402
+ /* An ACTUAL stage: each view is a full slide; scroll pages between slides
1403
+ (mandatory snap — one view owns the stage at rest, always). */
1404
+ .fl-voice-feed { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain;
1405
+ scroll-snap-type: y mandatory;
1406
+ display: flex; flex-direction: column; padding: 0 18px; scrollbar-width: none;
1407
+ -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 24px, #000 calc(100% - 22px), transparent);
1408
+ mask-image: linear-gradient(180deg, transparent 0, #000 24px, #000 calc(100% - 22px), transparent); }
1409
+ .fl-voice-feed::-webkit-scrollbar { display: none; }
1410
+ /* Slides are slightly shorter than the stage and snap to CENTER, so the
1411
+ neighbors peek in at the top/bottom edges — blurred, smaller, unmistakably
1412
+ "there's more" — and grow into the frame as they take focus. A too-tall
1413
+ view scrolls inside its card instead of hanging below the fold. */
1414
+ .fl-voice-slide { height: calc(100% - 84px); box-sizing: border-box; flex-shrink: 0;
1415
+ scroll-snap-align: center; scroll-snap-stop: always;
1416
+ display: flex; align-items: center; justify-content: center; padding: 4px 0;
1417
+ /* Off-stage: blurred, dimmed, visibly smaller; the focused one is crisp
1418
+ and whole. The transition IS the "animate into the frame" beat. */
1419
+ filter: blur(2.5px); opacity: .45; transform: scale(.78);
1420
+ transition: filter .45s ease, opacity .45s ease, transform .45s ease; }
1421
+ .fl-voice-slide.is-focus { filter: none; opacity: 1; transform: none; }
1422
+ /* Neighbors hug the boundary nearest the stage, so what peeks is the CARD's
1423
+ edge, not empty slide padding. */
1424
+ .fl-voice-slide.is-before { align-items: flex-end; }
1425
+ .fl-voice-slide.is-after { align-items: flex-start; }
1426
+ /* Edge spacers give the deck's first/last slide the scroll room to reach
1427
+ true center — without them the ends rest half-a-peek off-center. */
1428
+ .fl-voice-feed::before, .fl-voice-feed::after { content: ""; flex: 0 0 42px; }
1429
+ @media (prefers-reduced-motion: no-preference) {
1430
+ /* \`backwards\`, never \`both\`: a forwards fill would pin the keyframe's
1431
+ \`transform: none; opacity: 1\` over the off-stage shrink/dim forever. */
1432
+ .fl-voice-slide { animation: fl-item-in .36s cubic-bezier(.22, 1, .36, 1) backwards; }
1433
+ }
1434
+ /* Tall views scroll inside their slide — mandatory snap never traps content.
1435
+ No border-radius here: the card has no background of its own, so a radius
1436
+ would only clip the flush top corners of the sandboxed view (the generated
1437
+ title/table headers sit at the iframe's edge — margin:0 body). The rounding
1438
+ belongs to the view's own surfaces, and to the pending card below. */
1439
+ .fl-voice-slide .fl-voice-card { width: min(720px, 100%); max-height: 100%; overflow: auto;
1440
+ scrollbar-width: none; }
1441
+ .fl-voice-slide .fl-voice-card::-webkit-scrollbar { display: none; }
1442
+ .fl-voice-slide.is-pending .fl-voice-card { border: 1px solid var(--vendo-border); padding: 12px;
1443
+ border-radius: var(--vendo-radius); background: var(--vendo-glass-strong); }
1444
+ /* Slide dots — where you are among the session's views; tap to jump. */
1445
+ .fl-voice-dots { position: absolute; right: 7px; top: 50%; transform: translateY(-50%); z-index: 2;
1446
+ display: flex; flex-direction: column; gap: 8px; }
1447
+ .fl-voice-dots button { width: 7px; height: 7px; border-radius: 50%; border: 0; padding: 0;
1448
+ cursor: pointer; background: color-mix(in srgb, var(--vendo-fg) 22%, transparent);
1449
+ transition: background .2s ease, transform .2s ease; }
1450
+ .fl-voice-dots button.is-on { background: var(--vendo-accent); transform: scale(1.3); }
1451
+
1452
+ /* Lives in the head, right under the blob + status — the words stay with the
1453
+ presence. Fixed height (~2 lines) so the feed doesn't jump as lines stream. */
1454
+ /* Two sticky rows — your last line and the agent's — each clamped so long
1455
+ streaming lines show their tail, not their start. Settled lines dim
1456
+ instead of vanishing. */
1457
+ .fl-voice-caption { height: 62px; padding: 0 22px; text-align: center; max-width: 620px;
1458
+ font-size: 13.5px; line-height: 1.45; flex-shrink: 0; overflow: hidden;
1459
+ display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 2px; }
1460
+ .fl-voice-caption > span { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
1461
+ .fl-voice-caption .is-user { color: var(--vendo-fg-muted); font-size: 12.5px; -webkit-line-clamp: 1; }
1462
+ .fl-voice-caption .is-user::before { content: "“"; }
1463
+ .fl-voice-caption .is-user::after { content: "”"; }
1464
+ .fl-voice-caption .is-agent { color: var(--vendo-fg); -webkit-line-clamp: 2; }
1465
+ .fl-voice-caption .is-settled { opacity: .55; transition: opacity .4s ease; }
1466
+ .fl-voice-caption em { font-style: italic; color: var(--vendo-fg-muted); }
1467
+
1468
+ /* ---- consent bar: approvals dock at the edge, the agent's UI keeps the
1469
+ stage. Act tier breathes the listening ring (spoken yes acceptable);
1470
+ critical goes amber with the named confirm; settled = transient receipt. */
1471
+ .fl-voice-consent { margin: 0 18px 8px; padding: 9px 12px; border-radius: 13px; flex-shrink: 0;
1472
+ display: flex; align-items: center; gap: 10px; font-size: 12.5px;
1473
+ border: 1px solid var(--vendo-border-strong); background: var(--vendo-glass-strong);
1474
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1475
+ box-shadow: var(--vendo-shadow); animation: fl-item-in .3s cubic-bezier(.22, 1, .36, 1) both; }
1476
+ .fl-voice-consent.is-listening { animation: fl-item-in .3s cubic-bezier(.22, 1, .36, 1) both,
1477
+ fl-voice-ring 2.2s ease-in-out .3s infinite; }
1478
+ .fl-voice-consent-ic { display: grid; place-items: center; width: 26px; height: 26px; flex-shrink: 0;
1479
+ border-radius: 8px; border: 1px solid var(--vendo-border); color: var(--vendo-fg-muted); }
1480
+ .fl-voice-consent-copy { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
1481
+ .fl-voice-consent-title { font-weight: 600; color: var(--vendo-fg); overflow: hidden;
1482
+ text-overflow: ellipsis; white-space: nowrap; }
1483
+ .fl-voice-consent-fact { font-weight: 400; color: var(--vendo-fg-muted); }
1484
+ .fl-voice-consent-warn { font-size: 11px; font-weight: 500; color: var(--vendo-warn-text); }
1485
+ .fl-voice-consent-actions { display: flex; gap: 6px; flex-shrink: 0; }
1486
+ .fl-voice-consent.is-critical { border-color: color-mix(in srgb, var(--vendo-warn-edge) 55%, var(--vendo-border)); }
1487
+ .fl-voice-consent.is-critical .fl-voice-consent-ic { color: var(--vendo-warn-text);
1488
+ border-color: color-mix(in srgb, var(--vendo-warn-edge) 40%, var(--vendo-border)); }
1489
+ .fl-voice-consent.is-receipt { justify-content: center; font-weight: 600; color: var(--vendo-ok);
1490
+ border-color: color-mix(in srgb, var(--vendo-ok) 40%, var(--vendo-border)); }
1491
+ .fl-voice-consent.is-receipt.is-declined { color: var(--vendo-fg-muted);
1492
+ border-color: var(--vendo-border); }
1493
+
1494
+ .fl-voice-banner { margin: 0 18px 8px; padding: 9px 13px; border-radius: 12px; flex-shrink: 0;
1495
+ border: 1px solid var(--vendo-danger-border); background: var(--vendo-danger-bg);
1496
+ color: var(--vendo-danger); font-size: 12.5px; display: flex; align-items: center; gap: 10px; }
1497
+ .fl-voice-stage.is-reconnecting .fl-voice-banner { border-color: var(--vendo-border-strong);
1498
+ background: var(--vendo-glass-strong); color: var(--vendo-fg-muted); }
1499
+
1500
+ .fl-voice-foot { display: flex; align-items: center; justify-content: space-between;
1501
+ padding: 6px 14px 12px; flex-shrink: 0; }
1502
+ .fl-voice-drawer-btn { border: 0; background: transparent; color: var(--vendo-fg-muted);
1503
+ font: 500 11.5px/1 var(--vendo-font); letter-spacing: .02em; cursor: pointer; padding: 6px 4px; }
1504
+ .fl-voice-drawer-btn:hover { color: var(--vendo-fg); }
1505
+ .fl-voice-controls { display: flex; align-items: center; gap: 6px; }
1506
+ .fl-voice-controls .fl-icon-btn.is-active { color: var(--vendo-danger); }
1507
+
1508
+ .fl-voice-drawer { position: absolute; left: 10px; right: 10px; bottom: 46px; max-height: 46%;
1509
+ overflow: auto; z-index: 4; padding: 12px 14px; border-radius: 14px;
1510
+ border: 1px solid var(--vendo-border-strong); background: var(--vendo-glass-strong);
1511
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1512
+ box-shadow: var(--vendo-shadow); display: flex; flex-direction: column; gap: 8px;
1513
+ animation: fl-fade-in .16s ease; }
1514
+ .fl-voice-drawer-empty { font-size: 12px; color: var(--vendo-fg-muted); text-align: center; padding: 8px; }
1515
+ .fl-voice-line { display: grid; grid-template-columns: 44px 1fr; gap: 10px; font-size: 12.5px; line-height: 1.45; }
1516
+ .fl-voice-line-role { color: var(--vendo-fg-muted); font-weight: 600; font-size: 11px; padding-top: 1px; }
1517
+ .fl-voice-line.is-user span:last-child { color: var(--vendo-fg-muted); }
1518
+ .fl-voice-line.is-agent span:last-child { color: var(--vendo-fg); }
1519
+ .fl-voice-line em { font-style: italic; color: var(--vendo-fg-muted); }
1520
+
1521
+ /* ---- approval card voice/tier registers (ENG-185 × ENG-193) ---- */
1522
+ /* Act-tier while a spoken yes is acceptable: a soft breathing ring. */
1523
+ .fl-approval-listening { animation: fl-voice-ring 2.2s ease-in-out infinite; }
1524
+ @keyframes fl-voice-ring {
1525
+ 0%, 100% { box-shadow: 0 0 0 1px color-mix(in srgb, var(--vendo-accent) 34%, transparent); }
1526
+ 50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--vendo-accent) 12%, transparent); } }
1527
+ /* Critical: amber always-confirm register — voice announces, the hand confirms. */
1528
+ .fl-approval-critical { border-color: color-mix(in srgb, var(--vendo-warn-edge) 55%, var(--vendo-border)); }
1529
+ .fl-approval-critical .fl-approval-eyebrow { color: var(--vendo-warn-text); }
1530
+ .fl-approval-consequence { margin-top: 10px; font-size: 12px; font-weight: 500;
1531
+ color: var(--vendo-warn-text); }
1532
+ .fl-btn-critical { background: var(--vendo-warn-fill-critical); border-color: transparent; color: var(--vendo-warn-on-fill); }
1533
+ /* Settled: the card becomes a receipt. */
1534
+ .fl-approval-approved { border-color: color-mix(in srgb, var(--vendo-ok) 45%, var(--vendo-border)); }
1535
+ .fl-approval-declined { opacity: .7; }
1536
+ .fl-approval-outcome { margin-top: 12px; font: 600 12.5px/1.2 var(--vendo-font); }
1537
+ .fl-approval-outcome.is-approved { color: var(--vendo-ok); }
1538
+ .fl-approval-outcome.is-declined { color: var(--vendo-fg-muted); }
1539
+
1540
+ @media (prefers-reduced-motion: reduce) {
1541
+ .fl-voice-stage, .fl-voice-stage.is-leaving, .fl-voice-slide { animation: none; opacity: 1; }
1542
+ .fl-voice-canvas { transition: none; }
1543
+ .fl-voice-slide:not(.is-focus) { opacity: .45; }
1544
+ .fl-voice-blob { transition: none; transform: none !important; }
1545
+ .fl-approval-listening { animation: none;
1546
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--vendo-accent) 30%, transparent); }
1547
+ .fl-voice-consent, .fl-voice-consent.is-listening { animation: none;
1548
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--vendo-accent) 30%, transparent); }
1549
+ /* No animated blur for vestibular-sensitive users: unfocused slides dim only. */
1550
+ .fl-voice-slide { transition: none; filter: none; }
1551
+ .fl-voice-dots button { transition: none; }
1552
+ }
1553
+
1554
+ .fl-voice-consent.is-automation { display: block; padding: 0; background: none; border: none; box-shadow: none; }
1555
+ .fl-voice-consent.is-automation .fl-approval { width: 100%; max-width: none; }
1556
+
1557
+ /* --- a11y hardening (design port): guaranteed focus ring + AA ceremony buttons --- */
1558
+ .vendo-root :focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1559
+ /* Chromium applies :focus-visible to text inputs on ANY focus (including
1560
+ clicks), so the global keyboard ring would draw a hard rectangle inside the
1561
+ composer on every click. The composer container carries its own focus
1562
+ treatment (.fl-composer:has(:focus-visible)); the inner textarea stays bare. */
1563
+ .vendo-root .fl-composer textarea:focus-visible { outline: none; }
1564
+ /* Amber ceremony/critical confirm buttons stay AA 4.5:1 in BOTH schemes: dark
1565
+ amber fill + white text in light (7.1:1); light amber fill + near-black text
1566
+ in dark (8.7:1, and the fill itself pops ~8:1 off the dark warn-bg) — flipping only the fill
1567
+ would drop white-on-#d9a94e to 2.2:1 (ENG-226 review catch). */
1568
+ .fl-btn-ceremony, .fl-btn-critical { background: var(--vendo-warn); border-color: transparent;
1569
+ color: var(--vendo-warn-on-fill); }
1570
+ .fl-btn-ceremony:hover, .fl-btn-critical:hover { opacity: .92; background: var(--vendo-warn); }
1571
+
1572
+ /* ==================== ui-lane-panels lane block ====================
1573
+ Converged picks (see LANE-REPORT.md in the lane worktree):
1574
+ activity B (icon ledger) · vendo-activities B (approval queue pager) ·
1575
+ automations B (run-dot strip) · connected-accounts A+D+F (identity rows,
1576
+ two-step disconnect + undo, connect-ahead empty state).
1577
+ Every value derives from the existing --vendo-* tokens. */
1578
+
1579
+ /* ---- activity icon ledger (shared by ActivityPanel + VendoActivities) ---- */
1580
+ .fl-act-led { list-style: none; margin: 0; padding: 0; }
1581
+ .fl-act-led-row { display: grid; grid-template-columns: 26px minmax(0, 1.9fr) 1fr auto; gap: 10px;
1582
+ align-items: center; padding: 8px 13px; border-bottom: 1px solid var(--vendo-border); }
1583
+ .fl-act-led-row:last-child { border-bottom: 0; }
1584
+ .fl-act-led-row:hover { background: var(--vendo-accent-soft); }
1585
+ .fl-act-led-ic { width: 24px; height: 24px; border-radius: 8px; display: grid; place-items: center;
1586
+ background: var(--vendo-accent-soft); border: 1px solid var(--vendo-border); color: var(--vendo-fg);
1587
+ flex-shrink: 0; }
1588
+ .fl-act-led-ic svg { width: 13px; height: 13px; }
1589
+ .fl-act-led-main { min-width: 0; font-size: 12.5px; overflow: hidden; text-overflow: ellipsis;
1590
+ white-space: nowrap; }
1591
+ .fl-act-led-main b { font-weight: 550; }
1592
+ .fl-act-led-det { color: var(--vendo-fg-muted); font-size: 11.5px; }
1593
+ .fl-act-led-out { min-width: 0; }
1594
+ .fl-act-led-by { color: var(--vendo-fg-muted); font-size: 10.5px; }
1595
+ /* Narrow viewports (375px hosts): result wraps under the action so the
1596
+ outcome and timestamp never collide. */
1597
+ @media (max-width: 480px) {
1598
+ .fl-act-led-row { grid-template-columns: 26px minmax(0, 1fr) auto;
1599
+ grid-template-areas: "ic main when" "ic out out"; row-gap: 3px; }
1600
+ .fl-act-led-ic { grid-area: ic; }
1601
+ .fl-act-led-main { grid-area: main; }
1602
+ .fl-act-led-out { grid-area: out; }
1603
+ .fl-act-led-row > .fl-act-when { grid-area: when; }
1604
+ }
1605
+
1606
+ /* ---- vendo-activities approval queue pager ---- */
1607
+ .fl-approvals-pager { display: flex; align-items: center; gap: 8px; }
1608
+ .fl-approvals-dots { display: flex; gap: 4px; margin-left: auto; }
1609
+ .fl-approvals-dot { width: 6px; height: 6px; border-radius: 999px; background: var(--vendo-border-strong); }
1610
+ .fl-approvals-dot--on { background: var(--vendo-accent); }
1611
+ .fl-approvals-stack { position: relative; }
1612
+ .fl-approvals-stack .fl-approval { width: 100%; max-width: 100%; }
1613
+ .fl-approvals-slide { animation: fl-approval-enter .32s var(--vendo-motion-easing) both; }
1614
+ @keyframes fl-approval-enter { from { opacity: 0; transform: translateX(14px) scale(.985); } }
1615
+ .fl-approvals-ghost { position: absolute; inset: 6px -5px auto auto; width: 96%; height: 100%;
1616
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius);
1617
+ background: var(--vendo-glass); z-index: -1; }
1618
+
1619
+ /* ---- automations run-dot history strip ---- */
1620
+ .fl-auto-runs { display: flex; align-items: center; gap: 4px; padding: 12px 16px 14px;
1621
+ border-top: 1px solid var(--vendo-border); }
1622
+ .fl-auto-runs-lbl { font-size: 11px; color: var(--vendo-fg-muted); margin-right: 6px; white-space: nowrap; }
1623
+ .fl-auto-runs-dot { width: 14px; height: 7px; border-radius: 3px; background: var(--vendo-ok);
1624
+ opacity: .85; animation: fl-auto-runs-pop .3s var(--vendo-motion-easing) both; cursor: default; }
1625
+ .fl-auto-runs-dot[data-status="pending-approval"] { background: var(--vendo-warn-tint); }
1626
+ .fl-auto-runs-dot[data-status="error"] { background: var(--vendo-danger); }
1627
+ .fl-auto-runs-dot[data-status="stopped"] { background: var(--vendo-border-strong); }
1628
+ .fl-auto-runs-dot[data-status="running"] { background: var(--vendo-accent); }
1629
+ .fl-auto-runs-dot:hover { transform: scaleY(1.4); }
1630
+ @keyframes fl-auto-runs-pop { from { opacity: 0; transform: scaleY(.2); } }
1631
+ .fl-auto-runs-sum { margin-left: auto; font-size: 11px; color: var(--vendo-fg-muted);
1632
+ white-space: nowrap; }
1633
+
1634
+ /* ---- connected accounts: identity rows + disconnect ceremony + empty ---- */
1635
+ .fl-acct-logo { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
1636
+ background: var(--vendo-surface); border: 1px solid var(--vendo-border); flex-shrink: 0;
1637
+ box-shadow: inset 0 1px 0 light-dark(rgba(255,255,255,.58), rgba(255,255,255,.08)); }
1638
+ .fl-acct-title { display: flex; align-items: center; gap: 8px; }
1639
+ .fl-acct-chip { display: inline-flex; align-items: center; gap: 5px; border-radius: 999px;
1640
+ padding: 3px 9px; font: 600 10.5px/1.2 var(--vendo-font); }
1641
+ .fl-acct-chip i { width: 5px; height: 5px; border-radius: 999px; background: currentColor; }
1642
+ .fl-acct-chip--ok { color: var(--vendo-ok); background: color-mix(in srgb, var(--vendo-ok) 11%, transparent); }
1643
+ .fl-acct-chip--warn { color: var(--vendo-warn-text); background: color-mix(in srgb, var(--vendo-warn-tint) 14%, transparent); }
1644
+ .fl-acct-chip--danger { color: var(--vendo-danger); background: color-mix(in srgb, var(--vendo-danger) 11%, transparent); }
1645
+ .fl-acct-chip--off { color: var(--vendo-fg-muted); background: color-mix(in srgb, var(--vendo-fg) 7%, transparent); }
1646
+ .fl-acct-confirm { overflow: hidden; max-height: 0; transition: max-height .3s var(--vendo-motion-easing); }
1647
+ .fl-acct-confirm--open { max-height: 150px; }
1648
+ .fl-acct-confirm-inner { border-top: 1px solid var(--vendo-warn-border); background: var(--vendo-warn-bg);
1649
+ padding: 11px 16px; font-size: 12px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
1650
+ .fl-acct-confirm-inner b { font-weight: 600; }
1651
+ .fl-acct-confirm-sub { display: block; color: var(--vendo-fg-muted); font-size: 11.5px; margin-top: 2px; }
1652
+ .fl-acct-confirm-actions { margin-left: auto; display: flex; gap: 6px; flex-shrink: 0; }
1653
+ .fl-acct-confirm-actions .fl-btn { padding: 5px 12px; font-size: 11.5px; }
1654
+ .fl-acct-severed { display: flex; align-items: center; gap: 10px; padding: 12px 16px;
1655
+ border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius);
1656
+ background: color-mix(in srgb, var(--vendo-fg) 3%, transparent); font-size: 12.5px;
1657
+ color: var(--vendo-fg-muted); animation: fl-item-in .3s ease-out both; }
1658
+ .fl-acct-undo { margin-left: auto; display: inline-flex; align-items: center; gap: 7px; }
1659
+ .fl-acct-undo .fl-btn { padding: 5px 12px; font-size: 11.5px; }
1660
+ .fl-acct-undo-count { font-variant-numeric: tabular-nums; font-size: 11px; color: var(--vendo-fg-muted); }
1661
+ .fl-acct-ghost { border: 1.5px dashed var(--vendo-border-strong); border-radius: var(--vendo-radius);
1662
+ padding: 18px; display: flex; flex-direction: column; gap: 10px; }
1663
+ .fl-acct-ghost-title { font-weight: 600; font-size: 13.5px; }
1664
+ .fl-acct-ghost-copy { margin: 0; color: var(--vendo-fg-muted); font-size: 12.5px; line-height: 1.55; }
1665
+ .fl-acct-connect-row { display: flex; flex-wrap: wrap; gap: 8px; }
1666
+ .fl-acct-connect-chip { display: inline-flex; align-items: center; gap: 8px;
1667
+ border: 1.5px dashed var(--vendo-border-strong); border-radius: 999px; background: transparent;
1668
+ color: var(--vendo-fg); padding: 6px 13px 6px 7px; font: 600 12px/1.2 var(--vendo-font); cursor: pointer; }
1669
+ .fl-acct-connect-chip:hover { background: var(--vendo-accent-soft); border-style: solid; }
1670
+ .fl-acct-connect-chip:disabled { opacity: .6; cursor: default; }
1671
+ .fl-acct-connect-chip .fl-acct-logo { width: 24px; height: 24px; border-radius: 999px; }
1672
+ /* ================== end ui-lane-panels lane block ================== */
1673
+
1674
+ /* ================================================================
1675
+ voice-lane composite (2026-07-19) — ui-lane-voice's converged Round 2:
1676
+ PiP dock (P-C) · speaker lean (P-F) · rolling ticker (S-C) · idle
1677
+ invitation (S-E) · attention vignette (S-F) · spoken-yes consent (C-A) ·
1678
+ connect-during-voice slot (Cn-A) · mobile safe-area foot (M-A).
1679
+ One marked block so every lane's chrome-css edits merge cleanly.
1680
+ ================================================================ */
1681
+
1682
+ /* ---- S-C rolling ticker: the caption slot holds the last 3 transcript
1683
+ lines, newest bright, older fading and shrinking upward. */
1684
+ .fl-voice-caption { height: 84px; }
1685
+ .fl-voice-tick { animation: fl-voice-tick-up .4s cubic-bezier(.22, 1, .36, 1) both; }
1686
+ .fl-voice-tick.is-age-2 { opacity: .3; font-size: 11.5px; }
1687
+ .fl-voice-tick.is-age-1 { opacity: .55; font-size: 12.5px; }
1688
+ .fl-voice-tick.is-age-0 { opacity: 1; }
1689
+ .fl-voice-tick.is-age-0.is-settled { opacity: .8; }
1690
+ @keyframes fl-voice-tick-up { from { transform: translateY(9px); opacity: 0; } }
1691
+
1692
+ /* ---- P-C dock: once a view lands the head becomes a corner pill (travel is
1693
+ FLIP-animated in stage.tsx on fluidkit MorphSurface's BODY_SPRING; the ball
1694
+ remounts at 30px — never a scaled svg). The pill and the docked ticker own
1695
+ an aligned top band; the deck starts below it. */
1696
+ .fl-voice-stage.is-docked .fl-voice-canvas { grid-template-rows: 0fr auto 1fr; }
1697
+ .fl-voice-stage.is-docked .fl-voice-head { position: absolute; top: 12px; right: 14px; z-index: 5;
1698
+ flex-direction: row; align-items: center; gap: 8px; min-height: 52px;
1699
+ padding: 5px 12px 5px 6px; border-radius: 999px;
1700
+ border: 1px solid var(--vendo-border-strong); background: var(--vendo-glass-strong);
1701
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1702
+ box-shadow: var(--vendo-shadow); }
1703
+ .fl-voice-stage.is-docked .fl-voice-status { min-height: auto; }
1704
+ .fl-voice-stage.is-docked > .fl-voice-caption { position: absolute; top: 12px; left: 14px; z-index: 5;
1705
+ height: auto; min-height: 52px; max-width: min(46%, 360px); padding: 8px 12px;
1706
+ text-align: left; align-items: flex-start; justify-content: center;
1707
+ border-radius: 12px; border: 1px solid var(--vendo-border); background: var(--vendo-glass-strong);
1708
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1709
+ animation: fl-item-in .3s cubic-bezier(.22, 1, .36, 1) both; }
1710
+ .fl-voice-stage.is-docked > .fl-voice-caption .fl-voice-tick.is-age-2 { display: none; }
1711
+ .fl-voice-stage.is-docked .fl-voice-feedwrap { margin-top: 80px; }
1712
+
1713
+ /* ---- P-F speaker lean: the presence settles toward the user's words and
1714
+ lifts for its own — center-stage only; the docked pill stays still. */
1715
+ .fl-voice-stage:not(.is-docked) .fl-voice-blob { transition: transform .6s cubic-bezier(.22, 1, .36, 1), filter .6s ease; }
1716
+ .fl-voice-stage:not(.is-docked) .fl-voice-blob.is-lean-user { transform: translateY(7px) scale(.97); }
1717
+ .fl-voice-stage:not(.is-docked) .fl-voice-blob.is-lean-agent { transform: translateY(-5px) scale(1.04); filter: brightness(1.06); }
1718
+ .fl-voice-glow { width: 120px; height: 26px; margin-top: -20px; border-radius: 50%; flex-shrink: 0;
1719
+ background: radial-gradient(ellipse, color-mix(in srgb, var(--vendo-accent) 22%, transparent), transparent 70%);
1720
+ filter: blur(6px); pointer-events: none; animation: fl-fade-in .6s ease both; }
1721
+
1722
+ /* ---- S-E idle invitation: host-provided suggestion chips under the presence. */
1723
+ .fl-voice-invite { display: flex; flex-direction: column; gap: 8px; align-items: center; margin-top: 6px; }
1724
+ .fl-voice-chip { border: 1px solid var(--vendo-border-strong); border-radius: 999px; cursor: pointer;
1725
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1726
+ color: var(--vendo-fg); font: 500 12.5px/1 var(--vendo-font); padding: 10px 16px;
1727
+ animation: fl-item-in .4s cubic-bezier(.22, 1, .36, 1) backwards;
1728
+ transition: border-color .15s, transform .15s; }
1729
+ .fl-voice-chip:hover { border-color: var(--vendo-accent); transform: translateY(-1px); }
1730
+ .fl-voice-chip:nth-child(2) { animation-delay: .08s; }
1731
+ .fl-voice-chip:nth-child(3) { animation-delay: .16s; }
1732
+ .fl-voice-invite-hint { font: 500 11.5px/1 var(--vendo-font); color: var(--vendo-fg-muted); margin-top: 2px; }
1733
+
1734
+ /* ---- S-F attention vignette: a whisper-soft dim outside the point of
1735
+ attention — the ball while the agent speaks, the card once docked. */
1736
+ .fl-voice-spot { position: absolute; inset: 0; pointer-events: none; z-index: 1; opacity: 0;
1737
+ background: radial-gradient(circle var(--fl-spot-r, 260px) at var(--fl-spot-x, 50%) var(--fl-spot-y, 30%),
1738
+ transparent 60%, color-mix(in srgb, var(--vendo-fg) 5%, transparent));
1739
+ transition: opacity .8s ease; }
1740
+ .fl-voice-stage.is-spot-on .fl-voice-spot { opacity: 1; }
1741
+
1742
+ /* ---- C-A spoken-yes: the act-tier bar says voice works, with a live
1743
+ equalizer while the mic is open; a heard yes flips the hint. */
1744
+ .fl-voice-consent-hint { font-size: 11px; color: var(--vendo-fg-muted); display: flex; align-items: center; }
1745
+ .fl-voice-consent-hint.is-heard { color: var(--vendo-ok); font-weight: 600; }
1746
+ .fl-voice-eq { display: inline-flex; gap: 2px; align-items: flex-end; height: 12px; margin-left: 6px; }
1747
+ .fl-voice-eq i { width: 2.5px; height: 100%; border-radius: 2px; background: currentColor;
1748
+ animation: fl-voice-eq 1s ease-in-out infinite; }
1749
+ .fl-voice-eq i:nth-child(1) { height: 60%; }
1750
+ .fl-voice-eq i:nth-child(2) { animation-delay: .15s; }
1751
+ .fl-voice-eq i:nth-child(3) { height: 45%; animation-delay: .3s; }
1752
+ @keyframes fl-voice-eq { 0%, 100% { transform: scaleY(.5); } 50% { transform: scaleY(1); } }
1753
+
1754
+ /* ---- Cn-A connect-during-voice: the ConnectCard docks at the consent edge,
1755
+ centered (the approval card's max-width would left-hug a full-width slot),
1756
+ with the connecting hint stacked under the button as a caption. */
1757
+ .fl-voice-connect { margin: 0 18px 8px; flex-shrink: 0; display: flex; justify-content: center; }
1758
+ .fl-voice-connect .fl-approval { align-self: auto; width: 100%; margin-inline: auto;
1759
+ animation: fl-item-in .3s cubic-bezier(.22, 1, .36, 1) both; }
1760
+ .fl-voice-connect .fl-approval-actions { flex-wrap: wrap; row-gap: 6px; }
1761
+ .fl-voice-connect .fl-approval-actions .fl-approval-more { flex-basis: 100%; margin: 0; }
1762
+
1763
+ /* ---- M-A mobile safe-area foot: the controls clear the home indicator, and
1764
+ touch surfaces get real 48px targets. */
1765
+ .fl-voice-foot { padding-bottom: max(12px, env(safe-area-inset-bottom, 0px) + 10px); }
1766
+ @media (pointer: coarse) {
1767
+ .fl-voice-foot { padding: 10px 16px calc(env(safe-area-inset-bottom, 0px) + 20px); }
1768
+ .fl-voice-controls { gap: 10px; }
1769
+ .fl-voice-controls .fl-icon-btn { width: 48px; height: 48px; border-radius: 14px; }
1770
+ .fl-voice-controls .fl-btn { min-height: 48px; padding: 12px 26px; border-radius: 999px; font-size: 14px; }
1771
+ .fl-voice-drawer-btn { padding: 14px 10px; font-size: 12.5px; }
1772
+ }
1773
+
1774
+ @media (prefers-reduced-motion: reduce) {
1775
+ .fl-voice-tick, .fl-voice-chip, .fl-voice-glow, .fl-voice-eq i { animation: none; }
1776
+ .fl-voice-spot { transition: none; }
1777
+ .fl-voice-stage:not(.is-docked) .fl-voice-blob { transition: none; }
1778
+ }
1779
+
1780
+ /* ====================================================================
1781
+ ui-lane-thread block — the converged thread-surface picks (C1 ribbon,
1782
+ C5 bar pin, 2B/2C/2E/2F composer, 3A/3D list, 4B landing cards, 6B
1783
+ mobile jump, 8A-8E markdown). Derived from existing tokens only.
1784
+ ==================================================================== */
1785
+
1786
+ /* C1 — live status ribbon (glued above the composer while a turn works). */
1787
+ .fl-ribbon { display: flex; align-items: center; gap: 9px; margin: 0 16px -6px; padding: 8px 12px;
1788
+ border: 1px solid var(--vendo-border); border-radius: 12px; background: var(--vendo-glass-strong);
1789
+ -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1790
+ font: 500 12.5px/1.3 var(--vendo-font); color: var(--vendo-fg-muted); box-shadow: var(--vendo-shadow); }
1791
+ .fl-ribbon .fl-beat-orb { width: 9px; height: 9px; }
1792
+ .fl-ribbon-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1793
+ color: var(--vendo-fg); font-weight: 550; }
1794
+ @media (prefers-reduced-motion: no-preference) {
1795
+ .fl-ribbon { animation: fl-item-in .24s cubic-bezier(.22, 1, .36, 1) both; }
1796
+ .fl-ribbon-label { animation: fl-fade-in .22s ease both; }
1797
+ }
1798
+ .fl-ribbon-time { flex-shrink: 0; font: 500 10.5px/1 var(--vendo-font-mono); color: var(--vendo-fg-muted);
1799
+ opacity: .75; font-variant-numeric: tabular-nums; }
1800
+ .fl-ribbon-count { margin-left: auto; flex-shrink: 0; font: 600 10.5px/1.4 var(--vendo-font);
1801
+ border: 1px solid var(--vendo-border); border-radius: 999px; padding: 1px 7px; color: var(--vendo-fg-muted); }
1802
+
1803
+ /* C5 — the pin lives on the app-card bar once the view is ready (replaces the
1804
+ old footer row). Sits between the boot labels and the hairline. */
1805
+ .fl-barpin { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0;
1806
+ cursor: pointer; border: 0; background: transparent; color: var(--vendo-fg-muted);
1807
+ font: 550 11.5px/1 var(--vendo-font); padding: 4px 8px; border-radius: 7px;
1808
+ transition: background .12s, color .12s; }
1809
+ .fl-barpin:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
1810
+ .fl-barpin:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 1px; }
1811
+ @media (prefers-reduced-motion: no-preference) {
1812
+ .fl-appcard-bar[data-state="ready"] .fl-barpin { animation: fl-fade-in .3s ease both; }
1813
+ }
1814
+
1815
+ /* 2B — Send now on the queued pill. */
1816
+ .fl-queued-now { flex-shrink: 0; border: 0; background: none; cursor: pointer; padding: 3px 6px;
1817
+ border-radius: 6px; font: 600 11px/1.2 var(--vendo-font); color: var(--vendo-accent); }
1818
+ .fl-queued-now:hover { background: var(--vendo-accent-soft); }
1819
+
1820
+ /* 2C — focus bloom: hint row exists only while the TEXTAREA holds focus. The
1821
+ typing hints are a typing affordance — keying it off :focus-within grew the
1822
+ bar the instant ANY composer button was pressed, which shifted the icon row
1823
+ upward between mousedown and mouseup and turned the press into a dead click
1824
+ (dock/attach/send all moved out from under the pointer; caught by the e2e
1825
+ "affordances — dark" conformance spec). */
1826
+ .fl-hintrow { display: flex; align-items: center; gap: 12px; padding: 0 2px;
1827
+ font: 500 11px/1.4 var(--vendo-font); color: var(--vendo-fg-muted);
1828
+ max-height: 0; opacity: 0; overflow: hidden; margin: 0;
1829
+ transition: max-height .18s ease, opacity .18s ease, margin .18s ease; }
1830
+ .fl-composer:has(textarea:focus) .fl-hintrow { max-height: 22px; opacity: 1; margin-top: 2px; }
1831
+ .fl-kbd { font: 600 10px/1 var(--vendo-font-mono); border: 1px solid var(--vendo-border);
1832
+ border-bottom-width: 2px; border-radius: 4px; padding: 2px 4px; color: var(--vendo-fg-muted); }
1833
+
1834
+ /* 2E — the whole thread is the drop target; the overlay covers the surface
1835
+ with a centered card. (The composer-local .fl-drop geometry is superseded.) */
1836
+ .fl-drop--thread { position: absolute; inset: 10px; z-index: 30; display: grid; place-items: center;
1837
+ border-radius: 16px; border: 1.5px dashed var(--vendo-accent);
1838
+ background: color-mix(in srgb, var(--vendo-accent) 7%, var(--vendo-surface)); }
1839
+ .fl-drop-card { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
1840
+ color: var(--vendo-fg); font: 550 13px/1.4 var(--vendo-font); }
1841
+ /* The drop surface needs a positioning context on the thread itself. */
1842
+ .fl-thread { position: relative; }
1843
+
1844
+ /* 2F — attachment read ring + per-chip error with retry. */
1845
+ .fl-att-ring { position: relative; width: 18px; height: 18px; flex-shrink: 0; }
1846
+ .fl-att-ring svg { transform: rotate(-90deg); display: block; }
1847
+ .fl-att-ring circle { fill: none; stroke-width: 2.6; }
1848
+ .fl-att-ring-bg { stroke: var(--vendo-border); }
1849
+ .fl-att-ring-fg { stroke: var(--vendo-accent); stroke-linecap: round; transition: stroke-dashoffset .2s linear; }
1850
+ .fl-att-file--error { border-color: var(--vendo-danger-border); }
1851
+ .fl-att-fail { color: var(--vendo-danger); font-size: 10.5px; }
1852
+ .fl-att-retry { border: 0; background: none; padding: 0; cursor: pointer; font: inherit;
1853
+ color: var(--vendo-danger); text-decoration: underline; text-underline-offset: 2px; }
1854
+
1855
+ /* 3A — the new-replies bar docks onto the composer edge (replaces .fl-jump). */
1856
+ .fl-newbar { position: absolute; left: 16px; right: 16px; bottom: 0; z-index: 5; display: flex;
1857
+ align-items: center; justify-content: center; gap: 8px; padding: 8px 12px; cursor: pointer;
1858
+ border: 1px solid var(--vendo-border-strong); border-radius: 12px 12px 0 0; border-bottom: 0;
1859
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1860
+ font: 600 12px/1 var(--vendo-font); color: var(--vendo-fg); box-shadow: var(--vendo-shadow); }
1861
+ @media (prefers-reduced-motion: no-preference) {
1862
+ .fl-newbar { animation: fl-newbar-rise .22s cubic-bezier(.22, 1, .36, 1) both; }
1863
+ }
1864
+ @keyframes fl-newbar-rise { from { transform: translateY(100%); } to { transform: none; } }
1865
+ .fl-newbar:hover { border-color: var(--vendo-accent); }
1866
+ .fl-newbar:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1867
+ .fl-newbar small { color: var(--vendo-fg-muted); font-weight: 500; overflow: hidden;
1868
+ text-overflow: ellipsis; white-space: nowrap; max-width: 55%; }
1869
+ /* 6B — at phone widths (and in the takeover) the same affordance re-clothes as
1870
+ a bottom-center thumb pill; the snippet yields to the count. Centered via
1871
+ auto margins, NOT translateX — the fl-newbar-rise entrance animates the
1872
+ transform property with fill:both, which would overwrite a transform-based centering
1873
+ and land the pill half off-center (AI-review catch). The two pill blocks
1874
+ below are intentionally identical — keep them in lockstep (a media query and
1875
+ a class selector can't share one declaration block in this sheet). */
1876
+ @media (max-width: 480px) {
1877
+ .fl-newbar { left: 0; right: 0; bottom: 8px; margin: 0 auto; width: fit-content; max-width: calc(100% - 32px);
1878
+ border-radius: 999px; border-bottom: 1px solid var(--vendo-border-strong);
1879
+ padding: 7px 14px; font-size: 11.5px; }
1880
+ .fl-newbar small { display: none; }
1881
+ }
1882
+ /* mirror of the 480px pill block above — keep identical */
1883
+ .fl-takeover .fl-newbar { left: 0; right: 0; bottom: 8px; margin: 0 auto; width: fit-content; max-width: calc(100% - 32px);
1884
+ border-radius: 999px; border-bottom: 1px solid var(--vendo-border-strong);
1885
+ padding: 7px 14px; font-size: 11.5px; }
1886
+ .fl-takeover .fl-newbar small { display: none; }
1887
+
1888
+ /* 3D — fold-with-fade for restored huge bodies (user paste + markdown). */
1889
+ .fl-fold { position: relative; }
1890
+ .fl-fold:not(.fl-fold--open) { max-height: 190px; overflow: hidden; padding-bottom: 34px; }
1891
+ .fl-fold-veil { position: absolute; left: 0; right: 0; bottom: 0; display: grid; place-items: end center;
1892
+ padding-bottom: 6px; height: 88px;
1893
+ background: linear-gradient(180deg, transparent, var(--vendo-user-bubble) 82%); }
1894
+ .fl-turn-assistant .fl-fold-veil { background: linear-gradient(180deg, transparent, var(--vendo-bg) 82%); }
1895
+ .fl-fold--open .fl-fold-veil { position: static; height: auto; background: none; padding: 8px 0 0; }
1896
+ .fl-fold-pill { border: 1px solid var(--vendo-border-strong); border-radius: 999px;
1897
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1898
+ padding: 5px 12px; font: 600 11.5px/1.3 var(--vendo-font); color: var(--vendo-fg); cursor: pointer;
1899
+ box-shadow: var(--vendo-shadow); text-decoration: none; margin-top: 0; }
1900
+ .fl-fold-pill:hover { border-color: var(--vendo-accent); }
1901
+
1902
+ /* 4B — starter cards on the landing (object suggestions). */
1903
+ .fl-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px;
1904
+ width: 100%; max-width: 560px; }
1905
+ .fl-card { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; text-align: left;
1906
+ cursor: pointer; border: 1px solid var(--vendo-border); border-radius: var(--vendo-radius);
1907
+ background: var(--vendo-glass-strong); -webkit-backdrop-filter: var(--vendo-blur); backdrop-filter: var(--vendo-blur);
1908
+ padding: 12px 13px; color: var(--vendo-fg);
1909
+ transition: border-color .14s, transform .18s cubic-bezier(.22, 1, .36, 1), box-shadow .18s; }
1910
+ .fl-card:hover { border-color: var(--vendo-border-strong); transform: translateY(-1px);
1911
+ box-shadow: 0 2px 10px color-mix(in srgb, var(--vendo-fg) 8%, transparent); }
1912
+ .fl-card:active { transform: translateY(0); box-shadow: none; }
1913
+ .fl-card:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1914
+ .fl-card b { font: 600 12.5px/1.3 var(--vendo-font); }
1915
+ .fl-card span { font: 400 11.5px/1.45 var(--vendo-font); color: var(--vendo-fg-muted); }
1916
+ .fl-card svg { color: var(--vendo-fg-muted); }
1917
+
1918
+ /* 8A — code header bar (Copy is always visible; overrides the hover reveal). */
1919
+ .fl-codeblock { border: 1px solid var(--vendo-border); border-radius: 11px; overflow: hidden;
1920
+ background: var(--vendo-accent-soft); }
1921
+ .fl-md .fl-codeblock pre { margin: 0; border: 0; border-radius: 0; background: none; }
1922
+ .fl-codehead { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 13px;
1923
+ border-bottom: 1px solid var(--vendo-border); }
1924
+ .fl-codehead-lang { font: 600 11px/1 var(--vendo-font-mono); color: var(--vendo-fg-muted); }
1925
+ .fl-codehead-wrap { border: 0; background: none; cursor: pointer; margin-left: auto;
1926
+ font: 500 11px/1 var(--vendo-font); color: var(--vendo-fg-muted); padding: 4px 8px; border-radius: 6px; }
1927
+ .fl-codehead-wrap:hover { background: var(--vendo-accent-soft); color: var(--vendo-fg); }
1928
+ .fl-codehead-wrap--on { color: var(--vendo-accent); }
1929
+ .fl-codehead .fl-copy { position: static; opacity: 1; }
1930
+
1931
+ /* 8B — ledger tables: no zebra, hairline rows, numerals aligned. */
1932
+ .fl-md tbody tr:nth-child(even) { background: none; }
1933
+ .fl-md th, .fl-md td { border-bottom: 1px solid var(--vendo-border); }
1934
+ .fl-td-num { text-align: right; font-variant-numeric: tabular-nums; }
1935
+
1936
+ /* 8C — the settled turn's quiet sources row. */
1937
+ .fl-sources { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }
1938
+ .fl-source { display: inline-flex; align-items: center; gap: 5px;
1939
+ border: 1px solid var(--vendo-border); border-radius: 999px; background: var(--vendo-surface);
1940
+ font: 600 10px/1 var(--vendo-font); color: var(--vendo-fg-muted); padding: 3px 8px; }
1941
+ .fl-source i { width: 6px; height: 6px; border-radius: 2px; background: var(--vendo-accent); opacity: .7; }
1942
+ .fl-source-count { margin-left: 1px; color: var(--vendo-fg-muted); font-weight: 700; }
1943
+
1944
+ /* 8D — collapsible sections in restored long replies. The h2/h3 wrapper keeps
1945
+ document-outline semantics; the button inside carries all the styling. */
1946
+ .fl-mdsec { margin: 2px 0; }
1947
+ .fl-mdsec-h { margin: 0; font-size: inherit; font-weight: inherit; line-height: inherit; }
1948
+ .fl-mdsec-head { display: flex; align-items: center; gap: 7px; width: 100%; border: 0; background: none;
1949
+ padding: 4px 0; cursor: pointer; text-align: left;
1950
+ font: 650 1.05em/1.3 var(--vendo-font); color: var(--vendo-fg); }
1951
+ .fl-mdsec-head svg { flex-shrink: 0; color: var(--vendo-fg-muted); transition: transform .16s; }
1952
+ .fl-mdsec--open > .fl-mdsec-head svg { transform: rotate(90deg); }
1953
+ .fl-mdsec-head:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; border-radius: 6px; }
1954
+ .fl-mdsec-body { padding: 2px 0 4px; }
1955
+
1956
+ /* 8E — a streaming table's forming row. */
1957
+ .fl-tr-forming td { padding: var(--vendo-density-table-padding); }
1958
+ .fl-tr-forming .fl-skeleton-bar { display: block; height: 9px; width: 62%; border-radius: 5px; }
1959
+
1960
+ /* ================= ui-lane-cards converged picks ================= */
1961
+ /* 1-A · consequence-first approval. Distinct from .fl-approval-consequence
1962
+ (the amber voice-register line) — this is the neutral leading sentence. */
1963
+ .fl-approval-consequence-line { margin: 10px 0 0; font: 500 13px/1.5 var(--vendo-font);
1964
+ color: var(--vendo-fg); }
1965
+ .fl-approval-consequence-line strong { font-weight: 650; }
1966
+ .fl-approval-details { margin-top: 2px; }
1967
+ .fl-approval-details summary { color: var(--vendo-fg-muted); font-size: 11px; cursor: pointer;
1968
+ margin-top: 8px; }
1969
+ .fl-approval-details summary:focus-visible { outline: 2px solid var(--vendo-accent); outline-offset: 2px; }
1970
+ .fl-approval-details[open] summary { margin-bottom: 2px; }
1971
+
1972
+ /* 1-H · mobile approval sheet. A consent surface: the scrim does NOT dismiss
1973
+ and Esc is a no-op (enforced in approval-sheet.tsx) — deciding is the only
1974
+ way out. Sits above the takeover panel and the palette scrim. */
1975
+ .fl-approval-sheet-layer { position: fixed; inset: 0; z-index: 2147483004; }
1976
+ .fl-approval-sheet-scrim { position: absolute; inset: 0;
1977
+ background: color-mix(in srgb, var(--vendo-fg) 26%, transparent); }
1978
+ .fl-approval-sheet { position: absolute; left: 0; right: 0; bottom: 0;
1979
+ border-radius: 18px 18px 0 0; background: var(--vendo-surface);
1980
+ box-shadow: 0 -12px 40px color-mix(in srgb, var(--vendo-fg) 22%, transparent);
1981
+ padding: 8px 16px calc(16px + env(safe-area-inset-bottom, 0px) + var(--fl-kb-inset, 0px));
1982
+ max-height: 86vh; overflow-y: auto; overscroll-behavior: contain; outline: none; }
1983
+ .fl-approval-sheet-grabber { width: 36px; height: 4px; border-radius: 999px;
1984
+ background: var(--vendo-border-strong); margin: 4px auto 12px; }
1985
+ /* Inside the sheet the card sheds its own chrome — the sheet IS the surface. */
1986
+ .fl-approval-sheet .fl-approval { max-width: none; min-width: 0; width: 100%;
1987
+ border: 0; box-shadow: none; background: none; padding: 0;
1988
+ -webkit-backdrop-filter: none; backdrop-filter: none; }
1989
+ /* …except the ceremony register: a destructive ask keeps its warn wash. */
1990
+ .fl-approval-sheet .fl-approval--ceremony { border: 1px solid var(--vendo-warn-border);
1991
+ background: var(--vendo-warn-bg); padding: 12px; border-radius: var(--vendo-radius); }
1992
+ @media (prefers-reduced-motion: no-preference) {
1993
+ .fl-approval-sheet { animation: fl-sheet-up .42s cubic-bezier(.22,1.1,.36,1) both; }
1994
+ .fl-approval-sheet-scrim { animation: fl-fade-in .3s ease both; }
1995
+ }
1996
+ @keyframes fl-sheet-up { from { transform: translateY(100%); } to { transform: none; } }
1997
+ /* 1-H · thumb-zone decision buttons (same query as the ENG-228 block). */
1998
+ @media (max-width: 767px), (pointer: coarse) {
1999
+ .fl-approval-actions .fl-btn { padding: 14px 15px; font-size: 14px; flex: 1; }
2000
+ }
2001
+
2002
+ /* 3-A′ · real brand marks in the tray rows (monogram = fallback). */
2003
+ .fl-picker-ic img { width: 15px; height: 15px; object-fit: contain; display: block; }
2004
+
2005
+ /* 4-C · the morph docks into the Activity anchor; the anchor answers. */
2006
+ @media (prefers-reduced-motion: no-preference) {
2007
+ .fl-tab--bump { animation: fl-tab-bump .55s cubic-bezier(.22,1,.36,1); }
2008
+ }
2009
+ @keyframes fl-tab-bump {
2010
+ 0% { transform: scale(1); }
2011
+ 40% { transform: scale(1.1); color: var(--vendo-fg); }
2012
+ 100% { transform: scale(1); }
2013
+ }
2014
+
2015
+ /* 7-A · automation liveness: countdown + the run dot traveling the arrow. */
2016
+ .fl-auto-nextrun { font-variant-numeric: tabular-nums; }
2017
+ .fl-automation .fl-auto-arrow { position: relative; }
2018
+ .fl-auto-runner { position: absolute; top: -4.5px; left: 0; width: 8px; height: 8px;
2019
+ border-radius: 50%; background: var(--vendo-accent);
2020
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--vendo-accent) 18%, transparent); }
2021
+ @media (prefers-reduced-motion: no-preference) {
2022
+ .fl-auto-runner { animation: fl-auto-travel 1.5s ease-in-out infinite; }
2023
+ }
2024
+ @keyframes fl-auto-travel { from { left: -2%; } to { left: 98%; } }
2025
+ @media (prefers-reduced-motion: reduce) {
2026
+ /* The runner rests mid-arrow; the sheet arrives without motion. */
2027
+ .fl-auto-runner { animation: none; left: 46%; }
2028
+ .fl-approval-sheet { animation: fl-fade-in .18s ease both; }
2029
+ }
2030
+
2031
+ /* Cross-lane reduced-motion sweep (review finding): entrance/pulse animations
2032
+ that were neither wrapped in a no-preference block nor listed in an explicit
2033
+ reduce kill — settle instantly at their end state for vestibular-sensitive
2034
+ users. (The data-vendo-motion="reduced" root rule already covers theme-level
2035
+ reduction; this covers the OS preference.) */
2036
+ @media (prefers-reduced-motion: reduce) {
2037
+ .fl-overlay-scrim, .fl-toasts-card, .fl-voice-drawer,
2038
+ .fl-approvals-slide, .fl-auto-runs-dot, .fl-acct-severed { animation: none; opacity: 1; }
2039
+ }
2040
+
2041
+ `;
2042
+ //# sourceMappingURL=chrome-css.js.map