@aliwey/bmo 2.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 (100) hide show
  1. package/README.md +90 -0
  2. package/bin/bmo.js +188 -0
  3. package/cli.py +1129 -0
  4. package/config/__init__.py +0 -0
  5. package/config/__pycache__/__init__.cpython-313.pyc +0 -0
  6. package/config/__pycache__/settings.cpython-313.pyc +0 -0
  7. package/config/__pycache__/system-prompt.cpython-313.pyc +0 -0
  8. package/config/settings.py +104 -0
  9. package/config/system-prompt.json +18 -0
  10. package/core/__init__.py +0 -0
  11. package/core/__pycache__/__init__.cpython-313.pyc +0 -0
  12. package/core/__pycache__/bfp_a2a_bridge.cpython-313.pyc +0 -0
  13. package/core/__pycache__/bfp_agent.cpython-313.pyc +0 -0
  14. package/core/__pycache__/bfp_agent_card.cpython-313.pyc +0 -0
  15. package/core/__pycache__/bfp_connector.cpython-313.pyc +0 -0
  16. package/core/__pycache__/bfp_discovery.cpython-313.pyc +0 -0
  17. package/core/__pycache__/bfp_identity.cpython-313.pyc +0 -0
  18. package/core/__pycache__/bfp_tasks.cpython-313.pyc +0 -0
  19. package/core/__pycache__/bfp_transport.cpython-313.pyc +0 -0
  20. package/core/__pycache__/bmo_engine.cpython-313.pyc +0 -0
  21. package/core/__pycache__/bot_client.cpython-313.pyc +0 -0
  22. package/core/__pycache__/budget_tracker.cpython-313.pyc +0 -0
  23. package/core/__pycache__/cli_renderer.cpython-313.pyc +0 -0
  24. package/core/__pycache__/goal_runner.cpython-313.pyc +0 -0
  25. package/core/__pycache__/request_worker.cpython-313.pyc +0 -0
  26. package/core/__pycache__/security.cpython-313.pyc +0 -0
  27. package/core/__pycache__/shared_state.cpython-313.pyc +0 -0
  28. package/core/__pycache__/worker_manager.cpython-313.pyc +0 -0
  29. package/core/__pycache__/worker_multiproc.cpython-313.pyc +0 -0
  30. package/core/__pycache__/worker_protocol.cpython-313.pyc +0 -0
  31. package/core/__pycache__/worker_subprocess.cpython-313.pyc +0 -0
  32. package/core/bfp_a2a_bridge.py +399 -0
  33. package/core/bfp_agent.py +98 -0
  34. package/core/bfp_agent_card.py +161 -0
  35. package/core/bfp_connector.py +177 -0
  36. package/core/bfp_discovery.py +105 -0
  37. package/core/bfp_identity.py +83 -0
  38. package/core/bfp_tasks.py +70 -0
  39. package/core/bfp_transport.py +368 -0
  40. package/core/bmo_engine.py +405 -0
  41. package/core/bot_client.py +838 -0
  42. package/core/budget_tracker.py +62 -0
  43. package/core/cli_renderer.py +177 -0
  44. package/core/goal_runner.py +129 -0
  45. package/core/request_worker.py +242 -0
  46. package/core/security.py +42 -0
  47. package/core/shared_state.py +4 -0
  48. package/core/worker_manager.py +71 -0
  49. package/core/worker_multiproc.py +155 -0
  50. package/core/worker_protocol.py +30 -0
  51. package/core/worker_subprocess.py +222 -0
  52. package/handlers/__init__.py +0 -0
  53. package/handlers/__pycache__/__init__.cpython-313.pyc +0 -0
  54. package/handlers/__pycache__/messages.cpython-313.pyc +0 -0
  55. package/handlers/messages.py +2761 -0
  56. package/main.py +125 -0
  57. package/memory.md +43 -0
  58. package/models/__init__.py +0 -0
  59. package/models/__pycache__/__init__.cpython-313.pyc +0 -0
  60. package/models/__pycache__/chat_models.cpython-313.pyc +0 -0
  61. package/models/chat_models.py +143 -0
  62. package/package.json +50 -0
  63. package/registry/worker.js +108 -0
  64. package/registry/wrangler.toml +11 -0
  65. package/requirements.txt +13 -0
  66. package/scripts/bmo_init.js +115 -0
  67. package/scripts/postinstall.js +265 -0
  68. package/scripts/relay_cmd.js +276 -0
  69. package/scripts/web_cmd.js +136 -0
  70. package/setup.py +26 -0
  71. package/storage/__init__.py +0 -0
  72. package/storage/__pycache__/__init__.cpython-313.pyc +0 -0
  73. package/storage/__pycache__/sqlite_storage.cpython-313.pyc +0 -0
  74. package/storage/__pycache__/storage.cpython-313.pyc +0 -0
  75. package/storage/sqlite_storage.py +658 -0
  76. package/storage/storage.py +265 -0
  77. package/tools/__pycache__/bfp_relay.cpython-313.pyc +0 -0
  78. package/tools/__pycache__/get_session_summaries.cpython-313.pyc +0 -0
  79. package/tools/__pycache__/mcp_bridge.cpython-313.pyc +0 -0
  80. package/tools/__pycache__/mcp_server.cpython-313.pyc +0 -0
  81. package/tools/__pycache__/run_mcp_standalone.cpython-313.pyc +0 -0
  82. package/tools/__pycache__/task_registry.cpython-313.pyc +0 -0
  83. package/tools/__pycache__/test_mcp_connection.cpython-313.pyc +0 -0
  84. package/tools/bfp_relay.py +359 -0
  85. package/tools/bot.db +0 -0
  86. package/tools/get_session_summaries.py +45 -0
  87. package/tools/mcp_bridge.py +109 -0
  88. package/tools/mcp_server.py +531 -0
  89. package/tools/register_mcp_task.py +20 -0
  90. package/tools/run_detached.bat +32 -0
  91. package/tools/run_mcp_standalone.py +16 -0
  92. package/tools/task_registry.py +184 -0
  93. package/tools/test_mcp_connection.py +80 -0
  94. package/webchat/package-lock.json +1528 -0
  95. package/webchat/package.json +12 -0
  96. package/webchat/public/app.js +1293 -0
  97. package/webchat/public/index.html +226 -0
  98. package/webchat/public/index.html.bak +416 -0
  99. package/webchat/public/styles.css +2435 -0
  100. package/webchat/server.js +645 -0
