File size: 14,686 Bytes
f402bb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
/* 输入区(Composer)视觉层 —— 两层结构(design-system.md Warm Paper 铁律):
   上层 = textarea(呼吸空间足),下层 = 控件条:
     左组【对话|任务 分段 pill + 批准档 + 权限小字】,右组【思考滑轨 → 模型 → 发送】。
   组内聚拢(8px)、组间留白(16px)、控件统一 32px 高、圆角按令牌;
   模型选择是窄触发器 + 向上 popover(--shadow-float 描边浮层,不用毛玻璃)。
   窄窗时按「整组」换行,绝不把控件压扁——发送按钮永远待在右下角。
   本文件只服务 Composer.tsx;模式切换/批准档的原始规则在 task.css,
   这里用 .composer-bar 前缀做作用域内的密度统一(不改 task.css)。 */

/* ---------- 外层:贴底输入区 ---------- */
.composer-wrap {
  padding: 16px 48px 24px;
  border-top: 1px solid var(--border);
}

/* ---------- 输入盒:sunken 底,聚焦 accent 描边 + 极浅外晕 ---------- */
.composer {
  max-width: 760px;
  margin: 0 auto;
  padding: 12px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-float);
  background: var(--bg-sunken);
  transition: border-color var(--dur) var(--ease);
}

.composer:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent);
}

/* ---------- 上层:输入 textarea(不与控件抢空间) ---------- */
.composer-input {
  display: block;
  width: 100%;
  min-height: 44px;
  max-height: 200px;
  padding: 4px 2px 8px;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.65;
  resize: none;
  overflow-y: auto;
}

.composer-input:focus {
  outline: none;
}

.composer-input::placeholder {
  color: var(--text-tertiary);
}

/* ---------- 下层:控件条(左右两组) ---------- */
.composer-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px; /* 行间 8、组间 16:8px 网格 */
  margin-top: 8px;
}

.composer-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto; /* 不缩小:放不下就整组换行,永不挤压控件 */
}

.composer-group-end {
  margin-left: auto;
}

/* ---------- 模式切换(契约 6D):Codex 式无边框文字切换 ----------
   去掉容器边框与凹底(覆盖 task.css 基础款),激活档用暖陶土淡染,
   不再是实心 pill——与整条控制条的「文字优先」一致。 */
.composer-bar .mode-switch {
  gap: 2px;
  padding: 0;
  border: none;
  background: transparent;
}

.composer-bar .mode-pill {
  height: 28px;
  padding: 0 10px;
  border-radius: var(--radius-chip);
  font-size: 13px;
  color: var(--text-tertiary);
  background: transparent;
}

.composer-bar .mode-pill:hover {
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--accent-soft) 45%, transparent);
}

.composer-bar .mode-pill.is-active {
  background: color-mix(in srgb, var(--accent-soft) 85%, transparent);
  color: var(--accent);
}

.quick-tool-wrap{position:relative;z-index:20}
.composer-bar .quick-tool-trigger{display:inline-flex;align-items:center;gap:6px;height:27px;padding:0 8px;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--text-secondary);font:10px var(--font-sans);cursor:pointer}
.composer-bar .quick-tool-trigger:hover,.composer-bar .quick-tool-trigger[aria-expanded="true"]{color:var(--accent);background:var(--accent-soft)}
.quick-tool-menu{position:absolute;left:0;bottom:calc(100% + 9px);width:268px;padding:8px;border:1px solid var(--border);border-radius:8px;background:var(--bg-elevated);box-shadow:var(--shadow-float)}
.quick-tool-menu>strong{display:block;padding:5px 7px 8px;color:var(--text-tertiary);font-size:9px;font-weight:500}
.quick-tool-item{display:flex;align-items:center;gap:2px}
.quick-tool-item>button:first-child{display:flex;align-items:center;gap:9px;flex:1;min-width:0;height:34px;padding:0 8px;border:0;border-radius:5px;background:transparent;color:var(--text);font-size:10px;text-align:left;cursor:pointer}
.quick-tool-item>button:first-child:hover{background:var(--accent-soft)}
.quick-tool-item>button:first-child>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.quick-tool-pin{display:grid;place-items:center;width:27px;height:27px;border:0;border-radius:5px;background:transparent;color:var(--text-tertiary);cursor:pointer}
.quick-tool-pin:hover,.quick-tool-pin.is-pinned{color:var(--warning);background:var(--bg-sunken)}
.quick-tool-menu>small{display:block;padding:8px 7px 3px;border-top:1px solid var(--border);color:var(--text-tertiary);font-size:9px}
.research-consent{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:12px 14px;margin:0 8px 8px;border:1px solid color-mix(in srgb,var(--warning) 45%,var(--border));border-radius:7px;background:var(--bg-sunken)}
.research-consent>div{flex:1;min-width:220px}
.research-consent strong{font-size:11px;color:var(--text)}
.research-consent p{margin:4px 0 0;color:var(--text-secondary);font-size:10px;line-height:1.6}
.research-consent .ws-primary{padding:7px 10px}
.research-consent .ws-link{font-size:10px}

