@kupola/kupola 1.2.0 → 1.4.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -286
  3. package/adapters/axios.d.ts +34 -0
  4. package/adapters/axios.js +122 -0
  5. package/adapters/navios-http.d.ts +110 -0
  6. package/adapters/navios-http.js +151 -0
  7. package/css/components-ext.css +157 -0
  8. package/css/components.css +69 -0
  9. package/css/theme-dark.css +5 -5
  10. package/css/utilities.css +119 -1
  11. package/dist/css/accessibility.css +119 -0
  12. package/dist/css/animations.css +224 -0
  13. package/dist/css/brand-themes.css +300 -0
  14. package/dist/css/colors_and_type.css +441 -0
  15. package/dist/css/components-ext.css +4165 -0
  16. package/dist/css/components.css +1483 -0
  17. package/dist/css/kupola.css +1 -12
  18. package/dist/css/kupola.min.css +1 -0
  19. package/dist/css/responsive.css +697 -0
  20. package/dist/css/scaffold.css +145 -0
  21. package/dist/css/states.css +316 -0
  22. package/dist/css/theme-dark.css +296 -0
  23. package/dist/css/theme-light.css +296 -0
  24. package/dist/css/utilities.css +171 -0
  25. package/dist/icons.svg +284 -0
  26. package/dist/kupola.cjs.js +17409 -257
  27. package/dist/kupola.cjs.js.map +1 -1
  28. package/dist/kupola.css +9000 -0
  29. package/dist/kupola.esm.js +17183 -7597
  30. package/dist/kupola.esm.js.map +1 -1
  31. package/dist/kupola.min.css +1 -0
  32. package/dist/kupola.min.js +2 -0
  33. package/dist/kupola.min.js.map +1 -0
  34. package/dist/kupola.umd.js +17415 -257
  35. package/dist/kupola.umd.js.map +1 -1
  36. package/dist/plugins/vite-plugin-kupola.js +120 -0
  37. package/dist/types/kupola.d.ts +421 -323
  38. package/js/calendar.js +334 -25
  39. package/js/carousel.js +182 -48
  40. package/js/collapse.js +148 -34
  41. package/js/color-picker.js +416 -108
  42. package/js/component.js +8 -19
  43. package/js/countdown.js +9 -8
  44. package/js/data-bind.js +73 -16
  45. package/js/datepicker.js +488 -110
  46. package/js/depends.js +710 -0
  47. package/js/dialog.js +4 -2
  48. package/js/drawer.js +172 -8
  49. package/js/dropdown.js +272 -17
  50. package/js/dynamic-tags.js +156 -40
  51. package/js/fileupload.js +9 -8
  52. package/js/form.js +280 -254
  53. package/js/global-events.js +281 -188
  54. package/js/heatmap.js +10 -7
  55. package/js/i18n.js +18 -10
  56. package/js/icons.js +141 -161
  57. package/js/image-preview.js +146 -2
  58. package/js/initializer.js +151 -71
  59. package/js/kupola-core.js +123 -45
  60. package/js/kupola-lifecycle.js +13 -11
  61. package/js/message.js +8 -1
  62. package/js/modal.js +207 -59
  63. package/js/notification.js +8 -1
  64. package/js/numberinput.js +9 -8
  65. package/js/pagination.js +263 -0
  66. package/js/registry.js +29 -12
  67. package/js/select.js +482 -27
  68. package/js/slide-captcha.js +11 -2
  69. package/js/slider.js +442 -25
  70. package/js/statcard.js +9 -7
  71. package/js/table.js +1210 -0
  72. package/js/tag.js +268 -14
  73. package/js/theme-standalone.js +88 -0
  74. package/js/theme.js +14 -43
  75. package/js/timepicker.js +335 -66
  76. package/js/tooltip.js +317 -86
  77. package/js/utils.js +6 -2
  78. package/js/validation.js +6 -2
  79. package/js/virtual-list.js +11 -7
  80. package/js/web-components.js +288 -0
  81. package/package.json +81 -67
  82. package/plugins/vite-plugin-kupola.js +120 -0
  83. package/scripts/build-css.cjs +113 -0
  84. package/scripts/build-svg-sprite.cjs +107 -0
  85. package/types/kupola.d.ts +421 -323
  86. package/CHANGELOG.md +0 -130
  87. package/INTEGRATION.md +0 -440
  88. package/PROJECT_SUMMARY.md +0 -312
  89. package/SKILL.md +0 -572
  90. package/dist/utils/utils/Kupola.cs +0 -77
  91. package/dist/utils/utils/Kupola.java +0 -104
  92. package/dist/utils/utils/kupola.go +0 -120
  93. package/dist/utils/utils/kupola.js +0 -63
  94. package/dist/utils/utils/kupola.py +0 -1392
  95. package/dist/utils/utils/kupola.rb +0 -69
  96. package/js/composition-api.js +0 -458
  97. package/js/error-handler.js +0 -181
  98. package/js/http.js +0 -419
  99. package/js/kupola-devtools.js +0 -598
  100. package/js/performance.js +0 -250
  101. package/js/router.js +0 -396
  102. package/js/security.js +0 -189
  103. package/js/test-utils.js +0 -251
  104. package/templates/base.html +0 -30
  105. package/templates/base_dashboard.html +0 -99
  106. package/utils/Kupola.cs +0 -77
  107. package/utils/Kupola.java +0 -104
  108. package/utils/kupola.go +0 -120
  109. package/utils/kupola.js +0 -63
  110. package/utils/kupola.py +0 -1392
  111. package/utils/kupola.rb +0 -69
