undercity 1.0.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 (382) hide show
  1. package/AGENTS.md +26 -0
  2. package/README.md +58 -0
  3. package/actions/AGENTS.md +41 -0
  4. package/actions/_shared/container.js +16 -0
  5. package/actions/auth/ask-login/action.json +15 -0
  6. package/actions/auth/ask-signup/action.json +14 -0
  7. package/actions/display/clear/action.json +18 -0
  8. package/actions/display/clear/action.test.js +32 -0
  9. package/actions/display/markdown/action.json +12 -0
  10. package/actions/display/markdown/action.test.js +32 -0
  11. package/actions/display/rawHtml/action.json +24 -0
  12. package/actions/display/rawHtml/action.test.js +32 -0
  13. package/actions/display/safeHtml/action.json +24 -0
  14. package/actions/display/safeHtml/action.test.js +32 -0
  15. package/actions/display/text/action.js +9 -0
  16. package/actions/display/text/action.json +12 -0
  17. package/actions/display/text/action.test.js +40 -0
  18. package/actions/display/value/action.json +24 -0
  19. package/actions/display/value/action.test.js +32 -0
  20. package/actions/dom/addClass/action.json +23 -0
  21. package/actions/dom/addClass/action.test.js +32 -0
  22. package/actions/dom/focus/action.json +17 -0
  23. package/actions/dom/focus/action.test.js +32 -0
  24. package/actions/dom/hide/action.json +18 -0
  25. package/actions/dom/hide/action.test.js +32 -0
  26. package/actions/dom/removeClass/action.json +22 -0
  27. package/actions/dom/removeClass/action.test.js +32 -0
  28. package/actions/dom/scroll/action.json +29 -0
  29. package/actions/dom/scroll/action.test.js +32 -0
  30. package/actions/dom/setAttr/action.json +29 -0
  31. package/actions/dom/setAttr/action.test.js +32 -0
  32. package/actions/dom/setHtml/action.json +22 -0
  33. package/actions/dom/setHtml/action.test.js +32 -0
  34. package/actions/dom/setStyle/action.json +29 -0
  35. package/actions/dom/setStyle/action.test.js +32 -0
  36. package/actions/dom/setText/action.json +24 -0
  37. package/actions/dom/setText/action.test.js +32 -0
  38. package/actions/dom/show/action.json +18 -0
  39. package/actions/dom/show/action.test.js +32 -0
  40. package/actions/dom/toggle/action.json +17 -0
  41. package/actions/dom/toggle/action.test.js +32 -0
  42. package/actions/dom/toggleClass/action.json +22 -0
  43. package/actions/dom/toggleClass/action.test.js +32 -0
  44. package/actions/event/emit/action.json +24 -0
  45. package/actions/event/emit/action.test.js +32 -0
  46. package/actions/event/on/action.json +23 -0
  47. package/actions/event/on/action.test.js +32 -0
  48. package/actions/event/waitFor/action.json +28 -0
  49. package/actions/event/waitFor/action.test.js +32 -0
  50. package/actions/forms/bindField/action.js +27 -0
  51. package/actions/forms/bindField/action.json +24 -0
  52. package/actions/forms/bindField/action.test.js +20 -0
  53. package/actions/forms/check/action.json +22 -0
  54. package/actions/forms/check/action.test.js +32 -0
  55. package/actions/forms/clearErrors/action.json +11 -0
  56. package/actions/forms/clearErrors/action.test.js +35 -0
  57. package/actions/forms/clearField/action.json +17 -0
  58. package/actions/forms/clearField/action.test.js +32 -0
  59. package/actions/forms/getField/action.json +24 -0
  60. package/actions/forms/getField/action.test.js +32 -0
  61. package/actions/forms/getRange/action.json +22 -0
  62. package/actions/forms/getRange/action.test.js +32 -0
  63. package/actions/forms/getSelect/action.json +22 -0
  64. package/actions/forms/getSelect/action.test.js +32 -0
  65. package/actions/forms/index.js +140 -0
  66. package/actions/forms/serialize/action.json +24 -0
  67. package/actions/forms/serialize/action.test.js +32 -0
  68. package/actions/forms/setCheck/action.json +23 -0
  69. package/actions/forms/setCheck/action.test.js +32 -0
  70. package/actions/forms/setError/action.json +22 -0
  71. package/actions/forms/setError/action.test.js +32 -0
  72. package/actions/forms/setField/action.js +14 -0
  73. package/actions/forms/setField/action.json +24 -0
  74. package/actions/forms/setField/action.test.js +32 -0
  75. package/actions/forms/submit/action.json +18 -0
  76. package/actions/forms/submit/action.test.js +32 -0
  77. package/actions/forms/validate/action.json +24 -0
  78. package/actions/forms/validate/action.test.js +32 -0
  79. package/actions/http/delete/action.json +22 -0
  80. package/actions/http/delete/action.test.js +32 -0
  81. package/actions/http/get/action.json +24 -0
  82. package/actions/http/get/action.test.js +32 -0
  83. package/actions/http/post/action.json +30 -0
  84. package/actions/http/post/action.test.js +32 -0
  85. package/actions/http/put/action.json +27 -0
  86. package/actions/http/put/action.test.js +32 -0
  87. package/actions/http/upload/action.json +35 -0
  88. package/actions/http/upload/action.test.js +32 -0
  89. package/actions/index.js +306 -0
  90. package/actions/index.json +5 -0
  91. package/actions/input/askChoice/action.json +29 -0
  92. package/actions/input/askChoice/action.test.js +32 -0
  93. package/actions/input/askConfirm/action.json +24 -0
  94. package/actions/input/askConfirm/action.test.js +32 -0
  95. package/actions/input/askDate/action.json +24 -0
  96. package/actions/input/askDate/action.test.js +32 -0
  97. package/actions/input/askEmail/action.json +24 -0
  98. package/actions/input/askEmail/action.test.js +32 -0
  99. package/actions/input/askNumber/action.json +35 -0
  100. package/actions/input/askNumber/action.test.js +32 -0
  101. package/actions/input/askPassword/action.json +24 -0
  102. package/actions/input/askPassword/action.test.js +32 -0
  103. package/actions/input/askText/action.json +36 -0
  104. package/actions/input/askText/action.test.js +32 -0
  105. package/actions/logic/delay/action.json +18 -0
  106. package/actions/logic/delay/action.test.js +32 -0
  107. package/actions/logic/if/action.json +28 -0
  108. package/actions/logic/if/action.test.js +32 -0
  109. package/actions/logic/log/action.json +18 -0
  110. package/actions/logic/log/action.test.js +32 -0
  111. package/actions/logic/random/action.json +36 -0
  112. package/actions/logic/random/action.test.js +32 -0
  113. package/actions/logic/transform/action.json +24 -0
  114. package/actions/logic/transform/action.test.js +32 -0
  115. package/actions/media/askAudioUpload/action.json +30 -0
  116. package/actions/media/askAudioUpload/action.test.js +32 -0
  117. package/actions/media/askFileUpload/action.json +36 -0
  118. package/actions/media/askFileUpload/action.test.js +32 -0
  119. package/actions/media/askImageUpload/action.json +37 -0
  120. package/actions/media/askImageUpload/action.test.js +32 -0
  121. package/actions/media/askVideoUpload/action.js +74 -0
  122. package/actions/media/askVideoUpload/action.json +44 -0
  123. package/actions/media/askVideoUpload/action.test.js +51 -0
  124. package/actions/media/captureWebcam/action.json +24 -0
  125. package/actions/media/captureWebcam/action.test.js +32 -0
  126. package/actions/nav/back/action.json +11 -0
  127. package/actions/nav/back/action.test.js +35 -0
  128. package/actions/nav/goto/action.json +18 -0
  129. package/actions/nav/goto/action.test.js +32 -0
  130. package/actions/nav/redirect/action.json +28 -0
  131. package/actions/nav/redirect/action.test.js +32 -0
  132. package/actions/nav/reload/action.json +11 -0
  133. package/actions/nav/reload/action.test.js +35 -0
  134. package/actions/nav/reset/action.json +11 -0
  135. package/actions/nav/reset/action.test.js +35 -0
  136. package/actions/render/alert/action.js +12 -0
  137. package/actions/render/alert/action.json +36 -0
  138. package/actions/render/alert/action.test.js +32 -0
  139. package/actions/render/button/action.js +15 -0
  140. package/actions/render/button/action.json +44 -0
  141. package/actions/render/button/action.test.js +37 -0
  142. package/actions/render/clear/action.js +7 -0
  143. package/actions/render/clear/action.json +11 -0
  144. package/actions/render/clear/action.test.js +35 -0
  145. package/actions/render/divider/action.js +8 -0
  146. package/actions/render/divider/action.json +11 -0
  147. package/actions/render/divider/action.test.js +35 -0
  148. package/actions/render/field/action.js +17 -0
  149. package/actions/render/field/action.json +59 -0
  150. package/actions/render/field/action.test.js +57 -0
  151. package/actions/render/link/action.js +20 -0
  152. package/actions/render/link/action.json +30 -0
  153. package/actions/render/link/action.test.js +32 -0
  154. package/actions/render/markdown/action.json +18 -0
  155. package/actions/render/markdown/action.test.js +32 -0
  156. package/actions/render/paragraph/action.js +9 -0
  157. package/actions/render/paragraph/action.json +32 -0
  158. package/actions/render/paragraph/action.test.js +32 -0
  159. package/actions/render/section/action.js +10 -0
  160. package/actions/render/section/action.json +18 -0
  161. package/actions/render/section/action.test.js +32 -0
  162. package/actions/render/subtitle/action.js +9 -0
  163. package/actions/render/subtitle/action.json +18 -0
  164. package/actions/render/subtitle/action.test.js +32 -0
  165. package/actions/render/title/action.js +9 -0
  166. package/actions/render/title/action.json +30 -0
  167. package/actions/render/title/action.test.js +44 -0
  168. package/actions/session/clear/action.json +11 -0
  169. package/actions/session/clear/action.test.js +35 -0
  170. package/actions/session/load/action.json +22 -0
  171. package/actions/session/load/action.test.js +32 -0
  172. package/actions/session/local/action.json +22 -0
  173. package/actions/session/local/action.test.js +32 -0
  174. package/actions/session/save/action.json +22 -0
  175. package/actions/session/save/action.test.js +32 -0
  176. package/actions/ui/accordion/action.json +23 -0
  177. package/actions/ui/accordion/action.test.js +32 -0
  178. package/actions/ui/badge/action.json +22 -0
  179. package/actions/ui/badge/action.test.js +32 -0
  180. package/actions/ui/collapse/action.json +23 -0
  181. package/actions/ui/collapse/action.test.js +32 -0
  182. package/actions/ui/hideModal/action.json +17 -0
  183. package/actions/ui/hideModal/action.test.js +32 -0
  184. package/actions/ui/loading/action.json +18 -0
  185. package/actions/ui/loading/action.test.js +32 -0
  186. package/actions/ui/modal/action.json +18 -0
  187. package/actions/ui/modal/action.test.js +32 -0
  188. package/actions/ui/progress/action.json +24 -0
  189. package/actions/ui/progress/action.test.js +32 -0
  190. package/actions/ui/toast/action.json +29 -0
  191. package/actions/ui/toast/action.test.js +32 -0
  192. package/actions/ui/tooltip/action.json +17 -0
  193. package/actions/ui/tooltip/action.test.js +32 -0
  194. package/actions/user/carry/action.json +25 -0
  195. package/actions/user/carry/action.test.js +32 -0
  196. package/actions/user/check/action.json +24 -0
  197. package/actions/user/check/action.test.js +32 -0
  198. package/actions/user/clear/action.json +11 -0
  199. package/actions/user/clear/action.test.js +35 -0
  200. package/actions/user/delete/action.json +17 -0
  201. package/actions/user/delete/action.test.js +32 -0
  202. package/actions/user/dump/action.json +11 -0
  203. package/actions/user/dump/action.test.js +35 -0
  204. package/actions/user/get/action.json +24 -0
  205. package/actions/user/get/action.test.js +32 -0
  206. package/actions/user/merge/action.json +18 -0
  207. package/actions/user/merge/action.test.js +32 -0
  208. package/actions/user/set/action.json +24 -0
  209. package/actions/user/set/action.test.js +32 -0
  210. package/generator/base/css/bootstrap.min.css +6 -0
  211. package/generator/base/icons/app-indicator.svg +4 -0
  212. package/generator/base/icons/backpack.svg +4 -0
  213. package/generator/base/icons/broadcast.svg +3 -0
  214. package/generator/base/icons/bullseye.svg +6 -0
  215. package/generator/base/icons/chat-dots.svg +4 -0
  216. package/generator/base/icons/check-circle.svg +4 -0
  217. package/generator/base/icons/clipboard-check.svg +5 -0
  218. package/generator/base/icons/clipboard.svg +4 -0
  219. package/generator/base/icons/copy.svg +3 -0
  220. package/generator/base/icons/cursor.svg +3 -0
  221. package/generator/base/icons/diamond.svg +3 -0
  222. package/generator/base/icons/exclamation-triangle.svg +4 -0
  223. package/generator/base/icons/film.svg +3 -0
  224. package/generator/base/icons/floppy.svg +4 -0
  225. package/generator/base/icons/gear-wide-connected.svg +3 -0
  226. package/generator/base/icons/gear.svg +4 -0
  227. package/generator/base/icons/globe.svg +3 -0
  228. package/generator/base/icons/image.svg +4 -0
  229. package/generator/base/icons/layout-text-window.svg +4 -0
  230. package/generator/base/icons/lightning-charge.svg +3 -0
  231. package/generator/base/icons/magic.svg +3 -0
  232. package/generator/base/icons/pencil-square.svg +4 -0
  233. package/generator/base/icons/record-circle.svg +4 -0
  234. package/generator/base/icons/robot.svg +4 -0
  235. package/generator/base/icons/shield-check.svg +4 -0
  236. package/generator/base/icons/shield-lock.svg +4 -0
  237. package/generator/base/icons/signpost.svg +3 -0
  238. package/generator/base/icons/stars.svg +3 -0
  239. package/generator/base/icons/type.svg +3 -0
  240. package/generator/base/js/bootstrap.bundle.min.js +7 -0
  241. package/package.json +14 -0
  242. package/packages/undercity-http-server/index.js +249 -0
  243. package/packages/undercity-http-server/package.json +10 -0
  244. package/packages/undercity-parser/index.js +323 -0
  245. package/packages/undercity-parser/lexer.js +128 -0
  246. package/packages/undercity-parser/package.json +11 -0
  247. package/plugins/forms.js +397 -0
  248. package/plugins/index.js +83 -0
  249. package/plugins/multipage.js +165 -0
  250. package/plugins/wizard.js +239 -0
  251. package/projects/asd/project.json +1031 -0
  252. package/projects/test-1/project.json +335 -0
  253. package/projects/test-a/project.json +456 -0
  254. package/public/icons/arrows-angle-expand.svg +3 -0
  255. package/public/icons/arrows-fullscreen.svg +3 -0
  256. package/public/icons/bezier2.svg +3 -0
  257. package/public/icons/bootstrap/app-indicator.svg +4 -0
  258. package/public/icons/bootstrap/arrow-clockwise.svg +4 -0
  259. package/public/icons/bootstrap/arrow-counterclockwise.svg +4 -0
  260. package/public/icons/bootstrap/arrow-left.svg +3 -0
  261. package/public/icons/bootstrap/arrows-angle-expand.svg +3 -0
  262. package/public/icons/bootstrap/arrows-fullscreen.svg +3 -0
  263. package/public/icons/bootstrap/backpack.svg +4 -0
  264. package/public/icons/bootstrap/bezier2.svg +3 -0
  265. package/public/icons/bootstrap/bookmark-check.svg +4 -0
  266. package/public/icons/bootstrap/bookmark-plus.svg +4 -0
  267. package/public/icons/bootstrap/box-arrow-right.svg +4 -0
  268. package/public/icons/bootstrap/box-arrow-up.svg +4 -0
  269. package/public/icons/bootstrap/broadcast.svg +3 -0
  270. package/public/icons/bootstrap/bullseye.svg +6 -0
  271. package/public/icons/bootstrap/chat-dots.svg +4 -0
  272. package/public/icons/bootstrap/check-circle.svg +4 -0
  273. package/public/icons/bootstrap/check2.svg +3 -0
  274. package/public/icons/bootstrap/clipboard-check.svg +5 -0
  275. package/public/icons/bootstrap/clipboard.svg +4 -0
  276. package/public/icons/bootstrap/clock-history.svg +5 -0
  277. package/public/icons/bootstrap/command.svg +3 -0
  278. package/public/icons/bootstrap/copy.svg +3 -0
  279. package/public/icons/bootstrap/cursor.svg +3 -0
  280. package/public/icons/bootstrap/diagram-3.svg +3 -0
  281. package/public/icons/bootstrap/diamond.svg +3 -0
  282. package/public/icons/bootstrap/exclamation-triangle.svg +4 -0
  283. package/public/icons/bootstrap/eye.svg +4 -0
  284. package/public/icons/bootstrap/file-earmark-plus.svg +4 -0
  285. package/public/icons/bootstrap/film.svg +3 -0
  286. package/public/icons/bootstrap/floppy.svg +4 -0
  287. package/public/icons/bootstrap/folder2-open.svg +3 -0
  288. package/public/icons/bootstrap/gear-wide-connected.svg +3 -0
  289. package/public/icons/bootstrap/gear.svg +4 -0
  290. package/public/icons/bootstrap/globe.svg +3 -0
  291. package/public/icons/bootstrap/grid-3x3-gap.svg +3 -0
  292. package/public/icons/bootstrap/house-door.svg +3 -0
  293. package/public/icons/bootstrap/image.svg +4 -0
  294. package/public/icons/bootstrap/layout-text-window.svg +4 -0
  295. package/public/icons/bootstrap/lightning-charge.svg +3 -0
  296. package/public/icons/bootstrap/magic.svg +3 -0
  297. package/public/icons/bootstrap/pencil-square.svg +4 -0
  298. package/public/icons/bootstrap/pencil.svg +3 -0
  299. package/public/icons/bootstrap/play.svg +3 -0
  300. package/public/icons/bootstrap/plus-circle.svg +4 -0
  301. package/public/icons/bootstrap/plus-lg.svg +3 -0
  302. package/public/icons/bootstrap/record-circle.svg +4 -0
  303. package/public/icons/bootstrap/robot.svg +4 -0
  304. package/public/icons/bootstrap/save.svg +3 -0
  305. package/public/icons/bootstrap/scissors.svg +3 -0
  306. package/public/icons/bootstrap/shield-check.svg +4 -0
  307. package/public/icons/bootstrap/shield-lock.svg +4 -0
  308. package/public/icons/bootstrap/signpost.svg +3 -0
  309. package/public/icons/bootstrap/stars.svg +3 -0
  310. package/public/icons/bootstrap/stop-circle.svg +4 -0
  311. package/public/icons/bootstrap/terminal.svg +4 -0
  312. package/public/icons/bootstrap/trash3.svg +3 -0
  313. package/public/icons/bootstrap/type.svg +3 -0
  314. package/public/icons/bootstrap/x-circle.svg +4 -0
  315. package/public/icons/bootstrap/x-lg.svg +3 -0
  316. package/public/icons/bootstrap/zoom-in.svg +5 -0
  317. package/public/icons/bootstrap/zoom-out.svg +5 -0
  318. package/public/icons/bullseye.svg +6 -0
  319. package/public/icons/check2.svg +3 -0
  320. package/public/icons/cursor.svg +3 -0
  321. package/public/icons/diamond.svg +3 -0
  322. package/public/icons/eye.svg +4 -0
  323. package/public/icons/file-earmark-plus.svg +4 -0
  324. package/public/icons/floppy.svg +4 -0
  325. package/public/icons/gear.svg +4 -0
  326. package/public/icons/lightning-charge.svg +3 -0
  327. package/public/icons/pencil.svg +3 -0
  328. package/public/icons/play.svg +3 -0
  329. package/public/icons/plus-circle.svg +4 -0
  330. package/public/icons/record-circle.svg +4 -0
  331. package/public/icons/robot.svg +4 -0
  332. package/public/icons/save.svg +3 -0
  333. package/public/icons/stop-circle.svg +4 -0
  334. package/public/icons/terminal.svg +4 -0
  335. package/public/icons/trash3.svg +3 -0
  336. package/public/icons/x-circle.svg +4 -0
  337. package/public/icons/zoom-in.svg +5 -0
  338. package/public/icons/zoom-out.svg +5 -0
  339. package/public/index.html +424 -0
  340. package/public/testbench.html +899 -0
  341. package/scripts/extract-actions.js +128 -0
  342. package/server.js +11 -0
  343. package/src/emitter.js +48 -0
  344. package/src/generator/css.js +135 -0
  345. package/src/generator/index.js +122 -0
  346. package/src/generator/md-renderer-src.js +77 -0
  347. package/src/generator/page.js +300 -0
  348. package/src/generator/runtime.js +1632 -0
  349. package/src/generator/templates.js +508 -0
  350. package/src/ide/action-library.js +856 -0
  351. package/src/ide/af-icons.js +127 -0
  352. package/src/ide/app.js +1375 -0
  353. package/src/ide/command-line/commands.js +242 -0
  354. package/src/ide/command-line/index.js +329 -0
  355. package/src/ide/command-line/parser.js +21 -0
  356. package/src/ide/css/ide.css +1501 -0
  357. package/src/ide/graph.js +282 -0
  358. package/src/ide/history.js +46 -0
  359. package/src/ide/map-builder.js +583 -0
  360. package/src/ide/project-api.js +39 -0
  361. package/src/ide/savant-chat.js +513 -0
  362. package/src/ide/savant.js +1287 -0
  363. package/src/ide/thing-library.js +89 -0
  364. package/src/ide/undercity-map.js +978 -0
  365. package/src/lib/icons.js +72 -0
  366. package/src/lib/scope.js +88 -0
  367. package/src/lib/signal.js +155 -0
  368. package/src/lib/state-machine.js +113 -0
  369. package/src/server/index.js +96 -0
  370. package/src/server/routes/actions.js +144 -0
  371. package/src/server/routes/ai.js +176 -0
  372. package/src/server/routes/generate.js +54 -0
  373. package/src/server/routes/projects.js +106 -0
  374. package/src/server/routes/reset.js +30 -0
  375. package/src/server/routes/submit.js +30 -0
  376. package/src/server/routes/templates.js +139 -0
  377. package/src/server/routes/things.js +33 -0
  378. package/templates/auth-flow.json +335 -0
  379. package/templates/blank.json +39 -0
  380. package/things/auth-server/thing.json +17 -0
  381. package/things/persona-live/thing.json +20 -0
  382. package/things/workflow/thing.json +15 -0
