@polderlabs/bizar 4.4.13 → 4.5.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 (90) hide show
  1. package/bizar-dash/CHANGELOG.md +37 -276
  2. package/bizar-dash/dist/assets/main-CDFKHzBg.css +1 -0
  3. package/bizar-dash/dist/assets/main-NYFpS2wY.js +312 -0
  4. package/bizar-dash/dist/assets/main-NYFpS2wY.js.map +1 -0
  5. package/bizar-dash/dist/assets/{mobile-DSb-t42Y.js → mobile--0FBIKX3.js} +2 -2
  6. package/bizar-dash/dist/assets/{mobile-DSb-t42Y.js.map → mobile--0FBIKX3.js.map} +1 -1
  7. package/bizar-dash/dist/assets/mobile-OgRp8VIb.js +352 -0
  8. package/bizar-dash/dist/assets/mobile-OgRp8VIb.js.map +1 -0
  9. package/bizar-dash/dist/index.html +3 -3
  10. package/bizar-dash/dist/mobile.html +2 -2
  11. package/bizar-dash/skills/agent-baseline/SKILL.md +80 -0
  12. package/bizar-dash/skills/bizar/SKILL.md +96 -0
  13. package/bizar-dash/skills/chat/SKILL.md +74 -0
  14. package/bizar-dash/skills/lightrag/SKILL.md +75 -0
  15. package/bizar-dash/skills/minimax/SKILL.md +80 -0
  16. package/bizar-dash/skills/obsidian/SKILL.md +55 -0
  17. package/bizar-dash/skills/providers/SKILL.md +75 -0
  18. package/bizar-dash/skills/sdk/SKILL.md +138 -0
  19. package/bizar-dash/skills/self-improvement/SKILL.md +53 -0
  20. package/bizar-dash/skills/skills-cli/SKILL.md +94 -0
  21. package/bizar-dash/skills/usage/SKILL.md +62 -0
  22. package/bizar-dash/src/server/api.mjs +12 -0
  23. package/bizar-dash/src/server/memory-lightrag.mjs +5 -2
  24. package/bizar-dash/src/server/memory-store.mjs +38 -0
  25. package/bizar-dash/src/server/minimax-usage-store.mjs +372 -0
  26. package/bizar-dash/src/server/minimax.mjs +196 -5
  27. package/bizar-dash/src/server/providers-store.mjs +956 -0
  28. package/bizar-dash/src/server/routes/config.mjs +52 -1
  29. package/bizar-dash/src/server/routes/env-vars.mjs +165 -0
  30. package/bizar-dash/src/server/routes/lightrag.mjs +154 -0
  31. package/bizar-dash/src/server/routes/memory.mjs +241 -1
  32. package/bizar-dash/src/server/routes/opencode-session-detail.mjs +14 -29
  33. package/bizar-dash/src/server/routes/opencode-sessions.mjs +205 -3
  34. package/bizar-dash/src/server/routes/providers.mjs +266 -5
  35. package/bizar-dash/src/server/routes/skills.mjs +32 -43
  36. package/bizar-dash/src/server/routes/update.mjs +340 -0
  37. package/bizar-dash/src/server/routes/usage.mjs +136 -0
  38. package/bizar-dash/src/server/serve-info.mjs +135 -4
  39. package/bizar-dash/src/server/server.mjs +4 -0
  40. package/bizar-dash/src/server/skills-store.mjs +152 -262
  41. package/bizar-dash/src/web/App.tsx +118 -29
  42. package/bizar-dash/src/web/components/EnvVarManager.tsx +247 -0
  43. package/bizar-dash/src/web/components/SettingsSearch.tsx +213 -0
  44. package/bizar-dash/src/web/components/Topbar.tsx +0 -1
  45. package/bizar-dash/src/web/components/UsageChart.tsx +250 -0
  46. package/bizar-dash/src/web/components/UsageTable.tsx +90 -0
  47. package/bizar-dash/src/web/components/chat/ChatComposer.tsx +21 -25
  48. package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +199 -37
  49. package/bizar-dash/src/web/components/chat/ChatThread.tsx +29 -17
  50. package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +7 -1
  51. package/bizar-dash/src/web/components/chat/InfoPanel.tsx +71 -6
  52. package/bizar-dash/src/web/components/chat/useChat.ts +751 -257
  53. package/bizar-dash/src/web/lib/api.ts +43 -0
  54. package/bizar-dash/src/web/main.tsx +1 -0
  55. package/bizar-dash/src/web/mobile/views/MobileChat.tsx +110 -35
  56. package/bizar-dash/src/web/styles/chat.css +135 -1
  57. package/bizar-dash/src/web/styles/main.css +46 -0
  58. package/bizar-dash/src/web/styles/minimax-usage.css +335 -0
  59. package/bizar-dash/src/web/styles/settings.css +418 -0
  60. package/bizar-dash/src/web/styles/skills.css +302 -0
  61. package/bizar-dash/src/web/styles/tasks.css +288 -0
  62. package/bizar-dash/src/web/views/Chat.tsx +276 -48
  63. package/bizar-dash/src/web/views/Config.tsx +3 -2065
  64. package/bizar-dash/src/web/views/MiniMaxUsage.tsx +476 -461
  65. package/bizar-dash/src/web/views/Settings.tsx +6 -0
  66. package/bizar-dash/src/web/views/Skills.tsx +208 -260
  67. package/bizar-dash/src/web/views/Tasks.tsx +348 -1119
  68. package/bizar-dash/tests/chat-session-create.test.mjs +391 -0
  69. package/bizar-dash/tests/chat-session-stream.test.mjs +308 -0
  70. package/bizar-dash/tests/env-vars-store.test.mjs +216 -0
  71. package/bizar-dash/tests/lightrag-defaults.node.test.mjs +118 -0
  72. package/bizar-dash/tests/minimax-chat-usage.test.mjs +178 -0
  73. package/bizar-dash/tests/minimax-usage-store.node.test.mjs +293 -0
  74. package/bizar-dash/tests/opencode-sessions-detail.test.mjs +12 -9
  75. package/bizar-dash/tests/providers-store-backup-keys.node.test.mjs +479 -3
  76. package/bizar-dash/tests/providers-store-search.node.test.mjs +166 -0
  77. package/bizar-dash/tests/skills-list.test.mjs +232 -0
  78. package/bizar-dash/tests/skills-search.test.mjs +222 -0
  79. package/bizar-dash/tests/tasks-create.test.mjs +187 -0
  80. package/bizar-dash/tests/update-check.test.mjs +127 -0
  81. package/bizar-dash/tests/update-run.test.mjs +266 -0
  82. package/cli/bin.mjs +82 -1
  83. package/cli/provision.mjs +118 -4
  84. package/config/agents/_shared/SKILLS.md +109 -0
  85. package/package.json +1 -1
  86. package/bizar-dash/dist/assets/main-BB5mJurD.js +0 -352
  87. package/bizar-dash/dist/assets/main-BB5mJurD.js.map +0 -1
  88. package/bizar-dash/dist/assets/main-BsnQLXdh.css +0 -1
  89. package/bizar-dash/dist/assets/mobile-Dl1q7Cyq.js +0 -354
  90. package/bizar-dash/dist/assets/mobile-Dl1q7Cyq.js.map +0 -1