@@ -0,0 +1,2435 @@
1
+ /* ============================================================
2
+ BMO WebChat — Copper Atelier
3
+ Mobile-first, dark mode default, copper/emerald on zinc-slate.
4
+ Breakpoints: 480 / 768 / 1024 / 1280.
5
+ ============================================================ */
6
+
7
+ :root,
8
+ :root[data-theme="dark"] {
9
+ /* Colors - Warm Copper & Emerald (Dark Mode) */
10
+ --bg-deep: #111113;
11
+ --bg-primary: #18181b;
12
+ --bg-secondary: #1f1f23;
13
+ --bg-elevated: #27272a;
14
+ --bg-card: #1f1f23;
15
+ --bg-hover: #292524;
16
+
17
+ --accent-primary: #d97706;
18
+ --accent-primary-light: #f59e0b;
19
+ --accent-primary-dark: #b45309;
20
+ --accent-glow: rgba(217, 119, 6, 0.4);
21
+
22
+ --accent-secondary: #059669;
23
+ --accent-secondary-light: #10b981;
24
+ --accent-secondary-glow: rgba(5, 150, 105, 0.35);
25
+
26
+ --accent-tertiary: #10b981;
27
+ --accent-tertiary-glow: rgba(16, 185, 129, 0.35);
28
+
29
+ --accent-success: #10b981;
30
+ --accent-warning: #f59e0b;
31
+ --accent-danger: #ef4444;
32
+
33
+ --text-primary: #fafaf9;
34
+ --text-secondary: #a8a29e;
35
+ --text-muted: #78716c;
36
+ --text-inverse: #111113;
37
+
38
+ --border: #292524;
39
+ --border-light: #44403c;
40
+
41
+ --gradient-primary: linear-gradient(135deg, #b45309 0%, #d97706 50%, #f59e0b 100%);
42
+ --gradient-glow: linear-gradient(135deg, rgba(180,83,9,0.25), rgba(217,119,6,0.25), rgba(245,158,11,0.25));
43
+
44
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.4);
45
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.5);
46
+ --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.6);
47
+ --shadow-glow: 0 0 40px var(--accent-glow);
48
+
49
+ --radius-sm: 8px;
50
+ --radius-md: 12px;
51
+ --radius-lg: 16px;
52
+ --radius-xl: 24px;
53
+ --radius-full: 9999px;
54
+
55
+ /* 2026 Professional Animation Timing */
56
+ --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
57
+ --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
58
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
59
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
60
+
61
+ --dur-micro: 150ms;
62
+ --dur-fast: 250ms;
63
+ --dur-normal: 350ms;
64
+ --dur-slow: 500ms;
65
+
66
+ --transition-micro: var(--dur-micro) var(--ease-out-quart);
67
+ --transition-fast: var(--dur-fast) var(--ease-out-expo);
68
+ --transition-normal: var(--dur-normal) var(--ease-out-expo);
69
+ --transition-slow: var(--dur-slow) var(--ease-out-expo);
70
+
71
+ /* 2026 Responsive: Fluid spacing scale */
72
+ --space-xs: clamp(0.5rem, 0.25rem + 0.5vw, 0.75rem);
73
+ --space-sm: clamp(0.75rem, 0.5rem + 0.75vw, 1.25rem);
74
+ --space-md: clamp(1.25rem, 0.75rem + 1.5vw, 2rem);
75
+ --space-lg: clamp(2rem, 1rem + 3vw, 4rem);
76
+
77
+ /* 2026 Responsive: Fluid typography */
78
+ --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
79
+ --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
80
+ --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
81
+ --text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.25rem);
82
+ --text-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
83
+ --text-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 2rem);
84
+
85
+ /* Touch target min */
86
+ --touch-min: 44px;
87
+ }
88
+
89
+ :root[data-theme="light"] {
90
+ /* Colors - Warm Copper & Forest Green (Light Mode) */
91
+ --bg-deep: #fafaf9;
92
+ --bg-primary: #f5f5f4;
93
+ --bg-secondary: #e7e5e4;
94
+ --bg-elevated: #d6d3d1;
95
+ --bg-card: #f5f5f4;
96
+ --bg-hover: #d6d3d1;
97
+
98
+ --accent-primary: #b45309;
99
+ --accent-primary-light: #d97706;
100
+ --accent-primary-dark: #92400e;
101
+ --accent-glow: rgba(180, 83, 9, 0.25);
102
+
103
+ --accent-secondary: #047857;
104
+ --accent-secondary-light: #059669;
105
+ --accent-secondary-glow: rgba(4, 120, 87, 0.2);
106
+
107
+ --accent-tertiary: #059669;
108
+ --accent-tertiary-glow: rgba(5, 150, 105, 0.2);
109
+
110
+ --accent-success: #059669;
111
+ --accent-warning: #d97706;
112
+ --accent-danger: #dc2626;
113
+
114
+ --text-primary: #1c1917;
115
+ --text-secondary: #44403c;
116
+ --text-muted: #a8a29e;
117
+ --text-inverse: #fafaf9;
118
+
119
+ --border: #d6d3d1;
120
+ --border-light: #a8a29e;
121
+
122
+ --gradient-primary: linear-gradient(135deg, #92400e 0%, #b45309 50%, #d97706 100%);
123
+ --gradient-glow: linear-gradient(135deg, rgba(146,64,14,0.15), rgba(180,83,9,0.15), rgba(217,119,6,0.15));
124
+
125
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
126
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.1);
127
+ --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12);
128
+ --shadow-glow: 0 0 40px var(--accent-glow);
129
+ }
130
+
131
+ /* Reset (scoped — no global * transition) */
132
+ * {
133
+ margin: 0;
134
+ padding: 0;
135
+ box-sizing: border-box;
136
+ }
137
+
138
+ html {
139
+ -webkit-text-size-adjust: 100%;
140
+ }
141
+
142
+ body {
143
+ font-family: 'Cairo', 'Outfit', -apple-system, BlinkMacSystemFont, sans-serif;
144
+ background: var(--bg-deep);
145
+ color: var(--text-primary);
146
+ height: 100dvh;
147
+ overflow: hidden;
148
+ line-height: 1.6;
149
+ font-size: var(--text-base);
150
+ padding-top: env(safe-area-inset-top);
151
+ padding-right: env(safe-area-inset-right);
152
+ padding-bottom: env(safe-area-inset-bottom);
153
+ padding-left: env(safe-area-inset-left);
154
+ }
155
+
156
+ /* Scoped transitions on interactive elements only */
157
+ .btn-primary,
158
+ .btn-secondary,
159
+ .icon-btn,
160
+ .model-card,
161
+ .agent-card,
162
+ .toast,
163
+ .modal-content,
164
+ .modal-overlay,
165
+ .toolbar button,
166
+ .input-area button,
167
+ .session-item,
168
+ .profile-btn,
169
+ .suggestion-card,
170
+ .model-nav-btn,
171
+ .copy-btn,
172
+ .agent-action-btn {
173
+ transition:
174
+ background-color var(--transition-micro),
175
+ color var(--transition-micro),
176
+ border-color var(--transition-micro),
177
+ box-shadow var(--transition-micro),
178
+ transform var(--transition-micro),
179
+ opacity var(--transition-micro);
180
+ }
181
+
182
+ /* App container */
183
+ .app-container {
184
+ display: flex;
185
+ height: 100dvh;
186
+ position: relative;
187
+ background:
188
+ radial-gradient(ellipse at 20% 0%, rgba(217, 119, 6, 0.12) 0%, transparent 50%),
189
+ radial-gradient(ellipse at 80% 100%, rgba(5, 150, 105, 0.08) 0%, transparent 50%),
190
+ radial-gradient(ellipse at 50% 80%, rgba(245, 158, 11, 0.05) 0%, transparent 40%),
191
+ var(--bg-deep);
192
+ animation: pageLoad 0.6s var(--ease-out-expo);
193
+ }
194
+
195
+ @keyframes pageLoad {
196
+ from { opacity: 0; }
197
+ to { opacity: 1; }
198
+ }
199
+
200
+ @keyframes fadeSlideUp {
201
+ from { opacity: 0; transform: translateY(20px); }
202
+ to { opacity: 1; transform: translateY(0); }
203
+ }
204
+
205
+ @keyframes scaleIn {
206
+ from { opacity: 0; transform: scale(0.9); }
207
+ to { opacity: 1; transform: scale(1); }
208
+ }
209
+
210
+ @keyframes modalSlide {
211
+ from { opacity: 0; transform: scale(0.95) translateY(20px); }
212
+ to { opacity: 1; transform: scale(1) translateY(0); }
213
+ }
214
+
215
+ /* ============================================================
216
+ Sidebar — drawer on mobile, fixed column on desktop
217
+ ============================================================ */
218
+ .sidebar {
219
+ position: fixed;
220
+ top: 0;
221
+ bottom: 0;
222
+ left: 0;
223
+ width: min(86vw, 320px);
224
+ background: var(--bg-secondary);
225
+ border-right: 1px solid var(--border);
226
+ display: flex;
227
+ flex-direction: column;
228
+ overflow: hidden;
229
+ z-index: 20;
230
+ box-shadow: var(--shadow-lg);
231
+ transform: translateX(-100%);
232
+ padding-top: env(safe-area-inset-top);
233
+ padding-left: env(safe-area-inset-left);
234
+ animation: fadeSlideUp 0.5s var(--ease-out-expo) 0.1s both;
235
+ }
236
+
237
+ .sidebar::after {
238
+ content: '';
239
+ position: absolute;
240
+ top: 0;
241
+ right: 0;
242
+ width: 1px;
243
+ height: 100%;
244
+ background: linear-gradient(180deg, var(--accent-primary), transparent 60%);
245
+ opacity: 0.4;
246
+ pointer-events: none;
247
+ }
248
+
249
+ .sidebar-header {
250
+ padding: var(--space-sm) var(--space-md);
251
+ display: flex;
252
+ justify-content: space-between;
253
+ align-items: center;
254
+ border-bottom: 1px solid var(--border);
255
+ background: linear-gradient(180deg, var(--bg-elevated) 0%, var(--bg-secondary) 100%);
256
+ animation: fadeSlideUp 0.4s var(--ease-out-expo) 0.2s both;
257
+ min-height: var(--touch-min);
258
+ }
259
+
260
+ .sidebar-header h2 {
261
+ font-size: var(--text-base);
262
+ font-weight: 700;
263
+ color: var(--text-primary);
264
+ display: flex;
265
+ align-items: center;
266
+ gap: 12px;
267
+ letter-spacing: -0.02em;
268
+ }
269
+
270
+ .sidebar-header h2 i {
271
+ color: var(--accent-primary-light);
272
+ filter: drop-shadow(0 0 8px var(--accent-glow));
273
+ }
274
+
275
+ .sidebar-header button {
276
+ background: none;
277
+ border: none;
278
+ color: var(--text-muted);
279
+ cursor: pointer;
280
+ padding: 10px;
281
+ min-width: var(--touch-min);
282
+ min-height: var(--touch-min);
283
+ border-radius: var(--radius-sm);
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ }
288
+
289
+ .sidebar-header button:hover {
290
+ color: var(--text-primary);
291
+ background: var(--bg-hover);
292
+ }
293
+
294
+ .sidebar-header button:active {
295
+ transform: scale(0.97);
296
+ background: var(--bg-elevated);
297
+ }
298
+
299
+ .sidebar-header button:hover i {
300
+ color: var(--accent-primary-light);
301
+ }
302
+
303
+ .session-list {
304
+ flex: 1;
305
+ overflow-y: auto;
306
+ padding: var(--space-xs);
307
+ scrollbar-width: thin;
308
+ scrollbar-color: var(--border) transparent;
309
+ }
310
+
311
+ .session-list::-webkit-scrollbar { width: 4px; }
312
+ .session-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
313
+
314
+ .session-item {
315
+ padding: 12px 14px;
316
+ border-radius: var(--radius-md);
317
+ cursor: pointer;
318
+ margin-bottom: 6px;
319
+ border: 1px solid transparent;
320
+ position: relative;
321
+ background: transparent;
322
+ opacity: 0;
323
+ animation: fadeSlideUp 0.4s var(--ease-out-expo) forwards;
324
+ min-height: var(--touch-min);
325
+ }
326
+
327
+ .session-item:nth-child(1) { animation-delay: 0.25s; }
328
+ .session-item:nth-child(2) { animation-delay: 0.3s; }
329
+ .session-item:nth-child(3) { animation-delay: 0.35s; }
330
+ .session-item:nth-child(4) { animation-delay: 0.4s; }
331
+ .session-item:nth-child(5) { animation-delay: 0.45s; }
332
+
333
+ .session-item:hover {
334
+ background: var(--bg-card);
335
+ border-color: var(--border);
336
+ }
337
+
338
+ .session-item:active {
339
+ transform: scale(0.99);
340
+ background: var(--bg-elevated);
341
+ }
342
+
343
+ .session-item.active {
344
+ background: linear-gradient(135deg, rgba(217, 119, 6, 0.12) 0%, rgba(245, 158, 11, 0.08) 100%);
345
+ border-color: var(--accent-primary-dark);
346
+ box-shadow: 0 0 25px rgba(217, 119, 6, 0.15), inset 0 0 20px rgba(217, 119, 6, 0.05);
347
+ }
348
+
349
+ .session-item.active::before {
350
+ content: '';
351
+ position: absolute;
352
+ top: 0;
353
+ left: 0;
354
+ width: 4px;
355
+ height: 100%;
356
+ background: var(--gradient-primary);
357
+ border-radius: var(--radius-md) 0 0 var(--radius-md);
358
+ }
359
+
360
+ .session-title {
361
+ font-size: var(--text-sm);
362
+ color: var(--text-primary);
363
+ font-weight: 600;
364
+ margin-bottom: 4px;
365
+ display: flex;
366
+ align-items: center;
367
+ gap: 10px;
368
+ letter-spacing: -0.01em;
369
+ }
370
+
371
+ .session-title .dot {
372
+ width: 8px;
373
+ height: 8px;
374
+ border-radius: 50%;
375
+ background: var(--accent-primary-light);
376
+ box-shadow: 0 0 12px var(--accent-glow);
377
+ flex-shrink: 0;
378
+ animation: pulse-glow 2.5s ease-in-out infinite;
379
+ }
380
+
381
+ @keyframes pulse-glow {
382
+ 0%, 100% { box-shadow: 0 0 8px var(--accent-glow); transform: scale(1); }
383
+ 50% { box-shadow: 0 0 20px var(--accent-glow), 0 0 30px var(--accent-glow); transform: scale(1.1); }
384
+ }
385
+
386
+ .session-meta {
387
+ font-size: 12px;
388
+ color: var(--text-muted);
389
+ display: flex;
390
+ align-items: center;
391
+ gap: 8px;
392
+ }
393
+
394
+ .session-meta i { width: 14px; height: 14px; opacity: 0.7; }
395
+
396
+ .sidebar-footer {
397
+ padding: var(--space-xs) var(--space-sm);
398
+ border-top: 1px solid var(--border);
399
+ margin-top: auto;
400
+ padding-bottom: max(var(--space-xs), env(safe-area-inset-bottom));
401
+ }
402
+
403
+ .profile-btn {
404
+ width: 100%;
405
+ padding: 12px 14px;
406
+ border: 1px solid var(--border);
407
+ border-radius: var(--radius-md);
408
+ background: var(--bg-card);
409
+ color: var(--text-primary);
410
+ font-size: var(--text-sm);
411
+ font-weight: 500;
412
+ cursor: pointer;
413
+ display: flex;
414
+ align-items: center;
415
+ gap: 10px;
416
+ min-height: var(--touch-min);
417
+ font-family: inherit;
418
+ }
419
+
420
+ .profile-btn:hover {
421
+ border-color: var(--accent-primary);
422
+ background: var(--bg-hover);
423
+ }
424
+
425
+ .profile-btn:active {
426
+ transform: scale(0.99);
427
+ background: var(--bg-elevated);
428
+ }
429
+
430
+ .profile-btn i { color: var(--accent-primary-light); }
431
+
432
+ .sidebar-overlay {
433
+ display: none;
434
+ position: fixed;
435
+ inset: 0;
436
+ background: rgba(0, 0, 0, 0.5);
437
+ z-index: 9;
438
+ }
439
+
440
+ .sidebar-overlay.show { display: block; }
441
+
442
+ /* ============================================================
443
+ Main panel
444
+ ============================================================ */
445
+ .main-panel {
446
+ flex: 1;
447
+ display: flex;
448
+ flex-direction: column;
449
+ min-width: 0;
450
+ position: relative;
451
+ width: 100%;
452
+ }
453
+
454
+ /* ============================================================
455
+ Header row
456
+ ============================================================ */
457
+ .header-row {
458
+ display: flex;
459
+ align-items: center;
460
+ gap: var(--space-xs);
461
+ padding: var(--space-xs) var(--space-sm);
462
+ background: var(--bg-secondary);
463
+ border-bottom: 1px solid var(--border);
464
+ flex-shrink: 0;
465
+ position: relative;
466
+ animation: fadeSlideUp 0.4s var(--ease-out-expo) 0.15s both;
467
+ min-height: var(--touch-min);
468
+ padding-top: max(var(--space-xs), env(safe-area-inset-top));
469
+ }
470
+
471
+ .header-row::after {
472
+ content: '';
473
+ position: absolute;
474
+ bottom: 0;
475
+ left: 0;
476
+ right: 0;
477
+ height: 1px;
478
+ background: linear-gradient(90deg, transparent, var(--accent-glow), transparent);
479
+ }
480
+
481
+ .icon-btn {
482
+ background: none;
483
+ border: none;
484
+ color: var(--text-secondary);
485
+ cursor: pointer;
486
+ padding: 10px;
487
+ min-width: var(--touch-min);
488
+ min-height: var(--touch-min);
489
+ border-radius: var(--radius-md);
490
+ display: flex;
491
+ align-items: center;
492
+ justify-content: center;
493
+ position: relative;
494
+ overflow: hidden;
495
+ }
496
+
497
+ .icon-btn::before {
498
+ content: '';
499
+ position: absolute;
500
+ inset: 0;
501
+ background: var(--gradient-primary);
502
+ opacity: 0;
503
+ border-radius: var(--radius-md);
504
+ }
505
+
506
+ .icon-btn:hover {
507
+ color: var(--text-primary);
508
+ background: var(--bg-card);
509
+ }
510
+
511
+ .icon-btn:hover i { color: var(--accent-primary-light); }
512
+ .icon-btn:active { transform: scale(0.97); background: var(--bg-elevated); }
513
+
514
+ .icon-btn i {
515
+ width: 20px;
516
+ height: 20px;
517
+ position: relative;
518
+ z-index: 1;
519
+ }
520
+
521
+ .status-indicator {
522
+ display: flex;
523
+ align-items: center;
524
+ gap: 8px;
525
+ }
526
+
527
+ .status-dot {
528
+ width: 10px;
529
+ height: 10px;
530
+ border-radius: 50%;
531
+ background: var(--accent-success);
532
+ box-shadow: 0 0 16px rgba(34, 197, 94, 0.5);
533
+ position: relative;
534
+ flex-shrink: 0;
535
+ }
536
+
537
+ .status-dot::after {
538
+ content: '';
539
+ position: absolute;
540
+ inset: -4px;
541
+ border-radius: 50%;
542
+ background: var(--accent-success);
543
+ opacity: 0;
544
+ animation: status-pulse 2s ease-out infinite;
545
+ }
546
+
547
+ @keyframes status-pulse {
548
+ 0% { transform: scale(1); opacity: 0.6; }
549
+ 100% { transform: scale(2); opacity: 0; }
550
+ }
551
+
552
+ .status-dot.typing {
553
+ background: var(--accent-primary-light);
554
+ box-shadow: 0 0 20px var(--accent-glow);
555
+ animation: typing-pulse 0.8s ease-in-out infinite;
556
+ }
557
+
558
+ @keyframes typing-pulse {
559
+ 0%, 100% { transform: scale(1); }
560
+ 50% { transform: scale(1.3); }
561
+ }
562
+
563
+ .status-dot.offline {
564
+ background: var(--text-muted);
565
+ box-shadow: none;
566
+ }
567
+
568
+ .status-dot.offline::after { display: none; }
569
+
570
+ .status-text {
571
+ font-size: var(--text-sm);
572
+ font-weight: 500;
573
+ color: var(--text-secondary);
574
+ }
575
+
576
+ .header-right {
577
+ margin-left: auto;
578
+ display: flex;
579
+ align-items: center;
580
+ gap: 8px;
581
+ min-width: 0;
582
+ }
583
+
584
+ .model-badge,
585
+ .mode-badge {
586
+ font-size: 11px;
587
+ font-weight: 500;
588
+ padding: 5px 10px;
589
+ border-radius: var(--radius-full);
590
+ display: flex;
591
+ align-items: center;
592
+ gap: 6px;
593
+ letter-spacing: 0.3px;
594
+ white-space: nowrap;
595
+ }
596
+
597
+ .model-badge {
598
+ background: var(--bg-elevated);
599
+ color: var(--text-secondary);
600
+ border: 1px solid var(--border);
601
+ }
602
+
603
+ .model-badge:hover {
604
+ border-color: var(--accent-primary);
605
+ color: var(--text-primary);
606
+ box-shadow: 0 0 12px var(--accent-glow);
607
+ }
608
+
609
+ .model-badge i { width: 12px; height: 12px; }
610
+
611
+ .mode-badge {
612
+ font-weight: 700;
613
+ background: var(--gradient-primary);
614
+ color: white;
615
+ text-transform: uppercase;
616
+ letter-spacing: 0.8px;
617
+ box-shadow: 0 0 30px var(--accent-glow);
618
+ animation: badge-shimmer 3s ease-in-out infinite;
619
+ }
620
+
621
+ @keyframes badge-shimmer {
622
+ 0%, 100% { box-shadow: 0 0 20px var(--accent-glow); }
623
+ 50% { box-shadow: 0 0 40px var(--accent-glow), 0 0 60px var(--accent-glow); }
624
+ }
625
+
626
+ .mode-badge i { width: 14px; height: 14px; }
627
+
628
+ /* Hide status text on very narrow screens, keep the dot */
629
+ @media (max-width: 479px) {
630
+ .status-text { display: none; }
631
+ .mode-badge { display: none; }
632
+ }
633
+
634
+ /* ============================================================
635
+ Chat area
636
+ ============================================================ */
637
+ .chat-area {
638
+ flex: 1;
639
+ overflow-y: auto;
640
+ padding: var(--space-sm);
641
+ display: flex;
642
+ flex-direction: column;
643
+ gap: var(--space-xs);
644
+ scrollbar-width: thin;
645
+ scrollbar-color: var(--border) transparent;
646
+ position: relative;
647
+ min-height: 0;
648
+ }
649
+
650
+ .chat-area::before {
651
+ content: '';
652
+ position: absolute;
653
+ top: 0;
654
+ left: 50%;
655
+ transform: translateX(-50%);
656
+ width: min(400px, 80%);
657
+ height: 400px;
658
+ background: radial-gradient(circle, var(--gradient-glow) 0%, transparent 70%);
659
+ pointer-events: none;
660
+ }
661
+
662
+ .chat-area::-webkit-scrollbar { width: 6px; }
663
+ .chat-area::-webkit-scrollbar-thumb { background: var(--border); border-radius: 6px; }
664
+
665
+ /* ============================================================
666
+ Empty state — Copper Atelier hero
667
+ ============================================================ */
668
+ .chat-area .empty {
669
+ margin: auto;
670
+ text-align: center;
671
+ color: var(--text-muted);
672
+ display: flex;
673
+ flex-direction: column;
674
+ align-items: center;
675
+ gap: var(--space-sm);
676
+ width: 100%;
677
+ max-width: 560px;
678
+ padding: var(--space-md) var(--space-sm);
679
+ animation: fadeSlideUp 0.5s var(--ease-out-expo);
680
+ }
681
+
682
+ .empty-wordmark {
683
+ font-family: 'DM Serif Display', 'Cairo', serif;
684
+ font-weight: 400;
685
+ font-size: clamp(1.75rem, 1.2rem + 2.5vw, 2.75rem);
686
+ line-height: 1.15;
687
+ color: var(--text-primary);
688
+ letter-spacing: -0.02em;
689
+ position: relative;
690
+ display: inline-block;
691
+ padding-bottom: 0.4em;
692
+ opacity: 0;
693
+ animation: empty-rise 0.6s var(--ease-out-expo) 0.05s both;
694
+ }
695
+
696
+ .empty-wordmark::after {
697
+ content: '';
698
+ position: absolute;
699
+ left: 18%;
700
+ right: 18%;
701
+ bottom: 0;
702
+ height: 3px;
703
+ border-radius: var(--radius-full);
704
+ background: var(--gradient-primary);
705
+ box-shadow: 0 0 18px var(--accent-glow);
706
+ }
707
+
708
+ .empty-wordmark-accent {
709
+ background: var(--gradient-primary);
710
+ -webkit-background-clip: text;
711
+ background-clip: text;
712
+ color: transparent;
713
+ font-style: italic;
714
+ }
715
+
716
+ .empty-divider {
717
+ width: 100%;
718
+ max-width: 280px;
719
+ height: 14px;
720
+ --kufic-size: 14px;
721
+ background:
722
+ repeating-linear-gradient(
723
+ 90deg,
724
+ var(--accent-primary) 0 calc(var(--kufic-size) * 0.35),
725
+ transparent calc(var(--kufic-size) * 0.35) calc(var(--kufic-size) * 0.7),
726
+ var(--accent-primary) calc(var(--kufic-size) * 0.7) var(--kufic-size)
727
+ );
728
+ -webkit-mask: linear-gradient(180deg, transparent 0%, #000 25%, #000 75%, transparent 100%);
729
+ mask: linear-gradient(180deg, transparent 0%, #000 25%, #000 75%, transparent 100%);
730
+ opacity: 0.55;
731
+ animation: empty-rise 0.6s var(--ease-out-expo) 0.15s both;
732
+ }
733
+
734
+ .empty-sub {
735
+ font-size: var(--text-base);
736
+ color: var(--text-secondary);
737
+ margin: 0;
738
+ font-weight: 500;
739
+ animation: empty-rise 0.6s var(--ease-out-expo) 0.25s both;
740
+ }
741
+
742
+ .empty-suggestions {
743
+ display: grid;
744
+ grid-template-columns: 1fr;
745
+ gap: var(--space-xs);
746
+ width: 100%;
747
+ margin-top: var(--space-xs);
748
+ }
749
+
750
+ .suggestion-card {
751
+ display: flex;
752
+ align-items: center;
753
+ gap: 14px;
754
+ padding: 14px 16px;
755
+ background: var(--bg-card);
756
+ border: 1px solid var(--border);
757
+ border-radius: var(--radius-md);
758
+ color: var(--text-primary);
759
+ font-family: inherit;
760
+ font-size: var(--text-sm);
761
+ cursor: pointer;
762
+ text-align: left;
763
+ min-height: var(--touch-min);
764
+ position: relative;
765
+ overflow: hidden;
766
+ }
767
+
768
+ .suggestion-card::before {
769
+ content: '';
770
+ position: absolute;
771
+ inset: 0;
772
+ background: var(--gradient-glow);
773
+ opacity: 0;
774
+ pointer-events: none;
775
+ }
776
+
777
+ .suggestion-card:hover {
778
+ border-color: var(--accent-primary-dark);
779
+ background: var(--bg-elevated);
780
+ transform: translateY(-1px);
781
+ box-shadow: 0 6px 18px rgba(217, 119, 6, 0.18);
782
+ }
783
+
784
+ .suggestion-card:hover::before { opacity: 1; }
785
+ .suggestion-card:active { transform: scale(0.99); }
786
+
787
+ .suggestion-card:nth-child(1) { animation: empty-rise 0.5s var(--ease-out-expo) 0.35s both; }
788
+ .suggestion-card:nth-child(2) { animation: empty-rise 0.5s var(--ease-out-expo) 0.45s both; }
789
+ .suggestion-card:nth-child(3) { animation: empty-rise 0.5s var(--ease-out-expo) 0.55s both; }
790
+
791
+ .suggestion-icon {
792
+ width: 38px;
793
+ height: 38px;
794
+ border-radius: var(--radius-sm);
795
+ background: var(--bg-elevated);
796
+ display: flex;
797
+ align-items: center;
798
+ justify-content: center;
799
+ flex-shrink: 0;
800
+ color: var(--accent-primary-light);
801
+ }
802
+
803
+ .suggestion-icon i {
804
+ width: 18px;
805
+ height: 18px;
806
+ }
807
+
808
+ .suggestion-body {
809
+ display: flex;
810
+ flex-direction: column;
811
+ gap: 2px;
812
+ min-width: 0;
813
+ }
814
+
815
+ .suggestion-title {
816
+ font-weight: 600;
817
+ font-size: var(--text-sm);
818
+ color: var(--text-primary);
819
+ line-height: 1.3;
820
+ }
821
+
822
+ .suggestion-desc {
823
+ font-size: 12px;
824
+ color: var(--text-muted);
825
+ line-height: 1.4;
826
+ }
827
+
828
+ @keyframes empty-rise {
829
+ from { opacity: 0; transform: translateY(12px); }
830
+ to { opacity: 1; transform: translateY(0); }
831
+ }
832
+
833
+ /* ============================================================
834
+ Messages
835
+ ============================================================ */
836
+ .msg {
837
+ max-width: 92%;
838
+ padding: 12px 16px;
839
+ border-radius: var(--radius-lg);
840
+ line-height: 1.65;
841
+ font-size: var(--text-sm);
842
+ font-weight: 400;
843
+ word-wrap: break-word;
844
+ animation: message-appear 0.4s var(--ease-spring);
845
+ position: relative;
846
+ }
847
+
848
+ @keyframes message-appear {
849
+ from { opacity: 0; transform: translateY(16px) scale(0.96); }
850
+ to { opacity: 1; transform: translateY(0) scale(1); }
851
+ }
852
+
853
+ .msg.user {
854
+ align-self: flex-end;
855
+ background: var(--gradient-primary);
856
+ color: white;
857
+ border-bottom-left-radius: 4px;
858
+ box-shadow: var(--shadow-md), 0 0 35px var(--accent-glow),
859
+ inset 0 0 0 1px rgba(245, 158, 11, 0.4);
860
+ }
861
+
862
+ .msg.user:hover { transform: scale(1.01) translateY(-1px); }
863
+
864
+ .msg.bmo {
865
+ align-self: flex-start;
866
+ background: var(--bg-card);
867
+ border: 1px solid var(--border);
868
+ border-top: 1px solid var(--accent-secondary);
869
+ border-bottom-right-radius: 4px;
870
+ color: var(--text-primary);
871
+ }
872
+
873
+ .msg.bmo::before {
874
+ content: '';
875
+ position: absolute;
876
+ bottom: 0;
877
+ right: 0;
878
+ width: 20px;
879
+ height: 20px;
880
+ background: linear-gradient(225deg, transparent 50%, var(--bg-card) 50%);
881
+ border-radius: 0 0 16px 0;
882
+ }
883
+
884
+ .msg .time {
885
+ font-size: 11px;
886
+ font-weight: 400;
887
+ color: inherit;
888
+ opacity: 0.4;
889
+ margin-top: 8px;
890
+ text-align: right;
891
+ direction: ltr;
892
+ font-family: 'JetBrains Mono', monospace;
893
+ }
894
+
895
+ .msg.bmo .time { text-align: left; }
896
+
897
+ /* ============================================================
898
+ Thinking + Code blocks
899
+ ============================================================ */
900
+ .thinking-block {
901
+ margin-bottom: 12px;
902
+ border: 1px solid var(--border);
903
+ border-radius: var(--radius-md);
904
+ background: var(--bg-deep);
905
+ overflow: hidden;
906
+ }
907
+
908
+ .thinking-block summary {
909
+ padding: 10px 14px;
910
+ cursor: pointer;
911
+ font-size: 13px;
912
+ font-weight: 600;
913
+ color: var(--text-muted);
914
+ display: flex;
915
+ align-items: center;
916
+ gap: 8px;
917
+ user-select: none;
918
+ list-style: none;
919
+ min-height: var(--touch-min);
920
+ }
921
+
922
+ .thinking-block summary::-webkit-details-marker { display: none; }
923
+
924
+ .thinking-block summary::before {
925
+ content: '';
926
+ display: inline-block;
927
+ width: 16px;
928
+ height: 16px;
929
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2378716c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'%3E%3C/polyline%3E%3C/svg%3E");
930
+ background-size: contain;
931
+ background-repeat: no-repeat;
932
+ flex-shrink: 0;
933
+ }
934
+
935
+ .thinking-block[open] summary::before { transform: rotate(90deg); }
936
+
937
+ .thinking-block summary:hover {
938
+ background: var(--bg-hover);
939
+ color: var(--text-secondary);
940
+ }
941
+
942
+ .thinking-content {
943
+ padding: 12px 14px;
944
+ font-size: 13px;
945
+ color: var(--text-muted);
946
+ line-height: 1.7;
947
+ border-top: 1px solid var(--border);
948
+ font-style: italic;
949
+ }
950
+
951
+ .code-block {
952
+ background: var(--bg-deep);
953
+ border: 1px solid var(--border);
954
+ border-radius: var(--radius-md);
955
+ padding: 14px;
956
+ margin: 10px 0;
957
+ font-family: 'JetBrains Mono', monospace;
958
+ font-size: 13px;
959
+ overflow-x: auto;
960
+ direction: ltr;
961
+ text-align: left;
962
+ position: relative;
963
+ border-left: 3px solid var(--accent-primary);
964
+ }
965
+
966
+ .code-block code { color: var(--accent-tertiary); }
967
+
968
+ /* ============================================================
969
+ Toolbar
970
+ ============================================================ */
971
+ .toolbar {
972
+ display: flex;
973
+ flex-wrap: wrap;
974
+ gap: 8px;
975
+ padding: 10px var(--space-sm);
976
+ background: var(--bg-secondary);
977
+ border-top: 1px solid var(--border);
978
+ flex-shrink: 0;
979
+ position: relative;
980
+ animation: fadeSlideUp 0.4s var(--ease-out-expo) 0.3s both;
981
+ }
982
+
983
+ .toolbar::before {
984
+ content: '';
985
+ position: absolute;
986
+ top: 0;
987
+ left: 0;
988
+ right: 0;
989
+ height: 1px;
990
+ background: linear-gradient(90deg, transparent, var(--border-light), transparent);
991
+ }
992
+
993
+ .toolbar button {
994
+ padding: 8px 12px;
995
+ border-radius: var(--radius-md);
996
+ border: 1px solid var(--border);
997
+ background: var(--bg-card);
998
+ color: var(--text-primary);
999
+ font-size: 12px;
1000
+ font-weight: 500;
1001
+ cursor: pointer;
1002
+ white-space: nowrap;
1003
+ font-family: inherit;
1004
+ display: flex;
1005
+ align-items: center;
1006
+ gap: 6px;
1007
+ position: relative;
1008
+ overflow: hidden;
1009
+ min-height: var(--touch-min);
1010
+ flex: 1 1 auto;
1011
+ justify-content: center;
1012
+ }
1013
+
1014
+ .toolbar button::before {
1015
+ content: '';
1016
+ position: absolute;
1017
+ inset: 0;
1018
+ background: var(--gradient-glow);
1019
+ opacity: 0;
1020
+ pointer-events: none;
1021
+ }
1022
+
1023
+ .toolbar button i {
1024
+ width: 14px;
1025
+ height: 14px;
1026
+ color: var(--text-muted);
1027
+ position: relative;
1028
+ z-index: 1;
1029
+ }
1030
+
1031
+ .toolbar button:hover {
1032
+ border-color: var(--accent-primary-dark);
1033
+ color: var(--accent-primary-light);
1034
+ box-shadow: 0 6px 18px rgba(217, 119, 6, 0.18);
1035
+ }
1036
+
1037
+ .toolbar button:hover::before { opacity: 1; }
1038
+ .toolbar button:hover i { color: var(--accent-primary-light); }
1039
+ .toolbar button:active { transform: scale(0.97); }
1040
+
1041
+ /* ============================================================
1042
+ Input area
1043
+ ============================================================ */
1044
+ .input-area {
1045
+ padding: 10px var(--space-sm);
1046
+ padding-bottom: max(12px, env(safe-area-inset-bottom));
1047
+ background: var(--bg-secondary);
1048
+ border-top: 1px solid var(--border);
1049
+ display: flex;
1050
+ gap: 10px;
1051
+ flex-shrink: 0;
1052
+ position: relative;
1053
+ animation: fadeSlideUp 0.4s var(--ease-out-expo) 0.35s both;
1054
+ }
1055
+
1056
+ .input-area::before {
1057
+ content: '';
1058
+ position: absolute;
1059
+ top: 0;
1060
+ left: 0;
1061
+ right: 0;
1062
+ height: 2px;
1063
+ background: var(--gradient-primary);
1064
+ opacity: 0.4;
1065
+ }
1066
+
1067
+ .input-area input {
1068
+ flex: 1;
1069
+ min-width: 0;
1070
+ padding: 12px 16px;
1071
+ border-radius: var(--radius-xl);
1072
+ border: 2px solid var(--border);
1073
+ background: var(--bg-primary);
1074
+ color: var(--text-primary);
1075
+ font-family: inherit;
1076
+ font-size: var(--text-base);
1077
+ font-weight: 400;
1078
+ outline: none;
1079
+ }
1080
+
1081
+ .input-area input:focus {
1082
+ border-color: var(--accent-primary);
1083
+ box-shadow: 0 0 0 4px rgba(217, 119, 6, 0.15), var(--shadow-md);
1084
+ background: var(--bg-card);
1085
+ }
1086
+
1087
+ .input-area input::placeholder { color: var(--text-muted); }
1088
+
1089
+ .input-area button {
1090
+ width: var(--touch-min);
1091
+ height: var(--touch-min);
1092
+ border-radius: var(--radius-xl);
1093
+ border: none;
1094
+ background: var(--gradient-primary);
1095
+ color: white;
1096
+ cursor: pointer;
1097
+ display: flex;
1098
+ align-items: center;
1099
+ justify-content: center;
1100
+ flex-shrink: 0;
1101
+ position: relative;
1102
+ overflow: hidden;
1103
+ box-shadow: var(--shadow-glow);
1104
+ }
1105
+
1106
+ .input-area button::before {
1107
+ content: '';
1108
+ position: absolute;
1109
+ top: 0;
1110
+ left: -100%;
1111
+ width: 100%;
1112
+ height: 100%;
1113
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.25), transparent);
1114
+ pointer-events: none;
1115
+ }
1116
+
1117
+ .input-area button:hover {
1118
+ box-shadow: 0 0 50px var(--accent-glow), 0 8px 30px rgba(217, 119, 6, 0.35);
1119
+ }
1120
+
1121
+ .input-area button:hover::before { left: 100%; }
1122
+ .input-area button:active { transform: scale(0.96); }
1123
+ .input-area button:disabled {
1124
+ opacity: 0.35;
1125
+ cursor: not-allowed;
1126
+ box-shadow: none;
1127
+ background: var(--border);
1128
+ }
1129
+ .input-area button:disabled::before { display: none; }
1130
+
1131
+ .input-area button i {
1132
+ width: 20px;
1133
+ height: 20px;
1134
+ }
1135
+
1136
+ .input-area button:hover:not(:disabled) i { transform: translateX(2px); }
1137
+
1138
+ /* ============================================================
1139
+ Typing indicator
1140
+ ============================================================ */
1141
+ .typing-indicator {
1142
+ align-self: flex-start;
1143
+ display: none;
1144
+ background: var(--bg-card);
1145
+ border: 1px solid var(--border);
1146
+ padding: 12px 22px;
1147
+ border-radius: var(--radius-lg);
1148
+ border-bottom-right-radius: 4px;
1149
+ margin: 0 var(--space-sm);
1150
+ position: relative;
1151
+ }
1152
+
1153
+ .typing-indicator.show {
1154
+ display: flex;
1155
+ gap: 6px;
1156
+ align-items: center;
1157
+ margin-bottom: 12px;
1158
+ animation: message-appear 0.2s var(--ease-out-expo);
1159
+ }
1160
+
1161
+ .typing-indicator span {
1162
+ width: 8px;
1163
+ height: 8px;
1164
+ background: var(--accent-primary-light);
1165
+ border-radius: 50%;
1166
+ animation: typing-dot 1.4s infinite ease-in-out;
1167
+ }
1168
+
1169
+ .typing-indicator span:nth-child(1) { animation-delay: 0s; }
1170
+ .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
1171
+ .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
1172
+
1173
+ @keyframes typing-dot {
1174
+ 0%, 80%, 100% { transform: translateY(0); }
1175
+ 40% { transform: translateY(-12px); }
1176
+ }
1177
+
1178
+ .reasoning-live {
1179
+ animation: reasoning-pulse 2s ease-in-out infinite;
1180
+ }
1181
+
1182
+ @keyframes reasoning-pulse {
1183
+ 0%, 100% { border-color: var(--border); }
1184
+ 50% { border-color: var(--accent-primary-dark); box-shadow: 0 0 20px var(--accent-glow); }
1185
+ }
1186
+
1187
+ /* ============================================================
1188
+ Connection banner
1189
+ ============================================================ */
1190
+ #connBanner {
1191
+ display: none;
1192
+ position: fixed;
1193
+ top: 0;
1194
+ left: 0;
1195
+ right: 0;
1196
+ background: linear-gradient(90deg, var(--accent-danger), #ff6b6b);
1197
+ color: white;
1198
+ text-align: center;
1199
+ padding: 12px;
1200
+ font-size: 14px;
1201
+ font-weight: 600;
1202
+ z-index: 100;
1203
+ box-shadow: var(--shadow-lg);
1204
+ align-items: center;
1205
+ justify-content: center;
1206
+ gap: 10px;
1207
+ padding-top: max(12px, env(safe-area-inset-top));
1208
+ }
1209
+
1210
+ #connBanner.show {
1211
+ display: flex;
1212
+ animation: slideDown 0.3s var(--ease-out-expo);
1213
+ }
1214
+
1215
+ #connBanner i { width: 18px; height: 18px; }
1216
+
1217
+ @keyframes slideDown {
1218
+ from { transform: translateY(-100%); }
1219
+ to { transform: translateY(0); }
1220
+ }
1221
+
1222
+ /* ============================================================
1223
+ Modals — bottom sheet on mobile, centered on tablet+
1224
+ ============================================================ */
1225
+ .modal-overlay {
1226
+ display: none;
1227
+ position: fixed;
1228
+ inset: 0;
1229
+ background: rgba(0, 0, 0, 0.7);
1230
+ backdrop-filter: blur(4px);
1231
+ -webkit-backdrop-filter: blur(4px);
1232
+ z-index: 1000;
1233
+ align-items: flex-end;
1234
+ justify-content: center;
1235
+ padding: 0;
1236
+ }
1237
+
1238
+ .modal-overlay.show {
1239
+ display: flex;
1240
+ animation: fadeIn 0.2s var(--ease-out-expo);
1241
+ }
1242
+
1243
+ @keyframes fadeIn {
1244
+ from { opacity: 0; }
1245
+ to { opacity: 1; }
1246
+ }
1247
+
1248
+ .modal-content {
1249
+ background: var(--bg-secondary);
1250
+ border: 1px solid var(--border);
1251
+ border-top-left-radius: var(--radius-xl);
1252
+ border-top-right-radius: var(--radius-xl);
1253
+ border-bottom-left-radius: 0;
1254
+ border-bottom-right-radius: 0;
1255
+ width: 100%;
1256
+ max-width: 100%;
1257
+ max-height: 85vh;
1258
+ overflow: hidden;
1259
+ display: flex;
1260
+ flex-direction: column;
1261
+ animation: bottomSheet 0.35s var(--ease-spring);
1262
+ box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.5), 0 0 60px rgba(217, 119, 6, 0.2);
1263
+ padding-bottom: env(safe-area-inset-bottom);
1264
+ }
1265
+
1266
+ @keyframes bottomSheet {
1267
+ from { transform: translateY(100%); opacity: 0.6; }
1268
+ to { transform: translateY(0); opacity: 1; }
1269
+ }
1270
+
1271
+ .modal-header {
1272
+ display: flex;
1273
+ align-items: center;
1274
+ justify-content: space-between;
1275
+ padding: 16px 18px;
1276
+ border-bottom: 1px solid var(--border);
1277
+ background: var(--bg-elevated);
1278
+ flex-shrink: 0;
1279
+ }
1280
+
1281
+ .modal-header h3 {
1282
+ font-size: var(--text-base);
1283
+ font-weight: 700;
1284
+ display: flex;
1285
+ align-items: center;
1286
+ gap: 10px;
1287
+ letter-spacing: -0.02em;
1288
+ }
1289
+
1290
+ .modal-header h3 i { color: var(--accent-primary-light); }
1291
+
1292
+ .modal-close {
1293
+ background: none;
1294
+ border: none;
1295
+ color: var(--text-muted);
1296
+ cursor: pointer;
1297
+ padding: 8px;
1298
+ min-width: var(--touch-min);
1299
+ min-height: var(--touch-min);
1300
+ border-radius: var(--radius-sm);
1301
+ display: flex;
1302
+ align-items: center;
1303
+ justify-content: center;
1304
+ }
1305
+
1306
+ .modal-close:hover {
1307
+ color: var(--text-primary);
1308
+ background: var(--bg-hover);
1309
+ }
1310
+
1311
+ .modal-close:active { transform: scale(0.95); background: var(--bg-elevated); }
1312
+
1313
+ .modal-body {
1314
+ padding: 16px;
1315
+ overflow-y: auto;
1316
+ flex: 1;
1317
+ }
1318
+
1319
+ .modal-loading {
1320
+ display: flex;
1321
+ align-items: center;
1322
+ justify-content: center;
1323
+ gap: 12px;
1324
+ padding: 40px;
1325
+ color: var(--text-muted);
1326
+ }
1327
+
1328
+ .spin { animation: spin 1s linear infinite; }
1329
+ @keyframes spin { to { transform: rotate(360deg); } }
1330
+
1331
+ .inline-icon {
1332
+ width: 14px;
1333
+ height: 14px;
1334
+ vertical-align: -2px;
1335
+ display: inline-block;
1336
+ }
1337
+
1338
+ .model-providers { display: flex; flex-direction: column; gap: 20px; }
1339
+ .provider-section { }
1340
+ .provider-name {
1341
+ font-size: 14px;
1342
+ font-weight: 600;
1343
+ color: var(--text-secondary);
1344
+ margin-bottom: 12px;
1345
+ text-transform: uppercase;
1346
+ letter-spacing: 0.5px;
1347
+ }
1348
+
1349
+ .modal-empty {
1350
+ text-align: center;
1351
+ padding: 40px;
1352
+ color: var(--text-muted);
1353
+ }
1354
+ .modal-empty i { width: 48px; height: 48px; margin-bottom: 12px; opacity: 0.5; }
1355
+
1356
+ .tab-content { display: none; }
1357
+ .tab-content.active {
1358
+ display: block;
1359
+ animation: fadeSlideUp 0.3s var(--ease-out-expo);
1360
+ }
1361
+
1362
+ /* ============================================================
1363
+ Model selection
1364
+ ============================================================ */
1365
+ .model-grid {
1366
+ display: grid;
1367
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
1368
+ gap: 12px;
1369
+ }
1370
+
1371
+ .model-card {
1372
+ padding: 16px;
1373
+ border: 2px solid var(--border);
1374
+ border-radius: var(--radius-md);
1375
+ cursor: pointer;
1376
+ text-align: center;
1377
+ position: relative;
1378
+ overflow: hidden;
1379
+ min-height: var(--touch-min);
1380
+ }
1381
+
1382
+ .model-card::before {
1383
+ content: '';
1384
+ position: absolute;
1385
+ inset: 0;
1386
+ background: var(--gradient-glow);
1387
+ opacity: 0;
1388
+ pointer-events: none;
1389
+ }
1390
+
1391
+ .model-card:hover {
1392
+ border-color: var(--accent-primary-dark);
1393
+ transform: translateY(-2px);
1394
+ }
1395
+
1396
+ .model-card:hover::before { opacity: 1; }
1397
+ .model-card:active { transform: scale(0.99); }
1398
+
1399
+ .model-card.selected {
1400
+ border-color: var(--accent-primary);
1401
+ background: linear-gradient(135deg, rgba(217, 119, 6, 0.15) 0%, rgba(245, 158, 11, 0.1) 100%);
1402
+ box-shadow: 0 0 20px var(--accent-glow);
1403
+ }
1404
+
1405
+ .model-card.selected::after {
1406
+ content: '';
1407
+ position: absolute;
1408
+ top: 8px;
1409
+ right: 8px;
1410
+ width: 20px;
1411
+ height: 20px;
1412
+ background: var(--accent-success);
1413
+ border-radius: 50%;
1414
+ }
1415
+
1416
+ .model-card .model-name {
1417
+ font-size: 13px;
1418
+ font-weight: 600;
1419
+ color: var(--text-primary);
1420
+ margin-bottom: 4px;
1421
+ }
1422
+ .model-card .model-provider {
1423
+ font-size: 11px;
1424
+ color: var(--text-muted);
1425
+ }
1426
+
1427
+ .model-badge {
1428
+ position: absolute;
1429
+ top: 8px;
1430
+ left: 8px;
1431
+ padding: 2px 8px;
1432
+ border-radius: var(--radius-full);
1433
+ font-size: 10px;
1434
+ font-weight: 600;
1435
+ text-transform: uppercase;
1436
+ letter-spacing: 0.5px;
1437
+ }
1438
+
1439
+ .model-badge.free {
1440
+ background: var(--accent-success);
1441
+ color: white;
1442
+ }
1443
+
1444
+ .model-more {
1445
+ grid-column: 1 / -1;
1446
+ text-align: center;
1447
+ padding: 12px;
1448
+ color: var(--accent-primary);
1449
+ cursor: pointer;
1450
+ font-size: 13px;
1451
+ font-weight: 500;
1452
+ border: 1px dashed var(--border);
1453
+ border-radius: var(--radius-md);
1454
+ min-height: var(--touch-min);
1455
+ }
1456
+
1457
+ .model-more:hover {
1458
+ background: var(--bg-hover);
1459
+ border-color: var(--accent-primary);
1460
+ }
1461
+
1462
+ .model-header-bar {
1463
+ display: flex;
1464
+ flex-direction: column;
1465
+ gap: 6px;
1466
+ padding: 16px 20px;
1467
+ background: var(--bg-elevated);
1468
+ border-bottom: 1px solid var(--border);
1469
+ margin: -20px -20px 16px -20px;
1470
+ }
1471
+
1472
+ .model-page-title {
1473
+ font-size: 16px;
1474
+ font-weight: 700;
1475
+ color: var(--text-primary);
1476
+ }
1477
+
1478
+ .model-page-info {
1479
+ font-size: 12px;
1480
+ color: var(--text-muted);
1481
+ }
1482
+
1483
+ .model-pagination,
1484
+ .model-provider-nav {
1485
+ display: flex;
1486
+ gap: 10px;
1487
+ margin-top: 16px;
1488
+ justify-content: center;
1489
+ }
1490
+
1491
+ .model-nav-btn {
1492
+ padding: 10px 18px;
1493
+ border: 1px solid var(--border);
1494
+ border-radius: var(--radius-md);
1495
+ background: var(--bg-card);
1496
+ color: var(--text-primary);
1497
+ cursor: pointer;
1498
+ font-size: 13px;
1499
+ font-weight: 500;
1500
+ display: flex;
1501
+ align-items: center;
1502
+ gap: 6px;
1503
+ min-height: var(--touch-min);
1504
+ font-family: inherit;
1505
+ }
1506
+
1507
+ .model-nav-btn:hover {
1508
+ border-color: var(--accent-primary);
1509
+ background: var(--bg-hover);
1510
+ }
1511
+
1512
+ .model-nav-btn:active { transform: scale(0.98); }
1513
+
1514
+ .model-nav-btn.secondary { background: var(--bg-elevated); }
1515
+
1516
+ .model-nav-btn i { width: 16px; height: 16px; }
1517
+
1518
+ /* ============================================================
1519
+ Agent cards
1520
+ ============================================================ */
1521
+ .agent-progress {
1522
+ margin: 16px 0;
1523
+ padding: 16px;
1524
+ background: var(--bg-elevated);
1525
+ border-radius: var(--radius-md);
1526
+ border: 1px solid var(--border);
1527
+ }
1528
+
1529
+ .progress-bar-container {
1530
+ width: 100%;
1531
+ height: 8px;
1532
+ background: var(--bg-deep);
1533
+ border-radius: var(--radius-full);
1534
+ overflow: hidden;
1535
+ margin-bottom: 10px;
1536
+ }
1537
+
1538
+ .progress-bar {
1539
+ height: 100%;
1540
+ width: 0%;
1541
+ background: var(--gradient-primary);
1542
+ border-radius: var(--radius-full);
1543
+ transition: width 0.4s var(--ease-out-expo);
1544
+ }
1545
+
1546
+ .agent-progress p {
1547
+ font-size: 13px;
1548
+ color: var(--text-secondary);
1549
+ margin: 0;
1550
+ text-align: center;
1551
+ }
1552
+
1553
+ .agent-list {
1554
+ display: flex;
1555
+ flex-direction: column;
1556
+ gap: 12px;
1557
+ }
1558
+
1559
+ .agent-card {
1560
+ padding: 16px;
1561
+ border: 1px solid var(--border);
1562
+ border-radius: var(--radius-md);
1563
+ background: var(--bg-card);
1564
+ cursor: pointer;
1565
+ min-height: var(--touch-min);
1566
+ }
1567
+
1568
+ .agent-card:hover {
1569
+ border-color: var(--accent-primary-dark);
1570
+ transform: translateX(2px);
1571
+ }
1572
+
1573
+ .agent-card:active { transform: scale(0.99); }
1574
+
1575
+ .agent-card.active {
1576
+ border-color: var(--accent-primary);
1577
+ background: linear-gradient(135deg, rgba(217, 119, 6, 0.1) 0%, transparent 100%);
1578
+ }
1579
+
1580
+ .agent-name {
1581
+ font-size: 15px;
1582
+ font-weight: 600;
1583
+ color: var(--text-primary);
1584
+ display: flex;
1585
+ align-items: center;
1586
+ gap: 10px;
1587
+ margin-bottom: 6px;
1588
+ }
1589
+
1590
+ .agent-name i { color: var(--accent-secondary-light); }
1591
+
1592
+ .agent-desc {
1593
+ font-size: 13px;
1594
+ color: var(--text-muted);
1595
+ line-height: 1.5;
1596
+ }
1597
+
1598
+ .agent-actions {
1599
+ display: flex;
1600
+ gap: 8px;
1601
+ margin-top: 12px;
1602
+ padding-top: 12px;
1603
+ border-top: 1px solid var(--border);
1604
+ }
1605
+
1606
+ .agent-action-btn {
1607
+ flex: 1;
1608
+ padding: 8px 12px;
1609
+ border: 1px solid var(--border);
1610
+ border-radius: var(--radius-sm);
1611
+ background: var(--bg-elevated);
1612
+ color: var(--text-secondary);
1613
+ cursor: pointer;
1614
+ font-size: 12px;
1615
+ font-weight: 500;
1616
+ display: flex;
1617
+ align-items: center;
1618
+ justify-content: center;
1619
+ gap: 6px;
1620
+ min-height: var(--touch-min);
1621
+ font-family: inherit;
1622
+ }
1623
+
1624
+ .agent-action-btn:hover {
1625
+ border-color: var(--accent-primary);
1626
+ color: var(--text-primary);
1627
+ background: var(--bg-hover);
1628
+ }
1629
+
1630
+ .agent-action-btn:active { transform: scale(0.97); }
1631
+
1632
+ .agent-action-btn.danger:hover {
1633
+ border-color: var(--accent-danger);
1634
+ color: var(--accent-danger);
1635
+ }
1636
+
1637
+ .agent-action-btn i { width: 14px; height: 14px; }
1638
+
1639
+ .agent-actions-footer {
1640
+ display: flex;
1641
+ gap: 12px;
1642
+ margin-top: 16px;
1643
+ padding-top: 16px;
1644
+ border-top: 1px solid var(--border);
1645
+ }
1646
+
1647
+ .agent-actions-footer button { flex: 1; }
1648
+
1649
+ .restore-agent-btn {
1650
+ border-color: var(--accent-secondary);
1651
+ color: var(--accent-secondary-light);
1652
+ }
1653
+
1654
+ .restore-agent-btn:hover {
1655
+ background: var(--accent-secondary-glow);
1656
+ border-color: var(--accent-secondary-light);
1657
+ }
1658
+
1659
+ .agent-badge {
1660
+ font-size: 10px;
1661
+ padding: 3px 8px;
1662
+ border-radius: var(--radius-full);
1663
+ background: var(--accent-primary-dark);
1664
+ color: white;
1665
+ text-transform: uppercase;
1666
+ letter-spacing: 0.5px;
1667
+ margin-left: auto;
1668
+ }
1669
+
1670
+ /* ============================================================
1671
+ Forms + Buttons
1672
+ ============================================================ */
1673
+ .create-agent-form {
1674
+ display: flex;
1675
+ flex-direction: column;
1676
+ gap: 16px;
1677
+ }
1678
+
1679
+ .form-group {
1680
+ display: flex;
1681
+ flex-direction: column;
1682
+ gap: 8px;
1683
+ }
1684
+
1685
+ .form-group label {
1686
+ display: flex;
1687
+ align-items: center;
1688
+ gap: 8px;
1689
+ font-size: 13px;
1690
+ font-weight: 600;
1691
+ color: var(--text-secondary);
1692
+ margin-bottom: 8px;
1693
+ }
1694
+
1695
+ .form-group label i {
1696
+ width: 16px;
1697
+ height: 16px;
1698
+ color: var(--accent-primary-light);
1699
+ }
1700
+
1701
+ .form-group input,
1702
+ .form-group textarea {
1703
+ padding: 12px 14px;
1704
+ border: 2px solid var(--border);
1705
+ border-radius: var(--radius-md);
1706
+ background: var(--bg-primary);
1707
+ color: var(--text-primary);
1708
+ font-family: inherit;
1709
+ font-size: var(--text-sm);
1710
+ resize: vertical;
1711
+ }
1712
+
1713
+ .form-group input:focus,
1714
+ .form-group textarea:focus {
1715
+ border-color: var(--accent-primary);
1716
+ box-shadow: 0 0 0 4px rgba(217, 119, 6, 0.15);
1717
+ outline: none;
1718
+ }
1719
+
1720
+ .form-group input::placeholder,
1721
+ .form-group textarea::placeholder { color: var(--text-muted); }
1722
+
1723
+ .btn-primary {
1724
+ padding: 12px 20px;
1725
+ border: none;
1726
+ border-radius: var(--radius-md);
1727
+ background: var(--gradient-primary);
1728
+ color: white;
1729
+ font-size: 14px;
1730
+ font-weight: 600;
1731
+ cursor: pointer;
1732
+ display: flex;
1733
+ align-items: center;
1734
+ justify-content: center;
1735
+ gap: 8px;
1736
+ font-family: inherit;
1737
+ min-height: var(--touch-min);
1738
+ }
1739
+
1740
+ .btn-primary:hover {
1741
+ transform: translateY(-2px);
1742
+ box-shadow: 0 8px 24px rgba(217, 119, 6, 0.3);
1743
+ }
1744
+
1745
+ .btn-primary:active { transform: scale(0.97); }
1746
+
1747
+ .create-agent-btn {
1748
+ margin-top: 16px;
1749
+ width: 100%;
1750
+ }
1751
+
1752
+ .btn-secondary {
1753
+ padding: 12px 20px;
1754
+ border: 1px solid var(--border);
1755
+ border-radius: var(--radius-md);
1756
+ background: var(--bg-card);
1757
+ color: var(--text-primary);
1758
+ font-size: 14px;
1759
+ font-weight: 600;
1760
+ cursor: pointer;
1761
+ display: flex;
1762
+ align-items: center;
1763
+ justify-content: center;
1764
+ gap: 8px;
1765
+ font-family: inherit;
1766
+ min-height: var(--touch-min);
1767
+ }
1768
+
1769
+ .btn-secondary:hover { border-color: var(--accent-primary); background: var(--bg-hover); }
1770
+ .btn-secondary:active { transform: scale(0.97); }
1771
+
1772
+ .btn-primary i { width: 18px; height: 18px; }
1773
+
1774
+ /* ============================================================
1775
+ Profile modal
1776
+ ============================================================ */
1777
+ .profile-info {
1778
+ display: flex;
1779
+ align-items: center;
1780
+ gap: 16px;
1781
+ padding: 16px;
1782
+ background: var(--bg-card);
1783
+ border-radius: var(--radius-md);
1784
+ margin-bottom: 16px;
1785
+ }
1786
+
1787
+ .profile-avatar {
1788
+ width: 56px;
1789
+ height: 56px;
1790
+ border-radius: 50%;
1791
+ background: var(--gradient-primary);
1792
+ display: flex;
1793
+ align-items: center;
1794
+ justify-content: center;
1795
+ color: white;
1796
+ flex-shrink: 0;
1797
+ }
1798
+
1799
+ .profile-avatar i { width: 28px; height: 28px; }
1800
+
1801
+ .profile-details h4 {
1802
+ font-size: var(--text-base);
1803
+ font-weight: 600;
1804
+ }
1805
+
1806
+ .profile-id {
1807
+ font-size: 13px;
1808
+ color: var(--text-muted);
1809
+ font-family: 'JetBrains Mono', monospace;
1810
+ }
1811
+
1812
+ .profile-stats {
1813
+ display: grid;
1814
+ grid-template-columns: repeat(3, 1fr);
1815
+ gap: 10px;
1816
+ margin-bottom: 16px;
1817
+ }
1818
+
1819
+ .stat-card {
1820
+ padding: 14px 8px;
1821
+ background: var(--bg-card);
1822
+ border: 1px solid var(--border);
1823
+ border-radius: var(--radius-md);
1824
+ text-align: center;
1825
+ }
1826
+
1827
+ .stat-card i {
1828
+ width: 20px;
1829
+ height: 20px;
1830
+ color: var(--accent-primary-light);
1831
+ margin-bottom: 8px;
1832
+ }
1833
+
1834
+ .stat-card span {
1835
+ display: block;
1836
+ font-size: 16px;
1837
+ font-weight: 700;
1838
+ color: var(--text-primary);
1839
+ word-break: break-word;
1840
+ }
1841
+
1842
+ .stat-card small {
1843
+ font-size: 11px;
1844
+ color: var(--text-muted);
1845
+ text-transform: uppercase;
1846
+ letter-spacing: 0.5px;
1847
+ }
1848
+
1849
+ .profile-section { margin-bottom: 16px; }
1850
+
1851
+ .profile-section h4 {
1852
+ font-size: 14px;
1853
+ font-weight: 600;
1854
+ margin-bottom: 12px;
1855
+ color: var(--text-secondary);
1856
+ }
1857
+
1858
+ .setting-row {
1859
+ display: flex;
1860
+ justify-content: space-between;
1861
+ padding: 12px 0;
1862
+ border-bottom: 1px solid var(--border);
1863
+ }
1864
+
1865
+ .setting-row:last-child { border-bottom: none; }
1866
+
1867
+ .setting-value {
1868
+ color: var(--accent-primary-light);
1869
+ font-weight: 500;
1870
+ }
1871
+
1872
+ /* ============================================================
1873
+ Toast
1874
+ ============================================================ */
1875
+ .toast {
1876
+ position: fixed;
1877
+ bottom: max(16px, env(safe-area-inset-bottom));
1878
+ right: 16px;
1879
+ left: 16px;
1880
+ background: var(--bg-card);
1881
+ border: 1px solid var(--accent-primary-dark);
1882
+ border-radius: var(--radius-md);
1883
+ padding: 14px 18px;
1884
+ display: flex;
1885
+ align-items: center;
1886
+ gap: 12px;
1887
+ box-shadow: var(--shadow-lg), 0 0 25px var(--accent-glow);
1888
+ animation: toast-enter 0.4s var(--ease-spring);
1889
+ z-index: 50;
1890
+ }
1891
+
1892
+ .toast i {
1893
+ width: 18px;
1894
+ height: 18px;
1895
+ color: var(--accent-success);
1896
+ flex-shrink: 0;
1897
+ }
1898
+
1899
+ .toast-text {
1900
+ font-size: var(--text-sm);
1901
+ color: var(--text-primary);
1902
+ }
1903
+
1904
+ .toast.error {
1905
+ border-color: var(--accent-danger);
1906
+ box-shadow: var(--shadow-lg), 0 0 25px rgba(239, 68, 68, 0.2);
1907
+ }
1908
+
1909
+ .toast.error i { color: var(--accent-danger); }
1910
+
1911
+ @keyframes toast-enter {
1912
+ from { opacity: 0; transform: translateY(24px) scale(0.92); }
1913
+ to { opacity: 1; transform: translateY(0) scale(1); }
1914
+ }
1915
+
1916
+ .toast-exit {
1917
+ animation: toast-exit 0.3s var(--ease-out-expo) forwards;
1918
+ }
1919
+
1920
+ @keyframes toast-exit {
1921
+ to { opacity: 0; transform: translateX(30px); }
1922
+ }
1923
+
1924
+ /* ============================================================
1925
+ Breakpoints — mobile-first
1926
+ ============================================================ */
1927
+
1928
+ /* Large phone / phone landscape (≥ 480px) */
1929
+ @media (min-width: 480px) {
1930
+ .toolbar button {
1931
+ flex: 0 0 auto;
1932
+ }
1933
+ .toast {
1934
+ left: auto;
1935
+ max-width: 340px;
1936
+ }
1937
+ .empty-suggestions {
1938
+ grid-template-columns: 1fr 1fr;
1939
+ }
1940
+ .empty-suggestions .suggestion-card:nth-child(3) {
1941
+ grid-column: 1 / -1;
1942
+ }
1943
+ }
1944
+
1945
+ /* Tablet portrait (≥ 768px) — sidebar in flow, modal centered */
1946
+ @media (min-width: 768px) {
1947
+ .sidebar {
1948
+ position: relative;
1949
+ transform: none;
1950
+ width: 280px;
1951
+ min-width: 280px;
1952
+ flex: 0 0 280px;
1953
+ height: auto;
1954
+ box-shadow: none;
1955
+ padding-left: 0;
1956
+ padding-top: 0;
1957
+ }
1958
+ .sidebar-overlay { display: none !important; }
1959
+ #sidebarClose { display: none; }
1960
+ .header-row {
1961
+ padding: 14px 22px;
1962
+ gap: 14px;
1963
+ }
1964
+ .status-text { display: inline; }
1965
+ .mode-badge { display: flex; }
1966
+ .msg { max-width: 80%; font-size: var(--text-base); }
1967
+ .chat-area { padding: 22px; gap: 14px; }
1968
+ .toolbar { padding: 14px 22px; flex-wrap: nowrap; }
1969
+ .toolbar button { padding: 10px 16px; font-size: 13px; flex: 0 0 auto; }
1970
+ .input-area { padding: 16px 22px; }
1971
+ .typing-indicator { margin: 0 22px 12px; }
1972
+ .modal-overlay { align-items: center; padding: 24px; }
1973
+ .modal-content {
1974
+ border-radius: var(--radius-xl);
1975
+ max-width: 560px;
1976
+ max-height: 80vh;
1977
+ animation: modalSlide 0.4s var(--ease-spring);
1978
+ padding-bottom: 0;
1979
+ }
1980
+ .empty-suggestions {
1981
+ grid-template-columns: repeat(3, 1fr);
1982
+ }
1983
+ .empty-suggestions .suggestion-card:nth-child(3) {
1984
+ grid-column: auto;
1985
+ }
1986
+ }
1987
+
1988
+ /* Tablet landscape / small laptop (≥ 1024px) — sidebar with copper border */
1989
+ @media (min-width: 1024px) {
1990
+ .sidebar {
1991
+ width: 300px;
1992
+ min-width: 300px;
1993
+ flex: 0 0 300px;
1994
+ }
1995
+ .sidebar::after {
1996
+ width: 2px;
1997
+ opacity: 0.7;
1998
+ background: linear-gradient(180deg, var(--accent-primary) 0%, var(--accent-secondary) 50%, transparent 100%);
1999
+ }
2000
+ .chat-area { padding: 28px; }
2001
+ .msg { max-width: 72%; }
2002
+ .toolbar { padding: 16px 24px; }
2003
+ .input-area { padding: 18px 24px 22px; }
2004
+ .typing-indicator { margin: 0 24px 12px; }
2005
+ .empty-wordmark { font-size: clamp(2.25rem, 1.6rem + 2.5vw, 3rem); }
2006
+ .empty-suggestions { gap: 14px; }
2007
+ }
2008
+
2009
+ /* Desktop (≥ 1280px) */
2010
+ @media (min-width: 1280px) {
2011
+ .sidebar { width: 320px; min-width: 320px; flex: 0 0 320px; }
2012
+ .app-container {
2013
+ background:
2014
+ radial-gradient(ellipse at 20% 0%, rgba(217, 119, 6, 0.16) 0%, transparent 50%),
2015
+ radial-gradient(ellipse at 80% 100%, rgba(5, 150, 105, 0.10) 0%, transparent 50%),
2016
+ radial-gradient(ellipse at 50% 80%, rgba(245, 158, 11, 0.06) 0%, transparent 40%),
2017
+ var(--bg-deep);
2018
+ }
2019
+ .chat-area { padding: 32px 28px; }
2020
+ .msg { max-width: 68%; }
2021
+ }
2022
+
2023
+ /* ============================================================
2024
+ Accessibility
2025
+ ============================================================ */
2026
+ @media (prefers-reduced-motion: reduce) {
2027
+ *, *::before, *::after {
2028
+ animation-duration: 0.01ms !important;
2029
+ animation-iteration-count: 1 !important;
2030
+ transition-duration: 0.01ms !important;
2031
+ scroll-behavior: auto !important;
2032
+ }
2033
+ }
2034
+
2035
+ /* Focus visible for keyboard users */
2036
+ .btn-primary:focus-visible,
2037
+ .btn-secondary:focus-visible,
2038
+ .icon-btn:focus-visible,
2039
+ .toolbar button:focus-visible,
2040
+ .suggestion-card:focus-visible,
2041
+ .model-card:focus-visible,
2042
+ .agent-card:focus-visible,
2043
+ .input-area input:focus-visible,
2044
+ .input-area button:focus-visible,
2045
+ .modal-close:focus-visible,
2046
+ .profile-btn:focus-visible {
2047
+ outline: 2px solid var(--accent-primary-light);
2048
+ outline-offset: 2px;
2049
+ }
2050
+
2051
+ /* ============================================================
2052
+ Markdown content
2053
+ ============================================================ */
2054
+ .md-content {
2055
+ line-height: 1.7;
2056
+ font-size: var(--text-base);
2057
+ color: var(--text-primary);
2058
+ }
2059
+
2060
+ .md-content > *:first-child { margin-top: 0; }
2061
+ .md-content > *:last-child { margin-bottom: 0; }
2062
+
2063
+ .md-content h1 {
2064
+ font-size: var(--text-2xl);
2065
+ font-weight: 700;
2066
+ color: var(--text-primary);
2067
+ margin: 1.5em 0 0.6em;
2068
+ padding-bottom: 0.4em;
2069
+ border-bottom: 2px solid var(--border);
2070
+ letter-spacing: -0.02em;
2071
+ line-height: 1.3;
2072
+ }
2073
+
2074
+ .md-content h2 {
2075
+ font-size: var(--text-xl);
2076
+ font-weight: 700;
2077
+ color: var(--accent-primary-light);
2078
+ margin: 1.4em 0 0.5em;
2079
+ padding-bottom: 0.3em;
2080
+ border-bottom: 1px solid var(--border);
2081
+ letter-spacing: -0.015em;
2082
+ line-height: 1.35;
2083
+ }
2084
+
2085
+ .md-content h3 {
2086
+ font-size: var(--text-lg);
2087
+ font-weight: 600;
2088
+ color: var(--accent-secondary-light);
2089
+ margin: 1.2em 0 0.4em;
2090
+ letter-spacing: -0.01em;
2091
+ line-height: 1.4;
2092
+ }
2093
+
2094
+ .md-content h4 {
2095
+ font-size: var(--text-base);
2096
+ font-weight: 600;
2097
+ color: var(--text-primary);
2098
+ margin: 1em 0 0.3em;
2099
+ line-height: 1.45;
2100
+ }
2101
+
2102
+ .md-content h5 {
2103
+ font-size: var(--text-sm);
2104
+ font-weight: 600;
2105
+ color: var(--text-secondary);
2106
+ margin: 0.8em 0 0.3em;
2107
+ text-transform: uppercase;
2108
+ letter-spacing: 0.05em;
2109
+ line-height: 1.5;
2110
+ }
2111
+
2112
+ .md-content h6 {
2113
+ font-size: var(--text-sm);
2114
+ font-weight: 500;
2115
+ color: var(--text-muted);
2116
+ margin: 0.8em 0 0.3em;
2117
+ font-style: italic;
2118
+ line-height: 1.5;
2119
+ }
2120
+
2121
+ .md-content p {
2122
+ margin: 0.8em 0;
2123
+ line-height: 1.75;
2124
+ }
2125
+
2126
+ .md-content strong {
2127
+ font-weight: 700;
2128
+ color: var(--accent-primary-light);
2129
+ }
2130
+
2131
+ .md-content em {
2132
+ font-style: italic;
2133
+ color: var(--text-secondary);
2134
+ }
2135
+
2136
+ .md-content strong em { color: var(--accent-primary-light); }
2137
+
2138
+ .md-content code:not(pre code) {
2139
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
2140
+ font-size: 0.88em;
2141
+ background: var(--bg-deep);
2142
+ border: 1px solid var(--border);
2143
+ border-radius: var(--radius-sm);
2144
+ padding: 0.15em 0.45em;
2145
+ color: var(--accent-tertiary);
2146
+ white-space: nowrap;
2147
+ }
2148
+
2149
+ .md-content pre {
2150
+ background: var(--bg-deep);
2151
+ border: 1px solid var(--border);
2152
+ border-radius: var(--radius-md);
2153
+ padding: 0;
2154
+ margin: 1em 0;
2155
+ overflow-x: auto;
2156
+ position: relative;
2157
+ border-left: 3px solid var(--accent-primary);
2158
+ }
2159
+
2160
+ .md-content pre code {
2161
+ display: block;
2162
+ padding: 16px;
2163
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
2164
+ font-size: 13px;
2165
+ line-height: 1.6;
2166
+ color: var(--accent-tertiary);
2167
+ background: transparent;
2168
+ border: none;
2169
+ border-radius: 0;
2170
+ }
2171
+
2172
+ .code-header {
2173
+ display: flex;
2174
+ justify-content: space-between;
2175
+ align-items: center;
2176
+ padding: 8px 14px;
2177
+ background: var(--bg-elevated);
2178
+ border-bottom: 1px solid var(--border);
2179
+ border-radius: var(--radius-md) var(--radius-md) 0 0;
2180
+ font-size: 12px;
2181
+ position: sticky;
2182
+ top: 0;
2183
+ z-index: 1;
2184
+ backdrop-filter: blur(4px);
2185
+ -webkit-backdrop-filter: blur(4px);
2186
+ }
2187
+
2188
+ .code-header .lang-label {
2189
+ font-family: 'JetBrains Mono', monospace;
2190
+ font-size: 11px;
2191
+ font-weight: 600;
2192
+ color: var(--accent-secondary-light);
2193
+ text-transform: lowercase;
2194
+ letter-spacing: 0.03em;
2195
+ }
2196
+
2197
+ .copy-btn {
2198
+ background: none;
2199
+ border: 1px solid var(--border);
2200
+ border-radius: var(--radius-sm);
2201
+ padding: 4px 10px;
2202
+ font-size: 11px;
2203
+ font-weight: 500;
2204
+ color: var(--text-muted);
2205
+ cursor: pointer;
2206
+ display: flex;
2207
+ align-items: center;
2208
+ gap: 6px;
2209
+ font-family: inherit;
2210
+ min-height: 28px;
2211
+ }
2212
+
2213
+ .copy-btn:hover {
2214
+ color: var(--accent-primary-light);
2215
+ border-color: var(--accent-primary-dark);
2216
+ background: var(--bg-hover);
2217
+ }
2218
+
2219
+ .copy-btn:active { transform: scale(0.96); }
2220
+
2221
+ .copy-btn.copied {
2222
+ color: var(--accent-success);
2223
+ border-color: var(--accent-success);
2224
+ }
2225
+
2226
+ .copy-btn i { width: 14px; height: 14px; }
2227
+
2228
+ .code-block-with-lines {
2229
+ display: flex;
2230
+ padding: 16px 0;
2231
+ }
2232
+
2233
+ .code-block-with-lines .line-numbers {
2234
+ padding: 0 12px 0 16px;
2235
+ text-align: right;
2236
+ color: var(--text-muted);
2237
+ opacity: 0.4;
2238
+ user-select: none;
2239
+ border-right: 1px solid var(--border);
2240
+ font-size: 13px;
2241
+ line-height: 1.6;
2242
+ font-family: 'JetBrains Mono', monospace;
2243
+ min-width: 40px;
2244
+ }
2245
+
2246
+ .code-block-with-lines .code-content {
2247
+ padding-left: 16px;
2248
+ flex: 1;
2249
+ overflow-x: auto;
2250
+ }
2251
+
2252
+ .md-content blockquote {
2253
+ margin: 1em 0;
2254
+ padding: 12px 18px;
2255
+ border-left: 4px solid var(--accent-primary);
2256
+ background: linear-gradient(135deg, rgba(217, 119, 6, 0.06) 0%, rgba(245, 158, 11, 0.03) 100%);
2257
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
2258
+ color: var(--text-secondary);
2259
+ font-style: italic;
2260
+ }
2261
+
2262
+ .md-content blockquote p { margin: 0.4em 0; }
2263
+ .md-content blockquote strong { color: var(--accent-primary-light); }
2264
+ .md-content blockquote > blockquote {
2265
+ margin-top: 0.5em;
2266
+ border-left-color: var(--accent-secondary);
2267
+ }
2268
+
2269
+ .md-content table {
2270
+ width: 100%;
2271
+ margin: 1em 0;
2272
+ border-collapse: collapse;
2273
+ border: 1px solid var(--border);
2274
+ border-radius: var(--radius-md);
2275
+ overflow: hidden;
2276
+ font-size: var(--text-sm);
2277
+ }
2278
+
2279
+ .md-content thead {
2280
+ background: linear-gradient(135deg, var(--bg-elevated) 0%, var(--bg-card) 100%);
2281
+ }
2282
+
2283
+ .md-content thead th {
2284
+ padding: 12px 14px;
2285
+ text-align: left;
2286
+ font-weight: 600;
2287
+ color: var(--accent-primary-light);
2288
+ border-bottom: 2px solid var(--accent-primary-dark);
2289
+ white-space: nowrap;
2290
+ letter-spacing: 0.01em;
2291
+ }
2292
+
2293
+ .md-content tbody tr { transition: background-color var(--transition-micro); }
2294
+ .md-content tbody tr:nth-child(even) { background: var(--bg-deep); }
2295
+ .md-content tbody tr:hover { background: var(--bg-hover); }
2296
+ .md-content tbody td {
2297
+ padding: 10px 14px;
2298
+ border-bottom: 1px solid var(--border);
2299
+ color: var(--text-primary);
2300
+ vertical-align: top;
2301
+ }
2302
+ .md-content tbody tr:last-child td { border-bottom: none; }
2303
+
2304
+ .md-content ul,
2305
+ .md-content ol {
2306
+ margin: 0.8em 0;
2307
+ padding-left: 1.8em;
2308
+ }
2309
+
2310
+ .md-content ul { list-style: none; }
2311
+
2312
+ .md-content ul li {
2313
+ position: relative;
2314
+ padding-left: 0.6em;
2315
+ margin: 0.35em 0;
2316
+ line-height: 1.65;
2317
+ }
2318
+
2319
+ .md-content ul li::before {
2320
+ content: '';
2321
+ position: absolute;
2322
+ left: -1.2em;
2323
+ top: 0.65em;
2324
+ width: 6px;
2325
+ height: 6px;
2326
+ border-radius: 50%;
2327
+ background: var(--accent-primary);
2328
+ box-shadow: 0 0 6px var(--accent-glow);
2329
+ }
2330
+
2331
+ .md-content ol {
2332
+ counter-reset: list-counter;
2333
+ list-style: none;
2334
+ }
2335
+
2336
+ .md-content ol li {
2337
+ counter-increment: list-counter;
2338
+ margin: 0.35em 0;
2339
+ padding-left: 0.4em;
2340
+ line-height: 1.65;
2341
+ }
2342
+
2343
+ .md-content ol li::before {
2344
+ content: counter(list-counter) '.';
2345
+ color: var(--accent-secondary-light);
2346
+ font-weight: 600;
2347
+ margin-right: 0.5em;
2348
+ font-family: 'JetBrains Mono', monospace;
2349
+ font-size: 0.9em;
2350
+ }
2351
+
2352
+ .md-content li > ul,
2353
+ .md-content li > ol { margin: 0.3em 0; }
2354
+
2355
+ .md-content input[type="checkbox"] {
2356
+ appearance: none;
2357
+ -webkit-appearance: none;
2358
+ width: 18px;
2359
+ height: 18px;
2360
+ border: 2px solid var(--border-light);
2361
+ border-radius: var(--radius-sm);
2362
+ background: var(--bg-deep);
2363
+ cursor: pointer;
2364
+ vertical-align: middle;
2365
+ margin-right: 8px;
2366
+ position: relative;
2367
+ flex-shrink: 0;
2368
+ }
2369
+
2370
+ .md-content input[type="checkbox"]:checked {
2371
+ background: var(--accent-success);
2372
+ border-color: var(--accent-success);
2373
+ }
2374
+
2375
+ .md-content input[type="checkbox"]:checked::after {
2376
+ content: '';
2377
+ position: absolute;
2378
+ left: 5px;
2379
+ top: 2px;
2380
+ width: 5px;
2381
+ height: 9px;
2382
+ border: solid white;
2383
+ border-width: 0 2px 2px 0;
2384
+ transform: rotate(45deg);
2385
+ }
2386
+
2387
+ .md-content input[type="checkbox"]:hover { border-color: var(--accent-primary); }
2388
+
2389
+ .md-content .task-list-item {
2390
+ list-style: none;
2391
+ margin: 0.4em 0;
2392
+ display: flex;
2393
+ align-items: flex-start;
2394
+ }
2395
+
2396
+ .md-content .task-list-item input[type="checkbox"] { margin-top: 3px; }
2397
+
2398
+ .md-content hr {
2399
+ margin: 1.5em 0;
2400
+ border: none;
2401
+ height: 2px;
2402
+ background: linear-gradient(90deg, transparent, var(--accent-primary), var(--accent-secondary), transparent);
2403
+ border-radius: var(--radius-full);
2404
+ opacity: 0.5;
2405
+ }
2406
+
2407
+ .md-content a {
2408
+ color: var(--accent-primary-light);
2409
+ text-decoration: none;
2410
+ border-bottom: 1px solid transparent;
2411
+ font-weight: 500;
2412
+ }
2413
+
2414
+ .md-content a:hover {
2415
+ color: var(--accent-primary);
2416
+ border-bottom-color: var(--accent-primary);
2417
+ }
2418
+
2419
+ .md-content a:active { color: var(--accent-primary-dark); }
2420
+
2421
+ .md-content img {
2422
+ max-width: 100%;
2423
+ height: auto;
2424
+ border-radius: var(--radius-md);
2425
+ border: 1px solid var(--border);
2426
+ margin: 1em 0;
2427
+ box-shadow: var(--shadow-md);
2428
+ }
2429
+
2430
+ /* Arabic / RTL — Cairo is the only stack here */
2431
+ .md-content:lang(ar),
2432
+ .md-content .arabic-text,
2433
+ [dir="rtl"] {
2434
+ font-family: 'Cairo', sans-serif;
2435
+ }