@hanzo/browser-extension 1.7.2

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 (134) hide show
  1. package/.github/workflows/docs.yml +44 -0
  2. package/.github/workflows/release.yml +55 -0
  3. package/LICENSE +21 -0
  4. package/README.md +126 -0
  5. package/dist/browser-extension/README.md +43 -0
  6. package/dist/browser-extension/ai-worker.js +30 -0
  7. package/dist/browser-extension/background-firefox.js +617 -0
  8. package/dist/browser-extension/background.js +2737 -0
  9. package/dist/browser-extension/browser-control.js +683 -0
  10. package/dist/browser-extension/cdp-bridge-server.js +444 -0
  11. package/dist/browser-extension/chrome/ai-worker.js +571 -0
  12. package/dist/browser-extension/chrome/background.js +2737 -0
  13. package/dist/browser-extension/chrome/callback.html +17 -0
  14. package/dist/browser-extension/chrome/content-script.js +1270 -0
  15. package/dist/browser-extension/chrome/icon128.png +0 -0
  16. package/dist/browser-extension/chrome/icon16.png +0 -0
  17. package/dist/browser-extension/chrome/icon32.png +0 -0
  18. package/dist/browser-extension/chrome/icon48.png +0 -0
  19. package/dist/browser-extension/chrome/manifest.json +57 -0
  20. package/dist/browser-extension/chrome/popup.css +519 -0
  21. package/dist/browser-extension/chrome/popup.html +242 -0
  22. package/dist/browser-extension/chrome/popup.js +267 -0
  23. package/dist/browser-extension/chrome/sidebar.css +1176 -0
  24. package/dist/browser-extension/chrome/sidebar.html +280 -0
  25. package/dist/browser-extension/chrome/sidebar.js +778 -0
  26. package/dist/browser-extension/cli.js +233 -0
  27. package/dist/browser-extension/content-script.js +1270 -0
  28. package/dist/browser-extension/firefox/ai-worker.js +571 -0
  29. package/dist/browser-extension/firefox/background.js +617 -0
  30. package/dist/browser-extension/firefox/callback.html +17 -0
  31. package/dist/browser-extension/firefox/content-script.js +1270 -0
  32. package/dist/browser-extension/firefox/icon128.png +0 -0
  33. package/dist/browser-extension/firefox/icon16.png +0 -0
  34. package/dist/browser-extension/firefox/icon32.png +0 -0
  35. package/dist/browser-extension/firefox/icon48.png +0 -0
  36. package/dist/browser-extension/firefox/manifest.json +66 -0
  37. package/dist/browser-extension/firefox/popup.css +519 -0
  38. package/dist/browser-extension/firefox/popup.html +242 -0
  39. package/dist/browser-extension/firefox/popup.js +267 -0
  40. package/dist/browser-extension/firefox/sidebar.css +1176 -0
  41. package/dist/browser-extension/firefox/sidebar.html +280 -0
  42. package/dist/browser-extension/firefox/sidebar.js +778 -0
  43. package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
  44. package/dist/browser-extension/icon128.png +0 -0
  45. package/dist/browser-extension/icon16.png +0 -0
  46. package/dist/browser-extension/icon32.png +0 -0
  47. package/dist/browser-extension/icon48.png +0 -0
  48. package/dist/browser-extension/manifest.json +57 -0
  49. package/dist/browser-extension/package.json +41 -0
  50. package/dist/browser-extension/popup.css +468 -0
  51. package/dist/browser-extension/popup.html +191 -0
  52. package/dist/browser-extension/popup.js +267 -0
  53. package/dist/browser-extension/safari/Info.plist +21 -0
  54. package/dist/browser-extension/safari/ai-worker.js +571 -0
  55. package/dist/browser-extension/safari/background.js +2737 -0
  56. package/dist/browser-extension/safari/callback.html +17 -0
  57. package/dist/browser-extension/safari/content-script.js +1270 -0
  58. package/dist/browser-extension/safari/icon128.png +0 -0
  59. package/dist/browser-extension/safari/icon16.png +0 -0
  60. package/dist/browser-extension/safari/icon32.png +0 -0
  61. package/dist/browser-extension/safari/icon48.png +0 -0
  62. package/dist/browser-extension/safari/popup.css +519 -0
  63. package/dist/browser-extension/safari/popup.html +242 -0
  64. package/dist/browser-extension/safari/popup.js +267 -0
  65. package/dist/browser-extension/safari/sidebar.css +1176 -0
  66. package/dist/browser-extension/safari/sidebar.html +280 -0
  67. package/dist/browser-extension/safari/sidebar.js +778 -0
  68. package/dist/browser-extension/sidebar.css +718 -0
  69. package/dist/browser-extension/sidebar.html +184 -0
  70. package/dist/browser-extension/sidebar.js +778 -0
  71. package/dist/browser-extension/webgpu-ai.js +495 -0
  72. package/dist/cdp-bridge-server.js +411 -0
  73. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +1047 -0
  74. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  75. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  76. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  77. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
  78. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
  79. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
  80. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
  81. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
  82. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
  83. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
  84. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
  85. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
  86. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
  87. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
  88. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +6 -0
  89. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +21 -0
  90. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
  91. package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +20 -0
  92. package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
  93. package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +24 -0
  94. package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +61 -0
  95. package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +81 -0
  96. package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +42 -0
  97. package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +24 -0
  98. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +36 -0
  99. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +38 -0
  100. package/dist/safari/Hanzo AI/iOS (App)/Info.plist +27 -0
  101. package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +18 -0
  102. package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +13 -0
  103. package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +21 -0
  104. package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +124 -0
  105. package/dist/safari/Hanzo AI/macOS (App)/Info.plist +8 -0
  106. package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +13 -0
  107. package/docs/_config.yml +13 -0
  108. package/docs/_layouts/default.html +435 -0
  109. package/docs/index.md +54 -0
  110. package/install-extension.sh +75 -0
  111. package/manifest.json +29 -0
  112. package/package.json +32 -0
  113. package/src/ai-worker.js +571 -0
  114. package/src/callback.html +17 -0
  115. package/src/chat-widget.tsx +93 -0
  116. package/src/icon128.png +0 -0
  117. package/src/icon16.png +0 -0
  118. package/src/icon32.png +0 -0
  119. package/src/icon48.png +0 -0
  120. package/src/manifest-firefox.json +66 -0
  121. package/src/manifest.json +57 -0
  122. package/src/package.json +41 -0
  123. package/src/popup.css +519 -0
  124. package/src/popup.html +242 -0
  125. package/src/popup.js +192 -0
  126. package/src/sidebar.css +1176 -0
  127. package/src/sidebar.html +280 -0
  128. package/src/sidebar.js +884 -0
  129. package/src/webgpu.d.ts +131 -0
  130. package/test/claude-integration.test.ts +251 -0
  131. package/test/server-frameworks-edge-cases.test.ts +145 -0
  132. package/test/server-frameworks.test.ts +395 -0
  133. package/test-cdp-connection.js +140 -0
  134. package/tsconfig.json +19 -0