@@ -0,0 +1,1501 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ Undercity IDE — Dark Solarized Theme
3
+ Lightweight: CSS custom properties over Bootstrap dark base.
4
+ ═══════════════════════════════════════════════════════════════════════════ */
5
+
6
+ :root {
7
+ /* Solarized Dark palette */
8
+ --sol-base03: #002b36;
9
+ --sol-base02: #073642;
10
+ --sol-base01: #586e75;
11
+ --sol-base00: #657b83;
12
+ --sol-base0: #839496;
13
+ --sol-base1: #93a1a1;
14
+ --sol-yellow: #b58900;
15
+ --sol-orange: #cb4b16;
16
+ --sol-red: #dc322f;
17
+ --sol-magenta:#d33682;
18
+ --sol-violet: #6c71c4;
19
+ --sol-blue: #268bd2;
20
+ --sol-cyan: #2aa198;
21
+ --sol-green: #859900;
22
+
23
+ /* Semantic */
24
+ --bg: var(--sol-base03);
25
+ --bg-raised: var(--sol-base02);
26
+ --bg-overlay: rgba(7,54,66,.96);
27
+ --border: rgba(88,110,117,.35);
28
+ --border-em: rgba(38,139,210,.5);
29
+ --text: var(--sol-base0);
30
+ --text-muted: var(--sol-base01);
31
+ --text-em: var(--sol-base1);
32
+ --accent: var(--sol-blue);
33
+ --accent2: var(--sol-cyan);
34
+ --success: var(--sol-green);
35
+ --warning: var(--sol-yellow);
36
+ --danger: var(--sol-red);
37
+ --violet: var(--sol-violet);
38
+
39
+ --radius: 6px;
40
+ --radius-lg: 10px;
41
+ --transition: 140ms ease;
42
+
43
+ /* application-registry compatible aliases (--af-*) — eases v3 migration */
44
+ --af-bg: var(--bg);
45
+ --af-bg-2: var(--bg-raised);
46
+ --af-fg: var(--text);
47
+ --af-accent: var(--accent);
48
+ --af-accent-dim: color-mix(in srgb, var(--accent) 20%, transparent);
49
+ --af-border: var(--border);
50
+ --af-surface: var(--bg-raised);
51
+ --af-font-sans: 'Inter', system-ui, -apple-system, sans-serif;
52
+ --af-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
53
+ }
54
+
55
+ /* ── Reset / base ─────────────────────────────────────────────────────────── */
56
+ *, *::before, *::after { box-sizing: border-box; }
57
+
58
+ html, body {
59
+ height: 100%;
60
+ margin: 0;
61
+ overflow: hidden;
62
+ background: var(--bg);
63
+ color: var(--text);
64
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
65
+ font-size: 13px;
66
+ }
67
+
68
+ /* ── IDE shell ────────────────────────────────────────────────────────────── */
69
+ #ide-shell {
70
+ display: grid;
71
+ grid-template-rows: 44px 1fr;
72
+ height: 100vh;
73
+ width: 100vw;
74
+ }
75
+
76
+ /* ── Header bar ───────────────────────────────────────────────────────────── */
77
+ #ide-header {
78
+ background: var(--sol-base02);
79
+ border-bottom: 1px solid var(--border);
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 10px;
83
+ padding: 0 14px;
84
+ z-index: 100;
85
+ user-select: none;
86
+ }
87
+
88
+ .ide-logo {
89
+ font-weight: 800;
90
+ font-size: 15px;
91
+ color: var(--sol-cyan);
92
+ letter-spacing: -.03em;
93
+ margin-right: 6px;
94
+ white-space: nowrap;
95
+ }
96
+ .ide-logo span { color: var(--sol-blue); }
97
+
98
+ #project-select {
99
+ background: var(--bg);
100
+ border: 1px solid var(--border);
101
+ color: var(--text-em);
102
+ border-radius: var(--radius);
103
+ padding: 3px 8px;
104
+ font-size: 12px;
105
+ cursor: pointer;
106
+ min-width: 160px;
107
+ }
108
+ #project-select:focus { outline: none; border-color: var(--accent); }
109
+
110
+ .ide-btn {
111
+ background: transparent;
112
+ border: 1px solid var(--border);
113
+ color: var(--text);
114
+ border-radius: var(--radius);
115
+ padding: 3px 10px;
116
+ font-size: 12px;
117
+ cursor: pointer;
118
+ white-space: nowrap;
119
+ transition: all var(--transition);
120
+ display: inline-flex;
121
+ align-items: center;
122
+ gap: 6px;
123
+ }
124
+ .ide-btn:hover { border-color: var(--accent); color: var(--accent); }
125
+ .ide-btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
126
+ .ide-btn.primary:hover { background: #1a7abf; border-color: #1a7abf; }
127
+ .ide-btn.success { background: var(--success); border-color: var(--success); color: #fff; }
128
+ .ide-btn.success:hover { opacity: .85; }
129
+ .ide-btn.danger { background: var(--danger); border-color: var(--danger); color: #fff; }
130
+ .ide-btn af-icon { font-size: 13px; }
131
+
132
+ .ide-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }
133
+ .ide-spacer { flex: 1; }
134
+
135
+ /* ── Main split ───────────────────────────────────────────────────────────── */
136
+ #ide-body {
137
+ display: grid;
138
+ grid-template-rows: 1fr 8px 1fr;
139
+ min-height: 0;
140
+ overflow: hidden;
141
+ }
142
+
143
+ /* ── Map pane ─────────────────────────────────────────────────────────────── */
144
+ #map-pane {
145
+ display: flex;
146
+ flex-direction: column;
147
+ min-height: 0;
148
+ background: var(--bg);
149
+ position: relative;
150
+ }
151
+
152
+ #map-toolbar {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: 6px;
156
+ padding: 5px 10px;
157
+ background: var(--bg-raised);
158
+ border-bottom: 1px solid var(--border);
159
+ z-index: 10;
160
+ }
161
+
162
+ .map-tool {
163
+ width: 30px; height: 30px;
164
+ background: transparent;
165
+ border: 1px solid var(--border);
166
+ border-radius: var(--radius);
167
+ cursor: pointer;
168
+ display: flex; align-items: center; justify-content: center;
169
+ color: var(--text-muted);
170
+ font-size: 14px;
171
+ transition: all var(--transition);
172
+ }
173
+ .map-tool:hover { border-color: var(--accent2); color: var(--accent2); }
174
+ .map-tool.active { background: var(--bg); border-color: var(--accent); color: var(--accent); }
175
+ .map-tool-sep { width: 1px; height: 18px; background: var(--border); margin: 0 2px; }
176
+ .map-tool af-icon { font-size: 16px; }
177
+
178
+ #map-label {
179
+ font-size: 11px;
180
+ color: var(--text-muted);
181
+ margin-left: auto;
182
+ }
183
+
184
+ /* <undercity-map> fills the remaining flex space; cursor/tool modes are
185
+ handled internally by the Web Component's shadow CSS (:host rules). */
186
+ undercity-map {
187
+ flex: 1;
188
+ min-height: 0;
189
+ display: block;
190
+ }
191
+
192
+ /* SVG node/edge styles are scoped inside <undercity-map>'s shadow DOM (undercity-map.js).
193
+ CSS custom properties (--sol-*) pierce the shadow boundary for theming. */
194
+
195
+ /* ── Resize handle ────────────────────────────────────────────────────────── */
196
+ #split-handle {
197
+ background: var(--bg-raised);
198
+ border-top: 1px solid var(--border);
199
+ border-bottom: 1px solid var(--border);
200
+ cursor: ns-resize;
201
+ display: flex; align-items: center; justify-content: center;
202
+ }
203
+ #split-handle::after {
204
+ content: '⋯';
205
+ color: var(--text-muted);
206
+ font-size: 16px;
207
+ letter-spacing: 3px;
208
+ }
209
+
210
+ /* ── Savant pane ───────────────────────────────────────────────────────── */
211
+ #savant-pane {
212
+ display: grid;
213
+ grid-template-rows: auto 1fr;
214
+ min-height: 0;
215
+ background: var(--bg);
216
+ }
217
+
218
+ /* Savant header + breadcrumb */
219
+ #savant-header {
220
+ display: flex;
221
+ flex-direction: row;
222
+ align-items: center;
223
+ border-bottom: 1px solid var(--border);
224
+ background: var(--bg-raised);
225
+ min-height: 32px;
226
+ }
227
+ #savant-breadcrumb {
228
+ display: flex;
229
+ align-items: center;
230
+ gap: 4px;
231
+ padding: 0 8px 0 12px;
232
+ font-size: 11px;
233
+ white-space: nowrap;
234
+ flex-shrink: 0;
235
+ }
236
+ .bc-item { font-weight: 700; color: var(--text); }
237
+ .bc-room { color: var(--sol-cyan); }
238
+ .bc-thing { color: var(--sol-violet); }
239
+ .bc-sep { color: var(--text-muted); font-weight: 400; }
240
+ .bc-type { color: var(--text-muted); font-size: 10px; margin-left: 4px; }
241
+ .bc-idle { color: var(--text-muted); font-weight: 400; font-style: italic; }
242
+
243
+ /* Divider between breadcrumb and event tabs */
244
+ #savant-breadcrumb::after {
245
+ content: '';
246
+ display: block;
247
+ width: 1px;
248
+ height: 16px;
249
+ background: var(--border);
250
+ margin-left: 8px;
251
+ }
252
+
253
+ /* Event tabs */
254
+ #event-tabs {
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 2px;
258
+ position: relative;
259
+ padding: 0 3px;
260
+ flex: 1;
261
+ min-width: 0;
262
+ overflow-y: visible;
263
+ scrollbar-width: none;
264
+ }
265
+
266
+ .evt-tab {
267
+ position: relative;
268
+ background: transparent;
269
+ border: 1px solid transparent;
270
+ border-radius: var(--radius);
271
+ color: var(--text-muted);
272
+ font-size: 11px;
273
+ padding: 3px 10px;
274
+ margin-right: 6px;
275
+ cursor: pointer;
276
+ transition: all var(--transition);
277
+ font-weight: 600;
278
+ flex-shrink: 0;
279
+ }
280
+ .evt-tab:hover { color: var(--text); border-color: var(--border); }
281
+ .evt-tab.active { background: var(--bg); border-color: var(--border-em); color: var(--accent); }
282
+ .evt-badge {
283
+ font-size: 9px;
284
+ font-weight: 700;
285
+ min-width: 16px;
286
+ height: 16px;
287
+ line-height: 16px;
288
+ padding: 0 4px;
289
+ background: var(--sol-violet);
290
+ color: #fff;
291
+ pointer-events: none;
292
+ }
293
+ /* "+" add-listener tab */
294
+ .evt-tab-add {
295
+ color: var(--sol-green);
296
+ border-color: transparent;
297
+ font-size: 14px;
298
+ padding: 1px 8px;
299
+ opacity: 0.7;
300
+ }
301
+ .evt-tab-add:hover { opacity: 1; border-color: var(--sol-green); }
302
+ /* inline event-name input (replaces prompt) */
303
+ .evt-tab-input {
304
+ background: var(--bg);
305
+ border: 1px solid var(--sol-green);
306
+ border-radius: var(--radius);
307
+ color: var(--text);
308
+ font-size: 11px;
309
+ font-weight: 600;
310
+ font-family: inherit;
311
+ padding: 3px 8px;
312
+ width: 120px;
313
+ outline: none;
314
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--sol-green) 25%, transparent);
315
+ }
316
+ /* × remove button inside custom event tabs */
317
+ .evt-tab-remove {
318
+ margin-left: 5px;
319
+ font-size: 12px;
320
+ opacity: 0.5;
321
+ pointer-events: all;
322
+ line-height: 1;
323
+ }
324
+ .evt-tab-remove:hover { opacity: 1; color: var(--sol-red); }
325
+
326
+ /* Savant body: 4 columns with resize handles */
327
+ #savant-body {
328
+ display: grid;
329
+ grid-template-columns: 160px 4px 220px 4px 1fr 4px 260px;
330
+ min-height: 0;
331
+ overflow: hidden;
332
+ }
333
+
334
+ /* Vertical column resize handles */
335
+ .aw-handle {
336
+ background: var(--bg-raised);
337
+ border-left: 1px solid var(--border);
338
+ border-right: 1px solid var(--border);
339
+ cursor: ew-resize;
340
+ transition: background var(--transition);
341
+ display: flex;
342
+ align-items: center;
343
+ justify-content: center;
344
+ overflow: hidden;
345
+ }
346
+ .aw-handle::after {
347
+ content: '⋮';
348
+ color: var(--text-muted);
349
+ font-size: 14px;
350
+ pointer-events: none;
351
+ }
352
+ .aw-handle:hover { background: rgba(38,139,210,.25); }
353
+
354
+ /* Category pane */
355
+ #cat-pane {
356
+ border-right: 1px solid var(--border);
357
+ overflow-y: auto;
358
+ display: flex;
359
+ flex-direction: column;
360
+ }
361
+
362
+ .cat-header {
363
+ padding: 8px 10px 5px;
364
+ font-size: 10px;
365
+ font-weight: 700;
366
+ color: var(--text-muted);
367
+ text-transform: uppercase;
368
+ letter-spacing: .08em;
369
+ }
370
+
371
+ .cat-item {
372
+ display: flex;
373
+ align-items: center;
374
+ gap: 7px;
375
+ padding: 6px 12px;
376
+ cursor: pointer;
377
+ color: var(--text);
378
+ font-size: 12px;
379
+ border-left: 2px solid transparent;
380
+ transition: all var(--transition);
381
+ }
382
+ .cat-item:hover { background: var(--bg-raised); }
383
+ .cat-item.active { background: var(--bg-raised); border-left-color: var(--accent); color: var(--accent); }
384
+ .cat-icon {
385
+ font-size: 14px;
386
+ width: 18px;
387
+ text-align: center;
388
+ display: inline-flex;
389
+ align-items: center;
390
+ justify-content: center;
391
+ }
392
+
393
+ .cat-ai-section {
394
+ margin-top: auto;
395
+ border-top: 1px solid var(--border);
396
+ padding: 8px;
397
+ }
398
+ .cat-ai-input {
399
+ width: 100%;
400
+ background: var(--bg);
401
+ border: 1px solid var(--border);
402
+ border-radius: var(--radius);
403
+ color: var(--text);
404
+ font-size: 11px;
405
+ padding: 5px 8px;
406
+ resize: none;
407
+ outline: none;
408
+ }
409
+ .cat-ai-input:focus { border-color: var(--violet); }
410
+ .cat-ai-btn {
411
+ width: 100%;
412
+ margin-top: 5px;
413
+ background: var(--violet);
414
+ border: none;
415
+ border-radius: var(--radius);
416
+ color: #fff;
417
+ font-size: 11px;
418
+ font-weight: 600;
419
+ padding: 4px;
420
+ cursor: pointer;
421
+ transition: opacity var(--transition);
422
+ display: inline-flex;
423
+ align-items: center;
424
+ justify-content: center;
425
+ gap: 6px;
426
+ }
427
+ .cat-ai-btn:hover { opacity: .85; }
428
+ .cat-ai-btn:disabled{ opacity: .4; cursor: default; }
429
+
430
+ /* Action pane */
431
+ #act-pane {
432
+ border-right: 1px solid var(--border);
433
+ display: flex;
434
+ flex-direction: column;
435
+ overflow: hidden;
436
+ }
437
+
438
+ #act-list {
439
+ flex: 1;
440
+ overflow-y: auto;
441
+ padding: 6px;
442
+ }
443
+
444
+ #act-preview {
445
+ border-top: 1px solid var(--border);
446
+ padding: 8px;
447
+ min-height: 80px;
448
+ max-height: 220px;
449
+ overflow-y: auto;
450
+ background: var(--bg-base);
451
+ flex-shrink: 0;
452
+ }
453
+
454
+ .act-preview-empty {
455
+ font-size: 11px;
456
+ color: var(--text-muted);
457
+ text-align: center;
458
+ padding: 10px 4px;
459
+ }
460
+
461
+ #act-preview-name {
462
+ font-size: 12px;
463
+ font-weight: 700;
464
+ color: var(--text-em);
465
+ margin-bottom: 2px;
466
+ }
467
+
468
+ #act-preview-desc {
469
+ font-size: 10px;
470
+ color: var(--text-muted);
471
+ margin-bottom: 6px;
472
+ line-height: 1.4;
473
+ }
474
+
475
+ .act-preview-param {
476
+ display: flex;
477
+ gap: 6px;
478
+ align-items: baseline;
479
+ margin-bottom: 3px;
480
+ }
481
+
482
+ .act-preview-param-label {
483
+ font-size: 11px;
484
+ font-weight: 600;
485
+ color: var(--text-em);
486
+ min-width: 70px;
487
+ }
488
+
489
+ .act-preview-param-type {
490
+ font-size: 10px;
491
+ color: var(--text-muted);
492
+ font-family: var(--font-mono, monospace);
493
+ }
494
+
495
+ .act-group-label {
496
+ font-size: 9px;
497
+ font-weight: 700;
498
+ color: var(--text-muted);
499
+ text-transform: uppercase;
500
+ letter-spacing: .1em;
501
+ padding: 6px 4px 3px;
502
+ }
503
+
504
+ .act-card {
505
+ display: flex;
506
+ flex-direction: column;
507
+ padding: 7px 9px;
508
+ border-radius: var(--radius);
509
+ border: 1px solid var(--border);
510
+ margin-bottom: 4px;
511
+ cursor: pointer;
512
+ transition: all var(--transition);
513
+ background: var(--bg-raised);
514
+ }
515
+ .act-card:hover { border-color: var(--accent2); background: var(--bg-overlay); }
516
+ .act-card.selected { border-color: var(--accent); background: var(--bg-overlay); }
517
+ .act-card.dragging { opacity: 0.4; }
518
+ .act-card-name { font-size: 12px; font-weight: 600; color: var(--text-em); }
519
+ .act-card-desc { font-size: 10px; color: var(--text-muted); margin-top: 2px; line-height: 1.4; }
520
+ .act-card--ai { border-color: color-mix(in srgb, var(--sol-yellow) 40%, transparent); }
521
+ .act-card-ai-badge { color: var(--sol-yellow); font-size: 9px; margin-left: 5px; vertical-align: middle; }
522
+
523
+ /* Workflow drop zones (between steps) */
524
+ .wf-drop-zone {
525
+ height: 6px;
526
+ border-radius: 3px;
527
+ margin: 1px 0;
528
+ transition: height 0.15s, background 0.15s;
529
+ }
530
+ .wf-drop-zone.drag-over {
531
+ height: 16px;
532
+ background: var(--accent);
533
+ opacity: 0.5;
534
+ }
535
+ .wf-drop-target.drag-over {
536
+ outline: 2px dashed var(--accent);
537
+ outline-offset: 2px;
538
+ background: var(--bg-overlay);
539
+ }
540
+
541
+ /* Workflow pane */
542
+ #wf-pane {
543
+ display: flex;
544
+ flex-direction: column;
545
+ min-height: 0;
546
+ overflow: hidden;
547
+ }
548
+
549
+ #wf-header {
550
+ display: flex;
551
+ align-items: center;
552
+ gap: 8px;
553
+ padding: 7px 12px;
554
+ border-bottom: 1px solid var(--border);
555
+ }
556
+ #wf-title {
557
+ font-size: 11px;
558
+ font-weight: 700;
559
+ color: var(--text-muted);
560
+ text-transform: uppercase;
561
+ letter-spacing: .08em;
562
+ flex: 1;
563
+ }
564
+ .wf-help-btn {
565
+ background: none;
566
+ border: 1px solid var(--border);
567
+ border-radius: 50%;
568
+ width: 18px;
569
+ height: 18px;
570
+ font-size: 10px;
571
+ font-weight: 700;
572
+ color: var(--text-muted);
573
+ cursor: pointer;
574
+ display: flex;
575
+ align-items: center;
576
+ justify-content: center;
577
+ flex-shrink: 0;
578
+ line-height: 1;
579
+ padding: 0;
580
+ }
581
+ .wf-help-btn:hover, .wf-help-btn.active { border-color: var(--accent); color: var(--accent); }
582
+ .wf-workspace-btn {
583
+ background: none;
584
+ border: 1px solid var(--border);
585
+ border-radius: var(--radius);
586
+ width: 22px;
587
+ height: 18px;
588
+ font-size: 11px;
589
+ color: var(--text-muted);
590
+ cursor: pointer;
591
+ display: flex;
592
+ align-items: center;
593
+ justify-content: center;
594
+ flex-shrink: 0;
595
+ padding: 0;
596
+ }
597
+ .wf-workspace-btn:hover { border-color: var(--sol-cyan); color: var(--sol-cyan); }
598
+ .wf-help-panel {
599
+ padding: 10px 14px;
600
+ background: var(--bg-subtle, var(--bg));
601
+ border-bottom: 1px solid var(--border);
602
+ font-size: 12px;
603
+ line-height: 1.6;
604
+ color: var(--text);
605
+ }
606
+ .wf-help-body p { margin: 0 0 6px; }
607
+ .wf-help-body p:last-child { margin-bottom: 0; }
608
+ .wf-help-body code { background: var(--bg-code, var(--border)); padding: 1px 4px; border-radius: 3px; font-size: 11px; }
609
+ .param-input-inv-key { border-color: var(--sol-cyan) !important; }
610
+ .param-input-inv-key::placeholder { color: var(--sol-cyan); opacity: 0.5; }
611
+
612
+ #wf-steps {
613
+ flex: 1;
614
+ overflow-y: auto;
615
+ padding: 8px;
616
+ }
617
+
618
+ .wf-empty {
619
+ color: var(--text-muted);
620
+ font-size: 11px;
621
+ text-align: center;
622
+ padding: 20px;
623
+ line-height: 1.6;
624
+ }
625
+
626
+ .step-card {
627
+ background: var(--bg-raised);
628
+ border: 1px solid var(--border);
629
+ border-radius: var(--radius);
630
+ margin-bottom: 4px;
631
+ overflow: hidden;
632
+ }
633
+ .step-header {
634
+ display: flex;
635
+ align-items: center;
636
+ padding: 7px 10px;
637
+ gap: 7px;
638
+ }
639
+ .step-drag-handle {
640
+ cursor: grab;
641
+ color: var(--text-muted);
642
+ font-size: 14px;
643
+ line-height: 1;
644
+ padding: 0 2px;
645
+ flex-shrink: 0;
646
+ user-select: none;
647
+ }
648
+ .step-drag-handle:active { cursor: grabbing; }
649
+ .step-number {
650
+ font-size: 9px;
651
+ font-weight: 800;
652
+ color: var(--text-muted);
653
+ background: var(--bg);
654
+ border-radius: 3px;
655
+ padding: 1px 4px;
656
+ min-width: 20px;
657
+ text-align: center;
658
+ flex-shrink: 0;
659
+ }
660
+ .step-action-name {
661
+ flex: 1;
662
+ font-size: 12px;
663
+ font-weight: 600;
664
+ color: var(--text-em);
665
+ min-width: 0;
666
+ overflow: hidden;
667
+ text-overflow: ellipsis;
668
+ white-space: nowrap;
669
+ }
670
+ /* Basic / Configure / JSON mode pills */
671
+ .step-mode-pills {
672
+ display: flex;
673
+ background: var(--bg);
674
+ border: 1px solid var(--border);
675
+ border-radius: 20px;
676
+ overflow: hidden;
677
+ flex-shrink: 0;
678
+ }
679
+ .step-mode-pill {
680
+ background: none;
681
+ border: none;
682
+ color: var(--text-muted);
683
+ cursor: pointer;
684
+ font-size: 9px;
685
+ font-weight: 700;
686
+ letter-spacing: .04em;
687
+ padding: 2px 8px;
688
+ transition: background var(--transition), color var(--transition);
689
+ }
690
+ .step-mode-pill.active {
691
+ background: var(--accent);
692
+ color: #fff;
693
+ }
694
+ .step-mode-pill:not(.active):hover { color: var(--text-em); }
695
+ .step-controls { display: flex; gap: 4px; flex-shrink: 0; }
696
+ .step-btn {
697
+ background: none;
698
+ border: none;
699
+ color: var(--text-muted);
700
+ cursor: pointer;
701
+ font-size: 13px;
702
+ padding: 0 2px;
703
+ transition: color var(--transition);
704
+ line-height: 1;
705
+ display: inline-flex;
706
+ align-items: center;
707
+ justify-content: center;
708
+ }
709
+ .step-btn:hover { color: var(--text-em); }
710
+ .step-btn.del:hover { color: var(--danger); }
711
+ .step-collapse-btn {
712
+ background: transparent;
713
+ border: none;
714
+ cursor: pointer;
715
+ font-size: 12px;
716
+ color: var(--text-muted);
717
+ padding: 0 4px;
718
+ line-height: 1;
719
+ flex-shrink: 0;
720
+ }
721
+ .step-collapse-btn:hover { color: var(--text); }
722
+ .step-card.collapsed { opacity: 0.85; }
723
+ .step-card.collapsed .step-header { border-bottom: none; }
724
+ .step-card-unloaded { border-color: var(--danger, #dc3545) !important; opacity: 0.75; }
725
+ .step-unloaded-name { color: var(--danger, #dc3545) !important; font-style: italic; }
726
+ .step-unloaded-id { font-size: 10px; color: var(--text-muted); background: var(--bg); padding: 1px 5px; border-radius: 3px; flex-shrink: 0; }
727
+
728
+ .step-params {
729
+ padding: 0 10px 10px;
730
+ display: none;
731
+ flex-direction: column;
732
+ gap: 5px;
733
+ }
734
+ .step-params.open { display: flex; }
735
+ .param-row {
736
+ display: grid;
737
+ grid-template-columns: 88px 1fr;
738
+ align-items: center;
739
+ gap: 6px;
740
+ }
741
+ .param-label {
742
+ font-size: 10px;
743
+ color: var(--text-muted);
744
+ text-align: right;
745
+ white-space: nowrap;
746
+ overflow: hidden;
747
+ text-overflow: ellipsis;
748
+ }
749
+ .param-code-badge {
750
+ font-size: 8px; font-weight: 800; color: var(--sol-yellow);
751
+ background: rgba(181,137,0,.15); border-radius: 3px;
752
+ padding: 0 3px; vertical-align: middle; margin-left: 3px;
753
+ }
754
+ .param-input {
755
+ background: var(--bg);
756
+ border: 1px solid var(--border);
757
+ border-radius: 4px;
758
+ color: var(--text);
759
+ font-size: 11px;
760
+ padding: 3px 6px;
761
+ width: 100%;
762
+ font-family: 'Fira Code', 'Consolas', monospace;
763
+ transition: border-color var(--transition);
764
+ }
765
+ .param-input:focus { outline: none; border-color: var(--accent); }
766
+ .param-input-code { color: var(--sol-yellow); }
767
+
768
+ /* Basic mode helper elements */
769
+ .step-basic-desc {
770
+ font-size: 11px;
771
+ color: var(--text-muted);
772
+ padding: 0 2px 2px;
773
+ line-height: 1.5;
774
+ font-style: italic;
775
+ }
776
+ .step-basic-code-note {
777
+ display: flex;
778
+ align-items: center;
779
+ gap: 5px;
780
+ font-size: 10px;
781
+ color: var(--text-muted);
782
+ border-top: 1px solid var(--border);
783
+ padding-top: 6px;
784
+ margin-top: 2px;
785
+ }
786
+ .step-basic-code-note af-icon { font-size: 12px; }
787
+
788
+ /* JSON mode editor */
789
+ .step-json-editor {
790
+ font-family: 'Fira Code', 'Consolas', monospace;
791
+ font-size: 11px;
792
+ resize: vertical;
793
+ min-height: 80px;
794
+ }
795
+ .step-json-error {
796
+ font-size: 10px;
797
+ color: var(--danger);
798
+ margin-top: 2px;
799
+ font-family: monospace;
800
+ }
801
+
802
+ /* ── Properties panel (slide-in from right, confined to #map-pane) ─────────── */
803
+ #props-panel {
804
+ position: absolute;
805
+ top: 0;
806
+ right: 0;
807
+ bottom: 0;
808
+ width: 300px;
809
+ background: var(--bg-overlay);
810
+ border-left: 1px solid var(--border-em);
811
+ transform: translateX(100%);
812
+ transition: transform 240ms ease;
813
+ z-index: 50;
814
+ display: flex;
815
+ flex-direction: column;
816
+ backdrop-filter: blur(6px);
817
+ }
818
+ #props-panel.open { transform: translateX(0); }
819
+
820
+ #props-header {
821
+ display: flex;
822
+ align-items: center;
823
+ gap: 8px;
824
+ padding: 10px 14px;
825
+ border-bottom: 1px solid var(--border);
826
+ }
827
+ #props-title { flex: 1; font-size: 13px; font-weight: 700; color: var(--text-em); }
828
+ #props-close {
829
+ background: none;
830
+ border: none;
831
+ color: var(--text-muted);
832
+ cursor: pointer;
833
+ font-size: 18px;
834
+ line-height: 1;
835
+ display: inline-flex;
836
+ align-items: center;
837
+ justify-content: center;
838
+ }
839
+ #props-close:hover { color: var(--text-em); }
840
+
841
+ #props-body { flex: 1; overflow-y: auto; padding: 12px 14px; }
842
+
843
+ .props-field { margin-bottom: 12px; }
844
+ .props-label { display: block; font-size: 10px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .07em; margin-bottom: 4px; }
845
+ .props-input {
846
+ width: 100%;
847
+ background: var(--bg);
848
+ border: 1px solid var(--border);
849
+ border-radius: var(--radius);
850
+ color: var(--text-em);
851
+ font-size: 12px;
852
+ padding: 5px 8px;
853
+ }
854
+ .props-input:focus { outline: none; border-color: var(--accent); }
855
+ .props-select { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-em); font-size: 12px; padding: 5px 8px; }
856
+ .props-value { font-size: 12px; color: var(--text-em); padding: 2px 0; }
857
+ .props-hint { font-weight: 400; color: var(--text-muted); text-transform: none; letter-spacing: 0; }
858
+
859
+ .props-section { margin-bottom: 16px; }
860
+ .props-section-title {
861
+ display: flex; align-items: center; gap: 6px;
862
+ font-size: 10px; font-weight: 800; color: var(--text-muted);
863
+ text-transform: uppercase; letter-spacing: .09em;
864
+ margin-bottom: 8px; padding-bottom: 4px;
865
+ border-bottom: 1px solid var(--border);
866
+ }
867
+
868
+ /* ── Things panel ─────────────────────────────────────────────────────── */
869
+ .things-add-select {
870
+ margin-left: auto;
871
+ font-size: 10px;
872
+ background: var(--bg-raised);
873
+ border: 1px solid var(--border);
874
+ color: var(--text);
875
+ border-radius: var(--radius);
876
+ padding: 2px 4px;
877
+ }
878
+ .things-add-btn {
879
+ font-size: 10px;
880
+ background: var(--sol-green);
881
+ color: var(--bg);
882
+ border: none;
883
+ border-radius: var(--radius);
884
+ padding: 2px 8px;
885
+ cursor: pointer;
886
+ font-weight: 700;
887
+ }
888
+ .things-empty {
889
+ color: var(--text-muted);
890
+ font-size: 11px;
891
+ font-style: italic;
892
+ padding: 4px 0;
893
+ }
894
+ .thing-card {
895
+ background: var(--bg-raised);
896
+ border: 1px solid var(--border);
897
+ border-radius: var(--radius);
898
+ margin-bottom: 6px;
899
+ overflow: hidden;
900
+ }
901
+ .thing-card-head {
902
+ display: flex;
903
+ align-items: center;
904
+ gap: 6px;
905
+ padding: 6px 9px;
906
+ border-left: 3px solid var(--thing-color, var(--accent));
907
+ background: color-mix(in srgb, var(--thing-color, var(--accent)) 8%, var(--bg-raised));
908
+ }
909
+ .thing-card-label {
910
+ font-size: 11px;
911
+ font-weight: 700;
912
+ flex: 1;
913
+ color: var(--text);
914
+ }
915
+ .thing-card-actions { display: flex; gap: 4px; }
916
+ .thing-btn {
917
+ background: transparent;
918
+ border: none;
919
+ cursor: pointer;
920
+ font-size: 13px;
921
+ color: var(--text-muted);
922
+ padding: 0 2px;
923
+ }
924
+ .thing-btn:hover { color: var(--text); }
925
+ .thing-remove:hover { color: var(--sol-red); }
926
+ .thing-card-cfg {
927
+ display: flex;
928
+ flex-wrap: wrap;
929
+ gap: 4px;
930
+ padding: 4px 9px 6px;
931
+ }
932
+ .thing-cfg-item {
933
+ font-size: 10px;
934
+ color: var(--text-muted);
935
+ background: var(--bg);
936
+ border-radius: var(--radius);
937
+ padding: 1px 6px;
938
+ }
939
+
940
+ .route-row {
941
+ background: var(--bg-raised);
942
+ border: 1px solid var(--border);
943
+ border-radius: var(--radius);
944
+ padding: 7px 9px;
945
+ margin-bottom: 5px;
946
+ display: flex;
947
+ flex-direction: column;
948
+ gap: 4px;
949
+ }
950
+ .route-builder {
951
+ display: flex;
952
+ align-items: center;
953
+ gap: 4px;
954
+ }
955
+ .route-visual {
956
+ display: flex;
957
+ align-items: center;
958
+ gap: 4px;
959
+ flex: 1;
960
+ min-width: 0;
961
+ }
962
+ .route-advanced {
963
+ flex: 1;
964
+ min-width: 0;
965
+ }
966
+ .route-visual.hidden, .route-advanced.hidden { display: none; }
967
+ .route-key, .route-op {
968
+ background: var(--bg);
969
+ border: 1px solid var(--border);
970
+ border-radius: 4px;
971
+ color: var(--text);
972
+ font-size: 11px;
973
+ padding: 3px 5px;
974
+ }
975
+ .route-key { min-width: 0; flex: 1; }
976
+ .route-op { flex-shrink: 0; }
977
+ .route-val {
978
+ background: var(--bg);
979
+ border: 1px solid var(--border);
980
+ border-radius: 4px;
981
+ color: var(--text);
982
+ font-size: 11px;
983
+ padding: 3px 5px;
984
+ width: 72px;
985
+ flex-shrink: 0;
986
+ }
987
+ .route-toggle-mode {
988
+ background: none;
989
+ border: 1px solid var(--border);
990
+ border-radius: 4px;
991
+ color: var(--text-muted);
992
+ font-size: 10px;
993
+ padding: 2px 5px;
994
+ cursor: pointer;
995
+ flex-shrink: 0;
996
+ }
997
+ .route-toggle-mode:hover { border-color: var(--accent); color: var(--accent); }
998
+ .route-condition {
999
+ background: var(--bg);
1000
+ border: 1px solid var(--border);
1001
+ border-radius: 4px;
1002
+ color: var(--text);
1003
+ font-size: 11px;
1004
+ padding: 3px 6px;
1005
+ width: 100%;
1006
+ font-family: 'Fira Code', monospace;
1007
+ }
1008
+ .route-footer {
1009
+ display: flex;
1010
+ align-items: center;
1011
+ gap: 4px;
1012
+ }
1013
+ .route-target {
1014
+ background: var(--bg);
1015
+ border: 1px solid var(--border);
1016
+ border-radius: 4px;
1017
+ color: var(--text);
1018
+ font-size: 11px;
1019
+ padding: 3px 6px;
1020
+ flex: 1;
1021
+ }
1022
+ .route-del {
1023
+ background: none; border: none;
1024
+ color: var(--text-muted); cursor: pointer; font-size: 12px;
1025
+ display: inline-flex;
1026
+ align-items: center;
1027
+ justify-content: center;
1028
+ flex-shrink: 0;
1029
+ }
1030
+ .route-del:hover { color: var(--danger); }
1031
+ .add-route-btn {
1032
+ background: none;
1033
+ border: 1px dashed var(--border);
1034
+ border-radius: var(--radius);
1035
+ color: var(--text-muted);
1036
+ font-size: 11px;
1037
+ padding: 5px;
1038
+ width: 100%;
1039
+ cursor: pointer;
1040
+ transition: all var(--transition);
1041
+ }
1042
+ .add-route-btn:hover { border-color: var(--accent); color: var(--accent); }
1043
+
1044
+ /* ── Context menu ─────────────────────────────────────────────────────────── */
1045
+ #ctx-menu {
1046
+ position: fixed;
1047
+ background: var(--bg-overlay);
1048
+ border: 1px solid var(--border-em);
1049
+ border-radius: var(--radius-lg);
1050
+ padding: 5px;
1051
+ z-index: 9000;
1052
+ display: none;
1053
+ min-width: 160px;
1054
+ backdrop-filter: blur(8px);
1055
+ box-shadow: 0 8px 24px rgba(0,0,0,.4);
1056
+ }
1057
+ #ctx-menu.open { display: block; }
1058
+ .ctx-item {
1059
+ padding: 6px 12px;
1060
+ border-radius: var(--radius);
1061
+ cursor: pointer;
1062
+ font-size: 12px;
1063
+ color: var(--text);
1064
+ display: flex;
1065
+ align-items: center;
1066
+ gap: 8px;
1067
+ transition: background var(--transition);
1068
+ }
1069
+ .ctx-item:hover { background: var(--bg-raised); }
1070
+ .ctx-item.danger:hover { background: rgba(220,50,47,.15); color: var(--danger); }
1071
+ .ctx-item af-icon { font-size: 14px; }
1072
+ .ctx-sep { height: 1px; background: var(--border); margin: 4px 0; }
1073
+ .ctx-key { font-size: 10px; color: var(--text-muted); margin-left: auto; padding-left: 12px; }
1074
+
1075
+ /* ── Toast notifications ──────────────────────────────────────────────────── */
1076
+ #toast-area {
1077
+ position: fixed;
1078
+ bottom: 20px;
1079
+ right: 20px;
1080
+ z-index: 9999;
1081
+ display: flex;
1082
+ flex-direction: column;
1083
+ gap: 8px;
1084
+ pointer-events: none;
1085
+ }
1086
+ .ide-toast {
1087
+ background: var(--bg-overlay);
1088
+ border: 1px solid var(--border);
1089
+ border-radius: var(--radius-lg);
1090
+ padding: 8px 14px;
1091
+ font-size: 12px;
1092
+ color: var(--text-em);
1093
+ backdrop-filter: blur(6px);
1094
+ pointer-events: auto;
1095
+ animation: toastIn .2s ease;
1096
+ box-shadow: 0 4px 16px rgba(0,0,0,.3);
1097
+ }
1098
+ .ide-toast.success { border-left: 3px solid var(--success); }
1099
+ .ide-toast.error { border-left: 3px solid var(--danger); }
1100
+ .ide-toast.info { border-left: 3px solid var(--accent); }
1101
+ @keyframes toastIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
1102
+
1103
+ /* ── Scrollbars ───────────────────────────────────────────────────────────── */
1104
+ ::-webkit-scrollbar { width: 5px; height: 5px; }
1105
+ ::-webkit-scrollbar-track { background: transparent; }
1106
+ ::-webkit-scrollbar-thumb { background: var(--sol-base01); border-radius: 3px; }
1107
+ ::-webkit-scrollbar-thumb:hover { background: var(--sol-base00); }
1108
+
1109
+ /* ── Modal (new project / template gallery) ───────────────────────────────── */
1110
+ #new-project-modal, #save-template-modal {
1111
+ display: none;
1112
+ position: fixed; inset: 0; z-index: 8000;
1113
+ background: rgba(0,43,54,.82);
1114
+ backdrop-filter: blur(6px);
1115
+ align-items: center; justify-content: center;
1116
+ }
1117
+ #new-project-modal.open, #save-template-modal.open { display: flex; }
1118
+ .modal-box {
1119
+ background: var(--bg-raised);
1120
+ border: 1px solid var(--border-em);
1121
+ border-radius: var(--radius-lg);
1122
+ padding: 28px;
1123
+ width: 400px;
1124
+ box-shadow: 0 20px 64px rgba(0,0,0,.6);
1125
+ animation: modal-in 160ms ease both;
1126
+ }
1127
+ .modal-box.modal-gallery { width: 680px; max-height: 82vh; overflow-y: auto; }
1128
+ @keyframes modal-in {
1129
+ from { opacity: 0; transform: scale(.96) translateY(8px); }
1130
+ to { opacity: 1; transform: none; }
1131
+ }
1132
+ .modal-title { font-size: 16px; font-weight: 700; color: var(--text-em); margin-bottom: 20px; }
1133
+ .modal-field { margin-bottom: 14px; }
1134
+ .modal-label { display: block; font-size: 10px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .07em; margin-bottom: 5px; }
1135
+ .modal-input { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-em); font-size: 13px; padding: 8px 10px; transition: border-color var(--transition); }
1136
+ .modal-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(38,139,210,.18); }
1137
+ .modal-footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
1138
+ .modal-back {
1139
+ background: none;
1140
+ border: none;
1141
+ color: var(--accent);
1142
+ font-size: 12px;
1143
+ cursor: pointer;
1144
+ padding: 0;
1145
+ margin-bottom: 6px;
1146
+ display: inline-flex;
1147
+ align-items: center;
1148
+ gap: 6px;
1149
+ }
1150
+ .modal-back:hover { text-decoration: underline; }
1151
+
1152
+ /* Template card grid */
1153
+ .tmpl-gallery {
1154
+ display: grid;
1155
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
1156
+ gap: 12px;
1157
+ padding-bottom: 8px;
1158
+ }
1159
+ .tmpl-card {
1160
+ background: var(--bg);
1161
+ border: 2px solid var(--border);
1162
+ border-radius: var(--radius-lg);
1163
+ padding: 20px 16px;
1164
+ cursor: pointer;
1165
+ transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
1166
+ text-align: center;
1167
+ }
1168
+ .tmpl-card:hover {
1169
+ border-color: var(--accent);
1170
+ transform: translateY(-2px);
1171
+ box-shadow: 0 6px 20px rgba(38,139,210,.2);
1172
+ }
1173
+ .tmpl-card-icon {
1174
+ font-size: 2.4rem;
1175
+ margin-bottom: 10px;
1176
+ line-height: 1;
1177
+ display: inline-flex;
1178
+ align-items: center;
1179
+ justify-content: center;
1180
+ }
1181
+ .tmpl-card-name { font-size: 13px; font-weight: 700; color: var(--text-em); margin-bottom: 6px; }
1182
+ .tmpl-card-desc { font-size: 11px; color: var(--text-muted); line-height: 1.5; }
1183
+ .tmpl-loading { padding: 32px; text-align: center; color: var(--text-muted); grid-column: 1/-1; }
1184
+
1185
+ /* ── Welcome screen ───────────────────────────────────────────────────────── */
1186
+ #welcome-modal {
1187
+ display: none;
1188
+ position: fixed; inset: 0; z-index: 8500;
1189
+ background: rgba(0,43,54,.88);
1190
+ backdrop-filter: blur(8px);
1191
+ align-items: center; justify-content: center;
1192
+ }
1193
+ #welcome-modal.open { display: flex; }
1194
+
1195
+ .welcome-box {
1196
+ background: var(--bg-raised);
1197
+ border: 1px solid var(--border-em);
1198
+ border-radius: 16px;
1199
+ padding: 36px 40px 32px;
1200
+ width: 720px;
1201
+ max-width: 92vw;
1202
+ max-height: 90vh;
1203
+ overflow-y: auto;
1204
+ box-shadow: 0 24px 80px rgba(0,0,0,.65);
1205
+ animation: modal-in 180ms ease both;
1206
+ position: relative;
1207
+ }
1208
+
1209
+ .welcome-close {
1210
+ position: absolute; top: 14px; right: 14px;
1211
+ background: none; border: none; color: var(--text-muted);
1212
+ cursor: pointer; font-size: 18px; line-height: 1;
1213
+ display: inline-flex; align-items: center; justify-content: center;
1214
+ }
1215
+ .welcome-close:hover { color: var(--text-em); }
1216
+
1217
+ .welcome-brand { text-align: center; margin-bottom: 28px; }
1218
+ .welcome-logo {
1219
+ font-size: 32px; font-weight: 900;
1220
+ color: var(--sol-cyan); letter-spacing: -.04em;
1221
+ }
1222
+ .welcome-logo span { color: var(--sol-blue); }
1223
+ .welcome-tagline { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
1224
+
1225
+ .welcome-cols {
1226
+ display: grid;
1227
+ grid-template-columns: 1fr 1fr;
1228
+ gap: 28px;
1229
+ }
1230
+
1231
+ .welcome-col-title {
1232
+ font-size: 11px; font-weight: 800;
1233
+ color: var(--text-muted); text-transform: uppercase; letter-spacing: .08em;
1234
+ margin-bottom: 10px;
1235
+ display: flex; align-items: center; gap: 7px;
1236
+ }
1237
+ .welcome-col-title af-icon { font-size: 14px; }
1238
+
1239
+ .welcome-recent-item {
1240
+ display: flex; align-items: flex-start; gap: 10px;
1241
+ padding: 9px 10px;
1242
+ border-radius: var(--radius);
1243
+ cursor: pointer;
1244
+ font-size: 12px; color: var(--text-em);
1245
+ border: 1px solid transparent;
1246
+ transition: all var(--transition);
1247
+ margin-bottom: 4px;
1248
+ }
1249
+ .welcome-recent-item:hover {
1250
+ background: var(--bg);
1251
+ border-color: var(--border-em);
1252
+ }
1253
+ .welcome-recent-item af-icon { font-size: 18px; color: var(--accent); flex-shrink: 0; margin-top: 1px; }
1254
+ .welcome-recent-item .wr-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
1255
+ .welcome-recent-item .wr-name { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1256
+ .welcome-recent-item .wr-desc { font-size: 10px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
1257
+ .welcome-recent-item small { color: var(--text-muted); font-size: 10px; font-family: monospace; flex-shrink: 0; margin-top: 2px; }
1258
+
1259
+ .welcome-hint {
1260
+ font-size: 10px; color: var(--text-muted); margin-top: 10px;
1261
+ text-align: center; font-style: italic;
1262
+ }
1263
+
1264
+ .welcome-tmpl-grid {
1265
+ display: grid;
1266
+ grid-template-columns: repeat(3, 1fr);
1267
+ gap: 8px;
1268
+ }
1269
+ .welcome-tmpl-card {
1270
+ background: var(--bg);
1271
+ border: 1px solid var(--border);
1272
+ border-radius: var(--radius);
1273
+ padding: 12px 8px 10px;
1274
+ cursor: pointer;
1275
+ text-align: center;
1276
+ transition: border-color var(--transition), transform var(--transition);
1277
+ }
1278
+ .welcome-tmpl-card:hover {
1279
+ border-color: var(--accent);
1280
+ transform: translateY(-1px);
1281
+ }
1282
+ .welcome-tmpl-icon { font-size: 1.6rem; margin-bottom: 6px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }
1283
+ .welcome-tmpl-name { font-size: 10px; font-weight: 700; color: var(--text-em); }
1284
+
1285
+ /* Hidden when no recent projects */
1286
+ .d-none-ish { display: none !important; }
1287
+
1288
+ /* Selected template badge on step 2 */
1289
+ .tmpl-selected-badge { margin-bottom: 4px; }
1290
+ .tmpl-badge {
1291
+ display: inline-flex; align-items: center; gap: 6px;
1292
+ background: rgba(38,139,210,.12); border: 1px solid var(--accent);
1293
+ border-radius: 20px; padding: 3px 12px;
1294
+ font-size: 12px; color: var(--accent);
1295
+ }
1296
+
1297
+ /* ── AI Chat pane ────────────────────────────────────────────────────── */
1298
+ #chat-pane {
1299
+ display: flex;
1300
+ flex-direction: column;
1301
+ min-width: 200px;
1302
+ border-left: 1px solid var(--border);
1303
+ overflow: hidden;
1304
+ background: var(--bg-raised);
1305
+ }
1306
+
1307
+ #chat-header {
1308
+ display: flex;
1309
+ align-items: center;
1310
+ padding: 5px 8px;
1311
+ border-bottom: 1px solid var(--border);
1312
+ flex-shrink: 0;
1313
+ }
1314
+ #chat-title {
1315
+ font-size: 10px;
1316
+ font-weight: 800;
1317
+ text-transform: uppercase;
1318
+ letter-spacing: .09em;
1319
+ color: var(--text-muted);
1320
+ flex: 1;
1321
+ }
1322
+ #chat-clear-btn {
1323
+ background: transparent;
1324
+ border: none;
1325
+ cursor: pointer;
1326
+ color: var(--text-muted);
1327
+ font-size: 14px;
1328
+ padding: 0 2px;
1329
+ line-height: 1;
1330
+ }
1331
+ #chat-clear-btn:hover { color: var(--text); }
1332
+
1333
+ #chat-context-bar {
1334
+ font-size: 9px;
1335
+ color: var(--sol-violet);
1336
+ padding: 2px 8px;
1337
+ border-bottom: 1px solid var(--border);
1338
+ white-space: nowrap;
1339
+ overflow: hidden;
1340
+ text-overflow: ellipsis;
1341
+ flex-shrink: 0;
1342
+ min-height: 16px;
1343
+ }
1344
+
1345
+ #chat-messages {
1346
+ flex: 1;
1347
+ overflow-y: auto;
1348
+ padding: 8px;
1349
+ display: flex;
1350
+ flex-direction: column;
1351
+ gap: 6px;
1352
+ }
1353
+
1354
+ .chat-bubble {
1355
+ max-width: 90%;
1356
+ padding: 6px 10px;
1357
+ border-radius: 10px;
1358
+ font-size: 11px;
1359
+ line-height: 1.5;
1360
+ white-space: pre-wrap;
1361
+ word-break: break-word;
1362
+ }
1363
+ .chat-user {
1364
+ background: var(--sol-blue);
1365
+ color: #fff;
1366
+ align-self: flex-end;
1367
+ border-bottom-right-radius: 3px;
1368
+ }
1369
+ .chat-assistant {
1370
+ background: var(--bg);
1371
+ border: 1px solid var(--border);
1372
+ color: var(--text);
1373
+ align-self: flex-start;
1374
+ border-bottom-left-radius: 3px;
1375
+ }
1376
+ .chat-assistant[data-streaming] { opacity: 0.75; }
1377
+ .chat-error { border-color: var(--sol-red); color: var(--sol-red); }
1378
+ .chat-text { white-space: pre-wrap; word-break: break-word; }
1379
+ .chat-thinking {
1380
+ display: inline-block;
1381
+ font-size: 10px;
1382
+ color: var(--text-muted);
1383
+ font-style: italic;
1384
+ animation: chat-blink 1.2s ease-in-out infinite;
1385
+ }
1386
+ @keyframes chat-blink {
1387
+ 0%, 100% { opacity: 1; }
1388
+ 50% { opacity: 0.35; }
1389
+ }
1390
+
1391
+ /* Undercity-commands executable card */
1392
+ .chat-cmd-card {
1393
+ background: var(--bg);
1394
+ border: 1px solid var(--sol-cyan);
1395
+ border-radius: var(--radius);
1396
+ margin: 6px 0;
1397
+ overflow: hidden;
1398
+ }
1399
+ .chat-cmd-toolbar {
1400
+ display: flex;
1401
+ align-items: center;
1402
+ gap: 6px;
1403
+ padding: 5px 8px;
1404
+ background: rgba(42,161,152,.08);
1405
+ border-bottom: 1px solid transparent;
1406
+ }
1407
+ .chat-cmd-summary {
1408
+ flex: 1;
1409
+ font-size: 10px;
1410
+ font-weight: 700;
1411
+ color: var(--sol-cyan);
1412
+ font-family: 'Fira Code', monospace;
1413
+ }
1414
+ .chat-cmd-toggle {
1415
+ background: none;
1416
+ border: 1px solid var(--border);
1417
+ border-radius: 3px;
1418
+ color: var(--text-muted);
1419
+ font-size: 10px;
1420
+ padding: 1px 5px;
1421
+ cursor: pointer;
1422
+ }
1423
+ .chat-cmd-toggle.active, .chat-cmd-toggle:hover { border-color: var(--sol-cyan); color: var(--sol-cyan); }
1424
+ .chat-cmd-exec {
1425
+ background: var(--sol-cyan);
1426
+ border: none;
1427
+ border-radius: 3px;
1428
+ color: var(--bg);
1429
+ font-size: 10px;
1430
+ font-weight: 700;
1431
+ padding: 3px 10px;
1432
+ cursor: pointer;
1433
+ flex-shrink: 0;
1434
+ }
1435
+ .chat-cmd-exec:hover { filter: brightness(1.15); }
1436
+ .chat-cmd-exec.done { background: var(--sol-green); cursor: default; }
1437
+ .chat-cmd-exec.error { background: var(--sol-red); }
1438
+ .chat-cmd-exec:disabled { cursor: default; }
1439
+ .chat-cmd-rerun {
1440
+ background: none;
1441
+ border: 1px solid var(--sol-cyan);
1442
+ border-radius: 3px;
1443
+ color: var(--sol-cyan);
1444
+ font-size: .72rem;
1445
+ padding: 1px 6px;
1446
+ cursor: pointer;
1447
+ flex-shrink: 0;
1448
+ transition: background .15s, color .15s;
1449
+ }
1450
+ .chat-cmd-rerun:hover { background: var(--sol-cyan); color: var(--sol-base03); }
1451
+ .chat-cmd-rerun.ok { background: var(--sol-green); border-color: var(--sol-green); color: #fff; }
1452
+ .chat-cmd-rerun.error { border-color: var(--sol-red); color: var(--sol-red); }
1453
+ .chat-cmd-pre {
1454
+ margin: 0;
1455
+ padding: 6px 8px;
1456
+ font-size: 10px;
1457
+ font-family: 'Fira Code', monospace;
1458
+ color: var(--text-muted);
1459
+ background: var(--bg);
1460
+ overflow-x: auto;
1461
+ max-height: 160px;
1462
+ }
1463
+ .chat-cmd-error {
1464
+ padding: 5px 8px;
1465
+ color: var(--sol-red);
1466
+ font-size: 11px;
1467
+ }
1468
+
1469
+ #chat-input-row {
1470
+ display: flex;
1471
+ gap: 4px;
1472
+ padding: 6px 8px;
1473
+ border-top: 1px solid var(--border);
1474
+ flex-shrink: 0;
1475
+ }
1476
+ #chat-input {
1477
+ flex: 1;
1478
+ background: var(--bg);
1479
+ border: 1px solid var(--border);
1480
+ border-radius: var(--radius);
1481
+ color: var(--text);
1482
+ font-size: 11px;
1483
+ font-family: inherit;
1484
+ padding: 4px 8px;
1485
+ resize: none;
1486
+ outline: none;
1487
+ }
1488
+ #chat-input:focus { border-color: var(--sol-violet); }
1489
+ #chat-send-btn {
1490
+ background: var(--sol-violet);
1491
+ border: none;
1492
+ border-radius: var(--radius);
1493
+ color: #fff;
1494
+ font-size: 11px;
1495
+ font-weight: 700;
1496
+ padding: 0 10px;
1497
+ cursor: pointer;
1498
+ align-self: flex-end;
1499
+ height: 26px;
1500
+ }
1501
+ #chat-send-btn:disabled { opacity: 0.5; cursor: not-allowed; }