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

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 +665 -514
  2. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
  3. package/dist/cjs/jaak-stamps.cjs.entry.js +1991 -1057
  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 +483 -123
  8. package/dist/collection/components/my-component/my-component.js +915 -1120
  9. package/dist/collection/components/my-component/my-component.js.map +1 -1
  10. package/dist/collection/services/CameraService.js +590 -0
  11. package/dist/collection/services/CameraService.js.map +1 -0
  12. package/dist/collection/services/DetectionService.js +387 -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 +2011 -1082
  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 +1991 -1057
  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-9ed19fa4.entry.js +2 -0
  51. package/dist/jaak-stamps-webcomponent/p-9ed19fa4.entry.js.map +1 -0
  52. package/dist/types/components/my-component/my-component.d.ts +89 -108
  53. package/dist/types/components.d.ts +39 -9
  54. package/dist/types/services/CameraService.d.ts +47 -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,23 +31,29 @@ 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 {
46
- z-index: 1;
45
+ .detection-overlay {
46
+ z-index: 1;
47
+ pointer-events: none;
48
+ }
49
+
50
+ video {
51
+ z-index: 0;
47
52
  }
48
53
 
49
- video {
50
- z-index: 0;
54
+ /* Detection boxes for debug mode */
55
+ .detection-box {
56
+ transition: opacity 0.2s ease;
51
57
  }
52
58
 
53
59
 
@@ -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;
@@ -176,11 +175,79 @@ video {
176
175
  font-weight: 600;
177
176
  text-align: center;
178
177
  white-space: normal;
179
- background: rgba(128, 128, 128, 0.8);
178
+ background: rgba(0, 0, 0, 0.25);
179
+ backdrop-filter: blur(12px);
180
180
  padding: 12px 20px;
181
- border-radius: 20px;
181
+ border-radius: 8px;
182
182
  max-width: 300px;
183
183
  z-index: 20;
184
+ border: 1px solid rgba(255, 255, 255, 0.1);
185
+ }
186
+
187
+ /* Quality indicator */
188
+ .quality-indicator {
189
+ position: absolute;
190
+ top: 20px;
191
+ right: 20px;
192
+ display: flex;
193
+ align-items: center;
194
+ gap: 8px;
195
+ background: rgba(0, 0, 0, 0.8);
196
+ padding: 8px 12px;
197
+ border-radius: 20px;
198
+ z-index: 25;
199
+ transition: all 0.3s ease;
200
+ }
201
+
202
+ .quality-indicator.warning {
203
+ background: rgba(255, 152, 0, 0.9);
204
+ }
205
+
206
+ .quality-indicator.good {
207
+ background: rgba(76, 175, 80, 0.9);
208
+ }
209
+
210
+ .quality-score {
211
+ color: #fff;
212
+ font-size: 12px;
213
+ font-weight: 600;
214
+ min-width: 30px;
215
+ text-align: center;
216
+ }
217
+
218
+ .quality-status {
219
+ width: 20px;
220
+ height: 20px;
221
+ border-radius: 50%;
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ font-size: 14px;
226
+ font-weight: bold;
227
+ color: #fff;
228
+ transition: all 0.3s ease;
229
+ }
230
+
231
+ .quality-status.ready {
232
+ background: #4CAF50;
233
+ }
234
+
235
+ .quality-status.not-ready {
236
+ background: #f44336;
237
+ }
238
+
239
+ /* Enhanced card outline for quality warnings */
240
+ .card-outline.quality-warning {
241
+ animation: qualityWarning 1s ease-in-out infinite alternate;
242
+ }
243
+
244
+ @keyframes qualityWarning {
245
+ 0% {
246
+ box-shadow: 0 0 0 3px rgba(255, 152, 0, 0.6);
247
+ }
248
+ 100% {
249
+ box-shadow: 0 0 0 6px rgba(255, 152, 0, 0.3);
250
+ }
184
251
  }
185
252
 
186
253
 
@@ -227,15 +294,15 @@ video {
227
294
  @keyframes pulseGreen {
228
295
  0% {
229
296
  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);
297
+ box-shadow: 0 0 0 4px rgba(40, 167, 69, 0);
231
298
  }
232
299
  50% {
233
300
  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);
301
+ box-shadow: 0 0 0 8px rgba(40, 167, 69, 0.6);
235
302
  }
236
303
  100% {
237
304
  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);
305
+ box-shadow: 0 0 0 4px rgba(40, 167, 69, 0);
239
306
  }
240
307
  }
