mbkbucket 4.0.0 → 4.1.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 (40) hide show
  1. package/.env.example +16 -15
  2. package/README.md +613 -561
  3. package/index.js +36 -33
  4. package/lib/cli.js +239 -239
  5. package/lib/public/bucketadmin.css +2042 -2042
  6. package/lib/public/bucketadmin.js +1844 -1622
  7. package/lib/public/mbkbucket-helper-demo.html +0 -58
  8. package/lib/public/mbkbucket-helper.js +1 -9
  9. package/lib/src/config/validation.js +91 -86
  10. package/lib/src/controllers/api.controller.js +486 -459
  11. package/lib/src/controllers/dashboard.controller.js +69 -69
  12. package/lib/src/controllers/info.controller.js +13 -13
  13. package/lib/src/controllers/view.controller.js +234 -233
  14. package/lib/src/core/metrics.js +134 -0
  15. package/lib/src/core/storage/capabilities.js +58 -0
  16. package/lib/src/core/storage/errors.js +0 -5
  17. package/lib/src/core/storage/gdrive-auth.js +0 -36
  18. package/lib/src/core/storage/gdrive-provider.js +101 -43
  19. package/lib/src/core/storage/index.js +4 -1
  20. package/lib/src/core/storage/local-provider.js +507 -0
  21. package/lib/src/core/storage/models.js +90 -50
  22. package/lib/src/core/storage/path-strategy.js +14 -1
  23. package/lib/src/core/storage/s3-provider.js +17 -37
  24. package/lib/src/core/storage/storage-manager.js +70 -50
  25. package/lib/src/core/storage/storage-provider.js +49 -120
  26. package/lib/src/middleware/bucket-resolver.js +37 -37
  27. package/lib/src/routes/api.routes.js +4 -1
  28. package/lib/src/routes/index.js +60 -60
  29. package/lib/src/routes/view.routes.js +28 -28
  30. package/lib/src/services/s3.service.js +42 -42
  31. package/lib/src/services/storage.service.js +311 -213
  32. package/lib/src/utils/cleanup-scheduler.js +91 -0
  33. package/lib/src/utils/errors.js +56 -56
  34. package/lib/src/utils/helpers.js +6 -6
  35. package/package.json +3 -5
  36. package/views/bucket.hbs +0 -5
  37. package/views/bucketadmin_move_modal.hbs +35 -35
  38. package/views/bucketadmin_preview_modal.hbs +108 -108
  39. package/views/bucketadmincontent.hbs +193 -193
  40. package/views/mbkbucket_info.hbs +134 -134
