agent-loft 0.2.28 → 0.2.30

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/channels/web/server.ts +1 -1
  3. package/web/app.js +8 -5555
  4. package/web/css/base.css +291 -0
  5. package/web/css/composer.css +506 -0
  6. package/web/css/loader.css +196 -0
  7. package/web/css/messages.css +734 -0
  8. package/web/css/mobile.css +100 -0
  9. package/web/css/overlay.css +437 -0
  10. package/web/css/schedule.css +93 -0
  11. package/web/css/settings.css +335 -0
  12. package/web/css/sidebar.css +593 -0
  13. package/web/css/topbar.css +205 -0
  14. package/web/index.html +11 -1
  15. package/web/lib/api.js +26 -0
  16. package/web/lib/dom.js +101 -0
  17. package/web/lib/markdown.js +52 -0
  18. package/web/lib/overlay.js +144 -0
  19. package/web/lib/push.js +70 -0
  20. package/web/lib/time.js +60 -0
  21. package/web/lib/ws.js +232 -0
  22. package/web/settings/agents.js +210 -0
  23. package/web/settings/commands.js +411 -0
  24. package/web/settings/common.js +42 -0
  25. package/web/settings/feishu.js +181 -0
  26. package/web/settings/general.js +184 -0
  27. package/web/settings/index.js +63 -0
  28. package/web/settings/memory.js +366 -0
  29. package/web/settings/notify.js +80 -0
  30. package/web/settings/security.js +188 -0
  31. package/web/settings/users.js +189 -0
  32. package/web/state.js +44 -0
  33. package/web/views/auth.js +61 -0
  34. package/web/views/composer.js +324 -0
  35. package/web/views/conv-actions.js +404 -0
  36. package/web/views/interaction.js +140 -0
  37. package/web/views/layout.js +186 -0
  38. package/web/views/messages.js +510 -0
  39. package/web/views/quota.js +145 -0
  40. package/web/views/schedule.js +120 -0
  41. package/web/views/sidebar.js +455 -0
  42. package/web/views/slash.js +185 -0
  43. package/web/views/topbar.js +394 -0
  44. package/web/views/voice.js +189 -0
  45. package/web/style.css +0 -3500
