@jesonliu/lark-claudecode-bridge 1.4.2 → 2.0.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.
Files changed (45) hide show
  1. package/assets/web/css/main.css +766 -574
  2. package/assets/web/index.html +37 -17
  3. package/assets/web/js/auth.js +217 -0
  4. package/assets/web/js/bootstrap.js +36 -34
  5. package/assets/web/js/core.js +4 -3
  6. package/assets/web/js/main.js +79 -20
  7. package/assets/web/js/markdown.js +64 -0
  8. package/assets/web/js/pages/apps.js +338 -251
  9. package/assets/web/js/pages/chats.js +446 -0
  10. package/assets/web/js/pages/claude.js +243 -180
  11. package/assets/web/js/pages/mcp.js +59 -43
  12. package/assets/web/js/pages/memory.js +39 -43
  13. package/assets/web/js/pages/overview.js +430 -101
  14. package/assets/web/js/pages/permissions.js +40 -32
  15. package/assets/web/js/pages/plugins.js +51 -37
  16. package/assets/web/js/pages/skills.js +68 -92
  17. package/assets/web/js/pages/slash.js +31 -23
  18. package/assets/web/js/pages/workspaces.js +114 -73
  19. package/assets/web/js/theme.js +21 -18
  20. package/assets/web/js/ui.js +135 -32
  21. package/dist/bin/lcb.js +15 -0
  22. package/dist/bin/lcb.js.map +1 -1
  23. package/dist/gateway/feishu-gateway.d.ts +11 -0
  24. package/dist/gateway/feishu-gateway.js +5 -0
  25. package/dist/gateway/feishu-gateway.js.map +1 -1
  26. package/dist/gateway/gateway-registry.d.ts +16 -0
  27. package/dist/gateway/gateway-registry.js +10 -0
  28. package/dist/gateway/gateway-registry.js.map +1 -0
  29. package/dist/index.js +54 -41
  30. package/dist/index.js.map +1 -1
  31. package/dist/memory-installer.d.ts +7 -0
  32. package/dist/memory-installer.js +22 -5
  33. package/dist/memory-installer.js.map +1 -1
  34. package/dist/web/chats-api.d.ts +77 -0
  35. package/dist/web/chats-api.js +475 -0
  36. package/dist/web/chats-api.js.map +1 -0
  37. package/dist/web/logs-api.d.ts +37 -0
  38. package/dist/web/logs-api.js +141 -0
  39. package/dist/web/logs-api.js.map +1 -0
  40. package/dist/web/server.js +125 -6
  41. package/dist/web/server.js.map +1 -1
  42. package/dist/web/webauth.d.ts +44 -0
  43. package/dist/web/webauth.js +177 -0
  44. package/dist/web/webauth.js.map +1 -0
  45. package/package.json +1 -1
