@jaak.ai/stamps 2.0.0-beta.3 → 2.0.0-beta.4

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 (72) hide show
  1. package/README.md +216 -215
  2. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
  3. package/dist/cjs/jaak-stamps.cjs.entry.js +1786 -1052
  4. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  5. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/collection/components/my-component/my-component.css +440 -110
  8. package/dist/collection/components/my-component/my-component.js +829 -1120
  9. package/dist/collection/components/my-component/my-component.js.map +1 -1
  10. package/dist/collection/services/CameraService.js +453 -0
  11. package/dist/collection/services/CameraService.js.map +1 -0
  12. package/dist/collection/services/DetectionService.js +369 -0
  13. package/dist/collection/services/DetectionService.js.map +1 -0
  14. package/dist/collection/services/EventBusService.js +42 -0
  15. package/dist/collection/services/EventBusService.js.map +1 -0
  16. package/dist/collection/services/LoggerService.js +40 -0
  17. package/dist/collection/services/LoggerService.js.map +1 -0
  18. package/dist/collection/services/ServiceContainer.js +66 -0
  19. package/dist/collection/services/ServiceContainer.js.map +1 -0
  20. package/dist/collection/services/StateManagerService.js +109 -0
  21. package/dist/collection/services/StateManagerService.js.map +1 -0
  22. package/dist/collection/services/factories/DeviceStrategyFactory.js +16 -0
  23. package/dist/collection/services/factories/DeviceStrategyFactory.js.map +1 -0
  24. package/dist/collection/services/interfaces/ICameraService.js +2 -0
  25. package/dist/collection/services/interfaces/ICameraService.js.map +1 -0
  26. package/dist/collection/services/interfaces/IDetectionService.js +2 -0
  27. package/dist/collection/services/interfaces/IDetectionService.js.map +1 -0
  28. package/dist/collection/services/interfaces/IEventBus.js +2 -0
  29. package/dist/collection/services/interfaces/IEventBus.js.map +1 -0
  30. package/dist/collection/services/interfaces/ILogger.js +2 -0
  31. package/dist/collection/services/interfaces/ILogger.js.map +1 -0
  32. package/dist/collection/services/interfaces/IStateManager.js +2 -0
  33. package/dist/collection/services/interfaces/IStateManager.js.map +1 -0
  34. package/dist/collection/services/strategies/HighPerformanceDeviceStrategy.js +30 -0
  35. package/dist/collection/services/strategies/HighPerformanceDeviceStrategy.js.map +1 -0
  36. package/dist/collection/services/strategies/IDeviceStrategy.js +2 -0
  37. package/dist/collection/services/strategies/IDeviceStrategy.js.map +1 -0
  38. package/dist/collection/services/strategies/LowMemoryDeviceStrategy.js +30 -0
  39. package/dist/collection/services/strategies/LowMemoryDeviceStrategy.js.map +1 -0
  40. package/dist/collection/types/component-types.js +2 -0
  41. package/dist/collection/types/component-types.js.map +1 -0
  42. package/dist/components/jaak-stamps.js +1802 -1076
  43. package/dist/components/jaak-stamps.js.map +1 -1
  44. package/dist/esm/jaak-stamps-webcomponent.js +1 -1
  45. package/dist/esm/jaak-stamps.entry.js +1786 -1052
  46. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  47. package/dist/esm/loader.js +1 -1
  48. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  49. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  50. package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js +2 -0
  51. package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js.map +1 -0
  52. package/dist/types/components/my-component/my-component.d.ts +83 -108
  53. package/dist/types/components.d.ts +23 -9
  54. package/dist/types/services/CameraService.d.ts +46 -0
  55. package/dist/types/services/DetectionService.d.ts +35 -0
  56. package/dist/types/services/EventBusService.d.ts +9 -0
  57. package/dist/types/services/LoggerService.d.ts +12 -0
  58. package/dist/types/services/ServiceContainer.d.ts +27 -0
  59. package/dist/types/services/StateManagerService.d.ts +15 -0
  60. package/dist/types/services/factories/DeviceStrategyFactory.d.ts +4 -0
  61. package/dist/types/services/interfaces/ICameraService.d.ts +34 -0
  62. package/dist/types/services/interfaces/IDetectionService.d.ts +31 -0
  63. package/dist/types/services/interfaces/IEventBus.d.ts +16 -0
  64. package/dist/types/services/interfaces/ILogger.d.ts +8 -0
  65. package/dist/types/services/interfaces/IStateManager.d.ts +35 -0
  66. package/dist/types/services/strategies/HighPerformanceDeviceStrategy.d.ts +6 -0
  67. package/dist/types/services/strategies/IDeviceStrategy.d.ts +21 -0
  68. package/dist/types/services/strategies/LowMemoryDeviceStrategy.d.ts +6 -0
  69. package/dist/types/types/component-types.d.ts +36 -0
  70. package/package.json +3 -3
  71. package/dist/jaak-stamps-webcomponent/p-14eb13d8.entry.js +0 -2
  72. package/dist/jaak-stamps-webcomponent/p-14eb13d8.entry.js.map +0 -1