package/web/style.css DELETED
@@ -1,3500 +0,0 @@
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
- /* 放在 .field 里的复选框 / 单选框不套用上面输入框的宽度和内边距:
184
- 否则复选框被撑宽,旁边的文字会被挤成两行(比如飞书机器人的「可用的 Agent」) */
185
- .field input[type="checkbox"],
186
- .field input[type="radio"] {
187
- width: auto;
188
- padding: 0;
189
- flex-shrink: 0;
190
- }
191
-
192
- .input:focus,
193
- .field input:focus,
194
- .field select:focus,
195
- .field textarea:focus {
196
- border-color: var(--accent);
197
- }
198
-
199
- .btn {
200
- display: inline-flex;
201
- align-items: center;
202
- justify-content: center;
203
- gap: 6px;
204
- padding: 8px 14px;
205
- border-radius: 10px;
206
- border: 1px solid var(--border);
207
- background: var(--bg);
208
- font-size: 14px;
209
- white-space: nowrap;
210
- }
211
-
212
- .btn:hover {
213
- background: var(--bg-hover);
214
- }
215
-
216
- .btn svg {
217
- width: 18px;
218
- height: 18px;
219
- }
220
-
221
- .btn.primary {
222
- background: var(--fg);
223
- color: var(--bg);
224
- border-color: var(--fg);
225
- }
226
-
227
- .btn.primary:hover {
228
- opacity: 0.85;
229
- }
230
-
231
- .btn.accent {
232
- background: var(--accent);
233
- border-color: var(--accent);
234
- color: var(--accent-fg);
235
- }
236
-
237
- .btn.danger {
238
- color: var(--danger);
239
- }
240
-
241
- .btn.small {
242
- padding: 4px 10px;
243
- font-size: 13px;
244
- border-radius: 8px;
245
- }
246
-
247
- .btn:disabled {
248
- opacity: 0.5;
249
- cursor: default;
250
- }
251
-
252
- .error-text {
253
- color: var(--danger);
254
- font-size: 13px;
255
- min-height: 1em;
256
- }
257
-
258
- /* ---------- 布局 ---------- */
259
-
260
- .layout {
261
- display: flex;
262
- height: 100%;
263
- overflow: hidden;
264
- position: relative;
265
- }
266
-
267
- .sidebar {
268
- width: var(--side-w);
269
- flex-shrink: 0;
270
- position: relative;
271
- background: var(--bg-side);
272
- display: flex;
273
- flex-direction: column;
274
- border-right: 1px solid var(--border);
275
- padding-top: env(safe-area-inset-top);
276
- }
277
-
278
- /* 侧栏右边缘的拖动条:hover 时显示一条细线 */
279
- .side-resizer {
280
- position: absolute;
281
- top: 0;
282
- bottom: 0;
283
- right: -4px;
284
- width: 8px;
285
- cursor: col-resize;
286
- z-index: 10;
287
- touch-action: none;
288
- }
289
-
290
- .side-resizer::after {
291
- content: "";
292
- position: absolute;
293
- top: 0;
294
- bottom: 0;
295
- left: 3px;
296
- width: 2px;
297
- background: var(--accent);
298
- opacity: 0;
299
- transition: opacity 0.15s;
300
- }
301
-
302
- .side-resizer:hover::after,
303
- .side-resizing .side-resizer::after {
304
- opacity: 0.6;
305
- transition-delay: 0.1s;
306
- }
307
-
308
- body.side-resizing {
309
- cursor: col-resize;
310
- user-select: none;
311
- }
312
-
313
- @media (max-width: 768px) {
314
- .side-resizer {
315
- display: none;
316
- }
317
- }
318
-
319
- .side-top {
320
- padding: 10px 10px 0;
321
- display: flex;
322
- gap: 8px;
323
- }
324
-
325
- .side-top .new-chat {
326
- flex: 1;
327
- justify-content: flex-start;
328
- background: transparent;
329
- border: none;
330
- /* 和下面的会话行同字号、同字重 */
331
- padding: 7px 10px;
332
- gap: 8px;
333
- font-size: 14px;
334
- font-weight: 400;
335
- }
336
-
337
- .side-top .new-chat svg {
338
- width: 16px;
339
- height: 16px;
340
- }
341
-
342
- .side-top .new-chat:hover {
343
- background: var(--bg-hover);
344
- }
345
-
346
- .conv-list {
347
- flex: 1;
348
- overflow-y: auto;
349
- padding: 0 8px 8px;
350
- }
351
-
352
- .conv-group {
353
- display: flex;
354
- align-items: center;
355
- gap: 4px;
356
- width: 100%;
357
- font-size: 13px;
358
- color: var(--fg-faint);
359
- padding: 14px 10px 6px;
360
- text-align: left;
361
- }
362
-
363
- .conv-list > .conv-group:first-child {
364
- padding-top: 8px;
365
- }
366
-
367
- /* 分组标题 hover 时显示折叠箭头 */
368
- .conv-group .chev {
369
- display: inline-grid;
370
- visibility: hidden;
371
- transition: transform 0.15s;
372
- }
373
-
374
- .conv-group .chev svg {
375
- width: 12px;
376
- height: 12px;
377
- }
378
-
379
- .conv-group:hover .chev {
380
- visibility: visible;
381
- }
382
-
383
- .conv-group.collapsed .chev {
384
- transform: rotate(-90deg);
385
- }
386
-
387
- button.conv-group:hover {
388
- color: var(--fg-soft);
389
- }
390
-
391
- .conv-empty {
392
- font-size: 13px;
393
- color: var(--fg-faint);
394
- padding: 4px 10px;
395
- }
396
-
397
- .conv-more {
398
- display: block;
399
- width: 100%;
400
- text-align: left;
401
- padding: 6px 10px;
402
- border-radius: 8px;
403
- font-size: 13px;
404
- color: var(--fg-faint);
405
- }
406
-
407
- .conv-more:hover {
408
- color: var(--fg);
409
- }
410
-
411
- .sub-more .conv-more {
412
- padding-left: 36px;
413
- }
414
-
415
- .conv-item .lead {
416
- width: 14px;
417
- height: 14px;
418
- opacity: 0.85;
419
- }
420
-
421
- .conv-item.sub {
422
- padding-left: 36px;
423
- }
424
-
425
- .proj-row {
426
- position: relative;
427
- margin-top: 2px;
428
- }
429
-
430
- .conv-item.proj {
431
- gap: 10px;
432
- }
433
-
434
- /* 拖动目录排序:被拖的行变淡,落点处画一条横线 */
435
- .proj-row.dragging {
436
- opacity: 0.4;
437
- }
438
-
439
- .proj-row.drop-before::before,
440
- .proj-row.drop-after::after {
441
- content: "";
442
- position: absolute;
443
- left: 8px;
444
- right: 8px;
445
- height: 2px;
446
- border-radius: 1px;
447
- background: var(--accent, #3b82f6);
448
- pointer-events: none;
449
- z-index: 1;
450
- }
451
-
452
- .proj-row.drop-before::before {
453
- top: -2px;
454
- }
455
-
456
- .proj-row.drop-after::after {
457
- bottom: -2px;
458
- }
459
-
460
- .proj-icon {
461
- display: inline-grid;
462
- color: var(--fg-soft);
463
- flex-shrink: 0;
464
- }
465
-
466
- .proj-icon svg {
467
- width: 18px;
468
- height: 18px;
469
- }
470
-
471
- /* 目录行 hover 时右侧出现「在此目录开新对话」 */
472
- .proj-new {
473
- position: absolute;
474
- right: 4px;
475
- top: 50%;
476
- transform: translateY(-50%);
477
- width: 28px;
478
- height: 28px;
479
- display: none;
480
- place-items: center;
481
- border-radius: 50%;
482
- color: var(--fg-soft);
483
- }
484
-
485
- .proj-new svg {
486
- width: 15px;
487
- height: 15px;
488
- }
489
-
490
- .proj-new:hover {
491
- background: var(--bg-soft);
492
- color: var(--fg);
493
- }
494
-
495
- .proj-row:hover .proj-new {
496
- display: grid;
497
- }
498
-
499
- .proj-row:hover .conv-item.proj {
500
- padding-right: 36px;
501
- }
502
-
503
- @media (pointer: coarse) {
504
- .proj-new {
505
- display: grid;
506
- }
507
- }
508
-
509
- .conv-item {
510
- display: flex;
511
- align-items: center;
512
- gap: 8px;
513
- width: 100%;
514
- text-align: left;
515
- padding: 7px 10px;
516
- border-radius: 8px;
517
- font-size: 14px;
518
- position: relative;
519
- }
520
-
521
- .conv-item:hover {
522
- background: var(--bg-hover);
523
- }
524
-
525
- .conv-item.active {
526
- background: var(--bg-hover);
527
- }
528
-
529
- .conv-item .title {
530
- flex: 1;
531
- overflow: hidden;
532
- text-overflow: ellipsis;
533
- white-space: nowrap;
534
- }
535
-
536
- /* 跑马灯滚动时去掉省略号 */
537
- .conv-item .title.marquee {
538
- text-overflow: clip;
539
- }
540
-
541
- .conv-item .badge {
542
- font-size: 11px;
543
- color: var(--fg-faint);
544
- flex-shrink: 0;
545
- }
546
-
547
- .dot {
548
- width: 8px;
549
- height: 8px;
550
- border-radius: 50%;
551
- flex-shrink: 0;
552
- }
553
-
554
- /* 进行中:Codex 那种细圈转圈,一段弧在淡色圆环上转 */
555
- .conv-spin {
556
- width: 13px;
557
- height: 13px;
558
- flex-shrink: 0;
559
- border-radius: 50%;
560
- border: 1.5px solid color-mix(in srgb, var(--fg-faint) 28%, transparent);
561
- border-top-color: var(--fg-soft);
562
- animation: spin 0.75s linear infinite;
563
- }
564
-
565
- .dot.ask {
566
- background: #f59f00;
567
- }
568
-
569
- @keyframes pulse {
570
- 50% {
571
- opacity: 0.3;
572
- }
573
- }
574
-
575
- .side-bottom {
576
- border-top: 1px solid var(--border);
577
- padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
578
- display: flex;
579
- align-items: center;
580
- gap: 6px;
581
- min-height: 48px;
582
- }
583
-
584
- .side-gear {
585
- margin-left: auto;
586
- }
587
-
588
- /* 桌面端里:设置在顶栏「更多」里,侧栏底部只留额度(额度由桌面端统一查好推过来) */
589
- .desktop-settings .side-gear {
590
- display: none;
591
- }
592
-
593
- /* ---- 侧栏底部的额度 ---- */
594
- .quota {
595
- position: relative;
596
- flex: 1;
597
- min-width: 0;
598
- }
599
-
600
- .quota-btn {
601
- display: flex;
602
- flex-direction: column;
603
- gap: 4px;
604
- width: 100%;
605
- padding: 5px 6px;
606
- border-radius: 8px;
607
- text-align: left;
608
- }
609
-
610
- .quota-btn:hover {
611
- background: var(--bg-hover);
612
- }
613
-
614
- .quota.loading .quota-btn {
615
- opacity: 0.6;
616
- }
617
-
618
- .quota-row {
619
- display: flex;
620
- align-items: center;
621
- gap: 8px;
622
- font-size: 11px;
623
- color: var(--fg-soft);
624
- font-variant-numeric: tabular-nums;
625
- }
626
-
627
- .quota-icon svg {
628
- width: 13px;
629
- height: 13px;
630
- }
631
-
632
- .quota-icon {
633
- display: inline-grid;
634
- color: var(--fg-soft);
635
- flex-shrink: 0;
636
- }
637
-
638
- .quota-cell {
639
- display: flex;
640
- align-items: center;
641
- gap: 4px;
642
- flex: 1;
643
- min-width: 0;
644
- }
645
-
646
- .q-label {
647
- color: var(--fg-faint);
648
- flex-shrink: 0;
649
- }
650
-
651
- .q-bar {
652
- flex: 1;
653
- min-width: 14px;
654
- height: 4px;
655
- border-radius: 2px;
656
- background: color-mix(in srgb, var(--fg-faint) 22%, transparent);
657
- overflow: hidden;
658
- }
659
-
660
- .q-bar i {
661
- display: block;
662
- height: 100%;
663
- border-radius: 2px;
664
- background: var(--fg-soft);
665
- }
666
-
667
- .q-pct {
668
- flex-shrink: 0;
669
- min-width: 26px;
670
- text-align: right;
671
- }
672
-
673
- .quota-cell.warn .q-bar i {
674
- background: #f59f00;
675
- }
676
-
677
- .quota-cell.danger .q-bar i {
678
- background: var(--danger);
679
- }
680
-
681
- .quota-cell.danger .q-pct {
682
- color: var(--danger);
683
- }
684
-
685
- /* hover 详情:从底部向上弹出 */
686
- .quota-tip {
687
- position: absolute;
688
- left: 0;
689
- bottom: calc(100% + 8px);
690
- width: 310px;
691
- max-width: calc(100vw - 24px);
692
- padding: 10px 12px;
693
- border-radius: 12px;
694
- background: var(--bg);
695
- border: 1px solid var(--border);
696
- box-shadow: var(--shadow);
697
- font-size: 12px;
698
- color: var(--fg-soft);
699
- display: flex;
700
- flex-direction: column;
701
- gap: 10px;
702
- opacity: 0;
703
- visibility: hidden;
704
- transform: translateY(4px);
705
- transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
706
- pointer-events: none;
707
- z-index: 20;
708
- }
709
-
710
- .quota:hover .quota-tip {
711
- opacity: 1;
712
- visibility: visible;
713
- transform: none;
714
- transition-delay: 0.25s;
715
- }
716
-
717
- .qt-head {
718
- display: flex;
719
- align-items: center;
720
- gap: 6px;
721
- color: var(--fg);
722
- margin-bottom: 4px;
723
- }
724
-
725
- .qt-head .agent-icon {
726
- display: inline-grid;
727
- }
728
-
729
- .qt-head .agent-icon svg {
730
- width: 14px;
731
- height: 14px;
732
- }
733
-
734
- .qt-plan {
735
- margin-left: auto;
736
- font-size: 11px;
737
- color: var(--fg-faint);
738
- text-transform: capitalize;
739
- }
740
-
741
- .qt-row {
742
- display: grid;
743
- grid-template-columns: auto auto 1fr;
744
- gap: 8px;
745
- padding: 2px 0 2px 20px;
746
- }
747
-
748
- .qt-name {
749
- color: var(--fg);
750
- white-space: nowrap;
751
- }
752
-
753
- .qt-pct.warn {
754
- color: #d98200;
755
- }
756
-
757
- .qt-pct.danger {
758
- color: var(--danger);
759
- }
760
-
761
- .qt-reset {
762
- text-align: right;
763
- white-space: nowrap;
764
- color: var(--fg-faint);
765
- }
766
-
767
- .qt-extra {
768
- padding-left: 20px;
769
- color: var(--fg-faint);
770
- }
771
-
772
- .qt-extra.danger {
773
- color: var(--danger);
774
- }
775
-
776
- .qt-foot {
777
- border-top: 1px solid var(--border);
778
- padding-top: 8px;
779
- font-size: 11px;
780
- color: var(--fg-faint);
781
- }
782
-
783
-
784
- .main {
785
- flex: 1;
786
- display: flex;
787
- flex-direction: column;
788
- min-width: 0;
789
- position: relative;
790
- }
791
-
792
- .topbar {
793
- display: flex;
794
- align-items: center;
795
- gap: 6px;
796
- padding: calc(8px + env(safe-area-inset-top)) 12px 8px;
797
- min-height: 52px;
798
- /*
799
- * iOS 26+ 的主屏 PWA 会在页面顶端叠一层系统的模糊渐变(Liquid Glass 边缘效果),CSS 关不掉。
800
- * WebKit 只在顶端有「fixed / sticky、铺满宽度、高于 10px、纯色不透明」的元素时跳过它,
801
- * 并改用这个颜色延伸到状态栏。所以顶栏要 sticky + 不透明底色,不能是普通的流式元素。
802
- */
803
- background: var(--bg);
804
- position: sticky;
805
- top: 0;
806
- z-index: 5;
807
- }
808
-
809
- /* 保险:主屏 PWA 里再在最顶端放一条 fixed 的纯色细条(同样是为了让 WebKit 跳过边缘模糊)。
810
- 层级低于顶栏和侧栏,和顶栏同色,看不出来 */
811
- .edge-strip {
812
- display: none;
813
- }
814
-
815
- @media (display-mode: standalone) and (max-width: 768px) {
816
- .edge-strip {
817
- display: block;
818
- position: fixed;
819
- top: 0;
820
- left: 0;
821
- right: 0;
822
- height: max(12px, env(safe-area-inset-top));
823
- background: var(--bg);
824
- pointer-events: none;
825
- z-index: 4;
826
- }
827
- }
828
-
829
- /* 顶栏下沿:渐变 + 模糊,聊天内容滚上去时柔和地消失在顶栏后面 */
830
- /*
831
- * 顶栏浮在聊天内容上面:内容一直滚到窗口顶端,经过顶栏时先变模糊、再淡出到底色,
832
- * 没有分界线(参考 Claude 桌面端)。顶栏自身比按钮行高出一截,多出来的部分就是过渡带。
833
- * iOS 主屏 PWA 例外,见下面的媒体查询。
834
- */
835
- .topbar {
836
- position: absolute;
837
- left: 0;
838
- right: 0;
839
- padding-bottom: 20px;
840
- background: linear-gradient(
841
- to bottom,
842
- var(--bg) 0%,
843
- var(--bg) calc(100% - 22px),
844
- color-mix(in srgb, var(--bg) 75%, transparent) calc(100% - 13px),
845
- color-mix(in srgb, var(--bg) 30%, transparent) calc(100% - 5px),
846
- color-mix(in srgb, var(--bg) 0%, transparent) 100%
847
- );
848
- pointer-events: none;
849
- }
850
-
851
- .topbar > * {
852
- pointer-events: auto;
853
- }
854
-
855
- /* 模糊层:上实下虚,越往下越清楚,和渐变叠在一起 */
856
- .topbar::before {
857
- content: "";
858
- position: absolute;
859
- inset: 0;
860
- z-index: -1;
861
- -webkit-backdrop-filter: blur(10px);
862
- backdrop-filter: blur(10px);
863
- -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
864
- mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
865
- pointer-events: none;
866
- }
867
-
868
- /* 内容让出顶栏按钮行的高度(.main 前缀是为了压过手机端的 padding 简写) */
869
- .main .messages-inner {
870
- padding-top: calc(72px + env(safe-area-inset-top));
871
- }
872
-
873
- .messages {
874
- scroll-padding-top: calc(72px + env(safe-area-inset-top));
875
- }
876
-
877
- /* iOS 主屏 PWA:顶端必须是不透明的 sticky 元素才能避开系统的边缘模糊,回到普通顶栏 + 下方淡出 */
878
- @media (display-mode: standalone) and (max-width: 768px) {
879
- .topbar {
880
- position: sticky;
881
- padding-bottom: 8px;
882
- background: var(--bg);
883
- }
884
-
885
- .topbar::before {
886
- display: none;
887
- }
888
-
889
- .topbar::after {
890
- content: "";
891
- position: absolute;
892
- left: 0;
893
- right: 0;
894
- top: 100%;
895
- height: 24px;
896
- pointer-events: none;
897
- background: linear-gradient(
898
- to bottom,
899
- var(--bg),
900
- color-mix(in srgb, var(--bg) 60%, transparent) 40%,
901
- color-mix(in srgb, var(--bg) 0%, transparent)
902
- );
903
- }
904
-
905
- .main .messages-inner {
906
- padding-top: 16px;
907
- }
908
- }
909
-
910
- .topbar .menu-btn {
911
- display: none;
912
- }
913
-
914
- .icon-btn {
915
- width: 36px;
916
- height: 36px;
917
- display: inline-grid;
918
- place-items: center;
919
- border-radius: 8px;
920
- flex-shrink: 0;
921
- color: var(--fg-soft);
922
- }
923
-
924
- .icon-btn:hover {
925
- background: var(--bg-hover);
926
- }
927
-
928
- .icon-btn svg {
929
- width: 20px;
930
- height: 20px;
931
- }
932
-
933
- .top-title {
934
- flex: 1;
935
- min-width: 0;
936
- display: flex;
937
- align-items: center;
938
- gap: 6px;
939
- }
940
-
941
- .top-title .conv-name {
942
- font-size: 15px;
943
- font-weight: 500;
944
- overflow: hidden;
945
- text-overflow: ellipsis;
946
- white-space: nowrap;
947
- padding: 0 4px;
948
- }
949
-
950
- .pill {
951
- display: inline-flex;
952
- align-items: center;
953
- gap: 4px;
954
- padding: 5px 10px;
955
- border-radius: 999px;
956
- font-size: 14px;
957
- font-weight: 500;
958
- max-width: 100%;
959
- white-space: nowrap;
960
- }
961
-
962
- .pill:hover {
963
- background: var(--bg-hover);
964
- }
965
-
966
-
967
- .pill .sub {
968
- color: var(--fg-faint);
969
- font-weight: 400;
970
- overflow: hidden;
971
- text-overflow: ellipsis;
972
- }
973
-
974
- .pill svg {
975
- width: 14px;
976
- height: 14px;
977
- flex-shrink: 0;
978
- }
979
-
980
- /* ---------- 消息 ---------- */
981
-
982
- .messages {
983
- flex: 1;
984
- overflow-y: auto;
985
- overscroll-behavior: contain;
986
- scroll-behavior: auto;
987
- /* 留白(.messages-spacer)按消息的 offsetTop 计算,要以滚动容器为准 */
988
- position: relative;
989
- outline: none;
990
- }
991
-
992
- /* 发出消息后把它顶到最上面用的留白,高度由 app.js 算 */
993
- .messages-spacer {
994
- height: 0;
995
- flex-shrink: 0;
996
- }
997
-
998
- /* 自己往上翻了之后出现:点一下回到底部、恢复自动滚动 */
999
- .to-bottom {
1000
- position: absolute;
1001
- left: 50%;
1002
- bottom: calc(100% + 10px);
1003
- transform: translateX(-50%);
1004
- z-index: 5;
1005
- width: 34px;
1006
- height: 34px;
1007
- border-radius: 50%;
1008
- display: grid;
1009
- place-items: center;
1010
- background: var(--bg);
1011
- color: var(--fg-soft);
1012
- border: 1px solid var(--border);
1013
- box-shadow: var(--shadow);
1014
- }
1015
-
1016
- .to-bottom:hover {
1017
- color: var(--fg);
1018
- }
1019
-
1020
- .to-bottom[hidden] {
1021
- display: none;
1022
- }
1023
-
1024
- .to-bottom svg {
1025
- width: 18px;
1026
- height: 18px;
1027
- }
1028
-
1029
- .messages-inner {
1030
- max-width: 820px;
1031
- margin: 0 auto;
1032
- padding: 16px 20px 40px;
1033
- display: flex;
1034
- flex-direction: column;
1035
- gap: 18px;
1036
- }
1037
-
1038
- .empty {
1039
- margin: auto;
1040
- text-align: center;
1041
- color: var(--fg-soft);
1042
- padding: 40px 20px;
1043
- }
1044
-
1045
- .empty h2 {
1046
- font-size: 26px;
1047
- font-weight: 600;
1048
- color: var(--fg);
1049
- margin: 0 0 8px;
1050
- }
1051
-
1052
- /* 新对话的欢迎页:居中图标 + 大标题,目录名可点击切换 */
1053
- .messages-inner:has(> .empty) {
1054
- min-height: 100%;
1055
- }
1056
-
1057
- .empty.hero {
1058
- display: flex;
1059
- flex-direction: column;
1060
- align-items: center;
1061
- gap: 22px;
1062
- }
1063
-
1064
- .hero-logo {
1065
- display: inline-grid;
1066
- color: color-mix(in srgb, var(--fg-faint) 80%, transparent);
1067
- }
1068
-
1069
- .hero-logo svg {
1070
- width: 64px;
1071
- height: 64px;
1072
- }
1073
-
1074
- .empty.hero h2 {
1075
- font-size: clamp(22px, 4.2vw, 36px);
1076
- font-weight: 400;
1077
- line-height: 1.4;
1078
- letter-spacing: 0.01em;
1079
- margin: 0;
1080
- }
1081
-
1082
- .hero-dir {
1083
- font: inherit;
1084
- color: inherit;
1085
- max-width: 100%;
1086
- border-bottom: 1.5px dotted var(--fg-faint);
1087
- border-radius: 0;
1088
- padding: 0;
1089
- word-break: break-all;
1090
- }
1091
-
1092
- .hero-dir:hover {
1093
- border-bottom-color: var(--fg);
1094
- }
1095
-
1096
- /* 用户消息:附件在上、气泡在下,整组靠右 */
1097
- .msg-user-group {
1098
- display: flex;
1099
- flex-direction: column;
1100
- align-items: flex-end;
1101
- gap: 6px;
1102
- min-width: 0;
1103
- }
1104
-
1105
- .msg-user-group > .origin {
1106
- font-size: 12px;
1107
- color: var(--fg-faint);
1108
- }
1109
-
1110
- .msg-atts {
1111
- display: flex;
1112
- flex-wrap: wrap;
1113
- justify-content: flex-end;
1114
- align-items: flex-end;
1115
- gap: 6px;
1116
- max-width: 85%;
1117
- }
1118
-
1119
- .att-img {
1120
- width: 128px;
1121
- height: 128px;
1122
- padding: 0;
1123
- border: 1px solid var(--border);
1124
- border-radius: 12px;
1125
- overflow: hidden;
1126
- background: var(--bg-soft);
1127
- cursor: zoom-in;
1128
- }
1129
-
1130
- .att-img img {
1131
- width: 100%;
1132
- height: 100%;
1133
- object-fit: cover;
1134
- display: block;
1135
- }
1136
-
1137
- .att-file {
1138
- display: flex;
1139
- align-items: center;
1140
- gap: 10px;
1141
- width: 240px;
1142
- max-width: 100%;
1143
- padding: 8px 12px 8px 8px;
1144
- border: 1px solid var(--border);
1145
- border-radius: 12px;
1146
- background: var(--bg);
1147
- color: var(--fg);
1148
- text-decoration: none;
1149
- transition: background 0.12s;
1150
- }
1151
-
1152
- a.att-file:hover {
1153
- background: var(--bg-soft);
1154
- }
1155
-
1156
- .att-file.gone {
1157
- opacity: 0.6;
1158
- }
1159
-
1160
- .att-ext {
1161
- flex-shrink: 0;
1162
- width: 36px;
1163
- height: 36px;
1164
- border-radius: 8px;
1165
- display: grid;
1166
- place-items: center;
1167
- font-size: 10px;
1168
- font-weight: 600;
1169
- letter-spacing: 0.02em;
1170
- color: #fff;
1171
- background: var(--accent);
1172
- }
1173
-
1174
- .att-meta {
1175
- display: flex;
1176
- flex-direction: column;
1177
- min-width: 0;
1178
- }
1179
-
1180
- .att-name {
1181
- font-size: 13px;
1182
- overflow: hidden;
1183
- text-overflow: ellipsis;
1184
- white-space: nowrap;
1185
- }
1186
-
1187
- .att-size {
1188
- font-size: 12px;
1189
- color: var(--fg-faint);
1190
- }
1191
-
1192
- @media (max-width: 768px) {
1193
- .att-img {
1194
- width: 96px;
1195
- height: 96px;
1196
- }
1197
- }
1198
-
1199
- .msg-user {
1200
- align-self: flex-end;
1201
- max-width: 85%;
1202
- background: var(--user-bubble);
1203
- padding: 10px 16px;
1204
- border-radius: 20px;
1205
- white-space: pre-wrap;
1206
- word-break: break-word;
1207
- }
1208
-
1209
- .msg-user .origin {
1210
- display: block;
1211
- font-size: 12px;
1212
- color: var(--fg-faint);
1213
- margin-bottom: 2px;
1214
- }
1215
-
1216
-
1217
- .msg-ai {
1218
- display: flex;
1219
- flex-direction: column;
1220
- gap: 6px;
1221
- min-width: 0;
1222
- }
1223
-
1224
- .steps {
1225
- font-size: 13px;
1226
- color: var(--fg-soft);
1227
- }
1228
-
1229
- /* 过程摘要:一行,太长就省略;折叠箭头在文字后面 */
1230
- .steps summary {
1231
- cursor: pointer;
1232
- list-style: none;
1233
- display: flex;
1234
- align-items: center;
1235
- gap: 4px;
1236
- width: fit-content;
1237
- max-width: 100%;
1238
- padding: 2px 0;
1239
- user-select: none;
1240
- }
1241
-
1242
- .steps summary .steps-text {
1243
- min-width: 0;
1244
- overflow: hidden;
1245
- text-overflow: ellipsis;
1246
- white-space: nowrap;
1247
- }
1248
-
1249
- .steps summary .chev {
1250
- flex-shrink: 0;
1251
- display: inline-block;
1252
- transition: transform 0.15s;
1253
- font-size: 16px;
1254
- line-height: 1;
1255
- }
1256
-
1257
- .steps[open] summary .chev {
1258
- transform: rotate(90deg);
1259
- }
1260
-
1261
- /* 还在跑命令 / 工具:一道光从左扫到右 */
1262
- .shimmer {
1263
- color: transparent;
1264
- background: linear-gradient(
1265
- 90deg,
1266
- var(--fg-faint) 0%,
1267
- var(--fg-faint) 40%,
1268
- var(--fg) 50%,
1269
- var(--fg-faint) 60%,
1270
- var(--fg-faint) 100%
1271
- )
1272
- 0 0 / 250% 100%;
1273
- -webkit-background-clip: text;
1274
- background-clip: text;
1275
- animation: shimmer 1.8s linear infinite;
1276
- }
1277
-
1278
- @keyframes shimmer {
1279
- from {
1280
- background-position: 100% 0;
1281
- }
1282
- to {
1283
- background-position: 0% 0;
1284
- }
1285
- }
1286
-
1287
- .steps summary::-webkit-details-marker {
1288
- display: none;
1289
- }
1290
-
1291
-
1292
- .steps ol {
1293
- margin: 4px 0 0;
1294
- padding: 6px 0 6px 14px;
1295
- border-left: 2px solid var(--border);
1296
- list-style: none;
1297
- font-family: var(--mono);
1298
- font-size: 12px;
1299
- white-space: pre-wrap;
1300
- word-break: break-all;
1301
- max-height: 320px;
1302
- overflow-y: auto;
1303
- }
1304
-
1305
- .spinner {
1306
- width: 12px;
1307
- height: 12px;
1308
- border: 2px solid var(--border);
1309
- border-top-color: var(--accent);
1310
- border-radius: 50%;
1311
- animation: spin 0.8s linear infinite;
1312
- display: inline-block;
1313
- }
1314
-
1315
- @keyframes spin {
1316
- to {
1317
- transform: rotate(360deg);
1318
- }
1319
- }
1320
-
1321
- .thinking {
1322
- display: inline-flex;
1323
- align-items: center;
1324
- gap: 8px;
1325
- color: var(--fg-faint);
1326
- font-size: 14px;
1327
- }
1328
-
1329
- /* 回复进行中的实时用时,跟在星星动画后面 */
1330
- .ai-elapsed {
1331
- font-size: 13px;
1332
- color: var(--fg-faint);
1333
- font-variant-numeric: tabular-nums;
1334
- }
1335
-
1336
- /* ---------- logo 加载动画:三颗星依次跳起,台面跟着呼吸 ---------- */
1337
- .loft-loader {
1338
- --size: 26px;
1339
- display: inline-block;
1340
- flex-shrink: 0;
1341
- width: var(--size);
1342
- height: var(--size);
1343
- line-height: 0;
1344
- }
1345
-
1346
- .loft-loader.xl {
1347
- --size: 72px;
1348
- }
1349
-
1350
- .loft-loader svg {
1351
- display: block;
1352
- width: 100%;
1353
- height: 100%;
1354
- overflow: visible;
1355
- }
1356
-
1357
- .loft-loader path {
1358
- transform-box: fill-box;
1359
- transform-origin: 50% 50%;
1360
- animation-duration: 1.6s;
1361
- animation-iteration-count: infinite;
1362
- animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
1363
- animation-fill-mode: both;
1364
- animation-delay: calc(var(--t, 0ms) + var(--d, 0ms));
1365
- }
1366
-
1367
- .loft-loader .ll-star {
1368
- animation-name: loft-star;
1369
- }
1370
-
1371
- .loft-loader .ll-l {
1372
- --d: 0ms;
1373
- }
1374
-
1375
- .loft-loader .ll-c {
1376
- --d: 180ms;
1377
- }
1378
-
1379
- .loft-loader .ll-r {
1380
- --d: 360ms;
1381
- }
1382
-
1383
- .loft-loader .ll-plate {
1384
- animation-name: loft-plate;
1385
- --d: 260ms;
1386
- }
1387
-
1388
- .loft-loader .ll-shadow {
1389
- animation-name: loft-shadow;
1390
- --d: 320ms;
1391
- }
1392
-
1393
- @keyframes loft-star {
1394
- 0%,
1395
- 70%,
1396
- 100% {
1397
- transform: translateY(0) scale(0.72);
1398
- opacity: 0.4;
1399
- }
1400
- 28% {
1401
- transform: translateY(-22px) scale(1.06);
1402
- opacity: 1;
1403
- }
1404
- 48% {
1405
- transform: translateY(0) scale(0.92);
1406
- opacity: 0.85;
1407
- }
1408
- }
1409
-
1410
- @keyframes loft-plate {
1411
- 0%,
1412
- 100% {
1413
- opacity: 0.75;
1414
- }
1415
- 45% {
1416
- opacity: 1;
1417
- }
1418
- }
1419
-
1420
- @keyframes loft-shadow {
1421
- 0%,
1422
- 100% {
1423
- transform: translateY(-6px);
1424
- opacity: 0.32;
1425
- }
1426
- 50% {
1427
- transform: translateY(6px);
1428
- opacity: 0.12;
1429
- }
1430
- }
1431
-
1432
- @media (prefers-reduced-motion: reduce) {
1433
- .loft-loader .ll-star {
1434
- animation-name: loft-star-calm;
1435
- animation-duration: 2.4s;
1436
- }
1437
- .loft-loader .ll-shadow {
1438
- animation: none;
1439
- opacity: 0.3;
1440
- }
1441
- }
1442
-
1443
- /* 回复末尾的精简版:只有一颗星,旋转 + 放大缩小 */
1444
- .loft-stars {
1445
- display: inline-block;
1446
- flex-shrink: 0;
1447
- width: 18px;
1448
- height: 18px;
1449
- line-height: 0;
1450
- }
1451
-
1452
- /* 打开会话、读历史时用的大一号 */
1453
- .loft-stars.lg {
1454
- width: 32px;
1455
- height: 32px;
1456
- }
1457
-
1458
- .loft-stars svg {
1459
- display: block;
1460
- width: 100%;
1461
- height: 100%;
1462
- overflow: visible;
1463
- }
1464
-
1465
- .loft-stars path {
1466
- transform-box: fill-box;
1467
- transform-origin: 50% 50%;
1468
- animation: loft-twirl 1.8s cubic-bezier(0.45, 0, 0.25, 1) infinite both;
1469
- animation-delay: var(--t, 0ms);
1470
- }
1471
-
1472
- /* 四角星转 90° 正好回到原样,所以每轮转 180° 能无缝接上 */
1473
- @keyframes loft-twirl {
1474
- 0% {
1475
- transform: rotate(0deg) scale(0.6);
1476
- opacity: 0.55;
1477
- }
1478
- 45% {
1479
- transform: rotate(110deg) scale(1.12);
1480
- opacity: 1;
1481
- }
1482
- 100% {
1483
- transform: rotate(180deg) scale(0.6);
1484
- opacity: 0.55;
1485
- }
1486
- }
1487
-
1488
- @media (prefers-reduced-motion: reduce) {
1489
- .loft-stars path {
1490
- animation-name: loft-star-calm;
1491
- animation-duration: 2.4s;
1492
- }
1493
- }
1494
-
1495
- @keyframes loft-star-calm {
1496
- 0%,
1497
- 100% {
1498
- opacity: 0.4;
1499
- }
1500
- 40% {
1501
- opacity: 1;
1502
- }
1503
- }
1504
-
1505
- .footer-note {
1506
- font-size: 12px;
1507
- color: var(--fg-faint);
1508
- }
1509
-
1510
- .notice {
1511
- align-self: center;
1512
- font-size: 13px;
1513
- color: var(--fg-soft);
1514
- background: var(--bg-soft);
1515
- padding: 6px 14px;
1516
- border-radius: 12px;
1517
- max-width: 90%;
1518
- }
1519
-
1520
- .notice .md p {
1521
- margin: 0;
1522
- }
1523
-
1524
- .error-box {
1525
- border: 1px solid var(--danger);
1526
- color: var(--danger);
1527
- border-radius: 10px;
1528
- padding: 8px 12px;
1529
- font-size: 14px;
1530
- white-space: pre-wrap;
1531
- }
1532
-
1533
- /* markdown */
1534
- .md {
1535
- word-break: break-word;
1536
- overflow-wrap: anywhere;
1537
- }
1538
-
1539
- .md > :first-child {
1540
- margin-top: 0;
1541
- }
1542
-
1543
- .md > :last-child {
1544
- margin-bottom: 0;
1545
- }
1546
-
1547
- .md p {
1548
- margin: 0.6em 0;
1549
- }
1550
-
1551
- .md h1,
1552
- .md h2,
1553
- .md h3,
1554
- .md h4 {
1555
- margin: 1em 0 0.5em;
1556
- line-height: 1.35;
1557
- }
1558
-
1559
- .md h1 {
1560
- font-size: 1.4em;
1561
- }
1562
-
1563
- .md h2 {
1564
- font-size: 1.25em;
1565
- }
1566
-
1567
- .md h3 {
1568
- font-size: 1.1em;
1569
- }
1570
-
1571
- .md ul,
1572
- .md ol {
1573
- padding-left: 1.5em;
1574
- margin: 0.5em 0;
1575
- }
1576
-
1577
- .md li + li {
1578
- margin-top: 0.2em;
1579
- }
1580
-
1581
- .md a {
1582
- color: var(--link);
1583
- }
1584
-
1585
- .md blockquote {
1586
- margin: 0.6em 0;
1587
- padding: 0 0 0 12px;
1588
- border-left: 3px solid var(--border);
1589
- color: var(--fg-soft);
1590
- }
1591
-
1592
- .md table {
1593
- border-collapse: collapse;
1594
- display: block;
1595
- overflow-x: auto;
1596
- margin: 0.6em 0;
1597
- font-size: 14px;
1598
- }
1599
-
1600
- .md th,
1601
- .md td {
1602
- border: 1px solid var(--border);
1603
- padding: 6px 10px;
1604
- }
1605
-
1606
- .md th {
1607
- background: var(--bg-soft);
1608
- }
1609
-
1610
- .md code {
1611
- font-family: var(--mono);
1612
- font-size: 0.88em;
1613
- background: var(--bg-soft);
1614
- padding: 0.12em 0.35em;
1615
- border-radius: 5px;
1616
- }
1617
-
1618
- .md pre {
1619
- position: relative;
1620
- background: var(--code-bg);
1621
- border: 1px solid var(--border);
1622
- border-radius: 10px;
1623
- margin: 0.7em 0;
1624
- overflow: hidden;
1625
- }
1626
-
1627
- .md pre .code-head {
1628
- display: flex;
1629
- justify-content: space-between;
1630
- align-items: center;
1631
- font-size: 12px;
1632
- color: var(--fg-faint);
1633
- padding: 4px 10px;
1634
- border-bottom: 1px solid var(--border);
1635
- font-family: var(--font);
1636
- }
1637
-
1638
- .md pre code {
1639
- display: block;
1640
- padding: 10px 12px;
1641
- overflow-x: auto;
1642
- background: transparent;
1643
- font-size: 13px;
1644
- line-height: 1.5;
1645
- }
1646
-
1647
- .md pre code.hljs {
1648
- background: transparent;
1649
- }
1650
-
1651
- .copy-btn {
1652
- font-size: 12px;
1653
- color: var(--fg-faint);
1654
- padding: 2px 6px;
1655
- border-radius: 6px;
1656
- }
1657
-
1658
- .copy-btn:hover {
1659
- background: var(--bg-hover);
1660
- color: var(--fg);
1661
- }
1662
-
1663
- .ai-actions {
1664
- display: flex;
1665
- gap: 4px;
1666
- align-items: center;
1667
- /* 只有最后一条回复默认显示,前面的 hover 时才出来;用 opacity 占着位置,免得 hover 时内容跳动 */
1668
- opacity: 0;
1669
- transition: opacity 0.15s;
1670
- }
1671
-
1672
- .msg-ai.latest .ai-actions,
1673
- .msg-ai:hover .ai-actions,
1674
- .ai-actions:focus-within {
1675
- opacity: 1;
1676
- }
1677
-
1678
- /* 触屏没有 hover:都显示,否则前面的回复就没法复制 / 分叉了 */
1679
- @media (hover: none) {
1680
- .ai-actions {
1681
- opacity: 1;
1682
- }
1683
- }
1684
-
1685
- /* 用户消息下面的复制:hover 时才出来,和回复的操作栏一样用 opacity 占着位置 */
1686
- .user-actions {
1687
- display: flex;
1688
- margin-top: -4px;
1689
- opacity: 0;
1690
- transition: opacity 0.15s;
1691
- }
1692
-
1693
- .msg-user-group:hover .user-actions,
1694
- .user-actions:focus-within {
1695
- opacity: 1;
1696
- }
1697
-
1698
- @media (hover: none) {
1699
- .user-actions {
1700
- opacity: 1;
1701
- }
1702
- }
1703
-
1704
- .user-actions .icon-btn {
1705
- width: 26px;
1706
- height: 26px;
1707
- }
1708
-
1709
- .user-actions .icon-btn svg {
1710
- width: 15px;
1711
- height: 15px;
1712
- }
1713
-
1714
- .ai-actions .footer-note {
1715
- margin-left: 4px;
1716
- }
1717
-
1718
- .conv-item .fork-mark {
1719
- color: var(--fg-soft);
1720
- }
1721
-
1722
- /*
1723
- * 分叉树:分叉对话缩进挂在主对话下面,虚线连起来。
1724
- * 竖线从主对话标题下方往下走,每个分叉一个拐角;最后一个分叉的竖线只画到它的拐角为止。
1725
- * 行高约 34px(.conv-item 上下 7px + 一行字),拐角在 17px 处。
1726
- */
1727
- .fork-children {
1728
- margin-left: 16px;
1729
- }
1730
-
1731
- /* 「项目」里的会话行本身缩进 36px,竖线跟着右移 */
1732
- .fork-children.in-proj {
1733
- margin-left: 42px;
1734
- }
1735
-
1736
- /* 分叉的分叉:竖线对齐上一层分叉的标题 */
1737
- .fork-node .fork-children {
1738
- margin-left: 14px;
1739
- }
1740
-
1741
- .fork-children .conv-item,
1742
- .fork-children .conv-item.sub {
1743
- padding-left: 8px;
1744
- }
1745
-
1746
- .fork-node {
1747
- position: relative;
1748
- padding-left: 14px;
1749
- }
1750
-
1751
- .fork-node::before,
1752
- .fork-node::after {
1753
- content: "";
1754
- position: absolute;
1755
- left: 0;
1756
- border: 0 dashed var(--fg-faint);
1757
- opacity: 0.7;
1758
- pointer-events: none;
1759
- }
1760
-
1761
- .fork-node::before {
1762
- top: 0;
1763
- bottom: 0;
1764
- border-left-width: 1px;
1765
- }
1766
-
1767
- /* 第一个分叉的竖线往上接到主对话那一行 */
1768
- .fork-node:first-child::before {
1769
- top: -6px;
1770
- }
1771
-
1772
- .fork-node:last-child::before {
1773
- bottom: auto;
1774
- height: 17px;
1775
- }
1776
-
1777
- .fork-node:first-child:last-child::before {
1778
- height: 23px;
1779
- }
1780
-
1781
- .fork-node::after {
1782
- top: 17px;
1783
- width: 10px;
1784
- border-top-width: 1px;
1785
- }
1786
-
1787
- .ai-actions .icon-btn {
1788
- width: 28px;
1789
- height: 28px;
1790
- }
1791
-
1792
- .ai-actions .icon-btn svg {
1793
- width: 16px;
1794
- height: 16px;
1795
- }
1796
-
1797
- /* 交互卡 */
1798
- .ix-card {
1799
- border: 1px solid var(--warn-border);
1800
- background: var(--warn-bg);
1801
- border-radius: var(--radius);
1802
- padding: 12px 14px;
1803
- display: flex;
1804
- flex-direction: column;
1805
- gap: 10px;
1806
- }
1807
-
1808
- .ix-card.ask {
1809
- border-color: var(--ask-border);
1810
- background: var(--ask-bg);
1811
- }
1812
-
1813
- .ix-card.settled {
1814
- background: var(--bg-soft);
1815
- border-color: var(--border);
1816
- opacity: 0.85;
1817
- }
1818
-
1819
- .ix-card .ix-title {
1820
- font-weight: 600;
1821
- display: flex;
1822
- align-items: center;
1823
- gap: 6px;
1824
- }
1825
-
1826
- .ix-card .ix-detail {
1827
- font-size: 14px;
1828
- max-height: 340px;
1829
- overflow: auto;
1830
- }
1831
-
1832
- .ix-card .ix-buttons {
1833
- display: flex;
1834
- gap: 8px;
1835
- flex-wrap: wrap;
1836
- }
1837
-
1838
- .ix-card .ix-meta {
1839
- font-size: 12px;
1840
- color: var(--fg-faint);
1841
- }
1842
-
1843
- .ix-q {
1844
- display: flex;
1845
- flex-direction: column;
1846
- gap: 6px;
1847
- }
1848
-
1849
- .ix-q .q-head {
1850
- font-size: 14px;
1851
- }
1852
-
1853
- .ix-q .q-head b {
1854
- margin-right: 6px;
1855
- }
1856
-
1857
- .opt {
1858
- text-align: left;
1859
- border: 1px solid var(--border);
1860
- background: var(--bg);
1861
- border-radius: 10px;
1862
- padding: 8px 12px;
1863
- font-size: 14px;
1864
- }
1865
-
1866
- .opt:hover {
1867
- border-color: var(--fg-faint);
1868
- }
1869
-
1870
- .opt.on {
1871
- border-color: var(--accent);
1872
- box-shadow: inset 0 0 0 1px var(--accent);
1873
- }
1874
-
1875
- .opt small {
1876
- display: block;
1877
- color: var(--fg-soft);
1878
- font-size: 12px;
1879
- }
1880
-
1881
- /* ---------- 输入框 ---------- */
1882
-
1883
- .composer-wrap {
1884
- padding: 0 16px calc(12px + env(safe-area-inset-bottom));
1885
- position: relative;
1886
- z-index: 2;
1887
- }
1888
-
1889
- /* 输入框上沿的渐变:聊天内容滚到底部时柔和地淡出,不是被一刀切开(和顶栏下沿对称)。
1890
- 右边让出滚动条的宽度,免得把滚动条也盖淡 */
1891
- .composer-wrap::before {
1892
- content: "";
1893
- position: absolute;
1894
- left: 0;
1895
- right: 10px;
1896
- bottom: 100%;
1897
- height: 32px;
1898
- pointer-events: none;
1899
- background: linear-gradient(
1900
- to top,
1901
- var(--bg),
1902
- color-mix(in srgb, var(--bg) 70%, transparent) 40%,
1903
- color-mix(in srgb, var(--bg) 0%, transparent)
1904
- );
1905
- }
1906
-
1907
- .composer-box {
1908
- max-width: 820px;
1909
- margin: 0 auto;
1910
- }
1911
-
1912
- /* 输入框上方的灰色上下文条,下沿藏在输入框后面 */
1913
- .ctx-bar {
1914
- display: flex;
1915
- align-items: center;
1916
- gap: 6px;
1917
- margin: 0 14px -22px;
1918
- padding: 5px 10px 27px;
1919
- background: var(--bg-soft);
1920
- border-radius: 16px 16px 0 0;
1921
- font-size: 14px;
1922
- color: var(--fg);
1923
- }
1924
-
1925
- .ctx-bar .spacer {
1926
- flex: 1;
1927
- }
1928
-
1929
- .ctx-item {
1930
- display: inline-flex;
1931
- align-items: center;
1932
- gap: 8px;
1933
- min-width: 0;
1934
- height: 30px;
1935
- padding: 0 8px;
1936
- border-radius: 999px;
1937
- color: inherit;
1938
- font: inherit;
1939
- }
1940
-
1941
- .ctx-item .label {
1942
- overflow: hidden;
1943
- text-overflow: ellipsis;
1944
- white-space: nowrap;
1945
- }
1946
-
1947
- button.ctx-item:hover {
1948
- background: var(--bg-hover);
1949
- }
1950
-
1951
- .ctx-item.static {
1952
- flex-shrink: 0;
1953
- }
1954
-
1955
- .ctx-item svg {
1956
- width: 17px;
1957
- height: 17px;
1958
- flex-shrink: 0;
1959
- }
1960
-
1961
- .ctx-bar[hidden] {
1962
- display: none;
1963
- }
1964
-
1965
- .ctx-item .agent-icon {
1966
- display: inline-grid;
1967
- color: var(--fg-soft);
1968
- }
1969
-
1970
- .ctx-item .chev {
1971
- display: inline-grid;
1972
- margin-left: -2px;
1973
- }
1974
-
1975
- .ctx-item .chev svg {
1976
- width: 13px;
1977
- height: 13px;
1978
- color: var(--fg-faint);
1979
- }
1980
-
1981
- .composer {
1982
- background: var(--bg-input);
1983
- border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
1984
- border-radius: 22px;
1985
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03), 0 4px 16px rgba(0, 0, 0, 0.05);
1986
- padding: 0;
1987
- display: flex;
1988
- flex-direction: column;
1989
- gap: 0;
1990
- }
1991
-
1992
- .composer .icon-btn {
1993
- width: 32px;
1994
- height: 32px;
1995
- }
1996
-
1997
- .composer .icon-btn svg {
1998
- width: 18px;
1999
- height: 18px;
2000
- }
2001
-
2002
- .composer .add-btn {
2003
- color: var(--fg);
2004
- }
2005
-
2006
- .composer .add-btn svg {
2007
- width: 20px;
2008
- height: 20px;
2009
- }
2010
-
2011
- /* 输入框里的按钮 hover 都用圆形 / 胶囊底,和圆形发送按钮一致 */
2012
- .composer .icon-btn {
2013
- border-radius: 50%;
2014
- }
2015
-
2016
- .model-pill {
2017
- display: inline-flex;
2018
- align-items: center;
2019
- gap: 5px;
2020
- max-width: min(260px, 45vw);
2021
- height: 32px;
2022
- padding: 0 10px;
2023
- border-radius: 999px;
2024
- font-size: 14px;
2025
- color: var(--fg);
2026
- white-space: nowrap;
2027
- }
2028
-
2029
- .model-pill:hover {
2030
- background: var(--bg-hover);
2031
- }
2032
-
2033
- .model-pill .model-name {
2034
- overflow: hidden;
2035
- text-overflow: ellipsis;
2036
- }
2037
-
2038
- .model-pill .sub {
2039
- color: var(--fg-faint);
2040
- flex-shrink: 0;
2041
- }
2042
-
2043
- .model-pill svg {
2044
- width: 13px;
2045
- height: 13px;
2046
- color: var(--fg-faint);
2047
- flex-shrink: 0;
2048
- }
2049
-
2050
- .mode-pill {
2051
- display: inline-flex;
2052
- align-items: center;
2053
- height: 32px;
2054
- padding: 0 10px;
2055
- border-radius: 999px;
2056
- font-size: 13px;
2057
- color: var(--fg-faint);
2058
- white-space: nowrap;
2059
- }
2060
-
2061
- .mode-pill:hover {
2062
- background: var(--bg-hover);
2063
- color: var(--fg);
2064
- }
2065
-
2066
- .mode-pill.chat {
2067
- color: var(--accent);
2068
- }
2069
-
2070
- .topbar .mode-slot {
2071
- display: inline-flex;
2072
- flex-shrink: 0;
2073
- }
2074
-
2075
- .topbar .top-more svg {
2076
- width: 20px;
2077
- height: 20px;
2078
- }
2079
-
2080
- .composer.drag {
2081
- border-color: var(--accent);
2082
- }
2083
-
2084
- .composer textarea {
2085
- border: none;
2086
- outline: none;
2087
- background: transparent;
2088
- resize: none;
2089
- padding: 14px 16px 4px;
2090
- max-height: 40vh;
2091
- min-height: 50px;
2092
- line-height: 1.5;
2093
- font-size: 16px; /* iOS 小于 16px 会自动放大页面 */
2094
- }
2095
-
2096
- .composer textarea::placeholder {
2097
- color: color-mix(in srgb, var(--fg-faint) 70%, transparent);
2098
- }
2099
-
2100
- .composer .chips:not(:empty) {
2101
- padding: 10px 12px 0;
2102
- }
2103
-
2104
- .composer-row {
2105
- display: flex;
2106
- align-items: center;
2107
- gap: 2px;
2108
- padding: 4px 10px 10px 8px;
2109
- }
2110
-
2111
- .composer-row .spacer {
2112
- flex: 1;
2113
- }
2114
-
2115
- /* 上下文窗口圆环 + hover 气泡 */
2116
- .ctx-ring-slot {
2117
- display: inline-flex;
2118
- }
2119
-
2120
- /* 只是个指示器,不可点击:不加 hover 底色 */
2121
- .ctx-ring {
2122
- position: relative;
2123
- display: inline-grid;
2124
- place-items: center;
2125
- width: 22px;
2126
- height: 32px;
2127
- margin-right: 2px;
2128
- cursor: default;
2129
- outline: none;
2130
- }
2131
-
2132
- /* 视觉修正:旁边模型名是小写英文,字形重心比行框中心低 1px 多(macOS 的 SF 字体尤其明显),
2133
- 圆环按几何居中会显得偏高,往下挪 1px 对齐文字 */
2134
- .ctx-ring .ring {
2135
- display: inline-grid;
2136
- transform: translateY(1px);
2137
- }
2138
-
2139
- .ctx-ring svg {
2140
- width: 13px;
2141
- height: 13px;
2142
- }
2143
-
2144
- .ctx-ring .track {
2145
- fill: none;
2146
- stroke: color-mix(in srgb, var(--fg-faint) 28%, transparent);
2147
- stroke-width: 2.6;
2148
- }
2149
-
2150
- .ctx-ring .bar {
2151
- fill: none;
2152
- stroke: var(--fg-faint);
2153
- stroke-width: 2.6;
2154
- stroke-linecap: round;
2155
- }
2156
-
2157
- .ctx-ring.warn .bar {
2158
- stroke: #f59f00;
2159
- }
2160
-
2161
- .ctx-ring.danger .bar {
2162
- stroke: var(--danger);
2163
- }
2164
-
2165
- .ctx-ring .tip {
2166
- position: absolute;
2167
- bottom: calc(100% + 10px);
2168
- left: 50%;
2169
- transform: translate(-50%, 4px);
2170
- display: flex;
2171
- flex-direction: column;
2172
- align-items: center;
2173
- gap: 2px;
2174
- padding: 10px 16px;
2175
- border-radius: 12px;
2176
- background: #1f2023;
2177
- color: #f2f2f2;
2178
- font-size: 13px;
2179
- line-height: 1.5;
2180
- white-space: nowrap;
2181
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
2182
- opacity: 0;
2183
- visibility: hidden;
2184
- transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
2185
- pointer-events: none;
2186
- z-index: 30;
2187
- }
2188
-
2189
- .ctx-ring .tip-title {
2190
- color: #a8a8a8;
2191
- }
2192
-
2193
- .ctx-ring:hover .tip,
2194
- .ctx-ring:focus-visible .tip {
2195
- opacity: 1;
2196
- visibility: visible;
2197
- transform: translate(-50%, 0);
2198
- }
2199
-
2200
- .model-slot {
2201
- display: inline-flex;
2202
- min-width: 0;
2203
- }
2204
-
2205
- .mic-btn.recording {
2206
- color: var(--danger);
2207
- background: color-mix(in srgb, var(--danger) 12%, transparent);
2208
- animation: pulse 1.2s infinite;
2209
- }
2210
-
2211
- .send-btn {
2212
- width: 30px;
2213
- height: 30px;
2214
- flex-shrink: 0;
2215
- border-radius: 50%;
2216
- /* 像 GPT 那样:浅色模式黑底白箭头,深色模式反过来 */
2217
- background: var(--fg);
2218
- color: var(--bg);
2219
- display: grid;
2220
- place-items: center;
2221
- margin-left: 6px;
2222
- }
2223
-
2224
- .send-btn:disabled {
2225
- opacity: 0.4;
2226
- }
2227
-
2228
- .send-btn:has(.send-spinner) {
2229
- opacity: 1;
2230
- }
2231
-
2232
- /* 发送中:按钮里转圈,颜色跟着按钮的前景色走(深浅模式都看得清) */
2233
- .send-spinner {
2234
- width: 14px;
2235
- height: 14px;
2236
- border: 2px solid currentColor;
2237
- border-right-color: transparent;
2238
- border-radius: 50%;
2239
- animation: spin 0.8s linear infinite;
2240
- }
2241
-
2242
- textarea.sending {
2243
- opacity: 0.6;
2244
- }
2245
-
2246
- .send-btn svg {
2247
- width: 15px;
2248
- height: 15px;
2249
- }
2250
-
2251
- .chips {
2252
- display: flex;
2253
- flex-wrap: wrap;
2254
- gap: 6px;
2255
- padding: 0 4px;
2256
- }
2257
-
2258
- .chip {
2259
- display: inline-flex;
2260
- align-items: center;
2261
- gap: 6px;
2262
- background: var(--bg-soft);
2263
- border-radius: 8px;
2264
- padding: 4px 8px;
2265
- font-size: 13px;
2266
- max-width: 220px;
2267
- }
2268
-
2269
- .chip span {
2270
- overflow: hidden;
2271
- text-overflow: ellipsis;
2272
- white-space: nowrap;
2273
- }
2274
-
2275
- .chip button {
2276
- color: var(--fg-faint);
2277
- }
2278
-
2279
- .composer-hint {
2280
- text-align: center;
2281
- font-size: 12px;
2282
- color: var(--fg-faint);
2283
- margin-top: 6px;
2284
- }
2285
-
2286
- .conn-banner {
2287
- position: absolute;
2288
- top: calc(56px + env(safe-area-inset-top));
2289
- left: 50%;
2290
- transform: translateX(-50%);
2291
- background: var(--fg);
2292
- color: var(--bg);
2293
- padding: 4px 12px;
2294
- border-radius: 999px;
2295
- font-size: 12px;
2296
- z-index: 5;
2297
- }
2298
-
2299
- .conn-banner.clickable {
2300
- border: 0;
2301
- font: inherit;
2302
- font-size: 12px;
2303
- cursor: pointer;
2304
- }
2305
-
2306
- /* ---------- 弹层 ---------- */
2307
-
2308
- .overlay {
2309
- position: fixed;
2310
- inset: 0;
2311
- background: rgba(0, 0, 0, 0.4);
2312
- z-index: 40;
2313
- display: flex;
2314
- align-items: center;
2315
- justify-content: center;
2316
- padding: 16px;
2317
- }
2318
-
2319
- /* ---- 小弹窗(重命名) ---- */
2320
- .dialog-overlay {
2321
- background: rgba(0, 0, 0, 0.32);
2322
- animation: fade-in 0.12s ease-out;
2323
- }
2324
-
2325
- .dialog-overlay.leaving {
2326
- opacity: 0;
2327
- transition: opacity 0.12s;
2328
- }
2329
-
2330
- .dialog {
2331
- width: min(420px, 100%);
2332
- background: var(--bg);
2333
- border-radius: 18px;
2334
- padding: 20px 20px 16px;
2335
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2), 0 2px 8px rgba(0, 0, 0, 0.06);
2336
- display: flex;
2337
- flex-direction: column;
2338
- animation: dialog-in 0.16s cubic-bezier(0.2, 0.9, 0.3, 1.2);
2339
- }
2340
-
2341
- .dialog h3 {
2342
- margin: 0;
2343
- font-size: 17px;
2344
- font-weight: 600;
2345
- }
2346
-
2347
- .dialog-sub {
2348
- display: flex;
2349
- align-items: center;
2350
- gap: 6px;
2351
- margin: 6px 0 16px;
2352
- font-size: 13px;
2353
- color: var(--fg-faint);
2354
- }
2355
-
2356
- .dialog-sub .agent-icon {
2357
- display: inline-grid;
2358
- }
2359
-
2360
- .dialog-sub .agent-icon svg {
2361
- width: 14px;
2362
- height: 14px;
2363
- }
2364
-
2365
- .rename-input {
2366
- width: 100%;
2367
- height: 44px;
2368
- padding: 0 14px;
2369
- border: 1px solid var(--border);
2370
- border-radius: 12px;
2371
- background: var(--bg-input);
2372
- font-size: 15px;
2373
- outline: none;
2374
- transition: border-color 0.12s, box-shadow 0.12s;
2375
- }
2376
-
2377
- .rename-input:focus {
2378
- border-color: var(--accent);
2379
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
2380
- }
2381
-
2382
- .dialog-foot {
2383
- display: flex;
2384
- justify-content: flex-end;
2385
- gap: 8px;
2386
- margin-top: 18px;
2387
- }
2388
-
2389
- .dialog-foot .btn {
2390
- min-width: 72px;
2391
- border-radius: 999px;
2392
- padding: 8px 18px;
2393
- }
2394
-
2395
- .dialog-foot .btn.ghost {
2396
- border-color: transparent;
2397
- background: var(--bg-soft);
2398
- }
2399
-
2400
- .dialog-foot .btn.ghost:hover {
2401
- background: var(--bg-hover);
2402
- }
2403
-
2404
- .confirm-dialog .dialog-sub {
2405
- margin-bottom: 0;
2406
- min-width: 0;
2407
- }
2408
-
2409
- .confirm-dialog .dialog-sub > span:last-child {
2410
- overflow: hidden;
2411
- text-overflow: ellipsis;
2412
- white-space: nowrap;
2413
- }
2414
-
2415
- .dialog-msg {
2416
- margin: 12px 0 0;
2417
- font-size: 14px;
2418
- line-height: 1.6;
2419
- color: var(--fg-soft);
2420
- white-space: pre-line;
2421
- }
2422
-
2423
- .dialog-foot .btn.danger-fill {
2424
- background: var(--danger);
2425
- border-color: var(--danger);
2426
- color: #fff;
2427
- }
2428
-
2429
- .dialog-foot .btn.danger-fill:hover {
2430
- background: color-mix(in srgb, var(--danger) 88%, #000);
2431
- }
2432
-
2433
- .dialog-foot .btn.primary {
2434
- background: var(--accent);
2435
- border-color: var(--accent);
2436
- color: var(--accent-fg);
2437
- }
2438
-
2439
- @keyframes fade-in {
2440
- from {
2441
- opacity: 0;
2442
- }
2443
- }
2444
-
2445
- @keyframes dialog-in {
2446
- from {
2447
- opacity: 0;
2448
- transform: scale(0.96) translateY(6px);
2449
- }
2450
- }
2451
-
2452
- .modal {
2453
- background: var(--bg);
2454
- border-radius: 16px;
2455
- width: 100%;
2456
- max-width: 560px;
2457
- max-height: 86vh;
2458
- display: flex;
2459
- flex-direction: column;
2460
- box-shadow: var(--shadow);
2461
- overflow: hidden;
2462
- }
2463
-
2464
- .modal.wide {
2465
- max-width: 860px;
2466
- }
2467
-
2468
- /* 设置弹窗:固定高度 */
2469
- .modal.tall {
2470
- height: 86vh;
2471
- }
2472
-
2473
- .modal-head {
2474
- display: flex;
2475
- align-items: center;
2476
- padding: 14px 16px;
2477
- border-bottom: 1px solid var(--border);
2478
- gap: 8px;
2479
- }
2480
-
2481
- .modal-head h3 {
2482
- margin: 0;
2483
- font-size: 17px;
2484
- flex: 1;
2485
- }
2486
-
2487
- .modal-body {
2488
- padding: 14px 16px;
2489
- overflow-y: auto;
2490
- display: flex;
2491
- flex-direction: column;
2492
- gap: 12px;
2493
- }
2494
-
2495
- .modal-foot {
2496
- padding: 12px 16px;
2497
- border-top: 1px solid var(--border);
2498
- display: flex;
2499
- justify-content: flex-end;
2500
- gap: 8px;
2501
- }
2502
-
2503
- .list-item {
2504
- display: flex;
2505
- align-items: center;
2506
- gap: 10px;
2507
- padding: 10px 12px;
2508
- border: 1px solid var(--border);
2509
- border-radius: 10px;
2510
- text-align: left;
2511
- width: 100%;
2512
- }
2513
-
2514
- button.list-item:hover {
2515
- background: var(--bg-hover);
2516
- }
2517
-
2518
- .list-item .grow {
2519
- flex: 1;
2520
- min-width: 0;
2521
- }
2522
-
2523
- .list-item .t {
2524
- overflow: hidden;
2525
- text-overflow: ellipsis;
2526
- white-space: nowrap;
2527
- }
2528
-
2529
- .list-item .s {
2530
- font-size: 12px;
2531
- color: var(--fg-faint);
2532
- overflow: hidden;
2533
- text-overflow: ellipsis;
2534
- white-space: nowrap;
2535
- }
2536
-
2537
- .list-item.on {
2538
- border-color: var(--accent);
2539
- }
2540
-
2541
- /* ----- 目录选择器 ----- */
2542
- .dir-crumbs {
2543
- display: flex;
2544
- flex-wrap: wrap;
2545
- align-items: center;
2546
- gap: 2px;
2547
- font-size: 14px;
2548
- }
2549
-
2550
- .dir-crumbs .crumb {
2551
- padding: 2px 6px;
2552
- border-radius: 6px;
2553
- color: var(--accent);
2554
- }
2555
-
2556
- .dir-crumbs .crumb:last-child {
2557
- color: inherit;
2558
- font-weight: 600;
2559
- }
2560
-
2561
- .dir-crumbs .crumb:hover {
2562
- background: var(--bg-hover);
2563
- }
2564
-
2565
- .dir-crumbs .crumb-sep {
2566
- color: var(--fg-faint);
2567
- }
2568
-
2569
- .dir-list {
2570
- display: flex;
2571
- flex-direction: column;
2572
- gap: 6px;
2573
- min-height: 120px;
2574
- max-height: 50vh;
2575
- overflow-y: auto;
2576
- }
2577
-
2578
- .dir-item {
2579
- padding: 8px 12px;
2580
- }
2581
-
2582
- .dir-item .dir-icon {
2583
- width: 20px;
2584
- text-align: center;
2585
- }
2586
-
2587
- .dir-item .dir-chev {
2588
- color: var(--fg-faint);
2589
- font-size: 18px;
2590
- }
2591
-
2592
- .dir-manual {
2593
- flex: 1;
2594
- min-width: 160px;
2595
- padding: 8px 12px;
2596
- border: 1px solid var(--border);
2597
- border-radius: 10px;
2598
- background: var(--bg-input);
2599
- outline: none;
2600
- }
2601
-
2602
- .dir-manual:focus {
2603
- border-color: var(--accent);
2604
- }
2605
-
2606
- .modal-foot .grow {
2607
- flex: 1;
2608
- }
2609
-
2610
- .menu {
2611
- position: fixed;
2612
- z-index: 50;
2613
- background: var(--bg);
2614
- border: 1px solid var(--border);
2615
- border-radius: 12px;
2616
- box-shadow: var(--shadow);
2617
- padding: 6px;
2618
- min-width: 180px;
2619
- display: flex;
2620
- flex-direction: column;
2621
- }
2622
-
2623
- .menu button {
2624
- text-align: left;
2625
- padding: 8px 12px;
2626
- border-radius: 8px;
2627
- font-size: 14px;
2628
- display: flex;
2629
- align-items: center;
2630
- gap: 8px;
2631
- }
2632
-
2633
- .menu button:hover {
2634
- background: var(--bg-hover);
2635
- }
2636
-
2637
- .menu button.danger {
2638
- color: var(--danger);
2639
- }
2640
-
2641
- /* 贴着按钮弹出的选择面板(模型 / agent) */
2642
- .popover {
2643
- min-width: 220px;
2644
- max-width: min(340px, calc(100vw - 16px));
2645
- max-height: min(70vh, 520px);
2646
- overflow-y: auto;
2647
- border-radius: 14px;
2648
- padding: 6px;
2649
- }
2650
-
2651
- .popover .pop-head {
2652
- font-size: 12px;
2653
- color: var(--fg-faint);
2654
- padding: 6px 12px 4px;
2655
- }
2656
-
2657
- .popover .pop-item {
2658
- width: 100%;
2659
- gap: 10px;
2660
- }
2661
-
2662
- .popover .pop-item .grow {
2663
- flex: 1;
2664
- min-width: 0;
2665
- display: flex;
2666
- flex-direction: column;
2667
- gap: 2px;
2668
- }
2669
-
2670
- .popover .pop-item .s {
2671
- font-size: 12px;
2672
- color: var(--fg-faint);
2673
- white-space: normal;
2674
- }
2675
-
2676
- .popover .pop-item .check {
2677
- color: var(--accent);
2678
- font-weight: 600;
2679
- }
2680
-
2681
- .popover .agent-icon {
2682
- display: inline-grid;
2683
- color: var(--fg-soft);
2684
- }
2685
-
2686
- .popover .agent-icon svg {
2687
- width: 18px;
2688
- height: 18px;
2689
- }
2690
-
2691
- .popover .effort-seg {
2692
- display: flex;
2693
- gap: 2px;
2694
- margin: 2px 6px 6px;
2695
- padding: 3px;
2696
- background: var(--bg-soft);
2697
- border-radius: 999px;
2698
- }
2699
-
2700
- .popover .effort-seg button {
2701
- flex: 1;
2702
- justify-content: center;
2703
- padding: 5px 10px;
2704
- border-radius: 999px;
2705
- font-size: 13px;
2706
- color: var(--fg-soft);
2707
- }
2708
-
2709
- .popover .effort-seg button.on {
2710
- background: var(--bg);
2711
- color: var(--fg);
2712
- font-weight: 500;
2713
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
2714
- }
2715
-
2716
- .popover .pop-loading,
2717
- .popover .pop-error {
2718
- padding: 12px;
2719
- font-size: 13px;
2720
- color: var(--fg-soft);
2721
- }
2722
-
2723
- .menu .sep {
2724
- height: 1px;
2725
- background: var(--border);
2726
- margin: 4px 0;
2727
- }
2728
-
2729
- .toast {
2730
- position: fixed;
2731
- left: 50%;
2732
- bottom: calc(110px + env(safe-area-inset-bottom));
2733
- transform: translateX(-50%);
2734
- background: var(--fg);
2735
- color: var(--bg);
2736
- padding: 8px 16px;
2737
- border-radius: 10px;
2738
- font-size: 14px;
2739
- z-index: 60;
2740
- max-width: 90vw;
2741
- white-space: pre-wrap;
2742
- }
2743
-
2744
- /* ---------- 设置 ---------- */
2745
-
2746
- .settings {
2747
- display: flex;
2748
- min-height: 0;
2749
- flex: 1;
2750
- }
2751
-
2752
- .settings-nav {
2753
- width: 160px;
2754
- border-right: 1px solid var(--border);
2755
- padding: 8px;
2756
- display: flex;
2757
- flex-direction: column;
2758
- gap: 2px;
2759
- flex-shrink: 0;
2760
- }
2761
-
2762
- .settings-nav button {
2763
- text-align: left;
2764
- padding: 8px 10px;
2765
- border-radius: 8px;
2766
- font-size: 14px;
2767
- }
2768
-
2769
- .settings-nav button.on {
2770
- background: var(--bg-hover);
2771
- font-weight: 600;
2772
- }
2773
-
2774
- .settings-body {
2775
- flex: 1;
2776
- overflow-y: auto;
2777
- padding: 16px;
2778
- display: flex;
2779
- flex-direction: column;
2780
- gap: 14px;
2781
- }
2782
-
2783
- .section {
2784
- border: 1px solid var(--border);
2785
- border-radius: 12px;
2786
- padding: 14px;
2787
- display: flex;
2788
- flex-direction: column;
2789
- gap: 12px;
2790
- }
2791
-
2792
- .section h4 {
2793
- margin: 0;
2794
- font-size: 15px;
2795
- display: flex;
2796
- align-items: center;
2797
- gap: 8px;
2798
- }
2799
-
2800
- .section h4 .grow {
2801
- flex: 1;
2802
- }
2803
-
2804
- .row {
2805
- display: flex;
2806
- gap: 8px;
2807
- align-items: center;
2808
- flex-wrap: wrap;
2809
- }
2810
-
2811
- .check {
2812
- display: inline-flex;
2813
- align-items: center;
2814
- gap: 6px;
2815
- font-size: 14px;
2816
- cursor: pointer;
2817
- }
2818
-
2819
- .status-tag {
2820
- font-size: 12px;
2821
- padding: 1px 8px;
2822
- border-radius: 999px;
2823
- background: var(--bg-soft);
2824
- color: var(--fg-soft);
2825
- font-weight: 400;
2826
- }
2827
-
2828
- .status-tag.ok {
2829
- color: var(--ok);
2830
- }
2831
-
2832
- .status-tag.bad {
2833
- color: var(--danger);
2834
- }
2835
-
2836
- .qr {
2837
- align-self: center;
2838
- background: #fff;
2839
- padding: 8px;
2840
- border-radius: 10px;
2841
- }
2842
-
2843
- .muted {
2844
- color: var(--fg-faint);
2845
- font-size: 13px;
2846
- }
2847
-
2848
- /* ---------- 手机 ---------- */
2849
-
2850
- @media (max-width: 768px) {
2851
- /* 侧栏和遮罩用 absolute 而不是 fixed:iOS PWA 会拿贴着顶部的 fixed 元素给状态栏上色,
2852
- 遮罩一出来状态栏就变暗,关掉后还不恢复 */
2853
- .sidebar {
2854
- position: absolute;
2855
- inset: 0 auto 0 0;
2856
- z-index: 30;
2857
- transform: translateX(-100%);
2858
- transition: transform 0.2s ease;
2859
- width: min(84vw, 320px);
2860
- box-shadow: var(--shadow);
2861
- }
2862
-
2863
- .layout.side-open .sidebar {
2864
- transform: none;
2865
- }
2866
-
2867
- .layout.side-open .scrim {
2868
- position: absolute;
2869
- inset: 0;
2870
- background: rgba(0, 0, 0, 0.35);
2871
- z-index: 25;
2872
- }
2873
-
2874
- .topbar .menu-btn {
2875
- display: inline-grid;
2876
- }
2877
-
2878
- .messages-inner {
2879
- padding: 12px 14px 36px;
2880
- }
2881
-
2882
- .msg-user {
2883
- max-width: 90%;
2884
- }
2885
-
2886
- .md th,
2887
- .md td {
2888
- white-space: nowrap;
2889
- }
2890
-
2891
- .composer-wrap {
2892
- padding: 0 10px calc(8px + env(safe-area-inset-bottom));
2893
- }
2894
-
2895
- .composer-hint {
2896
- display: none;
2897
- }
2898
-
2899
- .ctx-bar {
2900
- margin: 0 10px -22px;
2901
- font-size: 13px;
2902
- }
2903
-
2904
- .hero-logo svg {
2905
- width: 52px;
2906
- height: 52px;
2907
- }
2908
-
2909
- .overlay {
2910
- padding: 0;
2911
- align-items: flex-end;
2912
- }
2913
-
2914
- /* 重命名这类小弹窗在手机上也居中,不贴底 */
2915
- .overlay.dialog-overlay {
2916
- padding: 16px;
2917
- align-items: center;
2918
- }
2919
-
2920
- .modal.tall {
2921
- height: 92vh;
2922
- }
2923
-
2924
- .modal,
2925
- .modal.wide {
2926
- max-width: none;
2927
- max-height: 92vh;
2928
- border-radius: 16px 16px 0 0;
2929
- padding-bottom: env(safe-area-inset-bottom);
2930
- }
2931
-
2932
- .settings {
2933
- flex-direction: column;
2934
- }
2935
-
2936
- .settings-nav {
2937
- width: auto;
2938
- flex-direction: row;
2939
- overflow-x: auto;
2940
- border-right: none;
2941
- border-bottom: 1px solid var(--border);
2942
- }
2943
-
2944
- .settings-nav button {
2945
- white-space: nowrap;
2946
- }
2947
- }
2948
-
2949
- /* ---------- 斜杠命令补全 ---------- */
2950
-
2951
- .composer {
2952
- position: relative;
2953
- }
2954
-
2955
- .slash-menu {
2956
- position: absolute;
2957
- left: 0;
2958
- right: 0;
2959
- bottom: calc(100% + 8px);
2960
- max-height: min(360px, 50vh);
2961
- overflow-y: auto;
2962
- background: var(--bg-input);
2963
- border: 1px solid var(--border);
2964
- border-radius: var(--radius);
2965
- box-shadow: var(--shadow);
2966
- padding: 6px;
2967
- z-index: 20;
2968
- }
2969
-
2970
- .slash-menu[hidden] {
2971
- display: none;
2972
- }
2973
-
2974
- .slash-item {
2975
- display: block;
2976
- width: 100%;
2977
- text-align: left;
2978
- padding: 8px 10px;
2979
- border-radius: 8px;
2980
- }
2981
-
2982
- .slash-item.on {
2983
- background: var(--bg-hover);
2984
- }
2985
-
2986
- .slash-head {
2987
- display: flex;
2988
- align-items: baseline;
2989
- gap: 8px;
2990
- min-width: 0;
2991
- }
2992
-
2993
- .slash-name {
2994
- font-family: var(--mono);
2995
- font-weight: 600;
2996
- }
2997
-
2998
- .slash-args {
2999
- font-family: var(--mono);
3000
- font-size: 12px;
3001
- color: var(--fg-soft);
3002
- white-space: nowrap;
3003
- overflow: hidden;
3004
- text-overflow: ellipsis;
3005
- }
3006
-
3007
- .slash-desc {
3008
- font-size: 12px;
3009
- color: var(--fg-faint);
3010
- overflow: hidden;
3011
- text-overflow: ellipsis;
3012
- white-space: nowrap;
3013
- }
3014
-
3015
- .slash-empty {
3016
- padding: 10px;
3017
- color: var(--fg-faint);
3018
- font-size: 13px;
3019
- }
3020
-
3021
- .slash-item .badge,
3022
- .cmd-row .badge {
3023
- font-size: 11px;
3024
- padding: 1px 6px;
3025
- border-radius: 6px;
3026
- background: var(--bg-soft);
3027
- color: var(--fg-soft);
3028
- margin-left: 6px;
3029
- }
3030
-
3031
- /* ---------- 设置 → 命令 ---------- */
3032
-
3033
- .cmd-list {
3034
- display: flex;
3035
- flex-direction: column;
3036
- gap: 6px;
3037
- max-height: 50vh;
3038
- overflow-y: auto;
3039
- }
3040
-
3041
- .cmd-row {
3042
- display: flex;
3043
- align-items: center;
3044
- gap: 8px;
3045
- padding: 6px 8px;
3046
- border: 1px solid var(--border);
3047
- border-radius: 10px;
3048
- background: var(--bg-input);
3049
- }
3050
-
3051
- .cmd-row.off {
3052
- opacity: 0.5;
3053
- }
3054
-
3055
- .cmd-row.dragging {
3056
- border-color: var(--accent);
3057
- }
3058
-
3059
- .cmd-row .grow {
3060
- flex: 1;
3061
- min-width: 0;
3062
- }
3063
-
3064
- .cmd-row .t {
3065
- overflow: hidden;
3066
- text-overflow: ellipsis;
3067
- white-space: nowrap;
3068
- }
3069
-
3070
- .cmd-row .s {
3071
- font-size: 12px;
3072
- color: var(--fg-faint);
3073
- overflow: hidden;
3074
- text-overflow: ellipsis;
3075
- white-space: nowrap;
3076
- }
3077
-
3078
- .cmd-grip {
3079
- cursor: grab;
3080
- color: var(--fg-faint);
3081
- user-select: none;
3082
- letter-spacing: -2px;
3083
- }
3084
-
3085
- .cmd-row input[type="checkbox"] {
3086
- width: auto;
3087
- }
3088
-
3089
- .cmd-row .icon-btn svg {
3090
- width: 16px;
3091
- height: 16px;
3092
- }
3093
-
3094
- .cmd-row .icon-btn.danger:hover {
3095
- color: var(--danger);
3096
- }
3097
-
3098
- .cmd-row .badge.custom {
3099
- background: color-mix(in srgb, var(--accent) 12%, transparent);
3100
- color: var(--accent);
3101
- }
3102
-
3103
- /* 筛选框 + 「添加命令」按钮一行 */
3104
- .cmd-tools {
3105
- flex-wrap: nowrap;
3106
- }
3107
-
3108
- .cmd-tools .input {
3109
- flex: 1;
3110
- min-width: 0;
3111
- }
3112
-
3113
- .cmd-tools .btn {
3114
- flex-shrink: 0;
3115
- display: inline-flex;
3116
- align-items: center;
3117
- gap: 4px;
3118
- }
3119
-
3120
- .cmd-tools .btn svg {
3121
- width: 16px;
3122
- height: 16px;
3123
- }
3124
-
3125
- /* 添加 / 编辑命令:命令名前面固定一个「/」 */
3126
- .cmd-name-input {
3127
- display: flex;
3128
- align-items: center;
3129
- gap: 6px;
3130
- }
3131
-
3132
- .cmd-name-input > span {
3133
- color: var(--fg-faint);
3134
- font-family: var(--mono);
3135
- }
3136
-
3137
- .field .cmd-name-input input {
3138
- flex: 1;
3139
- font-family: var(--mono);
3140
- }
3141
-
3142
- .brand-icon {
3143
- display: inline-grid;
3144
- width: 18px;
3145
- height: 18px;
3146
- flex-shrink: 0;
3147
- }
3148
-
3149
- .brand-icon svg {
3150
- width: 100%;
3151
- height: 100%;
3152
- }
3153
-
3154
- /* 设置 → Agent:输入框可选模型 */
3155
- .model-checks {
3156
- display: flex;
3157
- flex-direction: column;
3158
- gap: 2px;
3159
- border: 1px solid var(--border);
3160
- border-radius: 10px;
3161
- padding: 6px;
3162
- }
3163
-
3164
- .model-checks > small {
3165
- padding: 4px 6px;
3166
- }
3167
-
3168
- .model-check {
3169
- display: flex;
3170
- align-items: center;
3171
- gap: 10px;
3172
- padding: 6px;
3173
- border-radius: 8px;
3174
- cursor: pointer;
3175
- font-size: 14px;
3176
- }
3177
-
3178
- .model-check:hover {
3179
- background: var(--bg-hover);
3180
- }
3181
-
3182
- .field .model-check input[type="checkbox"] {
3183
- width: auto;
3184
- padding: 0;
3185
- flex-shrink: 0;
3186
- }
3187
-
3188
- .model-check .t {
3189
- white-space: nowrap;
3190
- }
3191
-
3192
- .model-check .s {
3193
- margin-left: auto;
3194
- font-size: 12px;
3195
- color: var(--fg-faint);
3196
- overflow: hidden;
3197
- text-overflow: ellipsis;
3198
- white-space: nowrap;
3199
- }
3200
-
3201
- /* ---------- 滚动条:细、无边框、无轨道,像 Codex ---------- */
3202
- ::-webkit-scrollbar {
3203
- width: 8px;
3204
- height: 8px;
3205
- }
3206
- ::-webkit-scrollbar-track,
3207
- ::-webkit-scrollbar-corner {
3208
- background: transparent;
3209
- }
3210
- ::-webkit-scrollbar-thumb {
3211
- background: color-mix(in srgb, var(--fg-faint) 32%, transparent);
3212
- border-radius: 999px;
3213
- border: 2px solid transparent;
3214
- background-clip: content-box;
3215
- }
3216
- ::-webkit-scrollbar-thumb:hover {
3217
- background-color: color-mix(in srgb, var(--fg-faint) 55%, transparent);
3218
- }
3219
- ::-webkit-scrollbar-button {
3220
- display: none;
3221
- }
3222
- /* 不认 ::-webkit-scrollbar 的浏览器(Firefox)用标准属性;Chrome 里设了标准属性会盖掉上面的,所以分开 */
3223
- @supports not selector(::-webkit-scrollbar) {
3224
- * {
3225
- scrollbar-width: thin;
3226
- scrollbar-color: color-mix(in srgb, var(--fg-faint) 40%, transparent) transparent;
3227
- }
3228
- }
3229
-
3230
- /* ---------- 图片附件:缩略图 + 点开看大图 ---------- */
3231
- .chip-img {
3232
- position: relative;
3233
- width: 56px;
3234
- height: 56px;
3235
- border-radius: 10px;
3236
- overflow: hidden;
3237
- background: var(--bg-soft);
3238
- flex-shrink: 0;
3239
- }
3240
- .chip-img img {
3241
- width: 100%;
3242
- height: 100%;
3243
- object-fit: cover;
3244
- display: block;
3245
- cursor: zoom-in;
3246
- }
3247
- .chip-img.uploading img {
3248
- opacity: 0.5;
3249
- }
3250
- .chip-img .spinner {
3251
- position: absolute;
3252
- left: 50%;
3253
- top: 50%;
3254
- margin: -6px 0 0 -6px;
3255
- pointer-events: none;
3256
- }
3257
- .chip-img .chip-x {
3258
- position: absolute;
3259
- top: 3px;
3260
- right: 3px;
3261
- width: 18px;
3262
- height: 18px;
3263
- border-radius: 50%;
3264
- background: rgba(0, 0, 0, 0.6);
3265
- color: #fff;
3266
- font-size: 13px;
3267
- line-height: 18px;
3268
- text-align: center;
3269
- padding: 0;
3270
- opacity: 0;
3271
- transition: opacity 0.12s;
3272
- }
3273
- .chip-img:hover .chip-x {
3274
- opacity: 1;
3275
- }
3276
- @media (hover: none) {
3277
- .chip-img .chip-x {
3278
- opacity: 1;
3279
- }
3280
- }
3281
-
3282
-
3283
- .lightbox {
3284
- position: fixed;
3285
- inset: 0;
3286
- z-index: 60;
3287
- background: rgba(0, 0, 0, 0.82);
3288
- display: flex;
3289
- flex-direction: column;
3290
- align-items: center;
3291
- justify-content: center;
3292
- gap: 10px;
3293
- padding: 24px;
3294
- cursor: zoom-out;
3295
- animation: fade-in 0.12s ease-out;
3296
- }
3297
- .lightbox img {
3298
- max-width: 100%;
3299
- max-height: calc(100% - 32px);
3300
- object-fit: contain;
3301
- border-radius: 6px;
3302
- box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5);
3303
- }
3304
-
3305
- .lightbox-bar {
3306
- display: flex;
3307
- align-items: center;
3308
- gap: 14px;
3309
- cursor: default;
3310
- }
3311
-
3312
- .lightbox-name {
3313
- color: rgba(255, 255, 255, 0.75);
3314
- font-size: 13px;
3315
- }
3316
-
3317
- .lightbox-dl {
3318
- color: #fff;
3319
- font-size: 13px;
3320
- text-decoration: none;
3321
- padding: 4px 14px;
3322
- border-radius: 999px;
3323
- background: rgba(255, 255, 255, 0.16);
3324
- }
3325
-
3326
- .lightbox-dl:hover {
3327
- background: rgba(255, 255, 255, 0.26);
3328
- }
3329
-
3330
- /* 设置 → Agent → 运行环境 */
3331
- .health-row {
3332
- display: flex;
3333
- flex-direction: column;
3334
- gap: 6px;
3335
- }
3336
- .health-row + .health-row {
3337
- border-top: 1px solid var(--border);
3338
- padding-top: 12px;
3339
- }
3340
- .health-head {
3341
- display: flex;
3342
- align-items: center;
3343
- gap: 8px;
3344
- }
3345
- .health-dot {
3346
- width: 8px;
3347
- height: 8px;
3348
- border-radius: 50%;
3349
- background: var(--danger);
3350
- flex: none;
3351
- }
3352
- .health-dot.ok {
3353
- background: var(--ok);
3354
- }
3355
- .health-state {
3356
- color: var(--fg-soft);
3357
- }
3358
- .health-off,
3359
- .health-meta {
3360
- color: var(--fg-faint);
3361
- font-size: 12px;
3362
- }
3363
- .health-fix {
3364
- display: flex;
3365
- flex-direction: column;
3366
- gap: 6px;
3367
- padding: 10px 12px;
3368
- border-radius: 10px;
3369
- background: var(--warn-bg);
3370
- border: 1px solid var(--warn-border);
3371
- font-size: 13px;
3372
- }
3373
- .health-fix small {
3374
- color: var(--fg-soft);
3375
- }
3376
- .health-cmd {
3377
- display: flex;
3378
- align-items: center;
3379
- gap: 8px;
3380
- }
3381
- .health-cmd code {
3382
- flex: 1;
3383
- min-width: 0;
3384
- overflow-x: auto;
3385
- white-space: nowrap;
3386
- padding: 5px 8px;
3387
- border-radius: 6px;
3388
- background: var(--code-bg);
3389
- font-size: 12px;
3390
- }
3391
-
3392
- /* 桌面端(Agent Loft for macOS)里:顶栏和侧栏顶部按住能拖动窗口,里面的按钮照常能点 */
3393
- .in-desktop .topbar,
3394
- .in-desktop .side-top {
3395
- -webkit-app-region: drag;
3396
- }
3397
- .in-desktop .topbar :is(button, a, input, select, textarea, label, .conv-name),
3398
- .in-desktop .side-top :is(button, a, input, select, textarea, label) {
3399
- -webkit-app-region: no-drag;
3400
- }
3401
-
3402
- /* ---------- 定时发送 ---------- */
3403
-
3404
- .sched-bar {
3405
- display: flex;
3406
- flex-direction: column;
3407
- gap: 4px;
3408
- margin: 0 14px 6px;
3409
- }
3410
-
3411
- .sched-bar[hidden] {
3412
- display: none;
3413
- }
3414
-
3415
- .sched-item {
3416
- display: flex;
3417
- align-items: center;
3418
- gap: 8px;
3419
- min-width: 0;
3420
- padding: 6px 6px 6px 10px;
3421
- border: 1px solid var(--border);
3422
- border-radius: 12px;
3423
- background: var(--bg-soft);
3424
- font-size: 13px;
3425
- color: var(--fg-soft);
3426
- }
3427
-
3428
- .sched-item svg {
3429
- width: 15px;
3430
- height: 15px;
3431
- flex-shrink: 0;
3432
- color: var(--accent);
3433
- }
3434
-
3435
- .sched-when {
3436
- flex-shrink: 0;
3437
- color: var(--fg);
3438
- font-weight: 500;
3439
- }
3440
-
3441
- .sched-text {
3442
- flex: 1;
3443
- min-width: 0;
3444
- overflow: hidden;
3445
- text-overflow: ellipsis;
3446
- white-space: nowrap;
3447
- }
3448
-
3449
- .sched-act {
3450
- flex-shrink: 0;
3451
- padding: 3px 8px;
3452
- border-radius: 8px;
3453
- font-size: 12px;
3454
- color: var(--fg-soft);
3455
- }
3456
-
3457
- .sched-act:hover {
3458
- background: var(--bg-hover);
3459
- color: var(--fg);
3460
- }
3461
-
3462
- .sched-input {
3463
- width: 100%;
3464
- box-sizing: border-box;
3465
- resize: vertical;
3466
- padding: 10px 12px;
3467
- border: 1px solid var(--border);
3468
- border-radius: 10px;
3469
- background: var(--bg-input);
3470
- color: var(--fg);
3471
- font: inherit;
3472
- }
3473
-
3474
- .sched-hint {
3475
- font-size: 12px;
3476
- line-height: 1.6;
3477
- }
3478
-
3479
- .sched-row {
3480
- display: flex;
3481
- align-items: center;
3482
- gap: 10px;
3483
- }
3484
-
3485
- .sched-time {
3486
- flex: 1;
3487
- padding: 7px 10px;
3488
- border: 1px solid var(--border);
3489
- border-radius: 10px;
3490
- background: var(--bg-input);
3491
- color: var(--fg);
3492
- font: inherit;
3493
- color-scheme: light dark;
3494
- }
3495
-
3496
- /* iOS 上双击会放大页面:关掉双击缩放(双指缩放照常) */
3497
- html,
3498
- body {
3499
- touch-action: manipulation;
3500
- }