mbkbucket 3.5.0 → 3.6.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 (42) hide show
  1. package/.env.example +14 -14
  2. package/.mbkbucket.config.example.json +14 -14
  3. package/LICENSE +20 -20
  4. package/README.md +377 -350
  5. package/index.js +30 -30
  6. package/lib/cli.js +649 -649
  7. package/lib/public/bucketadmin.css +1420 -1420
  8. package/lib/public/bucketadmin.js +1229 -1229
  9. package/lib/public/mbkbucket-helper-demo.html +1184 -1184
  10. package/lib/public/mbkbucket-helper.css +1235 -1235
  11. package/lib/public/mbkbucket-helper.js +1557 -1557
  12. package/lib/src/app.js +109 -109
  13. package/lib/src/cli/auth-helper.js +150 -150
  14. package/lib/src/config/index.js +112 -112
  15. package/lib/src/config/validation.js +73 -73
  16. package/lib/src/controllers/api.controller.js +410 -410
  17. package/lib/src/controllers/dashboard.controller.js +48 -48
  18. package/lib/src/controllers/info.controller.js +34 -34
  19. package/lib/src/controllers/view.controller.js +233 -233
  20. package/lib/src/middleware/async-handler.js +23 -23
  21. package/lib/src/middleware/bucket-resolver.js +37 -37
  22. package/lib/src/middleware/error-handler.js +54 -54
  23. package/lib/src/middleware/rate-limiter.js +22 -22
  24. package/lib/src/middleware/security.js +27 -27
  25. package/lib/src/routes/api.routes.js +54 -40
  26. package/lib/src/routes/index.js +40 -21
  27. package/lib/src/routes/info.routes.js +9 -9
  28. package/lib/src/routes/view.routes.js +25 -20
  29. package/lib/src/services/s3.service.js +603 -603
  30. package/lib/src/utils/errors.js +54 -54
  31. package/lib/src/utils/helpers.js +251 -251
  32. package/lib/src/utils/logger.js +17 -17
  33. package/package.json +83 -83
  34. package/views/bucket.handlebars +196 -196
  35. package/views/bucketadmin_alerts.handlebars +15 -15
  36. package/views/bucketadmin_delete_modal.handlebars +36 -36
  37. package/views/bucketadmin_filelist_skeleton.handlebars +32 -32
  38. package/views/bucketadmin_newfolder_modal.handlebars +29 -29
  39. package/views/bucketadmin_preview_modal.handlebars +40 -40
  40. package/views/bucketadmin_upload_modal.handlebars +54 -54
  41. package/views/bucketadmincontent.handlebars +141 -141
  42. package/views/mbkbucket_info.handlebars +232 -232
