nonebot-plugin-botui 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,1774 @@
1
+ /* ==========================================================================
2
+ BotUI · 静态样式表
3
+ 深色为默认主题,浅色主题通过 <html data-theme="light"> 切换。
4
+ 全部使用 CSS 变量,无外部字体 / 图片依赖。
5
+ ========================================================================== */
6
+
7
+ /* ---------- 主题变量 ---------- */
8
+ :root {
9
+ --font: system-ui, -apple-system, "Segoe UI", Roboto, "PingFang SC",
10
+ "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
11
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
12
+
13
+ --accent: #0099ff;
14
+ --accent-strong: #0084e0;
15
+ --accent-text: #7cc4ff;
16
+ --accent-soft: rgba(0, 153, 255, 0.14);
17
+ --danger: #ff3b30;
18
+ --ok: #22c55e;
19
+ --warn: #f59e0b;
20
+
21
+ --radius-sm: 6px;
22
+ --radius: 10px;
23
+ --radius-lg: 14px;
24
+ --sidebar-w: 300px;
25
+ --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
26
+ }
27
+
28
+ html[data-theme="dark"] {
29
+ --bg: #101216;
30
+ --bg-soft: #15181d;
31
+ --panel: #1a1e24;
32
+ --panel-2: #20252c;
33
+ --panel-3: #262c34;
34
+ --hover: rgba(255, 255, 255, 0.045);
35
+ --active: rgba(255, 255, 255, 0.07);
36
+ --border: rgba(255, 255, 255, 0.08);
37
+ --border-strong: rgba(255, 255, 255, 0.14);
38
+ --text: #e9ecf1;
39
+ --text-dim: #b6bec9;
40
+ --muted: #8b95a3;
41
+ --faint: #6a7482;
42
+ --bubble-in: #242a33;
43
+ --bubble-in-text: #e9ecf1;
44
+ --bubble-out: #0099ff;
45
+ --bubble-out-text: #ffffff;
46
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
47
+ --shadow: 0 6px 20px rgba(0, 0, 0, 0.42);
48
+ --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.6);
49
+ --scroll: rgba(255, 255, 255, 0.16);
50
+ --scroll-hover: rgba(255, 255, 255, 0.3);
51
+ --skel: linear-gradient(90deg, rgba(255, 255, 255, 0.04) 25%,
52
+ rgba(255, 255, 255, 0.09) 37%, rgba(255, 255, 255, 0.04) 63%);
53
+ }
54
+
55
+ html[data-theme="light"] {
56
+ --bg: #eef1f5;
57
+ --bg-soft: #f6f8fa;
58
+ --panel: #ffffff;
59
+ --panel-2: #f4f6f9;
60
+ --panel-3: #e9edf2;
61
+ --hover: rgba(15, 23, 42, 0.045);
62
+ --active: rgba(15, 23, 42, 0.075);
63
+ --border: rgba(15, 23, 42, 0.09);
64
+ --border-strong: rgba(15, 23, 42, 0.16);
65
+ --text: #16191d;
66
+ --text-dim: #3c434c;
67
+ --muted: #6b7480;
68
+ --faint: #949ca7;
69
+ --bubble-in: #ffffff;
70
+ --bubble-in-text: #16191d;
71
+ --bubble-out: #0099ff;
72
+ --bubble-out-text: #ffffff;
73
+ --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.08);
74
+ --shadow: 0 6px 20px rgba(15, 23, 42, 0.12);
75
+ --shadow-lg: 0 18px 50px rgba(15, 23, 42, 0.22);
76
+ --scroll: rgba(15, 23, 42, 0.18);
77
+ --scroll-hover: rgba(15, 23, 42, 0.34);
78
+ --skel: linear-gradient(90deg, rgba(15, 23, 42, 0.05) 25%,
79
+ rgba(15, 23, 42, 0.1) 37%, rgba(15, 23, 42, 0.05) 63%);
80
+ }
81
+
82
+ /* ---------- 基础重置 ---------- */
83
+ * { box-sizing: border-box; }
84
+
85
+ html, body { height: 100%; }
86
+
87
+ body {
88
+ margin: 0;
89
+ font-family: var(--font);
90
+ font-size: 14px;
91
+ line-height: 1.5;
92
+ color: var(--text);
93
+ background: var(--bg);
94
+ -webkit-font-smoothing: antialiased;
95
+ text-rendering: optimizeLegibility;
96
+ overflow: hidden;
97
+ }
98
+
99
+ button, input, textarea { font: inherit; color: inherit; }
100
+ button { cursor: pointer; border: none; background: none; }
101
+ img { display: block; max-width: 100%; }
102
+ :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
103
+
104
+ /* hidden 属性优先级最高,避免被 display:flex 之类的规则覆盖 */
105
+ [hidden] { display: none !important; }
106
+
107
+ svg {
108
+ width: 18px;
109
+ height: 18px;
110
+ fill: none;
111
+ stroke: currentColor;
112
+ stroke-width: 1.9;
113
+ stroke-linecap: round;
114
+ stroke-linejoin: round;
115
+ }
116
+
117
+ /* 细滚动条 */
118
+ * { scrollbar-width: thin; scrollbar-color: var(--scroll) transparent; }
119
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
120
+ ::-webkit-scrollbar-track { background: transparent; }
121
+ ::-webkit-scrollbar-thumb {
122
+ background: var(--scroll);
123
+ border-radius: 99px;
124
+ border: 2px solid transparent;
125
+ background-clip: padding-box;
126
+ }
127
+ ::-webkit-scrollbar-thumb:hover { background: var(--scroll-hover); background-clip: padding-box; }
128
+
129
+ /* ---------- 应用骨架 ---------- */
130
+ .app {
131
+ display: grid;
132
+ grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
133
+ height: 100vh;
134
+ height: 100dvh;
135
+ }
136
+
137
+ /* ---------- 侧边栏 ---------- */
138
+ .sidebar {
139
+ display: flex;
140
+ flex-direction: column;
141
+ min-height: 0;
142
+ background: var(--panel);
143
+ border-right: 1px solid var(--border);
144
+ }
145
+
146
+ .sidebar-head {
147
+ padding: 12px 12px 10px;
148
+ border-bottom: 1px solid var(--border);
149
+ }
150
+
151
+ .sidebar-title-row {
152
+ display: flex;
153
+ align-items: center;
154
+ justify-content: space-between;
155
+ gap: 8px;
156
+ margin-bottom: 10px;
157
+ }
158
+
159
+ .brand { display: flex; align-items: center; gap: 8px; min-width: 0; }
160
+
161
+ .brand-mark {
162
+ width: 22px;
163
+ height: 22px;
164
+ border-radius: 7px;
165
+ background: linear-gradient(135deg, var(--accent), #4fc3ff 55%, #7c5cff);
166
+ box-shadow: var(--shadow-sm);
167
+ position: relative;
168
+ flex: none;
169
+ }
170
+ .brand-mark::after {
171
+ content: "";
172
+ position: absolute;
173
+ inset: 6px 5px auto 5px;
174
+ height: 2px;
175
+ border-radius: 2px;
176
+ background: rgba(255, 255, 255, 0.9);
177
+ box-shadow: 0 4px 0 rgba(255, 255, 255, 0.65), 0 8px 0 rgba(255, 255, 255, 0.4);
178
+ }
179
+
180
+ .brand-text { font-size: 15px; font-weight: 650; letter-spacing: 0.2px; }
181
+
182
+ .icon-btn {
183
+ display: inline-flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ width: 30px;
187
+ height: 30px;
188
+ border-radius: 8px;
189
+ color: var(--muted);
190
+ transition: background 0.15s var(--ease), color 0.15s var(--ease);
191
+ flex: none;
192
+ }
193
+ .icon-btn:hover { background: var(--hover); color: var(--text); }
194
+ .icon-btn:active { background: var(--active); }
195
+
196
+ /* 会话头部的「备注」按钮:比普通图标钮小一号,紧跟在会话名后面 */
197
+ .head-rename { width: 22px; height: 22px; border-radius: 6px; }
198
+ .head-rename svg { width: 14px; height: 14px; }
199
+
200
+ /* 主题按钮:深色显示太阳,浅色显示月亮 */
201
+ .ico-sun, .ico-moon { display: none; }
202
+ html[data-theme="dark"] .ico-sun { display: block; }
203
+ html[data-theme="light"] .ico-moon { display: block; }
204
+
205
+ .search-wrap { position: relative; }
206
+
207
+ .search-ico {
208
+ position: absolute;
209
+ left: 9px;
210
+ top: 50%;
211
+ transform: translateY(-50%);
212
+ width: 15px;
213
+ height: 15px;
214
+ color: var(--faint);
215
+ pointer-events: none;
216
+ }
217
+
218
+ .search-input {
219
+ width: 100%;
220
+ height: 32px;
221
+ padding: 0 30px 0 30px;
222
+ border-radius: 8px;
223
+ border: 1px solid transparent;
224
+ background: var(--panel-2);
225
+ color: var(--text);
226
+ font-size: 13px;
227
+ transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
228
+ }
229
+ .search-input::placeholder { color: var(--faint); }
230
+ .search-input:focus {
231
+ outline: none;
232
+ border-color: var(--accent);
233
+ background: var(--panel-3);
234
+ }
235
+ .search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
236
+
237
+ /* 清空按钮:有内容时才出现 */
238
+ .search-clear {
239
+ position: absolute;
240
+ right: 6px;
241
+ top: 50%;
242
+ transform: translateY(-50%);
243
+ width: 20px;
244
+ height: 20px;
245
+ display: inline-flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ border-radius: 50%;
249
+ font-size: 11px;
250
+ color: var(--muted);
251
+ background: var(--panel-3);
252
+ transition: color 0.15s var(--ease), background 0.15s var(--ease);
253
+ }
254
+ .search-clear:hover { color: var(--text); background: var(--border-strong); }
255
+
256
+ /* 搜索范围切换:会话 / 消息 */
257
+ .search-tabs {
258
+ display: flex;
259
+ gap: 4px;
260
+ margin-top: 7px;
261
+ }
262
+ .search-tab {
263
+ flex: 1;
264
+ height: 26px;
265
+ border-radius: 7px;
266
+ font-size: 12px;
267
+ color: var(--muted);
268
+ background: var(--panel-2);
269
+ transition: color 0.15s var(--ease), background 0.15s var(--ease);
270
+ }
271
+ .search-tab:hover { color: var(--text); }
272
+ .search-tab.active { color: var(--accent-text); background: var(--accent-soft); font-weight: 600; }
273
+
274
+ /* ---------- 会话列表 ---------- */
275
+ .chat-list {
276
+ flex: 1;
277
+ min-height: 0;
278
+ overflow-y: auto;
279
+ overscroll-behavior: contain;
280
+ padding: 6px;
281
+ }
282
+
283
+ /* ---------- 消息搜索结果 ---------- */
284
+ .msg-results {
285
+ flex: 1;
286
+ min-height: 0;
287
+ overflow-y: auto;
288
+ overscroll-behavior: contain;
289
+ padding: 6px;
290
+ }
291
+ .hit-item {
292
+ padding: 8px 9px;
293
+ border-radius: var(--radius);
294
+ cursor: pointer;
295
+ transition: background 0.13s var(--ease);
296
+ }
297
+ .hit-item:hover { background: var(--hover); }
298
+ .hit-item:active { background: var(--active); }
299
+ .hit-top {
300
+ display: flex;
301
+ align-items: baseline;
302
+ justify-content: space-between;
303
+ gap: 8px;
304
+ margin-bottom: 3px;
305
+ }
306
+ .hit-chat {
307
+ font-size: 12.5px;
308
+ font-weight: 600;
309
+ color: var(--text);
310
+ overflow: hidden;
311
+ text-overflow: ellipsis;
312
+ white-space: nowrap;
313
+ }
314
+ .hit-time { flex: none; font-size: 11px; color: var(--faint); }
315
+ .hit-text {
316
+ font-size: 12.5px;
317
+ line-height: 1.5;
318
+ color: var(--text-dim);
319
+ display: -webkit-box;
320
+ -webkit-line-clamp: 2;
321
+ line-clamp: 2;
322
+ -webkit-box-orient: vertical;
323
+ overflow: hidden;
324
+ word-break: break-word;
325
+ }
326
+ .hit-who { color: var(--muted); }
327
+ .hit-text mark.hit {
328
+ background: rgba(255, 214, 10, 0.28);
329
+ color: inherit;
330
+ border-radius: 3px;
331
+ padding: 0 1px;
332
+ }
333
+ html[data-theme="light"] .hit-text mark.hit { background: rgba(255, 200, 0, 0.42); }
334
+
335
+ .chat-item {
336
+ display: flex;
337
+ gap: 10px;
338
+ align-items: center;
339
+ padding: 8px 9px;
340
+ border-radius: var(--radius);
341
+ cursor: pointer;
342
+ transition: background 0.13s var(--ease);
343
+ position: relative;
344
+ user-select: none;
345
+ }
346
+ .chat-item:hover { background: var(--hover); }
347
+ .chat-item.active { background: var(--accent-soft); }
348
+ .chat-item.active::before {
349
+ content: "";
350
+ position: absolute;
351
+ left: 0;
352
+ top: 12px;
353
+ bottom: 12px;
354
+ width: 3px;
355
+ border-radius: 0 3px 3px 0;
356
+ background: var(--accent);
357
+ }
358
+
359
+ .chat-item-main { flex: 1; min-width: 0; }
360
+
361
+ .chat-item-top {
362
+ display: flex;
363
+ align-items: baseline;
364
+ gap: 8px;
365
+ margin-bottom: 2px;
366
+ }
367
+
368
+ .chat-item-name {
369
+ flex: 1;
370
+ min-width: 0;
371
+ font-size: 13.5px;
372
+ font-weight: 600;
373
+ white-space: nowrap;
374
+ overflow: hidden;
375
+ text-overflow: ellipsis;
376
+ }
377
+
378
+ .chat-item-time {
379
+ font-size: 11px;
380
+ color: var(--faint);
381
+ flex: none;
382
+ font-variant-numeric: tabular-nums;
383
+ }
384
+
385
+ .chat-item-bottom {
386
+ display: flex;
387
+ align-items: center;
388
+ gap: 6px;
389
+ min-height: 18px;
390
+ }
391
+
392
+ .chat-item-last {
393
+ flex: 1;
394
+ min-width: 0;
395
+ font-size: 12.5px;
396
+ color: var(--muted);
397
+ white-space: nowrap;
398
+ overflow: hidden;
399
+ text-overflow: ellipsis;
400
+ }
401
+
402
+ .unread-pill {
403
+ flex: none;
404
+ min-width: 18px;
405
+ height: 18px;
406
+ padding: 0 5px;
407
+ border-radius: 9px;
408
+ background: var(--danger);
409
+ color: #fff;
410
+ font-size: 11px;
411
+ font-weight: 600;
412
+ line-height: 18px;
413
+ text-align: center;
414
+ font-variant-numeric: tabular-nums;
415
+ }
416
+ .unread-pill.muted { background: var(--panel-3); color: var(--faint); font-weight: 500; }
417
+
418
+ /* 头像:图片或首字彩色圆 */
419
+ .avatar {
420
+ flex: none;
421
+ width: 36px;
422
+ height: 36px;
423
+ border-radius: 50%;
424
+ overflow: hidden;
425
+ display: flex;
426
+ align-items: center;
427
+ justify-content: center;
428
+ color: #fff;
429
+ font-size: 14px;
430
+ font-weight: 600;
431
+ background: var(--panel-3);
432
+ line-height: 1;
433
+ user-select: none;
434
+ }
435
+ .avatar img { width: 100%; height: 100%; object-fit: cover; }
436
+ .avatar.lg { width: 44px; height: 44px; font-size: 16px; }
437
+ .avatar.sm { width: 28px; height: 28px; font-size: 12px; }
438
+
439
+ /* 同一人连续发言时的头像占位,保证气泡左侧对齐 */
440
+ .avatar-spacer { flex: none; width: 36px; }
441
+
442
+ /* 骨架屏 */
443
+ .skeleton-item { display: flex; gap: 10px; align-items: center; padding: 10px 9px; }
444
+ .sk-box, .sk-line {
445
+ background: var(--skel);
446
+ background-size: 400% 100%;
447
+ animation: sk 1.4s ease infinite;
448
+ border-radius: 6px;
449
+ }
450
+ .sk-box { width: 44px; height: 44px; border-radius: 50%; flex: none; }
451
+ .sk-lines { flex: 1; display: flex; flex-direction: column; gap: 8px; }
452
+ .sk-line { height: 9px; }
453
+ .sk-line.w60 { width: 60%; }
454
+ .sk-line.w85 { width: 85%; }
455
+ @keyframes sk { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
456
+
457
+ /* 空状态 */
458
+ .empty {
459
+ display: flex;
460
+ flex-direction: column;
461
+ align-items: center;
462
+ justify-content: center;
463
+ gap: 8px;
464
+ padding: 34px 16px;
465
+ color: var(--faint);
466
+ font-size: 12.5px;
467
+ text-align: center;
468
+ }
469
+ .empty-ico {
470
+ width: 42px;
471
+ height: 42px;
472
+ border-radius: 50%;
473
+ background: var(--panel-2);
474
+ display: flex;
475
+ align-items: center;
476
+ justify-content: center;
477
+ color: var(--faint);
478
+ }
479
+ .empty-ico svg { width: 20px; height: 20px; }
480
+
481
+ /* 侧边栏底部状态 */
482
+ .sidebar-foot {
483
+ border-top: 1px solid var(--border);
484
+ padding: 8px 12px 10px;
485
+ font-size: 11.5px;
486
+ color: var(--muted);
487
+ background: var(--panel);
488
+ }
489
+
490
+ .conn-row { display: flex; align-items: center; gap: 7px; }
491
+
492
+ .dot {
493
+ width: 8px;
494
+ height: 8px;
495
+ border-radius: 50%;
496
+ flex: none;
497
+ background: var(--faint);
498
+ transition: background 0.2s var(--ease), box-shadow 0.2s var(--ease);
499
+ }
500
+ .dot-ok { background: var(--ok); box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.16); }
501
+ .dot-poll { background: var(--warn); box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.16); animation: pulse 1.3s ease-in-out infinite; }
502
+ .dot-err { background: var(--danger); box-shadow: 0 0 0 3px rgba(255, 59, 48, 0.16); }
503
+ .dot-idle { background: var(--faint); }
504
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
505
+
506
+ .conn-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
507
+ .conn-meta {
508
+ margin-top: 3px;
509
+ font-size: 11px;
510
+ color: var(--faint);
511
+ white-space: nowrap;
512
+ overflow: hidden;
513
+ text-overflow: ellipsis;
514
+ font-variant-numeric: tabular-nums;
515
+ }
516
+ .conn-meta:empty { display: none; }
517
+
518
+ /* ---------- 会话区 ---------- */
519
+ .chat-pane {
520
+ display: grid;
521
+ grid-template-rows: auto minmax(0, 1fr) auto;
522
+ min-width: 0;
523
+ min-height: 0;
524
+ background: var(--bg-soft);
525
+ position: relative;
526
+ }
527
+
528
+ .chat-head {
529
+ display: flex;
530
+ align-items: center;
531
+ gap: 11px;
532
+ padding: 9px 14px;
533
+ background: var(--panel);
534
+ border-bottom: 1px solid var(--border);
535
+ min-height: 58px;
536
+ z-index: 3;
537
+ }
538
+
539
+ .back-btn { display: none; }
540
+
541
+ .head-avatar { flex: none; }
542
+
543
+ .head-main { flex: 1; min-width: 0; }
544
+
545
+ .head-name-row { display: flex; align-items: center; gap: 7px; min-width: 0; }
546
+
547
+ .head-name {
548
+ font-size: 15px;
549
+ font-weight: 620;
550
+ white-space: nowrap;
551
+ overflow: hidden;
552
+ text-overflow: ellipsis;
553
+ }
554
+
555
+ .badge {
556
+ flex: none;
557
+ font-size: 10.5px;
558
+ line-height: 16px;
559
+ padding: 0 6px;
560
+ border-radius: 5px;
561
+ background: var(--accent-soft);
562
+ color: var(--accent-text);
563
+ font-weight: 600;
564
+ letter-spacing: 0.3px;
565
+ }
566
+ .badge.kind-private { background: rgba(124, 92, 255, 0.16); color: #8b6bff; }
567
+
568
+ .head-sub {
569
+ font-size: 11.5px;
570
+ color: var(--muted);
571
+ white-space: nowrap;
572
+ overflow: hidden;
573
+ text-overflow: ellipsis;
574
+ font-variant-numeric: tabular-nums;
575
+ }
576
+
577
+ /* 消息滚动区(外层负责定位悬浮按钮) */
578
+ .msg-area { position: relative; min-height: 0; overflow: hidden; }
579
+
580
+ .msg-viewport {
581
+ position: absolute;
582
+ inset: 0;
583
+ overflow-y: auto;
584
+ overflow-x: hidden;
585
+ overscroll-behavior: contain;
586
+ padding: 12px 16px 16px;
587
+ scroll-behavior: smooth;
588
+ }
589
+
590
+ .msg-list { display: flex; flex-direction: column; }
591
+
592
+ /* 日期 / 时间分隔 */
593
+ .sep {
594
+ display: flex;
595
+ align-items: center;
596
+ justify-content: center;
597
+ margin: 14px 0 10px;
598
+ }
599
+ .sep span {
600
+ font-size: 11px;
601
+ color: var(--faint);
602
+ background: var(--panel-2);
603
+ border-radius: 99px;
604
+ padding: 2px 10px;
605
+ border: 1px solid var(--border);
606
+ }
607
+ .sep.time { margin: 9px 0 7px; }
608
+ .sep.time span { background: none; border: none; padding: 0; }
609
+
610
+ /* 加载更早 */
611
+ .load-more {
612
+ display: flex;
613
+ justify-content: center;
614
+ padding: 2px 0 12px;
615
+ }
616
+ .load-more button {
617
+ font-size: 12px;
618
+ color: var(--accent-text);
619
+ background: var(--accent-soft);
620
+ border-radius: 99px;
621
+ padding: 5px 14px;
622
+ transition: filter 0.15s var(--ease);
623
+ }
624
+ .load-more button:hover { filter: brightness(1.1); }
625
+ .load-more button:disabled { color: var(--faint); background: var(--panel-2); cursor: default; }
626
+
627
+ /* ---------- 消息行 ---------- */
628
+ .msg {
629
+ display: flex;
630
+ gap: 9px;
631
+ align-items: flex-start;
632
+ margin-top: 8px;
633
+ position: relative;
634
+ }
635
+ .msg.compact { margin-top: 3px; }
636
+ .msg.out { flex-direction: row-reverse; }
637
+
638
+ .msg-body { min-width: 0; max-width: min(72%, 620px); display: flex; flex-direction: column; }
639
+ .msg.out .msg-body { align-items: flex-end; }
640
+
641
+ .msg-meta {
642
+ display: flex;
643
+ align-items: center;
644
+ gap: 6px;
645
+ margin: 0 2px 3px;
646
+ font-size: 11.5px;
647
+ color: var(--muted);
648
+ line-height: 1.3;
649
+ }
650
+ .msg-name { font-weight: 600; color: var(--text-dim); }
651
+ .role-tag {
652
+ font-size: 10px;
653
+ line-height: 14px;
654
+ padding: 0 4px;
655
+ border-radius: 4px;
656
+ background: var(--panel-3);
657
+ color: var(--muted);
658
+ font-weight: 600;
659
+ }
660
+ .role-tag.owner { background: rgba(245, 158, 11, 0.18); color: #e09612; }
661
+ .role-tag.admin { background: var(--accent-soft); color: var(--accent-text); }
662
+ .msg-time { font-variant-numeric: tabular-nums; }
663
+
664
+ /* 气泡 */
665
+ .bubble {
666
+ position: relative;
667
+ padding: 7px 11px;
668
+ border-radius: var(--radius-lg);
669
+ background: var(--bubble-in);
670
+ color: var(--bubble-in-text);
671
+ border: 1px solid var(--border);
672
+ box-shadow: var(--shadow-sm);
673
+ font-size: 14px;
674
+ line-height: 1.55;
675
+ overflow-wrap: anywhere;
676
+ word-break: break-word;
677
+ max-width: 100%;
678
+ }
679
+ .msg.out .bubble {
680
+ background: var(--bubble-out);
681
+ color: var(--bubble-out-text);
682
+ border-color: transparent;
683
+ }
684
+
685
+ /* 气泡小尾巴 */
686
+ .bubble::after {
687
+ content: "";
688
+ position: absolute;
689
+ top: 11px;
690
+ width: 8px;
691
+ height: 8px;
692
+ background: inherit;
693
+ transform: rotate(45deg);
694
+ border-radius: 1px;
695
+ }
696
+ .msg.in .bubble::after { left: -4px; border-left: 1px solid var(--border); border-bottom: 1px solid var(--border); }
697
+ .msg.out .bubble::after { right: -4px; }
698
+
699
+ .bubble.media { padding: 4px; background: var(--bubble-in); border-color: var(--border); }
700
+ .msg.out .bubble.media { background: var(--bubble-out); }
701
+
702
+ .seg-text { white-space: pre-wrap; }
703
+ .seg-text + .seg-text { margin-top: 0; }
704
+
705
+ /* 段样式 */
706
+ .seg { display: inline; }
707
+ .seg-block { display: block; margin: 4px 0; }
708
+ .seg-at {
709
+ color: var(--accent);
710
+ font-weight: 600;
711
+ padding: 0 1px;
712
+ }
713
+ .msg.out .seg-at { color: #ffffff; text-decoration: underline; }
714
+
715
+ .chip {
716
+ display: inline-flex;
717
+ align-items: center;
718
+ gap: 4px;
719
+ max-width: 260px;
720
+ padding: 1px 7px;
721
+ margin: 1px 2px 1px 0;
722
+ border-radius: 6px;
723
+ font-size: 12.5px;
724
+ background: var(--panel-3);
725
+ color: var(--text-dim);
726
+ vertical-align: baseline;
727
+ overflow: hidden;
728
+ text-overflow: ellipsis;
729
+ white-space: nowrap;
730
+ }
731
+ .msg.out .chip { background: rgba(255, 255, 255, 0.18); color: #fff; }
732
+ .chip.clickable { cursor: pointer; }
733
+ .chip.clickable:hover { filter: brightness(1.15); }
734
+ .chip.seg-unknown { color: var(--faint); font-style: italic; background: transparent; padding-left: 0; }
735
+ .msg.out .chip.seg-unknown { color: rgba(255, 255, 255, 0.72); }
736
+ .chip.seg-reply::before { content: "↩"; font-size: 11px; opacity: 0.85; }
737
+ .chip.seg-face::before { content: "☺"; font-size: 11px; opacity: 0.85; }
738
+ .chip .chip-link { color: var(--accent); text-decoration: none; }
739
+ .msg.out .chip .chip-link { color: #fff; text-decoration: underline; }
740
+ .chip .chip-link:hover { text-decoration: underline; }
741
+
742
+ /* ---------- 引用消息 ----------
743
+ 只显示一个 id 是看不出回复了什么的,所以带摘要的引用块独立成行,
744
+ 在气泡里做一条左边框的缩进引用(和 QQ / Telegram 的观感一致)。 */
745
+ .quote {
746
+ display: block;
747
+ margin: 0 0 5px;
748
+ padding: 4px 8px;
749
+ border-left: 3px solid var(--accent);
750
+ border-radius: 0 6px 6px 0;
751
+ background: var(--panel-2);
752
+ color: var(--text-dim);
753
+ font-size: 12.5px;
754
+ line-height: 1.45;
755
+ max-width: 100%;
756
+ overflow: hidden;
757
+ text-overflow: ellipsis;
758
+ white-space: nowrap;
759
+ }
760
+ .msg.out .quote {
761
+ background: rgba(255, 255, 255, 0.16);
762
+ color: rgba(255, 255, 255, 0.9);
763
+ border-left-color: rgba(255, 255, 255, 0.75);
764
+ }
765
+ .quote .quote-who { font-weight: 600; }
766
+ .quote .quote-body { opacity: 0.92; }
767
+ .quote.clickable { cursor: pointer; }
768
+ .quote.clickable:hover { filter: brightness(1.08); }
769
+
770
+ /* ---------- @ 成员选择菜单 ---------- */
771
+ .at-menu {
772
+ position: fixed;
773
+ z-index: 20;
774
+ width: 240px;
775
+ max-height: 280px;
776
+ overflow-y: auto;
777
+ padding: 6px;
778
+ border: 1px solid var(--border);
779
+ border-radius: var(--radius);
780
+ background: var(--panel);
781
+ box-shadow: var(--shadow);
782
+ display: flex;
783
+ flex-direction: column;
784
+ gap: 2px;
785
+ }
786
+ .at-menu-empty {
787
+ padding: 10px 8px;
788
+ font-size: 12.5px;
789
+ color: var(--faint);
790
+ line-height: 1.5;
791
+ }
792
+ .at-item {
793
+ display: flex;
794
+ align-items: center;
795
+ gap: 8px;
796
+ padding: 5px 7px;
797
+ border-radius: var(--radius-sm);
798
+ text-align: left;
799
+ font-size: 13px;
800
+ color: var(--text);
801
+ }
802
+ .at-item:hover, .at-item.active { background: var(--hover); }
803
+ .at-item .at-item-main { flex: 1; min-width: 0; }
804
+ .at-item .at-item-name {
805
+ overflow: hidden;
806
+ text-overflow: ellipsis;
807
+ white-space: nowrap;
808
+ }
809
+ .at-item .at-item-id { font-size: 11.5px; color: var(--faint); }
810
+ .at-item .role-tag { flex: none; }
811
+
812
+ /* 图片最大宽度 240px;短边按比例自适应 */
813
+ .seg-image {
814
+ display: block;
815
+ margin: 2px;
816
+ border-radius: 10px;
817
+ cursor: zoom-in;
818
+ background: var(--panel-2);
819
+ max-width: 240px;
820
+ max-height: 320px;
821
+ width: auto;
822
+ height: auto;
823
+ transition: filter 0.15s var(--ease);
824
+ }
825
+ .seg-image:hover { filter: brightness(0.94); }
826
+
827
+ .img-fallback {
828
+ display: inline-flex;
829
+ align-items: center;
830
+ gap: 5px;
831
+ font-size: 12.5px;
832
+ color: var(--faint);
833
+ padding: 3px 8px;
834
+ }
835
+
836
+ /* ---------- 新消息悬浮按钮 ---------- */
837
+ .new-msg-btn {
838
+ position: absolute;
839
+ left: 50%;
840
+ bottom: 118px;
841
+ transform: translateX(-50%);
842
+ z-index: 4;
843
+ background: var(--accent);
844
+ color: #fff;
845
+ font-size: 12.5px;
846
+ font-weight: 600;
847
+ padding: 6px 14px;
848
+ border-radius: 99px;
849
+ box-shadow: var(--shadow);
850
+ transition: transform 0.16s var(--ease), filter 0.16s var(--ease);
851
+ }
852
+ .new-msg-btn:hover { filter: brightness(1.08); transform: translateX(-50%) translateY(-1px); }
853
+
854
+ /* ---------- 输入区 ---------- */
855
+ .composer {
856
+ border-top: 1px solid var(--border);
857
+ background: var(--panel);
858
+ padding: 8px 12px 10px;
859
+ display: flex;
860
+ flex-direction: column;
861
+ gap: 7px;
862
+ z-index: 3;
863
+ }
864
+
865
+ .composer-bar {
866
+ display: flex;
867
+ align-items: center;
868
+ gap: 8px;
869
+ font-size: 12px;
870
+ color: var(--text-dim);
871
+ background: var(--panel-2);
872
+ border-left: 3px solid var(--accent);
873
+ border-radius: var(--radius-sm);
874
+ padding: 4px 8px;
875
+ }
876
+ .bar-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
877
+ .bar-close { color: var(--muted); font-size: 12px; padding: 0 3px; border-radius: 4px; }
878
+ .bar-close:hover { color: var(--text); background: var(--hover); }
879
+
880
+ .pending-at { display: flex; flex-wrap: wrap; gap: 6px; }
881
+ .at-chip {
882
+ display: inline-flex;
883
+ align-items: center;
884
+ gap: 5px;
885
+ font-size: 12px;
886
+ background: var(--accent-soft);
887
+ color: var(--accent-text);
888
+ border-radius: 99px;
889
+ padding: 2px 6px 2px 10px;
890
+ }
891
+ .at-chip button { color: inherit; font-size: 11px; opacity: 0.75; }
892
+ .at-chip button:hover { opacity: 1; }
893
+
894
+ /* ---------- 待发送附件 ---------- */
895
+ .pending-files { display: flex; flex-wrap: wrap; gap: 6px; }
896
+ .file-chip {
897
+ display: inline-flex;
898
+ align-items: center;
899
+ gap: 6px;
900
+ max-width: 240px;
901
+ font-size: 12px;
902
+ background: var(--panel-2);
903
+ border: 1px solid var(--border);
904
+ border-radius: 8px;
905
+ padding: 3px 6px 3px 8px;
906
+ }
907
+ .file-chip.image { padding-left: 3px; }
908
+ .file-chip-thumb {
909
+ width: 26px;
910
+ height: 26px;
911
+ border-radius: 5px;
912
+ object-fit: cover;
913
+ flex: none;
914
+ }
915
+ .file-chip-badge {
916
+ flex: none;
917
+ font-size: 11px;
918
+ color: var(--accent-text);
919
+ background: var(--accent-soft);
920
+ border-radius: 5px;
921
+ padding: 2px 5px;
922
+ }
923
+ .file-chip-name {
924
+ min-width: 0;
925
+ overflow: hidden;
926
+ text-overflow: ellipsis;
927
+ white-space: nowrap;
928
+ color: var(--text);
929
+ }
930
+ .file-chip-size { flex: none; color: var(--muted); font-size: 11px; }
931
+ .file-chip button { color: var(--muted); font-size: 11px; flex: none; }
932
+ .file-chip button:hover { color: var(--text); }
933
+
934
+ /* ---------- 拖拽文件提示层 ---------- */
935
+ .drop-overlay {
936
+ position: fixed;
937
+ inset: 0;
938
+ z-index: 70;
939
+ display: flex;
940
+ align-items: center;
941
+ justify-content: center;
942
+ background: rgba(0, 0, 0, 0.42);
943
+ pointer-events: none;
944
+ }
945
+ .drop-overlay-card {
946
+ padding: 16px 22px;
947
+ border-radius: var(--radius);
948
+ background: var(--panel);
949
+ border: 2px dashed var(--accent);
950
+ color: var(--text);
951
+ font-size: 14px;
952
+ }
953
+
954
+ .composer-row { display: flex; align-items: flex-end; gap: 8px; }
955
+
956
+ .composer-tool {
957
+ width: 32px;
958
+ height: 32px;
959
+ border-radius: 8px;
960
+ background: var(--panel-2);
961
+ color: var(--text-dim);
962
+ font-weight: 700;
963
+ font-size: 15px;
964
+ flex: none;
965
+ transition: background 0.15s var(--ease), color 0.15s var(--ease);
966
+ }
967
+ .composer-tool:hover { background: var(--panel-3); color: var(--accent); }
968
+
969
+ .composer-input {
970
+ flex: 1;
971
+ min-width: 0;
972
+ resize: none;
973
+ border: 1px solid var(--border);
974
+ background: var(--panel-2);
975
+ color: var(--text);
976
+ border-radius: var(--radius);
977
+ padding: 7px 11px;
978
+ line-height: 1.5;
979
+ max-height: 132px; /* 约 5 行 */
980
+ min-height: 34px;
981
+ overflow-y: auto;
982
+ transition: border-color 0.15s var(--ease);
983
+ }
984
+ .composer-input::placeholder { color: var(--faint); }
985
+ .composer-input:focus { outline: none; border-color: var(--accent); }
986
+ .composer-input:disabled { opacity: 0.55; cursor: not-allowed; }
987
+
988
+ .send-btn {
989
+ flex: none;
990
+ height: 34px;
991
+ padding: 0 18px;
992
+ border-radius: 8px;
993
+ background: var(--accent);
994
+ color: #fff;
995
+ font-weight: 600;
996
+ transition: filter 0.15s var(--ease), opacity 0.15s var(--ease);
997
+ }
998
+ .send-btn:hover { filter: brightness(1.08); }
999
+ .send-btn:active { transform: translateY(1px); }
1000
+ .send-btn:disabled { opacity: 0.5; cursor: not-allowed; filter: none; }
1001
+
1002
+ .composer-hint {
1003
+ font-size: 11.5px;
1004
+ color: var(--warn);
1005
+ min-height: 0;
1006
+ }
1007
+ .composer-hint:empty { display: none; }
1008
+
1009
+ .composer.readonly .composer-input,
1010
+ .composer.readonly .composer-tool { opacity: 0.55; }
1011
+
1012
+ /* ---------- 图片灯箱 ---------- */
1013
+ .lightbox {
1014
+ position: fixed;
1015
+ inset: 0;
1016
+ z-index: 60;
1017
+ background: rgba(0, 0, 0, 0.86);
1018
+ display: flex;
1019
+ flex-direction: column;
1020
+ align-items: center;
1021
+ justify-content: center;
1022
+ gap: 14px;
1023
+ padding: 24px;
1024
+ cursor: zoom-out;
1025
+ animation: fade 0.16s var(--ease);
1026
+ }
1027
+ .lightbox img {
1028
+ max-width: 92vw;
1029
+ max-height: 84vh;
1030
+ border-radius: 8px;
1031
+ box-shadow: var(--shadow-lg);
1032
+ object-fit: contain;
1033
+ }
1034
+ .lightbox-tip { color: rgba(255, 255, 255, 0.6); font-size: 12px; }
1035
+ @keyframes fade { from { opacity: 0; } to { opacity: 1; } }
1036
+
1037
+ /* ---------- 文件卡片 / 音视频播放器 ---------- */
1038
+ .seg-file {
1039
+ max-width: 320px;
1040
+ padding: 4px 6px;
1041
+ gap: 7px;
1042
+ white-space: normal;
1043
+ overflow: visible;
1044
+ text-overflow: clip;
1045
+ text-align: left;
1046
+ }
1047
+ .file-badge {
1048
+ flex: none;
1049
+ display: inline-flex;
1050
+ align-items: center;
1051
+ justify-content: center;
1052
+ min-width: 34px;
1053
+ padding: 3px 5px;
1054
+ border-radius: 5px;
1055
+ font-size: 11px;
1056
+ font-weight: 600;
1057
+ background: var(--accent-soft);
1058
+ color: var(--accent-text);
1059
+ }
1060
+ .msg.out .file-badge { background: rgba(255, 255, 255, 0.22); color: #fff; }
1061
+ .file-main {
1062
+ display: flex;
1063
+ flex-direction: column;
1064
+ min-width: 0;
1065
+ line-height: 1.3;
1066
+ }
1067
+ .file-name {
1068
+ overflow: hidden;
1069
+ text-overflow: ellipsis;
1070
+ white-space: nowrap;
1071
+ max-width: 190px;
1072
+ font-size: 12.5px;
1073
+ color: var(--text);
1074
+ }
1075
+ .msg.out .file-name { color: #fff; }
1076
+ .file-size, .file-hint { font-size: 11px; color: var(--faint); }
1077
+ .msg.out .file-size, .msg.out .file-hint { color: rgba(255, 255, 255, 0.72); }
1078
+ .file-btn {
1079
+ flex: none;
1080
+ padding: 2px 7px;
1081
+ border-radius: 5px;
1082
+ font-size: 11.5px;
1083
+ border: 1px solid var(--border);
1084
+ background: var(--panel-2);
1085
+ color: var(--accent);
1086
+ cursor: pointer;
1087
+ text-decoration: none;
1088
+ }
1089
+ .msg.out .file-btn { border-color: rgba(255, 255, 255, 0.3); background: rgba(255, 255, 255, 0.14); color: #fff; }
1090
+ .file-btn:hover { filter: brightness(1.12); }
1091
+
1092
+ .seg-media { max-width: 100%; }
1093
+ .seg-player {
1094
+ display: block;
1095
+ width: 260px;
1096
+ max-width: 100%;
1097
+ margin: 3px 1px;
1098
+ border-radius: 8px;
1099
+ background: var(--panel-2);
1100
+ }
1101
+ .seg-player.seg-video { max-height: 300px; }
1102
+
1103
+ /* ---------- 文件预览弹窗 ---------- */
1104
+ .file-viewer {
1105
+ position: fixed;
1106
+ inset: 0;
1107
+ z-index: 70;
1108
+ background: rgba(0, 0, 0, 0.62);
1109
+ display: flex;
1110
+ align-items: center;
1111
+ justify-content: center;
1112
+ padding: 24px;
1113
+ animation: fade 0.16s var(--ease);
1114
+ }
1115
+ .file-card {
1116
+ display: flex;
1117
+ flex-direction: column;
1118
+ width: min(920px, 94vw);
1119
+ height: min(86vh, 900px);
1120
+ border: 1px solid var(--border);
1121
+ border-radius: var(--radius-lg);
1122
+ background: var(--panel);
1123
+ box-shadow: var(--shadow-lg);
1124
+ overflow: hidden;
1125
+ }
1126
+ .file-head {
1127
+ display: flex;
1128
+ align-items: center;
1129
+ gap: 10px;
1130
+ padding: 10px 14px;
1131
+ border-bottom: 1px solid var(--border);
1132
+ }
1133
+ .file-head-main { flex: 1; min-width: 0; }
1134
+ .file-title {
1135
+ margin: 0;
1136
+ font-size: 14px;
1137
+ font-weight: 600;
1138
+ overflow: hidden;
1139
+ text-overflow: ellipsis;
1140
+ white-space: nowrap;
1141
+ color: var(--text);
1142
+ }
1143
+ .file-meta {
1144
+ margin: 2px 0 0;
1145
+ font-size: 11.5px;
1146
+ color: var(--faint);
1147
+ min-height: 14px;
1148
+ }
1149
+ .file-action {
1150
+ flex: none;
1151
+ padding: 4px 10px;
1152
+ border-radius: 6px;
1153
+ font-size: 12.5px;
1154
+ border: 1px solid var(--border);
1155
+ background: var(--panel-2);
1156
+ color: var(--text);
1157
+ cursor: pointer;
1158
+ text-decoration: none;
1159
+ }
1160
+ .file-action:hover { filter: brightness(1.12); }
1161
+ .file-body {
1162
+ flex: 1;
1163
+ min-height: 0;
1164
+ overflow: auto;
1165
+ padding: 12px 14px;
1166
+ }
1167
+ .file-text {
1168
+ margin: 0;
1169
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1170
+ font-size: 12.5px;
1171
+ line-height: 1.6;
1172
+ white-space: pre-wrap;
1173
+ word-break: break-word;
1174
+ color: var(--text);
1175
+ }
1176
+ .file-image {
1177
+ display: block;
1178
+ max-width: 100%;
1179
+ max-height: 100%;
1180
+ margin: 0 auto;
1181
+ border-radius: 8px;
1182
+ }
1183
+ .file-frame {
1184
+ display: block;
1185
+ width: 100%;
1186
+ height: 100%;
1187
+ min-height: 460px;
1188
+ border: 0;
1189
+ border-radius: 8px;
1190
+ background: #fff;
1191
+ }
1192
+ .file-media { display: block; width: 100%; max-height: 100%; margin: 0 auto; }
1193
+
1194
+ /* ---------- 合并转发:可折叠的内嵌聊天记录 ----------
1195
+ 收起时只占一条标题栏,点开后原地展开成一条条小聊天记录(气泡样式),
1196
+ 不弹窗、也不把内容拼进当前气泡里。 */
1197
+ .fwd-card {
1198
+ display: block;
1199
+ margin: 3px 0 1px;
1200
+ width: 264px;
1201
+ max-width: 100%;
1202
+ border: 1px solid var(--border);
1203
+ border-radius: 10px;
1204
+ background: var(--panel-2);
1205
+ overflow: hidden;
1206
+ text-align: left;
1207
+ }
1208
+ .fwd-head {
1209
+ display: flex;
1210
+ align-items: center;
1211
+ gap: 8px;
1212
+ width: 100%;
1213
+ padding: 8px 10px;
1214
+ border: 0;
1215
+ background: var(--panel-3);
1216
+ color: var(--text-dim);
1217
+ font: inherit;
1218
+ font-size: 12.5px;
1219
+ text-align: left;
1220
+ cursor: pointer;
1221
+ }
1222
+ .fwd-head:hover { filter: brightness(1.06); }
1223
+ .fwd-title {
1224
+ flex: 1;
1225
+ min-width: 0;
1226
+ overflow: hidden;
1227
+ text-overflow: ellipsis;
1228
+ white-space: nowrap;
1229
+ font-weight: 600;
1230
+ }
1231
+ .fwd-count { flex: none; font-size: 11px; color: var(--faint); }
1232
+ .fwd-caret {
1233
+ flex: none;
1234
+ width: 7px;
1235
+ height: 7px;
1236
+ margin-right: 2px;
1237
+ border-right: 1.6px solid currentColor;
1238
+ border-bottom: 1.6px solid currentColor;
1239
+ transform: rotate(-45deg);
1240
+ transition: transform 0.16s var(--ease);
1241
+ }
1242
+ .fwd-card.open .fwd-caret { transform: rotate(45deg); }
1243
+ .fwd-body {
1244
+ padding: 9px 10px;
1245
+ max-height: 340px;
1246
+ overflow: auto;
1247
+ border-top: 1px solid var(--border);
1248
+ }
1249
+ .fwd-node + .fwd-node { margin-top: 8px; }
1250
+ .fwd-node .fwd-node-meta {
1251
+ display: flex;
1252
+ align-items: baseline;
1253
+ gap: 6px;
1254
+ margin-bottom: 2px;
1255
+ }
1256
+ .fwd-node-name { font-size: 11.5px; font-weight: 600; color: var(--accent-text); }
1257
+ .fwd-node-time { font-size: 10.5px; color: var(--faint); }
1258
+ /* 内层气泡固定用中性面板色 —— 选择器要压过 .msg.out .bubble,
1259
+ 否则「发出的转发」里每个节点的气泡都会被染成蓝色 */
1260
+ .fwd-card .fwd-node .bubble {
1261
+ padding: 5px 9px;
1262
+ font-size: 13px;
1263
+ background: var(--panel);
1264
+ color: var(--text);
1265
+ border-color: var(--border);
1266
+ box-shadow: none;
1267
+ }
1268
+ .fwd-card .fwd-node .bubble::after { display: none; }
1269
+ .fwd-hint { color: var(--faint); font-size: 12.5px; padding: 2px 0; }
1270
+
1271
+ /* 发出的消息里卡片改用半透明浅色,跟蓝色气泡协调 */
1272
+ .msg.out .fwd-card { border-color: rgba(255, 255, 255, 0.24); }
1273
+ .msg.out .fwd-head { background: rgba(255, 255, 255, 0.16); color: rgba(255, 255, 255, 0.94); }
1274
+ .msg.out .fwd-count { color: rgba(255, 255, 255, 0.7); }
1275
+ .msg.out .fwd-body { border-top-color: rgba(255, 255, 255, 0.18); }
1276
+ .msg.out .fwd-node-name { color: #fff; }
1277
+ .msg.out .fwd-node-time { color: rgba(255, 255, 255, 0.66); }
1278
+
1279
+ /* ---------- 右键菜单 ---------- */
1280
+ .ctx-menu {
1281
+ position: fixed;
1282
+ z-index: 70;
1283
+ min-width: 158px;
1284
+ padding: 5px;
1285
+ background: var(--panel);
1286
+ border: 1px solid var(--border-strong);
1287
+ border-radius: var(--radius);
1288
+ box-shadow: var(--shadow-lg);
1289
+ animation: pop 0.12s var(--ease);
1290
+ }
1291
+ @keyframes pop { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } }
1292
+
1293
+ .ctx-item {
1294
+ display: flex;
1295
+ align-items: center;
1296
+ gap: 8px;
1297
+ width: 100%;
1298
+ text-align: left;
1299
+ padding: 7px 9px;
1300
+ border-radius: var(--radius-sm);
1301
+ font-size: 13px;
1302
+ color: var(--text-dim);
1303
+ transition: background 0.12s var(--ease), color 0.12s var(--ease);
1304
+ }
1305
+ .ctx-item:hover { background: var(--hover); color: var(--text); }
1306
+ .ctx-item.danger:hover { background: rgba(255, 59, 48, 0.12); color: var(--danger); }
1307
+ .ctx-item[disabled] { opacity: 0.4; cursor: not-allowed; }
1308
+ .ctx-item[disabled]:hover { background: none; color: var(--text-dim); }
1309
+ .ctx-sep { height: 1px; margin: 4px 6px; background: var(--border); }
1310
+
1311
+ /* ---------- 机器人切换器(会话区右上角) ---------- */
1312
+ .bot-switch { position: relative; flex: none; }
1313
+
1314
+ .bot-btn {
1315
+ display: inline-flex;
1316
+ align-items: center;
1317
+ gap: 7px;
1318
+ height: 30px;
1319
+ max-width: 190px;
1320
+ padding: 0 8px 0 10px;
1321
+ border-radius: 8px;
1322
+ border: 1px solid var(--border);
1323
+ background: var(--panel-2);
1324
+ color: var(--text-dim);
1325
+ font-size: 12.5px;
1326
+ transition: background 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease);
1327
+ }
1328
+ .bot-btn:hover { background: var(--hover); color: var(--text); border-color: var(--border-strong); }
1329
+ .bot-btn[aria-expanded="true"] { background: var(--hover); color: var(--text); border-color: var(--border-strong); }
1330
+
1331
+ .bot-btn-name {
1332
+ min-width: 0;
1333
+ overflow: hidden;
1334
+ text-overflow: ellipsis;
1335
+ white-space: nowrap;
1336
+ font-variant-numeric: tabular-nums;
1337
+ }
1338
+ .bot-caret { width: 14px; height: 14px; flex: none; color: var(--faint); }
1339
+
1340
+ .bot-menu {
1341
+ position: absolute;
1342
+ right: 0;
1343
+ top: calc(100% + 6px);
1344
+ z-index: 60;
1345
+ min-width: 220px;
1346
+ max-width: min(320px, 86vw);
1347
+ max-height: min(400px, 62vh);
1348
+ overflow-y: auto;
1349
+ padding: 5px;
1350
+ background: var(--panel);
1351
+ border: 1px solid var(--border-strong);
1352
+ border-radius: var(--radius);
1353
+ box-shadow: var(--shadow-lg);
1354
+ animation: pop 0.12s var(--ease);
1355
+ }
1356
+
1357
+ .bot-item {
1358
+ display: flex;
1359
+ align-items: center;
1360
+ gap: 9px;
1361
+ width: 100%;
1362
+ text-align: left;
1363
+ padding: 7px 9px;
1364
+ border-radius: var(--radius-sm);
1365
+ transition: background 0.12s var(--ease);
1366
+ }
1367
+ .bot-item:hover { background: var(--hover); }
1368
+ .bot-item.active { background: var(--active); }
1369
+
1370
+ .bot-item-main { flex: 1; min-width: 0; }
1371
+ .bot-item-name {
1372
+ font-size: 13px;
1373
+ color: var(--text);
1374
+ overflow: hidden;
1375
+ text-overflow: ellipsis;
1376
+ white-space: nowrap;
1377
+ }
1378
+ .bot-item-sub {
1379
+ font-size: 11px;
1380
+ color: var(--faint);
1381
+ overflow: hidden;
1382
+ text-overflow: ellipsis;
1383
+ white-space: nowrap;
1384
+ font-variant-numeric: tabular-nums;
1385
+ }
1386
+
1387
+ /* 在线状态:复用侧栏的小圆点样式 */
1388
+ .bot-state {
1389
+ display: inline-flex;
1390
+ align-items: center;
1391
+ gap: 5px;
1392
+ flex: none;
1393
+ font-size: 11px;
1394
+ color: var(--faint);
1395
+ }
1396
+ .bot-state.online { color: var(--ok); }
1397
+ .bot-check { width: 15px; height: 15px; flex: none; color: var(--accent); }
1398
+ /* 机器人备注按钮:平时淡出,悬停该行才显现,避免挤占状态标记的位置 */
1399
+ .bot-item-rename {
1400
+ display: inline-flex;
1401
+ align-items: center;
1402
+ justify-content: center;
1403
+ width: 22px;
1404
+ height: 22px;
1405
+ flex: none;
1406
+ border-radius: 6px;
1407
+ color: var(--muted);
1408
+ cursor: pointer;
1409
+ opacity: 0;
1410
+ transition: opacity 0.12s var(--ease), background 0.12s var(--ease), color 0.12s var(--ease);
1411
+ }
1412
+ .bot-item:hover .bot-item-rename { opacity: 1; }
1413
+ .bot-item-rename:hover,
1414
+ .bot-item-rename:focus-visible { background: var(--hover); color: var(--text); opacity: 1; }
1415
+ .bot-item-rename svg { width: 13px; height: 13px; }
1416
+ .bot-menu-empty { padding: 12px 10px; font-size: 12px; color: var(--faint); text-align: center; }
1417
+ .bot-menu-sep { height: 1px; margin: 4px 6px; background: var(--border); }
1418
+
1419
+ /* ---------- 设置面板(右上角齿轮) ---------- */
1420
+ .settings {
1421
+ position: fixed;
1422
+ inset: 0;
1423
+ z-index: 75;
1424
+ background: rgba(0, 0, 0, 0.62);
1425
+ display: flex;
1426
+ align-items: center;
1427
+ justify-content: center;
1428
+ padding: 24px;
1429
+ animation: fade 0.16s var(--ease);
1430
+ }
1431
+ .settings-card {
1432
+ display: flex;
1433
+ flex-direction: column;
1434
+ width: min(520px, 94vw);
1435
+ max-height: min(80vh, 720px);
1436
+ border: 1px solid var(--border);
1437
+ border-radius: var(--radius-lg);
1438
+ background: var(--panel);
1439
+ box-shadow: var(--shadow-lg);
1440
+ overflow: hidden;
1441
+ }
1442
+ .settings-head {
1443
+ display: flex;
1444
+ align-items: center;
1445
+ justify-content: space-between;
1446
+ gap: 10px;
1447
+ padding: 10px 14px;
1448
+ border-bottom: 1px solid var(--border);
1449
+ }
1450
+ .settings-title { margin: 0; font-size: 14px; font-weight: 600; color: var(--text); }
1451
+ .settings-body { flex: 1; min-height: 0; overflow: auto; padding: 14px; }
1452
+ .settings-section + .settings-section { margin-top: 18px; }
1453
+ .settings-section-head {
1454
+ display: flex;
1455
+ align-items: center;
1456
+ justify-content: space-between;
1457
+ gap: 8px;
1458
+ }
1459
+ .settings-section-title { margin: 0; font-size: 13px; font-weight: 600; color: var(--text); }
1460
+ .settings-badge {
1461
+ flex: none;
1462
+ padding: 2px 8px;
1463
+ border-radius: 999px;
1464
+ font-size: 11px;
1465
+ border: 1px solid var(--border);
1466
+ background: var(--panel-2);
1467
+ color: var(--faint);
1468
+ }
1469
+ .settings-badge.on { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
1470
+ .settings-desc {
1471
+ margin: 6px 0 10px;
1472
+ font-size: 12px;
1473
+ line-height: 1.6;
1474
+ color: var(--faint);
1475
+ }
1476
+ .cache-stats {
1477
+ display: grid;
1478
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1479
+ gap: 8px;
1480
+ margin-bottom: 12px;
1481
+ }
1482
+ .cache-stat {
1483
+ padding: 8px 10px;
1484
+ border: 1px solid var(--border);
1485
+ border-radius: var(--radius-sm);
1486
+ background: var(--panel-2);
1487
+ min-width: 0;
1488
+ }
1489
+ .cache-stat-label { font-size: 11px; color: var(--faint); }
1490
+ .cache-stat-value {
1491
+ font-size: 14px;
1492
+ font-weight: 600;
1493
+ color: var(--text);
1494
+ font-variant-numeric: tabular-nums;
1495
+ overflow: hidden;
1496
+ text-overflow: ellipsis;
1497
+ white-space: nowrap;
1498
+ }
1499
+ .cache-stat-sub { font-size: 11px; color: var(--faint); }
1500
+ .cache-actions { display: flex; flex-wrap: wrap; gap: 8px; }
1501
+ .settings-btn {
1502
+ padding: 6px 12px;
1503
+ border-radius: 8px;
1504
+ border: 1px solid var(--border);
1505
+ background: var(--panel-2);
1506
+ color: var(--text-dim);
1507
+ font-size: 12.5px;
1508
+ cursor: pointer;
1509
+ transition: background 0.15s var(--ease), color 0.15s var(--ease);
1510
+ }
1511
+ .settings-btn:hover { background: var(--hover); color: var(--text); }
1512
+ .settings-btn.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }
1513
+ .settings-btn.danger:hover { background: rgba(255, 59, 48, 0.12); color: var(--danger); }
1514
+ /* 「待确认」状态:实心红底,第二次点击才真的清空 */
1515
+ .settings-btn.danger.armed {
1516
+ background: var(--danger);
1517
+ border-color: var(--danger);
1518
+ color: #fff;
1519
+ }
1520
+ .settings-btn.danger.armed:hover { background: var(--danger); color: #fff; }
1521
+ .settings-btn[disabled] { opacity: 0.45; cursor: not-allowed; }
1522
+ .settings-btn[disabled]:hover { background: var(--panel-2); color: var(--text-dim); }
1523
+
1524
+ /* 开关行(网页通知等布尔设置项) */
1525
+ .settings-switch {
1526
+ display: flex;
1527
+ align-items: center;
1528
+ gap: 10px;
1529
+ padding: 8px 2px;
1530
+ cursor: pointer;
1531
+ user-select: none;
1532
+ }
1533
+ .settings-switch + .settings-switch { border-top: 1px solid var(--border); }
1534
+ .settings-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
1535
+ .switch-track {
1536
+ position: relative;
1537
+ flex: none;
1538
+ width: 38px;
1539
+ height: 22px;
1540
+ border-radius: 999px;
1541
+ background: var(--panel-3);
1542
+ border: 1px solid var(--border-strong);
1543
+ transition: background 0.16s var(--ease), border-color 0.16s var(--ease);
1544
+ }
1545
+ .switch-track::after {
1546
+ content: "";
1547
+ position: absolute;
1548
+ top: 2px;
1549
+ left: 2px;
1550
+ width: 16px;
1551
+ height: 16px;
1552
+ border-radius: 50%;
1553
+ background: #fff;
1554
+ box-shadow: var(--shadow-sm);
1555
+ transition: transform 0.16s var(--ease);
1556
+ }
1557
+ .settings-switch input:checked + .switch-track {
1558
+ background: var(--accent);
1559
+ border-color: var(--accent);
1560
+ }
1561
+ .settings-switch input:checked + .switch-track::after { transform: translateX(16px); }
1562
+ .settings-switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
1563
+ .settings-switch input:disabled + .switch-track { opacity: 0.45; }
1564
+ .switch-text { font-size: 12.5px; color: var(--text-dim); }
1565
+ .settings-switch input:disabled ~ .switch-text { opacity: 0.55; }
1566
+
1567
+ /* ---------- 备注(别名)编辑弹窗 ---------- */
1568
+ .alias {
1569
+ position: fixed;
1570
+ inset: 0;
1571
+ z-index: 78;
1572
+ background: rgba(0, 0, 0, 0.62);
1573
+ display: flex;
1574
+ align-items: center;
1575
+ justify-content: center;
1576
+ padding: 24px;
1577
+ animation: fade 0.16s var(--ease);
1578
+ }
1579
+ .alias-card {
1580
+ width: min(380px, 92vw);
1581
+ border: 1px solid var(--border);
1582
+ border-radius: var(--radius-lg);
1583
+ background: var(--panel);
1584
+ box-shadow: var(--shadow-lg);
1585
+ padding: 16px;
1586
+ }
1587
+ .alias-title { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: var(--text); }
1588
+ .alias-desc { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--faint); }
1589
+ .alias-input {
1590
+ width: 100%;
1591
+ box-sizing: border-box;
1592
+ height: 36px;
1593
+ padding: 0 11px;
1594
+ border-radius: 8px;
1595
+ border: 1px solid var(--border);
1596
+ background: var(--panel-2);
1597
+ color: var(--text);
1598
+ }
1599
+ .alias-input:focus { outline: none; border-color: var(--accent); }
1600
+ .alias-actions {
1601
+ display: flex;
1602
+ justify-content: flex-end;
1603
+ gap: 8px;
1604
+ margin-top: 14px;
1605
+ }
1606
+ .alias-actions .settings-btn { padding: 7px 16px; }
1607
+ .alias-actions .settings-btn.primary {
1608
+ background: var(--accent);
1609
+ border-color: var(--accent);
1610
+ color: #fff;
1611
+ }
1612
+ .alias-actions .settings-btn.primary:hover { background: var(--accent); filter: brightness(1.08); }
1613
+
1614
+ /* ---------- 令牌输入页 ---------- */
1615
+ .gate {
1616
+ position: fixed;
1617
+ inset: 0;
1618
+ z-index: 80;
1619
+ display: flex;
1620
+ align-items: center;
1621
+ justify-content: center;
1622
+ background: var(--bg);
1623
+ padding: 20px;
1624
+ }
1625
+ .gate-card {
1626
+ width: 100%;
1627
+ max-width: 360px;
1628
+ background: var(--panel);
1629
+ border: 1px solid var(--border);
1630
+ border-radius: var(--radius-lg);
1631
+ box-shadow: var(--shadow-lg);
1632
+ padding: 26px 24px 20px;
1633
+ text-align: center;
1634
+ }
1635
+ .gate-logo {
1636
+ width: 44px;
1637
+ height: 44px;
1638
+ margin: 0 auto 14px;
1639
+ border-radius: 13px;
1640
+ background: linear-gradient(135deg, var(--accent), #4fc3ff 55%, #7c5cff);
1641
+ position: relative;
1642
+ box-shadow: var(--shadow);
1643
+ }
1644
+ .gate-logo::after {
1645
+ content: "";
1646
+ position: absolute;
1647
+ inset: 12px 10px auto 10px;
1648
+ height: 3px;
1649
+ border-radius: 3px;
1650
+ background: rgba(255, 255, 255, 0.92);
1651
+ box-shadow: 0 7px 0 rgba(255, 255, 255, 0.66), 0 14px 0 rgba(255, 255, 255, 0.4);
1652
+ }
1653
+ .gate-title { margin: 0 0 6px; font-size: 17px; font-weight: 650; }
1654
+ .gate-desc { margin: 0 0 16px; font-size: 12.5px; color: var(--muted); line-height: 1.6; }
1655
+ .gate-form { display: flex; gap: 8px; }
1656
+ .gate-input {
1657
+ flex: 1;
1658
+ min-width: 0;
1659
+ height: 36px;
1660
+ padding: 0 11px;
1661
+ border-radius: 8px;
1662
+ border: 1px solid var(--border);
1663
+ background: var(--panel-2);
1664
+ color: var(--text);
1665
+ }
1666
+ .gate-input:focus { outline: none; border-color: var(--accent); }
1667
+ .gate-submit {
1668
+ flex: none;
1669
+ height: 36px;
1670
+ padding: 0 18px;
1671
+ border-radius: 8px;
1672
+ background: var(--accent);
1673
+ color: #fff;
1674
+ font-weight: 600;
1675
+ }
1676
+ .gate-submit:hover { filter: brightness(1.08); }
1677
+ .gate-tip { margin: 14px 0 0; font-size: 11px; color: var(--faint); }
1678
+ .gate-error { margin: 12px 0 0; font-size: 12px; color: var(--danger); min-height: 0; }
1679
+ .gate-error:empty { display: none; }
1680
+
1681
+ /* ---------- 轻提示 ---------- */
1682
+ .toast {
1683
+ position: fixed;
1684
+ left: 50%;
1685
+ top: 18px;
1686
+ transform: translateX(-50%) translateY(-12px);
1687
+ z-index: 90;
1688
+ background: var(--panel);
1689
+ color: var(--text);
1690
+ border: 1px solid var(--border-strong);
1691
+ border-radius: 99px;
1692
+ padding: 7px 16px;
1693
+ font-size: 12.5px;
1694
+ box-shadow: var(--shadow-lg);
1695
+ opacity: 0;
1696
+ transition: opacity 0.18s var(--ease), transform 0.18s var(--ease);
1697
+ pointer-events: none;
1698
+ max-width: 80vw;
1699
+ overflow: hidden;
1700
+ text-overflow: ellipsis;
1701
+ white-space: nowrap;
1702
+ }
1703
+ .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
1704
+ .toast.error { color: var(--danger); border-color: rgba(255, 59, 48, 0.4); }
1705
+
1706
+ /* ---------- 响应式:窄屏单栏 ---------- */
1707
+ @media (max-width: 768px) {
1708
+ .app { grid-template-columns: minmax(0, 1fr); }
1709
+ .sidebar { border-right: none; }
1710
+ .app[data-pane="sidebar"] .chat-pane { display: none; }
1711
+ .app[data-pane="chat"] .sidebar { display: none; }
1712
+ .back-btn { display: inline-flex; }
1713
+ .msg-body { max-width: 84%; }
1714
+ .msg-viewport { padding: 10px 10px 12px; }
1715
+ .new-msg-btn { bottom: 130px; }
1716
+ .chat-pane { grid-template-rows: auto minmax(0, 1fr) auto; }
1717
+ .head-sub { font-size: 11px; }
1718
+ /* 窄屏下机器人切换器只留圆点与箭头,省出横向空间给会话名 */
1719
+ .bot-btn { max-width: 92px; padding-right: 6px; }
1720
+ .bot-btn-name { max-width: 54px; }
1721
+ .bot-menu { min-width: 200px; }
1722
+ /* 点输入框时让输入法不至于遮住内容 */
1723
+ .msg-viewport { scroll-padding-bottom: 16px; }
1724
+ }
1725
+
1726
+ /* 触屏 / 窄屏下把输入框字号提到 16px:
1727
+ iOS Safari 在聚焦 font-size < 16px 的输入框时会自动放大整页,
1728
+ 而且放大后不会自己缩回去,非常影响使用。视觉上几乎看不出差别。 */
1729
+ @media (max-width: 768px), (pointer: coarse) {
1730
+ .composer-input,
1731
+ .search-input,
1732
+ .gate-input { font-size: 16px; }
1733
+ /* 输入框变高会和 34px 的按钮不齐,这里一起对齐一下 */
1734
+ .composer-input { min-height: 36px; padding: 8px 11px; }
1735
+ .send-btn, .composer-tool { height: 36px; }
1736
+ /* 触屏上小按钮太难点,稍微放大点击区域 */
1737
+ .icon-btn { min-width: 36px; min-height: 36px; }
1738
+ }
1739
+
1740
+ /* 刘海屏 / 小白条:index.html 设了 viewport-fit=cover,
1741
+ 不用 safe-area-inset-* 的话内容会被状态栏或home指示条盖住。 */
1742
+ @supports (padding: max(0px)) {
1743
+ .sidebar-head {
1744
+ padding-top: max(10px, env(safe-area-inset-top));
1745
+ padding-left: max(12px, env(safe-area-inset-left));
1746
+ }
1747
+ .sidebar-foot { padding-bottom: max(8px, env(safe-area-inset-bottom)); }
1748
+ .chat-head {
1749
+ padding-top: max(8px, env(safe-area-inset-top));
1750
+ padding-right: max(12px, env(safe-area-inset-right));
1751
+ }
1752
+ .composer {
1753
+ padding-bottom: max(10px, env(safe-area-inset-bottom));
1754
+ padding-left: max(12px, env(safe-area-inset-left));
1755
+ padding-right: max(12px, env(safe-area-inset-right));
1756
+ }
1757
+ .chat-list { padding-left: env(safe-area-inset-left); }
1758
+ .msg-viewport {
1759
+ padding-left: max(10px, env(safe-area-inset-left));
1760
+ padding-right: max(10px, env(safe-area-inset-right));
1761
+ }
1762
+ }
1763
+
1764
+ @media (prefers-reduced-motion: reduce) {
1765
+ *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
1766
+ .msg-viewport { scroll-behavior: auto; }
1767
+ }
1768
+
1769
+ /* 高对比度模式下不要用半透明边框,否则边界会看不见 */
1770
+ @media (prefers-contrast: more) {
1771
+ html[data-theme="dark"] { --border: rgba(255, 255, 255, 0.28); --border-strong: rgba(255, 255, 255, 0.42); }
1772
+ html[data-theme="light"] { --border: rgba(15, 23, 42, 0.3); --border-strong: rgba(15, 23, 42, 0.5); }
1773
+ .chat-item.active, .bubble { border-width: 2px; }
1774
+ }