quantum-framework 0.18.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 (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,2058 @@
1
+ /**
2
+ * Quantum Admin 2.0 - Dark Theme
3
+ * Semantic CSS without Tailwind
4
+ */
5
+
6
+ /* ============================================================================
7
+ DESIGN TOKENS
8
+ ============================================================================ */
9
+
10
+ :root {
11
+ /* Primary Colors - Purple accent */
12
+ --q-primary-50: #faf5ff;
13
+ --q-primary-100: #f3e8ff;
14
+ --q-primary-200: #e9d5ff;
15
+ --q-primary-300: #d8b4fe;
16
+ --q-primary-400: #c084fc;
17
+ --q-primary-500: #a855f7;
18
+ --q-primary-600: #9333ea;
19
+ --q-primary-700: #7c3aed;
20
+ --q-primary-800: #6b21a8;
21
+ --q-primary-900: #581c87;
22
+
23
+ /* Status Colors */
24
+ --q-success: #22c55e;
25
+ --q-success-dim: rgba(34, 197, 94, 0.15);
26
+ --q-warning: #f59e0b;
27
+ --q-warning-dim: rgba(245, 158, 11, 0.15);
28
+ --q-danger: #ef4444;
29
+ --q-danger-dim: rgba(239, 68, 68, 0.15);
30
+ --q-info: #3b82f6;
31
+ --q-info-dim: rgba(59, 130, 246, 0.15);
32
+
33
+ /* Dark Theme Colors */
34
+ --q-bg-base: #0a0a0f;
35
+ --q-bg-raised: #12121a;
36
+ --q-bg-overlay: #1a1a24;
37
+ --q-bg-elevated: #22222e;
38
+ --q-bg-hover: #2a2a38;
39
+
40
+ --q-border: #2a2a38;
41
+ --q-border-light: #1f1f2a;
42
+ --q-border-focus: var(--q-primary-500);
43
+
44
+ --q-text-primary: #f8fafc;
45
+ --q-text-secondary: #a1a1aa;
46
+ --q-text-muted: #71717a;
47
+ --q-text-dim: #52525b;
48
+
49
+ /* Typography */
50
+ --q-font-sans: 'Inter', system-ui, -apple-system, sans-serif;
51
+ --q-font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
52
+
53
+ --q-text-xs: 0.75rem;
54
+ --q-text-sm: 0.875rem;
55
+ --q-text-base: 1rem;
56
+ --q-text-lg: 1.125rem;
57
+ --q-text-xl: 1.25rem;
58
+ --q-text-2xl: 1.5rem;
59
+ --q-text-3xl: 1.875rem;
60
+
61
+ /* Spacing */
62
+ --q-space-1: 0.25rem;
63
+ --q-space-2: 0.5rem;
64
+ --q-space-3: 0.75rem;
65
+ --q-space-4: 1rem;
66
+ --q-space-5: 1.25rem;
67
+ --q-space-6: 1.5rem;
68
+ --q-space-8: 2rem;
69
+ --q-space-10: 2.5rem;
70
+ --q-space-12: 3rem;
71
+
72
+ /* Radii */
73
+ --q-radius-sm: 4px;
74
+ --q-radius-md: 6px;
75
+ --q-radius-lg: 8px;
76
+ --q-radius-xl: 12px;
77
+ --q-radius-2xl: 16px;
78
+ --q-radius-full: 9999px;
79
+
80
+ /* Shadows (for dark theme, use glows) */
81
+ --q-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
82
+ --q-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
83
+ --q-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
84
+ --q-glow-primary: 0 0 20px rgba(168, 85, 247, 0.3);
85
+
86
+ /* Layout */
87
+ --qa-sidebar-width: 260px;
88
+ --qa-header-height: 56px;
89
+ }
90
+
91
+ /* ============================================================================
92
+ BASE STYLES
93
+ ============================================================================ */
94
+
95
+ *, *::before, *::after {
96
+ box-sizing: border-box;
97
+ margin: 0;
98
+ padding: 0;
99
+ }
100
+
101
+ html {
102
+ font-size: 16px;
103
+ -webkit-font-smoothing: antialiased;
104
+ -moz-osx-font-smoothing: grayscale;
105
+ }
106
+
107
+ body {
108
+ font-family: var(--q-font-sans);
109
+ font-size: var(--q-text-sm);
110
+ line-height: 1.5;
111
+ color: var(--q-text-primary);
112
+ background: var(--q-bg-base);
113
+ min-height: 100vh;
114
+ }
115
+
116
+ a {
117
+ color: var(--q-primary-400);
118
+ text-decoration: none;
119
+ }
120
+
121
+ a:hover {
122
+ color: var(--q-primary-300);
123
+ }
124
+
125
+ /* ============================================================================
126
+ LAYOUT
127
+ ============================================================================ */
128
+
129
+ .qa-layout {
130
+ display: flex;
131
+ min-height: 100vh;
132
+ }
133
+
134
+ /* Sidebar */
135
+ .qa-sidebar {
136
+ width: var(--qa-sidebar-width);
137
+ background: var(--q-bg-raised);
138
+ border-right: 1px solid var(--q-border);
139
+ position: fixed;
140
+ left: 0;
141
+ top: 0;
142
+ bottom: 0;
143
+ display: flex;
144
+ flex-direction: column;
145
+ z-index: 40;
146
+ }
147
+
148
+ .qa-sidebar-header {
149
+ padding: var(--q-space-5);
150
+ border-bottom: 1px solid var(--q-border-light);
151
+ }
152
+
153
+ .qa-sidebar-logo {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: var(--q-space-3);
157
+ text-decoration: none;
158
+ }
159
+
160
+ .qa-sidebar-logo-icon {
161
+ width: 36px;
162
+ height: 36px;
163
+ background: linear-gradient(135deg, var(--q-primary-500), var(--q-primary-700));
164
+ border-radius: var(--q-radius-lg);
165
+ display: flex;
166
+ align-items: center;
167
+ justify-content: center;
168
+ color: white;
169
+ font-weight: 700;
170
+ font-size: var(--q-text-base);
171
+ box-shadow: var(--q-glow-primary);
172
+ }
173
+
174
+ .qa-sidebar-logo-text {
175
+ font-weight: 700;
176
+ font-size: var(--q-text-lg);
177
+ color: var(--q-text-primary);
178
+ }
179
+
180
+ .qa-sidebar-version {
181
+ font-size: var(--q-text-xs);
182
+ color: var(--q-text-muted);
183
+ margin-left: var(--q-space-1);
184
+ }
185
+
186
+ .qa-sidebar-nav {
187
+ padding: var(--q-space-3);
188
+ flex: 1;
189
+ overflow-y: auto;
190
+ }
191
+
192
+ .qa-sidebar-section {
193
+ margin-top: var(--q-space-6);
194
+ }
195
+
196
+ .qa-sidebar-section:first-child {
197
+ margin-top: 0;
198
+ }
199
+
200
+ .qa-sidebar-section-title {
201
+ padding: var(--q-space-2) var(--q-space-3);
202
+ font-size: var(--q-text-xs);
203
+ font-weight: 600;
204
+ color: var(--q-text-dim);
205
+ text-transform: uppercase;
206
+ letter-spacing: 0.08em;
207
+ }
208
+
209
+ .qa-sidebar-link {
210
+ display: flex;
211
+ align-items: center;
212
+ gap: var(--q-space-3);
213
+ padding: var(--q-space-2) var(--q-space-3);
214
+ border-radius: var(--q-radius-lg);
215
+ color: var(--q-text-secondary);
216
+ font-weight: 500;
217
+ font-size: var(--q-text-sm);
218
+ text-decoration: none;
219
+ transition: all 0.15s ease;
220
+ margin-bottom: 2px;
221
+ }
222
+
223
+ .qa-sidebar-link:hover {
224
+ background: var(--q-bg-hover);
225
+ color: var(--q-text-primary);
226
+ }
227
+
228
+ .qa-sidebar-link.active {
229
+ background: var(--q-primary-600);
230
+ color: white;
231
+ box-shadow: var(--q-glow-primary);
232
+ }
233
+
234
+ .qa-sidebar-link svg {
235
+ width: 18px;
236
+ height: 18px;
237
+ flex-shrink: 0;
238
+ }
239
+
240
+ .qa-sidebar-footer {
241
+ padding: var(--q-space-4);
242
+ border-top: 1px solid var(--q-border-light);
243
+ }
244
+
245
+ .qa-sidebar-user {
246
+ display: flex;
247
+ align-items: center;
248
+ gap: var(--q-space-3);
249
+ padding: var(--q-space-2);
250
+ border-radius: var(--q-radius-lg);
251
+ transition: background 0.15s;
252
+ }
253
+
254
+ .qa-sidebar-user:hover {
255
+ background: var(--q-bg-hover);
256
+ }
257
+
258
+ .qa-sidebar-user-avatar {
259
+ width: 32px;
260
+ height: 32px;
261
+ background: var(--q-primary-600);
262
+ border-radius: var(--q-radius-full);
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: center;
266
+ color: white;
267
+ font-weight: 600;
268
+ font-size: var(--q-text-sm);
269
+ }
270
+
271
+ .qa-sidebar-user-info {
272
+ flex: 1;
273
+ min-width: 0;
274
+ }
275
+
276
+ .qa-sidebar-user-name {
277
+ font-size: var(--q-text-sm);
278
+ font-weight: 500;
279
+ color: var(--q-text-primary);
280
+ }
281
+
282
+ .qa-sidebar-user-role {
283
+ font-size: var(--q-text-xs);
284
+ color: var(--q-text-muted);
285
+ }
286
+
287
+ /* Main Content */
288
+ .qa-main {
289
+ flex: 1;
290
+ margin-left: var(--qa-sidebar-width);
291
+ display: flex;
292
+ flex-direction: column;
293
+ min-height: 100vh;
294
+ }
295
+
296
+ /* Header */
297
+ .qa-header {
298
+ height: var(--qa-header-height);
299
+ background: var(--q-bg-raised);
300
+ border-bottom: 1px solid var(--q-border);
301
+ padding: 0 var(--q-space-6);
302
+ display: flex;
303
+ align-items: center;
304
+ justify-content: space-between;
305
+ position: sticky;
306
+ top: 0;
307
+ z-index: 30;
308
+ }
309
+
310
+ .qa-header-title {
311
+ font-size: var(--q-text-lg);
312
+ font-weight: 600;
313
+ color: var(--q-text-primary);
314
+ }
315
+
316
+ .qa-header-actions {
317
+ display: flex;
318
+ align-items: center;
319
+ gap: var(--q-space-3);
320
+ }
321
+
322
+ .qa-header-status {
323
+ display: flex;
324
+ align-items: center;
325
+ gap: var(--q-space-2);
326
+ font-size: var(--q-text-sm);
327
+ color: var(--q-text-secondary);
328
+ }
329
+
330
+ .qa-header-status-dot {
331
+ width: 8px;
332
+ height: 8px;
333
+ border-radius: 50%;
334
+ background: var(--q-success);
335
+ }
336
+
337
+ /* Content */
338
+ .qa-content {
339
+ padding: var(--q-space-6);
340
+ flex: 1;
341
+ }
342
+
343
+ /* ============================================================================
344
+ CARDS
345
+ ============================================================================ */
346
+
347
+ .qa-card {
348
+ background: var(--q-bg-raised);
349
+ border: 1px solid var(--q-border);
350
+ border-radius: var(--q-radius-xl);
351
+ }
352
+
353
+ .qa-card-header {
354
+ padding: var(--q-space-5);
355
+ border-bottom: 1px solid var(--q-border-light);
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: space-between;
359
+ }
360
+
361
+ .qa-card-title {
362
+ font-size: var(--q-text-base);
363
+ font-weight: 600;
364
+ color: var(--q-text-primary);
365
+ }
366
+
367
+ .qa-card-subtitle {
368
+ font-size: var(--q-text-sm);
369
+ color: var(--q-text-muted);
370
+ margin-top: var(--q-space-1);
371
+ }
372
+
373
+ .qa-card-body {
374
+ padding: var(--q-space-5);
375
+ }
376
+
377
+ .qa-card-footer {
378
+ padding: var(--q-space-4) var(--q-space-5);
379
+ border-top: 1px solid var(--q-border-light);
380
+ background: var(--q-bg-overlay);
381
+ border-radius: 0 0 var(--q-radius-xl) var(--q-radius-xl);
382
+ }
383
+
384
+ /* Stat Cards */
385
+ .qa-stat-card {
386
+ background: var(--q-bg-raised);
387
+ border: 1px solid var(--q-border);
388
+ border-radius: var(--q-radius-xl);
389
+ padding: var(--q-space-5);
390
+ }
391
+
392
+ .qa-stat-label {
393
+ font-size: var(--q-text-sm);
394
+ color: var(--q-text-muted);
395
+ margin-bottom: var(--q-space-2);
396
+ }
397
+
398
+ .qa-stat-value {
399
+ font-size: var(--q-text-2xl);
400
+ font-weight: 700;
401
+ color: var(--q-text-primary);
402
+ }
403
+
404
+ .qa-stat-change {
405
+ font-size: var(--q-text-sm);
406
+ margin-top: var(--q-space-2);
407
+ display: flex;
408
+ align-items: center;
409
+ gap: var(--q-space-1);
410
+ }
411
+
412
+ .qa-stat-change.positive { color: var(--q-success); }
413
+ .qa-stat-change.negative { color: var(--q-danger); }
414
+
415
+ .qa-stat-icon {
416
+ width: 48px;
417
+ height: 48px;
418
+ border-radius: var(--q-radius-xl);
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: center;
422
+ }
423
+
424
+ /* ============================================================================
425
+ ACTIVITY LIST
426
+ ============================================================================ */
427
+
428
+ .qa-activity-item {
429
+ display: flex;
430
+ align-items: flex-start;
431
+ gap: var(--q-space-3);
432
+ padding: var(--q-space-3) 0;
433
+ border-bottom: 1px solid var(--q-border-light);
434
+ }
435
+
436
+ .qa-activity-item:last-child {
437
+ border-bottom: none;
438
+ }
439
+
440
+ .qa-activity-icon {
441
+ width: 32px;
442
+ height: 32px;
443
+ border-radius: var(--q-radius-full);
444
+ background: var(--q-bg-overlay);
445
+ display: flex;
446
+ align-items: center;
447
+ justify-content: center;
448
+ flex-shrink: 0;
449
+ }
450
+
451
+ /* ============================================================================
452
+ CONNECTOR CARDS
453
+ ============================================================================ */
454
+
455
+ .qa-connector-card {
456
+ background: var(--q-bg-raised);
457
+ border: 1px solid var(--q-border);
458
+ border-radius: var(--q-radius-lg);
459
+ padding: var(--q-space-4);
460
+ transition: all 0.15s ease;
461
+ }
462
+
463
+ .qa-connector-card:hover {
464
+ border-color: var(--q-border-focus);
465
+ box-shadow: var(--q-glow-primary);
466
+ }
467
+
468
+ .qa-connector-header {
469
+ display: flex;
470
+ align-items: flex-start;
471
+ justify-content: space-between;
472
+ margin-bottom: var(--q-space-3);
473
+ }
474
+
475
+ .qa-connector-info {
476
+ display: flex;
477
+ align-items: center;
478
+ gap: var(--q-space-3);
479
+ }
480
+
481
+ .qa-connector-icon {
482
+ width: 40px;
483
+ height: 40px;
484
+ border-radius: var(--q-radius-lg);
485
+ display: flex;
486
+ align-items: center;
487
+ justify-content: center;
488
+ font-weight: 700;
489
+ font-size: var(--q-text-sm);
490
+ }
491
+
492
+ .qa-connector-details {
493
+ flex: 1;
494
+ }
495
+
496
+ .qa-connector-name {
497
+ font-weight: 600;
498
+ color: var(--q-text-primary);
499
+ display: flex;
500
+ align-items: center;
501
+ gap: var(--q-space-2);
502
+ }
503
+
504
+ .qa-connector-provider {
505
+ font-size: var(--q-text-sm);
506
+ color: var(--q-text-muted);
507
+ }
508
+
509
+ .qa-connector-status {
510
+ display: flex;
511
+ align-items: center;
512
+ gap: var(--q-space-1);
513
+ }
514
+
515
+ .qa-connector-status-dot {
516
+ width: 8px;
517
+ height: 8px;
518
+ border-radius: 50%;
519
+ }
520
+
521
+ .qa-connector-status-dot.connected { background: var(--q-success); }
522
+ .qa-connector-status-dot.disconnected { background: var(--q-text-dim); }
523
+ .qa-connector-status-dot.error { background: var(--q-danger); }
524
+ .qa-connector-status-dot.unknown { background: var(--q-warning); }
525
+
526
+ .qa-connector-status-text {
527
+ font-size: var(--q-text-xs);
528
+ color: var(--q-text-muted);
529
+ text-transform: capitalize;
530
+ }
531
+
532
+ .qa-connector-meta {
533
+ font-family: var(--q-font-mono);
534
+ font-size: var(--q-text-sm);
535
+ color: var(--q-text-secondary);
536
+ margin-bottom: var(--q-space-3);
537
+ }
538
+
539
+ .qa-connector-actions {
540
+ display: flex;
541
+ align-items: center;
542
+ justify-content: space-between;
543
+ padding-top: var(--q-space-3);
544
+ border-top: 1px solid var(--q-border-light);
545
+ }
546
+
547
+ /* ============================================================================
548
+ BUTTONS
549
+ ============================================================================ */
550
+
551
+ .qa-btn {
552
+ display: inline-flex;
553
+ align-items: center;
554
+ justify-content: center;
555
+ gap: var(--q-space-2);
556
+ padding: var(--q-space-2) var(--q-space-4);
557
+ border-radius: var(--q-radius-lg);
558
+ font-weight: 600;
559
+ font-size: var(--q-text-sm);
560
+ font-family: inherit;
561
+ border: none;
562
+ cursor: pointer;
563
+ transition: all 0.15s ease;
564
+ text-decoration: none;
565
+ white-space: nowrap;
566
+ }
567
+
568
+ .qa-btn:disabled {
569
+ opacity: 0.5;
570
+ cursor: not-allowed;
571
+ }
572
+
573
+ .qa-btn svg {
574
+ width: 16px;
575
+ height: 16px;
576
+ }
577
+
578
+ .qa-btn-primary {
579
+ background: var(--q-primary-600);
580
+ color: white;
581
+ }
582
+
583
+ .qa-btn-primary:hover:not(:disabled) {
584
+ background: var(--q-primary-500);
585
+ box-shadow: var(--q-glow-primary);
586
+ }
587
+
588
+ .qa-btn-secondary {
589
+ background: var(--q-bg-elevated);
590
+ color: var(--q-text-primary);
591
+ border: 1px solid var(--q-border);
592
+ }
593
+
594
+ .qa-btn-secondary:hover:not(:disabled) {
595
+ background: var(--q-bg-hover);
596
+ border-color: var(--q-text-muted);
597
+ }
598
+
599
+ .qa-btn-ghost {
600
+ background: transparent;
601
+ color: var(--q-text-secondary);
602
+ }
603
+
604
+ .qa-btn-ghost:hover:not(:disabled) {
605
+ background: var(--q-bg-hover);
606
+ color: var(--q-text-primary);
607
+ }
608
+
609
+ .qa-btn-danger {
610
+ background: var(--q-danger-dim);
611
+ color: var(--q-danger);
612
+ }
613
+
614
+ .qa-btn-danger:hover:not(:disabled) {
615
+ background: var(--q-danger);
616
+ color: white;
617
+ }
618
+
619
+ .qa-btn-success {
620
+ background: var(--q-success-dim);
621
+ color: var(--q-success);
622
+ }
623
+
624
+ .qa-btn-success:hover:not(:disabled) {
625
+ background: var(--q-success);
626
+ color: white;
627
+ }
628
+
629
+ .qa-btn-sm {
630
+ padding: var(--q-space-1) var(--q-space-2);
631
+ font-size: var(--q-text-xs);
632
+ }
633
+
634
+ .qa-btn-lg {
635
+ padding: var(--q-space-3) var(--q-space-6);
636
+ font-size: var(--q-text-base);
637
+ }
638
+
639
+ .qa-btn-icon {
640
+ padding: var(--q-space-2);
641
+ }
642
+
643
+ .qa-btn-block {
644
+ width: 100%;
645
+ }
646
+
647
+ /* ============================================================================
648
+ FORMS
649
+ ============================================================================ */
650
+
651
+ .qa-form-group {
652
+ margin-bottom: var(--q-space-4);
653
+ }
654
+
655
+ .qa-form-row {
656
+ display: grid;
657
+ grid-template-columns: repeat(2, 1fr);
658
+ gap: var(--q-space-4);
659
+ }
660
+
661
+ .qa-label {
662
+ display: block;
663
+ font-weight: 500;
664
+ font-size: var(--q-text-sm);
665
+ color: var(--q-text-secondary);
666
+ margin-bottom: var(--q-space-2);
667
+ }
668
+
669
+ .qa-input {
670
+ width: 100%;
671
+ padding: var(--q-space-2) var(--q-space-3);
672
+ background: var(--q-bg-overlay);
673
+ border: 1px solid var(--q-border);
674
+ border-radius: var(--q-radius-lg);
675
+ color: var(--q-text-primary);
676
+ font-size: var(--q-text-sm);
677
+ font-family: inherit;
678
+ transition: all 0.15s ease;
679
+ }
680
+
681
+ .qa-input::placeholder {
682
+ color: var(--q-text-dim);
683
+ }
684
+
685
+ .qa-input:focus {
686
+ outline: none;
687
+ border-color: var(--q-primary-500);
688
+ box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.15);
689
+ }
690
+
691
+ .qa-input:disabled {
692
+ background: var(--q-bg-base);
693
+ color: var(--q-text-muted);
694
+ cursor: not-allowed;
695
+ }
696
+
697
+ .qa-input-hint {
698
+ font-size: var(--q-text-xs);
699
+ color: var(--q-text-muted);
700
+ margin-top: var(--q-space-1);
701
+ }
702
+
703
+ .qa-select {
704
+ appearance: none;
705
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2371717a' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
706
+ background-position: right 0.5rem center;
707
+ background-repeat: no-repeat;
708
+ background-size: 1.5em 1.5em;
709
+ padding-right: 2.5rem;
710
+ }
711
+
712
+ .qa-textarea {
713
+ min-height: 100px;
714
+ resize: vertical;
715
+ }
716
+
717
+ .qa-checkbox-group {
718
+ display: flex;
719
+ align-items: center;
720
+ gap: var(--q-space-2);
721
+ }
722
+
723
+ .qa-checkbox {
724
+ width: 18px;
725
+ height: 18px;
726
+ accent-color: var(--q-primary-500);
727
+ }
728
+
729
+ .qa-radio-group {
730
+ display: flex;
731
+ gap: var(--q-space-4);
732
+ }
733
+
734
+ .qa-radio-option {
735
+ display: flex;
736
+ align-items: center;
737
+ gap: var(--q-space-2);
738
+ cursor: pointer;
739
+ }
740
+
741
+ .qa-radio-option input {
742
+ accent-color: var(--q-primary-500);
743
+ }
744
+
745
+ /* ============================================================================
746
+ TABS
747
+ ============================================================================ */
748
+
749
+ .qa-tabs {
750
+ display: flex;
751
+ gap: var(--q-space-1);
752
+ padding: var(--q-space-1);
753
+ background: var(--q-bg-overlay);
754
+ border-radius: var(--q-radius-lg);
755
+ margin-bottom: var(--q-space-6);
756
+ }
757
+
758
+ .qa-tab {
759
+ flex: 1;
760
+ padding: var(--q-space-2) var(--q-space-4);
761
+ font-weight: 500;
762
+ font-size: var(--q-text-sm);
763
+ color: var(--q-text-muted);
764
+ background: transparent;
765
+ border: none;
766
+ border-radius: var(--q-radius-md);
767
+ cursor: pointer;
768
+ transition: all 0.15s ease;
769
+ text-align: center;
770
+ }
771
+
772
+ .qa-tab:hover {
773
+ color: var(--q-text-primary);
774
+ background: var(--q-bg-hover);
775
+ }
776
+
777
+ .qa-tab.active {
778
+ color: var(--q-text-primary);
779
+ background: var(--q-bg-raised);
780
+ }
781
+
782
+ .qa-tab-panel {
783
+ display: none;
784
+ }
785
+
786
+ .qa-tab-panel.active {
787
+ display: block;
788
+ }
789
+
790
+ .qa-tab-content {
791
+ display: block;
792
+ }
793
+
794
+ .qa-tab-content.qa-hidden {
795
+ display: none;
796
+ }
797
+
798
+ /* Switch toggle */
799
+ .qa-switch {
800
+ position: relative;
801
+ display: inline-block;
802
+ width: 44px;
803
+ height: 24px;
804
+ }
805
+
806
+ .qa-switch input {
807
+ opacity: 0;
808
+ width: 0;
809
+ height: 0;
810
+ }
811
+
812
+ .qa-switch-slider {
813
+ position: absolute;
814
+ cursor: pointer;
815
+ top: 0;
816
+ left: 0;
817
+ right: 0;
818
+ bottom: 0;
819
+ background: var(--q-bg-tertiary);
820
+ border: 1px solid var(--q-border);
821
+ border-radius: var(--q-radius-full);
822
+ transition: all 0.2s ease;
823
+ }
824
+
825
+ .qa-switch-slider:before {
826
+ position: absolute;
827
+ content: "";
828
+ height: 18px;
829
+ width: 18px;
830
+ left: 2px;
831
+ bottom: 2px;
832
+ background: var(--q-text-muted);
833
+ border-radius: 50%;
834
+ transition: all 0.2s ease;
835
+ }
836
+
837
+ .qa-switch input:checked + .qa-switch-slider {
838
+ background: var(--q-primary);
839
+ border-color: var(--q-primary);
840
+ }
841
+
842
+ .qa-switch input:checked + .qa-switch-slider:before {
843
+ transform: translateX(20px);
844
+ background: white;
845
+ }
846
+
847
+ .qa-switch input:disabled + .qa-switch-slider {
848
+ opacity: 0.5;
849
+ cursor: not-allowed;
850
+ }
851
+
852
+ /* Connector icon */
853
+ .qa-connector-icon {
854
+ width: 40px;
855
+ height: 40px;
856
+ border-radius: var(--q-radius-lg);
857
+ background: var(--q-bg-tertiary);
858
+ display: flex;
859
+ align-items: center;
860
+ justify-content: center;
861
+ color: var(--q-text-muted);
862
+ }
863
+
864
+ /* Form row */
865
+ .qa-form-row {
866
+ display: grid;
867
+ grid-template-columns: repeat(2, 1fr);
868
+ gap: var(--q-space-4);
869
+ }
870
+
871
+ @media (max-width: 600px) {
872
+ .qa-form-row {
873
+ grid-template-columns: 1fr;
874
+ }
875
+ }
876
+
877
+ /* Subtabs (pill style) */
878
+ .qa-subtabs {
879
+ display: flex;
880
+ gap: var(--q-space-2);
881
+ margin-bottom: var(--q-space-4);
882
+ flex-wrap: wrap;
883
+ }
884
+
885
+ .qa-subtab {
886
+ padding: var(--q-space-1) var(--q-space-3);
887
+ font-size: var(--q-text-sm);
888
+ font-weight: 500;
889
+ color: var(--q-text-muted);
890
+ background: transparent;
891
+ border: 1px solid var(--q-border);
892
+ border-radius: var(--q-radius-full);
893
+ cursor: pointer;
894
+ transition: all 0.15s ease;
895
+ display: flex;
896
+ align-items: center;
897
+ gap: var(--q-space-1);
898
+ }
899
+
900
+ .qa-subtab:hover {
901
+ border-color: var(--q-text-muted);
902
+ color: var(--q-text-primary);
903
+ }
904
+
905
+ .qa-subtab.active {
906
+ background: var(--q-primary-600);
907
+ border-color: var(--q-primary-600);
908
+ color: white;
909
+ }
910
+
911
+ .qa-subtab svg {
912
+ width: 14px;
913
+ height: 14px;
914
+ }
915
+
916
+ /* ============================================================================
917
+ BADGES
918
+ ============================================================================ */
919
+
920
+ .qa-badge {
921
+ display: inline-flex;
922
+ align-items: center;
923
+ padding: 2px var(--q-space-2);
924
+ font-size: var(--q-text-xs);
925
+ font-weight: 500;
926
+ border-radius: var(--q-radius-full);
927
+ }
928
+
929
+ .qa-badge-primary {
930
+ background: rgba(168, 85, 247, 0.15);
931
+ color: var(--q-primary-400);
932
+ }
933
+
934
+ .qa-badge-success {
935
+ background: var(--q-success-dim);
936
+ color: var(--q-success);
937
+ }
938
+
939
+ .qa-badge-warning {
940
+ background: var(--q-warning-dim);
941
+ color: var(--q-warning);
942
+ }
943
+
944
+ .qa-badge-danger {
945
+ background: var(--q-danger-dim);
946
+ color: var(--q-danger);
947
+ }
948
+
949
+ .qa-badge-info {
950
+ background: var(--q-info-dim);
951
+ color: var(--q-info);
952
+ }
953
+
954
+ .qa-badge-muted {
955
+ background: rgba(148, 163, 184, 0.15);
956
+ color: var(--q-text-secondary);
957
+ }
958
+
959
+ .qa-badge-gray {
960
+ background: var(--q-bg-elevated);
961
+ color: var(--q-text-muted);
962
+ }
963
+
964
+ /* ============================================================================
965
+ MODAL
966
+ ============================================================================ */
967
+
968
+ .qa-modal-overlay {
969
+ position: fixed;
970
+ inset: 0;
971
+ background: rgba(0, 0, 0, 0.7);
972
+ backdrop-filter: blur(4px);
973
+ display: flex;
974
+ align-items: center;
975
+ justify-content: center;
976
+ z-index: 100;
977
+ opacity: 0;
978
+ visibility: hidden;
979
+ transition: all 0.2s ease;
980
+ }
981
+
982
+ .qa-modal-overlay.active {
983
+ opacity: 1;
984
+ visibility: visible;
985
+ }
986
+
987
+ .qa-modal {
988
+ background: var(--q-bg-raised);
989
+ border: 1px solid var(--q-border);
990
+ border-radius: var(--q-radius-xl);
991
+ width: 100%;
992
+ max-width: 500px;
993
+ max-height: 90vh;
994
+ overflow: hidden;
995
+ display: flex;
996
+ flex-direction: column;
997
+ transform: translateY(20px) scale(0.95);
998
+ transition: transform 0.2s ease;
999
+ }
1000
+
1001
+ .qa-modal-overlay.active .qa-modal {
1002
+ transform: translateY(0) scale(1);
1003
+ }
1004
+
1005
+ .qa-modal-lg {
1006
+ max-width: 700px;
1007
+ }
1008
+
1009
+ .qa-modal-header {
1010
+ padding: var(--q-space-5);
1011
+ border-bottom: 1px solid var(--q-border-light);
1012
+ display: flex;
1013
+ align-items: center;
1014
+ justify-content: space-between;
1015
+ }
1016
+
1017
+ .qa-modal-title {
1018
+ font-size: var(--q-text-lg);
1019
+ font-weight: 600;
1020
+ color: var(--q-text-primary);
1021
+ }
1022
+
1023
+ .qa-modal-close {
1024
+ padding: var(--q-space-1);
1025
+ color: var(--q-text-muted);
1026
+ background: none;
1027
+ border: none;
1028
+ cursor: pointer;
1029
+ border-radius: var(--q-radius-md);
1030
+ transition: all 0.15s;
1031
+ }
1032
+
1033
+ .qa-modal-close:hover {
1034
+ background: var(--q-bg-hover);
1035
+ color: var(--q-text-primary);
1036
+ }
1037
+
1038
+ .qa-modal-close svg {
1039
+ width: 20px;
1040
+ height: 20px;
1041
+ }
1042
+
1043
+ .qa-modal-body {
1044
+ padding: var(--q-space-5);
1045
+ overflow-y: auto;
1046
+ flex: 1;
1047
+ }
1048
+
1049
+ .qa-modal-footer {
1050
+ padding: var(--q-space-4) var(--q-space-5);
1051
+ border-top: 1px solid var(--q-border-light);
1052
+ display: flex;
1053
+ justify-content: flex-end;
1054
+ gap: var(--q-space-2);
1055
+ }
1056
+
1057
+ /* Alternative modal structure with backdrop */
1058
+ .qa-modal.qa-hidden {
1059
+ display: none;
1060
+ }
1061
+
1062
+ .qa-modal:not(.qa-hidden) {
1063
+ position: fixed;
1064
+ inset: 0;
1065
+ z-index: 100;
1066
+ display: flex;
1067
+ align-items: center;
1068
+ justify-content: center;
1069
+ }
1070
+
1071
+ .qa-modal-backdrop {
1072
+ position: absolute;
1073
+ inset: 0;
1074
+ background: rgba(0, 0, 0, 0.7);
1075
+ backdrop-filter: blur(4px);
1076
+ }
1077
+
1078
+ .qa-modal .qa-modal-content {
1079
+ position: relative;
1080
+ background: var(--q-bg-raised);
1081
+ border: 1px solid var(--q-border);
1082
+ border-radius: var(--q-radius-xl);
1083
+ width: 100%;
1084
+ max-width: 500px;
1085
+ max-height: 90vh;
1086
+ overflow: hidden;
1087
+ display: flex;
1088
+ flex-direction: column;
1089
+ animation: modalSlideIn 0.2s ease;
1090
+ }
1091
+
1092
+ @keyframes modalSlideIn {
1093
+ from {
1094
+ opacity: 0;
1095
+ transform: translateY(-20px) scale(0.95);
1096
+ }
1097
+ to {
1098
+ opacity: 1;
1099
+ transform: translateY(0) scale(1);
1100
+ }
1101
+ }
1102
+
1103
+ /* Card hover effect */
1104
+ .qa-card-hover {
1105
+ transition: all 0.2s ease;
1106
+ }
1107
+
1108
+ .qa-card-hover:hover {
1109
+ border-color: var(--q-primary);
1110
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);
1111
+ transform: translateY(-2px);
1112
+ }
1113
+
1114
+ /* Project icon */
1115
+ .qa-project-icon {
1116
+ width: 40px;
1117
+ height: 40px;
1118
+ border-radius: var(--q-radius-lg);
1119
+ background: var(--q-primary-dim);
1120
+ display: flex;
1121
+ align-items: center;
1122
+ justify-content: center;
1123
+ color: var(--q-primary);
1124
+ }
1125
+
1126
+ /* ============================================================================
1127
+ GRID
1128
+ ============================================================================ */
1129
+
1130
+ .qa-grid {
1131
+ display: grid;
1132
+ gap: var(--q-space-4);
1133
+ }
1134
+
1135
+ .qa-grid-2 { grid-template-columns: repeat(2, 1fr); }
1136
+ .qa-grid-3 { grid-template-columns: repeat(3, 1fr); }
1137
+ .qa-grid-4 { grid-template-columns: repeat(4, 1fr); }
1138
+
1139
+ @media (max-width: 1200px) {
1140
+ .qa-grid-4 { grid-template-columns: repeat(3, 1fr); }
1141
+ }
1142
+
1143
+ @media (max-width: 900px) {
1144
+ .qa-grid-3, .qa-grid-4 { grid-template-columns: repeat(2, 1fr); }
1145
+ }
1146
+
1147
+ @media (max-width: 600px) {
1148
+ .qa-grid-2, .qa-grid-3, .qa-grid-4 { grid-template-columns: 1fr; }
1149
+ }
1150
+
1151
+ /* ============================================================================
1152
+ TABLE
1153
+ ============================================================================ */
1154
+
1155
+ .qa-table {
1156
+ width: 100%;
1157
+ border-collapse: collapse;
1158
+ }
1159
+
1160
+ .qa-table th {
1161
+ text-align: left;
1162
+ padding: var(--q-space-3) var(--q-space-4);
1163
+ font-size: var(--q-text-xs);
1164
+ font-weight: 600;
1165
+ color: var(--q-text-muted);
1166
+ text-transform: uppercase;
1167
+ letter-spacing: 0.05em;
1168
+ border-bottom: 1px solid var(--q-border);
1169
+ }
1170
+
1171
+ .qa-table td {
1172
+ padding: var(--q-space-3) var(--q-space-4);
1173
+ border-bottom: 1px solid var(--q-border-light);
1174
+ color: var(--q-text-primary);
1175
+ }
1176
+
1177
+ .qa-table tbody tr:hover {
1178
+ background: var(--q-bg-hover);
1179
+ }
1180
+
1181
+ .qa-table tbody tr:last-child td {
1182
+ border-bottom: none;
1183
+ }
1184
+
1185
+ /* ============================================================================
1186
+ EMPTY STATE
1187
+ ============================================================================ */
1188
+
1189
+ .qa-empty {
1190
+ text-align: center;
1191
+ padding: var(--q-space-12) var(--q-space-6);
1192
+ color: var(--q-text-muted);
1193
+ }
1194
+
1195
+ .qa-empty-icon {
1196
+ width: 48px;
1197
+ height: 48px;
1198
+ margin: 0 auto var(--q-space-4);
1199
+ color: var(--q-text-dim);
1200
+ }
1201
+
1202
+ .qa-empty-title {
1203
+ font-size: var(--q-text-lg);
1204
+ font-weight: 500;
1205
+ color: var(--q-text-secondary);
1206
+ margin-bottom: var(--q-space-2);
1207
+ }
1208
+
1209
+ .qa-empty-text {
1210
+ font-size: var(--q-text-sm);
1211
+ }
1212
+
1213
+ /* ============================================================================
1214
+ PROVIDER ICONS
1215
+ ============================================================================ */
1216
+
1217
+ .qa-provider-postgres { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }
1218
+ .qa-provider-mysql { background: rgba(249, 115, 22, 0.15); color: #fb923c; }
1219
+ .qa-provider-mariadb { background: rgba(234, 179, 8, 0.15); color: #facc15; }
1220
+ .qa-provider-mongodb { background: rgba(34, 197, 94, 0.15); color: #4ade80; }
1221
+ .qa-provider-redis { background: rgba(239, 68, 68, 0.15); color: #f87171; }
1222
+ .qa-provider-rabbitmq { background: rgba(249, 115, 22, 0.15); color: #fb923c; }
1223
+ .qa-provider-kafka { background: rgba(113, 113, 122, 0.15); color: #a1a1aa; }
1224
+ .qa-provider-minio { background: rgba(236, 72, 153, 0.15); color: #f472b6; }
1225
+ .qa-provider-s3 { background: rgba(249, 115, 22, 0.15); color: #fb923c; }
1226
+ .qa-provider-ollama { background: rgba(168, 85, 247, 0.15); color: #c084fc; }
1227
+ .qa-provider-anthropic { background: rgba(217, 119, 6, 0.15); color: #fbbf24; }
1228
+ .qa-provider-openai { background: rgba(16, 185, 129, 0.15); color: #34d399; }
1229
+ .qa-provider-lmstudio { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }
1230
+ .qa-provider-memcached { background: rgba(34, 211, 238, 0.15); color: #22d3ee; }
1231
+ .qa-provider-redis_queue { background: rgba(239, 68, 68, 0.15); color: #f87171; }
1232
+ .qa-provider-openrouter { background: rgba(139, 92, 246, 0.15); color: #a78bfa; }
1233
+ .qa-provider-influxdb { background: rgba(34, 211, 238, 0.15); color: #22d3ee; }
1234
+
1235
+ /* ============================================================================
1236
+ UTILITY CLASSES
1237
+ ============================================================================ */
1238
+
1239
+ .qa-hidden { display: none !important; }
1240
+ .qa-flex { display: flex; }
1241
+ .qa-flex-col { flex-direction: column; }
1242
+ .qa-items-center { align-items: center; }
1243
+ .qa-items-start { align-items: flex-start; }
1244
+ .qa-justify-between { justify-content: space-between; }
1245
+ .qa-justify-end { justify-content: flex-end; }
1246
+ .qa-justify-center { justify-content: center; }
1247
+ .qa-flex-wrap { flex-wrap: wrap; }
1248
+ .qa-flex-1 { flex: 1; }
1249
+
1250
+ .qa-gap-1 { gap: var(--q-space-1); }
1251
+ .qa-gap-2 { gap: var(--q-space-2); }
1252
+ .qa-gap-3 { gap: var(--q-space-3); }
1253
+ .qa-gap-4 { gap: var(--q-space-4); }
1254
+ .qa-gap-6 { gap: var(--q-space-6); }
1255
+
1256
+ .qa-mt-2 { margin-top: var(--q-space-2); }
1257
+ .qa-mt-4 { margin-top: var(--q-space-4); }
1258
+ .qa-mt-6 { margin-top: var(--q-space-6); }
1259
+ .qa-mb-2 { margin-bottom: var(--q-space-2); }
1260
+ .qa-mb-4 { margin-bottom: var(--q-space-4); }
1261
+ .qa-mb-6 { margin-bottom: var(--q-space-6); }
1262
+ .qa-ml-2 { margin-left: var(--q-space-2); }
1263
+ .qa-mr-2 { margin-right: var(--q-space-2); }
1264
+
1265
+ .qa-p-4 { padding: var(--q-space-4); }
1266
+ .qa-p-6 { padding: var(--q-space-6); }
1267
+
1268
+ .qa-text-center { text-align: center; }
1269
+ .qa-text-right { text-align: right; }
1270
+ .qa-text-xs { font-size: var(--q-text-xs); }
1271
+ .qa-text-sm { font-size: var(--q-text-sm); }
1272
+ .qa-text-lg { font-size: var(--q-text-lg); }
1273
+ .qa-text-xl { font-size: var(--q-text-xl); }
1274
+ .qa-text-2xl { font-size: var(--q-text-2xl); }
1275
+
1276
+ .qa-text-primary { color: var(--q-text-primary); }
1277
+ .qa-text-secondary { color: var(--q-text-secondary); }
1278
+ .qa-text-muted { color: var(--q-text-muted); }
1279
+ .qa-text-success { color: var(--q-success); }
1280
+ .qa-text-danger { color: var(--q-danger); }
1281
+ .qa-text-warning { color: var(--q-warning); }
1282
+
1283
+ .qa-font-mono { font-family: var(--q-font-mono); }
1284
+ .qa-font-medium { font-weight: 500; }
1285
+ .qa-font-semibold { font-weight: 600; }
1286
+ .qa-font-bold { font-weight: 700; }
1287
+
1288
+ .qa-truncate {
1289
+ overflow: hidden;
1290
+ text-overflow: ellipsis;
1291
+ white-space: nowrap;
1292
+ }
1293
+
1294
+ .qa-w-full { width: 100%; }
1295
+
1296
+ /* ============================================================================
1297
+ ANIMATIONS
1298
+ ============================================================================ */
1299
+
1300
+ @keyframes qa-spin {
1301
+ to { transform: rotate(360deg); }
1302
+ }
1303
+
1304
+ @keyframes qa-pulse {
1305
+ 0%, 100% { opacity: 1; }
1306
+ 50% { opacity: 0.5; }
1307
+ }
1308
+
1309
+ @keyframes qa-fade-in {
1310
+ from { opacity: 0; }
1311
+ to { opacity: 1; }
1312
+ }
1313
+
1314
+ .qa-spinner {
1315
+ width: 20px;
1316
+ height: 20px;
1317
+ border: 2px solid var(--q-border);
1318
+ border-top-color: var(--q-primary-500);
1319
+ border-radius: 50%;
1320
+ animation: qa-spin 0.8s linear infinite;
1321
+ }
1322
+
1323
+ .qa-pulse { animation: qa-pulse 2s ease-in-out infinite; }
1324
+ .qa-fade-in { animation: qa-fade-in 0.3s ease-out; }
1325
+
1326
+ /* Additional utility classes */
1327
+ .qa-space-y-2 > * + * { margin-top: var(--q-space-2); }
1328
+ .qa-space-y-3 > * + * { margin-top: var(--q-space-3); }
1329
+ .qa-space-y-4 > * + * { margin-top: var(--q-space-4); }
1330
+
1331
+ .qa-cursor-pointer { cursor: pointer; }
1332
+ .qa-border-success { border-color: var(--q-success) !important; }
1333
+ .qa-border-muted { border-color: var(--q-text-dim) !important; }
1334
+
1335
+ .qa-bg-dark { background: var(--q-bg-dark); }
1336
+ .qa-rounded { border-radius: var(--q-radius-base); }
1337
+
1338
+ hr.qa-my-4 {
1339
+ margin-top: var(--q-space-4);
1340
+ margin-bottom: var(--q-space-4);
1341
+ border: none;
1342
+ border-top: 1px solid var(--q-border);
1343
+ }
1344
+
1345
+ /* Environment Cards */
1346
+ .qa-card[style*="border-left"] {
1347
+ background: var(--q-bg-panel);
1348
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
1349
+ }
1350
+ .qa-card[style*="border-left"]:hover {
1351
+ transform: translateY(-2px);
1352
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
1353
+ }
1354
+
1355
+ /* ============================================================================
1356
+ SCROLLBAR
1357
+ ============================================================================ */
1358
+
1359
+ ::-webkit-scrollbar {
1360
+ width: 8px;
1361
+ height: 8px;
1362
+ }
1363
+
1364
+ ::-webkit-scrollbar-track {
1365
+ background: var(--q-bg-base);
1366
+ }
1367
+
1368
+ ::-webkit-scrollbar-thumb {
1369
+ background: var(--q-border);
1370
+ border-radius: var(--q-radius-full);
1371
+ }
1372
+
1373
+ ::-webkit-scrollbar-thumb:hover {
1374
+ background: var(--q-text-dim);
1375
+ }
1376
+
1377
+ /* ============================================================================
1378
+ LOGIN PAGE
1379
+ ============================================================================ */
1380
+
1381
+ .qa-login-page {
1382
+ min-height: 100vh;
1383
+ display: flex;
1384
+ align-items: center;
1385
+ justify-content: center;
1386
+ background: var(--q-bg-base);
1387
+ }
1388
+
1389
+ .qa-login-card {
1390
+ width: 100%;
1391
+ max-width: 400px;
1392
+ padding: var(--q-space-8);
1393
+ background: var(--q-bg-raised);
1394
+ border: 1px solid var(--q-border);
1395
+ border-radius: var(--q-radius-xl);
1396
+ }
1397
+
1398
+ .qa-login-logo {
1399
+ text-align: center;
1400
+ margin-bottom: var(--q-space-8);
1401
+ }
1402
+
1403
+ .qa-login-logo-icon {
1404
+ width: 56px;
1405
+ height: 56px;
1406
+ margin: 0 auto var(--q-space-4);
1407
+ background: linear-gradient(135deg, var(--q-primary-500), var(--q-primary-700));
1408
+ border-radius: var(--q-radius-xl);
1409
+ display: flex;
1410
+ align-items: center;
1411
+ justify-content: center;
1412
+ color: white;
1413
+ font-weight: 700;
1414
+ font-size: var(--q-text-xl);
1415
+ box-shadow: var(--q-glow-primary);
1416
+ }
1417
+
1418
+ .qa-login-title {
1419
+ font-size: var(--q-text-xl);
1420
+ font-weight: 700;
1421
+ color: var(--q-text-primary);
1422
+ }
1423
+
1424
+ .qa-login-subtitle {
1425
+ font-size: var(--q-text-sm);
1426
+ color: var(--q-text-muted);
1427
+ margin-top: var(--q-space-1);
1428
+ }
1429
+
1430
+ /* ============================================================================
1431
+ SECTION HEADERS
1432
+ ============================================================================ */
1433
+
1434
+ .qa-section-header {
1435
+ display: flex;
1436
+ align-items: center;
1437
+ justify-content: space-between;
1438
+ margin-bottom: var(--q-space-6);
1439
+ }
1440
+
1441
+ .qa-section-title {
1442
+ font-size: var(--q-text-lg);
1443
+ font-weight: 600;
1444
+ color: var(--q-text-primary);
1445
+ }
1446
+
1447
+ .qa-section-subtitle {
1448
+ font-size: var(--q-text-sm);
1449
+ color: var(--q-text-muted);
1450
+ margin-top: var(--q-space-1);
1451
+ }
1452
+
1453
+ /* ============================================================================
1454
+ DOCKER STATUS
1455
+ ============================================================================ */
1456
+
1457
+ .qa-docker-status {
1458
+ display: flex;
1459
+ align-items: center;
1460
+ gap: var(--q-space-2);
1461
+ padding: var(--q-space-2) var(--q-space-3);
1462
+ background: var(--q-bg-overlay);
1463
+ border-radius: var(--q-radius-full);
1464
+ font-size: var(--q-text-sm);
1465
+ }
1466
+
1467
+ .qa-docker-status.connected {
1468
+ background: var(--q-success-dim);
1469
+ color: var(--q-success);
1470
+ }
1471
+
1472
+ .qa-docker-status.disconnected {
1473
+ background: var(--q-danger-dim);
1474
+ color: var(--q-danger);
1475
+ }
1476
+
1477
+ /* ============================================================================
1478
+ STATUS BADGES (for HTMX responses)
1479
+ ============================================================================ */
1480
+
1481
+ .qa-status-badge {
1482
+ display: inline-flex;
1483
+ align-items: center;
1484
+ gap: var(--q-space-2);
1485
+ }
1486
+
1487
+ .qa-status-dot {
1488
+ width: 8px;
1489
+ height: 8px;
1490
+ border-radius: 50%;
1491
+ flex-shrink: 0;
1492
+ }
1493
+
1494
+ .qa-status-dot.success, .qa-status-dot.connected { background: var(--q-success); }
1495
+ .qa-status-dot.error { background: var(--q-danger); }
1496
+ .qa-status-dot.warning { background: var(--q-warning); }
1497
+ .qa-status-dot.muted, .qa-status-dot.unknown { background: var(--q-text-dim); }
1498
+
1499
+ .qa-status-text {
1500
+ font-size: var(--q-text-sm);
1501
+ color: var(--q-text-muted);
1502
+ }
1503
+
1504
+ .qa-status-text.success { color: var(--q-success); }
1505
+ .qa-status-text.error { color: var(--q-danger); }
1506
+ .qa-status-text.warning { color: var(--q-warning); }
1507
+
1508
+ /* ============================================================================
1509
+ DIVIDER
1510
+ ============================================================================ */
1511
+
1512
+ .qa-divider {
1513
+ height: 1px;
1514
+ background: var(--q-border);
1515
+ margin: var(--q-space-6) 0;
1516
+ }
1517
+
1518
+ /* ============================================================================
1519
+ DROPDOWN
1520
+ ============================================================================ */
1521
+
1522
+ .qa-dropdown {
1523
+ position: relative;
1524
+ display: inline-block;
1525
+ }
1526
+
1527
+ .qa-dropdown-menu {
1528
+ position: absolute;
1529
+ top: 100%;
1530
+ right: 0;
1531
+ min-width: 160px;
1532
+ background: var(--q-bg-elevated);
1533
+ border: 1px solid var(--q-border);
1534
+ border-radius: var(--q-radius-lg);
1535
+ padding: var(--q-space-1);
1536
+ z-index: 50;
1537
+ opacity: 0;
1538
+ visibility: hidden;
1539
+ transform: translateY(-4px);
1540
+ transition: all 0.15s ease;
1541
+ }
1542
+
1543
+ .qa-dropdown.open .qa-dropdown-menu {
1544
+ opacity: 1;
1545
+ visibility: visible;
1546
+ transform: translateY(4px);
1547
+ }
1548
+
1549
+ .qa-dropdown-item {
1550
+ display: flex;
1551
+ align-items: center;
1552
+ gap: var(--q-space-2);
1553
+ padding: var(--q-space-2) var(--q-space-3);
1554
+ font-size: var(--q-text-sm);
1555
+ color: var(--q-text-secondary);
1556
+ border-radius: var(--q-radius-md);
1557
+ cursor: pointer;
1558
+ transition: all 0.1s;
1559
+ }
1560
+
1561
+ .qa-dropdown-item:hover {
1562
+ background: var(--q-bg-hover);
1563
+ color: var(--q-text-primary);
1564
+ }
1565
+
1566
+ .qa-dropdown-item.danger {
1567
+ color: var(--q-danger);
1568
+ }
1569
+
1570
+ .qa-dropdown-item.danger:hover {
1571
+ background: var(--q-danger-dim);
1572
+ }
1573
+
1574
+ /* ============================================================================
1575
+ CSS-ONLY TAB SYSTEM (radio button trick)
1576
+ ============================================================================ */
1577
+
1578
+ .qa-tab-radio { display: none; }
1579
+
1580
+ .qa-tabs-bar {
1581
+ display: flex;
1582
+ gap: 0;
1583
+ border-bottom: 1px solid var(--q-border);
1584
+ margin-bottom: 24px;
1585
+ }
1586
+
1587
+ .qa-tab-label {
1588
+ padding: 10px 20px;
1589
+ cursor: pointer;
1590
+ font-size: var(--q-text-sm);
1591
+ font-weight: 500;
1592
+ color: var(--q-text-muted);
1593
+ border-bottom: 2px solid transparent;
1594
+ transition: all 0.2s;
1595
+ }
1596
+
1597
+ .qa-tab-label:hover {
1598
+ color: var(--q-text-primary);
1599
+ }
1600
+
1601
+ /* Tab activation via :checked sibling selectors */
1602
+ #tab-general:checked ~ .qa-tabs-bar label[for="tab-general"],
1603
+ #tab-connectors:checked ~ .qa-tabs-bar label[for="tab-connectors"],
1604
+ #tab-components:checked ~ .qa-tabs-bar label[for="tab-components"],
1605
+ #tab-config:checked ~ .qa-tabs-bar label[for="tab-config"],
1606
+ #tab-environments:checked ~ .qa-tabs-bar label[for="tab-environments"],
1607
+ #tab-runtime:checked ~ .qa-tabs-bar label[for="tab-runtime"],
1608
+ #tab-routes:checked ~ .qa-tabs-bar label[for="tab-routes"],
1609
+ #cdtab-general:checked ~ .qa-tabs-bar label[for="cdtab-general"],
1610
+ #cdtab-tests:checked ~ .qa-tabs-bar label[for="cdtab-tests"] {
1611
+ color: var(--q-primary-400);
1612
+ border-bottom-color: var(--q-primary-400);
1613
+ }
1614
+
1615
+ /* Hide all panels by default */
1616
+ .qa-tabs-content > .qa-panel-general,
1617
+ .qa-tabs-content > .qa-panel-connectors,
1618
+ .qa-tabs-content > .qa-panel-components,
1619
+ .qa-tabs-content > .qa-panel-config,
1620
+ .qa-tabs-content > .qa-panel-environments,
1621
+ .qa-tabs-content > .qa-panel-runtime,
1622
+ .qa-tabs-content > .qa-panel-routes,
1623
+ .qa-tabs-content > .qa-panel-cd-general,
1624
+ .qa-tabs-content > .qa-panel-cd-tests {
1625
+ display: none;
1626
+ }
1627
+
1628
+ /* Show active panel */
1629
+ #tab-general:checked ~ .qa-tabs-content > .qa-panel-general,
1630
+ #tab-connectors:checked ~ .qa-tabs-content > .qa-panel-connectors,
1631
+ #tab-components:checked ~ .qa-tabs-content > .qa-panel-components,
1632
+ #tab-config:checked ~ .qa-tabs-content > .qa-panel-config,
1633
+ #tab-environments:checked ~ .qa-tabs-content > .qa-panel-environments,
1634
+ #tab-runtime:checked ~ .qa-tabs-content > .qa-panel-runtime,
1635
+ #tab-routes:checked ~ .qa-tabs-content > .qa-panel-routes,
1636
+ #cdtab-general:checked ~ .qa-tabs-content > .qa-panel-cd-general,
1637
+ #cdtab-tests:checked ~ .qa-tabs-content > .qa-panel-cd-tests {
1638
+ display: block;
1639
+ }
1640
+
1641
+ /* ============================================================================
1642
+ CONNECTOR SUB-TABS (nested pills inside connectors panel)
1643
+ ============================================================================ */
1644
+
1645
+ .qa-conn-subtab-radio { display: none; }
1646
+
1647
+ .qa-conn-subtabs-bar {
1648
+ display: flex;
1649
+ gap: 8px;
1650
+ margin-bottom: 20px;
1651
+ }
1652
+
1653
+ .qa-conn-subtab-label {
1654
+ padding: 6px 16px;
1655
+ cursor: pointer;
1656
+ font-size: var(--q-text-sm);
1657
+ font-weight: 500;
1658
+ color: var(--q-text-muted);
1659
+ border: 1px solid var(--q-border);
1660
+ border-radius: var(--q-radius-full);
1661
+ transition: all 0.2s;
1662
+ user-select: none;
1663
+ }
1664
+
1665
+ .qa-conn-subtab-label:hover {
1666
+ color: var(--q-text-primary);
1667
+ border-color: var(--q-text-muted);
1668
+ }
1669
+
1670
+ /* Sub-tab activation via :checked sibling selectors */
1671
+ #conn-subtab-public:checked ~ .qa-conn-subtabs-bar label[for="conn-subtab-public"],
1672
+ #conn-subtab-private:checked ~ .qa-conn-subtabs-bar label[for="conn-subtab-private"],
1673
+ #conn-subtab-new:checked ~ .qa-conn-subtabs-bar label[for="conn-subtab-new"] {
1674
+ color: var(--q-primary-400);
1675
+ border-color: var(--q-primary-400);
1676
+ background: rgba(168, 85, 247, 0.1);
1677
+ }
1678
+
1679
+ /* Hide all sub-panels by default */
1680
+ .qa-conn-subtabs-content > .qa-conn-panel-public,
1681
+ .qa-conn-subtabs-content > .qa-conn-panel-private,
1682
+ .qa-conn-subtabs-content > .qa-conn-panel-new {
1683
+ display: none;
1684
+ }
1685
+
1686
+ /* Show active sub-panel */
1687
+ #conn-subtab-public:checked ~ .qa-conn-subtabs-content > .qa-conn-panel-public,
1688
+ #conn-subtab-private:checked ~ .qa-conn-subtabs-content > .qa-conn-panel-private,
1689
+ #conn-subtab-new:checked ~ .qa-conn-subtabs-content > .qa-conn-panel-new {
1690
+ display: block;
1691
+ }
1692
+
1693
+ /* ============================================================================
1694
+ CONNECTOR TYPE BADGES
1695
+ ============================================================================ */
1696
+
1697
+ .qa-type-database { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }
1698
+ .qa-type-message_queue, .qa-type-mq { background: rgba(168, 85, 247, 0.15); color: #c084fc; }
1699
+ .qa-type-cache { background: rgba(234, 179, 8, 0.15); color: #facc15; }
1700
+ .qa-type-storage { background: rgba(34, 197, 94, 0.15); color: #4ade80; }
1701
+ .qa-type-ai { background: rgba(236, 72, 153, 0.15); color: #f472b6; }
1702
+
1703
+ /* ============================================================================
1704
+ PROCESS STATUS BADGES
1705
+ ============================================================================ */
1706
+
1707
+ .qa-process-running {
1708
+ display: inline-flex;
1709
+ align-items: center;
1710
+ gap: 6px;
1711
+ padding: 3px 10px;
1712
+ font-size: var(--q-text-xs);
1713
+ font-weight: 600;
1714
+ border-radius: var(--q-radius-full);
1715
+ background: var(--q-success-dim);
1716
+ color: var(--q-success);
1717
+ }
1718
+
1719
+ .qa-process-running::before {
1720
+ content: '';
1721
+ width: 7px;
1722
+ height: 7px;
1723
+ border-radius: 50%;
1724
+ background: var(--q-success);
1725
+ animation: qa-pulse 2s ease-in-out infinite;
1726
+ }
1727
+
1728
+ .qa-process-stopped {
1729
+ display: inline-flex;
1730
+ align-items: center;
1731
+ gap: 6px;
1732
+ padding: 3px 10px;
1733
+ font-size: var(--q-text-xs);
1734
+ font-weight: 600;
1735
+ border-radius: var(--q-radius-full);
1736
+ background: var(--q-bg-elevated);
1737
+ color: var(--q-text-muted);
1738
+ }
1739
+
1740
+ .qa-process-stopped::before {
1741
+ content: '';
1742
+ width: 7px;
1743
+ height: 7px;
1744
+ border-radius: 50%;
1745
+ background: var(--q-text-dim);
1746
+ }
1747
+
1748
+ /* ============================================================================
1749
+ LOG VIEWER
1750
+ ============================================================================ */
1751
+
1752
+ .qa-log-viewer {
1753
+ background: #0d0d14;
1754
+ border: 1px solid var(--q-border);
1755
+ border-radius: var(--q-radius-lg);
1756
+ padding: 16px;
1757
+ font-family: var(--q-font-mono);
1758
+ font-size: 0.8rem;
1759
+ line-height: 1.6;
1760
+ color: #a1a1aa;
1761
+ max-height: 400px;
1762
+ overflow-y: auto;
1763
+ white-space: pre-wrap;
1764
+ word-break: break-all;
1765
+ }
1766
+
1767
+ .qa-log-viewer:empty::after {
1768
+ content: 'No log output yet.';
1769
+ color: var(--q-text-dim);
1770
+ font-style: italic;
1771
+ }
1772
+
1773
+ /* ============================================================================
1774
+ ENVIRONMENT CARDS
1775
+ ============================================================================ */
1776
+
1777
+ .qa-env-card {
1778
+ background: var(--q-bg-raised);
1779
+ border: 1px solid var(--q-border);
1780
+ border-left: 4px solid var(--q-text-dim);
1781
+ border-radius: var(--q-radius-lg);
1782
+ padding: var(--q-space-5);
1783
+ transition: transform 0.15s, box-shadow 0.15s;
1784
+ }
1785
+
1786
+ .qa-env-card:hover {
1787
+ transform: translateY(-1px);
1788
+ box-shadow: var(--q-shadow-md);
1789
+ }
1790
+
1791
+ .qa-env-dev {
1792
+ border-left-color: var(--q-info);
1793
+ }
1794
+
1795
+ .qa-env-staging {
1796
+ border-left-color: var(--q-warning);
1797
+ }
1798
+
1799
+ .qa-env-prod, .qa-env-production {
1800
+ border-left-color: var(--q-success);
1801
+ }
1802
+
1803
+ /* ============================================================================
1804
+ APPLICATION PROJECT CARDS (list view)
1805
+ ============================================================================ */
1806
+
1807
+ .qa-app-card {
1808
+ display: flex;
1809
+ align-items: center;
1810
+ gap: 16px;
1811
+ padding: 16px 20px;
1812
+ border-bottom: 1px solid var(--q-border);
1813
+ text-decoration: none;
1814
+ transition: background 0.15s;
1815
+ }
1816
+
1817
+ .qa-app-card:hover {
1818
+ background: var(--q-bg-overlay);
1819
+ }
1820
+
1821
+ .qa-app-card:last-child {
1822
+ border-bottom: none;
1823
+ }
1824
+
1825
+ .qa-app-card-icon {
1826
+ width: 40px;
1827
+ height: 40px;
1828
+ border-radius: var(--q-radius-lg);
1829
+ background: linear-gradient(135deg, var(--q-primary-600), var(--q-primary-800));
1830
+ display: flex;
1831
+ align-items: center;
1832
+ justify-content: center;
1833
+ color: white;
1834
+ font-weight: 700;
1835
+ font-size: var(--q-text-sm);
1836
+ flex-shrink: 0;
1837
+ }
1838
+
1839
+ .qa-app-metrics {
1840
+ display: flex;
1841
+ align-items: center;
1842
+ gap: 16px;
1843
+ flex-shrink: 0;
1844
+ }
1845
+
1846
+ .qa-app-metric {
1847
+ display: flex;
1848
+ flex-direction: column;
1849
+ align-items: center;
1850
+ min-width: 48px;
1851
+ }
1852
+
1853
+ .qa-app-metric-value {
1854
+ font-weight: 600;
1855
+ font-size: var(--q-text-sm);
1856
+ color: var(--q-text-primary);
1857
+ }
1858
+
1859
+ .qa-app-metric-label {
1860
+ font-size: 0.65rem;
1861
+ color: var(--q-text-dim);
1862
+ text-transform: uppercase;
1863
+ letter-spacing: 0.04em;
1864
+ }
1865
+
1866
+ /* ============================================================================
1867
+ SEARCH BAR
1868
+ ============================================================================ */
1869
+
1870
+ .qa-search-bar {
1871
+ display: flex;
1872
+ align-items: center;
1873
+ gap: 8px;
1874
+ background: var(--q-bg-overlay);
1875
+ border: 1px solid var(--q-border);
1876
+ border-radius: var(--q-radius-lg);
1877
+ padding: 0 12px;
1878
+ transition: border-color 0.15s;
1879
+ }
1880
+
1881
+ .qa-search-bar:focus-within {
1882
+ border-color: var(--q-primary-500);
1883
+ box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.15);
1884
+ }
1885
+
1886
+ .qa-search-bar input {
1887
+ flex: 1;
1888
+ background: transparent;
1889
+ border: none;
1890
+ outline: none;
1891
+ color: var(--q-text-primary);
1892
+ font-size: var(--q-text-sm);
1893
+ padding: 8px 0;
1894
+ font-family: inherit;
1895
+ }
1896
+
1897
+ .qa-search-bar input::placeholder {
1898
+ color: var(--q-text-dim);
1899
+ }
1900
+
1901
+ .qa-search-bar svg {
1902
+ width: 16px;
1903
+ height: 16px;
1904
+ color: var(--q-text-dim);
1905
+ flex-shrink: 0;
1906
+ }
1907
+
1908
+ /* ============================================================================
1909
+ EMPTY STATE (enhanced)
1910
+ ============================================================================ */
1911
+
1912
+ .qa-empty-icon svg {
1913
+ display: inline-block;
1914
+ }
1915
+
1916
+ .qa-empty-action {
1917
+ margin-top: var(--q-space-4);
1918
+ }
1919
+
1920
+ /* ============================================================================
1921
+ SOURCE CODE VIEWER
1922
+ ============================================================================ */
1923
+
1924
+ .qa-source-viewer {
1925
+ display: flex;
1926
+ overflow-x: auto;
1927
+ background: #0d0d14;
1928
+ border-radius: var(--q-radius-xl);
1929
+ font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
1930
+ font-size: 0.8125rem;
1931
+ line-height: 1.7;
1932
+ }
1933
+
1934
+ .qa-source-gutter {
1935
+ padding: 20px 0;
1936
+ text-align: right;
1937
+ color: #3a3a4a;
1938
+ user-select: none;
1939
+ border-right: 1px solid #1e1e2a;
1940
+ flex-shrink: 0;
1941
+ min-width: 52px;
1942
+ }
1943
+
1944
+ .qa-source-gutter div {
1945
+ padding: 0 12px;
1946
+ }
1947
+
1948
+ .qa-source-gutter div:hover {
1949
+ color: #71717a;
1950
+ background: rgba(255, 255, 255, 0.03);
1951
+ }
1952
+
1953
+ .qa-source-code {
1954
+ margin: 0;
1955
+ padding: 20px 16px;
1956
+ background: transparent;
1957
+ color: #c9d1d9;
1958
+ overflow-x: auto;
1959
+ tab-size: 4;
1960
+ white-space: pre;
1961
+ flex: 1;
1962
+ min-width: 0;
1963
+ }
1964
+
1965
+ /* Syntax highlight token colors (GitHub Dark theme) */
1966
+ .hl-tag { color: #7ee787; }
1967
+ .hl-attr { color: #d2a8ff; }
1968
+ .hl-str { color: #a5d6ff; }
1969
+ .hl-cmt { color: #546370; font-style: italic; }
1970
+ .hl-kw { color: #ff7b72; }
1971
+ .hl-fn { color: #d2a8ff; }
1972
+ .hl-num { color: #79c0ff; }
1973
+ .hl-op { color: #ff7b72; }
1974
+ .hl-var { color: #ffa657; }
1975
+ .hl-dec { color: #ffa657; }
1976
+ .hl-sql { color: #79c0ff; font-weight: 600; }
1977
+ .hl-punct { color: #8b949e; }
1978
+
1979
+ /* ============================================================================
1980
+ CONNECTOR STAT CARD ITEMS
1981
+ ============================================================================ */
1982
+
1983
+ .qa-stat-connector-item {
1984
+ display: flex;
1985
+ align-items: center;
1986
+ gap: 8px;
1987
+ padding: 4px 0;
1988
+ font-size: var(--q-text-sm);
1989
+ }
1990
+ .qa-stat-connector-item + .qa-stat-connector-item {
1991
+ border-top: 1px solid var(--q-border-light);
1992
+ }
1993
+
1994
+ /* ============================================================================
1995
+ CONFIG EDITOR
1996
+ ============================================================================ */
1997
+
1998
+ .qa-config-viewer {
1999
+ background: #0d0d14;
2000
+ border-radius: 0 0 var(--q-radius-xl) var(--q-radius-xl);
2001
+ overflow: auto;
2002
+ max-height: 300px;
2003
+ }
2004
+
2005
+ .qa-config-pre {
2006
+ margin: 0;
2007
+ padding: 20px;
2008
+ font-family: var(--q-font-mono);
2009
+ font-size: 0.8125rem;
2010
+ line-height: 1.7;
2011
+ color: #a1a1aa;
2012
+ white-space: pre-wrap;
2013
+ word-break: break-word;
2014
+ }
2015
+
2016
+ .qa-config-editor {
2017
+ font-family: var(--q-font-mono) !important;
2018
+ font-size: 0.8125rem !important;
2019
+ line-height: 1.7;
2020
+ background: #0d0d14;
2021
+ color: #c9d1d9;
2022
+ border: 1px solid var(--q-border);
2023
+ border-radius: var(--q-radius-lg);
2024
+ padding: 16px;
2025
+ resize: vertical;
2026
+ min-height: 300px;
2027
+ tab-size: 2;
2028
+ white-space: pre;
2029
+ overflow-x: auto;
2030
+ width: 100%;
2031
+ }
2032
+
2033
+ .qa-config-editor:focus {
2034
+ outline: none;
2035
+ border-color: var(--q-primary-500);
2036
+ box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.15);
2037
+ }
2038
+
2039
+ .qa-config-diff {
2040
+ margin: 0;
2041
+ padding: 16px 20px;
2042
+ font-family: var(--q-font-mono);
2043
+ font-size: 0.8rem;
2044
+ line-height: 1.6;
2045
+ color: #a1a1aa;
2046
+ white-space: pre-wrap;
2047
+ word-break: break-word;
2048
+ background: #0d0d14;
2049
+ border-radius: 0 0 var(--q-radius-xl) var(--q-radius-xl);
2050
+ max-height: 250px;
2051
+ overflow-y: auto;
2052
+ }
2053
+
2054
+ .qa-input-hint {
2055
+ margin-top: 6px;
2056
+ font-size: var(--q-text-xs);
2057
+ color: var(--q-text-dim);
2058
+ }