skillcaddy 0.27.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 (99) hide show
  1. package/CHANGELOG.md +497 -0
  2. package/CONTEXT.md +149 -0
  3. package/LICENSE +21 -0
  4. package/README.md +499 -0
  5. package/README_CN.md +482 -0
  6. package/collection-metadata/github/mattpocock.json +16 -0
  7. package/lib/canonicalJson.js +11 -0
  8. package/lib/claudeStore.js +135 -0
  9. package/lib/collectionEnablement.js +115 -0
  10. package/lib/collectionSetup.js +199 -0
  11. package/lib/enablePlan.js +116 -0
  12. package/lib/enablementScope.js +8 -0
  13. package/lib/hermesStore.js +21 -0
  14. package/lib/libraryImage.js +1785 -0
  15. package/lib/managerInstall.js +109 -0
  16. package/lib/managerSourceWorkflow.js +234 -0
  17. package/lib/projectActions.js +24 -0
  18. package/lib/projectPath.js +51 -0
  19. package/lib/roots.js +99 -0
  20. package/lib/skillLinkStore.js +68 -0
  21. package/lib/skillMetadata.js +191 -0
  22. package/lib/skillStore.js +541 -0
  23. package/lib/sourceAcquisition.js +475 -0
  24. package/lib/sourceAcquisitionAdapter.js +47 -0
  25. package/lib/sourceAcquisitionError.js +18 -0
  26. package/lib/sourceAcquisitionPolicy.js +139 -0
  27. package/lib/sourceArchive.js +363 -0
  28. package/lib/sourceArchiveWorkspace.js +36 -0
  29. package/lib/sourceGit.js +95 -0
  30. package/lib/sourceGitAcquisitionAdapter.js +145 -0
  31. package/lib/sourceGitBatchUpdate.js +168 -0
  32. package/lib/sourceGitRepair.js +227 -0
  33. package/lib/sourceGitStaging.js +139 -0
  34. package/lib/sourceGitUpgradeAdapter.js +583 -0
  35. package/lib/sourceGitUrl.js +170 -0
  36. package/lib/sourceHttp.js +302 -0
  37. package/lib/sourceLocal.js +200 -0
  38. package/lib/sourceLocalAcquisitionAdapter.js +107 -0
  39. package/lib/sourceManager.js +242 -0
  40. package/lib/sourceMigration.js +172 -0
  41. package/lib/sourceMigrationIssue.js +6 -0
  42. package/lib/sourcePath.js +6 -0
  43. package/lib/sourcePolicy.js +53 -0
  44. package/lib/sourceRecord.js +295 -0
  45. package/lib/sourceRegistry.js +155 -0
  46. package/lib/sourceRemoteArchiveAcquisitionAdapter.js +147 -0
  47. package/lib/sourceRemoteFileAcquisitionAdapter.js +95 -0
  48. package/lib/sourceRemoteFilePolicy.js +62 -0
  49. package/lib/sourceRemoteFileWorkspace.js +55 -0
  50. package/lib/sourceSkillDiscovery.js +117 -0
  51. package/lib/sourceTree.js +185 -0
  52. package/lib/sourceUpgrade.js +596 -0
  53. package/lib/sourceUpgradeAdapter.js +41 -0
  54. package/lib/sourceUpgradePolicy.js +170 -0
  55. package/lib/sourceUpgradeTransaction.js +202 -0
  56. package/lib/sourceValidation.js +120 -0
  57. package/lib/sourceWorkspace.js +37 -0
  58. package/lib/specGate.js +235 -0
  59. package/lib/tuiActions.js +169 -0
  60. package/lib/tuiInstall.js +133 -0
  61. package/lib/tuiLayout.js +94 -0
  62. package/lib/version.js +17 -0
  63. package/lib/webManager.js +370 -0
  64. package/package.json +74 -0
  65. package/public/agentsUi.js +138 -0
  66. package/public/app.js +1431 -0
  67. package/public/claude.css +2 -0
  68. package/public/claudeUi.js +119 -0
  69. package/public/emptyState.js +12 -0
  70. package/public/enabled.css +303 -0
  71. package/public/favicon.svg +5 -0
  72. package/public/index.html +199 -0
  73. package/public/skillcaddy_CN.png +0 -0
  74. package/public/skillcaddy_EN.png +0 -0
  75. package/public/styles.css +1611 -0
  76. package/scripts/cli.js +647 -0
  77. package/scripts/cron-sync-update-git.sh +128 -0
  78. package/scripts/pull-github.sh +22 -0
  79. package/scripts/source.js +638 -0
  80. package/scripts/tui.js +1058 -0
  81. package/server.js +196 -0
  82. package/skills/skillcaddy-manager/SKILL.md +93 -0
  83. package/skills/skillcaddy-manager/agents/openai.yaml +7 -0
  84. package/skills/skillcaddy-manager/references/METADATA.md +75 -0
  85. package/skills/skillcaddy-manager/references/OPERATIONS.md +315 -0
  86. package/skills/skillcaddy-manager/references/RECOMMENDATION_GUIDE.md +51 -0
  87. package/skills/skillcaddy-manager/references/featured-skills.json +564 -0
  88. package/skills/skillcaddy-manager/references/skill-platforms.json +48 -0
  89. package/skills/skillcaddy-manager/scripts/check-conflicts.cjs +117 -0
  90. package/skills/skillcaddy-manager/scripts/check-global-skills.cjs +169 -0
  91. package/skills/skillcaddy-manager/scripts/translate-skill-notes.cjs +297 -0
  92. package/skills/skillcaddy-manager/scripts/version-manager.cjs +146 -0
  93. package/skills/skillcaddy-manager/scripts/view-recommendations.cjs +279 -0
  94. package/skills/skillcaddy-manager/skillcaddy.json +9 -0
  95. package/skills/spec-pipeline/spec-direction-gate/SKILL.md +119 -0
  96. package/skills/spec-pipeline/spec-direction-gate/check-approval.py +110 -0
  97. package/skills/spec-pipeline/spec-draft-intake/SKILL.md +116 -0
  98. package/skills/spec-pipeline/spec-role-contract/SKILL.md +113 -0
  99. package/skills/spec-pipeline/spec-role-contract/check-roles.py +108 -0