@@ -31,25 +31,31 @@ h1 {
31
31
  overflow: hidden;
32
32
  }
33
33
 
34
- video, canvas {
34
+ video, .detection-overlay {
35
35
  position: absolute;
36
36
  width: 100%;
37
37
  height: 100%;
38
38
  border-radius: 8px;
39
39
  }
40
40
 
41
- video.mirror, canvas.mirror {
41
+ video.mirror, .detection-overlay.mirror {
42
42
  transform: rotateY(180deg);
43
43
  }
44
44
 
45
- canvas {
45
+ .detection-overlay {
46
46
  z-index: 1;
47
+ pointer-events: none;
47
48
  }
48
49
 
49
50
  video {
50
51
  z-index: 0;
51
52
  }
52
53
 
54
+ /* Detection boxes for debug mode */
55
+ .detection-box {
56
+ transition: opacity 0.2s ease;
57
+ }
58
+
53
59
 
54
60
  .status {
55
61
  margin-top: 16px;
@@ -79,12 +85,10 @@ video {
79
85
  border: none;
80
86
  border-radius: 4px;
81
87
  background: transparent;
82
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
83
88
  opacity: 0.8;
84
89
  }
85
90
 
86
91
  .card-outline.perfect-match {
87
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
88
92
  }
89
93
 
90
94
  /* Lados individuales de la máscara */
@@ -92,79 +96,74 @@ video {
92
96
  position: absolute;
93
97
  background: #999;
94
98
  transition: background-color 0.3s ease;
99
+ border-radius: 1px;
100
+ }
101
+
102
+ .side-top.aligned {
103
+ border-left-color: #28a745;
104
+ border-top-color: #28a745;
105
+ }
106
+
107
+ .side-right.aligned {
108
+ border-right-color: #28a745;
109
+ border-top-color: #28a745;
110
+ }
111
+
112
+ .side-bottom.aligned {
113
+ border-left-color: #28a745;
114
+ border-bottom-color: #28a745;
95
115
  }
96
116
 
97
- .side.aligned {
98
- background: #28a745;
117
+ .side-left.aligned {
118
+ border-right-color: #28a745;
119
+ border-bottom-color: #28a745;
99
120
  }
100
121
 
101
122
  .side-top {
102
- top: 0;
103
- left: 0;
104
- width: 100%;
105
- height: 3px;
123
+ top: -3px;
124
+ left: -3px;
125
+ width: 30px;
126
+ height: 30px;
127
+ border-left: 6px solid #ffffff;
128
+ border-top: 6px solid #ffffff;
129
+ background: transparent;
106
130
  }
107
131
 
108
132
  .side-right {
109
- top: 0;
110
- right: 0;
111
- width: 3px;
112
- height: 100%;
133
+ top: -3px;
134
+ right: -3px;
135
+ width: 30px;
136
+ height: 30px;
137
+ border-right: 6px solid #ffffff;
138
+ border-top: 6px solid #ffffff;
139
+ background: transparent;
113
140
  }
114
141
 
115
142
  .side-bottom {
116
- bottom: 0;
117
- left: 0;
118
- width: 100%;
119
- height: 3px;
143
+ bottom: -3px;
144
+ left: -3px;
145
+ width: 30px;
146
+ height: 30px;
147
+ border-left: 6px solid #ffffff;
148
+ border-bottom: 6px solid #ffffff;
149
+ background: transparent;
120
150
  }
121
151
 
122
152
  .side-left {
123
- top: 0;
124
- left: 0;
125
- width: 3px;
126
- height: 100%;
153
+ bottom: -3px;
154
+ right: -3px;
155
+ width: 30px;
156
+ height: 30px;
157
+ border-right: 6px solid #ffffff;
158
+ border-bottom: 6px solid #ffffff;
159
+ background: transparent;
127
160
  }
128
161
 
129
- .corner {
130
- position: absolute;
131
- width: 20px;
132
- height: 20px;
133
- border: 2px solid #999;
134
- z-index: 12;
135
- }
136
162
 
137
- .corner-tl {
138
- top: -10px;
139
- left: -10px;
140
- border-right: none;
141
- border-bottom: none;
142
- }
143
163
 
144
- .corner-tr {
145
- top: -10px;
146
- right: -10px;
147
- border-left: none;
148
- border-bottom: none;
149
- }
150
164
 
151
- .corner-bl {
152
- bottom: -10px;
153
- left: -10px;
154
- border-right: none;
155
- border-top: none;
156
- }
157
165
 
158
- .corner-br {
159
- bottom: -10px;
160
- right: -10px;
161
- border-left: none;
162
- border-top: none;
163
- }
164
166
 
165
- .corner.perfect-match {
166
- border-color: #28a745;
167
- }
168
167
 
169
168
  .guide-text {
170
169
  position: absolute;
@@ -183,6 +182,72 @@ video {
183
182
  z-index: 20;
184
183
  }
185
184
 
185
+ /* Quality indicator */
186
+ .quality-indicator {
187
+ position: absolute;
188
+ top: 20px;
189
+ right: 20px;
190
+ display: flex;
191
+ align-items: center;
192
+ gap: 8px;
193
+ background: rgba(0, 0, 0, 0.8);
194
+ padding: 8px 12px;
195
+ border-radius: 20px;
196
+ z-index: 25;
197
+ transition: all 0.3s ease;
198
+ }
199
+
200
+ .quality-indicator.warning {
201
+ background: rgba(255, 152, 0, 0.9);
202
+ }
203
+
204
+ .quality-indicator.good {
205
+ background: rgba(76, 175, 80, 0.9);
206
+ }
207
+
208
+ .quality-score {
209
+ color: #fff;
210
+ font-size: 12px;
211
+ font-weight: 600;
212
+ min-width: 30px;
213
+ text-align: center;
214
+ }
215
+
216
+ .quality-status {
217
+ width: 20px;
218
+ height: 20px;
219
+ border-radius: 50%;
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: center;
223
+ font-size: 14px;
224
+ font-weight: bold;
225
+ color: #fff;
226
+ transition: all 0.3s ease;
227
+ }
228
+
229
+ .quality-status.ready {
230
+ background: #4CAF50;
231
+ }
232
+
233
+ .quality-status.not-ready {
234
+ background: #f44336;
235
+ }
236
+
237
+ /* Enhanced card outline for quality warnings */
238
+ .card-outline.quality-warning {
239
+ animation: qualityWarning 1s ease-in-out infinite alternate;
240
+ }
241
+
242
+ @keyframes qualityWarning {
243
+ 0% {
244
+ box-shadow: 0 0 0 3px rgba(255, 152, 0, 0.6);
245
+ }
246
+ 100% {
247
+ box-shadow: 0 0 0 6px rgba(255, 152, 0, 0.3);
248
+ }
249
+ }
250
+
186
251
 
187
252
  /* Animación de captura */
188
253
  .capture-animation {
@@ -227,15 +292,15 @@ video {
227
292
  @keyframes pulseGreen {
228
293
  0% {
229
294
  border-color: #28a745;
230
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7), 0 0 0 4px rgba(40, 167, 69, 0);
295
+ box-shadow: 0 0 0 4px rgba(40, 167, 69, 0);
231
296
  }
232
297
  50% {
233
298
  border-color: #28a745;
234
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7), 0 0 0 8px rgba(40, 167, 69, 0.6);
299
+ box-shadow: 0 0 0 8px rgba(40, 167, 69, 0.6);
235
300
  }
236
301
  100% {
237
302
  border-color: #28a745;
238
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7), 0 0 0 4px rgba(40, 167, 69, 0);
303
+ box-shadow: 0 0 0 4px rgba(40, 167, 69, 0);
239
304
  }
240
305
  }
241
306
 
@@ -481,32 +546,13 @@ video {
481
546
  pointer-events: auto;
482
547
  }
483
548
 
484
- .flip-camera-button {
485
- height: 40px;
486
- padding: 0 16px;
487
- border: none;
488
- border-radius: 8px;
489
- background: rgba(0, 0, 0, 0.6);
490
- backdrop-filter: blur(12px);
491
- color: #ffffff;
492
- font-size: 12px;
493
- font-weight: 500;
494
- cursor: pointer;
495
- transition: all 0.2s ease;
496
- display: flex;
497
- align-items: center;
498
- justify-content: center;
499
- border: 1px solid rgba(255, 255, 255, 0.1);
500
- white-space: nowrap;
501
- min-width: fit-content;
502
- }
503
549
 
504
550
  .camera-selector-button {
505
- height: 40px;
506
- padding: 0 16px;
551
+ height: 32px;
552
+ padding: 0 10px;
507
553
  border: none;
508
554
  border-radius: 8px;
509
- background: rgba(0, 0, 0, 0.6);
555
+ background: rgba(0, 0, 0, 0.25);
510
556
  backdrop-filter: blur(12px);
511
557
  color: #ffffff;
512
558
  font-size: 12px;
@@ -521,26 +567,52 @@ video {
521
567
  min-width: fit-content;
522
568
  }
523
569
 
524
- .flip-camera-button:hover,
525
570
  .camera-selector-button:hover {
526
571
  background: rgba(0, 0, 0, 0.8);
527
572
  border-color: rgba(255, 255, 255, 0.2);
528
573
  transform: translateY(-1px);
529
574
  }
530
575
 
531
- .flip-camera-button:active,
532
576
  .camera-selector-button:active {
533
577
  transform: translateY(0);
534
578
  background: rgba(0, 0, 0, 0.9);
535
579
  }
536
580
 
581
+ .camera-selector-button:disabled,
582
+ .camera-selector-button.loading {
583
+ opacity: 0.7;
584
+ cursor: not-allowed;
585
+ pointer-events: none;
586
+ }
587
+
588
+ .camera-selector-button:disabled:hover,
589
+ .camera-selector-button.loading:hover {
590
+ transform: none;
591
+ background: rgba(0, 0, 0, 0.6);
592
+ border-color: rgba(255, 255, 255, 0.1);
593
+ }
594
+
595
+ .button-spinner {
596
+ width: 16px;
597
+ height: 16px;
598
+ border: 2px solid rgba(255, 255, 255, 0.3);
599
+ border-top: 2px solid #ffffff;
600
+ border-radius: 50%;
601
+ animation: spin 1s linear infinite;
602
+ }
603
+
604
+ @keyframes spin {
605
+ 0% { transform: rotate(0deg); }
606
+ 100% { transform: rotate(360deg); }
607
+ }
608
+
537
609
  /* Camera selector dropdown */
538
610
  .camera-selector-dropdown {
539
611
  position: absolute;
540
612
  top: 56px;
541
613
  right: 16px;
542
614
  z-index: 30;
543
- background: rgba(0, 0, 0, 0.85);
615
+ background: rgba(0, 0, 0, 0.25);
544
616
  backdrop-filter: blur(20px);
545
617
  border-radius: 12px;
546
618
  min-width: 260px;
@@ -566,7 +638,7 @@ video {
566
638
  display: flex;
567
639
  justify-content: space-between;
568
640
  align-items: center;
569
- padding: 12px 16px;
641
+ padding: 8px 12px;
570
642
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
571
643
  }
572
644
 
@@ -605,7 +677,7 @@ video {
605
677
 
606
678
  .camera-option {
607
679
  width: 100%;
608
- padding: 10px 16px;
680
+ padding: 8px 12px;
609
681
  border: none;
610
682
  background: none;
611
683
  text-align: left;
@@ -643,7 +715,7 @@ video {
643
715
  }
644
716
 
645
717
  .device-info {
646
- padding: 8px 16px;
718
+ padding: 6px 12px;
647
719
  border-top: 1px solid rgba(255, 255, 255, 0.1);
648
720
  background: rgba(255, 255, 255, 0.05);
649
721
  }
@@ -663,13 +735,6 @@ video {
663
735
  gap: 6px;
664
736
  }
665
737
 
666
- .flip-camera-button {
667
- height: 36px;
668
- padding: 0 12px;
669
- font-size: 11px;
670
- border-radius: 6px;
671
- }
672
-
673
738
  .camera-selector-button {
674
739
  height: 36px;
675
740
  padding: 0 12px;
@@ -685,15 +750,15 @@ video {
685
750
  }
686
751
 
687
752
  .camera-selector-header {
688
- padding: 10px 14px;
753
+ padding: 6px 10px;
689
754
  }
690
755
 
691
756
  .camera-option {
692
- padding: 8px 14px;
757
+ padding: 6px 10px;
693
758
  }
694
759
 
695
760
  .device-info {
696
- padding: 6px 14px;
761
+ padding: 4px 10px;
697
762
  }
698
763
  }
699
764
 
@@ -713,38 +778,131 @@ video {
713
778
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
714
779
  }
715
780
 
716
- /* Animación de carga */
781
+ /* Estado siempre visible del componente */
782
+ .component-status {
783
+ position: absolute;
784
+ top: 16px;
785
+ left: 16px;
786
+ background: rgba(0, 0, 0, 0.25);
787
+ backdrop-filter: blur(20px);
788
+ border-radius: 12px;
789
+ border: 1px solid rgba(255, 255, 255, 0.1);
790
+ display: flex;
791
+ align-items: center;
792
+ gap: 6px;
793
+ padding: 6px 10px;
794
+ z-index: 40;
795
+ height: 32px;
796
+ width: fit-content;
797
+ animation: slideInFromTop 0.3s ease-out;
798
+ }
799
+
800
+
801
+ .status-spinner {
802
+ width: 16px;
803
+ height: 16px;
804
+ border: 1px solid rgba(255, 255, 255, 0.3);
805
+ border-top: 1px solid #ffffff;
806
+ border-radius: 50%;
807
+ animation: statusSpin 1s linear infinite;
808
+ flex-shrink: 0;
809
+ }
810
+
811
+ .status-content {
812
+ display: flex;
813
+ flex-direction: column;
814
+ gap: 1px;
815
+ }
816
+
817
+ .status-message {
818
+ color: #ffffff;
819
+ font-size: 12px;
820
+ font-weight: 500;
821
+ margin: 0;
822
+ }
823
+
824
+ .status-description {
825
+ color: rgba(255, 255, 255, 0.7);
826
+ font-size: 10px;
827
+ line-height: 1.2;
828
+ margin: 0;
829
+ }
830
+
831
+ @keyframes statusSpin {
832
+ 0% {
833
+ transform: rotate(0deg);
834
+ }
835
+ 100% {
836
+ transform: rotate(360deg);
837
+ }
838
+ }
839
+
840
+ /* Responsive para estado en móviles */
841
+ @media (max-width: 480px) {
842
+ .component-status {
843
+ top: 12px;
844
+ left: 12px;
845
+ padding: 4px 8px;
846
+ gap: 4px;
847
+ height: 28px;
848
+ border-radius: 8px;
849
+ }
850
+
851
+ .status-spinner {
852
+ width: 14px;
853
+ height: 14px;
854
+ }
855
+
856
+ .status-message {
857
+ font-size: 11px;
858
+ }
859
+
860
+ .status-description {
861
+ font-size: 9px;
862
+ }
863
+ }
864
+
865
+ /* Animación de carga mejorada */
717
866
  .loading-overlay {
718
867
  position: absolute;
719
868
  top: 0;
720
869
  left: 0;
721
870
  width: 100%;
722
871
  height: 100%;
723
- background: rgba(0, 0, 0, 0.8);
872
+ background: rgba(0, 0, 0, 0.85);
873
+ backdrop-filter: blur(4px);
724
874
  display: flex;
725
875
  flex-direction: column;
726
876
  align-items: center;
727
877
  justify-content: center;
728
878
  z-index: 30;
729
- border-radius: 20px;
879
+ border-radius: 8px;
730
880
  }
731
881
 
732
882
  .loading-spinner {
733
- width: 60px;
734
- height: 60px;
735
- border: 4px solid rgba(255, 255, 255, 0.2);
736
- border-top: 4px solid #007bff;
883
+ width: 50px;
884
+ height: 50px;
885
+ border: 3px solid rgba(255, 255, 255, 0.15);
886
+ border-top: 3px solid #28a745;
737
887
  border-radius: 50%;
738
- animation: spin 1s linear infinite;
739
- margin-bottom: 20px;
888
+ animation: spin 1s ease-in-out infinite;
889
+ margin-bottom: 16px;
740
890
  }
741
891
 
742
892
  .loading-text {
743
- color: white;
744
- font-size: 16px;
893
+ color: #ffffff;
894
+ font-size: 14px;
745
895
  font-weight: 500;
746
896
  text-align: center;
747
897
  opacity: 0.9;
898
+ margin-bottom: 4px;
899
+ }
900
+
901
+ .loading-description {
902
+ color: rgba(255, 255, 255, 0.7);
903
+ font-size: 12px;
904
+ text-align: center;
905
+ opacity: 0.8;
748
906
  }
749
907
 
750
908
  @keyframes spin {
@@ -754,4 +912,176 @@ video {
754
912
  100% {
755
913
  transform: rotate(360deg);
756
914
  }
757
- }
915
+ }
916
+
917
+ /* Monitor de Performance - Diseño compacto y minimalista */
918
+ .performance-monitor {
919
+ position: absolute;
920
+ top: 70px;
921
+ left: 16px;
922
+ background: rgba(0, 0, 0, 0.25);
923
+ backdrop-filter: blur(20px);
924
+ border-radius: 12px;
925
+ border: 1px solid rgba(255, 255, 255, 0.1);
926
+ z-index: 35;
927
+ width: fit-content;
928
+ animation: slideInFromLeft 0.3s ease-out;
929
+ transition: all 0.3s ease;
930
+ }
931
+
932
+ @keyframes slideInFromLeft {
933
+ 0% {
934
+ opacity: 0;
935
+ transform: translateX(-20px) scale(0.95);
936
+ }
937
+ 100% {
938
+ opacity: 1;
939
+ transform: translateX(0) scale(1);
940
+ }
941
+ }
942
+
943
+
944
+ .performance-expanded {
945
+ padding: 6px 10px;
946
+ }
947
+
948
+ .metrics-row {
949
+ display: flex;
950
+ gap: 8px;
951
+ margin-bottom: 4px;
952
+ }
953
+
954
+ .metrics-row:last-child {
955
+ margin-bottom: 0;
956
+ }
957
+
958
+ .metric-compact {
959
+ display: flex;
960
+ flex-direction: column;
961
+ align-items: center;
962
+ gap: 2px;
963
+ min-width: 50px;
964
+ }
965
+
966
+ .metric-label {
967
+ font-size: 9px;
968
+ color: rgba(255, 255, 255, 0.6);
969
+ font-weight: 500;
970
+ text-transform: uppercase;
971
+ letter-spacing: 0.3px;
972
+ }
973
+
974
+ .metric-value {
975
+ font-size: 10px;
976
+ font-weight: 600;
977
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
978
+ padding: 2px 4px;
979
+ border-radius: 3px;
980
+ text-align: center;
981
+ white-space: nowrap;
982
+ }
983
+
984
+ .metric-value.good {
985
+ color: #4ade80;
986
+ background: rgba(74, 222, 128, 0.1);
987
+ border: 1px solid rgba(74, 222, 128, 0.2);
988
+ }
989
+
990
+ .metric-value.warning {
991
+ color: #fbbf24;
992
+ background: rgba(251, 191, 36, 0.1);
993
+ border: 1px solid rgba(251, 191, 36, 0.2);
994
+ }
995
+
996
+ .metric-value.danger {
997
+ color: #f87171;
998
+ background: rgba(248, 113, 113, 0.1);
999
+ border: 1px solid rgba(248, 113, 113, 0.2);
1000
+ }
1001
+
1002
+ /* Responsive para monitor de performance */
1003
+ @media (max-width: 480px) {
1004
+ .performance-monitor {
1005
+ top: 60px;
1006
+ left: 12px;
1007
+ width: fit-content;
1008
+ }
1009
+
1010
+ .performance-expanded {
1011
+ padding: 4px 8px;
1012
+ }
1013
+
1014
+ .metrics-row {
1015
+ gap: 6px;
1016
+ margin-bottom: 3px;
1017
+ }
1018
+
1019
+ .metric-compact {
1020
+ min-width: 45px;
1021
+ gap: 1px;
1022
+ }
1023
+
1024
+ .metric-label {
1025
+ font-size: 8px;
1026
+ }
1027
+
1028
+ .metric-value {
1029
+ font-size: 9px;
1030
+ padding: 1px 3px;
1031
+ }
1032
+ }
1033
+
1034
+ /* Quality Monitor */
1035
+ .quality-monitor {
1036
+ position: absolute;
1037
+ top: 200px;
1038
+ left: 16px;
1039
+ background: rgba(0, 0, 0, 0.25);
1040
+ backdrop-filter: blur(20px);
1041
+ border-radius: 12px;
1042
+ border: 1px solid rgba(255, 255, 255, 0.1);
1043
+ z-index: 35;
1044
+ width: fit-content;
1045
+ animation: slideInFromLeft 0.3s ease-out;
1046
+ transition: all 0.3s ease;
1047
+ }
1048
+
1049
+ .quality-text {
1050
+ padding: 6px 10px;
1051
+ font-size: 11px;
1052
+ color: white;
1053
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1054
+ line-height: 1.4;
1055
+ }
1056
+
1057
+ .quality-fail {
1058
+ color: #ff9999;
1059
+ }
1060
+
1061
+ /* Animación pulsante para valores críticos */
1062
+ @keyframes pulse {
1063
+ 0%, 100% {
1064
+ opacity: 1;
1065
+ }
1066
+ 50% {
1067
+ opacity: 0.7;
1068
+ }
1069
+ }
1070
+
1071
+ .metric-value.danger {
1072
+ animation: pulse 2s infinite;
1073
+ }
1074
+
1075
+ /* Mobile optimizations */
1076
+ @media (max-width: 480px) {
1077
+ .quality-monitor {
1078
+ top: 160px;
1079
+ left: 12px;
1080
+ }
1081
+
1082
+ .quality-text {
1083
+ padding: 4px 8px;
1084
+ font-size: 10px;
1085
+ }
1086
+ }
1087
+