@mooncompany/uplink-chat 0.5.2 → 0.32.3

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 (215) hide show
  1. package/LICENSE +14 -1
  2. package/README.md +105 -3
  3. package/bin/uplink.js +3 -0
  4. package/middleware/error-handler.js +1 -0
  5. package/package.json +89 -5
  6. package/public/css/agents.1fd7567a.css +1499 -0
  7. package/public/css/app.bc7e7484.css +2819 -0
  8. package/public/css/artifacts.css +488 -0
  9. package/public/css/commands.css +77 -0
  10. package/public/css/connection.css +131 -0
  11. package/public/css/cron-panel.css +364 -0
  12. package/public/css/dashboard.css +233 -0
  13. package/public/css/developer.css +342 -0
  14. package/public/css/files.css +123 -0
  15. package/public/css/markdown.css +156 -0
  16. package/public/css/message-actions.css +285 -0
  17. package/public/css/mobile.css +614 -0
  18. package/public/css/panels-unified.css +485 -0
  19. package/public/css/premium.css +415 -0
  20. package/public/css/realtime.css +189 -0
  21. package/public/css/satellites.7fa72088.css +632 -0
  22. package/public/css/settings-redesign.css +1322 -0
  23. package/public/css/shortcuts.css +185 -0
  24. package/public/css/split-view.4bc23474.css +858 -0
  25. package/public/css/themes.css +387 -0
  26. package/public/css/timestamps.css +54 -0
  27. package/public/css/variables.css +81 -0
  28. package/public/dist/bundle.493af136.js +1 -0
  29. package/public/favicon-256.png +0 -0
  30. package/public/icon-192.png +0 -0
  31. package/public/icon-512.png +0 -0
  32. package/public/img/icons/icon-alert-triangle.svg +17 -0
  33. package/public/img/icons/icon-brain.svg +20 -0
  34. package/public/img/icons/icon-brand-python.svg +19 -0
  35. package/public/img/icons/icon-camera.svg +16 -0
  36. package/public/img/icons/icon-chart-bar.svg +18 -0
  37. package/public/img/icons/icon-check.svg +15 -0
  38. package/public/img/icons/icon-circle-check.svg +16 -0
  39. package/public/img/icons/icon-clipboard.svg +16 -0
  40. package/public/img/icons/icon-cloud.svg +15 -0
  41. package/public/img/icons/icon-confetti.svg +24 -0
  42. package/public/img/icons/icon-device-mobile.svg +17 -0
  43. package/public/img/icons/icon-diamond.svg +16 -0
  44. package/public/img/icons/icon-file-text.svg +19 -0
  45. package/public/img/icons/icon-file-type-css.svg +19 -0
  46. package/public/img/icons/icon-file-type-csv.svg +19 -0
  47. package/public/img/icons/icon-file-type-doc.svg +19 -0
  48. package/public/img/icons/icon-file-type-html.svg +23 -0
  49. package/public/img/icons/icon-file-type-js.svg +18 -0
  50. package/public/img/icons/icon-file-type-pdf.svg +20 -0
  51. package/public/img/icons/icon-file-zip.svg +22 -0
  52. package/public/img/icons/icon-file.svg +16 -0
  53. package/public/img/icons/icon-folder.svg +15 -0
  54. package/public/img/icons/icon-headphones.svg +17 -0
  55. package/public/img/icons/icon-hourglass.svg +18 -0
  56. package/public/img/icons/icon-keyboard.svg +22 -0
  57. package/public/img/icons/icon-link.svg +17 -0
  58. package/public/img/icons/icon-lock-open.svg +17 -0
  59. package/public/img/icons/icon-lock.svg +17 -0
  60. package/public/img/icons/icon-mail.svg +16 -0
  61. package/public/img/icons/icon-message-dots.svg +18 -0
  62. package/public/img/icons/icon-microphone-2.svg +16 -0
  63. package/public/img/icons/icon-microphone.svg +18 -0
  64. package/public/img/icons/icon-movie.svg +22 -0
  65. package/public/img/icons/icon-music.svg +18 -0
  66. package/public/img/icons/icon-palette.svg +18 -0
  67. package/public/img/icons/icon-paperclip.svg +15 -0
  68. package/public/img/icons/icon-pencil.svg +16 -0
  69. package/public/img/icons/icon-photo.svg +18 -0
  70. package/public/img/icons/icon-presentation.svg +19 -0
  71. package/public/img/icons/icon-robot.svg +23 -0
  72. package/public/img/icons/icon-rocket.svg +17 -0
  73. package/public/img/icons/icon-satellite.svg +20 -0
  74. package/public/img/icons/icon-settings.svg +16 -0
  75. package/public/img/icons/icon-shield-lock.svg +17 -0
  76. package/public/img/icons/icon-sparkles.svg +15 -0
  77. package/public/img/icons/icon-star-filled.svg +11 -0
  78. package/public/img/icons/icon-tool.svg +15 -0
  79. package/public/img/icons/icon-trash.svg +19 -0
  80. package/public/img/icons/icon-volume.svg +17 -0
  81. package/public/img/icons/icon-world.svg +19 -0
  82. package/public/img/icons/icon-x.svg +16 -0
  83. package/public/img/logo.svg +13 -0
  84. package/public/img/wordmark.svg +35 -0
  85. package/public/index.html +1195 -0
  86. package/public/js/agents-data.js +1 -0
  87. package/public/js/agents-ui.js +1 -0
  88. package/public/js/agents.js +1 -0
  89. package/public/js/app.js +1 -0
  90. package/public/js/appearance-settings.js +1 -0
  91. package/public/js/artifacts.js +1 -0
  92. package/public/js/audio-pcm-processor.js +1 -0
  93. package/public/js/audio-queue.js +1 -0
  94. package/public/js/bootstrap.js +1 -0
  95. package/public/js/chat.js +1 -0
  96. package/public/js/commands.js +1 -0
  97. package/public/js/connection-api.js +1 -0
  98. package/public/js/connection.js +1 -0
  99. package/public/js/context-tracker.js +1 -0
  100. package/public/js/core.js +1 -0
  101. package/public/js/cron-panel.js +1 -0
  102. package/public/js/dashboard.js +1 -0
  103. package/public/js/developer.js +1 -0
  104. package/public/js/encryption.js +1 -0
  105. package/public/js/errors.js +1 -0
  106. package/public/js/event-bus.js +1 -0
  107. package/public/js/fetch-utils.js +1 -0
  108. package/public/js/file-handler.js +1 -0
  109. package/public/js/files.js +1 -0
  110. package/public/js/gateway-chat.js +1 -0
  111. package/public/js/logger.js +1 -0
  112. package/public/js/markdown.js +1 -0
  113. package/public/js/message-actions.js +1 -0
  114. package/public/js/message-renderer.js +1 -0
  115. package/public/js/missed-messages.js +1 -0
  116. package/public/js/mobile-debug.js +1 -0
  117. package/public/js/notifications.js +1 -0
  118. package/public/js/offline-queue.js +1 -0
  119. package/public/js/onboarding.js +1 -0
  120. package/public/js/panels.js +1 -0
  121. package/public/js/premium.js +1 -0
  122. package/public/js/primary-header.js +1 -0
  123. package/public/js/realtime-voice.js +1 -0
  124. package/public/js/satellite-sync.js +1 -0
  125. package/public/js/satellite-ui.js +1 -0
  126. package/public/js/satellites.js +1 -0
  127. package/public/js/settings.js +1 -0
  128. package/public/js/shortcuts.js +1 -0
  129. package/public/js/split-chat.js +1 -0
  130. package/public/js/split-resize.js +1 -0
  131. package/public/js/splitview.js +1 -0
  132. package/public/js/storage.js +1 -0
  133. package/public/js/streaming-handler.js +1 -0
  134. package/public/js/stt-settings.js +1 -0
  135. package/public/js/themes.js +1 -0
  136. package/public/js/timestamps.js +1 -0
  137. package/public/js/tts-settings.js +1 -0
  138. package/public/js/ui.js +1 -0
  139. package/public/js/update-notifier.js +1 -0
  140. package/public/js/utils/constants.js +1 -0
  141. package/public/js/utils/icons.js +1 -0
  142. package/public/js/utils/sanitize.js +1 -0
  143. package/public/js/utils/sse-parser.js +1 -0
  144. package/public/js/vad.js +1 -0
  145. package/public/js/vendor/dompurify.min.js +2 -0
  146. package/public/js/voice-settings-v2.js +1 -0
  147. package/public/js/voice.js +1 -0
  148. package/public/manifest.json +66 -0
  149. package/public/moon_texture.jpg +0 -0
  150. package/public/sw.js +1 -0
  151. package/public/three.min.js +6 -0
  152. package/public/u-icon.png +0 -0
  153. package/server/channel.js +1 -0
  154. package/server/chat.js +1 -0
  155. package/server/config-store.js +1 -0
  156. package/server/config.js +1 -0
  157. package/server/context.js +1 -0
  158. package/server/gateway-api-proxy.js +1 -0
  159. package/server/gateway-commands.js +1 -0
  160. package/server/gateway-proxy.js +1 -0
  161. package/server/index.js +1 -0
  162. package/server/logger.js +1 -0
  163. package/server/message-store.js +1 -0
  164. package/server/middleware/auth.js +1 -0
  165. package/server/middleware.js +1 -0
  166. package/server/openclaw-discover.js +1 -0
  167. package/server/premium/index.js +1 -0
  168. package/server/premium/license.js +1 -0
  169. package/server/realtime/bridge.js +1 -0
  170. package/server/realtime/index.js +1 -0
  171. package/server/realtime/tts-stream.js +1 -0
  172. package/server/routes/agents.js +1 -0
  173. package/server/routes/artifacts.js +1 -0
  174. package/server/routes/chat.js +1 -0
  175. package/server/routes/config-settings.js +1 -0
  176. package/server/routes/config.js +1 -0
  177. package/server/routes/cron.js +1 -0
  178. package/server/routes/files.js +1 -0
  179. package/server/routes/index.js +1 -0
  180. package/server/routes/media.js +1 -0
  181. package/server/routes/missed-messages.js +1 -0
  182. package/server/routes/premium.js +1 -0
  183. package/server/routes/push.js +1 -0
  184. package/server/routes/satellite.js +1 -0
  185. package/server/routes/status.js +1 -0
  186. package/server/routes/stt.js +1 -0
  187. package/server/routes/voice.js +1 -0
  188. package/server/routes/webhooks.js +1 -0
  189. package/server/routes.js +1 -0
  190. package/server/runtime-config.js +1 -0
  191. package/server/share.js +1 -0
  192. package/server/stt/faster-whisper.js +1 -0
  193. package/server/stt/groq.js +1 -0
  194. package/server/stt/index.js +1 -0
  195. package/server/stt/openai.js +1 -0
  196. package/server/sync.js +1 -0
  197. package/server/tailscale-https.js +1 -0
  198. package/server/tts.js +1 -0
  199. package/server/update-checker.js +1 -0
  200. package/server/utils/filename.js +1 -0
  201. package/server/utils.js +1 -0
  202. package/server/watchdog.js +3 -0
  203. package/server/websocket/broadcast.js +1 -0
  204. package/server/websocket/connections.js +1 -0
  205. package/server/websocket/index.js +1 -0
  206. package/server/websocket/routing.js +1 -0
  207. package/server/websocket/sync.js +1 -0
  208. package/server.js +1 -0
  209. package/utils/detect-tool-usage.js +1 -0
  210. package/utils/errors.js +1 -0
  211. package/utils/html-escape.js +1 -0
  212. package/utils/id-sanitize.js +1 -0
  213. package/utils/response.js +1 -0
  214. package/utils/with-retry.js +1 -0
  215. package/index.js +0 -2