@@ -0,0 +1,1611 @@
1
+ :root {
2
+ color-scheme: light;
3
+ /* 从 public/skillcaddy_CN.png 与 public/skillcaddy_EN.png 的书包图标、字标取样。
4
+ 主蓝负责品牌与行动,深海军蓝承载文字和工作台,暖橙/柔绿只做语义强调。 */
5
+ --brand-blue: #2f70fd;
6
+ --brand-blue-strong: #155df9;
7
+ --brand-blue-active: #0a4ffb;
8
+ --brand-navy: #08122c;
9
+ --brand-blue-wash: #eaf2ff;
10
+ --primary: var(--brand-blue);
11
+ /* 主按钮/正文蓝:白字 5.30:1,canvas 上作文本 5.06:1。 */
12
+ --primary-strong: var(--brand-blue-strong);
13
+ /* hover/active:白字 5.96:1。 */
14
+ --primary-active: var(--brand-blue-active);
15
+ --primary-disabled: var(--brand-blue-wash);
16
+ --ink: var(--brand-navy);
17
+ --body: #3e485c;
18
+ --body-strong: #12243d;
19
+ --muted: #5f687a;
20
+ /* 次要文字:三处底色(surface-soft/surface-card/canvas)都 ≥4.63:1(WCAG AA)。 */
21
+ --muted-soft: #5d6c83;
22
+ --hairline: #d2deed;
23
+ --hairline-soft: #e3edf9;
24
+ --canvas: #f7fafe;
25
+ --surface-soft: #eef5fd;
26
+ --surface-card: #e6f0fd;
27
+ --surface-dark: var(--brand-navy);
28
+ --surface-dark-elevated: #12243d;
29
+ --surface-dark-soft: #0a152b;
30
+ --on-primary: #ffffff;
31
+ --on-dark: #f8fafd;
32
+ --on-dark-soft: #b6caea;
33
+ --accent-green: #94bbaa;
34
+ --accent-amber: #f18744;
35
+ --success: #2a7a5a;
36
+ /* warning 只在 advice 徽标上成对使用:暖色背景配深色文字。 */
37
+ --warning-surface: #fff0e4;
38
+ --warning-ink: #8a4a1f;
39
+ --error: #c64545;
40
+ /* 深色 toast 上的错误文本:#c64545 压深底只有 ~2.5:1,需提亮到 8.7:1。 */
41
+ --error-on-dark: #f2a6a6;
42
+ --scroll-thumb: #a9bddb;
43
+ --selection: #ccddff;
44
+ --shadow-toast: 0 8px 24px rgba(8, 18, 44, 0.24);
45
+ --scope-agents-surface: #edf4ff;
46
+ --scope-agents-line: #c8daf7;
47
+ --scope-agents-ink: #245bb6;
48
+ --scope-claude-surface: #fff2e8;
49
+ --scope-claude-line: #f0d2bc;
50
+ --scope-claude-ink: #945124;
51
+ --scope-global-surface: #f1f4f8;
52
+ --scope-global-line: #d4dce7;
53
+ --scope-global-ink: #42536c;
54
+ --scope-hermes-surface: #fff8df;
55
+ --scope-hermes-line: #eadba4;
56
+ --scope-hermes-ink: #78601b;
57
+ --radius-md: 8px;
58
+ --radius-lg: 12px;
59
+ --radius-xl: 16px;
60
+ /* 三个字族全部自带兜底:本地工具需离线可用,不引入网络字体依赖。 */
61
+ --display: Georgia, "Times New Roman", "Songti SC", serif;
62
+ --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif;
63
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
64
+ }
65
+
66
+ @media (prefers-color-scheme: dark) {
67
+ :root {
68
+ color-scheme: dark;
69
+ --primary: #78a6ff;
70
+ --primary-strong: #4f86f7;
71
+ --primary-active: #6f9fff;
72
+ --primary-disabled: #24324a;
73
+ --ink: #f5f8ff;
74
+ --body: #c9d3e3;
75
+ --body-strong: #eef4ff;
76
+ --muted: #aebbd0;
77
+ --muted-soft: #a9b8ce;
78
+ --hairline: #33425a;
79
+ --hairline-soft: #26364e;
80
+ --canvas: #0b1322;
81
+ --surface-soft: #111d30;
82
+ --surface-card: #182843;
83
+ --surface-dark: #050a15;
84
+ --surface-dark-elevated: #182943;
85
+ --surface-dark-soft: #091426;
86
+ --on-primary: #08122c;
87
+ --on-dark: #f8fafd;
88
+ --on-dark-soft: #b9c9e3;
89
+ --accent-green: #77b99f;
90
+ --accent-amber: #f0a06a;
91
+ --success: #75d1aa;
92
+ --warning-surface: #3b291f;
93
+ --warning-ink: #ffc79d;
94
+ --error: #d95768;
95
+ --error-on-dark: #ffb4bd;
96
+ --scroll-thumb: #5d7190;
97
+ --selection: #284d88;
98
+ --shadow-toast: 0 12px 32px rgba(0, 0, 0, 0.42);
99
+ --scope-agents-surface: #13243d;
100
+ --scope-agents-line: #2e4f7b;
101
+ --scope-agents-ink: #9cc0ff;
102
+ --scope-claude-surface: #2b211d;
103
+ --scope-claude-line: #624332;
104
+ --scope-claude-ink: #ffc69f;
105
+ --scope-global-surface: #171f2c;
106
+ --scope-global-line: #354154;
107
+ --scope-global-ink: #c3cfe0;
108
+ --scope-hermes-surface: #282519;
109
+ --scope-hermes-line: #5b512b;
110
+ --scope-hermes-ink: #f1d875;
111
+ }
112
+ }
113
+
114
+ * { box-sizing: border-box; }
115
+
116
+ html {
117
+ scrollbar-color: var(--scroll-thumb) var(--canvas);
118
+ scrollbar-width: thin;
119
+ }
120
+
121
+ ::selection {
122
+ background: var(--selection);
123
+ color: var(--ink);
124
+ }
125
+
126
+ ::-webkit-scrollbar {
127
+ width: 10px;
128
+ height: 10px;
129
+ }
130
+
131
+ ::-webkit-scrollbar-track {
132
+ background: var(--canvas);
133
+ }
134
+
135
+ ::-webkit-scrollbar-thumb {
136
+ border: 2px solid var(--canvas);
137
+ border-radius: 999px;
138
+ background: var(--scroll-thumb);
139
+ }
140
+
141
+ body {
142
+ margin: 0;
143
+ min-height: 100vh;
144
+ background: var(--canvas);
145
+ color: var(--ink);
146
+ font-family: var(--sans);
147
+ }
148
+
149
+ button,
150
+ input,
151
+ select,
152
+ textarea {
153
+ font: inherit;
154
+ }
155
+
156
+ input,
157
+ textarea {
158
+ caret-color: var(--primary-strong);
159
+ }
160
+
161
+ .shell {
162
+ width: min(1200px, calc(100vw - 32px));
163
+ margin: 0 auto;
164
+ padding: 24px 0 40px;
165
+ }
166
+
167
+ .topbar {
168
+ display: flex;
169
+ min-height: 64px;
170
+ align-items: center;
171
+ justify-content: space-between;
172
+ gap: 24px;
173
+ border-bottom: 1px solid var(--hairline);
174
+ }
175
+
176
+ .brand,
177
+ .topbar-actions,
178
+ .actions,
179
+ .scope-action-group {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 8px;
183
+ }
184
+
185
+ /* Topbar 的 Hermes 开关:和版本号同一行、视觉密度与 chip 一致。
186
+ 关闭时整个已启用面板的 Hermes 段、库分组里的 Hermes 按钮会同步消失。 */
187
+ .topbar-toggle {
188
+ display: inline-flex;
189
+ align-items: center;
190
+ gap: 8px;
191
+ min-height: 36px;
192
+ padding: 4px 12px 4px 8px;
193
+ border: 1px solid var(--hairline);
194
+ border-radius: 999px;
195
+ background: var(--canvas);
196
+ color: var(--muted);
197
+ font: 500 13px/1 var(--sans);
198
+ cursor: pointer;
199
+ user-select: none;
200
+ white-space: nowrap;
201
+ }
202
+
203
+ .topbar-toggle:hover {
204
+ background: var(--surface-card);
205
+ color: var(--ink);
206
+ }
207
+
208
+ .topbar-toggle input {
209
+ position: absolute;
210
+ width: 1px;
211
+ height: 1px;
212
+ margin: -1px;
213
+ padding: 0;
214
+ overflow: hidden;
215
+ clip: rect(0 0 0 0);
216
+ white-space: nowrap;
217
+ border: 0;
218
+ }
219
+
220
+ .topbar-toggle-track {
221
+ position: relative;
222
+ flex: 0 0 auto;
223
+ width: 30px;
224
+ height: 18px;
225
+ border-radius: 999px;
226
+ background: var(--surface-card);
227
+ transition: background-color 140ms ease;
228
+ }
229
+
230
+ .topbar-toggle > span {
231
+ display: block;
232
+ margin: 0;
233
+ }
234
+
235
+ .topbar-toggle-track::after {
236
+ position: absolute;
237
+ top: 2px;
238
+ left: 2px;
239
+ width: 14px;
240
+ height: 14px;
241
+ border-radius: 999px;
242
+ background: var(--canvas);
243
+ box-shadow: 0 1px 2px rgba(8, 18, 44, 0.18);
244
+ content: "";
245
+ transition: transform 140ms ease;
246
+ }
247
+
248
+ .topbar-toggle input:checked ~ .topbar-toggle-track {
249
+ background: var(--primary-strong);
250
+ }
251
+
252
+ .topbar-toggle input:checked ~ .topbar-toggle-track::after {
253
+ transform: translateX(12px);
254
+ }
255
+
256
+ .topbar-toggle input:focus-visible ~ .topbar-toggle-track {
257
+ outline: 2px solid var(--primary-strong);
258
+ outline-offset: 2px;
259
+ }
260
+
261
+ .topbar-toggle:has(input:checked) {
262
+ color: var(--ink);
263
+ border-color: var(--primary-wash, var(--primary-strong));
264
+ }
265
+
266
+ .topbar-link {
267
+ display: inline-flex;
268
+ min-height: 36px;
269
+ align-items: center;
270
+ gap: 6px;
271
+ border: 1px solid var(--hairline);
272
+ border-radius: 999px;
273
+ background: var(--canvas);
274
+ color: var(--muted);
275
+ padding: 0 10px;
276
+ font: 500 13px/1 var(--sans);
277
+ text-decoration: none;
278
+ white-space: nowrap;
279
+ }
280
+
281
+ .topbar-link:hover {
282
+ background: var(--surface-card);
283
+ color: var(--ink);
284
+ }
285
+
286
+ .topbar-link:focus-visible {
287
+ outline: 2px solid var(--primary-strong);
288
+ outline-offset: 2px;
289
+ }
290
+
291
+ .github-icon {
292
+ width: 16px;
293
+ height: 16px;
294
+ flex: 0 0 16px;
295
+ }
296
+
297
+ @media (prefers-reduced-motion: reduce) {
298
+ .topbar-toggle-track,
299
+ .topbar-toggle-track::after {
300
+ transition: none;
301
+ }
302
+ }
303
+
304
+ /* Hermes 开关关闭:整段已启用面板的 Hermes 段 + 库分组里的 Hermes 操作全部折叠。
305
+ JS 端会同步停止拉取 hermes 列表渲染,但这里仍要兜底,避免任何旁路渲染时露馅。 */
306
+ body.hermes-hidden [data-hermes-section],
307
+ body.hermes-hidden .hermes-scope-actions,
308
+ body.hermes-hidden .skill-hermes-action,
309
+ body.hermes-hidden [data-focus-scope="hermes"] {
310
+ display: none !important;
311
+ }
312
+
313
+ .brand {
314
+ color: var(--ink);
315
+ font-size: 18px;
316
+ font-weight: 500;
317
+ }
318
+
319
+ .brand-mark {
320
+ position: relative;
321
+ width: 18px;
322
+ height: 18px;
323
+ flex: 0 0 18px;
324
+ }
325
+
326
+ .brand-mark::before,
327
+ .brand-mark::after {
328
+ position: absolute;
329
+ top: 50%;
330
+ left: 50%;
331
+ width: 18px;
332
+ height: 2px;
333
+ border-radius: 999px;
334
+ background: var(--brand-blue-strong);
335
+ content: "";
336
+ transform: translate(-50%, -50%);
337
+ }
338
+
339
+ .brand-mark::after { transform: translate(-50%, -50%) rotate(90deg); }
340
+
341
+ .hero {
342
+ display: grid;
343
+ grid-template-columns: minmax(0, 1fr) minmax(340px, 480px);
344
+ gap: 48px;
345
+ align-items: center;
346
+ padding: 80px 0 48px;
347
+ }
348
+
349
+ .hero-copy {
350
+ max-width: 650px;
351
+ }
352
+
353
+ h1,
354
+ h2,
355
+ h3,
356
+ p {
357
+ margin-top: 0;
358
+ }
359
+
360
+ h1,
361
+ h2,
362
+ h3 {
363
+ color: var(--ink);
364
+ }
365
+
366
+ h1 {
367
+ margin-bottom: 22px;
368
+ font-family: var(--display);
369
+ font-size: clamp(40px, 6vw, 64px);
370
+ font-weight: 500;
371
+ letter-spacing: -0.02em;
372
+ line-height: 1.05;
373
+ }
374
+
375
+ h2 {
376
+ margin-bottom: 0;
377
+ font-size: 22px;
378
+ font-weight: 500;
379
+ letter-spacing: 0;
380
+ line-height: 1.3;
381
+ }
382
+
383
+ h3 {
384
+ margin-bottom: 0;
385
+ font-size: 18px;
386
+ font-weight: 500;
387
+ line-height: 1.35;
388
+ }
389
+
390
+ .lede {
391
+ max-width: 590px;
392
+ margin-bottom: 0;
393
+ color: var(--body);
394
+ font-size: 18px;
395
+ line-height: 1.55;
396
+ }
397
+
398
+ .product-surface {
399
+ overflow: hidden;
400
+ border-radius: var(--radius-xl);
401
+ background: var(--surface-dark);
402
+ color: var(--on-dark);
403
+ padding: 24px;
404
+ }
405
+
406
+ .surface-header {
407
+ display: flex;
408
+ align-items: center;
409
+ gap: 8px;
410
+ margin-bottom: 24px;
411
+ color: var(--on-dark-soft);
412
+ font: 13px/1.4 var(--mono);
413
+ }
414
+
415
+ .surface-header span {
416
+ width: 10px;
417
+ height: 10px;
418
+ border-radius: 999px;
419
+ background: var(--primary);
420
+ }
421
+
422
+ .surface-header span:nth-child(2) { background: var(--accent-amber); }
423
+ .surface-header span:nth-child(3) { background: var(--accent-green); }
424
+ .surface-header strong { margin-left: auto; font-weight: 400; }
425
+
426
+ .surface-grid {
427
+ display: grid;
428
+ grid-template-columns: repeat(3, minmax(0, 1fr));
429
+ gap: 1px;
430
+ overflow: hidden;
431
+ border: 1px solid var(--surface-dark-elevated);
432
+ border-radius: var(--radius-lg);
433
+ background: var(--surface-dark-elevated);
434
+ }
435
+
436
+ .surface-grid div {
437
+ min-width: 0;
438
+ background: var(--surface-dark-soft);
439
+ padding: 18px 14px;
440
+ }
441
+
442
+ .surface-grid span,
443
+ .surface-path {
444
+ display: block;
445
+ color: var(--on-dark-soft);
446
+ font: 12px/1.45 var(--mono);
447
+ }
448
+
449
+ .surface-grid strong {
450
+ display: block;
451
+ margin-top: 8px;
452
+ overflow: hidden;
453
+ color: var(--on-dark);
454
+ font-family: var(--display);
455
+ font-size: 34px;
456
+ font-weight: 500;
457
+ font-variant-numeric: tabular-nums;
458
+ letter-spacing: -0.02em;
459
+ line-height: 1;
460
+ text-overflow: ellipsis;
461
+ white-space: nowrap;
462
+ }
463
+
464
+ .surface-path {
465
+ margin: 20px 0 0;
466
+ overflow-wrap: anywhere;
467
+ }
468
+
469
+ /* 老用户(有项目历史或 URL 带 projectPath)不需要每天读一遍产品说服文案:
470
+ hero 坍缩成一条状态带,工作区回到首屏。完整 hero 只留给首次访客。 */
471
+ .hero.is-compact {
472
+ display: block;
473
+ padding: 20px 0 24px;
474
+ }
475
+
476
+ .hero.is-compact .hero-copy {
477
+ display: none;
478
+ }
479
+
480
+ .hero.is-compact .product-surface {
481
+ display: flex;
482
+ flex-wrap: wrap;
483
+ align-items: center;
484
+ gap: 10px 20px;
485
+ padding: 12px 16px;
486
+ border-radius: var(--radius-lg);
487
+ }
488
+
489
+ .hero.is-compact .surface-header {
490
+ margin: 0;
491
+ flex: 0 0 auto;
492
+ }
493
+
494
+ .hero.is-compact .surface-grid {
495
+ display: flex;
496
+ gap: 16px;
497
+ overflow: visible;
498
+ border: 0;
499
+ border-radius: 0;
500
+ background: transparent;
501
+ }
502
+
503
+ .hero.is-compact .surface-grid div {
504
+ display: flex;
505
+ align-items: baseline;
506
+ gap: 6px;
507
+ padding: 0;
508
+ background: transparent;
509
+ }
510
+
511
+ .hero.is-compact .surface-grid strong {
512
+ margin: 0;
513
+ font-family: var(--mono);
514
+ font-size: 15px;
515
+ letter-spacing: 0;
516
+ }
517
+
518
+ .hero.is-compact .surface-path {
519
+ flex: 1 1 220px;
520
+ min-width: 0;
521
+ margin: 0;
522
+ text-align: right;
523
+ }
524
+
525
+ .advice-list {
526
+ /* 此前的 .advice-list 走横向铺开的内联列表;现在 advice 收缩为 📢 触发的 popover,
527
+ 容器本身的边距/边框由 .advice-popover 提供。:empty 仍要 display:none 兜底渲染前的空状态。 */
528
+ display: grid;
529
+ gap: 8px;
530
+ margin: 0;
531
+ padding: 0;
532
+ }
533
+
534
+ .advice-list:empty {
535
+ display: none;
536
+ }
537
+
538
+ /* Popover 触发按钮:放在 panel-title 右侧、来源过滤左侧。
539
+ 📢 是内容信号,不是控制状态——视觉上用一个比版本号更轻的 chip 形态表达。 */
540
+ .library-title-actions {
541
+ display: flex;
542
+ align-items: center;
543
+ gap: 8px;
544
+ margin-left: auto;
545
+ }
546
+
547
+ .advice-popover-anchor {
548
+ position: relative;
549
+ display: inline-flex;
550
+ align-items: center;
551
+ }
552
+
553
+ .advice-toggle {
554
+ display: inline-flex;
555
+ align-items: center;
556
+ gap: 6px;
557
+ min-height: 32px;
558
+ border: 1px solid var(--hairline);
559
+ border-radius: 999px;
560
+ background: var(--canvas);
561
+ color: var(--ink);
562
+ padding: 0 12px 0 10px;
563
+ font: 500 13px/1.4 var(--sans);
564
+ white-space: nowrap;
565
+ }
566
+
567
+ .advice-toggle:hover,
568
+ .advice-toggle[aria-expanded="true"] {
569
+ background: var(--surface-card);
570
+ color: var(--ink);
571
+ border-color: var(--primary-strong);
572
+ }
573
+
574
+ .advice-icon {
575
+ display: inline-flex;
576
+ flex: 0 0 auto;
577
+ width: 16px;
578
+ height: 16px;
579
+ color: currentColor;
580
+ }
581
+
582
+ .advice-toggle .count {
583
+ margin: 0;
584
+ border-radius: 999px;
585
+ background: var(--surface-card);
586
+ color: var(--ink);
587
+ padding: 1px 7px;
588
+ font: 500 12px/1.4 var(--sans);
589
+ font-variant-numeric: tabular-nums;
590
+ }
591
+
592
+ /* 出现 warning 时整体偏暖:徽标底色换到 warning 表面,文案色用 warning-ink。 */
593
+ .advice-toggle.has-warning {
594
+ background: var(--warning-surface);
595
+ border-color: var(--warning-surface);
596
+ color: var(--warning-ink);
597
+ }
598
+
599
+ .advice-toggle.has-warning .count {
600
+ background: var(--canvas);
601
+ color: var(--warning-ink);
602
+ }
603
+
604
+ /* Popover 面板:固定在按钮下方右对齐;最大高度 + 滚动以容纳 8 条 advice。 */
605
+ .advice-popover {
606
+ position: absolute;
607
+ top: calc(100% + 8px);
608
+ right: 0;
609
+ z-index: 30;
610
+ display: grid;
611
+ gap: 8px;
612
+ width: min(440px, calc(100vw - 32px));
613
+ max-height: min(60vh, 520px);
614
+ overflow-y: auto;
615
+ border: 1px solid var(--hairline);
616
+ border-radius: var(--radius-md);
617
+ background: var(--canvas);
618
+ box-shadow: 0 12px 32px rgba(8, 18, 44, 0.14);
619
+ padding: 12px;
620
+ }
621
+
622
+ .advice-popover[hidden] {
623
+ display: none;
624
+ }
625
+
626
+ .advice-popover-header {
627
+ display: flex;
628
+ align-items: center;
629
+ justify-content: space-between;
630
+ gap: 8px;
631
+ margin: -4px 0 4px;
632
+ padding: 0 4px;
633
+ color: var(--muted);
634
+ font: 500 12px/1.4 var(--sans);
635
+ letter-spacing: 0.5px;
636
+ text-transform: uppercase;
637
+ }
638
+
639
+ .advice-popover-close {
640
+ display: inline-flex;
641
+ width: 24px;
642
+ height: 24px;
643
+ align-items: center;
644
+ justify-content: center;
645
+ border: 0;
646
+ border-radius: 999px;
647
+ background: transparent;
648
+ color: var(--muted);
649
+ padding: 0;
650
+ font: 600 16px/1 var(--sans);
651
+ min-height: 24px;
652
+ }
653
+
654
+ .advice-popover-close:hover,
655
+ .advice-popover-close:active {
656
+ background: var(--surface-card);
657
+ color: var(--ink);
658
+ }
659
+
660
+ .library-search {
661
+ padding: 12px 20px;
662
+ border-bottom: 1px solid var(--hairline);
663
+ }
664
+
665
+ .library-search input {
666
+ min-height: 36px;
667
+ padding: 0 14px;
668
+ }
669
+
670
+ .library-search input::placeholder {
671
+ color: var(--muted-soft);
672
+ }
673
+
674
+ /* 严重级别由文字徽标(提示/注意)承载,颜色只做辅助——
675
+ 此前的 4px 侧边彩条是级别的唯一编码,也是最典型的 AI 生成 UI 图案。 */
676
+ .advice {
677
+ display: grid;
678
+ grid-template-columns: minmax(0, 1fr) auto;
679
+ gap: 12px;
680
+ align-items: start;
681
+ border: 1px solid var(--hairline);
682
+ border-radius: var(--radius-md);
683
+ background: var(--surface-soft);
684
+ padding: 12px;
685
+ }
686
+
687
+ .advice-aside {
688
+ display: flex;
689
+ flex-direction: column;
690
+ align-items: flex-end;
691
+ gap: 6px;
692
+ }
693
+
694
+ .advice-severity {
695
+ border-radius: 999px;
696
+ background: var(--surface-card);
697
+ color: var(--body-strong);
698
+ padding: 2px 8px;
699
+ font: 500 11px/1.4 var(--sans);
700
+ white-space: nowrap;
701
+ }
702
+
703
+ .advice.warning .advice-severity {
704
+ background: var(--warning-surface);
705
+ color: var(--warning-ink);
706
+ }
707
+
708
+ .advice strong {
709
+ display: block;
710
+ margin-bottom: 4px;
711
+ color: var(--body-strong);
712
+ font-size: 14px;
713
+ line-height: 1.35;
714
+ }
715
+
716
+ .advice p {
717
+ margin: 0;
718
+ color: var(--muted);
719
+ font-size: 13px;
720
+ line-height: 1.45;
721
+ overflow-wrap: anywhere;
722
+ }
723
+
724
+ .advice-type {
725
+ color: var(--muted-soft);
726
+ font: 12px/1.4 var(--mono);
727
+ }
728
+
729
+ .advice-action {
730
+ margin-top: 8px;
731
+ padding: 6px 9px;
732
+ font-size: 12px;
733
+ }
734
+
735
+ .controls {
736
+ display: grid;
737
+ grid-template-columns: 1fr auto auto;
738
+ gap: 12px;
739
+ align-items: end;
740
+ margin-bottom: 24px;
741
+ border: 1px solid var(--hairline);
742
+ border-radius: var(--radius-lg);
743
+ background: var(--surface-soft);
744
+ padding: 16px;
745
+ }
746
+
747
+ .project-history {
748
+ display: flex;
749
+ grid-column: 1 / -1;
750
+ flex-wrap: wrap;
751
+ gap: 8px;
752
+ min-width: 0;
753
+ }
754
+
755
+ .project-chip {
756
+ display: inline-grid;
757
+ grid-template-columns: minmax(0, 1fr) 28px;
758
+ align-items: center;
759
+ max-width: min(100%, 360px);
760
+ min-height: 32px;
761
+ overflow: hidden;
762
+ border: 1px solid var(--hairline);
763
+ border-radius: var(--radius-md);
764
+ background: var(--canvas);
765
+ color: var(--body);
766
+ font: 12px/1.4 var(--mono);
767
+ }
768
+
769
+ .project-chip:hover {
770
+ background: var(--surface-card);
771
+ color: var(--ink);
772
+ }
773
+
774
+ .project-chip-path,
775
+ .project-chip-remove {
776
+ min-height: 30px;
777
+ border: 0;
778
+ border-radius: 0;
779
+ background: transparent;
780
+ color: inherit;
781
+ font: inherit;
782
+ }
783
+
784
+ .project-chip-path {
785
+ min-width: 0;
786
+ overflow: hidden;
787
+ padding: 4px 10px 4px 12px;
788
+ text-align: left;
789
+ text-overflow: ellipsis;
790
+ white-space: nowrap;
791
+ }
792
+
793
+ .project-chip-path:disabled {
794
+ cursor: not-allowed;
795
+ color: var(--muted);
796
+ }
797
+
798
+ .project-chip-remove {
799
+ display: grid;
800
+ place-items: center;
801
+ width: 28px;
802
+ padding: 4px 0;
803
+ border-left: 1px solid var(--hairline);
804
+ color: var(--muted);
805
+ }
806
+
807
+ .project-chip-remove:hover {
808
+ background: var(--ink);
809
+ color: var(--canvas);
810
+ }
811
+
812
+ .controls label > span,
813
+ .metadata-form label > span {
814
+ display: block;
815
+ margin-bottom: 8px;
816
+ color: var(--muted);
817
+ font: 500 13px/1.4 var(--sans);
818
+ }
819
+
820
+ .field-hint {
821
+ display: block;
822
+ margin: 0 0 8px;
823
+ color: var(--muted-soft);
824
+ font: 12px/1.4 var(--sans);
825
+ }
826
+
827
+ .controls label > span {
828
+ margin-bottom: 4px;
829
+ }
830
+
831
+ input,
832
+ select,
833
+ textarea {
834
+ width: 100%;
835
+ min-height: 40px;
836
+ border: 1px solid var(--hairline);
837
+ border-radius: var(--radius-md);
838
+ background: var(--canvas);
839
+ color: var(--ink);
840
+ padding: 0 14px;
841
+ }
842
+
843
+ textarea {
844
+ min-height: 88px;
845
+ padding: 10px 14px;
846
+ resize: vertical;
847
+ }
848
+
849
+ input:focus-visible,
850
+ select:focus-visible,
851
+ textarea:focus-visible {
852
+ border-color: var(--primary-strong);
853
+ outline: 2px solid var(--primary-strong);
854
+ outline-offset: 1px;
855
+ }
856
+
857
+ /* 输入框此前有焦点环而按钮没有:键盘用户会在全站最主要的交互体上丢失位置。
858
+ offset 2px 在按钮与环之间留出画布底色,深色按钮上环也保持可辨。 */
859
+ button:focus-visible {
860
+ outline: 2px solid var(--primary-strong);
861
+ outline-offset: 2px;
862
+ }
863
+
864
+ button {
865
+ min-height: 40px;
866
+ border: 1px solid transparent;
867
+ border-radius: var(--radius-md);
868
+ background: var(--primary-strong);
869
+ color: var(--on-primary);
870
+ cursor: pointer;
871
+ padding: 0 20px;
872
+ font-size: 14px;
873
+ font-weight: 500;
874
+ letter-spacing: 0;
875
+ white-space: nowrap;
876
+ }
877
+
878
+ button:active,
879
+ button:hover {
880
+ background: var(--primary-active);
881
+ }
882
+
883
+ button:disabled {
884
+ cursor: not-allowed;
885
+ background: var(--primary-disabled);
886
+ color: var(--muted);
887
+ }
888
+
889
+ button.is-enabled {
890
+ background: var(--surface-soft);
891
+ color: var(--success);
892
+ border: 1px solid var(--success);
893
+ }
894
+
895
+ button[aria-disabled="true"] {
896
+ cursor: default;
897
+ }
898
+
899
+ button.secondary {
900
+ border-color: var(--hairline);
901
+ background: var(--canvas);
902
+ color: var(--ink);
903
+ }
904
+
905
+ button.secondary:active,
906
+ button.secondary:hover {
907
+ background: var(--surface-card);
908
+ }
909
+
910
+ button.danger,
911
+ .actions .danger {
912
+ background: var(--surface-dark-elevated);
913
+ color: var(--on-dark);
914
+ }
915
+
916
+ button.danger:active,
917
+ button.danger:hover,
918
+ .actions .danger:active,
919
+ .actions .danger:hover {
920
+ background: var(--error);
921
+ color: var(--on-primary);
922
+ }
923
+
924
+ button.danger:disabled,
925
+ .actions .danger:disabled {
926
+ background: var(--primary-disabled);
927
+ color: var(--muted);
928
+ }
929
+
930
+ .icon-button {
931
+ display: inline-flex;
932
+ width: 36px;
933
+ height: 36px;
934
+ min-height: 36px;
935
+ align-items: center;
936
+ justify-content: center;
937
+ border: 1px solid var(--hairline);
938
+ border-radius: 999px;
939
+ background: var(--canvas);
940
+ color: var(--ink);
941
+ padding: 0;
942
+ font-size: 18px;
943
+ line-height: 1;
944
+ }
945
+
946
+ .icon-button:active,
947
+ .icon-button:hover {
948
+ background: var(--surface-card);
949
+ }
950
+
951
+ .version {
952
+ display: inline-block;
953
+ padding: 4px 12px;
954
+ border-radius: 999px;
955
+ background: var(--surface-card);
956
+ color: var(--ink);
957
+ font: 500 13px/1.4 var(--sans);
958
+ }
959
+
960
+ .version:empty { display: none; }
961
+
962
+ .workspace {
963
+ display: grid;
964
+ grid-template-columns: minmax(440px, 0.92fr) minmax(0, 1.08fr);
965
+ gap: 24px;
966
+ align-items: start;
967
+ }
968
+
969
+ .panel {
970
+ overflow: hidden;
971
+ border: 1px solid var(--hairline);
972
+ border-radius: var(--radius-lg);
973
+ background: var(--canvas);
974
+ }
975
+
976
+ .panel-title {
977
+ display: flex;
978
+ min-height: 72px;
979
+ align-items: center;
980
+ justify-content: space-between;
981
+ gap: 16px;
982
+ border-bottom: 1px solid var(--hairline);
983
+ padding: 18px 20px;
984
+ }
985
+
986
+ .panel-title > span,
987
+ .meta,
988
+ .path {
989
+ color: var(--muted);
990
+ font: 13px/1.5 var(--mono);
991
+ }
992
+
993
+ .panel-title select {
994
+ width: 168px;
995
+ }
996
+
997
+ .tag-tabs {
998
+ display: flex;
999
+ flex-wrap: nowrap;
1000
+ gap: 8px;
1001
+ overflow-x: auto;
1002
+ border-bottom: 1px solid var(--hairline);
1003
+ background: var(--canvas);
1004
+ padding: 12px 20px;
1005
+ }
1006
+
1007
+ /* 可滚动线索:右缘渐隐遮罩,窄屏下滚动条已隐藏时提示还有更多标签。 */
1008
+ .tag-tabs::after {
1009
+ position: sticky;
1010
+ right: -20px;
1011
+ flex: 0 0 28px;
1012
+ width: 28px;
1013
+ margin-left: -28px;
1014
+ background: linear-gradient(to right, transparent, var(--canvas) 85%);
1015
+ content: "";
1016
+ pointer-events: none;
1017
+ }
1018
+
1019
+ .tag-tabs:empty {
1020
+ display: none;
1021
+ }
1022
+
1023
+ .category-tab {
1024
+ min-height: 32px;
1025
+ border-color: transparent;
1026
+ background: transparent;
1027
+ color: var(--muted);
1028
+ padding: 0 14px;
1029
+ }
1030
+
1031
+ .category-tab:active,
1032
+ .category-tab:hover,
1033
+ .category-tab.is-active {
1034
+ background: var(--surface-card);
1035
+ color: var(--ink);
1036
+ }
1037
+
1038
+ .list {
1039
+ display: grid;
1040
+ gap: 1px;
1041
+ background: var(--hairline);
1042
+ }
1043
+
1044
+ .skill-group {
1045
+ min-width: 0;
1046
+ background: var(--canvas);
1047
+ }
1048
+
1049
+ .group-bar {
1050
+ display: flex;
1051
+ min-width: 0;
1052
+ align-items: center;
1053
+ border-bottom: 1px solid var(--hairline);
1054
+ background: var(--surface-card);
1055
+ padding: 16px 20px;
1056
+ }
1057
+
1058
+ .group-head {
1059
+ display: flex;
1060
+ flex: 1 1 auto;
1061
+ width: 100%;
1062
+ min-height: 0;
1063
+ min-width: 0;
1064
+ flex-wrap: wrap;
1065
+ align-items: center;
1066
+ justify-content: flex-start;
1067
+ column-gap: 8px;
1068
+ row-gap: 5px;
1069
+ text-align: left;
1070
+ }
1071
+
1072
+ .group-toggle {
1073
+ display: flex;
1074
+ align-items: center;
1075
+ gap: 8px;
1076
+ min-height: 28px;
1077
+ min-width: 0;
1078
+ border: 0;
1079
+ border-radius: 0;
1080
+ background: transparent;
1081
+ color: var(--ink);
1082
+ padding: 0;
1083
+ font: inherit;
1084
+ text-align: left;
1085
+ }
1086
+
1087
+ .group-toggle:active,
1088
+ .group-toggle:hover {
1089
+ background: transparent;
1090
+ color: var(--primary-active);
1091
+ }
1092
+
1093
+ .group-actions {
1094
+ display: inline-flex;
1095
+ flex: 0 0 auto;
1096
+ align-items: center;
1097
+ gap: 8px;
1098
+ }
1099
+
1100
+ .scope-divider {
1101
+ width: 1px;
1102
+ height: 24px;
1103
+ flex: 0 0 1px;
1104
+ background: var(--hairline);
1105
+ }
1106
+
1107
+ /* 作用域图例:此前全局按钮用「G+」「G×」自造记号,含义只存在于悬停 title 里。 */
1108
+ .scope-label {
1109
+ flex: 0 0 auto;
1110
+ color: var(--muted);
1111
+ font: 500 11px/1 var(--sans);
1112
+ letter-spacing: 0.5px;
1113
+ }
1114
+
1115
+ .group-enable-all,
1116
+ .group-enable-global,
1117
+ .group-enable-hermes {
1118
+ min-width: 44px;
1119
+ height: 36px;
1120
+ background: var(--primary-strong);
1121
+ color: var(--on-primary);
1122
+ padding: 0 12px;
1123
+ font-size: 12px;
1124
+ white-space: nowrap;
1125
+ font-weight: 500;
1126
+ font-variant-numeric: tabular-nums;
1127
+ }
1128
+
1129
+ .group-enable-all:active,
1130
+ .group-enable-all:hover,
1131
+ .group-enable-global:active,
1132
+ .group-enable-global:hover,
1133
+ .group-enable-hermes:active,
1134
+ .group-enable-hermes:hover {
1135
+ background: var(--primary-active);
1136
+ }
1137
+
1138
+ .group-enable-all:disabled,
1139
+ .group-enable-global:disabled,
1140
+ .group-enable-hermes:disabled {
1141
+ background: var(--primary-disabled);
1142
+ color: var(--muted);
1143
+ }
1144
+
1145
+ .group-enable-all.is-complete {
1146
+ background: var(--success);
1147
+ color: var(--on-primary);
1148
+ }
1149
+
1150
+ .group-enable-global.is-complete {
1151
+ background: var(--success);
1152
+ color: var(--on-primary);
1153
+ }
1154
+
1155
+ .group-enable-hermes.is-complete {
1156
+ background: var(--success);
1157
+ color: var(--on-primary);
1158
+ }
1159
+
1160
+ .group-disable-all {
1161
+ width: 36px;
1162
+ min-width: 36px;
1163
+ height: 36px;
1164
+ }
1165
+
1166
+ .group-heading {
1167
+ min-width: 0;
1168
+ margin: 0;
1169
+ font-size: 18px;
1170
+ font-weight: 600;
1171
+ line-height: 1.3;
1172
+ }
1173
+
1174
+ .group-toggle .title {
1175
+ overflow-wrap: anywhere;
1176
+ }
1177
+
1178
+ .group-head p {
1179
+ flex: 0 0 100%;
1180
+ margin: 5px 0 0;
1181
+ min-width: 0;
1182
+ color: var(--muted);
1183
+ font: 12px/1.4 var(--mono);
1184
+ overflow-wrap: anywhere;
1185
+ }
1186
+
1187
+ .chevron {
1188
+ display: inline-flex;
1189
+ align-items: center;
1190
+ justify-content: center;
1191
+ flex-shrink: 0;
1192
+ width: 18px;
1193
+ height: 1em;
1194
+ color: var(--primary-strong);
1195
+ font: 700 14px/1 var(--mono);
1196
+ transition: transform 120ms ease;
1197
+ }
1198
+
1199
+ @media (prefers-reduced-motion: reduce) {
1200
+ .chevron {
1201
+ transition: none;
1202
+ }
1203
+ }
1204
+
1205
+ .is-collapsed .chevron {
1206
+ transform: rotate(-90deg);
1207
+ }
1208
+
1209
+ .is-collapsed .group-items {
1210
+ display: none;
1211
+ }
1212
+
1213
+ .group-items {
1214
+ display: grid;
1215
+ gap: 1px;
1216
+ background: var(--hairline);
1217
+ }
1218
+
1219
+ .empty,
1220
+ .skill {
1221
+ background: var(--canvas);
1222
+ padding: 16px 20px;
1223
+ }
1224
+
1225
+ .empty {
1226
+ display: flex;
1227
+ flex-direction: column;
1228
+ color: var(--muted);
1229
+ font: 14px/1.55 var(--sans);
1230
+ }
1231
+
1232
+ .empty strong {
1233
+ margin-bottom: 4px;
1234
+ color: var(--body-strong);
1235
+ font-weight: 500;
1236
+ }
1237
+
1238
+ .empty-action {
1239
+ align-self: flex-start;
1240
+ margin-top: 12px;
1241
+ min-height: 34px;
1242
+ padding: 0 12px;
1243
+ font-size: 13px;
1244
+ }
1245
+
1246
+ .skill {
1247
+ display: grid;
1248
+ gap: 10px;
1249
+ }
1250
+
1251
+ .skill-head {
1252
+ display: flex;
1253
+ align-items: center;
1254
+ justify-content: space-between;
1255
+ gap: 12px;
1256
+ }
1257
+
1258
+ .name {
1259
+ min-width: 0;
1260
+ overflow-wrap: anywhere;
1261
+ color: var(--body-strong);
1262
+ font-weight: 500;
1263
+ }
1264
+
1265
+ .badge {
1266
+ flex-shrink: 0;
1267
+ border: 0;
1268
+ border-radius: 999px;
1269
+ background: var(--surface-card);
1270
+ color: var(--ink);
1271
+ padding: 4px 12px;
1272
+ font: 500 13px/1.4 var(--sans);
1273
+ white-space: nowrap;
1274
+ }
1275
+
1276
+ /* 组头徽标:移入 group-head 后紧随标题行。margin-left:auto 在桌面把它
1277
+ 推到行尾(与原来 bar 行尾位置一致);窄屏由 group-head 的 flex-wrap
1278
+ 自然落在标题行,不再独占一行。 */
1279
+ .group-head > .badge {
1280
+ margin-left: auto;
1281
+ min-width: 0;
1282
+ max-width: 100%;
1283
+ overflow: hidden;
1284
+ text-overflow: ellipsis;
1285
+ }
1286
+
1287
+ .skill-tags {
1288
+ display: flex;
1289
+ flex-wrap: wrap;
1290
+ gap: 6px;
1291
+ }
1292
+
1293
+ .skill-tags:empty {
1294
+ display: none;
1295
+ }
1296
+
1297
+ .tag-pill {
1298
+ border-radius: 999px;
1299
+ background: var(--surface-card);
1300
+ color: var(--ink);
1301
+ padding: 4px 10px;
1302
+ font: 500 13px/1.4 var(--sans);
1303
+ }
1304
+
1305
+ .tag-pill.is-muted {
1306
+ background: var(--surface-soft);
1307
+ color: var(--muted);
1308
+ }
1309
+
1310
+ .note {
1311
+ margin: 0;
1312
+ color: var(--body);
1313
+ font: 14px/1.55 var(--sans);
1314
+ }
1315
+
1316
+ .note.is-empty {
1317
+ color: var(--muted-soft);
1318
+ }
1319
+
1320
+ .metadata-form {
1321
+ display: grid;
1322
+ gap: 12px;
1323
+ border: 1px solid var(--hairline);
1324
+ border-radius: var(--radius-md);
1325
+ background: var(--surface-soft);
1326
+ padding: 14px;
1327
+ }
1328
+
1329
+ .metadata-actions {
1330
+ display: flex;
1331
+ flex-wrap: wrap;
1332
+ gap: 8px;
1333
+ }
1334
+
1335
+ .toggle-field {
1336
+ display: flex;
1337
+ min-height: 44px;
1338
+ align-items: center;
1339
+ gap: 10px;
1340
+ }
1341
+
1342
+ .toggle-field input {
1343
+ width: 24px;
1344
+ min-height: 24px;
1345
+ accent-color: var(--primary-strong);
1346
+ }
1347
+
1348
+ .toggle-field span {
1349
+ margin: 0;
1350
+ color: var(--body);
1351
+ }
1352
+
1353
+ .actions {
1354
+ flex-wrap: wrap;
1355
+ }
1356
+
1357
+ .actions button {
1358
+ min-height: 34px;
1359
+ padding: 0 12px;
1360
+ font-size: 14px;
1361
+ }
1362
+
1363
+ .path {
1364
+ overflow-wrap: anywhere;
1365
+ }
1366
+
1367
+ /* 反馈必须落在视野内:库面板几千像素长,页尾的一行小字等于没有反馈。
1368
+ 固定右下 toast;空态用 opacity 而非 display:none,元素留在可达性树里,
1369
+ live region 写入时读屏才能稳定播报。 */
1370
+ .message-region {
1371
+ position: fixed;
1372
+ right: 24px;
1373
+ bottom: 24px;
1374
+ z-index: 40;
1375
+ display: flex;
1376
+ flex-direction: column;
1377
+ gap: 8px;
1378
+ max-width: min(480px, calc(100vw - 48px));
1379
+ margin: 0;
1380
+ pointer-events: none;
1381
+ }
1382
+
1383
+ .message {
1384
+ margin: 0;
1385
+ border-radius: var(--radius-md);
1386
+ background: var(--surface-dark);
1387
+ color: var(--on-dark);
1388
+ padding: 12px 16px;
1389
+ font: 13px/1.5 var(--mono);
1390
+ box-shadow: var(--shadow-toast);
1391
+ overflow-wrap: anywhere;
1392
+ pointer-events: auto;
1393
+ transition: opacity 160ms ease, transform 160ms ease;
1394
+ }
1395
+
1396
+ .message:empty {
1397
+ opacity: 0;
1398
+ transform: translateY(6px);
1399
+ padding: 0;
1400
+ box-shadow: none;
1401
+ pointer-events: none;
1402
+ }
1403
+
1404
+ .message.is-error {
1405
+ color: var(--error-on-dark);
1406
+ }
1407
+
1408
+ @media (prefers-reduced-motion: reduce) {
1409
+ .message {
1410
+ transition: none;
1411
+ }
1412
+ }
1413
+
1414
+ @media (max-width: 1120px) {
1415
+ .workspace {
1416
+ grid-template-columns: 1fr;
1417
+ }
1418
+ }
1419
+
1420
+ @media (max-width: 980px) {
1421
+ .hero {
1422
+ grid-template-columns: 1fr;
1423
+ }
1424
+
1425
+ .hero {
1426
+ gap: 28px;
1427
+ padding-top: 48px;
1428
+ }
1429
+ }
1430
+
1431
+ @media (max-width: 760px) {
1432
+ .shell {
1433
+ width: min(100% - 32px, 1200px);
1434
+ padding-top: 14px;
1435
+ }
1436
+
1437
+ /* 首访移动端 hero 716px 营销墙:h1 降级、统计保持 3 列横排,
1438
+ 表单与工作区回到首屏附近。 */
1439
+ .hero {
1440
+ padding: 28px 0 24px;
1441
+ }
1442
+
1443
+ h1 {
1444
+ font-size: 30px;
1445
+ }
1446
+
1447
+ .lede {
1448
+ font-size: 16px;
1449
+ }
1450
+
1451
+ /* 触控目标:36px/34px 桌面密度在手指下不可靠,全部提到 44px。 */
1452
+ .icon-button {
1453
+ width: 44px;
1454
+ height: 44px;
1455
+ min-height: 44px;
1456
+ }
1457
+
1458
+ .actions button,
1459
+ .metadata-actions button,
1460
+ .empty-action {
1461
+ min-height: 44px;
1462
+ }
1463
+
1464
+ .group-enable-all,
1465
+ .group-enable-global {
1466
+ height: 44px;
1467
+ }
1468
+
1469
+ .group-disable-all {
1470
+ width: 44px;
1471
+ min-width: 44px;
1472
+ height: 44px;
1473
+ }
1474
+
1475
+ .project-chip {
1476
+ grid-template-columns: minmax(0, 1fr) 44px;
1477
+ min-height: 44px;
1478
+ }
1479
+
1480
+ .project-chip-remove {
1481
+ width: 44px;
1482
+ min-height: 44px;
1483
+ }
1484
+
1485
+ /* 26 个标签堆成 337px 的墙会把列表推出屏外:窄屏隐藏滚动条(渐隐遮罩提示)。
1486
+ nowrap + 横向滚动已是 .tag-tabs 基础样式,桌面同样生效。 */
1487
+ .tag-tabs {
1488
+ scrollbar-width: none;
1489
+ }
1490
+
1491
+ .tag-tabs::-webkit-scrollbar {
1492
+ display: none;
1493
+ }
1494
+
1495
+ .category-tab {
1496
+ flex: 0 0 auto;
1497
+ min-height: 44px;
1498
+ }
1499
+
1500
+ .group-toggle {
1501
+ min-height: 44px;
1502
+ }
1503
+
1504
+ input,
1505
+ select,
1506
+ textarea {
1507
+ min-height: 44px;
1508
+ }
1509
+
1510
+ .project-chip-path,
1511
+ .project-chip-remove {
1512
+ min-height: 44px;
1513
+ }
1514
+
1515
+ .controls button {
1516
+ min-height: 44px;
1517
+ }
1518
+
1519
+ .library-search input {
1520
+ min-height: 44px;
1521
+ }
1522
+
1523
+ .message-region {
1524
+ right: 12px;
1525
+ bottom: 12px;
1526
+ max-width: calc(100vw - 24px);
1527
+ }
1528
+
1529
+ .topbar {
1530
+ min-height: 56px;
1531
+ }
1532
+
1533
+ .topbar-link {
1534
+ width: 36px;
1535
+ justify-content: center;
1536
+ padding: 0;
1537
+ }
1538
+
1539
+ .topbar-link-label {
1540
+ display: none;
1541
+ }
1542
+
1543
+ .hero {
1544
+ padding: 40px 0 28px;
1545
+ }
1546
+
1547
+ .hero.is-compact {
1548
+ padding: 20px 0 24px;
1549
+ }
1550
+
1551
+ .hero.is-compact .product-surface {
1552
+ gap: 10px 14px;
1553
+ }
1554
+
1555
+ .hero.is-compact .surface-header strong {
1556
+ display: none;
1557
+ }
1558
+
1559
+ .hero.is-compact .surface-grid {
1560
+ flex: 1 1 220px;
1561
+ justify-content: space-between;
1562
+ gap: 10px;
1563
+ }
1564
+
1565
+ .hero.is-compact .surface-grid div {
1566
+ min-width: 0;
1567
+ }
1568
+
1569
+ .hero.is-compact .surface-grid span {
1570
+ overflow: hidden;
1571
+ text-overflow: ellipsis;
1572
+ white-space: nowrap;
1573
+ }
1574
+
1575
+ .hero.is-compact .surface-path {
1576
+ flex-basis: 100%;
1577
+ text-align: left;
1578
+ }
1579
+
1580
+ h1 {
1581
+ font-size: 30px;
1582
+ }
1583
+
1584
+ .controls {
1585
+ grid-template-columns: 1fr;
1586
+ }
1587
+
1588
+ /* 移动端单列时原件库(主工作流)排到只读的已启用面板之前。 */
1589
+ .library-panel {
1590
+ order: -1;
1591
+ }
1592
+
1593
+ .panel-title {
1594
+ align-items: stretch;
1595
+ flex-direction: column;
1596
+ }
1597
+
1598
+ .panel-title select {
1599
+ width: 100%;
1600
+ }
1601
+ }
1602
+
1603
+ @media (max-width: 520px) {
1604
+ /* 组头操作区(项目 +/× + 全局 +/× + 图例)整行换到标题与徽标下方,
1605
+ 徽标已随标题留在首行。 */
1606
+ .group-actions {
1607
+ flex: 1 1 100%;
1608
+ flex-wrap: wrap;
1609
+ justify-content: flex-end;
1610
+ }
1611
+ }