agent-loft 0.0.0-stage → 0.2.8

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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -2
  3. package/bin/cli.js +52 -0
  4. package/package.json +64 -4
  5. package/src/agents/claude/account.ts +122 -0
  6. package/src/agents/claude/driver.ts +216 -0
  7. package/src/agents/claude/errors.ts +129 -0
  8. package/src/agents/claude/permissions.ts +260 -0
  9. package/src/agents/claude/probe.ts +54 -0
  10. package/src/agents/claude/session.ts +487 -0
  11. package/src/agents/codex/account.ts +122 -0
  12. package/src/agents/codex/app-server.ts +346 -0
  13. package/src/agents/codex/driver.ts +210 -0
  14. package/src/agents/codex/errors.ts +158 -0
  15. package/src/agents/codex/protocol.ts +284 -0
  16. package/src/agents/codex/refusals.ts +62 -0
  17. package/src/agents/codex/session.ts +773 -0
  18. package/src/channels/feishu/bot.ts +669 -0
  19. package/src/channels/feishu/cards.ts +360 -0
  20. package/src/channels/feishu/client.ts +185 -0
  21. package/src/channels/feishu/envelope.ts +117 -0
  22. package/src/channels/feishu/index.ts +62 -0
  23. package/src/channels/feishu/message.ts +115 -0
  24. package/src/channels/feishu/register.ts +171 -0
  25. package/src/channels/feishu/slash-sync.ts +192 -0
  26. package/src/channels/feishu/turn-stream.ts +98 -0
  27. package/src/channels/web/api.ts +645 -0
  28. package/src/channels/web/auth.ts +204 -0
  29. package/src/channels/web/http.ts +118 -0
  30. package/src/channels/web/push.ts +218 -0
  31. package/src/channels/web/server.ts +446 -0
  32. package/src/cli/doctor.ts +39 -0
  33. package/src/cli/import.ts +155 -0
  34. package/src/cli/pair.ts +35 -0
  35. package/src/cli/passwd.ts +15 -0
  36. package/src/cli/service.ts +137 -0
  37. package/src/core/agent-env.ts +11 -0
  38. package/src/core/command-catalog.ts +112 -0
  39. package/src/core/commands.ts +104 -0
  40. package/src/core/config.ts +285 -0
  41. package/src/core/dedup.ts +16 -0
  42. package/src/core/footers.ts +88 -0
  43. package/src/core/hub.ts +1152 -0
  44. package/src/core/interactions.ts +273 -0
  45. package/src/core/pairing.ts +156 -0
  46. package/src/core/store.ts +178 -0
  47. package/src/core/types.ts +213 -0
  48. package/src/core/uploads.ts +200 -0
  49. package/src/home.ts +43 -0
  50. package/src/main.ts +68 -0
  51. package/web/app.js +3731 -0
  52. package/web/apple-touch-icon.png +0 -0
  53. package/web/icon-maskable.svg +13 -0
  54. package/web/icon.svg +12 -0
  55. package/web/index.html +23 -0
  56. package/web/manifest.webmanifest +15 -0
  57. package/web/style.css +2604 -0
  58. package/web/sw.js +76 -0
