painapple-code 1.0.0__py3-none-any.whl

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 (436) hide show
  1. painapple_code/__init__.py +30 -0
  2. painapple_code/__main__.py +18 -0
  3. painapple_code/_version.py +24 -0
  4. painapple_code/auth_middleware.py +930 -0
  5. painapple_code/cli/__init__.py +204 -0
  6. painapple_code/cli/deploy/__init__.py +15 -0
  7. painapple_code/cli/deploy/claude_seed.py +41 -0
  8. painapple_code/cli/deploy/config.py +260 -0
  9. painapple_code/cli/deploy/container.py +715 -0
  10. painapple_code/cli/deploy/launch.py +163 -0
  11. painapple_code/cli/deploy/runtime.py +223 -0
  12. painapple_code/cli/lifecycle_cmd.py +443 -0
  13. painapple_code/cli/list_cmd.py +572 -0
  14. painapple_code/cli/manage_cmd.py +670 -0
  15. painapple_code/cli/netinfo.py +125 -0
  16. painapple_code/cli/profiles.py +390 -0
  17. painapple_code/cli/serve_args.py +163 -0
  18. painapple_code/cli/serve_config.py +256 -0
  19. painapple_code/cli/setup_cmd.py +664 -0
  20. painapple_code/cli/ui.py +438 -0
  21. painapple_code/cost_analytics.py +879 -0
  22. painapple_code/data/models.defaults.yaml +18 -0
  23. painapple_code/data/models.yaml +18 -0
  24. painapple_code/data/presets.defaults.json +32 -0
  25. painapple_code/data/strings.yaml +2269 -0
  26. painapple_code/helpers.py +406 -0
  27. painapple_code/paths.py +1514 -0
  28. painapple_code/prompt_explorer.py +984 -0
  29. painapple_code/providers/__init__.py +224 -0
  30. painapple_code/providers/base.py +710 -0
  31. painapple_code/providers/claude/__init__.py +74 -0
  32. painapple_code/providers/claude/capabilities.py +218 -0
  33. painapple_code/providers/claude/errors.py +79 -0
  34. painapple_code/providers/claude/launch.py +50 -0
  35. painapple_code/providers/claude/summary.py +89 -0
  36. painapple_code/providers/claude/translate.py +74 -0
  37. painapple_code/providers/claude_sdk/__init__.py +139 -0
  38. painapple_code/providers/claude_sdk/driver.py +412 -0
  39. painapple_code/providers/codex/__init__.py +87 -0
  40. painapple_code/providers/codex/capabilities.py +321 -0
  41. painapple_code/providers/codex/errors.py +70 -0
  42. painapple_code/providers/codex/launch.py +142 -0
  43. painapple_code/providers/codex/summary.py +196 -0
  44. painapple_code/providers/codex/translate.py +204 -0
  45. painapple_code/providers/codex_app_server/__init__.py +100 -0
  46. painapple_code/providers/codex_app_server/capabilities.py +41 -0
  47. painapple_code/providers/codex_app_server/launch.py +202 -0
  48. painapple_code/providers/codex_app_server/summary.py +291 -0
  49. painapple_code/providers/codex_app_server/translate.py +263 -0
  50. painapple_code/providers/codex_app_server/transport.py +238 -0
  51. painapple_code/routes/__init__.py +0 -0
  52. painapple_code/routes/api_agents.py +441 -0
  53. painapple_code/routes/api_app.py +368 -0
  54. painapple_code/routes/api_app_commit_sections.py +127 -0
  55. painapple_code/routes/api_app_config.py +997 -0
  56. painapple_code/routes/api_app_session_prefs.py +217 -0
  57. painapple_code/routes/api_browser.py +690 -0
  58. painapple_code/routes/api_commands.py +374 -0
  59. painapple_code/routes/api_costs.py +128 -0
  60. painapple_code/routes/api_drafts.py +139 -0
  61. painapple_code/routes/api_exec.py +149 -0
  62. painapple_code/routes/api_files.py +542 -0
  63. painapple_code/routes/api_git.py +657 -0
  64. painapple_code/routes/api_logs.py +649 -0
  65. painapple_code/routes/api_plugins.py +275 -0
  66. painapple_code/routes/api_project_config.py +418 -0
  67. painapple_code/routes/api_prompts.py +231 -0
  68. painapple_code/routes/api_providers.py +53 -0
  69. painapple_code/routes/api_search.py +411 -0
  70. painapple_code/routes/api_session_stash.py +234 -0
  71. painapple_code/routes/api_session_welcome.py +151 -0
  72. painapple_code/routes/api_sessions.py +742 -0
  73. painapple_code/routes/api_shadow.py +323 -0
  74. painapple_code/routes/api_shadow_db.py +512 -0
  75. painapple_code/routes/api_shadow_files.py +332 -0
  76. painapple_code/routes/api_shadow_search.py +476 -0
  77. painapple_code/routes/api_skills.py +610 -0
  78. painapple_code/routes/api_tasks.py +147 -0
  79. painapple_code/routes/api_terminal.py +540 -0
  80. painapple_code/routes/api_upload.py +293 -0
  81. painapple_code/routes/api_viewer.py +229 -0
  82. painapple_code/routes/dependencies.py +109 -0
  83. painapple_code/routes/ws_chat.py +837 -0
  84. painapple_code/server.py +2208 -0
  85. painapple_code/server_logging.py +263 -0
  86. painapple_code/services/__init__.py +0 -0
  87. painapple_code/services/agent_session.py +2738 -0
  88. painapple_code/session_store.py +253 -0
  89. painapple_code/session_store_core.py +879 -0
  90. painapple_code/shadow_db.py +830 -0
  91. painapple_code/shadow_db_plans.py +369 -0
  92. painapple_code/shadow_db_queries.py +595 -0
  93. painapple_code/shadow_db_schema.py +676 -0
  94. painapple_code/shadow_git.py +1296 -0
  95. painapple_code/shadow_git_frontmatter.py +314 -0
  96. painapple_code/shadow_git_sections.py +520 -0
  97. painapple_code/shadow_git_summary.py +462 -0
  98. painapple_code/shadow_parser.py +560 -0
  99. painapple_code/static/css/00-variables.css +276 -0
  100. painapple_code/static/css/01-base.css +245 -0
  101. painapple_code/static/css/02-tooltips.css +36 -0
  102. painapple_code/static/css/09-left-rail.css +448 -0
  103. painapple_code/static/css/10-header.css +777 -0
  104. painapple_code/static/css/11-connection-bar.css +120 -0
  105. painapple_code/static/css/20-messages.css +750 -0
  106. painapple_code/static/css/21-tool-blocks.css +2340 -0
  107. painapple_code/static/css/22-edit-diff.css +619 -0
  108. painapple_code/static/css/23-thinking.css +1584 -0
  109. painapple_code/static/css/24-background-tasks.css +359 -0
  110. painapple_code/static/css/25-context-block.css +252 -0
  111. painapple_code/static/css/26-session-setup.css +144 -0
  112. painapple_code/static/css/30-markdown.css +854 -0
  113. painapple_code/static/css/40-input.css +2418 -0
  114. painapple_code/static/css/41-autocomplete.css +127 -0
  115. painapple_code/static/css/42-activity-strip.css +97 -0
  116. painapple_code/static/css/43-file-autocomplete.css +121 -0
  117. painapple_code/static/css/44-snippets-autocomplete.css +224 -0
  118. painapple_code/static/css/45-selection-bar.css +433 -0
  119. painapple_code/static/css/46-keyboard-bar.css +119 -0
  120. painapple_code/static/css/47-keyboard-longpress.css +116 -0
  121. painapple_code/static/css/47-token-profile.css +106 -0
  122. painapple_code/static/css/50-welcome.css +3095 -0
  123. painapple_code/static/css/51-modals.css +301 -0
  124. painapple_code/static/css/52-utilities.css +77 -0
  125. painapple_code/static/css/53-image-upload.css +456 -0
  126. painapple_code/static/css/54-todo-list.css +102 -0
  127. painapple_code/static/css/55-file-upload.css +113 -0
  128. painapple_code/static/css/56-chat-navigator.css +218 -0
  129. painapple_code/static/css/56-permission-card.css +332 -0
  130. painapple_code/static/css/56-plan-approval.css +204 -0
  131. painapple_code/static/css/56-question-form.css +602 -0
  132. painapple_code/static/css/57-swipe-indicator.css +95 -0
  133. painapple_code/static/css/58-session-families.css +627 -0
  134. painapple_code/static/css/59-about.css +196 -0
  135. painapple_code/static/css/61-log-explorer.css +723 -0
  136. painapple_code/static/css/62-json-tree.css +489 -0
  137. painapple_code/static/css/62-skills-widget.css +650 -0
  138. painapple_code/static/css/63-commands-widget.css +30 -0
  139. painapple_code/static/css/63-plugins-widget.css +174 -0
  140. painapple_code/static/css/63-terminal.css +516 -0
  141. painapple_code/static/css/64-search-files-widget.css +448 -0
  142. painapple_code/static/css/65-snippets-widget.css +426 -0
  143. painapple_code/static/css/66-active-sessions.css +979 -0
  144. painapple_code/static/css/66-agents-widget.css +265 -0
  145. painapple_code/static/css/66-file-explorer-widget.css +855 -0
  146. painapple_code/static/css/66-git-panel.css +791 -0
  147. painapple_code/static/css/66-history-explorer.css +1496 -0
  148. painapple_code/static/css/67-diff-viewer.css +602 -0
  149. painapple_code/static/css/67-editor-view.css +748 -0
  150. painapple_code/static/css/67-file-preview-widget.css +1873 -0
  151. painapple_code/static/css/68-browser-widget.css +337 -0
  152. painapple_code/static/css/68-compare-wizard.css +355 -0
  153. painapple_code/static/css/68-csv-preview.css +106 -0
  154. painapple_code/static/css/68-diff-preview.css +103 -0
  155. painapple_code/static/css/68-helpers-install-widget.css +491 -0
  156. painapple_code/static/css/68-image-annotate.css +346 -0
  157. painapple_code/static/css/68-terminal-view.css +98 -0
  158. painapple_code/static/css/68-uploads-widget.css +229 -0
  159. painapple_code/static/css/69-cost-analytics.css +537 -0
  160. painapple_code/static/css/70-config-panel.css +3736 -0
  161. painapple_code/static/css/70-excalidraw.css +136 -0
  162. painapple_code/static/css/70-prompt-explorer.css +890 -0
  163. painapple_code/static/css/71-chart.css +111 -0
  164. painapple_code/static/css/72-discussion-sidebar.css +678 -0
  165. painapple_code/static/css/74-debug-logs.css +656 -0
  166. painapple_code/static/css/80-open-dialog.css +146 -0
  167. painapple_code/static/css/80-quick-switcher.css +383 -0
  168. painapple_code/static/css/80-widget-system.css +1763 -0
  169. painapple_code/static/css/81-quick-actions.css +1020 -0
  170. painapple_code/static/css/82-context-popover.css +1233 -0
  171. painapple_code/static/css/83-context-menu.css +339 -0
  172. painapple_code/static/css/85-lazy-loading.css +102 -0
  173. painapple_code/static/css/86-zen-mode.css +708 -0
  174. painapple_code/static/css/87-grid-switcher.css +346 -0
  175. painapple_code/static/css/login.css +198 -0
  176. painapple_code/static/dist/app.bundle.js +7177 -0
  177. painapple_code/static/feature-triage.html +446 -0
  178. painapple_code/static/icons/apple-touch-icon.png +0 -0
  179. painapple_code/static/icons/favicon-32.png +0 -0
  180. painapple_code/static/icons/favicon.ico +0 -0
  181. painapple_code/static/icons/icon-128.png +0 -0
  182. painapple_code/static/icons/icon-144.png +0 -0
  183. painapple_code/static/icons/icon-152.png +0 -0
  184. painapple_code/static/icons/icon-180.png +0 -0
  185. painapple_code/static/icons/icon-192.png +0 -0
  186. painapple_code/static/icons/icon-384.png +0 -0
  187. painapple_code/static/icons/icon-512.png +0 -0
  188. painapple_code/static/icons/icon-72.png +0 -0
  189. painapple_code/static/icons/icon-96.png +0 -0
  190. painapple_code/static/js/action-delegate.js +187 -0
  191. painapple_code/static/js/activity-strip.js +193 -0
  192. painapple_code/static/js/app/context-menus.js +619 -0
  193. painapple_code/static/js/app/file-preview.js +163 -0
  194. painapple_code/static/js/app/init-ui.js +574 -0
  195. painapple_code/static/js/app/input-events.js +561 -0
  196. painapple_code/static/js/app/input-resize.js +313 -0
  197. painapple_code/static/js/app/message-actions.js +419 -0
  198. painapple_code/static/js/app/panels.js +210 -0
  199. painapple_code/static/js/app/rendering-delegators.js +246 -0
  200. painapple_code/static/js/app/server-loading.js +365 -0
  201. painapple_code/static/js/app/session-ops.js +287 -0
  202. painapple_code/static/js/app/session-switch.js +443 -0
  203. painapple_code/static/js/app/settings-helpers.js +280 -0
  204. painapple_code/static/js/app/startup-welcome.js +290 -0
  205. painapple_code/static/js/app-context.js +157 -0
  206. painapple_code/static/js/app.js +2134 -0
  207. painapple_code/static/js/auth-fetch.js +46 -0
  208. painapple_code/static/js/background-tasks.js +274 -0
  209. painapple_code/static/js/boot.js +73 -0
  210. painapple_code/static/js/caret-position.js +171 -0
  211. painapple_code/static/js/chat-navigator.js +710 -0
  212. painapple_code/static/js/chat-search.js +323 -0
  213. painapple_code/static/js/command-executor.js +176 -0
  214. painapple_code/static/js/command-store.js +497 -0
  215. painapple_code/static/js/components.js +1414 -0
  216. painapple_code/static/js/config.js +218 -0
  217. painapple_code/static/js/context-menu.js +740 -0
  218. painapple_code/static/js/controllers/chat-controller.js +4252 -0
  219. painapple_code/static/js/controllers/dialog-controller.js +217 -0
  220. painapple_code/static/js/controllers/tab-controller.js +1828 -0
  221. painapple_code/static/js/controllers/thinking-controller.js +915 -0
  222. painapple_code/static/js/diff-utils.js +486 -0
  223. painapple_code/static/js/drafts-pill.js +95 -0
  224. painapple_code/static/js/editor-view.js +815 -0
  225. painapple_code/static/js/effort-settings.js +430 -0
  226. painapple_code/static/js/feature-triage.js +811 -0
  227. painapple_code/static/js/file-autocomplete.js +516 -0
  228. painapple_code/static/js/file-tabs.js +123 -0
  229. painapple_code/static/js/gestures.js +448 -0
  230. painapple_code/static/js/grid-switcher.js +334 -0
  231. painapple_code/static/js/input-handler.js +1472 -0
  232. painapple_code/static/js/keyboard-bar.js +495 -0
  233. painapple_code/static/js/layout-switcher.js +109 -0
  234. painapple_code/static/js/linkify-utils.js +200 -0
  235. painapple_code/static/js/login.js +141 -0
  236. painapple_code/static/js/open-dialog.js +879 -0
  237. painapple_code/static/js/orphan-terminals.js +373 -0
  238. painapple_code/static/js/path-utils.js +179 -0
  239. painapple_code/static/js/perf-marks.js +102 -0
  240. painapple_code/static/js/permission-settings.js +475 -0
  241. painapple_code/static/js/pointer-input.js +59 -0
  242. painapple_code/static/js/preview/json-tree-menu.js +226 -0
  243. painapple_code/static/js/preview/json-tree-toolbar.js +291 -0
  244. painapple_code/static/js/preview/json-tree.js +457 -0
  245. painapple_code/static/js/preview/preview-breadcrumb.js +387 -0
  246. painapple_code/static/js/preview/preview-edit.js +367 -0
  247. painapple_code/static/js/preview/preview-events.js +361 -0
  248. painapple_code/static/js/preview/preview-history.js +567 -0
  249. painapple_code/static/js/preview/preview-inline-edit.js +869 -0
  250. painapple_code/static/js/preview/preview-poll.js +108 -0
  251. painapple_code/static/js/preview/preview-render.js +572 -0
  252. painapple_code/static/js/preview/preview-search.js +421 -0
  253. painapple_code/static/js/preview/preview-state.js +256 -0
  254. painapple_code/static/js/preview/preview-utils.js +251 -0
  255. painapple_code/static/js/preview-plugins/chart-plugin.js +22 -0
  256. painapple_code/static/js/preview-plugins/csv-plugin.js +188 -0
  257. painapple_code/static/js/preview-plugins/diff-plugin.js +258 -0
  258. painapple_code/static/js/preview-plugins/excalidraw-plugin.js +25 -0
  259. painapple_code/static/js/preview-plugins/html-plugin.js +104 -0
  260. painapple_code/static/js/preview-plugins/image-plugin.js +20 -0
  261. painapple_code/static/js/preview-plugins/index.js +34 -0
  262. painapple_code/static/js/preview-plugins/json-plugin.js +99 -0
  263. painapple_code/static/js/preview-plugins/jsonl-plugin.js +152 -0
  264. painapple_code/static/js/preview-plugins/markdown-plugin.js +266 -0
  265. painapple_code/static/js/preview-plugins/panzoom-plugin.js +63 -0
  266. painapple_code/static/js/preview-plugins/plugin-helpers.js +282 -0
  267. painapple_code/static/js/project-color-picker.js +110 -0
  268. painapple_code/static/js/project-colors.js +163 -0
  269. painapple_code/static/js/prompt-favorites.js +187 -0
  270. painapple_code/static/js/quick-actions-menu.js +1736 -0
  271. painapple_code/static/js/quick-actions-registry.js +1239 -0
  272. painapple_code/static/js/quick-switcher/controller.js +294 -0
  273. painapple_code/static/js/quick-switcher/fuzzy-scorer.js +123 -0
  274. painapple_code/static/js/quick-switcher/index.js +30 -0
  275. painapple_code/static/js/quick-switcher/providers/base-provider.js +51 -0
  276. painapple_code/static/js/quick-switcher/providers/command-provider.js +56 -0
  277. painapple_code/static/js/quick-switcher/providers/file-provider.js +291 -0
  278. painapple_code/static/js/quick-switcher/providers/panel-provider.js +132 -0
  279. painapple_code/static/js/quick-switcher/providers/project-provider.js +361 -0
  280. painapple_code/static/js/quick-switcher/providers/read-files-provider.js +104 -0
  281. painapple_code/static/js/quick-switcher/providers/skills-provider.js +129 -0
  282. painapple_code/static/js/quick-switcher/registry.js +69 -0
  283. painapple_code/static/js/quick-switcher/ui/item.js +54 -0
  284. painapple_code/static/js/quick-switcher/ui/picker.js +464 -0
  285. painapple_code/static/js/recent-opens.js +40 -0
  286. painapple_code/static/js/scroll-manager.js +530 -0
  287. painapple_code/static/js/scroll-state-machine.js +359 -0
  288. painapple_code/static/js/selection/action-bar.js +793 -0
  289. painapple_code/static/js/selection/index.js +15 -0
  290. painapple_code/static/js/selection/selection-handler.js +877 -0
  291. painapple_code/static/js/selection/state.js +181 -0
  292. painapple_code/static/js/session/agent-progress.js +202 -0
  293. painapple_code/static/js/session/handle-agent-message.js +481 -0
  294. painapple_code/static/js/session/handle-message.js +550 -0
  295. painapple_code/static/js/session/interactive.js +587 -0
  296. painapple_code/static/js/session/message-store.js +271 -0
  297. painapple_code/static/js/session/messages.js +253 -0
  298. painapple_code/static/js/session/persistence.js +179 -0
  299. painapple_code/static/js/session/restore.js +136 -0
  300. painapple_code/static/js/session/sync.js +333 -0
  301. painapple_code/static/js/session-container-pool.js +371 -0
  302. painapple_code/static/js/session-setup-panel.js +274 -0
  303. painapple_code/static/js/session.js +1047 -0
  304. painapple_code/static/js/shortcut-hints.js +272 -0
  305. painapple_code/static/js/shortcuts.js +1146 -0
  306. painapple_code/static/js/skills-autocomplete.js +262 -0
  307. painapple_code/static/js/snippets-autocomplete.js +738 -0
  308. painapple_code/static/js/stash-refs-view.js +83 -0
  309. painapple_code/static/js/stash-ui.js +768 -0
  310. painapple_code/static/js/stash.js +785 -0
  311. painapple_code/static/js/status-bar.js +1184 -0
  312. painapple_code/static/js/token-profile.js +274 -0
  313. painapple_code/static/js/tool-renderer-blocks.js +1626 -0
  314. painapple_code/static/js/tool-renderer-thinking.js +813 -0
  315. painapple_code/static/js/tool-renderer.js +1500 -0
  316. painapple_code/static/js/tooltips.js +197 -0
  317. painapple_code/static/js/upload-manager.js +1019 -0
  318. painapple_code/static/js/utils.js +521 -0
  319. painapple_code/static/js/welcome/api.js +363 -0
  320. painapple_code/static/js/welcome/cards.js +626 -0
  321. painapple_code/static/js/welcome/context-menu.js +585 -0
  322. painapple_code/static/js/welcome/families.js +801 -0
  323. painapple_code/static/js/welcome/preview.js +234 -0
  324. painapple_code/static/js/welcome/state.js +129 -0
  325. painapple_code/static/js/welcome.js +1874 -0
  326. painapple_code/static/js/widget-system/base-widget.js +717 -0
  327. painapple_code/static/js/widget-system/device-manager.js +178 -0
  328. painapple_code/static/js/widget-system/event-bus.js +152 -0
  329. painapple_code/static/js/widget-system/icons.js +120 -0
  330. painapple_code/static/js/widget-system/index.js +49 -0
  331. painapple_code/static/js/widget-system/init.js +54 -0
  332. painapple_code/static/js/widget-system/types/bottom-sheet.js +307 -0
  333. painapple_code/static/js/widget-system/types/floating.js +915 -0
  334. painapple_code/static/js/widget-system/types/index.js +40 -0
  335. painapple_code/static/js/widget-system/types/modal.js +147 -0
  336. painapple_code/static/js/widget-system/types/sidebar.js +158 -0
  337. painapple_code/static/js/widget-system/types/tab.js +146 -0
  338. painapple_code/static/js/widget-system/types/top-sheet.js +203 -0
  339. painapple_code/static/js/widget-system/widget-manager.js +1187 -0
  340. painapple_code/static/js/widgets/about-widget.js +260 -0
  341. painapple_code/static/js/widgets/active-sessions-widget.js +760 -0
  342. painapple_code/static/js/widgets/agents-widget.js +897 -0
  343. painapple_code/static/js/widgets/browser-widget.js +579 -0
  344. painapple_code/static/js/widgets/commands-widget.js +694 -0
  345. painapple_code/static/js/widgets/config/commit-sections.js +449 -0
  346. painapple_code/static/js/widgets/config/dir-autocomplete.js +224 -0
  347. painapple_code/static/js/widgets/config/gestures.js +161 -0
  348. painapple_code/static/js/widgets/config/models-tab.js +988 -0
  349. painapple_code/static/js/widgets/config/quick-actions-tab.js +882 -0
  350. painapple_code/static/js/widgets/config/shortcut-editor.js +587 -0
  351. painapple_code/static/js/widgets/config/state.js +517 -0
  352. painapple_code/static/js/widgets/config/system-controls.js +90 -0
  353. painapple_code/static/js/widgets/config-widget.js +1535 -0
  354. painapple_code/static/js/widgets/cost-analytics-widget.js +621 -0
  355. painapple_code/static/js/widgets/debug-widget.js +693 -0
  356. painapple_code/static/js/widgets/diff-viewer-widget.js +1420 -0
  357. painapple_code/static/js/widgets/discussion-widget.js +1107 -0
  358. painapple_code/static/js/widgets/file-explorer-widget.js +2166 -0
  359. painapple_code/static/js/widgets/file-preview-widget.js +861 -0
  360. painapple_code/static/js/widgets/git-widget.js +794 -0
  361. painapple_code/static/js/widgets/helpers-install-widget.js +720 -0
  362. painapple_code/static/js/widgets/history-explorer-widget.js +1804 -0
  363. painapple_code/static/js/widgets/image-annotate-widget.js +951 -0
  364. painapple_code/static/js/widgets/image-preview-widget.js +692 -0
  365. painapple_code/static/js/widgets/index.js +176 -0
  366. painapple_code/static/js/widgets/log-explorer-widget.js +1057 -0
  367. painapple_code/static/js/widgets/plugins-widget.js +305 -0
  368. painapple_code/static/js/widgets/prompt-explorer-widget.js +1119 -0
  369. painapple_code/static/js/widgets/search-files-widget.js +529 -0
  370. painapple_code/static/js/widgets/skills-widget.js +843 -0
  371. painapple_code/static/js/widgets/snippets-widget.js +479 -0
  372. painapple_code/static/js/widgets/sub-agents-widget.js +333 -0
  373. painapple_code/static/js/widgets/tasks-widget.js +379 -0
  374. painapple_code/static/js/widgets/terminal/connection.js +283 -0
  375. painapple_code/static/js/widgets/terminal/gestures.js +357 -0
  376. painapple_code/static/js/widgets/terminal/init.js +642 -0
  377. painapple_code/static/js/widgets/terminal/link-providers.js +532 -0
  378. painapple_code/static/js/widgets/terminal/osc52.js +213 -0
  379. painapple_code/static/js/widgets/terminal/render.js +159 -0
  380. painapple_code/static/js/widgets/terminal/size.js +54 -0
  381. painapple_code/static/js/widgets/terminal/state.js +211 -0
  382. painapple_code/static/js/widgets/terminal/wrap-utils.js +101 -0
  383. painapple_code/static/js/widgets/terminal-widget.js +793 -0
  384. painapple_code/static/js/widgets/uploads-widget.js +461 -0
  385. painapple_code/static/js/widgets/zen-widget.js +1001 -0
  386. painapple_code/static/login.html +51 -0
  387. painapple_code/static/manifest.json +73 -0
  388. painapple_code/static/sw.js +293 -0
  389. painapple_code/static/vendor/LICENSES.txt +769 -0
  390. painapple_code/static/vendor/README.md +103 -0
  391. painapple_code/static/vendor/codemirror.js +35 -0
  392. painapple_code/static/vendor/codemirror.js.LEGAL.txt +304 -0
  393. painapple_code/static/vendor/github-markdown-dark.min.css +1124 -0
  394. painapple_code/static/vendor/highlight-github-dark.min.css +10 -0
  395. painapple_code/static/vendor/highlight-lang-dockerfile.min.js +8 -0
  396. painapple_code/static/vendor/highlight-lang-nginx.min.js +21 -0
  397. painapple_code/static/vendor/highlight-lang-properties.min.js +10 -0
  398. painapple_code/static/vendor/highlight-lang-scala.min.js +28 -0
  399. painapple_code/static/vendor/highlight.min.js +1213 -0
  400. painapple_code/static/vendor/marked.min.js +6 -0
  401. painapple_code/static/vendor/purify.min.js +3 -0
  402. painapple_code/static/vendor/xterm-addon-fit.js +2 -0
  403. painapple_code/static/vendor/xterm.css +209 -0
  404. painapple_code/static/vendor/xterm.js +2 -0
  405. painapple_code/static/web-client.html +635 -0
  406. painapple_code/subprocess_registry.py +535 -0
  407. painapple_code/tls_cert.py +79 -0
  408. painapple_code/tools/agents/shadow-git-helper.md +400 -0
  409. painapple_code/tools/excalidraw-to-svg.js +143 -0
  410. painapple_code/tools/install-helpers.sh +148 -0
  411. painapple_code/tools/shadow-git +320 -0
  412. painapple_code/tools/shadow-query +120 -0
  413. painapple_code/tools/vegalite-to-svg.js +79 -0
  414. painapple_code/turn_query.py +766 -0
  415. painapple_code/turn_tracker.py +221 -0
  416. painapple_code/utils/__init__.py +0 -0
  417. painapple_code/utils/agent_cli.py +306 -0
  418. painapple_code/utils/chart.py +103 -0
  419. painapple_code/utils/excalidraw.py +107 -0
  420. painapple_code/utils/file_lock.py +162 -0
  421. painapple_code/utils/file_paths.py +648 -0
  422. painapple_code/utils/generate_icons.py +251 -0
  423. painapple_code/utils/proc.py +205 -0
  424. painapple_code/utils/pty_backend.py +59 -0
  425. painapple_code/utils/pty_posix.py +160 -0
  426. painapple_code/utils/pty_windows.py +245 -0
  427. painapple_code/utils/token_profiles.py +91 -0
  428. painapple_code/viewer_templates.py +657 -0
  429. painapple_code/welcome_search.py +879 -0
  430. painapple_code-1.0.0.dist-info/METADATA +292 -0
  431. painapple_code-1.0.0.dist-info/RECORD +436 -0
  432. painapple_code-1.0.0.dist-info/WHEEL +5 -0
  433. painapple_code-1.0.0.dist-info/entry_points.txt +2 -0
  434. painapple_code-1.0.0.dist-info/licenses/LICENSE +661 -0
  435. painapple_code-1.0.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +261 -0
  436. painapple_code-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,276 @@
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ CSS VARIABLES
3
+ ═══════════════════════════════════════════════════════════════════ */
4
+ :root {
5
+ /* Font scale factor (1.0 = 100%) - controlled by JS */
6
+ --font-scale: 1;
7
+
8
+ --bg-primary: #0d1117;
9
+ --bg-secondary: #161b22;
10
+ --bg-tertiary: #21262d;
11
+ --bg-hover: #30363d;
12
+ --bg-active: #388bfd22;
13
+
14
+ --border-primary: #30363d;
15
+ --border-secondary: #21262d;
16
+
17
+ --text-primary: #e6edf3;
18
+ --text-secondary: #8b949e;
19
+ --text-muted: #6e7681;
20
+
21
+ --accent: #58a6ff;
22
+ --accent-hover: #79b8ff;
23
+ --accent-muted: #388bfd44;
24
+ --accent-rgb: 88, 166, 255; /* rgb triplet of --accent, for rgba() tints;
25
+ kept in sync by applyInstanceConfig() */
26
+
27
+ --success: #3fb950;
28
+ --warning: #d29922;
29
+ --error: #f85149;
30
+
31
+ /* Semantic color palette — data viz, file types, git statuses, tag chips.
32
+ These stay FIXED across instances. For interactive accents (focus,
33
+ selection, links, active states) use --accent — it follows the
34
+ per-instance color (green/red/orange/gray). */
35
+ --accent-blue: #58a6ff;
36
+ --accent-green: #22c55e;
37
+ --accent-yellow: #f0a020;
38
+ --accent-orange: #f59e0b;
39
+ --accent-red: #ef4444;
40
+ --accent-purple: #8b5cf6;
41
+
42
+ /* Stash comment-bubble glyphs. Used as mask-image so background-color
43
+ tints them — an emoji renders in its own fixed colours and can't be
44
+ recoloured, which is why the commented state used to need a translucent
45
+ disc behind it. Same rounded-bubble silhouette in both states so the
46
+ "has a comment" change reads purely as a colour change:
47
+ outline = no comment yet (grey), filled = has a comment (violet).
48
+ A *filled circle* bubble was rejected here: at the ~11px render size it
49
+ reads as an anonymous dot rather than a comment mark. */
50
+ --stash-bubble-glyph-outline: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 3h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9l-5 4.5V17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z'/%3E%3C/svg%3E");
51
+ --stash-bubble-glyph-filled: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' fill-rule='evenodd' d='M4 3h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9l-5 4.5V17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm2.5 4.2h11v2.2h-11V7.2zm0 4.4h7v2.2h-7v-2.2z'/%3E%3C/svg%3E");
52
+
53
+ --user-bg: #1c3a5f;
54
+ --assistant-bg: #161b22;
55
+ --system-bg: transparent;
56
+ --tool-bg: #1c2128;
57
+ --tool-border: #f7830888;
58
+
59
+ --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
60
+ --font-mono: 'SF Mono', 'Fira Code', 'JetBrains Mono', Consolas, monospace;
61
+
62
+ /* Font-size scale (everything × --font-scale so the font-size setting
63
+ reaches the whole UI). base = UI default; content = reading surfaces
64
+ (chat bubbles, thinking, zen) which sit one step larger. */
65
+ --font-size-xs: calc(11px * var(--font-scale));
66
+ --font-size-sm: calc(12px * var(--font-scale));
67
+ --font-size-base: calc(13px * var(--font-scale));
68
+ --font-size-md: calc(14px * var(--font-scale));
69
+ --font-size-content: calc(15px * var(--font-scale));
70
+ --font-size-lg: calc(16px * var(--font-scale));
71
+ --font-size-xl: calc(20px * var(--font-scale));
72
+
73
+ /* Corner radius scale. Deliberately squarish — this app avoids heavy
74
+ rounding. Always use these vars, never hardcoded px (circles/toggle
75
+ knobs keep 50%/999px). */
76
+ --radius-xs: 2px;
77
+ --radius-sm: 3px;
78
+ --radius-md: 5px;
79
+ --radius-lg: 8px;
80
+
81
+ --shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
82
+
83
+ --input-height: 60px;
84
+
85
+ /* Dynamic: updated by JS when input area resizes */
86
+ --input-area-height: 80px;
87
+
88
+ /* Floating buttons (FAB, chat navigator) inactive opacity - controlled by JS */
89
+ --floating-opacity-inactive: 0.7;
90
+
91
+ /* ═══════════════════════════════════════════════════════════════════
92
+ Z-INDEX SCALE
93
+ See docs-ai/z-index-guide.md for full documentation
94
+ ═══════════════════════════════════════════════════════════════════ */
95
+
96
+ /* Internal element layering (within components) */
97
+ --z-internal: 1;
98
+ --z-internal-raised: 10;
99
+
100
+ /* Base UI elements */
101
+ --z-base-ui: 100;
102
+ --z-base-ui-raised: 150;
103
+
104
+ /* Legacy panels (terminal, git, changes, log-explorer) */
105
+ --z-panel-git: 840;
106
+ --z-panel-changes: 850;
107
+ --z-panel-terminal: 900;
108
+ --z-panel-log: 999;
109
+
110
+ /* Widget system (see 80-widget-system.css for widget-specific vars) */
111
+ --z-widget-base: 1100;
112
+ --z-widget-max: 1700;
113
+
114
+ /* Overlays (dropdowns, context menus, popovers) */
115
+ --z-overlay: 2000;
116
+ --z-overlay-submenu: 2100;
117
+ --z-overlay-autocomplete: 2500;
118
+
119
+ /* Mobile rail drawer (above content, below modals) */
120
+ --z-rail-scrim: 1990;
121
+ --z-rail-drawer: 2000;
122
+
123
+ /* Modals (dialogs requiring attention) */
124
+ --z-modal: 3000;
125
+ --z-modal-backdrop: 2900;
126
+
127
+ /* Always-on-top UI (must be visible above everything) */
128
+ --z-always-top: 4000;
129
+ --z-always-top-fab: 4500;
130
+ --z-always-top-keyboard: 4500;
131
+ /* Selection panel: above the FAB (it overlaps it bottom-right),
132
+ still below ephemeral feedback so its own tooltips stay visible */
133
+ --z-selection-panel: 4600;
134
+
135
+ /* Ephemeral feedback (toasts, tooltips) */
136
+ --z-toast: 5000;
137
+ --z-tooltip: 5000;
138
+ }
139
+
140
+ /* ═══════════════════════════════════════════════════════════════════
141
+ LAYOUT MODES: compact | normal | spacious
142
+ Set via <html data-layout="...">. Two var families respond:
143
+ --sp-N numeric spacing scale — N is the pixel value in NORMAL mode.
144
+ Use for any whitespace that should breathe with density:
145
+ padding, gap, margin, row height. Do NOT use for alignment
146
+ geometry, popup positioning offsets, or icon dimensions.
147
+ --layout-* semantic tokens for the core chat surfaces (header,
148
+ messages, input, tool blocks).
149
+ Full rules: docs-ai/layout-density-guide.md
150
+
151
+ @generated by tools/gen_density_css.py from tools/design-tokens.yaml — edit the YAML
152
+ and regenerate; do not hand-edit below this banner.
153
+ ═══════════════════════════════════════════════════════════════════ */
154
+
155
+ /* Default: normal layout */
156
+ :root {
157
+ --sp-2: 2px;
158
+ --sp-3: 3px;
159
+ --sp-4: 4px;
160
+ --sp-5: 5px;
161
+ --sp-6: 6px;
162
+ --sp-8: 8px;
163
+ --sp-10: 10px;
164
+ --sp-12: 12px;
165
+ --sp-14: 14px;
166
+ --sp-16: 16px;
167
+ --sp-20: 20px;
168
+ --sp-24: 24px;
169
+ --sp-32: 32px;
170
+ --sp-48: 48px;
171
+
172
+ --layout-header-height: 44px;
173
+ --layout-widget-header-height: 40px;
174
+ --layout-content-padding: 14px;
175
+ --layout-gap-xs: 4px;
176
+ --layout-gap-sm: 6px;
177
+ --layout-gap-md: 10px;
178
+ --layout-gap-lg: 14px;
179
+ --layout-msg-padding-v: 8px;
180
+ --layout-msg-padding-h: 12px;
181
+ --layout-msg-radius: var(--radius-md);
182
+ --layout-line-height: 1.5;
183
+ --layout-line-height-tight: 1.4;
184
+ --layout-menu-line-height: 1.4;
185
+ --layout-btn-xs: 20px;
186
+ --layout-btn-sm: 28px;
187
+ --layout-btn-md: 32px;
188
+ --layout-btn-lg: 36px;
189
+ --layout-input-padding-v: 10px;
190
+ --layout-input-padding-h: 16px;
191
+ --layout-tool-padding: 8px 12px;
192
+ --layout-block-margin: 8px;
193
+ --layout-paragraph-margin: 6px;
194
+ }
195
+
196
+ /* Compact layout - minimal spacing */
197
+ [data-layout="compact"] {
198
+ --sp-2: 1px;
199
+ --sp-3: 2px;
200
+ --sp-4: 2px;
201
+ --sp-5: 3px;
202
+ --sp-6: 4px;
203
+ --sp-8: 5px;
204
+ --sp-10: 6px;
205
+ --sp-12: 8px;
206
+ --sp-14: 8px;
207
+ --sp-16: 10px;
208
+ --sp-20: 13px;
209
+ --sp-24: 15px;
210
+ --sp-32: 20px;
211
+ --sp-48: 30px;
212
+
213
+ --layout-header-height: 36px;
214
+ --layout-widget-header-height: 34px;
215
+ --layout-content-padding: 8px;
216
+ --layout-gap-xs: 2px;
217
+ --layout-gap-sm: 4px;
218
+ --layout-gap-md: 6px;
219
+ --layout-gap-lg: 8px;
220
+ --layout-msg-padding-v: 5px;
221
+ --layout-msg-padding-h: 8px;
222
+ --layout-msg-radius: var(--radius-sm);
223
+ --layout-line-height: 1.35;
224
+ --layout-line-height-tight: 1.3;
225
+ --layout-menu-line-height: 1.2;
226
+ --layout-btn-xs: 18px;
227
+ --layout-btn-sm: 24px;
228
+ --layout-btn-md: 28px;
229
+ --layout-btn-lg: 32px;
230
+ --layout-input-padding-v: 6px;
231
+ --layout-input-padding-h: 12px;
232
+ --layout-tool-padding: 5px 8px;
233
+ --layout-block-margin: 4px;
234
+ --layout-paragraph-margin: 3px;
235
+ }
236
+
237
+ /* Spacious layout - comfortable spacing */
238
+ [data-layout="spacious"] {
239
+ --sp-2: 3px;
240
+ --sp-3: 4px;
241
+ --sp-4: 6px;
242
+ --sp-5: 7px;
243
+ --sp-6: 9px;
244
+ --sp-8: 11px;
245
+ --sp-10: 14px;
246
+ --sp-12: 16px;
247
+ --sp-14: 19px;
248
+ --sp-16: 22px;
249
+ --sp-20: 27px;
250
+ --sp-24: 32px;
251
+ --sp-32: 42px;
252
+ --sp-48: 62px;
253
+
254
+ --layout-header-height: 52px;
255
+ --layout-widget-header-height: 46px;
256
+ --layout-content-padding: 20px;
257
+ --layout-gap-xs: 6px;
258
+ --layout-gap-sm: 10px;
259
+ --layout-gap-md: 14px;
260
+ --layout-gap-lg: 20px;
261
+ --layout-msg-padding-v: 12px;
262
+ --layout-msg-padding-h: 16px;
263
+ --layout-msg-radius: var(--radius-lg);
264
+ --layout-line-height: 1.6;
265
+ --layout-line-height-tight: 1.5;
266
+ --layout-menu-line-height: 1.5;
267
+ --layout-btn-xs: 24px;
268
+ --layout-btn-sm: 32px;
269
+ --layout-btn-md: 38px;
270
+ --layout-btn-lg: 44px;
271
+ --layout-input-padding-v: 14px;
272
+ --layout-input-padding-h: 20px;
273
+ --layout-tool-padding: 10px 14px;
274
+ --layout-block-margin: 12px;
275
+ --layout-paragraph-margin: 8px;
276
+ }
@@ -0,0 +1,245 @@
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ RESET & BASE
3
+ ═══════════════════════════════════════════════════════════════════ */
4
+ *, *::before, *::after {
5
+ box-sizing: border-box;
6
+ margin: 0;
7
+ padding: 0;
8
+ }
9
+
10
+ html, body {
11
+ height: 100%;
12
+ overflow: hidden;
13
+ /* Kill iPadOS text autosizing ("font boosting"): WKWebView inflates text
14
+ inside blocks wider than the viewport (e.g. max-content diff hunks),
15
+ scaling each block by its width. We own the type scale — never adjust. */
16
+ -webkit-text-size-adjust: 100%;
17
+ text-size-adjust: 100%;
18
+ /* Prevent browser's swipe-to-navigate gesture */
19
+ overscroll-behavior-x: none;
20
+ /* Disable pan gestures that could trigger browser navigation */
21
+ touch-action: pan-y pinch-zoom;
22
+ }
23
+
24
+ body {
25
+ font-family: var(--font-sans);
26
+ font-size: var(--font-size-md);
27
+ line-height: 1.5;
28
+ background: var(--bg-primary);
29
+ color: var(--text-primary);
30
+ /* App-shell selection model: the chrome (buttons, toolbars, tab strip,
31
+ status bar, rail, labels) is NOT text-selectable — on iPad a double-tap
32
+ or drag would otherwise blue-highlight button labels ("Edit"/"History").
33
+ Real content re-enables selection below. Widgets portal to document.body
34
+ (siblings of #app), so this default reaches them too. */
35
+ user-select: none;
36
+ -webkit-user-select: none;
37
+ -webkit-touch-callout: none;
38
+ }
39
+
40
+ /* ─────────────────────────────────────────────────────────────────────
41
+ Selectable content — opt back IN everywhere the user needs to copy.
42
+ More-specific chrome rules inside these (e.g. .tool-header, .line-number,
43
+ .sbs-linenum, .json-toggle, .stash-bubble) keep their own user-select:none.
44
+ ───────────────────────────────────────────────────────────────────── */
45
+ .message-content,
46
+ .markdown-content,
47
+ .tool-content,
48
+ .tool-output,
49
+ .bash-output,
50
+ .line-content,
51
+ .preview-rendered,
52
+ .preview-fm-fields,
53
+ .sbs-text,
54
+ .he-diff-content,
55
+ .he-diff-line,
56
+ .git-diff-container,
57
+ .git-diff-line,
58
+ .cm-editor,
59
+ .cm-content,
60
+ .json-key,
61
+ .json-string,
62
+ .json-number,
63
+ .json-bool,
64
+ .json-null,
65
+ .jsonl-row-content,
66
+ .pe-card-content,
67
+ .pe-response-text,
68
+ .cost-value,
69
+ .stat-value,
70
+ .metric-value,
71
+ .sf-line-text,
72
+ .logs-content,
73
+ .log-raw-item,
74
+ input,
75
+ textarea,
76
+ select,
77
+ #message-input,
78
+ [contenteditable="true"],
79
+ [contenteditable=""] {
80
+ user-select: text;
81
+ -webkit-user-select: text;
82
+ -webkit-touch-callout: default;
83
+ }
84
+
85
+ /* ─────────────────────────────────────────────────────────────────────
86
+ Images opt back into the native iOS long-press callout ("Copy Image",
87
+ "Save to Photos", "Share"). This is the ONLY way to copy image bytes on
88
+ an iPad PWA — navigator.clipboard.write() rejects image blobs inside
89
+ standalone WKWebView, so the app's own "Copy Image" can't work there.
90
+ The app's custom long-press menus stand down on touch (see
91
+ lastInputWasTouch() in context-menu.js) so the two never compete;
92
+ desktop right-click still gets the richer app menu.
93
+ ───────────────────────────────────────────────────────────────────── */
94
+ .uploads-thumb img,
95
+ .img-preview-main {
96
+ -webkit-touch-callout: default;
97
+ /* WebKit suppresses the image callout when selection is off, even
98
+ though an <img> has no selectable text of its own. */
99
+ user-select: auto;
100
+ -webkit-user-select: auto;
101
+ }
102
+
103
+ /* Buttons render the app font instead of the UA default (Arial @ 13.33px).
104
+ Weakest possible selector — any classed rule still wins. */
105
+ button {
106
+ font-family: inherit;
107
+ font-size: var(--font-size-base);
108
+ }
109
+
110
+ /* iOS: Reduce form accessory bar interference */
111
+ input, textarea {
112
+ /* Prevent text size adjustment on orientation change */
113
+ -webkit-text-size-adjust: 100%;
114
+ }
115
+
116
+ /* Remove iOS default styling for text inputs only (not checkboxes/radios) */
117
+ input:not([type="checkbox"]):not([type="radio"]),
118
+ textarea {
119
+ -webkit-appearance: none;
120
+ -moz-appearance: none;
121
+ appearance: none;
122
+ }
123
+
124
+ /* Prevent iOS zoom on input focus (font-size >= 16px) */
125
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
126
+ input, textarea, select {
127
+ font-size: var(--font-size-lg);
128
+ }
129
+ }
130
+
131
+ /* ═══════════════════════════════════════════════════════════════════
132
+ LAYOUT
133
+ ═══════════════════════════════════════════════════════════════════ */
134
+ #app {
135
+ display: flex;
136
+ flex-direction: column;
137
+ height: 100%;
138
+ }
139
+
140
+ /* Per-instance accent stripe at top of viewport (set by --instance-name flag) */
141
+ .instance-stripe {
142
+ height: 3px;
143
+ flex-shrink: 0;
144
+ /* background color set inline by JS from INSTANCE.accent */
145
+ }
146
+
147
+ /* ═══════════════════════════════════════════════════════════════════
148
+ IMAGE VIEWER (for file tabs - viewing full images with zoom)
149
+ ═══════════════════════════════════════════════════════════════════ */
150
+ .image-viewer {
151
+ flex: 1;
152
+ min-height: 0;
153
+ display: flex;
154
+ flex-direction: column;
155
+ background: var(--bg-tertiary);
156
+ position: relative;
157
+ }
158
+
159
+ .image-viewer-toolbar {
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ gap: var(--sp-8);
164
+ padding: var(--sp-8) var(--sp-12);
165
+ background: var(--bg-secondary);
166
+ border-bottom: 1px solid var(--border-color);
167
+ flex-shrink: 0;
168
+ }
169
+
170
+ .image-viewer-toolbar button {
171
+ background: var(--bg-tertiary);
172
+ border: 1px solid var(--border-color);
173
+ color: var(--text-primary);
174
+ padding: var(--sp-4) var(--sp-10);
175
+ border-radius: var(--radius-sm);
176
+ cursor: pointer;
177
+ font-size: var(--font-size-md);
178
+ min-width: 32px;
179
+ }
180
+
181
+ .image-viewer-toolbar button:hover {
182
+ background: var(--bg-hover);
183
+ }
184
+
185
+ .image-viewer-toolbar button:active {
186
+ background: var(--accent);
187
+ }
188
+
189
+ .image-viewer-zoom-level {
190
+ font-size: var(--font-size-sm);
191
+ color: var(--text-secondary);
192
+ min-width: 50px;
193
+ text-align: center;
194
+ font-variant-numeric: tabular-nums;
195
+ }
196
+
197
+ .image-viewer-container {
198
+ flex: 1;
199
+ overflow: auto;
200
+ overscroll-behavior: contain;
201
+ padding: var(--sp-16);
202
+ cursor: grab;
203
+ /* When zoomed: normal block layout for scrolling */
204
+ }
205
+
206
+ .image-viewer-container:active {
207
+ cursor: grabbing;
208
+ }
209
+
210
+ .image-viewer-container.fit-mode {
211
+ /* When fit: center the image */
212
+ display: flex;
213
+ align-items: center;
214
+ justify-content: center;
215
+ cursor: zoom-in;
216
+ }
217
+
218
+ .image-viewer img {
219
+ border-radius: var(--radius-sm);
220
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
221
+ /* Dimensions set by JS for zoom, no max constraints */
222
+ flex-shrink: 0;
223
+ }
224
+
225
+ .image-viewer-container.fit-mode img {
226
+ max-width: 100%;
227
+ max-height: 100%;
228
+ object-fit: contain;
229
+ /* Reset explicit dimensions in fit mode */
230
+ width: auto !important;
231
+ height: auto !important;
232
+ }
233
+
234
+
235
+ /* ─────────────────────────────────────────────────────────────────────
236
+ Native form controls follow the instance accent.
237
+ Without this, checkboxes/radios/sliders render the browser-default
238
+ blue regardless of the per-instance color (green/red/orange/gray).
239
+ ───────────────────────────────────────────────────────────────────── */
240
+ input[type="checkbox"],
241
+ input[type="radio"],
242
+ input[type="range"],
243
+ progress {
244
+ accent-color: var(--accent);
245
+ }
@@ -0,0 +1,36 @@
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ TOOLTIP SYSTEM
3
+ JS-driven tooltips using position:fixed (immune to overflow clipping).
4
+ CSS only provides styling for the tooltip element created by tooltips.js.
5
+
6
+ Usage:
7
+ <button data-tooltip="Hello">Click</button>
8
+ <button data-tooltip="Hello" data-tooltip-position="right">Click</button>
9
+ ═══════════════════════════════════════════════════════════════════ */
10
+
11
+ /* Tooltip element (created by tooltips.js, appended to body)
12
+ Pinned at top:0/left:0 — JS moves it with `transform: translate3d`.
13
+ Position writes via transform are compositor-only and do NOT
14
+ invalidate the WebKit selection/caret paint layer (left/top do). */
15
+ .tooltip-fixed {
16
+ position: fixed;
17
+ top: 0;
18
+ left: 0;
19
+ padding: var(--sp-4) var(--sp-8);
20
+ background: var(--bg-primary);
21
+ border: 1px solid var(--border-primary);
22
+ border-radius: var(--radius-sm);
23
+ font-size: var(--font-size-sm);
24
+ color: var(--text-secondary);
25
+ white-space: nowrap;
26
+ pointer-events: none;
27
+ z-index: var(--z-tooltip);
28
+ line-height: 1.4;
29
+ opacity: 0;
30
+ transition: opacity 0.12s ease;
31
+ will-change: transform, opacity;
32
+ }
33
+
34
+ .tooltip-fixed.visible {
35
+ opacity: 1;
36
+ }