@pactor-app/chat 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/styles.css ADDED
@@ -0,0 +1,1704 @@
1
+ /**
2
+ * pactor-chat 皮肤样式表(单文件)。
3
+ *
4
+ * 技术选型参考 DeepTutor web:语义 CSS 变量 + 语义 class,无 antd。
5
+ *
6
+ * 换肤契约(与 pactor-ui-radix 一致):
7
+ * 1. 覆盖 CSS 变量(在本样式表之后注入 `--pactor-chat-primary: …;` 等);
8
+ * 2. 内置暗色:`<html data-pactor-theme="dark">`(或挂在任意祖先容器上);
9
+ * 3. 直接覆盖 `.pactor-chat-*` class。
10
+ *
11
+ * 使用:import 'pactor-chat/styles.css';
12
+ */
13
+
14
+ /* ============================================================
15
+ * 1. 皮肤 token(light)
16
+ * ============================================================ */
17
+
18
+ .pactor-chat-view,
19
+ .pactor-chat-layout,
20
+ .pactor-chat-shell,
21
+ .pactor-chat-workspace,
22
+ .pactor-chat-inspector,
23
+ .pactor-chat-notice {
24
+ --pactor-chat-bg: #f7f6f4;
25
+ --pactor-chat-sidebar-bg: #efedea;
26
+ --pactor-chat-fg: #1a1d26;
27
+ --pactor-chat-muted: #f4f4f6;
28
+ --pactor-chat-muted-fg: #6b7180;
29
+ --pactor-chat-card: #ffffff;
30
+ --pactor-chat-border: #e6e7eb;
31
+ --pactor-chat-primary: #3c47dd;
32
+ --pactor-chat-primary-fg: #ffffff;
33
+ --pactor-chat-danger: #d4380d;
34
+ --pactor-chat-danger-bg: #fff2f0;
35
+ --pactor-chat-success: #389e0d;
36
+ --pactor-chat-user-bubble-bg: #eef0fe;
37
+ --pactor-chat-user-bubble-border: rgb(60 71 221 / 35%);
38
+ --pactor-chat-code-bg: #f6f7f9;
39
+ /* 旧通用圆角令牌(保留兼容);新组件改用下方圆角阶梯 */
40
+ --pactor-chat-radius: 12px;
41
+ /* 圆角阶梯:sm 控件 / md 卡片 / lg 气泡 / xl composer */
42
+ --pactor-chat-radius-sm: 6px;
43
+ --pactor-chat-radius-md: 8px;
44
+ --pactor-chat-radius-lg: 16px;
45
+ --pactor-chat-radius-xl: 26px;
46
+ /* 投影:sm 气泡/卡片轻投影;composer 柔和分层投影 */
47
+ --pactor-chat-shadow-sm: 0 1px 2px rgb(0 0 0 / 4%);
48
+ --pactor-chat-shadow-composer:
49
+ 0 1px 2px rgb(0 0 0 / 3%),
50
+ 0 10px 28px -10px rgb(0 0 0 / 8%);
51
+ /* 衬线展示字体栈:空状态问候 / chat 布局标题 */
52
+ --pactor-chat-font-display: 'Songti SC', 'Noto Serif SC', Georgia,
53
+ 'Times New Roman', serif;
54
+ /* AppShell:侧栏宽度 / 移动端顶栏高度 / 抽屉遮罩色 */
55
+ --pactor-chat-sidebar-width: 240px;
56
+ --pactor-chat-shell-topbar-height: 44px;
57
+ --pactor-chat-shell-scrim: rgb(0 0 0 / 40%);
58
+ /* 产出物面板(spec: chat-artifact-panel):桌面固定宽右栏 */
59
+ --pactor-chat-inspector-width: 320px;
60
+ /* 对话列限宽居中(spec: chat-app-shell 嵌入契约):置 none 关闭限宽 */
61
+ --pactor-chat-content-width: 768px;
62
+ }
63
+
64
+ .pactor-chat-view {
65
+
66
+ display: flex;
67
+ flex-direction: column;
68
+ height: 100%;
69
+ gap: 12px;
70
+ color: var(--pactor-chat-fg);
71
+ background: var(--pactor-chat-bg);
72
+ font-size: 14px;
73
+ line-height: 1.6;
74
+ }
75
+
76
+ /* 暗色皮肤:data-pactor-theme="dark"(html 或任意祖先容器)。
77
+ 只覆盖令牌(颜色/投影),组件规则不区分主题。 */
78
+ [data-pactor-theme='dark'] .pactor-chat-view,
79
+ [data-pactor-theme='dark'] .pactor-chat-layout,
80
+ [data-pactor-theme='dark'] .pactor-chat-shell,
81
+ [data-pactor-theme='dark'] .pactor-chat-workspace,
82
+ [data-pactor-theme='dark'] .pactor-chat-notice,
83
+ .pactor-chat-view[data-pactor-theme='dark'],
84
+ .pactor-chat-layout[data-pactor-theme='dark'],
85
+ .pactor-chat-shell[data-pactor-theme='dark'],
86
+ .pactor-chat-workspace[data-pactor-theme='dark'],
87
+ .pactor-chat-notice[data-pactor-theme='dark'] {
88
+ --pactor-chat-bg: #14161c;
89
+ --pactor-chat-sidebar-bg: #1b1e26;
90
+ --pactor-chat-fg: #e4e6ee;
91
+ --pactor-chat-muted: #1e2129;
92
+ --pactor-chat-muted-fg: #8b90a0;
93
+ --pactor-chat-card: #1a1d24;
94
+ --pactor-chat-border: #2c3038;
95
+ --pactor-chat-primary: #5b66f0;
96
+ --pactor-chat-primary-fg: #ffffff;
97
+ --pactor-chat-danger: #e8690c;
98
+ --pactor-chat-danger-bg: #2b1d16;
99
+ --pactor-chat-success: #49aa19;
100
+ --pactor-chat-user-bubble-bg: #262a45;
101
+ --pactor-chat-user-bubble-border: rgb(91 102 240 / 45%);
102
+ --pactor-chat-code-bg: #1e2129;
103
+ --pactor-chat-shadow-sm: 0 1px 2px rgb(0 0 0 / 35%);
104
+ --pactor-chat-shadow-composer:
105
+ 0 1px 2px rgb(0 0 0 / 4%),
106
+ 0 12px 32px -10px rgb(0 0 0 / 55%);
107
+ --pactor-chat-shell-scrim: rgb(0 0 0 / 55%);
108
+ --pactor-chat-font-display: 'Songti SC', 'Noto Serif SC', Georgia,
109
+ 'Times New Roman', serif;
110
+ }
111
+
112
+ /* ============================================================
113
+ * 2. 布局(chat 布局 + 消息区)
114
+ * ============================================================ */
115
+
116
+ .pactor-chat-layout {
117
+ display: flex;
118
+ flex-direction: column;
119
+ height: 100%;
120
+ background: var(--pactor-chat-bg);
121
+ color: var(--pactor-chat-fg);
122
+ }
123
+
124
+ .pactor-chat-layout__header {
125
+ padding: 12px 16px;
126
+ border-bottom: 1px solid var(--pactor-chat-border);
127
+ font-family: var(--pactor-chat-font-display);
128
+ font-size: 15px;
129
+ font-weight: 600;
130
+ }
131
+
132
+ .pactor-chat-layout__main {
133
+ flex: 1;
134
+ min-height: 0;
135
+ padding: 16px;
136
+ display: flex;
137
+ flex-direction: column;
138
+ }
139
+
140
+ /* ------------------------------------------------------------
141
+ * ChatWorkspace(spec: chat-dsl-page):createChatWorkspace 工厂
142
+ * 返回组件的外层容器 = 可选头部(title + headerExtra)+ ChatView。
143
+ * ------------------------------------------------------------ */
144
+
145
+ .pactor-chat-workspace {
146
+ display: flex;
147
+ flex-direction: column;
148
+ height: 100%;
149
+ min-height: 0;
150
+ /* 对话列缺省限宽居中(spec: chat-app-shell 嵌入契约):
151
+ * shell content / 面板 host / 独立块级容器三场景统一生效 */
152
+ width: 100%;
153
+ max-width: var(--pactor-chat-content-width);
154
+ margin-inline: auto;
155
+ background: var(--pactor-chat-bg);
156
+ color: var(--pactor-chat-fg);
157
+ font-size: 14px;
158
+ line-height: 1.6;
159
+ }
160
+
161
+ .pactor-chat-workspace__header {
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: space-between;
165
+ gap: 12px;
166
+ padding: 10px 16px;
167
+ border-bottom: 1px solid var(--pactor-chat-border);
168
+ flex-shrink: 0;
169
+ }
170
+
171
+ .pactor-chat-workspace__title {
172
+ font-family: var(--pactor-chat-font-display);
173
+ font-size: 15px;
174
+ font-weight: 600;
175
+ }
176
+
177
+ .pactor-chat-workspace__header-extra {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 8px;
181
+ }
182
+
183
+ .pactor-chat-workspace > .pactor-chat-view {
184
+ flex: 1;
185
+ min-height: 0;
186
+ }
187
+
188
+ /* ------------------------------------------------------------
189
+ * AppShell(spec: chat-app-shell):侧栏 + 主区外壳。
190
+ * 桌面(≥768px)flex 同行;移动端(<768px)侧栏退出文档流
191
+ * 变为覆盖抽屉,布局切换全部由媒体查询表达,JS 只管开合。
192
+ /* AppShell(spec: chat-app-shell):侧栏 + 主区外壳。
193
+ * 桌面(≥768px)flex 同行;移动端(<768px)侧栏退出文档流
194
+ * 变为覆盖抽屉,布局切换全部由媒体查询表达,JS 只管开合。
195
+ * 高度填满父容器(height: 100%):嵌入任意定高容器即正确;
196
+ * 父级无定高时退化为内容高度。standalone 顶层挂载时宿主
197
+ * 容器定高(如 100dvh)属宿主职责(嵌入契约)。
198
+ * ------------------------------------------------------------ */
199
+
200
+ .pactor-chat-shell {
201
+ display: flex;
202
+ height: 100%;
203
+ overflow: hidden;
204
+ background: var(--pactor-chat-bg);
205
+ color: var(--pactor-chat-fg);
206
+ font-size: 14px;
207
+ line-height: 1.6;
208
+ }
209
+
210
+ /* 桌面:侧栏为固定宽度 flex 列;背景独立令牌(决策 D5:比工作区
211
+ * 暖白灰深一档),暗色经令牌覆盖自动生效 */
212
+ .pactor-chat-shell__sidebar {
213
+ width: var(--pactor-chat-sidebar-width);
214
+ flex-shrink: 0;
215
+ border-right: 1px solid var(--pactor-chat-border);
216
+ background: var(--pactor-chat-sidebar-bg);
217
+ }
218
+
219
+ /* 框架模式(提供 brand / sidebarFooter 时):品牌行 + 滚动区 + 底部区
220
+ * 的 flex 列;未提供时侧栏直挂调用方内容(零渲染承诺) */
221
+ .pactor-chat-shell__sidebar--framed {
222
+ display: flex;
223
+ flex-direction: column;
224
+ }
225
+
226
+ /* 桌面品牌行(决策 D3):brand 左对齐,折叠钮在右 */
227
+ .pactor-chat-shell__sidebar-header {
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: space-between;
231
+ gap: 8px;
232
+ flex-shrink: 0;
233
+ padding: 12px 12px 4px;
234
+ }
235
+
236
+ .pactor-chat-shell__brand {
237
+ flex: 1;
238
+ min-width: 0;
239
+ display: flex;
240
+ align-items: center;
241
+ gap: 8px;
242
+ }
243
+
244
+ /* 侧栏滚动区:菜单(height:100% + 自有 overflow)之外的任意内容
245
+ * 也可滚动;底部区固定不随滚动 */
246
+ .pactor-chat-shell__sidebar-body {
247
+ flex: 1;
248
+ min-height: 0;
249
+ overflow-y: auto;
250
+ }
251
+
252
+ .pactor-chat-shell__sidebar-footer {
253
+ flex-shrink: 0;
254
+ padding: 12px;
255
+ border-top: 1px solid var(--pactor-chat-border);
256
+ }
257
+
258
+ /* 桌面折叠(icon rail,决策 D3):收窄为图标栏——菜单只显图标,
259
+ * label / badge / dot / 分组标题 / 底部区 / 品牌文案隐藏(图标以
260
+ * title 属性兜底可访问名,见 ChatSidebarMenu)。仅桌面生效:移动端
261
+ * 抽屉语义不受影响 */
262
+ @media (min-width: 768px) {
263
+ .pactor-chat-shell__sidebar--collapsed {
264
+ width: 64px;
265
+ }
266
+
267
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-shell__sidebar-header {
268
+ justify-content: center;
269
+ padding-inline: 8px;
270
+ }
271
+
272
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-shell__brand {
273
+ display: none;
274
+ }
275
+
276
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu {
277
+ padding-inline: 8px;
278
+ }
279
+
280
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu__item {
281
+ justify-content: center;
282
+ padding-inline: 0;
283
+ }
284
+
285
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu__label,
286
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu__badge,
287
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu__dot,
288
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-menu__group,
289
+ .pactor-chat-shell__sidebar--collapsed .pactor-chat-shell__sidebar-footer {
290
+ display: none;
291
+ }
292
+ }
293
+
294
+ .pactor-chat-shell__main {
295
+ flex: 1;
296
+ min-width: 0;
297
+ display: flex;
298
+ flex-direction: column;
299
+ overflow: hidden;
300
+ }
301
+
302
+ /* 移动端顶栏:菜单按钮 + brand 插槽;桌面隐藏 */
303
+ .pactor-chat-shell__topbar {
304
+ display: none;
305
+ align-items: center;
306
+ gap: 4px;
307
+ height: var(--pactor-chat-shell-topbar-height);
308
+ flex-shrink: 0;
309
+ padding: 0 8px;
310
+ border-bottom: 1px solid var(--pactor-chat-border);
311
+ }
312
+
313
+ .pactor-chat-shell__menu svg {
314
+ width: 18px;
315
+ height: 18px;
316
+ }
317
+
318
+ .pactor-chat-shell__content {
319
+ flex: 1;
320
+ min-height: 0;
321
+ display: flex;
322
+ flex-direction: column;
323
+ overflow: hidden;
324
+ padding: 12px 16px 16px;
325
+ }
326
+
327
+ /* 对话列在 shell content 内的间距(content 区 padding 承担)与
328
+ * 面板打开时的贴右处理见下方 :has 规则 */
329
+
330
+ /* 产出物面板打开(spec: chat-artifact-panel):面板贴容器右缘——
331
+ * 内容区右/上/下 padding 归零,面板 border-left 作分隔线 */
332
+ .pactor-chat-shell__content:has(> .pactor-chat-inspector-host) {
333
+ padding-top: 0;
334
+ padding-right: 0;
335
+ padding-bottom: 0;
336
+ }
337
+
338
+ /* 抽屉遮罩:仅打开时渲染;桌面隐藏 */
339
+ .pactor-chat-shell__scrim {
340
+ display: none;
341
+ position: fixed;
342
+ inset: 0;
343
+ z-index: 40;
344
+ background: var(--pactor-chat-shell-scrim);
345
+ }
346
+
347
+ @media (max-width: 767px) {
348
+ .pactor-chat-shell__sidebar {
349
+ position: fixed;
350
+ top: 0;
351
+ bottom: 0;
352
+ left: 0;
353
+ z-index: 50;
354
+ box-shadow: var(--pactor-chat-shadow-composer);
355
+ transform: translateX(-100%);
356
+ transition: transform 0.2s ease-out;
357
+ }
358
+
359
+ /* 移动端品牌维持顶栏现状(决策 D3):抽屉内不重复渲染品牌行 */
360
+ .pactor-chat-shell__sidebar-header {
361
+ display: none;
362
+ }
363
+
364
+ .pactor-chat-shell__sidebar[data-open='true'] {
365
+ transform: translateX(0);
366
+ }
367
+
368
+ .pactor-chat-shell__scrim {
369
+ display: block;
370
+ }
371
+
372
+ .pactor-chat-shell__topbar {
373
+ display: flex;
374
+ }
375
+ }
376
+
377
+ /* ------------------------------------------------------------
378
+ * ArtifactPanel(spec: chat-artifact-panel,设计决策 D2):
379
+ * 产出物预览面板。桌面(≥768px)为工作区右侧固定宽栏(flex 同行,
380
+ * 宽度经 --pactor-chat-inspector-width 可调);移动端(<768px)
381
+ * 退化为右侧覆盖抽屉(遮罩点击关闭),与 AppShell 同一断点。
382
+ * 面板关闭 / 未配置时不渲染 DOM(组合层保证)。
383
+ * ------------------------------------------------------------ */
384
+
385
+ /* 面板打开时的同行容器:workspace(或 AppShell)与面板 flex 并排,
386
+ * host 在 shell content 内撑满剩余高度与宽度 */
387
+ .pactor-chat-inspector-host {
388
+ display: flex;
389
+ flex: 1;
390
+ width: 100%;
391
+ min-height: 0;
392
+ overflow: hidden;
393
+ }
394
+
395
+ /* 面板打开时 host 内的直子:AppShell 填满剩余空间;workspace 只缩不伸,
396
+ * 宽度受 --pactor-chat-content-width 限宽,margin auto 在剩余空间内居中 */
397
+ .pactor-chat-inspector-host > .pactor-chat-shell {
398
+ flex: 1;
399
+ min-width: 0;
400
+ }
401
+
402
+ .pactor-chat-inspector-host > .pactor-chat-workspace {
403
+ flex: 0 1 auto;
404
+ min-width: 0;
405
+ }
406
+
407
+ .pactor-chat-inspector {
408
+ position: relative;
409
+ display: flex;
410
+ flex-direction: column;
411
+ width: var(--pactor-chat-inspector-width);
412
+ flex-shrink: 0;
413
+ border-left: 1px solid var(--pactor-chat-border);
414
+ background: var(--pactor-chat-bg);
415
+ color: var(--pactor-chat-fg);
416
+ font-size: 14px;
417
+ line-height: 1.6;
418
+ overflow: hidden;
419
+ }
420
+
421
+ /* 拖拽调宽手柄(spec: chat-artifact-panel / 拖拽调宽):
422
+ * 面板左缘内覆 8px 热区(overflow:hidden 会裁掉负偏移,故内覆而非外探) */
423
+ .pactor-chat-inspector__resize {
424
+ position: absolute;
425
+ left: 0;
426
+ top: 0;
427
+ bottom: 0;
428
+ width: 8px;
429
+ cursor: col-resize;
430
+ z-index: 1;
431
+ touch-action: none;
432
+ }
433
+
434
+ .pactor-chat-inspector__resize:hover,
435
+ .pactor-chat-inspector__resize:active {
436
+ background: color-mix(
437
+ in oklab,
438
+ var(--pactor-chat-primary) 35%,
439
+ transparent
440
+ );
441
+ }
442
+
443
+ .pactor-chat-inspector__header {
444
+ display: flex;
445
+ align-items: center;
446
+ gap: 8px;
447
+ padding: 10px 12px;
448
+ border-bottom: 1px solid var(--pactor-chat-border);
449
+ flex-shrink: 0;
450
+ }
451
+
452
+ .pactor-chat-inspector__title {
453
+ flex: 1;
454
+ min-width: 0;
455
+ overflow: hidden;
456
+ text-overflow: ellipsis;
457
+ white-space: nowrap;
458
+ font-family: var(--pactor-chat-font-display);
459
+ font-size: 14px;
460
+ font-weight: 600;
461
+ }
462
+
463
+ /* kind 角标(与产出物卡片角标同款) */
464
+ .pactor-chat-inspector__kind,
465
+ .pactor-chat-artifact-card__kind {
466
+ flex-shrink: 0;
467
+ padding: 0 6px;
468
+ border-radius: 999px;
469
+ background: var(--pactor-chat-muted);
470
+ color: var(--pactor-chat-muted-fg);
471
+ font-size: 11px;
472
+ line-height: 18px;
473
+ }
474
+
475
+ .pactor-chat-inspector__close {
476
+ flex-shrink: 0;
477
+ }
478
+
479
+ .pactor-chat-inspector__body {
480
+ flex: 1;
481
+ min-height: 0;
482
+ overflow-y: auto;
483
+ padding: 12px;
484
+ }
485
+
486
+ /* code 产出物:只读代码块(language 右上角标,不引高亮依赖) */
487
+ .pactor-chat-inspector__code {
488
+ position: relative;
489
+ }
490
+
491
+ .pactor-chat-inspector__code pre {
492
+ margin: 0;
493
+ padding: 10px 12px;
494
+ border: 1px solid var(--pactor-chat-border);
495
+ border-radius: var(--pactor-chat-radius-md);
496
+ background: var(--pactor-chat-code-bg);
497
+ overflow-x: auto;
498
+ font-size: 12.5px;
499
+ }
500
+
501
+ .pactor-chat-inspector__code-lang {
502
+ position: absolute;
503
+ top: 6px;
504
+ right: 8px;
505
+ padding: 0 6px;
506
+ border-radius: 999px;
507
+ background: var(--pactor-chat-muted);
508
+ color: var(--pactor-chat-muted-fg);
509
+ font-size: 11px;
510
+ line-height: 18px;
511
+ }
512
+
513
+ /* text 产出物:预格式文本 */
514
+ .pactor-chat-inspector__text {
515
+ margin: 0;
516
+ white-space: pre-wrap;
517
+ word-break: break-word;
518
+ font-size: 13px;
519
+ }
520
+
521
+ /* 窄屏覆盖抽屉遮罩:仅面板打开时渲染;桌面隐藏(同 AppShell scrim 模式) */
522
+ .pactor-chat-inspector__scrim {
523
+ display: none;
524
+ position: fixed;
525
+ inset: 0;
526
+ z-index: 40;
527
+ background: var(--pactor-chat-shell-scrim);
528
+ }
529
+
530
+ @media (max-width: 767px) {
531
+ .pactor-chat-inspector {
532
+ position: fixed;
533
+ top: 0;
534
+ bottom: 0;
535
+ right: 0;
536
+ z-index: 50;
537
+ box-shadow: var(--pactor-chat-shadow-composer);
538
+ }
539
+
540
+ /* 窄屏覆盖抽屉形态:不显示拖拽手柄(spec scenario: 窄屏无拖拽手柄) */
541
+ .pactor-chat-inspector__resize {
542
+ display: none;
543
+ }
544
+
545
+ .pactor-chat-inspector__scrim {
546
+ display: block;
547
+ }
548
+ }
549
+
550
+ /* ------------------------------------------------------------
551
+ * 产出物卡片(spec: chat-artifact-panel / artifact 消息 part):
552
+ * 消息流内 artifact part 的内联呈现——标题 + kind 角标 + 打开按钮。
553
+ * ------------------------------------------------------------ */
554
+
555
+ .pactor-chat-artifact-card {
556
+ display: flex;
557
+ align-items: center;
558
+ gap: 8px;
559
+ margin: 8px 0;
560
+ padding: 10px 12px;
561
+ border: 1px solid var(--pactor-chat-border);
562
+ border-radius: var(--pactor-chat-radius-md);
563
+ background: var(--pactor-chat-card);
564
+ box-shadow: var(--pactor-chat-shadow-sm);
565
+ }
566
+
567
+ .pactor-chat-artifact-card__title {
568
+ flex: 1;
569
+ min-width: 0;
570
+ overflow: hidden;
571
+ text-overflow: ellipsis;
572
+ white-space: nowrap;
573
+ font-weight: 600;
574
+ font-size: 13px;
575
+ }
576
+
577
+ .pactor-chat-artifact-card__open {
578
+ flex-shrink: 0;
579
+ padding: 4px 10px;
580
+ border: 1px solid var(--pactor-chat-border);
581
+ border-radius: var(--pactor-chat-radius-sm);
582
+ background: transparent;
583
+ color: var(--pactor-chat-primary);
584
+ font-size: 12px;
585
+ cursor: pointer;
586
+ transition: background 0.15s ease;
587
+ }
588
+
589
+ .pactor-chat-artifact-card__open:hover {
590
+ background: var(--pactor-chat-muted);
591
+ }
592
+
593
+ /* ------------------------------------------------------------
594
+ * Chat 组件内建侧栏菜单(spec: chat-dsl-component):
595
+ * menu 数据驱动的导航项(图标 + 分组标题 + badge + disabled),
596
+ * 承载于 AppShell 侧栏;颜色全部经 --pactor-chat-* 令牌,
597
+ * 暗色由令牌覆盖自动生效。
598
+ * ------------------------------------------------------------ */
599
+
600
+ .pactor-chat-menu {
601
+ display: flex;
602
+ flex-direction: column;
603
+ gap: 2px;
604
+ height: 100%;
605
+ padding: 12px;
606
+ overflow-y: auto;
607
+ box-sizing: border-box;
608
+ }
609
+
610
+ .pactor-chat-menu__group {
611
+ padding: 10px 10px 4px;
612
+ color: var(--pactor-chat-muted-fg);
613
+ font-size: 12px;
614
+ }
615
+
616
+ .pactor-chat-menu__item {
617
+ display: flex;
618
+ align-items: center;
619
+ gap: 8px;
620
+ width: 100%;
621
+ padding: 8px 10px;
622
+ border: none;
623
+ border-radius: var(--pactor-chat-radius);
624
+ background: transparent;
625
+ color: var(--pactor-chat-fg);
626
+ font-size: 14px;
627
+ line-height: 1.4;
628
+ text-align: left;
629
+ cursor: pointer;
630
+ transition: background 0.15s ease;
631
+ }
632
+
633
+ .pactor-chat-menu__item:hover {
634
+ background: var(--pactor-chat-muted);
635
+ }
636
+
637
+ .pactor-chat-menu__item--active,
638
+ .pactor-chat-menu__item--active:hover {
639
+ background: var(--pactor-chat-user-bubble-bg);
640
+ color: var(--pactor-chat-primary);
641
+ }
642
+
643
+ .pactor-chat-menu__item:disabled,
644
+ .pactor-chat-menu__item:disabled:hover {
645
+ background: transparent;
646
+ color: var(--pactor-chat-muted-fg);
647
+ opacity: 0.6;
648
+ cursor: not-allowed;
649
+ }
650
+
651
+ .pactor-chat-menu__icon {
652
+ display: inline-flex;
653
+ flex-shrink: 0;
654
+ align-items: center;
655
+ }
656
+
657
+ /* 未知图标名的占位圆点(不抛错的受控降级) */
658
+ .pactor-chat-menu__icon-placeholder {
659
+ width: 6px;
660
+ height: 6px;
661
+ margin: 0 4px;
662
+ flex-shrink: 0;
663
+ border-radius: 50%;
664
+ background: var(--pactor-chat-muted-fg);
665
+ opacity: 0.5;
666
+ }
667
+
668
+ .pactor-chat-menu__label {
669
+ flex: 1;
670
+ min-width: 0;
671
+ overflow: hidden;
672
+ text-overflow: ellipsis;
673
+ white-space: nowrap;
674
+ }
675
+
676
+ .pactor-chat-menu__badge {
677
+ flex-shrink: 0;
678
+ padding: 0 6px;
679
+ border-radius: 999px;
680
+ background: var(--pactor-chat-muted);
681
+ color: var(--pactor-chat-muted-fg);
682
+ font-size: 12px;
683
+ line-height: 18px;
684
+ }
685
+
686
+ .pactor-chat-menu__item--active .pactor-chat-menu__badge {
687
+ background: var(--pactor-chat-user-bubble-bg);
688
+ color: var(--pactor-chat-primary);
689
+ }
690
+
691
+ /* 菜单项状态圆点(spec: chat-dsl-component / 菜单项状态点,决策 D4):
692
+ * label 右侧的 danger 系小圆点(参考图红点),与 badge 可共存 */
693
+ .pactor-chat-menu__dot {
694
+ flex-shrink: 0;
695
+ width: 6px;
696
+ height: 6px;
697
+ border-radius: 50%;
698
+ background: var(--pactor-chat-danger);
699
+ }
700
+
701
+ /* Chat 服务缺失的受控提示块(未配置 ChatServicesProvider 时渲染) */
702
+ .pactor-chat-notice {
703
+ padding: 24px 16px;
704
+ border: 1px dashed var(--pactor-chat-border);
705
+ border-radius: var(--pactor-chat-radius-md);
706
+ background: var(--pactor-chat-bg);
707
+ color: var(--pactor-chat-muted-fg);
708
+ font-size: 13px;
709
+ line-height: 1.6;
710
+ text-align: center;
711
+ }
712
+
713
+
714
+ /* 消息滚动区:overflow-anchor none 配合 useChatAutoScroll(防浏览器
715
+ 滚动锚定与贴底跟随互相拉扯);上下 mask 渐隐 + 6px 细滚动条 */
716
+ .pactor-chat-messages {
717
+ position: relative;
718
+ flex: 1;
719
+ min-height: 0;
720
+ overflow-y: auto;
721
+ overflow-anchor: none;
722
+ display: flex;
723
+ flex-direction: column;
724
+ gap: 16px;
725
+ padding: 4px 2px;
726
+ scrollbar-width: thin;
727
+ scrollbar-color: var(--pactor-chat-border) transparent;
728
+ -webkit-mask-image: linear-gradient(
729
+ to bottom,
730
+ transparent,
731
+ #000 24px,
732
+ #000 calc(100% - 24px),
733
+ transparent
734
+ );
735
+ mask-image: linear-gradient(
736
+ to bottom,
737
+ transparent,
738
+ #000 24px,
739
+ #000 calc(100% - 24px),
740
+ transparent
741
+ );
742
+ }
743
+
744
+ .pactor-chat-messages::-webkit-scrollbar {
745
+ width: 6px;
746
+ height: 6px;
747
+ }
748
+
749
+ .pactor-chat-messages::-webkit-scrollbar-track {
750
+ background: transparent;
751
+ }
752
+
753
+ .pactor-chat-messages::-webkit-scrollbar-thumb {
754
+ background: var(--pactor-chat-border);
755
+ border-radius: 3px;
756
+ }
757
+
758
+ .pactor-chat-messages::-webkit-scrollbar-thumb:hover {
759
+ background: var(--pactor-chat-muted-fg);
760
+ }
761
+
762
+ /* ============================================================
763
+ * 3. 空状态(spec: chat-empty-state)
764
+ * ============================================================ */
765
+
766
+ /* 空态居中组(决策 D1):EmptyState 与 Composer 同一垂直居中列。
767
+ * margin auto 在消息区(flex 列容器)内双向居中;内容高于视口时
768
+ * auto 边距归零,配合消息区 overflow-y auto 从顶部自然滚动
769
+ * (极矮视口不裁切) */
770
+ .pactor-chat-view__empty-stack {
771
+ display: flex;
772
+ flex-direction: column;
773
+ gap: 24px;
774
+ width: 100%;
775
+ max-width: var(--pactor-chat-content-width);
776
+ margin: auto;
777
+ padding: 16px 0;
778
+ }
779
+
780
+ .pactor-chat-view__empty-stack .pactor-chat-empty {
781
+ flex: none;
782
+ }
783
+
784
+ .pactor-chat-empty {
785
+ flex: 1;
786
+ display: flex;
787
+ flex-direction: column;
788
+ align-items: center;
789
+ justify-content: center;
790
+ gap: 12px;
791
+ padding: 32px 16px;
792
+ text-align: center;
793
+ }
794
+
795
+ .pactor-chat-empty__greeting {
796
+ font-family: var(--pactor-chat-font-display);
797
+ font-size: 26px;
798
+ font-weight: 500;
799
+ line-height: 1.4;
800
+ }
801
+
802
+ .pactor-chat-empty__subtitle {
803
+ color: var(--pactor-chat-muted-fg);
804
+ font-size: 13px;
805
+ }
806
+
807
+ .pactor-chat-empty__suggestions {
808
+ display: flex;
809
+ flex-wrap: wrap;
810
+ justify-content: center;
811
+ gap: 8px;
812
+ margin-top: 8px;
813
+ }
814
+
815
+ .pactor-chat-empty__suggestion {
816
+ padding: 6px 14px;
817
+ border: 1px solid var(--pactor-chat-border);
818
+ border-radius: 999px;
819
+ background: var(--pactor-chat-card);
820
+ color: var(--pactor-chat-fg);
821
+ font-size: 13px;
822
+ cursor: pointer;
823
+ transition:
824
+ border-color 0.15s ease,
825
+ background 0.15s ease;
826
+ }
827
+
828
+ .pactor-chat-empty__suggestion:hover {
829
+ border-color: var(--pactor-chat-primary);
830
+ background: var(--pactor-chat-muted);
831
+ }
832
+
833
+ /* ============================================================
834
+ * 4. 消息气泡
835
+ * ============================================================ */
836
+
837
+ .pactor-chat-message {
838
+ display: flex;
839
+ flex-direction: column;
840
+ gap: 4px;
841
+ max-width: 100%;
842
+ }
843
+
844
+ .pactor-chat-message__body {
845
+ display: flex;
846
+ flex-direction: column;
847
+ gap: 8px;
848
+ min-width: 0;
849
+ }
850
+
851
+ /* user:右侧圆角气泡(16px 圆角 + 轻投影) */
852
+ .pactor-chat-message--user {
853
+ align-items: flex-end;
854
+ }
855
+
856
+ .pactor-chat-message--user .pactor-chat-message__body {
857
+ max-width: 75%;
858
+ padding: 10px 16px;
859
+ border-radius: var(--pactor-chat-radius-lg);
860
+ border: 1px solid var(--pactor-chat-user-bubble-border);
861
+ background: var(--pactor-chat-user-bubble-bg);
862
+ box-shadow: var(--pactor-chat-shadow-sm);
863
+ }
864
+
865
+ /* assistant:左侧通栏排版(无气泡底色) */
866
+ .pactor-chat-message--assistant {
867
+ align-items: stretch;
868
+ }
869
+
870
+ /* system:居中弱提示 */
871
+ .pactor-chat-message--system {
872
+ align-items: center;
873
+ color: var(--pactor-chat-muted-fg);
874
+ font-size: 12px;
875
+ }
876
+
877
+ /* 待响应占位 */
878
+ .pactor-chat-message__pending {
879
+ color: var(--pactor-chat-muted-fg);
880
+ }
881
+
882
+ /* hover 操作条(assistant) */
883
+ .pactor-chat-message__actions {
884
+ display: flex;
885
+ gap: 4px;
886
+ opacity: 0;
887
+ transition: opacity 0.15s ease;
888
+ }
889
+
890
+ .pactor-chat-message:hover .pactor-chat-message__actions,
891
+ .pactor-chat-message__actions:focus-within {
892
+ opacity: 1;
893
+ }
894
+
895
+ /* error 消息的重试入口常显(不依赖 hover) */
896
+ .pactor-chat-message__actions--visible {
897
+ opacity: 1;
898
+ }
899
+
900
+ /* user 消息内联编辑框(编辑重发) */
901
+ .pactor-chat-message__edit {
902
+ display: flex;
903
+ flex-direction: column;
904
+ gap: 8px;
905
+ max-width: 75%;
906
+ width: 100%;
907
+ padding: 10px 12px;
908
+ border: 1px solid var(--pactor-chat-user-bubble-border);
909
+ border-radius: var(--pactor-chat-radius-lg);
910
+ background: var(--pactor-chat-user-bubble-bg);
911
+ }
912
+
913
+ .pactor-chat-message__edit-input {
914
+ border: none;
915
+ outline: none;
916
+ resize: vertical;
917
+ background: transparent;
918
+ color: var(--pactor-chat-fg);
919
+ font: inherit;
920
+ line-height: 1.6;
921
+ }
922
+
923
+ .pactor-chat-message__edit-actions {
924
+ display: flex;
925
+ justify-content: flex-end;
926
+ gap: 8px;
927
+ }
928
+
929
+ .pactor-chat-message__edit-button {
930
+ padding: 4px 12px;
931
+ border: 1px solid var(--pactor-chat-border);
932
+ border-radius: var(--pactor-chat-radius-sm);
933
+ background: var(--pactor-chat-card);
934
+ color: var(--pactor-chat-fg);
935
+ font-size: 12.5px;
936
+ cursor: pointer;
937
+ }
938
+
939
+ .pactor-chat-message__edit-button--confirm {
940
+ border-color: var(--pactor-chat-primary);
941
+ background: var(--pactor-chat-primary);
942
+ color: var(--pactor-chat-primary-fg);
943
+ }
944
+
945
+ /* ============================================================
946
+ * 5. 图标按钮 / 浮动按钮
947
+ * ============================================================ */
948
+
949
+ /* quiet 图标按钮:透明底,hover 增亮;图标统一 15px */
950
+ .pactor-chat-icon-button {
951
+ display: inline-flex;
952
+ align-items: center;
953
+ justify-content: center;
954
+ padding: 4px;
955
+ border: none;
956
+ border-radius: var(--pactor-chat-radius-md);
957
+ background: transparent;
958
+ color: var(--pactor-chat-muted-fg);
959
+ cursor: pointer;
960
+ transition:
961
+ background 0.15s ease,
962
+ color 0.15s ease,
963
+ transform 0.1s ease;
964
+ }
965
+
966
+ .pactor-chat-icon-button svg {
967
+ width: 15px;
968
+ height: 15px;
969
+ }
970
+
971
+ .pactor-chat-icon-button:hover {
972
+ background: var(--pactor-chat-muted);
973
+ color: var(--pactor-chat-fg);
974
+ }
975
+
976
+ .pactor-chat-icon-button:active {
977
+ transform: scale(0.92);
978
+ }
979
+
980
+ /* "回到底部"浮动按钮(bottom 避开滚动区底部 mask 渐隐带) */
981
+ .pactor-chat-scroll-bottom {
982
+ position: sticky;
983
+ bottom: 28px;
984
+ align-self: center;
985
+ display: inline-flex;
986
+ align-items: center;
987
+ gap: 6px;
988
+ padding: 6px 12px;
989
+ border: 1px solid var(--pactor-chat-border);
990
+ border-radius: 999px;
991
+ background: var(--pactor-chat-card);
992
+ color: var(--pactor-chat-muted-fg);
993
+ font-size: 12px;
994
+ cursor: pointer;
995
+ box-shadow: var(--pactor-chat-shadow-composer);
996
+ }
997
+
998
+ .pactor-chat-scroll-bottom:hover {
999
+ color: var(--pactor-chat-fg);
1000
+ }
1001
+
1002
+ /* ============================================================
1003
+ * 6. 活动轨迹(spec: chat-activity-trace):状态头 + 轨迹条目 + thinking
1004
+ * ============================================================ */
1005
+
1006
+ .pactor-chat-trace {
1007
+ display: flex;
1008
+ flex-direction: column;
1009
+ gap: 2px;
1010
+ font-size: 12.5px;
1011
+ }
1012
+
1013
+ /* 状态头 / 条目头 / thinking 头共用的单行按钮形态 */
1014
+ .pactor-chat-trace__header,
1015
+ .pactor-chat-trace__entry-header,
1016
+ .pactor-chat-thinking__header {
1017
+ display: flex;
1018
+ align-items: center;
1019
+ gap: 6px;
1020
+ width: 100%;
1021
+ padding: 3px 0;
1022
+ border: none;
1023
+ background: transparent;
1024
+ color: var(--pactor-chat-muted-fg);
1025
+ font-size: inherit;
1026
+ text-align: left;
1027
+ }
1028
+
1029
+ button.pactor-chat-trace__header,
1030
+ .pactor-chat-trace__entry-header,
1031
+ .pactor-chat-thinking__header {
1032
+ cursor: pointer;
1033
+ }
1034
+
1035
+ button.pactor-chat-trace__header:hover,
1036
+ .pactor-chat-trace__entry-header:hover,
1037
+ .pactor-chat-thinking__header:hover {
1038
+ color: var(--pactor-chat-fg);
1039
+ }
1040
+
1041
+ /* 头部内图标/文字统一 flex 对齐(svg 默认按基线对齐会下沉) */
1042
+ .pactor-chat-trace__header > span,
1043
+ .pactor-chat-trace__entry-header > span,
1044
+ .pactor-chat-thinking__header > span {
1045
+ display: inline-flex;
1046
+ align-items: center;
1047
+ line-height: 1;
1048
+ min-width: 0;
1049
+ }
1050
+
1051
+ /* 状态文案:流式期间呼吸动画(纯 CSS) */
1052
+ .pactor-chat-trace__status-text--breathing {
1053
+ animation: pactor-chat-breathing 1.8s cubic-bezier(0.4, 0, 0.6, 1) infinite;
1054
+ }
1055
+
1056
+ @keyframes pactor-chat-breathing {
1057
+ 0%,
1058
+ 100% {
1059
+ opacity: 1;
1060
+ }
1061
+ 50% {
1062
+ opacity: 0.45;
1063
+ }
1064
+ }
1065
+
1066
+ /* 状态图标脉冲:流式期间(图标为 spinner 时)轻微缩放逐帧"呼吸",
1067
+ 与文案呼吸不同周期,避免机械同步感 */
1068
+ .pactor-chat-trace__status-icon:has(.pactor-chat-spin),
1069
+ .pactor-chat-thinking[data-streaming='true'] .pactor-chat-thinking__icon {
1070
+ animation: pactor-chat-mark-pulse 2.4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
1071
+ transform-origin: center;
1072
+ }
1073
+
1074
+ @keyframes pactor-chat-mark-pulse {
1075
+ 0%,
1076
+ 100% {
1077
+ transform: scale(0.9);
1078
+ }
1079
+ 50% {
1080
+ transform: scale(1.08);
1081
+ }
1082
+ }
1083
+
1084
+ .pactor-chat-trace__elapsed {
1085
+ color: var(--pactor-chat-muted-fg);
1086
+ font-variant-numeric: tabular-nums;
1087
+ }
1088
+
1089
+ /* chevron 展开旋转(状态头 / 条目 / thinking 共用) */
1090
+ .pactor-chat-trace__chevron {
1091
+ display: inline-flex;
1092
+ flex-shrink: 0;
1093
+ transition: transform 0.15s ease;
1094
+ }
1095
+
1096
+ .pactor-chat-trace[data-open='true'] > .pactor-chat-trace__header
1097
+ .pactor-chat-trace__chevron,
1098
+ .pactor-chat-trace__entry[data-open='true'] .pactor-chat-trace__chevron,
1099
+ .pactor-chat-thinking[data-open='true'] .pactor-chat-trace__chevron {
1100
+ transform: rotate(90deg);
1101
+ }
1102
+
1103
+ /* 轨迹条目列表:缩进对齐状态头文本 */
1104
+ .pactor-chat-trace__entries {
1105
+ display: flex;
1106
+ flex-direction: column;
1107
+ gap: 2px;
1108
+ margin-left: 4px;
1109
+ }
1110
+
1111
+ .pactor-chat-trace__entry-title {
1112
+ flex-shrink: 0;
1113
+ }
1114
+
1115
+ /* 参数摘要:单行省略 */
1116
+ .pactor-chat-trace__entry-args {
1117
+ flex: 1;
1118
+ overflow: hidden;
1119
+ text-overflow: ellipsis;
1120
+ white-space: nowrap;
1121
+ color: var(--pactor-chat-muted-fg);
1122
+ opacity: 0.8;
1123
+ }
1124
+
1125
+ /* 条目状态色 */
1126
+ .pactor-chat-trace__entry[data-status='running'] .pactor-chat-trace__entry-icon {
1127
+ color: var(--pactor-chat-primary);
1128
+ }
1129
+
1130
+ .pactor-chat-trace__entry[data-status='success'] .pactor-chat-trace__entry-icon {
1131
+ color: var(--pactor-chat-success);
1132
+ }
1133
+
1134
+ .pactor-chat-trace__entry[data-status='failed'] .pactor-chat-trace__entry-icon {
1135
+ color: var(--pactor-chat-danger);
1136
+ }
1137
+
1138
+ /* 展开详情:参数与结果/错误 */
1139
+ .pactor-chat-trace__entry-body {
1140
+ padding: 2px 0 6px 24px;
1141
+ color: var(--pactor-chat-muted-fg);
1142
+ }
1143
+
1144
+ .pactor-chat-trace__entry-detail {
1145
+ margin: 0;
1146
+ font-size: 12px;
1147
+ white-space: pre-wrap;
1148
+ word-break: break-word;
1149
+ }
1150
+
1151
+ /* thinking 折叠卡:进行中指示(图标旋转沿用 .pactor-chat-spin) */
1152
+ .pactor-chat-thinking__icon {
1153
+ color: var(--pactor-chat-muted-fg);
1154
+ }
1155
+
1156
+ .pactor-chat-thinking[data-streaming='true'] .pactor-chat-thinking__icon {
1157
+ color: var(--pactor-chat-primary);
1158
+ }
1159
+
1160
+ .pactor-chat-thinking__body {
1161
+ padding: 2px 0 6px 24px;
1162
+ color: var(--pactor-chat-muted-fg);
1163
+ }
1164
+
1165
+ .pactor-chat-thinking__body .pactor-markdown > :first-child {
1166
+ margin-top: 0;
1167
+ }
1168
+
1169
+ .pactor-chat-thinking__body .pactor-markdown > :last-child {
1170
+ margin-bottom: 0;
1171
+ }
1172
+
1173
+ /* running 旋转 */
1174
+ .pactor-chat-spin {
1175
+ animation: pactor-chat-spin 1s linear infinite;
1176
+ }
1177
+
1178
+ @keyframes pactor-chat-spin {
1179
+ to {
1180
+ transform: rotate(360deg);
1181
+ }
1182
+ }
1183
+
1184
+ /* ============================================================
1185
+ * 7. 其他 part
1186
+ * ============================================================ */
1187
+
1188
+ .pactor-chat-text {
1189
+ white-space: pre-wrap;
1190
+ word-break: break-word;
1191
+ }
1192
+
1193
+ .pactor-chat-error {
1194
+ display: flex;
1195
+ align-items: flex-start;
1196
+ gap: 8px;
1197
+ padding: 8px 12px;
1198
+ border: 1px solid var(--pactor-chat-danger);
1199
+ border-radius: var(--pactor-chat-radius-md);
1200
+ background: var(--pactor-chat-danger-bg);
1201
+ color: var(--pactor-chat-danger);
1202
+ font-size: 12.5px;
1203
+ }
1204
+
1205
+ /* 图标与首行文字对齐(svg 默认按基线对齐会下沉) */
1206
+ .pactor-chat-error > svg {
1207
+ flex-shrink: 0;
1208
+ margin-top: 3px;
1209
+ display: block;
1210
+ }
1211
+
1212
+ .pactor-chat-status {
1213
+ color: var(--pactor-chat-muted-fg);
1214
+ font-size: 12px;
1215
+ }
1216
+
1217
+ .pactor-chat-dsl-pending {
1218
+ color: var(--pactor-chat-muted-fg);
1219
+ font-size: 12px;
1220
+ }
1221
+
1222
+ .pactor-chat-denied {
1223
+ border: 1px dashed var(--pactor-chat-border);
1224
+ border-radius: var(--pactor-chat-radius-sm);
1225
+ padding: 8px;
1226
+ color: var(--pactor-chat-muted-fg);
1227
+ font-size: 12px;
1228
+ }
1229
+
1230
+ /* ============================================================
1231
+ * 8. Markdown 排版(chat 作为 pactor-markdown 的宿主主题)
1232
+ * ============================================================ */
1233
+
1234
+ .pactor-chat-view .pactor-markdown > :first-child {
1235
+ margin-top: 0;
1236
+ }
1237
+
1238
+ .pactor-chat-view .pactor-markdown > :last-child {
1239
+ margin-bottom: 0;
1240
+ }
1241
+
1242
+ .pactor-chat-view .pactor-markdown pre {
1243
+ margin: 8px 0;
1244
+ padding: 10px 12px;
1245
+ border: 1px solid var(--pactor-chat-border);
1246
+ border-radius: var(--pactor-chat-radius-md);
1247
+ background: var(--pactor-chat-code-bg);
1248
+ overflow-x: auto;
1249
+ font-size: 12.5px;
1250
+ }
1251
+
1252
+ .pactor-chat-view .pactor-markdown :not(pre) > code {
1253
+ padding: 2px 5px;
1254
+ border-radius: 4px;
1255
+ background: var(--pactor-chat-code-bg);
1256
+ font-size: 0.9em;
1257
+ }
1258
+
1259
+ .pactor-chat-view .pactor-markdown table {
1260
+ border-collapse: collapse;
1261
+ margin: 8px 0;
1262
+ }
1263
+
1264
+ .pactor-chat-view .pactor-markdown th,
1265
+ .pactor-chat-view .pactor-markdown td {
1266
+ padding: 6px 12px;
1267
+ border: 1px solid var(--pactor-chat-border);
1268
+ }
1269
+
1270
+ .pactor-chat-view .pactor-markdown th {
1271
+ background: var(--pactor-chat-muted);
1272
+ }
1273
+
1274
+ .pactor-chat-view .pactor-markdown a {
1275
+ color: var(--pactor-chat-primary);
1276
+ }
1277
+
1278
+ .pactor-chat-view .pactor-markdown blockquote {
1279
+ margin: 8px 0;
1280
+ padding: 2px 12px;
1281
+ border-left: 3px solid var(--pactor-chat-border);
1282
+ color: var(--pactor-chat-muted-fg);
1283
+ }
1284
+
1285
+ .pactor-chat-view .pactor-markdown img {
1286
+ max-width: 100%;
1287
+ }
1288
+
1289
+ /* ============================================================
1290
+ * 9. Composer
1291
+ * ============================================================ */
1292
+
1293
+ .pactor-chat-composer {
1294
+ display: flex;
1295
+ flex-direction: column;
1296
+ gap: 8px;
1297
+ padding: 12px 14px;
1298
+ border: 1px solid var(--pactor-chat-border);
1299
+ border-radius: var(--pactor-chat-radius-xl);
1300
+ background: var(--pactor-chat-card);
1301
+ box-shadow: var(--pactor-chat-shadow-composer);
1302
+ transition: border-color 0.15s ease;
1303
+ }
1304
+
1305
+ .pactor-chat-composer:focus-within {
1306
+ border-color: var(--pactor-chat-primary);
1307
+ }
1308
+
1309
+ /* 拖拽悬停视觉态(附件拖入时) */
1310
+ .pactor-chat-composer--dragover {
1311
+ border-color: var(--pactor-chat-primary);
1312
+ background: var(--pactor-chat-muted);
1313
+ }
1314
+
1315
+ /* 输入行:textarea + 发送/停止按钮 */
1316
+ .pactor-chat-composer__row {
1317
+ display: flex;
1318
+ gap: 8px;
1319
+ align-items: flex-end;
1320
+ }
1321
+
1322
+ .pactor-chat-composer__input {
1323
+ flex: 1;
1324
+ min-width: 0;
1325
+ border: none;
1326
+ outline: none;
1327
+ resize: none;
1328
+ background: transparent;
1329
+ color: var(--pactor-chat-fg);
1330
+ font: inherit;
1331
+ line-height: 22px;
1332
+ /* 单行时与 32px 发送按钮等高,文字(含 placeholder)垂直居中 */
1333
+ min-height: 32px;
1334
+ padding: 5px 0;
1335
+ max-height: 200px;
1336
+ }
1337
+
1338
+ .pactor-chat-composer__input::placeholder {
1339
+ color: var(--pactor-chat-muted-fg);
1340
+ }
1341
+
1342
+ /* 发送 / 停止按钮:圆形主按钮 */
1343
+ .pactor-chat-composer__button {
1344
+ position: relative;
1345
+ display: inline-flex;
1346
+ align-items: center;
1347
+ justify-content: center;
1348
+ width: 32px;
1349
+ height: 32px;
1350
+ flex-shrink: 0;
1351
+ border: none;
1352
+ border-radius: 999px;
1353
+ background: var(--pactor-chat-primary);
1354
+ color: var(--pactor-chat-primary-fg);
1355
+ cursor: pointer;
1356
+ transition: opacity 0.15s ease;
1357
+ }
1358
+
1359
+ .pactor-chat-composer__button:disabled {
1360
+ opacity: 0.4;
1361
+ cursor: not-allowed;
1362
+ }
1363
+
1364
+ .pactor-chat-composer__button--stop {
1365
+ background: var(--pactor-chat-danger);
1366
+ }
1367
+
1368
+ /* 停止态进行中光环(纯 CSS keyframes,随按钮圆形) */
1369
+ .pactor-chat-composer__button--stop::after {
1370
+ content: '';
1371
+ position: absolute;
1372
+ inset: -3px;
1373
+ border: 2px solid var(--pactor-chat-danger);
1374
+ border-radius: 999px;
1375
+ pointer-events: none;
1376
+ animation: pactor-chat-ring 1.4s ease-out infinite;
1377
+ }
1378
+
1379
+ @keyframes pactor-chat-ring {
1380
+ 0% {
1381
+ transform: scale(0.92);
1382
+ opacity: 0.6;
1383
+ }
1384
+ 100% {
1385
+ transform: scale(1.3);
1386
+ opacity: 0;
1387
+ }
1388
+ }
1389
+
1390
+ /* 附件卡片区 */
1391
+ .pactor-chat-composer__attachments {
1392
+ display: flex;
1393
+ flex-wrap: wrap;
1394
+ gap: 8px;
1395
+ }
1396
+
1397
+ .pactor-chat-composer__attachment {
1398
+ position: relative;
1399
+ display: inline-flex;
1400
+ align-items: center;
1401
+ border: 1px solid var(--pactor-chat-border);
1402
+ border-radius: var(--pactor-chat-radius-md);
1403
+ background: var(--pactor-chat-muted);
1404
+ cursor: pointer;
1405
+ }
1406
+
1407
+ .pactor-chat-composer__attachment-thumb img {
1408
+ display: block;
1409
+ width: 40px;
1410
+ height: 40px;
1411
+ object-fit: cover;
1412
+ border-radius: 7px;
1413
+ }
1414
+
1415
+ .pactor-chat-composer__attachment-info {
1416
+ display: inline-flex;
1417
+ align-items: center;
1418
+ gap: 6px;
1419
+ padding: 8px 10px;
1420
+ font-size: 12.5px;
1421
+ color: var(--pactor-chat-fg);
1422
+ }
1423
+
1424
+ .pactor-chat-composer__attachment-name {
1425
+ max-width: 160px;
1426
+ overflow: hidden;
1427
+ text-overflow: ellipsis;
1428
+ white-space: nowrap;
1429
+ }
1430
+
1431
+ .pactor-chat-composer__attachment-size {
1432
+ color: var(--pactor-chat-muted-fg);
1433
+ }
1434
+
1435
+ .pactor-chat-composer__attachment-remove {
1436
+ position: absolute;
1437
+ top: -6px;
1438
+ right: -6px;
1439
+ padding: 2px;
1440
+ border: 1px solid var(--pactor-chat-border);
1441
+ border-radius: 50%;
1442
+ background: var(--pactor-chat-card);
1443
+ }
1444
+
1445
+ /* 移除按钮是微型圆形按钮,保持 12px 小图标 */
1446
+ .pactor-chat-composer__attachment-remove svg {
1447
+ width: 12px;
1448
+ height: 12px;
1449
+ }
1450
+
1451
+ /* 工具栏:渲染槽 + "+" / 附件入口 */
1452
+ .pactor-chat-composer__toolbar {
1453
+ display: flex;
1454
+ align-items: center;
1455
+ flex-wrap: wrap;
1456
+ gap: 6px;
1457
+ }
1458
+
1459
+ .pactor-chat-composer__toolbar-spacer {
1460
+ flex: 1;
1461
+ }
1462
+
1463
+ /* ------------------------------------------------------------
1464
+ * 内建锚定弹层 AnchoredPopover(chat-builtin-features 设计决策 D3):
1465
+ * position: fixed,top/bottom/left 由 JS 按锚点计算(上方优先、
1466
+ * 空间不足翻转为 --below);首帧 visibility:hidden 量高后显示。
1467
+ * 浮于 chat 内其它浮层之上(侧栏抽屉 50 / 遮罩 40 之上)。
1468
+ * ------------------------------------------------------------ */
1469
+
1470
+ .pactor-chat-popover {
1471
+ position: fixed;
1472
+ z-index: 60;
1473
+ padding: 4px;
1474
+ max-height: 280px;
1475
+ overflow-y: auto;
1476
+ border: 1px solid var(--pactor-chat-border);
1477
+ border-radius: var(--pactor-chat-radius-md);
1478
+ background: var(--pactor-chat-card);
1479
+ color: var(--pactor-chat-fg);
1480
+ box-shadow: var(--pactor-chat-shadow-composer);
1481
+ font-size: 14px;
1482
+ line-height: 1.5;
1483
+ scrollbar-width: thin;
1484
+ scrollbar-color: var(--pactor-chat-border) transparent;
1485
+ }
1486
+
1487
+ /* ------------------------------------------------------------
1488
+ * 内建特性(chat-builtin-features):模型 chip / 上下文 chips /
1489
+ * 弹层候选列表 / header 操作组与可编辑标题。全部只用既有
1490
+ * --pactor-chat-* 语义令牌,暗色经令牌覆盖自动生效。
1491
+ * ------------------------------------------------------------ */
1492
+
1493
+ /* 弹层候选行(模型列表 / 上下文候选共用) */
1494
+ .pactor-chat-popover__item {
1495
+ display: flex;
1496
+ align-items: center;
1497
+ gap: 8px;
1498
+ width: 100%;
1499
+ min-width: 160px;
1500
+ padding: 6px 10px;
1501
+ border: none;
1502
+ border-radius: var(--pactor-chat-radius-sm);
1503
+ background: transparent;
1504
+ color: var(--pactor-chat-fg);
1505
+ font-size: 13px;
1506
+ text-align: left;
1507
+ cursor: pointer;
1508
+ transition: background 0.15s ease;
1509
+ }
1510
+
1511
+ .pactor-chat-popover__item:hover {
1512
+ background: var(--pactor-chat-muted);
1513
+ }
1514
+
1515
+ .pactor-chat-popover__item-label {
1516
+ flex: 1;
1517
+ min-width: 0;
1518
+ overflow: hidden;
1519
+ text-overflow: ellipsis;
1520
+ white-space: nowrap;
1521
+ }
1522
+
1523
+ /* 选中项勾选标记 */
1524
+ .pactor-chat-popover__item-check {
1525
+ flex-shrink: 0;
1526
+ color: var(--pactor-chat-primary);
1527
+ }
1528
+
1529
+ /* 上下文候选列表:分组头 / loading 与空态提示 / 内联错误 */
1530
+ .pactor-chat-source-list {
1531
+ display: flex;
1532
+ flex-direction: column;
1533
+ gap: 2px;
1534
+ min-width: 180px;
1535
+ }
1536
+
1537
+ .pactor-chat-source-list__group {
1538
+ display: flex;
1539
+ flex-direction: column;
1540
+ gap: 2px;
1541
+ }
1542
+
1543
+ .pactor-chat-source-list__group-label {
1544
+ padding: 6px 10px 2px;
1545
+ color: var(--pactor-chat-muted-fg);
1546
+ font-size: 12px;
1547
+ }
1548
+
1549
+ .pactor-chat-source-list__hint {
1550
+ padding: 6px 10px;
1551
+ color: var(--pactor-chat-muted-fg);
1552
+ font-size: 12.5px;
1553
+ }
1554
+
1555
+ .pactor-chat-source-list__error {
1556
+ padding: 6px 10px;
1557
+ color: var(--pactor-chat-danger);
1558
+ font-size: 12.5px;
1559
+ }
1560
+
1561
+ /* 内建模型 chip(Composer 工具栏右端,toolbarEnd 槽内容之前) */
1562
+ .pactor-chat-model-chip {
1563
+ display: inline-flex;
1564
+ align-items: center;
1565
+ gap: 4px;
1566
+ padding: 4px 10px;
1567
+ border: 1px solid var(--pactor-chat-border);
1568
+ border-radius: 999px;
1569
+ background: var(--pactor-chat-card);
1570
+ color: var(--pactor-chat-muted-fg);
1571
+ font-size: 12.5px;
1572
+ cursor: pointer;
1573
+ transition:
1574
+ border-color 0.15s ease,
1575
+ color 0.15s ease;
1576
+ }
1577
+
1578
+ .pactor-chat-model-chip:hover {
1579
+ border-color: var(--pactor-chat-primary);
1580
+ color: var(--pactor-chat-fg);
1581
+ }
1582
+
1583
+ .pactor-chat-model-chip__label {
1584
+ max-width: 160px;
1585
+ overflow: hidden;
1586
+ text-overflow: ellipsis;
1587
+ white-space: nowrap;
1588
+ }
1589
+
1590
+ /* 上下文 chips 区(输入区上方) */
1591
+ .pactor-chat-composer__contexts {
1592
+ display: flex;
1593
+ flex-wrap: wrap;
1594
+ gap: 6px;
1595
+ }
1596
+
1597
+ .pactor-chat-context-chip {
1598
+ display: inline-flex;
1599
+ align-items: center;
1600
+ gap: 2px;
1601
+ padding: 3px 4px 3px 10px;
1602
+ border: 1px solid var(--pactor-chat-border);
1603
+ border-radius: 999px;
1604
+ background: var(--pactor-chat-muted);
1605
+ color: var(--pactor-chat-fg);
1606
+ font-size: 12.5px;
1607
+ }
1608
+
1609
+ .pactor-chat-context-chip__label {
1610
+ max-width: 180px;
1611
+ overflow: hidden;
1612
+ text-overflow: ellipsis;
1613
+ white-space: nowrap;
1614
+ }
1615
+
1616
+ .pactor-chat-context-chip__remove {
1617
+ padding: 2px;
1618
+ }
1619
+
1620
+ .pactor-chat-context-chip__remove svg {
1621
+ width: 12px;
1622
+ height: 12px;
1623
+ }
1624
+
1625
+ /* 内建 header 操作组 + 可编辑标题(spec: chat-dsl-component / Header 配置) */
1626
+ /* header 位模型 chip(spec: chat-model-selector,决策 D2):chip + title
1627
+ * 组成左端组(chip 在 title 之前);未配置 headerStart 槽时不渲染本容器 */
1628
+ .pactor-chat-workspace__header-left {
1629
+ display: flex;
1630
+ align-items: center;
1631
+ gap: 10px;
1632
+ min-width: 0;
1633
+ }
1634
+
1635
+ .pactor-chat-workspace__header-right {
1636
+ display: flex;
1637
+ align-items: center;
1638
+ gap: 8px;
1639
+ }
1640
+
1641
+ .pactor-chat-workspace__header-actions {
1642
+ display: flex;
1643
+ align-items: center;
1644
+ gap: 4px;
1645
+ }
1646
+
1647
+ /* 可编辑标题:按钮形态继承标题排版,hover 提示可点击 */
1648
+ .pactor-chat-workspace__title--editable {
1649
+ border: none;
1650
+ border-radius: var(--pactor-chat-radius-sm);
1651
+ background: transparent;
1652
+ color: inherit;
1653
+ cursor: pointer;
1654
+ padding: 2px 6px;
1655
+ }
1656
+
1657
+ .pactor-chat-workspace__title--editable:hover {
1658
+ background: var(--pactor-chat-muted);
1659
+ }
1660
+
1661
+ .pactor-chat-workspace__title-input {
1662
+ border: 1px solid var(--pactor-chat-border);
1663
+ border-radius: var(--pactor-chat-radius-sm);
1664
+ background: var(--pactor-chat-card);
1665
+ color: var(--pactor-chat-fg);
1666
+ font: inherit;
1667
+ font-size: 14px;
1668
+ padding: 2px 8px;
1669
+ outline: none;
1670
+ }
1671
+
1672
+ .pactor-chat-workspace__title-input:focus {
1673
+ border-color: var(--pactor-chat-primary);
1674
+ }
1675
+
1676
+ /* ============================================================
1677
+ * 10. 动效降级(prefers-reduced-motion)
1678
+ * ============================================================ */
1679
+
1680
+ /* 遵循系统级减弱动效设置:过渡缩短到近乎即时;循环动画(呼吸文案、
1681
+ 停止光环、状态图标脉冲、spinner 旋转)整体移除,保留静态色态指示 */
1682
+ @media (prefers-reduced-motion: reduce) {
1683
+ .pactor-chat-view *,
1684
+ .pactor-chat-view *::before,
1685
+ .pactor-chat-view *::after,
1686
+ .pactor-chat-layout *,
1687
+ .pactor-chat-layout *::before,
1688
+ .pactor-chat-layout *::after,
1689
+ .pactor-chat-shell *,
1690
+ .pactor-chat-shell *::before,
1691
+ .pactor-chat-shell *::after {
1692
+ animation-duration: 0.001ms !important;
1693
+ animation-iteration-count: 1 !important;
1694
+ transition-duration: 0.001ms !important;
1695
+ }
1696
+
1697
+ .pactor-chat-trace__status-text--breathing,
1698
+ .pactor-chat-trace__status-icon:has(.pactor-chat-spin),
1699
+ .pactor-chat-thinking[data-streaming='true'] .pactor-chat-thinking__icon,
1700
+ .pactor-chat-spin,
1701
+ .pactor-chat-composer__button--stop::after {
1702
+ animation: none !important;
1703
+ }
1704
+ }