@@ -0,0 +1,1322 @@
1
+ /**
2
+ * Settings Panel Redesign
3
+ * Visual cohesion pass — consistent spacing, typography,
4
+ * polished toggles, voice sub-grouping.
5
+ *
6
+ * CONSTRAINTS: No JS logic changes. All IDs/classes JS touches are preserved.
7
+ * This file layers on top of app.css settings styles.
8
+ */
9
+
10
+ /* ==========================================================================
11
+ PANEL HEADER — Richer identity
12
+ ========================================================================== */
13
+
14
+ .settings-panel-header {
15
+ padding: var(--space-4) var(--space-5);
16
+ gap: var(--space-3);
17
+ min-height: 56px;
18
+ }
19
+
20
+ .settings-panel-title {
21
+ font-family: var(--font-mono);
22
+ font-size: var(--text-sm);
23
+ color: var(--accent);
24
+ letter-spacing: 1px;
25
+ text-transform: uppercase;
26
+ display: flex;
27
+ align-items: center;
28
+ gap: var(--space-2);
29
+ }
30
+
31
+ .settings-panel-title::before {
32
+ content: '';
33
+ display: inline-block;
34
+ width: 6px;
35
+ height: 6px;
36
+ border-radius: 50%;
37
+ background: var(--accent);
38
+ box-shadow: 0 0 6px var(--accent-30);
39
+ flex-shrink: 0;
40
+ }
41
+
42
+ .settings-panel-close {
43
+ width: 36px;
44
+ height: 36px;
45
+ border-radius: var(--radius-md);
46
+ font-size: var(--text-lg);
47
+ color: var(--text-dim);
48
+ transition: color 0.15s, background 0.15s;
49
+ }
50
+
51
+ .settings-panel-close:hover {
52
+ color: var(--text);
53
+ background: var(--accent-10);
54
+ }
55
+
56
+ /* ==========================================================================
57
+ SECTION HEADERS — Elevated, card-like feel
58
+ ========================================================================== */
59
+
60
+ .settings-section {
61
+ border-bottom: 1px solid var(--border);
62
+ border-radius: 0;
63
+ overflow: hidden;
64
+ }
65
+
66
+ .settings-section:last-child {
67
+ border-bottom: none;
68
+ }
69
+
70
+ .settings-section-header {
71
+ padding: var(--space-4) var(--space-3);
72
+ min-height: 52px;
73
+ gap: var(--space-3);
74
+ border-radius: 0;
75
+ transition: background 0.15s, color 0.15s;
76
+ position: relative;
77
+ }
78
+
79
+ .settings-section-header:hover {
80
+ background: var(--accent-05);
81
+ color: var(--text);
82
+ }
83
+
84
+ .settings-section-header[aria-expanded="true"] {
85
+ color: var(--accent);
86
+ }
87
+
88
+ .settings-section-header[aria-expanded="true"] .settings-section-icon {
89
+ color: var(--accent);
90
+ }
91
+
92
+ .settings-section-icon {
93
+ width: 32px;
94
+ height: 32px;
95
+ border-radius: var(--radius-md);
96
+ background: var(--accent-10);
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ flex-shrink: 0;
101
+ color: var(--accent);
102
+ transition: background 0.15s;
103
+ }
104
+
105
+ .settings-section-header:hover .settings-section-icon {
106
+ background: var(--accent-15);
107
+ }
108
+
109
+ .settings-section-icon svg {
110
+ width: 16px;
111
+ height: 16px;
112
+ }
113
+
114
+ .settings-section-title {
115
+ font-family: var(--font-mono);
116
+ font-size: var(--text-xs);
117
+ text-transform: uppercase;
118
+ letter-spacing: 0.5px;
119
+ color: var(--text-muted);
120
+ }
121
+
122
+ .settings-section-chevron {
123
+ color: var(--text-dim);
124
+ transition: transform 0.2s ease, color 0.15s;
125
+ }
126
+
127
+ .settings-section-header:hover .settings-section-chevron {
128
+ color: var(--accent);
129
+ }
130
+
131
+ .settings-section-header[aria-expanded="true"] .settings-section-chevron {
132
+ color: var(--accent);
133
+ transform: rotate(90deg);
134
+ }
135
+
136
+ .settings-section-chevron svg {
137
+ width: 14px;
138
+ height: 14px;
139
+ }
140
+
141
+ /* Danger zone overrides */
142
+ .settings-section-danger .settings-section-icon {
143
+ background: rgba(220, 38, 38, 0.1);
144
+ color: var(--warning);
145
+ }
146
+
147
+ .settings-section-danger .settings-section-header {
148
+ color: var(--text-dim);
149
+ }
150
+
151
+ .settings-section-danger .settings-section-header:hover {
152
+ background: rgba(220, 38, 38, 0.05);
153
+ color: var(--error);
154
+ }
155
+
156
+ .settings-section-danger .settings-section-header:hover .settings-section-icon {
157
+ background: rgba(220, 38, 38, 0.15);
158
+ color: var(--error);
159
+ }
160
+
161
+ /* ==========================================================================
162
+ SECTION BODY & ROWS — Tight, iOS-style list
163
+ ========================================================================== */
164
+
165
+ .settings-section-body {
166
+ transition: max-height 0.28s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
167
+ max-height: 2400px; /* Voice section is huge */
168
+ opacity: 1;
169
+ padding: 0 var(--space-3) var(--space-2);
170
+ }
171
+
172
+ .settings-section-body.collapsed {
173
+ max-height: 0;
174
+ opacity: 0;
175
+ pointer-events: none;
176
+ padding-bottom: 0;
177
+ }
178
+
179
+ .setting-row {
180
+ padding: var(--space-4) var(--space-2);
181
+ gap: var(--space-3);
182
+ min-height: 52px;
183
+ border-bottom: 1px solid var(--border);
184
+ transition: background 0.1s;
185
+ border-radius: var(--radius-sm);
186
+ }
187
+
188
+ .setting-row:hover {
189
+ background: var(--white-05, rgba(255,255,255,0.03));
190
+ }
191
+
192
+ .setting-row:last-child {
193
+ border-bottom: none;
194
+ }
195
+
196
+ .setting-label {
197
+ font-size: var(--text-sm);
198
+ font-weight: 500;
199
+ color: var(--text);
200
+ line-height: 1.3;
201
+ }
202
+
203
+ .setting-desc {
204
+ font-size: var(--text-xs);
205
+ color: var(--text-dim);
206
+ margin-top: 3px;
207
+ line-height: 1.4;
208
+ }
209
+
210
+ /* ==========================================================================
211
+ INPUTS & SELECTS — Consistent, polished
212
+ ========================================================================== */
213
+
214
+ .setting-input {
215
+ background: var(--bg-input);
216
+ border: 1px solid var(--border);
217
+ border-radius: var(--radius-md);
218
+ padding: var(--space-2) var(--space-3);
219
+ color: var(--text);
220
+ font-size: var(--text-sm);
221
+ width: 130px;
222
+ outline: none;
223
+ transition: border-color 0.15s, box-shadow 0.15s;
224
+ height: 36px;
225
+ }
226
+
227
+ .setting-input:hover {
228
+ border-color: var(--accent-30);
229
+ }
230
+
231
+ .setting-input:focus {
232
+ border-color: var(--accent);
233
+ box-shadow: 0 0 0 3px var(--accent-10);
234
+ }
235
+
236
+ .setting-select {
237
+ background: var(--bg-input);
238
+ border: 1px solid var(--border);
239
+ border-radius: var(--radius-md);
240
+ padding: var(--space-2) var(--space-3);
241
+ color: var(--text);
242
+ font-size: var(--text-sm);
243
+ outline: none;
244
+ cursor: pointer;
245
+ height: 36px;
246
+ transition: border-color 0.15s, box-shadow 0.15s;
247
+ flex-shrink: 0;
248
+ /* Custom arrow */
249
+ appearance: none;
250
+ -webkit-appearance: none;
251
+ 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' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
252
+ background-repeat: no-repeat;
253
+ background-position: right 10px center;
254
+ padding-right: 32px;
255
+ }
256
+
257
+ .setting-select:hover {
258
+ border-color: var(--accent-30);
259
+ }
260
+
261
+ .setting-select:focus,
262
+ .setting-select:focus-visible {
263
+ border-color: var(--accent);
264
+ box-shadow: 0 0 0 3px var(--accent-10);
265
+ outline: none;
266
+ }
267
+
268
+ .setting-input-group {
269
+ display: flex;
270
+ gap: var(--space-2);
271
+ margin-top: var(--space-3);
272
+ min-width: 0;
273
+ max-width: 100%;
274
+ }
275
+
276
+ .setting-input-mono {
277
+ flex: 1;
278
+ min-width: 0;
279
+ font-family: var(--font-mono);
280
+ font-size: var(--text-xs);
281
+ letter-spacing: 0;
282
+ }
283
+
284
+ .setting-input-wide {
285
+ max-width: 200px;
286
+ width: 100%;
287
+ }
288
+
289
+ /* ==========================================================================
290
+ BUTTONS — Refined sizing, better hover feedback
291
+ ========================================================================== */
292
+
293
+ .setting-btn {
294
+ display: inline-flex;
295
+ align-items: center;
296
+ justify-content: center;
297
+ padding: 0 var(--space-4);
298
+ border-radius: var(--radius-md);
299
+ font-size: var(--text-xs);
300
+ font-weight: 600;
301
+ letter-spacing: 0.2px;
302
+ cursor: pointer;
303
+ border: none;
304
+ transition: background 0.15s, opacity 0.15s, box-shadow 0.15s, transform 0.1s;
305
+ white-space: nowrap;
306
+ height: 34px;
307
+ flex-shrink: 0;
308
+ }
309
+
310
+ .setting-btn:focus-visible {
311
+ outline: 2px solid var(--accent);
312
+ outline-offset: 2px;
313
+ }
314
+
315
+ .setting-btn:active {
316
+ transform: scale(0.96);
317
+ }
318
+
319
+ .setting-btn-primary {
320
+ background: var(--accent);
321
+ color: var(--text-inverse, white);
322
+ box-shadow: 0 1px 3px var(--accent-30);
323
+ }
324
+
325
+ .setting-btn-primary:hover {
326
+ opacity: 0.88;
327
+ box-shadow: 0 2px 6px var(--accent-40);
328
+ }
329
+
330
+ .setting-btn-secondary {
331
+ background: var(--bg-input);
332
+ border: 1px solid var(--border);
333
+ color: var(--text-muted);
334
+ }
335
+
336
+ .setting-btn-secondary:hover {
337
+ background: var(--accent-10);
338
+ border-color: var(--accent-20);
339
+ color: var(--text);
340
+ }
341
+
342
+ .setting-btn-danger {
343
+ background: var(--error);
344
+ color: white;
345
+ }
346
+
347
+ .setting-btn-danger:hover {
348
+ opacity: 0.85;
349
+ box-shadow: 0 2px 6px rgba(220, 38, 38, 0.35);
350
+ }
351
+
352
+ /* ==========================================================================
353
+ TOGGLES — Unified style (both .toggle and .toggle-switch labels)
354
+ ========================================================================== */
355
+
356
+ /* Existing .toggle (div-based, JS-controlled) */
357
+ .toggle {
358
+ width: 44px;
359
+ height: 24px;
360
+ background: var(--border);
361
+ border-radius: var(--radius-full);
362
+ position: relative;
363
+ cursor: pointer;
364
+ transition: background 0.2s;
365
+ flex-shrink: 0;
366
+ border: 2px solid transparent;
367
+ }
368
+
369
+ .toggle:hover {
370
+ border-color: var(--accent-20);
371
+ }
372
+
373
+ .toggle:focus-visible {
374
+ outline: 2px solid var(--accent);
375
+ outline-offset: 2px;
376
+ }
377
+
378
+ .toggle.on {
379
+ background: var(--accent);
380
+ border-color: transparent;
381
+ }
382
+
383
+ .toggle::after {
384
+ content: '';
385
+ position: absolute;
386
+ width: 18px;
387
+ height: 18px;
388
+ background: white;
389
+ border-radius: var(--radius-full);
390
+ top: 1px;
391
+ left: 1px;
392
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
393
+ box-shadow: 0 1px 3px rgba(0,0,0,0.25);
394
+ }
395
+
396
+ .toggle.on::after {
397
+ transform: translateX(20px);
398
+ }
399
+
400
+ .toggle.disabled {
401
+ opacity: 0.4;
402
+ cursor: not-allowed;
403
+ }
404
+
405
+ /* Input checkbox-based toggles (.toggle-switch label + .toggle-slider) */
406
+ .toggle-switch {
407
+ position: relative;
408
+ display: inline-flex;
409
+ width: 44px;
410
+ height: 24px;
411
+ flex-shrink: 0;
412
+ cursor: pointer;
413
+ }
414
+
415
+ .toggle-switch input {
416
+ opacity: 0;
417
+ width: 0;
418
+ height: 0;
419
+ position: absolute;
420
+ }
421
+
422
+ .toggle-slider {
423
+ position: absolute;
424
+ inset: 0;
425
+ background: var(--border);
426
+ border-radius: var(--radius-full);
427
+ transition: background 0.2s;
428
+ border: 2px solid transparent;
429
+ }
430
+
431
+ .toggle-slider::before {
432
+ content: '';
433
+ position: absolute;
434
+ width: 18px;
435
+ height: 18px;
436
+ background: white;
437
+ border-radius: var(--radius-full);
438
+ top: 1px;
439
+ left: 1px;
440
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
441
+ box-shadow: 0 1px 3px rgba(0,0,0,0.25);
442
+ }
443
+
444
+ .toggle-switch input:checked + .toggle-slider {
445
+ background: var(--accent);
446
+ }
447
+
448
+ .toggle-switch input:checked + .toggle-slider::before {
449
+ transform: translateX(20px);
450
+ }
451
+
452
+ .toggle-switch:hover .toggle-slider {
453
+ border-color: var(--accent-20);
454
+ }
455
+
456
+ .toggle-switch input:focus-visible + .toggle-slider {
457
+ outline: 2px solid var(--accent);
458
+ outline-offset: 2px;
459
+ border-radius: var(--radius-full);
460
+ }
461
+
462
+ /* ==========================================================================
463
+ VOICE SECTION — Sub-group visual hierarchy
464
+ ========================================================================== */
465
+
466
+ /* Sub-group container */
467
+ .voice-subgroup {
468
+ margin: var(--space-3) 0 var(--space-1);
469
+ border: 1px solid var(--border);
470
+ border-radius: var(--radius-lg);
471
+ overflow: hidden;
472
+ background: var(--accent-05);
473
+ }
474
+
475
+ .voice-subgroup-header {
476
+ display: flex;
477
+ align-items: center;
478
+ gap: var(--space-2);
479
+ padding: var(--space-3) var(--space-4);
480
+ background: var(--accent-10);
481
+ border-bottom: 1px solid var(--border);
482
+ }
483
+
484
+ .voice-subgroup-icon {
485
+ font-size: 13px;
486
+ line-height: 1;
487
+ flex-shrink: 0;
488
+ }
489
+
490
+ .voice-subgroup-title {
491
+ font-size: var(--text-xs);
492
+ font-weight: 700;
493
+ text-transform: uppercase;
494
+ letter-spacing: 0.8px;
495
+ color: var(--accent);
496
+ }
497
+
498
+ .voice-subgroup .setting-row {
499
+ border-radius: 0;
500
+ padding-left: var(--space-4);
501
+ padding-right: var(--space-4);
502
+ }
503
+
504
+ .voice-subgroup .setting-row:last-child {
505
+ border-bottom: none;
506
+ }
507
+
508
+ /* Voice mode selector cards — more compact, horizontal on desktop */
509
+ .voice-mode-cards {
510
+ display: grid;
511
+ grid-template-columns: 1fr;
512
+ gap: var(--space-2);
513
+ margin-top: var(--space-3);
514
+ }
515
+
516
+ @media (min-width: 480px) {
517
+ .voice-mode-cards {
518
+ grid-template-columns: repeat(3, 1fr);
519
+ }
520
+ }
521
+
522
+ .voice-mode-card {
523
+ display: flex;
524
+ flex-direction: column;
525
+ align-items: center;
526
+ text-align: center;
527
+ gap: var(--space-2);
528
+ padding: var(--space-4) var(--space-3);
529
+ background: var(--bg-input);
530
+ border: 2px solid var(--border);
531
+ border-radius: var(--radius-lg);
532
+ cursor: pointer;
533
+ transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
534
+ }
535
+
536
+ @media (max-width: 479px) {
537
+ .voice-mode-card {
538
+ flex-direction: row;
539
+ text-align: left;
540
+ padding: var(--space-3) var(--space-4);
541
+ }
542
+ }
543
+
544
+ .voice-mode-card:hover {
545
+ border-color: var(--accent-40);
546
+ background: var(--accent-05);
547
+ }
548
+
549
+ .voice-mode-card.selected {
550
+ border-color: var(--accent);
551
+ background: var(--accent-10);
552
+ box-shadow: 0 0 0 1px var(--accent-20);
553
+ }
554
+
555
+ .voice-mode-icon {
556
+ font-size: 24px;
557
+ line-height: 1;
558
+ flex-shrink: 0;
559
+ }
560
+
561
+ .voice-mode-content {
562
+ flex: 1;
563
+ }
564
+
565
+ .voice-mode-title {
566
+ font-size: var(--text-xs);
567
+ font-weight: 700;
568
+ color: var(--text);
569
+ letter-spacing: 0.1px;
570
+ margin-bottom: 2px;
571
+ }
572
+
573
+ .voice-mode-desc {
574
+ font-size: var(--text-xs);
575
+ color: var(--text-dim);
576
+ line-height: 1.35;
577
+ }
578
+
579
+ .voice-mode-card.selected .voice-mode-title {
580
+ color: var(--accent);
581
+ }
582
+
583
+ .voice-mode-card:focus-visible {
584
+ outline: 2px solid var(--accent);
585
+ outline-offset: 2px;
586
+ }
587
+
588
+ /* ==========================================================================
589
+ PROGRESSIVE DISCLOSURE — Voice context panels
590
+ ========================================================================== */
591
+
592
+ /* Inline mode panels (inside the Voice Mode subgroup) */
593
+ .voice-context-panel {
594
+ max-height: 0;
595
+ opacity: 0;
596
+ overflow: hidden;
597
+ transition: max-height 0.32s cubic-bezier(0.4, 0, 0.2, 1),
598
+ opacity 0.22s ease;
599
+ }
600
+
601
+ .voice-context-panel--visible {
602
+ max-height: 600px;
603
+ opacity: 1;
604
+ }
605
+
606
+ /* For the legacy setting-hidden approach — keep it working */
607
+ #pushToTalkSettings,
608
+ #liveVoiceSettings,
609
+ #agentVoiceSettings {
610
+ margin-top: 0;
611
+ }
612
+
613
+ /* ── Context panels wrapper (Voice Output + Voice Input subgroups) ── */
614
+
615
+ .voice-context-panels {
616
+ /* Container — no special styles needed; children animate themselves */
617
+ }
618
+
619
+ /* Individual subgroups that are context-aware */
620
+ [data-voice-context] {
621
+ max-height: 800px; /* generous upper bound */
622
+ opacity: 1;
623
+ overflow: hidden;
624
+ transition: max-height 0.32s cubic-bezier(0.4, 0, 0.2, 1),
625
+ opacity 0.22s ease,
626
+ margin 0.22s ease;
627
+ }
628
+
629
+ [data-voice-context].voice-context-hidden {
630
+ max-height: 0;
631
+ opacity: 0;
632
+ pointer-events: none;
633
+ margin-top: 0 !important;
634
+ margin-bottom: 0 !important;
635
+ }
636
+
637
+ /* ── Advanced Voice Settings Expander ── */
638
+
639
+ .voice-advanced-expander {
640
+ /* Hidden until a mode is selected */
641
+ max-height: 0;
642
+ opacity: 0;
643
+ overflow: hidden;
644
+ transition: max-height 0.25s cubic-bezier(0.4, 0, 0.2, 1),
645
+ opacity 0.2s ease,
646
+ margin 0.2s ease;
647
+ }
648
+
649
+ .voice-advanced-expander--visible {
650
+ max-height: 200px;
651
+ opacity: 1;
652
+ margin-top: var(--space-2);
653
+ }
654
+
655
+ .voice-advanced-expander-btn {
656
+ display: flex;
657
+ align-items: center;
658
+ gap: var(--space-2);
659
+ width: 100%;
660
+ padding: var(--space-3) var(--space-4);
661
+ background: transparent;
662
+ border: 1px dashed var(--border);
663
+ border-radius: var(--radius-lg);
664
+ cursor: pointer;
665
+ color: var(--text-dim);
666
+ font-size: var(--text-xs);
667
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
668
+ }
669
+
670
+ .voice-advanced-expander-btn:hover {
671
+ border-color: var(--accent-30);
672
+ color: var(--text);
673
+ background: var(--accent-05);
674
+ }
675
+
676
+ .voice-advanced-expander--open .voice-advanced-expander-btn {
677
+ border-color: var(--accent-40);
678
+ border-style: solid;
679
+ color: var(--accent);
680
+ background: var(--accent-05);
681
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
682
+ border-bottom-color: transparent;
683
+ }
684
+
685
+ .voice-advanced-expander-icon {
686
+ font-size: 14px;
687
+ flex-shrink: 0;
688
+ opacity: 0.8;
689
+ }
690
+
691
+ .voice-advanced-expander-label {
692
+ font-weight: 600;
693
+ font-size: var(--text-xs);
694
+ letter-spacing: 0.1px;
695
+ flex-shrink: 0;
696
+ }
697
+
698
+ .voice-advanced-expander-hint {
699
+ font-size: var(--text-xs);
700
+ color: var(--text-dim);
701
+ flex: 1;
702
+ text-align: left;
703
+ overflow: hidden;
704
+ text-overflow: ellipsis;
705
+ white-space: nowrap;
706
+ }
707
+
708
+ .voice-advanced-expander-chevron {
709
+ flex-shrink: 0;
710
+ transition: transform 0.2s ease;
711
+ color: var(--text-dim);
712
+ }
713
+
714
+ .voice-advanced-expander--open .voice-advanced-expander-chevron {
715
+ transform: rotate(90deg);
716
+ color: var(--accent);
717
+ }
718
+
719
+ /* ── Agent Voice: inline STT Advanced row ── */
720
+
721
+ .voice-advanced-row {
722
+ border-top: 1px solid var(--border);
723
+ }
724
+
725
+ .voice-advanced-toggle {
726
+ display: flex;
727
+ align-items: center;
728
+ gap: var(--space-2);
729
+ width: 100%;
730
+ padding: var(--space-3) var(--space-4);
731
+ background: transparent;
732
+ border: none;
733
+ cursor: pointer;
734
+ color: var(--text-dim);
735
+ font-size: var(--text-xs);
736
+ transition: color 0.15s, background 0.15s;
737
+ text-align: left;
738
+ }
739
+
740
+ .voice-advanced-toggle:hover {
741
+ color: var(--text);
742
+ background: var(--white-05, rgba(255,255,255,0.03));
743
+ }
744
+
745
+ .voice-advanced-toggle[aria-expanded="true"] {
746
+ color: var(--accent);
747
+ }
748
+
749
+ .voice-advanced-toggle-label {
750
+ font-weight: 600;
751
+ flex-shrink: 0;
752
+ }
753
+
754
+ .voice-advanced-toggle-hint {
755
+ flex: 1;
756
+ color: var(--text-dim);
757
+ font-size: var(--text-xs);
758
+ overflow: hidden;
759
+ text-overflow: ellipsis;
760
+ white-space: nowrap;
761
+ }
762
+
763
+ .voice-advanced-chevron {
764
+ flex-shrink: 0;
765
+ transition: transform 0.2s ease;
766
+ }
767
+
768
+ .voice-advanced-toggle[aria-expanded="true"] .voice-advanced-chevron {
769
+ transform: rotate(90deg);
770
+ }
771
+
772
+ .voice-advanced-panel {
773
+ max-height: 0;
774
+ overflow: hidden;
775
+ transition: max-height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
776
+ }
777
+
778
+ .voice-advanced-panel--open {
779
+ max-height: 300px;
780
+ }
781
+
782
+ /* ==========================================================================
783
+ REDUCED MOTION addendum
784
+ ========================================================================== */
785
+
786
+ @media (prefers-reduced-motion: reduce) {
787
+ .voice-context-panel,
788
+ [data-voice-context],
789
+ .voice-advanced-expander,
790
+ .voice-advanced-panel {
791
+ transition: opacity 0.15s, max-height 0s;
792
+ }
793
+ }
794
+
795
+ /* TTS provider sub-panel */
796
+ .tts-provider-config {
797
+ background: var(--accent-05);
798
+ border-top: 1px solid var(--border);
799
+ border-radius: 0 0 var(--radius-md) var(--radius-md);
800
+ padding: var(--space-1) 0 0;
801
+ }
802
+
803
+ .tts-provider-config .setting-row {
804
+ padding-left: var(--space-4);
805
+ padding-right: var(--space-4);
806
+ }
807
+
808
+ .tts-provider-config .setting-row:last-child {
809
+ border-bottom: none;
810
+ }
811
+
812
+ /* VAD slider polish */
813
+ #vadSensitivitySlider {
814
+ -webkit-appearance: none;
815
+ appearance: none;
816
+ height: 4px;
817
+ border-radius: 2px;
818
+ background: var(--border);
819
+ outline: none;
820
+ cursor: pointer;
821
+ flex: 1;
822
+ }
823
+
824
+ #vadSensitivitySlider::-webkit-slider-thumb {
825
+ -webkit-appearance: none;
826
+ width: 18px;
827
+ height: 18px;
828
+ border-radius: 50%;
829
+ background: var(--accent);
830
+ cursor: pointer;
831
+ box-shadow: 0 0 0 3px var(--accent-20);
832
+ transition: box-shadow 0.15s;
833
+ }
834
+
835
+ #vadSensitivitySlider::-webkit-slider-thumb:hover {
836
+ box-shadow: 0 0 0 5px var(--accent-20);
837
+ }
838
+
839
+ #vadSensitivitySlider::-moz-range-thumb {
840
+ width: 18px;
841
+ height: 18px;
842
+ border-radius: 50%;
843
+ background: var(--accent);
844
+ cursor: pointer;
845
+ border: none;
846
+ box-shadow: 0 0 0 3px var(--accent-20);
847
+ }
848
+
849
+ #vadSensitivitySlider:focus-visible {
850
+ box-shadow: 0 0 0 2px var(--accent);
851
+ }
852
+
853
+ /* ==========================================================================
854
+ STATUS INDICATOR — More distinctive
855
+ ========================================================================== */
856
+
857
+ .status-indicator {
858
+ width: 10px;
859
+ height: 10px;
860
+ border-radius: var(--radius-full);
861
+ background: var(--text-dim);
862
+ flex-shrink: 0;
863
+ position: relative;
864
+ }
865
+
866
+ .status-indicator.connected::after {
867
+ content: '';
868
+ position: absolute;
869
+ inset: -3px;
870
+ border-radius: 50%;
871
+ background: var(--success);
872
+ opacity: 0.25;
873
+ }
874
+
875
+ .status-indicator.connected {
876
+ background: var(--success);
877
+ }
878
+
879
+ .status-indicator.disconnected {
880
+ background: var(--error);
881
+ }
882
+
883
+ /* ==========================================================================
884
+ PREMIUM SECTION — Keep the marketing feel
885
+ ========================================================================== */
886
+
887
+ .premium-badge {
888
+ font-size: var(--text-xs);
889
+ font-weight: 700;
890
+ background: var(--accent);
891
+ color: var(--text-inverse, white);
892
+ padding: 2px var(--space-2);
893
+ border-radius: var(--radius-full);
894
+ letter-spacing: 0.3px;
895
+ margin-left: auto;
896
+ margin-right: var(--space-2);
897
+ }
898
+
899
+ /* ==========================================================================
900
+ SECTION PANEL — Content padding consistency
901
+ ========================================================================== */
902
+
903
+ .settings-panel-content {
904
+ padding: var(--space-2) var(--space-4);
905
+ }
906
+
907
+ /* ==========================================================================
908
+ MOBILE ADJUSTMENTS
909
+ ========================================================================== */
910
+
911
+ @media (max-width: 768px) {
912
+ .settings-panel-content {
913
+ padding: var(--space-2) var(--space-3);
914
+ }
915
+
916
+ .setting-row {
917
+ padding: var(--space-3) var(--space-2);
918
+ min-height: 56px;
919
+ }
920
+
921
+ .setting-input {
922
+ width: 110px;
923
+ }
924
+
925
+ .setting-select {
926
+ max-width: 140px;
927
+ }
928
+
929
+ .setting-btn {
930
+ padding: 0 var(--space-3);
931
+ height: 36px;
932
+ }
933
+
934
+ /* Voice mode cards stack vertically on small screens */
935
+ .voice-mode-cards {
936
+ grid-template-columns: 1fr;
937
+ }
938
+
939
+ .voice-mode-card {
940
+ flex-direction: row;
941
+ text-align: left;
942
+ }
943
+ }
944
+
945
+ /* ==========================================================================
946
+ REDUCED MOTION
947
+ ========================================================================== */
948
+
949
+ @media (prefers-reduced-motion: reduce) {
950
+ .settings-section-body {
951
+ transition: opacity 0.15s;
952
+ }
953
+
954
+ .settings-section-chevron {
955
+ transition: color 0.15s;
956
+ }
957
+
958
+ .toggle,
959
+ .toggle::after,
960
+ .toggle-slider,
961
+ .toggle-slider::before {
962
+ transition: none;
963
+ }
964
+
965
+ .voice-mode-card {
966
+ transition: none;
967
+ }
968
+ }
969
+
970
+ /* ==========================================================================
971
+ VOICE SETTINGS V2 — Quick Setup Card + Accordions
972
+ ========================================================================== */
973
+
974
+ /* ── Setup Card ── */
975
+
976
+ .v2-setup-card {
977
+ margin: var(--space-3) var(--space-2) var(--space-2);
978
+ border: 1px solid var(--accent-30, rgba(232, 132, 26, 0.3));
979
+ border-radius: var(--radius-md);
980
+ background: var(--accent-05, rgba(232, 132, 26, 0.05));
981
+ overflow: hidden;
982
+ }
983
+
984
+ .v2-setup-header {
985
+ display: flex;
986
+ align-items: center;
987
+ justify-content: space-between;
988
+ padding: var(--space-2) var(--space-3);
989
+ border-bottom: 1px solid var(--accent-15, rgba(232, 132, 26, 0.15));
990
+ }
991
+
992
+ .v2-setup-title {
993
+ font-family: var(--font-mono);
994
+ font-size: var(--text-xs);
995
+ text-transform: uppercase;
996
+ letter-spacing: 0.5px;
997
+ color: var(--accent);
998
+ font-weight: 600;
999
+ }
1000
+
1001
+ .v2-setup-banner {
1002
+ display: inline-flex;
1003
+ align-items: center;
1004
+ gap: 5px;
1005
+ font-size: var(--text-xs);
1006
+ font-weight: 600;
1007
+ color: #22c55e;
1008
+ background: rgba(34, 197, 94, 0.1);
1009
+ border: 1px solid rgba(34, 197, 94, 0.25);
1010
+ border-radius: var(--radius-sm);
1011
+ padding: 2px 8px;
1012
+ }
1013
+
1014
+ .v2-setup-rows {
1015
+ display: flex;
1016
+ flex-direction: column;
1017
+ }
1018
+
1019
+ .v2-setup-row {
1020
+ display: flex;
1021
+ align-items: center;
1022
+ gap: var(--space-3);
1023
+ padding: var(--space-3) var(--space-3);
1024
+ cursor: pointer;
1025
+ transition: background 0.12s;
1026
+ border-bottom: 1px solid var(--border);
1027
+ }
1028
+
1029
+ .v2-setup-row:last-child {
1030
+ border-bottom: none;
1031
+ }
1032
+
1033
+ .v2-setup-row:hover {
1034
+ background: var(--accent-08, rgba(232, 132, 26, 0.08));
1035
+ }
1036
+
1037
+ .v2-setup-row:focus-visible {
1038
+ outline: 2px solid var(--accent);
1039
+ outline-offset: -2px;
1040
+ }
1041
+
1042
+ .v2-setup-row[data-muted="true"] {
1043
+ opacity: 0.45;
1044
+ cursor: default;
1045
+ pointer-events: none;
1046
+ }
1047
+
1048
+ .v2-setup-row[data-muted="true"]:hover {
1049
+ background: transparent;
1050
+ }
1051
+
1052
+ /* Status dot */
1053
+ .v2-setup-dot {
1054
+ flex-shrink: 0;
1055
+ width: 8px;
1056
+ height: 8px;
1057
+ border-radius: 50%;
1058
+ transition: background 0.2s, box-shadow 0.2s;
1059
+ background: var(--text-dim);
1060
+ }
1061
+
1062
+ .v2-setup-dot[data-state="done"] {
1063
+ background: #22c55e;
1064
+ box-shadow: 0 0 6px rgba(34, 197, 94, 0.5);
1065
+ }
1066
+
1067
+ .v2-setup-dot[data-state="todo"] {
1068
+ background: var(--accent);
1069
+ box-shadow: 0 0 6px var(--accent-30, rgba(232, 132, 26, 0.4));
1070
+ }
1071
+
1072
+ .v2-setup-dot[data-state="empty"] {
1073
+ background: transparent;
1074
+ border: 1.5px solid var(--text-dim);
1075
+ box-shadow: none;
1076
+ }
1077
+
1078
+ .v2-setup-dot[data-state="off"] {
1079
+ background: transparent;
1080
+ border: 1.5px dashed var(--text-dim);
1081
+ box-shadow: none;
1082
+ opacity: 0.5;
1083
+ }
1084
+
1085
+ .v2-setup-row-content {
1086
+ flex: 1;
1087
+ display: flex;
1088
+ flex-direction: column;
1089
+ gap: 2px;
1090
+ min-width: 0;
1091
+ }
1092
+
1093
+ .v2-setup-row-label {
1094
+ font-size: var(--text-sm);
1095
+ font-weight: 500;
1096
+ color: var(--text);
1097
+ line-height: 1.3;
1098
+ }
1099
+
1100
+ .v2-setup-row-sub {
1101
+ font-size: var(--text-xs);
1102
+ color: var(--text-muted);
1103
+ line-height: 1.3;
1104
+ white-space: nowrap;
1105
+ overflow: hidden;
1106
+ text-overflow: ellipsis;
1107
+ }
1108
+
1109
+ .v2-setup-row-arrow {
1110
+ flex-shrink: 0;
1111
+ color: var(--text-dim);
1112
+ opacity: 0.6;
1113
+ transition: opacity 0.12s, transform 0.12s;
1114
+ }
1115
+
1116
+ .v2-setup-row:hover .v2-setup-row-arrow {
1117
+ opacity: 1;
1118
+ transform: translateX(2px);
1119
+ }
1120
+
1121
+ /* ── Accordions ── */
1122
+
1123
+ .v2-accordion {
1124
+ border-bottom: 1px solid var(--border);
1125
+ }
1126
+
1127
+ .v2-accordion:last-of-type {
1128
+ border-bottom: none;
1129
+ }
1130
+
1131
+ .v2-accordion-header {
1132
+ width: 100%;
1133
+ display: flex;
1134
+ align-items: center;
1135
+ gap: var(--space-3);
1136
+ padding: var(--space-3) var(--space-3);
1137
+ background: transparent;
1138
+ border: none;
1139
+ cursor: pointer;
1140
+ color: var(--text);
1141
+ text-align: left;
1142
+ min-height: 48px;
1143
+ transition: background 0.12s;
1144
+ border-radius: 0;
1145
+ }
1146
+
1147
+ .v2-accordion-header:hover {
1148
+ background: var(--white-05, rgba(255,255,255,0.03));
1149
+ }
1150
+
1151
+ .v2-accordion-header:focus-visible {
1152
+ outline: 2px solid var(--accent);
1153
+ outline-offset: -2px;
1154
+ }
1155
+
1156
+ .v2-accordion-icon {
1157
+ flex-shrink: 0;
1158
+ width: 28px;
1159
+ height: 28px;
1160
+ border-radius: var(--radius-sm);
1161
+ background: var(--accent-10, rgba(232, 132, 26, 0.1));
1162
+ display: flex;
1163
+ align-items: center;
1164
+ justify-content: center;
1165
+ color: var(--accent);
1166
+ transition: background 0.12s;
1167
+ }
1168
+
1169
+ .v2-accordion-header:hover .v2-accordion-icon {
1170
+ background: var(--accent-15, rgba(232, 132, 26, 0.15));
1171
+ }
1172
+
1173
+ .v2-accordion--open .v2-accordion-icon {
1174
+ background: var(--accent-15, rgba(232, 132, 26, 0.15));
1175
+ }
1176
+
1177
+ .v2-accordion-header-content {
1178
+ flex: 1;
1179
+ display: flex;
1180
+ flex-direction: column;
1181
+ gap: 2px;
1182
+ min-width: 0;
1183
+ }
1184
+
1185
+ .v2-accordion-title {
1186
+ font-size: var(--text-sm);
1187
+ font-weight: 500;
1188
+ color: var(--text);
1189
+ line-height: 1.3;
1190
+ transition: color 0.12s;
1191
+ }
1192
+
1193
+ .v2-accordion--open .v2-accordion-title {
1194
+ color: var(--accent);
1195
+ }
1196
+
1197
+ .v2-accordion-summary {
1198
+ font-size: var(--text-xs);
1199
+ color: var(--text-muted);
1200
+ line-height: 1.3;
1201
+ }
1202
+
1203
+ .v2-accordion-chevron {
1204
+ flex-shrink: 0;
1205
+ color: var(--text-dim);
1206
+ transition: transform 0.2s ease, color 0.12s;
1207
+ }
1208
+
1209
+ .v2-accordion--open .v2-accordion-chevron {
1210
+ transform: rotate(90deg);
1211
+ color: var(--accent);
1212
+ }
1213
+
1214
+ /* Accordion body — grid-rows animation */
1215
+ .v2-accordion-body {
1216
+ display: grid;
1217
+ grid-template-rows: 0fr;
1218
+ transition: grid-template-rows 0.25s cubic-bezier(0.4, 0, 0.2, 1);
1219
+ overflow: hidden;
1220
+ }
1221
+
1222
+ .v2-accordion--open .v2-accordion-body {
1223
+ grid-template-rows: 1fr;
1224
+ }
1225
+
1226
+ .v2-accordion-body > * {
1227
+ min-height: 0;
1228
+ overflow: hidden;
1229
+ }
1230
+
1231
+ /* Inner wrapper so children overflow correctly */
1232
+ .v2-accordion-body-inner {
1233
+ overflow: hidden;
1234
+ }
1235
+
1236
+ /* ── TTS disabled state ── */
1237
+ .v2-accordion--tts-disabled .v2-accordion-header {
1238
+ opacity: 0.5;
1239
+ }
1240
+
1241
+ .v2-accordion--tts-disabled .v2-accordion-header::after {
1242
+ content: 'Off';
1243
+ font-family: var(--font-mono);
1244
+ font-size: 10px;
1245
+ font-weight: 600;
1246
+ text-transform: uppercase;
1247
+ letter-spacing: 0.5px;
1248
+ color: var(--text-dim);
1249
+ background: var(--bg-elevated, #141C2B);
1250
+ border: 1px solid var(--border);
1251
+ border-radius: var(--radius-sm);
1252
+ padding: 1px 6px;
1253
+ margin-left: auto;
1254
+ flex-shrink: 0;
1255
+ }
1256
+
1257
+ .v2-accordion--tts-disabled .v2-accordion-body {
1258
+ opacity: 0.5;
1259
+ pointer-events: none;
1260
+ }
1261
+
1262
+ /* ── Reduced motion ── */
1263
+ @media (prefers-reduced-motion: reduce) {
1264
+ .v2-accordion-body {
1265
+ transition: none;
1266
+ }
1267
+ .v2-accordion-chevron {
1268
+ transition: color 0.12s;
1269
+ }
1270
+ }
1271
+
1272
+ /* ==========================================================================
1273
+ VOICE SETTINGS V2 — Mobile fixes
1274
+ ========================================================================== */
1275
+
1276
+ /* Prevent setup card rows from wrapping on narrow screens */
1277
+ .v2-setup-row {
1278
+ flex-wrap: nowrap;
1279
+ }
1280
+
1281
+ .v2-setup-row-arrow {
1282
+ flex-shrink: 0;
1283
+ }
1284
+
1285
+ /* Accordions fill full width, no inherited padding cutting them */
1286
+ .v2-accordion {
1287
+ width: 100%;
1288
+ box-sizing: border-box;
1289
+ margin-left: 0;
1290
+ margin-right: 0;
1291
+ }
1292
+
1293
+ .v2-accordion-header {
1294
+ width: 100%;
1295
+ box-sizing: border-box;
1296
+ }
1297
+
1298
+ /* Tighter accordion header padding on mobile */
1299
+ @media (max-width: 480px) {
1300
+ .v2-accordion-header {
1301
+ padding: var(--space-3) var(--space-2);
1302
+ }
1303
+
1304
+ .v2-setup-card {
1305
+ margin: var(--space-3) var(--space-1) var(--space-2);
1306
+ }
1307
+
1308
+ .v2-setup-row {
1309
+ padding: var(--space-3) var(--space-2);
1310
+ }
1311
+
1312
+ .v2-setup-row-sub {
1313
+ max-width: 180px;
1314
+ }
1315
+ }
1316
+
1317
+ /* iOS button reset for accordion headers */
1318
+ .v2-accordion-header {
1319
+ -webkit-appearance: none;
1320
+ -moz-appearance: none;
1321
+ appearance: none;
1322
+ }