codexmate 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.en.md +8 -4
  2. package/README.md +8 -4
  3. package/cli/config-health.js +338 -0
  4. package/cli.js +1136 -584
  5. package/lib/cli-models-utils.js +186 -27
  6. package/lib/cli-network-utils.js +117 -101
  7. package/package.json +8 -1
  8. package/web-ui/app.js +381 -5532
  9. package/web-ui/index.html +15 -2231
  10. package/web-ui/logic.agents-diff.mjs +386 -0
  11. package/web-ui/logic.claude.mjs +108 -0
  12. package/web-ui/logic.mjs +5 -793
  13. package/web-ui/logic.runtime.mjs +124 -0
  14. package/web-ui/logic.sessions.mjs +263 -0
  15. package/web-ui/modules/api.mjs +69 -0
  16. package/web-ui/modules/app.computed.dashboard.mjs +113 -0
  17. package/web-ui/modules/app.computed.index.mjs +13 -0
  18. package/web-ui/modules/app.computed.session.mjs +141 -0
  19. package/web-ui/modules/app.constants.mjs +15 -0
  20. package/web-ui/modules/app.methods.agents.mjs +493 -0
  21. package/web-ui/modules/app.methods.claude-config.mjs +174 -0
  22. package/web-ui/modules/app.methods.codex-config.mjs +640 -0
  23. package/web-ui/modules/app.methods.index.mjs +86 -0
  24. package/web-ui/modules/app.methods.install.mjs +157 -0
  25. package/web-ui/modules/app.methods.navigation.mjs +478 -0
  26. package/web-ui/modules/app.methods.openclaw-core.mjs +514 -0
  27. package/web-ui/modules/app.methods.openclaw-editing.mjs +337 -0
  28. package/web-ui/modules/app.methods.openclaw-persist.mjs +251 -0
  29. package/web-ui/modules/app.methods.providers.mjs +265 -0
  30. package/web-ui/modules/app.methods.runtime.mjs +323 -0
  31. package/web-ui/modules/app.methods.session-actions.mjs +457 -0
  32. package/web-ui/modules/app.methods.session-browser.mjs +435 -0
  33. package/web-ui/modules/app.methods.session-timeline.mjs +441 -0
  34. package/web-ui/modules/app.methods.session-trash.mjs +419 -0
  35. package/web-ui/modules/app.methods.startup-claude.mjs +406 -0
  36. package/web-ui/partials/index/layout-footer.html +69 -0
  37. package/web-ui/partials/index/layout-header.html +337 -0
  38. package/web-ui/partials/index/modal-config-template-agents.html +125 -0
  39. package/web-ui/partials/index/modal-confirm-toast.html +32 -0
  40. package/web-ui/partials/index/modal-health-check.html +72 -0
  41. package/web-ui/partials/index/modal-openclaw-config.html +275 -0
  42. package/web-ui/partials/index/modal-skills.html +184 -0
  43. package/web-ui/partials/index/modals-basic.html +196 -0
  44. package/web-ui/partials/index/panel-config-claude.html +100 -0
  45. package/web-ui/partials/index/panel-config-codex.html +237 -0
  46. package/web-ui/partials/index/panel-config-openclaw.html +84 -0
  47. package/web-ui/partials/index/panel-market.html +174 -0
  48. package/web-ui/partials/index/panel-sessions.html +387 -0
  49. package/web-ui/partials/index/panel-settings.html +166 -0
  50. package/web-ui/source-bundle.cjs +233 -0
  51. package/web-ui/styles/base-theme.css +373 -0
  52. package/web-ui/styles/controls-forms.css +354 -0
  53. package/web-ui/styles/feedback.css +108 -0
  54. package/web-ui/styles/health-check-dialog.css +144 -0
  55. package/web-ui/styles/layout-shell.css +330 -0
  56. package/web-ui/styles/modals-core.css +449 -0
  57. package/web-ui/styles/navigation-panels.css +381 -0
  58. package/web-ui/styles/openclaw-structured.css +266 -0
  59. package/web-ui/styles/responsive.css +416 -0
  60. package/web-ui/styles/sessions-list.css +414 -0
  61. package/web-ui/styles/sessions-preview.css +405 -0
  62. package/web-ui/styles/sessions-toolbar-trash.css +243 -0
  63. package/web-ui/styles/sessions-usage.css +276 -0
  64. package/web-ui/styles/skills-list.css +298 -0
  65. package/web-ui/styles/skills-market.css +335 -0
  66. package/web-ui/styles/titles-cards.css +407 -0
  67. package/web-ui/styles.css +16 -4668
