openvoiceui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/.env.example +104 -0
  2. package/Dockerfile +30 -0
  3. package/LICENSE +21 -0
  4. package/README.md +638 -0
  5. package/SETUP.md +360 -0
  6. package/app.py +232 -0
  7. package/auto-approve-devices.js +111 -0
  8. package/cli/index.js +372 -0
  9. package/config/__init__.py +4 -0
  10. package/config/default.yaml +43 -0
  11. package/config/flags.yaml +67 -0
  12. package/config/loader.py +203 -0
  13. package/config/providers.yaml +71 -0
  14. package/config/speech_normalization.yaml +182 -0
  15. package/config/theme.json +4 -0
  16. package/data/greetings.json +25 -0
  17. package/default-pages/ai-image-creator.html +915 -0
  18. package/default-pages/bulk-image-uploader.html +492 -0
  19. package/default-pages/desktop.html +2865 -0
  20. package/default-pages/file-explorer.html +854 -0
  21. package/default-pages/interactive-map.html +655 -0
  22. package/default-pages/style-guide.html +1005 -0
  23. package/default-pages/website-setup.html +1623 -0
  24. package/deploy/openclaw/Dockerfile +46 -0
  25. package/deploy/openvoiceui.service +30 -0
  26. package/deploy/setup-nginx.sh +50 -0
  27. package/deploy/setup-sudo.sh +306 -0
  28. package/deploy/skill-runner/Dockerfile +19 -0
  29. package/deploy/skill-runner/requirements.txt +14 -0
  30. package/deploy/skill-runner/server.py +269 -0
  31. package/deploy/supertonic/Dockerfile +22 -0
  32. package/deploy/supertonic/server.py +79 -0
  33. package/docker-compose.pinokio.yml +11 -0
  34. package/docker-compose.yml +59 -0
  35. package/greetings.json +25 -0
  36. package/index.html +65 -0
  37. package/inject-device-identity.js +142 -0
  38. package/package.json +82 -0
  39. package/profiles/default.json +114 -0
  40. package/profiles/manager.py +354 -0
  41. package/profiles/schema.json +337 -0
  42. package/prompts/voice-system-prompt.md +149 -0
  43. package/providers/__init__.py +39 -0
  44. package/providers/base.py +63 -0
  45. package/providers/llm/__init__.py +12 -0
  46. package/providers/llm/base.py +71 -0
  47. package/providers/llm/clawdbot_provider.py +112 -0
  48. package/providers/llm/zai_provider.py +115 -0
  49. package/providers/registry.py +320 -0
  50. package/providers/stt/__init__.py +12 -0
  51. package/providers/stt/base.py +58 -0
  52. package/providers/stt/webspeech_provider.py +49 -0
  53. package/providers/stt/whisper_provider.py +100 -0
  54. package/providers/tts/__init__.py +20 -0
  55. package/providers/tts/base.py +91 -0
  56. package/providers/tts/groq_provider.py +74 -0
  57. package/providers/tts/supertonic_provider.py +72 -0
  58. package/requirements.txt +38 -0
  59. package/routes/__init__.py +10 -0
  60. package/routes/admin.py +515 -0
  61. package/routes/canvas.py +1315 -0
  62. package/routes/chat.py +51 -0
  63. package/routes/conversation.py +2158 -0
  64. package/routes/elevenlabs_hybrid.py +306 -0
  65. package/routes/greetings.py +98 -0
  66. package/routes/icons.py +279 -0
  67. package/routes/image_gen.py +364 -0
  68. package/routes/instructions.py +190 -0
  69. package/routes/music.py +838 -0
  70. package/routes/onboarding.py +43 -0
  71. package/routes/pi.py +62 -0
  72. package/routes/profiles.py +215 -0
  73. package/routes/report_issue.py +68 -0
  74. package/routes/static_files.py +533 -0
  75. package/routes/suno.py +664 -0
  76. package/routes/theme.py +81 -0
  77. package/routes/transcripts.py +199 -0
  78. package/routes/vision.py +348 -0
  79. package/routes/workspace.py +288 -0
  80. package/server.py +1510 -0
  81. package/services/__init__.py +1 -0
  82. package/services/auth.py +143 -0
  83. package/services/canvas_versioning.py +239 -0
  84. package/services/db_pool.py +107 -0
  85. package/services/gateway.py +16 -0
  86. package/services/gateway_manager.py +333 -0
  87. package/services/gateways/__init__.py +12 -0
  88. package/services/gateways/base.py +110 -0
  89. package/services/gateways/compat.py +264 -0
  90. package/services/gateways/openclaw.py +1134 -0
  91. package/services/health.py +100 -0
  92. package/services/memory_client.py +455 -0
  93. package/services/paths.py +26 -0
  94. package/services/speech_normalizer.py +285 -0
  95. package/services/tts.py +270 -0
  96. package/setup-config.js +262 -0
  97. package/sounds/air_horn.mp3 +0 -0
  98. package/sounds/bruh.mp3 +0 -0
  99. package/sounds/crowd_cheer.mp3 +0 -0
  100. package/sounds/gunshot.mp3 +0 -0
  101. package/sounds/impact.mp3 +0 -0
  102. package/sounds/lets_go.mp3 +0 -0
  103. package/sounds/record_stop.mp3 +0 -0
  104. package/sounds/rewind.mp3 +0 -0
  105. package/sounds/sad_trombone.mp3 +0 -0
  106. package/sounds/scratch_long.mp3 +0 -0
  107. package/sounds/yeah.mp3 +0 -0
  108. package/src/adapters/ClawdBotAdapter.js +264 -0
  109. package/src/adapters/_template.js +133 -0
  110. package/src/adapters/elevenlabs-classic.js +841 -0
  111. package/src/adapters/elevenlabs-hybrid.js +812 -0
  112. package/src/adapters/hume-evi.js +676 -0
  113. package/src/admin.html +1339 -0
  114. package/src/app.js +8802 -0
  115. package/src/core/Config.js +173 -0
  116. package/src/core/EmotionEngine.js +307 -0
  117. package/src/core/EventBridge.js +180 -0
  118. package/src/core/EventBus.js +117 -0
  119. package/src/core/VoiceSession.js +607 -0
  120. package/src/face/BaseFace.js +259 -0
  121. package/src/face/EyeFace.js +208 -0
  122. package/src/face/HaloSmokeFace.js +509 -0
  123. package/src/face/manifest.json +27 -0
  124. package/src/face/previews/eyes.svg +16 -0
  125. package/src/face/previews/orb.svg +29 -0
  126. package/src/features/MusicPlayer.js +620 -0
  127. package/src/features/Soundboard.js +128 -0
  128. package/src/providers/DeepgramSTT.js +472 -0
  129. package/src/providers/DeepgramStreamingSTT.js +766 -0
  130. package/src/providers/GroqSTT.js +559 -0
  131. package/src/providers/TTSPlayer.js +323 -0
  132. package/src/providers/WebSpeechSTT.js +479 -0
  133. package/src/providers/tts/BaseTTSProvider.js +81 -0
  134. package/src/providers/tts/HumeProvider.js +77 -0
  135. package/src/providers/tts/SupertonicProvider.js +174 -0
  136. package/src/providers/tts/index.js +140 -0
  137. package/src/shell/adapter-registry.js +154 -0
  138. package/src/shell/caller-bridge.js +35 -0
  139. package/src/shell/camera-bridge.js +28 -0
  140. package/src/shell/canvas-bridge.js +32 -0
  141. package/src/shell/commercial-bridge.js +44 -0
  142. package/src/shell/face-bridge.js +44 -0
  143. package/src/shell/music-bridge.js +60 -0
  144. package/src/shell/orchestrator.js +233 -0
  145. package/src/shell/profile-discovery.js +303 -0
  146. package/src/shell/sounds-bridge.js +28 -0
  147. package/src/shell/transcript-bridge.js +61 -0
  148. package/src/shell/waveform-bridge.js +33 -0
  149. package/src/styles/base.css +2862 -0
  150. package/src/styles/face.css +417 -0
  151. package/src/styles/pi-overrides.css +89 -0
  152. package/src/styles/theme-dark.css +67 -0
  153. package/src/test-tts.html +175 -0
  154. package/src/ui/AppShell.js +544 -0
  155. package/src/ui/ProfileSwitcher.js +228 -0
  156. package/src/ui/SessionControl.js +240 -0
  157. package/src/ui/face/FacePicker.js +195 -0
  158. package/src/ui/face/FaceRenderer.js +309 -0
  159. package/src/ui/settings/PlaylistEditor.js +366 -0
  160. package/src/ui/settings/SettingsPanel.css +684 -0
  161. package/src/ui/settings/SettingsPanel.js +419 -0
  162. package/src/ui/settings/TTSVoicePreview.js +210 -0
  163. package/src/ui/themes/ThemeManager.js +213 -0
  164. package/src/ui/visualizers/BaseVisualizer.js +29 -0
  165. package/src/ui/visualizers/PartyFXVisualizer.css +291 -0
  166. package/src/ui/visualizers/PartyFXVisualizer.js +637 -0
  167. package/static/emulators/jsdos/js-dos.css +1 -0
  168. package/static/emulators/jsdos/js-dos.js +22 -0
  169. package/static/favicon.svg +55 -0
  170. package/static/icons/apple-touch-icon.png +0 -0
  171. package/static/icons/favicon-32.png +0 -0
  172. package/static/icons/icon-192.png +0 -0
  173. package/static/icons/icon-512.png +0 -0
  174. package/static/install.html +449 -0
  175. package/static/manifest.json +26 -0
  176. package/static/sw.js +21 -0
  177. package/tts_providers/__init__.py +136 -0
  178. package/tts_providers/base_provider.py +319 -0
  179. package/tts_providers/groq_provider.py +155 -0
  180. package/tts_providers/hume_provider.py +226 -0
  181. package/tts_providers/providers_config.json +119 -0
  182. package/tts_providers/qwen3_provider.py +371 -0
  183. package/tts_providers/resemble_provider.py +315 -0
  184. package/tts_providers/supertonic_provider.py +557 -0
  185. package/tts_providers/supertonic_tts.py +399 -0
