claude-team-dashboard 1.2.2

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.

Potentially problematic release.


This version of claude-team-dashboard might be problematic. Click here for more details.

Files changed (49) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/LICENSE +21 -0
  3. package/README.md +722 -0
  4. package/cleanup.js +73 -0
  5. package/config.js +50 -0
  6. package/dist/assets/icons-Ijf8rQIc.js +1 -0
  7. package/dist/assets/index-Cqc1m1x_.css +1 -0
  8. package/dist/assets/index-jGy3ms0W.js +9 -0
  9. package/dist/assets/react-vendor-DbmSkCAF.js +1 -0
  10. package/dist/index.html +16 -0
  11. package/index.html +13 -0
  12. package/package.json +93 -0
  13. package/server.js +953 -0
  14. package/src/App.jsx +372 -0
  15. package/src/animations-enhanced.css +929 -0
  16. package/src/animations.css +783 -0
  17. package/src/components/ActivityFeed.jsx +289 -0
  18. package/src/components/AgentActivity.jsx +104 -0
  19. package/src/components/AgentCard.jsx +163 -0
  20. package/src/components/AgentOutputViewer.jsx +334 -0
  21. package/src/components/ArchiveViewer.jsx +283 -0
  22. package/src/components/ConnectionStatus.jsx +124 -0
  23. package/src/components/DetailedTaskProgress.jsx +126 -0
  24. package/src/components/ErrorBoundary.jsx +132 -0
  25. package/src/components/Header.jsx +154 -0
  26. package/src/components/LiveAgentStream.jsx +176 -0
  27. package/src/components/LiveCommunication.jsx +326 -0
  28. package/src/components/LiveMetrics.jsx +100 -0
  29. package/src/components/RealTimeMessages.jsx +298 -0
  30. package/src/components/SkeletonLoader.jsx +384 -0
  31. package/src/components/StatsOverview.jsx +209 -0
  32. package/src/components/SystemStatus.jsx +57 -0
  33. package/src/components/TaskList.jsx +306 -0
  34. package/src/components/TeamCard.jsx +126 -0
  35. package/src/components/TeamHistory.jsx +204 -0
  36. package/src/components/__tests__/ConnectionStatus.test.jsx +54 -0
  37. package/src/components/__tests__/StatsOverview.test.jsx +66 -0
  38. package/src/config/constants.js +59 -0
  39. package/src/hooks/useCounterAnimation.js +219 -0
  40. package/src/hooks/useWebSocket.js +76 -0
  41. package/src/index.css +1818 -0
  42. package/src/main.jsx +17 -0
  43. package/src/polish-enhancements.css +303 -0
  44. package/src/premium-visual-polish.css +830 -0
  45. package/src/responsive-enhancements.css +666 -0
  46. package/src/styles/theme.css +395 -0
  47. package/src/test/setup.js +19 -0
  48. package/start.js +36 -0
  49. package/vite.config.js +37 -0