@@ -0,0 +1,1483 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ components.css — Design System Component Definitions
3
+ Auto-extracted from preview/component-*.html
4
+ DO NOT EDIT MANUALLY — regenerate via extract-components-css.mjs
5
+ ═══════════════════════════════════════════════════════════════ */
6
+
7
+ /* ── Activity Rail ─────────────────────────────────────────── */
8
+ /* ===== Activity Rail ===== */
9
+ .ds-activityrail {
10
+ display: inline-flex;
11
+ flex-direction: column;
12
+ align-items: center;
13
+ gap: var(--spacer-4);
14
+ width: 48px;
15
+ padding: var(--spacer-8) 0;
16
+ background: var(--bg-base-secondary);
17
+ border-right: 1px solid var(--border-neutral-l1);
18
+ }
19
+ .ds-activityrail__btn {
20
+ position: relative;
21
+ display: inline-flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ width: 36px;
25
+ height: 36px;
26
+ border-radius: var(--radius-8);
27
+ background: transparent;
28
+ border: none;
29
+ cursor: pointer;
30
+ }
31
+ .ds-activityrail__btn:hover { background: var(--bg-overlay-l2); }
32
+ .ds-activityrail__btn.is-active {
33
+ background: var(--bg-overlay-l3);
34
+ }
35
+ .ds-activityrail__btn.is-active::before {
36
+ content: "";
37
+ position: absolute;
38
+ left: -8px;
39
+ top: 50%;
40
+ transform: translateY(-50%);
41
+ width: 3px;
42
+ height: 20px;
43
+ border-radius: var(--radius-full);
44
+ background: var(--bg-brand);
45
+ }
46
+ .ds-activityrail__divider {
47
+ width: 24px;
48
+ height: 1px;
49
+ margin: var(--spacer-4) 0;
50
+ background: var(--border-neutral-l2);
51
+ }
52
+ .ds-activityrail__spacer { flex: 1; }
53
+
54
+ /* ── Alert ─────────────────────────────────────────────────── */
55
+ /* ===== Alert / Banner ===== */
56
+ .ds-alert {
57
+ display: flex; gap: var(--spacer-12);
58
+ padding: var(--spacer-12) var(--spacer-16);
59
+ background: var(--bg-base-secondary);
60
+ border: 1px solid var(--border-neutral-l1);
61
+ border-radius: var(--radius-4);
62
+ color: var(--text-default);
63
+ align-items: flex-start;
64
+ }
65
+ .ds-alert__icon { flex-shrink: 0; margin-top: 1px; display: inline-flex; }
66
+ .ds-alert--normal { background: var(--bg-overlay-l1); border-color: var(--border-neutral-l1); }
67
+ .ds-alert--normal .ds-alert__icon, .ds-alert--normal .icon { filter: brightness(0) saturate(100%) invert(50%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(90%) contrast(85%); }
68
+ .ds-alert--success { background: var(--status-success-surface-l1); border-color: var(--status-success-default); }
69
+ .ds-alert--success .ds-alert__icon, .ds-alert--success .icon { filter: brightness(0) saturate(100%) invert(46%) sepia(58%) saturate(223%) hue-rotate(92deg) brightness(90%) contrast(93%); }
70
+ .ds-alert--warning { background: var(--status-warning-surface-l1); border-color: var(--status-warning-default); }
71
+ .ds-alert--warning .ds-alert__icon, .ds-alert--warning .icon { filter: brightness(0) saturate(100%) invert(70%) sepia(65%) saturate(469%) hue-rotate(359deg) brightness(98%) contrast(92%); }
72
+ .ds-alert--danger { background: var(--status-error-surface-l1); border-color: var(--status-error-default); }
73
+ .ds-alert--danger .ds-alert__icon, .ds-alert--danger .icon { filter: brightness(0) saturate(100%) invert(23%) sepia(93%) saturate(707%) hue-rotate(349deg) brightness(96%) contrast(96%); }
74
+ .ds-alert--info { background: var(--status-info-surface-l1); border-color: var(--status-info-default); }
75
+ .ds-alert--info .ds-alert__icon, .ds-alert--info .icon { color: var(--status-info-default); filter: none; }
76
+ .ds-alert__title { font-weight: var(--font-weight-medium, 500); margin-bottom: var(--spacer-4); }
77
+ .ds-alert__desc { color: var(--text-secondary); font-size: var(--body-sm-font-size); }
78
+
79
+ /* ── Avatar ────────────────────────────────────────────────── */
80
+ /* ===== Avatar ===== */
81
+ .ds-avatar {
82
+ display: inline-flex; align-items: center; justify-content: center;
83
+ width: 32px; height: 32px; border-radius: 50%;
84
+ background: var(--bg-overlay-l3);
85
+ color: var(--text-default);
86
+ font-size: var(--body-sm-font-size); font-weight: var(--font-weight-strong);
87
+ flex-shrink: 0;
88
+ }
89
+ .ds-avatar--sm { width: 24px; height: 24px; font-size: var(--body-xs-font-size); }
90
+ .ds-avatar--lg { width: 40px; height: 40px; }
91
+ .ds-avatar--square { border-radius: var(--radius-4); }
92
+ .ds-avatar--accent { background: var(--bg-brand); color: var(--text-onbrand); }
93
+
94
+ /* ── Buttons ───────────────────────────────────────────────── */
95
+ /* ===== Buttons =====
96
+ * Hierarchy (one BRAND/green CTA per page max):
97
+ * primary → high-contrast neutral (white). Default "main action".
98
+ * secondary→ neutral surface, used for any neighbour action.
99
+ * tertiary → ghost (no fill, no border), used for dense toolbars / inline.
100
+ * danger / danger-subtle / warning / brand / link.
101
+ * Sizes follow the Figma "Sm / Default / Large": 24 / 28 / 32 / 36
102
+ * Geek hard-edged — radii are tight (4 / 6 max).
103
+ */
104
+ .ds-btn {
105
+ display: inline-flex; align-items: center; justify-content: center;
106
+ gap: var(--spacer-6);
107
+ padding: 0 var(--spacer-12); height: 28px;
108
+ border-radius: var(--radius-4);
109
+ border: 1px solid transparent;
110
+ cursor: pointer; user-select: none; white-space: nowrap;
111
+ font-family: var(--body-sm-strong-font-family);
112
+ font-size: var(--body-sm-strong-font-size);
113
+ line-height: 1;
114
+ font-weight: var(--body-sm-strong-font-weight);
115
+ transition: background .12s ease, color .12s ease, border-color .12s ease, opacity .12s ease;
116
+ position: relative;
117
+ }
118
+ .ds-btn .icon { color: currentColor; }
119
+ .ds-btn--sm { height: 24px; padding: 0 var(--spacer-8); border-radius: var(--radius-4); font-size: var(--body-xs-font-size); }
120
+ .ds-btn--md { height: 28px; padding: 0 var(--spacer-12); border-radius: var(--radius-4); }
121
+ .ds-btn--lg { height: 32px; padding: 0 var(--spacer-16); border-radius: var(--radius-4); font-size: var(--body-base-font-size); }
122
+
123
+ /* PRIMARY = high-contrast neutral (white). Use this when you don't need
124
+ * brand emphasis. Page rule: at most ONE brand button per page; every other
125
+ * "main" action falls back to this neutral primary. */
126
+ .ds-btn--primary { background: var(--bg-brand); color: var(--text-onbrand); border-color: var(--bg-brand); }
127
+ .ds-btn--primary:hover { background: var(--bg-brand-hover); border-color: var(--bg-brand-hover); }
128
+ .ds-btn--primary:active { background: var(--bg-brand); opacity: 0.8; }
129
+ .ds-btn--primary[disabled] { background: var(--bg-brand-disabled); color: var(--text-tertiary); border-color: var(--border-neutral-l1); cursor: not-allowed; }
130
+
131
+ /* SECONDARY = neutral surface */
132
+ .ds-btn--secondary { background: var(--bg-overlay-l2); color: var(--text-default); border-color: var(--border-neutral-l1); }
133
+ .ds-btn--secondary:hover { background: var(--bg-overlay-l3); border-color: var(--border-neutral-l2); }
134
+ .ds-btn--secondary:active { background: var(--bg-overlay-l1); }
135
+ .ds-btn--secondary[disabled] { color: var(--text-tertiary); cursor: not-allowed; opacity: .6; }
136
+
137
+ .ds-btn--tertiary { background: transparent; color: var(--text-default); border-color: transparent; }
138
+ .ds-btn--tertiary:hover { background: var(--bg-overlay-l2); }
139
+ .ds-btn--tertiary:active { background: var(--bg-overlay-l1); }
140
+ .ds-btn--tertiary[disabled] { color: var(--text-tertiary); cursor: not-allowed; }
141
+
142
+ .ds-btn--ghost { background: transparent; color: var(--text-default); border-color: var(--border-neutral-l2); }
143
+ .ds-btn--ghost:hover { background: var(--bg-overlay-l1); border-color: var(--border-neutral-l3); }
144
+ .ds-btn--ghost:active { background: var(--bg-overlay-l2); }
145
+ .ds-btn--ghost[disabled] { color: var(--text-tertiary); border-color: var(--border-neutral-l1); cursor: not-allowed; }
146
+
147
+ /* DANGER strong (filled) */
148
+ .ds-btn--danger,
149
+ .ds-btn--danger-strong {
150
+ background: var(--status-error-default); color: var(--special-white);
151
+ border-color: var(--status-error-default);
152
+ }
153
+ .ds-btn--danger:hover,
154
+ .ds-btn--danger-strong:hover { filter: brightness(0.92); }
155
+ .ds-btn--danger:active,
156
+ .ds-btn--danger-strong:active { filter: brightness(0.84); }
157
+ .ds-btn--danger[disabled],
158
+ .ds-btn--danger-strong[disabled] { opacity: .5; cursor: not-allowed; }
159
+
160
+ /* DANGER subtle (tinted surface) */
161
+ .ds-btn--danger-subtle {
162
+ background: var(--status-error-surface-l1);
163
+ color: var(--status-error-default);
164
+ border-color: var(--status-error-surface-l2);
165
+ }
166
+ .ds-btn--danger-subtle:hover { background: var(--status-error-surface-l2); }
167
+ .ds-btn--danger-subtle:active { background: var(--status-error-surface-l1); }
168
+ .ds-btn--danger-subtle[disabled] { opacity: .5; cursor: not-allowed; }
169
+
170
+ /* WARNING */
171
+ .ds-btn--warning {
172
+ background: var(--status-warning-default); color: var(--text-onbrand);
173
+ border-color: var(--status-warning-default);
174
+ }
175
+ .ds-btn--warning:hover { filter: brightness(0.94); }
176
+ .ds-btn--warning:active { filter: brightness(0.86); }
177
+ .ds-btn--warning[disabled] { opacity: .5; cursor: not-allowed; }
178
+
179
+ .ds-btn--info {
180
+ background: var(--status-primary-default); color: var(--text-onbrand);
181
+ border-color: var(--status-primary-default);
182
+ }
183
+ .ds-btn--info:hover { filter: brightness(0.94); }
184
+ .ds-btn--info:active { filter: brightness(0.86); }
185
+ .ds-btn--info[disabled] { opacity: .5; cursor: not-allowed; }
186
+
187
+ .ds-btn--success {
188
+ background: var(--status-success-default); color: var(--text-onbrand);
189
+ border-color: var(--status-success-default);
190
+ }
191
+ .ds-btn--success:hover { filter: brightness(0.94); }
192
+ .ds-btn--success:active { filter: brightness(0.86); }
193
+ .ds-btn--success[disabled] { opacity: .5; cursor: not-allowed; }
194
+
195
+ .ds-btn--error {
196
+ background: var(--status-error-default); color: var(--text-onbrand);
197
+ border-color: var(--status-error-default);
198
+ }
199
+ .ds-btn--error:hover { filter: brightness(0.94); }
200
+ .ds-btn--error:active { filter: brightness(0.86); }
201
+ .ds-btn--error[disabled] { opacity: .5; cursor: not-allowed; }
202
+
203
+ .ds-btn--confirm {
204
+ background: var(--bg-brand); color: var(--text-onbrand);
205
+ border-color: var(--bg-brand);
206
+ }
207
+ .ds-btn--confirm:hover { background: var(--bg-brand-hover); border-color: var(--bg-brand-hover); }
208
+ .ds-btn--confirm:active { filter: brightness(0.92); }
209
+ .ds-btn--confirm[disabled] { background: var(--bg-brand-disabled, var(--bg-overlay-l3)); border-color: transparent; color: var(--text-tertiary); cursor: not-allowed; }
210
+
211
+ /* BRAND — exactly the Figma "Brand" row. Use AT MOST one per page. */
212
+ .ds-btn--brand { background: var(--bg-brand); color: var(--text-onbrand); border-color: var(--bg-brand); }
213
+ .ds-btn--brand:hover { background: var(--bg-brand-hover); border-color: var(--bg-brand-hover); }
214
+ .ds-btn--brand:active { filter: brightness(0.92); }
215
+ .ds-btn--brand[disabled] { background: var(--bg-brand-disabled, var(--bg-overlay-l3)); border-color: transparent; color: var(--text-tertiary); cursor: not-allowed; }
216
+
217
+ /* LINK */
218
+ .ds-btn--link { background: transparent; color: var(--text-default); border-color: transparent; padding: 0; height: auto; }
219
+ .ds-btn--link:hover { color: var(--text-default-hover); text-decoration: underline; }
220
+ .ds-btn--link[disabled] { color: var(--text-tertiary); text-decoration: none; cursor: not-allowed; }
221
+
222
+ /* ICON BUTTON — square */
223
+ .ds-btn--icon { padding: 0; width: 28px; justify-content: center; }
224
+ .ds-btn--icon.ds-btn--sm { width: 24px; }
225
+ .ds-btn--icon.ds-btn--lg { width: 32px; }
226
+
227
+ /* BUTTON GROUP — segmented, hard edged */
228
+ .ds-btn-group { display: inline-flex; }
229
+ .ds-btn-group > .ds-btn { border-radius: 0; margin-left: -1px; }
230
+ .ds-btn-group > .ds-btn:first-child { border-top-left-radius: var(--radius-4); border-bottom-left-radius: var(--radius-4); margin-left: 0; }
231
+ .ds-btn-group > .ds-btn:last-child { border-top-right-radius: var(--radius-4); border-bottom-right-radius: var(--radius-4); }
232
+ .ds-btn-group > .ds-btn.is-active { background: var(--bg-brand); color: var(--text-onbrand); border-color: var(--bg-brand); }
233
+
234
+ .ds-btn__badge {
235
+ position: absolute;
236
+ top: -6px;
237
+ right: -6px;
238
+ min-width: 16px;
239
+ height: 16px;
240
+ padding: 0 4px;
241
+ font-size: 10px;
242
+ font-weight: 600;
243
+ color: var(--text-onbrand);
244
+ background: var(--bg-brand);
245
+ border-radius: 8px;
246
+ display: inline-flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ white-space: nowrap;
250
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
251
+ }
252
+
253
+ /* ── Cards ─────────────────────────────────────────────────── */
254
+ /* ===== Card ===== */
255
+ .ds-card {
256
+ background: var(--bg-base-secondary);
257
+ border: 1px solid var(--border-neutral-l1);
258
+ border-radius: var(--radius-4);
259
+ padding: var(--spacer-24);
260
+ }
261
+ .ds-card__title { font-size: var(--heading-xs-font-size); line-height: var(--heading-xs-line-height); font-weight: var(--heading-xs-font-weight); margin-bottom: var(--spacer-8); }
262
+ .ds-card__desc { font-size: var(--body-sm-font-size); line-height: var(--body-sm-line-height); color: var(--text-secondary); }
263
+
264
+ /* ── Chat Composer ─────────────────────────────────────────── */
265
+ /* ===== Chat Composer ===== */
266
+ .ds-composer {
267
+ display: flex;
268
+ flex-direction: column;
269
+ gap: var(--spacer-8);
270
+ width: 100%;
271
+ max-width: 720px;
272
+ padding: var(--spacer-12);
273
+ background: var(--bg-overlay-l1);
274
+ border: 1px solid var(--border-neutral-l2);
275
+ border-radius: var(--radius-10);
276
+ }
277
+ .ds-composer:focus-within {
278
+ border-color: var(--border-brand);
279
+ }
280
+ .ds-composer__input {
281
+ width: 100%;
282
+ min-height: 56px;
283
+ max-height: 200px;
284
+ resize: vertical;
285
+ border: none;
286
+ outline: none;
287
+ background: transparent;
288
+ color: var(--text-default);
289
+ font-size: var(--body-md-font-size);
290
+ line-height: var(--body-md-line-height);
291
+ font-weight: var(--body-md-font-weight);
292
+ }
293
+ .ds-composer__input::placeholder {
294
+ color: var(--text-tertiary);
295
+ }
296
+ .ds-composer__toolbar {
297
+ display: flex;
298
+ align-items: center;
299
+ justify-content: space-between;
300
+ gap: var(--spacer-8);
301
+ }
302
+ .ds-composer__tools {
303
+ display: flex;
304
+ align-items: center;
305
+ gap: var(--spacer-4);
306
+ }
307
+ .ds-composer__icon-btn {
308
+ display: inline-flex;
309
+ align-items: center;
310
+ justify-content: center;
311
+ width: 32px;
312
+ height: 32px;
313
+ padding: 0;
314
+ border: none;
315
+ border-radius: var(--radius-6);
316
+ background: transparent;
317
+ cursor: pointer;
318
+ }
319
+ .ds-composer__icon-btn:hover {
320
+ background: var(--bg-overlay-l2);
321
+ }
322
+ .ds-composer__model {
323
+ display: inline-flex;
324
+ align-items: center;
325
+ gap: var(--spacer-4);
326
+ height: 28px;
327
+ padding: 0 var(--spacer-8);
328
+ border: 1px solid var(--border-neutral-l2);
329
+ border-radius: var(--radius-full);
330
+ background: var(--bg-overlay-l2);
331
+ color: var(--text-secondary);
332
+ font-size: var(--body-sm-font-size);
333
+ line-height: var(--body-sm-line-height);
334
+ cursor: pointer;
335
+ }
336
+ .ds-composer__model:hover {
337
+ background: var(--bg-overlay-l3);
338
+ color: var(--text-default);
339
+ }
340
+ .ds-composer__actions {
341
+ display: flex;
342
+ align-items: center;
343
+ gap: var(--spacer-8);
344
+ }
345
+ .ds-composer__send {
346
+ display: inline-flex;
347
+ align-items: center;
348
+ justify-content: center;
349
+ width: 36px;
350
+ height: 36px;
351
+ padding: 0;
352
+ border: none;
353
+ border-radius: var(--radius-8);
354
+ background: var(--bg-brand);
355
+ cursor: pointer;
356
+ }
357
+ .ds-composer__send:hover {
358
+ background: var(--bg-brand-hover);
359
+ }
360
+
361
+ /* ── Dialog ────────────────────────────────────────────────── */
362
+ /* ===== Dialog / Modal ===== */
363
+ .ds-backdrop {
364
+ position: relative;
365
+ background: rgba(0,0,0,.5);
366
+ border: 1px solid var(--border-neutral-l1);
367
+ padding: var(--spacer-32) var(--spacer-24);
368
+ display: flex; align-items: center; justify-content: center;
369
+ }
370
+ .ds-dialog {
371
+ background: var(--bg-base-secondary);
372
+ border: 1px solid var(--border-neutral-l1);
373
+ border-radius: var(--radius-4);
374
+ width: 100%; max-width: 420px;
375
+ overflow: hidden;
376
+ }
377
+ .ds-dialog__head {
378
+ padding: var(--spacer-16) var(--spacer-24);
379
+ display: flex; align-items: center; justify-content: space-between;
380
+ border-bottom: 1px solid var(--border-neutral-l1);
381
+ }
382
+ .ds-dialog__title { font-size: var(--heading-xs-font-size); font-weight: var(--heading-xs-font-weight); color: var(--text-default); }
383
+ .ds-dialog__close {
384
+ width: 24px; height: 24px;
385
+ display: inline-flex; align-items: center; justify-content: center;
386
+ background: transparent; border: none; color: var(--icon-secondary);
387
+ cursor: pointer; border-radius: var(--radius-4);
388
+ }
389
+ .ds-dialog__close:hover { background: var(--bg-overlay-l2); color: var(--icon-default); }
390
+ .ds-dialog__body { padding: var(--spacer-16) var(--spacer-24); color: var(--text-secondary); font-size: var(--body-sm-font-size); line-height: var(--body-sm-line-height); }
391
+ .ds-dialog__foot {
392
+ padding: var(--spacer-12) var(--spacer-24);
393
+ display: flex; justify-content: flex-end; gap: var(--spacer-8);
394
+ border-top: 1px solid var(--border-neutral-l1);
395
+ }
396
+
397
+ /* ===== Drawer ===== */
398
+ .ds-drawer {
399
+ background: var(--bg-base-secondary);
400
+ border: 1px solid var(--border-neutral-l1);
401
+ border-radius: var(--radius-4);
402
+ width: 100%; max-width: 360px;
403
+ display: flex; flex-direction: column;
404
+ }
405
+ .ds-drawer__head { padding: var(--spacer-16) var(--spacer-24); border-bottom: 1px solid var(--border-neutral-l1); display: flex; justify-content: space-between; align-items: center; }
406
+ .ds-drawer__body { padding: var(--spacer-16) var(--spacer-24); flex: 1; }
407
+
408
+ /* ── Editor Tabs ───────────────────────────────────────────── */
409
+ /* ===== Editor Tabs ===== */
410
+ .ds-editortabs {
411
+ display: flex;
412
+ align-items: stretch;
413
+ border-bottom: 1px solid var(--border-neutral-l1);
414
+ background-color: var(--bg-base-default);
415
+ background-image: linear-gradient(var(--special-bgtabsoverlay), var(--special-bgtabsoverlay));
416
+ }
417
+ .ds-editortab {
418
+ display: inline-flex;
419
+ align-items: center;
420
+ column-gap: 8px;
421
+ padding: 0 14px;
422
+ height: 40px;
423
+ color: var(--text-secondary);
424
+ font-size: 12px;
425
+ font-weight: 500;
426
+ border-right: 1px solid var(--border-neutral-l1);
427
+ cursor: pointer;
428
+ white-space: nowrap;
429
+ background: transparent;
430
+ min-width: 0;
431
+ }
432
+ .ds-editortab:hover {
433
+ color: var(--text-default);
434
+ background-image: linear-gradient(var(--bg-overlay-l1), var(--bg-overlay-l1));
435
+ }
436
+ .ds-editortab.is-active {
437
+ background: var(--bg-base-secondary);
438
+ color: var(--text-default);
439
+ box-shadow: inset 0 1px 0 0 var(--icon-default);
440
+ }
441
+ .ds-editortab.is-active:hover { background: var(--bg-base-secondary); }
442
+ .ds-editortab .ic {
443
+ width: 14px; height: 14px;
444
+ flex-shrink: 0;
445
+ display: inline-flex; align-items: center; justify-content: center;
446
+ }
447
+ .ds-editortab .close {
448
+ width: 16px; height: 16px;
449
+ display: inline-flex; align-items: center; justify-content: center;
450
+ color: var(--icon-tertiary);
451
+ }
452
+ .ds-editortab.is-active .close { color: var(--icon-secondary); }
453
+ .ds-editortabs__spacer { flex: 1; min-width: 0; border-right: 0; }
454
+ .ds-editortabs__actions {
455
+ display: inline-flex;
456
+ align-items: center;
457
+ column-gap: 4px;
458
+ padding: 0 8px;
459
+ color: var(--icon-secondary);
460
+ }
461
+ .ds-editortabs__actions button {
462
+ width: 24px; height: 24px;
463
+ display: inline-flex; align-items: center; justify-content: center;
464
+ background: transparent; border: 0;
465
+ color: inherit;
466
+ cursor: pointer;
467
+ border-radius: 4px;
468
+ }
469
+ .ds-editortabs__actions button:hover {
470
+ color: var(--icon-default);
471
+ background: var(--bg-overlay-l1);
472
+ }
473
+
474
+ /* ── File Tree ─────────────────────────────────────────────── */
475
+ /* ===== File Tree ===== */
476
+ .ds-filetree {
477
+ width: 260px;
478
+ padding: var(--spacer-4);
479
+ background: var(--bg-base-secondary);
480
+ border: 1px solid var(--border-neutral-l1);
481
+ border-radius: var(--radius-6);
482
+ font-size: var(--body-sm-font-size);
483
+ color: var(--text-default);
484
+ }
485
+ .ds-filetree__row {
486
+ display: flex;
487
+ align-items: center;
488
+ gap: var(--spacer-6);
489
+ height: 26px;
490
+ padding: 0 var(--spacer-6);
491
+ padding-left: var(--spacer-6);
492
+ border-radius: var(--radius-4);
493
+ cursor: pointer;
494
+ white-space: nowrap;
495
+ }
496
+ .ds-filetree__row[data-depth="1"] { padding-left: calc(var(--spacer-6) + 16px); }
497
+ .ds-filetree__row[data-depth="2"] { padding-left: calc(var(--spacer-6) + 32px); }
498
+ .ds-filetree__row[data-depth="3"] { padding-left: calc(var(--spacer-6) + 48px); }
499
+ .ds-filetree__row:hover { background: var(--bg-overlay-l2); }
500
+ .ds-filetree__row.is-active {
501
+ background: var(--bg-overlay-l3);
502
+ color: var(--text-default-hover);
503
+ }
504
+ .ds-filetree__chevron {
505
+ display: inline-flex;
506
+ width: 14px;
507
+ height: 14px;
508
+ flex: 0 0 14px;
509
+ }
510
+ .ds-filetree__chevron--leaf { visibility: hidden; }
511
+ .ds-filetree__label { overflow: hidden; text-overflow: ellipsis; }
512
+ .ds-filetree__icon--folder { filter: none; }
513
+ .ds-filetree__icon--ts { color: var(--accent-blue); }
514
+ .ds-filetree__icon--css { color: var(--code-attribute); }
515
+ .ds-filetree__icon--json { color: var(--code-constant); }
516
+
517
+ /* ── Forms ─────────────────────────────────────────────────── */
518
+ /* ===== Input / Search ===== */
519
+ .ds-input {
520
+ display: flex; align-items: center; gap: var(--spacer-8);
521
+ padding: 0 var(--spacer-12); height: 28px;
522
+ background: var(--bg-overlay-l1);
523
+ border: 1px solid var(--border-neutral-l1);
524
+ border-radius: var(--radius-4);
525
+ color: var(--text-default);
526
+ width: 100%;
527
+ font-size: var(--body-sm-font-size); line-height: 1;
528
+ }
529
+ .ds-input:focus-within { border-color: var(--border-brand); background-color: var(--bg-overlay-l2); }
530
+ .ds-input input {
531
+ flex: 1; background: transparent; border: none; outline: none;
532
+ color: var(--text-default); font: inherit;
533
+ }
534
+ .ds-input input::placeholder { color: var(--text-tertiary); }
535
+ .ds-input__icon { color: var(--icon-secondary); display: inline-flex; }
536
+
537
+ .ds-input--sm { height: 22px; font-size: var(--body-xs-font-size); }
538
+ .ds-input--lg { height: 36px; font-size: var(--body-md-font-size); }
539
+
540
+ .ds-input.is-error { border-color: var(--bg-error-default); }
541
+ .ds-input.is-success { border-color: var(--bg-success-default); }
542
+
543
+ .ds-input__status-icon {
544
+ position: absolute;
545
+ right: 12px;
546
+ top: 50%;
547
+ transform: translateY(-50%);
548
+ pointer-events: none;
549
+ }
550
+
551
+ .ds-input__status-icon--success {
552
+ color: var(--bg-success-default);
553
+ }
554
+
555
+ .ds-input__error {
556
+ display: block;
557
+ margin-top: 4px;
558
+ font-size: 12px;
559
+ color: var(--text-error);
560
+ }
561
+
562
+ .ds-input--prefix {
563
+ padding-left: 32px;
564
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239599A6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'></circle><line x1='21' y1='21' x2='16.65' y2='16.65'></line></svg>");
565
+ background-size: 16px 16px;
566
+ background-repeat: no-repeat;
567
+ background-position: left 12px center;
568
+ }
569
+
570
+ .ds-input--textarea {
571
+ height: auto; min-height: 60px;
572
+ resize: vertical;
573
+ padding-top: var(--spacer-8);
574
+ padding-bottom: var(--spacer-8);
575
+ }
576
+
577
+ .ds-search { position: relative; }
578
+
579
+
580
+
581
+ /* ===== Textarea ===== */
582
+ .ds-textarea {
583
+ width: 100%; min-height: 96px; padding: var(--spacer-8) var(--spacer-12);
584
+ background: var(--bg-overlay-l1);
585
+ border: 1px solid var(--border-neutral-l1);
586
+ border-radius: var(--radius-4);
587
+ color: var(--text-default);
588
+ font-family: var(--body-base-font-family);
589
+ font-size: var(--body-sm-font-size);
590
+ line-height: var(--body-base-line-height);
591
+ resize: vertical;
592
+ }
593
+ .ds-textarea:focus { outline: none; border-color: var(--border-brand); }
594
+
595
+ /* ===== Slider ===== */
596
+ .ds-slider { -webkit-appearance: none; appearance: none; width: 100%; }
597
+ .ds-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--text-default); border: 2px solid var(--bg-base-default); box-shadow: 0 0 0 1px var(--border-neutral-l2); cursor: pointer; }
598
+ .ds-slider::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--text-default); border: 2px solid var(--bg-base-default); box-shadow: 0 0 0 1px var(--border-neutral-l2); cursor: pointer; }
599
+
600
+
601
+ .ds-switch-row {
602
+ display: flex; align-items: center; justify-content: space-between;
603
+ gap: var(--spacer-16); padding: var(--spacer-8) 0;
604
+ max-width: 480px;
605
+ }
606
+ .ds-switch-row__text { display: flex; flex-direction: column; gap: var(--spacer-4); }
607
+ .ds-switch-row__title { font-size: var(--body-sm-font-size); color: var(--text-default); }
608
+ .ds-switch-row__hint { font-size: var(--body-xs-font-size); color: var(--text-tertiary); }
609
+
610
+ /* ── Kbd ───────────────────────────────────────────────────── */
611
+ /* ===== Kbd ===== */
612
+ .ds-kbd {
613
+ display: inline-flex;
614
+ align-items: center;
615
+ justify-content: center;
616
+ min-width: 22px;
617
+ height: 22px;
618
+ padding: 0 var(--spacer-6);
619
+ font-family: var(--code-editor-font-family);
620
+ font-size: var(--body-xs-font-size);
621
+ line-height: 1;
622
+ font-weight: var(--font-weight-medium);
623
+ color: var(--text-secondary);
624
+ background: var(--bg-overlay-l2);
625
+ border: 1px solid var(--border-neutral-l2);
626
+ border-bottom-width: 2px;
627
+ border-radius: var(--radius-4);
628
+ }
629
+ .ds-kbd__combo {
630
+ display: inline-flex;
631
+ align-items: center;
632
+ gap: var(--spacer-4);
633
+ }
634
+ .ds-kbd__plus {
635
+ color: var(--text-tertiary);
636
+ font-size: var(--body-xs-font-size);
637
+ }
638
+ .ds-kbd__row {
639
+ display: flex;
640
+ flex-wrap: wrap;
641
+ align-items: center;
642
+ gap: var(--spacer-16);
643
+ }
644
+
645
+ /* ── Menu ──────────────────────────────────────────────────── */
646
+ /* ===== Menu ===== */
647
+ .ds-menu {
648
+ background: var(--bg-menu);
649
+ border: 1px solid var(--border-neutral-l1);
650
+ border-radius: var(--radius-4);
651
+ padding: var(--spacer-4);
652
+ min-width: 180px;
653
+ }
654
+ .ds-menu__item {
655
+ display: flex; align-items: center; gap: var(--spacer-8);
656
+ padding: var(--spacer-6) var(--spacer-8);
657
+ border-radius: var(--radius-2);
658
+ color: var(--text-default);
659
+ font-size: var(--body-sm-font-size);
660
+ cursor: pointer;
661
+ }
662
+ .ds-menu__item .icon { color: var(--icon-secondary); }
663
+ .ds-menu__item:hover { background: var(--bg-overlay-l2); }
664
+ .ds-menu__item--danger { color: var(--status-error-default); }
665
+ .ds-menu__item--danger .icon { color: var(--status-error-default); }
666
+ .ds-menu__divider { height: 1px; background: var(--border-neutral-l1); margin: var(--spacer-4) 0; }
667
+ .ds-menu__shortcut { margin-left: auto; color: var(--text-tertiary); font-size: var(--body-xs-font-size); font-family: var(--code-editor-font-family); }
668
+
669
+ /* ── Nav List ──────────────────────────────────────────────── */
670
+ /* ===== Nav list ===== */
671
+ .ds-navlist {
672
+ display: flex;
673
+ flex-direction: column;
674
+ gap: var(--spacer-16);
675
+ width: 240px;
676
+ padding: var(--spacer-12);
677
+ background: var(--bg-menu);
678
+ border: 1px solid var(--border-neutral-l1);
679
+ border-radius: var(--radius-10);
680
+ }
681
+ .ds-navlist__group {
682
+ display: flex;
683
+ flex-direction: column;
684
+ gap: 2px;
685
+ }
686
+ .ds-navlist__group-title {
687
+ padding: var(--spacer-6) var(--spacer-8);
688
+ font-size: var(--body-xs-font-size);
689
+ line-height: var(--body-xs-line-height);
690
+ font-weight: var(--font-weight-medium);
691
+ letter-spacing: 0.06em;
692
+ text-transform: uppercase;
693
+ color: var(--text-tertiary);
694
+ }
695
+ .ds-navlist__item {
696
+ display: flex;
697
+ align-items: center;
698
+ gap: var(--spacer-8);
699
+ padding: var(--spacer-8);
700
+ border-radius: var(--radius-6);
701
+ font-size: var(--body-sm-font-size);
702
+ line-height: var(--body-sm-line-height);
703
+ font-weight: var(--font-weight-medium);
704
+ color: var(--text-secondary);
705
+ text-decoration: none;
706
+ cursor: pointer;
707
+ }
708
+ .ds-navlist__item:hover {
709
+ background: var(--bg-overlay-l2);
710
+ color: var(--text-default);
711
+ }
712
+ .ds-navlist__item.is-active {
713
+ background: var(--bg-brand);
714
+ color: var(--text-onbrand);
715
+ }
716
+ .ds-navlist__item.is-active .icon {
717
+ filter: brightness(0) saturate(100%) invert(1);
718
+ }
719
+ .ds-navlist__item.is-active:hover {
720
+ background: var(--bg-brand);
721
+ color: var(--text-onbrand);
722
+ }
723
+ .ds-navlist__item.is-active:hover .icon {
724
+ filter: brightness(0) saturate(100%) invert(1);
725
+ }
726
+ .ds-navlist__label { flex: 1; min-width: 0; }
727
+ .ds-navlist__badge {
728
+ font-size: var(--body-xs-font-size);
729
+ font-variant-numeric: tabular-nums;
730
+ color: var(--text-tertiary);
731
+ }
732
+ .ds-navlist__item.is-active .ds-navlist__badge { color: var(--text-onbrand); }
733
+
734
+ /* ── Page Header ───────────────────────────────────────────── */
735
+ /* ===== Page header ===== */
736
+ .ds-pagehead {
737
+ display: flex;
738
+ align-items: flex-start;
739
+ justify-content: space-between;
740
+ gap: var(--spacer-24);
741
+ padding: var(--spacer-24) 0;
742
+ border-bottom: 1px solid var(--border-neutral-l1);
743
+ }
744
+ .ds-pagehead__main {
745
+ display: flex;
746
+ flex-direction: column;
747
+ gap: var(--spacer-6);
748
+ }
749
+ .ds-pagehead__title {
750
+ font-size: var(--heading-lg-font-size);
751
+ line-height: var(--heading-lg-line-height);
752
+ font-weight: var(--font-weight-strong);
753
+ color: var(--text-default);
754
+ }
755
+ .ds-pagehead__subtitle {
756
+ font-size: var(--body-sm-font-size);
757
+ line-height: var(--body-sm-line-height);
758
+ color: var(--text-tertiary);
759
+ }
760
+ .ds-pagehead__actions {
761
+ display: flex;
762
+ align-items: center;
763
+ gap: var(--spacer-8);
764
+ flex-shrink: 0;
765
+ }
766
+ .ds-pagehead__btn {
767
+ display: inline-flex;
768
+ align-items: center;
769
+ gap: var(--spacer-6);
770
+ height: 32px;
771
+ padding: 0 var(--spacer-12);
772
+ font-size: var(--body-sm-font-size);
773
+ font-weight: var(--font-weight-medium);
774
+ color: var(--text-default);
775
+ background: var(--bg-overlay-l2);
776
+ border: 1px solid var(--border-neutral-l2);
777
+ border-radius: var(--radius-6);
778
+ cursor: pointer;
779
+ }
780
+ .ds-pagehead__btn.is-primary {
781
+ color: var(--text-onbrand);
782
+ background: var(--bg-brand);
783
+ border-color: var(--border-brand);
784
+ }
785
+
786
+ /* ── Pagination ────────────────────────────────────────────── */
787
+ /* ===== Pagination ===== */
788
+ .ds-pagination { display: inline-flex; gap: var(--spacer-4); }
789
+ .ds-pagination__item {
790
+ min-width: 24px; height: 24px; padding: 0 var(--spacer-6);
791
+ display: inline-flex; align-items: center; justify-content: center;
792
+ background: transparent; color: var(--text-secondary);
793
+ border: 1px solid var(--border-neutral-l1);
794
+ border-radius: var(--radius-2);
795
+ font: inherit; font-size: var(--body-xs-font-size);
796
+ cursor: pointer;
797
+ }
798
+ .ds-pagination__item:hover { background: var(--bg-overlay-l2); color: var(--text-default); }
799
+ .ds-pagination__item.is-active { background: var(--bg-overlay-l3); color: var(--text-default); border-color: var(--border-neutral-l2); }
800
+ .ds-pagination__item[disabled] { opacity: .4; cursor: not-allowed; }
801
+
802
+ /* ── Stat Card ─────────────────────────────────────────────── */
803
+ /* ===== Stat card ===== */
804
+ .ds-statcard {
805
+ display: flex;
806
+ flex-direction: column;
807
+ gap: var(--spacer-8);
808
+ padding: var(--spacer-16);
809
+ background: var(--bg-base-secondary);
810
+ border: 1px solid var(--border-neutral-l1);
811
+ border-radius: var(--radius-10);
812
+ min-width: 200px;
813
+ }
814
+ .ds-statcard__label {
815
+ font-size: var(--body-xs-font-size);
816
+ line-height: var(--body-xs-line-height);
817
+ font-weight: var(--font-weight-medium);
818
+ letter-spacing: 0.08em;
819
+ text-transform: uppercase;
820
+ color: var(--text-tertiary);
821
+ }
822
+ .ds-statcard__value {
823
+ font-family: var(--code-editor-font-family);
824
+ font-variant-numeric: tabular-nums;
825
+ font-size: var(--heading-lg-font-size);
826
+ line-height: var(--heading-lg-line-height);
827
+ font-weight: var(--font-weight-strong);
828
+ color: var(--text-default);
829
+ }
830
+ .ds-statcard__delta {
831
+ display: inline-flex;
832
+ align-items: center;
833
+ gap: var(--spacer-4);
834
+ font-size: var(--body-sm-font-size);
835
+ line-height: var(--body-sm-line-height);
836
+ font-weight: var(--font-weight-medium);
837
+ font-variant-numeric: tabular-nums;
838
+ }
839
+ .ds-statcard__delta.is-up { color: var(--status-success-default); }
840
+ .ds-statcard__delta.is-down { color: var(--status-error-default); }
841
+ .ds-statcard__delta .ds-statcard__caption {
842
+ color: var(--text-tertiary);
843
+ font-weight: var(--font-weight-default);
844
+ }
845
+ .ds-statcard__grid {
846
+ display: flex;
847
+ flex-wrap: wrap;
848
+ gap: var(--spacer-16);
849
+ }
850
+
851
+ /* ── Status Bar ────────────────────────────────────────────── */
852
+ /* ===== Status Bar ===== */
853
+ .ds-statusbar {
854
+ display: flex;
855
+ align-items: center;
856
+ justify-content: space-between;
857
+ height: 24px;
858
+ padding: 0 var(--spacer-8);
859
+ background: var(--bg-base-secondary);
860
+ border-top: 1px solid var(--border-neutral-l1);
861
+ font-size: var(--body-xs-font-size);
862
+ color: var(--text-secondary);
863
+ }
864
+ .ds-statusbar__group {
865
+ display: flex;
866
+ align-items: center;
867
+ gap: var(--spacer-4);
868
+ }
869
+ .ds-statusbar__item {
870
+ display: inline-flex;
871
+ align-items: center;
872
+ gap: var(--spacer-6);
873
+ height: 20px;
874
+ padding: 0 var(--spacer-6);
875
+ border-radius: var(--radius-4);
876
+ color: var(--text-secondary);
877
+ cursor: pointer;
878
+ }
879
+ .ds-statusbar__item:hover {
880
+ background: var(--bg-overlay-l2);
881
+ color: var(--text-default);
882
+ }
883
+ .ds-statusbar__dot {
884
+ width: 8px;
885
+ height: 8px;
886
+ border-radius: var(--radius-full);
887
+ }
888
+ .ds-statusbar__dot--success { background: var(--status-success-default); }
889
+ .ds-statusbar__dot--warning { background: var(--status-warning-default); }
890
+ .ds-statusbar__dot--error { background: var(--status-error-default); }
891
+
892
+ /* ── Table Panel ───────────────────────────────────────────── */
893
+ /* ===== Table Panel ===== */
894
+ .ds-tablepanel {
895
+ background: var(--bg-layout-1);
896
+ border: 1px solid var(--border-1);
897
+ border-radius: 0 0 var(--radius-4) var(--radius-4);
898
+ border-top: none;
899
+ overflow: hidden;
900
+ }
901
+ .ds-tablepanel table { width: 100%; border-collapse: collapse; }
902
+ .ds-tablepanel th, .ds-tablepanel td {
903
+ padding: var(--spacer-12) var(--spacer-16);
904
+ border-bottom: 1px solid var(--border-1);
905
+ font-size: var(--body-sm-font-size);
906
+ text-align: left;
907
+ }
908
+ .ds-tablepanel th {
909
+ color: var(--text-tertiary);
910
+ font-weight: var(--font-weight-default);
911
+ font-size: var(--body-xs-font-size);
912
+ text-transform: uppercase;
913
+ letter-spacing: 0.04em;
914
+ background: var(--bg-overlay-l1);
915
+ }
916
+ .ds-tablepanel td { color: var(--text-default); }
917
+ .ds-tablepanel tr:last-child td { border-bottom: none; }
918
+ .ds-tablepanel td.num, .ds-tablepanel th.num {
919
+ text-align: right;
920
+ font-family: var(--code-editor-font-family);
921
+ font-variant-numeric: tabular-nums;
922
+ }
923
+ .ds-tablepanel__foot {
924
+ display: flex;
925
+ align-items: center;
926
+ justify-content: space-between;
927
+ padding: var(--spacer-8) var(--spacer-16);
928
+ border-top: 1px solid var(--border-1);
929
+ color: var(--text-tertiary);
930
+ font-size: var(--body-xs-font-size);
931
+ gap: var(--spacer-12);
932
+ }
933
+
934
+ /* Local-only header bar to demonstrate the "external header above the panel" usage pattern */
935
+ .pv-tp-header {
936
+ background: var(--bg-layout-1);
937
+ border: 1px solid var(--border-1);
938
+ border-bottom: none;
939
+ border-radius: var(--radius-4) var(--radius-4) 0 0;
940
+ padding: var(--spacer-12) var(--spacer-16);
941
+ display: flex; align-items: center; justify-content: space-between;
942
+ gap: var(--spacer-12);
943
+ }
944
+ .pv-tp-header h3 { margin: 0; font-size: var(--body-md-font-size, 14px); color: var(--text-default); }
945
+ .pv-tp-header .meta { color: var(--text-tertiary); font-size: var(--body-xs-font-size); }
946
+
947
+ /* ── Table ─────────────────────────────────────────────────── */
948
+ /* ===== Table ===== */
949
+ .ds-table { width: 100%; border-collapse: collapse; }
950
+ .ds-table th, .ds-table td { text-align: left; padding: var(--spacer-12) var(--spacer-8); border-bottom: 1px solid var(--border-neutral-l1); font-size: var(--body-sm-font-size); }
951
+ .ds-table th { color: var(--text-tertiary); font-weight: var(--font-weight-default, 400); font-size: var(--body-xs-font-size); text-transform: uppercase; letter-spacing: 0.04em; }
952
+ .ds-table td { color: var(--text-default); }
953
+ .ds-table tr:last-child td { border-bottom: none; }
954
+ /* Numeric cells in tables default to mono for column alignment */
955
+ .ds-table td.num,
956
+ .ds-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
957
+
958
+ /* Table wrapper: rounded, bordered container */
959
+ .ds-table-wrap {
960
+ border: 1px solid var(--border-neutral-l1);
961
+ border-radius: var(--radius-8);
962
+ overflow: hidden;
963
+ background: var(--bg-base-secondary);
964
+ }
965
+ /* Toolbar: search on the left, actions on the right */
966
+ .ds-table__toolbar {
967
+ display: flex; align-items: center; justify-content: space-between;
968
+ gap: var(--spacer-12);
969
+ padding: var(--spacer-12);
970
+ border-bottom: 1px solid var(--border-neutral-l1);
971
+ }
972
+ .ds-table__toolbar-actions { display: flex; align-items: center; gap: var(--spacer-8); }
973
+ /* Footer: row count on the left, pagination on the right */
974
+ .ds-table__footer {
975
+ display: flex; align-items: center; justify-content: space-between;
976
+ gap: var(--spacer-12);
977
+ padding: var(--spacer-12);
978
+ border-top: 1px solid var(--border-neutral-l1);
979
+ font-size: var(--body-xs-font-size); color: var(--text-tertiary);
980
+ }
981
+ .ds-table__pagination { display: flex; align-items: center; gap: var(--spacer-8); }
982
+
983
+ /* ── Tabs ──────────────────────────────────────────────────── */
984
+ /* ===== Tabs ===== */
985
+ .ds-tabs { display: flex; gap: var(--spacer-24); border-bottom: 1px solid var(--border-neutral-l1); }
986
+ .ds-tab {
987
+ padding: var(--spacer-12) 0;
988
+ background: transparent; border: none;
989
+ color: var(--text-tertiary); cursor: pointer;
990
+ font: inherit; font-size: var(--body-sm-font-size);
991
+ position: relative;
992
+ }
993
+ .ds-tab:hover { color: var(--text-default); }
994
+ .ds-tab.is-active { color: var(--text-default); }
995
+ .ds-tab.is-active::after {
996
+ content: ''; position: absolute;
997
+ left: 0; right: 0; bottom: -1px; height: 2px;
998
+ background: var(--icon-default);
999
+ }
1000
+
1001
+ /* Filled tabs: selected item gets a filled background + radius, no underline */
1002
+ .ds-tabs--filled { border-bottom: none; gap: var(--spacer-4); }
1003
+ .ds-tabs--filled .ds-tab {
1004
+ padding: var(--spacer-6) var(--spacer-12);
1005
+ border-radius: var(--radius-4);
1006
+ }
1007
+ .ds-tabs--filled .ds-tab.is-active::after { display: none; }
1008
+ .ds-tabs--filled .ds-tab.is-active {
1009
+ background: var(--bg-overlay-l3);
1010
+ color: var(--text-default);
1011
+ }
1012
+
1013
+ /* Closable tabs: each tab carries an inline close button on the right */
1014
+ .ds-tabs--closable .ds-tab {
1015
+ display: inline-flex; align-items: center; gap: var(--spacer-8);
1016
+ }
1017
+ .ds-tab__close {
1018
+ display: inline-flex; align-items: center; justify-content: center;
1019
+ width: 16px; height: 16px;
1020
+ border-radius: var(--radius-2);
1021
+ color: var(--icon-secondary);
1022
+ }
1023
+ .ds-tab__close:hover { background: var(--bg-overlay-l3); color: var(--icon-default); }
1024
+
1025
+ /* ── Tag ───────────────────────────────────────────────────── */
1026
+ /* ===== Tag / Badge ===== */
1027
+ .ds-tag {
1028
+ display: inline-flex; align-items: center;
1029
+ padding: 0 var(--spacer-6); height: 18px;
1030
+ border-radius: var(--radius-2);
1031
+ font-size: var(--body-xs-font-size); line-height: 1;
1032
+ background: var(--bg-overlay-l2); color: var(--text-secondary);
1033
+ border: 1px solid var(--border-neutral-l1);
1034
+ }
1035
+ .ds-tag--brand { background: var(--bg-brand-popup); color: var(--text-brand); }
1036
+ .ds-tag--success { background: var(--status-success-surface-l1); color: var(--status-success-default); }
1037
+ .ds-tag--warning { background: var(--status-warning-surface-l1); color: var(--status-warning-default); }
1038
+ .ds-tag--danger { background: var(--status-error-surface-l1); color: var(--status-error-default); }
1039
+ /* Count badge: numeric pill for list counts */
1040
+ .ds-tag--count {
1041
+ justify-content: center;
1042
+ min-width: 18px; padding: 0 var(--spacer-6);
1043
+ border-radius: var(--radius-full);
1044
+ background: var(--bg-overlay-l3); color: var(--text-secondary);
1045
+ border: none;
1046
+ font-variant-numeric: tabular-nums;
1047
+ }
1048
+ /* Neutral strong: plan-style emphasis badge */
1049
+ .ds-tag--neutral-strong {
1050
+ background: var(--bg-overlay-l4); color: var(--text-default);
1051
+ border: none; font-weight: var(--font-weight-medium);
1052
+ }
1053
+ .ds-tag__close {
1054
+ margin-left: 6px;
1055
+ padding: 0;
1056
+ width: 12px;
1057
+ height: 12px;
1058
+ display: flex;
1059
+ align-items: center;
1060
+ justify-content: center;
1061
+ background: none;
1062
+ border: none;
1063
+ cursor: pointer;
1064
+ color: inherit;
1065
+ opacity: 0.6;
1066
+ transition: opacity 0.2s ease;
1067
+ }
1068
+ .ds-tag__close:hover {
1069
+ opacity: 1;
1070
+ }
1071
+ .ds-tag--closable {
1072
+ padding-right: 4px;
1073
+ }
1074
+
1075
+ /* ── Workbench Titlebar ────────────────────────────────────── */
1076
+ /* ===== Workbench Titlebar ===== */
1077
+ .ds-wbtitlebar {
1078
+ display: flex;
1079
+ align-items: center;
1080
+ justify-content: space-between;
1081
+ gap: var(--spacer-12);
1082
+ height: 40px;
1083
+ padding: 0 var(--spacer-12);
1084
+ background: var(--bg-base-secondary);
1085
+ border-bottom: 1px solid var(--border-neutral-l1);
1086
+ }
1087
+ .ds-wbtitlebar__left,
1088
+ .ds-wbtitlebar__right {
1089
+ display: flex;
1090
+ align-items: center;
1091
+ gap: var(--spacer-8);
1092
+ }
1093
+ .ds-wbtitlebar__lights {
1094
+ display: flex;
1095
+ align-items: center;
1096
+ gap: var(--spacer-8);
1097
+ margin-right: var(--spacer-8);
1098
+ }
1099
+ .ds-wbtitlebar__light {
1100
+ width: 12px;
1101
+ height: 12px;
1102
+ border-radius: var(--radius-full);
1103
+ }
1104
+ .ds-wbtitlebar__light--close { background: var(--status-error-default); }
1105
+ .ds-wbtitlebar__light--min { background: var(--status-alert-default); }
1106
+ .ds-wbtitlebar__light--max { background: var(--status-success-default); }
1107
+ .ds-wbtitlebar__mode-chip {
1108
+ display: inline-flex;
1109
+ align-items: center;
1110
+ gap: var(--spacer-6);
1111
+ height: 24px;
1112
+ padding: 0 var(--spacer-8);
1113
+ background: var(--bg-brand);
1114
+ color: var(--text-onbrand);
1115
+ border-radius: var(--radius-full);
1116
+ font-size: var(--body-xs-font-size);
1117
+ font-weight: var(--font-weight-medium);
1118
+ }
1119
+ .ds-wbtitlebar__project-selector {
1120
+ display: inline-flex;
1121
+ align-items: center;
1122
+ gap: var(--spacer-6);
1123
+ height: 24px;
1124
+ padding: 0 var(--spacer-8);
1125
+ background: var(--bg-overlay-l1);
1126
+ color: var(--text-default);
1127
+ border: 1px solid var(--border-neutral-l2);
1128
+ border-radius: var(--radius-6);
1129
+ font-size: var(--body-sm-font-size);
1130
+ cursor: pointer;
1131
+ }
1132
+ .ds-wbtitlebar__project-selector:hover {
1133
+ background: var(--bg-overlay-l2);
1134
+ color: var(--text-default-hover);
1135
+ }
1136
+ .ds-wbtitlebar__iconbtn {
1137
+ display: inline-flex;
1138
+ align-items: center;
1139
+ justify-content: center;
1140
+ width: 28px;
1141
+ height: 28px;
1142
+ border-radius: var(--radius-6);
1143
+ background: transparent;
1144
+ border: none;
1145
+ cursor: pointer;
1146
+ }
1147
+ .ds-wbtitlebar__iconbtn:hover { background: var(--bg-overlay-l2); }
1148
+ .ds-wbtitlebar .icon { display: block; }
1149
+
1150
+ /* ===== Setting row ===== */
1151
+ .ds-settingrow {
1152
+ display: flex;
1153
+ align-items: center;
1154
+ justify-content: space-between;
1155
+ gap: var(--spacer-24);
1156
+ padding: var(--spacer-16) var(--spacer-24);
1157
+ }
1158
+ .ds-settingrow__main {
1159
+ display: flex;
1160
+ flex-direction: column;
1161
+ gap: var(--spacer-4);
1162
+ min-width: 0;
1163
+ }
1164
+ .ds-settingrow__title {
1165
+ font-size: var(--body-md-font-size);
1166
+ line-height: var(--body-md-line-height);
1167
+ font-weight: var(--font-weight-medium);
1168
+ color: var(--text-default);
1169
+ }
1170
+ .ds-settingrow__desc {
1171
+ font-size: var(--body-sm-font-size);
1172
+ line-height: var(--body-sm-line-height);
1173
+ color: var(--text-tertiary);
1174
+ }
1175
+ .ds-settingrow__control {
1176
+ display: inline-flex;
1177
+ align-items: center;
1178
+ gap: var(--spacer-8);
1179
+ flex-shrink: 0;
1180
+ }
1181
+
1182
+ /* === Variant A: select === */
1183
+ .ds-settingrow__select {
1184
+ position: relative;
1185
+ display: inline-flex;
1186
+ align-items: center;
1187
+ justify-content: space-between;
1188
+ gap: var(--spacer-12);
1189
+ min-width: 200px;
1190
+ height: 36px;
1191
+ padding: 0 var(--spacer-12);
1192
+ font-size: var(--body-sm-font-size);
1193
+ font-weight: var(--font-weight-medium);
1194
+ color: var(--text-default);
1195
+ background: var(--bg-overlay-l2);
1196
+ border: 1px solid var(--border-neutral-l2);
1197
+ border-radius: var(--radius-6);
1198
+ cursor: pointer;
1199
+ }
1200
+ .ds-settingrow__select:hover { background: var(--bg-overlay-l3); }
1201
+ .ds-settingrow__select .icon { color: var(--icon-tertiary); flex-shrink: 0; }
1202
+
1203
+ /* === Variant B: button === */
1204
+ .ds-settingrow__btn {
1205
+ display: inline-flex;
1206
+ align-items: center;
1207
+ gap: var(--spacer-6);
1208
+ height: 36px;
1209
+ padding: 0 var(--spacer-16);
1210
+ font-size: var(--body-sm-font-size);
1211
+ font-weight: var(--font-weight-medium);
1212
+ color: var(--text-default);
1213
+ background: var(--bg-overlay-l2);
1214
+ border: 1px solid var(--border-neutral-l2);
1215
+ border-radius: var(--radius-6);
1216
+ cursor: pointer;
1217
+ }
1218
+ .ds-settingrow__btn:hover { background: var(--bg-overlay-l3); }
1219
+ .ds-settingrow__btn .icon { color: var(--icon-tertiary); }
1220
+
1221
+ /* danger text button (e.g. 清除 / Clear) */
1222
+ .ds-settingrow__btn--danger {
1223
+ color: var(--status-error-default);
1224
+ }
1225
+ .ds-settingrow__btn--danger:hover {
1226
+ background: var(--status-error-surface-l1);
1227
+ border-color: var(--status-error-surface-l2);
1228
+ }
1229
+
1230
+ /* === Variant C: select-with-icon (select + trailing icon button) === */
1231
+ .ds-settingrow__iconbtn {
1232
+ display: inline-flex;
1233
+ align-items: center;
1234
+ justify-content: center;
1235
+ width: 36px;
1236
+ height: 36px;
1237
+ color: var(--icon-secondary);
1238
+ background: transparent;
1239
+ border: 1px solid var(--border-neutral-l2);
1240
+ border-radius: var(--radius-6);
1241
+ cursor: pointer;
1242
+ }
1243
+ .ds-settingrow__iconbtn:hover {
1244
+ background: var(--bg-overlay-l2);
1245
+ color: var(--icon-default);
1246
+ }
1247
+
1248
+ /* === Panel container === */
1249
+ .ds-settingrow__panel {
1250
+ display: flex;
1251
+ flex-direction: column;
1252
+ background: var(--bg-base-secondary);
1253
+ border: 1px solid var(--border-neutral-l1);
1254
+ border-radius: var(--radius-10);
1255
+ overflow: hidden;
1256
+ }
1257
+ .ds-settingrow__panel > .ds-settingrow + .ds-settingrow {
1258
+ border-top: 1px solid var(--border-neutral-l1);
1259
+ }
1260
+
1261
+ /* === Section group label (e.g. 基础设置 / 偏好设置 / 数据管理) === */
1262
+ .ds-settingrow__group {
1263
+ display: flex;
1264
+ flex-direction: column;
1265
+ gap: var(--spacer-12);
1266
+ }
1267
+ .ds-settingrow__group + .ds-settingrow__group {
1268
+ margin-top: var(--spacer-24);
1269
+ }
1270
+ .ds-settingrow__grouplabel {
1271
+ font-size: var(--body-sm-font-size);
1272
+ font-weight: var(--font-weight-medium);
1273
+ color: var(--text-secondary);
1274
+ padding-left: var(--spacer-4);
1275
+ }
1276
+
1277
+ /* ── Form Layout ─────────────────────────────────────────────── */
1278
+ .ds-form {
1279
+ display: flex;
1280
+ flex-direction: column;
1281
+ gap: var(--spacer-16);
1282
+ padding: var(--spacer-24);
1283
+ }
1284
+
1285
+ .ds-form__group {
1286
+ display: flex;
1287
+ flex-direction: column;
1288
+ gap: var(--spacer-6);
1289
+ }
1290
+
1291
+ .ds-form__label {
1292
+ font-size: var(--body-sm-font-size);
1293
+ font-weight: var(--font-weight-medium);
1294
+ color: var(--text-default);
1295
+ }
1296
+
1297
+ .ds-form__required {
1298
+ color: var(--bg-error-default);
1299
+ }
1300
+
1301
+ .ds-form__error {
1302
+ font-size: var(--body-xs-font-size);
1303
+ color: var(--bg-error-default);
1304
+ min-height: 16px;
1305
+ }
1306
+
1307
+ .ds-form__actions {
1308
+ display: flex;
1309
+ justify-content: flex-end;
1310
+ gap: var(--spacer-8);
1311
+ margin-top: var(--spacer-16);
1312
+ }
1313
+
1314
+ .ds-radio-group {
1315
+ display: flex;
1316
+ gap: var(--spacer-16);
1317
+ flex-wrap: wrap;
1318
+ }
1319
+
1320
+ .ds-check-group {
1321
+ display: flex;
1322
+ flex-direction: column;
1323
+ gap: var(--spacer-6);
1324
+ }
1325
+
1326
+ /* ── Dropdown ─────────────────────────────────────────────────── */
1327
+ .ds-dropdown {
1328
+ position: relative;
1329
+ display: block;
1330
+ width: 100%;
1331
+ }
1332
+
1333
+ .ds-dropdown__trigger {
1334
+ display: flex;
1335
+ align-items: center;
1336
+ justify-content: space-between;
1337
+ width: 100%;
1338
+ height: 28px;
1339
+ padding: 0 var(--spacer-12);
1340
+ background: var(--bg-overlay-l1);
1341
+ border: 1px solid var(--border-neutral-l1);
1342
+ border-radius: var(--radius-4);
1343
+ color: var(--text-default);
1344
+ font-size: var(--body-sm-font-size);
1345
+ cursor: pointer;
1346
+ appearance: none;
1347
+ -webkit-appearance: none;
1348
+ }
1349
+
1350
+ .ds-dropdown__trigger:hover {
1351
+ background: var(--bg-overlay-l2);
1352
+ }
1353
+
1354
+ .ds-dropdown__trigger:focus {
1355
+ outline: none;
1356
+ border-color: var(--border-brand);
1357
+ }
1358
+
1359
+ .ds-dropdown__trigger svg {
1360
+ width: 14px;
1361
+ height: 14px;
1362
+ color: var(--text-secondary);
1363
+ flex-shrink: 0;
1364
+ transition: transform 0.2s ease;
1365
+ }
1366
+
1367
+ .ds-dropdown.is-open .ds-dropdown__trigger svg {
1368
+ transform: rotate(180deg);
1369
+ }
1370
+
1371
+ .ds-dropdown__menu {
1372
+ position: absolute;
1373
+ top: calc(100% + 4px);
1374
+ left: 0;
1375
+ width: 100%;
1376
+ background: var(--bg-base-secondary);
1377
+ border: 1px solid var(--border-neutral-l2);
1378
+ border-radius: var(--radius-4);
1379
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
1380
+ z-index: 100;
1381
+ display: none;
1382
+ padding: var(--spacer-4);
1383
+ box-sizing: border-box;
1384
+ }
1385
+
1386
+ .ds-dropdown__menu.is-open {
1387
+ display: block;
1388
+ }
1389
+
1390
+ .ds-dropdown__item {
1391
+ display: flex;
1392
+ align-items: center;
1393
+ width: 100%;
1394
+ padding: var(--spacer-8) var(--spacer-12);
1395
+ background: none;
1396
+ border: none;
1397
+ border-radius: var(--radius-2);
1398
+ color: var(--text-default);
1399
+ font-size: var(--body-sm-font-size);
1400
+ cursor: pointer;
1401
+ text-align: left;
1402
+ }
1403
+
1404
+ .ds-dropdown__item:hover {
1405
+ background: var(--bg-overlay-l1);
1406
+ }
1407
+
1408
+ .ds-dropdown__item.is-selected {
1409
+ background: var(--bg-brand);
1410
+ color: var(--text-onbrand);
1411
+ }
1412
+
1413
+ .ds-dropdown__item.is-disabled {
1414
+ opacity: 0.5;
1415
+ cursor: not-allowed;
1416
+ }
1417
+
1418
+ .ds-dropdown__item__icon {
1419
+ margin-right: var(--spacer-8);
1420
+ color: var(--icon-secondary);
1421
+ flex-shrink: 0;
1422
+ width: 14px;
1423
+ height: 14px;
1424
+ }
1425
+
1426
+ .ds-dropdown__item.is-selected .ds-dropdown__item__icon {
1427
+ color: var(--text-onbrand);
1428
+ }
1429
+
1430
+ /* ── List ─────────────────────────────────────────────────────── */
1431
+ .ds-list {
1432
+ display: flex;
1433
+ flex-direction: column;
1434
+ gap: var(--spacer-4);
1435
+ background: var(--bg-base-secondary);
1436
+ border: 1px solid var(--border-neutral-l2);
1437
+ border-radius: var(--radius-4);
1438
+ padding: var(--spacer-4);
1439
+ }
1440
+
1441
+ .ds-list__item {
1442
+ display: flex;
1443
+ align-items: center;
1444
+ padding: var(--spacer-8) var(--spacer-12);
1445
+ border-radius: var(--radius-2);
1446
+ cursor: pointer;
1447
+ transition: background-color 0.15s ease;
1448
+ }
1449
+
1450
+ .ds-list__item:hover {
1451
+ background: var(--bg-overlay-l1);
1452
+ }
1453
+
1454
+ .ds-list__item.is-selected {
1455
+ background: var(--bg-brand);
1456
+ color: var(--text-onbrand);
1457
+ }
1458
+
1459
+ .ds-list__item.is-disabled {
1460
+ opacity: 0.5;
1461
+ cursor: not-allowed;
1462
+ }
1463
+
1464
+ .ds-list__item__icon {
1465
+ margin-right: var(--spacer-8);
1466
+ color: var(--icon-secondary);
1467
+ flex-shrink: 0;
1468
+ width: 14px;
1469
+ height: 14px;
1470
+ }
1471
+
1472
+ .ds-list__item.is-selected .ds-list__item__icon {
1473
+ color: var(--text-onbrand);
1474
+ }
1475
+
1476
+ .ds-list__item__content {
1477
+ flex: 1;
1478
+ }
1479
+
1480
+ .ds-list__item__meta {
1481
+ font-size: var(--body-xs-font-size);
1482
+ color: var(--text-tertiary);
1483
+ }