@@ -1,574 +1,766 @@
1
- /* ============================================================
2
- Web 配置页样式 · v2 视觉升级
3
- 约定:所有选择器与旧版保持兼容(JS 大量依赖 class/ID 钩子,勿改名)
4
- —— 卡片 / 按钮 / 输入 / 表格 / 标签 / 抽屉 / 弹层 / Toast
5
- —— 自动暗色模式(prefers-color-scheme)+ 减弱动效偏好
6
- ============================================================ */
7
- :root {
8
- color-scheme: light;
9
- /* 色板(飞书系) */
10
- --bg: #eef1f6;
11
- --card: #ffffff;
12
- --field: #ffffff;
13
- --border: #e4e7ee;
14
- --border-strong: #d3d9e4;
15
- --text: #1f2329;
16
- --muted: #646a73;
17
- --primary: #3370ff;
18
- --primary-strong: #2b5fe3;
19
- --primary-weak: #eef3ff;
20
- --primary-ring: rgba(51, 112, 255, .16);
21
- --danger: #f54f4f;
22
- --ok: #2ea121;
23
- --warn: #d97a00;
24
- /* 状态标签底/字色 */
25
- --ok-bg: #e9f7e5;
26
- --warn-bg: #fff3e0;
27
- --err-bg: #feecec;
28
- --off-bg: #f0f1f5;
29
- --ok-tx: #2ea121;
30
- --warn-tx: #d97a00;
31
- --err-tx: #f54f4f;
32
- --off-tx: #8a9099;
33
- /* 未保存条(warn 弱化底) */
34
- --warn-weak: #fff8ef;
35
- --warn-weak-border: #ffe1bb;
36
- /* 代码 / 等宽 */
37
- --code-bg: rgba(31, 35, 41, .06);
38
- --mono: Consolas, "SF Mono", "Cascadia Mono", Menlo, monospace;
39
- /* 圆角与阴影 */
40
- --radius: 14px;
41
- --radius-sm: 9px;
42
- --shadow-1: 0 1px 2px rgba(31, 35, 41, .04), 0 1px 6px rgba(31, 35, 41, .03);
43
- --shadow-2: 0 8px 28px rgba(31, 35, 41, .12);
44
- --shadow-pop: 0 12px 40px rgba(31, 35, 41, .16);
45
- /* 头部 */
46
- --header-bg: rgba(255, 255, 255, .82);
47
- --spin-track: #d9e2f5;
48
- --toast-bg: rgba(31, 35, 41, .93);
49
- }
50
-
51
- @media (prefers-color-scheme: dark) {
52
- :root:not([data-theme="light"]) {
53
- color-scheme: dark;
54
- --bg: #0e1117;
55
- --card: #161a23;
56
- --field: #10141d;
57
- --border: #262c3a;
58
- --border-strong: #363e50;
59
- --text: #e7eaf1;
60
- --muted: #97a0b2;
61
- --primary: #4d80ff;
62
- --primary-strong: #6996ff;
63
- --primary-weak: rgba(77, 128, 255, .14);
64
- --primary-ring: rgba(77, 128, 255, .28);
65
- --danger: #ff7373;
66
- --ok: #5ad24a;
67
- --warn: #ffa23e;
68
- --ok-bg: rgba(52, 199, 36, .13);
69
- --warn-bg: rgba(255, 136, 0, .13);
70
- --err-bg: rgba(245, 79, 79, .13);
71
- --off-bg: rgba(255, 255, 255, .06);
72
- --ok-tx: #5ad24a;
73
- --warn-tx: #ffa23e;
74
- --err-tx: #ff7373;
75
- --off-tx: #97a0b2;
76
- --warn-weak: rgba(255, 136, 0, .09);
77
- --warn-weak-border: rgba(255, 136, 0, .32);
78
- --code-bg: rgba(255, 255, 255, .09);
79
- --shadow-1: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 8px rgba(0, 0, 0, .18);
80
- --shadow-2: 0 8px 28px rgba(0, 0, 0, .45);
81
- --shadow-pop: 0 12px 40px rgba(0, 0, 0, .55);
82
- --header-bg: rgba(19, 23, 31, .82);
83
- --spin-track: rgba(255, 255, 255, .16);
84
- --toast-bg: rgba(58, 64, 78, .95);
85
- }
86
- }
87
-
88
- /* ---------- 基础 ---------- */
89
- * { box-sizing: border-box; }
90
- body {
91
- margin: 0;
92
- font: 14px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
93
- background:
94
- radial-gradient(1000px 480px at 6% -120px, rgba(51, 112, 255, .09), transparent 62%),
95
- radial-gradient(820px 420px at 100% -160px, rgba(150, 110, 255, .06), transparent 58%),
96
- var(--bg);
97
- color: var(--text);
98
- }
99
- ::selection { background: var(--primary-weak); }
100
-
101
- /* 滚动条(Chromium/Safari + Firefox) */
102
- ::-webkit-scrollbar { width: 10px; height: 10px; }
103
- ::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; border: 2px solid transparent; background-clip: padding-box; }
104
- ::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }
105
- ::-webkit-scrollbar-track { background: transparent; }
106
- * { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
107
-
108
- /* ---------- 顶栏 ---------- */
109
- header {
110
- background: var(--header-bg);
111
- -webkit-backdrop-filter: blur(14px) saturate(1.5);
112
- backdrop-filter: blur(14px) saturate(1.5);
113
- border-bottom: 1px solid var(--border);
114
- padding: 0 24px;
115
- height: 56px;
116
- display: flex;
117
- align-items: center;
118
- gap: 14px;
119
- position: sticky;
120
- top: 0;
121
- z-index: 10;
122
- }
123
- .brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
124
- .logo {
125
- width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
126
- display: inline-flex; align-items: center; justify-content: center;
127
- background: linear-gradient(135deg, #3370ff 0%, #5b8cff 60%, #7c5bff 130%);
128
- box-shadow: 0 2px 8px rgba(51, 112, 255, .35);
129
- }
130
- header h1 { font-size: 15.5px; font-weight: 650; margin: 0; letter-spacing: .01em; white-space: nowrap; }
131
- header .meta {
132
- color: var(--muted); font-size: 12px;
133
- background: var(--card); border: 1px solid var(--border);
134
- border-radius: 999px; padding: 2px 11px;
135
- font-variant-numeric: tabular-nums; white-space: nowrap;
136
- }
137
- header .meta:empty { display: none; }
138
- header .spacer { flex: 1; }
139
-
140
- .stale-bar {
141
- background: var(--warn-bg); color: var(--warn-tx);
142
- padding: 9px 24px; font-size: 13px; border-bottom: 1px solid var(--border);
143
- }
144
- .stale-bar[hidden] { display: none; }
145
-
146
- /* ---------- 布局 / 侧栏 ---------- */
147
- .layout { display: flex; min-height: calc(100vh - 56px); }
148
- nav {
149
- width: 196px; flex: 0 0 auto;
150
- padding: 16px 10px 24px;
151
- position: sticky; top: 56px; align-self: flex-start;
152
- max-height: calc(100vh - 56px); overflow-y: auto;
153
- }
154
- nav button {
155
- display: flex; align-items: center; gap: 10px;
156
- width: 100%; padding: 8px 12px; margin: 2px 0;
157
- border: 0; background: none; border-radius: var(--radius-sm);
158
- cursor: pointer; font-size: 13.5px; color: var(--text);
159
- transition: background .15s, color .15s;
160
- position: relative;
161
- }
162
- nav button .ico { display: flex; align-items: center; color: var(--muted); transition: color .15s; }
163
- nav button:hover { background: rgba(127, 140, 170, .10); }
164
- nav button:hover .ico { color: var(--text); }
165
- nav button.active { background: var(--primary-weak); color: var(--primary); font-weight: 600; }
166
- nav button.active .ico { color: var(--primary); }
167
- nav button.active::before {
168
- content: ''; position: absolute; left: -10px; top: 50%; transform: translateY(-50%);
169
- width: 3px; height: 18px; border-radius: 0 3px 3px 0; background: var(--primary);
170
- }
171
- nav button:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
172
-
173
- main { flex: 1; min-width: 0; padding: 24px 36px 56px; }
174
- @media (min-width: 1800px) { main { max-width: 1560px; } }
175
- @media (max-width: 860px) {
176
- header { padding: 0 16px; }
177
- header h1 { font-size: 14px; }
178
- .layout { flex-direction: column; }
179
- nav {
180
- width: auto; max-height: none; position: sticky; top: 56px; z-index: 9;
181
- display: flex; flex-wrap: nowrap; overflow-x: auto; gap: 4px;
182
- padding: 8px 12px; background: var(--header-bg);
183
- -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
184
- border-right: 0; border-bottom: 1px solid var(--border);
185
- }
186
- nav button { width: auto; flex: 0 0 auto; padding: 6px 12px; }
187
- nav button.active::before { display: none; }
188
- main { padding: 16px 16px 40px; }
189
- }
190
-
191
- /* ---------- 页头(main.js 注入:图标 + 标题) ---------- */
192
- .page-head { display: flex; align-items: center; gap: 12px; margin: 2px 0 20px; }
193
- .page-head .ico {
194
- width: 36px; height: 36px; border-radius: 11px; flex: 0 0 auto;
195
- display: inline-flex; align-items: center; justify-content: center;
196
- background: var(--primary-weak); color: var(--primary);
197
- }
198
- .page-head h2 { margin: 0; font-size: 18px; font-weight: 650; letter-spacing: .01em; }
199
- #pageBody { animation: lcb-fade .18s ease; }
200
- @keyframes lcb-fade { from { opacity: 0; transform: translateY(4px); } }
201
-
202
- /* ---------- 卡片 ---------- */
203
- .card {
204
- background: var(--card); border: 1px solid var(--border);
205
- border-radius: var(--radius); padding: 20px 22px; margin-bottom: 18px;
206
- box-shadow: var(--shadow-1);
207
- transition: box-shadow .2s;
208
- }
209
- .card:hover { box-shadow: var(--shadow-2); }
210
- .card h3 { margin: 0 0 4px; font-size: 15px; font-weight: 650; }
211
- .card h3 .dirty-dot { display: none; margin-left: 6px; font-size: 11.5px; color: var(--warn); font-weight: 500; }
212
- .card .desc { color: var(--muted); font-size: 12.5px; margin-bottom: 12px; line-height: 1.7; }
213
- /* 卡内小节(概览「版本与更新」双区块):相邻小节间分隔线,首节不加(免疫未来插入其它 div) */
214
- .card-sub + .card-sub { border-top: 1px solid var(--border); margin-top: 14px; padding-top: 14px; }
215
- .card-sub-title { margin: 0 0 8px; font-size: 13.5px; font-weight: 650; }
216
- main h4 { font-size: 13.5px; font-weight: 600; }
217
-
218
- /* ---------- 表单 ---------- */
219
- label { display: block; font-size: 12px; color: var(--muted); margin: 10px 0 5px; }
220
- input[type=text], input[type=password], input[type=number], input[type=search], select, textarea {
221
- width: 100%; padding: 8px 12px;
222
- border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
223
- font: inherit; background: var(--field); color: var(--text);
224
- transition: border-color .15s, box-shadow .15s;
225
- }
226
- input:hover, select:hover, textarea:hover { border-color: var(--muted); }
227
- input:focus, select:focus, textarea:focus {
228
- outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-ring);
229
- }
230
- input, select, textarea { accent-color: var(--primary); }
231
- textarea { font-family: var(--mono); font-size: 12.5px; min-height: 96px; line-height: 1.6; resize: vertical; }
232
- select { cursor: pointer; }
233
-
234
- .row { display: flex; gap: 12px; }
235
- .row > * { flex: 1; min-width: 0; }
236
- /* 两列布局:配置项多的区块(如全局默认配置)一行 2 个,避免 4 列挤压 */
237
- .row-2col { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 16px; }
238
- /* .row 内按钮按内容宽:内联 flex:0 展开会把按钮压到单字宽,一律走类规则 */
239
- .row > .btn, .row > .btn-wrap { flex: 0 0 auto; align-self: end; }
240
- .btn-wrap { display: flex; }
241
- @media (max-width: 860px) { .row { flex-direction: column; } .row-2col { grid-template-columns: 1fr; } }
242
-
243
- /* 输入框 + 行内按钮组合(路径框带「浏览」) */
244
- .input-btn { display: flex; gap: 8px; }
245
- .input-btn > input { flex: 1; min-width: 0; }
246
- .input-btn > .btn { flex: 0 0 auto; align-self: center; }
247
-
248
- /* ---------- 按钮 ---------- */
249
- .btn, nav button, .savebar .btn, .subtabs button, .chip { white-space: nowrap; }
250
- .btn {
251
- padding: 7px 16px; border-radius: var(--radius-sm);
252
- border: 1px solid var(--border-strong); background: var(--card); color: var(--text);
253
- cursor: pointer; font: inherit; font-size: 13.5px;
254
- transition: background .15s, border-color .15s, color .15s, box-shadow .15s, transform .06s;
255
- }
256
- .btn:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-weak); }
257
- .btn:active { transform: translateY(1px); }
258
- .btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-ring); }
259
- .btn:disabled { opacity: .55; cursor: not-allowed; transform: none; }
260
- .btn.primary {
261
- background: var(--primary); border-color: var(--primary); color: #fff;
262
- box-shadow: 0 2px 8px rgba(51, 112, 255, .32);
263
- }
264
- .btn.primary:hover { background: var(--primary-strong); border-color: var(--primary-strong); color: #fff; }
265
- .btn.danger { color: var(--danger); }
266
- .btn.danger:hover { border-color: var(--danger); background: var(--err-bg); color: var(--danger); }
267
- .btn.sm { padding: 4px 11px; font-size: 12.5px; border-radius: 8px; }
268
-
269
- /* ---------- Chips / 代码 ---------- */
270
- .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
271
- .chip {
272
- display: inline-flex; align-items: center; gap: 6px;
273
- background: var(--card); border: 1px solid var(--border);
274
- padding: 3px 11px; border-radius: 999px;
275
- font-size: 12.5px; font-family: var(--mono); color: var(--text);
276
- }
277
- .chip button { border: 0; background: none; color: var(--muted); cursor: pointer; padding: 0; font-size: 13px; line-height: 1; }
278
- .chip button:hover { color: var(--danger); }
279
- code {
280
- font-family: var(--mono); font-size: .92em;
281
- background: var(--code-bg); border-radius: 5px; padding: 1px 5px;
282
- word-break: break-all;
283
- }
284
- pre.report {
285
- background: var(--field); border: 1px solid var(--border); border-radius: var(--radius-sm);
286
- padding: 12px 14px; font-size: 12px; overflow: auto; white-space: pre-wrap;
287
- }
288
-
289
- /* ---------- 表格 ---------- */
290
- table { width: 100%; border-collapse: collapse; font-size: 13px; }
291
- /* 列表操作列:按钮一律横排(.btn 自身 nowrap,但 td 内模板换行空白给了折行点 → 竖排) */
292
- td.ops { white-space: nowrap; }
293
- th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
294
- thead th {
295
- color: var(--muted); font-weight: 500; font-size: 12px; letter-spacing: .03em;
296
- border-bottom: 1px solid var(--border-strong);
297
- }
298
- tbody tr { transition: background .12s; }
299
- tbody tr:hover { background: rgba(127, 140, 170, .05); }
300
- tbody tr:last-child td { border-bottom: 0; }
301
- tr.empty-row td { text-align: center; padding: 22px 10px; color: var(--muted); }
302
-
303
- /* ---------- 状态标签 ---------- */
304
- .tag {
305
- display: inline-flex; align-items: center; gap: 5px;
306
- padding: 2px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 500;
307
- white-space: nowrap; /* 状态标签(如「未随本页启动」)不折行 */
308
- }
309
- .tag::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
310
- .tag.ok { background: var(--ok-bg); color: var(--ok-tx); }
311
- .tag.off { background: var(--off-bg); color: var(--off-tx); }
312
- .tag.off::before { opacity: .5; }
313
- .tag.warn { background: var(--warn-bg); color: var(--warn-tx); }
314
- .tag.err { background: var(--err-bg); color: var(--err-tx); }
315
- /* chip / 按钮内嵌徽标(模型 1M 标记等):紧凑变体,去状态圆点 */
316
- .chip .tag, .btn .tag { font-size: 10px; padding: 1px 6px; gap: 0; }
317
- .chip .tag::before, .btn .tag::before { display: none; }
318
-
319
- /* ---------- 单选行 ---------- */
320
- .radio-row { display: flex; gap: 22px; margin: 8px 0; }
321
- .radio-row label { display: flex; align-items: center; gap: 6px; margin: 0; color: var(--text); font-size: 13.5px; cursor: pointer; }
322
- .radio-row input { accent-color: var(--primary); }
323
-
324
- /* ---------- 开关(原生 checkbox + 伪元素轨道;覆盖全局 label 的 block/margin) ---------- */
325
- .switch-row { display: flex; align-items: center; gap: 10px; margin: 10px 0 8px; }
326
- /* 表格单元格等紧凑容器用:去掉表单区默认的上下边距,避免与同行左侧文字错位 */
327
- .switch-row.tight { margin: 0; }
328
- .switch {
329
- position: relative; display: inline-flex; flex: 0 0 auto;
330
- width: 42px; height: 24px; margin: 0; cursor: pointer;
331
- }
332
- .switch input { position: absolute; width: 0; height: 0; opacity: 0; }
333
- .switch .track {
334
- position: absolute; inset: 0; border-radius: 999px;
335
- background: var(--border-strong); transition: background .16s;
336
- }
337
- .switch .track::after {
338
- content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
339
- border-radius: 50%; background: #fff; box-shadow: var(--shadow-1); transition: transform .16s;
340
- }
341
- /* 开启 = 全部放行(放手模式),用 warn 色提示当前处于高风险态 */
342
- .switch input:checked + .track { background: var(--warn); }
343
- .switch input:checked + .track::after { transform: translateX(18px); }
344
- .switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--primary-ring); }
345
- .switch-label { font-size: 13.5px; color: var(--text); }
346
- /* 开关开启时名单区暂不生效:整体置灰且不可交互(顺带让「恢复默认」等按钮不可点) */
347
- .block-disabled { opacity: .45; pointer-events: none; }
348
-
349
- /* ---------- 保存条 / 未保存标记 ---------- */
350
- .savebar {
351
- display: flex; gap: 10px; margin-top: 14px; align-items: center;
352
- padding: 9px 12px; border-radius: var(--radius-sm);
353
- background: var(--warn-weak); border: 1px solid var(--warn-weak-border);
354
- }
355
- .savebar .state { font-size: 12px; color: var(--warn-tx); }
356
- .savebar .state::before { content: '● '; font-size: 9px; vertical-align: 1px; }
357
-
358
- /* ---------- 应用子卡片 / 提示 ---------- */
359
- .app-card { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 4px 16px 14px; margin-bottom: 12px; position: relative; }
360
- .app-card .del { position: absolute; top: 10px; right: 12px; }
361
- .hint { font-size: 12px; color: var(--muted); }
362
- .footer-note { color: var(--muted); font-size: 12px; margin-top: 8px; }
363
-
364
- /* ---------- 子页签 ---------- */
365
- .subtabs { display: flex; gap: 8px; margin-bottom: 14px; }
366
- .subtabs button {
367
- padding: 6px 15px; border-radius: 999px; border: 1px solid var(--border-strong);
368
- background: none; cursor: pointer; font: inherit; font-size: 13px; color: var(--text);
369
- transition: background .15s, color .15s, border-color .15s;
370
- }
371
- .subtabs button:hover { border-color: var(--primary); color: var(--primary); }
372
- .subtabs button.active { background: var(--primary-weak); color: var(--primary); border-color: var(--primary); font-weight: 600; }
373
-
374
- /* ---------- Toast ---------- */
375
- #toast {
376
- position: fixed; top: 22px; left: 50%;
377
- transform: translateX(-50%) translateY(-14px);
378
- background: var(--toast-bg); color: #fff;
379
- -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
380
- padding: 10px 22px; border-radius: 999px; font-size: 13px;
381
- box-shadow: var(--shadow-2);
382
- opacity: 0; transition: opacity .25s, transform .25s;
383
- pointer-events: none; max-width: 80vw; z-index: 100;
384
- }
385
- #toast.show { opacity: .97; transform: translateX(-50%) translateY(0); }
386
- #toast.err { background: var(--danger); }
387
-
388
- /* ---------- 桥接器重启 / 离线全页遮罩 ---------- */
389
- .br-mask { position: fixed; inset: 0; background: rgba(15, 19, 24, .5); z-index: 90; display: flex; align-items: center; justify-content: center; animation: lcb-fade .18s ease; }
390
- .br-mask-card {
391
- background: var(--card); border-radius: 16px; padding: 28px 36px; text-align: center;
392
- box-shadow: var(--shadow-pop); max-width: 440px; font-size: 14px;
393
- border: 1px solid var(--border);
394
- }
395
- .br-spin, .br-spin-sm { border-radius: 50%; border-style: solid; border-color: var(--spin-track); border-top-color: var(--primary); animation: brspin .9s linear infinite; }
396
- .br-spin { width: 26px; height: 26px; margin: 0 auto 12px; border-width: 3px; }
397
- /* 表格内小号 spinner(斜杠命令远端拉取等异步加载占位) */
398
- .br-spin-sm { width: 18px; height: 18px; margin: 0 auto 10px; border-width: 2px; }
399
- @keyframes brspin { to { transform: rotate(360deg); } }
400
-
401
- /* ---------- 右侧抽屉(应用 / 斜杠命令 / 档案编辑共用) ---------- */
402
- .drawer-mask { position: fixed; inset: 0; background: rgba(15, 19, 24, .38); z-index: 50; display: flex; justify-content: flex-end; animation: lcb-fade .18s ease; }
403
- .drawer-mask[hidden] { display: none; }
404
- .drawer {
405
- position: relative; /* 拖拽手柄的定位基准 */
406
- width: min(980px, 94vw); height: 100%;
407
- background: var(--card); border-left: 1px solid var(--border);
408
- display: flex; flex-direction: column;
409
- box-shadow: -12px 0 40px rgba(15, 19, 24, .18);
410
- animation: lcb-drawer .22s cubic-bezier(.22, .8, .36, 1);
411
- }
412
- @keyframes lcb-drawer { from { transform: translateX(48px); opacity: .4; } }
413
- /* 左边缘拖拽调宽手柄:8px 命中区(半出界更易命中),视觉条仅 2px、悬停/拖拽时显主题色 */
414
- .drawer-resize { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; cursor: ew-resize; z-index: 2; touch-action: none; }
415
- .drawer-resize::after { content: ''; position: absolute; left: 3px; top: 0; bottom: 0; width: 2px; background: transparent; transition: background .15s; }
416
- .drawer-resize:hover::after, .drawer-resize.dragging::after { background: var(--primary); }
417
- /* 拖拽期间全局改光标 + 禁选中(防正文文字反白跟随) */
418
- body.drawer-resizing { cursor: ew-resize; user-select: none; }
419
- .drawer > header { display: flex; align-items: center; justify-content: space-between; padding: 0 20px; height: 52px; border-bottom: 1px solid var(--border); position: static; background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
420
- .drawer > header h3 { margin: 0; font-size: 15px; font-weight: 650; }
421
- .drawer-body { flex: 1; overflow-y: auto; padding: 18px 22px; }
422
- .drawer-foot { padding: 12px 20px; border-top: 1px solid var(--border); display: flex; gap: 10px; align-items: center; }
423
- .drawer-foot .spacer { flex: 1; }
424
-
425
- /* ---------- 居中 modal(目录选择等轻量交互;z-index 低于断连遮罩 br-mask=90) ---------- */
426
- .modal-mask { position: fixed; inset: 0; background: rgba(15, 19, 24, .42); z-index: 80; display: flex; align-items: center; justify-content: center; animation: lcb-fade .16s ease; }
427
- .modal {
428
- width: min(560px, 92vw); background: var(--card); border-radius: 16px; padding: 18px 22px;
429
- box-shadow: var(--shadow-pop); border: 1px solid var(--border);
430
- animation: lcb-pop .18s cubic-bezier(.22, .8, .36, 1);
431
- }
432
- @keyframes lcb-pop { from { transform: scale(.965); opacity: .5; } }
433
- .dir-list { border: 1px solid var(--border); border-radius: var(--radius-sm); max-height: 46vh; overflow-y: auto; margin-top: 10px; }
434
- .dir-list button {
435
- display: block; width: 100%; text-align: left; padding: 8px 12px;
436
- border: 0; border-bottom: 1px solid var(--border); background: none; cursor: pointer; font: inherit;
437
- transition: background .12s, color .12s;
438
- }
439
- .dir-list button:last-child { border-bottom: 0; }
440
- .dir-list button:hover { background: var(--primary-weak); color: var(--primary); }
441
- .dir-list .empty { padding: 14px 12px; color: var(--muted); font-size: 12.5px; text-align: center; }
442
-
443
- /* ---------- 可搜索 combobox(安装插件选择器) ---------- */
444
- .combo { position: relative; }
445
- .combo-panel {
446
- position: absolute; top: calc(100% + 5px); left: 0; right: 0;
447
- background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
448
- box-shadow: var(--shadow-2); max-height: 320px; overflow-y: auto; z-index: 40;
449
- }
450
- .combo-panel[hidden] { display: none; }
451
- .combo-item { padding: 8px 12px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background .12s; }
452
- .combo-item:last-child { border-bottom: 0; }
453
- .combo-item:hover { background: var(--primary-weak); }
454
- .combo-item b { margin-right: 6px; }
455
- .combo-empty { padding: 12px; color: var(--muted); font-size: 12.5px; }
456
-
457
- /* ---------- 可搜索多选字段(分身白名单):外框对齐输入框观感,chips + 搜索行 ---------- */
458
- .msel { position: relative; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--field); padding: 2px 10px; transition: border-color .15s, box-shadow .15s; }
459
- .msel:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-ring); }
460
- .msel-chips { margin: 4px 0; }
461
- .msel-chips:empty { display: none; }
462
- .msel .msel-input { border: 0; background: none; box-shadow: none; width: 100%; padding: 6px 2px; font-size: 13.5px; }
463
- .msel .msel-input:focus { border: 0; box-shadow: none; } /* 覆盖全局 input:focus(焦点态由 .msel:focus-within 呈现);带 .msel 前缀提特异性,防被 input[type=text] (0,1,1) 压制 */
464
- .combo-item.active { background: var(--primary-weak); } /* 键盘高亮(:hover 已有) */
465
- .msel-check { float: right; color: var(--primary); font-weight: 650; }
466
- .chip.ghost { border-style: dashed; color: var(--muted); }
467
-
468
- /* ---------- 操作进度弹框(update-all 真实 i/N,单操作时间缓动模拟) ---------- */
469
- .prog { height: 8px; border-radius: 999px; background: var(--off-bg); border: 1px solid var(--border); overflow: hidden; margin-top: 12px; }
470
- .prog-bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(--primary), var(--primary-strong)); border-radius: 999px; transition: width .3s; }
471
- .prog-bar.done { background: var(--ok); }
472
-
473
- /* ---------- 减弱动效偏好 ---------- */
474
- @media (prefers-reduced-motion: reduce) {
475
- *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
476
- }
477
-
478
- /* ---------- 手动主题(顶栏切换写入 data-theme;auto = 不设属性,走上方系统媒体查询) ---------- */
479
- :root[data-theme="dark"] {
480
- color-scheme: dark;
481
- --bg: #0e1117;
482
- --card: #161a23;
483
- --field: #10141d;
484
- --border: #262c3a;
485
- --border-strong: #363e50;
486
- --text: #e7eaf1;
487
- --muted: #97a0b2;
488
- --primary: #4d80ff;
489
- --primary-strong: #6996ff;
490
- --primary-weak: rgba(77, 128, 255, .14);
491
- --primary-ring: rgba(77, 128, 255, .28);
492
- --danger: #ff7373;
493
- --ok: #5ad24a;
494
- --warn: #ffa23e;
495
- --ok-bg: rgba(52, 199, 36, .13);
496
- --warn-bg: rgba(255, 136, 0, .13);
497
- --err-bg: rgba(245, 79, 79, .13);
498
- --off-bg: rgba(255, 255, 255, .06);
499
- --ok-tx: #5ad24a;
500
- --warn-tx: #ffa23e;
501
- --err-tx: #ff7373;
502
- --off-tx: #97a0b2;
503
- --warn-weak: rgba(255, 136, 0, .09);
504
- --warn-weak-border: rgba(255, 136, 0, .32);
505
- --code-bg: rgba(255, 255, 255, .09);
506
- --shadow-1: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 8px rgba(0, 0, 0, .18);
507
- --shadow-2: 0 8px 28px rgba(0, 0, 0, .45);
508
- --shadow-pop: 0 12px 40px rgba(0, 0, 0, .55);
509
- --header-bg: rgba(19, 23, 31, .82);
510
- --spin-track: rgba(255, 255, 255, .16);
511
- --toast-bg: rgba(58, 64, 78, .95);
512
- }
513
-
514
- /* ---------- 主题切换分段控件(顶栏) ---------- */
515
- .theme-switch {
516
- display: inline-flex; gap: 2px; padding: 3px;
517
- background: var(--card); border: 1px solid var(--border); border-radius: 999px;
518
- }
519
- .theme-switch button {
520
- display: inline-flex; align-items: center; justify-content: center;
521
- width: 30px; height: 24px; border: 0; background: none; border-radius: 999px;
522
- cursor: pointer; color: var(--muted);
523
- transition: background .15s, color .15s;
524
- }
525
- .theme-switch button:hover { color: var(--text); background: rgba(127, 140, 170, .12); }
526
- .theme-switch button.active { background: var(--primary-weak); color: var(--primary); }
527
- .theme-switch svg { display: block; }
528
-
529
- /* ---------- 列表工具栏(各列表页顶部按钮统一形态) ---------- */
530
- .list-toolbar { display: flex; gap: 8px; align-items: center; justify-content: flex-end; margin-bottom: 12px; }
531
- .list-toolbar .spacer { flex: 1; }
532
- .list-search { margin-bottom: 10px; }
533
-
534
- /* ---------- 页内一级 tab(下划线式;权限页等) ---------- */
535
- .tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
536
- .tabs button {
537
- padding: 9px 18px; border: 0; background: none; cursor: pointer;
538
- font: inherit; font-size: 14px; color: var(--muted);
539
- border-bottom: 2px solid transparent; margin-bottom: -1px;
540
- transition: color .15s, border-color .15s;
541
- }
542
- .tabs button:hover { color: var(--text); }
543
- .tabs button.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }
544
-
545
- /* ---------- 风格化确认 / 输入弹窗(替代浏览器原生 confirm / prompt) ---------- */
546
- .dlg { width: min(430px, 92vw); padding: 22px 24px 18px; }
547
- .dlg-title { margin: 0 0 10px; font-size: 15.5px; font-weight: 650; display: flex; align-items: center; gap: 8px; }
548
- .dlg-title .dlg-ico {
549
- width: 26px; height: 26px; border-radius: 8px; flex: 0 0 auto;
550
- display: inline-flex; align-items: center; justify-content: center;
551
- background: var(--err-bg); color: var(--err-tx); font-size: 14px;
552
- }
553
- .dlg-title.danger { color: var(--danger); }
554
- .dlg-msg { font-size: 13.5px; line-height: 1.75; color: var(--text); white-space: pre-line; word-break: break-word; }
555
- .dlg-msg code { font-size: 12.5px; }
556
- .dlg-input { margin-top: 12px; }
557
- .dlg-foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
558
-
559
- /* 实心危险按钮(弹窗确认键):与 .btn.danger(描边)区分 */
560
- .btn.danger-solid { background: var(--danger); border-color: var(--danger); color: #fff; }
561
- .btn.danger-solid:hover { background: var(--danger); border-color: var(--danger); color: #fff; filter: brightness(1.07); }
562
-
563
- /* ---------- 扫码授权二维码(设备流) ---------- */
564
- /* 白底是刻意的:lark-cli 生成的 PNG 本身是白底黑码,容器若跟随暗色主题就会在图片
565
- 周围露出一圈深色,看着像二维码被裁掉。固定白底在任何主题下都与图片本身一致,
566
- 也保证手机扫得出来。 */
567
- .qr-box {
568
- display: flex; justify-content: center; align-items: center;
569
- margin-top: 12px; padding: 12px; background: #fff;
570
- border: 1px solid var(--border); border-radius: 12px; color-scheme: light;
571
- }
572
- .qr-box img { display: block; width: 220px; height: 220px; }
573
- /* 链接可整段选中复制;长 URL 必须能折行,否则会把弹窗撑爆 */
574
- .qr-url { margin-top: 8px; line-height: 1.6; word-break: break-all; user-select: all; }
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ 配置台设计系统(prototype/index.html 重构原型 1:1 落地)
3
+ 结构:Tokens → Base → Topbar → Layout/Sidenav → PageHead → Panel
4
+ → Tiles → Dot/Tag → Buttons → Forms → RCards → Switch → Tables
5
+ → Chips → Tabs → Drawer → Dlg/ModalMask → Toast → Tip → Savebar
6
+ → Banner/Misc → 卡片网格 → 厂商档案 → 工作区 → 会话 → 锁屏
7
+ → UserRow → 现有组件保留区(msel/目录选择/进度/二维码…)→ Responsive
8
+ ═══════════════════════════════════════════════════════════════ */
9
+
10
+ /* ═══ Tokens ═══ */
11
+ :root{
12
+ color-scheme:light;
13
+ --bg:#f3f5f9; --card:#fff; --field:#fff; --sunk:#f6f8fb;
14
+ --border:#e4e8f0; --border2:#cfd6e4;
15
+ --ink:#1c2333; --mut:#697180; --faint:#9aa3b4;
16
+ --pri:#3370ff; --pri-h:#2b5fe3; --pri-w:#edf3ff; --pri-ring:rgba(51,112,255,.18);
17
+ --ok:#1f9d55; --ok-bg:#e7f6ec; --ok-tx:#177c43;
18
+ --warn:#d97706; --warn-bg:#fdf3e2; --warn-tx:#a85d03;
19
+ --err:#e5484d; --err-bg:#fdecec; --err-tx:#c7363b;
20
+ --off-bg:#eef0f5; --off-tx:#7a8294;
21
+ --code-bg:rgba(28,35,51,.06);
22
+ --spin-track:var(--border2);
23
+ --mono:"JetBrains Mono","SF Mono",Consolas,"Cascadia Mono",Menlo,monospace;
24
+ --r:12px; --r-s:8px;
25
+ --shadow:0 1px 2px rgba(16,24,40,.05);
26
+ --shadow-2:0 10px 32px rgba(16,24,40,.14);
27
+ --header-bg:rgba(255,255,255,.86);
28
+ --nav-w:212px;
29
+ /* 旧变量别名:页面内联样式/历史组件仍引用旧名(--primary/--muted/--danger…),统一桥接到新 tokens */
30
+ --primary:var(--pri); --primary-strong:var(--pri-h); --primary-weak:var(--pri-w); --primary-ring:var(--pri-ring);
31
+ --text:var(--ink); --muted:var(--mut); --border-strong:var(--border2); --danger:var(--err);
32
+ --radius:var(--r); --radius-sm:var(--r-s); --shadow-pop:var(--shadow-2); --accent:var(--pri);
33
+ }
34
+ :root[data-theme="dark"]{
35
+ color-scheme:dark;
36
+ --bg:#0f1218; --card:#161b26; --field:#10141d; --sunk:#1a2030;
37
+ --border:#272e3f; --border2:#3a4358;
38
+ --ink:#e8ebf2; --mut:#98a1b3; --faint:#6b7488;
39
+ --pri:#4d80ff; --pri-h:#6996ff; --pri-w:rgba(77,128,255,.15); --pri-ring:rgba(77,128,255,.3);
40
+ --ok:#43c072; --ok-bg:rgba(46,161,33,.14); --ok-tx:#5ad286;
41
+ --warn:#f09d3e; --warn-bg:rgba(255,136,0,.12); --warn-tx:#ffb45e;
42
+ --err:#ff7076; --err-bg:rgba(229,72,77,.14); --err-tx:#ff8f94;
43
+ --off-bg:rgba(255,255,255,.06); --off-tx:#98a1b3;
44
+ --code-bg:rgba(255,255,255,.09);
45
+ --shadow:0 1px 2px rgba(0,0,0,.3);
46
+ --shadow-2:0 10px 32px rgba(0,0,0,.5);
47
+ --header-bg:rgba(17,21,29,.86);
48
+ }
49
+
50
+ /* ═══ Base ═══ */
51
+ *{box-sizing:border-box}
52
+ [hidden]{display:none!important} /* 组件类 display 会覆盖 UA 的 [hidden] 样式,此处强制兜底 */
53
+ html{-webkit-text-size-adjust:100%}
54
+ body{
55
+ margin:0;
56
+ font:13.5px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
57
+ background:var(--bg); color:var(--ink);
58
+ }
59
+ ::selection{background:var(--pri-w)}
60
+ ::-webkit-scrollbar{width:10px;height:10px}
61
+ ::-webkit-scrollbar-thumb{background:var(--border2);border-radius:8px;border:2px solid transparent;background-clip:padding-box}
62
+ ::-webkit-scrollbar-track{background:transparent}
63
+ *{scrollbar-width:thin;scrollbar-color:var(--border2) transparent}
64
+ a{color:var(--pri);text-decoration:none}
65
+ a:hover{text-decoration:underline}
66
+ code{font-family:var(--mono);font-size:.9em;background:var(--code-bg);border-radius:5px;padding:1px 5px;word-break:break-all}
67
+ h1,h2,h3,h4{margin:0;font-weight:650}
68
+ button{font:inherit}
69
+ :focus-visible{outline:2px solid var(--pri);outline-offset:2px;border-radius:4px}
70
+
71
+ /* ═══ Topbar ═══ */
72
+ .topbar{
73
+ height:54px; padding:0 20px;
74
+ display:flex; align-items:center; gap:12px;
75
+ background:var(--header-bg);
76
+ -webkit-backdrop-filter:blur(14px) saturate(1.4); backdrop-filter:blur(14px) saturate(1.4);
77
+ border-bottom:1px solid var(--border);
78
+ position:sticky; top:0; z-index:30;
79
+ }
80
+ .brand{display:flex;align-items:center;gap:10px;min-width:0}
81
+ .brand .logo{
82
+ width:28px;height:28px;border-radius:8px;flex:0 0 auto;
83
+ display:inline-flex;align-items:center;justify-content:center;
84
+ background:linear-gradient(135deg,#3370ff,#7c5bff 130%);
85
+ box-shadow:0 2px 8px rgba(51,112,255,.32);
86
+ }
87
+ .brand h1{font-size:14.5px;letter-spacing:.01em;white-space:nowrap}
88
+ .pill{
89
+ font-size:11.5px;color:var(--mut);background:var(--card);
90
+ border:1px solid var(--border);border-radius:999px;padding:1px 10px;
91
+ font-variant-numeric:tabular-nums;white-space:nowrap;
92
+ }
93
+ .pill.accent{background:var(--pri-w);border-color:transparent;color:var(--pri)}
94
+ .topbar .sp{flex:1}
95
+ .theme-btn{
96
+ width:32px;height:30px;border-radius:8px;border:1px solid var(--border);
97
+ background:var(--card);color:var(--mut);cursor:pointer;
98
+ display:inline-flex;align-items:center;justify-content:center;
99
+ transition:color .15s,border-color .15s;
100
+ }
101
+ .theme-btn:hover{color:var(--ink);border-color:var(--border2)}
102
+
103
+ /* ═══ Layout / Sidenav ═══ */
104
+ .layout{display:flex;min-height:calc(100vh - 54px)}
105
+ .sidenav{
106
+ width:var(--nav-w);flex:0 0 auto;
107
+ padding:14px 10px 28px;
108
+ position:sticky;top:54px;align-self:flex-start;
109
+ max-height:calc(100vh - 54px);overflow-y:auto;
110
+ }
111
+ .nav-search{position:relative;margin:0 4px 12px}
112
+ .nav-search svg{position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--faint);pointer-events:none}
113
+ .nav-search input{
114
+ width:100%;padding:7px 10px 7px 30px;font:inherit;font-size:12.5px;
115
+ border:1px solid var(--border);border-radius:var(--r-s);
116
+ background:var(--field);color:var(--ink);
117
+ }
118
+ .nav-search input:focus{outline:none;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-ring)}
119
+ .nav-group{margin-bottom:6px}
120
+ .nav-group-label{
121
+ font-size:11px;color:var(--faint);font-weight:600;letter-spacing:.06em;
122
+ padding:10px 12px 4px;white-space:nowrap;
123
+ }
124
+ .nav-item{
125
+ display:flex;align-items:center;gap:9px;width:100%;
126
+ padding:7px 12px;margin:1px 0;border:0;background:none;border-radius:var(--r-s);
127
+ cursor:pointer;font-size:13px;color:var(--ink);text-align:left;
128
+ transition:background .14s,color .14s;position:relative;
129
+ }
130
+ .nav-item .ico{display:flex;color:var(--mut);transition:color .14s;flex:0 0 auto}
131
+ .nav-item:hover{background:rgba(127,140,170,.1)}
132
+ .nav-item:hover .ico{color:var(--ink)}
133
+ .nav-item.active{background:var(--pri-w);color:var(--pri);font-weight:600}
134
+ .nav-item.active .ico{color:var(--pri)}
135
+ .nav-item .nav-badge{
136
+ margin-left:auto;min-width:16px;height:16px;padding:0 5px;border-radius:999px;
137
+ background:var(--err-bg);color:var(--err-tx);font-size:10px;font-weight:600;
138
+ display:inline-flex;align-items:center;justify-content:center;
139
+ }
140
+ .nav-item.nav-hide{display:none}
141
+
142
+ main{flex:1;min-width:0;padding:22px 30px 90px}
143
+ @media (min-width:1760px){main{max-width:1400px}}
144
+
145
+ /* ═══ Page head ═══ */
146
+ .page-head{display:flex;align-items:flex-start;gap:13px;margin:2px 0 20px;flex-wrap:wrap}
147
+ .page-head .ico{
148
+ width:38px;height:38px;border-radius:11px;flex:0 0 auto;
149
+ display:inline-flex;align-items:center;justify-content:center;
150
+ background:var(--pri-w);color:var(--pri);
151
+ }
152
+ .page-head h2{font-size:18px;letter-spacing:.01em}
153
+ .page-head .page-desc{color:var(--mut);font-size:12.5px;margin-top:2px}
154
+ .page-head .page-actions{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
155
+ #view{animation:fadein .18s ease}
156
+ @keyframes fadein{from{opacity:0;transform:translateY(4px)}}
157
+ #pageLegend{margin-top:26px}
158
+
159
+ /* ═══ Panel(统一卡片) ═══ */
160
+ /* overflow:visible:表头 ⓘ 的悬浮提示不能被卡片裁掉(主人反馈 #9);卡内内容自带 padding 不贴角,圆角不受影响 */
161
+ .panel{
162
+ background:var(--card);border:1px solid var(--border);border-radius:var(--r);
163
+ box-shadow:var(--shadow);margin-bottom:16px;overflow:visible;
164
+ }
165
+ .panel-head{
166
+ display:flex;align-items:center;gap:12px;flex-wrap:wrap;
167
+ padding:14px 18px 0;
168
+ }
169
+ .panel-head h3{font-size:14.5px}
170
+ .panel-sub{color:var(--mut);font-size:12px;margin-top:1px}
171
+ .panel-actions{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
172
+ .panel-body{padding:14px 18px 18px}
173
+ .panel-foot{
174
+ padding:10px 18px;border-top:1px solid var(--border);
175
+ color:var(--faint);font-size:12px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;
176
+ }
177
+ .panel > hr{border:0;border-top:1px solid var(--border);margin:14px 0}
178
+ .sub-title{font-size:12.5px;font-weight:650;margin:0 0 10px;display:flex;align-items:center;gap:8px}
179
+ /* 兼容别名:首装向导 / 兜底提示等少量历史标记仍用 .card,观感对齐 .panel */
180
+ .card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow);margin-bottom:16px;padding:16px 18px}
181
+ .card > h3{font-size:14.5px}
182
+ .card .desc{color:var(--mut);font-size:12.5px;margin-bottom:12px;line-height:1.7}
183
+
184
+ /* ═══ Status tiles(概览看板) ═══ */
185
+ .tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-bottom:16px}
186
+ @media (max-width:1280px){.tiles{grid-template-columns:repeat(2,1fr)}}
187
+ @media (max-width:640px){.tiles{grid-template-columns:1fr}}
188
+ .tile{
189
+ background:var(--card);border:1px solid var(--border);border-radius:var(--r);
190
+ box-shadow:var(--shadow);padding:14px 16px 12px;
191
+ display:flex;flex-direction:column;gap:3px;min-width:0;
192
+ }
193
+ .tile-top{display:flex;align-items:center;gap:7px}
194
+ .tile-top .tile-ico{margin-left:auto;color:var(--faint);display:flex}
195
+ .tile-state{font-size:12.5px;font-weight:650}
196
+ .tile-name{font-size:15px;font-weight:650;margin-top:2px}
197
+ .tile-sub{color:var(--mut);font-size:12px;min-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
198
+ .tile-actions{display:flex;gap:6px;margin-top:8px}
199
+ .tile-actions .btn{padding:4px 10px;font-size:12px}
200
+
201
+ /* ═══ Dot / Tag ═══ */
202
+ .dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto;display:inline-block}
203
+ .dot.ok{background:var(--ok);box-shadow:0 0 0 3px var(--ok-bg)}
204
+ .dot.off{background:var(--faint)}
205
+ .dot.warn{background:var(--warn);box-shadow:0 0 0 3px var(--warn-bg)}
206
+ .dot.err{background:var(--err);box-shadow:0 0 0 3px var(--err-bg)}
207
+ .tag{
208
+ display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
209
+ padding:1px 9px;border-radius:999px;font-size:11px;font-weight:550;vertical-align:1px;
210
+ }
211
+ .tag.ok{background:var(--ok-bg);color:var(--ok-tx)}
212
+ .tag.warn{background:var(--warn-bg);color:var(--warn-tx)}
213
+ .tag.err{background:var(--err-bg);color:var(--err-tx)}
214
+ .tag.off{background:var(--off-bg);color:var(--off-tx)}
215
+ .tag.info{background:var(--pri-w);color:var(--pri)}
216
+ .tag.ghost{background:none;border:1px dashed var(--border2);color:var(--mut)}
217
+
218
+ /* ═══ Buttons ═══ */
219
+ .btn{
220
+ display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
221
+ padding:6px 14px;border-radius:var(--r-s);
222
+ border:1px solid var(--border2);background:var(--card);color:var(--ink);
223
+ cursor:pointer;font-size:13px;line-height:1.5;
224
+ transition:background .15s,border-color .15s,color .15s,transform .06s;
225
+ }
226
+ .btn:hover{border-color:var(--pri);color:var(--pri);background:var(--pri-w)}
227
+ .btn:active{transform:translateY(1px)}
228
+ .btn:disabled{opacity:.5;cursor:not-allowed}
229
+ .btn.primary{background:var(--pri);border-color:var(--pri);color:#fff;box-shadow:0 1px 6px rgba(51,112,255,.3)}
230
+ .btn.primary:hover{background:var(--pri-h);border-color:var(--pri-h);color:#fff}
231
+ .btn.danger{color:var(--err)}
232
+ .btn.danger:hover{border-color:var(--err);background:var(--err-bg);color:var(--err)}
233
+ .btn.danger-solid{background:var(--err);border-color:var(--err);color:#fff}
234
+ .btn.danger-solid:hover{background:#d6383d;border-color:#d6383d;color:#fff;filter:brightness(1.05)}
235
+ .btn.sm{padding:3px 10px;font-size:12px;border-radius:7px}
236
+ .btn.ghost{border-color:transparent;background:none;color:var(--mut)}
237
+ .btn.ghost:hover{color:var(--pri);background:var(--pri-w);border-color:transparent}
238
+ .btn .spin{
239
+ width:13px;height:13px;border-radius:50%;flex:0 0 auto;
240
+ border:2px solid var(--border2);border-top-color:var(--pri);
241
+ animation:spin .8s linear infinite;
242
+ }
243
+ @keyframes spin{to{transform:rotate(360deg)}}
244
+
245
+ /* ═══ Forms ═══ */
246
+ label.fld{display:block;font-size:12px;color:var(--mut);margin:12px 0 5px}
247
+ label.fld:first-child{margin-top:0}
248
+ input[type=text],input[type=password],input[type=number],input[type=search],input[type=date],select,textarea{
249
+ width:100%;padding:7px 11px;
250
+ border:1px solid var(--border2);border-radius:var(--r-s);
251
+ font:inherit;font-size:13px;background:var(--field);color:var(--ink);
252
+ transition:border-color .15s,box-shadow .15s;
253
+ }
254
+ input:hover,select:hover,textarea:hover{border-color:var(--faint)}
255
+ input:focus,select:focus,textarea:focus{outline:none;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-ring)}
256
+ textarea{font-family:var(--mono);font-size:12.5px;min-height:90px;line-height:1.6;resize:vertical}
257
+ textarea[style*="font-family:inherit"],textarea.plain{font-family:inherit;font-size:13px}
258
+ select{cursor:pointer}
259
+ input[type=checkbox],input[type=radio]{accent-color:var(--pri)}
260
+ .grid2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 18px}
261
+ @media (max-width:860px){.grid2{grid-template-columns:1fr}}
262
+ .grid3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2px 16px}
263
+ @media (max-width:1100px){.grid3{grid-template-columns:1fr}}
264
+ .frow{display:flex;gap:12px;align-items:flex-start}
265
+ .frow>*{flex:1;min-width:0}
266
+ .frow .btn,.frow .btn-wrap{flex:0 0 auto;align-self:flex-end}
267
+ .input-btn{display:flex;gap:8px}
268
+ .input-btn>input{flex:1;min-width:0}
269
+ .input-btn>.btn{flex:0 0 auto;align-self:center}
270
+ /* 历史表单行(bootstrap 向导 / pickDirectory 顶部) */
271
+ .row{display:flex;gap:12px}
272
+ .row>*{flex:1;min-width:0}
273
+ .row>.btn,.row>.btn-wrap{flex:0 0 auto;align-self:end}
274
+ .row-2col{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 16px;align-items:start}
275
+ .btn-wrap{display:flex}
276
+ @media (max-width:860px){.row{flex-direction:column}.row-2col{grid-template-columns:1fr}}
277
+ .hint{font-size:12px;color:var(--mut)}
278
+ .footer-note{color:var(--mut);font-size:12px;margin-top:8px}
279
+
280
+ /* ═══ Radio cards ═══ */
281
+ .rcards{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;margin:10px 0}
282
+ .rcard{
283
+ border:1px solid var(--border2);border-radius:10px;padding:12px 14px;cursor:pointer;
284
+ display:flex;gap:10px;align-items:flex-start;background:var(--field);
285
+ transition:border-color .15s,background .15s;
286
+ }
287
+ .rcard:hover{border-color:var(--pri)}
288
+ .rcard input{margin-top:3px}
289
+ .rcard.on{border-color:var(--pri);background:var(--pri-w)}
290
+ .rcard b{font-size:13px;display:block}
291
+ .rcard .hint{margin-top:2px}
292
+ /* 历史单选行(bootstrap 向导) */
293
+ .radio-row{display:flex;gap:22px;margin:8px 0;flex-wrap:wrap}
294
+ .radio-row label{display:flex;align-items:center;gap:6px;margin:0;color:var(--ink);font-size:13.5px;cursor:pointer}
295
+
296
+ /* ═══ Switch ═══ */
297
+ .switch-row{display:flex;align-items:center;gap:10px;margin:8px 0}
298
+ .switch{position:relative;display:inline-flex;flex:0 0 auto;width:40px;height:23px;margin:0;cursor:pointer}
299
+ .switch input{position:absolute;width:0;height:0;opacity:0}
300
+ .switch .track{position:absolute;inset:0;border-radius:999px;background:var(--border2);transition:background .16s}
301
+ .switch .track::after{
302
+ content:'';position:absolute;top:2px;left:2px;width:19px;height:19px;border-radius:50%;
303
+ background:#fff;box-shadow:var(--shadow);transition:transform .16s;
304
+ }
305
+ .switch input:checked+.track{background:var(--pri)}
306
+ .switch input:checked+.track::after{transform:translateX(17px)}
307
+ .switch input:focus-visible+.track{box-shadow:0 0 0 3px var(--pri-ring)}
308
+ .switch-label{font-size:13px}
309
+ .switch.tight{width:34px;height:20px}
310
+ .switch.tight .track::after{width:16px;height:16px}
311
+ .switch.tight input:checked+.track::after{transform:translateX(14px)}
312
+
313
+ /* ═══ Tables ═══ */
314
+ table{width:100%;border-collapse:collapse;font-size:13px}
315
+ th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--border);vertical-align:top}
316
+ thead th{color:var(--mut);font-weight:550;font-size:11.5px;letter-spacing:.04em;border-bottom:1px solid var(--border2)}
317
+ tbody tr{transition:background .12s}
318
+ tbody tr:hover{background:rgba(127,140,170,.05)}
319
+ tbody tr:last-child td{border-bottom:0}
320
+ tr.empty td{text-align:center;padding:26px 10px;color:var(--mut)}
321
+ td.ops{white-space:nowrap}
322
+ tr.rowlink{cursor:pointer}
323
+ .kv td:first-child{width:150px;color:var(--mut);font-size:12.5px}
324
+
325
+ /* ═══ Chips(可编辑名单) ═══ */
326
+ .chips{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0}
327
+ .echips{display:flex;flex-wrap:wrap;gap:7px;align-items:center;padding:9px 11px;min-height:40px}
328
+ .echips.on-box{border:1px solid var(--border2);border-radius:var(--r-s);background:var(--field)}
329
+ .chip{
330
+ display:inline-flex;align-items:center;gap:6px;
331
+ background:var(--card);border:1px solid var(--border);
332
+ padding:2px 6px 2px 11px;border-radius:999px;
333
+ font-size:12px;font-family:var(--mono);color:var(--ink);white-space:nowrap;
334
+ }
335
+ .chip .x,.chip>button{
336
+ border:0;background:none;color:var(--faint);cursor:pointer;
337
+ font-size:13px;line-height:1;padding:1px 4px;border-radius:50%;
338
+ }
339
+ .chip .x:hover,.chip>button:hover{color:var(--err);background:var(--err-bg)}
340
+ .chip.src{font-family:inherit;background:var(--off-bg);border-color:transparent;color:var(--mut)}
341
+ .chip.ghost{border-style:dashed;color:var(--mut)}
342
+ .chip .tag,.btn .tag{font-size:10px;padding:1px 6px;gap:0}
343
+
344
+ /* ═══ Tabs ═══ */
345
+ .tabs{display:flex;gap:2px;border-bottom:1px solid var(--border);margin-bottom:16px;flex-wrap:wrap}
346
+ .tabs button{
347
+ padding:8px 16px;border:0;background:none;cursor:pointer;font:inherit;font-size:13.5px;
348
+ color:var(--mut);border-bottom:2px solid transparent;margin-bottom:-1px;
349
+ transition:color .15s,border-color .15s;
350
+ }
351
+ .tabs button:hover{color:var(--ink)}
352
+ .tabs button.active{color:var(--pri);border-bottom-color:var(--pri);font-weight:600}
353
+ .tabs .dot{margin-left:5px;vertical-align:1px}
354
+ .subtabs{display:flex;gap:7px;margin-bottom:14px;flex-wrap:wrap}
355
+ .subtabs button{
356
+ padding:5px 14px;border-radius:999px;border:1px solid var(--border2);
357
+ background:none;cursor:pointer;font:inherit;font-size:12.5px;color:var(--ink);
358
+ transition:all .15s;
359
+ }
360
+ .subtabs button:hover{border-color:var(--pri);color:var(--pri)}
361
+ .subtabs button.active{background:var(--pri-w);color:var(--pri);border-color:var(--pri);font-weight:600}
362
+
363
+ /* ═══ Drawer ═══ */
364
+ .mask{position:fixed;inset:0;background:rgba(13,17,26,.42);z-index:50;display:flex;justify-content:flex-end;animation:fadein .16s ease}
365
+ .mask.center{justify-content:center;align-items:center}
366
+ .mask[hidden]{display:none}
367
+ .drawer{
368
+ position:relative; /* 左缘拖拽手柄的定位基准 */
369
+ width:min(960px,94vw);height:100%;background:var(--card);
370
+ border-left:1px solid var(--border);display:flex;flex-direction:column;
371
+ box-shadow:-12px 0 40px rgba(13,17,26,.2);
372
+ animation:slidein .22s cubic-bezier(.22,.8,.36,1);
373
+ }
374
+ .drawer.narrow{width:min(560px,94vw)}
375
+ @keyframes slidein{from{transform:translateX(40px);opacity:.4}}
376
+ /* 左边缘拖拽调宽手柄:8px 命中区,视觉条 2px、悬停/拖拽显主题色(localStorage 记忆 · 双击恢复默认) */
377
+ .drawer-resize{position:absolute;left:-4px;top:0;bottom:0;width:8px;cursor:ew-resize;z-index:2;touch-action:none}
378
+ .drawer-resize::after{content:'';position:absolute;left:3px;top:0;bottom:0;width:2px;background:transparent;transition:background .15s}
379
+ .drawer-resize:hover::after,.drawer-resize.dragging::after{background:var(--pri)}
380
+ body.drawer-resizing{cursor:ew-resize;user-select:none}
381
+ .drawer>header{
382
+ display:flex;align-items:center;gap:12px;padding:0 20px;height:52px;
383
+ border-bottom:1px solid var(--border);flex:0 0 auto;
384
+ }
385
+ .drawer>header h3{font-size:14.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
386
+ .drawer-body{flex:1;overflow-y:auto;padding:18px 22px}
387
+ .drawer-foot{
388
+ padding:12px 20px;border-top:1px solid var(--border);
389
+ display:flex;gap:10px;align-items:center;flex:0 0 auto;
390
+ }
391
+ .drawer-foot .sp{flex:1}
392
+ /* 抽屉内左侧子导航(skill 文件浏览等) */
393
+ .dw-layout{display:flex;gap:20px;align-items:flex-start}
394
+ .dw-nav{width:150px;flex:0 0 auto;position:sticky;top:0;display:flex;flex-direction:column;gap:2px}
395
+ .dw-nav button{
396
+ display:flex;align-items:center;gap:8px;width:100%;padding:7px 11px;
397
+ border:0;background:none;border-radius:var(--r-s);cursor:pointer;
398
+ font:inherit;font-size:12.5px;color:var(--mut);text-align:left;transition:all .14s;
399
+ }
400
+ .dw-nav button:hover{background:rgba(127,140,170,.09);color:var(--ink)}
401
+ .dw-nav button.active{background:var(--pri-w);color:var(--pri);font-weight:600}
402
+ .dw-nav button .cnt{margin-left:auto;font-size:11px;color:var(--faint)}
403
+ .dw-pane{flex:1;min-width:0}
404
+ @media (max-width:760px){.dw-layout{flex-direction:column}.dw-nav{flex-direction:row;flex-wrap:wrap;width:100%;position:static}}
405
+
406
+ /* ═══ Dlg(confirmDialog/promptDialog 自挂载弹窗) ═══ */
407
+ .modal-mask{position:fixed;inset:0;background:rgba(13,17,26,.42);z-index:80;display:flex;align-items:center;justify-content:center;animation:fadein .16s ease}
408
+ .dlg{
409
+ width:min(430px,92vw);background:var(--card);border-radius:14px;padding:20px 22px 16px;
410
+ box-shadow:var(--shadow-2);border:1px solid var(--border);
411
+ animation:pop .16s cubic-bezier(.22,.8,.36,1);
412
+ }
413
+ @keyframes pop{from{transform:scale(.96);opacity:.5}}
414
+ .dlg-title{font-size:15px;display:flex;align-items:center;gap:8px;margin-bottom:10px}
415
+ .dlg-title.danger{color:var(--err)}
416
+ .dlg-msg{font-size:13px;line-height:1.75;white-space:pre-line;word-break:break-word;color:var(--ink)}
417
+ .dlg-input{width:100%;padding:7px 11px;border:1px solid var(--border2);border-radius:var(--r-s);font:inherit;font-size:13px;background:var(--field);color:var(--ink)}
418
+ .dlg-foot{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}
419
+
420
+ /* ═══ Modal(通用居中弹窗:openModal() 用,宽度可配) ═══ */
421
+ .modal{
422
+ background:var(--card);border-radius:14px;border:1px solid var(--border);
423
+ box-shadow:var(--shadow-2);width:min(520px,92vw);max-height:88vh;
424
+ display:flex;flex-direction:column;
425
+ animation:pop .16s cubic-bezier(.22,.8,.36,1);
426
+ }
427
+ .modal-head{
428
+ display:flex;align-items:center;gap:10px;flex:0 0 auto;
429
+ padding:16px 20px 12px;border-bottom:1px solid var(--border);
430
+ }
431
+ .modal-head h3{font-size:14.5px;flex:1;min-width:0}
432
+ .modal-body{padding:16px 20px;overflow-y:auto}
433
+ .modal-foot{
434
+ padding:12px 20px 16px;border-top:1px solid var(--border);flex:0 0 auto;
435
+ display:flex;gap:10px;align-items:center;justify-content:flex-end;
436
+ }
437
+ .modal-foot .sp{flex:1}
438
+
439
+ /* ═══ Toast ═══ */
440
+ #toast{
441
+ position:fixed;top:20px;left:50%;transform:translateX(-50%) translateY(-12px);
442
+ background:rgba(28,35,51,.94);color:#fff;
443
+ -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
444
+ padding:9px 20px;border-radius:999px;font-size:13px;
445
+ box-shadow:var(--shadow-2);opacity:0;transition:opacity .25s,transform .25s;
446
+ pointer-events:none;max-width:80vw;z-index:300;
447
+ }
448
+ #toast.show{opacity:.97;transform:translateX(-50%) translateY(0)}
449
+ #toast.err{background:var(--err)}
450
+
451
+ /* ═══ Tooltip(信息收纳:ⓘ 悬浮显示) ═══ */
452
+ .tip{position:relative;display:inline-flex;color:var(--faint);cursor:help;vertical-align:-2px}
453
+ .tip:hover{color:var(--pri)}
454
+ .tip::after{
455
+ content:attr(data-tip);
456
+ position:absolute;left:50%;bottom:calc(100% + 7px);transform:translateX(-50%) translateY(4px);
457
+ background:rgba(28,35,51,.95);color:#fff;font-size:11.5px;font-weight:400;line-height:1.6;
458
+ padding:7px 11px;border-radius:8px;width:max-content;max-width:280px;white-space:normal;
459
+ opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;z-index:60;
460
+ text-align:left;font-family:inherit;
461
+ }
462
+ .tip:hover::after{opacity:1;transform:translateX(-50%) translateY(0)}
463
+ /* 卡片头部的 ⓘ 向下弹:贴近视口顶部时向上弹会被裁掉(主人反馈 #9) */
464
+ .panel-actions .tip::after{bottom:auto;top:calc(100% + 7px);transform:translateX(-50%) translateY(-4px)}
465
+ .panel-actions .tip:hover::after{transform:translateX(-50%) translateY(0)}
466
+
467
+ /* ═══ Savebar(未保存条;页内卡级保存行复用同类名) ═══ */
468
+ .savebar{
469
+ position:fixed;bottom:22px;left:50%;transform:translateX(-50%);
470
+ background:var(--card);border:1px solid var(--warn);border-radius:999px;
471
+ box-shadow:var(--shadow-2);padding:8px 10px 8px 18px;
472
+ display:flex;align-items:center;gap:12px;z-index:40;
473
+ animation:rise .2s ease;
474
+ }
475
+ @keyframes rise{from{transform:translate(-50%,10px);opacity:0}}
476
+ .savebar .state{font-size:12.5px;color:var(--warn-tx);display:flex;align-items:center;gap:7px}
477
+ .savebar[hidden]{display:none}
478
+ .savebar[style*="display:none"],.savebar[style*="display: none"]{position:static;transform:none;box-shadow:none;border:0;padding:10px 0 0;animation:none;background:none}
479
+ .savebar[style*="display:none"] .state,.savebar[style*="display: none"] .state{color:var(--warn-tx)}
480
+ .dirty-dot{display:none;margin-left:6px;font-size:11.5px;color:var(--warn-tx);font-weight:500}
481
+ /* 区域整体置灰禁用(记忆页/权限页联动开关用) */
482
+ .block-disabled{opacity:.45;pointer-events:none}
483
+
484
+ /* ═══ Banner / Empty / Misc ═══ */
485
+ .stale-bar{background:var(--warn-bg);color:var(--warn-tx);padding:9px 24px;font-size:13px;border-bottom:1px solid var(--border)}
486
+ .stale-bar[hidden]{display:none}
487
+ .banner{border-radius:10px;padding:9px 13px;font-size:12.5px;line-height:1.7;display:flex;gap:8px;align-items:flex-start}
488
+ .banner.warn{background:var(--warn-bg);color:var(--warn-tx)}
489
+ .banner.err{background:var(--err-bg);color:var(--err-tx)}
490
+ .banner.info{background:var(--pri-w);color:var(--pri)}
491
+ .banner b{font-weight:650}
492
+ .empty{text-align:center;padding:30px 16px;color:var(--mut)}
493
+ .empty .btn{margin-top:10px}
494
+ .mono{font-family:var(--mono);font-size:12px}
495
+ .mut{color:var(--mut)}
496
+ .dim{color:var(--faint)}
497
+ details.adv{border:1px solid var(--border);border-radius:10px;padding:0 14px;background:var(--sunk)}
498
+ details.adv>summary{cursor:pointer;font-size:12.5px;color:var(--mut);padding:10px 0;list-style:none;display:flex;align-items:center;gap:6px}
499
+ details.adv>summary::before{content:'▸';transition:transform .15s;font-size:10px}
500
+ details.adv[open]>summary::before{transform:rotate(90deg)}
501
+ details.adv>.adv-body{padding:2px 2px 14px}
502
+ .mini-note{font-size:11.5px;color:var(--faint);line-height:1.7}
503
+
504
+ /* ═══ App 卡片网格 ═══ */
505
+ .cardgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
506
+ .acard{
507
+ background:var(--card);border:1px solid var(--border);border-radius:var(--r);
508
+ box-shadow:var(--shadow);padding:16px;cursor:pointer;
509
+ transition:border-color .15s,box-shadow .15s;display:flex;flex-direction:column;gap:9px;
510
+ }
511
+ .acard:hover{border-color:var(--pri);box-shadow:var(--shadow-2)}
512
+ .acard-head{display:flex;align-items:center;gap:8px}
513
+ .acard-head b{font-size:14.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
514
+ .acard-head .dot{margin-left:auto}
515
+ .acard-meta{display:flex;flex-wrap:wrap;gap:6px 14px;color:var(--mut);font-size:12px}
516
+ .acard-meta span{display:inline-flex;align-items:center;gap:5px;min-width:0}
517
+ .acard-foot{display:flex;gap:6px;margin-top:2px}
518
+ .acard.newcard{
519
+ border-style:dashed;border-color:var(--border2);background:none;
520
+ align-items:center;justify-content:center;color:var(--mut);min-height:130px;
521
+ box-shadow:none;gap:6px;
522
+ }
523
+ .acard.newcard:hover{color:var(--pri);border-color:var(--pri);background:var(--pri-w)}
524
+
525
+ /* ═══ pickChips 弹层(供沿用 combo 结构的组件用) ═══ */
526
+ .pick{position:relative}
527
+ .pick .pick-pop{
528
+ position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:30;
529
+ background:var(--card);border:1px solid var(--border2);border-radius:10px;
530
+ box-shadow:var(--shadow-2);max-height:220px;overflow-y:auto;padding:4px;
531
+ }
532
+ .pick .pick-pop[hidden]{display:none}
533
+ .pick .pick-opt{
534
+ display:flex;align-items:center;gap:8px;width:100%;text-align:left;
535
+ border:0;background:none;cursor:pointer;font:inherit;font-size:12.5px;color:var(--ink);
536
+ padding:6px 9px;border-radius:7px;transition:background .12s;
537
+ }
538
+ .pick .pick-opt:hover{background:var(--pri-w)}
539
+ .pick .pick-opt .sub{color:var(--faint);font-size:11px;margin-left:auto;font-family:var(--mono)}
540
+ .pick .pick-empty{padding:10px;color:var(--faint);font-size:12px;text-align:center}
541
+
542
+ /* ═══ 可搜索多选/单选字段(multiSelectField / singleSelectField) ═══ */
543
+ .msel{position:relative;border:1px solid var(--border2);border-radius:var(--r-s);background:var(--field);padding:2px 10px;transition:border-color .15s,box-shadow .15s}
544
+ .msel:focus-within{border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-ring)}
545
+ .msel-chips{margin:4px 0}
546
+ .msel-chips:empty{display:none}
547
+ .msel .msel-input{border:0;background:none;box-shadow:none;width:100%;padding:6px 2px;font-size:13px}
548
+ .msel .msel-input:focus{border:0;box-shadow:none}
549
+ .combo{position:relative}
550
+ .combo-panel,.msel .combo-panel{
551
+ position:absolute;left:-1px;right:-1px;top:calc(100% + 5px);
552
+ background:var(--card);border:1px solid var(--border2);border-radius:10px;
553
+ box-shadow:var(--shadow-2);max-height:280px;overflow-y:auto;z-index:40;
554
+ }
555
+ .combo-panel[hidden]{display:none}
556
+ .combo-item{padding:8px 12px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .12s}
557
+ .combo-item:last-child{border-bottom:0}
558
+ .combo-item:hover{background:var(--pri-w)}
559
+ .combo-item.active{background:var(--pri-w)}
560
+ .combo-item b{margin-right:6px}
561
+ .combo-empty{padding:12px;color:var(--mut);font-size:12.5px}
562
+ .msel-check{float:right;color:var(--pri);font-weight:650}
563
+
564
+ /* ═══ 目录选择弹层(pickDirectory,文件管理器风格) ═══ */
565
+ .modal.dp{width:min(680px,94vw)}
566
+ .dp-head{display:flex;align-items:center;gap:12px;margin-bottom:12px}
567
+ .dp-head b{font-size:15px;flex:0 0 auto}
568
+ .dp-path{flex:1;min-width:0;text-align:left;color:var(--mut);font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
569
+ .dp-toolbar{display:flex;gap:8px;margin-bottom:10px}
570
+ .dp-toolbar input{flex:1;min-width:0}
571
+ .dp-toolbar .btn{flex:0 0 auto}
572
+ .dp-grid{
573
+ display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:6px;
574
+ max-height:52vh;overflow-y:auto;padding:10px;
575
+ border:1px solid var(--border);border-radius:10px;background:var(--sunk);
576
+ }
577
+ .dp-item{
578
+ display:flex;align-items:center;gap:8px;min-width:0;
579
+ padding:8px 10px;border:1px solid transparent;border-radius:8px;
580
+ background:var(--card);color:var(--ink);cursor:pointer;font:inherit;font-size:13px;text-align:left;
581
+ transition:border-color .12s,color .12s;
582
+ }
583
+ .dp-item svg{flex:0 0 auto;color:var(--warn)}
584
+ .dp-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
585
+ .dp-item:hover{border-color:var(--pri);color:var(--pri)}
586
+ .dp-empty{padding:22px 12px;color:var(--mut);font-size:12.5px;text-align:center;grid-column:1/-1}
587
+ .dp-foot{display:flex;align-items:center;gap:10px;margin-top:12px}
588
+ /* 会话页 AI 气泡:Markdown 渲染后的内容块间距(p/pre 等自带 inline style)与原文纯文本 */
589
+ .m-bubble .m-raw{white-space:pre-wrap}
590
+ .m-bubble pre{max-width:100%;overflow-x:auto}
591
+
592
+ /* ═══ 厂商档案卡(加宽版网格) ═══ */
593
+ .cardgrid.wide{grid-template-columns:repeat(auto-fill,minmax(420px,1fr))}
594
+ @media (max-width:960px){.cardgrid.wide{grid-template-columns:1fr}}
595
+ /* 档案单选小卡(生效配置 Tab) */
596
+ .pfcards{display:flex;flex-wrap:wrap;gap:10px}
597
+ .pfcard{
598
+ border:1px solid var(--border2);border-radius:10px;padding:10px 14px;cursor:pointer;
599
+ background:var(--field);min-width:180px;transition:border-color .15s,background .15s;
600
+ }
601
+ .pfcard:hover{border-color:var(--pri)}
602
+ .pfcard.on{border-color:var(--pri);background:var(--pri-w);box-shadow:0 0 0 3px var(--pri-ring)}
603
+ .pfcard b{font-size:13px;display:flex;align-items:center;gap:7px}
604
+ .pfcard .hint{margin-top:3px;font-size:11.5px}
605
+
606
+ /* ═══ 工作区卡片列表 ═══ */
607
+ .ws-list{display:flex;flex-direction:column}
608
+ .ws-item{
609
+ display:flex;align-items:center;gap:13px;padding:12px 4px;
610
+ border-bottom:1px solid var(--border);
611
+ }
612
+ .ws-item:last-child{border-bottom:0}
613
+ .ws-item .ws-ico{
614
+ width:36px;height:36px;border-radius:10px;flex:0 0 auto;
615
+ display:inline-flex;align-items:center;justify-content:center;
616
+ background:var(--warn-bg);color:var(--warn);
617
+ }
618
+ .ws-item .ws-main{flex:1;min-width:120px}
619
+ .ws-item .ws-name{font-size:13.5px;font-weight:600;display:flex;align-items:center;gap:8px}
620
+ .ws-item .ws-path{color:var(--mut);font-size:11.5px;font-family:var(--mono);margin-top:2px;word-break:break-all}
621
+ .ws-item .ws-ops{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
622
+ /* 选目录弹窗内已选路径卡 */
623
+ .picked-path{
624
+ display:flex;align-items:center;gap:11px;border:1px solid var(--border);
625
+ border-radius:10px;padding:11px 14px;background:var(--sunk);
626
+ }
627
+ .picked-path .ws-ico{width:32px;height:32px;border-radius:9px}
628
+ .picked-path b{font-size:13px}
629
+ .picked-path .hint{font-size:11.5px;color:var(--mut)}
630
+
631
+ /* ═══ 会话页(查询条件 + 会话列表 + 消息流) ═══ */
632
+ .chats-layout{display:grid;grid-template-columns:290px minmax(0,1fr);gap:14px;align-items:start}
633
+ @media (max-width:1080px){.chats-layout{grid-template-columns:1fr}}
634
+ .chat-list-panel{padding:0!important}
635
+ /* 消息流固定高度滚动(主人反馈 #4c:不随内容无限拉高) */
636
+ .chats-scroll{max-height:calc(100vh - 330px);overflow-y:auto;padding:2px 6px 2px 2px}
637
+ /* 任务块(关键词定位的锚点):默认透明,命中高亮时描边 */
638
+ .chat-task{padding:4px 6px;border-radius:10px;transition:background .15s}
639
+ .chat-task.kw-active{background:var(--pri-w);outline:1.5px solid var(--pri)}
640
+ mark.kw-mark{background:var(--warn-bg);color:var(--warn-tx);border-radius:3px;padding:0 2px}
641
+ .chat-obj{
642
+ display:flex;gap:10px;padding:11px 14px;cursor:pointer;
643
+ border-bottom:1px solid var(--border);transition:background .12s;align-items:flex-start;
644
+ }
645
+ .chat-obj:last-child{border-bottom:0}
646
+ .chat-obj:hover{background:rgba(127,140,170,.06)}
647
+ .chat-obj.active{background:var(--pri-w)}
648
+ .chat-obj .c-ava{
649
+ width:34px;height:34px;border-radius:9px;flex:0 0 auto;
650
+ display:inline-flex;align-items:center;justify-content:center;
651
+ background:var(--pri-w);color:var(--pri);font-size:12.5px;font-weight:650;
652
+ }
653
+ .chat-obj .c-main{flex:1;min-width:0}
654
+ .chat-obj .c-top{display:flex;align-items:center;gap:6px}
655
+ .chat-obj .c-name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
656
+ .chat-obj .c-time{margin-left:auto;color:var(--faint);font-size:11px;flex:0 0 auto}
657
+ .chat-obj .c-prev{color:var(--mut);font-size:11.5px;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
658
+ .chat-obj .c-topic{font-size:12px;font-weight:600;color:var(--ink);margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
659
+ .chat-obj .c-badges{display:flex;gap:5px;margin-top:4px;align-items:center}
660
+ .cmsg-day{display:flex;align-items:center;gap:12px;color:var(--faint);font-size:11.5px;margin:16px 0 10px}
661
+ .cmsg-day::before,.cmsg-day::after{content:'';flex:1;border-top:1px solid var(--border)}
662
+ .cmsg{display:flex;margin:8px 0;gap:9px}
663
+ .cmsg .m-ava{
664
+ width:28px;height:28px;border-radius:8px;flex:0 0 auto;margin-top:2px;
665
+ display:inline-flex;align-items:center;justify-content:center;
666
+ background:var(--off-bg);color:var(--mut);font-size:11px;font-weight:650;
667
+ }
668
+ .cmsg .m-body{max-width:min(76%,740px)}
669
+ .cmsg .m-meta{font-size:11px;color:var(--faint);margin-bottom:3px;display:flex;gap:8px;align-items:center}
670
+ .cmsg .m-bubble{
671
+ background:var(--card);border:1px solid var(--border);border-radius:11px;
672
+ padding:8px 13px;font-size:13px;line-height:1.7;word-break:break-word;
673
+ }
674
+ .cmsg.me{flex-direction:row-reverse}
675
+ .cmsg.me .m-body{display:flex;flex-direction:column;align-items:flex-end}
676
+ .cmsg.me .m-bubble{background:var(--pri-w);border-color:transparent}
677
+ .cmsg .m-link{font-size:11.5px;margin-top:4px}
678
+ .cmsg .m-full{margin-top:6px;font-size:12.5px;color:var(--mut);background:var(--sunk);border:1px dashed var(--border2);border-radius:9px;padding:9px 12px;line-height:1.7;white-space:pre-wrap}
679
+ .cmsg .m-full[hidden]{display:none}
680
+ .csum{
681
+ border:1px solid var(--border);border-radius:11px;background:var(--card);
682
+ padding:11px 14px;margin:10px 0 10px 37px;max-width:min(76%,640px);
683
+ }
684
+ .csum-top{display:flex;align-items:center;gap:8px}
685
+ .csum-top b{font-size:13px}
686
+ .csum-top .tag{margin-left:auto}
687
+ .csum-stats{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:8px;font-size:12px;color:var(--mut)}
688
+ .csum-stats b{color:var(--ink);font-variant-numeric:tabular-nums}
689
+
690
+ /* ═══ 设置 / 密码锁屏 ═══ */
691
+ .lockmask{
692
+ position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;
693
+ background:rgba(13,17,26,.55);
694
+ -webkit-backdrop-filter:blur(18px) saturate(1.2);backdrop-filter:blur(18px) saturate(1.2);
695
+ animation:fadein .18s ease;
696
+ }
697
+ .lockmask[hidden]{display:none}
698
+ .lockcard{
699
+ width:min(360px,92vw);background:var(--card);border:1px solid var(--border);
700
+ border-radius:18px;box-shadow:var(--shadow-2);padding:30px 28px 24px;text-align:center;
701
+ animation:pop .18s cubic-bezier(.22,.8,.36,1);
702
+ }
703
+ .lockcard .lock-logo{
704
+ width:46px;height:46px;border-radius:13px;margin:0 auto 14px;
705
+ display:inline-flex;align-items:center;justify-content:center;
706
+ background:linear-gradient(135deg,#3370ff,#7c5bff 130%);color:#fff;
707
+ box-shadow:0 4px 14px rgba(51,112,255,.35);
708
+ }
709
+ .lockcard h3{font-size:16px}
710
+ .lockcard .lock-sub{color:var(--mut);font-size:12.5px;margin:5px 0 18px}
711
+ .lockcard input{margin-bottom:10px;text-align:center;letter-spacing:.2em}
712
+ .lock-err{color:var(--err-tx);font-size:12px;min-height:18px;margin-bottom:6px}
713
+ .lock-tip{color:var(--faint);font-size:11px;margin-top:12px;line-height:1.7}
714
+ @keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-7px)}75%{transform:translateX(7px)}}
715
+ .shake{animation:shake .28s ease}
716
+
717
+ /* ═══ User row(记忆用户 / 机器人行) ═══ */
718
+ .urow{display:flex;align-items:center;gap:12px;padding:11px 0;border-bottom:1px solid var(--border);flex-wrap:wrap}
719
+ .urow:last-child{border-bottom:0}
720
+ .urow .u-ava{
721
+ width:32px;height:32px;border-radius:9px;flex:0 0 auto;
722
+ display:inline-flex;align-items:center;justify-content:center;
723
+ background:var(--pri-w);color:var(--pri);font-size:13px;font-weight:650;
724
+ }
725
+ .urow .u-main{flex:1;min-width:180px}
726
+ .urow .u-name{font-size:13px;font-weight:600;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
727
+ .urow .u-sub{color:var(--mut);font-size:11.5px;margin-top:1px}
728
+ .urow .u-ops{display:flex;gap:6px;flex-wrap:wrap}
729
+
730
+ /* ═══ 现有组件保留区(进度 / 二维码 / 运行遮罩) ═══ */
731
+ .prog{height:8px;border-radius:999px;background:var(--off-bg);border:1px solid var(--border);overflow:hidden;margin-top:12px}
732
+ .prog-bar{height:100%;width:0%;background:linear-gradient(90deg,var(--pri),var(--pri-h));border-radius:999px;transition:width .3s}
733
+ .prog-bar.done{background:var(--ok)}
734
+ pre.report{background:var(--field);border:1px solid var(--border);border-radius:var(--r-s);padding:12px 14px;font-size:12px;overflow:auto;white-space:pre-wrap;margin:0}
735
+ .br-spin,.br-spin-sm{border-radius:50%;border-style:solid;border-color:var(--spin-track);border-top-color:var(--pri);animation:brspin .9s linear infinite}
736
+ .br-spin{width:26px;height:26px;margin:0 auto 12px;border-width:3px}
737
+ .br-spin-sm{width:18px;height:18px;margin:0 auto 10px;border-width:2px}
738
+ @keyframes brspin{to{transform:rotate(360deg)}}
739
+ /* 扫码授权二维码:固定白底(lark-cli 生成的 PNG 本身白底黑码,主题跟随会在暗色下露边) */
740
+ .qr-box{
741
+ display:flex;justify-content:center;align-items:center;
742
+ margin-top:12px;padding:12px;background:#fff;
743
+ border:1px solid var(--border);border-radius:12px;color-scheme:light;
744
+ }
745
+ .qr-box img{display:block;width:220px;height:220px}
746
+ .qr-url{margin-top:8px;line-height:1.6;word-break:break-all;user-select:all}
747
+
748
+ /* ═══ Responsive ═══ */
749
+ @media (max-width:900px){
750
+ .layout{flex-direction:column}
751
+ .sidenav{
752
+ width:auto;max-height:none;position:sticky;top:54px;z-index:20;
753
+ display:flex;gap:4px;overflow-x:auto;padding:8px 12px;
754
+ background:var(--header-bg);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
755
+ border-bottom:1px solid var(--border);
756
+ }
757
+ .nav-search{display:none}
758
+ .nav-group{display:contents}
759
+ .nav-group-label{display:none}
760
+ .nav-item{width:auto;flex:0 0 auto;padding:6px 12px}
761
+ main{padding:16px 16px 90px}
762
+ .page-head .page-actions{margin-left:0;width:100%}
763
+ }
764
+ @media (prefers-reduced-motion:reduce){
765
+ *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
766
+ }