241
308
 
@@ -442,13 +509,42 @@ video {
442
509
  }
443
510
  }
444
511
 
445
- /* Bot\u00f3n para saltar reverso */
446
- .skip-button {
512
+ /* Sección para saltar reverso */
513
+ .skip-section {
447
514
  position: absolute;
448
515
  bottom: 20px;
449
516
  left: 50%;
450
517
  transform: translateX(-50%);
451
518
  z-index: 25;
519
+ display: flex;
520
+ flex-direction: column;
521
+ align-items: center;
522
+ width: 100%;
523
+ max-width: 300px;
524
+ }
525
+
526
+ .skip-explanation {
527
+ background: rgba(0, 0, 0, 0.5);
528
+ color: #ffffff;
529
+ padding: 10px 16px;
530
+ border-radius: 8px;
531
+ font-size: 14px;
532
+ font-weight: 500;
533
+ text-align: center;
534
+ margin-bottom: 12px;
535
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
536
+ backdrop-filter: blur(12px);
537
+ border: 1px solid rgba(255, 255, 255, 0.1);
538
+ animation: fadeIn 0.3s ease-in-out;
539
+ }
540
+
541
+ @keyframes fadeIn {
542
+ from { opacity: 0; transform: translateY(10px); }
543
+ to { opacity: 1; transform: translateY(0); }
544
+ }
545
+
546
+ /* Botón para saltar reverso */
547
+ .skip-button {
452
548
  pointer-events: auto;
453
549
  background: #fff;
454
550
  color: #333;
@@ -467,7 +563,7 @@ video {
467
563
 
468
564
  .skip-button:active {
469
565
  background: #e9ecef;
470
- transform: translateX(-50%) translateY(0);
566
+ transform: translateY(1px);
471
567
  }
472
568
 
473
569
  /* Camera controls */
@@ -481,32 +577,13 @@ video {
481
577
  pointer-events: auto;
482
578
  }
483
579
 
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
580
 
504
581
  .camera-selector-button {
505
- height: 40px;
506
- padding: 0 16px;
582
+ height: 32px;
583
+ padding: 0 10px;
507
584
  border: none;
508
585
  border-radius: 8px;
509
- background: rgba(0, 0, 0, 0.6);
586
+ background: rgba(0, 0, 0, 0.25);
510
587
  backdrop-filter: blur(12px);
511
588
  color: #ffffff;
512
589
  font-size: 12px;
@@ -521,26 +598,52 @@ video {
521
598
  min-width: fit-content;
522
599
  }
523
600
 
524
- .flip-camera-button:hover,
525
601
  .camera-selector-button:hover {
526
602
  background: rgba(0, 0, 0, 0.8);
527
603
  border-color: rgba(255, 255, 255, 0.2);
528
604
  transform: translateY(-1px);
529
605
  }
530
606
 
531
- .flip-camera-button:active,
532
607
  .camera-selector-button:active {
533
608
  transform: translateY(0);
534
609
  background: rgba(0, 0, 0, 0.9);
535
610
  }
536
611
 
612
+ .camera-selector-button:disabled,
613
+ .camera-selector-button.loading {
614
+ opacity: 0.7;
615
+ cursor: not-allowed;
616
+ pointer-events: none;
617
+ }
618
+
619
+ .camera-selector-button:disabled:hover,
620
+ .camera-selector-button.loading:hover {
621
+ transform: none;
622
+ background: rgba(0, 0, 0, 0.6);
623
+ border-color: rgba(255, 255, 255, 0.1);
624
+ }
625
+
626
+ .button-spinner {
627
+ width: 16px;
628
+ height: 16px;
629
+ border: 2px solid rgba(255, 255, 255, 0.3);
630
+ border-top: 2px solid #ffffff;
631
+ border-radius: 50%;
632
+ animation: spin 1s linear infinite;
633
+ }
634
+
635
+ @keyframes spin {
636
+ 0% { transform: rotate(0deg); }
637
+ 100% { transform: rotate(360deg); }
638
+ }
639
+
537
640
  /* Camera selector dropdown */
538
641
  .camera-selector-dropdown {
539
642
  position: absolute;
540
643
  top: 56px;
541
644
  right: 16px;
542
645
  z-index: 30;
543
- background: rgba(0, 0, 0, 0.85);
646
+ background: rgba(0, 0, 0, 0.25);
544
647
  backdrop-filter: blur(20px);
545
648
  border-radius: 12px;
546
649
  min-width: 260px;
@@ -566,7 +669,7 @@ video {
566
669
  display: flex;
567
670
  justify-content: space-between;
568
671
  align-items: center;
569
- padding: 12px 16px;
672
+ padding: 8px 12px;
570
673
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
571
674
  }
572
675
 
@@ -605,7 +708,7 @@ video {
605
708
 
606
709
  .camera-option {
607
710
  width: 100%;
608
- padding: 10px 16px;
711
+ padding: 8px 12px;
609
712
  border: none;
610
713
  background: none;
611
714
  text-align: left;
@@ -643,7 +746,7 @@ video {
643
746
  }
644
747
 
645
748
  .device-info {
646
- padding: 8px 16px;
749
+ padding: 6px 12px;
647
750
  border-top: 1px solid rgba(255, 255, 255, 0.1);
648
751
  background: rgba(255, 255, 255, 0.05);
649
752
  }
@@ -662,38 +765,31 @@ video {
662
765
  right: 12px;
663
766
  gap: 6px;
664
767
  }
665
-
666
- .flip-camera-button {
667
- height: 36px;
668
- padding: 0 12px;
669
- font-size: 11px;
670
- border-radius: 6px;
671
- }
672
-
768
+
673
769
  .camera-selector-button {
674
770
  height: 36px;
675
771
  padding: 0 12px;
676
772
  font-size: 11px;
677
773
  border-radius: 6px;
678
774
  }
679
-
775
+
680
776
  .camera-selector-dropdown {
681
777
  right: 12px;
682
778
  top: 48px;
683
779
  min-width: 240px;
684
780
  max-width: calc(100vw - 24px);
685
781
  }
686
-
782
+
687
783
  .camera-selector-header {
688
- padding: 10px 14px;
784
+ padding: 6px 10px;
689
785
  }
690
-
786
+
691
787
  .camera-option {
692
- padding: 8px 14px;
788
+ padding: 6px 10px;
693
789
  }
694
-
790
+
695
791
  .device-info {
696
- padding: 6px 14px;
792
+ padding: 4px 10px;
697
793
  }
698
794
  }
699
795
 
@@ -713,38 +809,131 @@ video {
713
809
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
714
810
  }
715
811
 
716
- /* Animación de carga */
812
+ /* Estado siempre visible del componente */
813
+ .component-status {
814
+ position: absolute;
815
+ top: 16px;
816
+ left: 16px;
817
+ background: rgba(0, 0, 0, 0.25);
818
+ backdrop-filter: blur(20px);
819
+ border-radius: 12px;
820
+ border: 1px solid rgba(255, 255, 255, 0.1);
821
+ display: flex;
822
+ align-items: center;
823
+ gap: 6px;
824
+ padding: 6px 10px;
825
+ z-index: 40;
826
+ height: 32px;
827
+ width: fit-content;
828
+ animation: slideInFromTop 0.3s ease-out;
829
+ }
830
+
831
+
832
+ .status-spinner {
833
+ width: 16px;
834
+ height: 16px;
835
+ border: 1px solid rgba(255, 255, 255, 0.3);
836
+ border-top: 1px solid #ffffff;
837
+ border-radius: 50%;
838
+ animation: statusSpin 1s linear infinite;
839
+ flex-shrink: 0;
840
+ }
841
+
842
+ .status-content {
843
+ display: flex;
844
+ flex-direction: column;
845
+ gap: 1px;
846
+ }
847
+
848
+ .status-message {
849
+ color: #ffffff;
850
+ font-size: 12px;
851
+ font-weight: 500;
852
+ margin: 0;
853
+ }
854
+
855
+ .status-description {
856
+ color: rgba(255, 255, 255, 0.7);
857
+ font-size: 10px;
858
+ line-height: 1.2;
859
+ margin: 0;
860
+ }
861
+
862
+ @keyframes statusSpin {
863
+ 0% {
864
+ transform: rotate(0deg);
865
+ }
866
+ 100% {
867
+ transform: rotate(360deg);
868
+ }
869
+ }
870
+
871
+ /* Responsive para estado en móviles */
872
+ @media (max-width: 480px) {
873
+ .component-status {
874
+ top: 12px;
875
+ left: 12px;
876
+ padding: 4px 8px;
877
+ gap: 4px;
878
+ height: 28px;
879
+ border-radius: 8px;
880
+ }
881
+
882
+ .status-spinner {
883
+ width: 14px;
884
+ height: 14px;
885
+ }
886
+
887
+ .status-message {
888
+ font-size: 11px;
889
+ }
890
+
891
+ .status-description {
892
+ font-size: 9px;
893
+ }
894
+ }
895
+
896
+ /* Animación de carga mejorada */
717
897
  .loading-overlay {
718
898
  position: absolute;
719
899
  top: 0;
720
900
  left: 0;
721
901
  width: 100%;
722
902
  height: 100%;
723
- background: rgba(0, 0, 0, 0.8);
903
+ background: rgba(0, 0, 0, 0.85);
904
+ backdrop-filter: blur(4px);
724
905
  display: flex;
725
906
  flex-direction: column;
726
907
  align-items: center;
727
908
  justify-content: center;
728
909
  z-index: 30;
729
- border-radius: 20px;
910
+ border-radius: 8px;
730
911
  }
731
912
 
732
913
  .loading-spinner {
733
- width: 60px;
734
- height: 60px;
735
- border: 4px solid rgba(255, 255, 255, 0.2);
736
- border-top: 4px solid #007bff;
914
+ width: 50px;
915
+ height: 50px;
916
+ border: 3px solid rgba(255, 255, 255, 0.15);
917
+ border-top: 3px solid #28a745;
737
918
  border-radius: 50%;
738
- animation: spin 1s linear infinite;
739
- margin-bottom: 20px;
919
+ animation: spin 1s ease-in-out infinite;
920
+ margin-bottom: 16px;
740
921
  }
741
922
 
742
923
  .loading-text {
743
- color: white;
744
- font-size: 16px;
924
+ color: #ffffff;
925
+ font-size: 14px;
745
926
  font-weight: 500;
746
927
  text-align: center;
747
928
  opacity: 0.9;
929
+ margin-bottom: 4px;
930
+ }
931
+
932
+ .loading-description {
933
+ color: rgba(255, 255, 255, 0.7);
934
+ font-size: 12px;
935
+ text-align: center;
936
+ opacity: 0.8;
748
937
  }
749
938
 
750
939
  @keyframes spin {
@@ -754,4 +943,175 @@ video {
754
943
  100% {
755
944
  transform: rotate(360deg);
756
945
  }
757
- }
946
+ }
947
+
948
+ /* Monitor de Performance - Diseño compacto y minimalista */
949
+ .performance-monitor {
950
+ position: absolute;
951
+ top: 70px;
952
+ left: 16px;
953
+ background: rgba(0, 0, 0, 0.25);
954
+ backdrop-filter: blur(20px);
955
+ border-radius: 12px;
956
+ border: 1px solid rgba(255, 255, 255, 0.1);
957
+ z-index: 35;
958
+ width: fit-content;
959
+ animation: slideInFromLeft 0.3s ease-out;
960
+ transition: all 0.3s ease;
961
+ }
962
+
963
+ @keyframes slideInFromLeft {
964
+ 0% {
965
+ opacity: 0;
966
+ transform: translateX(-20px) scale(0.95);
967
+ }
968
+ 100% {
969
+ opacity: 1;
970
+ transform: translateX(0) scale(1);
971
+ }
972
+ }
973
+
974
+
975
+ .performance-expanded {
976
+ padding: 6px 10px;
977
+ }
978
+
979
+ .metrics-row {
980
+ display: flex;
981
+ gap: 8px;
982
+ margin-bottom: 4px;
983
+ }
984
+
985
+ .metrics-row:last-child {
986
+ margin-bottom: 0;
987
+ }
988
+
989
+ .metric-compact {
990
+ display: flex;
991
+ flex-direction: column;
992
+ align-items: center;
993
+ gap: 2px;
994
+ min-width: 50px;
995
+ }
996
+
997
+ .metric-label {
998
+ font-size: 9px;
999
+ color: rgba(255, 255, 255, 0.6);
1000
+ font-weight: 500;
1001
+ text-transform: uppercase;
1002
+ letter-spacing: 0.3px;
1003
+ }
1004
+
1005
+ .metric-value {
1006
+ font-size: 10px;
1007
+ font-weight: 600;
1008
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1009
+ padding: 2px 4px;
1010
+ border-radius: 3px;
1011
+ text-align: center;
1012
+ white-space: nowrap;
1013
+ }
1014
+
1015
+ .metric-value.good {
1016
+ color: #4ade80;
1017
+ background: rgba(74, 222, 128, 0.1);
1018
+ border: 1px solid rgba(74, 222, 128, 0.2);
1019
+ }
1020
+
1021
+ .metric-value.warning {
1022
+ color: #fbbf24;
1023
+ background: rgba(251, 191, 36, 0.1);
1024
+ border: 1px solid rgba(251, 191, 36, 0.2);
1025
+ }
1026
+
1027
+ .metric-value.danger {
1028
+ color: #f87171;
1029
+ background: rgba(248, 113, 113, 0.1);
1030
+ border: 1px solid rgba(248, 113, 113, 0.2);
1031
+ }
1032
+
1033
+ /* Responsive para monitor de performance */
1034
+ @media (max-width: 480px) {
1035
+ .performance-monitor {
1036
+ top: 60px;
1037
+ left: 12px;
1038
+ width: fit-content;
1039
+ }
1040
+
1041
+ .performance-expanded {
1042
+ padding: 4px 8px;
1043
+ }
1044
+
1045
+ .metrics-row {
1046
+ gap: 6px;
1047
+ margin-bottom: 3px;
1048
+ }
1049
+
1050
+ .metric-compact {
1051
+ min-width: 45px;
1052
+ gap: 1px;
1053
+ }
1054
+
1055
+ .metric-label {
1056
+ font-size: 8px;
1057
+ }
1058
+
1059
+ .metric-value {
1060
+ font-size: 9px;
1061
+ padding: 1px 3px;
1062
+ }
1063
+ }
1064
+
1065
+ /* Quality Monitor */
1066
+ .quality-monitor {
1067
+ position: absolute;
1068
+ top: 200px;
1069
+ left: 16px;
1070
+ background: rgba(0, 0, 0, 0.25);
1071
+ backdrop-filter: blur(20px);
1072
+ border-radius: 12px;
1073
+ border: 1px solid rgba(255, 255, 255, 0.1);
1074
+ z-index: 35;
1075
+ width: fit-content;
1076
+ animation: slideInFromLeft 0.3s ease-out;
1077
+ transition: all 0.3s ease;
1078
+ }
1079
+
1080
+ .quality-text {
1081
+ padding: 6px 10px;
1082
+ font-size: 11px;
1083
+ color: white;
1084
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1085
+ line-height: 1.4;
1086
+ }
1087
+
1088
+ .quality-fail {
1089
+ color: #ff9999;
1090
+ }
1091
+
1092
+ /* Animación pulsante para valores críticos */
1093
+ @keyframes pulse {
1094
+ 0%, 100% {
1095
+ opacity: 1;
1096
+ }
1097
+ 50% {
1098
+ opacity: 0.7;
1099
+ }
1100
+ }
1101
+
1102
+ .metric-value.danger {
1103
+ animation: pulse 2s infinite;
1104
+ }
1105
+
1106
+ /* Mobile optimizations */
1107
+ @media (max-width: 480px) {
1108
+ .quality-monitor {
1109
+ top: 160px;
1110
+ left: 12px;
1111
+ }
1112
+
1113
+ .quality-text {
1114
+ padding: 4px 8px;
1115
+ font-size: 10px;
1116
+ }
1117
+ }