@@ -1,2042 +1,2042 @@
1
- /* ==========================================================================
2
- MBKBucket File Manager - Clean, Modern Storage Dashboard
3
- Design System: Refined Slate & Deep Teal Palette
4
- ========================================================================== */
5
-
6
- :root {
7
- /* Brand / Primary Palette */
8
- --primary-color-ml: #0f766e;
9
- --primary-light-color-ml: #f0fdfa;
10
- --primary-dark-color-ml: #115e59;
11
- --secondary-color-ml: #14b8a6;
12
- --dark-color-ml: #0f172a;
13
- --light-color-ml: #f8fafc;
14
- --gray-color-ml: #64748b;
15
- --gray-light-color-ml: #e2e8f0;
16
- --danger-color-ml: #ef4444;
17
- --warning-color-ml: #f59e0b;
18
- --success-color-ml: #10b981;
19
- --info-color-ml: #0284c7;
20
-
21
- /* Aliases */
22
- --primary: var(--primary-color-ml);
23
- --primary-lt: var(--primary-light-color-ml);
24
- --primary-dk: var(--primary-dark-color-ml);
25
- --primary-hover: #134e4a;
26
- --primary-active: #084c47;
27
-
28
- /* Surfaces & Backgrounds */
29
- --body-bg: #f8fafc;
30
- --bg-surface: #ffffff;
31
- --bg-surface-secondary: #f8fafc;
32
- --bg-surface-tertiary: #f1f5f9;
33
- --bg-surface-hover: #f1f5f9;
34
-
35
- /* Borders */
36
- --border-color: #e2e8f0;
37
- --border-color-light: #f1f5f9;
38
- --border-color-focus: #0f766e;
39
-
40
- /* Text */
41
- --text: #0f172a;
42
- --text-secondary: #475569;
43
- --text-muted: #64748b;
44
- --text-disabled: #94a3b8;
45
-
46
- /* Accent Colors */
47
- --blue: #2563eb;
48
- --azure: #0891b2;
49
- --green: #10b981;
50
- --yellow: #d97706;
51
- --orange: #ea580c;
52
- --red: #ef4444;
53
- --purple: #7c3aed;
54
- --cyan: #0f766e;
55
-
56
- /* Light Accent Tints */
57
- --green-lt: #ecfdf5;
58
- --red-lt: #fef2f2;
59
- --yellow-lt: #fffbeb;
60
- --blue-lt: #eff6ff;
61
- --azure-lt: #ecfeff;
62
- --purple-lt: #f5f3ff;
63
- --cyan-lt: #f0fdfa;
64
-
65
- /* Geometry */
66
- --radius-sm: 6px;
67
- --radius: 8px;
68
- --radius-lg: 12px;
69
- --radius-xl: 16px;
70
-
71
- /* Modern Subtle Shadows */
72
- --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.05);
73
- --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
74
- --shadow: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
75
- --shadow-md: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -4px rgba(15, 23, 42, 0.03);
76
- --shadow-lg: 0 20px 25px -5px rgba(15, 23, 42, 0.08), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
77
- --shadow-dropdown: 0 10px 25px -5px rgba(15, 23, 42, 0.12), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
78
-
79
- /* Fonts */
80
- --font: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
81
- --font-headings: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
82
- --font-mono: "Segoe UI Mono", "Cascadia Code", Consolas, "Courier New", monospace;
83
- }
84
-
85
- /* ==========================================================================
86
- Base Layout & Reset
87
- ========================================================================== */
88
- .page-wrapper,
89
- .page-wrapper *,
90
- .page-wrapper *::before,
91
- .page-wrapper *::after,
92
- .modal,
93
- .modal * {
94
- box-sizing: border-box;
95
- }
96
-
97
- body,
98
- button,
99
- input,
100
- optgroup,
101
- select,
102
- textarea,
103
- .page-wrapper,
104
- .modal,
105
- .modal-content,
106
- .info-card,
107
- .info-value,
108
- .info-label,
109
- .file-info-pane,
110
- .fm-context-menu,
111
- .toast-notification,
112
- .batch-bar-inner {
113
- font-family: var(--font);
114
- }
115
-
116
- .page-wrapper {
117
- max-width: 1600px;
118
- margin: 0 auto;
119
- width: 100%;
120
- }
121
-
122
- /* ==========================================================================
123
- Page Header
124
- ========================================================================== */
125
- .page-header {
126
- display: flex;
127
- align-items: center;
128
- justify-content: space-between;
129
- margin-bottom: 1rem;
130
- padding: 0.85rem 1.25rem;
131
- border: 1px solid var(--border-color);
132
- border-radius: var(--radius-lg);
133
- background: #ffffff;
134
- box-shadow: var(--shadow-xs);
135
- }
136
-
137
- .page-header-row {
138
- display: flex;
139
- align-items: center;
140
- justify-content: space-between;
141
- width: 100%;
142
- gap: 1rem;
143
- }
144
-
145
- .page-pretitle {
146
- font-size: 11px;
147
- font-weight: 700;
148
- text-transform: uppercase;
149
- letter-spacing: 0.06em;
150
- color: var(--primary);
151
- margin-bottom: 3px;
152
- }
153
-
154
- .page-title {
155
- font-family: var(--font-headings);
156
- font-size: 1.35rem;
157
- font-weight: 700;
158
- color: var(--text);
159
- margin: 0;
160
- line-height: 1.25;
161
- letter-spacing: -0.015em;
162
- display: flex;
163
- align-items: center;
164
- gap: 0.5rem;
165
- }
166
-
167
- .page-actions {
168
- display: flex;
169
- align-items: center;
170
- gap: 0.5rem;
171
- }
172
-
173
- /* ==========================================================================
174
- Button System
175
- ========================================================================== */
176
- .btn {
177
- display: inline-flex;
178
- align-items: center;
179
- justify-content: center;
180
- gap: 0.45rem;
181
- font-family: var(--font);
182
- font-size: 13px;
183
- font-weight: 600;
184
- line-height: 1.4;
185
- padding: 7px 14px;
186
- border-radius: var(--radius-sm);
187
- border: 1px solid transparent;
188
- cursor: pointer;
189
- transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
190
- text-decoration: none;
191
- white-space: nowrap;
192
- user-select: none;
193
- }
194
-
195
- .btn svg {
196
- flex-shrink: 0;
197
- }
198
-
199
- .btn:focus-visible {
200
- outline: none;
201
- box-shadow: 0 0 0 2px var(--primary-light-color-ml), 0 0 0 4px var(--primary);
202
- }
203
-
204
- .btn-primary {
205
- background: var(--primary);
206
- color: #ffffff;
207
- border-color: var(--primary-dark-color-ml);
208
- box-shadow: var(--shadow-xs);
209
- }
210
-
211
- .btn-primary:hover {
212
- background: var(--primary-hover);
213
- border-color: var(--primary-hover);
214
- color: #ffffff;
215
- }
216
-
217
- .btn-primary:active {
218
- background: var(--primary-active);
219
- }
220
-
221
- .btn-outline {
222
- background: #ffffff;
223
- color: var(--text);
224
- border-color: var(--border-color);
225
- box-shadow: var(--shadow-xs);
226
- }
227
-
228
- .btn-outline:hover {
229
- background: #f8fafc;
230
- color: var(--text);
231
- border-color: #cbd5e1;
232
- }
233
-
234
- .btn-outline:active {
235
- background: #f1f5f9;
236
- }
237
-
238
- .btn-danger {
239
- background: var(--danger-color-ml);
240
- color: #ffffff;
241
- border-color: var(--danger-color-ml);
242
- box-shadow: var(--shadow-xs);
243
- }
244
-
245
- .btn-danger:hover {
246
- background: #dc2626;
247
- border-color: #dc2626;
248
- color: #ffffff;
249
- }
250
-
251
- .btn-danger:active {
252
- background: #b91c1c;
253
- }
254
-
255
- .btn-sm {
256
- padding: 5px 10px;
257
- font-size: 12px;
258
- border-radius: var(--radius-sm);
259
- }
260
-
261
- .btn-icon {
262
- width: 32px;
263
- height: 32px;
264
- padding: 0;
265
- display: inline-flex;
266
- align-items: center;
267
- justify-content: center;
268
- }
269
-
270
- /* ==========================================================================
271
- Main File Manager Card & Layout
272
- ========================================================================== */
273
- .card.file-manager {
274
- background: #ffffff;
275
- border: 1px solid var(--border-color);
276
- border-radius: var(--radius-lg);
277
- box-shadow: var(--shadow-sm);
278
- overflow: hidden;
279
- }
280
-
281
- .fm-layout {
282
- display: grid;
283
- grid-template-columns: 260px minmax(0, 1fr);
284
- height: calc(100vh - 170px);
285
- min-height: 580px;
286
- max-height: 900px;
287
- }
288
-
289
- /* ==========================================================================
290
- Left Sidebar Tree (Explorer)
291
- ========================================================================== */
292
- .fm-tree-wrap {
293
- border-right: 1px solid var(--border-color);
294
- background: #f8fafc;
295
- display: flex;
296
- flex-direction: column;
297
- padding: 12px 10px;
298
- min-height: 0;
299
- }
300
-
301
- .fm-tree-header {
302
- padding: 4px 8px 8px;
303
- display: flex;
304
- align-items: center;
305
- justify-content: space-between;
306
- }
307
-
308
- .fm-tree-title {
309
- font-family: var(--font-headings);
310
- font-size: 11px;
311
- font-weight: 700;
312
- text-transform: uppercase;
313
- letter-spacing: 0.06em;
314
- color: var(--text-muted);
315
- }
316
-
317
- .fm-tree {
318
- flex: 1 1 auto;
319
- overflow-y: auto;
320
- padding-right: 4px;
321
- }
322
-
323
- .fm-tree::-webkit-scrollbar {
324
- width: 4px;
325
- }
326
-
327
- .fm-tree::-webkit-scrollbar-thumb {
328
- background: #cbd5e1;
329
- border-radius: 2px;
330
- }
331
-
332
- .tree-group {
333
- margin-bottom: 2px;
334
- }
335
-
336
- .tree-link {
337
- display: flex;
338
- align-items: center;
339
- gap: 8px;
340
- width: 100%;
341
- padding: 6px 10px;
342
- background: transparent;
343
- border: none;
344
- border-radius: var(--radius-sm);
345
- font-family: var(--font);
346
- font-size: 13px;
347
- color: var(--text-secondary);
348
- text-align: left;
349
- cursor: pointer;
350
- transition: background-color 0.12s ease, color 0.12s ease;
351
- user-select: none;
352
- font-weight: 500;
353
- }
354
-
355
- .tree-link:hover {
356
- background: #f1f5f9;
357
- color: var(--text);
358
- }
359
-
360
- .tree-link.active {
361
- background: var(--primary-light-color-ml);
362
- color: var(--primary-dark-color-ml);
363
- font-weight: 600;
364
- }
365
-
366
- .tree-link svg {
367
- color: var(--text-muted);
368
- flex-shrink: 0;
369
- }
370
-
371
- .tree-link.active svg {
372
- color: var(--primary);
373
- }
374
-
375
- .tree-link span {
376
- flex: 1 1 auto;
377
- min-width: 0;
378
- overflow: hidden;
379
- text-overflow: ellipsis;
380
- white-space: nowrap;
381
- font-size: 13px;
382
- }
383
-
384
- .tree-subs {
385
- display: flex;
386
- flex-direction: column;
387
- margin-left: 12px;
388
- padding-left: 6px;
389
- border-left: 1px solid var(--border-color);
390
- }
391
-
392
- .tree-sub {
393
- padding-left: 10px;
394
- }
395
-
396
- .tree-badge {
397
- font-size: 10.5px;
398
- padding: 1px 6px;
399
- border-radius: 99px;
400
- background: #e2e8f0;
401
- color: var(--text-secondary);
402
- font-weight: 600;
403
- }
404
-
405
- .tree-link.active .tree-badge {
406
- background: #ccfbf1;
407
- color: var(--primary-dark-color-ml);
408
- }
409
-
410
- /* ==========================================================================
411
- Sidebar Storage & Bucket Switcher
412
- ========================================================================== */
413
- .fm-storage {
414
- margin-top: auto;
415
- padding: 12px;
416
- border-top: 1px solid var(--border-color);
417
- background: #ffffff;
418
- border-radius: var(--radius-sm);
419
- border: 1px solid var(--border-color);
420
- box-shadow: var(--shadow-xs);
421
- }
422
-
423
- .fm-storage-label {
424
- font-size: 11px;
425
- font-weight: 700;
426
- text-transform: uppercase;
427
- letter-spacing: 0.05em;
428
- color: var(--text-muted);
429
- margin-bottom: 6px;
430
- }
431
-
432
- .bucket-switcher-wrap {
433
- position: relative;
434
- }
435
-
436
- .bucket-switcher-control {
437
- position: relative;
438
- display: flex;
439
- align-items: center;
440
- }
441
-
442
- .bucket-switcher-icon {
443
- position: absolute;
444
- left: 9px;
445
- color: var(--primary);
446
- pointer-events: none;
447
- }
448
-
449
- .bucket-switcher-select {
450
- width: 100%;
451
- padding: 6px 10px 6px 28px;
452
- font-family: var(--font);
453
- font-size: 12.5px;
454
- font-weight: 600;
455
- color: var(--text);
456
- background: #ffffff;
457
- border: 1px solid var(--border-color);
458
- border-radius: var(--radius-sm);
459
- outline: none;
460
- cursor: pointer;
461
- appearance: auto;
462
- transition: border-color 0.12s ease, box-shadow 0.12s ease;
463
- }
464
-
465
- .bucket-switcher-select:focus {
466
- border-color: var(--primary);
467
- box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
468
- }
469
-
470
- .bucket-switcher-status {
471
- font-size: 11px;
472
- color: var(--primary);
473
- margin-top: 4px;
474
- display: block;
475
- }
476
-
477
- .bucket-switcher-status.is-hidden {
478
- display: none;
479
- }
480
-
481
- .storage-bar {
482
- height: 4px;
483
- background: #f1f5f9;
484
- border-radius: 2px;
485
- overflow: hidden;
486
- margin: 8px 0 6px;
487
- }
488
-
489
- .fm-storage-meta {
490
- font-size: 11.5px;
491
- color: var(--text-muted);
492
- font-weight: 500;
493
- }
494
-
495
- .fm-storage-subinfo {
496
- font-size: 11px;
497
- color: var(--text-muted);
498
- margin-top: 2px;
499
- white-space: nowrap;
500
- overflow: hidden;
501
- text-overflow: ellipsis;
502
- }
503
-
504
- /* ==========================================================================
505
- Main Content Area & Toolbar
506
- ========================================================================== */
507
- .fm-main {
508
- display: flex;
509
- flex-direction: column;
510
- min-height: 0;
511
- background: #ffffff;
512
- }
513
-
514
- .fm-toolbar {
515
- display: flex;
516
- align-items: center;
517
- justify-content: space-between;
518
- gap: 12px;
519
- padding: 10px 16px;
520
- border-bottom: 1px solid var(--border-color);
521
- flex-shrink: 0;
522
- background: #ffffff;
523
- flex-wrap: wrap;
524
- }
525
-
526
- .fm-breadcrumb {
527
- display: flex;
528
- align-items: center;
529
- gap: 4px;
530
- flex-wrap: wrap;
531
- min-height: 32px;
532
- }
533
-
534
- .bc-link {
535
- background: transparent;
536
- border: none;
537
- font-family: var(--font);
538
- font-size: 13px;
539
- color: var(--text-muted);
540
- cursor: pointer;
541
- padding: 3px 6px;
542
- border-radius: var(--radius-sm);
543
- transition: background-color 0.12s ease, color 0.12s ease;
544
- display: inline-flex;
545
- align-items: center;
546
- gap: 4px;
547
- font-weight: 500;
548
- }
549
-
550
- .bc-link:hover {
551
- background: #f1f5f9;
552
- color: var(--text);
553
- }
554
-
555
- .bc-link.current {
556
- color: var(--text);
557
- font-weight: 600;
558
- cursor: default;
559
- }
560
-
561
- .bc-link.current:hover {
562
- background: transparent;
563
- }
564
-
565
- .fm-breadcrumb .sep {
566
- color: #cbd5e1;
567
- font-size: 12px;
568
- user-select: none;
569
- }
570
-
571
- .fm-toolbar-actions {
572
- display: flex;
573
- align-items: center;
574
- gap: 8px;
575
- margin-left: auto;
576
- }
577
-
578
- /* Quick Filters - Segmented Control */
579
- .quick-filter-group {
580
- display: inline-flex;
581
- background: #f1f5f9;
582
- border: 1px solid var(--border-color);
583
- border-radius: var(--radius-sm);
584
- padding: 2px;
585
- gap: 2px;
586
- }
587
-
588
- .quick-filter-btn {
589
- background: transparent;
590
- border: none;
591
- font-family: var(--font);
592
- font-size: 12px;
593
- font-weight: 500;
594
- color: var(--text-secondary);
595
- padding: 3px 9px;
596
- border-radius: 4px;
597
- cursor: pointer;
598
- transition: background-color 0.12s ease, color 0.12s ease;
599
- }
600
-
601
- .quick-filter-btn:hover {
602
- color: var(--text);
603
- }
604
-
605
- .quick-filter-btn.active {
606
- background: #ffffff;
607
- color: var(--primary-dark-color-ml);
608
- font-weight: 600;
609
- box-shadow: var(--shadow-xs);
610
- }
611
-
612
- /* Search Box */
613
- .search-box {
614
- position: relative;
615
- width: 200px;
616
- display: flex;
617
- align-items: center;
618
- }
619
-
620
- .search-box .s-icon {
621
- position: absolute;
622
- left: 9px;
623
- width: 14px;
624
- height: 14px;
625
- color: var(--text-muted);
626
- pointer-events: none;
627
- }
628
-
629
- .search-box input {
630
- width: 100%;
631
- padding: 5px 24px 5px 28px;
632
- font-family: var(--font);
633
- font-size: 12.5px;
634
- border: 1px solid var(--border-color);
635
- border-radius: var(--radius-sm);
636
- background: #ffffff;
637
- color: var(--text);
638
- outline: none;
639
- transition: border-color 0.12s ease, box-shadow 0.12s ease;
640
- }
641
-
642
- .search-box input:focus {
643
- border-color: var(--primary);
644
- box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
645
- }
646
-
647
- .search-clear-btn {
648
- position: absolute;
649
- right: 6px;
650
- background: transparent;
651
- border: none;
652
- color: var(--text-muted);
653
- cursor: pointer;
654
- font-size: 15px;
655
- line-height: 1;
656
- padding: 2px;
657
- }
658
-
659
- .search-clear-btn:hover {
660
- color: var(--text);
661
- }
662
-
663
- /* View Switcher */
664
- .fm-view-toggle {
665
- display: inline-flex;
666
- border: 1px solid var(--border-color);
667
- border-radius: var(--radius-sm);
668
- overflow: hidden;
669
- background: #ffffff;
670
- }
671
-
672
- .view-btn {
673
- width: 30px;
674
- height: 28px;
675
- border: none;
676
- background: transparent;
677
- cursor: pointer;
678
- color: var(--text-muted);
679
- display: flex;
680
- align-items: center;
681
- justify-content: center;
682
- transition: background-color 0.12s ease, color 0.12s ease;
683
- }
684
-
685
- .view-btn:hover {
686
- background: #f1f5f9;
687
- color: var(--text);
688
- }
689
-
690
- .view-btn.active {
691
- background: var(--primary-light-color-ml);
692
- color: var(--primary-dark-color-ml);
693
- }
694
-
695
- .view-btn#view-thumbs {
696
- border-left: 1px solid var(--border-color);
697
- }
698
-
699
- /* ==========================================================================
700
- File Grid Container & Grid Items
701
- ========================================================================== */
702
- .fm-grid-wrap {
703
- flex: 1 1 auto;
704
- overflow-y: auto;
705
- padding: 16px;
706
- position: relative;
707
- background: #ffffff;
708
- }
709
-
710
- .fm-grid-wrap::-webkit-scrollbar {
711
- width: 6px;
712
- }
713
-
714
- .fm-grid-wrap::-webkit-scrollbar-thumb {
715
- background: #cbd5e1;
716
- border-radius: 3px;
717
- }
718
-
719
- /* Grid View */
720
- .fm-grid.view-grid {
721
- display: grid;
722
- grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
723
- grid-auto-rows: max-content;
724
- align-content: start;
725
- gap: 12px;
726
- }
727
-
728
- .fm-item {
729
- position: relative;
730
- background: #ffffff;
731
- border: 1px solid var(--border-color);
732
- border-radius: var(--radius);
733
- cursor: pointer;
734
- font-family: var(--font);
735
- text-align: left;
736
- transition: border-color 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
737
- user-select: none;
738
- }
739
-
740
- .fm-item:hover {
741
- border-color: #cbd5e1;
742
- box-shadow: var(--shadow-sm);
743
- }
744
-
745
- .fm-item.is-selected {
746
- border-color: var(--primary);
747
- background: var(--primary-light-color-ml);
748
- }
749
-
750
- /* Item in Grid View */
751
- .fm-grid.view-grid .fm-item {
752
- padding: 10px;
753
- display: flex;
754
- flex-direction: column;
755
- align-items: flex-start;
756
- gap: 8px;
757
- }
758
-
759
- .fm-grid.view-grid .fm-item-icon {
760
- width: 100%;
761
- aspect-ratio: 16 / 10;
762
- border-radius: var(--radius-sm);
763
- display: flex;
764
- align-items: center;
765
- justify-content: center;
766
- flex-shrink: 0;
767
- background: #f8fafc;
768
- border: 1px solid var(--border-color-light);
769
- overflow: hidden;
770
- position: relative;
771
- }
772
-
773
- .fm-item-thumb {
774
- width: 100%;
775
- height: 100%;
776
- object-fit: cover;
777
- transition: opacity 0.2s ease;
778
- }
779
-
780
- .fm-item-thumb.fm-lazy-thumb {
781
- opacity: 0;
782
- }
783
-
784
- .fm-item-thumb.fm-lazy-thumb.is-loaded {
785
- opacity: 1;
786
- }
787
-
788
- .fm-item-icon .ext {
789
- font-size: 11px;
790
- font-weight: 700;
791
- letter-spacing: 0.04em;
792
- text-transform: uppercase;
793
- padding: 2px 7px;
794
- border-radius: 4px;
795
- }
796
-
797
- .fm-item-icon .folder-svg {
798
- width: 40px;
799
- height: 40px;
800
- }
801
-
802
- .fm-grid.view-grid .fm-item-details {
803
- width: 100%;
804
- min-width: 0;
805
- }
806
-
807
- .fm-item-name {
808
- font-size: 12.5px;
809
- font-weight: 600;
810
- color: var(--text);
811
- overflow: hidden;
812
- text-overflow: ellipsis;
813
- white-space: nowrap;
814
- min-width: 0;
815
- line-height: 1.35;
816
- }
817
-
818
- .fm-item-meta {
819
- font-size: 11px;
820
- color: var(--text-muted);
821
- margin-top: 2px;
822
- white-space: nowrap;
823
- overflow: hidden;
824
- text-overflow: ellipsis;
825
- }
826
-
827
- /* Star & Menu Action Triggers */
828
- .fm-star {
829
- position: absolute;
830
- top: 6px;
831
- left: 6px;
832
- width: 22px;
833
- height: 22px;
834
- display: flex;
835
- align-items: center;
836
- justify-content: center;
837
- cursor: pointer;
838
- border-radius: 50%;
839
- color: var(--text-disabled);
840
- opacity: 0;
841
- background: #ffffff;
842
- border: 1px solid var(--border-color);
843
- box-shadow: var(--shadow-xs);
844
- transition: opacity 0.12s ease, color 0.12s ease;
845
- z-index: 2;
846
- }
847
-
848
- .fm-item:hover .fm-star,
849
- .fm-item.starred .fm-star {
850
- opacity: 1;
851
- }
852
-
853
- .fm-star.on {
854
- color: #eab308;
855
- opacity: 1;
856
- }
857
-
858
- .fm-star:hover {
859
- color: #eab308;
860
- }
861
-
862
- .fm-item-menu {
863
- position: absolute;
864
- top: 6px;
865
- right: 6px;
866
- width: 22px;
867
- height: 22px;
868
- border: 1px solid var(--border-color);
869
- background: #ffffff;
870
- border-radius: 50%;
871
- display: flex;
872
- align-items: center;
873
- justify-content: center;
874
- cursor: pointer;
875
- color: var(--text-muted);
876
- opacity: 0;
877
- box-shadow: var(--shadow-xs);
878
- transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease;
879
- z-index: 2;
880
- }
881
-
882
- .fm-item:hover .fm-item-menu {
883
- opacity: 1;
884
- }
885
-
886
- .fm-item-menu:hover {
887
- background: #f8fafc;
888
- color: var(--text);
889
- }
890
-
891
- /* ==========================================================================
892
- List View
893
- ========================================================================== */
894
- .fm-grid.view-list {
895
- display: flex;
896
- flex-direction: column;
897
- gap: 2px;
898
- }
899
-
900
- .fm-grid.view-list .fm-item {
901
- padding: 6px 12px;
902
- display: grid;
903
- grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
904
- gap: 10px;
905
- align-items: center;
906
- border-radius: var(--radius-sm);
907
- border: 1px solid transparent;
908
- }
909
-
910
- .fm-grid.view-list .fm-item:hover {
911
- background: #f8fafc;
912
- border-color: var(--border-color);
913
- }
914
-
915
- .fm-grid.view-list .fm-item.is-selected {
916
- background: var(--primary-light-color-ml);
917
- border-color: #ccfbf1;
918
- }
919
-
920
- .fm-grid.view-list .fm-item-icon {
921
- width: 28px;
922
- height: 28px;
923
- border-radius: 4px;
924
- display: flex;
925
- align-items: center;
926
- justify-content: center;
927
- background: #f8fafc;
928
- border: 1px solid var(--border-color-light);
929
- }
930
-
931
- .fm-grid.view-list .fm-item-icon .ext {
932
- font-size: 10px;
933
- font-weight: 700;
934
- padding: 1px 4px;
935
- }
936
-
937
- .fm-grid.view-list .fm-item-icon .folder-svg {
938
- width: 20px;
939
- height: 20px;
940
- }
941
-
942
- .fm-grid.view-list .fm-star,
943
- .fm-grid.view-list .fm-item-menu {
944
- position: static;
945
- opacity: 1;
946
- background: transparent;
947
- border: none;
948
- box-shadow: none;
949
- }
950
-
951
- .fm-grid.view-list .fm-item-meta {
952
- font-size: 12px;
953
- margin-top: 0;
954
- }
955
-
956
- .fm-list-header {
957
- display: grid;
958
- grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
959
- gap: 10px;
960
- align-items: center;
961
- padding: 6px 12px;
962
- font-size: 11px;
963
- font-weight: 700;
964
- text-transform: uppercase;
965
- letter-spacing: 0.05em;
966
- color: var(--text-muted);
967
- border-bottom: 1px solid var(--border-color);
968
- margin-bottom: 2px;
969
- }
970
-
971
- /* ==========================================================================
972
- Empty State & Skeletons
973
- ========================================================================== */
974
- .fm-empty {
975
- padding: 64px 20px;
976
- text-align: center;
977
- color: var(--text-muted);
978
- display: flex;
979
- flex-direction: column;
980
- align-items: center;
981
- justify-content: center;
982
- }
983
-
984
- .fm-empty[hidden],
985
- [hidden] {
986
- display: none !important;
987
- }
988
-
989
- .fm-empty svg {
990
- color: #cbd5e1;
991
- margin-bottom: 12px;
992
- }
993
-
994
- .fm-empty .empty-title {
995
- font-family: var(--font-headings);
996
- font-size: 15px;
997
- font-weight: 700;
998
- color: var(--text);
999
- margin-bottom: 4px;
1000
- }
1001
-
1002
- .fm-empty .empty-desc {
1003
- font-size: 13px;
1004
- max-width: 360px;
1005
- color: var(--text-secondary);
1006
- }
1007
-
1008
- .fm-skeleton-grid {
1009
- display: grid;
1010
- grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
1011
- gap: 12px;
1012
- width: 100%;
1013
- }
1014
-
1015
- .fm-skeleton-card {
1016
- background: #ffffff;
1017
- border: 1px solid var(--border-color);
1018
- border-radius: var(--radius);
1019
- padding: 10px;
1020
- display: flex;
1021
- flex-direction: column;
1022
- gap: 8px;
1023
- }
1024
-
1025
- .fm-skeleton-icon {
1026
- width: 100%;
1027
- aspect-ratio: 16 / 10;
1028
- border-radius: var(--radius-sm);
1029
- background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1030
- background-size: 200% 100%;
1031
- animation: fm-shimmer 1.5s infinite;
1032
- }
1033
-
1034
- .fm-skeleton-line {
1035
- height: 10px;
1036
- border-radius: 4px;
1037
- background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1038
- background-size: 200% 100%;
1039
- animation: fm-shimmer 1.5s infinite;
1040
- }
1041
-
1042
- .fm-skeleton-line.w-75 { width: 75%; }
1043
- .fm-skeleton-line.w-50 { width: 50%; }
1044
-
1045
- @keyframes fm-shimmer {
1046
- 0% { background-position: 200% 0; }
1047
- 100% { background-position: -200% 0; }
1048
- }
1049
-
1050
- /* ==========================================================================
1051
- Context Menu
1052
- ========================================================================== */
1053
- .fm-context-menu {
1054
- position: fixed;
1055
- z-index: 1000;
1056
- background: #ffffff;
1057
- border: 1px solid var(--border-color);
1058
- border-radius: var(--radius-sm);
1059
- box-shadow: var(--shadow-dropdown);
1060
- padding: 4px;
1061
- min-width: 165px;
1062
- animation: fm-menu-pop 0.1s cubic-bezier(0.16, 1, 0.3, 1);
1063
- }
1064
-
1065
- @keyframes fm-menu-pop {
1066
- from { opacity: 0; transform: scale(0.96); }
1067
- to { opacity: 1; transform: scale(1); }
1068
- }
1069
-
1070
- .fm-context-item {
1071
- display: flex;
1072
- align-items: center;
1073
- gap: 8px;
1074
- width: 100%;
1075
- padding: 6px 10px;
1076
- border: none;
1077
- background: transparent;
1078
- font-family: var(--font);
1079
- font-size: 12.5px;
1080
- font-weight: 500;
1081
- color: var(--text);
1082
- border-radius: 4px;
1083
- cursor: pointer;
1084
- text-align: left;
1085
- transition: background-color 0.1s ease, color 0.1s ease;
1086
- }
1087
-
1088
- .fm-context-item:hover {
1089
- background: #f1f5f9;
1090
- color: var(--primary-dark-color-ml);
1091
- }
1092
-
1093
- .fm-context-item.danger:hover {
1094
- background: var(--red-lt);
1095
- color: var(--danger-color-ml);
1096
- }
1097
-
1098
- .fm-context-divider {
1099
- height: 1px;
1100
- background: var(--border-color);
1101
- margin: 3px 0;
1102
- }
1103
-
1104
- /* ==========================================================================
1105
- Modals & Dialogs
1106
- ========================================================================== */
1107
- .modal {
1108
- display: none;
1109
- position: fixed;
1110
- inset: 0;
1111
- z-index: 1050;
1112
- overflow-x: hidden;
1113
- overflow-y: auto;
1114
- background: rgba(15, 23, 42, 0.5);
1115
- backdrop-filter: blur(4px);
1116
- align-items: center;
1117
- justify-content: center;
1118
- padding: 1rem;
1119
- }
1120
-
1121
- .modal.show {
1122
- display: flex;
1123
- }
1124
-
1125
- .modal-dialog {
1126
- position: relative;
1127
- width: 100%;
1128
- max-width: 480px;
1129
- margin: auto;
1130
- animation: modal-enter 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1131
- }
1132
-
1133
- .modal-dialog.modal-lg {
1134
- max-width: 680px;
1135
- }
1136
-
1137
- .modal-dialog.preview-modal-dialog {
1138
- max-width: 900px;
1139
- }
1140
-
1141
- .preview-modal-dialog.is-fullscreen {
1142
- max-width: 98vw;
1143
- height: 96vh;
1144
- }
1145
-
1146
- .preview-modal-dialog.is-fullscreen .modal-content {
1147
- height: 100%;
1148
- }
1149
-
1150
- .preview-modal-dialog.is-fullscreen .preview-content {
1151
- max-height: calc(96vh - 120px);
1152
- }
1153
-
1154
- @keyframes modal-enter {
1155
- from { opacity: 0; transform: translateY(-8px) scale(0.98); }
1156
- to { opacity: 1; transform: translateY(0) scale(1); }
1157
- }
1158
-
1159
- .modal-content {
1160
- position: relative;
1161
- display: flex;
1162
- flex-direction: column;
1163
- width: 100%;
1164
- background: #ffffff;
1165
- border: 1px solid var(--border-color);
1166
- border-radius: var(--radius-xl);
1167
- box-shadow: var(--shadow-dropdown);
1168
- outline: 0;
1169
- overflow: hidden;
1170
- }
1171
-
1172
- .modal-header {
1173
- display: flex;
1174
- align-items: center;
1175
- justify-content: space-between;
1176
- padding: 12px 18px;
1177
- border-bottom: 1px solid var(--border-color);
1178
- background: #ffffff;
1179
- }
1180
-
1181
- .modal-title {
1182
- font-family: var(--font-headings);
1183
- display: flex;
1184
- align-items: center;
1185
- gap: 8px;
1186
- font-size: 15px;
1187
- font-weight: 700;
1188
- color: var(--text);
1189
- margin: 0;
1190
- }
1191
-
1192
- .modal-title-icon {
1193
- color: var(--primary);
1194
- }
1195
-
1196
- .btn-close {
1197
- background: transparent;
1198
- border: none;
1199
- font-size: 20px;
1200
- line-height: 1;
1201
- color: var(--text-muted);
1202
- cursor: pointer;
1203
- padding: 4px;
1204
- border-radius: var(--radius-sm);
1205
- transition: color 0.12s ease, background-color 0.12s ease;
1206
- }
1207
-
1208
- .btn-close:hover {
1209
- color: var(--text);
1210
- background: #f1f5f9;
1211
- }
1212
-
1213
- .modal-body {
1214
- position: relative;
1215
- flex: 1 1 auto;
1216
- padding: 18px;
1217
- }
1218
-
1219
- .modal-footer {
1220
- display: flex;
1221
- align-items: center;
1222
- justify-content: flex-end;
1223
- gap: 8px;
1224
- padding: 12px 18px;
1225
- border-top: 1px solid var(--border-color);
1226
- background: #f8fafc;
1227
- }
1228
-
1229
- /* ==========================================================================
1230
- Upload Dropzone & Queue
1231
- ========================================================================== */
1232
- .upload-drop-zone {
1233
- border: 1.5px dashed #cbd5e1;
1234
- border-radius: var(--radius);
1235
- padding: 28px 16px;
1236
- text-align: center;
1237
- background: #f8fafc;
1238
- cursor: pointer;
1239
- transition: border-color 0.12s ease, background-color 0.12s ease;
1240
- }
1241
-
1242
- .upload-drop-zone:hover,
1243
- .upload-drop-zone.dragover {
1244
- border-color: var(--primary);
1245
- background: var(--primary-light-color-ml);
1246
- }
1247
-
1248
- .drop-icon {
1249
- color: var(--primary);
1250
- margin-bottom: 8px;
1251
- }
1252
-
1253
- .drop-text {
1254
- font-size: 13.5px;
1255
- font-weight: 600;
1256
- color: var(--text);
1257
- }
1258
-
1259
- .drop-browse-link {
1260
- color: var(--primary);
1261
- text-decoration: underline;
1262
- cursor: pointer;
1263
- }
1264
-
1265
- .drop-hint {
1266
- font-size: 11.5px;
1267
- color: var(--text-muted);
1268
- margin-top: 4px;
1269
- }
1270
-
1271
- .upload-queue {
1272
- max-height: 200px;
1273
- overflow-y: auto;
1274
- display: flex;
1275
- flex-direction: column;
1276
- gap: 6px;
1277
- margin-top: 12px;
1278
- }
1279
-
1280
- .upload-queue-item {
1281
- display: flex;
1282
- align-items: center;
1283
- justify-content: space-between;
1284
- padding: 8px 12px;
1285
- background: #f8fafc;
1286
- border: 1px solid var(--border-color);
1287
- border-radius: var(--radius-sm);
1288
- font-size: 12.5px;
1289
- }
1290
-
1291
- .upload-queue-meta {
1292
- color: var(--text-muted);
1293
- font-size: 11.5px;
1294
- }
1295
-
1296
- .progress-bar-wrap {
1297
- height: 4px;
1298
- background: #e2e8f0;
1299
- border-radius: 2px;
1300
- overflow: hidden;
1301
- }
1302
-
1303
- .progress-bar-inner {
1304
- height: 100%;
1305
- background: var(--primary);
1306
- transition: width 0.18s ease;
1307
- }
1308
-
1309
- .upload-percent {
1310
- font-size: 12px;
1311
- font-weight: 700;
1312
- color: var(--primary);
1313
- }
1314
-
1315
- /* Form Controls in Modals */
1316
- .form-label {
1317
- font-size: 12.5px;
1318
- font-weight: 600;
1319
- color: var(--text);
1320
- margin-bottom: 5px;
1321
- display: block;
1322
- }
1323
-
1324
- .form-control {
1325
- width: 100%;
1326
- padding: 7px 11px;
1327
- font-family: var(--font);
1328
- font-size: 13px;
1329
- color: var(--text);
1330
- background: #ffffff;
1331
- border: 1px solid var(--border-color);
1332
- border-radius: var(--radius-sm);
1333
- outline: none;
1334
- transition: border-color 0.12s ease, box-shadow 0.12s ease;
1335
- }
1336
-
1337
- .form-control:focus {
1338
- border-color: var(--primary);
1339
- box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
1340
- }
1341
-
1342
- .form-text {
1343
- font-size: 11.5px;
1344
- color: var(--text-muted);
1345
- margin-top: 4px;
1346
- }
1347
-
1348
- /* ==========================================================================
1349
- Preview Modal Content
1350
- ========================================================================== */
1351
- .preview-modal-header {
1352
- display: flex;
1353
- align-items: center;
1354
- justify-content: space-between;
1355
- padding: 10px 16px;
1356
- background: #ffffff;
1357
- color: var(--text);
1358
- border-bottom: 1px solid var(--border-color);
1359
- }
1360
-
1361
- .preview-header-left {
1362
- display: flex;
1363
- align-items: center;
1364
- gap: 12px;
1365
- }
1366
-
1367
- .preview-tabs {
1368
- display: inline-flex;
1369
- background: #f1f5f9;
1370
- padding: 2px;
1371
- border-radius: var(--radius-sm);
1372
- gap: 2px;
1373
- }
1374
-
1375
- .preview-tab {
1376
- background: transparent;
1377
- border: none;
1378
- color: var(--text-secondary);
1379
- font-size: 12px;
1380
- font-weight: 500;
1381
- padding: 3px 9px;
1382
- border-radius: 4px;
1383
- cursor: pointer;
1384
- transition: background-color 0.12s ease, color 0.12s ease;
1385
- font-family: var(--font);
1386
- }
1387
-
1388
- .preview-tab.active {
1389
- background: #ffffff;
1390
- color: var(--primary-dark-color-ml);
1391
- font-weight: 600;
1392
- box-shadow: var(--shadow-xs);
1393
- }
1394
-
1395
- .preview-content {
1396
- max-height: 70vh;
1397
- overflow: auto;
1398
- display: flex;
1399
- align-items: center;
1400
- justify-content: center;
1401
- background: #09090b;
1402
- min-height: 280px;
1403
- }
1404
-
1405
- .preview-content img {
1406
- max-width: 100%;
1407
- max-height: 70vh;
1408
- object-fit: contain;
1409
- }
1410
-
1411
- .preview-content video,
1412
- .preview-content audio {
1413
- max-width: 100%;
1414
- max-height: 70vh;
1415
- }
1416
-
1417
- .preview-code-block {
1418
- width: 100%;
1419
- height: 100%;
1420
- max-height: 70vh;
1421
- margin: 0;
1422
- padding: 16px;
1423
- background: #18181b;
1424
- color: #f4f4f5;
1425
- font-family: var(--font-mono);
1426
- font-size: 12.5px;
1427
- overflow: auto;
1428
- line-height: 1.55;
1429
- tab-size: 2;
1430
- }
1431
-
1432
- .preview-code-block code {
1433
- color: inherit;
1434
- background: transparent;
1435
- font-family: inherit;
1436
- font-size: inherit;
1437
- }
1438
-
1439
- .preview-iframe {
1440
- width: 100%;
1441
- height: 70vh;
1442
- border: none;
1443
- }
1444
-
1445
- .rendered-markdown {
1446
- padding: 1.5rem;
1447
- color: var(--text);
1448
- background: #ffffff;
1449
- line-height: 1.65;
1450
- max-height: 70vh;
1451
- overflow-y: auto;
1452
- font-family: var(--font);
1453
- }
1454
-
1455
- .rendered-markdown h1,
1456
- .rendered-markdown h2,
1457
- .rendered-markdown h3 {
1458
- color: var(--text);
1459
- font-family: var(--font-headings);
1460
- font-weight: 700;
1461
- margin-top: 1.25rem;
1462
- margin-bottom: 0.5rem;
1463
- }
1464
-
1465
- .rendered-markdown code {
1466
- background: #f1f5f9;
1467
- color: var(--primary-dark-color-ml);
1468
- padding: 2px 5px;
1469
- border-radius: 4px;
1470
- font-family: var(--font-mono);
1471
- font-size: 12px;
1472
- }
1473
-
1474
- .rendered-markdown pre {
1475
- background: #18181b;
1476
- color: #f4f4f5;
1477
- padding: 1rem;
1478
- border-radius: var(--radius);
1479
- overflow-x: auto;
1480
- }
1481
-
1482
- .rendered-markdown table {
1483
- width: 100%;
1484
- border-collapse: collapse;
1485
- margin: 1rem 0;
1486
- }
1487
-
1488
- .rendered-markdown th,
1489
- .rendered-markdown td {
1490
- border: 1px solid var(--border-color);
1491
- padding: 8px 12px;
1492
- text-align: left;
1493
- }
1494
-
1495
- .rendered-markdown th {
1496
- background: #f8fafc;
1497
- font-weight: 600;
1498
- color: var(--text);
1499
- }
1500
-
1501
- /* Metadata Info Cards */
1502
- .file-info-pane {
1503
- background: #f8fafc;
1504
- padding: 1.25rem;
1505
- }
1506
-
1507
- .info-card {
1508
- background: #ffffff;
1509
- border: 1px solid var(--border-color);
1510
- border-radius: var(--radius-sm);
1511
- padding: 10px 12px;
1512
- font-family: var(--font);
1513
- }
1514
-
1515
- .info-label {
1516
- font-size: 11px;
1517
- font-weight: 700;
1518
- text-transform: uppercase;
1519
- letter-spacing: 0.04em;
1520
- color: var(--text-muted);
1521
- margin-bottom: 3px;
1522
- font-family: var(--font-headings);
1523
- }
1524
-
1525
- .info-value {
1526
- font-size: 13px;
1527
- color: var(--text);
1528
- word-break: break-all;
1529
- font-family: var(--font);
1530
- line-height: 1.45;
1531
- }
1532
-
1533
- .info-value.font-mono,
1534
- .font-mono {
1535
- font-family: var(--font-mono) !important;
1536
- font-size: 12px;
1537
- }
1538
-
1539
- .font-semibold {
1540
- font-weight: 600 !important;
1541
- }
1542
-
1543
- .text-break {
1544
- word-break: break-all !important;
1545
- overflow-wrap: break-word !important;
1546
- }
1547
-
1548
- .text-truncate {
1549
- overflow: hidden !important;
1550
- text-overflow: ellipsis !important;
1551
- white-space: nowrap !important;
1552
- }
1553
-
1554
- .small {
1555
- font-size: 12px !important;
1556
- }
1557
-
1558
- /* ==========================================================================
1559
- Floating Batch Action Bar
1560
- ========================================================================== */
1561
- .batch-action-bar {
1562
- position: fixed;
1563
- bottom: 24px;
1564
- left: 50%;
1565
- transform: translateX(-50%);
1566
- z-index: 1000;
1567
- animation: batch-slide 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1568
- }
1569
-
1570
- @keyframes batch-slide {
1571
- from { opacity: 0; transform: translate(-50%, 12px); }
1572
- to { opacity: 1; transform: translate(-50%, 0); }
1573
- }
1574
-
1575
- .batch-bar-inner {
1576
- display: flex;
1577
- align-items: center;
1578
- gap: 12px;
1579
- padding: 8px 14px;
1580
- background: #0f172a;
1581
- color: #ffffff;
1582
- border-radius: var(--radius-lg);
1583
- box-shadow: var(--shadow-lg);
1584
- border: 1px solid rgba(255, 255, 255, 0.12);
1585
- }
1586
-
1587
- .batch-selection-info {
1588
- display: flex;
1589
- align-items: center;
1590
- gap: 8px;
1591
- font-size: 12.5px;
1592
- font-weight: 500;
1593
- }
1594
-
1595
- .batch-count-badge {
1596
- background: var(--primary);
1597
- color: #ffffff;
1598
- font-weight: 700;
1599
- font-size: 11px;
1600
- padding: 1px 7px;
1601
- border-radius: 999px;
1602
- }
1603
-
1604
- .batch-actions {
1605
- display: flex;
1606
- align-items: center;
1607
- gap: 6px;
1608
- }
1609
-
1610
- .batch-actions .btn-outline-light {
1611
- background: rgba(255, 255, 255, 0.1);
1612
- color: #ffffff;
1613
- border: 1px solid rgba(255, 255, 255, 0.2);
1614
- }
1615
-
1616
- .batch-actions .btn-outline-light:hover {
1617
- background: rgba(255, 255, 255, 0.2);
1618
- }
1619
-
1620
- /* ==========================================================================
1621
- Toasts & Alerts
1622
- ========================================================================== */
1623
- .toast-container {
1624
- position: fixed;
1625
- bottom: 20px;
1626
- right: 20px;
1627
- z-index: 1100;
1628
- display: flex;
1629
- flex-direction: column;
1630
- gap: 8px;
1631
- pointer-events: none;
1632
- }
1633
-
1634
- .toast-notification {
1635
- pointer-events: auto;
1636
- display: flex;
1637
- align-items: center;
1638
- gap: 10px;
1639
- padding: 9px 14px;
1640
- border-radius: var(--radius-sm);
1641
- background: #0f172a;
1642
- color: #ffffff;
1643
- font-family: var(--font);
1644
- font-size: 13px;
1645
- font-weight: 500;
1646
- box-shadow: var(--shadow-lg);
1647
- min-width: 260px;
1648
- max-width: 400px;
1649
- transition: transform 0.2s ease, opacity 0.2s ease;
1650
- border: 1px solid rgba(255, 255, 255, 0.1);
1651
- }
1652
-
1653
- .toast-notification.success {
1654
- background: #065f46;
1655
- border-color: #047857;
1656
- }
1657
-
1658
- .toast-notification.error {
1659
- background: #991b1b;
1660
- border-color: #b91c1c;
1661
- }
1662
-
1663
- .toast-notification.warning {
1664
- background: #92400e;
1665
- border-color: #b45309;
1666
- }
1667
-
1668
- .toast-close-btn {
1669
- margin-left: auto;
1670
- background: transparent;
1671
- border: none;
1672
- color: rgba(255, 255, 255, 0.8);
1673
- cursor: pointer;
1674
- font-size: 16px;
1675
- line-height: 1;
1676
- }
1677
-
1678
- .toast-close-btn:hover {
1679
- color: #ffffff;
1680
- }
1681
-
1682
- /* Flash alerts */
1683
- .alert {
1684
- padding: 10px 14px;
1685
- border-radius: var(--radius-sm);
1686
- margin-bottom: 1rem;
1687
- display: flex;
1688
- align-items: center;
1689
- gap: 8px;
1690
- font-size: 13px;
1691
- border: 1px solid transparent;
1692
- }
1693
-
1694
- .alert-success {
1695
- background: #ecfdf5;
1696
- color: #065f46;
1697
- border-color: #a7f3d0;
1698
- }
1699
-
1700
- .alert-danger {
1701
- background: #fef2f2;
1702
- color: #991b1b;
1703
- border-color: #fecaca;
1704
- }
1705
-
1706
- /* ==========================================================================
1707
- Pagination
1708
- ========================================================================== */
1709
- .pagination-container {
1710
- padding: 10px 16px;
1711
- border-top: 1px solid var(--border-color);
1712
- display: flex;
1713
- align-items: center;
1714
- justify-content: flex-end;
1715
- background: #ffffff;
1716
- }
1717
-
1718
- .pagination {
1719
- display: flex;
1720
- align-items: center;
1721
- gap: 4px;
1722
- list-style: none;
1723
- margin: 0;
1724
- padding: 0;
1725
- }
1726
-
1727
- .page-item .page-link {
1728
- display: flex;
1729
- align-items: center;
1730
- justify-content: center;
1731
- min-width: 28px;
1732
- height: 28px;
1733
- padding: 0 6px;
1734
- border-radius: var(--radius-sm);
1735
- border: 1px solid var(--border-color);
1736
- background: #ffffff;
1737
- color: var(--text-secondary);
1738
- font-size: 12px;
1739
- font-weight: 600;
1740
- text-decoration: none;
1741
- cursor: pointer;
1742
- transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
1743
- }
1744
-
1745
- .page-item .page-link:hover {
1746
- background: #f1f5f9;
1747
- color: var(--text);
1748
- }
1749
-
1750
- .page-item.active .page-link {
1751
- background: var(--primary);
1752
- border-color: var(--primary);
1753
- color: #ffffff;
1754
- }
1755
-
1756
- .page-item.disabled .page-link {
1757
- opacity: 0.4;
1758
- cursor: not-allowed;
1759
- }
1760
-
1761
- /* ==========================================================================
1762
- Provider Badges & Connection Status
1763
- ========================================================================== */
1764
- .provider-badge {
1765
- display: inline-flex;
1766
- align-items: center;
1767
- gap: 4px;
1768
- font-size: 11px;
1769
- font-weight: 700;
1770
- text-transform: uppercase;
1771
- letter-spacing: 0.04em;
1772
- padding: 2px 7px;
1773
- border-radius: 4px;
1774
- background: #f1f5f9;
1775
- color: var(--text-secondary);
1776
- border: 1px solid var(--border-color);
1777
- vertical-align: middle;
1778
- font-family: var(--font-headings);
1779
- }
1780
-
1781
- .provider-badge.provider-gdrive,
1782
- .provider-badge.provider-googledrive,
1783
- .provider-badge.provider-google-drive {
1784
- background: #eff6ff;
1785
- color: #1d4ed8;
1786
- border-color: #bfdbfe;
1787
- }
1788
-
1789
- .provider-badge.provider-s3 {
1790
- background: #fff7ed;
1791
- color: #c2410c;
1792
- border-color: #fed7aa;
1793
- }
1794
-
1795
- .provider-badge.provider-r2 {
1796
- background: #fff7ed;
1797
- color: #c2410c;
1798
- border-color: #fed7aa;
1799
- }
1800
-
1801
- .provider-badge.provider-minio {
1802
- background: #fef2f2;
1803
- color: #b91c1c;
1804
- border-color: #fecaca;
1805
- }
1806
-
1807
- .health-status-badge {
1808
- display: inline-flex;
1809
- align-items: center;
1810
- gap: 5px;
1811
- font-size: 11px;
1812
- font-weight: 600;
1813
- padding: 2px 7px;
1814
- border-radius: 4px;
1815
- background: #ecfdf5;
1816
- color: #047857;
1817
- border: 1px solid #a7f3d0;
1818
- }
1819
-
1820
- .health-status-badge.unhealthy {
1821
- background: #fef2f2;
1822
- color: #b91c1c;
1823
- border-color: #fecaca;
1824
- }
1825
-
1826
- .health-status-badge.checking {
1827
- background: #fffbeb;
1828
- color: #b45309;
1829
- border-color: #fde68a;
1830
- }
1831
-
1832
- .health-dot {
1833
- width: 6px;
1834
- height: 6px;
1835
- border-radius: 50%;
1836
- background: #10b981;
1837
- }
1838
-
1839
- .health-status-badge.unhealthy .health-dot {
1840
- background: #ef4444;
1841
- }
1842
-
1843
- .health-status-badge.checking .health-dot {
1844
- background: #f59e0b;
1845
- }
1846
-
1847
- .health-check-btn {
1848
- background: transparent;
1849
- border: none;
1850
- cursor: pointer;
1851
- color: var(--text-muted);
1852
- padding: 2px 4px;
1853
- border-radius: var(--radius-sm);
1854
- transition: color 0.12s ease, background-color 0.12s ease;
1855
- }
1856
-
1857
- .health-check-btn:hover {
1858
- color: var(--primary);
1859
- background: var(--primary-light-color-ml);
1860
- }
1861
-
1862
- .storage-latency-tag {
1863
- font-size: 11px;
1864
- font-family: var(--font-mono);
1865
- color: var(--text-muted);
1866
- }
1867
-
1868
- /* ==========================================================================
1869
- Mobile & Responsive Adaptations
1870
- ========================================================================== */
1871
- @media (max-width: 900px) {
1872
- .page-wrapper {
1873
- padding: 0;
1874
- max-width: 100%;
1875
- overflow-x: hidden;
1876
- }
1877
-
1878
- .card.file-manager {
1879
- border-radius: var(--radius);
1880
- width: 100%;
1881
- }
1882
-
1883
- .fm-layout {
1884
- grid-template-columns: 100%;
1885
- height: auto;
1886
- min-height: 0;
1887
- max-height: none;
1888
- }
1889
-
1890
- .fm-tree-wrap {
1891
- border-right: none;
1892
- border-bottom: 1px solid var(--border-color);
1893
- padding: 10px 14px;
1894
- background: #f8fafc;
1895
- }
1896
-
1897
- .fm-tree-header,
1898
- .fm-tree {
1899
- display: none;
1900
- }
1901
-
1902
- .fm-storage {
1903
- margin-top: 0;
1904
- padding: 8px 12px;
1905
- background: #ffffff;
1906
- border: 1px solid var(--border-color);
1907
- }
1908
-
1909
- .fm-main {
1910
- width: 100%;
1911
- min-width: 0;
1912
- }
1913
-
1914
- .fm-grid-wrap {
1915
- min-height: 380px;
1916
- padding: 12px;
1917
- }
1918
-
1919
- .fm-grid.view-grid {
1920
- grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
1921
- gap: 8px;
1922
- }
1923
-
1924
- .fm-item-menu {
1925
- opacity: 1;
1926
- }
1927
-
1928
- .fm-star.on {
1929
- opacity: 1;
1930
- }
1931
- }
1932
-
1933
- @media (max-width: 640px) {
1934
- .page-header {
1935
- padding: 0.75rem 1rem;
1936
- margin-bottom: 0.75rem;
1937
- border-radius: var(--radius);
1938
- }
1939
-
1940
- .page-header-row {
1941
- flex-direction: column;
1942
- align-items: stretch;
1943
- gap: 10px;
1944
- }
1945
-
1946
- .page-actions {
1947
- width: 100%;
1948
- display: flex;
1949
- justify-content: stretch;
1950
- gap: 6px;
1951
- }
1952
-
1953
- .page-actions .btn {
1954
- flex: 1 1 0;
1955
- min-width: 0;
1956
- justify-content: center;
1957
- padding: 6px 8px;
1958
- font-size: 12px;
1959
- }
1960
-
1961
- .fm-toolbar {
1962
- flex-direction: column;
1963
- align-items: stretch;
1964
- gap: 8px;
1965
- padding: 8px 10px;
1966
- }
1967
-
1968
- .fm-breadcrumb {
1969
- max-width: 100%;
1970
- overflow-x: auto;
1971
- white-space: nowrap;
1972
- padding-bottom: 2px;
1973
- scrollbar-width: none;
1974
- }
1975
-
1976
- .fm-breadcrumb::-webkit-scrollbar {
1977
- display: none;
1978
- }
1979
-
1980
- .fm-toolbar-actions {
1981
- width: 100%;
1982
- display: flex;
1983
- flex-direction: column;
1984
- align-items: stretch;
1985
- gap: 8px;
1986
- }
1987
-
1988
- .quick-filter-group {
1989
- width: 100%;
1990
- display: flex;
1991
- }
1992
-
1993
- .quick-filter-btn {
1994
- flex: 1 1 0;
1995
- text-align: center;
1996
- padding: 4px 6px;
1997
- font-size: 11.5px;
1998
- }
1999
-
2000
- .search-box {
2001
- width: 100%;
2002
- }
2003
-
2004
- .fm-grid.view-grid {
2005
- grid-template-columns: repeat(2, minmax(0, 1fr));
2006
- gap: 8px;
2007
- }
2008
-
2009
- .fm-grid.view-grid .fm-item {
2010
- padding: 8px;
2011
- gap: 6px;
2012
- }
2013
-
2014
- .fm-item-name {
2015
- font-size: 12px;
2016
- }
2017
-
2018
- .fm-item-meta {
2019
- font-size: 10.5px;
2020
- }
2021
-
2022
- .fm-grid.view-list {
2023
- gap: 4px;
2024
- }
2025
-
2026
- .fm-grid.view-list .fm-item {
2027
- display: flex;
2028
- align-items: center;
2029
- gap: 8px;
2030
- padding: 8px 10px;
2031
- }
2032
-
2033
- .fm-grid.view-list .fm-item-size,
2034
- .fm-grid.view-list .fm-item-date,
2035
- .fm-grid.view-list .fm-star-wrap {
2036
- display: none;
2037
- }
2038
-
2039
- .fm-list-header {
2040
- display: none;
2041
- }
2042
- }
1
+ /* ==========================================================================
2
+ MBKBucket File Manager - Clean, Modern Storage Dashboard
3
+ Design System: Refined Slate & Deep Teal Palette
4
+ ========================================================================== */
5
+
6
+ :root {
7
+ /* Brand / Primary Palette */
8
+ --primary-color-ml: #0f766e;
9
+ --primary-light-color-ml: #f0fdfa;
10
+ --primary-dark-color-ml: #115e59;
11
+ --secondary-color-ml: #14b8a6;
12
+ --dark-color-ml: #0f172a;
13
+ --light-color-ml: #f8fafc;
14
+ --gray-color-ml: #64748b;
15
+ --gray-light-color-ml: #e2e8f0;
16
+ --danger-color-ml: #ef4444;
17
+ --warning-color-ml: #f59e0b;
18
+ --success-color-ml: #10b981;
19
+ --info-color-ml: #0284c7;
20
+
21
+ /* Aliases */
22
+ --primary: var(--primary-color-ml);
23
+ --primary-lt: var(--primary-light-color-ml);
24
+ --primary-dk: var(--primary-dark-color-ml);
25
+ --primary-hover: #134e4a;
26
+ --primary-active: #084c47;
27
+
28
+ /* Surfaces & Backgrounds */
29
+ --body-bg: #f8fafc;
30
+ --bg-surface: #ffffff;
31
+ --bg-surface-secondary: #f8fafc;
32
+ --bg-surface-tertiary: #f1f5f9;
33
+ --bg-surface-hover: #f1f5f9;
34
+
35
+ /* Borders */
36
+ --border-color: #e2e8f0;
37
+ --border-color-light: #f1f5f9;
38
+ --border-color-focus: #0f766e;
39
+
40
+ /* Text */
41
+ --text: #0f172a;
42
+ --text-secondary: #475569;
43
+ --text-muted: #64748b;
44
+ --text-disabled: #94a3b8;
45
+
46
+ /* Accent Colors */
47
+ --blue: #2563eb;
48
+ --azure: #0891b2;
49
+ --green: #10b981;
50
+ --yellow: #d97706;
51
+ --orange: #ea580c;
52
+ --red: #ef4444;
53
+ --purple: #7c3aed;
54
+ --cyan: #0f766e;
55
+
56
+ /* Light Accent Tints */
57
+ --green-lt: #ecfdf5;
58
+ --red-lt: #fef2f2;
59
+ --yellow-lt: #fffbeb;
60
+ --blue-lt: #eff6ff;
61
+ --azure-lt: #ecfeff;
62
+ --purple-lt: #f5f3ff;
63
+ --cyan-lt: #f0fdfa;
64
+
65
+ /* Geometry */
66
+ --radius-sm: 6px;
67
+ --radius: 8px;
68
+ --radius-lg: 12px;
69
+ --radius-xl: 16px;
70
+
71
+ /* Modern Subtle Shadows */
72
+ --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.05);
73
+ --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
74
+ --shadow: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
75
+ --shadow-md: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -4px rgba(15, 23, 42, 0.03);
76
+ --shadow-lg: 0 20px 25px -5px rgba(15, 23, 42, 0.08), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
77
+ --shadow-dropdown: 0 10px 25px -5px rgba(15, 23, 42, 0.12), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
78
+
79
+ /* Fonts */
80
+ --font: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
81
+ --font-headings: "Segoe UI", -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
82
+ --font-mono: "Segoe UI Mono", "Cascadia Code", Consolas, "Courier New", monospace;
83
+ }
84
+
85
+ /* ==========================================================================
86
+ Base Layout & Reset
87
+ ========================================================================== */
88
+ .page-wrapper,
89
+ .page-wrapper *,
90
+ .page-wrapper *::before,
91
+ .page-wrapper *::after,
92
+ .modal,
93
+ .modal * {
94
+ box-sizing: border-box;
95
+ }
96
+
97
+ body,
98
+ button,
99
+ input,
100
+ optgroup,
101
+ select,
102
+ textarea,
103
+ .page-wrapper,
104
+ .modal,
105
+ .modal-content,
106
+ .info-card,
107
+ .info-value,
108
+ .info-label,
109
+ .file-info-pane,
110
+ .fm-context-menu,
111
+ .toast-notification,
112
+ .batch-bar-inner {
113
+ font-family: var(--font);
114
+ }
115
+
116
+ .page-wrapper {
117
+ max-width: 1600px;
118
+ margin: 0 auto;
119
+ width: 100%;
120
+ }
121
+
122
+ /* ==========================================================================
123
+ Page Header
124
+ ========================================================================== */
125
+ .page-header {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: space-between;
129
+ margin-bottom: 1rem;
130
+ padding: 0.85rem 1.25rem;
131
+ border: 1px solid var(--border-color);
132
+ border-radius: var(--radius-lg);
133
+ background: #ffffff;
134
+ box-shadow: var(--shadow-xs);
135
+ }
136
+
137
+ .page-header-row {
138
+ display: flex;
139
+ align-items: center;
140
+ justify-content: space-between;
141
+ width: 100%;
142
+ gap: 1rem;
143
+ }
144
+
145
+ .page-pretitle {
146
+ font-size: 11px;
147
+ font-weight: 700;
148
+ text-transform: uppercase;
149
+ letter-spacing: 0.06em;
150
+ color: var(--primary);
151
+ margin-bottom: 3px;
152
+ }
153
+
154
+ .page-title {
155
+ font-family: var(--font-headings);
156
+ font-size: 1.35rem;
157
+ font-weight: 700;
158
+ color: var(--text);
159
+ margin: 0;
160
+ line-height: 1.25;
161
+ letter-spacing: -0.015em;
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 0.5rem;
165
+ }
166
+
167
+ .page-actions {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: 0.5rem;
171
+ }
172
+
173
+ /* ==========================================================================
174
+ Button System
175
+ ========================================================================== */
176
+ .btn {
177
+ display: inline-flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ gap: 0.45rem;
181
+ font-family: var(--font);
182
+ font-size: 13px;
183
+ font-weight: 600;
184
+ line-height: 1.4;
185
+ padding: 7px 14px;
186
+ border-radius: var(--radius-sm);
187
+ border: 1px solid transparent;
188
+ cursor: pointer;
189
+ transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, color 0.12s ease;
190
+ text-decoration: none;
191
+ white-space: nowrap;
192
+ user-select: none;
193
+ }
194
+
195
+ .btn svg {
196
+ flex-shrink: 0;
197
+ }
198
+
199
+ .btn:focus-visible {
200
+ outline: none;
201
+ box-shadow: 0 0 0 2px var(--primary-light-color-ml), 0 0 0 4px var(--primary);
202
+ }
203
+
204
+ .btn-primary {
205
+ background: var(--primary);
206
+ color: #ffffff;
207
+ border-color: var(--primary-dark-color-ml);
208
+ box-shadow: var(--shadow-xs);
209
+ }
210
+
211
+ .btn-primary:hover {
212
+ background: var(--primary-hover);
213
+ border-color: var(--primary-hover);
214
+ color: #ffffff;
215
+ }
216
+
217
+ .btn-primary:active {
218
+ background: var(--primary-active);
219
+ }
220
+
221
+ .btn-outline {
222
+ background: #ffffff;
223
+ color: var(--text);
224
+ border-color: var(--border-color);
225
+ box-shadow: var(--shadow-xs);
226
+ }
227
+
228
+ .btn-outline:hover {
229
+ background: #f8fafc;
230
+ color: var(--text);
231
+ border-color: #cbd5e1;
232
+ }
233
+
234
+ .btn-outline:active {
235
+ background: #f1f5f9;
236
+ }
237
+
238
+ .btn-danger {
239
+ background: var(--danger-color-ml);
240
+ color: #ffffff;
241
+ border-color: var(--danger-color-ml);
242
+ box-shadow: var(--shadow-xs);
243
+ }
244
+
245
+ .btn-danger:hover {
246
+ background: #dc2626;
247
+ border-color: #dc2626;
248
+ color: #ffffff;
249
+ }
250
+
251
+ .btn-danger:active {
252
+ background: #b91c1c;
253
+ }
254
+
255
+ .btn-sm {
256
+ padding: 5px 10px;
257
+ font-size: 12px;
258
+ border-radius: var(--radius-sm);
259
+ }
260
+
261
+ .btn-icon {
262
+ width: 32px;
263
+ height: 32px;
264
+ padding: 0;
265
+ display: inline-flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ }
269
+
270
+ /* ==========================================================================
271
+ Main File Manager Card & Layout
272
+ ========================================================================== */
273
+ .card.file-manager {
274
+ background: #ffffff;
275
+ border: 1px solid var(--border-color);
276
+ border-radius: var(--radius-lg);
277
+ box-shadow: var(--shadow-sm);
278
+ overflow: hidden;
279
+ }
280
+
281
+ .fm-layout {
282
+ display: grid;
283
+ grid-template-columns: 260px minmax(0, 1fr);
284
+ height: calc(100vh - 170px);
285
+ min-height: 580px;
286
+ max-height: 900px;
287
+ }
288
+
289
+ /* ==========================================================================
290
+ Left Sidebar Tree (Explorer)
291
+ ========================================================================== */
292
+ .fm-tree-wrap {
293
+ border-right: 1px solid var(--border-color);
294
+ background: #f8fafc;
295
+ display: flex;
296
+ flex-direction: column;
297
+ padding: 12px 10px;
298
+ min-height: 0;
299
+ }
300
+
301
+ .fm-tree-header {
302
+ padding: 4px 8px 8px;
303
+ display: flex;
304
+ align-items: center;
305
+ justify-content: space-between;
306
+ }
307
+
308
+ .fm-tree-title {
309
+ font-family: var(--font-headings);
310
+ font-size: 11px;
311
+ font-weight: 700;
312
+ text-transform: uppercase;
313
+ letter-spacing: 0.06em;
314
+ color: var(--text-muted);
315
+ }
316
+
317
+ .fm-tree {
318
+ flex: 1 1 auto;
319
+ overflow-y: auto;
320
+ padding-right: 4px;
321
+ }
322
+
323
+ .fm-tree::-webkit-scrollbar {
324
+ width: 4px;
325
+ }
326
+
327
+ .fm-tree::-webkit-scrollbar-thumb {
328
+ background: #cbd5e1;
329
+ border-radius: 2px;
330
+ }
331
+
332
+ .tree-group {
333
+ margin-bottom: 2px;
334
+ }
335
+
336
+ .tree-link {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 8px;
340
+ width: 100%;
341
+ padding: 6px 10px;
342
+ background: transparent;
343
+ border: none;
344
+ border-radius: var(--radius-sm);
345
+ font-family: var(--font);
346
+ font-size: 13px;
347
+ color: var(--text-secondary);
348
+ text-align: left;
349
+ cursor: pointer;
350
+ transition: background-color 0.12s ease, color 0.12s ease;
351
+ user-select: none;
352
+ font-weight: 500;
353
+ }
354
+
355
+ .tree-link:hover {
356
+ background: #f1f5f9;
357
+ color: var(--text);
358
+ }
359
+
360
+ .tree-link.active {
361
+ background: var(--primary-light-color-ml);
362
+ color: var(--primary-dark-color-ml);
363
+ font-weight: 600;
364
+ }
365
+
366
+ .tree-link svg {
367
+ color: var(--text-muted);
368
+ flex-shrink: 0;
369
+ }
370
+
371
+ .tree-link.active svg {
372
+ color: var(--primary);
373
+ }
374
+
375
+ .tree-link span {
376
+ flex: 1 1 auto;
377
+ min-width: 0;
378
+ overflow: hidden;
379
+ text-overflow: ellipsis;
380
+ white-space: nowrap;
381
+ font-size: 13px;
382
+ }
383
+
384
+ .tree-subs {
385
+ display: flex;
386
+ flex-direction: column;
387
+ margin-left: 12px;
388
+ padding-left: 6px;
389
+ border-left: 1px solid var(--border-color);
390
+ }
391
+
392
+ .tree-sub {
393
+ padding-left: 10px;
394
+ }
395
+
396
+ .tree-badge {
397
+ font-size: 10.5px;
398
+ padding: 1px 6px;
399
+ border-radius: 99px;
400
+ background: #e2e8f0;
401
+ color: var(--text-secondary);
402
+ font-weight: 600;
403
+ }
404
+
405
+ .tree-link.active .tree-badge {
406
+ background: #ccfbf1;
407
+ color: var(--primary-dark-color-ml);
408
+ }
409
+
410
+ /* ==========================================================================
411
+ Sidebar Storage & Bucket Switcher
412
+ ========================================================================== */
413
+ .fm-storage {
414
+ margin-top: auto;
415
+ padding: 12px;
416
+ border-top: 1px solid var(--border-color);
417
+ background: #ffffff;
418
+ border-radius: var(--radius-sm);
419
+ border: 1px solid var(--border-color);
420
+ box-shadow: var(--shadow-xs);
421
+ }
422
+
423
+ .fm-storage-label {
424
+ font-size: 11px;
425
+ font-weight: 700;
426
+ text-transform: uppercase;
427
+ letter-spacing: 0.05em;
428
+ color: var(--text-muted);
429
+ margin-bottom: 6px;
430
+ }
431
+
432
+ .bucket-switcher-wrap {
433
+ position: relative;
434
+ }
435
+
436
+ .bucket-switcher-control {
437
+ position: relative;
438
+ display: flex;
439
+ align-items: center;
440
+ }
441
+
442
+ .bucket-switcher-icon {
443
+ position: absolute;
444
+ left: 9px;
445
+ color: var(--primary);
446
+ pointer-events: none;
447
+ }
448
+
449
+ .bucket-switcher-select {
450
+ width: 100%;
451
+ padding: 6px 10px 6px 28px;
452
+ font-family: var(--font);
453
+ font-size: 12.5px;
454
+ font-weight: 600;
455
+ color: var(--text);
456
+ background: #ffffff;
457
+ border: 1px solid var(--border-color);
458
+ border-radius: var(--radius-sm);
459
+ outline: none;
460
+ cursor: pointer;
461
+ appearance: auto;
462
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
463
+ }
464
+
465
+ .bucket-switcher-select:focus {
466
+ border-color: var(--primary);
467
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
468
+ }
469
+
470
+ .bucket-switcher-status {
471
+ font-size: 11px;
472
+ color: var(--primary);
473
+ margin-top: 4px;
474
+ display: block;
475
+ }
476
+
477
+ .bucket-switcher-status.is-hidden {
478
+ display: none;
479
+ }
480
+
481
+ .storage-bar {
482
+ height: 4px;
483
+ background: #f1f5f9;
484
+ border-radius: 2px;
485
+ overflow: hidden;
486
+ margin: 8px 0 6px;
487
+ }
488
+
489
+ .fm-storage-meta {
490
+ font-size: 11.5px;
491
+ color: var(--text-muted);
492
+ font-weight: 500;
493
+ }
494
+
495
+ .fm-storage-subinfo {
496
+ font-size: 11px;
497
+ color: var(--text-muted);
498
+ margin-top: 2px;
499
+ white-space: nowrap;
500
+ overflow: hidden;
501
+ text-overflow: ellipsis;
502
+ }
503
+
504
+ /* ==========================================================================
505
+ Main Content Area & Toolbar
506
+ ========================================================================== */
507
+ .fm-main {
508
+ display: flex;
509
+ flex-direction: column;
510
+ min-height: 0;
511
+ background: #ffffff;
512
+ }
513
+
514
+ .fm-toolbar {
515
+ display: flex;
516
+ align-items: center;
517
+ justify-content: space-between;
518
+ gap: 12px;
519
+ padding: 10px 16px;
520
+ border-bottom: 1px solid var(--border-color);
521
+ flex-shrink: 0;
522
+ background: #ffffff;
523
+ flex-wrap: wrap;
524
+ }
525
+
526
+ .fm-breadcrumb {
527
+ display: flex;
528
+ align-items: center;
529
+ gap: 4px;
530
+ flex-wrap: wrap;
531
+ min-height: 32px;
532
+ }
533
+
534
+ .bc-link {
535
+ background: transparent;
536
+ border: none;
537
+ font-family: var(--font);
538
+ font-size: 13px;
539
+ color: var(--text-muted);
540
+ cursor: pointer;
541
+ padding: 3px 6px;
542
+ border-radius: var(--radius-sm);
543
+ transition: background-color 0.12s ease, color 0.12s ease;
544
+ display: inline-flex;
545
+ align-items: center;
546
+ gap: 4px;
547
+ font-weight: 500;
548
+ }
549
+
550
+ .bc-link:hover {
551
+ background: #f1f5f9;
552
+ color: var(--text);
553
+ }
554
+
555
+ .bc-link.current {
556
+ color: var(--text);
557
+ font-weight: 600;
558
+ cursor: default;
559
+ }
560
+
561
+ .bc-link.current:hover {
562
+ background: transparent;
563
+ }
564
+
565
+ .fm-breadcrumb .sep {
566
+ color: #cbd5e1;
567
+ font-size: 12px;
568
+ user-select: none;
569
+ }
570
+
571
+ .fm-toolbar-actions {
572
+ display: flex;
573
+ align-items: center;
574
+ gap: 8px;
575
+ margin-left: auto;
576
+ }
577
+
578
+ /* Quick Filters - Segmented Control */
579
+ .quick-filter-group {
580
+ display: inline-flex;
581
+ background: #f1f5f9;
582
+ border: 1px solid var(--border-color);
583
+ border-radius: var(--radius-sm);
584
+ padding: 2px;
585
+ gap: 2px;
586
+ }
587
+
588
+ .quick-filter-btn {
589
+ background: transparent;
590
+ border: none;
591
+ font-family: var(--font);
592
+ font-size: 12px;
593
+ font-weight: 500;
594
+ color: var(--text-secondary);
595
+ padding: 3px 9px;
596
+ border-radius: 4px;
597
+ cursor: pointer;
598
+ transition: background-color 0.12s ease, color 0.12s ease;
599
+ }
600
+
601
+ .quick-filter-btn:hover {
602
+ color: var(--text);
603
+ }
604
+
605
+ .quick-filter-btn.active {
606
+ background: #ffffff;
607
+ color: var(--primary-dark-color-ml);
608
+ font-weight: 600;
609
+ box-shadow: var(--shadow-xs);
610
+ }
611
+
612
+ /* Search Box */
613
+ .search-box {
614
+ position: relative;
615
+ width: 200px;
616
+ display: flex;
617
+ align-items: center;
618
+ }
619
+
620
+ .search-box .s-icon {
621
+ position: absolute;
622
+ left: 9px;
623
+ width: 14px;
624
+ height: 14px;
625
+ color: var(--text-muted);
626
+ pointer-events: none;
627
+ }
628
+
629
+ .search-box input {
630
+ width: 100%;
631
+ padding: 5px 24px 5px 28px;
632
+ font-family: var(--font);
633
+ font-size: 12.5px;
634
+ border: 1px solid var(--border-color);
635
+ border-radius: var(--radius-sm);
636
+ background: #ffffff;
637
+ color: var(--text);
638
+ outline: none;
639
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
640
+ }
641
+
642
+ .search-box input:focus {
643
+ border-color: var(--primary);
644
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
645
+ }
646
+
647
+ .search-clear-btn {
648
+ position: absolute;
649
+ right: 6px;
650
+ background: transparent;
651
+ border: none;
652
+ color: var(--text-muted);
653
+ cursor: pointer;
654
+ font-size: 15px;
655
+ line-height: 1;
656
+ padding: 2px;
657
+ }
658
+
659
+ .search-clear-btn:hover {
660
+ color: var(--text);
661
+ }
662
+
663
+ /* View Switcher */
664
+ .fm-view-toggle {
665
+ display: inline-flex;
666
+ border: 1px solid var(--border-color);
667
+ border-radius: var(--radius-sm);
668
+ overflow: hidden;
669
+ background: #ffffff;
670
+ }
671
+
672
+ .view-btn {
673
+ width: 30px;
674
+ height: 28px;
675
+ border: none;
676
+ background: transparent;
677
+ cursor: pointer;
678
+ color: var(--text-muted);
679
+ display: flex;
680
+ align-items: center;
681
+ justify-content: center;
682
+ transition: background-color 0.12s ease, color 0.12s ease;
683
+ }
684
+
685
+ .view-btn:hover {
686
+ background: #f1f5f9;
687
+ color: var(--text);
688
+ }
689
+
690
+ .view-btn.active {
691
+ background: var(--primary-light-color-ml);
692
+ color: var(--primary-dark-color-ml);
693
+ }
694
+
695
+ .view-btn#view-thumbs {
696
+ border-left: 1px solid var(--border-color);
697
+ }
698
+
699
+ /* ==========================================================================
700
+ File Grid Container & Grid Items
701
+ ========================================================================== */
702
+ .fm-grid-wrap {
703
+ flex: 1 1 auto;
704
+ overflow-y: auto;
705
+ padding: 16px;
706
+ position: relative;
707
+ background: #ffffff;
708
+ }
709
+
710
+ .fm-grid-wrap::-webkit-scrollbar {
711
+ width: 6px;
712
+ }
713
+
714
+ .fm-grid-wrap::-webkit-scrollbar-thumb {
715
+ background: #cbd5e1;
716
+ border-radius: 3px;
717
+ }
718
+
719
+ /* Grid View */
720
+ .fm-grid.view-grid {
721
+ display: grid;
722
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
723
+ grid-auto-rows: max-content;
724
+ align-content: start;
725
+ gap: 12px;
726
+ }
727
+
728
+ .fm-item {
729
+ position: relative;
730
+ background: #ffffff;
731
+ border: 1px solid var(--border-color);
732
+ border-radius: var(--radius);
733
+ cursor: pointer;
734
+ font-family: var(--font);
735
+ text-align: left;
736
+ transition: border-color 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
737
+ user-select: none;
738
+ }
739
+
740
+ .fm-item:hover {
741
+ border-color: #cbd5e1;
742
+ box-shadow: var(--shadow-sm);
743
+ }
744
+
745
+ .fm-item.is-selected {
746
+ border-color: var(--primary);
747
+ background: var(--primary-light-color-ml);
748
+ }
749
+
750
+ /* Item in Grid View */
751
+ .fm-grid.view-grid .fm-item {
752
+ padding: 10px;
753
+ display: flex;
754
+ flex-direction: column;
755
+ align-items: flex-start;
756
+ gap: 8px;
757
+ }
758
+
759
+ .fm-grid.view-grid .fm-item-icon {
760
+ width: 100%;
761
+ aspect-ratio: 16 / 10;
762
+ border-radius: var(--radius-sm);
763
+ display: flex;
764
+ align-items: center;
765
+ justify-content: center;
766
+ flex-shrink: 0;
767
+ background: #f8fafc;
768
+ border: 1px solid var(--border-color-light);
769
+ overflow: hidden;
770
+ position: relative;
771
+ }
772
+
773
+ .fm-item-thumb {
774
+ width: 100%;
775
+ height: 100%;
776
+ object-fit: cover;
777
+ transition: opacity 0.2s ease;
778
+ }
779
+
780
+ .fm-item-thumb.fm-lazy-thumb {
781
+ opacity: 0;
782
+ }
783
+
784
+ .fm-item-thumb.fm-lazy-thumb.is-loaded {
785
+ opacity: 1;
786
+ }
787
+
788
+ .fm-item-icon .ext {
789
+ font-size: 11px;
790
+ font-weight: 700;
791
+ letter-spacing: 0.04em;
792
+ text-transform: uppercase;
793
+ padding: 2px 7px;
794
+ border-radius: 4px;
795
+ }
796
+
797
+ .fm-item-icon .folder-svg {
798
+ width: 40px;
799
+ height: 40px;
800
+ }
801
+
802
+ .fm-grid.view-grid .fm-item-details {
803
+ width: 100%;
804
+ min-width: 0;
805
+ }
806
+
807
+ .fm-item-name {
808
+ font-size: 12.5px;
809
+ font-weight: 600;
810
+ color: var(--text);
811
+ overflow: hidden;
812
+ text-overflow: ellipsis;
813
+ white-space: nowrap;
814
+ min-width: 0;
815
+ line-height: 1.35;
816
+ }
817
+
818
+ .fm-item-meta {
819
+ font-size: 11px;
820
+ color: var(--text-muted);
821
+ margin-top: 2px;
822
+ white-space: nowrap;
823
+ overflow: hidden;
824
+ text-overflow: ellipsis;
825
+ }
826
+
827
+ /* Star & Menu Action Triggers */
828
+ .fm-star {
829
+ position: absolute;
830
+ top: 6px;
831
+ left: 6px;
832
+ width: 22px;
833
+ height: 22px;
834
+ display: flex;
835
+ align-items: center;
836
+ justify-content: center;
837
+ cursor: pointer;
838
+ border-radius: 50%;
839
+ color: var(--text-disabled);
840
+ opacity: 0;
841
+ background: #ffffff;
842
+ border: 1px solid var(--border-color);
843
+ box-shadow: var(--shadow-xs);
844
+ transition: opacity 0.12s ease, color 0.12s ease;
845
+ z-index: 2;
846
+ }
847
+
848
+ .fm-item:hover .fm-star,
849
+ .fm-item.starred .fm-star {
850
+ opacity: 1;
851
+ }
852
+
853
+ .fm-star.on {
854
+ color: #eab308;
855
+ opacity: 1;
856
+ }
857
+
858
+ .fm-star:hover {
859
+ color: #eab308;
860
+ }
861
+
862
+ .fm-item-menu {
863
+ position: absolute;
864
+ top: 6px;
865
+ right: 6px;
866
+ width: 22px;
867
+ height: 22px;
868
+ border: 1px solid var(--border-color);
869
+ background: #ffffff;
870
+ border-radius: 50%;
871
+ display: flex;
872
+ align-items: center;
873
+ justify-content: center;
874
+ cursor: pointer;
875
+ color: var(--text-muted);
876
+ opacity: 0;
877
+ box-shadow: var(--shadow-xs);
878
+ transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease;
879
+ z-index: 2;
880
+ }
881
+
882
+ .fm-item:hover .fm-item-menu {
883
+ opacity: 1;
884
+ }
885
+
886
+ .fm-item-menu:hover {
887
+ background: #f8fafc;
888
+ color: var(--text);
889
+ }
890
+
891
+ /* ==========================================================================
892
+ List View
893
+ ========================================================================== */
894
+ .fm-grid.view-list {
895
+ display: flex;
896
+ flex-direction: column;
897
+ gap: 2px;
898
+ }
899
+
900
+ .fm-grid.view-list .fm-item {
901
+ padding: 6px 12px;
902
+ display: grid;
903
+ grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
904
+ gap: 10px;
905
+ align-items: center;
906
+ border-radius: var(--radius-sm);
907
+ border: 1px solid transparent;
908
+ }
909
+
910
+ .fm-grid.view-list .fm-item:hover {
911
+ background: #f8fafc;
912
+ border-color: var(--border-color);
913
+ }
914
+
915
+ .fm-grid.view-list .fm-item.is-selected {
916
+ background: var(--primary-light-color-ml);
917
+ border-color: #ccfbf1;
918
+ }
919
+
920
+ .fm-grid.view-list .fm-item-icon {
921
+ width: 28px;
922
+ height: 28px;
923
+ border-radius: 4px;
924
+ display: flex;
925
+ align-items: center;
926
+ justify-content: center;
927
+ background: #f8fafc;
928
+ border: 1px solid var(--border-color-light);
929
+ }
930
+
931
+ .fm-grid.view-list .fm-item-icon .ext {
932
+ font-size: 10px;
933
+ font-weight: 700;
934
+ padding: 1px 4px;
935
+ }
936
+
937
+ .fm-grid.view-list .fm-item-icon .folder-svg {
938
+ width: 20px;
939
+ height: 20px;
940
+ }
941
+
942
+ .fm-grid.view-list .fm-star,
943
+ .fm-grid.view-list .fm-item-menu {
944
+ position: static;
945
+ opacity: 1;
946
+ background: transparent;
947
+ border: none;
948
+ box-shadow: none;
949
+ }
950
+
951
+ .fm-grid.view-list .fm-item-meta {
952
+ font-size: 12px;
953
+ margin-top: 0;
954
+ }
955
+
956
+ .fm-list-header {
957
+ display: grid;
958
+ grid-template-columns: 20px 30px 1fr 110px 140px 28px 28px;
959
+ gap: 10px;
960
+ align-items: center;
961
+ padding: 6px 12px;
962
+ font-size: 11px;
963
+ font-weight: 700;
964
+ text-transform: uppercase;
965
+ letter-spacing: 0.05em;
966
+ color: var(--text-muted);
967
+ border-bottom: 1px solid var(--border-color);
968
+ margin-bottom: 2px;
969
+ }
970
+
971
+ /* ==========================================================================
972
+ Empty State & Skeletons
973
+ ========================================================================== */
974
+ .fm-empty {
975
+ padding: 64px 20px;
976
+ text-align: center;
977
+ color: var(--text-muted);
978
+ display: flex;
979
+ flex-direction: column;
980
+ align-items: center;
981
+ justify-content: center;
982
+ }
983
+
984
+ .fm-empty[hidden],
985
+ [hidden] {
986
+ display: none !important;
987
+ }
988
+
989
+ .fm-empty svg {
990
+ color: #cbd5e1;
991
+ margin-bottom: 12px;
992
+ }
993
+
994
+ .fm-empty .empty-title {
995
+ font-family: var(--font-headings);
996
+ font-size: 15px;
997
+ font-weight: 700;
998
+ color: var(--text);
999
+ margin-bottom: 4px;
1000
+ }
1001
+
1002
+ .fm-empty .empty-desc {
1003
+ font-size: 13px;
1004
+ max-width: 360px;
1005
+ color: var(--text-secondary);
1006
+ }
1007
+
1008
+ .fm-skeleton-grid {
1009
+ display: grid;
1010
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
1011
+ gap: 12px;
1012
+ width: 100%;
1013
+ }
1014
+
1015
+ .fm-skeleton-card {
1016
+ background: #ffffff;
1017
+ border: 1px solid var(--border-color);
1018
+ border-radius: var(--radius);
1019
+ padding: 10px;
1020
+ display: flex;
1021
+ flex-direction: column;
1022
+ gap: 8px;
1023
+ }
1024
+
1025
+ .fm-skeleton-icon {
1026
+ width: 100%;
1027
+ aspect-ratio: 16 / 10;
1028
+ border-radius: var(--radius-sm);
1029
+ background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1030
+ background-size: 200% 100%;
1031
+ animation: fm-shimmer 1.5s infinite;
1032
+ }
1033
+
1034
+ .fm-skeleton-line {
1035
+ height: 10px;
1036
+ border-radius: 4px;
1037
+ background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
1038
+ background-size: 200% 100%;
1039
+ animation: fm-shimmer 1.5s infinite;
1040
+ }
1041
+
1042
+ .fm-skeleton-line.w-75 { width: 75%; }
1043
+ .fm-skeleton-line.w-50 { width: 50%; }
1044
+
1045
+ @keyframes fm-shimmer {
1046
+ 0% { background-position: 200% 0; }
1047
+ 100% { background-position: -200% 0; }
1048
+ }
1049
+
1050
+ /* ==========================================================================
1051
+ Context Menu
1052
+ ========================================================================== */
1053
+ .fm-context-menu {
1054
+ position: fixed;
1055
+ z-index: 1000;
1056
+ background: #ffffff;
1057
+ border: 1px solid var(--border-color);
1058
+ border-radius: var(--radius-sm);
1059
+ box-shadow: var(--shadow-dropdown);
1060
+ padding: 4px;
1061
+ min-width: 165px;
1062
+ animation: fm-menu-pop 0.1s cubic-bezier(0.16, 1, 0.3, 1);
1063
+ }
1064
+
1065
+ @keyframes fm-menu-pop {
1066
+ from { opacity: 0; transform: scale(0.96); }
1067
+ to { opacity: 1; transform: scale(1); }
1068
+ }
1069
+
1070
+ .fm-context-item {
1071
+ display: flex;
1072
+ align-items: center;
1073
+ gap: 8px;
1074
+ width: 100%;
1075
+ padding: 6px 10px;
1076
+ border: none;
1077
+ background: transparent;
1078
+ font-family: var(--font);
1079
+ font-size: 12.5px;
1080
+ font-weight: 500;
1081
+ color: var(--text);
1082
+ border-radius: 4px;
1083
+ cursor: pointer;
1084
+ text-align: left;
1085
+ transition: background-color 0.1s ease, color 0.1s ease;
1086
+ }
1087
+
1088
+ .fm-context-item:hover {
1089
+ background: #f1f5f9;
1090
+ color: var(--primary-dark-color-ml);
1091
+ }
1092
+
1093
+ .fm-context-item.danger:hover {
1094
+ background: var(--red-lt);
1095
+ color: var(--danger-color-ml);
1096
+ }
1097
+
1098
+ .fm-context-divider {
1099
+ height: 1px;
1100
+ background: var(--border-color);
1101
+ margin: 3px 0;
1102
+ }
1103
+
1104
+ /* ==========================================================================
1105
+ Modals & Dialogs
1106
+ ========================================================================== */
1107
+ .modal {
1108
+ display: none;
1109
+ position: fixed;
1110
+ inset: 0;
1111
+ z-index: 1050;
1112
+ overflow-x: hidden;
1113
+ overflow-y: auto;
1114
+ background: rgba(15, 23, 42, 0.5);
1115
+ backdrop-filter: blur(4px);
1116
+ align-items: center;
1117
+ justify-content: center;
1118
+ padding: 1rem;
1119
+ }
1120
+
1121
+ .modal.show {
1122
+ display: flex;
1123
+ }
1124
+
1125
+ .modal-dialog {
1126
+ position: relative;
1127
+ width: 100%;
1128
+ max-width: 480px;
1129
+ margin: auto;
1130
+ animation: modal-enter 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1131
+ }
1132
+
1133
+ .modal-dialog.modal-lg {
1134
+ max-width: 680px;
1135
+ }
1136
+
1137
+ .modal-dialog.preview-modal-dialog {
1138
+ max-width: 900px;
1139
+ }
1140
+
1141
+ .preview-modal-dialog.is-fullscreen {
1142
+ max-width: 98vw;
1143
+ height: 96vh;
1144
+ }
1145
+
1146
+ .preview-modal-dialog.is-fullscreen .modal-content {
1147
+ height: 100%;
1148
+ }
1149
+
1150
+ .preview-modal-dialog.is-fullscreen .preview-content {
1151
+ max-height: calc(96vh - 120px);
1152
+ }
1153
+
1154
+ @keyframes modal-enter {
1155
+ from { opacity: 0; transform: translateY(-8px) scale(0.98); }
1156
+ to { opacity: 1; transform: translateY(0) scale(1); }
1157
+ }
1158
+
1159
+ .modal-content {
1160
+ position: relative;
1161
+ display: flex;
1162
+ flex-direction: column;
1163
+ width: 100%;
1164
+ background: #ffffff;
1165
+ border: 1px solid var(--border-color);
1166
+ border-radius: var(--radius-xl);
1167
+ box-shadow: var(--shadow-dropdown);
1168
+ outline: 0;
1169
+ overflow: hidden;
1170
+ }
1171
+
1172
+ .modal-header {
1173
+ display: flex;
1174
+ align-items: center;
1175
+ justify-content: space-between;
1176
+ padding: 12px 18px;
1177
+ border-bottom: 1px solid var(--border-color);
1178
+ background: #ffffff;
1179
+ }
1180
+
1181
+ .modal-title {
1182
+ font-family: var(--font-headings);
1183
+ display: flex;
1184
+ align-items: center;
1185
+ gap: 8px;
1186
+ font-size: 15px;
1187
+ font-weight: 700;
1188
+ color: var(--text);
1189
+ margin: 0;
1190
+ }
1191
+
1192
+ .modal-title-icon {
1193
+ color: var(--primary);
1194
+ }
1195
+
1196
+ .btn-close {
1197
+ background: transparent;
1198
+ border: none;
1199
+ font-size: 20px;
1200
+ line-height: 1;
1201
+ color: var(--text-muted);
1202
+ cursor: pointer;
1203
+ padding: 4px;
1204
+ border-radius: var(--radius-sm);
1205
+ transition: color 0.12s ease, background-color 0.12s ease;
1206
+ }
1207
+
1208
+ .btn-close:hover {
1209
+ color: var(--text);
1210
+ background: #f1f5f9;
1211
+ }
1212
+
1213
+ .modal-body {
1214
+ position: relative;
1215
+ flex: 1 1 auto;
1216
+ padding: 18px;
1217
+ }
1218
+
1219
+ .modal-footer {
1220
+ display: flex;
1221
+ align-items: center;
1222
+ justify-content: flex-end;
1223
+ gap: 8px;
1224
+ padding: 12px 18px;
1225
+ border-top: 1px solid var(--border-color);
1226
+ background: #f8fafc;
1227
+ }
1228
+
1229
+ /* ==========================================================================
1230
+ Upload Dropzone & Queue
1231
+ ========================================================================== */
1232
+ .upload-drop-zone {
1233
+ border: 1.5px dashed #cbd5e1;
1234
+ border-radius: var(--radius);
1235
+ padding: 28px 16px;
1236
+ text-align: center;
1237
+ background: #f8fafc;
1238
+ cursor: pointer;
1239
+ transition: border-color 0.12s ease, background-color 0.12s ease;
1240
+ }
1241
+
1242
+ .upload-drop-zone:hover,
1243
+ .upload-drop-zone.dragover {
1244
+ border-color: var(--primary);
1245
+ background: var(--primary-light-color-ml);
1246
+ }
1247
+
1248
+ .drop-icon {
1249
+ color: var(--primary);
1250
+ margin-bottom: 8px;
1251
+ }
1252
+
1253
+ .drop-text {
1254
+ font-size: 13.5px;
1255
+ font-weight: 600;
1256
+ color: var(--text);
1257
+ }
1258
+
1259
+ .drop-browse-link {
1260
+ color: var(--primary);
1261
+ text-decoration: underline;
1262
+ cursor: pointer;
1263
+ }
1264
+
1265
+ .drop-hint {
1266
+ font-size: 11.5px;
1267
+ color: var(--text-muted);
1268
+ margin-top: 4px;
1269
+ }
1270
+
1271
+ .upload-queue {
1272
+ max-height: 200px;
1273
+ overflow-y: auto;
1274
+ display: flex;
1275
+ flex-direction: column;
1276
+ gap: 6px;
1277
+ margin-top: 12px;
1278
+ }
1279
+
1280
+ .upload-queue-item {
1281
+ display: flex;
1282
+ align-items: center;
1283
+ justify-content: space-between;
1284
+ padding: 8px 12px;
1285
+ background: #f8fafc;
1286
+ border: 1px solid var(--border-color);
1287
+ border-radius: var(--radius-sm);
1288
+ font-size: 12.5px;
1289
+ }
1290
+
1291
+ .upload-queue-meta {
1292
+ color: var(--text-muted);
1293
+ font-size: 11.5px;
1294
+ }
1295
+
1296
+ .progress-bar-wrap {
1297
+ height: 4px;
1298
+ background: #e2e8f0;
1299
+ border-radius: 2px;
1300
+ overflow: hidden;
1301
+ }
1302
+
1303
+ .progress-bar-inner {
1304
+ height: 100%;
1305
+ background: var(--primary);
1306
+ transition: width 0.18s ease;
1307
+ }
1308
+
1309
+ .upload-percent {
1310
+ font-size: 12px;
1311
+ font-weight: 700;
1312
+ color: var(--primary);
1313
+ }
1314
+
1315
+ /* Form Controls in Modals */
1316
+ .form-label {
1317
+ font-size: 12.5px;
1318
+ font-weight: 600;
1319
+ color: var(--text);
1320
+ margin-bottom: 5px;
1321
+ display: block;
1322
+ }
1323
+
1324
+ .form-control {
1325
+ width: 100%;
1326
+ padding: 7px 11px;
1327
+ font-family: var(--font);
1328
+ font-size: 13px;
1329
+ color: var(--text);
1330
+ background: #ffffff;
1331
+ border: 1px solid var(--border-color);
1332
+ border-radius: var(--radius-sm);
1333
+ outline: none;
1334
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
1335
+ }
1336
+
1337
+ .form-control:focus {
1338
+ border-color: var(--primary);
1339
+ box-shadow: 0 0 0 2px rgba(15, 118, 110, 0.15);
1340
+ }
1341
+
1342
+ .form-text {
1343
+ font-size: 11.5px;
1344
+ color: var(--text-muted);
1345
+ margin-top: 4px;
1346
+ }
1347
+
1348
+ /* ==========================================================================
1349
+ Preview Modal Content
1350
+ ========================================================================== */
1351
+ .preview-modal-header {
1352
+ display: flex;
1353
+ align-items: center;
1354
+ justify-content: space-between;
1355
+ padding: 10px 16px;
1356
+ background: #ffffff;
1357
+ color: var(--text);
1358
+ border-bottom: 1px solid var(--border-color);
1359
+ }
1360
+
1361
+ .preview-header-left {
1362
+ display: flex;
1363
+ align-items: center;
1364
+ gap: 12px;
1365
+ }
1366
+
1367
+ .preview-tabs {
1368
+ display: inline-flex;
1369
+ background: #f1f5f9;
1370
+ padding: 2px;
1371
+ border-radius: var(--radius-sm);
1372
+ gap: 2px;
1373
+ }
1374
+
1375
+ .preview-tab {
1376
+ background: transparent;
1377
+ border: none;
1378
+ color: var(--text-secondary);
1379
+ font-size: 12px;
1380
+ font-weight: 500;
1381
+ padding: 3px 9px;
1382
+ border-radius: 4px;
1383
+ cursor: pointer;
1384
+ transition: background-color 0.12s ease, color 0.12s ease;
1385
+ font-family: var(--font);
1386
+ }
1387
+
1388
+ .preview-tab.active {
1389
+ background: #ffffff;
1390
+ color: var(--primary-dark-color-ml);
1391
+ font-weight: 600;
1392
+ box-shadow: var(--shadow-xs);
1393
+ }
1394
+
1395
+ .preview-content {
1396
+ max-height: 70vh;
1397
+ overflow: auto;
1398
+ display: flex;
1399
+ align-items: center;
1400
+ justify-content: center;
1401
+ background: #09090b;
1402
+ min-height: 280px;
1403
+ }
1404
+
1405
+ .preview-content img {
1406
+ max-width: 100%;
1407
+ max-height: 70vh;
1408
+ object-fit: contain;
1409
+ }
1410
+
1411
+ .preview-content video,
1412
+ .preview-content audio {
1413
+ max-width: 100%;
1414
+ max-height: 70vh;
1415
+ }
1416
+
1417
+ .preview-code-block {
1418
+ width: 100%;
1419
+ height: 100%;
1420
+ max-height: 70vh;
1421
+ margin: 0;
1422
+ padding: 16px;
1423
+ background: #18181b;
1424
+ color: #f4f4f5;
1425
+ font-family: var(--font-mono);
1426
+ font-size: 12.5px;
1427
+ overflow: auto;
1428
+ line-height: 1.55;
1429
+ tab-size: 2;
1430
+ }
1431
+
1432
+ .preview-code-block code {
1433
+ color: inherit;
1434
+ background: transparent;
1435
+ font-family: inherit;
1436
+ font-size: inherit;
1437
+ }
1438
+
1439
+ .preview-iframe {
1440
+ width: 100%;
1441
+ height: 70vh;
1442
+ border: none;
1443
+ }
1444
+
1445
+ .rendered-markdown {
1446
+ padding: 1.5rem;
1447
+ color: var(--text);
1448
+ background: #ffffff;
1449
+ line-height: 1.65;
1450
+ max-height: 70vh;
1451
+ overflow-y: auto;
1452
+ font-family: var(--font);
1453
+ }
1454
+
1455
+ .rendered-markdown h1,
1456
+ .rendered-markdown h2,
1457
+ .rendered-markdown h3 {
1458
+ color: var(--text);
1459
+ font-family: var(--font-headings);
1460
+ font-weight: 700;
1461
+ margin-top: 1.25rem;
1462
+ margin-bottom: 0.5rem;
1463
+ }
1464
+
1465
+ .rendered-markdown code {
1466
+ background: #f1f5f9;
1467
+ color: var(--primary-dark-color-ml);
1468
+ padding: 2px 5px;
1469
+ border-radius: 4px;
1470
+ font-family: var(--font-mono);
1471
+ font-size: 12px;
1472
+ }
1473
+
1474
+ .rendered-markdown pre {
1475
+ background: #18181b;
1476
+ color: #f4f4f5;
1477
+ padding: 1rem;
1478
+ border-radius: var(--radius);
1479
+ overflow-x: auto;
1480
+ }
1481
+
1482
+ .rendered-markdown table {
1483
+ width: 100%;
1484
+ border-collapse: collapse;
1485
+ margin: 1rem 0;
1486
+ }
1487
+
1488
+ .rendered-markdown th,
1489
+ .rendered-markdown td {
1490
+ border: 1px solid var(--border-color);
1491
+ padding: 8px 12px;
1492
+ text-align: left;
1493
+ }
1494
+
1495
+ .rendered-markdown th {
1496
+ background: #f8fafc;
1497
+ font-weight: 600;
1498
+ color: var(--text);
1499
+ }
1500
+
1501
+ /* Metadata Info Cards */
1502
+ .file-info-pane {
1503
+ background: #f8fafc;
1504
+ padding: 1.25rem;
1505
+ }
1506
+
1507
+ .info-card {
1508
+ background: #ffffff;
1509
+ border: 1px solid var(--border-color);
1510
+ border-radius: var(--radius-sm);
1511
+ padding: 10px 12px;
1512
+ font-family: var(--font);
1513
+ }
1514
+
1515
+ .info-label {
1516
+ font-size: 11px;
1517
+ font-weight: 700;
1518
+ text-transform: uppercase;
1519
+ letter-spacing: 0.04em;
1520
+ color: var(--text-muted);
1521
+ margin-bottom: 3px;
1522
+ font-family: var(--font-headings);
1523
+ }
1524
+
1525
+ .info-value {
1526
+ font-size: 13px;
1527
+ color: var(--text);
1528
+ word-break: break-all;
1529
+ font-family: var(--font);
1530
+ line-height: 1.45;
1531
+ }
1532
+
1533
+ .info-value.font-mono,
1534
+ .font-mono {
1535
+ font-family: var(--font-mono) !important;
1536
+ font-size: 12px;
1537
+ }
1538
+
1539
+ .font-semibold {
1540
+ font-weight: 600 !important;
1541
+ }
1542
+
1543
+ .text-break {
1544
+ word-break: break-all !important;
1545
+ overflow-wrap: break-word !important;
1546
+ }
1547
+
1548
+ .text-truncate {
1549
+ overflow: hidden !important;
1550
+ text-overflow: ellipsis !important;
1551
+ white-space: nowrap !important;
1552
+ }
1553
+
1554
+ .small {
1555
+ font-size: 12px !important;
1556
+ }
1557
+
1558
+ /* ==========================================================================
1559
+ Floating Batch Action Bar
1560
+ ========================================================================== */
1561
+ .batch-action-bar {
1562
+ position: fixed;
1563
+ bottom: 24px;
1564
+ left: 50%;
1565
+ transform: translateX(-50%);
1566
+ z-index: 1000;
1567
+ animation: batch-slide 0.18s cubic-bezier(0.16, 1, 0.3, 1);
1568
+ }
1569
+
1570
+ @keyframes batch-slide {
1571
+ from { opacity: 0; transform: translate(-50%, 12px); }
1572
+ to { opacity: 1; transform: translate(-50%, 0); }
1573
+ }
1574
+
1575
+ .batch-bar-inner {
1576
+ display: flex;
1577
+ align-items: center;
1578
+ gap: 12px;
1579
+ padding: 8px 14px;
1580
+ background: #0f172a;
1581
+ color: #ffffff;
1582
+ border-radius: var(--radius-lg);
1583
+ box-shadow: var(--shadow-lg);
1584
+ border: 1px solid rgba(255, 255, 255, 0.12);
1585
+ }
1586
+
1587
+ .batch-selection-info {
1588
+ display: flex;
1589
+ align-items: center;
1590
+ gap: 8px;
1591
+ font-size: 12.5px;
1592
+ font-weight: 500;
1593
+ }
1594
+
1595
+ .batch-count-badge {
1596
+ background: var(--primary);
1597
+ color: #ffffff;
1598
+ font-weight: 700;
1599
+ font-size: 11px;
1600
+ padding: 1px 7px;
1601
+ border-radius: 999px;
1602
+ }
1603
+
1604
+ .batch-actions {
1605
+ display: flex;
1606
+ align-items: center;
1607
+ gap: 6px;
1608
+ }
1609
+
1610
+ .batch-actions .btn-outline-light {
1611
+ background: rgba(255, 255, 255, 0.1);
1612
+ color: #ffffff;
1613
+ border: 1px solid rgba(255, 255, 255, 0.2);
1614
+ }
1615
+
1616
+ .batch-actions .btn-outline-light:hover {
1617
+ background: rgba(255, 255, 255, 0.2);
1618
+ }
1619
+
1620
+ /* ==========================================================================
1621
+ Toasts & Alerts
1622
+ ========================================================================== */
1623
+ .toast-container {
1624
+ position: fixed;
1625
+ bottom: 20px;
1626
+ right: 20px;
1627
+ z-index: 1100;
1628
+ display: flex;
1629
+ flex-direction: column;
1630
+ gap: 8px;
1631
+ pointer-events: none;
1632
+ }
1633
+
1634
+ .toast-notification {
1635
+ pointer-events: auto;
1636
+ display: flex;
1637
+ align-items: center;
1638
+ gap: 10px;
1639
+ padding: 9px 14px;
1640
+ border-radius: var(--radius-sm);
1641
+ background: #0f172a;
1642
+ color: #ffffff;
1643
+ font-family: var(--font);
1644
+ font-size: 13px;
1645
+ font-weight: 500;
1646
+ box-shadow: var(--shadow-lg);
1647
+ min-width: 260px;
1648
+ max-width: 400px;
1649
+ transition: transform 0.2s ease, opacity 0.2s ease;
1650
+ border: 1px solid rgba(255, 255, 255, 0.1);
1651
+ }
1652
+
1653
+ .toast-notification.success {
1654
+ background: #065f46;
1655
+ border-color: #047857;
1656
+ }
1657
+
1658
+ .toast-notification.error {
1659
+ background: #991b1b;
1660
+ border-color: #b91c1c;
1661
+ }
1662
+
1663
+ .toast-notification.warning {
1664
+ background: #92400e;
1665
+ border-color: #b45309;
1666
+ }
1667
+
1668
+ .toast-close-btn {
1669
+ margin-left: auto;
1670
+ background: transparent;
1671
+ border: none;
1672
+ color: rgba(255, 255, 255, 0.8);
1673
+ cursor: pointer;
1674
+ font-size: 16px;
1675
+ line-height: 1;
1676
+ }
1677
+
1678
+ .toast-close-btn:hover {
1679
+ color: #ffffff;
1680
+ }
1681
+
1682
+ /* Flash alerts */
1683
+ .alert {
1684
+ padding: 10px 14px;
1685
+ border-radius: var(--radius-sm);
1686
+ margin-bottom: 1rem;
1687
+ display: flex;
1688
+ align-items: center;
1689
+ gap: 8px;
1690
+ font-size: 13px;
1691
+ border: 1px solid transparent;
1692
+ }
1693
+
1694
+ .alert-success {
1695
+ background: #ecfdf5;
1696
+ color: #065f46;
1697
+ border-color: #a7f3d0;
1698
+ }
1699
+
1700
+ .alert-danger {
1701
+ background: #fef2f2;
1702
+ color: #991b1b;
1703
+ border-color: #fecaca;
1704
+ }
1705
+
1706
+ /* ==========================================================================
1707
+ Pagination
1708
+ ========================================================================== */
1709
+ .pagination-container {
1710
+ padding: 10px 16px;
1711
+ border-top: 1px solid var(--border-color);
1712
+ display: flex;
1713
+ align-items: center;
1714
+ justify-content: flex-end;
1715
+ background: #ffffff;
1716
+ }
1717
+
1718
+ .pagination {
1719
+ display: flex;
1720
+ align-items: center;
1721
+ gap: 4px;
1722
+ list-style: none;
1723
+ margin: 0;
1724
+ padding: 0;
1725
+ }
1726
+
1727
+ .page-item .page-link {
1728
+ display: flex;
1729
+ align-items: center;
1730
+ justify-content: center;
1731
+ min-width: 28px;
1732
+ height: 28px;
1733
+ padding: 0 6px;
1734
+ border-radius: var(--radius-sm);
1735
+ border: 1px solid var(--border-color);
1736
+ background: #ffffff;
1737
+ color: var(--text-secondary);
1738
+ font-size: 12px;
1739
+ font-weight: 600;
1740
+ text-decoration: none;
1741
+ cursor: pointer;
1742
+ transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
1743
+ }
1744
+
1745
+ .page-item .page-link:hover {
1746
+ background: #f1f5f9;
1747
+ color: var(--text);
1748
+ }
1749
+
1750
+ .page-item.active .page-link {
1751
+ background: var(--primary);
1752
+ border-color: var(--primary);
1753
+ color: #ffffff;
1754
+ }
1755
+
1756
+ .page-item.disabled .page-link {
1757
+ opacity: 0.4;
1758
+ cursor: not-allowed;
1759
+ }
1760
+
1761
+ /* ==========================================================================
1762
+ Provider Badges & Connection Status
1763
+ ========================================================================== */
1764
+ .provider-badge {
1765
+ display: inline-flex;
1766
+ align-items: center;
1767
+ gap: 4px;
1768
+ font-size: 11px;
1769
+ font-weight: 700;
1770
+ text-transform: uppercase;
1771
+ letter-spacing: 0.04em;
1772
+ padding: 2px 7px;
1773
+ border-radius: 4px;
1774
+ background: #f1f5f9;
1775
+ color: var(--text-secondary);
1776
+ border: 1px solid var(--border-color);
1777
+ vertical-align: middle;
1778
+ font-family: var(--font-headings);
1779
+ }
1780
+
1781
+ .provider-badge.provider-gdrive,
1782
+ .provider-badge.provider-googledrive,
1783
+ .provider-badge.provider-google-drive {
1784
+ background: #eff6ff;
1785
+ color: #1d4ed8;
1786
+ border-color: #bfdbfe;
1787
+ }
1788
+
1789
+ .provider-badge.provider-s3 {
1790
+ background: #fff7ed;
1791
+ color: #c2410c;
1792
+ border-color: #fed7aa;
1793
+ }
1794
+
1795
+ .provider-badge.provider-r2 {
1796
+ background: #fff7ed;
1797
+ color: #c2410c;
1798
+ border-color: #fed7aa;
1799
+ }
1800
+
1801
+ .provider-badge.provider-minio {
1802
+ background: #fef2f2;
1803
+ color: #b91c1c;
1804
+ border-color: #fecaca;
1805
+ }
1806
+
1807
+ .health-status-badge {
1808
+ display: inline-flex;
1809
+ align-items: center;
1810
+ gap: 5px;
1811
+ font-size: 11px;
1812
+ font-weight: 600;
1813
+ padding: 2px 7px;
1814
+ border-radius: 4px;
1815
+ background: #ecfdf5;
1816
+ color: #047857;
1817
+ border: 1px solid #a7f3d0;
1818
+ }
1819
+
1820
+ .health-status-badge.unhealthy {
1821
+ background: #fef2f2;
1822
+ color: #b91c1c;
1823
+ border-color: #fecaca;
1824
+ }
1825
+
1826
+ .health-status-badge.checking {
1827
+ background: #fffbeb;
1828
+ color: #b45309;
1829
+ border-color: #fde68a;
1830
+ }
1831
+
1832
+ .health-dot {
1833
+ width: 6px;
1834
+ height: 6px;
1835
+ border-radius: 50%;
1836
+ background: #10b981;
1837
+ }
1838
+
1839
+ .health-status-badge.unhealthy .health-dot {
1840
+ background: #ef4444;
1841
+ }
1842
+
1843
+ .health-status-badge.checking .health-dot {
1844
+ background: #f59e0b;
1845
+ }
1846
+
1847
+ .health-check-btn {
1848
+ background: transparent;
1849
+ border: none;
1850
+ cursor: pointer;
1851
+ color: var(--text-muted);
1852
+ padding: 2px 4px;
1853
+ border-radius: var(--radius-sm);
1854
+ transition: color 0.12s ease, background-color 0.12s ease;
1855
+ }
1856
+
1857
+ .health-check-btn:hover {
1858
+ color: var(--primary);
1859
+ background: var(--primary-light-color-ml);
1860
+ }
1861
+
1862
+ .storage-latency-tag {
1863
+ font-size: 11px;
1864
+ font-family: var(--font-mono);
1865
+ color: var(--text-muted);
1866
+ }
1867
+
1868
+ /* ==========================================================================
1869
+ Mobile & Responsive Adaptations
1870
+ ========================================================================== */
1871
+ @media (max-width: 900px) {
1872
+ .page-wrapper {
1873
+ padding: 0;
1874
+ max-width: 100%;
1875
+ overflow-x: hidden;
1876
+ }
1877
+
1878
+ .card.file-manager {
1879
+ border-radius: var(--radius);
1880
+ width: 100%;
1881
+ }
1882
+
1883
+ .fm-layout {
1884
+ grid-template-columns: 100%;
1885
+ height: auto;
1886
+ min-height: 0;
1887
+ max-height: none;
1888
+ }
1889
+
1890
+ .fm-tree-wrap {
1891
+ border-right: none;
1892
+ border-bottom: 1px solid var(--border-color);
1893
+ padding: 10px 14px;
1894
+ background: #f8fafc;
1895
+ }
1896
+
1897
+ .fm-tree-header,
1898
+ .fm-tree {
1899
+ display: none;
1900
+ }
1901
+
1902
+ .fm-storage {
1903
+ margin-top: 0;
1904
+ padding: 8px 12px;
1905
+ background: #ffffff;
1906
+ border: 1px solid var(--border-color);
1907
+ }
1908
+
1909
+ .fm-main {
1910
+ width: 100%;
1911
+ min-width: 0;
1912
+ }
1913
+
1914
+ .fm-grid-wrap {
1915
+ min-height: 380px;
1916
+ padding: 12px;
1917
+ }
1918
+
1919
+ .fm-grid.view-grid {
1920
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
1921
+ gap: 8px;
1922
+ }
1923
+
1924
+ .fm-item-menu {
1925
+ opacity: 1;
1926
+ }
1927
+
1928
+ .fm-star.on {
1929
+ opacity: 1;
1930
+ }
1931
+ }
1932
+
1933
+ @media (max-width: 640px) {
1934
+ .page-header {
1935
+ padding: 0.75rem 1rem;
1936
+ margin-bottom: 0.75rem;
1937
+ border-radius: var(--radius);
1938
+ }
1939
+
1940
+ .page-header-row {
1941
+ flex-direction: column;
1942
+ align-items: stretch;
1943
+ gap: 10px;
1944
+ }
1945
+
1946
+ .page-actions {
1947
+ width: 100%;
1948
+ display: flex;
1949
+ justify-content: stretch;
1950
+ gap: 6px;
1951
+ }
1952
+
1953
+ .page-actions .btn {
1954
+ flex: 1 1 0;
1955
+ min-width: 0;
1956
+ justify-content: center;
1957
+ padding: 6px 8px;
1958
+ font-size: 12px;
1959
+ }
1960
+
1961
+ .fm-toolbar {
1962
+ flex-direction: column;
1963
+ align-items: stretch;
1964
+ gap: 8px;
1965
+ padding: 8px 10px;
1966
+ }
1967
+
1968
+ .fm-breadcrumb {
1969
+ max-width: 100%;
1970
+ overflow-x: auto;
1971
+ white-space: nowrap;
1972
+ padding-bottom: 2px;
1973
+ scrollbar-width: none;
1974
+ }
1975
+
1976
+ .fm-breadcrumb::-webkit-scrollbar {
1977
+ display: none;
1978
+ }
1979
+
1980
+ .fm-toolbar-actions {
1981
+ width: 100%;
1982
+ display: flex;
1983
+ flex-direction: column;
1984
+ align-items: stretch;
1985
+ gap: 8px;
1986
+ }
1987
+
1988
+ .quick-filter-group {
1989
+ width: 100%;
1990
+ display: flex;
1991
+ }
1992
+
1993
+ .quick-filter-btn {
1994
+ flex: 1 1 0;
1995
+ text-align: center;
1996
+ padding: 4px 6px;
1997
+ font-size: 11.5px;
1998
+ }
1999
+
2000
+ .search-box {
2001
+ width: 100%;
2002
+ }
2003
+
2004
+ .fm-grid.view-grid {
2005
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2006
+ gap: 8px;
2007
+ }
2008
+
2009
+ .fm-grid.view-grid .fm-item {
2010
+ padding: 8px;
2011
+ gap: 6px;
2012
+ }
2013
+
2014
+ .fm-item-name {
2015
+ font-size: 12px;
2016
+ }
2017
+
2018
+ .fm-item-meta {
2019
+ font-size: 10.5px;
2020
+ }
2021
+
2022
+ .fm-grid.view-list {
2023
+ gap: 4px;
2024
+ }
2025
+
2026
+ .fm-grid.view-list .fm-item {
2027
+ display: flex;
2028
+ align-items: center;
2029
+ gap: 8px;
2030
+ padding: 8px 10px;
2031
+ }
2032
+
2033
+ .fm-grid.view-list .fm-item-size,
2034
+ .fm-grid.view-list .fm-item-date,
2035
+ .fm-grid.view-list .fm-star-wrap {
2036
+ display: none;
2037
+ }
2038
+
2039
+ .fm-list-header {
2040
+ display: none;
2041
+ }
2042
+ }