@@ -0,0 +1,929 @@
1
+ /* ========================================
2
+ ENHANCED ANIMATION SYSTEM
3
+ Motion Design System v1.0
4
+ Created: 2026-02-10
5
+ ======================================== */
6
+
7
+ /* ==========================================
8
+ SKELETON LOADING ANIMATIONS
9
+ ========================================== */
10
+
11
+ /* Enhanced shimmer with dual-layer effect */
12
+ @keyframes shimmerFlow {
13
+ 0% {
14
+ background-position: -200% center;
15
+ }
16
+ 100% {
17
+ background-position: 200% center;
18
+ }
19
+ }
20
+
21
+ .skeleton-animated {
22
+ background: linear-gradient(
23
+ 90deg,
24
+ rgba(55, 65, 81, 0.4) 0%,
25
+ rgba(75, 85, 99, 0.6) 50%,
26
+ rgba(55, 65, 81, 0.4) 100%
27
+ );
28
+ background-size: 200% 100%;
29
+ animation: shimmerFlow 1.8s ease-in-out infinite;
30
+ border-radius: 8px;
31
+ position: relative;
32
+ overflow: hidden;
33
+ }
34
+
35
+ .skeleton-animated::after {
36
+ content: '';
37
+ position: absolute;
38
+ inset: 0;
39
+ background: linear-gradient(
40
+ 90deg,
41
+ transparent 0%,
42
+ rgba(255, 255, 255, 0.05) 50%,
43
+ transparent 100%
44
+ );
45
+ animation: shimmerFlow 1.8s ease-in-out infinite;
46
+ animation-delay: 0.2s;
47
+ }
48
+
49
+ /* Skeleton variants */
50
+ .skeleton-text { height: 16px; width: 100%; }
51
+ .skeleton-title { height: 24px; width: 75%; }
52
+ .skeleton-avatar { width: 48px; height: 48px; border-radius: 50%; }
53
+ .skeleton-icon { width: 40px; height: 40px; border-radius: 12px; }
54
+ .skeleton-card { padding: 24px; border-radius: 16px; }
55
+ .skeleton-line { height: 14px; margin-bottom: 12px; }
56
+ .skeleton-line:last-child { width: 60%; }
57
+
58
+ /* ==========================================
59
+ COUNTER ANIMATIONS
60
+ ========================================== */
61
+
62
+ /* Value change pulse effect */
63
+ @keyframes counterPulse {
64
+ 0% {
65
+ transform: scale(1);
66
+ color: inherit;
67
+ }
68
+ 50% {
69
+ transform: scale(1.15);
70
+ color: #f97316; /* Claude orange */
71
+ text-shadow: 0 0 20px rgba(249, 115, 22, 0.6);
72
+ }
73
+ 100% {
74
+ transform: scale(1);
75
+ color: inherit;
76
+ }
77
+ }
78
+
79
+ .counter-updated {
80
+ animation: counterPulse 600ms cubic-bezier(0.4, 0.0, 0.2, 1);
81
+ }
82
+
83
+ /* Number increment indicator */
84
+ @keyframes counterIncrement {
85
+ 0% {
86
+ opacity: 0;
87
+ transform: translateY(20px);
88
+ }
89
+ 50% {
90
+ opacity: 1;
91
+ }
92
+ 100% {
93
+ opacity: 0;
94
+ transform: translateY(-10px);
95
+ }
96
+ }
97
+
98
+ .counter-increment-indicator {
99
+ position: absolute;
100
+ top: -10px;
101
+ right: 0;
102
+ color: #4ade80;
103
+ font-size: 12px;
104
+ font-weight: 600;
105
+ animation: counterIncrement 800ms cubic-bezier(0.4, 0.0, 0.2, 1);
106
+ pointer-events: none;
107
+ }
108
+
109
+ /* ==========================================
110
+ TAB TRANSITION ANIMATIONS
111
+ ========================================== */
112
+
113
+ /* Crossfade with scale */
114
+ @keyframes tabPanelEnter {
115
+ from {
116
+ opacity: 0;
117
+ transform: scale(0.97) translateY(10px);
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ transform: scale(1) translateY(0);
122
+ }
123
+ }
124
+
125
+ @keyframes tabPanelExit {
126
+ from {
127
+ opacity: 1;
128
+ transform: scale(1);
129
+ }
130
+ to {
131
+ opacity: 0;
132
+ transform: scale(0.98);
133
+ }
134
+ }
135
+
136
+ .tab-panel-enter {
137
+ animation: tabPanelEnter 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
138
+ }
139
+
140
+ .tab-panel-exit {
141
+ animation: tabPanelExit 200ms cubic-bezier(0.4, 0.0, 1, 1);
142
+ pointer-events: none;
143
+ }
144
+
145
+ /* Tab button active state */
146
+ .tab-button-active {
147
+ position: relative;
148
+ }
149
+
150
+ .tab-button-active::after {
151
+ content: '';
152
+ position: absolute;
153
+ bottom: -2px;
154
+ left: 0;
155
+ right: 0;
156
+ height: 3px;
157
+ background: linear-gradient(90deg, #f97316, #fb923c);
158
+ border-radius: 3px 3px 0 0;
159
+ animation: tabUnderlineGrow 300ms cubic-bezier(0.4, 0.0, 0.2, 1);
160
+ }
161
+
162
+ @keyframes tabUnderlineGrow {
163
+ from {
164
+ transform: scaleX(0);
165
+ opacity: 0;
166
+ }
167
+ to {
168
+ transform: scaleX(1);
169
+ opacity: 1;
170
+ }
171
+ }
172
+
173
+ /* ==========================================
174
+ ENHANCED CARD HOVER EFFECTS
175
+ ========================================== */
176
+
177
+ /* Card with glow border on hover */
178
+ .card-glow {
179
+ position: relative;
180
+ transition: all 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
181
+ }
182
+
183
+ .card-glow::before {
184
+ content: '';
185
+ position: absolute;
186
+ inset: -1px;
187
+ background: linear-gradient(135deg, rgba(249, 115, 22, 0.3), transparent 50%, rgba(249, 115, 22, 0.1));
188
+ border-radius: 17px;
189
+ opacity: 0;
190
+ transition: opacity 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
191
+ z-index: -1;
192
+ filter: blur(8px);
193
+ }
194
+
195
+ .card-glow:hover {
196
+ transform: translateY(-4px);
197
+ box-shadow:
198
+ 0 12px 48px rgba(0, 0, 0, 0.4),
199
+ 0 0 0 1px rgba(249, 115, 22, 0.3);
200
+ }
201
+
202
+ .card-glow:hover::before {
203
+ opacity: 1;
204
+ }
205
+
206
+ /* Stat card with top accent line */
207
+ .stat-card-enhanced {
208
+ position: relative;
209
+ overflow: hidden;
210
+ }
211
+
212
+ .stat-card-enhanced::after {
213
+ content: '';
214
+ position: absolute;
215
+ top: 0;
216
+ left: 0;
217
+ right: 0;
218
+ height: 3px;
219
+ background: linear-gradient(90deg, transparent, rgba(249, 115, 22, 0.6), transparent);
220
+ opacity: 0;
221
+ transition: opacity 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
222
+ }
223
+
224
+ .stat-card-enhanced:hover::after {
225
+ opacity: 1;
226
+ }
227
+
228
+ /* ==========================================
229
+ TOAST NOTIFICATION ANIMATIONS
230
+ ========================================== */
231
+
232
+ /* Enhanced toast entry with bounce */
233
+ @keyframes toastSlideInRight {
234
+ from {
235
+ opacity: 0;
236
+ transform: translateX(100%) scale(0.95);
237
+ }
238
+ 60% {
239
+ opacity: 1;
240
+ transform: translateX(-8px) scale(1);
241
+ }
242
+ to {
243
+ transform: translateX(0);
244
+ }
245
+ }
246
+
247
+ @keyframes toastSlideOutRight {
248
+ from {
249
+ opacity: 1;
250
+ transform: translateX(0);
251
+ }
252
+ to {
253
+ opacity: 0;
254
+ transform: translateX(100%) scale(0.95);
255
+ }
256
+ }
257
+
258
+ .toast-enter {
259
+ animation: toastSlideInRight 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
260
+ }
261
+
262
+ .toast-exit {
263
+ animation: toastSlideOutRight 300ms cubic-bezier(0.4, 0.0, 1, 1);
264
+ }
265
+
266
+ /* Toast stack reordering */
267
+ .toast-item {
268
+ transition: all 300ms cubic-bezier(0.4, 0.0, 0.2, 1);
269
+ }
270
+
271
+ /* Success toast pulse */
272
+ @keyframes toastSuccessPulse {
273
+ 0%, 100% {
274
+ box-shadow: 0 4px 12px rgba(34, 197, 94, 0.2);
275
+ }
276
+ 50% {
277
+ box-shadow: 0 4px 20px rgba(34, 197, 94, 0.4);
278
+ }
279
+ }
280
+
281
+ .toast-success {
282
+ animation: toastSuccessPulse 1.5s ease-in-out 2;
283
+ }
284
+
285
+ /* ==========================================
286
+ AGENT STATUS TRANSITION ANIMATIONS
287
+ ========================================== */
288
+
289
+ /* Status indicator base */
290
+ .agent-status-indicator {
291
+ width: 12px;
292
+ height: 12px;
293
+ border-radius: 50%;
294
+ position: relative;
295
+ transition: all 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
296
+ }
297
+
298
+ /* Idle → Active transition */
299
+ @keyframes statusActivate {
300
+ 0% {
301
+ background: rgba(156, 163, 175, 0.5);
302
+ box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.4);
303
+ }
304
+ 50% {
305
+ transform: scale(1.4);
306
+ box-shadow: 0 0 20px 4px rgba(34, 197, 94, 0.6);
307
+ }
308
+ 100% {
309
+ background: rgba(34, 197, 94, 1);
310
+ transform: scale(1);
311
+ box-shadow: 0 0 12px 2px rgba(34, 197, 94, 0.4);
312
+ }
313
+ }
314
+
315
+ .agent-status-indicator.active {
316
+ animation: statusActivate 600ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
317
+ background: rgba(34, 197, 94, 1);
318
+ box-shadow: 0 0 12px 2px rgba(34, 197, 94, 0.4);
319
+ }
320
+
321
+ /* Active → Completed transition */
322
+ @keyframes statusComplete {
323
+ 0% {
324
+ background: rgba(34, 197, 94, 1);
325
+ }
326
+ 20% {
327
+ transform: scale(1.2);
328
+ }
329
+ 40% {
330
+ transform: scale(0.8);
331
+ }
332
+ 60% {
333
+ transform: scale(1.1);
334
+ }
335
+ 100% {
336
+ background: rgba(74, 222, 128, 1);
337
+ transform: scale(1);
338
+ box-shadow: 0 0 16px 3px rgba(74, 222, 128, 0.6);
339
+ }
340
+ }
341
+
342
+ .agent-status-indicator.completed {
343
+ animation: statusComplete 800ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
344
+ background: rgba(74, 222, 128, 1);
345
+ box-shadow: 0 0 16px 3px rgba(74, 222, 128, 0.6);
346
+ }
347
+
348
+ /* Idle state (gray) */
349
+ .agent-status-indicator.idle {
350
+ background: rgba(156, 163, 175, 0.5);
351
+ box-shadow: 0 0 6px 1px rgba(156, 163, 175, 0.3);
352
+ }
353
+
354
+ /* Error state */
355
+ @keyframes statusError {
356
+ 0%, 100% {
357
+ background: rgba(239, 68, 68, 1);
358
+ }
359
+ 50% {
360
+ transform: scale(1.2);
361
+ background: rgba(248, 113, 113, 1);
362
+ }
363
+ }
364
+
365
+ .agent-status-indicator.error {
366
+ animation: statusError 600ms cubic-bezier(0.4, 0.0, 0.2, 1) 3;
367
+ background: rgba(239, 68, 68, 1);
368
+ box-shadow: 0 0 12px 2px rgba(239, 68, 68, 0.5);
369
+ }
370
+
371
+ /* ==========================================
372
+ TASK COMPLETION CELEBRATION
373
+ ========================================== */
374
+
375
+ /* Main celebration animation */
376
+ @keyframes taskCelebrate {
377
+ 0% {
378
+ transform: scale(1);
379
+ filter: brightness(1);
380
+ }
381
+ 25% {
382
+ transform: scale(1.15) rotate(5deg);
383
+ filter: brightness(1.3);
384
+ }
385
+ 50% {
386
+ transform: scale(1.08) rotate(-3deg);
387
+ filter: brightness(1.2);
388
+ }
389
+ 75% {
390
+ transform: scale(1.12) rotate(2deg);
391
+ filter: brightness(1.15);
392
+ }
393
+ 100% {
394
+ transform: scale(1);
395
+ filter: brightness(1);
396
+ }
397
+ }
398
+
399
+ /* Particle burst effect */
400
+ @keyframes particleBurst {
401
+ 0% {
402
+ opacity: 1;
403
+ transform: translate(0, 0) scale(0);
404
+ }
405
+ 50% {
406
+ opacity: 1;
407
+ }
408
+ 100% {
409
+ opacity: 0;
410
+ transform: translate(var(--tx), var(--ty)) scale(1);
411
+ }
412
+ }
413
+
414
+ .task-completed-celebration {
415
+ animation: taskCelebrate 800ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
416
+ position: relative;
417
+ }
418
+
419
+ /* Celebration particles */
420
+ .task-completed-celebration::before,
421
+ .task-completed-celebration::after {
422
+ content: '✨';
423
+ position: absolute;
424
+ font-size: 20px;
425
+ opacity: 0;
426
+ pointer-events: none;
427
+ }
428
+
429
+ .task-completed-celebration::before {
430
+ animation: particleBurst 1s ease-out;
431
+ --tx: -40px;
432
+ --ty: -40px;
433
+ left: 50%;
434
+ top: 50%;
435
+ }
436
+
437
+ .task-completed-celebration::after {
438
+ animation: particleBurst 1s ease-out;
439
+ animation-delay: 0.1s;
440
+ --tx: 40px;
441
+ --ty: -40px;
442
+ left: 50%;
443
+ top: 50%;
444
+ }
445
+
446
+ /* Success checkmark pop */
447
+ @keyframes checkmarkPop {
448
+ 0% {
449
+ transform: scale(0) rotate(-180deg);
450
+ opacity: 0;
451
+ }
452
+ 60% {
453
+ transform: scale(1.2) rotate(10deg);
454
+ opacity: 1;
455
+ }
456
+ 100% {
457
+ transform: scale(1) rotate(0deg);
458
+ }
459
+ }
460
+
461
+ .checkmark-celebration {
462
+ animation: checkmarkPop 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
463
+ }
464
+
465
+ /* ==========================================
466
+ PROGRESS BAR ANIMATIONS
467
+ ========================================== */
468
+
469
+ /* Progress bar fill with easing */
470
+ @keyframes progressBarFill {
471
+ from {
472
+ transform: scaleX(0);
473
+ transform-origin: left;
474
+ }
475
+ to {
476
+ transform: scaleX(1);
477
+ transform-origin: left;
478
+ }
479
+ }
480
+
481
+ .progress-bar-fill {
482
+ animation: progressBarFill 1000ms cubic-bezier(0.4, 0.0, 0.2, 1);
483
+ transition: width 600ms cubic-bezier(0.4, 0.0, 0.2, 1);
484
+ transform-origin: left;
485
+ }
486
+
487
+ /* Stagger multiple progress bars */
488
+ .progress-bar-item:nth-child(1) .progress-bar-fill { animation-delay: 0ms; }
489
+ .progress-bar-item:nth-child(2) .progress-bar-fill { animation-delay: 100ms; }
490
+ .progress-bar-item:nth-child(3) .progress-bar-fill { animation-delay: 200ms; }
491
+ .progress-bar-item:nth-child(4) .progress-bar-fill { animation-delay: 300ms; }
492
+ .progress-bar-item:nth-child(5) .progress-bar-fill { animation-delay: 400ms; }
493
+ .progress-bar-item:nth-child(6) .progress-bar-fill { animation-delay: 500ms; }
494
+
495
+ /* Indeterminate progress bar */
496
+ @keyframes progressIndeterminate {
497
+ 0% {
498
+ transform: translateX(-100%);
499
+ }
500
+ 100% {
501
+ transform: translateX(400%);
502
+ }
503
+ }
504
+
505
+ .progress-indeterminate::after {
506
+ content: '';
507
+ position: absolute;
508
+ top: 0;
509
+ left: 0;
510
+ width: 25%;
511
+ height: 100%;
512
+ background: linear-gradient(90deg, transparent, rgba(249, 115, 22, 0.6), transparent);
513
+ animation: progressIndeterminate 1.5s ease-in-out infinite;
514
+ }
515
+
516
+ /* Circular progress (donut chart) */
517
+ @keyframes circleProgress {
518
+ from {
519
+ stroke-dashoffset: var(--circumference);
520
+ }
521
+ to {
522
+ stroke-dashoffset: calc(var(--circumference) - (var(--circumference) * var(--progress) / 100));
523
+ }
524
+ }
525
+
526
+ .circle-progress {
527
+ stroke-dasharray: var(--circumference);
528
+ stroke-dashoffset: var(--circumference);
529
+ animation: circleProgress 1200ms cubic-bezier(0.4, 0.0, 0.2, 1) forwards;
530
+ transform-origin: center;
531
+ transform: rotate(-90deg);
532
+ transition: stroke-dashoffset 600ms cubic-bezier(0.4, 0.0, 0.2, 1);
533
+ }
534
+
535
+ /* ==========================================
536
+ LIST ITEM STAGGERED ANIMATIONS
537
+ ========================================== */
538
+
539
+ /* Enhanced slide-in with stagger */
540
+ @keyframes listItemSlideIn {
541
+ from {
542
+ opacity: 0;
543
+ transform: translateX(40px);
544
+ }
545
+ to {
546
+ opacity: 1;
547
+ transform: translateX(0);
548
+ }
549
+ }
550
+
551
+ .activity-item,
552
+ .task-item {
553
+ animation: listItemSlideIn 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
554
+ animation-fill-mode: both;
555
+ }
556
+
557
+ /* Extended stagger for longer lists */
558
+ .activity-item:nth-child(1),
559
+ .task-item:nth-child(1) { animation-delay: 0ms; }
560
+ .activity-item:nth-child(2),
561
+ .task-item:nth-child(2) { animation-delay: 60ms; }
562
+ .activity-item:nth-child(3),
563
+ .task-item:nth-child(3) { animation-delay: 120ms; }
564
+ .activity-item:nth-child(4),
565
+ .task-item:nth-child(4) { animation-delay: 180ms; }
566
+ .activity-item:nth-child(5),
567
+ .task-item:nth-child(5) { animation-delay: 240ms; }
568
+ .activity-item:nth-child(6),
569
+ .task-item:nth-child(6) { animation-delay: 300ms; }
570
+ .activity-item:nth-child(7),
571
+ .task-item:nth-child(7) { animation-delay: 360ms; }
572
+ .activity-item:nth-child(8),
573
+ .task-item:nth-child(8) { animation-delay: 420ms; }
574
+ .activity-item:nth-child(9),
575
+ .task-item:nth-child(9) { animation-delay: 480ms; }
576
+ .activity-item:nth-child(10),
577
+ .task-item:nth-child(10) { animation-delay: 540ms; }
578
+
579
+ /* New item highlight at top of list */
580
+ @keyframes newItemHighlight {
581
+ 0% {
582
+ background: rgba(249, 115, 22, 0.3);
583
+ transform: scale(1.02);
584
+ }
585
+ 100% {
586
+ background: transparent;
587
+ transform: scale(1);
588
+ }
589
+ }
590
+
591
+ .new-item-highlight {
592
+ animation: newItemHighlight 1000ms cubic-bezier(0.4, 0.0, 0.2, 1);
593
+ }
594
+
595
+ /* ==========================================
596
+ MODAL/DIALOG ANIMATIONS
597
+ ========================================== */
598
+
599
+ /* Backdrop fade with blur */
600
+ @keyframes backdropFadeIn {
601
+ from {
602
+ opacity: 0;
603
+ backdrop-filter: blur(0px);
604
+ }
605
+ to {
606
+ opacity: 1;
607
+ backdrop-filter: blur(8px);
608
+ }
609
+ }
610
+
611
+ @keyframes backdropFadeOut {
612
+ from {
613
+ opacity: 1;
614
+ backdrop-filter: blur(8px);
615
+ }
616
+ to {
617
+ opacity: 0;
618
+ backdrop-filter: blur(0px);
619
+ }
620
+ }
621
+
622
+ .modal-backdrop-enter {
623
+ animation: backdropFadeIn 300ms cubic-bezier(0.4, 0.0, 0.2, 1);
624
+ }
625
+
626
+ .modal-backdrop-exit {
627
+ animation: backdropFadeOut 200ms cubic-bezier(0.4, 0.0, 1, 1);
628
+ }
629
+
630
+ /* Modal content entrance with bounce */
631
+ @keyframes modalContentEnter {
632
+ from {
633
+ opacity: 0;
634
+ transform: scale(0.92) translateY(-30px);
635
+ }
636
+ 60% {
637
+ opacity: 1;
638
+ transform: scale(1.02) translateY(0);
639
+ }
640
+ to {
641
+ transform: scale(1) translateY(0);
642
+ }
643
+ }
644
+
645
+ @keyframes modalContentExit {
646
+ from {
647
+ opacity: 1;
648
+ transform: scale(1) translateY(0);
649
+ }
650
+ to {
651
+ opacity: 0;
652
+ transform: scale(0.92) translateY(-30px);
653
+ }
654
+ }
655
+
656
+ .modal-content-enter {
657
+ animation: modalContentEnter 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
658
+ }
659
+
660
+ .modal-content-exit {
661
+ animation: modalContentExit 200ms cubic-bezier(0.4, 0.0, 1, 1);
662
+ }
663
+
664
+ /* ==========================================
665
+ BUTTON PRESS ANIMATIONS
666
+ ========================================== */
667
+
668
+ /* Enhanced button with ripple effect */
669
+ .button-press {
670
+ position: relative;
671
+ overflow: hidden;
672
+ transition: all 200ms cubic-bezier(0.4, 0.0, 0.2, 1);
673
+ }
674
+
675
+ .button-press:hover {
676
+ transform: translateY(-2px);
677
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
678
+ }
679
+
680
+ .button-press:active {
681
+ transform: translateY(0) scale(0.98);
682
+ transition: all 100ms cubic-bezier(0.4, 0.0, 1, 1);
683
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
684
+ }
685
+
686
+ /* Ripple effect on click */
687
+ @keyframes rippleEffect {
688
+ from {
689
+ transform: translate(-50%, -50%) scale(0);
690
+ opacity: 1;
691
+ }
692
+ to {
693
+ transform: translate(-50%, -50%) scale(4);
694
+ opacity: 0;
695
+ }
696
+ }
697
+
698
+ .button-ripple {
699
+ position: relative;
700
+ overflow: hidden;
701
+ }
702
+
703
+ .button-ripple::after {
704
+ content: '';
705
+ position: absolute;
706
+ top: var(--ripple-y, 50%);
707
+ left: var(--ripple-x, 50%);
708
+ width: 20px;
709
+ height: 20px;
710
+ border-radius: 50%;
711
+ background: rgba(255, 255, 255, 0.5);
712
+ transform: translate(-50%, -50%) scale(0);
713
+ pointer-events: none;
714
+ }
715
+
716
+ .button-ripple:active::after {
717
+ animation: rippleEffect 600ms cubic-bezier(0.4, 0.0, 0.2, 1);
718
+ }
719
+
720
+ /* ==========================================
721
+ ENHANCED BADGE ANIMATIONS
722
+ ========================================== */
723
+
724
+ /* Badge entrance with pop */
725
+ @keyframes badgePopEnhanced {
726
+ 0% {
727
+ opacity: 0;
728
+ transform: scale(0.5) rotate(-10deg);
729
+ }
730
+ 60% {
731
+ opacity: 1;
732
+ transform: scale(1.1) rotate(5deg);
733
+ }
734
+ 100% {
735
+ transform: scale(1) rotate(0deg);
736
+ }
737
+ }
738
+
739
+ .badge-pop {
740
+ animation: badgePopEnhanced 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
741
+ }
742
+
743
+ /* Badge state change highlight */
744
+ @keyframes badgeStateChange {
745
+ 0% {
746
+ transform: scale(1);
747
+ }
748
+ 50% {
749
+ transform: scale(1.2);
750
+ filter: brightness(1.3);
751
+ }
752
+ 100% {
753
+ transform: scale(1);
754
+ }
755
+ }
756
+
757
+ .badge-state-change {
758
+ animation: badgeStateChange 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
759
+ }
760
+
761
+ /* ==========================================
762
+ ICON HOVER ANIMATIONS
763
+ ========================================== */
764
+
765
+ /* Icon bounce on hover */
766
+ @keyframes iconBounce {
767
+ 0%, 100% {
768
+ transform: translateY(0);
769
+ }
770
+ 50% {
771
+ transform: translateY(-4px);
772
+ }
773
+ }
774
+
775
+ .icon-hover-bounce:hover {
776
+ animation: iconBounce 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
777
+ }
778
+
779
+ /* Icon rotate on hover */
780
+ .icon-hover-rotate {
781
+ transition: transform 300ms cubic-bezier(0.4, 0.0, 0.2, 1);
782
+ }
783
+
784
+ .icon-hover-rotate:hover {
785
+ transform: rotate(15deg) scale(1.1);
786
+ }
787
+
788
+ /* Icon pulse on hover */
789
+ @keyframes iconPulse {
790
+ 0%, 100% {
791
+ transform: scale(1);
792
+ }
793
+ 50% {
794
+ transform: scale(1.2);
795
+ }
796
+ }
797
+
798
+ .icon-hover-pulse:hover {
799
+ animation: iconPulse 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
800
+ }
801
+
802
+ /* ==========================================
803
+ ACCESSIBILITY - REDUCED MOTION
804
+ ========================================== */
805
+
806
+ @media (prefers-reduced-motion: reduce) {
807
+ /* Disable all animations for users who prefer reduced motion */
808
+ *,
809
+ *::before,
810
+ *::after {
811
+ animation-duration: 0.01ms !important;
812
+ animation-iteration-count: 1 !important;
813
+ transition-duration: 0.01ms !important;
814
+ scroll-behavior: auto !important;
815
+ }
816
+
817
+ /* Keep functional state changes but instant */
818
+ .skeleton-animated,
819
+ .loading-spinner,
820
+ .agent-status-indicator,
821
+ .progress-bar-fill,
822
+ .circle-progress {
823
+ animation: none !important;
824
+ }
825
+
826
+ /* Maintain layout transitions but instant */
827
+ .button-press:hover,
828
+ .card-glow:hover,
829
+ .tab-panel-enter,
830
+ .modal-content-enter {
831
+ animation: none !important;
832
+ transition-duration: 0ms !important;
833
+ }
834
+ }
835
+
836
+ /* ==========================================
837
+ PERFORMANCE OPTIMIZATION HELPERS
838
+ ========================================== */
839
+
840
+ /* will-change for elements actively animating */
841
+ .will-change-transform {
842
+ will-change: transform;
843
+ }
844
+
845
+ .will-change-opacity {
846
+ will-change: opacity;
847
+ }
848
+
849
+ .will-change-transform-opacity {
850
+ will-change: transform, opacity;
851
+ }
852
+
853
+ /* Remove will-change after animation */
854
+ .animation-complete {
855
+ will-change: auto;
856
+ }
857
+
858
+ /* GPU acceleration hint */
859
+ .gpu-accelerated {
860
+ transform: translateZ(0);
861
+ backface-visibility: hidden;
862
+ perspective: 1000px;
863
+ }
864
+
865
+ /* ==========================================
866
+ UTILITY CLASSES
867
+ ========================================== */
868
+
869
+ /* Fade-in utility */
870
+ .fade-in {
871
+ animation: fadeIn 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
872
+ }
873
+
874
+ @keyframes fadeIn {
875
+ from {
876
+ opacity: 0;
877
+ }
878
+ to {
879
+ opacity: 1;
880
+ }
881
+ }
882
+
883
+ /* Slide-up utility */
884
+ .slide-up {
885
+ animation: slideUp 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
886
+ }
887
+
888
+ @keyframes slideUp {
889
+ from {
890
+ opacity: 0;
891
+ transform: translateY(20px);
892
+ }
893
+ to {
894
+ opacity: 1;
895
+ transform: translateY(0);
896
+ }
897
+ }
898
+
899
+ /* Scale-in utility */
900
+ .scale-in {
901
+ animation: scaleIn 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
902
+ }
903
+
904
+ @keyframes scaleIn {
905
+ from {
906
+ opacity: 0;
907
+ transform: scale(0.9);
908
+ }
909
+ to {
910
+ opacity: 1;
911
+ transform: scale(1);
912
+ }
913
+ }
914
+
915
+ /* Rotate-in utility */
916
+ .rotate-in {
917
+ animation: rotateIn 600ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
918
+ }
919
+
920
+ @keyframes rotateIn {
921
+ from {
922
+ opacity: 0;
923
+ transform: rotate(-180deg) scale(0.5);
924
+ }
925
+ to {
926
+ opacity: 1;
927
+ transform: rotate(0deg) scale(1);
928
+ }
929
+ }