@@ -0,0 +1,2862 @@
1
+ /* =============================================================
2
+ Base Application Styles
3
+ Controls, panels, music, party effects, settings, auth, canvas
4
+ ============================================================= */
5
+
6
+ /* Canvas padded mode — OS-style inset for external URLs */
7
+ #canvas-container.canvas-padded {
8
+ background: #111 !important;
9
+ }
10
+ #canvas-container.canvas-padded #canvas-iframe {
11
+ position: absolute !important;
12
+ top: 40px !important; left: 40px !important; right: 40px !important; bottom: 40px !important;
13
+ width: auto !important; height: auto !important;
14
+ border-radius: 12px !important;
15
+ box-shadow: 0 0 40px rgba(0,0,0,0.6) !important;
16
+ }
17
+
18
+ /* Control buttons — Edge Tabs (Concept A) */
19
+ .controls-left, .controls-right {
20
+ position: fixed;
21
+ top: 50%;
22
+ transform: translateY(-50%);
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 4px;
26
+ z-index: 100;
27
+ }
28
+ .controls-left { left: 0; }
29
+ .controls-right { right: 0; }
30
+
31
+ .edge-tab {
32
+ width: 44px;
33
+ height: 52px;
34
+ background: rgba(0, 136, 255, 0.08);
35
+ border: 1px solid rgba(0, 136, 255, 0.25);
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ font-size: 20px;
40
+ color: var(--blue);
41
+ backdrop-filter: blur(8px);
42
+ cursor: pointer;
43
+ transition: all 0.3s;
44
+ }
45
+ .edge-tab.left {
46
+ border-left: none;
47
+ border-radius: 0 14px 14px 0;
48
+ }
49
+ .edge-tab.right {
50
+ border-right: none;
51
+ border-radius: 14px 0 0 14px;
52
+ }
53
+ .edge-tab:hover {
54
+ background: rgba(0, 136, 255, 0.18);
55
+ border-color: var(--blue-bright);
56
+ box-shadow: 0 0 15px rgba(0, 136, 255, 0.2);
57
+ width: 52px;
58
+ }
59
+
60
+ /* Active states per button type */
61
+ .edge-tab.call-button.active { background: rgba(0, 255, 102, 0.18); border-color: rgba(0, 255, 102, 0.6); color: var(--green); box-shadow: 0 0 25px rgba(0, 255, 102, 0.5), 0 0 50px rgba(0, 255, 102, 0.2); }
62
+ .edge-tab.call-button.connecting { background: rgba(255, 221, 0, 0.12); border-color: rgba(255, 221, 0, 0.4); color: var(--yellow); box-shadow: 0 0 20px rgba(255, 221, 0, 0.3); }
63
+ .edge-tab.wake-button.active { background: rgba(0, 255, 102, 0.12); border-color: rgba(0, 255, 102, 0.4); color: var(--green); box-shadow: 0 0 20px rgba(0, 255, 102, 0.3); }
64
+ .edge-tab.wake-button.listening { background: rgba(255, 221, 0, 0.12); border-color: rgba(255, 221, 0, 0.4); color: var(--yellow); box-shadow: 0 0 20px rgba(255, 221, 0, 0.3); animation: yellow-pulse-glow 1.5s ease-in-out infinite; }
65
+ .edge-tab.camera-button.active { background: rgba(0, 136, 255, 0.18); border-color: var(--blue-bright); }
66
+ .edge-tab.music-button.active { background: rgba(0, 136, 255, 0.18); border-color: var(--blue-bright); box-shadow: 0 0 20px rgba(0, 136, 255, 0.3); }
67
+ .edge-tab.canvas-button.active { background: rgba(0, 255, 255, 0.12); border-color: var(--cyan); box-shadow: 0 0 15px rgba(0, 255, 255, 0.3); }
68
+ .edge-tab.face-button.active { background: rgba(0, 255, 102, 0.12); border-color: rgba(0, 255, 102, 0.4); color: var(--green); box-shadow: 0 0 15px rgba(0, 255, 102, 0.3); }
69
+ .edge-tab.mode-button.active { background: rgba(160, 80, 255, 0.18); border-color: rgba(160, 80, 255, 0.6); color: #c084fc; box-shadow: 0 0 20px rgba(160, 80, 255, 0.4); }
70
+ .edge-tab.ptt-button { touch-action: none; user-select: none; }
71
+ .edge-tab.ptt-button.ptt-mode { background: rgba(255, 160, 0, 0.12); border-color: rgba(255, 160, 0, 0.4); color: #ffa500; }
72
+ .edge-tab.ptt-button.holding { background: rgba(239, 68, 68, 0.25); border-color: rgba(239, 68, 68, 0.7); color: #f87171; box-shadow: 0 0 25px rgba(239, 68, 68, 0.5), 0 0 50px rgba(239, 68, 68, 0.2); animation: ptt-pulse 0.8s ease-in-out infinite; }
73
+ @keyframes ptt-pulse { 0%,100% { box-shadow: 0 0 25px rgba(239,68,68,0.5); } 50% { box-shadow: 0 0 40px rgba(239,68,68,0.8), 0 0 60px rgba(239,68,68,0.3); } }
74
+
75
+ /* Face Recognition Panel */
76
+ .face-panel {
77
+ position: fixed;
78
+ right: -320px;
79
+ top: 50%;
80
+ transform: translateY(-50%);
81
+ width: 300px;
82
+ max-height: 80vh;
83
+ background: rgba(10, 10, 20, 0.95);
84
+ backdrop-filter: blur(12px);
85
+ border: 1px solid var(--blue);
86
+ border-right: none;
87
+ border-radius: 12px 0 0 12px;
88
+ padding: 15px;
89
+ z-index: 150;
90
+ transition: right 0.3s ease;
91
+ overflow-y: auto;
92
+ }
93
+ .face-panel.open { right: 0; }
94
+ .fp-header {
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
+ margin-bottom: 12px;
99
+ color: var(--blue-bright);
100
+ font-size: 14px;
101
+ font-weight: 600;
102
+ }
103
+ .fp-close {
104
+ background: none; border: none; color: #6e7681; font-size: 20px; cursor: pointer;
105
+ }
106
+ .fp-close:hover { color: #fff; }
107
+ .fp-face-list {
108
+ list-style: none; padding: 0; margin: 0 0 12px 0;
109
+ }
110
+ .fp-face-list li {
111
+ padding: 6px 10px;
112
+ font-size: 13px;
113
+ display: flex;
114
+ justify-content: space-between;
115
+ align-items: center;
116
+ color: var(--blue);
117
+ border-bottom: 1px solid rgba(255,255,255,0.04);
118
+ }
119
+ .fp-face-list .confidence { font-size: 11px; }
120
+ .fp-face-list .confidence.high { color: var(--green); }
121
+ .fp-face-list .confidence.medium { color: var(--yellow); }
122
+ .fp-face-list .confidence.low { color: #ff6b35; }
123
+ .fp-actions { margin-bottom: 10px; }
124
+ .fp-btn {
125
+ padding: 8px 14px;
126
+ background: transparent;
127
+ border: 1px solid var(--blue);
128
+ border-radius: 6px;
129
+ color: var(--blue);
130
+ cursor: pointer;
131
+ font-size: 12px;
132
+ transition: all 0.2s;
133
+ }
134
+ .fp-btn:hover {
135
+ background: rgba(0, 136, 255, 0.15);
136
+ border-color: var(--blue-bright);
137
+ }
138
+ .fp-btn.fp-upload { border-color: var(--green); color: var(--green); }
139
+ .fp-btn.fp-upload:hover { background: rgba(0, 255, 102, 0.12); }
140
+ .fp-status {
141
+ font-size: 12px;
142
+ color: var(--cyan);
143
+ margin-top: 6px;
144
+ min-height: 18px;
145
+ }
146
+ .fp-register {
147
+ border-top: 1px solid rgba(0, 136, 255, 0.15);
148
+ padding-top: 10px;
149
+ margin-top: 8px;
150
+ }
151
+ .fp-register input[type="text"] {
152
+ width: 100%;
153
+ padding: 8px;
154
+ background: rgba(0, 0, 0, 0.4);
155
+ border: 1px solid var(--blue);
156
+ border-radius: 6px;
157
+ color: #e6edf3;
158
+ font-size: 13px;
159
+ margin-bottom: 8px;
160
+ }
161
+ .fp-register-btns { display: flex; gap: 8px; margin-bottom: 8px; }
162
+ .fp-photos {
163
+ display: flex; flex-wrap: wrap; gap: 5px;
164
+ }
165
+ .fp-photos .photo-item {
166
+ position: relative; width: 50px; height: 50px;
167
+ }
168
+ .fp-photos .photo-item img {
169
+ width: 100%; height: 100%; object-fit: cover;
170
+ border-radius: 5px; border: 1px solid var(--blue);
171
+ }
172
+ .fp-photos .photo-item .delete-photo {
173
+ position: absolute; top: -5px; right: -5px;
174
+ width: 18px; height: 18px;
175
+ background: #ef4444; border: none; border-radius: 50%;
176
+ color: white; font-size: 10px; cursor: pointer;
177
+ display: none; align-items: center; justify-content: center;
178
+ }
179
+ .fp-photos .photo-item:hover .delete-photo { display: flex; }
180
+
181
+ /* Mode Picker Popup */
182
+ .mode-picker {
183
+ position: fixed;
184
+ left: 52px;
185
+ top: 50%;
186
+ transform: translateY(-50%);
187
+ width: 230px;
188
+ background: rgba(10, 8, 20, 0.97);
189
+ backdrop-filter: blur(14px);
190
+ border: 1px solid rgba(160, 80, 255, 0.35);
191
+ border-radius: 12px;
192
+ padding: 8px 6px;
193
+ z-index: 200;
194
+ display: none;
195
+ flex-direction: column;
196
+ gap: 2px;
197
+ box-shadow: 0 8px 32px rgba(0,0,0,0.6), 0 0 0 1px rgba(160,80,255,0.1);
198
+ }
199
+ .mode-picker.open { display: flex; }
200
+ .mode-picker-label {
201
+ font-size: 10px;
202
+ font-weight: 700;
203
+ letter-spacing: 0.1em;
204
+ color: rgba(160, 80, 255, 0.6);
205
+ padding: 4px 10px 6px;
206
+ text-transform: uppercase;
207
+ }
208
+ .mode-option {
209
+ display: flex;
210
+ align-items: center;
211
+ gap: 10px;
212
+ width: 100%;
213
+ padding: 9px 10px;
214
+ background: transparent;
215
+ border: none;
216
+ border-radius: 8px;
217
+ cursor: pointer;
218
+ transition: background 0.15s;
219
+ text-align: left;
220
+ }
221
+ .mode-option:hover { background: rgba(160, 80, 255, 0.1); }
222
+ .mode-option.active { background: rgba(160, 80, 255, 0.12); }
223
+ .mode-opt-icon { font-size: 18px; flex-shrink: 0; width: 24px; text-align: center; }
224
+ .mode-opt-info { display: flex; flex-direction: column; flex: 1; gap: 1px; }
225
+ .mode-opt-name { font-size: 13px; font-weight: 600; color: #e2e8f0; }
226
+ .mode-opt-desc { font-size: 11px; color: #6e7681; }
227
+ .mode-opt-check { font-size: 12px; color: #c084fc; width: 14px; text-align: center; flex-shrink: 0; }
228
+
229
+ /* Agent-to-Agent Panel — slides out from left edge */
230
+ .a2a-panel {
231
+ position: fixed;
232
+ left: -340px;
233
+ top: 50%;
234
+ transform: translateY(-50%);
235
+ width: 320px;
236
+ max-height: 85vh;
237
+ background: rgba(10, 8, 20, 0.96);
238
+ backdrop-filter: blur(12px);
239
+ border: 1px solid rgba(160, 80, 255, 0.4);
240
+ border-left: none;
241
+ border-radius: 0 12px 12px 0;
242
+ padding: 16px;
243
+ z-index: 150;
244
+ transition: left 0.3s ease;
245
+ overflow-y: auto;
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 12px;
249
+ }
250
+ .a2a-panel.open { left: 0; }
251
+ .a2a-header {
252
+ display: flex;
253
+ justify-content: space-between;
254
+ align-items: center;
255
+ color: #c084fc;
256
+ font-size: 14px;
257
+ font-weight: 600;
258
+ }
259
+ .a2a-close {
260
+ background: none; border: none; color: #6e7681; font-size: 20px; cursor: pointer;
261
+ }
262
+ .a2a-close:hover { color: #fff; }
263
+ .a2a-config { display: flex; flex-direction: column; gap: 6px; }
264
+ .a2a-label { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.05em; }
265
+ .a2a-config select {
266
+ background: rgba(160, 80, 255, 0.08);
267
+ border: 1px solid rgba(160, 80, 255, 0.3);
268
+ color: #c084fc;
269
+ padding: 7px 10px;
270
+ border-radius: 8px;
271
+ font-size: 13px;
272
+ width: 100%;
273
+ }
274
+ .a2a-status-row {
275
+ display: flex;
276
+ justify-content: space-between;
277
+ align-items: center;
278
+ padding: 8px 10px;
279
+ background: rgba(160, 80, 255, 0.06);
280
+ border: 1px solid rgba(160, 80, 255, 0.15);
281
+ border-radius: 8px;
282
+ }
283
+ .a2a-turn-indicator { display: flex; align-items: center; gap: 7px; font-size: 13px; color: #8b949e; }
284
+ .a2a-dot {
285
+ width: 8px; height: 8px; border-radius: 50%;
286
+ background: #3d3d3d;
287
+ transition: background 0.3s, box-shadow 0.3s;
288
+ }
289
+ .a2a-dot.active { background: #c084fc; box-shadow: 0 0 8px rgba(160, 80, 255, 0.8); }
290
+ .a2a-dot.speaking { background: #4ade80; box-shadow: 0 0 8px rgba(74, 222, 128, 0.8); animation: a2a-speaking-pulse 0.6s ease-in-out infinite; }
291
+ .a2a-dot.waiting { background: #facc15; box-shadow: 0 0 8px rgba(250, 204, 21, 0.6); }
292
+ @keyframes a2a-speaking-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.4); } }
293
+ .a2a-room-id { font-size: 10px; color: #4d5260; font-family: monospace; }
294
+ .a2a-controls { display: flex; gap: 8px; }
295
+ .a2a-btn {
296
+ flex: 1;
297
+ padding: 9px 12px;
298
+ border-radius: 8px;
299
+ border: 1px solid rgba(160, 80, 255, 0.4);
300
+ background: rgba(160, 80, 255, 0.1);
301
+ color: #c084fc;
302
+ font-size: 13px;
303
+ cursor: pointer;
304
+ transition: all 0.2s;
305
+ }
306
+ .a2a-btn:hover { background: rgba(160, 80, 255, 0.2); border-color: #c084fc; }
307
+ .a2a-btn.a2a-stop { border-color: rgba(239, 68, 68, 0.4); background: rgba(239, 68, 68, 0.1); color: #f87171; }
308
+ .a2a-btn.a2a-stop:hover { background: rgba(239, 68, 68, 0.2); }
309
+ .a2a-transcript {
310
+ flex: 1;
311
+ min-height: 120px;
312
+ max-height: 300px;
313
+ overflow-y: auto;
314
+ padding: 8px;
315
+ background: rgba(0, 0, 0, 0.3);
316
+ border: 1px solid rgba(160, 80, 255, 0.1);
317
+ border-radius: 8px;
318
+ font-size: 12px;
319
+ line-height: 1.5;
320
+ }
321
+ .a2a-transcript-empty { color: #3d3d3d; font-style: italic; text-align: center; padding: 20px 0; }
322
+ .a2a-msg { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid rgba(255,255,255,0.04); }
323
+ .a2a-msg:last-child { border-bottom: none; margin-bottom: 0; }
324
+ .a2a-msg-who { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px; }
325
+ .a2a-msg-who.assistant { color: #60a5fa; }
326
+ .a2a-msg-who.pgai { color: #c084fc; }
327
+ .a2a-msg-who.human { color: #4ade80; }
328
+ .a2a-msg-text { color: #cdd9e5; }
329
+
330
+ /* ===== Listen Mode Panel — slides out from right edge ===== */
331
+ .listen-panel {
332
+ position: fixed;
333
+ right: -360px;
334
+ top: 0;
335
+ bottom: 0;
336
+ width: 340px;
337
+ background: rgba(12, 18, 24, 0.97);
338
+ border-left: 1px solid rgba(20, 184, 166, 0.3);
339
+ z-index: 200;
340
+ display: flex;
341
+ flex-direction: column;
342
+ padding: 16px;
343
+ gap: 12px;
344
+ transition: right 0.3s ease;
345
+ backdrop-filter: blur(12px);
346
+ }
347
+ .listen-panel.open { right: 44px; } /* leave room for right edge controls */
348
+ .listen-header {
349
+ display: flex;
350
+ justify-content: space-between;
351
+ align-items: center;
352
+ font-size: 13px;
353
+ font-weight: 600;
354
+ color: #2dd4bf;
355
+ text-transform: uppercase;
356
+ letter-spacing: 0.08em;
357
+ }
358
+ .listen-close {
359
+ background: none; border: none; color: #4d5260;
360
+ font-size: 18px; cursor: pointer; padding: 0 4px;
361
+ line-height: 1; transition: color 0.2s;
362
+ }
363
+ .listen-close:hover { color: #cdd9e5; }
364
+ .listen-meta {
365
+ display: flex;
366
+ justify-content: space-between;
367
+ align-items: center;
368
+ font-size: 11px;
369
+ color: #4d5260;
370
+ }
371
+ #listen-word-count { font-family: monospace; }
372
+ .listen-clear-btn {
373
+ background: none; border: 1px solid rgba(255,255,255,0.08);
374
+ color: #4d5260; font-size: 11px; cursor: pointer;
375
+ padding: 2px 8px; border-radius: 4px; transition: all 0.2s;
376
+ }
377
+ .listen-clear-btn:hover { border-color: rgba(239,68,68,0.4); color: #f87171; }
378
+ .listen-transcript {
379
+ flex: 1;
380
+ overflow-y: auto;
381
+ font-size: 13px;
382
+ color: #cdd9e5;
383
+ line-height: 1.6;
384
+ scrollbar-width: thin;
385
+ }
386
+ .listen-empty { color: #3d3d3d; font-style: italic; text-align: center; padding: 20px 0; }
387
+ .listen-sentence {
388
+ margin-bottom: 4px;
389
+ padding-bottom: 4px;
390
+ animation: listen-fade-in 0.2s ease;
391
+ }
392
+ @keyframes listen-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
393
+ .listen-interim { display: none; } /* interim now renders inline in the transcript */
394
+ .listen-title-input {
395
+ background: rgba(255,255,255,0.04);
396
+ border: 1px solid rgba(255,255,255,0.1);
397
+ border-radius: 6px;
398
+ color: #cdd9e5;
399
+ font-size: 13px;
400
+ padding: 7px 10px;
401
+ outline: none;
402
+ width: 100%;
403
+ box-sizing: border-box;
404
+ transition: border-color 0.2s;
405
+ }
406
+ .listen-title-input:focus { border-color: rgba(20,184,166,0.5); }
407
+ .listen-title-input::placeholder { color: #3d3d3d; }
408
+ .listen-actions { display: flex; gap: 6px; }
409
+ .listen-action-btn {
410
+ flex: 1;
411
+ padding: 11px 12px;
412
+ background: rgba(255,255,255,0.04);
413
+ border: 1px solid rgba(255,255,255,0.1);
414
+ border-radius: 8px;
415
+ color: #8b949e;
416
+ font-size: 12px;
417
+ font-weight: 500;
418
+ cursor: pointer;
419
+ transition: all 0.2s;
420
+ white-space: nowrap;
421
+ }
422
+ .listen-action-btn:hover:not(:disabled) { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.2); color: #c9d1d9; }
423
+ .listen-action-btn:disabled { opacity: 0.35; cursor: not-allowed; }
424
+ .listen-save-btn:hover:not(:disabled) { background: rgba(20,184,166,0.12); border-color: rgba(20,184,166,0.35); color: #2dd4bf; }
425
+ .listen-send-btn:hover:not(:disabled) { background: rgba(59,130,246,0.12); border-color: rgba(59,130,246,0.35); color: #60a5fa; }
426
+ .listen-talk-btn { background: rgba(20, 184, 166, 0.12); border-color: rgba(20, 184, 166, 0.35); color: #2dd4bf; }
427
+ .listen-talk-btn:hover:not(:disabled) { background: rgba(20, 184, 166, 0.22); border-color: #2dd4bf; }
428
+ .listen-talk-btn.saving { color: #facc15; border-color: rgba(250,204,21,0.4); }
429
+ .listen-send-btn.sending { color: #facc15; border-color: rgba(250,204,21,0.4); }
430
+ .listen-save-status {
431
+ font-size: 11px;
432
+ color: #4d5260;
433
+ text-align: center;
434
+ min-height: 16px;
435
+ }
436
+ .listen-save-status.ok { color: #4ade80; }
437
+ .listen-save-status.err { color: #f87171; }
438
+
439
+ /* ── Theme presets (data-theme-preset on body) ── */
440
+ /* Each preset overrides the default blue accent with a profile colour. */
441
+ body[data-theme-preset="green"] { --theme-accent: 0,255,102; --theme-accent-hex: #00ff66; }
442
+ body[data-theme-preset="purple"] { --theme-accent: 160,80,255; --theme-accent-hex: #a050ff; }
443
+ body[data-theme-preset="red"] { --theme-accent: 255,60,60; --theme-accent-hex: #ff3c3c; }
444
+ body[data-theme-preset="orange"] { --theme-accent: 255,140,0; --theme-accent-hex: #ff8c00; }
445
+ body[data-theme-preset="blue"] { --theme-accent: 0,136,255; --theme-accent-hex: #0088ff; }
446
+
447
+ /* Apply preset to edge tabs and listen panel accent colour */
448
+ body[data-theme-preset] .edge-tab { background: rgba(var(--theme-accent),0.08); border-color: rgba(var(--theme-accent),0.25); color: var(--theme-accent-hex); }
449
+ body[data-theme-preset] .edge-tab:hover { background: rgba(var(--theme-accent),0.14); border-color: rgba(var(--theme-accent),0.5); }
450
+ body[data-theme-preset] .listen-panel { border-color: rgba(var(--theme-accent),0.35); }
451
+
452
+ /* ── Profile mode badge ── */
453
+ /* Shown bottom-right when profile.ui.show_mode_badge = true */
454
+ .profile-mode-badge {
455
+ position: fixed;
456
+ bottom: 12px;
457
+ right: 12px;
458
+ z-index: 50;
459
+ font-size: 10px;
460
+ font-weight: 600;
461
+ letter-spacing: 0.08em;
462
+ text-transform: uppercase;
463
+ color: rgba(255,255,255,0.5);
464
+ background: rgba(255,255,255,0.05);
465
+ border: 1px solid rgba(255,255,255,0.12);
466
+ border-radius: 4px;
467
+ padding: 3px 8px;
468
+ pointer-events: none;
469
+ }
470
+
471
+ /* PTT mode indicator on status bar (optional future use) */
472
+ .ptt-mode-active-badge {
473
+ display: none;
474
+ font-size: 11px;
475
+ color: #ffa500;
476
+ background: rgba(255,160,0,0.1);
477
+ border: 1px solid rgba(255,160,0,0.3);
478
+ border-radius: 4px;
479
+ padding: 2px 6px;
480
+ }
481
+ .ptt-mode-active-badge.visible { display: inline-block; }
482
+
483
+ /* Action Console button - bottom left floating */
484
+ .console-button {
485
+ position: fixed;
486
+ bottom: 10px;
487
+ left: 10px;
488
+ width: 40px; height: 40px;
489
+ border-radius: 50%;
490
+ border: 1px solid var(--green);
491
+ background: transparent;
492
+ cursor: pointer;
493
+ display: flex;
494
+ align-items: center;
495
+ justify-content: center;
496
+ font-size: 20px;
497
+ transition: all 0.3s;
498
+ z-index: 200;
499
+ font-family: monospace;
500
+ color: var(--green);
501
+ }
502
+ .console-button:hover {
503
+ border-color: #00ff88;
504
+ box-shadow: 0 0 15px rgba(0, 255, 102, 0.3);
505
+ transform: scale(1.05);
506
+ }
507
+ .console-button.active { border-color: var(--cyan); box-shadow: 0 0 15px rgba(0, 255, 255, 0.3); }
508
+ .console-button .unread-dot {
509
+ position: absolute; top: 8px; right: 8px;
510
+ width: 10px; height: 10px;
511
+ background: var(--green);
512
+ border-radius: 50%;
513
+ display: none;
514
+ }
515
+
516
+ /* Action Console panel */
517
+ #action-console {
518
+ position: fixed;
519
+ bottom: 60px;
520
+ left: 10px;
521
+ width: 400px;
522
+ max-height: 50vh;
523
+ z-index: 200;
524
+ background: rgba(0, 0, 0, 0.95);
525
+ backdrop-filter: blur(10px);
526
+ border: 1px solid rgba(0, 255, 102, 0.3);
527
+ border-radius: 12px;
528
+ display: none;
529
+ flex-direction: column;
530
+ overflow: hidden;
531
+ }
532
+ #action-console .ac-header {
533
+ display: flex;
534
+ justify-content: space-between;
535
+ align-items: center;
536
+ padding: 10px 14px;
537
+ border-bottom: 1px solid rgba(0, 255, 102, 0.15);
538
+ font-size: 13px;
539
+ color: var(--green);
540
+ letter-spacing: 1px;
541
+ text-transform: uppercase;
542
+ font-family: monospace;
543
+ }
544
+ #action-console .ac-close {
545
+ background: none; border: none; color: var(--text-dim);
546
+ cursor: pointer; font-size: 18px; padding: 0 4px;
547
+ }
548
+ #action-console .ac-close:hover { color: #fff; }
549
+ #action-console .ac-clear {
550
+ background: none; border: none; color: var(--text-dim);
551
+ cursor: pointer; font-size: 11px; padding: 2px 8px;
552
+ text-transform: uppercase; letter-spacing: 0.5px;
553
+ }
554
+ #action-console .ac-clear:hover { color: var(--green); }
555
+ #action-console .ac-entries {
556
+ flex: 1;
557
+ overflow-y: auto;
558
+ padding: 8px;
559
+ display: flex;
560
+ flex-direction: column;
561
+ gap: 2px;
562
+ font-family: monospace;
563
+ font-size: 12px;
564
+ }
565
+ #action-console .ac-entry {
566
+ padding: 4px 8px;
567
+ border-radius: 4px;
568
+ color: #8b949e;
569
+ border-left: 3px solid transparent;
570
+ line-height: 1.4;
571
+ }
572
+ #action-console .ac-entry.tool { border-left-color: #ffa657; color: #c9d1d9; }
573
+ #action-console .ac-entry.lifecycle { border-left-color: #79c0ff; color: #8b949e; }
574
+ #action-console .ac-entry.system { border-left-color: var(--green); color: var(--green); }
575
+ #action-console .ac-entry.error { border-left-color: #f85149; color: #f85149; }
576
+ #action-console .ac-entry.chat { border-left-color: var(--cyan); color: #8b949e; }
577
+ #action-console .ac-ts { color: #484f58; margin-right: 6px; }
578
+ #action-console .ac-icon { margin-right: 4px; }
579
+ #action-console .ac-detail { color: #8b949e; font-size: 11px; margin-left: 24px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100% - 30px); font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; }
580
+ /* Action console edge tabs — right side of panel */
581
+ .ac-side-tabs {
582
+ position: absolute;
583
+ right: -37px;
584
+ top: 50%;
585
+ transform: translateY(-50%);
586
+ display: flex;
587
+ flex-direction: column;
588
+ gap: 4px;
589
+ }
590
+ .ac-tab {
591
+ width: 36px;
592
+ height: 42px;
593
+ background: rgba(0, 136, 255, 0.08);
594
+ border: 1px solid rgba(0, 136, 255, 0.25);
595
+ border-right: none;
596
+ border-radius: 0 10px 10px 0;
597
+ display: flex;
598
+ align-items: center;
599
+ justify-content: center;
600
+ font-size: 15px;
601
+ color: var(--blue);
602
+ backdrop-filter: blur(8px);
603
+ cursor: pointer;
604
+ transition: all 0.3s;
605
+ }
606
+ .ac-tab:hover {
607
+ background: rgba(0, 136, 255, 0.18);
608
+ border-color: var(--blue-bright);
609
+ box-shadow: 0 0 12px rgba(0, 136, 255, 0.2);
610
+ width: 42px;
611
+ }
612
+ .ac-tab.danger:hover {
613
+ background: rgba(255, 80, 80, 0.18);
614
+ border-color: rgba(255, 80, 80, 0.5);
615
+ color: #f85149;
616
+ box-shadow: 0 0 12px rgba(255, 80, 80, 0.2);
617
+ }
618
+ .ac-tab .ac-tab-tooltip {
619
+ display: none;
620
+ position: absolute;
621
+ right: 44px;
622
+ white-space: nowrap;
623
+ background: rgba(0, 0, 0, 0.9);
624
+ border: 1px solid rgba(0, 255, 102, 0.3);
625
+ padding: 4px 10px;
626
+ border-radius: 6px;
627
+ font-size: 11px;
628
+ color: #c9d1d9;
629
+ font-family: monospace;
630
+ pointer-events: none;
631
+ }
632
+ .ac-tab:hover .ac-tab-tooltip { display: block; }
633
+
634
+ @media (max-width: 500px) {
635
+ #action-console { width: calc(100vw - 20px); left: 10px; }
636
+ }
637
+ @media (max-width: 768px) {
638
+ .console-button {
639
+ width: 36px;
640
+ height: 36px;
641
+ font-size: 16px;
642
+ bottom: 8px;
643
+ left: 8px;
644
+ }
645
+ }
646
+
647
+ /* Transcript button - bottom right floating */
648
+ .transcript-button {
649
+ position: fixed;
650
+ bottom: 10px;
651
+ right: 10px;
652
+ width: 40px; height: 40px;
653
+ border-radius: 50%;
654
+ border: 1px solid var(--blue);
655
+ background: transparent;
656
+ cursor: pointer;
657
+ display: flex;
658
+ align-items: center;
659
+ justify-content: center;
660
+ font-size: 24px;
661
+ transition: all 0.3s;
662
+ z-index: 9999;
663
+ }
664
+ .transcript-button:hover {
665
+ border-color: var(--blue-bright);
666
+ box-shadow: 0 0 15px rgba(0, 136, 255, 0.3);
667
+ transform: scale(1.05);
668
+ }
669
+ .transcript-button.active { border-color: var(--cyan); box-shadow: 0 0 15px rgba(0, 255, 255, 0.3); }
670
+ .transcript-button .unread-dot {
671
+ position: absolute; top: 8px; right: 8px;
672
+ width: 10px; height: 10px;
673
+ background: var(--cyan);
674
+ border-radius: 50%;
675
+ display: none;
676
+ }
677
+
678
+ /* Transcript panel */
679
+ #transcript-panel {
680
+ position: fixed;
681
+ bottom: 60px;
682
+ right: 10px;
683
+ width: 380px;
684
+ max-height: 50vh;
685
+ z-index: 9999;
686
+ background: rgba(0, 0, 0, 0.95);
687
+ backdrop-filter: blur(10px);
688
+ border: 1px solid rgba(0, 136, 255, 0.3);
689
+ border-radius: 12px;
690
+ display: none;
691
+ flex-direction: column;
692
+ overflow: hidden;
693
+ }
694
+ #transcript-panel .tp-header {
695
+ display: flex;
696
+ justify-content: space-between;
697
+ align-items: center;
698
+ padding: 10px 14px;
699
+ border-bottom: 1px solid rgba(0, 136, 255, 0.15);
700
+ font-size: 13px;
701
+ color: var(--cyan);
702
+ letter-spacing: 1px;
703
+ text-transform: uppercase;
704
+ }
705
+ #transcript-panel .tp-close {
706
+ background: none; border: none; color: var(--text-dim);
707
+ cursor: pointer; font-size: 18px; padding: 0 4px;
708
+ }
709
+ #transcript-panel .tp-close:hover { color: #fff; }
710
+ #transcript-panel .tp-messages {
711
+ flex: 1;
712
+ overflow-y: auto;
713
+ padding: 10px;
714
+ display: flex;
715
+ flex-direction: column;
716
+ gap: 8px;
717
+ }
718
+ #transcript-panel .tp-msg {
719
+ max-width: 85%;
720
+ padding: 8px 12px;
721
+ border-radius: 10px;
722
+ font-size: 13px;
723
+ line-height: 1.4;
724
+ word-wrap: break-word;
725
+ overflow-wrap: break-word;
726
+ }
727
+ #transcript-panel .tp-msg.user {
728
+ align-self: flex-end;
729
+ background: rgba(0, 136, 255, 0.15);
730
+ border: 1px solid rgba(0, 136, 255, 0.2);
731
+ }
732
+ #transcript-panel .tp-msg.assistant {
733
+ align-self: flex-start;
734
+ background: rgba(255, 255, 255, 0.05);
735
+ border: 1px solid rgba(255, 255, 255, 0.08);
736
+ }
737
+ #transcript-panel .tp-meta {
738
+ font-size: 10px;
739
+ color: var(--text-dim);
740
+ margin-bottom: 3px;
741
+ }
742
+ #transcript-panel .tp-text { color: #e0e0e0; }
743
+ #transcript-panel .tp-text strong { color: #fff; }
744
+ #transcript-panel .tp-text code {
745
+ background: rgba(0, 255, 255, 0.1);
746
+ padding: 1px 4px;
747
+ border-radius: 3px;
748
+ font-size: 12px;
749
+ }
750
+ #transcript-panel .tp-img-icon {
751
+ width: 28px;
752
+ height: 28px;
753
+ border-radius: 4px;
754
+ object-fit: cover;
755
+ vertical-align: middle;
756
+ margin-right: 6px;
757
+ border: 1px solid rgba(255, 255, 255, 0.15);
758
+ cursor: pointer;
759
+ }
760
+ #transcript-panel .tp-img-icon:hover {
761
+ border-color: rgba(0, 229, 255, 0.5);
762
+ box-shadow: 0 0 6px rgba(0, 229, 255, 0.3);
763
+ }
764
+ #transcript-panel .tp-dragover {
765
+ outline: 2px dashed rgba(0, 229, 255, 0.5);
766
+ outline-offset: -4px;
767
+ }
768
+ @media (max-width: 500px) {
769
+ #transcript-panel { width: calc(100vw - 40px); right: 20px; }
770
+ .controls-left, .controls-right { gap: 2px; }
771
+ .edge-tab {
772
+ width: 44px;
773
+ min-width: 44px;
774
+ height: 48px;
775
+ min-height: 48px;
776
+ font-size: 16px;
777
+ }
778
+ .edge-tab:hover { width: 48px; }
779
+ #canvas-menu-button {
780
+ width: 36px;
781
+ height: 36px;
782
+ font-size: 14px;
783
+ }
784
+ .transcript-button {
785
+ width: 36px;
786
+ height: 36px;
787
+ font-size: 16px;
788
+ }
789
+ }
790
+ @media (max-width: 768px) {
791
+ /* face-box uses smooth vw scaling — no override needed */
792
+
793
+ /* Tighter edge tabs */
794
+ .controls-left, .controls-right { gap: 3px; }
795
+ .edge-tab {
796
+ width: 38px;
797
+ height: 46px;
798
+ font-size: 16px;
799
+ }
800
+ .edge-tab:hover { width: 44px; }
801
+
802
+ /* Corner buttons - slightly bigger than sides but smaller than desktop */
803
+ #canvas-menu-button {
804
+ width: 36px;
805
+ height: 36px;
806
+ font-size: 16px;
807
+ top: 8px;
808
+ left: 8px;
809
+ }
810
+ #auth-section {
811
+ top: 8px;
812
+ right: 8px;
813
+ }
814
+ .transcript-button {
815
+ width: 36px;
816
+ height: 36px;
817
+ font-size: 20px;
818
+ bottom: 8px;
819
+ right: 8px;
820
+ }
821
+
822
+ }
823
+ /* Transcript thinking indicator */
824
+ #transcript-panel .tp-msg.tp-thinking {
825
+ background: rgba(0, 170, 255, 0.08);
826
+ border: 1px solid rgba(0, 170, 255, 0.15);
827
+ }
828
+ /* Transcript thinking dots */
829
+ .tp-dots { display: flex; gap: 6px; padding: 8px 0; }
830
+ .tp-dots span {
831
+ width: 8px; height: 8px;
832
+ background: rgba(0, 170, 255, 0.8);
833
+ border-radius: 50%;
834
+ animation: tp-bounce 1.4s ease-in-out infinite;
835
+ }
836
+ .tp-dots span:nth-child(2) { animation-delay: 0.2s; }
837
+ .tp-dots span:nth-child(3) { animation-delay: 0.4s; }
838
+ @keyframes tp-bounce {
839
+ 0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
840
+ 40% { transform: translateY(-8px); opacity: 1; }
841
+ }
842
+
843
+ /* Camera preview in edge tab */
844
+ .camera-button { position: relative; overflow: hidden; }
845
+ .camera-button video {
846
+ position: absolute;
847
+ width: 100%; height: 100%;
848
+ object-fit: cover;
849
+ border-radius: 0 14px 14px 0;
850
+ opacity: 0;
851
+ transition: opacity 0.3s;
852
+ }
853
+ .camera-button.active video { opacity: 1; }
854
+ .camera-button.active .camera-icon { display: none; }
855
+
856
+ /* Transcript input bar */
857
+ .tp-input-bar {
858
+ display: flex;
859
+ align-items: center;
860
+ gap: 6px;
861
+ padding: 8px 10px;
862
+ border-top: 1px solid rgba(0, 136, 255, 0.15);
863
+ background: rgba(0, 0, 0, 0.3);
864
+ }
865
+ .tp-text-input {
866
+ flex: 1;
867
+ background: rgba(255, 255, 255, 0.06);
868
+ border: 1px solid rgba(0, 136, 255, 0.2);
869
+ border-radius: 8px;
870
+ color: #e0e0e0;
871
+ padding: 8px 10px;
872
+ font-size: 13px;
873
+ font-family: inherit;
874
+ outline: none;
875
+ min-width: 0;
876
+ }
877
+ .tp-text-input:focus { border-color: rgba(0, 229, 255, 0.5); }
878
+ .tp-text-input::placeholder { color: rgba(255, 255, 255, 0.25); }
879
+ .tp-send-btn {
880
+ background: none;
881
+ border: none;
882
+ color: var(--cyan);
883
+ cursor: pointer;
884
+ font-size: 18px;
885
+ padding: 4px;
886
+ opacity: 0.7;
887
+ transition: opacity 0.2s;
888
+ }
889
+ .tp-send-btn:hover { opacity: 1; }
890
+ .tp-upload-btn {
891
+ cursor: pointer;
892
+ font-size: 16px;
893
+ padding: 4px;
894
+ opacity: 0.5;
895
+ transition: opacity 0.2s;
896
+ line-height: 1;
897
+ }
898
+ .tp-upload-btn:hover { opacity: 1; }
899
+
900
+ .tp-file-preview {
901
+ display: flex;
902
+ align-items: center;
903
+ gap: 4px;
904
+ background: rgba(0, 136, 255, 0.12);
905
+ border: 1px solid rgba(0, 136, 255, 0.25);
906
+ border-radius: 6px;
907
+ padding: 3px 8px;
908
+ font-size: 11px;
909
+ color: var(--cyan);
910
+ max-width: 140px;
911
+ white-space: nowrap;
912
+ overflow: hidden;
913
+ text-overflow: ellipsis;
914
+ }
915
+ .tp-file-clear {
916
+ background: none;
917
+ border: none;
918
+ color: #888;
919
+ cursor: pointer;
920
+ font-size: 12px;
921
+ padding: 0 2px;
922
+ flex-shrink: 0;
923
+ }
924
+ .tp-file-clear:hover { color: #fff; }
925
+
926
+ /* Error message */
927
+ .error-message {
928
+ position: fixed;
929
+ bottom: 20px;
930
+ left: 50%;
931
+ transform: translateX(-50%);
932
+ background: rgba(255, 0, 0, 0.2);
933
+ border: 1px solid var(--red);
934
+ color: var(--red);
935
+ padding: 10px 20px;
936
+ border-radius: 10px;
937
+ display: none;
938
+ z-index: 1000;
939
+ }
940
+
941
+ .error-message.visible { display: block; }
942
+
943
+ /* Face notification */
944
+ .face-notification {
945
+ position: fixed;
946
+ top: 15%;
947
+ left: 50%;
948
+ transform: translateX(-50%);
949
+ background: var(--panel-bg);
950
+ border: 1px solid var(--green);
951
+ color: var(--green);
952
+ padding: 10px 20px;
953
+ border-radius: 10px;
954
+ opacity: 0;
955
+ transition: opacity 0.3s;
956
+ z-index: 1000;
957
+ }
958
+
959
+ .face-notification.visible { opacity: 1; }
960
+
961
+ /* Agent Activity Chip — live agent state indicator (top-center, below settings) */
962
+ .agent-activity-chip {
963
+ position: fixed;
964
+ top: 34px;
965
+ left: 50%;
966
+ transform: translateX(-50%) translateY(-4px) scale(0.96);
967
+ background: rgba(50, 55, 65, 0.95);
968
+ border: 1px solid rgba(180, 190, 210, 0.3);
969
+ color: #e8eaed;
970
+ padding: 5px 14px 5px 10px;
971
+ border-radius: 0 0 12px 12px;
972
+ display: none;
973
+ align-items: center;
974
+ gap: 7px;
975
+ font-size: 11px;
976
+ font-family: var(--font-mono, monospace);
977
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255,255,255,0.07);
978
+ overflow: hidden;
979
+ opacity: 0;
980
+ transition: opacity 0.2s ease, transform 0.2s ease;
981
+ pointer-events: none;
982
+ z-index: 1400;
983
+ max-width: 340px;
984
+ }
985
+
986
+ .agent-activity-chip.visible {
987
+ opacity: 1;
988
+ transform: translateX(-50%) translateY(0) scale(1);
989
+ }
990
+
991
+ .agent-activity-chip .chip-icon {
992
+ font-family: var(--font-mono, monospace);
993
+ font-size: 9px;
994
+ font-weight: 700;
995
+ letter-spacing: 0.06em;
996
+ text-transform: uppercase;
997
+ color: #60a5fa;
998
+ background: rgba(59, 130, 246, 0.18);
999
+ border: 1px solid rgba(59, 130, 246, 0.3);
1000
+ padding: 1px 5px;
1001
+ border-radius: 3px;
1002
+ flex-shrink: 0;
1003
+ min-width: 24px;
1004
+ text-align: center;
1005
+ }
1006
+
1007
+ .agent-activity-chip .chip-text {
1008
+ overflow: hidden;
1009
+ text-overflow: ellipsis;
1010
+ white-space: nowrap;
1011
+ color: #b0b8c8;
1012
+ font-size: 10px;
1013
+ }
1014
+
1015
+ @keyframes chip-update {
1016
+ 0% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
1017
+ 35% { opacity: 0.2; transform: translateX(-50%) translateY(-2px) scale(0.95); }
1018
+ 100% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
1019
+ }
1020
+
1021
+ .agent-activity-chip.updating {
1022
+ animation: chip-update 0.22s ease;
1023
+ }
1024
+
1025
+ /* ===== MUSIC PANEL — Slide-up card (Concept T) ===== */
1026
+ .music-panel {
1027
+ position: fixed;
1028
+ bottom: 0;
1029
+ left: 50%;
1030
+ max-width: 520px;
1031
+ width: calc(100% - 128px);
1032
+ background: rgba(5, 10, 20, 0.97);
1033
+ border: 1px solid rgba(0, 229, 255, 0.25);
1034
+ border-bottom: none;
1035
+ border-radius: 14px 14px 0 0;
1036
+ transform: translateX(-50%) translateY(100%);
1037
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1038
+ z-index: 200;
1039
+ overflow: hidden;
1040
+ box-shadow: 0 -4px 25px rgba(0, 229, 255, 0.25),
1041
+ 0 0 40px rgba(0, 229, 255, 0.12),
1042
+ inset 0 1px 0 rgba(0, 229, 255, 0.1);
1043
+ }
1044
+ .music-panel.open {
1045
+ transform: translateX(-50%) translateY(0);
1046
+ }
1047
+
1048
+ /* --- Full view --- */
1049
+ .mp-full {
1050
+ position: relative;
1051
+ padding: 10px 16px 8px;
1052
+ display: flex;
1053
+ flex-direction: column;
1054
+ gap: 5px;
1055
+ }
1056
+ .mp-waveform-bg {
1057
+ position: absolute;
1058
+ bottom: 0; left: 0; right: 0;
1059
+ height: 40px;
1060
+ display: flex;
1061
+ align-items: flex-end;
1062
+ gap: 2px;
1063
+ padding: 0 10px;
1064
+ opacity: 0;
1065
+ pointer-events: none;
1066
+ transition: opacity 0.4s;
1067
+ }
1068
+ .music-panel.playing .mp-waveform-bg {
1069
+ opacity: 0.12;
1070
+ }
1071
+ .mp-waveform-bg .bar {
1072
+ flex: 1;
1073
+ background: var(--cyan);
1074
+ border-radius: 1px 1px 0 0;
1075
+ min-width: 2px;
1076
+ transform-origin: bottom;
1077
+ animation: mp-eq-bounce var(--d, 0.8s) ease-in-out infinite alternate;
1078
+ animation-play-state: paused;
1079
+ }
1080
+ .music-panel.playing .mp-waveform-bg .bar {
1081
+ animation-play-state: running;
1082
+ }
1083
+ @keyframes mp-eq-bounce {
1084
+ 0% { transform: scaleY(0.3); opacity: 0.4; }
1085
+ 100% { transform: scaleY(1); opacity: 1; }
1086
+ }
1087
+
1088
+ .mp-collapse {
1089
+ position: absolute;
1090
+ top: -12px; right: -12px;
1091
+ width: 24px;
1092
+ height: 24px;
1093
+ background: rgba(5, 10, 20, 0.95);
1094
+ border: 1px solid rgba(0, 229, 255, 0.3);
1095
+ border-radius: 50%;
1096
+ color: var(--blue-dim);
1097
+ font-size: 0.7rem;
1098
+ cursor: pointer;
1099
+ padding: 0;
1100
+ z-index: 3;
1101
+ display: flex;
1102
+ align-items: center;
1103
+ justify-content: center;
1104
+ transition: all 0.2s;
1105
+ box-shadow: 0 0 8px rgba(0, 229, 255, 0.15);
1106
+ line-height: 1;
1107
+ }
1108
+ .mp-collapse:hover {
1109
+ color: var(--cyan);
1110
+ border-color: var(--cyan);
1111
+ box-shadow: 0 0 12px rgba(0, 229, 255, 0.3);
1112
+ }
1113
+
1114
+ .mp-info-row {
1115
+ display: flex;
1116
+ align-items: center;
1117
+ gap: 10px;
1118
+ position: relative;
1119
+ z-index: 1;
1120
+ }
1121
+ .mp-track-info {
1122
+ display: flex;
1123
+ flex-direction: column;
1124
+ min-width: 0;
1125
+ flex: 1;
1126
+ }
1127
+ .mp-track-info .track-label {
1128
+ font-size: 0.6rem;
1129
+ color: var(--blue-dim);
1130
+ text-transform: uppercase;
1131
+ letter-spacing: 0.5px;
1132
+ line-height: 1.1;
1133
+ }
1134
+ .mp-track-info .track-name {
1135
+ color: var(--cyan);
1136
+ font-size: 0.8rem;
1137
+ overflow: hidden;
1138
+ text-overflow: ellipsis;
1139
+ white-space: nowrap;
1140
+ line-height: 1.3;
1141
+ }
1142
+
1143
+ .mp-timeline-row {
1144
+ display: flex;
1145
+ align-items: center;
1146
+ gap: 6px;
1147
+ position: relative;
1148
+ z-index: 1;
1149
+ }
1150
+ .mp-time {
1151
+ font-size: 0.6rem;
1152
+ color: var(--blue-dim);
1153
+ min-width: 28px;
1154
+ text-align: center;
1155
+ font-variant-numeric: tabular-nums;
1156
+ }
1157
+ .mp-timeline-wrap {
1158
+ flex: 1;
1159
+ position: relative;
1160
+ height: 4px;
1161
+ }
1162
+ .mp-timeline {
1163
+ width: 100%;
1164
+ height: 4px;
1165
+ -webkit-appearance: none;
1166
+ appearance: none;
1167
+ background: rgba(0, 229, 255, 0.15);
1168
+ border-radius: 2px;
1169
+ cursor: pointer;
1170
+ position: relative;
1171
+ z-index: 2;
1172
+ margin: 0;
1173
+ }
1174
+ .mp-timeline::-webkit-slider-thumb {
1175
+ -webkit-appearance: none;
1176
+ width: 10px;
1177
+ height: 10px;
1178
+ border-radius: 50%;
1179
+ background: var(--cyan);
1180
+ cursor: pointer;
1181
+ box-shadow: 0 0 6px rgba(0, 229, 255, 0.5);
1182
+ }
1183
+ .mp-timeline-fill {
1184
+ position: absolute;
1185
+ top: 0; left: 0;
1186
+ height: 4px;
1187
+ background: var(--cyan);
1188
+ border-radius: 2px;
1189
+ pointer-events: none;
1190
+ z-index: 1;
1191
+ }
1192
+
1193
+ .mp-controls-row {
1194
+ display: flex;
1195
+ align-items: center;
1196
+ justify-content: center;
1197
+ gap: 8px;
1198
+ position: relative;
1199
+ z-index: 1;
1200
+ }
1201
+ .mp-controls-row button,
1202
+ .mp-mini button {
1203
+ background: none;
1204
+ border: 1px solid var(--blue-dim);
1205
+ color: var(--blue);
1206
+ width: 28px;
1207
+ height: 28px;
1208
+ min-width: 28px;
1209
+ min-height: 28px;
1210
+ border-radius: 50%;
1211
+ cursor: pointer;
1212
+ font-size: 0.8rem;
1213
+ transition: all 0.2s;
1214
+ padding: 0;
1215
+ line-height: 1;
1216
+ flex-shrink: 0;
1217
+ }
1218
+ .mp-controls-row button:hover,
1219
+ .mp-mini button:hover {
1220
+ border-color: var(--cyan);
1221
+ color: var(--cyan);
1222
+ }
1223
+ .mp-controls-row .mp-play,
1224
+ .mp-mini .mp-play {
1225
+ width: 34px;
1226
+ height: 34px;
1227
+ min-width: 34px;
1228
+ min-height: 34px;
1229
+ font-size: 1rem;
1230
+ border-color: var(--cyan);
1231
+ color: var(--cyan);
1232
+ box-shadow: 0 0 8px rgba(0, 229, 255, 0.3);
1233
+ }
1234
+
1235
+ .mp-vol {
1236
+ width: 50px;
1237
+ height: 4px;
1238
+ -webkit-appearance: none;
1239
+ background: var(--blue-dim);
1240
+ border-radius: 2px;
1241
+ cursor: pointer;
1242
+ }
1243
+ .mp-vol::-webkit-slider-thumb {
1244
+ -webkit-appearance: none;
1245
+ width: 12px;
1246
+ height: 12px;
1247
+ border-radius: 50%;
1248
+ background: var(--cyan);
1249
+ cursor: pointer;
1250
+ }
1251
+
1252
+ .mp-toggle {
1253
+ display: flex;
1254
+ align-items: center;
1255
+ gap: 4px;
1256
+ }
1257
+ .mp-toggle label {
1258
+ color: #888;
1259
+ font-size: 0.65rem;
1260
+ cursor: pointer;
1261
+ }
1262
+ .mp-toggle input[type="checkbox"] {
1263
+ width: 14px;
1264
+ height: 14px;
1265
+ cursor: pointer;
1266
+ accent-color: var(--cyan);
1267
+ }
1268
+
1269
+ /* --- Mini view: no container, just floating buttons --- */
1270
+ .music-panel.state-mini {
1271
+ background: none;
1272
+ border-color: transparent;
1273
+ box-shadow: none;
1274
+ }
1275
+ .mp-mini {
1276
+ display: flex;
1277
+ align-items: center;
1278
+ justify-content: center;
1279
+ gap: 8px;
1280
+ padding: 6px 16px;
1281
+ }
1282
+ .mp-mini .mp-mini-vol {
1283
+ width: 55px;
1284
+ }
1285
+ .mp-expand {
1286
+ background: none !important;
1287
+ border: 1px solid rgba(0, 229, 255, 0.3) !important;
1288
+ color: var(--blue-dim) !important;
1289
+ font-size: 0.7rem;
1290
+ cursor: pointer;
1291
+ padding: 0;
1292
+ width: 24px !important;
1293
+ min-width: 24px !important;
1294
+ height: 24px !important;
1295
+ min-height: 24px !important;
1296
+ border-radius: 50% !important;
1297
+ display: flex;
1298
+ align-items: center;
1299
+ justify-content: center;
1300
+ transition: all 0.2s;
1301
+ }
1302
+ .mp-expand:hover {
1303
+ color: var(--cyan) !important;
1304
+ border-color: var(--cyan) !important;
1305
+ box-shadow: 0 0 8px rgba(0, 229, 255, 0.3);
1306
+ }
1307
+
1308
+ /* --- Music panel responsive --- */
1309
+ @media (max-width: 600px) {
1310
+ .music-panel { width: calc(100% - 100px); }
1311
+ .mp-full { padding: 8px 12px 6px; }
1312
+ .mp-track-info .track-name { font-size: 0.75rem; }
1313
+ }
1314
+ @media (max-width: 500px) {
1315
+ .music-panel { width: calc(100% - 92px); }
1316
+ .mp-mini .mp-mini-vol { display: none; }
1317
+ .mp-vol { width: 40px; }
1318
+ .mp-controls-row .mp-toggle { display: none; }
1319
+ }
1320
+ @media (max-width: 400px) {
1321
+ .music-panel { width: calc(100% - 88px); }
1322
+ .mp-full { padding: 6px 8px 4px; gap: 3px; }
1323
+ .mp-mini { padding: 4px 10px; gap: 6px; }
1324
+ }
1325
+
1326
+ /* Playlist selector in music panel */
1327
+ .mp-full select {
1328
+ background: rgba(5, 10, 20, 0.9);
1329
+ border: 1px solid var(--blue-dim);
1330
+ color: var(--cyan);
1331
+ padding: 3px 6px;
1332
+ border-radius: 6px;
1333
+ font-size: 0.7rem;
1334
+ cursor: pointer;
1335
+ outline: none;
1336
+ transition: all 0.2s;
1337
+ flex-shrink: 0;
1338
+ }
1339
+ .mp-full select:hover,
1340
+ .mp-full select:focus {
1341
+ border-color: var(--cyan);
1342
+ box-shadow: 0 0 8px rgba(0, 255, 255, 0.3);
1343
+ }
1344
+ .mp-full select option {
1345
+ background: #0a0a14;
1346
+ color: var(--cyan);
1347
+ }
1348
+
1349
+ /* ===== PARTY EFFECTS ===== */
1350
+ .party-effects-container {
1351
+ position: fixed;
1352
+ top: 0;
1353
+ left: 0;
1354
+ width: 100%;
1355
+ height: 100%;
1356
+ pointer-events: none;
1357
+ z-index: 0;
1358
+ opacity: 0;
1359
+ transition: opacity 0.5s ease;
1360
+ }
1361
+ .party-effects-container.active { opacity: 1; }
1362
+
1363
+ /* Center glow */
1364
+ .center-glow {
1365
+ position: absolute;
1366
+ top: 50%;
1367
+ left: 50%;
1368
+ width: 400px;
1369
+ height: 400px;
1370
+ transform: translate(-50%, -50%);
1371
+ background: radial-gradient(circle, rgba(0, 200, 255, 0.3) 0%, transparent 70%);
1372
+ border-radius: 50%;
1373
+ opacity: 0.5;
1374
+ transition: all 0.1s ease;
1375
+ }
1376
+
1377
+ /* ===== PARTY EFFECTS - EXACT FROM ai-eyes ===== */
1378
+ .party-effects-container {
1379
+ position: fixed;
1380
+ top: 0;
1381
+ left: 0;
1382
+ width: 100%;
1383
+ height: 100%;
1384
+ pointer-events: none;
1385
+ z-index: 0;
1386
+ overflow: hidden;
1387
+ opacity: 0;
1388
+ transition: opacity 0.3s ease;
1389
+ }
1390
+ .party-effects-container.active { opacity: 1; }
1391
+
1392
+ /* Center Glow - pulses behind face with audio */
1393
+ .center-glow {
1394
+ position: fixed;
1395
+ top: 50%;
1396
+ left: 50%;
1397
+ transform: translate(-50%, -50%);
1398
+ width: 600px;
1399
+ height: 600px;
1400
+ border-radius: 50%;
1401
+ background: radial-gradient(circle, rgba(0, 136, 255, 0.15) 0%, rgba(0, 255, 255, 0.05) 40%, transparent 70%);
1402
+ filter: blur(60px);
1403
+ pointer-events: none;
1404
+ z-index: 0;
1405
+ }
1406
+
1407
+ /* Beat Flash - screen flash on bass hits */
1408
+ .beat-flash {
1409
+ position: fixed;
1410
+ top: 0;
1411
+ left: 0;
1412
+ width: 100%;
1413
+ height: 100%;
1414
+ background: radial-gradient(circle, rgba(0, 255, 255, 0.3), transparent 70%);
1415
+ pointer-events: none;
1416
+ opacity: 0;
1417
+ z-index: 1;
1418
+ }
1419
+
1420
+ /* Screen shake on bass */
1421
+ .shake {
1422
+ animation: screenShake 0.1s ease-out;
1423
+ }
1424
+ @keyframes screenShake {
1425
+ 0%, 100% { transform: translate(0, 0); }
1426
+ 25% { transform: translate(calc(var(--shake-amount, 5px) * -1), var(--shake-amount, 5px)); }
1427
+ 50% { transform: translate(var(--shake-amount, 5px), calc(var(--shake-amount, 5px) * -1)); }
1428
+ 75% { transform: translate(calc(var(--shake-amount, 5px) * -1), calc(var(--shake-amount, 5px) * -1)); }
1429
+ }
1430
+
1431
+ /* Ripple container */
1432
+ .ripple-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
1433
+ .sound-ripple {
1434
+ position: absolute;
1435
+ border: 2px solid var(--cyan);
1436
+ border-radius: 50%;
1437
+ opacity: 0;
1438
+ animation: ripple-expand 1s ease-out forwards;
1439
+ }
1440
+ @keyframes ripple-expand {
1441
+ 0% { width: 0; height: 0; opacity: 0.6; }
1442
+ 100% { width: 300px; height: 300px; opacity: 0; }
1443
+ }
1444
+
1445
+ /* Explosion container */
1446
+ .explosion-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
1447
+ .explosion-particle {
1448
+ position: absolute;
1449
+ width: 8px;
1450
+ height: 8px;
1451
+ background: var(--orange);
1452
+ border-radius: 50%;
1453
+ pointer-events: none;
1454
+ }
1455
+
1456
+ /* Fireworks container */
1457
+ .fireworks-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
1458
+ .firework-particle {
1459
+ position: absolute;
1460
+ width: 6px;
1461
+ height: 6px;
1462
+ border-radius: 50%;
1463
+ pointer-events: none;
1464
+ }
1465
+
1466
+ /* Particles - orbit around center */
1467
+ .party-particle-container {
1468
+ position: absolute;
1469
+ width: 100%;
1470
+ height: 100%;
1471
+ pointer-events: none;
1472
+ }
1473
+ .party-particle {
1474
+ position: absolute;
1475
+ width: 6px;
1476
+ height: 6px;
1477
+ background: var(--cyan);
1478
+ border-radius: 50%;
1479
+ opacity: 0;
1480
+ }
1481
+
1482
+ /* Disco Dots - orbit and react */
1483
+ .disco-container {
1484
+ position: absolute;
1485
+ width: 100%;
1486
+ height: 100%;
1487
+ pointer-events: none;
1488
+ }
1489
+ .disco-dot {
1490
+ position: absolute;
1491
+ width: 15px;
1492
+ height: 15px;
1493
+ background: white;
1494
+ border-radius: 50%;
1495
+ filter: blur(3px);
1496
+ opacity: 0;
1497
+ transition: left 0.1s ease-out, top 0.1s ease-out, opacity 0.2s;
1498
+ }
1499
+
1500
+ /* Waveform oscilloscope - FULL SCREEN background effect */
1501
+ .oscilloscope-container {
1502
+ position: fixed;
1503
+ top: 0;
1504
+ left: 0;
1505
+ width: 100vw;
1506
+ height: 100vh;
1507
+ opacity: 0;
1508
+ pointer-events: none;
1509
+ z-index: 0;
1510
+ transition: opacity 0.3s;
1511
+ }
1512
+ .oscilloscope-container.active { opacity: 1; }
1513
+ #oscilloscope-canvas {
1514
+ width: 100%;
1515
+ height: 100%;
1516
+ filter: drop-shadow(0 0 30px var(--cyan)) drop-shadow(0 0 60px var(--blue));
1517
+ }
1518
+
1519
+ /* Settings Drawer (top-center dropdown) */
1520
+ .settings-drawer {
1521
+ position: fixed;
1522
+ top: 0;
1523
+ left: 50%;
1524
+ transform: translateX(-50%);
1525
+ z-index: 1500;
1526
+ display: flex;
1527
+ flex-direction: column;
1528
+ align-items: center;
1529
+ pointer-events: none;
1530
+ }
1531
+
1532
+ .settings-drawer .settings-tab,
1533
+ .settings-drawer.open .settings-panel {
1534
+ pointer-events: auto;
1535
+ }
1536
+
1537
+ .settings-tab {
1538
+ padding: 5px 18px;
1539
+ background: var(--panel-bg);
1540
+ border: 1px solid var(--blue-dim);
1541
+ border-top: none;
1542
+ border-radius: 0 0 8px 8px;
1543
+ cursor: pointer;
1544
+ color: #aaa;
1545
+ font-size: 11px;
1546
+ letter-spacing: 1px;
1547
+ transition: all 0.2s;
1548
+ user-select: none;
1549
+ display: flex;
1550
+ align-items: center;
1551
+ gap: 6px;
1552
+ }
1553
+
1554
+ .settings-tab:hover {
1555
+ background: var(--blue-dim);
1556
+ color: white;
1557
+ }
1558
+
1559
+ .settings-drawer.open .settings-tab {
1560
+ background: var(--blue-dim);
1561
+ color: white;
1562
+ }
1563
+
1564
+ .settings-panel {
1565
+ background: var(--panel-bg);
1566
+ border: 1px solid var(--blue-dim);
1567
+ border-top: none;
1568
+ border-radius: 0 0 8px 8px;
1569
+ padding: 16px;
1570
+ width: 240px;
1571
+ display: flex;
1572
+ flex-direction: column;
1573
+ gap: 14px;
1574
+ transform: scaleY(0);
1575
+ transform-origin: top;
1576
+ opacity: 0;
1577
+ pointer-events: none;
1578
+ transition: transform 0.25s ease, opacity 0.2s ease;
1579
+ }
1580
+
1581
+ .settings-drawer.open .settings-panel {
1582
+ transform: scaleY(1);
1583
+ opacity: 1;
1584
+ pointer-events: auto;
1585
+ }
1586
+
1587
+ .settings-panel label {
1588
+ font-size: 11px;
1589
+ color: #888;
1590
+ text-transform: uppercase;
1591
+ letter-spacing: 1px;
1592
+ }
1593
+
1594
+ .settings-panel select {
1595
+ width: 100%;
1596
+ background: #222;
1597
+ color: white;
1598
+ border: 1px solid #555;
1599
+ padding: 6px 10px;
1600
+ border-radius: 4px;
1601
+ cursor: pointer;
1602
+ font-size: 13px;
1603
+ }
1604
+
1605
+ .settings-panel select:hover {
1606
+ border-color: var(--blue);
1607
+ }
1608
+
1609
+ .settings-group {
1610
+ display: flex;
1611
+ flex-direction: column;
1612
+ gap: 4px;
1613
+ }
1614
+
1615
+ .provider-status {
1616
+ font-size: 11px;
1617
+ color: #4ade80;
1618
+ }
1619
+
1620
+ .settings-divider {
1621
+ border-top: 1px solid #333;
1622
+ }
1623
+
1624
+ /* PTT Hotkey row */
1625
+ .ptt-hotkey-row {
1626
+ display: flex;
1627
+ align-items: center;
1628
+ gap: 6px;
1629
+ margin-top: 4px;
1630
+ }
1631
+ .ptt-hotkey-label {
1632
+ flex: 1;
1633
+ font-size: 12px;
1634
+ font-weight: 600;
1635
+ color: #e6edf3;
1636
+ background: rgba(255,255,255,0.05);
1637
+ border: 1px solid #333;
1638
+ border-radius: 4px;
1639
+ padding: 4px 8px;
1640
+ min-width: 80px;
1641
+ text-align: center;
1642
+ font-family: monospace;
1643
+ }
1644
+ .ptt-hotkey-btn {
1645
+ background: rgba(0,136,255,0.1);
1646
+ color: var(--blue);
1647
+ border: 1px solid rgba(0,136,255,0.3);
1648
+ border-radius: 4px;
1649
+ padding: 4px 10px;
1650
+ font-size: 11px;
1651
+ cursor: pointer;
1652
+ white-space: nowrap;
1653
+ }
1654
+ .ptt-hotkey-btn:hover { background: rgba(0,136,255,0.2); }
1655
+ .ptt-hotkey-clear { color: #888; border-color: #444; background: transparent; }
1656
+ .ptt-hotkey-clear:hover { color: #f87171; border-color: #f87171; background: transparent; }
1657
+
1658
+ .settings-btn {
1659
+ background: #222;
1660
+ color: var(--blue);
1661
+ border: 1px solid var(--blue-dim);
1662
+ padding: 6px 12px;
1663
+ border-radius: 4px;
1664
+ cursor: pointer;
1665
+ font-size: 12px;
1666
+ transition: all 0.2s;
1667
+ }
1668
+
1669
+ .settings-btn:hover {
1670
+ background: var(--blue-dim);
1671
+ color: white;
1672
+ }
1673
+
1674
+ .face-id-status {
1675
+ font-size: 12px;
1676
+ color: #888;
1677
+ }
1678
+
1679
+ .face-id-status.identified {
1680
+ color: var(--green);
1681
+ }
1682
+
1683
+ .face-id-known {
1684
+ font-size: 11px;
1685
+ color: #666;
1686
+ max-height: 80px;
1687
+ overflow-y: auto;
1688
+ }
1689
+
1690
+ /* Supertonic TTS UI */
1691
+ .supertonic-ui {
1692
+ position: fixed;
1693
+ bottom: 100px;
1694
+ left: 50%;
1695
+ transform: translateX(-50%);
1696
+ background: var(--panel-bg);
1697
+ border: 1px solid var(--blue);
1698
+ padding: 15px 20px;
1699
+ border-radius: 10px;
1700
+ display: flex;
1701
+ gap: 10px;
1702
+ align-items: center;
1703
+ z-index: 100;
1704
+ }
1705
+ .tts-input {
1706
+ background: #333;
1707
+ color: white;
1708
+ border: 1px solid #555;
1709
+ padding: 10px 15px;
1710
+ border-radius: 5px;
1711
+ font-family: 'Courier New', monospace;
1712
+ font-size: 14px;
1713
+ width: 300px;
1714
+ }
1715
+ .tts-input:focus {
1716
+ outline: none;
1717
+ border-color: var(--blue);
1718
+ }
1719
+ .tts-speak-btn {
1720
+ background: var(--blue);
1721
+ color: white;
1722
+ border: none;
1723
+ padding: 10px 20px;
1724
+ border-radius: 5px;
1725
+ cursor: pointer;
1726
+ font-family: 'Courier New', monospace;
1727
+ font-size: 14px;
1728
+ transition: background 0.2s;
1729
+ }
1730
+ .tts-speak-btn:hover {
1731
+ background: var(--blue-bright);
1732
+ }
1733
+ .tts-voice-select {
1734
+ background: #333;
1735
+ color: white;
1736
+ border: 1px solid #555;
1737
+ padding: 10px;
1738
+ border-radius: 5px;
1739
+ cursor: pointer;
1740
+ font-family: 'Courier New', monospace;
1741
+ }
1742
+
1743
+ /* Wake Word Detection - yellow glow when listening for trigger */
1744
+ @keyframes yellow-pulse-glow {
1745
+ 0%, 100% {
1746
+ box-shadow: 0 0 20px rgba(255, 221, 0, 0.4);
1747
+ transform: scale(1);
1748
+ }
1749
+ 50% {
1750
+ box-shadow: 0 0 40px rgba(255, 221, 0, 0.8);
1751
+ transform: scale(1.05);
1752
+ }
1753
+ }
1754
+
1755
+ /* Green glow when triggered/active */
1756
+ @keyframes green-pulse-glow {
1757
+ 0%, 100% {
1758
+ box-shadow: 0 0 20px rgba(0, 255, 102, 0.4);
1759
+ transform: scale(1);
1760
+ }
1761
+ 50% {
1762
+ box-shadow: 0 0 40px rgba(0, 255, 102, 0.8);
1763
+ transform: scale(1.05);
1764
+ }
1765
+ }
1766
+
1767
+ /* Auto-triggered call button - yellow flash then green */
1768
+ .call-button.auto-triggered {
1769
+ animation: auto-trigger-flash 0.5s ease-out;
1770
+ }
1771
+
1772
+ @keyframes auto-trigger-flash {
1773
+ 0% {
1774
+ border-color: var(--yellow);
1775
+ box-shadow: 0 0 0 0 rgba(255, 221, 0, 0.8);
1776
+ }
1777
+ 100% {
1778
+ border-color: var(--green);
1779
+ box-shadow: 0 0 0 20px rgba(255, 221, 0, 0);
1780
+ }
1781
+ }
1782
+
1783
+ /* Auth section */
1784
+ #auth-section {
1785
+ position: fixed;
1786
+ top: 10px;
1787
+ right: 10px;
1788
+ z-index: 1000;
1789
+ }
1790
+
1791
+ /* Custom User Menu */
1792
+ .user-menu-container {
1793
+ position: relative;
1794
+ z-index: 100;
1795
+ }
1796
+
1797
+ .user-avatar-btn {
1798
+ width: 38px;
1799
+ height: 38px;
1800
+ border-radius: 50%;
1801
+ border: 2px solid var(--blue-dim);
1802
+ padding: 0;
1803
+ cursor: pointer;
1804
+ overflow: hidden;
1805
+ background: #111;
1806
+ transition: border-color 0.2s, box-shadow 0.2s;
1807
+ display: flex;
1808
+ align-items: center;
1809
+ justify-content: center;
1810
+ }
1811
+
1812
+ .user-avatar-btn:hover {
1813
+ border-color: var(--blue);
1814
+ box-shadow: 0 0 12px rgba(0, 136, 255, 0.4);
1815
+ }
1816
+
1817
+ .user-avatar-btn img {
1818
+ width: 100%;
1819
+ height: 100%;
1820
+ object-fit: cover;
1821
+ border-radius: 50%;
1822
+ }
1823
+
1824
+ .avatar-fallback {
1825
+ width: 100%;
1826
+ height: 100%;
1827
+ display: flex;
1828
+ align-items: center;
1829
+ justify-content: center;
1830
+ font-size: 13px;
1831
+ font-weight: bold;
1832
+ color: var(--blue);
1833
+ background: rgba(0, 136, 255, 0.15);
1834
+ border-radius: 50%;
1835
+ }
1836
+
1837
+ .user-dropdown {
1838
+ position: absolute;
1839
+ top: 46px;
1840
+ right: 0;
1841
+ width: 260px;
1842
+ background: #0e1117;
1843
+ border: 1px solid rgba(0, 136, 255, 0.25);
1844
+ border-radius: 12px;
1845
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(0, 136, 255, 0.08);
1846
+ display: none;
1847
+ overflow: hidden;
1848
+ animation: dropdownFade 0.18s ease;
1849
+ max-height: 80vh;
1850
+ overflow-y: auto;
1851
+ z-index: 10000;
1852
+ }
1853
+
1854
+ .user-dropdown.open {
1855
+ display: block;
1856
+ }
1857
+
1858
+ @keyframes dropdownFade {
1859
+ from { opacity: 0; transform: translateY(-6px) scale(0.98); }
1860
+ to { opacity: 1; transform: translateY(0) scale(1); }
1861
+ }
1862
+
1863
+ .user-dropdown-header {
1864
+ padding: 14px;
1865
+ display: flex;
1866
+ align-items: center;
1867
+ gap: 12px;
1868
+ background: linear-gradient(135deg, rgba(0, 136, 255, 0.08) 0%, rgba(0, 255, 255, 0.04) 100%);
1869
+ border-bottom: 1px solid rgba(0, 136, 255, 0.15);
1870
+ }
1871
+
1872
+ .udh-avatar {
1873
+ width: 42px;
1874
+ height: 42px;
1875
+ border-radius: 50%;
1876
+ border: 2px solid var(--blue);
1877
+ overflow: hidden;
1878
+ flex-shrink: 0;
1879
+ display: flex;
1880
+ align-items: center;
1881
+ justify-content: center;
1882
+ background: #111;
1883
+ }
1884
+
1885
+ .udh-avatar img {
1886
+ width: 100%;
1887
+ height: 100%;
1888
+ object-fit: cover;
1889
+ }
1890
+
1891
+ .user-dropdown-info {
1892
+ flex: 1;
1893
+ min-width: 0;
1894
+ }
1895
+
1896
+ .user-dropdown-name {
1897
+ color: #fff;
1898
+ font-size: 14px;
1899
+ font-weight: 600;
1900
+ white-space: nowrap;
1901
+ overflow: hidden;
1902
+ text-overflow: ellipsis;
1903
+ letter-spacing: 0.2px;
1904
+ }
1905
+
1906
+ .user-dropdown-email {
1907
+ color: #556;
1908
+ font-size: 11px;
1909
+ white-space: nowrap;
1910
+ overflow: hidden;
1911
+ text-overflow: ellipsis;
1912
+ margin-top: 2px;
1913
+ }
1914
+
1915
+ .udm-section-label {
1916
+ padding: 10px 14px 4px;
1917
+ font-size: 10px;
1918
+ font-weight: 700;
1919
+ letter-spacing: 1.2px;
1920
+ text-transform: uppercase;
1921
+ color: #445;
1922
+ }
1923
+
1924
+ .user-dropdown-item {
1925
+ display: flex;
1926
+ align-items: center;
1927
+ gap: 10px;
1928
+ padding: 9px 14px;
1929
+ color: #aab;
1930
+ cursor: pointer;
1931
+ transition: background 0.12s, color 0.12s;
1932
+ font-size: 13px;
1933
+ line-height: 1.3;
1934
+ }
1935
+
1936
+ .user-dropdown-item:hover {
1937
+ background: rgba(0, 136, 255, 0.08);
1938
+ color: #fff;
1939
+ }
1940
+
1941
+ .udi-icon {
1942
+ font-size: 15px;
1943
+ width: 20px;
1944
+ text-align: center;
1945
+ flex-shrink: 0;
1946
+ opacity: 0.85;
1947
+ }
1948
+
1949
+ .user-dropdown-item.danger {
1950
+ color: #a44;
1951
+ }
1952
+
1953
+ .user-dropdown-item.danger:hover {
1954
+ background: rgba(255, 34, 68, 0.08);
1955
+ color: #f66;
1956
+ }
1957
+
1958
+ .user-dropdown-divider {
1959
+ height: 1px;
1960
+ background: rgba(255, 255, 255, 0.05);
1961
+ margin: 4px 0;
1962
+ }
1963
+
1964
+ #login-btn {
1965
+ background: var(--blue);
1966
+ color: white;
1967
+ border: none;
1968
+ padding: 8px 16px;
1969
+ border-radius: 5px;
1970
+ cursor: pointer;
1971
+ font-family: 'Courier New', monospace;
1972
+ }
1973
+
1974
+ #login-btn:hover { background: var(--blue-bright); }
1975
+
1976
+ /* Mode Selector (now inside settings drawer) */
1977
+ .mode-selector {
1978
+ display: none;
1979
+ }
1980
+
1981
+ /* Clawdbot Chat UI */
1982
+ .clawdbot-container {
1983
+ position: fixed;
1984
+ bottom: 20px;
1985
+ left: 50%;
1986
+ transform: translateX(-50%);
1987
+ width: 90%;
1988
+ max-width: 600px;
1989
+ z-index: 100;
1990
+ display: none;
1991
+ }
1992
+
1993
+ .clawdbot-container.active {
1994
+ display: flex;
1995
+ flex-direction: column;
1996
+ }
1997
+
1998
+ .chat-history {
1999
+ background: rgba(10, 10, 18, 0.95);
2000
+ border-radius: 12px;
2001
+ border: 1px solid var(--blue-dim);
2002
+ padding: 16px;
2003
+ max-height: 300px;
2004
+ overflow-y: auto;
2005
+ margin-bottom: 12px;
2006
+ color: white;
2007
+ font-family: 'Courier New', monospace;
2008
+ }
2009
+
2010
+ /* chat-history scrollbar inherits from global theme */
2011
+
2012
+ .message {
2013
+ margin-bottom: 12px;
2014
+ padding: 10px 14px;
2015
+ border-radius: 8px;
2016
+ line-height: 1.4;
2017
+ word-wrap: break-word;
2018
+ }
2019
+
2020
+ .message-user {
2021
+ background: rgba(0, 136, 255, 0.2);
2022
+ border-left: 3px solid var(--blue);
2023
+ color: #e0e0ff;
2024
+ }
2025
+
2026
+ .message-assistant {
2027
+ background: rgba(0, 255, 102, 0.1);
2028
+ border-left: 3px solid var(--green);
2029
+ color: #e0ffe0;
2030
+ }
2031
+
2032
+ .message-system {
2033
+ background: rgba(255, 255, 255, 0.05);
2034
+ color: #888;
2035
+ font-style: italic;
2036
+ text-align: center;
2037
+ }
2038
+
2039
+ .input-container {
2040
+ display: flex;
2041
+ gap: 8px;
2042
+ }
2043
+
2044
+ .input-container input {
2045
+ flex: 1;
2046
+ padding: 14px 18px;
2047
+ border-radius: 8px;
2048
+ border: 1px solid #444;
2049
+ background: rgba(30, 30, 40, 0.9);
2050
+ color: white;
2051
+ font-size: 16px;
2052
+ font-family: 'Courier New', monospace;
2053
+ outline: none;
2054
+ transition: border-color 0.2s, box-shadow 0.2s;
2055
+ }
2056
+
2057
+ .input-container input:focus {
2058
+ border-color: var(--blue);
2059
+ box-shadow: 0 0 10px rgba(0, 136, 255, 0.3);
2060
+ }
2061
+
2062
+ .input-container input::placeholder {
2063
+ color: #666;
2064
+ }
2065
+
2066
+ .input-container button {
2067
+ padding: 14px 28px;
2068
+ border-radius: 8px;
2069
+ border: none;
2070
+ background: linear-gradient(135deg, var(--blue) 0%, var(--blue-dim) 100%);
2071
+ color: white;
2072
+ font-size: 16px;
2073
+ font-family: 'Courier New', monospace;
2074
+ font-weight: bold;
2075
+ cursor: pointer;
2076
+ transition: transform 0.2s, box-shadow 0.2s;
2077
+ }
2078
+
2079
+ .input-container button:hover {
2080
+ transform: translateY(-2px);
2081
+ box-shadow: 0 4px 15px rgba(0, 136, 255, 0.4);
2082
+ }
2083
+
2084
+ .input-container button:active {
2085
+ transform: translateY(0);
2086
+ }
2087
+
2088
+ .input-container button:disabled {
2089
+ background: #444;
2090
+ cursor: not-allowed;
2091
+ transform: none;
2092
+ box-shadow: none;
2093
+ }
2094
+
2095
+ /* Connection status indicator for Clawdbot */
2096
+ .clawdbot-status {
2097
+ display: flex;
2098
+ align-items: center;
2099
+ gap: 6px;
2100
+ font-size: 12px;
2101
+ padding: 6px 10px;
2102
+ background: rgba(0, 0, 0, 0.5);
2103
+ border-radius: 4px;
2104
+ margin-bottom: 8px;
2105
+ }
2106
+
2107
+ .clawdbot-status-dot {
2108
+ width: 8px;
2109
+ height: 8px;
2110
+ border-radius: 50%;
2111
+ background: var(--red);
2112
+ animation: pulse 2s infinite;
2113
+ }
2114
+
2115
+ .clawdbot-status-dot.connected {
2116
+ background: var(--green);
2117
+ animation: none;
2118
+ }
2119
+
2120
+ .clawdbot-status-dot.connecting {
2121
+ background: var(--yellow);
2122
+ }
2123
+
2124
+ /* ===== CANVAS MENU SYSTEM ===== */
2125
+ /* Canvas Menu Button - Top Left Corner */
2126
+ #canvas-menu-button {
2127
+ position: fixed;
2128
+ top: 10px;
2129
+ left: 10px;
2130
+ width: 40px;
2131
+ height: 40px;
2132
+ border-radius: 50%;
2133
+ background: rgba(30, 30, 50, 0.9);
2134
+ border: 1px solid rgba(74, 158, 255, 0.5);
2135
+ color: white;
2136
+ font-size: 20px;
2137
+ cursor: pointer;
2138
+ z-index: 200;
2139
+ display: flex;
2140
+ align-items: center;
2141
+ justify-content: center;
2142
+ transition: all 0.2s;
2143
+ }
2144
+
2145
+ #canvas-menu-button:hover {
2146
+ background: rgba(74, 158, 255, 0.3);
2147
+ border-color: rgba(74, 158, 255, 0.8);
2148
+ transform: scale(1.1);
2149
+ }
2150
+
2151
+ #canvas-menu-button.active {
2152
+ background: rgba(74, 158, 255, 0.4);
2153
+ border-color: #4a9eff;
2154
+ }
2155
+
2156
+ /* Canvas Menu Modal */
2157
+ .canvas-menu-modal {
2158
+ position: fixed;
2159
+ top: 0;
2160
+ left: 0;
2161
+ right: 0;
2162
+ bottom: 0;
2163
+ z-index: 250;
2164
+ display: flex;
2165
+ align-items: center;
2166
+ justify-content: center;
2167
+ }
2168
+
2169
+ .cmm-backdrop {
2170
+ position: absolute;
2171
+ top: 0;
2172
+ left: 0;
2173
+ right: 0;
2174
+ bottom: 0;
2175
+ background: rgba(0, 0, 0, 0.7);
2176
+ }
2177
+
2178
+ .cmm-content {
2179
+ position: relative;
2180
+ z-index: 1;
2181
+ width: 600px;
2182
+ max-width: 90vw;
2183
+ max-height: 80vh;
2184
+ background: rgba(15, 15, 25, 0.98);
2185
+ border: 2px solid rgba(74, 158, 255, 0.4);
2186
+ border-radius: 12px;
2187
+ display: flex;
2188
+ flex-direction: column;
2189
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
2190
+ }
2191
+
2192
+ .cmm-header {
2193
+ padding: 16px;
2194
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
2195
+ display: flex;
2196
+ gap: 12px;
2197
+ }
2198
+
2199
+ #canvas-search {
2200
+ flex: 1;
2201
+ padding: 10px 14px;
2202
+ background: rgba(255, 255, 255, 0.05);
2203
+ border: 1px solid rgba(255, 255, 255, 0.1);
2204
+ border-radius: 8px;
2205
+ color: white;
2206
+ font-size: 14px;
2207
+ }
2208
+
2209
+ #canvas-search:focus {
2210
+ outline: none;
2211
+ border-color: rgba(74, 158, 255, 0.6);
2212
+ }
2213
+
2214
+ .cmm-close {
2215
+ width: 36px;
2216
+ height: 36px;
2217
+ background: transparent;
2218
+ border: 1px solid rgba(255, 255, 255, 0.2);
2219
+ border-radius: 8px;
2220
+ color: white;
2221
+ font-size: 24px;
2222
+ cursor: pointer;
2223
+ transition: all 0.2s;
2224
+ }
2225
+
2226
+ .cmm-close:hover {
2227
+ background: rgba(255, 255, 255, 0.1);
2228
+ border-color: rgba(255, 255, 255, 0.3);
2229
+ }
2230
+
2231
+ .cmm-quick-actions {
2232
+ padding: 8px 16px;
2233
+ display: flex;
2234
+ gap: 8px;
2235
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
2236
+ }
2237
+
2238
+ .cmm-qa {
2239
+ padding: 6px 12px;
2240
+ background: rgba(255, 255, 255, 0.05);
2241
+ border: 1px solid rgba(255, 255, 255, 0.1);
2242
+ border-radius: 6px;
2243
+ color: #8b949e;
2244
+ font-size: 12px;
2245
+ cursor: pointer;
2246
+ transition: all 0.2s;
2247
+ }
2248
+
2249
+ .cmm-qa:hover {
2250
+ background: rgba(255, 255, 255, 0.1);
2251
+ color: white;
2252
+ }
2253
+
2254
+ .cmm-qa.active {
2255
+ background: rgba(74, 158, 255, 0.2);
2256
+ border-color: rgba(74, 158, 255, 0.5);
2257
+ color: white;
2258
+ }
2259
+
2260
+ .cmm-categories {
2261
+ flex: 1;
2262
+ overflow-y: auto;
2263
+ padding: 12px;
2264
+ }
2265
+
2266
+ .cmm-category {
2267
+ margin-bottom: 8px;
2268
+ }
2269
+
2270
+ .cmm-cat-header {
2271
+ display: flex;
2272
+ align-items: center;
2273
+ padding: 10px 12px;
2274
+ background: rgba(255, 255, 255, 0.03);
2275
+ border-radius: 6px;
2276
+ cursor: pointer;
2277
+ user-select: none;
2278
+ transition: background 0.2s;
2279
+ }
2280
+
2281
+ .cmm-cat-header:hover {
2282
+ background: rgba(255, 255, 255, 0.06);
2283
+ }
2284
+
2285
+ .cmm-cat-icon {
2286
+ margin-right: 8px;
2287
+ font-size: 16px;
2288
+ }
2289
+
2290
+ .cmm-cat-name {
2291
+ flex: 1;
2292
+ font-weight: 500;
2293
+ color: #e6edf3;
2294
+ }
2295
+
2296
+ .cmm-cat-count {
2297
+ color: #6e7681;
2298
+ font-size: 12px;
2299
+ margin-right: 8px;
2300
+ }
2301
+
2302
+ .cmm-cat-expand {
2303
+ color: #6e7681;
2304
+ font-size: 10px;
2305
+ transition: transform 0.2s;
2306
+ }
2307
+
2308
+ .cmm-category.expanded .cmm-cat-expand {
2309
+ transform: rotate(180deg);
2310
+ }
2311
+
2312
+ .cmm-cat-pages {
2313
+ max-height: 0;
2314
+ overflow: hidden;
2315
+ transition: max-height 0.3s ease-out;
2316
+ }
2317
+
2318
+ .cmm-category.expanded .cmm-cat-pages {
2319
+ max-height: 500px;
2320
+ }
2321
+
2322
+ .cmm-page {
2323
+ display: flex;
2324
+ align-items: center;
2325
+ padding: 8px 12px 8px 36px;
2326
+ border-radius: 4px;
2327
+ cursor: pointer;
2328
+ transition: background 0.15s;
2329
+ }
2330
+
2331
+ .cmm-page:hover {
2332
+ background: rgba(74, 158, 255, 0.15);
2333
+ }
2334
+
2335
+ .cmm-page-star {
2336
+ margin-right: 8px;
2337
+ opacity: 0.3;
2338
+ cursor: pointer;
2339
+ font-size: 12px;
2340
+ transition: opacity 0.2s;
2341
+ }
2342
+
2343
+ .cmm-page-star:hover {
2344
+ opacity: 0.7;
2345
+ }
2346
+
2347
+ .cmm-page-star.active {
2348
+ opacity: 1;
2349
+ color: #f1c40f;
2350
+ }
2351
+
2352
+ .cmm-page-name {
2353
+ flex: 1;
2354
+ font-size: 14px;
2355
+ color: #c9d1d9;
2356
+ }
2357
+
2358
+ .cmm-page-time {
2359
+ color: #6e7681;
2360
+ font-size: 11px;
2361
+ }
2362
+
2363
+ .cmm-footer {
2364
+ padding: 12px 16px;
2365
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
2366
+ display: flex;
2367
+ justify-content: space-between;
2368
+ align-items: center;
2369
+ }
2370
+
2371
+ #cmm-page-count {
2372
+ color: #6e7681;
2373
+ font-size: 12px;
2374
+ }
2375
+
2376
+ #cmm-edit-mode {
2377
+ padding: 6px 12px;
2378
+ background: transparent;
2379
+ border: 1px solid rgba(255, 255, 255, 0.2);
2380
+ border-radius: 6px;
2381
+ color: #8b949e;
2382
+ font-size: 12px;
2383
+ cursor: pointer;
2384
+ transition: all 0.2s;
2385
+ }
2386
+
2387
+ #cmm-edit-mode:hover {
2388
+ background: rgba(255, 255, 255, 0.1);
2389
+ color: white;
2390
+ }
2391
+
2392
+ #cmm-edit-mode.active {
2393
+ background: rgba(74, 158, 255, 0.2);
2394
+ border-color: rgba(74, 158, 255, 0.5);
2395
+ color: white;
2396
+ }
2397
+
2398
+ /* Empty state */
2399
+ .cmm-empty {
2400
+ padding: 40px;
2401
+ text-align: center;
2402
+ color: #6e7681;
2403
+ }
2404
+
2405
+ /* Loading state */
2406
+ .cmm-loading {
2407
+ padding: 40px;
2408
+ text-align: center;
2409
+ color: #6e7681;
2410
+ }
2411
+
2412
+ /* Drag and drop states */
2413
+ .cmm-page.dragging {
2414
+ opacity: 0.5;
2415
+ background: rgba(74, 158, 255, 0.3);
2416
+ transform: scale(1.02);
2417
+ }
2418
+
2419
+ .cmm-cat-pages.drag-over {
2420
+ background: rgba(74, 158, 255, 0.1);
2421
+ border: 2px dashed rgba(74, 158, 255, 0.5);
2422
+ border-radius: 4px;
2423
+ margin: 4px 0;
2424
+ }
2425
+
2426
+ .cmm-category.dragging {
2427
+ opacity: 0.7;
2428
+ transform: scale(0.98);
2429
+ }
2430
+
2431
+ .cmm-categories.drag-over-top {
2432
+ padding-top: 40px;
2433
+ position: relative;
2434
+ }
2435
+
2436
+ .cmm-categories.drag-over-top::before {
2437
+ content: 'Drop here';
2438
+ position: absolute;
2439
+ top: 10px;
2440
+ left: 50%;
2441
+ transform: translateX(-50%);
2442
+ color: #4a9eff;
2443
+ font-size: 12px;
2444
+ padding: 8px 16px;
2445
+ border: 2px dashed #4a9eff;
2446
+ border-radius: 4px;
2447
+ }
2448
+
2449
+ /* Edit mode styles */
2450
+ .cmm-content.edit-mode .cmm-page {
2451
+ cursor: grab;
2452
+ }
2453
+
2454
+ .cmm-content.edit-mode .cmm-page:active {
2455
+ cursor: grabbing;
2456
+ }
2457
+
2458
+ .cmm-content.edit-mode .cmm-cat-header {
2459
+ cursor: grab;
2460
+ }
2461
+
2462
+ .cmm-content.edit-mode .cmm-cat-header:active {
2463
+ cursor: grabbing;
2464
+ }
2465
+
2466
+ /* Delete button on pages - always visible but dim */
2467
+ .cmm-page-delete {
2468
+ margin-left: auto;
2469
+ opacity: 0.25;
2470
+ cursor: pointer;
2471
+ font-size: 16px;
2472
+ color: #6e7681;
2473
+ transition: all 0.2s;
2474
+ padding: 2px 8px;
2475
+ border-radius: 3px;
2476
+ font-weight: bold;
2477
+ }
2478
+
2479
+ .cmm-page:hover .cmm-page-delete {
2480
+ opacity: 0.6;
2481
+ }
2482
+
2483
+ .cmm-page-delete:hover {
2484
+ opacity: 1 !important;
2485
+ color: #ff5c5c;
2486
+ background: rgba(255, 92, 92, 0.15);
2487
+ }
2488
+
2489
+ /* Confirmation modal */
2490
+ .cmm-confirm-modal {
2491
+ position: fixed;
2492
+ top: 0;
2493
+ left: 0;
2494
+ right: 0;
2495
+ bottom: 0;
2496
+ z-index: 300;
2497
+ display: flex;
2498
+ align-items: center;
2499
+ justify-content: center;
2500
+ background: rgba(0, 0, 0, 0.8);
2501
+ }
2502
+
2503
+ .cmm-confirm-box {
2504
+ background: rgba(20, 20, 35, 0.98);
2505
+ border: 2px solid rgba(255, 92, 92, 0.5);
2506
+ border-radius: 12px;
2507
+ padding: 24px;
2508
+ max-width: 400px;
2509
+ text-align: center;
2510
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
2511
+ }
2512
+
2513
+ .cmm-confirm-icon {
2514
+ font-size: 48px;
2515
+ margin-bottom: 16px;
2516
+ }
2517
+
2518
+ .cmm-confirm-title {
2519
+ font-size: 18px;
2520
+ font-weight: 600;
2521
+ color: #ff5c5c;
2522
+ margin-bottom: 12px;
2523
+ }
2524
+
2525
+ .cmm-confirm-message {
2526
+ color: #8b949e;
2527
+ font-size: 14px;
2528
+ margin-bottom: 8px;
2529
+ line-height: 1.5;
2530
+ }
2531
+
2532
+ .cmm-confirm-page-name {
2533
+ color: #e6edf3;
2534
+ font-weight: 500;
2535
+ word-break: break-word;
2536
+ margin-bottom: 20px;
2537
+ padding: 8px;
2538
+ background: rgba(255, 255, 255, 0.05);
2539
+ border-radius: 4px;
2540
+ }
2541
+
2542
+ .cmm-confirm-buttons {
2543
+ display: flex;
2544
+ gap: 12px;
2545
+ justify-content: center;
2546
+ }
2547
+
2548
+ .cmm-confirm-btn {
2549
+ padding: 10px 24px;
2550
+ border-radius: 6px;
2551
+ font-size: 14px;
2552
+ font-weight: 500;
2553
+ cursor: pointer;
2554
+ transition: all 0.2s;
2555
+ border: none;
2556
+ }
2557
+
2558
+ .cmm-confirm-btn.cancel {
2559
+ background: rgba(255, 255, 255, 0.1);
2560
+ color: #8b949e;
2561
+ }
2562
+
2563
+ .cmm-confirm-btn.cancel:hover {
2564
+ background: rgba(255, 255, 255, 0.15);
2565
+ color: white;
2566
+ }
2567
+
2568
+ .cmm-confirm-btn.delete {
2569
+ background: rgba(255, 92, 92, 0.2);
2570
+ color: #ff5c5c;
2571
+ }
2572
+
2573
+ .cmm-confirm-btn.delete:hover {
2574
+ background: rgba(255, 92, 92, 0.35);
2575
+ }
2576
+
2577
+ /* Drop zone indicator */
2578
+ .cmm-drop-zone {
2579
+ height: 40px;
2580
+ border: 2px dashed rgba(74, 158, 255, 0.3);
2581
+ border-radius: 4px;
2582
+ margin: 4px 0;
2583
+ display: flex;
2584
+ align-items: center;
2585
+ justify-content: center;
2586
+ color: #4a9eff;
2587
+ font-size: 12px;
2588
+ transition: all 0.2s;
2589
+ }
2590
+
2591
+ .cmm-drop-zone.active {
2592
+ border-color: rgba(74, 158, 255, 0.8);
2593
+ background: rgba(74, 158, 255, 0.1);
2594
+ }
2595
+
2596
+ /* ── Canvas Menu: Mobile ── */
2597
+ @media (max-width: 640px) {
2598
+ /* Slide up as a bottom sheet */
2599
+ .canvas-menu-modal {
2600
+ align-items: flex-end !important;
2601
+ }
2602
+ .cmm-content {
2603
+ width: 100vw !important;
2604
+ max-width: 100vw !important;
2605
+ max-height: 92vh !important;
2606
+ border-radius: 16px 16px 0 0 !important;
2607
+ margin: 0 !important;
2608
+ }
2609
+ /* Quick actions: wrap so they don't overflow */
2610
+ .cmm-quick-actions {
2611
+ flex-wrap: wrap;
2612
+ gap: 6px;
2613
+ }
2614
+ /* Bigger touch targets */
2615
+ .cmm-cat-header {
2616
+ padding: 14px 12px;
2617
+ min-height: 52px;
2618
+ }
2619
+ .cmm-page {
2620
+ padding: 12px 12px 12px 36px;
2621
+ min-height: 48px;
2622
+ }
2623
+ .cmm-page-name {
2624
+ font-size: 15px;
2625
+ }
2626
+ /* Give category pages room to expand */
2627
+ .cmm-category.expanded .cmm-cat-pages {
2628
+ max-height: 3000px !important;
2629
+ }
2630
+ /* Search input: full-width, bigger */
2631
+ #canvas-search {
2632
+ font-size: 16px; /* prevents iOS auto-zoom on focus */
2633
+ padding: 12px 14px;
2634
+ }
2635
+ .cmm-close {
2636
+ width: 44px;
2637
+ height: 44px;
2638
+ font-size: 20px;
2639
+ }
2640
+ .cmm-header {
2641
+ padding: 14px 12px;
2642
+ }
2643
+ /* Footer: stack on small screens */
2644
+ .cmm-footer {
2645
+ flex-wrap: wrap;
2646
+ gap: 8px;
2647
+ }
2648
+ }
2649
+
2650
+ /* ================================================================
2651
+ Issue Report Button + Modal
2652
+ ================================================================ */
2653
+
2654
+ /* Caution triangle button — top, halfway between center and right edge */
2655
+ .issue-report-btn {
2656
+ position: fixed;
2657
+ top: 8px;
2658
+ left: 75%;
2659
+ transform: translateX(-50%);
2660
+ background: transparent;
2661
+ border: 1px solid rgba(245, 158, 11, 0.0);
2662
+ color: rgba(245, 158, 11, 0.35);
2663
+ width: 30px;
2664
+ height: 30px;
2665
+ border-radius: 6px;
2666
+ cursor: pointer;
2667
+ display: flex;
2668
+ align-items: center;
2669
+ justify-content: center;
2670
+ z-index: 1200;
2671
+ transition: color 0.2s, background 0.2s, border-color 0.2s, box-shadow 0.2s;
2672
+ padding: 0;
2673
+ }
2674
+
2675
+ .issue-report-btn:hover {
2676
+ color: rgba(245, 158, 11, 0.9);
2677
+ background: rgba(245, 158, 11, 0.10);
2678
+ border-color: rgba(245, 158, 11, 0.4);
2679
+ box-shadow: 0 0 12px rgba(245, 158, 11, 0.2);
2680
+ }
2681
+
2682
+ /* Modal backdrop */
2683
+ .issue-report-modal {
2684
+ position: fixed;
2685
+ inset: 0;
2686
+ background: rgba(0, 0, 0, 0.65);
2687
+ backdrop-filter: blur(4px);
2688
+ z-index: 3000;
2689
+ display: flex;
2690
+ align-items: center;
2691
+ justify-content: center;
2692
+ padding: 16px;
2693
+ }
2694
+
2695
+ /* Modal box */
2696
+ .irm-box {
2697
+ background: #0e1117;
2698
+ border: 1px solid rgba(245, 158, 11, 0.4);
2699
+ border-radius: 12px;
2700
+ width: 100%;
2701
+ max-width: 420px;
2702
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(245,158,11,0.08);
2703
+ display: flex;
2704
+ flex-direction: column;
2705
+ overflow: hidden;
2706
+ }
2707
+
2708
+ .irm-header {
2709
+ display: flex;
2710
+ align-items: center;
2711
+ justify-content: space-between;
2712
+ padding: 14px 16px 12px;
2713
+ border-bottom: 1px solid rgba(255, 255, 255, 0.07);
2714
+ }
2715
+
2716
+ .irm-title {
2717
+ font-size: 13px;
2718
+ font-weight: 600;
2719
+ color: #e2e8f0;
2720
+ letter-spacing: 0.02em;
2721
+ }
2722
+
2723
+ .irm-close {
2724
+ background: none;
2725
+ border: none;
2726
+ color: #666;
2727
+ font-size: 20px;
2728
+ cursor: pointer;
2729
+ line-height: 1;
2730
+ padding: 0 2px;
2731
+ transition: color 0.15s;
2732
+ }
2733
+ .irm-close:hover { color: #ccc; }
2734
+
2735
+ .irm-body {
2736
+ padding: 16px;
2737
+ display: flex;
2738
+ flex-direction: column;
2739
+ gap: 12px;
2740
+ }
2741
+
2742
+ .irm-field {
2743
+ display: flex;
2744
+ flex-direction: column;
2745
+ gap: 5px;
2746
+ }
2747
+
2748
+ .irm-label {
2749
+ font-size: 11px;
2750
+ color: #888;
2751
+ letter-spacing: 0.04em;
2752
+ text-transform: uppercase;
2753
+ }
2754
+
2755
+ .irm-select,
2756
+ .irm-textarea {
2757
+ background: rgba(255, 255, 255, 0.05);
2758
+ border: 1px solid rgba(255, 255, 255, 0.12);
2759
+ border-radius: 6px;
2760
+ color: #d1d5db;
2761
+ font-size: 13px;
2762
+ padding: 8px 10px;
2763
+ font-family: inherit;
2764
+ transition: border-color 0.2s;
2765
+ outline: none;
2766
+ width: 100%;
2767
+ box-sizing: border-box;
2768
+ }
2769
+
2770
+ .irm-select:focus,
2771
+ .irm-textarea:focus {
2772
+ border-color: rgba(245, 158, 11, 0.5);
2773
+ }
2774
+
2775
+ .irm-textarea {
2776
+ resize: vertical;
2777
+ min-height: 90px;
2778
+ line-height: 1.5;
2779
+ }
2780
+
2781
+ .irm-context-row {
2782
+ display: flex;
2783
+ gap: 6px;
2784
+ align-items: flex-start;
2785
+ flex-wrap: wrap;
2786
+ }
2787
+
2788
+ .irm-context-label {
2789
+ font-size: 10px;
2790
+ color: #555;
2791
+ white-space: nowrap;
2792
+ padding-top: 1px;
2793
+ }
2794
+
2795
+ .irm-context-value {
2796
+ font-size: 10px;
2797
+ color: #555;
2798
+ font-family: var(--font-mono, monospace);
2799
+ word-break: break-all;
2800
+ }
2801
+
2802
+ .irm-footer {
2803
+ display: flex;
2804
+ align-items: center;
2805
+ justify-content: space-between;
2806
+ padding: 12px 16px;
2807
+ border-top: 1px solid rgba(255, 255, 255, 0.07);
2808
+ gap: 10px;
2809
+ }
2810
+
2811
+ .irm-status {
2812
+ font-size: 11px;
2813
+ color: #6b7280;
2814
+ flex: 1;
2815
+ }
2816
+
2817
+ .irm-status.success { color: #4ade80; }
2818
+ .irm-status.error { color: #f87171; }
2819
+
2820
+ .irm-btns {
2821
+ display: flex;
2822
+ gap: 8px;
2823
+ }
2824
+
2825
+ .irm-btn {
2826
+ padding: 7px 16px;
2827
+ border-radius: 6px;
2828
+ font-size: 12px;
2829
+ font-weight: 600;
2830
+ cursor: pointer;
2831
+ border: 1px solid transparent;
2832
+ transition: all 0.15s;
2833
+ letter-spacing: 0.02em;
2834
+ }
2835
+
2836
+ .irm-cancel {
2837
+ background: transparent;
2838
+ border-color: rgba(255,255,255,0.15);
2839
+ color: #9ca3af;
2840
+ }
2841
+ .irm-cancel:hover { border-color: rgba(255,255,255,0.3); color: #e2e8f0; }
2842
+
2843
+ .irm-submit {
2844
+ background: rgba(245, 158, 11, 0.15);
2845
+ border-color: rgba(245, 158, 11, 0.5);
2846
+ color: #f59e0b;
2847
+ }
2848
+ .irm-submit:hover {
2849
+ background: rgba(245, 158, 11, 0.25);
2850
+ border-color: rgba(245, 158, 11, 0.8);
2851
+ }
2852
+ .irm-submit:disabled {
2853
+ opacity: 0.4;
2854
+ cursor: not-allowed;
2855
+ }
2856
+
2857
+ @media (max-width: 768px) {
2858
+ .issue-report-btn {
2859
+ left: 75%;
2860
+ top: 8px;
2861
+ }
2862
+ }