@@ -0,0 +1,373 @@
1
+ /* Use local font stacks only; avoid third-party font fetches. */
2
+
3
+ /* ============================================
4
+ 设计系统 - Design Tokens
5
+ ============================================ */
6
+ :root {
7
+ /* 色彩系统:去除杂纹,强调干净留白与温柔橙红 */
8
+ --color-brand: #D0583A;
9
+ --color-brand-dark: #B8442B;
10
+ --color-brand-light: rgba(208, 88, 58, 0.14);
11
+ --color-brand-subtle: rgba(201, 94, 75, 0.2);
12
+
13
+ --color-bg: #F8F2EA;
14
+ --color-surface: #FFFDFC;
15
+ --color-surface-alt: #FFF8F2;
16
+ --color-surface-elevated: #FFFFFF;
17
+ --color-surface-tint: rgba(255, 255, 255, 0.84);
18
+ --color-text-primary: #1B1714;
19
+ --color-text-secondary: #473C34;
20
+ --color-text-tertiary: #6F6054;
21
+ --color-text-muted: #6C5B50;
22
+ --color-border: #D8C9B8;
23
+ --color-border-soft: rgba(216, 201, 184, 0.38);
24
+ --color-border-strong: rgba(216, 201, 184, 0.68);
25
+
26
+ --color-success: #4B8B6A;
27
+ --color-error: #C44536;
28
+
29
+ --bg-warm-gradient:
30
+ linear-gradient(180deg, #F8F2EA 0%, #F8F2EA 100%);
31
+
32
+ /* 字体系统 */
33
+ --font-family-body: 'JetBrainsMono Nerd Font Mono', 'OPPO Sans 4.0', 'Fira Mono', 'JetBrains Mono', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', monospace;
34
+ --font-family-display: 'JetBrainsMono Nerd Font Mono', 'OPPO Sans 4.0', 'Fira Mono', 'JetBrains Mono', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', monospace;
35
+ --font-family-mono: 'JetBrainsMono Nerd Font Mono', 'OPPO Sans 4.0', 'Fira Mono', 'JetBrains Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
36
+ --font-family: var(--font-family-body);
37
+
38
+ --font-size-display: 52px;
39
+ --font-size-title: 18px;
40
+ --font-size-large: 20px;
41
+ --font-size-body: 15px;
42
+ --font-size-secondary: 13px;
43
+ --font-size-caption: 11px;
44
+
45
+ --font-weight-display: 600;
46
+ --font-weight-primary: 600;
47
+ --font-weight-title: 600;
48
+ --font-weight-body: 400;
49
+ --font-weight-secondary: 500;
50
+ --font-weight-caption: 500;
51
+
52
+ --line-height-tight: 1.12;
53
+ --line-height-normal: 1.5;
54
+
55
+ /* 间距系统 */
56
+ --spacing-xs: 8px;
57
+ --spacing-sm: 16px;
58
+ --spacing-md: 24px;
59
+ --spacing-lg: 40px;
60
+ --spacing-xl: 64px;
61
+
62
+ /* 圆角系统 */
63
+ --radius-sm: 8px;
64
+ --radius-md: 10px;
65
+ --radius-lg: 12px;
66
+ --radius-xl: 18px;
67
+ --radius-full: 50px;
68
+
69
+ /* 阴影系统 - 多层叠加提升真实感 */
70
+ --shadow-subtle: 0 1px 2px rgba(31, 26, 23, 0.03);
71
+ --shadow-card: 0 6px 18px rgba(31, 26, 23, 0.06);
72
+ --shadow-card-hover: 0 10px 24px rgba(31, 26, 23, 0.08);
73
+ --shadow-float: 0 12px 26px rgba(31, 26, 23, 0.12);
74
+ --shadow-raised: 0 10px 20px rgba(31, 26, 23, 0.1);
75
+ --shadow-modal:
76
+ 0 8px 24px rgba(31, 26, 23, 0.08),
77
+ 0 24px 64px rgba(31, 26, 23, 0.06);
78
+ --shadow-input-focus:
79
+ 0 0 0 3px var(--color-brand-light),
80
+ 0 1px 3px rgba(31, 26, 23, 0.04);
81
+
82
+ /* 动画 - 更细腻的曲线 */
83
+ --transition-instant: 100ms;
84
+ --transition-fast: 120ms;
85
+ --transition-normal: 200ms;
86
+ --transition-slow: 300ms;
87
+ --ease-spring: cubic-bezier(0.16, 1, 0.3, 1);
88
+ --ease-spring-soft: cubic-bezier(0.25, 1, 0.5, 1);
89
+ --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
90
+ --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
91
+ }
92
+
93
+ /* ============================================
94
+ 手机桌面 UA 兜底:触控设备强制紧凑排版
95
+ ============================================ */
96
+ body.force-compact {
97
+ --font-size-title: 20px;
98
+ --font-size-body: 16px;
99
+ --font-size-secondary: 14px;
100
+ --font-size-caption: 12px;
101
+ }
102
+
103
+ body.force-compact .container {
104
+ max-width: 760px;
105
+ padding: 10px 10px 16px;
106
+ }
107
+
108
+ body.force-compact .provider-fast-switch {
109
+ position: sticky;
110
+ top: 8px;
111
+ z-index: 16;
112
+ }
113
+
114
+ body.force-compact .provider-fast-switch-select {
115
+ min-height: 44px;
116
+ font-size: 16px;
117
+ }
118
+
119
+ body.force-compact .app-shell {
120
+ grid-template-columns: 1fr;
121
+ gap: 12px;
122
+ }
123
+
124
+ body.force-compact .main-panel {
125
+ position: relative;
126
+ top: auto;
127
+ align-self: stretch;
128
+ width: 100%;
129
+ height: auto;
130
+ }
131
+
132
+ body.force-compact .side-rail,
133
+ body.force-compact .status-inspector {
134
+ display: none;
135
+ }
136
+
137
+ body.force-compact .top-tabs {
138
+ display: grid !important;
139
+ grid-template-columns: repeat(1, minmax(0, 1fr));
140
+ }
141
+
142
+ @media (min-width: 541px) {
143
+ body.force-compact .top-tabs {
144
+ grid-template-columns: repeat(2, minmax(0, 1fr));
145
+ }
146
+ }
147
+
148
+ body.force-compact .hero-logo {
149
+ display: block;
150
+ }
151
+
152
+ body.force-compact .hero-github {
153
+ display: flex;
154
+ }
155
+
156
+ body.force-compact .main-panel {
157
+ padding: 14px 12px;
158
+ }
159
+
160
+ body.force-compact .hero-title {
161
+ font-size: 34px;
162
+ }
163
+
164
+ body.force-compact .card {
165
+ display: flex;
166
+ flex-direction: column;
167
+ align-items: flex-start;
168
+ justify-content: flex-start;
169
+ padding: 12px;
170
+ gap: 8px;
171
+ }
172
+
173
+ body.force-compact .card-leading {
174
+ align-items: flex-start;
175
+ width: 100%;
176
+ }
177
+
178
+ body.force-compact .card-content {
179
+ width: 100%;
180
+ }
181
+
182
+ body.force-compact .card-title,
183
+ body.force-compact .card-title > span:first-child {
184
+ white-space: normal;
185
+ overflow: visible;
186
+ text-overflow: clip;
187
+ overflow-wrap: anywhere;
188
+ }
189
+
190
+ body.force-compact .card-subtitle {
191
+ white-space: normal;
192
+ overflow: hidden;
193
+ text-overflow: clip;
194
+ overflow-wrap: anywhere;
195
+ display: -webkit-box;
196
+ -webkit-line-clamp: 2;
197
+ -webkit-box-orient: vertical;
198
+ }
199
+
200
+ body.force-compact .card-trailing {
201
+ width: 100%;
202
+ margin-top: 0;
203
+ grid-auto-flow: row;
204
+ grid-auto-columns: 1fr;
205
+ justify-content: stretch;
206
+ justify-items: end;
207
+ }
208
+
209
+ body.force-compact .card-trailing .card-actions {
210
+ width: 100%;
211
+ justify-content: flex-end;
212
+ justify-self: stretch;
213
+ flex-wrap: wrap;
214
+ }
215
+
216
+ body.force-compact .card-actions {
217
+ opacity: 1;
218
+ transform: none;
219
+ }
220
+
221
+ body.force-compact .card-trailing .pill,
222
+ body.force-compact .card-trailing .latency {
223
+ justify-self: end;
224
+ }
225
+
226
+ body.force-compact .btn-add,
227
+ body.force-compact .btn-tool,
228
+ body.force-compact .card-action-btn {
229
+ min-height: 44px;
230
+ }
231
+
232
+ /* ============================================
233
+ 基础重置
234
+ ============================================ */
235
+ * {
236
+ margin: 0;
237
+ padding: 0;
238
+ box-sizing: border-box;
239
+ }
240
+
241
+ /* 仅屏幕阅读器可见 */
242
+ .sr-only {
243
+ position: absolute;
244
+ width: 1px;
245
+ height: 1px;
246
+ padding: 0;
247
+ margin: -1px;
248
+ overflow: hidden;
249
+ clip: rect(0, 0, 0, 0);
250
+ white-space: nowrap;
251
+ border: 0;
252
+ }
253
+
254
+ body {
255
+ font-family: var(--font-family-body);
256
+ background-color: var(--color-bg);
257
+ background: var(--bg-warm-gradient);
258
+ color: var(--color-text-primary);
259
+ display: flex;
260
+ justify-content: center;
261
+ align-items: center;
262
+ min-height: 100vh;
263
+ padding: var(--spacing-lg) var(--spacing-md);
264
+ -webkit-font-smoothing: antialiased;
265
+ -moz-osx-font-smoothing: grayscale;
266
+ position: relative;
267
+ overflow-x: hidden;
268
+ }
269
+
270
+ .fab-install {
271
+ position: fixed;
272
+ left: 16px;
273
+ bottom: calc(16px + env(safe-area-inset-bottom, 0px));
274
+ z-index: 90;
275
+ display: inline-grid;
276
+ place-items: center;
277
+ width: 50px;
278
+ height: 50px;
279
+ min-width: 44px;
280
+ min-height: 44px;
281
+ padding: 0;
282
+ border-radius: var(--radius-full);
283
+ border: 1px solid rgba(255, 255, 255, 0.28);
284
+ background:
285
+ linear-gradient(135deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.04) 100%),
286
+ linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-dark) 100%);
287
+ color: #fff;
288
+ font-size: var(--font-size-secondary);
289
+ font-weight: var(--font-weight-secondary);
290
+ letter-spacing: 0.015em;
291
+ box-shadow: var(--shadow-float);
292
+ cursor: pointer;
293
+ overflow: hidden;
294
+ transition:
295
+ transform var(--transition-fast) var(--ease-spring),
296
+ box-shadow var(--transition-fast) var(--ease-spring),
297
+ filter var(--transition-fast) var(--ease-smooth);
298
+ animation: fabPulse 3.2s ease-in-out infinite;
299
+ }
300
+
301
+ .fab-install::after {
302
+ content: "";
303
+ position: absolute;
304
+ inset: 1px;
305
+ border-radius: inherit;
306
+ border: 1px solid rgba(255, 255, 255, 0.12);
307
+ pointer-events: none;
308
+ }
309
+
310
+ .fab-install-icon {
311
+ width: 20px;
312
+ height: 20px;
313
+ display: inline-grid;
314
+ place-items: center;
315
+ color: #fff;
316
+ background: transparent;
317
+ box-shadow: none;
318
+ flex-shrink: 0;
319
+ }
320
+
321
+ .fab-install-icon svg {
322
+ width: 18px;
323
+ height: 18px;
324
+ }
325
+
326
+ .fab-install:hover {
327
+ transform: translateY(-1px);
328
+ box-shadow: var(--shadow-raised);
329
+ filter: saturate(1.04);
330
+ }
331
+
332
+ .fab-install:active {
333
+ transform: translateY(0);
334
+ filter: saturate(0.98);
335
+ }
336
+
337
+ @media (max-width: 640px) {
338
+ .fab-install {
339
+ left: 12px;
340
+ bottom: calc(12px + env(safe-area-inset-bottom, 0px));
341
+ width: 44px;
342
+ height: 44px;
343
+ padding: 0;
344
+ font-size: var(--font-size-secondary);
345
+ }
346
+
347
+ .fab-install-icon {
348
+ width: 18px;
349
+ height: 18px;
350
+ }
351
+
352
+ .fab-install-icon svg {
353
+ width: 16px;
354
+ height: 16px;
355
+ }
356
+ }
357
+
358
+ @keyframes fabPulse {
359
+ 0%,
360
+ 100% {
361
+ box-shadow: var(--shadow-float);
362
+ }
363
+ 50% {
364
+ box-shadow: 0 14px 30px rgba(31, 26, 23, 0.14);
365
+ }
366
+ }
367
+
368
+ @media (prefers-reduced-motion: reduce) {
369
+ .fab-install {
370
+ animation: none;
371
+ transition: none;
372
+ }
373
+ }
@@ -0,0 +1,354 @@
1
+ /* ============================================
2
+ 选择器 - 用于模型选择
3
+ ============================================ */
4
+ .selector-section {
5
+ background: linear-gradient(to bottom, var(--color-surface) 0%, rgba(255, 255, 255, 0.92) 100%);
6
+ border-radius: var(--radius-lg);
7
+ padding: calc(var(--spacing-sm) + 2px);
8
+ margin-bottom: 16px;
9
+ box-shadow: var(--shadow-card);
10
+ border: 1px solid var(--color-border-soft);
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--spacing-xs);
14
+ }
15
+
16
+ .selector-header {
17
+ display: flex;
18
+ justify-content: space-between;
19
+ align-items: center;
20
+ margin-bottom: var(--spacing-xs);
21
+ }
22
+
23
+ .settings-tab-header {
24
+ justify-content: flex-end;
25
+ align-items: center;
26
+ }
27
+
28
+ .settings-tab-actions {
29
+ display: flex;
30
+ flex-wrap: wrap;
31
+ gap: 8px;
32
+ justify-content: flex-end;
33
+ }
34
+
35
+ .settings-tab-actions .btn-tool,
36
+ .settings-tab-actions .btn-tool-compact {
37
+ width: auto;
38
+ }
39
+
40
+ .trash-header-actions {
41
+ display: flex;
42
+ flex-direction: row;
43
+ flex-wrap: nowrap;
44
+ align-items: stretch;
45
+ justify-content: flex-end;
46
+ width: auto;
47
+ max-width: 100%;
48
+ margin-left: auto;
49
+ }
50
+
51
+ .selector-header .trash-header-actions > .btn-tool,
52
+ .selector-header .trash-header-actions > .btn-tool-compact {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ align-self: stretch;
57
+ margin: 0;
58
+ width: auto;
59
+ min-width: 0;
60
+ max-width: 100%;
61
+ height: 32px;
62
+ min-height: 32px;
63
+ padding: 0 10px;
64
+ line-height: 1;
65
+ vertical-align: top;
66
+ position: relative;
67
+ top: 0;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ .selector-header .trash-header-actions > .btn-tool:not(:disabled):hover,
72
+ .selector-header .trash-header-actions > .btn-tool-compact:not(:disabled):hover {
73
+ transform: none;
74
+ }
75
+
76
+ .selector-title {
77
+ font-size: var(--font-size-caption);
78
+ font-weight: var(--font-weight-secondary);
79
+ color: var(--color-text-muted);
80
+ text-transform: none;
81
+ letter-spacing: 0.04em;
82
+ opacity: 0.85;
83
+ }
84
+
85
+ .selector-actions {
86
+ display: flex;
87
+ gap: var(--spacing-xs);
88
+ }
89
+
90
+ .health-report {
91
+ margin-top: 10px;
92
+ padding: 10px 12px;
93
+ border-radius: var(--radius-md);
94
+ border: 1px solid var(--color-border-soft);
95
+ background: var(--color-surface-alt);
96
+ display: grid;
97
+ gap: 8px;
98
+ }
99
+
100
+ .health-remote-toggle {
101
+ display: inline-flex;
102
+ align-items: center;
103
+ gap: 8px;
104
+ font-size: var(--font-size-caption);
105
+ color: var(--color-text-secondary);
106
+ }
107
+
108
+ .health-remote-toggle input {
109
+ accent-color: var(--color-brand);
110
+ }
111
+
112
+ .health-ok {
113
+ color: var(--color-success);
114
+ font-weight: var(--font-weight-secondary);
115
+ }
116
+
117
+ .health-issue {
118
+ background: #fff6f5;
119
+ border-left: 3px solid var(--color-error);
120
+ padding: 8px 10px;
121
+ border-radius: 10px;
122
+ }
123
+
124
+ .health-issue-title {
125
+ font-size: var(--font-size-caption);
126
+ font-weight: var(--font-weight-secondary);
127
+ color: var(--color-text-primary);
128
+ margin-bottom: 4px;
129
+ }
130
+
131
+ .health-issue-suggestion {
132
+ font-size: var(--font-size-caption);
133
+ color: var(--color-text-secondary);
134
+ line-height: 1.4;
135
+ }
136
+
137
+ .btn-icon {
138
+ width: 28px;
139
+ height: 28px;
140
+ border-radius: var(--radius-sm);
141
+ border: none;
142
+ background: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-dark) 100%);
143
+ color: white;
144
+ cursor: pointer;
145
+ font-size: 16px;
146
+ display: flex;
147
+ align-items: center;
148
+ justify-content: center;
149
+ transition: all var(--transition-fast) var(--ease-spring);
150
+ box-shadow: 0 2px 4px rgba(210, 107, 90, 0.2);
151
+ }
152
+
153
+ .btn-icon:hover {
154
+ transform: translateY(-1px) scale(1.05);
155
+ box-shadow: 0 4px 8px rgba(210, 107, 90, 0.25);
156
+ }
157
+
158
+ .btn-icon:active {
159
+ transform: translateY(0) scale(0.98);
160
+ }
161
+
162
+ .model-select {
163
+ width: 100%;
164
+ padding: 12px var(--spacing-sm);
165
+ padding-right: 40px;
166
+ border: 1px solid var(--color-border-soft);
167
+ border-radius: var(--radius-sm);
168
+ font-size: var(--font-size-body);
169
+ font-weight: var(--font-weight-body);
170
+ background-color: var(--color-surface-alt);
171
+ color: var(--color-text-primary);
172
+ outline: none;
173
+ cursor: pointer;
174
+ appearance: none;
175
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23505A66' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
176
+ background-repeat: no-repeat;
177
+ background-position: right 14px center;
178
+ background-size: 12px;
179
+ transition: all var(--transition-fast) var(--ease-smooth);
180
+ box-shadow: inset 0 1px 2px rgba(31, 26, 23, 0.04);
181
+ }
182
+
183
+ .model-select:hover {
184
+ border-color: var(--color-border-strong);
185
+ background-color: var(--color-surface);
186
+ }
187
+
188
+ .model-select:focus {
189
+ background-color: var(--color-surface);
190
+ border-color: var(--color-brand);
191
+ box-shadow: var(--shadow-input-focus);
192
+ }
193
+
194
+ .model-input {
195
+ width: 100%;
196
+ padding: 12px var(--spacing-sm);
197
+ border: 1px solid var(--color-border-soft);
198
+ border-radius: var(--radius-sm);
199
+ font-size: var(--font-size-body);
200
+ font-weight: var(--font-weight-body);
201
+ background-color: var(--color-surface-alt);
202
+ color: var(--color-text-primary);
203
+ outline: none;
204
+ transition: all var(--transition-fast) var(--ease-smooth);
205
+ box-shadow: inset 0 1px 2px rgba(31, 26, 23, 0.04);
206
+ }
207
+
208
+ .model-input:hover {
209
+ border-color: var(--color-border-strong);
210
+ background-color: var(--color-surface);
211
+ }
212
+
213
+ .model-input:focus {
214
+ background-color: var(--color-surface);
215
+ border-color: var(--color-brand);
216
+ box-shadow: var(--shadow-input-focus);
217
+ }
218
+
219
+ .config-template-hint {
220
+ margin-top: 8px;
221
+ margin-bottom: 10px;
222
+ font-size: var(--font-size-caption);
223
+ color: var(--color-text-tertiary);
224
+ line-height: 1.4;
225
+ }
226
+
227
+ .codex-config-grid {
228
+ display: grid;
229
+ gap: var(--spacing-sm);
230
+ grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
231
+ align-items: start;
232
+ }
233
+
234
+ .codex-config-field {
235
+ min-width: 0;
236
+ margin-bottom: 0;
237
+ }
238
+
239
+ .btn-template-editor {
240
+ width: 100%;
241
+ margin-top: 2px;
242
+ }
243
+
244
+ /* ============================================
245
+ 按钮
246
+ ============================================ */
247
+ .btn-add {
248
+ width: 100%;
249
+ padding: 14px var(--spacing-sm);
250
+ border: 1.5px dashed rgba(208, 196, 182, 0.6);
251
+ border-radius: var(--radius-lg);
252
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0.15) 100%);
253
+ font-size: var(--font-size-body);
254
+ font-weight: var(--font-weight-secondary);
255
+ color: var(--color-text-tertiary);
256
+ cursor: pointer;
257
+ transition: all var(--transition-normal) var(--ease-spring);
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ gap: var(--spacing-xs);
262
+ }
263
+
264
+ .btn-add + .selector-section,
265
+ .selector-section + .btn-add,
266
+ .btn-add + .card-list,
267
+ .card-list + .btn-add {
268
+ margin-top: 12px;
269
+ }
270
+
271
+ .btn-add:hover {
272
+ border-color: var(--color-brand);
273
+ color: var(--color-brand);
274
+ background: linear-gradient(to bottom, rgba(210, 107, 90, 0.05) 0%, rgba(210, 107, 90, 0.02) 100%);
275
+ transform: translateY(-1px);
276
+ }
277
+
278
+ .btn-add:active {
279
+ transform: translateY(0) scale(0.99);
280
+ }
281
+
282
+ .btn-add .icon {
283
+ width: 18px;
284
+ height: 18px;
285
+ transition: transform var(--transition-normal) var(--ease-spring);
286
+ }
287
+
288
+ .btn-add:hover .icon {
289
+ transform: rotate(90deg);
290
+ }
291
+
292
+ .btn-tool {
293
+ padding: 12px var(--spacing-sm);
294
+ border-radius: var(--radius-sm);
295
+ border: 1px solid var(--color-border-soft);
296
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.85) 100%);
297
+ font-size: var(--font-size-body);
298
+ font-weight: var(--font-weight-secondary);
299
+ color: var(--color-text-secondary);
300
+ cursor: pointer;
301
+ transition: all var(--transition-fast) var(--ease-spring);
302
+ box-shadow: var(--shadow-subtle);
303
+ letter-spacing: -0.01em;
304
+ width: 100%;
305
+ text-align: center;
306
+ }
307
+
308
+ .selector-section .btn-tool + .btn-tool {
309
+ margin-left: 0;
310
+ margin-top: var(--spacing-xs);
311
+ }
312
+
313
+ .selector-header .trash-header-actions > .btn-tool + .btn-tool {
314
+ margin-top: 0;
315
+ }
316
+
317
+ .btn-tool:not(:disabled):hover {
318
+ border-color: var(--color-brand);
319
+ color: var(--color-brand);
320
+ transform: translateY(-1px);
321
+ box-shadow: 0 4px 8px rgba(210, 107, 90, 0.12);
322
+ }
323
+
324
+ .btn-tool:disabled,
325
+ .btn-tool[disabled] {
326
+ opacity: 0.6;
327
+ cursor: not-allowed;
328
+ }
329
+
330
+ .btn-tool:disabled:hover,
331
+ .btn-tool[disabled]:hover,
332
+ .btn-tool:disabled:active,
333
+ .btn-tool[disabled]:active,
334
+ .btn-tool-compact:disabled:hover,
335
+ .btn-tool-compact[disabled]:hover,
336
+ .btn-tool-compact:disabled:active,
337
+ .btn-tool-compact[disabled]:active {
338
+ border-color: var(--color-border-soft);
339
+ color: var(--color-text-secondary);
340
+ transform: none;
341
+ box-shadow: var(--shadow-subtle);
342
+ }
343
+
344
+ .btn-tool-compact {
345
+ padding: 9px 12px;
346
+ font-size: var(--font-size-secondary);
347
+ }
348
+
349
+ .selector-header .btn-tool-compact {
350
+ padding: 6px 10px;
351
+ font-size: var(--font-size-caption);
352
+ line-height: 1.1;
353
+ box-shadow: var(--shadow-subtle);
354
+ }