@@ -0,0 +1,418 @@
1
+ /* ─────────────────────────────────────────────────────────────────────
2
+ Settings view CSS — new sections for the overhauled Settings page.
3
+ ───────────────────────────────────────────────────────────────────── */
4
+
5
+ /* Settings view layout */
6
+ .view-settings {
7
+ gap: var(--space-5);
8
+ }
9
+
10
+ /* Settings inner layout: sticky sidebar nav + scrollable content */
11
+ .settings-body {
12
+ display: grid;
13
+ grid-template-columns: 200px 1fr;
14
+ gap: var(--space-5);
15
+ align-items: start;
16
+ }
17
+
18
+ @media (max-width: 800px) {
19
+ .settings-body {
20
+ grid-template-columns: 1fr;
21
+ }
22
+ }
23
+
24
+ /* Left: settings sidebar nav */
25
+ .settings-nav {
26
+ position: sticky;
27
+ top: 72px;
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: 2px;
31
+ max-height: calc(100vh - 100px);
32
+ overflow-y: auto;
33
+ }
34
+
35
+ .settings-nav-item {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 8px;
39
+ padding: 6px 10px;
40
+ border-radius: var(--radius);
41
+ border: 1px solid transparent;
42
+ background: transparent;
43
+ color: var(--text-dim);
44
+ font-size: 13px;
45
+ font-weight: 500;
46
+ cursor: pointer;
47
+ text-align: left;
48
+ width: 100%;
49
+ transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast);
50
+ }
51
+
52
+ .settings-nav-item:hover {
53
+ background: var(--bg-elev-2);
54
+ color: var(--text);
55
+ }
56
+
57
+ .settings-nav-item-active {
58
+ background: var(--accent-bg);
59
+ color: var(--accent-2);
60
+ border-color: var(--accent-border);
61
+ }
62
+
63
+ .settings-nav-section-label {
64
+ font-size: 10px;
65
+ text-transform: uppercase;
66
+ letter-spacing: 0.06em;
67
+ color: var(--text-dim);
68
+ padding: 10px 10px 4px;
69
+ font-weight: 600;
70
+ }
71
+
72
+ /* Right: settings content area */
73
+ .settings-content {
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: var(--space-4);
77
+ min-width: 0;
78
+ }
79
+
80
+ /* Search within settings */
81
+ .settings-search {
82
+ position: relative;
83
+ margin-bottom: var(--space-3);
84
+ }
85
+
86
+ .settings-search-input-wrap {
87
+ position: relative;
88
+ display: flex;
89
+ align-items: center;
90
+ }
91
+
92
+ .settings-search-icon {
93
+ position: absolute;
94
+ left: 10px;
95
+ color: var(--text-dim);
96
+ pointer-events: none;
97
+ }
98
+
99
+ .settings-search-input {
100
+ padding-left: 32px !important;
101
+ padding-right: 32px !important;
102
+ }
103
+
104
+ .settings-search-clear {
105
+ position: absolute;
106
+ right: 4px;
107
+ }
108
+
109
+ .settings-search-results {
110
+ position: absolute;
111
+ top: calc(100% + 4px);
112
+ left: 0;
113
+ right: 0;
114
+ background: var(--bg-elev);
115
+ border: 1px solid var(--border);
116
+ border-radius: var(--radius-md);
117
+ box-shadow: var(--shadow-2);
118
+ z-index: 100;
119
+ max-height: 300px;
120
+ overflow-y: auto;
121
+ display: flex;
122
+ flex-direction: column;
123
+ gap: 2px;
124
+ padding: 4px;
125
+ }
126
+
127
+ .settings-search-result {
128
+ display: flex;
129
+ align-items: center;
130
+ gap: 8px;
131
+ padding: 6px 10px;
132
+ border-radius: var(--radius-sm);
133
+ border: none;
134
+ background: transparent;
135
+ color: var(--text);
136
+ font-size: 13px;
137
+ cursor: pointer;
138
+ text-align: left;
139
+ width: 100%;
140
+ transition: background var(--motion-fast);
141
+ }
142
+
143
+ .settings-search-result:hover,
144
+ .settings-search-result-active {
145
+ background: var(--bg-elev-2);
146
+ }
147
+
148
+ .settings-search-result-type {
149
+ font-size: 10px;
150
+ font-family: var(--font-mono);
151
+ text-transform: uppercase;
152
+ color: var(--text-dim);
153
+ min-width: 40px;
154
+ }
155
+
156
+ .settings-search-result-type-section {
157
+ color: var(--accent-2);
158
+ }
159
+
160
+ .settings-search-result-label {
161
+ flex: 1;
162
+ font-weight: 500;
163
+ }
164
+
165
+ .settings-search-result-key {
166
+ font-size: 11px;
167
+ color: var(--text-dim);
168
+ }
169
+
170
+ .settings-search-empty {
171
+ padding: 8px 10px;
172
+ font-size: 13px;
173
+ }
174
+
175
+ /* Highlight animation for matched cards */
176
+ @keyframes settings-section-highlight {
177
+ 0% { border-color: var(--border); }
178
+ 30% { border-color: var(--accent); box-shadow: var(--shadow-glow); }
179
+ 100% { border-color: var(--border); }
180
+ }
181
+
182
+ .settings-section-highlighted {
183
+ animation: settings-section-highlight 1.5s var(--ease);
184
+ }
185
+
186
+ /* Provider section */
187
+ .provider-card-grid {
188
+ display: grid;
189
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
190
+ gap: var(--space-4);
191
+ }
192
+
193
+ .provider-card-inner {
194
+ display: flex;
195
+ flex-direction: column;
196
+ gap: var(--space-2);
197
+ }
198
+
199
+ .provider-card-head {
200
+ display: flex;
201
+ align-items: flex-start;
202
+ justify-content: space-between;
203
+ gap: var(--space-2);
204
+ }
205
+
206
+ .provider-card-name {
207
+ font-weight: 600;
208
+ font-size: 14px;
209
+ }
210
+
211
+ .provider-card-id {
212
+ font-size: 11px;
213
+ font-family: var(--font-mono);
214
+ color: var(--text-dim);
215
+ }
216
+
217
+ .provider-card-meta-row {
218
+ display: flex;
219
+ gap: 8px;
220
+ flex-wrap: wrap;
221
+ font-size: 12px;
222
+ color: var(--text-dim);
223
+ }
224
+
225
+ .key-status {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ gap: 4px;
229
+ font-size: 11px;
230
+ font-family: var(--font-mono);
231
+ }
232
+
233
+ .key-status-ok { color: var(--success); }
234
+ .key-status-missing { color: var(--error); }
235
+
236
+ /* EnvVarManager */
237
+ .env-var-manager {
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: var(--space-3);
241
+ }
242
+
243
+ .env-var-toolbar {
244
+ display: flex;
245
+ gap: var(--space-2);
246
+ align-items: center;
247
+ }
248
+
249
+ .env-var-empty {
250
+ display: flex;
251
+ flex-direction: column;
252
+ align-items: center;
253
+ gap: 6px;
254
+ padding: 24px 16px;
255
+ text-align: center;
256
+ color: var(--text-dim);
257
+ border: 1px dashed var(--border);
258
+ border-radius: var(--radius-md);
259
+ font-size: 13px;
260
+ }
261
+
262
+ .env-var-list {
263
+ display: flex;
264
+ flex-direction: column;
265
+ gap: 4px;
266
+ }
267
+
268
+ .env-var-row {
269
+ display: flex;
270
+ align-items: center;
271
+ gap: var(--space-3);
272
+ padding: 8px 10px;
273
+ background: var(--bg-elev-2);
274
+ border: 1px solid var(--border);
275
+ border-radius: var(--radius);
276
+ font-size: 13px;
277
+ transition: border-color var(--motion-fast);
278
+ }
279
+
280
+ .env-var-row:hover {
281
+ border-color: var(--border-strong);
282
+ }
283
+
284
+ .env-var-row-editing {
285
+ border-color: var(--accent-border);
286
+ background: var(--bg-elev-3);
287
+ }
288
+
289
+ .env-var-name {
290
+ font-weight: 600;
291
+ min-width: 160px;
292
+ font-size: 12px;
293
+ }
294
+
295
+ .env-var-value {
296
+ flex: 1;
297
+ min-width: 0;
298
+ overflow: hidden;
299
+ text-overflow: ellipsis;
300
+ white-space: nowrap;
301
+ }
302
+
303
+ .env-var-value-masked {
304
+ color: var(--text-dim);
305
+ }
306
+
307
+ .env-var-source {
308
+ font-size: 11px;
309
+ min-width: 70px;
310
+ }
311
+
312
+ .env-var-actions {
313
+ display: flex;
314
+ align-items: center;
315
+ gap: 4px;
316
+ flex-shrink: 0;
317
+ }
318
+
319
+ .env-var-add-form {
320
+ display: flex;
321
+ flex-direction: column;
322
+ gap: 8px;
323
+ padding: 12px;
324
+ background: var(--bg-elev-2);
325
+ border: 1px solid var(--accent-border);
326
+ border-radius: var(--radius);
327
+ }
328
+
329
+ .env-var-add-row {
330
+ display: flex;
331
+ gap: var(--space-2);
332
+ align-items: center;
333
+ flex-wrap: wrap;
334
+ }
335
+
336
+ /* Memory section */
337
+ .memory-field-row {
338
+ display: grid;
339
+ grid-template-columns: 140px 1fr;
340
+ gap: var(--space-3);
341
+ align-items: flex-start;
342
+ }
343
+
344
+ .memory-field-label {
345
+ font-size: 12px;
346
+ font-weight: 500;
347
+ color: var(--text-dim);
348
+ padding-top: 8px;
349
+ }
350
+
351
+ /* System LLM selector */
352
+ .system-llm-card {
353
+ display: flex;
354
+ flex-direction: column;
355
+ gap: var(--space-3);
356
+ }
357
+
358
+ /* Skills placeholder */
359
+ .skills-paths-list {
360
+ display: flex;
361
+ flex-direction: column;
362
+ gap: 6px;
363
+ }
364
+
365
+ .skill-path-row {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: var(--space-3);
369
+ padding: 6px 10px;
370
+ background: var(--bg-elev-2);
371
+ border: 1px solid var(--border);
372
+ border-radius: var(--radius);
373
+ font-size: 12px;
374
+ }
375
+
376
+ .skill-path-name {
377
+ font-family: var(--font-mono);
378
+ font-weight: 600;
379
+ min-width: 160px;
380
+ }
381
+
382
+ .skill-path-url {
383
+ flex: 1;
384
+ color: var(--text-dim);
385
+ overflow: hidden;
386
+ text-overflow: ellipsis;
387
+ white-space: nowrap;
388
+ }
389
+
390
+ /* MiniMax usage section */
391
+ .minimax-usage-placeholder {
392
+ display: flex;
393
+ align-items: center;
394
+ gap: var(--space-3);
395
+ padding: 12px 16px;
396
+ background: var(--bg-elev-2);
397
+ border: 1px dashed var(--border);
398
+ border-radius: var(--radius-md);
399
+ font-size: 13px;
400
+ color: var(--text-dim);
401
+ }
402
+
403
+ /* ─── Shared field-row (used in memory + others) ─── */
404
+ .field-row {
405
+ display: grid;
406
+ grid-template-columns: 140px 1fr;
407
+ gap: var(--space-3);
408
+ align-items: flex-start;
409
+ }
410
+
411
+ @media (max-width: 600px) {
412
+ .field-row {
413
+ grid-template-columns: 1fr;
414
+ }
415
+ .memory-field-row {
416
+ grid-template-columns: 1fr;
417
+ }
418
+ }
@@ -0,0 +1,302 @@
1
+ /* ============================================================================
2
+ * src/web/styles/skills.css
3
+ *
4
+ * v4.0.0 — Styles for the skills browser (Skills.tsx).
5
+ * Reuses dashboard CSS variables (--accent, --bg, --bg-1, --border, --text,
6
+ * --text-dim, --radius, --space-*, etc.) and matches existing patterns.
7
+ * ========================================================================== */
8
+
9
+ /* ── View layout ──────────────────────────────────────────────────────────── */
10
+ .view-skills {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--space-4, 16px);
14
+ padding: 16px 20px 32px;
15
+ max-width: 1280px;
16
+ margin: 0 auto;
17
+ width: 100%;
18
+ }
19
+
20
+ .view-skills .view-header {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: flex-end;
24
+ gap: 16px;
25
+ flex-wrap: wrap;
26
+ }
27
+
28
+ .view-skills .view-actions {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 8px;
32
+ }
33
+
34
+ /* ── Search input (header) ───────────────────────────────────────────────── */
35
+ .view-skills .search-input {
36
+ position: relative;
37
+ display: flex;
38
+ align-items: center;
39
+ }
40
+
41
+ .view-skills .search-input svg {
42
+ position: absolute;
43
+ left: 10px;
44
+ color: var(--text-dim);
45
+ pointer-events: none;
46
+ }
47
+
48
+ .view-skills .search-input .input {
49
+ padding-left: 32px;
50
+ width: 260px;
51
+ }
52
+
53
+ /* ── Source tabs ──────────────────────────────────────────────────────────── */
54
+ .skills-tabs {
55
+ display: flex;
56
+ gap: 4px;
57
+ border-bottom: 1px solid var(--border);
58
+ padding-bottom: 0;
59
+ }
60
+
61
+ .skills-tab {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 6px;
65
+ padding: 8px 14px;
66
+ background: transparent;
67
+ border: 1px solid transparent;
68
+ border-bottom: none;
69
+ border-radius: var(--radius) var(--radius) 0 0;
70
+ color: var(--text-dim);
71
+ font-size: 13px;
72
+ font-weight: 500;
73
+ cursor: pointer;
74
+ transition: background var(--motion-fast), color var(--motion-fast);
75
+ position: relative;
76
+ bottom: -1px;
77
+ }
78
+
79
+ .skills-tab:hover {
80
+ background: var(--bg-1);
81
+ color: var(--text);
82
+ }
83
+
84
+ .skills-tab-active {
85
+ background: var(--bg-1);
86
+ border-color: var(--border);
87
+ color: var(--accent);
88
+ }
89
+
90
+ .skills-tab-count {
91
+ background: var(--bg-2);
92
+ border-radius: 10px;
93
+ font-size: 11px;
94
+ padding: 1px 6px;
95
+ color: var(--text-dim);
96
+ }
97
+
98
+ .skills-tab-active .skills-tab-count {
99
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
100
+ color: var(--accent);
101
+ }
102
+
103
+ /* ── Section ─────────────────────────────────────────────────────────────── */
104
+ .skills-section {
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: var(--space-3, 12px);
108
+ }
109
+
110
+ .skills-section-title {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 6px;
114
+ font-size: 13px;
115
+ font-weight: 600;
116
+ color: var(--text-dim);
117
+ text-transform: uppercase;
118
+ letter-spacing: 0.05em;
119
+ margin: 0;
120
+ }
121
+
122
+ /* ── Skills grid ────────────────────────────────────────────────────────── */
123
+ .skills-grid {
124
+ display: grid;
125
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
126
+ gap: var(--space-3, 12px);
127
+ }
128
+
129
+ /* ── Skill card ─────────────────────────────────────────────────────────── */
130
+ .skill-card {
131
+ display: flex;
132
+ flex-direction: column;
133
+ gap: 10px;
134
+ padding: 14px 16px;
135
+ cursor: default;
136
+ }
137
+
138
+ .skill-card-head {
139
+ display: flex;
140
+ align-items: flex-start;
141
+ gap: 10px;
142
+ }
143
+
144
+ .skill-card-icon {
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ width: 36px;
149
+ height: 36px;
150
+ border-radius: var(--radius);
151
+ flex-shrink: 0;
152
+ color: var(--accent);
153
+ }
154
+
155
+ .skill-card-title-area {
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 4px;
159
+ min-width: 0;
160
+ }
161
+
162
+ .skill-card-title {
163
+ font-size: 14px;
164
+ font-weight: 600;
165
+ color: var(--text);
166
+ line-height: 1.3;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ white-space: nowrap;
170
+ }
171
+
172
+ .skill-card-desc {
173
+ font-size: 13px;
174
+ color: var(--text-dim);
175
+ line-height: 1.5;
176
+ margin: 0;
177
+ display: -webkit-box;
178
+ -webkit-line-clamp: 3;
179
+ -webkit-box-orient: vertical;
180
+ overflow: hidden;
181
+ }
182
+
183
+ .skill-card-actions {
184
+ display: flex;
185
+ gap: 6px;
186
+ margin-top: auto;
187
+ }
188
+
189
+ /* ── Source badge ────────────────────────────────────────────────────────── */
190
+ .skill-source-badge {
191
+ display: inline-flex;
192
+ align-items: center;
193
+ padding: 2px 8px;
194
+ border-radius: 10px;
195
+ font-size: 11px;
196
+ font-weight: 600;
197
+ letter-spacing: 0.03em;
198
+ text-transform: uppercase;
199
+ width: fit-content;
200
+ }
201
+
202
+ .skill-source-badge[data-source="shipped"] {
203
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
204
+ color: var(--accent);
205
+ }
206
+
207
+ .skill-source-badge[data-source="user"] {
208
+ background: color-mix(in srgb, var(--success, #22c55e) 12%, transparent);
209
+ color: var(--success, #22c55e);
210
+ }
211
+
212
+ .skill-source-badge[data-source="project"] {
213
+ background: color-mix(in srgb, var(--warning, #f59e0b) 12%, transparent);
214
+ color: var(--warning, #f59e0b);
215
+ }
216
+
217
+ /* ── Skeleton card ───────────────────────────────────────────────────────── */
218
+ .skill-card-skeleton {
219
+ height: 140px;
220
+ background: linear-gradient(
221
+ 90deg,
222
+ var(--bg-1) 25%,
223
+ var(--bg-2) 50%,
224
+ var(--bg-1) 75%
225
+ );
226
+ background-size: 200% 100%;
227
+ animation: skills-shimmer 1.4s ease-in-out infinite;
228
+ border-radius: var(--radius);
229
+ }
230
+
231
+ @keyframes skills-shimmer {
232
+ 0% { background-position: 200% 0; }
233
+ 100% { background-position: -200% 0; }
234
+ }
235
+
236
+ /* ── Skill detail modal ──────────────────────────────────────────────────── */
237
+ .skill-detail {
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: 14px;
241
+ }
242
+
243
+ .skill-detail-meta {
244
+ display: flex;
245
+ align-items: center;
246
+ gap: 10px;
247
+ flex-wrap: wrap;
248
+ }
249
+
250
+ .skill-detail-desc {
251
+ font-size: 14px;
252
+ color: var(--text);
253
+ line-height: 1.6;
254
+ margin: 0;
255
+ padding: 12px;
256
+ background: var(--bg-1);
257
+ border-radius: var(--radius);
258
+ border-left: 3px solid var(--accent);
259
+ }
260
+
261
+ .skill-detail-body {
262
+ max-height: 420px;
263
+ overflow-y: auto;
264
+ border: 1px solid var(--border);
265
+ border-radius: var(--radius);
266
+ }
267
+
268
+ .skill-body-pre {
269
+ margin: 0;
270
+ padding: 14px;
271
+ font-family: var(--mono);
272
+ font-size: 12px;
273
+ line-height: 1.6;
274
+ color: var(--text);
275
+ white-space: pre-wrap;
276
+ word-break: break-word;
277
+ background: var(--bg-1);
278
+ }
279
+
280
+ /* ── Highlight ────────────────────────────────────────────────────────────── */
281
+ .skill-highlight {
282
+ background: color-mix(in srgb, var(--accent) 25%, transparent);
283
+ color: var(--accent);
284
+ border-radius: 2px;
285
+ padding: 0 1px;
286
+ }
287
+
288
+ /* ── Footer ──────────────────────────────────────────────────────────────── */
289
+ .view-skills .view-footer {
290
+ padding-top: var(--space-3, 12px);
291
+ border-top: 1px solid var(--border);
292
+ color: var(--text-dim);
293
+ font-size: 12px;
294
+ }
295
+
296
+ /* ── View loading ────────────────────────────────────────────────────────── */
297
+ .view-loading {
298
+ display: flex;
299
+ justify-content: center;
300
+ align-items: center;
301
+ padding: 48px;
302
+ }