/* ---------- 批准档(仅任务模式):彩色文字 + 安全图标,去边框下拉 ----------
   Codex 的「⚠ 完全访问」范式:select 视觉隐藏为纯文字载体,图标与文字
   承担全部观感;全访问=陶土警示色,智能=暖中性偏正向,询问=中性。 */
.composer-bar .perm-picker {
  gap: 5px;
  height: 28px;
  padding: 0 6px;
  border-radius: var(--radius-chip);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}

.composer-bar .perm-picker:hover {
  background: color-mix(in srgb, var(--accent-soft) 45%, transparent);
}

.composer-bar .perm-picker select {
  appearance: none;
  -webkit-appearance: none;
  height: 28px;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.composer-bar .perm-picker select:focus {
  outline: none;
}

.composer-bar .perm-picker select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* 图标与文字同色:按档位着色(图标靠 color: inherit 跟随) */
.composer-bar .perm-picker.is-full-access {
  color: var(--danger);
}
.composer-bar .perm-picker.is-smart-approve {
  color: var(--accent);
}
.composer-bar .perm-picker.is-always-ask {
  color: var(--text-secondary);
}

/* ---------- 权限总闸状态小字(只读,契约 13A) ---------- */
.composer-bar .perm-gate-hint {
  align-self: center;
  font-size: 11.5px;
  line-height: 1.2;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* ---------- 模型选择:窄触发器 + 向上 popover ---------- */
.model-menu-wrap {
  position: relative;
  display: inline-flex;
}

.model-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  max-width: 176px;
  padding: 0 6px;
  border: none;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 12.5px;
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

.model-trigger:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--accent-soft) 45%, transparent);
}

.model-trigger[aria-expanded="true"] {
  color: var(--text);
  background: color-mix(in srgb, var(--accent-soft) 60%, transparent);
}

.model-trigger:focus-visible,
.model-option:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.model-trigger-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.model-trigger-caret {
  flex: 0 0 auto;
  color: var(--text-tertiary);
}

/* 「云」徽章:与全站徽章同尺寸同字重(同 bench 云徽章口径) */
.model-cloud {
  flex: 0 0 auto;
  font-size: 11px;
  line-height: 1;
  padding: 3px 6px;
  border-radius: var(--radius-chip);
  background: var(--accent-soft);
  color: var(--text);
}

/* popover:Warm Paper 浮层(elevated 底 + 1px 描边 + --shadow-float;
   毛玻璃禁用——透明窗口上 WebKit 的 backdrop-filter 有已知坑)。
   入场 = opacity + translateY 6px,180ms。 */
.model-menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  z-index: 30;
  min-width: 236px;
  max-width: 320px;
  max-height: 264px;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-float);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-float);
  animation: model-menu-in 180ms var(--ease);
}

@keyframes model-menu-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .model-menu {
    animation: none;
  }
}

.model-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: none;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 12.5px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}

.model-option:hover {
  background: color-mix(in srgb, var(--accent-soft) 40%, transparent);
}

.model-option.is-active {
  background: var(--accent-soft);
}

.model-option-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 空态(没模型):触发器只显示短句,完整人话在浮层里 */
.model-menu-empty {
  margin: 0;
  padding: 6px 8px;
  max-width: 264px;
  color: var(--text-tertiary);
  font-size: 12px;
  line-height: 1.6;
}