package/web/style.css ADDED
@@ -0,0 +1,2604 @@
1
+ :root {
2
+ --bg: #ffffff;
3
+ --bg-side: #f9f9f9;
4
+ --bg-soft: #f4f4f4;
5
+ --bg-hover: #ececec;
6
+ --bg-input: #ffffff;
7
+ --fg: #0d0d0d;
8
+ --fg-soft: #5d5d5d;
9
+ --fg-faint: #8f8f8f;
10
+ --border: #e5e5e5;
11
+ --accent: #2563eb;
12
+ --accent-fg: #ffffff;
13
+ --link: #2563eb;
14
+ --danger: #d93f3f;
15
+ --warn-bg: #fff7e6;
16
+ --warn-border: #f5c26b;
17
+ --ask-bg: #f4f0ff;
18
+ --ask-border: #b9a6f5;
19
+ --ok: #1a9d55;
20
+ --user-bubble: #f0f0f0;
21
+ --code-bg: #f6f8fa;
22
+ --shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
23
+ --radius: 14px;
24
+ --side-w: 272px;
25
+ --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
26
+ "Helvetica Neue", Arial, sans-serif;
27
+ --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
28
+ color-scheme: light dark;
29
+ }
30
+
31
+ @media (prefers-color-scheme: dark) {
32
+ :root {
33
+ --bg: #212121;
34
+ --bg-side: #171717;
35
+ --bg-soft: #2a2a2a;
36
+ --bg-hover: #333333;
37
+ --bg-input: #303030;
38
+ --fg: #ececec;
39
+ --fg-soft: #b4b4b4;
40
+ --fg-faint: #8a8a8a;
41
+ --border: #3a3a3a;
42
+ --link: #60a5fa;
43
+ --warn-bg: #3a2f1a;
44
+ --warn-border: #8a6a2a;
45
+ --ask-bg: #2c2640;
46
+ --ask-border: #6a58b0;
47
+ --user-bubble: #303030;
48
+ --code-bg: #171717;
49
+ --shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
50
+ }
51
+ }
52
+
53
+ * {
54
+ box-sizing: border-box;
55
+ }
56
+
57
+ html,
58
+ body {
59
+ margin: 0;
60
+ height: 100%;
61
+ background: var(--bg);
62
+ color: var(--fg);
63
+ font-family: var(--font);
64
+ font-size: 15px;
65
+ line-height: 1.6;
66
+ -webkit-text-size-adjust: 100%;
67
+ -webkit-tap-highlight-color: transparent;
68
+ }
69
+
70
+ #app {
71
+ height: 100%;
72
+ height: 100dvh;
73
+ }
74
+
75
+ button {
76
+ font: inherit;
77
+ color: inherit;
78
+ cursor: pointer;
79
+ border: none;
80
+ background: none;
81
+ }
82
+
83
+ input,
84
+ textarea,
85
+ select {
86
+ font: inherit;
87
+ color: inherit;
88
+ }
89
+
90
+ .boot {
91
+ display: grid;
92
+ place-items: center;
93
+ height: 100%;
94
+ color: var(--fg-faint);
95
+ }
96
+
97
+ /* ---------- 登录 ---------- */
98
+
99
+ .auth {
100
+ display: grid;
101
+ place-items: center;
102
+ height: 100%;
103
+ padding: 24px;
104
+ }
105
+
106
+ .auth-card {
107
+ width: 100%;
108
+ max-width: 360px;
109
+ display: flex;
110
+ flex-direction: column;
111
+ gap: 14px;
112
+ }
113
+
114
+ .auth-card h1 {
115
+ font-size: 24px;
116
+ margin: 0 0 4px;
117
+ text-align: center;
118
+ }
119
+
120
+ .auth-card p {
121
+ margin: 0;
122
+ color: var(--fg-soft);
123
+ font-size: 14px;
124
+ text-align: center;
125
+ }
126
+
127
+ .field {
128
+ display: flex;
129
+ flex-direction: column;
130
+ gap: 6px;
131
+ }
132
+
133
+ .field > span {
134
+ font-size: 13px;
135
+ color: var(--fg-soft);
136
+ }
137
+
138
+ /* 设置页的模型 / 思考程度下拉:读取失败时里面会换成文本框 + 提示 */
139
+ .picker {
140
+ display: flex;
141
+ flex-direction: column;
142
+ gap: 6px;
143
+ }
144
+
145
+ .field small {
146
+ color: var(--fg-faint);
147
+ font-size: 12px;
148
+ }
149
+
150
+ .input,
151
+ .field input,
152
+ .field select,
153
+ .field textarea {
154
+ width: 100%;
155
+ padding: 10px 12px;
156
+ border: 1px solid var(--border);
157
+ border-radius: 10px;
158
+ background: var(--bg-input);
159
+ outline: none;
160
+ }
161
+
162
+ /* 原生下拉框各平台长得不一样(macOS 上忽略内边距、高度对不齐),统一成和输入框一样的外观 */
163
+ .field select,
164
+ select.input {
165
+ -webkit-appearance: none;
166
+ appearance: none;
167
+ height: 46px;
168
+ padding: 0 36px 0 12px;
169
+ line-height: 44px;
170
+ cursor: pointer;
171
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238f8f8f' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
172
+ background-repeat: no-repeat;
173
+ background-position: right 12px center;
174
+ background-size: 14px;
175
+ text-overflow: ellipsis;
176
+ }
177
+
178
+ .field select:disabled {
179
+ cursor: default;
180
+ opacity: 0.7;
181
+ }
182
+
183
+ .input:focus,
184
+ .field input:focus,
185
+ .field select:focus,
186
+ .field textarea:focus {
187
+ border-color: var(--accent);
188
+ }
189
+
190
+ .btn {
191
+ display: inline-flex;
192
+ align-items: center;
193
+ justify-content: center;
194
+ gap: 6px;
195
+ padding: 8px 14px;
196
+ border-radius: 10px;
197
+ border: 1px solid var(--border);
198
+ background: var(--bg);
199
+ font-size: 14px;
200
+ white-space: nowrap;
201
+ }
202
+
203
+ .btn:hover {
204
+ background: var(--bg-hover);
205
+ }
206
+
207
+ .btn svg {
208
+ width: 18px;
209
+ height: 18px;
210
+ }
211
+
212
+ .btn.primary {
213
+ background: var(--fg);
214
+ color: var(--bg);
215
+ border-color: var(--fg);
216
+ }
217
+
218
+ .btn.primary:hover {
219
+ opacity: 0.85;
220
+ }
221
+
222
+ .btn.accent {
223
+ background: var(--accent);
224
+ border-color: var(--accent);
225
+ color: var(--accent-fg);
226
+ }
227
+
228
+ .btn.danger {
229
+ color: var(--danger);
230
+ }
231
+
232
+ .btn.small {
233
+ padding: 4px 10px;
234
+ font-size: 13px;
235
+ border-radius: 8px;
236
+ }
237
+
238
+ .btn:disabled {
239
+ opacity: 0.5;
240
+ cursor: default;
241
+ }
242
+
243
+ .error-text {
244
+ color: var(--danger);
245
+ font-size: 13px;
246
+ min-height: 1em;
247
+ }
248
+
249
+ /* ---------- 布局 ---------- */
250
+
251
+ .layout {
252
+ display: flex;
253
+ height: 100%;
254
+ overflow: hidden;
255
+ position: relative;
256
+ }
257
+
258
+ .sidebar {
259
+ width: var(--side-w);
260
+ flex-shrink: 0;
261
+ position: relative;
262
+ background: var(--bg-side);
263
+ display: flex;
264
+ flex-direction: column;
265
+ border-right: 1px solid var(--border);
266
+ padding-top: env(safe-area-inset-top);
267
+ }
268
+
269
+ /* 侧栏右边缘的拖动条:hover 时显示一条细线 */
270
+ .side-resizer {
271
+ position: absolute;
272
+ top: 0;
273
+ bottom: 0;
274
+ right: -4px;
275
+ width: 8px;
276
+ cursor: col-resize;
277
+ z-index: 10;
278
+ touch-action: none;
279
+ }
280
+
281
+ .side-resizer::after {
282
+ content: "";
283
+ position: absolute;
284
+ top: 0;
285
+ bottom: 0;
286
+ left: 3px;
287
+ width: 2px;
288
+ background: var(--accent);
289
+ opacity: 0;
290
+ transition: opacity 0.15s;
291
+ }
292
+
293
+ .side-resizer:hover::after,
294
+ .side-resizing .side-resizer::after {
295
+ opacity: 0.6;
296
+ transition-delay: 0.1s;
297
+ }
298
+
299
+ body.side-resizing {
300
+ cursor: col-resize;
301
+ user-select: none;
302
+ }
303
+
304
+ @media (max-width: 768px) {
305
+ .side-resizer {
306
+ display: none;
307
+ }
308
+ }
309
+
310
+ .side-top {
311
+ padding: 10px 10px 0;
312
+ display: flex;
313
+ gap: 8px;
314
+ }
315
+
316
+ .side-top .new-chat {
317
+ flex: 1;
318
+ justify-content: flex-start;
319
+ background: transparent;
320
+ border: none;
321
+ /* 和下面的会话行同字号、同字重 */
322
+ padding: 7px 10px;
323
+ gap: 8px;
324
+ font-size: 14px;
325
+ font-weight: 400;
326
+ }
327
+
328
+ .side-top .new-chat svg {
329
+ width: 16px;
330
+ height: 16px;
331
+ }
332
+
333
+ .side-top .new-chat:hover {
334
+ background: var(--bg-hover);
335
+ }
336
+
337
+ .conv-list {
338
+ flex: 1;
339
+ overflow-y: auto;
340
+ padding: 0 8px 8px;
341
+ }
342
+
343
+ .conv-group {
344
+ display: flex;
345
+ align-items: center;
346
+ gap: 4px;
347
+ width: 100%;
348
+ font-size: 13px;
349
+ color: var(--fg-faint);
350
+ padding: 14px 10px 6px;
351
+ text-align: left;
352
+ }
353
+
354
+ .conv-list > .conv-group:first-child {
355
+ padding-top: 8px;
356
+ }
357
+
358
+ /* 分组标题 hover 时显示折叠箭头 */
359
+ .conv-group .chev {
360
+ display: inline-grid;
361
+ visibility: hidden;
362
+ transition: transform 0.15s;
363
+ }
364
+
365
+ .conv-group .chev svg {
366
+ width: 12px;
367
+ height: 12px;
368
+ }
369
+
370
+ .conv-group:hover .chev {
371
+ visibility: visible;
372
+ }
373
+
374
+ .conv-group.collapsed .chev {
375
+ transform: rotate(-90deg);
376
+ }
377
+
378
+ button.conv-group:hover {
379
+ color: var(--fg-soft);
380
+ }
381
+
382
+ .conv-empty {
383
+ font-size: 13px;
384
+ color: var(--fg-faint);
385
+ padding: 4px 10px;
386
+ }
387
+
388
+ .conv-more {
389
+ display: block;
390
+ width: 100%;
391
+ text-align: left;
392
+ padding: 6px 10px;
393
+ border-radius: 8px;
394
+ font-size: 13px;
395
+ color: var(--fg-faint);
396
+ }
397
+
398
+ .conv-more:hover {
399
+ color: var(--fg);
400
+ }
401
+
402
+ .sub-more .conv-more {
403
+ padding-left: 36px;
404
+ }
405
+
406
+ .conv-item .lead {
407
+ width: 14px;
408
+ height: 14px;
409
+ opacity: 0.85;
410
+ }
411
+
412
+ .conv-item.sub {
413
+ padding-left: 36px;
414
+ }
415
+
416
+ .proj-row {
417
+ position: relative;
418
+ margin-top: 2px;
419
+ }
420
+
421
+ .conv-item.proj {
422
+ gap: 10px;
423
+ }
424
+
425
+ .proj-icon {
426
+ display: inline-grid;
427
+ color: var(--fg-soft);
428
+ flex-shrink: 0;
429
+ }
430
+
431
+ .proj-icon svg {
432
+ width: 18px;
433
+ height: 18px;
434
+ }
435
+
436
+ /* 目录行 hover 时右侧出现「在此目录开新对话」 */
437
+ .proj-new {
438
+ position: absolute;
439
+ right: 4px;
440
+ top: 50%;
441
+ transform: translateY(-50%);
442
+ width: 28px;
443
+ height: 28px;
444
+ display: none;
445
+ place-items: center;
446
+ border-radius: 50%;
447
+ color: var(--fg-soft);
448
+ }
449
+
450
+ .proj-new svg {
451
+ width: 15px;
452
+ height: 15px;
453
+ }
454
+
455
+ .proj-new:hover {
456
+ background: var(--bg-soft);
457
+ color: var(--fg);
458
+ }
459
+
460
+ .proj-row:hover .proj-new {
461
+ display: grid;
462
+ }
463
+
464
+ .proj-row:hover .conv-item.proj {
465
+ padding-right: 36px;
466
+ }
467
+
468
+ @media (pointer: coarse) {
469
+ .proj-new {
470
+ display: grid;
471
+ }
472
+ }
473
+
474
+ .conv-item {
475
+ display: flex;
476
+ align-items: center;
477
+ gap: 8px;
478
+ width: 100%;
479
+ text-align: left;
480
+ padding: 7px 10px;
481
+ border-radius: 8px;
482
+ font-size: 14px;
483
+ position: relative;
484
+ }
485
+
486
+ .conv-item:hover {
487
+ background: var(--bg-hover);
488
+ }
489
+
490
+ .conv-item.active {
491
+ background: var(--bg-hover);
492
+ }
493
+
494
+ .conv-item .title {
495
+ flex: 1;
496
+ overflow: hidden;
497
+ text-overflow: ellipsis;
498
+ white-space: nowrap;
499
+ }
500
+
501
+ /* 跑马灯滚动时去掉省略号 */
502
+ .conv-item .title.marquee {
503
+ text-overflow: clip;
504
+ }
505
+
506
+ .conv-item .badge {
507
+ font-size: 11px;
508
+ color: var(--fg-faint);
509
+ flex-shrink: 0;
510
+ }
511
+
512
+ .dot {
513
+ width: 8px;
514
+ height: 8px;
515
+ border-radius: 50%;
516
+ flex-shrink: 0;
517
+ }
518
+
519
+ .dot.busy {
520
+ background: var(--accent);
521
+ animation: pulse 1.2s infinite;
522
+ }
523
+
524
+ .dot.ask {
525
+ background: #f59f00;
526
+ }
527
+
528
+ @keyframes pulse {
529
+ 50% {
530
+ opacity: 0.3;
531
+ }
532
+ }
533
+
534
+ .side-bottom {
535
+ border-top: 1px solid var(--border);
536
+ padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
537
+ display: flex;
538
+ align-items: center;
539
+ gap: 6px;
540
+ min-height: 48px;
541
+ }
542
+
543
+ .side-gear {
544
+ margin-left: auto;
545
+ }
546
+
547
+ /* ---- 侧栏底部的额度 ---- */
548
+ .quota {
549
+ position: relative;
550
+ flex: 1;
551
+ min-width: 0;
552
+ }
553
+
554
+ .quota-btn {
555
+ display: flex;
556
+ flex-direction: column;
557
+ gap: 4px;
558
+ width: 100%;
559
+ padding: 5px 6px;
560
+ border-radius: 8px;
561
+ text-align: left;
562
+ }
563
+
564
+ .quota-btn:hover {
565
+ background: var(--bg-hover);
566
+ }
567
+
568
+ .quota.loading .quota-btn {
569
+ opacity: 0.6;
570
+ }
571
+
572
+ .quota-row {
573
+ display: flex;
574
+ align-items: center;
575
+ gap: 8px;
576
+ font-size: 11px;
577
+ color: var(--fg-soft);
578
+ font-variant-numeric: tabular-nums;
579
+ }
580
+
581
+ .quota-icon svg {
582
+ width: 13px;
583
+ height: 13px;
584
+ }
585
+
586
+ .quota-icon {
587
+ display: inline-grid;
588
+ color: var(--fg-soft);
589
+ flex-shrink: 0;
590
+ }
591
+
592
+ .quota-cell {
593
+ display: flex;
594
+ align-items: center;
595
+ gap: 4px;
596
+ flex: 1;
597
+ min-width: 0;
598
+ }
599
+
600
+ .q-label {
601
+ color: var(--fg-faint);
602
+ flex-shrink: 0;
603
+ }
604
+
605
+ .q-bar {
606
+ flex: 1;
607
+ min-width: 14px;
608
+ height: 4px;
609
+ border-radius: 2px;
610
+ background: color-mix(in srgb, var(--fg-faint) 22%, transparent);
611
+ overflow: hidden;
612
+ }
613
+
614
+ .q-bar i {
615
+ display: block;
616
+ height: 100%;
617
+ border-radius: 2px;
618
+ background: var(--fg-soft);
619
+ }
620
+
621
+ .q-pct {
622
+ flex-shrink: 0;
623
+ min-width: 26px;
624
+ text-align: right;
625
+ }
626
+
627
+ .quota-cell.warn .q-bar i {
628
+ background: #f59f00;
629
+ }
630
+
631
+ .quota-cell.danger .q-bar i {
632
+ background: var(--danger);
633
+ }
634
+
635
+ .quota-cell.danger .q-pct {
636
+ color: var(--danger);
637
+ }
638
+
639
+ /* hover 详情:从底部向上弹出 */
640
+ .quota-tip {
641
+ position: absolute;
642
+ left: 0;
643
+ bottom: calc(100% + 8px);
644
+ width: 310px;
645
+ max-width: calc(100vw - 24px);
646
+ padding: 10px 12px;
647
+ border-radius: 12px;
648
+ background: var(--bg);
649
+ border: 1px solid var(--border);
650
+ box-shadow: var(--shadow);
651
+ font-size: 12px;
652
+ color: var(--fg-soft);
653
+ display: flex;
654
+ flex-direction: column;
655
+ gap: 10px;
656
+ opacity: 0;
657
+ visibility: hidden;
658
+ transform: translateY(4px);
659
+ transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
660
+ pointer-events: none;
661
+ z-index: 20;
662
+ }
663
+
664
+ .quota:hover .quota-tip {
665
+ opacity: 1;
666
+ visibility: visible;
667
+ transform: none;
668
+ transition-delay: 0.25s;
669
+ }
670
+
671
+ .qt-head {
672
+ display: flex;
673
+ align-items: center;
674
+ gap: 6px;
675
+ color: var(--fg);
676
+ margin-bottom: 4px;
677
+ }
678
+
679
+ .qt-head .agent-icon {
680
+ display: inline-grid;
681
+ }
682
+
683
+ .qt-head .agent-icon svg {
684
+ width: 14px;
685
+ height: 14px;
686
+ }
687
+
688
+ .qt-plan {
689
+ margin-left: auto;
690
+ font-size: 11px;
691
+ color: var(--fg-faint);
692
+ text-transform: capitalize;
693
+ }
694
+
695
+ .qt-row {
696
+ display: grid;
697
+ grid-template-columns: auto auto 1fr;
698
+ gap: 8px;
699
+ padding: 2px 0 2px 20px;
700
+ }
701
+
702
+ .qt-name {
703
+ color: var(--fg);
704
+ white-space: nowrap;
705
+ }
706
+
707
+ .qt-pct.warn {
708
+ color: #d98200;
709
+ }
710
+
711
+ .qt-pct.danger {
712
+ color: var(--danger);
713
+ }
714
+
715
+ .qt-reset {
716
+ text-align: right;
717
+ white-space: nowrap;
718
+ color: var(--fg-faint);
719
+ }
720
+
721
+ .qt-extra {
722
+ padding-left: 20px;
723
+ color: var(--fg-faint);
724
+ }
725
+
726
+ .qt-extra.danger {
727
+ color: var(--danger);
728
+ }
729
+
730
+ .qt-foot {
731
+ border-top: 1px solid var(--border);
732
+ padding-top: 8px;
733
+ font-size: 11px;
734
+ color: var(--fg-faint);
735
+ }
736
+
737
+
738
+ .main {
739
+ flex: 1;
740
+ display: flex;
741
+ flex-direction: column;
742
+ min-width: 0;
743
+ position: relative;
744
+ }
745
+
746
+ .topbar {
747
+ display: flex;
748
+ align-items: center;
749
+ gap: 6px;
750
+ padding: calc(8px + env(safe-area-inset-top)) 12px 8px;
751
+ min-height: 52px;
752
+ border-bottom: 1px solid transparent;
753
+ /*
754
+ * iOS 26+ 的主屏 PWA 会在页面顶端叠一层系统的模糊渐变(Liquid Glass 边缘效果),CSS 关不掉。
755
+ * WebKit 只在顶端有「fixed / sticky、铺满宽度、高于 10px、纯色不透明」的元素时跳过它,
756
+ * 并改用这个颜色延伸到状态栏。所以顶栏要 sticky + 不透明底色,不能是普通的流式元素。
757
+ */
758
+ background: var(--bg);
759
+ position: sticky;
760
+ top: 0;
761
+ z-index: 5;
762
+ }
763
+
764
+ /* 保险:主屏 PWA 里再在最顶端放一条 fixed 的纯色细条(同样是为了让 WebKit 跳过边缘模糊)。
765
+ 层级低于顶栏和侧栏,和顶栏同色,看不出来 */
766
+ .edge-strip {
767
+ display: none;
768
+ }
769
+
770
+ @media (display-mode: standalone) and (max-width: 768px) {
771
+ .edge-strip {
772
+ display: block;
773
+ position: fixed;
774
+ top: 0;
775
+ left: 0;
776
+ right: 0;
777
+ height: max(12px, env(safe-area-inset-top));
778
+ background: var(--bg);
779
+ pointer-events: none;
780
+ z-index: 4;
781
+ }
782
+ }
783
+
784
+ /* 顶栏下沿:渐变 + 模糊,聊天内容滚上去时柔和地消失在顶栏后面 */
785
+ /*
786
+ * 顶栏浮在聊天内容上面:内容一直滚到窗口顶端,经过顶栏时先变模糊、再淡出到底色,
787
+ * 没有分界线(参考 Claude 桌面端)。顶栏自身比按钮行高出一截,多出来的部分就是过渡带。
788
+ * iOS 主屏 PWA 例外,见下面的媒体查询。
789
+ */
790
+ .topbar {
791
+ position: absolute;
792
+ left: 0;
793
+ right: 0;
794
+ padding-bottom: 20px;
795
+ background: linear-gradient(
796
+ to bottom,
797
+ var(--bg) 0%,
798
+ var(--bg) calc(100% - 22px),
799
+ color-mix(in srgb, var(--bg) 75%, transparent) calc(100% - 13px),
800
+ color-mix(in srgb, var(--bg) 30%, transparent) calc(100% - 5px),
801
+ color-mix(in srgb, var(--bg) 0%, transparent) 100%
802
+ );
803
+ pointer-events: none;
804
+ }
805
+
806
+ .topbar > * {
807
+ pointer-events: auto;
808
+ }
809
+
810
+ /* 模糊层:上实下虚,越往下越清楚,和渐变叠在一起 */
811
+ .topbar::before {
812
+ content: "";
813
+ position: absolute;
814
+ inset: 0;
815
+ z-index: -1;
816
+ -webkit-backdrop-filter: blur(10px);
817
+ backdrop-filter: blur(10px);
818
+ -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
819
+ mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
820
+ pointer-events: none;
821
+ }
822
+
823
+ /* 内容让出顶栏按钮行的高度(.main 前缀是为了压过手机端的 padding 简写) */
824
+ .main .messages-inner {
825
+ padding-top: calc(72px + env(safe-area-inset-top));
826
+ }
827
+
828
+ .messages {
829
+ scroll-padding-top: calc(72px + env(safe-area-inset-top));
830
+ }
831
+
832
+ /* iOS 主屏 PWA:顶端必须是不透明的 sticky 元素才能避开系统的边缘模糊,回到普通顶栏 + 下方淡出 */
833
+ @media (display-mode: standalone) and (max-width: 768px) {
834
+ .topbar {
835
+ position: sticky;
836
+ padding-bottom: 8px;
837
+ background: var(--bg);
838
+ }
839
+
840
+ .topbar::before {
841
+ display: none;
842
+ }
843
+
844
+ .topbar::after {
845
+ content: "";
846
+ position: absolute;
847
+ left: 0;
848
+ right: 0;
849
+ top: 100%;
850
+ height: 24px;
851
+ pointer-events: none;
852
+ background: linear-gradient(
853
+ to bottom,
854
+ var(--bg),
855
+ color-mix(in srgb, var(--bg) 60%, transparent) 40%,
856
+ color-mix(in srgb, var(--bg) 0%, transparent)
857
+ );
858
+ }
859
+
860
+ .main .messages-inner {
861
+ padding-top: 16px;
862
+ }
863
+ }
864
+
865
+ .topbar .menu-btn {
866
+ display: none;
867
+ }
868
+
869
+ .icon-btn {
870
+ width: 36px;
871
+ height: 36px;
872
+ display: inline-grid;
873
+ place-items: center;
874
+ border-radius: 8px;
875
+ flex-shrink: 0;
876
+ color: var(--fg-soft);
877
+ }
878
+
879
+ .icon-btn:hover {
880
+ background: var(--bg-hover);
881
+ }
882
+
883
+ .icon-btn svg {
884
+ width: 20px;
885
+ height: 20px;
886
+ }
887
+
888
+ .top-title {
889
+ flex: 1;
890
+ min-width: 0;
891
+ display: flex;
892
+ align-items: center;
893
+ gap: 6px;
894
+ }
895
+
896
+ .top-title .conv-name {
897
+ font-size: 15px;
898
+ font-weight: 500;
899
+ overflow: hidden;
900
+ text-overflow: ellipsis;
901
+ white-space: nowrap;
902
+ padding: 0 4px;
903
+ }
904
+
905
+ .pill {
906
+ display: inline-flex;
907
+ align-items: center;
908
+ gap: 4px;
909
+ padding: 5px 10px;
910
+ border-radius: 999px;
911
+ font-size: 14px;
912
+ font-weight: 500;
913
+ max-width: 100%;
914
+ white-space: nowrap;
915
+ }
916
+
917
+ .pill:hover {
918
+ background: var(--bg-hover);
919
+ }
920
+
921
+
922
+ .pill .sub {
923
+ color: var(--fg-faint);
924
+ font-weight: 400;
925
+ overflow: hidden;
926
+ text-overflow: ellipsis;
927
+ }
928
+
929
+ .pill svg {
930
+ width: 14px;
931
+ height: 14px;
932
+ flex-shrink: 0;
933
+ }
934
+
935
+ /* ---------- 消息 ---------- */
936
+
937
+ .messages {
938
+ flex: 1;
939
+ overflow-y: auto;
940
+ overscroll-behavior: contain;
941
+ scroll-behavior: auto;
942
+ }
943
+
944
+ .messages-inner {
945
+ max-width: 820px;
946
+ margin: 0 auto;
947
+ padding: 16px 20px 24px;
948
+ display: flex;
949
+ flex-direction: column;
950
+ gap: 18px;
951
+ }
952
+
953
+ .empty {
954
+ margin: auto;
955
+ text-align: center;
956
+ color: var(--fg-soft);
957
+ padding: 40px 20px;
958
+ }
959
+
960
+ .empty h2 {
961
+ font-size: 26px;
962
+ font-weight: 600;
963
+ color: var(--fg);
964
+ margin: 0 0 8px;
965
+ }
966
+
967
+ /* 新对话的欢迎页:居中图标 + 大标题,目录名可点击切换 */
968
+ .messages-inner:has(> .empty) {
969
+ min-height: 100%;
970
+ }
971
+
972
+ .empty.hero {
973
+ display: flex;
974
+ flex-direction: column;
975
+ align-items: center;
976
+ gap: 22px;
977
+ }
978
+
979
+ .hero-logo {
980
+ display: inline-grid;
981
+ color: color-mix(in srgb, var(--fg-faint) 80%, transparent);
982
+ }
983
+
984
+ .hero-logo svg {
985
+ width: 64px;
986
+ height: 64px;
987
+ }
988
+
989
+ .empty.hero h2 {
990
+ font-size: clamp(22px, 4.2vw, 36px);
991
+ font-weight: 400;
992
+ line-height: 1.4;
993
+ letter-spacing: 0.01em;
994
+ margin: 0;
995
+ }
996
+
997
+ .hero-dir {
998
+ font: inherit;
999
+ color: inherit;
1000
+ max-width: 100%;
1001
+ border-bottom: 1.5px dotted var(--fg-faint);
1002
+ border-radius: 0;
1003
+ padding: 0;
1004
+ word-break: break-all;
1005
+ }
1006
+
1007
+ .hero-dir:hover {
1008
+ border-bottom-color: var(--fg);
1009
+ }
1010
+
1011
+ .msg-user {
1012
+ align-self: flex-end;
1013
+ max-width: 85%;
1014
+ background: var(--user-bubble);
1015
+ padding: 10px 16px;
1016
+ border-radius: 20px;
1017
+ white-space: pre-wrap;
1018
+ word-break: break-word;
1019
+ }
1020
+
1021
+ .msg-user .origin {
1022
+ display: block;
1023
+ font-size: 12px;
1024
+ color: var(--fg-faint);
1025
+ margin-bottom: 2px;
1026
+ }
1027
+
1028
+ .msg-user .files {
1029
+ margin-top: 6px;
1030
+ font-size: 13px;
1031
+ color: var(--fg-soft);
1032
+ }
1033
+
1034
+ .msg-ai {
1035
+ display: flex;
1036
+ flex-direction: column;
1037
+ gap: 6px;
1038
+ min-width: 0;
1039
+ }
1040
+
1041
+ .steps {
1042
+ font-size: 13px;
1043
+ color: var(--fg-soft);
1044
+ }
1045
+
1046
+ .steps summary {
1047
+ cursor: pointer;
1048
+ list-style: none;
1049
+ display: inline-flex;
1050
+ align-items: center;
1051
+ gap: 6px;
1052
+ padding: 2px 0;
1053
+ user-select: none;
1054
+ }
1055
+
1056
+ .steps summary::-webkit-details-marker {
1057
+ display: none;
1058
+ }
1059
+
1060
+ .steps summary::before {
1061
+ content: "›";
1062
+ display: inline-block;
1063
+ transition: transform 0.15s;
1064
+ font-size: 16px;
1065
+ line-height: 1;
1066
+ }
1067
+
1068
+ .steps[open] summary::before {
1069
+ transform: rotate(90deg);
1070
+ }
1071
+
1072
+ .steps ol {
1073
+ margin: 4px 0 0;
1074
+ padding: 6px 0 6px 14px;
1075
+ border-left: 2px solid var(--border);
1076
+ list-style: none;
1077
+ font-family: var(--mono);
1078
+ font-size: 12px;
1079
+ white-space: pre-wrap;
1080
+ word-break: break-all;
1081
+ max-height: 320px;
1082
+ overflow-y: auto;
1083
+ }
1084
+
1085
+ .spinner {
1086
+ width: 12px;
1087
+ height: 12px;
1088
+ border: 2px solid var(--border);
1089
+ border-top-color: var(--accent);
1090
+ border-radius: 50%;
1091
+ animation: spin 0.8s linear infinite;
1092
+ display: inline-block;
1093
+ }
1094
+
1095
+ @keyframes spin {
1096
+ to {
1097
+ transform: rotate(360deg);
1098
+ }
1099
+ }
1100
+
1101
+ .thinking {
1102
+ display: inline-flex;
1103
+ align-items: center;
1104
+ gap: 8px;
1105
+ color: var(--fg-faint);
1106
+ font-size: 14px;
1107
+ }
1108
+
1109
+ .footer-note {
1110
+ font-size: 12px;
1111
+ color: var(--fg-faint);
1112
+ }
1113
+
1114
+ .notice {
1115
+ align-self: center;
1116
+ font-size: 13px;
1117
+ color: var(--fg-soft);
1118
+ background: var(--bg-soft);
1119
+ padding: 6px 14px;
1120
+ border-radius: 12px;
1121
+ max-width: 90%;
1122
+ }
1123
+
1124
+ .notice .md p {
1125
+ margin: 0;
1126
+ }
1127
+
1128
+ .error-box {
1129
+ border: 1px solid var(--danger);
1130
+ color: var(--danger);
1131
+ border-radius: 10px;
1132
+ padding: 8px 12px;
1133
+ font-size: 14px;
1134
+ white-space: pre-wrap;
1135
+ }
1136
+
1137
+ /* markdown */
1138
+ .md {
1139
+ word-break: break-word;
1140
+ overflow-wrap: anywhere;
1141
+ }
1142
+
1143
+ .md > :first-child {
1144
+ margin-top: 0;
1145
+ }
1146
+
1147
+ .md > :last-child {
1148
+ margin-bottom: 0;
1149
+ }
1150
+
1151
+ .md p {
1152
+ margin: 0.6em 0;
1153
+ }
1154
+
1155
+ .md h1,
1156
+ .md h2,
1157
+ .md h3,
1158
+ .md h4 {
1159
+ margin: 1em 0 0.5em;
1160
+ line-height: 1.35;
1161
+ }
1162
+
1163
+ .md h1 {
1164
+ font-size: 1.4em;
1165
+ }
1166
+
1167
+ .md h2 {
1168
+ font-size: 1.25em;
1169
+ }
1170
+
1171
+ .md h3 {
1172
+ font-size: 1.1em;
1173
+ }
1174
+
1175
+ .md ul,
1176
+ .md ol {
1177
+ padding-left: 1.5em;
1178
+ margin: 0.5em 0;
1179
+ }
1180
+
1181
+ .md li + li {
1182
+ margin-top: 0.2em;
1183
+ }
1184
+
1185
+ .md a {
1186
+ color: var(--link);
1187
+ }
1188
+
1189
+ .md blockquote {
1190
+ margin: 0.6em 0;
1191
+ padding: 0 0 0 12px;
1192
+ border-left: 3px solid var(--border);
1193
+ color: var(--fg-soft);
1194
+ }
1195
+
1196
+ .md table {
1197
+ border-collapse: collapse;
1198
+ display: block;
1199
+ overflow-x: auto;
1200
+ margin: 0.6em 0;
1201
+ font-size: 14px;
1202
+ }
1203
+
1204
+ .md th,
1205
+ .md td {
1206
+ border: 1px solid var(--border);
1207
+ padding: 6px 10px;
1208
+ }
1209
+
1210
+ .md th {
1211
+ background: var(--bg-soft);
1212
+ }
1213
+
1214
+ .md code {
1215
+ font-family: var(--mono);
1216
+ font-size: 0.88em;
1217
+ background: var(--bg-soft);
1218
+ padding: 0.12em 0.35em;
1219
+ border-radius: 5px;
1220
+ }
1221
+
1222
+ .md pre {
1223
+ position: relative;
1224
+ background: var(--code-bg);
1225
+ border: 1px solid var(--border);
1226
+ border-radius: 10px;
1227
+ margin: 0.7em 0;
1228
+ overflow: hidden;
1229
+ }
1230
+
1231
+ .md pre .code-head {
1232
+ display: flex;
1233
+ justify-content: space-between;
1234
+ align-items: center;
1235
+ font-size: 12px;
1236
+ color: var(--fg-faint);
1237
+ padding: 4px 10px;
1238
+ border-bottom: 1px solid var(--border);
1239
+ font-family: var(--font);
1240
+ }
1241
+
1242
+ .md pre code {
1243
+ display: block;
1244
+ padding: 10px 12px;
1245
+ overflow-x: auto;
1246
+ background: transparent;
1247
+ font-size: 13px;
1248
+ line-height: 1.5;
1249
+ }
1250
+
1251
+ .md pre code.hljs {
1252
+ background: transparent;
1253
+ }
1254
+
1255
+ .copy-btn {
1256
+ font-size: 12px;
1257
+ color: var(--fg-faint);
1258
+ padding: 2px 6px;
1259
+ border-radius: 6px;
1260
+ }
1261
+
1262
+ .copy-btn:hover {
1263
+ background: var(--bg-hover);
1264
+ color: var(--fg);
1265
+ }
1266
+
1267
+ .ai-actions {
1268
+ display: flex;
1269
+ gap: 4px;
1270
+ align-items: center;
1271
+ /* 只有最后一条回复默认显示,前面的 hover 时才出来;用 opacity 占着位置,免得 hover 时内容跳动 */
1272
+ opacity: 0;
1273
+ transition: opacity 0.15s;
1274
+ }
1275
+
1276
+ .msg-ai.latest .ai-actions,
1277
+ .msg-ai:hover .ai-actions,
1278
+ .ai-actions:focus-within {
1279
+ opacity: 1;
1280
+ }
1281
+
1282
+ /* 触屏没有 hover:都显示,否则前面的回复就没法复制 / 分叉了 */
1283
+ @media (hover: none) {
1284
+ .ai-actions {
1285
+ opacity: 1;
1286
+ }
1287
+ }
1288
+
1289
+ .ai-actions .footer-note {
1290
+ margin-left: 4px;
1291
+ }
1292
+
1293
+ .conv-item .fork-mark {
1294
+ color: var(--fg-soft);
1295
+ }
1296
+
1297
+ /*
1298
+ * 分叉树:分叉对话缩进挂在主对话下面,虚线连起来。
1299
+ * 竖线从主对话标题下方往下走,每个分叉一个拐角;最后一个分叉的竖线只画到它的拐角为止。
1300
+ * 行高约 34px(.conv-item 上下 7px + 一行字),拐角在 17px 处。
1301
+ */
1302
+ .fork-children {
1303
+ margin-left: 16px;
1304
+ }
1305
+
1306
+ /* 「项目」里的会话行本身缩进 36px,竖线跟着右移 */
1307
+ .fork-children.in-proj {
1308
+ margin-left: 42px;
1309
+ }
1310
+
1311
+ /* 分叉的分叉:竖线对齐上一层分叉的标题 */
1312
+ .fork-node .fork-children {
1313
+ margin-left: 14px;
1314
+ }
1315
+
1316
+ .fork-children .conv-item,
1317
+ .fork-children .conv-item.sub {
1318
+ padding-left: 8px;
1319
+ }
1320
+
1321
+ .fork-node {
1322
+ position: relative;
1323
+ padding-left: 14px;
1324
+ }
1325
+
1326
+ .fork-node::before,
1327
+ .fork-node::after {
1328
+ content: "";
1329
+ position: absolute;
1330
+ left: 0;
1331
+ border: 0 dashed var(--fg-faint);
1332
+ opacity: 0.7;
1333
+ pointer-events: none;
1334
+ }
1335
+
1336
+ .fork-node::before {
1337
+ top: 0;
1338
+ bottom: 0;
1339
+ border-left-width: 1px;
1340
+ }
1341
+
1342
+ /* 第一个分叉的竖线往上接到主对话那一行 */
1343
+ .fork-node:first-child::before {
1344
+ top: -6px;
1345
+ }
1346
+
1347
+ .fork-node:last-child::before {
1348
+ bottom: auto;
1349
+ height: 17px;
1350
+ }
1351
+
1352
+ .fork-node:first-child:last-child::before {
1353
+ height: 23px;
1354
+ }
1355
+
1356
+ .fork-node::after {
1357
+ top: 17px;
1358
+ width: 10px;
1359
+ border-top-width: 1px;
1360
+ }
1361
+
1362
+ .ai-actions .icon-btn {
1363
+ width: 28px;
1364
+ height: 28px;
1365
+ }
1366
+
1367
+ .ai-actions .icon-btn svg {
1368
+ width: 16px;
1369
+ height: 16px;
1370
+ }
1371
+
1372
+ /* 交互卡 */
1373
+ .ix-card {
1374
+ border: 1px solid var(--warn-border);
1375
+ background: var(--warn-bg);
1376
+ border-radius: var(--radius);
1377
+ padding: 12px 14px;
1378
+ display: flex;
1379
+ flex-direction: column;
1380
+ gap: 10px;
1381
+ }
1382
+
1383
+ .ix-card.ask {
1384
+ border-color: var(--ask-border);
1385
+ background: var(--ask-bg);
1386
+ }
1387
+
1388
+ .ix-card.settled {
1389
+ background: var(--bg-soft);
1390
+ border-color: var(--border);
1391
+ opacity: 0.85;
1392
+ }
1393
+
1394
+ .ix-card .ix-title {
1395
+ font-weight: 600;
1396
+ display: flex;
1397
+ align-items: center;
1398
+ gap: 6px;
1399
+ }
1400
+
1401
+ .ix-card .ix-detail {
1402
+ font-size: 14px;
1403
+ max-height: 340px;
1404
+ overflow: auto;
1405
+ }
1406
+
1407
+ .ix-card .ix-buttons {
1408
+ display: flex;
1409
+ gap: 8px;
1410
+ flex-wrap: wrap;
1411
+ }
1412
+
1413
+ .ix-card .ix-meta {
1414
+ font-size: 12px;
1415
+ color: var(--fg-faint);
1416
+ }
1417
+
1418
+ .ix-q {
1419
+ display: flex;
1420
+ flex-direction: column;
1421
+ gap: 6px;
1422
+ }
1423
+
1424
+ .ix-q .q-head {
1425
+ font-size: 14px;
1426
+ }
1427
+
1428
+ .ix-q .q-head b {
1429
+ margin-right: 6px;
1430
+ }
1431
+
1432
+ .opt {
1433
+ text-align: left;
1434
+ border: 1px solid var(--border);
1435
+ background: var(--bg);
1436
+ border-radius: 10px;
1437
+ padding: 8px 12px;
1438
+ font-size: 14px;
1439
+ }
1440
+
1441
+ .opt:hover {
1442
+ border-color: var(--fg-faint);
1443
+ }
1444
+
1445
+ .opt.on {
1446
+ border-color: var(--accent);
1447
+ box-shadow: inset 0 0 0 1px var(--accent);
1448
+ }
1449
+
1450
+ .opt small {
1451
+ display: block;
1452
+ color: var(--fg-soft);
1453
+ font-size: 12px;
1454
+ }
1455
+
1456
+ /* ---------- 输入框 ---------- */
1457
+
1458
+ .composer-wrap {
1459
+ padding: 0 16px calc(12px + env(safe-area-inset-bottom));
1460
+ }
1461
+
1462
+ .composer-box {
1463
+ max-width: 820px;
1464
+ margin: 0 auto;
1465
+ }
1466
+
1467
+ /* 输入框上方的灰色上下文条,下沿藏在输入框后面 */
1468
+ .ctx-bar {
1469
+ display: flex;
1470
+ align-items: center;
1471
+ gap: 6px;
1472
+ margin: 0 14px -22px;
1473
+ padding: 5px 10px 27px;
1474
+ background: var(--bg-soft);
1475
+ border-radius: 16px 16px 0 0;
1476
+ font-size: 14px;
1477
+ color: var(--fg);
1478
+ }
1479
+
1480
+ .ctx-bar .spacer {
1481
+ flex: 1;
1482
+ }
1483
+
1484
+ .ctx-item {
1485
+ display: inline-flex;
1486
+ align-items: center;
1487
+ gap: 8px;
1488
+ min-width: 0;
1489
+ height: 30px;
1490
+ padding: 0 8px;
1491
+ border-radius: 999px;
1492
+ color: inherit;
1493
+ font: inherit;
1494
+ }
1495
+
1496
+ .ctx-item .label {
1497
+ overflow: hidden;
1498
+ text-overflow: ellipsis;
1499
+ white-space: nowrap;
1500
+ }
1501
+
1502
+ button.ctx-item:hover {
1503
+ background: var(--bg-hover);
1504
+ }
1505
+
1506
+ .ctx-item.static {
1507
+ flex-shrink: 0;
1508
+ }
1509
+
1510
+ .ctx-item svg {
1511
+ width: 17px;
1512
+ height: 17px;
1513
+ flex-shrink: 0;
1514
+ }
1515
+
1516
+ .ctx-bar[hidden] {
1517
+ display: none;
1518
+ }
1519
+
1520
+ .ctx-item .agent-icon {
1521
+ display: inline-grid;
1522
+ color: var(--fg-soft);
1523
+ }
1524
+
1525
+ .ctx-item .chev {
1526
+ display: inline-grid;
1527
+ margin-left: -2px;
1528
+ }
1529
+
1530
+ .ctx-item .chev svg {
1531
+ width: 13px;
1532
+ height: 13px;
1533
+ color: var(--fg-faint);
1534
+ }
1535
+
1536
+ .composer {
1537
+ background: var(--bg-input);
1538
+ border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
1539
+ border-radius: 22px;
1540
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03), 0 4px 16px rgba(0, 0, 0, 0.05);
1541
+ padding: 0;
1542
+ display: flex;
1543
+ flex-direction: column;
1544
+ gap: 0;
1545
+ }
1546
+
1547
+ .composer .icon-btn {
1548
+ width: 32px;
1549
+ height: 32px;
1550
+ }
1551
+
1552
+ .composer .icon-btn svg {
1553
+ width: 18px;
1554
+ height: 18px;
1555
+ }
1556
+
1557
+ .composer .add-btn {
1558
+ color: var(--fg);
1559
+ }
1560
+
1561
+ .composer .add-btn svg {
1562
+ width: 20px;
1563
+ height: 20px;
1564
+ }
1565
+
1566
+ /* 输入框里的按钮 hover 都用圆形 / 胶囊底,和圆形发送按钮一致 */
1567
+ .composer .icon-btn {
1568
+ border-radius: 50%;
1569
+ }
1570
+
1571
+ .model-pill {
1572
+ display: inline-flex;
1573
+ align-items: center;
1574
+ gap: 5px;
1575
+ max-width: min(260px, 45vw);
1576
+ height: 32px;
1577
+ padding: 0 10px;
1578
+ border-radius: 999px;
1579
+ font-size: 14px;
1580
+ color: var(--fg);
1581
+ white-space: nowrap;
1582
+ }
1583
+
1584
+ .model-pill:hover {
1585
+ background: var(--bg-hover);
1586
+ }
1587
+
1588
+ .model-pill .model-name {
1589
+ overflow: hidden;
1590
+ text-overflow: ellipsis;
1591
+ }
1592
+
1593
+ .model-pill .sub {
1594
+ color: var(--fg-faint);
1595
+ flex-shrink: 0;
1596
+ }
1597
+
1598
+ .model-pill svg {
1599
+ width: 13px;
1600
+ height: 13px;
1601
+ color: var(--fg-faint);
1602
+ flex-shrink: 0;
1603
+ }
1604
+
1605
+ .composer.drag {
1606
+ border-color: var(--accent);
1607
+ }
1608
+
1609
+ .composer textarea {
1610
+ border: none;
1611
+ outline: none;
1612
+ background: transparent;
1613
+ resize: none;
1614
+ padding: 14px 16px 4px;
1615
+ max-height: 40vh;
1616
+ min-height: 50px;
1617
+ line-height: 1.5;
1618
+ font-size: 16px; /* iOS 小于 16px 会自动放大页面 */
1619
+ }
1620
+
1621
+ .composer textarea::placeholder {
1622
+ color: color-mix(in srgb, var(--fg-faint) 70%, transparent);
1623
+ }
1624
+
1625
+ .composer .chips:not(:empty) {
1626
+ padding: 10px 12px 0;
1627
+ }
1628
+
1629
+ .composer-row {
1630
+ display: flex;
1631
+ align-items: center;
1632
+ gap: 2px;
1633
+ padding: 4px 10px 10px 8px;
1634
+ }
1635
+
1636
+ .composer-row .spacer {
1637
+ flex: 1;
1638
+ }
1639
+
1640
+ /* 上下文窗口圆环 + hover 气泡 */
1641
+ .ctx-ring-slot {
1642
+ display: inline-flex;
1643
+ }
1644
+
1645
+ /* 只是个指示器,不可点击:不加 hover 底色 */
1646
+ .ctx-ring {
1647
+ position: relative;
1648
+ display: inline-grid;
1649
+ place-items: center;
1650
+ width: 22px;
1651
+ height: 32px;
1652
+ margin-right: 2px;
1653
+ cursor: default;
1654
+ outline: none;
1655
+ }
1656
+
1657
+ /* 视觉修正:旁边模型名是小写英文,字形重心比行框中心低 1px 多(macOS 的 SF 字体尤其明显),
1658
+ 圆环按几何居中会显得偏高,往下挪 1px 对齐文字 */
1659
+ .ctx-ring .ring {
1660
+ display: inline-grid;
1661
+ transform: translateY(1px);
1662
+ }
1663
+
1664
+ .ctx-ring svg {
1665
+ width: 13px;
1666
+ height: 13px;
1667
+ }
1668
+
1669
+ .ctx-ring .track {
1670
+ fill: none;
1671
+ stroke: color-mix(in srgb, var(--fg-faint) 28%, transparent);
1672
+ stroke-width: 2.6;
1673
+ }
1674
+
1675
+ .ctx-ring .bar {
1676
+ fill: none;
1677
+ stroke: var(--fg-faint);
1678
+ stroke-width: 2.6;
1679
+ stroke-linecap: round;
1680
+ }
1681
+
1682
+ .ctx-ring.warn .bar {
1683
+ stroke: #f59f00;
1684
+ }
1685
+
1686
+ .ctx-ring.danger .bar {
1687
+ stroke: var(--danger);
1688
+ }
1689
+
1690
+ .ctx-ring .tip {
1691
+ position: absolute;
1692
+ bottom: calc(100% + 10px);
1693
+ left: 50%;
1694
+ transform: translate(-50%, 4px);
1695
+ display: flex;
1696
+ flex-direction: column;
1697
+ align-items: center;
1698
+ gap: 2px;
1699
+ padding: 10px 16px;
1700
+ border-radius: 12px;
1701
+ background: #1f2023;
1702
+ color: #f2f2f2;
1703
+ font-size: 13px;
1704
+ line-height: 1.5;
1705
+ white-space: nowrap;
1706
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
1707
+ opacity: 0;
1708
+ visibility: hidden;
1709
+ transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
1710
+ pointer-events: none;
1711
+ z-index: 30;
1712
+ }
1713
+
1714
+ .ctx-ring .tip-title {
1715
+ color: #a8a8a8;
1716
+ }
1717
+
1718
+ .ctx-ring:hover .tip,
1719
+ .ctx-ring:focus-visible .tip {
1720
+ opacity: 1;
1721
+ visibility: visible;
1722
+ transform: translate(-50%, 0);
1723
+ }
1724
+
1725
+ .model-slot {
1726
+ display: inline-flex;
1727
+ min-width: 0;
1728
+ }
1729
+
1730
+ .mic-btn.recording {
1731
+ color: var(--danger);
1732
+ background: color-mix(in srgb, var(--danger) 12%, transparent);
1733
+ animation: pulse 1.2s infinite;
1734
+ }
1735
+
1736
+ .send-btn {
1737
+ width: 30px;
1738
+ height: 30px;
1739
+ flex-shrink: 0;
1740
+ border-radius: 50%;
1741
+ /* 像 GPT 那样:浅色模式黑底白箭头,深色模式反过来 */
1742
+ background: var(--fg);
1743
+ color: var(--bg);
1744
+ display: grid;
1745
+ place-items: center;
1746
+ margin-left: 6px;
1747
+ }
1748
+
1749
+ .send-btn:disabled {
1750
+ opacity: 0.4;
1751
+ }
1752
+
1753
+ .send-btn svg {
1754
+ width: 15px;
1755
+ height: 15px;
1756
+ }
1757
+
1758
+ .chips {
1759
+ display: flex;
1760
+ flex-wrap: wrap;
1761
+ gap: 6px;
1762
+ padding: 0 4px;
1763
+ }
1764
+
1765
+ .chip {
1766
+ display: inline-flex;
1767
+ align-items: center;
1768
+ gap: 6px;
1769
+ background: var(--bg-soft);
1770
+ border-radius: 8px;
1771
+ padding: 4px 8px;
1772
+ font-size: 13px;
1773
+ max-width: 220px;
1774
+ }
1775
+
1776
+ .chip span {
1777
+ overflow: hidden;
1778
+ text-overflow: ellipsis;
1779
+ white-space: nowrap;
1780
+ }
1781
+
1782
+ .chip button {
1783
+ color: var(--fg-faint);
1784
+ }
1785
+
1786
+ .composer-hint {
1787
+ text-align: center;
1788
+ font-size: 12px;
1789
+ color: var(--fg-faint);
1790
+ margin-top: 6px;
1791
+ }
1792
+
1793
+ .conn-banner {
1794
+ position: absolute;
1795
+ top: calc(56px + env(safe-area-inset-top));
1796
+ left: 50%;
1797
+ transform: translateX(-50%);
1798
+ background: var(--fg);
1799
+ color: var(--bg);
1800
+ padding: 4px 12px;
1801
+ border-radius: 999px;
1802
+ font-size: 12px;
1803
+ z-index: 5;
1804
+ }
1805
+
1806
+ /* ---------- 弹层 ---------- */
1807
+
1808
+ .overlay {
1809
+ position: fixed;
1810
+ inset: 0;
1811
+ background: rgba(0, 0, 0, 0.4);
1812
+ z-index: 40;
1813
+ display: flex;
1814
+ align-items: center;
1815
+ justify-content: center;
1816
+ padding: 16px;
1817
+ }
1818
+
1819
+ /* ---- 小弹窗(重命名) ---- */
1820
+ .dialog-overlay {
1821
+ background: rgba(0, 0, 0, 0.32);
1822
+ animation: fade-in 0.12s ease-out;
1823
+ }
1824
+
1825
+ .dialog-overlay.leaving {
1826
+ opacity: 0;
1827
+ transition: opacity 0.12s;
1828
+ }
1829
+
1830
+ .dialog {
1831
+ width: min(420px, 100%);
1832
+ background: var(--bg);
1833
+ border-radius: 18px;
1834
+ padding: 20px 20px 16px;
1835
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2), 0 2px 8px rgba(0, 0, 0, 0.06);
1836
+ display: flex;
1837
+ flex-direction: column;
1838
+ animation: dialog-in 0.16s cubic-bezier(0.2, 0.9, 0.3, 1.2);
1839
+ }
1840
+
1841
+ .dialog h3 {
1842
+ margin: 0;
1843
+ font-size: 17px;
1844
+ font-weight: 600;
1845
+ }
1846
+
1847
+ .dialog-sub {
1848
+ display: flex;
1849
+ align-items: center;
1850
+ gap: 6px;
1851
+ margin: 6px 0 16px;
1852
+ font-size: 13px;
1853
+ color: var(--fg-faint);
1854
+ }
1855
+
1856
+ .dialog-sub .agent-icon {
1857
+ display: inline-grid;
1858
+ }
1859
+
1860
+ .dialog-sub .agent-icon svg {
1861
+ width: 14px;
1862
+ height: 14px;
1863
+ }
1864
+
1865
+ .rename-input {
1866
+ width: 100%;
1867
+ height: 44px;
1868
+ padding: 0 14px;
1869
+ border: 1px solid var(--border);
1870
+ border-radius: 12px;
1871
+ background: var(--bg-input);
1872
+ font-size: 15px;
1873
+ outline: none;
1874
+ transition: border-color 0.12s, box-shadow 0.12s;
1875
+ }
1876
+
1877
+ .rename-input:focus {
1878
+ border-color: var(--accent);
1879
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
1880
+ }
1881
+
1882
+ .dialog-foot {
1883
+ display: flex;
1884
+ justify-content: flex-end;
1885
+ gap: 8px;
1886
+ margin-top: 18px;
1887
+ }
1888
+
1889
+ .dialog-foot .btn {
1890
+ min-width: 72px;
1891
+ border-radius: 999px;
1892
+ padding: 8px 18px;
1893
+ }
1894
+
1895
+ .dialog-foot .btn.ghost {
1896
+ border-color: transparent;
1897
+ background: var(--bg-soft);
1898
+ }
1899
+
1900
+ .dialog-foot .btn.ghost:hover {
1901
+ background: var(--bg-hover);
1902
+ }
1903
+
1904
+ .dialog-foot .btn.primary {
1905
+ background: var(--accent);
1906
+ border-color: var(--accent);
1907
+ color: var(--accent-fg);
1908
+ }
1909
+
1910
+ @keyframes fade-in {
1911
+ from {
1912
+ opacity: 0;
1913
+ }
1914
+ }
1915
+
1916
+ @keyframes dialog-in {
1917
+ from {
1918
+ opacity: 0;
1919
+ transform: scale(0.96) translateY(6px);
1920
+ }
1921
+ }
1922
+
1923
+ .modal {
1924
+ background: var(--bg);
1925
+ border-radius: 16px;
1926
+ width: 100%;
1927
+ max-width: 560px;
1928
+ max-height: 86vh;
1929
+ display: flex;
1930
+ flex-direction: column;
1931
+ box-shadow: var(--shadow);
1932
+ overflow: hidden;
1933
+ }
1934
+
1935
+ .modal.wide {
1936
+ max-width: 860px;
1937
+ }
1938
+
1939
+ .modal-head {
1940
+ display: flex;
1941
+ align-items: center;
1942
+ padding: 14px 16px;
1943
+ border-bottom: 1px solid var(--border);
1944
+ gap: 8px;
1945
+ }
1946
+
1947
+ .modal-head h3 {
1948
+ margin: 0;
1949
+ font-size: 17px;
1950
+ flex: 1;
1951
+ }
1952
+
1953
+ .modal-body {
1954
+ padding: 14px 16px;
1955
+ overflow-y: auto;
1956
+ display: flex;
1957
+ flex-direction: column;
1958
+ gap: 12px;
1959
+ }
1960
+
1961
+ .modal-foot {
1962
+ padding: 12px 16px;
1963
+ border-top: 1px solid var(--border);
1964
+ display: flex;
1965
+ justify-content: flex-end;
1966
+ gap: 8px;
1967
+ }
1968
+
1969
+ .list-item {
1970
+ display: flex;
1971
+ align-items: center;
1972
+ gap: 10px;
1973
+ padding: 10px 12px;
1974
+ border: 1px solid var(--border);
1975
+ border-radius: 10px;
1976
+ text-align: left;
1977
+ width: 100%;
1978
+ }
1979
+
1980
+ button.list-item:hover {
1981
+ background: var(--bg-hover);
1982
+ }
1983
+
1984
+ .list-item .grow {
1985
+ flex: 1;
1986
+ min-width: 0;
1987
+ }
1988
+
1989
+ .list-item .t {
1990
+ overflow: hidden;
1991
+ text-overflow: ellipsis;
1992
+ white-space: nowrap;
1993
+ }
1994
+
1995
+ .list-item .s {
1996
+ font-size: 12px;
1997
+ color: var(--fg-faint);
1998
+ overflow: hidden;
1999
+ text-overflow: ellipsis;
2000
+ white-space: nowrap;
2001
+ }
2002
+
2003
+ .list-item.on {
2004
+ border-color: var(--accent);
2005
+ }
2006
+
2007
+ /* ----- 目录选择器 ----- */
2008
+ .dir-crumbs {
2009
+ display: flex;
2010
+ flex-wrap: wrap;
2011
+ align-items: center;
2012
+ gap: 2px;
2013
+ font-size: 14px;
2014
+ }
2015
+
2016
+ .dir-crumbs .crumb {
2017
+ padding: 2px 6px;
2018
+ border-radius: 6px;
2019
+ color: var(--accent);
2020
+ }
2021
+
2022
+ .dir-crumbs .crumb:last-child {
2023
+ color: inherit;
2024
+ font-weight: 600;
2025
+ }
2026
+
2027
+ .dir-crumbs .crumb:hover {
2028
+ background: var(--bg-hover);
2029
+ }
2030
+
2031
+ .dir-crumbs .crumb-sep {
2032
+ color: var(--fg-faint);
2033
+ }
2034
+
2035
+ .dir-list {
2036
+ display: flex;
2037
+ flex-direction: column;
2038
+ gap: 6px;
2039
+ min-height: 120px;
2040
+ max-height: 50vh;
2041
+ overflow-y: auto;
2042
+ }
2043
+
2044
+ .dir-item {
2045
+ padding: 8px 12px;
2046
+ }
2047
+
2048
+ .dir-item .dir-icon {
2049
+ width: 20px;
2050
+ text-align: center;
2051
+ }
2052
+
2053
+ .dir-item .dir-chev {
2054
+ color: var(--fg-faint);
2055
+ font-size: 18px;
2056
+ }
2057
+
2058
+ .dir-manual {
2059
+ flex: 1;
2060
+ min-width: 160px;
2061
+ padding: 8px 12px;
2062
+ border: 1px solid var(--border);
2063
+ border-radius: 10px;
2064
+ background: var(--bg-input);
2065
+ outline: none;
2066
+ }
2067
+
2068
+ .dir-manual:focus {
2069
+ border-color: var(--accent);
2070
+ }
2071
+
2072
+ .modal-foot .grow {
2073
+ flex: 1;
2074
+ }
2075
+
2076
+ .menu {
2077
+ position: fixed;
2078
+ z-index: 50;
2079
+ background: var(--bg);
2080
+ border: 1px solid var(--border);
2081
+ border-radius: 12px;
2082
+ box-shadow: var(--shadow);
2083
+ padding: 6px;
2084
+ min-width: 180px;
2085
+ display: flex;
2086
+ flex-direction: column;
2087
+ }
2088
+
2089
+ .menu button {
2090
+ text-align: left;
2091
+ padding: 8px 12px;
2092
+ border-radius: 8px;
2093
+ font-size: 14px;
2094
+ display: flex;
2095
+ align-items: center;
2096
+ gap: 8px;
2097
+ }
2098
+
2099
+ .menu button:hover {
2100
+ background: var(--bg-hover);
2101
+ }
2102
+
2103
+ /* 贴着按钮弹出的选择面板(模型 / agent) */
2104
+ .popover {
2105
+ min-width: 220px;
2106
+ max-width: min(340px, calc(100vw - 16px));
2107
+ max-height: min(70vh, 520px);
2108
+ overflow-y: auto;
2109
+ border-radius: 14px;
2110
+ padding: 6px;
2111
+ }
2112
+
2113
+ .popover .pop-head {
2114
+ font-size: 12px;
2115
+ color: var(--fg-faint);
2116
+ padding: 6px 12px 4px;
2117
+ }
2118
+
2119
+ .popover .pop-item {
2120
+ width: 100%;
2121
+ gap: 10px;
2122
+ }
2123
+
2124
+ .popover .pop-item .grow {
2125
+ flex: 1;
2126
+ min-width: 0;
2127
+ display: flex;
2128
+ flex-direction: column;
2129
+ gap: 2px;
2130
+ }
2131
+
2132
+ .popover .pop-item .s {
2133
+ font-size: 12px;
2134
+ color: var(--fg-faint);
2135
+ white-space: normal;
2136
+ }
2137
+
2138
+ .popover .pop-item .check {
2139
+ color: var(--accent);
2140
+ font-weight: 600;
2141
+ }
2142
+
2143
+ .popover .agent-icon {
2144
+ display: inline-grid;
2145
+ color: var(--fg-soft);
2146
+ }
2147
+
2148
+ .popover .agent-icon svg {
2149
+ width: 18px;
2150
+ height: 18px;
2151
+ }
2152
+
2153
+ .popover .effort-seg {
2154
+ display: flex;
2155
+ gap: 2px;
2156
+ margin: 2px 6px 6px;
2157
+ padding: 3px;
2158
+ background: var(--bg-soft);
2159
+ border-radius: 999px;
2160
+ }
2161
+
2162
+ .popover .effort-seg button {
2163
+ flex: 1;
2164
+ justify-content: center;
2165
+ padding: 5px 10px;
2166
+ border-radius: 999px;
2167
+ font-size: 13px;
2168
+ color: var(--fg-soft);
2169
+ }
2170
+
2171
+ .popover .effort-seg button.on {
2172
+ background: var(--bg);
2173
+ color: var(--fg);
2174
+ font-weight: 500;
2175
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
2176
+ }
2177
+
2178
+ .popover .pop-loading,
2179
+ .popover .pop-error {
2180
+ padding: 12px;
2181
+ font-size: 13px;
2182
+ color: var(--fg-soft);
2183
+ }
2184
+
2185
+ .menu .sep {
2186
+ height: 1px;
2187
+ background: var(--border);
2188
+ margin: 4px 0;
2189
+ }
2190
+
2191
+ .toast {
2192
+ position: fixed;
2193
+ left: 50%;
2194
+ bottom: calc(110px + env(safe-area-inset-bottom));
2195
+ transform: translateX(-50%);
2196
+ background: var(--fg);
2197
+ color: var(--bg);
2198
+ padding: 8px 16px;
2199
+ border-radius: 10px;
2200
+ font-size: 14px;
2201
+ z-index: 60;
2202
+ max-width: 90vw;
2203
+ white-space: pre-wrap;
2204
+ }
2205
+
2206
+ /* ---------- 设置 ---------- */
2207
+
2208
+ .settings {
2209
+ display: flex;
2210
+ min-height: 0;
2211
+ flex: 1;
2212
+ }
2213
+
2214
+ .settings-nav {
2215
+ width: 160px;
2216
+ border-right: 1px solid var(--border);
2217
+ padding: 8px;
2218
+ display: flex;
2219
+ flex-direction: column;
2220
+ gap: 2px;
2221
+ flex-shrink: 0;
2222
+ }
2223
+
2224
+ .settings-nav button {
2225
+ text-align: left;
2226
+ padding: 8px 10px;
2227
+ border-radius: 8px;
2228
+ font-size: 14px;
2229
+ }
2230
+
2231
+ .settings-nav button.on {
2232
+ background: var(--bg-hover);
2233
+ font-weight: 600;
2234
+ }
2235
+
2236
+ .settings-body {
2237
+ flex: 1;
2238
+ overflow-y: auto;
2239
+ padding: 16px;
2240
+ display: flex;
2241
+ flex-direction: column;
2242
+ gap: 14px;
2243
+ }
2244
+
2245
+ .section {
2246
+ border: 1px solid var(--border);
2247
+ border-radius: 12px;
2248
+ padding: 14px;
2249
+ display: flex;
2250
+ flex-direction: column;
2251
+ gap: 12px;
2252
+ }
2253
+
2254
+ .section h4 {
2255
+ margin: 0;
2256
+ font-size: 15px;
2257
+ display: flex;
2258
+ align-items: center;
2259
+ gap: 8px;
2260
+ }
2261
+
2262
+ .section h4 .grow {
2263
+ flex: 1;
2264
+ }
2265
+
2266
+ .row {
2267
+ display: flex;
2268
+ gap: 8px;
2269
+ align-items: center;
2270
+ flex-wrap: wrap;
2271
+ }
2272
+
2273
+ .check {
2274
+ display: inline-flex;
2275
+ align-items: center;
2276
+ gap: 6px;
2277
+ font-size: 14px;
2278
+ cursor: pointer;
2279
+ }
2280
+
2281
+ .status-tag {
2282
+ font-size: 12px;
2283
+ padding: 1px 8px;
2284
+ border-radius: 999px;
2285
+ background: var(--bg-soft);
2286
+ color: var(--fg-soft);
2287
+ font-weight: 400;
2288
+ }
2289
+
2290
+ .status-tag.ok {
2291
+ color: var(--ok);
2292
+ }
2293
+
2294
+ .status-tag.bad {
2295
+ color: var(--danger);
2296
+ }
2297
+
2298
+ .qr {
2299
+ align-self: center;
2300
+ background: #fff;
2301
+ padding: 8px;
2302
+ border-radius: 10px;
2303
+ }
2304
+
2305
+ .muted {
2306
+ color: var(--fg-faint);
2307
+ font-size: 13px;
2308
+ }
2309
+
2310
+ /* ---------- 手机 ---------- */
2311
+
2312
+ @media (max-width: 768px) {
2313
+ /* 侧栏和遮罩用 absolute 而不是 fixed:iOS PWA 会拿贴着顶部的 fixed 元素给状态栏上色,
2314
+ 遮罩一出来状态栏就变暗,关掉后还不恢复 */
2315
+ .sidebar {
2316
+ position: absolute;
2317
+ inset: 0 auto 0 0;
2318
+ z-index: 30;
2319
+ transform: translateX(-100%);
2320
+ transition: transform 0.2s ease;
2321
+ width: min(84vw, 320px);
2322
+ box-shadow: var(--shadow);
2323
+ }
2324
+
2325
+ .layout.side-open .sidebar {
2326
+ transform: none;
2327
+ }
2328
+
2329
+ .layout.side-open .scrim {
2330
+ position: absolute;
2331
+ inset: 0;
2332
+ background: rgba(0, 0, 0, 0.35);
2333
+ z-index: 25;
2334
+ }
2335
+
2336
+ .topbar .menu-btn {
2337
+ display: inline-grid;
2338
+ }
2339
+
2340
+ .messages-inner {
2341
+ padding: 12px 14px 20px;
2342
+ }
2343
+
2344
+ .msg-user {
2345
+ max-width: 90%;
2346
+ }
2347
+
2348
+ .md th,
2349
+ .md td {
2350
+ white-space: nowrap;
2351
+ }
2352
+
2353
+ .composer-wrap {
2354
+ padding: 0 10px calc(8px + env(safe-area-inset-bottom));
2355
+ }
2356
+
2357
+ .composer-hint {
2358
+ display: none;
2359
+ }
2360
+
2361
+ .ctx-bar {
2362
+ margin: 0 10px -22px;
2363
+ font-size: 13px;
2364
+ }
2365
+
2366
+ .hero-logo svg {
2367
+ width: 52px;
2368
+ height: 52px;
2369
+ }
2370
+
2371
+ .overlay {
2372
+ padding: 0;
2373
+ align-items: flex-end;
2374
+ }
2375
+
2376
+ /* 重命名这类小弹窗在手机上也居中,不贴底 */
2377
+ .overlay.dialog-overlay {
2378
+ padding: 16px;
2379
+ align-items: center;
2380
+ }
2381
+
2382
+ .modal,
2383
+ .modal.wide {
2384
+ max-width: none;
2385
+ max-height: 92vh;
2386
+ border-radius: 16px 16px 0 0;
2387
+ padding-bottom: env(safe-area-inset-bottom);
2388
+ }
2389
+
2390
+ .settings {
2391
+ flex-direction: column;
2392
+ }
2393
+
2394
+ .settings-nav {
2395
+ width: auto;
2396
+ flex-direction: row;
2397
+ overflow-x: auto;
2398
+ border-right: none;
2399
+ border-bottom: 1px solid var(--border);
2400
+ }
2401
+
2402
+ .settings-nav button {
2403
+ white-space: nowrap;
2404
+ }
2405
+ }
2406
+
2407
+ /* ---------- 斜杠命令补全 ---------- */
2408
+
2409
+ .composer {
2410
+ position: relative;
2411
+ }
2412
+
2413
+ .slash-menu {
2414
+ position: absolute;
2415
+ left: 0;
2416
+ right: 0;
2417
+ bottom: calc(100% + 8px);
2418
+ max-height: min(360px, 50vh);
2419
+ overflow-y: auto;
2420
+ background: var(--bg-input);
2421
+ border: 1px solid var(--border);
2422
+ border-radius: var(--radius);
2423
+ box-shadow: var(--shadow);
2424
+ padding: 6px;
2425
+ z-index: 20;
2426
+ }
2427
+
2428
+ .slash-menu[hidden] {
2429
+ display: none;
2430
+ }
2431
+
2432
+ .slash-item {
2433
+ display: block;
2434
+ width: 100%;
2435
+ text-align: left;
2436
+ padding: 8px 10px;
2437
+ border-radius: 8px;
2438
+ }
2439
+
2440
+ .slash-item.on {
2441
+ background: var(--bg-hover);
2442
+ }
2443
+
2444
+ .slash-head {
2445
+ display: flex;
2446
+ align-items: baseline;
2447
+ gap: 8px;
2448
+ min-width: 0;
2449
+ }
2450
+
2451
+ .slash-name {
2452
+ font-family: var(--mono);
2453
+ font-weight: 600;
2454
+ }
2455
+
2456
+ .slash-args {
2457
+ font-family: var(--mono);
2458
+ font-size: 12px;
2459
+ color: var(--fg-soft);
2460
+ white-space: nowrap;
2461
+ overflow: hidden;
2462
+ text-overflow: ellipsis;
2463
+ }
2464
+
2465
+ .slash-desc {
2466
+ font-size: 12px;
2467
+ color: var(--fg-faint);
2468
+ overflow: hidden;
2469
+ text-overflow: ellipsis;
2470
+ white-space: nowrap;
2471
+ }
2472
+
2473
+ .slash-empty {
2474
+ padding: 10px;
2475
+ color: var(--fg-faint);
2476
+ font-size: 13px;
2477
+ }
2478
+
2479
+ .slash-item .badge,
2480
+ .cmd-row .badge {
2481
+ font-size: 11px;
2482
+ padding: 1px 6px;
2483
+ border-radius: 6px;
2484
+ background: var(--bg-soft);
2485
+ color: var(--fg-soft);
2486
+ margin-left: 6px;
2487
+ }
2488
+
2489
+ /* ---------- 设置 → 命令 ---------- */
2490
+
2491
+ .cmd-list {
2492
+ display: flex;
2493
+ flex-direction: column;
2494
+ gap: 6px;
2495
+ max-height: 50vh;
2496
+ overflow-y: auto;
2497
+ }
2498
+
2499
+ .cmd-row {
2500
+ display: flex;
2501
+ align-items: center;
2502
+ gap: 8px;
2503
+ padding: 6px 8px;
2504
+ border: 1px solid var(--border);
2505
+ border-radius: 10px;
2506
+ background: var(--bg-input);
2507
+ }
2508
+
2509
+ .cmd-row.off {
2510
+ opacity: 0.5;
2511
+ }
2512
+
2513
+ .cmd-row.dragging {
2514
+ border-color: var(--accent);
2515
+ }
2516
+
2517
+ .cmd-row .grow {
2518
+ flex: 1;
2519
+ min-width: 0;
2520
+ }
2521
+
2522
+ .cmd-row .t {
2523
+ overflow: hidden;
2524
+ text-overflow: ellipsis;
2525
+ white-space: nowrap;
2526
+ }
2527
+
2528
+ .cmd-row .s {
2529
+ font-size: 12px;
2530
+ color: var(--fg-faint);
2531
+ overflow: hidden;
2532
+ text-overflow: ellipsis;
2533
+ white-space: nowrap;
2534
+ }
2535
+
2536
+ .cmd-grip {
2537
+ cursor: grab;
2538
+ color: var(--fg-faint);
2539
+ user-select: none;
2540
+ letter-spacing: -2px;
2541
+ }
2542
+
2543
+ .cmd-row input[type="checkbox"] {
2544
+ width: auto;
2545
+ }
2546
+
2547
+ .brand-icon {
2548
+ display: inline-grid;
2549
+ width: 18px;
2550
+ height: 18px;
2551
+ flex-shrink: 0;
2552
+ }
2553
+
2554
+ .brand-icon svg {
2555
+ width: 100%;
2556
+ height: 100%;
2557
+ }
2558
+
2559
+ /* 设置 → Agent:输入框可选模型 */
2560
+ .model-checks {
2561
+ display: flex;
2562
+ flex-direction: column;
2563
+ gap: 2px;
2564
+ border: 1px solid var(--border);
2565
+ border-radius: 10px;
2566
+ padding: 6px;
2567
+ }
2568
+
2569
+ .model-checks > small {
2570
+ padding: 4px 6px;
2571
+ }
2572
+
2573
+ .model-check {
2574
+ display: flex;
2575
+ align-items: center;
2576
+ gap: 10px;
2577
+ padding: 6px;
2578
+ border-radius: 8px;
2579
+ cursor: pointer;
2580
+ font-size: 14px;
2581
+ }
2582
+
2583
+ .model-check:hover {
2584
+ background: var(--bg-hover);
2585
+ }
2586
+
2587
+ .field .model-check input[type="checkbox"] {
2588
+ width: auto;
2589
+ padding: 0;
2590
+ flex-shrink: 0;
2591
+ }
2592
+
2593
+ .model-check .t {
2594
+ white-space: nowrap;
2595
+ }
2596
+
2597
+ .model-check .s {
2598
+ margin-left: auto;
2599
+ font-size: 12px;
2600
+ color: var(--fg-faint);
2601
+ overflow: hidden;
2602
+ text-overflow: ellipsis;
2603
+ white-space: nowrap;
2604
+ }