@@ -1,1235 +1,1235 @@
1
- /**
2
- * mbkbucket-helper.css v1.0.0
3
- * ─────────────────────────────────────────────────────────────────────────────
4
- * Scoped styles for MBKBucket frontend helper components.
5
- * All selectors prefixed with .mbkh- to avoid collisions.
6
- *
7
- * Follows the mbkbucket design system (light-mode, teal/green palette).
8
- * Inherits --primary-color-ml, --font, etc. if bucketadmin.css is also loaded.
9
- * Falls back to standalone tokens if used without bucketadmin.css.
10
- * ─────────────────────────────────────────────────────────────────────────────
11
- */
12
-
13
- /* ─── Standalone design tokens (fallbacks via @property-like approach) ──────── */
14
- :root {
15
- /* Colours */
16
- --mbkh-primary: var(--primary-color-ml, #0f766e);
17
- --mbkh-primary-lt: var(--primary-light-color-ml, #d7f4ee);
18
- --mbkh-primary-dk: var(--primary-dark-color-ml, #0b4f4a);
19
- --mbkh-primary-hover: var(--primary-hover, #0d635c);
20
-
21
- --mbkh-danger: var(--danger-color-ml, #dc2626);
22
- --mbkh-success: var(--success-color-ml, #16a34a);
23
- --mbkh-warning: var(--warning-color-ml, #d97706);
24
-
25
- /* Backgrounds */
26
- --mbkh-body-bg: var(--body-bg, #f4f7f3);
27
- --mbkh-surface: var(--bg-surface, rgba(255,255,255,0.85));
28
- --mbkh-surface2: var(--bg-surface-secondary, rgba(244,247,243,0.85));
29
- --mbkh-surface3: var(--bg-surface-tertiary, #e2ede8);
30
-
31
- /* Borders */
32
- --mbkh-border: var(--border-color, rgba(15,118,110,0.16));
33
- --mbkh-border-lt: var(--border-color-light, rgba(15,118,110,0.08));
34
- --mbkh-border-active: rgba(15,118,110,0.45);
35
-
36
- /* Text */
37
- --mbkh-text: var(--text, #1f2a2a);
38
- --mbkh-text-sec: var(--text-secondary, #425855);
39
- --mbkh-text-muted: var(--text-muted, #667c79);
40
- --mbkh-text-dim: var(--text-disabled, #a0b2af);
41
-
42
- /* Typography */
43
- --mbkh-font: var(--font, "IBM Plex Sans", "Segoe UI", sans-serif);
44
- --mbkh-font-heading: var(--font-headings, "Sora", "Segoe UI", sans-serif);
45
- --mbkh-font-mono: var(--font-mono, "JetBrains Mono", Consolas, monospace);
46
-
47
- /* Shape */
48
- --mbkh-radius: var(--radius-lg, 14px);
49
- --mbkh-radius-md: var(--radius, 8px);
50
- --mbkh-radius-sm: var(--radius-sm, 6px);
51
-
52
- /* Shadows */
53
- --mbkh-shadow: var(--shadow-lg,
54
- 0 20px 40px rgba(15,118,110,0.12),
55
- 0 4px 12px rgba(0,0,0,0.06));
56
- --mbkh-shadow-sm: var(--shadow-md,
57
- 0 8px 20px rgba(15,118,110,0.08),
58
- 0 2px 6px rgba(0,0,0,0.04));
59
- --mbkh-shadow-dropdown: var(--shadow-dropdown,
60
- 0 12px 30px rgba(15,42,42,0.14),
61
- 0 4px 10px rgba(0,0,0,0.05));
62
-
63
- /* Transition */
64
- --mbkh-transition: 0.15s ease-in-out;
65
- }
66
-
67
- /* ─── Reset inside helper components ───────────────────────────────────────── */
68
- .mbkh-modal *,
69
- .mbkh-picker *,
70
- .mbkh-uploader *,
71
- .mbkh-toast-container * {
72
- box-sizing: border-box;
73
- margin: 0;
74
- padding: 0;
75
- }
76
-
77
- /* ═══════════════════════════════════════════════════════════════════════════
78
- OVERLAY + MODAL
79
- ═══════════════════════════════════════════════════════════════════════════ */
80
-
81
- .mbkh-overlay {
82
- position: fixed;
83
- inset: 0;
84
- z-index: 99990;
85
- background: rgba(15, 42, 42, 0.45);
86
- backdrop-filter: blur(4px);
87
- -webkit-backdrop-filter: blur(4px);
88
- display: flex;
89
- align-items: center;
90
- justify-content: center;
91
- padding: 16px;
92
- animation: mbkh-fade-in 0.18s ease;
93
- }
94
-
95
- @keyframes mbkh-fade-in { from { opacity: 0; } to { opacity: 1; } }
96
-
97
- .mbkh-overlay.mbkh-closing {
98
- animation: mbkh-fade-out 0.16s ease forwards;
99
- }
100
- @keyframes mbkh-fade-out { to { opacity: 0; } }
101
-
102
- /* ─── Modal shell ──────────────────────────────────────────────────────────── */
103
- .mbkh-modal {
104
- font-family: var(--mbkh-font);
105
- color: var(--mbkh-text);
106
- background: rgba(255, 255, 255, 0.98);
107
- border: 1px solid rgba(255, 255, 255, 0.95);
108
- border-radius: var(--mbkh-radius);
109
- box-shadow: 0 24px 60px rgba(15, 42, 42, 0.2), 0 4px 16px rgba(0, 0, 0, 0.06);
110
- backdrop-filter: blur(16px);
111
- -webkit-backdrop-filter: blur(16px);
112
- width: 100%;
113
- max-width: 920px;
114
- height: min(86vh, 680px);
115
- display: flex;
116
- flex-direction: column;
117
- overflow: hidden;
118
- animation: mbkh-slide-up 0.2s cubic-bezier(0.34, 1.3, 0.64, 1);
119
- }
120
-
121
- @keyframes mbkh-slide-up {
122
- from { opacity: 0; transform: translateY(16px) scale(0.98); }
123
- to { opacity: 1; transform: translateY(0) scale(1); }
124
- }
125
-
126
- /* ─── Modal header ─────────────────────────────────────────────────────────── */
127
- .mbkh-modal-header {
128
- display: flex;
129
- align-items: center;
130
- gap: 10px;
131
- padding: 12px 18px 11px;
132
- border-bottom: 1px solid var(--mbkh-border);
133
- background: rgba(244, 247, 243, 0.85);
134
- flex-shrink: 0;
135
- }
136
-
137
- .mbkh-modal-logo {
138
- width: 26px; height: 26px;
139
- background: var(--mbkh-primary);
140
- border-radius: var(--mbkh-radius-sm);
141
- display: flex; align-items: center; justify-content: center;
142
- color: #fff;
143
- flex-shrink: 0;
144
- box-shadow: 0 2px 4px rgba(15, 118, 110, 0.25);
145
- }
146
- .mbkh-modal-logo svg { width: 14px; height: 14px; }
147
-
148
- .mbkh-modal-title {
149
- font-family: var(--mbkh-font-heading);
150
- font-size: 14px;
151
- font-weight: 700;
152
- color: var(--mbkh-primary-dk);
153
- flex: 1;
154
- min-width: 0;
155
- white-space: nowrap;
156
- overflow: hidden;
157
- text-overflow: ellipsis;
158
- }
159
-
160
- .mbkh-header-actions {
161
- display: flex;
162
- align-items: center;
163
- gap: 8px;
164
- flex-shrink: 0;
165
- }
166
-
167
- .mbkh-btn-upload-header {
168
- display: inline-flex;
169
- align-items: center;
170
- gap: 5px;
171
- padding: 4px 10px;
172
- background: var(--mbkh-primary-lt);
173
- color: var(--mbkh-primary-dk);
174
- border: 1px solid rgba(15, 118, 110, 0.2);
175
- border-radius: var(--mbkh-radius-sm);
176
- font-family: var(--mbkh-font);
177
- font-size: 12px;
178
- font-weight: 600;
179
- cursor: pointer;
180
- transition: all var(--mbkh-transition);
181
- }
182
- .mbkh-btn-upload-header:hover {
183
- background: var(--mbkh-primary);
184
- color: #ffffff;
185
- border-color: var(--mbkh-primary);
186
- }
187
-
188
- .mbkh-modal-close {
189
- width: 28px; height: 28px;
190
- border: none;
191
- background: transparent;
192
- color: var(--mbkh-text-muted);
193
- border-radius: var(--mbkh-radius-sm);
194
- cursor: pointer;
195
- display: flex; align-items: center; justify-content: center;
196
- transition: all var(--mbkh-transition);
197
- flex-shrink: 0;
198
- }
199
- .mbkh-modal-close:hover {
200
- background: rgba(220, 38, 38, 0.1);
201
- color: var(--mbkh-danger);
202
- }
203
-
204
- /* ─── Toolbar ──────────────────────────────────────────────────────────────── */
205
- .mbkh-toolbar {
206
- display: flex;
207
- align-items: center;
208
- justify-content: space-between;
209
- gap: 12px;
210
- padding: 8px 16px;
211
- border-bottom: 1px solid var(--mbkh-border-lt);
212
- background: rgba(255, 255, 255, 0.8);
213
- flex-shrink: 0;
214
- flex-wrap: wrap;
215
- }
216
-
217
- .mbkh-breadcrumb {
218
- display: flex;
219
- align-items: center;
220
- gap: 4px;
221
- flex: 1;
222
- min-width: 0;
223
- overflow-x: auto;
224
- padding-bottom: 1px;
225
- }
226
- .mbkh-breadcrumb::-webkit-scrollbar { display: none; }
227
-
228
- .mbkh-crumb {
229
- display: inline-flex;
230
- align-items: center;
231
- gap: 4px;
232
- padding: 4px 8px;
233
- border-radius: var(--mbkh-radius-sm);
234
- font-size: 12.5px;
235
- font-weight: 500;
236
- color: var(--mbkh-text-muted);
237
- cursor: pointer;
238
- transition: all var(--mbkh-transition);
239
- white-space: nowrap;
240
- max-width: 140px;
241
- overflow: hidden;
242
- text-overflow: ellipsis;
243
- border: none;
244
- background: transparent;
245
- font-family: var(--mbkh-font);
246
- }
247
- .mbkh-crumb:hover {
248
- background: var(--mbkh-primary-lt);
249
- color: var(--mbkh-primary-dk);
250
- }
251
- .mbkh-crumb.mbkh-crumb-active {
252
- color: var(--mbkh-primary-dk);
253
- font-weight: 700;
254
- background: rgba(15, 118, 110, 0.08);
255
- cursor: default;
256
- pointer-events: none;
257
- }
258
- .mbkh-crumb-text {
259
- overflow: hidden;
260
- text-overflow: ellipsis;
261
- white-space: nowrap;
262
- }
263
-
264
- .mbkh-crumb-sep {
265
- color: var(--mbkh-text-dim);
266
- font-size: 11px;
267
- font-weight: 600;
268
- flex-shrink: 0;
269
- }
270
-
271
- .mbkh-toolbar-actions {
272
- display: flex;
273
- align-items: center;
274
- gap: 8px;
275
- flex-shrink: 0;
276
- }
277
-
278
- /* Search */
279
- .mbkh-search-wrap {
280
- position: relative;
281
- display: flex;
282
- align-items: center;
283
- }
284
- .mbkh-search-icon {
285
- position: absolute;
286
- left: 9px;
287
- color: var(--mbkh-text-muted);
288
- pointer-events: none;
289
- display: flex;
290
- align-items: center;
291
- }
292
- .mbkh-search {
293
- background: var(--mbkh-surface2);
294
- border: 1px solid var(--mbkh-border);
295
- border-radius: var(--mbkh-radius-md);
296
- color: var(--mbkh-text);
297
- font-family: var(--mbkh-font);
298
- font-size: 12.5px;
299
- padding: 5px 10px 5px 28px;
300
- outline: none;
301
- width: 170px;
302
- transition: border-color var(--mbkh-transition), box-shadow var(--mbkh-transition), width var(--mbkh-transition);
303
- }
304
- .mbkh-search:focus {
305
- border-color: var(--mbkh-primary);
306
- box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.1);
307
- background: #ffffff;
308
- width: 210px;
309
- }
310
- .mbkh-search::placeholder { color: var(--mbkh-text-dim); }
311
-
312
- /* View toggle */
313
- .mbkh-view-toggle {
314
- display: inline-flex;
315
- gap: 1px;
316
- background: var(--mbkh-surface2);
317
- border: 1px solid var(--mbkh-border);
318
- border-radius: var(--mbkh-radius-md);
319
- padding: 2px;
320
- flex-shrink: 0;
321
- }
322
- .mbkh-view-btn {
323
- width: 26px; height: 26px;
324
- border: none;
325
- background: transparent;
326
- color: var(--mbkh-text-muted);
327
- border-radius: var(--mbkh-radius-sm);
328
- cursor: pointer;
329
- display: flex; align-items: center; justify-content: center;
330
- transition: all var(--mbkh-transition);
331
- }
332
- .mbkh-view-btn:hover { color: var(--mbkh-primary-dk); }
333
- .mbkh-view-btn.mbkh-active {
334
- background: var(--mbkh-primary);
335
- color: #fff;
336
- box-shadow: 0 1px 3px rgba(15, 118, 110, 0.2);
337
- }
338
-
339
- /* ─── Filter Bar ───────────────────────────────────────────────────────────── */
340
- .mbkh-filter-bar {
341
- display: flex;
342
- align-items: center;
343
- gap: 4px;
344
- padding: 6px 16px;
345
- background: rgba(244, 247, 243, 0.6);
346
- border-bottom: 1px solid var(--mbkh-border);
347
- overflow-x: auto;
348
- }
349
- .mbkh-filter-bar::-webkit-scrollbar { display: none; }
350
-
351
- .mbkh-filter-btn {
352
- padding: 3px 10px;
353
- border-radius: 20px;
354
- border: 1px solid transparent;
355
- background: transparent;
356
- font-family: var(--mbkh-font);
357
- font-size: 11.5px;
358
- font-weight: 600;
359
- color: var(--mbkh-text-sec);
360
- cursor: pointer;
361
- transition: all var(--mbkh-transition);
362
- white-space: nowrap;
363
- }
364
- .mbkh-filter-btn:hover {
365
- background: rgba(255, 255, 255, 0.8);
366
- color: var(--mbkh-primary-dk);
367
- }
368
- .mbkh-filter-btn.mbkh-active {
369
- background: #ffffff;
370
- color: var(--mbkh-primary);
371
- border-color: rgba(15, 118, 110, 0.2);
372
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
373
- }
374
-
375
- /* In-modal Upload Banner */
376
- .mbkh-modal-upload-banner {
377
- padding: 8px 18px;
378
- background: rgba(15, 118, 110, 0.08);
379
- border-bottom: 1px solid rgba(15, 118, 110, 0.15);
380
- display: flex;
381
- flex-direction: column;
382
- gap: 5px;
383
- animation: mbkh-fade-in 0.15s ease;
384
- }
385
- .mbkh-upload-banner-text {
386
- font-size: 12px;
387
- font-weight: 600;
388
- color: var(--mbkh-primary-dk);
389
- }
390
- .mbkh-upload-banner-bar {
391
- height: 4px;
392
- background: var(--mbkh-surface3);
393
- border-radius: 2px;
394
- overflow: hidden;
395
- }
396
- .mbkh-upload-banner-fill {
397
- height: 100%;
398
- width: 0%;
399
- background: var(--mbkh-primary);
400
- transition: width 0.2s ease;
401
- }
402
-
403
- /* Drag overlay */
404
- .mbkh-drag-overlay {
405
- position: absolute;
406
- inset: 0;
407
- background: rgba(244, 247, 243, 0.92);
408
- backdrop-filter: blur(4px);
409
- z-index: 50;
410
- display: flex;
411
- align-items: center;
412
- justify-content: center;
413
- padding: 24px;
414
- pointer-events: none;
415
- }
416
- .mbkh-drag-box {
417
- width: 100%;
418
- max-width: 440px;
419
- border: 2px dashed var(--mbkh-primary);
420
- border-radius: var(--mbkh-radius);
421
- background: rgba(255, 255, 255, 0.9);
422
- padding: 36px 24px;
423
- display: flex;
424
- flex-direction: column;
425
- align-items: center;
426
- gap: 12px;
427
- color: var(--mbkh-primary);
428
- box-shadow: 0 12px 30px rgba(15, 118, 110, 0.15);
429
- }
430
- .mbkh-drag-text {
431
- font-family: var(--mbkh-font-heading);
432
- font-size: 14px;
433
- font-weight: 700;
434
- color: var(--mbkh-primary-dk);
435
- text-align: center;
436
- }
437
-
438
- /* ─── Modal body / file grid ───────────────────────────────────────────────── */
439
- .mbkh-modal-body {
440
- flex: 1;
441
- overflow: hidden;
442
- display: flex;
443
- flex-direction: column;
444
- background: rgba(244, 247, 243, 0.35);
445
- position: relative;
446
- }
447
-
448
- .mbkh-file-grid {
449
- flex: 1;
450
- overflow-y: auto;
451
- padding: 16px;
452
- display: grid;
453
- grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
454
- grid-auto-rows: max-content;
455
- gap: 12px;
456
- align-content: start;
457
- }
458
- .mbkh-file-grid::-webkit-scrollbar { width: 6px; }
459
- .mbkh-file-grid::-webkit-scrollbar-track { background: transparent; }
460
- .mbkh-file-grid::-webkit-scrollbar-thumb {
461
- background: var(--mbkh-border);
462
- border-radius: 3px;
463
- }
464
- .mbkh-file-grid::-webkit-scrollbar-thumb:hover {
465
- background: var(--mbkh-primary);
466
- }
467
-
468
- /* ─── Grid View Item Card ──────────────────────────────────────────────────── */
469
- .mbkh-item {
470
- position: relative;
471
- background: rgba(255, 255, 255, 0.95);
472
- border: 1px solid rgba(15, 118, 110, 0.15);
473
- border-radius: var(--mbkh-radius-md);
474
- padding: 8px;
475
- cursor: pointer;
476
- display: flex;
477
- flex-direction: column;
478
- gap: 7px;
479
- transition: all var(--mbkh-transition);
480
- user-select: none;
481
- min-width: 0;
482
- box-shadow: 0 2px 4px rgba(15, 118, 110, 0.04);
483
- }
484
- .mbkh-item:hover {
485
- border-color: var(--mbkh-primary);
486
- transform: translateY(-2px);
487
- box-shadow: 0 6px 16px rgba(15, 118, 110, 0.1);
488
- background: #ffffff;
489
- }
490
- .mbkh-item.mbkh-selected {
491
- border-color: var(--mbkh-primary);
492
- background: rgba(215, 244, 238, 0.4);
493
- box-shadow: 0 0 0 2px var(--mbkh-primary), 0 8px 20px rgba(15, 118, 110, 0.12);
494
- }
495
-
496
- /* Card preview area */
497
- .mbkh-card-preview {
498
- width: 100%;
499
- aspect-ratio: 16 / 11;
500
- border-radius: var(--mbkh-radius-sm);
501
- background: var(--mbkh-surface3);
502
- display: flex;
503
- align-items: center;
504
- justify-content: center;
505
- overflow: hidden;
506
- position: relative;
507
- border: 1px solid rgba(15, 118, 110, 0.08);
508
- }
509
- .mbkh-card-preview.mbkh-thumb img {
510
- width: 100%;
511
- height: 100%;
512
- object-fit: cover;
513
- transition: transform 0.2s ease;
514
- }
515
- .mbkh-item:hover .mbkh-card-preview.mbkh-thumb img {
516
- transform: scale(1.04);
517
- }
518
-
519
- .mbkh-folder-preview {
520
- background: var(--mbkh-primary-lt);
521
- }
522
- .mbkh-folder-svg {
523
- width: 38px;
524
- height: 38px;
525
- }
526
-
527
- .mbkh-ext-tag {
528
- position: absolute;
529
- bottom: 4px;
530
- right: 4px;
531
- font-family: var(--mbkh-font-mono);
532
- font-size: 9px;
533
- font-weight: 700;
534
- padding: 1px 5px;
535
- border-radius: 3px;
536
- background: rgba(15, 42, 42, 0.75);
537
- color: #ffffff;
538
- backdrop-filter: blur(4px);
539
- letter-spacing: 0.04em;
540
- text-transform: uppercase;
541
- }
542
-
543
- /* Card details */
544
- .mbkh-card-details {
545
- width: 100%;
546
- min-width: 0;
547
- display: flex;
548
- flex-direction: column;
549
- gap: 2px;
550
- }
551
- .mbkh-card-name {
552
- font-size: 12px;
553
- font-weight: 600;
554
- color: var(--mbkh-text);
555
- overflow: hidden;
556
- text-overflow: ellipsis;
557
- white-space: nowrap;
558
- line-height: 1.3;
559
- }
560
- .mbkh-card-meta {
561
- font-size: 10.5px;
562
- color: var(--mbkh-text-muted);
563
- font-family: var(--mbkh-font-mono);
564
- overflow: hidden;
565
- text-overflow: ellipsis;
566
- white-space: nowrap;
567
- }
568
-
569
- /* Checkmark badge */
570
- .mbkh-check-badge {
571
- position: absolute;
572
- top: 6px;
573
- right: 6px;
574
- width: 20px;
575
- height: 20px;
576
- border-radius: 50%;
577
- background: var(--mbkh-primary);
578
- color: #ffffff;
579
- display: flex;
580
- align-items: center;
581
- justify-content: center;
582
- opacity: 0;
583
- transform: scale(0.7);
584
- transition: all 0.15s cubic-bezier(0.34, 1.4, 0.64, 1);
585
- box-shadow: 0 2px 6px rgba(15, 118, 110, 0.35);
586
- z-index: 3;
587
- }
588
- .mbkh-item.mbkh-selected .mbkh-check-badge {
589
- opacity: 1;
590
- transform: scale(1);
591
- }
592
-
593
- /* ─── List Mode ────────────────────────────────────────────────────────────── */
594
- .mbkh-file-grid.mbkh-list-mode {
595
- grid-template-columns: 1fr;
596
- gap: 3px;
597
- padding: 10px 14px;
598
- }
599
-
600
- .mbkh-file-grid.mbkh-list-mode .mbkh-item {
601
- flex-direction: row;
602
- align-items: center;
603
- padding: 6px 12px;
604
- gap: 12px;
605
- border-radius: var(--mbkh-radius-sm);
606
- display: grid;
607
- grid-template-columns: 28px 1fr auto 80px 20px;
608
- }
609
- .mbkh-file-grid.mbkh-list-mode .mbkh-item:hover { transform: none; }
610
-
611
- .mbkh-row-icon {
612
- width: 28px;
613
- height: 28px;
614
- border-radius: var(--mbkh-radius-sm);
615
- display: flex;
616
- align-items: center;
617
- justify-content: center;
618
- flex-shrink: 0;
619
- overflow: hidden;
620
- background: var(--mbkh-surface2);
621
- }
622
- .mbkh-row-icon.mbkh-thumb img {
623
- width: 100%; height: 100%; object-fit: cover;
624
- }
625
- .mbkh-row-name {
626
- font-size: 12.5px;
627
- font-weight: 600;
628
- color: var(--mbkh-text);
629
- overflow: hidden;
630
- text-overflow: ellipsis;
631
- white-space: nowrap;
632
- }
633
- .mbkh-row-badge {
634
- font-size: 10px;
635
- font-weight: 700;
636
- padding: 2px 7px;
637
- border-radius: 4px;
638
- letter-spacing: 0.04em;
639
- background: var(--mbkh-primary-lt);
640
- color: var(--mbkh-primary-dk);
641
- }
642
- .mbkh-row-size {
643
- font-size: 11px;
644
- color: var(--mbkh-text-muted);
645
- font-family: var(--mbkh-font-mono);
646
- text-align: right;
647
- }
648
- .mbkh-file-grid.mbkh-list-mode .mbkh-check-badge {
649
- position: static;
650
- width: 18px;
651
- height: 18px;
652
- }
653
-
654
- /* ─── Empty / Loading / Error states ──────────────────────────────────────── */
655
- .mbkh-state {
656
- flex: 1;
657
- display: flex;
658
- flex-direction: column;
659
- align-items: center;
660
- justify-content: center;
661
- gap: 8px;
662
- color: var(--mbkh-text-muted);
663
- padding: 48px 24px;
664
- text-align: center;
665
- }
666
- .mbkh-spinner {
667
- width: 32px; height: 32px;
668
- border: 3px solid var(--mbkh-border);
669
- border-top-color: var(--mbkh-primary);
670
- border-radius: 50%;
671
- animation: mbkh-spin 0.7s linear infinite;
672
- }
673
- .mbkh-state-text {
674
- font-size: 13px;
675
- font-weight: 500;
676
- color: var(--mbkh-text-sec);
677
- margin-top: 4px;
678
- }
679
- .mbkh-state-icon {
680
- margin-bottom: 2px;
681
- }
682
- .mbkh-state-title {
683
- font-family: var(--mbkh-font-heading);
684
- font-size: 15px;
685
- font-weight: 700;
686
- color: var(--mbkh-text);
687
- }
688
- .mbkh-state-sub {
689
- font-size: 12.5px;
690
- color: var(--mbkh-text-muted);
691
- max-width: 320px;
692
- line-height: 1.5;
693
- }
694
-
695
- /* ─── Modal footer ─────────────────────────────────────────────────────────── */
696
- .mbkh-modal-footer {
697
- display: flex;
698
- align-items: center;
699
- justify-content: space-between;
700
- gap: 12px;
701
- padding: 10px 18px;
702
- border-top: 1px solid var(--mbkh-border);
703
- background: rgba(244, 247, 243, 0.9);
704
- flex-shrink: 0;
705
- }
706
-
707
- .mbkh-selected-wrap {
708
- flex: 1;
709
- min-width: 0;
710
- display: flex;
711
- align-items: center;
712
- gap: 8px;
713
- }
714
-
715
- .mbkh-selected-placeholder {
716
- font-size: 12px;
717
- color: var(--mbkh-text-dim);
718
- font-style: italic;
719
- }
720
-
721
- .mbkh-sel-thumb {
722
- width: 30px; height: 30px;
723
- border-radius: var(--mbkh-radius-sm);
724
- overflow: hidden;
725
- border: 1px solid var(--mbkh-border);
726
- flex-shrink: 0;
727
- }
728
- .mbkh-sel-thumb img {
729
- width: 100%; height: 100%; object-fit: cover;
730
- }
731
-
732
- .mbkh-sel-badge {
733
- font-size: 10px;
734
- font-weight: 700;
735
- padding: 3px 6px;
736
- border-radius: 4px;
737
- flex-shrink: 0;
738
- }
739
-
740
- .mbkh-sel-info {
741
- flex: 1;
742
- min-width: 0;
743
- }
744
- .mbkh-sel-name {
745
- font-size: 12px;
746
- font-weight: 600;
747
- color: var(--mbkh-primary-dk);
748
- overflow: hidden;
749
- text-overflow: ellipsis;
750
- white-space: nowrap;
751
- }
752
- .mbkh-sel-meta {
753
- font-size: 10.5px;
754
- color: var(--mbkh-text-muted);
755
- font-family: var(--mbkh-font-mono);
756
- }
757
-
758
- .mbkh-sel-clear {
759
- border: none;
760
- background: transparent;
761
- color: var(--mbkh-text-dim);
762
- cursor: pointer;
763
- padding: 2px 4px;
764
- border-radius: 3px;
765
- display: flex;
766
- align-items: center;
767
- transition: all var(--mbkh-transition);
768
- }
769
- .mbkh-sel-clear:hover {
770
- color: var(--mbkh-danger);
771
- background: rgba(220, 38, 38, 0.1);
772
- }
773
-
774
- /* Multi-selection tray */
775
- .mbkh-multi-tray {
776
- display: flex;
777
- align-items: center;
778
- gap: 8px;
779
- flex: 1;
780
- min-width: 0;
781
- overflow: hidden;
782
- }
783
- .mbkh-multi-count {
784
- font-size: 12px;
785
- font-weight: 700;
786
- color: var(--mbkh-primary-dk);
787
- white-space: nowrap;
788
- flex-shrink: 0;
789
- }
790
- .mbkh-multi-chips {
791
- display: flex;
792
- align-items: center;
793
- gap: 4px;
794
- flex: 1;
795
- min-width: 0;
796
- overflow-x: auto;
797
- }
798
- .mbkh-multi-chips::-webkit-scrollbar { display: none; }
799
- .mbkh-multi-chip {
800
- display: inline-flex;
801
- align-items: center;
802
- gap: 4px;
803
- padding: 2px 8px;
804
- background: #ffffff;
805
- border: 1px solid var(--mbkh-border);
806
- border-radius: 20px;
807
- font-size: 11px;
808
- color: var(--mbkh-text);
809
- white-space: nowrap;
810
- max-width: 130px;
811
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
812
- }
813
- .mbkh-multi-chip-name {
814
- overflow: hidden;
815
- text-overflow: ellipsis;
816
- white-space: nowrap;
817
- }
818
- .mbkh-multi-chip-rm {
819
- color: var(--mbkh-text-dim);
820
- cursor: pointer;
821
- display: flex;
822
- align-items: center;
823
- }
824
- .mbkh-multi-chip-rm:hover { color: var(--mbkh-danger); }
825
- .mbkh-multi-chip-more {
826
- font-size: 11px;
827
- font-weight: 600;
828
- color: var(--mbkh-primary);
829
- white-space: nowrap;
830
- padding: 0 4px;
831
- }
832
-
833
- .mbkh-footer-btns {
834
- display: flex;
835
- align-items: center;
836
- gap: 8px;
837
- flex-shrink: 0;
838
- }
839
-
840
- /* ─── Buttons ──────────────────────────────────────────────────────────────── */
841
- .mbkh-btn {
842
- display: inline-flex;
843
- align-items: center;
844
- gap: 6px;
845
- padding: 7px 16px;
846
- border-radius: var(--mbkh-radius-md);
847
- font-family: var(--mbkh-font);
848
- font-size: 13px;
849
- font-weight: 600;
850
- cursor: pointer;
851
- border: 1px solid transparent;
852
- transition: all var(--mbkh-transition);
853
- white-space: nowrap;
854
- flex-shrink: 0;
855
- text-decoration: none;
856
- line-height: 1.4;
857
- }
858
- .mbkh-btn:active { transform: translateY(0) !important; opacity: 0.92; }
859
-
860
- .mbkh-btn-ghost {
861
- background: rgba(255, 255, 255, 0.9);
862
- border-color: var(--mbkh-border);
863
- color: var(--mbkh-text-sec);
864
- }
865
- .mbkh-btn-ghost:hover {
866
- background: var(--mbkh-primary-lt);
867
- color: var(--mbkh-primary-dk);
868
- border-color: var(--mbkh-primary);
869
- }
870
-
871
- .mbkh-btn-primary {
872
- background: var(--mbkh-primary);
873
- color: #fff;
874
- border-color: var(--mbkh-primary);
875
- box-shadow: 0 2px 4px rgba(15, 118, 110, 0.2);
876
- }
877
- .mbkh-btn-primary:hover {
878
- background: var(--mbkh-primary-dk);
879
- border-color: var(--mbkh-primary-dk);
880
- transform: translateY(-1px);
881
- color: #fff;
882
- }
883
- .mbkh-btn-primary:disabled {
884
- opacity: 0.45;
885
- cursor: not-allowed;
886
- pointer-events: none;
887
- }
888
-
889
- /* Load-more */
890
- .mbkh-load-more-wrap {
891
- display: flex;
892
- justify-content: center;
893
- padding: 8px;
894
- grid-column: 1 / -1;
895
- }
896
-
897
- /* ═══════════════════════════════════════════════════════════════════════════
898
- FILE PICKER INPUT
899
- ═══════════════════════════════════════════════════════════════════════════ */
900
-
901
- .mbkh-picker {
902
- font-family: var(--mbkh-font);
903
- display: flex;
904
- align-items: stretch;
905
- border-radius: var(--mbkh-radius-md);
906
- border: 1px solid var(--mbkh-border);
907
- background: var(--mbkh-surface2);
908
- overflow: hidden;
909
- transition: border-color var(--mbkh-transition), box-shadow var(--mbkh-transition);
910
- min-width: 0;
911
- }
912
- .mbkh-picker:focus-within {
913
- border-color: var(--mbkh-primary);
914
- box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.1);
915
- }
916
-
917
- .mbkh-picker-value {
918
- flex: 1;
919
- background: transparent;
920
- border: none;
921
- outline: none;
922
- color: var(--mbkh-text);
923
- font-family: var(--mbkh-font);
924
- font-size: 13px;
925
- padding: 8px 10px;
926
- min-width: 0;
927
- cursor: default;
928
- }
929
- .mbkh-picker-value::placeholder { color: var(--mbkh-text-dim); }
930
-
931
- .mbkh-picker-actions {
932
- display: flex;
933
- align-items: center;
934
- flex-shrink: 0;
935
- border-left: 1px solid var(--mbkh-border);
936
- }
937
-
938
- .mbkh-picker-btn {
939
- display: flex;
940
- align-items: center;
941
- gap: 5px;
942
- padding: 0 13px;
943
- height: 100%;
944
- border: none;
945
- background: transparent;
946
- color: var(--mbkh-text-muted);
947
- font-family: var(--mbkh-font);
948
- font-size: 12.5px;
949
- font-weight: 600;
950
- cursor: pointer;
951
- transition: background var(--mbkh-transition), color var(--mbkh-transition);
952
- white-space: nowrap;
953
- }
954
- .mbkh-picker-btn:hover {
955
- background: var(--mbkh-primary-lt);
956
- color: var(--mbkh-primary-dk);
957
- }
958
-
959
- .mbkh-picker-clear {
960
- width: 30px; height: 100%;
961
- display: flex; align-items: center; justify-content: center;
962
- border: none;
963
- background: transparent;
964
- color: var(--mbkh-text-dim);
965
- cursor: pointer;
966
- border-left: 1px solid var(--mbkh-border-lt);
967
- transition: color var(--mbkh-transition), background var(--mbkh-transition);
968
- }
969
- .mbkh-picker-clear:hover {
970
- color: var(--mbkh-danger);
971
- background: rgba(220, 38, 38, 0.07);
972
- }
973
- .mbkh-picker-clear[hidden] { display: none; }
974
-
975
- /* ═══════════════════════════════════════════════════════════════════════════
976
- UPLOAD WIDGET
977
- ═══════════════════════════════════════════════════════════════════════════ */
978
-
979
- .mbkh-uploader {
980
- font-family: var(--mbkh-font);
981
- color: var(--mbkh-text);
982
- display: flex;
983
- flex-direction: column;
984
- gap: 10px;
985
- }
986
-
987
- /* Drop zone */
988
- .mbkh-dropzone {
989
- border: 2px dashed var(--mbkh-border);
990
- border-radius: var(--mbkh-radius);
991
- padding: 28px 20px;
992
- text-align: center;
993
- cursor: pointer;
994
- transition: border-color var(--mbkh-transition), background var(--mbkh-transition);
995
- background: rgba(255, 255, 255, 0.6);
996
- display: flex;
997
- flex-direction: column;
998
- align-items: center;
999
- gap: 8px;
1000
- }
1001
- .mbkh-dropzone:hover,
1002
- .mbkh-dropzone.mbkh-drag-over {
1003
- border-color: var(--mbkh-primary);
1004
- background: var(--mbkh-primary-lt);
1005
- }
1006
-
1007
- .mbkh-dropzone-icon {
1008
- width: 44px; height: 44px;
1009
- border-radius: 12px;
1010
- background: var(--mbkh-surface2);
1011
- border: 1px solid var(--mbkh-border);
1012
- display: flex; align-items: center; justify-content: center;
1013
- color: var(--mbkh-text-muted);
1014
- margin-bottom: 2px;
1015
- transition: color var(--mbkh-transition), background var(--mbkh-transition), border-color var(--mbkh-transition);
1016
- }
1017
- .mbkh-dropzone:hover .mbkh-dropzone-icon,
1018
- .mbkh-dropzone.mbkh-drag-over .mbkh-dropzone-icon {
1019
- background: rgba(15, 118, 110, 0.12);
1020
- border-color: rgba(15, 118, 110, 0.25);
1021
- color: var(--mbkh-primary);
1022
- }
1023
-
1024
- .mbkh-dropzone-title {
1025
- font-family: var(--mbkh-font-heading);
1026
- font-size: 13.5px;
1027
- font-weight: 600;
1028
- color: var(--mbkh-text);
1029
- }
1030
- .mbkh-dropzone-sub {
1031
- font-size: 12px;
1032
- color: var(--mbkh-text-muted);
1033
- }
1034
- .mbkh-dropzone-sub strong {
1035
- color: var(--mbkh-primary);
1036
- cursor: pointer;
1037
- text-decoration: underline;
1038
- text-underline-offset: 2px;
1039
- font-weight: 600;
1040
- }
1041
-
1042
- /* Upload queue list */
1043
- .mbkh-upload-list {
1044
- display: flex;
1045
- flex-direction: column;
1046
- gap: 5px;
1047
- max-height: 280px;
1048
- overflow-y: auto;
1049
- }
1050
- .mbkh-upload-list::-webkit-scrollbar { width: 5px; }
1051
- .mbkh-upload-list::-webkit-scrollbar-track { background: transparent; }
1052
- .mbkh-upload-list::-webkit-scrollbar-thumb {
1053
- background: var(--mbkh-border);
1054
- border-radius: 3px;
1055
- }
1056
-
1057
- /* Upload item */
1058
- .mbkh-upload-item {
1059
- display: flex;
1060
- align-items: center;
1061
- gap: 10px;
1062
- padding: 9px 12px;
1063
- background: rgba(255, 255, 255, 0.85);
1064
- border: 1px solid var(--mbkh-border);
1065
- border-radius: var(--mbkh-radius-md);
1066
- transition: border-color var(--mbkh-transition);
1067
- }
1068
- .mbkh-upload-item.mbkh-done { border-color: rgba(22,163,74,0.3); background: rgba(22,163,74,0.03); }
1069
- .mbkh-upload-item.mbkh-error { border-color: rgba(220,38,38,0.3); background: rgba(220,38,38,0.03); }
1070
-
1071
- .mbkh-upload-file-icon {
1072
- width: 32px; height: 32px;
1073
- border-radius: var(--mbkh-radius-sm);
1074
- background: var(--mbkh-surface2);
1075
- border: 1px solid var(--mbkh-border-lt);
1076
- display: flex; align-items: center; justify-content: center;
1077
- font-family: var(--mbkh-font);
1078
- font-size: 9px;
1079
- font-weight: 700;
1080
- letter-spacing: 0.04em;
1081
- color: var(--mbkh-text-muted);
1082
- flex-shrink: 0;
1083
- }
1084
-
1085
- .mbkh-upload-info {
1086
- flex: 1;
1087
- min-width: 0;
1088
- display: flex;
1089
- flex-direction: column;
1090
- gap: 4px;
1091
- }
1092
- .mbkh-upload-name {
1093
- font-size: 12.5px;
1094
- font-weight: 500;
1095
- white-space: nowrap;
1096
- overflow: hidden;
1097
- text-overflow: ellipsis;
1098
- color: var(--mbkh-text);
1099
- }
1100
-
1101
- .mbkh-upload-progress-row {
1102
- display: flex;
1103
- align-items: center;
1104
- gap: 8px;
1105
- }
1106
-
1107
- .mbkh-progress-bar-wrap {
1108
- flex: 1;
1109
- height: 4px;
1110
- background: var(--mbkh-surface3);
1111
- border-radius: 2px;
1112
- overflow: hidden;
1113
- }
1114
- .mbkh-progress-bar {
1115
- height: 100%;
1116
- border-radius: 2px;
1117
- background: var(--mbkh-primary);
1118
- transition: width 0.25s ease;
1119
- width: 0%;
1120
- }
1121
- .mbkh-upload-item.mbkh-done .mbkh-progress-bar { background: var(--mbkh-success); width: 100% !important; }
1122
- .mbkh-upload-item.mbkh-error .mbkh-progress-bar { background: var(--mbkh-danger); }
1123
-
1124
- .mbkh-upload-pct {
1125
- font-size: 11px;
1126
- font-family: var(--mbkh-font-mono);
1127
- color: var(--mbkh-text-muted);
1128
- min-width: 30px;
1129
- text-align: right;
1130
- flex-shrink: 0;
1131
- }
1132
- .mbkh-upload-status {
1133
- font-size: 11px;
1134
- color: var(--mbkh-text-muted);
1135
- }
1136
- .mbkh-upload-item.mbkh-done .mbkh-upload-status { color: var(--mbkh-success); font-weight: 600; }
1137
- .mbkh-upload-item.mbkh-error .mbkh-upload-status { color: var(--mbkh-danger); font-weight: 600; }
1138
-
1139
- .mbkh-upload-remove {
1140
- width: 26px; height: 26px;
1141
- border: none;
1142
- background: transparent;
1143
- color: var(--mbkh-text-dim);
1144
- border-radius: var(--mbkh-radius-sm);
1145
- cursor: pointer;
1146
- display: flex; align-items: center; justify-content: center;
1147
- flex-shrink: 0;
1148
- transition: color var(--mbkh-transition), background var(--mbkh-transition);
1149
- }
1150
- .mbkh-upload-remove:hover {
1151
- color: var(--mbkh-danger);
1152
- background: rgba(220, 38, 38, 0.08);
1153
- }
1154
-
1155
- /* Upload actions bar */
1156
- .mbkh-upload-actions {
1157
- display: flex;
1158
- gap: 8px;
1159
- align-items: center;
1160
- justify-content: flex-end;
1161
- }
1162
- .mbkh-upload-summary {
1163
- flex: 1;
1164
- font-size: 12px;
1165
- color: var(--mbkh-text-muted);
1166
- }
1167
-
1168
- /* ═══════════════════════════════════════════════════════════════════════════
1169
- TOAST NOTIFICATIONS
1170
- ═══════════════════════════════════════════════════════════════════════════ */
1171
-
1172
- .mbkh-toast-container {
1173
- position: fixed;
1174
- bottom: 20px;
1175
- right: 20px;
1176
- z-index: 99999;
1177
- display: flex;
1178
- flex-direction: column;
1179
- gap: 8px;
1180
- pointer-events: none;
1181
- }
1182
-
1183
- .mbkh-toast {
1184
- font-family: var(--mbkh-font);
1185
- font-size: 13px;
1186
- color: var(--mbkh-text);
1187
- background: rgba(255, 255, 255, 0.96);
1188
- border: 1px solid rgba(255, 255, 255, 0.9);
1189
- border-radius: var(--mbkh-radius-md);
1190
- padding: 10px 14px;
1191
- box-shadow: var(--mbkh-shadow-dropdown);
1192
- display: flex;
1193
- align-items: center;
1194
- gap: 9px;
1195
- min-width: 230px;
1196
- max-width: 340px;
1197
- pointer-events: all;
1198
- animation: mbkh-toast-in 0.2s cubic-bezier(0.34, 1.3, 0.64, 1);
1199
- border-left: 3px solid var(--mbkh-primary);
1200
- }
1201
- .mbkh-toast.mbkh-toast-success { border-left-color: var(--mbkh-success); }
1202
- .mbkh-toast.mbkh-toast-error { border-left-color: var(--mbkh-danger); }
1203
- .mbkh-toast.mbkh-toast-warning { border-left-color: var(--mbkh-warning); }
1204
- .mbkh-toast.mbkh-toast-info { border-left-color: var(--mbkh-primary); }
1205
-
1206
- @keyframes mbkh-toast-in {
1207
- from { opacity: 0; transform: translateX(24px); }
1208
- to { opacity: 1; transform: translateX(0); }
1209
- }
1210
- .mbkh-toast.mbkh-toast-out {
1211
- animation: mbkh-toast-out 0.18s ease forwards;
1212
- }
1213
- @keyframes mbkh-toast-out {
1214
- to { opacity: 0; transform: translateX(24px); }
1215
- }
1216
-
1217
- .mbkh-toast-icon { flex-shrink: 0; }
1218
- .mbkh-toast-msg { flex: 1; line-height: 1.45; color: var(--mbkh-text-sec); }
1219
-
1220
- /* ═══════════════════════════════════════════════════════════════════════════
1221
- RESPONSIVE
1222
- ═══════════════════════════════════════════════════════════════════════════ */
1223
-
1224
- @media (max-width: 600px) {
1225
- .mbkh-modal {
1226
- height: 95dvh;
1227
- max-width: 100%;
1228
- border-radius: var(--mbkh-radius-sm);
1229
- }
1230
- .mbkh-file-grid {
1231
- grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
1232
- }
1233
- .mbkh-search { width: 130px; }
1234
- .mbkh-search:focus { width: 160px; }
1235
- }
1
+ /**
2
+ * mbkbucket-helper.css v1.0.0
3
+ * ─────────────────────────────────────────────────────────────────────────────
4
+ * Scoped styles for MBKBucket frontend helper components.
5
+ * All selectors prefixed with .mbkh- to avoid collisions.
6
+ *
7
+ * Follows the mbkbucket design system (light-mode, teal/green palette).
8
+ * Inherits --primary-color-ml, --font, etc. if bucketadmin.css is also loaded.
9
+ * Falls back to standalone tokens if used without bucketadmin.css.
10
+ * ─────────────────────────────────────────────────────────────────────────────
11
+ */
12
+
13
+ /* ─── Standalone design tokens (fallbacks via @property-like approach) ──────── */
14
+ :root {
15
+ /* Colours */
16
+ --mbkh-primary: var(--primary-color-ml, #0f766e);
17
+ --mbkh-primary-lt: var(--primary-light-color-ml, #d7f4ee);
18
+ --mbkh-primary-dk: var(--primary-dark-color-ml, #0b4f4a);
19
+ --mbkh-primary-hover: var(--primary-hover, #0d635c);
20
+
21
+ --mbkh-danger: var(--danger-color-ml, #dc2626);
22
+ --mbkh-success: var(--success-color-ml, #16a34a);
23
+ --mbkh-warning: var(--warning-color-ml, #d97706);
24
+
25
+ /* Backgrounds */
26
+ --mbkh-body-bg: var(--body-bg, #f4f7f3);
27
+ --mbkh-surface: var(--bg-surface, rgba(255,255,255,0.85));
28
+ --mbkh-surface2: var(--bg-surface-secondary, rgba(244,247,243,0.85));
29
+ --mbkh-surface3: var(--bg-surface-tertiary, #e2ede8);
30
+
31
+ /* Borders */
32
+ --mbkh-border: var(--border-color, rgba(15,118,110,0.16));
33
+ --mbkh-border-lt: var(--border-color-light, rgba(15,118,110,0.08));
34
+ --mbkh-border-active: rgba(15,118,110,0.45);
35
+
36
+ /* Text */
37
+ --mbkh-text: var(--text, #1f2a2a);
38
+ --mbkh-text-sec: var(--text-secondary, #425855);
39
+ --mbkh-text-muted: var(--text-muted, #667c79);
40
+ --mbkh-text-dim: var(--text-disabled, #a0b2af);
41
+
42
+ /* Typography */
43
+ --mbkh-font: var(--font, "IBM Plex Sans", "Segoe UI", sans-serif);
44
+ --mbkh-font-heading: var(--font-headings, "Sora", "Segoe UI", sans-serif);
45
+ --mbkh-font-mono: var(--font-mono, "JetBrains Mono", Consolas, monospace);
46
+
47
+ /* Shape */
48
+ --mbkh-radius: var(--radius-lg, 14px);
49
+ --mbkh-radius-md: var(--radius, 8px);
50
+ --mbkh-radius-sm: var(--radius-sm, 6px);
51
+
52
+ /* Shadows */
53
+ --mbkh-shadow: var(--shadow-lg,
54
+ 0 20px 40px rgba(15,118,110,0.12),
55
+ 0 4px 12px rgba(0,0,0,0.06));
56
+ --mbkh-shadow-sm: var(--shadow-md,
57
+ 0 8px 20px rgba(15,118,110,0.08),
58
+ 0 2px 6px rgba(0,0,0,0.04));
59
+ --mbkh-shadow-dropdown: var(--shadow-dropdown,
60
+ 0 12px 30px rgba(15,42,42,0.14),
61
+ 0 4px 10px rgba(0,0,0,0.05));
62
+
63
+ /* Transition */
64
+ --mbkh-transition: 0.15s ease-in-out;
65
+ }
66
+
67
+ /* ─── Reset inside helper components ───────────────────────────────────────── */
68
+ .mbkh-modal *,
69
+ .mbkh-picker *,
70
+ .mbkh-uploader *,
71
+ .mbkh-toast-container * {
72
+ box-sizing: border-box;
73
+ margin: 0;
74
+ padding: 0;
75
+ }
76
+
77
+ /* ═══════════════════════════════════════════════════════════════════════════
78
+ OVERLAY + MODAL
79
+ ═══════════════════════════════════════════════════════════════════════════ */
80
+
81
+ .mbkh-overlay {
82
+ position: fixed;
83
+ inset: 0;
84
+ z-index: 99990;
85
+ background: rgba(15, 42, 42, 0.45);
86
+ backdrop-filter: blur(4px);
87
+ -webkit-backdrop-filter: blur(4px);
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ padding: 16px;
92
+ animation: mbkh-fade-in 0.18s ease;
93
+ }
94
+
95
+ @keyframes mbkh-fade-in { from { opacity: 0; } to { opacity: 1; } }
96
+
97
+ .mbkh-overlay.mbkh-closing {
98
+ animation: mbkh-fade-out 0.16s ease forwards;
99
+ }
100
+ @keyframes mbkh-fade-out { to { opacity: 0; } }
101
+
102
+ /* ─── Modal shell ──────────────────────────────────────────────────────────── */
103
+ .mbkh-modal {
104
+ font-family: var(--mbkh-font);
105
+ color: var(--mbkh-text);
106
+ background: rgba(255, 255, 255, 0.98);
107
+ border: 1px solid rgba(255, 255, 255, 0.95);
108
+ border-radius: var(--mbkh-radius);
109
+ box-shadow: 0 24px 60px rgba(15, 42, 42, 0.2), 0 4px 16px rgba(0, 0, 0, 0.06);
110
+ backdrop-filter: blur(16px);
111
+ -webkit-backdrop-filter: blur(16px);
112
+ width: 100%;
113
+ max-width: 920px;
114
+ height: min(86vh, 680px);
115
+ display: flex;
116
+ flex-direction: column;
117
+ overflow: hidden;
118
+ animation: mbkh-slide-up 0.2s cubic-bezier(0.34, 1.3, 0.64, 1);
119
+ }
120
+
121
+ @keyframes mbkh-slide-up {
122
+ from { opacity: 0; transform: translateY(16px) scale(0.98); }
123
+ to { opacity: 1; transform: translateY(0) scale(1); }
124
+ }
125
+
126
+ /* ─── Modal header ─────────────────────────────────────────────────────────── */
127
+ .mbkh-modal-header {
128
+ display: flex;
129
+ align-items: center;
130
+ gap: 10px;
131
+ padding: 12px 18px 11px;
132
+ border-bottom: 1px solid var(--mbkh-border);
133
+ background: rgba(244, 247, 243, 0.85);
134
+ flex-shrink: 0;
135
+ }
136
+
137
+ .mbkh-modal-logo {
138
+ width: 26px; height: 26px;
139
+ background: var(--mbkh-primary);
140
+ border-radius: var(--mbkh-radius-sm);
141
+ display: flex; align-items: center; justify-content: center;
142
+ color: #fff;
143
+ flex-shrink: 0;
144
+ box-shadow: 0 2px 4px rgba(15, 118, 110, 0.25);
145
+ }
146
+ .mbkh-modal-logo svg { width: 14px; height: 14px; }
147
+
148
+ .mbkh-modal-title {
149
+ font-family: var(--mbkh-font-heading);
150
+ font-size: 14px;
151
+ font-weight: 700;
152
+ color: var(--mbkh-primary-dk);
153
+ flex: 1;
154
+ min-width: 0;
155
+ white-space: nowrap;
156
+ overflow: hidden;
157
+ text-overflow: ellipsis;
158
+ }
159
+
160
+ .mbkh-header-actions {
161
+ display: flex;
162
+ align-items: center;
163
+ gap: 8px;
164
+ flex-shrink: 0;
165
+ }
166
+
167
+ .mbkh-btn-upload-header {
168
+ display: inline-flex;
169
+ align-items: center;
170
+ gap: 5px;
171
+ padding: 4px 10px;
172
+ background: var(--mbkh-primary-lt);
173
+ color: var(--mbkh-primary-dk);
174
+ border: 1px solid rgba(15, 118, 110, 0.2);
175
+ border-radius: var(--mbkh-radius-sm);
176
+ font-family: var(--mbkh-font);
177
+ font-size: 12px;
178
+ font-weight: 600;
179
+ cursor: pointer;
180
+ transition: all var(--mbkh-transition);
181
+ }
182
+ .mbkh-btn-upload-header:hover {
183
+ background: var(--mbkh-primary);
184
+ color: #ffffff;
185
+ border-color: var(--mbkh-primary);
186
+ }
187
+
188
+ .mbkh-modal-close {
189
+ width: 28px; height: 28px;
190
+ border: none;
191
+ background: transparent;
192
+ color: var(--mbkh-text-muted);
193
+ border-radius: var(--mbkh-radius-sm);
194
+ cursor: pointer;
195
+ display: flex; align-items: center; justify-content: center;
196
+ transition: all var(--mbkh-transition);
197
+ flex-shrink: 0;
198
+ }
199
+ .mbkh-modal-close:hover {
200
+ background: rgba(220, 38, 38, 0.1);
201
+ color: var(--mbkh-danger);
202
+ }
203
+
204
+ /* ─── Toolbar ──────────────────────────────────────────────────────────────── */
205
+ .mbkh-toolbar {
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: space-between;
209
+ gap: 12px;
210
+ padding: 8px 16px;
211
+ border-bottom: 1px solid var(--mbkh-border-lt);
212
+ background: rgba(255, 255, 255, 0.8);
213
+ flex-shrink: 0;
214
+ flex-wrap: wrap;
215
+ }
216
+
217
+ .mbkh-breadcrumb {
218
+ display: flex;
219
+ align-items: center;
220
+ gap: 4px;
221
+ flex: 1;
222
+ min-width: 0;
223
+ overflow-x: auto;
224
+ padding-bottom: 1px;
225
+ }
226
+ .mbkh-breadcrumb::-webkit-scrollbar { display: none; }
227
+
228
+ .mbkh-crumb {
229
+ display: inline-flex;
230
+ align-items: center;
231
+ gap: 4px;
232
+ padding: 4px 8px;
233
+ border-radius: var(--mbkh-radius-sm);
234
+ font-size: 12.5px;
235
+ font-weight: 500;
236
+ color: var(--mbkh-text-muted);
237
+ cursor: pointer;
238
+ transition: all var(--mbkh-transition);
239
+ white-space: nowrap;
240
+ max-width: 140px;
241
+ overflow: hidden;
242
+ text-overflow: ellipsis;
243
+ border: none;
244
+ background: transparent;
245
+ font-family: var(--mbkh-font);
246
+ }
247
+ .mbkh-crumb:hover {
248
+ background: var(--mbkh-primary-lt);
249
+ color: var(--mbkh-primary-dk);
250
+ }
251
+ .mbkh-crumb.mbkh-crumb-active {
252
+ color: var(--mbkh-primary-dk);
253
+ font-weight: 700;
254
+ background: rgba(15, 118, 110, 0.08);
255
+ cursor: default;
256
+ pointer-events: none;
257
+ }
258
+ .mbkh-crumb-text {
259
+ overflow: hidden;
260
+ text-overflow: ellipsis;
261
+ white-space: nowrap;
262
+ }
263
+
264
+ .mbkh-crumb-sep {
265
+ color: var(--mbkh-text-dim);
266
+ font-size: 11px;
267
+ font-weight: 600;
268
+ flex-shrink: 0;
269
+ }
270
+
271
+ .mbkh-toolbar-actions {
272
+ display: flex;
273
+ align-items: center;
274
+ gap: 8px;
275
+ flex-shrink: 0;
276
+ }
277
+
278
+ /* Search */
279
+ .mbkh-search-wrap {
280
+ position: relative;
281
+ display: flex;
282
+ align-items: center;
283
+ }
284
+ .mbkh-search-icon {
285
+ position: absolute;
286
+ left: 9px;
287
+ color: var(--mbkh-text-muted);
288
+ pointer-events: none;
289
+ display: flex;
290
+ align-items: center;
291
+ }
292
+ .mbkh-search {
293
+ background: var(--mbkh-surface2);
294
+ border: 1px solid var(--mbkh-border);
295
+ border-radius: var(--mbkh-radius-md);
296
+ color: var(--mbkh-text);
297
+ font-family: var(--mbkh-font);
298
+ font-size: 12.5px;
299
+ padding: 5px 10px 5px 28px;
300
+ outline: none;
301
+ width: 170px;
302
+ transition: border-color var(--mbkh-transition), box-shadow var(--mbkh-transition), width var(--mbkh-transition);
303
+ }
304
+ .mbkh-search:focus {
305
+ border-color: var(--mbkh-primary);
306
+ box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.1);
307
+ background: #ffffff;
308
+ width: 210px;
309
+ }
310
+ .mbkh-search::placeholder { color: var(--mbkh-text-dim); }
311
+
312
+ /* View toggle */
313
+ .mbkh-view-toggle {
314
+ display: inline-flex;
315
+ gap: 1px;
316
+ background: var(--mbkh-surface2);
317
+ border: 1px solid var(--mbkh-border);
318
+ border-radius: var(--mbkh-radius-md);
319
+ padding: 2px;
320
+ flex-shrink: 0;
321
+ }
322
+ .mbkh-view-btn {
323
+ width: 26px; height: 26px;
324
+ border: none;
325
+ background: transparent;
326
+ color: var(--mbkh-text-muted);
327
+ border-radius: var(--mbkh-radius-sm);
328
+ cursor: pointer;
329
+ display: flex; align-items: center; justify-content: center;
330
+ transition: all var(--mbkh-transition);
331
+ }
332
+ .mbkh-view-btn:hover { color: var(--mbkh-primary-dk); }
333
+ .mbkh-view-btn.mbkh-active {
334
+ background: var(--mbkh-primary);
335
+ color: #fff;
336
+ box-shadow: 0 1px 3px rgba(15, 118, 110, 0.2);
337
+ }
338
+
339
+ /* ─── Filter Bar ───────────────────────────────────────────────────────────── */
340
+ .mbkh-filter-bar {
341
+ display: flex;
342
+ align-items: center;
343
+ gap: 4px;
344
+ padding: 6px 16px;
345
+ background: rgba(244, 247, 243, 0.6);
346
+ border-bottom: 1px solid var(--mbkh-border);
347
+ overflow-x: auto;
348
+ }
349
+ .mbkh-filter-bar::-webkit-scrollbar { display: none; }
350
+
351
+ .mbkh-filter-btn {
352
+ padding: 3px 10px;
353
+ border-radius: 20px;
354
+ border: 1px solid transparent;
355
+ background: transparent;
356
+ font-family: var(--mbkh-font);
357
+ font-size: 11.5px;
358
+ font-weight: 600;
359
+ color: var(--mbkh-text-sec);
360
+ cursor: pointer;
361
+ transition: all var(--mbkh-transition);
362
+ white-space: nowrap;
363
+ }
364
+ .mbkh-filter-btn:hover {
365
+ background: rgba(255, 255, 255, 0.8);
366
+ color: var(--mbkh-primary-dk);
367
+ }
368
+ .mbkh-filter-btn.mbkh-active {
369
+ background: #ffffff;
370
+ color: var(--mbkh-primary);
371
+ border-color: rgba(15, 118, 110, 0.2);
372
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
373
+ }
374
+
375
+ /* In-modal Upload Banner */
376
+ .mbkh-modal-upload-banner {
377
+ padding: 8px 18px;
378
+ background: rgba(15, 118, 110, 0.08);
379
+ border-bottom: 1px solid rgba(15, 118, 110, 0.15);
380
+ display: flex;
381
+ flex-direction: column;
382
+ gap: 5px;
383
+ animation: mbkh-fade-in 0.15s ease;
384
+ }
385
+ .mbkh-upload-banner-text {
386
+ font-size: 12px;
387
+ font-weight: 600;
388
+ color: var(--mbkh-primary-dk);
389
+ }
390
+ .mbkh-upload-banner-bar {
391
+ height: 4px;
392
+ background: var(--mbkh-surface3);
393
+ border-radius: 2px;
394
+ overflow: hidden;
395
+ }
396
+ .mbkh-upload-banner-fill {
397
+ height: 100%;
398
+ width: 0%;
399
+ background: var(--mbkh-primary);
400
+ transition: width 0.2s ease;
401
+ }
402
+
403
+ /* Drag overlay */
404
+ .mbkh-drag-overlay {
405
+ position: absolute;
406
+ inset: 0;
407
+ background: rgba(244, 247, 243, 0.92);
408
+ backdrop-filter: blur(4px);
409
+ z-index: 50;
410
+ display: flex;
411
+ align-items: center;
412
+ justify-content: center;
413
+ padding: 24px;
414
+ pointer-events: none;
415
+ }
416
+ .mbkh-drag-box {
417
+ width: 100%;
418
+ max-width: 440px;
419
+ border: 2px dashed var(--mbkh-primary);
420
+ border-radius: var(--mbkh-radius);
421
+ background: rgba(255, 255, 255, 0.9);
422
+ padding: 36px 24px;
423
+ display: flex;
424
+ flex-direction: column;
425
+ align-items: center;
426
+ gap: 12px;
427
+ color: var(--mbkh-primary);
428
+ box-shadow: 0 12px 30px rgba(15, 118, 110, 0.15);
429
+ }
430
+ .mbkh-drag-text {
431
+ font-family: var(--mbkh-font-heading);
432
+ font-size: 14px;
433
+ font-weight: 700;
434
+ color: var(--mbkh-primary-dk);
435
+ text-align: center;
436
+ }
437
+
438
+ /* ─── Modal body / file grid ───────────────────────────────────────────────── */
439
+ .mbkh-modal-body {
440
+ flex: 1;
441
+ overflow: hidden;
442
+ display: flex;
443
+ flex-direction: column;
444
+ background: rgba(244, 247, 243, 0.35);
445
+ position: relative;
446
+ }
447
+
448
+ .mbkh-file-grid {
449
+ flex: 1;
450
+ overflow-y: auto;
451
+ padding: 16px;
452
+ display: grid;
453
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
454
+ grid-auto-rows: max-content;
455
+ gap: 12px;
456
+ align-content: start;
457
+ }
458
+ .mbkh-file-grid::-webkit-scrollbar { width: 6px; }
459
+ .mbkh-file-grid::-webkit-scrollbar-track { background: transparent; }
460
+ .mbkh-file-grid::-webkit-scrollbar-thumb {
461
+ background: var(--mbkh-border);
462
+ border-radius: 3px;
463
+ }
464
+ .mbkh-file-grid::-webkit-scrollbar-thumb:hover {
465
+ background: var(--mbkh-primary);
466
+ }
467
+
468
+ /* ─── Grid View Item Card ──────────────────────────────────────────────────── */
469
+ .mbkh-item {
470
+ position: relative;
471
+ background: rgba(255, 255, 255, 0.95);
472
+ border: 1px solid rgba(15, 118, 110, 0.15);
473
+ border-radius: var(--mbkh-radius-md);
474
+ padding: 8px;
475
+ cursor: pointer;
476
+ display: flex;
477
+ flex-direction: column;
478
+ gap: 7px;
479
+ transition: all var(--mbkh-transition);
480
+ user-select: none;
481
+ min-width: 0;
482
+ box-shadow: 0 2px 4px rgba(15, 118, 110, 0.04);
483
+ }
484
+ .mbkh-item:hover {
485
+ border-color: var(--mbkh-primary);
486
+ transform: translateY(-2px);
487
+ box-shadow: 0 6px 16px rgba(15, 118, 110, 0.1);
488
+ background: #ffffff;
489
+ }
490
+ .mbkh-item.mbkh-selected {
491
+ border-color: var(--mbkh-primary);
492
+ background: rgba(215, 244, 238, 0.4);
493
+ box-shadow: 0 0 0 2px var(--mbkh-primary), 0 8px 20px rgba(15, 118, 110, 0.12);
494
+ }
495
+
496
+ /* Card preview area */
497
+ .mbkh-card-preview {
498
+ width: 100%;
499
+ aspect-ratio: 16 / 11;
500
+ border-radius: var(--mbkh-radius-sm);
501
+ background: var(--mbkh-surface3);
502
+ display: flex;
503
+ align-items: center;
504
+ justify-content: center;
505
+ overflow: hidden;
506
+ position: relative;
507
+ border: 1px solid rgba(15, 118, 110, 0.08);
508
+ }
509
+ .mbkh-card-preview.mbkh-thumb img {
510
+ width: 100%;
511
+ height: 100%;
512
+ object-fit: cover;
513
+ transition: transform 0.2s ease;
514
+ }
515
+ .mbkh-item:hover .mbkh-card-preview.mbkh-thumb img {
516
+ transform: scale(1.04);
517
+ }
518
+
519
+ .mbkh-folder-preview {
520
+ background: var(--mbkh-primary-lt);
521
+ }
522
+ .mbkh-folder-svg {
523
+ width: 38px;
524
+ height: 38px;
525
+ }
526
+
527
+ .mbkh-ext-tag {
528
+ position: absolute;
529
+ bottom: 4px;
530
+ right: 4px;
531
+ font-family: var(--mbkh-font-mono);
532
+ font-size: 9px;
533
+ font-weight: 700;
534
+ padding: 1px 5px;
535
+ border-radius: 3px;
536
+ background: rgba(15, 42, 42, 0.75);
537
+ color: #ffffff;
538
+ backdrop-filter: blur(4px);
539
+ letter-spacing: 0.04em;
540
+ text-transform: uppercase;
541
+ }
542
+
543
+ /* Card details */
544
+ .mbkh-card-details {
545
+ width: 100%;
546
+ min-width: 0;
547
+ display: flex;
548
+ flex-direction: column;
549
+ gap: 2px;
550
+ }
551
+ .mbkh-card-name {
552
+ font-size: 12px;
553
+ font-weight: 600;
554
+ color: var(--mbkh-text);
555
+ overflow: hidden;
556
+ text-overflow: ellipsis;
557
+ white-space: nowrap;
558
+ line-height: 1.3;
559
+ }
560
+ .mbkh-card-meta {
561
+ font-size: 10.5px;
562
+ color: var(--mbkh-text-muted);
563
+ font-family: var(--mbkh-font-mono);
564
+ overflow: hidden;
565
+ text-overflow: ellipsis;
566
+ white-space: nowrap;
567
+ }
568
+
569
+ /* Checkmark badge */
570
+ .mbkh-check-badge {
571
+ position: absolute;
572
+ top: 6px;
573
+ right: 6px;
574
+ width: 20px;
575
+ height: 20px;
576
+ border-radius: 50%;
577
+ background: var(--mbkh-primary);
578
+ color: #ffffff;
579
+ display: flex;
580
+ align-items: center;
581
+ justify-content: center;
582
+ opacity: 0;
583
+ transform: scale(0.7);
584
+ transition: all 0.15s cubic-bezier(0.34, 1.4, 0.64, 1);
585
+ box-shadow: 0 2px 6px rgba(15, 118, 110, 0.35);
586
+ z-index: 3;
587
+ }
588
+ .mbkh-item.mbkh-selected .mbkh-check-badge {
589
+ opacity: 1;
590
+ transform: scale(1);
591
+ }
592
+
593
+ /* ─── List Mode ────────────────────────────────────────────────────────────── */
594
+ .mbkh-file-grid.mbkh-list-mode {
595
+ grid-template-columns: 1fr;
596
+ gap: 3px;
597
+ padding: 10px 14px;
598
+ }
599
+
600
+ .mbkh-file-grid.mbkh-list-mode .mbkh-item {
601
+ flex-direction: row;
602
+ align-items: center;
603
+ padding: 6px 12px;
604
+ gap: 12px;
605
+ border-radius: var(--mbkh-radius-sm);
606
+ display: grid;
607
+ grid-template-columns: 28px 1fr auto 80px 20px;
608
+ }
609
+ .mbkh-file-grid.mbkh-list-mode .mbkh-item:hover { transform: none; }
610
+
611
+ .mbkh-row-icon {
612
+ width: 28px;
613
+ height: 28px;
614
+ border-radius: var(--mbkh-radius-sm);
615
+ display: flex;
616
+ align-items: center;
617
+ justify-content: center;
618
+ flex-shrink: 0;
619
+ overflow: hidden;
620
+ background: var(--mbkh-surface2);
621
+ }
622
+ .mbkh-row-icon.mbkh-thumb img {
623
+ width: 100%; height: 100%; object-fit: cover;
624
+ }
625
+ .mbkh-row-name {
626
+ font-size: 12.5px;
627
+ font-weight: 600;
628
+ color: var(--mbkh-text);
629
+ overflow: hidden;
630
+ text-overflow: ellipsis;
631
+ white-space: nowrap;
632
+ }
633
+ .mbkh-row-badge {
634
+ font-size: 10px;
635
+ font-weight: 700;
636
+ padding: 2px 7px;
637
+ border-radius: 4px;
638
+ letter-spacing: 0.04em;
639
+ background: var(--mbkh-primary-lt);
640
+ color: var(--mbkh-primary-dk);
641
+ }
642
+ .mbkh-row-size {
643
+ font-size: 11px;
644
+ color: var(--mbkh-text-muted);
645
+ font-family: var(--mbkh-font-mono);
646
+ text-align: right;
647
+ }
648
+ .mbkh-file-grid.mbkh-list-mode .mbkh-check-badge {
649
+ position: static;
650
+ width: 18px;
651
+ height: 18px;
652
+ }
653
+
654
+ /* ─── Empty / Loading / Error states ──────────────────────────────────────── */
655
+ .mbkh-state {
656
+ flex: 1;
657
+ display: flex;
658
+ flex-direction: column;
659
+ align-items: center;
660
+ justify-content: center;
661
+ gap: 8px;
662
+ color: var(--mbkh-text-muted);
663
+ padding: 48px 24px;
664
+ text-align: center;
665
+ }
666
+ .mbkh-spinner {
667
+ width: 32px; height: 32px;
668
+ border: 3px solid var(--mbkh-border);
669
+ border-top-color: var(--mbkh-primary);
670
+ border-radius: 50%;
671
+ animation: mbkh-spin 0.7s linear infinite;
672
+ }
673
+ .mbkh-state-text {
674
+ font-size: 13px;
675
+ font-weight: 500;
676
+ color: var(--mbkh-text-sec);
677
+ margin-top: 4px;
678
+ }
679
+ .mbkh-state-icon {
680
+ margin-bottom: 2px;
681
+ }
682
+ .mbkh-state-title {
683
+ font-family: var(--mbkh-font-heading);
684
+ font-size: 15px;
685
+ font-weight: 700;
686
+ color: var(--mbkh-text);
687
+ }
688
+ .mbkh-state-sub {
689
+ font-size: 12.5px;
690
+ color: var(--mbkh-text-muted);
691
+ max-width: 320px;
692
+ line-height: 1.5;
693
+ }
694
+
695
+ /* ─── Modal footer ─────────────────────────────────────────────────────────── */
696
+ .mbkh-modal-footer {
697
+ display: flex;
698
+ align-items: center;
699
+ justify-content: space-between;
700
+ gap: 12px;
701
+ padding: 10px 18px;
702
+ border-top: 1px solid var(--mbkh-border);
703
+ background: rgba(244, 247, 243, 0.9);
704
+ flex-shrink: 0;
705
+ }
706
+
707
+ .mbkh-selected-wrap {
708
+ flex: 1;
709
+ min-width: 0;
710
+ display: flex;
711
+ align-items: center;
712
+ gap: 8px;
713
+ }
714
+
715
+ .mbkh-selected-placeholder {
716
+ font-size: 12px;
717
+ color: var(--mbkh-text-dim);
718
+ font-style: italic;
719
+ }
720
+
721
+ .mbkh-sel-thumb {
722
+ width: 30px; height: 30px;
723
+ border-radius: var(--mbkh-radius-sm);
724
+ overflow: hidden;
725
+ border: 1px solid var(--mbkh-border);
726
+ flex-shrink: 0;
727
+ }
728
+ .mbkh-sel-thumb img {
729
+ width: 100%; height: 100%; object-fit: cover;
730
+ }
731
+
732
+ .mbkh-sel-badge {
733
+ font-size: 10px;
734
+ font-weight: 700;
735
+ padding: 3px 6px;
736
+ border-radius: 4px;
737
+ flex-shrink: 0;
738
+ }
739
+
740
+ .mbkh-sel-info {
741
+ flex: 1;
742
+ min-width: 0;
743
+ }
744
+ .mbkh-sel-name {
745
+ font-size: 12px;
746
+ font-weight: 600;
747
+ color: var(--mbkh-primary-dk);
748
+ overflow: hidden;
749
+ text-overflow: ellipsis;
750
+ white-space: nowrap;
751
+ }
752
+ .mbkh-sel-meta {
753
+ font-size: 10.5px;
754
+ color: var(--mbkh-text-muted);
755
+ font-family: var(--mbkh-font-mono);
756
+ }
757
+
758
+ .mbkh-sel-clear {
759
+ border: none;
760
+ background: transparent;
761
+ color: var(--mbkh-text-dim);
762
+ cursor: pointer;
763
+ padding: 2px 4px;
764
+ border-radius: 3px;
765
+ display: flex;
766
+ align-items: center;
767
+ transition: all var(--mbkh-transition);
768
+ }
769
+ .mbkh-sel-clear:hover {
770
+ color: var(--mbkh-danger);
771
+ background: rgba(220, 38, 38, 0.1);
772
+ }
773
+
774
+ /* Multi-selection tray */
775
+ .mbkh-multi-tray {
776
+ display: flex;
777
+ align-items: center;
778
+ gap: 8px;
779
+ flex: 1;
780
+ min-width: 0;
781
+ overflow: hidden;
782
+ }
783
+ .mbkh-multi-count {
784
+ font-size: 12px;
785
+ font-weight: 700;
786
+ color: var(--mbkh-primary-dk);
787
+ white-space: nowrap;
788
+ flex-shrink: 0;
789
+ }
790
+ .mbkh-multi-chips {
791
+ display: flex;
792
+ align-items: center;
793
+ gap: 4px;
794
+ flex: 1;
795
+ min-width: 0;
796
+ overflow-x: auto;
797
+ }
798
+ .mbkh-multi-chips::-webkit-scrollbar { display: none; }
799
+ .mbkh-multi-chip {
800
+ display: inline-flex;
801
+ align-items: center;
802
+ gap: 4px;
803
+ padding: 2px 8px;
804
+ background: #ffffff;
805
+ border: 1px solid var(--mbkh-border);
806
+ border-radius: 20px;
807
+ font-size: 11px;
808
+ color: var(--mbkh-text);
809
+ white-space: nowrap;
810
+ max-width: 130px;
811
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
812
+ }
813
+ .mbkh-multi-chip-name {
814
+ overflow: hidden;
815
+ text-overflow: ellipsis;
816
+ white-space: nowrap;
817
+ }
818
+ .mbkh-multi-chip-rm {
819
+ color: var(--mbkh-text-dim);
820
+ cursor: pointer;
821
+ display: flex;
822
+ align-items: center;
823
+ }
824
+ .mbkh-multi-chip-rm:hover { color: var(--mbkh-danger); }
825
+ .mbkh-multi-chip-more {
826
+ font-size: 11px;
827
+ font-weight: 600;
828
+ color: var(--mbkh-primary);
829
+ white-space: nowrap;
830
+ padding: 0 4px;
831
+ }
832
+
833
+ .mbkh-footer-btns {
834
+ display: flex;
835
+ align-items: center;
836
+ gap: 8px;
837
+ flex-shrink: 0;
838
+ }
839
+
840
+ /* ─── Buttons ──────────────────────────────────────────────────────────────── */
841
+ .mbkh-btn {
842
+ display: inline-flex;
843
+ align-items: center;
844
+ gap: 6px;
845
+ padding: 7px 16px;
846
+ border-radius: var(--mbkh-radius-md);
847
+ font-family: var(--mbkh-font);
848
+ font-size: 13px;
849
+ font-weight: 600;
850
+ cursor: pointer;
851
+ border: 1px solid transparent;
852
+ transition: all var(--mbkh-transition);
853
+ white-space: nowrap;
854
+ flex-shrink: 0;
855
+ text-decoration: none;
856
+ line-height: 1.4;
857
+ }
858
+ .mbkh-btn:active { transform: translateY(0) !important; opacity: 0.92; }
859
+
860
+ .mbkh-btn-ghost {
861
+ background: rgba(255, 255, 255, 0.9);
862
+ border-color: var(--mbkh-border);
863
+ color: var(--mbkh-text-sec);
864
+ }
865
+ .mbkh-btn-ghost:hover {
866
+ background: var(--mbkh-primary-lt);
867
+ color: var(--mbkh-primary-dk);
868
+ border-color: var(--mbkh-primary);
869
+ }
870
+
871
+ .mbkh-btn-primary {
872
+ background: var(--mbkh-primary);
873
+ color: #fff;
874
+ border-color: var(--mbkh-primary);
875
+ box-shadow: 0 2px 4px rgba(15, 118, 110, 0.2);
876
+ }
877
+ .mbkh-btn-primary:hover {
878
+ background: var(--mbkh-primary-dk);
879
+ border-color: var(--mbkh-primary-dk);
880
+ transform: translateY(-1px);
881
+ color: #fff;
882
+ }
883
+ .mbkh-btn-primary:disabled {
884
+ opacity: 0.45;
885
+ cursor: not-allowed;
886
+ pointer-events: none;
887
+ }
888
+
889
+ /* Load-more */
890
+ .mbkh-load-more-wrap {
891
+ display: flex;
892
+ justify-content: center;
893
+ padding: 8px;
894
+ grid-column: 1 / -1;
895
+ }
896
+
897
+ /* ═══════════════════════════════════════════════════════════════════════════
898
+ FILE PICKER INPUT
899
+ ═══════════════════════════════════════════════════════════════════════════ */
900
+
901
+ .mbkh-picker {
902
+ font-family: var(--mbkh-font);
903
+ display: flex;
904
+ align-items: stretch;
905
+ border-radius: var(--mbkh-radius-md);
906
+ border: 1px solid var(--mbkh-border);
907
+ background: var(--mbkh-surface2);
908
+ overflow: hidden;
909
+ transition: border-color var(--mbkh-transition), box-shadow var(--mbkh-transition);
910
+ min-width: 0;
911
+ }
912
+ .mbkh-picker:focus-within {
913
+ border-color: var(--mbkh-primary);
914
+ box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.1);
915
+ }
916
+
917
+ .mbkh-picker-value {
918
+ flex: 1;
919
+ background: transparent;
920
+ border: none;
921
+ outline: none;
922
+ color: var(--mbkh-text);
923
+ font-family: var(--mbkh-font);
924
+ font-size: 13px;
925
+ padding: 8px 10px;
926
+ min-width: 0;
927
+ cursor: default;
928
+ }
929
+ .mbkh-picker-value::placeholder { color: var(--mbkh-text-dim); }
930
+
931
+ .mbkh-picker-actions {
932
+ display: flex;
933
+ align-items: center;
934
+ flex-shrink: 0;
935
+ border-left: 1px solid var(--mbkh-border);
936
+ }
937
+
938
+ .mbkh-picker-btn {
939
+ display: flex;
940
+ align-items: center;
941
+ gap: 5px;
942
+ padding: 0 13px;
943
+ height: 100%;
944
+ border: none;
945
+ background: transparent;
946
+ color: var(--mbkh-text-muted);
947
+ font-family: var(--mbkh-font);
948
+ font-size: 12.5px;
949
+ font-weight: 600;
950
+ cursor: pointer;
951
+ transition: background var(--mbkh-transition), color var(--mbkh-transition);
952
+ white-space: nowrap;
953
+ }
954
+ .mbkh-picker-btn:hover {
955
+ background: var(--mbkh-primary-lt);
956
+ color: var(--mbkh-primary-dk);
957
+ }
958
+
959
+ .mbkh-picker-clear {
960
+ width: 30px; height: 100%;
961
+ display: flex; align-items: center; justify-content: center;
962
+ border: none;
963
+ background: transparent;
964
+ color: var(--mbkh-text-dim);
965
+ cursor: pointer;
966
+ border-left: 1px solid var(--mbkh-border-lt);
967
+ transition: color var(--mbkh-transition), background var(--mbkh-transition);
968
+ }
969
+ .mbkh-picker-clear:hover {
970
+ color: var(--mbkh-danger);
971
+ background: rgba(220, 38, 38, 0.07);
972
+ }
973
+ .mbkh-picker-clear[hidden] { display: none; }
974
+
975
+ /* ═══════════════════════════════════════════════════════════════════════════
976
+ UPLOAD WIDGET
977
+ ═══════════════════════════════════════════════════════════════════════════ */
978
+
979
+ .mbkh-uploader {
980
+ font-family: var(--mbkh-font);
981
+ color: var(--mbkh-text);
982
+ display: flex;
983
+ flex-direction: column;
984
+ gap: 10px;
985
+ }
986
+
987
+ /* Drop zone */
988
+ .mbkh-dropzone {
989
+ border: 2px dashed var(--mbkh-border);
990
+ border-radius: var(--mbkh-radius);
991
+ padding: 28px 20px;
992
+ text-align: center;
993
+ cursor: pointer;
994
+ transition: border-color var(--mbkh-transition), background var(--mbkh-transition);
995
+ background: rgba(255, 255, 255, 0.6);
996
+ display: flex;
997
+ flex-direction: column;
998
+ align-items: center;
999
+ gap: 8px;
1000
+ }
1001
+ .mbkh-dropzone:hover,
1002
+ .mbkh-dropzone.mbkh-drag-over {
1003
+ border-color: var(--mbkh-primary);
1004
+ background: var(--mbkh-primary-lt);
1005
+ }
1006
+
1007
+ .mbkh-dropzone-icon {
1008
+ width: 44px; height: 44px;
1009
+ border-radius: 12px;
1010
+ background: var(--mbkh-surface2);
1011
+ border: 1px solid var(--mbkh-border);
1012
+ display: flex; align-items: center; justify-content: center;
1013
+ color: var(--mbkh-text-muted);
1014
+ margin-bottom: 2px;
1015
+ transition: color var(--mbkh-transition), background var(--mbkh-transition), border-color var(--mbkh-transition);
1016
+ }
1017
+ .mbkh-dropzone:hover .mbkh-dropzone-icon,
1018
+ .mbkh-dropzone.mbkh-drag-over .mbkh-dropzone-icon {
1019
+ background: rgba(15, 118, 110, 0.12);
1020
+ border-color: rgba(15, 118, 110, 0.25);
1021
+ color: var(--mbkh-primary);
1022
+ }
1023
+
1024
+ .mbkh-dropzone-title {
1025
+ font-family: var(--mbkh-font-heading);
1026
+ font-size: 13.5px;
1027
+ font-weight: 600;
1028
+ color: var(--mbkh-text);
1029
+ }
1030
+ .mbkh-dropzone-sub {
1031
+ font-size: 12px;
1032
+ color: var(--mbkh-text-muted);
1033
+ }
1034
+ .mbkh-dropzone-sub strong {
1035
+ color: var(--mbkh-primary);
1036
+ cursor: pointer;
1037
+ text-decoration: underline;
1038
+ text-underline-offset: 2px;
1039
+ font-weight: 600;
1040
+ }
1041
+
1042
+ /* Upload queue list */
1043
+ .mbkh-upload-list {
1044
+ display: flex;
1045
+ flex-direction: column;
1046
+ gap: 5px;
1047
+ max-height: 280px;
1048
+ overflow-y: auto;
1049
+ }
1050
+ .mbkh-upload-list::-webkit-scrollbar { width: 5px; }
1051
+ .mbkh-upload-list::-webkit-scrollbar-track { background: transparent; }
1052
+ .mbkh-upload-list::-webkit-scrollbar-thumb {
1053
+ background: var(--mbkh-border);
1054
+ border-radius: 3px;
1055
+ }
1056
+
1057
+ /* Upload item */
1058
+ .mbkh-upload-item {
1059
+ display: flex;
1060
+ align-items: center;
1061
+ gap: 10px;
1062
+ padding: 9px 12px;
1063
+ background: rgba(255, 255, 255, 0.85);
1064
+ border: 1px solid var(--mbkh-border);
1065
+ border-radius: var(--mbkh-radius-md);
1066
+ transition: border-color var(--mbkh-transition);
1067
+ }
1068
+ .mbkh-upload-item.mbkh-done { border-color: rgba(22,163,74,0.3); background: rgba(22,163,74,0.03); }
1069
+ .mbkh-upload-item.mbkh-error { border-color: rgba(220,38,38,0.3); background: rgba(220,38,38,0.03); }
1070
+
1071
+ .mbkh-upload-file-icon {
1072
+ width: 32px; height: 32px;
1073
+ border-radius: var(--mbkh-radius-sm);
1074
+ background: var(--mbkh-surface2);
1075
+ border: 1px solid var(--mbkh-border-lt);
1076
+ display: flex; align-items: center; justify-content: center;
1077
+ font-family: var(--mbkh-font);
1078
+ font-size: 9px;
1079
+ font-weight: 700;
1080
+ letter-spacing: 0.04em;
1081
+ color: var(--mbkh-text-muted);
1082
+ flex-shrink: 0;
1083
+ }
1084
+
1085
+ .mbkh-upload-info {
1086
+ flex: 1;
1087
+ min-width: 0;
1088
+ display: flex;
1089
+ flex-direction: column;
1090
+ gap: 4px;
1091
+ }
1092
+ .mbkh-upload-name {
1093
+ font-size: 12.5px;
1094
+ font-weight: 500;
1095
+ white-space: nowrap;
1096
+ overflow: hidden;
1097
+ text-overflow: ellipsis;
1098
+ color: var(--mbkh-text);
1099
+ }
1100
+
1101
+ .mbkh-upload-progress-row {
1102
+ display: flex;
1103
+ align-items: center;
1104
+ gap: 8px;
1105
+ }
1106
+
1107
+ .mbkh-progress-bar-wrap {
1108
+ flex: 1;
1109
+ height: 4px;
1110
+ background: var(--mbkh-surface3);
1111
+ border-radius: 2px;
1112
+ overflow: hidden;
1113
+ }
1114
+ .mbkh-progress-bar {
1115
+ height: 100%;
1116
+ border-radius: 2px;
1117
+ background: var(--mbkh-primary);
1118
+ transition: width 0.25s ease;
1119
+ width: 0%;
1120
+ }
1121
+ .mbkh-upload-item.mbkh-done .mbkh-progress-bar { background: var(--mbkh-success); width: 100% !important; }
1122
+ .mbkh-upload-item.mbkh-error .mbkh-progress-bar { background: var(--mbkh-danger); }
1123
+
1124
+ .mbkh-upload-pct {
1125
+ font-size: 11px;
1126
+ font-family: var(--mbkh-font-mono);
1127
+ color: var(--mbkh-text-muted);
1128
+ min-width: 30px;
1129
+ text-align: right;
1130
+ flex-shrink: 0;
1131
+ }
1132
+ .mbkh-upload-status {
1133
+ font-size: 11px;
1134
+ color: var(--mbkh-text-muted);
1135
+ }
1136
+ .mbkh-upload-item.mbkh-done .mbkh-upload-status { color: var(--mbkh-success); font-weight: 600; }
1137
+ .mbkh-upload-item.mbkh-error .mbkh-upload-status { color: var(--mbkh-danger); font-weight: 600; }
1138
+
1139
+ .mbkh-upload-remove {
1140
+ width: 26px; height: 26px;
1141
+ border: none;
1142
+ background: transparent;
1143
+ color: var(--mbkh-text-dim);
1144
+ border-radius: var(--mbkh-radius-sm);
1145
+ cursor: pointer;
1146
+ display: flex; align-items: center; justify-content: center;
1147
+ flex-shrink: 0;
1148
+ transition: color var(--mbkh-transition), background var(--mbkh-transition);
1149
+ }
1150
+ .mbkh-upload-remove:hover {
1151
+ color: var(--mbkh-danger);
1152
+ background: rgba(220, 38, 38, 0.08);
1153
+ }
1154
+
1155
+ /* Upload actions bar */
1156
+ .mbkh-upload-actions {
1157
+ display: flex;
1158
+ gap: 8px;
1159
+ align-items: center;
1160
+ justify-content: flex-end;
1161
+ }
1162
+ .mbkh-upload-summary {
1163
+ flex: 1;
1164
+ font-size: 12px;
1165
+ color: var(--mbkh-text-muted);
1166
+ }
1167
+
1168
+ /* ═══════════════════════════════════════════════════════════════════════════
1169
+ TOAST NOTIFICATIONS
1170
+ ═══════════════════════════════════════════════════════════════════════════ */
1171
+
1172
+ .mbkh-toast-container {
1173
+ position: fixed;
1174
+ bottom: 20px;
1175
+ right: 20px;
1176
+ z-index: 99999;
1177
+ display: flex;
1178
+ flex-direction: column;
1179
+ gap: 8px;
1180
+ pointer-events: none;
1181
+ }
1182
+
1183
+ .mbkh-toast {
1184
+ font-family: var(--mbkh-font);
1185
+ font-size: 13px;
1186
+ color: var(--mbkh-text);
1187
+ background: rgba(255, 255, 255, 0.96);
1188
+ border: 1px solid rgba(255, 255, 255, 0.9);
1189
+ border-radius: var(--mbkh-radius-md);
1190
+ padding: 10px 14px;
1191
+ box-shadow: var(--mbkh-shadow-dropdown);
1192
+ display: flex;
1193
+ align-items: center;
1194
+ gap: 9px;
1195
+ min-width: 230px;
1196
+ max-width: 340px;
1197
+ pointer-events: all;
1198
+ animation: mbkh-toast-in 0.2s cubic-bezier(0.34, 1.3, 0.64, 1);
1199
+ border-left: 3px solid var(--mbkh-primary);
1200
+ }
1201
+ .mbkh-toast.mbkh-toast-success { border-left-color: var(--mbkh-success); }
1202
+ .mbkh-toast.mbkh-toast-error { border-left-color: var(--mbkh-danger); }
1203
+ .mbkh-toast.mbkh-toast-warning { border-left-color: var(--mbkh-warning); }
1204
+ .mbkh-toast.mbkh-toast-info { border-left-color: var(--mbkh-primary); }
1205
+
1206
+ @keyframes mbkh-toast-in {
1207
+ from { opacity: 0; transform: translateX(24px); }
1208
+ to { opacity: 1; transform: translateX(0); }
1209
+ }
1210
+ .mbkh-toast.mbkh-toast-out {
1211
+ animation: mbkh-toast-out 0.18s ease forwards;
1212
+ }
1213
+ @keyframes mbkh-toast-out {
1214
+ to { opacity: 0; transform: translateX(24px); }
1215
+ }
1216
+
1217
+ .mbkh-toast-icon { flex-shrink: 0; }
1218
+ .mbkh-toast-msg { flex: 1; line-height: 1.45; color: var(--mbkh-text-sec); }
1219
+
1220
+ /* ═══════════════════════════════════════════════════════════════════════════
1221
+ RESPONSIVE
1222
+ ═══════════════════════════════════════════════════════════════════════════ */
1223
+
1224
+ @media (max-width: 600px) {
1225
+ .mbkh-modal {
1226
+ height: 95dvh;
1227
+ max-width: 100%;
1228
+ border-radius: var(--mbkh-radius-sm);
1229
+ }
1230
+ .mbkh-file-grid {
1231
+ grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
1232
+ }
1233
+ .mbkh-search { width: 130px; }
1234
+ .mbkh-search:focus { width: 160px; }
1235
+ }