/* ---------- 右组动作:快捷键提示 + 发送/停止 ---------- */
.composer-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.composer-hint {
  font-size: 12px;
  line-height: 1;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* 发送:Codex 式圆形图标按钮(暖陶土实底 + ↑),去文字。 */
.btn-send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: var(--bg);
  cursor: pointer;
  transition:
    background-color var(--dur) var(--ease),
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.btn-send:hover:not(:disabled) {
  filter: brightness(0.94);
}

.btn-send:active:not(:disabled) {
  transform: scale(0.94);
}

.btn-send:disabled {
  opacity: 0.4;
  cursor: default;
}

.btn-send:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* 停止:圆形描边图标按钮(□),与发送同尺寸。 */
.btn-stop {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}

.btn-stop:hover {
  background: var(--accent-soft);
}

.btn-stop:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.composer-error {
  max-width: 760px;
  margin: 0 auto 8px;
  color: var(--danger);
  font-size: 12.5px;
}

/* ---------- 思考强度胶囊滑轨(契约 6F)----------
   Warm Paper 基调:sunken 细轨 + 五个刻度点 + 圆点手柄;
   手柄 150ms transform 过渡滑动;Ultra 档手柄与轨道末端用 accent
   渐变提示「最烧脑」。不引外部滑块库。
   收紧版:档名衬线小字(约 50px)+ 72px 轨道(五档间距 18px),
   整条约 128px;任务模式/狂暴锁 Ultra 的语义一字未改。 */
/* ── 思考强度滑块(契约 6F)—— 对齐参考设计 ──────────────────────
   顶行「思考强度」标题 + 右侧当前档值;下方暗色渐变轨道 + 白色圆旋钮。
   五档(关/低/中/高/炽焰)连续拖拽,松手吸附。 */
.think-slider {
  display: flex; flex-direction: column; gap: 5px;
  flex: 0 0 auto; width: 220px; min-width: 0;
}
.think-slider.is-disabled { opacity: 0.45; pointer-events: none; }
.think-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 6px;
}
.think-label {
  font-size: 11px; color: var(--ink-3); white-space: nowrap;
}
.think-value {
  font-size: 11px; color: var(--ink-1); font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: color var(--dur-2) var(--ease);
}
.think-slider[data-lv="4"] .think-value { color: var(--warning); }

/* 暗色圆角轨道 + 渐变填充 + 白色圆旋钮 */
.think-track {
  position: relative; height: 16px; border-radius: 999px;
  background: linear-gradient(180deg, rgba(0,0,0,0.35), rgba(0,0,0,0.15));
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.35);
  cursor: pointer; touch-action: none;
}
.think-fill {
  position: absolute; left: 2px; top: 2px; bottom: 2px;
  width: calc((var(--think-pos, 0) / 4) * (100% - 4px));
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(217,119,87,0.55), rgba(201,162,39,0.75));
  transition: width var(--dur-2) var(--ease);
  overflow: hidden;
}
.think-knob {
  position: absolute; top: 50%;
  left: calc(2px + (var(--think-pos, 0) / 4) * (100% - 4px));
  width: 16px; height: 16px; transform: translate(-50%, -50%);
  border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.45), 0 0 0 1px rgba(0,0,0,0.08);
  transition: left var(--dur-2) var(--ease);
  pointer-events: none;
}
.think-slider[data-lv="4"] .think-knob {
  box-shadow: 0 1px 4px rgba(0,0,0,0.45), 0 0 8px rgba(201,162,39,0.6);
}
.think-slider.is-dragging .think-knob,
.think-slider.is-dragging .think-fill { transition: none; }

/* 星点(飞驰小点,随档位加速) */
.think-spark {
  position: absolute; top: 50%; width: 3px; height: 3px;
  transform: translateY(-50%); border-radius: 50%;
  background: rgba(255,255,255,0.85); opacity: 0; pointer-events: none;
  animation: think-fly var(--d, 1400ms) var(--ease) infinite;
  animation-delay: var(--delay, 0ms);
}
@keyframes think-fly {
  0% { left: 0; opacity: 0; }
  15% { opacity: var(--o, 0.8); }
  85% { opacity: var(--o, 0.8); }
  100% { left: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .think-spark { animation: none; opacity: 0; }
}