@@ -0,0 +1,66 @@
1
+ {
2
+ "manifest_version": 3,
3
+ "name": "Hanzo AI",
4
+ "version": "1.7.2",
5
+ "description": "AI-powered dev assistant — click-to-code navigation, source maps, WebGPU AI, and MCP integration for Claude Code.",
6
+ "permissions": [
7
+ "activeTab",
8
+ "identity",
9
+ "storage",
10
+ "tabs",
11
+ "webNavigation",
12
+ "scripting"
13
+ ],
14
+ "host_permissions": [
15
+ "http://localhost/*",
16
+ "https://localhost/*",
17
+ "<all_urls>"
18
+ ],
19
+ "content_security_policy": {
20
+ "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
21
+ },
22
+ "content_scripts": [
23
+ {
24
+ "matches": ["<all_urls>"],
25
+ "js": ["content-script.js"],
26
+ "run_at": "document_idle"
27
+ }
28
+ ],
29
+ "background": {
30
+ "scripts": ["background.js"],
31
+ "type": "module"
32
+ },
33
+ "action": {
34
+ "default_popup": "popup.html",
35
+ "default_icon": {
36
+ "16": "icon16.png",
37
+ "48": "icon48.png",
38
+ "128": "icon128.png"
39
+ }
40
+ },
41
+ "sidebar_action": {
42
+ "default_title": "Hanzo AI",
43
+ "default_panel": "sidebar.html",
44
+ "default_icon": {
45
+ "16": "icon16.png",
46
+ "48": "icon48.png"
47
+ }
48
+ },
49
+ "web_accessible_resources": [
50
+ {
51
+ "resources": ["ai-worker.js", "models/*"],
52
+ "matches": ["<all_urls>"]
53
+ }
54
+ ],
55
+ "browser_specific_settings": {
56
+ "gecko": {
57
+ "id": "hanzo-ai@hanzo.ai",
58
+ "strict_min_version": "109.0"
59
+ },
60
+ "gecko_android": {}
61
+ },
62
+ "data_collection_permissions": {
63
+ "purposes": ["functionality"],
64
+ "data_categories": ["technical_data"]
65
+ }
66
+ }
@@ -0,0 +1,519 @@
1
+ /* Hanzo AI Browser Extension Popup — Monochrome Vibrancy */
2
+
3
+ :root {
4
+ --primary: #FFFFFF;
5
+ --primary-dark: #D4D4D4;
6
+ --bg: #000000;
7
+ --surface: #0A0A0A;
8
+ --surface-light: #1A1A1A;
9
+ --text: #FFFFFF;
10
+ --text-dim: #888888;
11
+ --border: rgba(255,255,255,0.08);
12
+ --border-strong: rgba(255,255,255,0.14);
13
+ --glass: rgba(255,255,255,0.04);
14
+ --glass-strong: rgba(255,255,255,0.07);
15
+ --success: #4CAF50;
16
+ --warning: #FFC107;
17
+ --error: #F44336;
18
+ }
19
+
20
+ * {
21
+ margin: 0;
22
+ padding: 0;
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ body {
27
+ width: 380px;
28
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Inter', 'Segoe UI', sans-serif;
29
+ background: var(--bg);
30
+ color: var(--text);
31
+ font-size: 14px;
32
+ line-height: 1.5;
33
+ -webkit-font-smoothing: antialiased;
34
+ -moz-osx-font-smoothing: grayscale;
35
+ }
36
+
37
+ .container {
38
+ background: var(--surface);
39
+ min-height: 500px;
40
+ position: relative;
41
+ }
42
+
43
+ /* Ambient glow */
44
+ .container::before {
45
+ content: '';
46
+ position: absolute;
47
+ top: 0;
48
+ left: 0;
49
+ right: 0;
50
+ height: 120px;
51
+ background: radial-gradient(ellipse at 50% 0%, rgba(255,255,255,0.03) 0%, transparent 70%);
52
+ pointer-events: none;
53
+ }
54
+
55
+ /* Animations */
56
+ @keyframes fadeIn {
57
+ from { opacity: 0; transform: translateY(4px); }
58
+ to { opacity: 1; transform: translateY(0); }
59
+ }
60
+
61
+ @keyframes shimmer {
62
+ 0% { background-position: -200% 0; }
63
+ 100% { background-position: 200% 0; }
64
+ }
65
+
66
+ @keyframes pulse {
67
+ 0% { opacity: 1; }
68
+ 50% { opacity: 0.5; }
69
+ 100% { opacity: 1; }
70
+ }
71
+
72
+ @keyframes glowPulse {
73
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); }
74
+ 50% { box-shadow: 0 0 12px 2px rgba(255,255,255,0.06); }
75
+ }
76
+
77
+ /* Header */
78
+ header {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 12px;
82
+ padding: 16px;
83
+ border-bottom: 1px solid var(--border);
84
+ background: rgba(0,0,0,0.6);
85
+ backdrop-filter: blur(20px) saturate(180%);
86
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
87
+ position: relative;
88
+ z-index: 10;
89
+ }
90
+
91
+ .logo {
92
+ width: 24px;
93
+ height: 24px;
94
+ color: var(--text);
95
+ filter: drop-shadow(0 0 6px rgba(255,255,255,0.15));
96
+ }
97
+
98
+ h1 {
99
+ font-size: 18px;
100
+ font-weight: 600;
101
+ letter-spacing: -0.01em;
102
+ }
103
+
104
+ h2 {
105
+ font-size: 16px;
106
+ font-weight: 600;
107
+ margin-bottom: 8px;
108
+ }
109
+
110
+ h3 {
111
+ font-size: 14px;
112
+ font-weight: 600;
113
+ margin-bottom: 12px;
114
+ }
115
+
116
+ /* Sections */
117
+ .section {
118
+ padding: 20px;
119
+ animation: fadeIn 0.3s ease;
120
+ }
121
+
122
+ .section.hidden {
123
+ display: none;
124
+ }
125
+
126
+ .subtitle {
127
+ color: var(--text-dim);
128
+ margin-bottom: 20px;
129
+ }
130
+
131
+ /* Buttons */
132
+ .btn {
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ gap: 8px;
137
+ width: 100%;
138
+ padding: 12px 16px;
139
+ border: none;
140
+ border-radius: 8px;
141
+ font-size: 14px;
142
+ font-weight: 500;
143
+ cursor: pointer;
144
+ transition: all 0.25s ease;
145
+ position: relative;
146
+ overflow: hidden;
147
+ }
148
+
149
+ .btn-primary {
150
+ background: var(--primary);
151
+ color: #000000;
152
+ font-weight: 600;
153
+ }
154
+
155
+ /* Shimmer sweep */
156
+ .btn-primary::after {
157
+ content: '';
158
+ position: absolute;
159
+ top: 0;
160
+ left: -100%;
161
+ width: 100%;
162
+ height: 100%;
163
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
164
+ transition: left 0.5s ease;
165
+ }
166
+
167
+ .btn-primary:hover {
168
+ background: var(--primary-dark);
169
+ box-shadow: 0 0 16px rgba(255,255,255,0.12);
170
+ }
171
+
172
+ .btn-primary:hover::after {
173
+ left: 100%;
174
+ }
175
+
176
+ .btn-secondary {
177
+ background: var(--glass-strong);
178
+ color: var(--text);
179
+ border: 1px solid var(--border);
180
+ backdrop-filter: blur(8px);
181
+ -webkit-backdrop-filter: blur(8px);
182
+ }
183
+
184
+ .btn-secondary:hover {
185
+ background: var(--glass);
186
+ border-color: var(--border-strong);
187
+ box-shadow: 0 0 8px rgba(255,255,255,0.05);
188
+ }
189
+
190
+ .btn-icon {
191
+ width: 32px;
192
+ height: 32px;
193
+ padding: 0;
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: center;
197
+ background: transparent;
198
+ border: none;
199
+ border-radius: 6px;
200
+ cursor: pointer;
201
+ transition: all 0.2s;
202
+ color: var(--text-dim);
203
+ }
204
+
205
+ .btn-icon:hover {
206
+ background: var(--glass-strong);
207
+ color: var(--text);
208
+ }
209
+
210
+ .btn-icon svg {
211
+ width: 18px;
212
+ height: 18px;
213
+ stroke-width: 1.5;
214
+ }
215
+
216
+ .icon {
217
+ width: 20px;
218
+ height: 20px;
219
+ }
220
+
221
+ /* User Info */
222
+ .user-info {
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 12px;
226
+ padding: 16px;
227
+ background: var(--glass-strong);
228
+ backdrop-filter: blur(12px);
229
+ -webkit-backdrop-filter: blur(12px);
230
+ border: 1px solid var(--border);
231
+ border-radius: 8px;
232
+ }
233
+
234
+ .avatar {
235
+ width: 40px;
236
+ height: 40px;
237
+ border-radius: 50%;
238
+ background: var(--border);
239
+ border: 1px solid var(--border);
240
+ }
241
+
242
+ .user-info > div {
243
+ flex: 1;
244
+ }
245
+
246
+ .user-name {
247
+ font-weight: 600;
248
+ }
249
+
250
+ .user-email {
251
+ font-size: 12px;
252
+ color: var(--text-dim);
253
+ }
254
+
255
+ /* Features */
256
+ .features {
257
+ display: flex;
258
+ flex-direction: column;
259
+ gap: 12px;
260
+ }
261
+
262
+ .feature-toggle label {
263
+ display: flex;
264
+ align-items: center;
265
+ gap: 12px;
266
+ padding: 12px;
267
+ background: var(--glass-strong);
268
+ border: 1px solid var(--border);
269
+ border-radius: 8px;
270
+ cursor: pointer;
271
+ transition: all 0.2s;
272
+ }
273
+
274
+ .feature-toggle label:hover {
275
+ background: var(--glass);
276
+ border-color: var(--border-strong);
277
+ }
278
+
279
+ .feature-toggle input {
280
+ display: none;
281
+ }
282
+
283
+ .toggle {
284
+ position: relative;
285
+ width: 44px;
286
+ height: 24px;
287
+ background: rgba(255,255,255,0.1);
288
+ border-radius: 12px;
289
+ transition: background 0.3s;
290
+ flex-shrink: 0;
291
+ }
292
+
293
+ .toggle::after {
294
+ content: '';
295
+ position: absolute;
296
+ top: 2px;
297
+ left: 2px;
298
+ width: 20px;
299
+ height: 20px;
300
+ background: white;
301
+ border-radius: 50%;
302
+ transition: transform 0.3s;
303
+ box-shadow: 0 1px 4px rgba(0,0,0,0.3);
304
+ }
305
+
306
+ input:checked + .toggle {
307
+ background: var(--text);
308
+ }
309
+
310
+ input:checked + .toggle::after {
311
+ transform: translateX(20px);
312
+ }
313
+
314
+ .feature-info {
315
+ flex: 1;
316
+ }
317
+
318
+ .feature-info small {
319
+ display: block;
320
+ color: var(--text-dim);
321
+ font-size: 12px;
322
+ }
323
+
324
+ /* Status */
325
+ .status {
326
+ display: flex;
327
+ flex-direction: column;
328
+ gap: 12px;
329
+ }
330
+
331
+ .status-item {
332
+ display: flex;
333
+ align-items: center;
334
+ gap: 8px;
335
+ }
336
+
337
+ .status-dot {
338
+ width: 8px;
339
+ height: 8px;
340
+ border-radius: 50%;
341
+ background: rgba(255,255,255,0.1);
342
+ transition: all 0.3s;
343
+ }
344
+
345
+ .status-dot.connected {
346
+ background: var(--success);
347
+ box-shadow: 0 0 8px rgba(76, 175, 80, 0.3);
348
+ animation: glowPulse 3s infinite;
349
+ }
350
+
351
+ .status-dot.warning {
352
+ background: var(--warning);
353
+ box-shadow: 0 0 8px rgba(255, 193, 7, 0.2);
354
+ }
355
+
356
+ .status-dot.error {
357
+ background: var(--error);
358
+ box-shadow: 0 0 8px rgba(244, 67, 54, 0.2);
359
+ }
360
+
361
+ .status-dot.connecting {
362
+ animation: pulse 1.5s infinite;
363
+ }
364
+
365
+ .status-detail {
366
+ margin-left: auto;
367
+ font-size: 12px;
368
+ color: var(--text-dim);
369
+ }
370
+
371
+ /* Actions */
372
+ .actions {
373
+ display: flex;
374
+ gap: 12px;
375
+ }
376
+
377
+ .actions .btn {
378
+ flex: 1;
379
+ }
380
+
381
+ /* Guide */
382
+ .guide {
383
+ background: var(--glass-strong);
384
+ border: 1px solid var(--border);
385
+ padding: 16px;
386
+ border-radius: 8px;
387
+ }
388
+
389
+ .guide h3 {
390
+ margin-bottom: 8px;
391
+ }
392
+
393
+ .guide p {
394
+ font-size: 12px;
395
+ color: var(--text-dim);
396
+ margin-bottom: 4px;
397
+ }
398
+
399
+ kbd {
400
+ display: inline-block;
401
+ padding: 2px 6px;
402
+ background: rgba(255,255,255,0.06);
403
+ border: 1px solid var(--border);
404
+ border-radius: 4px;
405
+ font-family: monospace;
406
+ font-size: 11px;
407
+ }
408
+
409
+ /* Settings */
410
+ .settings-header {
411
+ display: flex;
412
+ align-items: center;
413
+ gap: 12px;
414
+ margin-bottom: 20px;
415
+ }
416
+
417
+ .settings-header h2 {
418
+ margin: 0;
419
+ }
420
+
421
+ .setting-group {
422
+ margin-bottom: 24px;
423
+ }
424
+
425
+ .setting-group label {
426
+ display: block;
427
+ margin-bottom: 12px;
428
+ color: var(--text-dim);
429
+ font-size: 12px;
430
+ }
431
+
432
+ .setting-group input[type="text"],
433
+ .setting-group input[type="number"],
434
+ .setting-group select {
435
+ width: 100%;
436
+ padding: 8px 12px;
437
+ background: var(--glass-strong);
438
+ border: 1px solid var(--border);
439
+ border-radius: 6px;
440
+ color: var(--text);
441
+ font-size: 14px;
442
+ margin-top: 4px;
443
+ transition: border-color 0.2s;
444
+ }
445
+
446
+ .setting-group input:focus,
447
+ .setting-group select:focus {
448
+ border-color: var(--border-strong);
449
+ outline: none;
450
+ }
451
+
452
+ .setting-group input[type="checkbox"] {
453
+ margin-right: 8px;
454
+ accent-color: var(--primary);
455
+ }
456
+
457
+ /* Backend Picker */
458
+ .backend-picker {
459
+ margin-bottom: 0;
460
+ }
461
+
462
+ .backend-picker h3 {
463
+ margin-bottom: 8px;
464
+ }
465
+
466
+ .backend-select-wrapper select {
467
+ width: 100%;
468
+ padding: 8px 12px;
469
+ background: var(--glass-strong);
470
+ border: 1px solid var(--border);
471
+ border-radius: 6px;
472
+ color: var(--text);
473
+ font-size: 14px;
474
+ cursor: pointer;
475
+ appearance: none;
476
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
477
+ background-repeat: no-repeat;
478
+ background-position: right 12px center;
479
+ transition: border-color 0.2s;
480
+ }
481
+
482
+ .backend-select-wrapper select:focus {
483
+ outline: none;
484
+ border-color: var(--border-strong);
485
+ }
486
+
487
+ .backend-status {
488
+ display: flex;
489
+ align-items: center;
490
+ gap: 8px;
491
+ margin-top: 8px;
492
+ font-size: 12px;
493
+ color: var(--text-dim);
494
+ }
495
+
496
+ /* Utilities */
497
+ .divider {
498
+ height: 1px;
499
+ background: var(--border);
500
+ margin: 16px 0;
501
+ }
502
+
503
+ .help-text {
504
+ text-align: center;
505
+ font-size: 12px;
506
+ color: var(--text-dim);
507
+ margin-top: 16px;
508
+ }
509
+
510
+ .help-text a {
511
+ color: var(--text-dim);
512
+ text-decoration: none;
513
+ transition: color 0.2s;
514
+ }
515
+
516
+ .help-text a:hover {
517
+ color: var(--text);
518
+ text-decoration: underline;
519
+ }