claude-code-limiter-server 1.0.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.
@@ -0,0 +1,1374 @@
1
+ /* ============================================================
2
+ Claude Code Limiter — Dashboard Stylesheet
3
+ Dark theme, system-ui font, CSS custom properties
4
+ ============================================================ */
5
+
6
+ /* --- CSS Variables / Theme --- */
7
+ :root {
8
+ --bg-primary: #0d1117;
9
+ --bg-secondary: #161b22;
10
+ --bg-tertiary: #1c2129;
11
+ --bg-hover: #1f262e;
12
+ --border: #30363d;
13
+ --border-light: #3b434b;
14
+ --text-primary: #e6edf3;
15
+ --text-secondary:#8b949e;
16
+ --text-muted: #6e7681;
17
+ --accent-blue: #58a6ff;
18
+ --accent-green: #3fb950;
19
+ --accent-yellow: #d29922;
20
+ --accent-red: #f85149;
21
+ --accent-purple: #bc8cff;
22
+ --accent-orange: #f0883e;
23
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.3);
24
+ --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
25
+ --shadow-lg: 0 8px 24px rgba(0,0,0,0.5);
26
+ --radius-sm: 6px;
27
+ --radius-md: 8px;
28
+ --radius-lg: 12px;
29
+ --sidebar-width: 240px;
30
+ --header-height: 56px;
31
+ --font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
32
+ --transition: 150ms ease;
33
+ }
34
+
35
+ /* --- Reset --- */
36
+ *, *::before, *::after {
37
+ box-sizing: border-box;
38
+ margin: 0;
39
+ padding: 0;
40
+ }
41
+
42
+ html {
43
+ font-size: 14px;
44
+ -webkit-font-smoothing: antialiased;
45
+ -moz-osx-font-smoothing: grayscale;
46
+ }
47
+
48
+ body {
49
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
50
+ background: var(--bg-primary);
51
+ color: var(--text-primary);
52
+ line-height: 1.5;
53
+ overflow-x: hidden;
54
+ min-height: 100vh;
55
+ }
56
+
57
+ a { color: var(--accent-blue); text-decoration: none; }
58
+ a:hover { text-decoration: underline; }
59
+
60
+ /* --- Utility --- */
61
+ .hidden { display: none !important; }
62
+ .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
63
+
64
+ /* ============================================================
65
+ LOGIN SCREEN
66
+ ============================================================ */
67
+ .login-screen {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ min-height: 100vh;
72
+ padding: 1rem;
73
+ background: var(--bg-primary);
74
+ }
75
+
76
+ .login-card {
77
+ width: 100%;
78
+ max-width: 380px;
79
+ background: var(--bg-secondary);
80
+ border: 1px solid var(--border);
81
+ border-radius: var(--radius-lg);
82
+ padding: 2.5rem 2rem;
83
+ box-shadow: var(--shadow-lg);
84
+ }
85
+
86
+ .login-logo {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 0.75rem;
90
+ margin-bottom: 0.25rem;
91
+ }
92
+
93
+ .login-logo h1 {
94
+ font-size: 1.25rem;
95
+ font-weight: 600;
96
+ color: var(--text-primary);
97
+ }
98
+
99
+ .login-subtitle {
100
+ color: var(--text-secondary);
101
+ margin-bottom: 2rem;
102
+ padding-left: 3.25rem;
103
+ font-size: 0.9rem;
104
+ }
105
+
106
+ /* ============================================================
107
+ FORMS
108
+ ============================================================ */
109
+ .form-group {
110
+ margin-bottom: 1.25rem;
111
+ }
112
+
113
+ .form-group label {
114
+ display: block;
115
+ margin-bottom: 0.4rem;
116
+ font-size: 0.85rem;
117
+ font-weight: 500;
118
+ color: var(--text-secondary);
119
+ }
120
+
121
+ .form-group input,
122
+ .form-group select,
123
+ .form-group textarea {
124
+ width: 100%;
125
+ padding: 0.6rem 0.75rem;
126
+ background: var(--bg-tertiary);
127
+ border: 1px solid var(--border);
128
+ border-radius: var(--radius-sm);
129
+ color: var(--text-primary);
130
+ font-size: 0.95rem;
131
+ font-family: inherit;
132
+ transition: border-color var(--transition);
133
+ }
134
+
135
+ .form-group input:focus,
136
+ .form-group select:focus,
137
+ .form-group textarea:focus {
138
+ outline: none;
139
+ border-color: var(--accent-blue);
140
+ box-shadow: 0 0 0 3px rgba(88,166,255,0.15);
141
+ }
142
+
143
+ .form-group input::placeholder {
144
+ color: var(--text-muted);
145
+ }
146
+
147
+ .form-group select {
148
+ cursor: pointer;
149
+ appearance: none;
150
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b949e' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
151
+ background-repeat: no-repeat;
152
+ background-position: right 0.75rem center;
153
+ padding-right: 2rem;
154
+ }
155
+
156
+ .form-error {
157
+ color: var(--accent-red);
158
+ font-size: 0.85rem;
159
+ margin-top: 0.75rem;
160
+ }
161
+
162
+ .form-hint {
163
+ color: var(--text-muted);
164
+ font-size: 0.8rem;
165
+ margin-top: 0.25rem;
166
+ }
167
+
168
+ .form-row {
169
+ display: grid;
170
+ grid-template-columns: 1fr 1fr;
171
+ gap: 1rem;
172
+ }
173
+
174
+ .form-row-3 {
175
+ display: grid;
176
+ grid-template-columns: 1fr 1fr 1fr;
177
+ gap: 1rem;
178
+ }
179
+
180
+ /* ============================================================
181
+ BUTTONS
182
+ ============================================================ */
183
+ .btn {
184
+ display: inline-flex;
185
+ align-items: center;
186
+ justify-content: center;
187
+ gap: 0.4rem;
188
+ padding: 0.55rem 1rem;
189
+ border: 1px solid var(--border);
190
+ border-radius: var(--radius-sm);
191
+ background: var(--bg-tertiary);
192
+ color: var(--text-primary);
193
+ font-size: 0.875rem;
194
+ font-family: inherit;
195
+ font-weight: 500;
196
+ cursor: pointer;
197
+ transition: all var(--transition);
198
+ white-space: nowrap;
199
+ }
200
+
201
+ .btn:hover {
202
+ background: var(--bg-hover);
203
+ border-color: var(--border-light);
204
+ }
205
+
206
+ .btn:active { transform: scale(0.98); }
207
+
208
+ .btn-primary {
209
+ background: var(--accent-blue);
210
+ border-color: var(--accent-blue);
211
+ color: #0d1117;
212
+ }
213
+ .btn-primary:hover {
214
+ background: #79b8ff;
215
+ border-color: #79b8ff;
216
+ }
217
+
218
+ .btn-success {
219
+ background: var(--accent-green);
220
+ border-color: var(--accent-green);
221
+ color: #0d1117;
222
+ }
223
+ .btn-success:hover {
224
+ background: #56d364;
225
+ border-color: #56d364;
226
+ }
227
+
228
+ .btn-danger {
229
+ background: var(--accent-red);
230
+ border-color: var(--accent-red);
231
+ color: #fff;
232
+ }
233
+ .btn-danger:hover {
234
+ background: #ff6a5e;
235
+ border-color: #ff6a5e;
236
+ }
237
+
238
+ .btn-warning {
239
+ background: var(--accent-yellow);
240
+ border-color: var(--accent-yellow);
241
+ color: #0d1117;
242
+ }
243
+ .btn-warning:hover {
244
+ background: #e0a52d;
245
+ border-color: #e0a52d;
246
+ }
247
+
248
+ .btn-ghost {
249
+ background: transparent;
250
+ border-color: transparent;
251
+ color: var(--text-secondary);
252
+ }
253
+ .btn-ghost:hover {
254
+ background: var(--bg-hover);
255
+ color: var(--text-primary);
256
+ }
257
+
258
+ .btn-sm {
259
+ padding: 0.35rem 0.7rem;
260
+ font-size: 0.8rem;
261
+ }
262
+
263
+ .btn-block {
264
+ width: 100%;
265
+ }
266
+
267
+ .btn-icon {
268
+ width: 32px;
269
+ height: 32px;
270
+ padding: 0;
271
+ border-radius: var(--radius-sm);
272
+ }
273
+
274
+ .btn[disabled] {
275
+ opacity: 0.5;
276
+ cursor: not-allowed;
277
+ pointer-events: none;
278
+ }
279
+
280
+ /* ============================================================
281
+ APP SHELL / LAYOUT
282
+ ============================================================ */
283
+ .app-shell {
284
+ display: flex;
285
+ min-height: 100vh;
286
+ }
287
+
288
+ .mobile-header {
289
+ display: none;
290
+ position: fixed;
291
+ top: 0;
292
+ left: 0;
293
+ right: 0;
294
+ height: var(--header-height);
295
+ background: var(--bg-secondary);
296
+ border-bottom: 1px solid var(--border);
297
+ padding: 0 1rem;
298
+ align-items: center;
299
+ z-index: 100;
300
+ gap: 0.75rem;
301
+ }
302
+
303
+ .mobile-title {
304
+ font-size: 1rem;
305
+ font-weight: 600;
306
+ flex: 1;
307
+ }
308
+
309
+ /* Hamburger */
310
+ .hamburger-btn {
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: 4px;
314
+ background: none;
315
+ border: none;
316
+ cursor: pointer;
317
+ padding: 4px;
318
+ }
319
+ .hamburger-btn span {
320
+ display: block;
321
+ width: 20px;
322
+ height: 2px;
323
+ background: var(--text-primary);
324
+ border-radius: 2px;
325
+ transition: transform var(--transition);
326
+ }
327
+
328
+ /* Sidebar Overlay */
329
+ .sidebar-overlay {
330
+ position: fixed;
331
+ inset: 0;
332
+ background: rgba(0,0,0,0.5);
333
+ z-index: 199;
334
+ }
335
+
336
+ /* ============================================================
337
+ SIDEBAR
338
+ ============================================================ */
339
+ .sidebar {
340
+ position: fixed;
341
+ top: 0;
342
+ left: 0;
343
+ bottom: 0;
344
+ width: var(--sidebar-width);
345
+ background: var(--bg-secondary);
346
+ border-right: 1px solid var(--border);
347
+ display: flex;
348
+ flex-direction: column;
349
+ z-index: 200;
350
+ overflow-y: auto;
351
+ }
352
+
353
+ .sidebar-header {
354
+ display: flex;
355
+ align-items: center;
356
+ gap: 0.65rem;
357
+ padding: 1.25rem 1rem;
358
+ border-bottom: 1px solid var(--border);
359
+ }
360
+
361
+ .sidebar-brand strong {
362
+ display: block;
363
+ font-size: 0.95rem;
364
+ color: var(--text-primary);
365
+ }
366
+
367
+ .sidebar-team {
368
+ display: block;
369
+ font-size: 0.75rem;
370
+ color: var(--text-muted);
371
+ margin-top: 1px;
372
+ }
373
+
374
+ .nav-list {
375
+ list-style: none;
376
+ padding: 0.75rem 0.5rem;
377
+ flex: 1;
378
+ }
379
+
380
+ .nav-list li { margin-bottom: 2px; }
381
+
382
+ .nav-link {
383
+ display: flex;
384
+ align-items: center;
385
+ gap: 0.6rem;
386
+ padding: 0.6rem 0.75rem;
387
+ border-radius: var(--radius-sm);
388
+ color: var(--text-secondary);
389
+ font-size: 0.9rem;
390
+ font-weight: 500;
391
+ transition: all var(--transition);
392
+ text-decoration: none;
393
+ }
394
+
395
+ .nav-link:hover {
396
+ background: var(--bg-hover);
397
+ color: var(--text-primary);
398
+ text-decoration: none;
399
+ }
400
+
401
+ .nav-link.active {
402
+ background: rgba(88,166,255,0.1);
403
+ color: var(--accent-blue);
404
+ }
405
+
406
+ .nav-icon {
407
+ width: 18px;
408
+ height: 18px;
409
+ flex-shrink: 0;
410
+ }
411
+
412
+ .sidebar-footer {
413
+ padding: 1rem;
414
+ border-top: 1px solid var(--border);
415
+ display: flex;
416
+ flex-direction: column;
417
+ gap: 0.75rem;
418
+ }
419
+
420
+ /* WebSocket Status */
421
+ .ws-status {
422
+ display: flex;
423
+ align-items: center;
424
+ gap: 0.5rem;
425
+ font-size: 0.75rem;
426
+ color: var(--text-muted);
427
+ }
428
+
429
+ .ws-dot {
430
+ width: 8px;
431
+ height: 8px;
432
+ border-radius: 50%;
433
+ background: var(--text-muted);
434
+ flex-shrink: 0;
435
+ transition: background var(--transition);
436
+ }
437
+
438
+ .ws-dot.connected { background: var(--accent-green); }
439
+ .ws-dot.connecting { background: var(--accent-yellow); animation: pulse 1.5s infinite; }
440
+ .ws-dot.disconnected { background: var(--accent-red); }
441
+
442
+ .ws-indicator {
443
+ display: flex;
444
+ align-items: center;
445
+ }
446
+
447
+ @keyframes pulse {
448
+ 0%, 100% { opacity: 1; }
449
+ 50% { opacity: 0.3; }
450
+ }
451
+
452
+ /* ============================================================
453
+ MAIN CONTENT
454
+ ============================================================ */
455
+ .content {
456
+ flex: 1;
457
+ margin-left: var(--sidebar-width);
458
+ padding: 2rem;
459
+ min-height: 100vh;
460
+ }
461
+
462
+ /* ============================================================
463
+ PAGE HEADERS
464
+ ============================================================ */
465
+ .page-header {
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: space-between;
469
+ margin-bottom: 1.75rem;
470
+ flex-wrap: wrap;
471
+ gap: 1rem;
472
+ }
473
+
474
+ .page-header h2 {
475
+ font-size: 1.5rem;
476
+ font-weight: 600;
477
+ }
478
+
479
+ .page-header-actions {
480
+ display: flex;
481
+ gap: 0.5rem;
482
+ }
483
+
484
+ .breadcrumb {
485
+ display: flex;
486
+ align-items: center;
487
+ gap: 0.4rem;
488
+ font-size: 0.85rem;
489
+ color: var(--text-muted);
490
+ margin-bottom: 0.5rem;
491
+ }
492
+
493
+ .breadcrumb a { color: var(--text-secondary); }
494
+ .breadcrumb a:hover { color: var(--accent-blue); }
495
+
496
+ /* ============================================================
497
+ STATS ROW
498
+ ============================================================ */
499
+ .stats-row {
500
+ display: grid;
501
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
502
+ gap: 1rem;
503
+ margin-bottom: 1.75rem;
504
+ }
505
+
506
+ .stat-card {
507
+ background: var(--bg-secondary);
508
+ border: 1px solid var(--border);
509
+ border-radius: var(--radius-md);
510
+ padding: 1.25rem;
511
+ }
512
+
513
+ .stat-label {
514
+ font-size: 0.8rem;
515
+ color: var(--text-muted);
516
+ text-transform: uppercase;
517
+ letter-spacing: 0.5px;
518
+ margin-bottom: 0.35rem;
519
+ }
520
+
521
+ .stat-value {
522
+ font-size: 1.75rem;
523
+ font-weight: 700;
524
+ color: var(--text-primary);
525
+ line-height: 1.2;
526
+ }
527
+
528
+ .stat-sub {
529
+ font-size: 0.8rem;
530
+ color: var(--text-secondary);
531
+ margin-top: 0.25rem;
532
+ }
533
+
534
+ /* ============================================================
535
+ CARDS
536
+ ============================================================ */
537
+ .card {
538
+ background: var(--bg-secondary);
539
+ border: 1px solid var(--border);
540
+ border-radius: var(--radius-md);
541
+ overflow: hidden;
542
+ }
543
+
544
+ .card-header {
545
+ display: flex;
546
+ align-items: center;
547
+ justify-content: space-between;
548
+ padding: 1rem 1.25rem;
549
+ border-bottom: 1px solid var(--border);
550
+ }
551
+
552
+ .card-header h3 {
553
+ font-size: 1rem;
554
+ font-weight: 600;
555
+ }
556
+
557
+ .card-body { padding: 1.25rem; }
558
+
559
+ .card-body-flush { padding: 0; }
560
+
561
+ /* ============================================================
562
+ USER CARDS GRID (Overview)
563
+ ============================================================ */
564
+ .user-grid {
565
+ display: grid;
566
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
567
+ gap: 1rem;
568
+ margin-bottom: 1.75rem;
569
+ }
570
+
571
+ .user-card {
572
+ background: var(--bg-secondary);
573
+ border: 1px solid var(--border);
574
+ border-radius: var(--radius-md);
575
+ padding: 1.25rem;
576
+ transition: border-color var(--transition), box-shadow var(--transition);
577
+ cursor: pointer;
578
+ }
579
+
580
+ .user-card:hover {
581
+ border-color: var(--border-light);
582
+ box-shadow: var(--shadow-sm);
583
+ }
584
+
585
+ .user-card-head {
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: space-between;
589
+ margin-bottom: 1rem;
590
+ }
591
+
592
+ .user-card-info {
593
+ display: flex;
594
+ align-items: center;
595
+ gap: 0.75rem;
596
+ }
597
+
598
+ .user-avatar {
599
+ width: 36px;
600
+ height: 36px;
601
+ border-radius: 50%;
602
+ display: flex;
603
+ align-items: center;
604
+ justify-content: center;
605
+ font-weight: 700;
606
+ font-size: 0.9rem;
607
+ color: #0d1117;
608
+ flex-shrink: 0;
609
+ }
610
+
611
+ .user-card-name {
612
+ font-weight: 600;
613
+ font-size: 0.95rem;
614
+ }
615
+
616
+ .user-card-slug {
617
+ font-size: 0.8rem;
618
+ color: var(--text-muted);
619
+ font-family: var(--font-mono);
620
+ }
621
+
622
+ .user-card-usage {
623
+ margin-bottom: 0.75rem;
624
+ }
625
+
626
+ .user-card-actions {
627
+ display: flex;
628
+ gap: 0.4rem;
629
+ justify-content: flex-end;
630
+ }
631
+
632
+ /* ============================================================
633
+ STATUS BADGES
634
+ ============================================================ */
635
+ .badge {
636
+ display: inline-flex;
637
+ align-items: center;
638
+ gap: 0.3rem;
639
+ padding: 0.2rem 0.6rem;
640
+ border-radius: 999px;
641
+ font-size: 0.75rem;
642
+ font-weight: 600;
643
+ text-transform: uppercase;
644
+ letter-spacing: 0.3px;
645
+ }
646
+
647
+ .badge-active {
648
+ background: rgba(63,185,80,0.15);
649
+ color: var(--accent-green);
650
+ }
651
+
652
+ .badge-paused {
653
+ background: rgba(210,153,34,0.15);
654
+ color: var(--accent-yellow);
655
+ }
656
+
657
+ .badge-killed {
658
+ background: rgba(248,81,73,0.15);
659
+ color: var(--accent-red);
660
+ }
661
+
662
+ .badge-model {
663
+ background: rgba(88,166,255,0.12);
664
+ color: var(--accent-blue);
665
+ font-family: var(--font-mono);
666
+ font-size: 0.7rem;
667
+ text-transform: lowercase;
668
+ }
669
+
670
+ /* ============================================================
671
+ PROGRESS BARS
672
+ ============================================================ */
673
+ .progress-row {
674
+ margin-bottom: 0.6rem;
675
+ }
676
+
677
+ .progress-label {
678
+ display: flex;
679
+ justify-content: space-between;
680
+ font-size: 0.8rem;
681
+ margin-bottom: 0.3rem;
682
+ }
683
+
684
+ .progress-label-name {
685
+ color: var(--text-secondary);
686
+ font-weight: 500;
687
+ }
688
+
689
+ .progress-label-value {
690
+ color: var(--text-muted);
691
+ font-family: var(--font-mono);
692
+ font-size: 0.75rem;
693
+ }
694
+
695
+ .progress-bar {
696
+ height: 6px;
697
+ background: var(--bg-tertiary);
698
+ border-radius: 3px;
699
+ overflow: hidden;
700
+ position: relative;
701
+ }
702
+
703
+ .progress-fill {
704
+ height: 100%;
705
+ border-radius: 3px;
706
+ transition: width 0.4s ease;
707
+ min-width: 0;
708
+ }
709
+
710
+ .progress-fill-ok {
711
+ background: linear-gradient(90deg, var(--accent-green), #56d364);
712
+ }
713
+
714
+ .progress-fill-warn {
715
+ background: linear-gradient(90deg, var(--accent-yellow), #e0a52d);
716
+ }
717
+
718
+ .progress-fill-danger {
719
+ background: linear-gradient(90deg, var(--accent-red), #ff6a5e);
720
+ }
721
+
722
+ .progress-fill-blue {
723
+ background: linear-gradient(90deg, var(--accent-blue), #79b8ff);
724
+ }
725
+
726
+ .progress-bar-lg {
727
+ height: 10px;
728
+ border-radius: 5px;
729
+ }
730
+
731
+ .progress-bar-lg .progress-fill {
732
+ border-radius: 5px;
733
+ }
734
+
735
+ /* Limit marker on progress bar */
736
+ .progress-bar-container {
737
+ position: relative;
738
+ }
739
+
740
+ .progress-limit-marker {
741
+ position: absolute;
742
+ top: -2px;
743
+ bottom: -2px;
744
+ width: 2px;
745
+ background: var(--text-primary);
746
+ border-radius: 1px;
747
+ z-index: 1;
748
+ }
749
+
750
+ /* ============================================================
751
+ TABLES
752
+ ============================================================ */
753
+ .table-wrap {
754
+ overflow-x: auto;
755
+ }
756
+
757
+ table {
758
+ width: 100%;
759
+ border-collapse: collapse;
760
+ }
761
+
762
+ table th,
763
+ table td {
764
+ padding: 0.7rem 1rem;
765
+ text-align: left;
766
+ border-bottom: 1px solid var(--border);
767
+ }
768
+
769
+ table th {
770
+ font-size: 0.75rem;
771
+ font-weight: 600;
772
+ text-transform: uppercase;
773
+ letter-spacing: 0.5px;
774
+ color: var(--text-muted);
775
+ background: var(--bg-tertiary);
776
+ position: sticky;
777
+ top: 0;
778
+ }
779
+
780
+ table tbody tr:nth-child(even) {
781
+ background: rgba(255,255,255,0.015);
782
+ }
783
+
784
+ table tbody tr:hover {
785
+ background: var(--bg-hover);
786
+ }
787
+
788
+ table td {
789
+ font-size: 0.875rem;
790
+ }
791
+
792
+ /* ============================================================
793
+ MODALS
794
+ ============================================================ */
795
+ .modal-overlay {
796
+ position: fixed;
797
+ inset: 0;
798
+ background: rgba(0,0,0,0.6);
799
+ display: flex;
800
+ align-items: center;
801
+ justify-content: center;
802
+ z-index: 500;
803
+ padding: 1rem;
804
+ animation: fadeIn 0.15s ease;
805
+ }
806
+
807
+ .modal-content {
808
+ background: var(--bg-secondary);
809
+ border: 1px solid var(--border);
810
+ border-radius: var(--radius-lg);
811
+ width: 100%;
812
+ max-width: 540px;
813
+ max-height: 90vh;
814
+ overflow-y: auto;
815
+ box-shadow: var(--shadow-lg);
816
+ animation: slideUp 0.2s ease;
817
+ }
818
+
819
+ .modal-sm { max-width: 400px; }
820
+ .modal-lg { max-width: 720px; }
821
+
822
+ .modal-header {
823
+ display: flex;
824
+ align-items: center;
825
+ justify-content: space-between;
826
+ padding: 1.25rem 1.5rem;
827
+ border-bottom: 1px solid var(--border);
828
+ }
829
+
830
+ .modal-header h3 {
831
+ font-size: 1.1rem;
832
+ font-weight: 600;
833
+ }
834
+
835
+ .modal-close {
836
+ background: none;
837
+ border: none;
838
+ color: var(--text-muted);
839
+ font-size: 1.5rem;
840
+ cursor: pointer;
841
+ padding: 0.25rem;
842
+ line-height: 1;
843
+ transition: color var(--transition);
844
+ }
845
+ .modal-close:hover { color: var(--text-primary); }
846
+
847
+ .modal-body {
848
+ padding: 1.5rem;
849
+ }
850
+
851
+ .modal-footer,
852
+ .modal-actions {
853
+ display: flex;
854
+ justify-content: flex-end;
855
+ gap: 0.5rem;
856
+ padding: 1rem 1.5rem;
857
+ border-top: 1px solid var(--border);
858
+ }
859
+
860
+ @keyframes fadeIn {
861
+ from { opacity: 0; }
862
+ to { opacity: 1; }
863
+ }
864
+
865
+ @keyframes slideUp {
866
+ from { opacity: 0; transform: translateY(12px); }
867
+ to { opacity: 1; transform: translateY(0); }
868
+ }
869
+
870
+ /* ============================================================
871
+ TOAST NOTIFICATIONS
872
+ ============================================================ */
873
+ .toast-container {
874
+ position: fixed;
875
+ top: 1rem;
876
+ right: 1rem;
877
+ z-index: 9999;
878
+ display: flex;
879
+ flex-direction: column;
880
+ gap: 0.5rem;
881
+ pointer-events: none;
882
+ max-width: 400px;
883
+ }
884
+
885
+ .toast {
886
+ display: flex;
887
+ align-items: flex-start;
888
+ gap: 0.6rem;
889
+ padding: 0.85rem 1rem;
890
+ background: var(--bg-secondary);
891
+ border: 1px solid var(--border);
892
+ border-radius: var(--radius-md);
893
+ box-shadow: var(--shadow-md);
894
+ pointer-events: auto;
895
+ animation: toastIn 0.3s ease;
896
+ min-width: 280px;
897
+ }
898
+
899
+ .toast.removing {
900
+ animation: toastOut 0.25s ease forwards;
901
+ }
902
+
903
+ .toast-icon {
904
+ font-size: 1.1rem;
905
+ flex-shrink: 0;
906
+ margin-top: 1px;
907
+ }
908
+
909
+ .toast-body {
910
+ flex: 1;
911
+ min-width: 0;
912
+ }
913
+
914
+ .toast-title {
915
+ font-weight: 600;
916
+ font-size: 0.85rem;
917
+ margin-bottom: 0.15rem;
918
+ }
919
+
920
+ .toast-message {
921
+ font-size: 0.8rem;
922
+ color: var(--text-secondary);
923
+ word-break: break-word;
924
+ }
925
+
926
+ .toast-close {
927
+ background: none;
928
+ border: none;
929
+ color: var(--text-muted);
930
+ font-size: 1.1rem;
931
+ cursor: pointer;
932
+ padding: 0;
933
+ line-height: 1;
934
+ flex-shrink: 0;
935
+ }
936
+
937
+ .toast-info { border-left: 3px solid var(--accent-blue); }
938
+ .toast-success { border-left: 3px solid var(--accent-green); }
939
+ .toast-warning { border-left: 3px solid var(--accent-yellow); }
940
+ .toast-error { border-left: 3px solid var(--accent-red); }
941
+
942
+ @keyframes toastIn {
943
+ from { opacity: 0; transform: translateX(40px); }
944
+ to { opacity: 1; transform: translateX(0); }
945
+ }
946
+
947
+ @keyframes toastOut {
948
+ from { opacity: 1; transform: translateX(0); }
949
+ to { opacity: 0; transform: translateX(40px); }
950
+ }
951
+
952
+ /* ============================================================
953
+ LIVE FEED
954
+ ============================================================ */
955
+ .live-feed {
956
+ max-height: 360px;
957
+ overflow-y: auto;
958
+ }
959
+
960
+ .feed-item {
961
+ display: flex;
962
+ align-items: flex-start;
963
+ gap: 0.65rem;
964
+ padding: 0.6rem 1.25rem;
965
+ border-bottom: 1px solid var(--border);
966
+ font-size: 0.825rem;
967
+ animation: feedIn 0.25s ease;
968
+ }
969
+
970
+ .feed-item:last-child { border-bottom: none; }
971
+
972
+ .feed-dot {
973
+ width: 8px;
974
+ height: 8px;
975
+ border-radius: 50%;
976
+ flex-shrink: 0;
977
+ margin-top: 6px;
978
+ }
979
+
980
+ .feed-dot-check { background: var(--accent-blue); }
981
+ .feed-dot-counted { background: var(--accent-green); }
982
+ .feed-dot-blocked { background: var(--accent-red); }
983
+ .feed-dot-status { background: var(--accent-yellow); }
984
+ .feed-dot-system { background: var(--text-muted); }
985
+
986
+ .feed-content { flex: 1; min-width: 0; }
987
+
988
+ .feed-user {
989
+ font-weight: 600;
990
+ color: var(--text-primary);
991
+ }
992
+
993
+ .feed-detail {
994
+ color: var(--text-secondary);
995
+ }
996
+
997
+ .feed-time {
998
+ font-size: 0.75rem;
999
+ color: var(--text-muted);
1000
+ flex-shrink: 0;
1001
+ font-family: var(--font-mono);
1002
+ }
1003
+
1004
+ .feed-empty {
1005
+ padding: 2rem;
1006
+ text-align: center;
1007
+ color: var(--text-muted);
1008
+ }
1009
+
1010
+ @keyframes feedIn {
1011
+ from { opacity: 0; transform: translateY(-8px); }
1012
+ to { opacity: 1; transform: translateY(0); }
1013
+ }
1014
+
1015
+ /* ============================================================
1016
+ CREDIT GAUGE (canvas wrapper)
1017
+ ============================================================ */
1018
+ .gauge-wrap {
1019
+ display: flex;
1020
+ align-items: center;
1021
+ justify-content: center;
1022
+ padding: 1rem;
1023
+ }
1024
+
1025
+ .gauge-wrap canvas {
1026
+ max-width: 100%;
1027
+ }
1028
+
1029
+ /* ============================================================
1030
+ CHART CONTAINERS
1031
+ ============================================================ */
1032
+ .chart-container {
1033
+ position: relative;
1034
+ width: 100%;
1035
+ }
1036
+
1037
+ .chart-container canvas {
1038
+ width: 100% !important;
1039
+ display: block;
1040
+ }
1041
+
1042
+ /* ============================================================
1043
+ USER DETAIL PAGE
1044
+ ============================================================ */
1045
+ .detail-grid {
1046
+ display: grid;
1047
+ grid-template-columns: 280px 1fr;
1048
+ gap: 1.5rem;
1049
+ margin-bottom: 1.5rem;
1050
+ }
1051
+
1052
+ .detail-sidebar-card {
1053
+ display: flex;
1054
+ flex-direction: column;
1055
+ align-items: center;
1056
+ gap: 0.75rem;
1057
+ text-align: center;
1058
+ }
1059
+
1060
+ .detail-avatar {
1061
+ width: 64px;
1062
+ height: 64px;
1063
+ border-radius: 50%;
1064
+ display: flex;
1065
+ align-items: center;
1066
+ justify-content: center;
1067
+ font-weight: 700;
1068
+ font-size: 1.5rem;
1069
+ color: #0d1117;
1070
+ }
1071
+
1072
+ .detail-name {
1073
+ font-size: 1.2rem;
1074
+ font-weight: 600;
1075
+ }
1076
+
1077
+ .detail-meta {
1078
+ font-size: 0.8rem;
1079
+ color: var(--text-muted);
1080
+ }
1081
+
1082
+ .detail-actions {
1083
+ display: flex;
1084
+ flex-direction: column;
1085
+ gap: 0.4rem;
1086
+ width: 100%;
1087
+ margin-top: 0.5rem;
1088
+ }
1089
+
1090
+ /* Limits list */
1091
+ .limits-list {
1092
+ list-style: none;
1093
+ }
1094
+
1095
+ .limit-item {
1096
+ display: flex;
1097
+ align-items: center;
1098
+ justify-content: space-between;
1099
+ padding: 0.65rem 0;
1100
+ border-bottom: 1px solid var(--border);
1101
+ font-size: 0.85rem;
1102
+ }
1103
+
1104
+ .limit-item:last-child { border-bottom: none; }
1105
+
1106
+ .limit-type {
1107
+ display: flex;
1108
+ align-items: center;
1109
+ gap: 0.5rem;
1110
+ }
1111
+
1112
+ .limit-value {
1113
+ font-family: var(--font-mono);
1114
+ font-weight: 600;
1115
+ color: var(--text-primary);
1116
+ }
1117
+
1118
+ /* Install command box */
1119
+ .install-box {
1120
+ background: var(--bg-primary);
1121
+ border: 1px solid var(--border);
1122
+ border-radius: var(--radius-sm);
1123
+ padding: 0.75rem 1rem;
1124
+ margin-top: 1rem;
1125
+ display: flex;
1126
+ align-items: center;
1127
+ gap: 0.5rem;
1128
+ }
1129
+
1130
+ .install-box code {
1131
+ flex: 1;
1132
+ font-family: var(--font-mono);
1133
+ font-size: 0.8rem;
1134
+ color: var(--accent-green);
1135
+ word-break: break-all;
1136
+ }
1137
+
1138
+ .install-box .btn {
1139
+ flex-shrink: 0;
1140
+ }
1141
+
1142
+ /* ============================================================
1143
+ SETTINGS PAGE
1144
+ ============================================================ */
1145
+ .settings-section {
1146
+ margin-bottom: 2rem;
1147
+ }
1148
+
1149
+ .settings-section h3 {
1150
+ font-size: 1.05rem;
1151
+ font-weight: 600;
1152
+ margin-bottom: 1rem;
1153
+ padding-bottom: 0.5rem;
1154
+ border-bottom: 1px solid var(--border);
1155
+ }
1156
+
1157
+ .weight-grid {
1158
+ display: grid;
1159
+ grid-template-columns: repeat(3, 1fr);
1160
+ gap: 1rem;
1161
+ }
1162
+
1163
+ .weight-card {
1164
+ background: var(--bg-tertiary);
1165
+ border: 1px solid var(--border);
1166
+ border-radius: var(--radius-sm);
1167
+ padding: 1rem;
1168
+ text-align: center;
1169
+ }
1170
+
1171
+ .weight-model {
1172
+ font-family: var(--font-mono);
1173
+ font-weight: 600;
1174
+ text-transform: capitalize;
1175
+ margin-bottom: 0.5rem;
1176
+ color: var(--text-primary);
1177
+ }
1178
+
1179
+ .weight-card input {
1180
+ width: 80px;
1181
+ text-align: center;
1182
+ padding: 0.4rem;
1183
+ background: var(--bg-primary);
1184
+ border: 1px solid var(--border);
1185
+ border-radius: var(--radius-sm);
1186
+ color: var(--text-primary);
1187
+ font-family: var(--font-mono);
1188
+ font-size: 1.1rem;
1189
+ }
1190
+
1191
+ .weight-card input:focus {
1192
+ outline: none;
1193
+ border-color: var(--accent-blue);
1194
+ }
1195
+
1196
+ /* ============================================================
1197
+ PRESET BUTTONS (Add User modal)
1198
+ ============================================================ */
1199
+ .presets-row {
1200
+ display: flex;
1201
+ gap: 0.5rem;
1202
+ margin-bottom: 1rem;
1203
+ flex-wrap: wrap;
1204
+ }
1205
+
1206
+ .preset-btn {
1207
+ padding: 0.5rem 0.9rem;
1208
+ border-radius: var(--radius-sm);
1209
+ border: 1px solid var(--border);
1210
+ background: var(--bg-tertiary);
1211
+ color: var(--text-secondary);
1212
+ font-size: 0.825rem;
1213
+ cursor: pointer;
1214
+ transition: all var(--transition);
1215
+ }
1216
+
1217
+ .preset-btn:hover {
1218
+ border-color: var(--accent-blue);
1219
+ color: var(--accent-blue);
1220
+ }
1221
+
1222
+ .preset-btn.selected {
1223
+ background: rgba(88,166,255,0.12);
1224
+ border-color: var(--accent-blue);
1225
+ color: var(--accent-blue);
1226
+ font-weight: 600;
1227
+ }
1228
+
1229
+ /* ============================================================
1230
+ EMPTY STATES
1231
+ ============================================================ */
1232
+ .empty-state {
1233
+ display: flex;
1234
+ flex-direction: column;
1235
+ align-items: center;
1236
+ justify-content: center;
1237
+ padding: 4rem 2rem;
1238
+ color: var(--text-muted);
1239
+ text-align: center;
1240
+ }
1241
+
1242
+ .empty-state svg {
1243
+ width: 48px;
1244
+ height: 48px;
1245
+ margin-bottom: 1rem;
1246
+ opacity: 0.4;
1247
+ }
1248
+
1249
+ .empty-state p {
1250
+ font-size: 0.95rem;
1251
+ margin-bottom: 1rem;
1252
+ }
1253
+
1254
+ /* ============================================================
1255
+ SPINNER
1256
+ ============================================================ */
1257
+ .spinner {
1258
+ width: 24px;
1259
+ height: 24px;
1260
+ border: 3px solid var(--border);
1261
+ border-top-color: var(--accent-blue);
1262
+ border-radius: 50%;
1263
+ animation: spin 0.6s linear infinite;
1264
+ margin: 2rem auto;
1265
+ }
1266
+
1267
+ @keyframes spin {
1268
+ to { transform: rotate(360deg); }
1269
+ }
1270
+
1271
+ /* ============================================================
1272
+ MISC HELPERS
1273
+ ============================================================ */
1274
+ .text-green { color: var(--accent-green); }
1275
+ .text-yellow { color: var(--accent-yellow); }
1276
+ .text-red { color: var(--accent-red); }
1277
+ .text-blue { color: var(--accent-blue); }
1278
+ .text-muted { color: var(--text-muted); }
1279
+ .text-mono { font-family: var(--font-mono); }
1280
+ .text-sm { font-size: 0.8rem; }
1281
+ .text-center { text-align: center; }
1282
+ .mt-1 { margin-top: 0.5rem; }
1283
+ .mt-2 { margin-top: 1rem; }
1284
+ .mt-3 { margin-top: 1.5rem; }
1285
+ .mb-1 { margin-bottom: 0.5rem; }
1286
+ .mb-2 { margin-bottom: 1rem; }
1287
+ .mb-3 { margin-bottom: 1.5rem; }
1288
+ .gap-row { display: flex; gap: 0.5rem; align-items: center; }
1289
+ .flex-1 { flex: 1; }
1290
+
1291
+ .two-col {
1292
+ display: grid;
1293
+ grid-template-columns: 1fr 1fr;
1294
+ gap: 1.5rem;
1295
+ }
1296
+
1297
+ .section-divider {
1298
+ border: none;
1299
+ border-top: 1px solid var(--border);
1300
+ margin: 1.5rem 0;
1301
+ }
1302
+
1303
+ /* ============================================================
1304
+ RESPONSIVE
1305
+ ============================================================ */
1306
+ @media (max-width: 768px) {
1307
+ .sidebar {
1308
+ transform: translateX(-100%);
1309
+ transition: transform 0.25s ease;
1310
+ }
1311
+
1312
+ .sidebar.open {
1313
+ transform: translateX(0);
1314
+ }
1315
+
1316
+ .mobile-header {
1317
+ display: flex;
1318
+ }
1319
+
1320
+ .content {
1321
+ margin-left: 0;
1322
+ padding: 1rem;
1323
+ padding-top: calc(var(--header-height) + 1rem);
1324
+ }
1325
+
1326
+ .detail-grid {
1327
+ grid-template-columns: 1fr;
1328
+ }
1329
+
1330
+ .two-col {
1331
+ grid-template-columns: 1fr;
1332
+ }
1333
+
1334
+ .user-grid {
1335
+ grid-template-columns: 1fr;
1336
+ }
1337
+
1338
+ .stats-row {
1339
+ grid-template-columns: repeat(2, 1fr);
1340
+ }
1341
+
1342
+ .form-row {
1343
+ grid-template-columns: 1fr;
1344
+ }
1345
+
1346
+ .form-row-3 {
1347
+ grid-template-columns: 1fr;
1348
+ }
1349
+
1350
+ .weight-grid {
1351
+ grid-template-columns: 1fr;
1352
+ }
1353
+
1354
+ .page-header {
1355
+ flex-direction: column;
1356
+ align-items: flex-start;
1357
+ }
1358
+
1359
+ .toast-container {
1360
+ left: 1rem;
1361
+ right: 1rem;
1362
+ max-width: none;
1363
+ }
1364
+
1365
+ .toast {
1366
+ min-width: 0;
1367
+ }
1368
+ }
1369
+
1370
+ @media (max-width: 480px) {
1371
+ .stats-row {
1372
+ grid-template-columns: 1fr;
1373
+ }
1374
+ }