@jjlmoya/utils-streaming 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +134 -0
  3. package/src/category/i18n/es.ts +134 -0
  4. package/src/category/i18n/fr.ts +134 -0
  5. package/src/category/index.ts +12 -0
  6. package/src/category/seo.astro +14 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +24 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +148 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/sorteo/bibliography.astro +14 -0
  25. package/src/tool/sorteo/component.astro +1319 -0
  26. package/src/tool/sorteo/engine.ts +143 -0
  27. package/src/tool/sorteo/i18n/en.ts +253 -0
  28. package/src/tool/sorteo/i18n/es.ts +253 -0
  29. package/src/tool/sorteo/i18n/fr.ts +253 -0
  30. package/src/tool/sorteo/index.ts +29 -0
  31. package/src/tool/sorteo/seo.astro +14 -0
  32. package/src/tool/sorteo/ui-manager.ts +81 -0
  33. package/src/tool/sorteo/ui.ts +30 -0
  34. package/src/tool/tebasCheck/bibliography.astro +14 -0
  35. package/src/tool/tebasCheck/component.astro +587 -0
  36. package/src/tool/tebasCheck/engine.ts +116 -0
  37. package/src/tool/tebasCheck/i18n/en.ts +254 -0
  38. package/src/tool/tebasCheck/i18n/es.ts +254 -0
  39. package/src/tool/tebasCheck/i18n/fr.ts +254 -0
  40. package/src/tool/tebasCheck/index.ts +29 -0
  41. package/src/tool/tebasCheck/ips.json +31 -0
  42. package/src/tool/tebasCheck/seo.astro +14 -0
  43. package/src/tool/tebasCheck/types.ts +45 -0
  44. package/src/tool/tebasCheck/ui-manager.ts +31 -0
  45. package/src/tools.ts +8 -0
  46. package/src/types.ts +71 -0
@@ -0,0 +1,1319 @@
1
+ ---
2
+ import { Icon } from 'astro-icon/components';
3
+ import { SORTEO_TOOL } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await SORTEO_TOOL.entry.i18n[locale]?.();
12
+ const ui = content?.ui;
13
+ ---
14
+
15
+ <div id="sorteo-app" class="sorteo-container">
16
+ <div id="main-grid" class="sorteo-grid">
17
+ <div id="sidebar-panel" class="sorteo-sidebar">
18
+ <div class="sorteo-stats-card">
19
+ <div class="sorteo-stats-icon">
20
+ <Icon name="mdi:account-group" />
21
+ </div>
22
+ <div class="sorteo-stats-content">
23
+ <h2 class="sorteo-stats-label">{ui?.totalParticipants}</h2>
24
+ <div class="sorteo-stats-value-wrapper">
25
+ <span id="count-display" class="sorteo-count">0</span>
26
+ <span id="ready-badge" class="sorteo-badge hidden">{ui?.ready}</span>
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="sorteo-panel-tabs">
32
+ <div class="sorteo-tabs-header">
33
+ <button id="tab-participants-btn" class="sorteo-tab-btn active" type="button">
34
+ {ui?.participants}
35
+ </button>
36
+ <button id="tab-settings-btn" class="sorteo-tab-btn" type="button">
37
+ {ui?.settings}
38
+ </button>
39
+ </div>
40
+
41
+ <div id="tab-participants-view" class="sorteo-tab-view">
42
+ <div class="sorteo-view-actions">
43
+ <label class="sorteo-upload-label">
44
+ <Icon name="mdi:file-upload-outline" />
45
+ {ui?.importFile}
46
+ <input type="file" id="file-import" accept=".txt,.csv,.json" class="hidden" />
47
+ </label>
48
+
49
+ <button id="clear-btn" class="sorteo-icon-btn" title={ui?.clearAll}>
50
+ <Icon name="mdi:trash-can-outline" />
51
+ </button>
52
+ </div>
53
+
54
+ <div class="sorteo-textarea-wrapper">
55
+ <textarea
56
+ id="participants-input"
57
+ class="sorteo-textarea"
58
+ placeholder={ui?.placeholder}
59
+ spellcheck="false"
60
+ ></textarea>
61
+ <div class="sorteo-textarea-fade"></div>
62
+ </div>
63
+
64
+ <div class="sorteo-view-footer">
65
+ <span>{ui?.onePerLine}</span>
66
+ <span id="line-count">0 {ui?.lines}</span>
67
+ </div>
68
+ </div>
69
+
70
+ <div id="tab-settings-view" class="sorteo-tab-view hidden">
71
+ <div class="sorteo-settings-content">
72
+ <div class="sorteo-settings-section">
73
+ <h3 class="sorteo-section-title">
74
+ <Icon name="mdi:filter-variant" /> {ui?.filters}
75
+ </h3>
76
+
77
+ <div class="sorteo-options-list">
78
+ <label class="sorteo-option-item">
79
+ <span class="sorteo-option-label">{ui?.allowDuplicates}</span>
80
+ <div class="sorteo-switch">
81
+ <input type="checkbox" id="opt-duplicates" class="sr-only" />
82
+ <div class="sorteo-switch-slider"></div>
83
+ </div>
84
+ </label>
85
+
86
+ <label class="sorteo-option-item">
87
+ <span class="sorteo-option-label">{ui?.winnerCount}</span>
88
+ <input
89
+ type="number"
90
+ id="opt-winner-count"
91
+ min="1"
92
+ max="50"
93
+ value="1"
94
+ class="sorteo-number-input"
95
+ />
96
+ </label>
97
+
98
+ <label class="sorteo-option-item">
99
+ <span class="sorteo-option-label">{ui?.autoRemove}</span>
100
+ <div class="sorteo-switch">
101
+ <input type="checkbox" id="opt-auto-remove" class="sr-only" />
102
+ <div class="sorteo-switch-slider success"></div>
103
+ </div>
104
+ </label>
105
+
106
+ <div class="sorteo-field-group">
107
+ <span class="sorteo-field-label">{ui?.blacklist}</span>
108
+ <textarea
109
+ id="blacklist-input"
110
+ class="sorteo-textarea-small"
111
+ placeholder={ui?.blacklistPlaceholder}
112
+ ></textarea>
113
+ <p class="sorteo-field-info">{ui?.blacklistInfo}</p>
114
+ </div>
115
+ </div>
116
+ </div>
117
+
118
+ <div class="sorteo-settings-section">
119
+ <h3 class="sorteo-section-title">
120
+ <Icon name="mdi:auto-fix" /> {ui?.sceneEffects}
121
+ </h3>
122
+
123
+ <div class="sorteo-options-list">
124
+ <label class="sorteo-option-item">
125
+ <span class="sorteo-option-label">{ui?.countdown}</span>
126
+ <div class="sorteo-switch">
127
+ <input type="checkbox" id="opt-countdown" class="sr-only" checked />
128
+ <div class="sorteo-switch-slider primary"></div>
129
+ </div>
130
+ </label>
131
+
132
+ <label class="sorteo-option-item">
133
+ <span class="sorteo-option-label">{ui?.confetti}</span>
134
+ <div class="sorteo-switch">
135
+ <input type="checkbox" id="opt-confetti" class="sr-only" checked />
136
+ <div class="sorteo-switch-slider primary"></div>
137
+ </div>
138
+ </label>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+
146
+ <div id="stage-panel" class="sorteo-stage">
147
+ <button id="zen-toggle" class="sorteo-zen-btn" title={ui?.zenMode}>
148
+ <Icon id="icon-zen-open" name="mdi:dock-left" />
149
+ <Icon id="icon-zen-close" name="mdi:window-maximize" class="hidden" />
150
+ </button>
151
+
152
+ <div class="sorteo-studio">
153
+ <div class="sorteo-studio-header">
154
+ <div class="sorteo-dots">
155
+ <div class="dot red"></div>
156
+ <div class="dot yellow"></div>
157
+ <div class="dot green"></div>
158
+ </div>
159
+ <div class="sorteo-version">LIVE STUDIO v2.0</div>
160
+ </div>
161
+
162
+ <div class="sorteo-arena">
163
+ <div class="sorteo-grid-bg"></div>
164
+ <div class="sorteo-glow"></div>
165
+
166
+ <div class="sorteo-content">
167
+ <div id="state-empty" class="sorteo-state-empty">
168
+ <div class="sorteo-empty-icon">
169
+ <Icon name="mdi:ticket-outline" />
170
+ </div>
171
+ <h2 class="sorteo-empty-title">{ui?.waitingParticipants}</h2>
172
+ </div>
173
+
174
+ <div id="state-countdown" class="sorteo-state-countdown hidden">
175
+ <div id="countdown-number" class="sorteo-countdown-text">3</div>
176
+ </div>
177
+
178
+ <div id="state-active" class="sorteo-state-active hidden">
179
+ <div class="sorteo-active-label">{ui?.winner}</div>
180
+
181
+ <div class="sorteo-winner-display">
182
+ <h2 id="main-display" class="sorteo-winner-name">???</h2>
183
+ </div>
184
+
185
+ <div id="multi-results" class="sorteo-multi-results hidden"></div>
186
+
187
+ <div id="winner-actions" class="sorteo-winner-actions hidden">
188
+ <button id="btn-reroll" class="sorteo-reroll-btn">
189
+ {ui?.reroll}
190
+ </button>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </div>
195
+
196
+ <div class="sorteo-studio-footer">
197
+ <button id="trigger-btn" class="sorteo-main-btn" disabled>
198
+ <div class="sorteo-btn-glow"></div>
199
+ <div class="sorteo-btn-content">
200
+ <span>{ui?.startGiveaway}</span>
201
+ <Icon name="mdi:arrow-right" />
202
+ </div>
203
+ </button>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ <div class="sorteo-history">
210
+ <div class="sorteo-history-container">
211
+ <h3 class="sorteo-history-title">
212
+ <Icon name="mdi:history" />
213
+ {ui?.history}
214
+ </h3>
215
+ <div id="history-list" class="sorteo-history-list">
216
+ <span class="sorteo-no-winners">{ui?.noWinnersYet}</span>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ <script>
223
+ import { GiveawayEngine } from './engine';
224
+ import {
225
+ playBeep,
226
+ runCountdownSequence,
227
+ triggerConfetti,
228
+ addToHistory,
229
+ } from './ui-manager';
230
+
231
+ const engine = new GiveawayEngine();
232
+ const els = {
233
+ input: document.getElementById('participants-input') as HTMLTextAreaElement,
234
+ blacklistInput: document.getElementById('blacklist-input') as HTMLTextAreaElement,
235
+ countDisplay: document.getElementById('count-display'),
236
+ lineCount: document.getElementById('line-count'),
237
+ readyBadge: document.getElementById('ready-badge'),
238
+ triggerBtn: document.getElementById('trigger-btn') as HTMLButtonElement,
239
+ clearBtn: document.getElementById('clear-btn'),
240
+ fileImport: document.getElementById('file-import') as HTMLInputElement,
241
+ tabParticipantsBtn: document.getElementById('tab-participants-btn'),
242
+ tabSettingsBtn: document.getElementById('tab-settings-btn'),
243
+ tabParticipantsView: document.getElementById('tab-participants-view'),
244
+ tabSettingsView: document.getElementById('tab-settings-view'),
245
+ stateEmpty: document.getElementById('state-empty'),
246
+ stateActive: document.getElementById('state-active'),
247
+ stateCountdown: document.getElementById('state-countdown'),
248
+ mainDisplay: document.getElementById('main-display'),
249
+ countdownNumber: document.getElementById('countdown-number'),
250
+ winnerActions: document.getElementById('winner-actions'),
251
+ btnReroll: document.getElementById('btn-reroll'),
252
+ historyList: document.getElementById('history-list'),
253
+ optCountdown: document.getElementById('opt-countdown') as HTMLInputElement,
254
+ optConfetti: document.getElementById('opt-confetti') as HTMLInputElement,
255
+ optDuplicates: document.getElementById('opt-duplicates') as HTMLInputElement,
256
+ optWinnerCount: document.getElementById('opt-winner-count') as HTMLInputElement,
257
+ optAutoRemove: document.getElementById('opt-auto-remove') as HTMLInputElement,
258
+ multiResults: document.getElementById('multi-results'),
259
+ sidebarPanel: document.getElementById('sidebar-panel'),
260
+ stagePanel: document.getElementById('stage-panel'),
261
+ zenToggle: document.getElementById('zen-toggle'),
262
+ };
263
+
264
+ let isRunning = false;
265
+ let audioContext: AudioContext | null = null;
266
+ let isZenMode = false;
267
+ const historyEmptyText = 'Aún no hay ganadores...';
268
+
269
+ function initAudio() {
270
+ if (audioContext) return;
271
+ const AudioContextClass = window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;
272
+ audioContext = new AudioContextClass();
273
+ }
274
+
275
+ function toggleStage(active: boolean) {
276
+ els.stateEmpty?.classList.toggle('hidden', active);
277
+ els.stateActive?.classList.toggle('hidden', !active);
278
+ }
279
+
280
+ function handleZen() {
281
+ isZenMode = !isZenMode;
282
+ els.sidebarPanel?.classList.toggle('hidden', isZenMode);
283
+ els.stagePanel?.classList.toggle('zen-active', isZenMode);
284
+ document.getElementById('icon-zen-open')?.classList.toggle('hidden', isZenMode);
285
+ document.getElementById('icon-zen-close')?.classList.toggle('hidden', !isZenMode);
286
+ }
287
+
288
+ function update() {
289
+ engine.setAllowDuplicates(els.optDuplicates.checked);
290
+ engine.setBlacklistFromText(els.blacklistInput.value);
291
+ engine.setParticipantsFromText(els.input.value);
292
+ const count = engine.getCount();
293
+ if (els.countDisplay) els.countDisplay.textContent = count.toString();
294
+ const isValid = count >= 1;
295
+ els.readyBadge?.classList.toggle('hidden', !isValid);
296
+ els.triggerBtn.disabled = !isValid || isRunning;
297
+ els.stateEmpty?.classList.toggle('hidden-anim', count > 0);
298
+ if (count === 0) els.stateActive?.classList.add('hidden');
299
+ }
300
+
301
+ function tab(name: 'participants' | 'settings') {
302
+ const isP = name === 'participants';
303
+ els.tabParticipantsView?.classList.toggle('hidden', !isP);
304
+ els.tabSettingsView?.classList.toggle('hidden', isP);
305
+ els.tabParticipantsBtn?.classList.toggle('active', isP);
306
+ els.tabSettingsBtn?.classList.toggle('active', !isP);
307
+ }
308
+
309
+ async function start() {
310
+ if (isRunning || engine.getCount() < 1) return;
311
+ isRunning = true;
312
+ els.triggerBtn.disabled = true;
313
+ initAudio();
314
+ toggleStage(false);
315
+ if (els.optCountdown.checked) await runCountdownSequence(els, audioContext, playBeep);
316
+ toggleStage(true);
317
+ await animateRoll(engine.getParticipants(), parseInt(els.optWinnerCount?.value || '1'));
318
+ }
319
+
320
+ async function animateRoll(participants: string[], winnerCount: number) {
321
+ const duration = 2000;
322
+ const startT = Date.now();
323
+ const frame = () => {
324
+ const elapsed = Date.now() - startT;
325
+ const progress = Math.min(elapsed / duration, 1);
326
+ if (progress < 1) {
327
+ if (Math.random() > (1 - Math.pow(1 - progress, 3)) * 0.8) {
328
+ if (els.mainDisplay) {
329
+ const part = participants[Math.floor(Math.random() * participants.length)];
330
+ els.mainDisplay.textContent = part || '';
331
+ }
332
+ playBeep(audioContext, 200, 0.02, 'sawtooth');
333
+ }
334
+ requestAnimationFrame(frame);
335
+ } else finalize(winnerCount);
336
+ };
337
+ frame();
338
+ }
339
+
340
+ function finalize(count: number) {
341
+ const winners = engine.pickWinners(count);
342
+ renderWinners(winners);
343
+ if (els.optConfetti.checked) triggerConfetti(document.querySelector('.sorteo-arena'));
344
+ playBeep(audioContext, 880, 0.3, 'sine');
345
+ addToHistory(els.historyList, winners, historyEmptyText);
346
+ if (els.optAutoRemove.checked) {
347
+ winners.forEach(w => engine.removeParticipant(w));
348
+ const lines = els.input.value.split('\n');
349
+ winners.forEach(w => {
350
+ const idx = lines.findIndex(l => l.trim().toLowerCase().startsWith(w.toLowerCase()));
351
+ if (idx !== -1) lines.splice(idx, 1);
352
+ });
353
+ els.input.value = lines.join('\n');
354
+ }
355
+ update();
356
+ els.winnerActions?.classList.remove('hidden');
357
+ isRunning = false;
358
+ els.triggerBtn.disabled = false;
359
+ }
360
+
361
+ function renderWinners(winners: string[]) {
362
+ if (winners.length === 1) {
363
+ if (els.mainDisplay) {
364
+ els.mainDisplay.textContent = winners[0] || '';
365
+ els.mainDisplay.classList.remove('hidden');
366
+ els.mainDisplay.classList.add('winner-success', 'scale-up');
367
+ }
368
+ els.multiResults?.classList.add('hidden');
369
+ } else {
370
+ els.mainDisplay?.classList.add('hidden');
371
+ els.multiResults?.classList.remove('hidden');
372
+ if (els.multiResults) els.multiResults.innerHTML = winners.map((w, i) => `<div class="sorteo-result-card animate-zoom-in" style="animation-delay: ${i * 50}ms"><span class="sorteo-result-name">${w}</span><div class="sorteo-result-idx">#${i + 1}</div></div>`).join('');
373
+ }
374
+ }
375
+
376
+ els.input.addEventListener('input', update);
377
+ els.blacklistInput?.addEventListener('input', update);
378
+ els.optDuplicates?.addEventListener('change', update);
379
+ els.zenToggle?.addEventListener('click', handleZen);
380
+ els.tabParticipantsBtn?.addEventListener('click', () => tab('participants'));
381
+ els.tabSettingsBtn?.addEventListener('click', () => tab('settings'));
382
+ els.triggerBtn.addEventListener('click', start);
383
+ els.btnReroll?.addEventListener('click', start);
384
+ els.clearBtn?.addEventListener('click', () => {
385
+ els.input.value = '';
386
+ update();
387
+ if (els.mainDisplay) els.mainDisplay.textContent = '???';
388
+ els.stateActive?.classList.add('hidden');
389
+ els.stateEmpty?.classList.remove('hidden', 'hidden-anim');
390
+ });
391
+ update();
392
+ </script>
393
+
394
+ <style>
395
+ .sorteo-container {
396
+ --sorteo-primary: #6366f1;
397
+ --sorteo-secondary: #a855f7;
398
+ --sorteo-accent: #ec4899;
399
+ --sorteo-success: #10b981;
400
+ --sorteo-warning: #fbbf24;
401
+ --sorteo-danger: #ef4444;
402
+ --sorteo-bg: #f8fafc;
403
+ --sorteo-card: #fff;
404
+ --sorteo-border: #e2e8f0;
405
+ --sorteo-text: #1e293b;
406
+ --sorteo-text-muted: #64748b;
407
+ --sorteo-studio-bg: #0f172a;
408
+
409
+ width: 100%;
410
+ max-width: 80rem;
411
+ margin: 0 auto;
412
+ padding: 1.5rem;
413
+ }
414
+
415
+ :global(.theme-dark) .sorteo-container {
416
+ --sorteo-bg: #020617;
417
+ --sorteo-card: #0f172a;
418
+ --sorteo-border: #1e293b;
419
+ --sorteo-text: #f1f5f9;
420
+ --sorteo-text-muted: #94a3b8;
421
+ }
422
+
423
+ .sorteo-grid {
424
+ display: grid;
425
+ grid-template-columns: 1fr;
426
+ gap: 1.5rem;
427
+ }
428
+
429
+ @media (min-width: 1280px) {
430
+ .sorteo-grid {
431
+ grid-template-columns: repeat(12, 1fr);
432
+ }
433
+ }
434
+
435
+ .sorteo-sidebar {
436
+ grid-column: span 1;
437
+ display: flex;
438
+ flex-direction: column;
439
+ gap: 1.5rem;
440
+ height: 800px;
441
+ transition: all 0.5s ease;
442
+ }
443
+
444
+ @media (min-width: 1280px) {
445
+ .sorteo-sidebar {
446
+ grid-column: span 4;
447
+ }
448
+ }
449
+
450
+ .sorteo-sidebar.hidden {
451
+ display: none;
452
+ }
453
+
454
+ .sorteo-stats-card {
455
+ background: var(--sorteo-card);
456
+ border-radius: 1.5rem;
457
+ padding: 1.5rem;
458
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
459
+ border: 1px solid var(--sorteo-border);
460
+ position: relative;
461
+ overflow: hidden;
462
+ flex-shrink: 0;
463
+ }
464
+
465
+ .sorteo-stats-icon {
466
+ position: absolute;
467
+ top: 0;
468
+ right: 0;
469
+ padding: 1rem;
470
+ opacity: 0.1;
471
+ transition: opacity 0.3s;
472
+ }
473
+
474
+ .sorteo-stats-card:hover .sorteo-stats-icon {
475
+ opacity: 0.2;
476
+ }
477
+
478
+ .sorteo-stats-icon [data-icon] {
479
+ width: 6rem;
480
+ height: 6rem;
481
+ color: var(--sorteo-primary);
482
+ }
483
+
484
+ .sorteo-stats-label {
485
+ font-size: 0.75rem;
486
+ font-weight: 700;
487
+ text-transform: uppercase;
488
+ letter-spacing: 0.05em;
489
+ color: var(--sorteo-text-muted);
490
+ margin: 0;
491
+ }
492
+
493
+ .sorteo-stats-value-wrapper {
494
+ display: flex;
495
+ align-items: baseline;
496
+ gap: 0.5rem;
497
+ margin-top: 0.25rem;
498
+ }
499
+
500
+ .sorteo-count {
501
+ font-size: 3rem;
502
+ font-weight: 900;
503
+ color: var(--sorteo-text);
504
+ letter-spacing: -0.05em;
505
+ }
506
+
507
+ .sorteo-badge {
508
+ font-size: 0.75rem;
509
+ font-weight: 600;
510
+ color: var(--sorteo-success);
511
+ background: rgba(16, 185, 129, 0.1);
512
+ padding: 0.125rem 0.5rem;
513
+ border-radius: 9999px;
514
+ }
515
+
516
+ .sorteo-panel-tabs {
517
+ flex: 1;
518
+ background: var(--sorteo-card);
519
+ border-radius: 1.5rem;
520
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
521
+ border: 1px solid var(--sorteo-border);
522
+ display: flex;
523
+ flex-direction: column;
524
+ overflow: hidden;
525
+ min-height: 0;
526
+ }
527
+
528
+ .sorteo-tabs-header {
529
+ display: flex;
530
+ border-bottom: 1px solid var(--sorteo-border);
531
+ }
532
+
533
+ .sorteo-tab-btn {
534
+ flex: 1;
535
+ padding: 1rem;
536
+ font-size: 0.875rem;
537
+ font-weight: 600;
538
+ text-align: center;
539
+ border: none;
540
+ border-bottom: 2px solid transparent;
541
+ background: transparent;
542
+ color: var(--sorteo-text-muted);
543
+ cursor: pointer;
544
+ transition: all 0.2s;
545
+ outline: none;
546
+ }
547
+
548
+ .sorteo-tab-btn.active {
549
+ border-bottom-color: var(--sorteo-primary);
550
+ color: var(--sorteo-primary);
551
+ background: rgba(99, 102, 241, 0.05);
552
+ }
553
+
554
+ .sorteo-tab-view {
555
+ flex: 1;
556
+ display: flex;
557
+ flex-direction: column;
558
+ min-height: 0;
559
+ }
560
+
561
+ .sorteo-tab-view.hidden {
562
+ display: none;
563
+ }
564
+
565
+ .sorteo-view-actions {
566
+ padding: 0.5rem 1rem;
567
+ border-bottom: 1px solid var(--sorteo-border);
568
+ display: flex;
569
+ justify-content: space-between;
570
+ align-items: center;
571
+ gap: 0.5rem;
572
+ }
573
+
574
+ .sorteo-upload-label {
575
+ cursor: pointer;
576
+ padding: 0.375rem 0.75rem;
577
+ border-radius: 0.5rem;
578
+ font-size: 0.75rem;
579
+ font-weight: 700;
580
+ background: rgba(99, 102, 241, 0.05);
581
+ color: var(--sorteo-primary);
582
+ display: flex;
583
+ align-items: center;
584
+ gap: 0.5rem;
585
+ transition: background 0.2s;
586
+ }
587
+
588
+ .sorteo-upload-label:hover {
589
+ background: rgba(99, 102, 241, 0.1);
590
+ }
591
+
592
+ .sorteo-icon-btn {
593
+ color: var(--sorteo-text-muted);
594
+ padding: 0.5rem;
595
+ border-radius: 0.5rem;
596
+ border: none;
597
+ background: transparent;
598
+ cursor: pointer;
599
+ transition: all 0.2s;
600
+ }
601
+
602
+ .sorteo-icon-btn:hover {
603
+ color: var(--sorteo-danger);
604
+ background: rgba(239, 68, 68, 0.05);
605
+ }
606
+
607
+ .sorteo-textarea-wrapper {
608
+ flex: 1;
609
+ position: relative;
610
+ min-height: 0;
611
+ }
612
+
613
+ .sorteo-textarea {
614
+ width: 100%;
615
+ height: 100%;
616
+ padding: 1rem;
617
+ border: none;
618
+ background: transparent;
619
+ resize: none;
620
+ font-size: 0.875rem;
621
+ line-height: 1.5;
622
+ color: var(--sorteo-text);
623
+ outline: none;
624
+ }
625
+
626
+ .sorteo-textarea-fade {
627
+ position: absolute;
628
+ bottom: 0;
629
+ left: 0;
630
+ width: 100%;
631
+ height: 2rem;
632
+ background: linear-gradient(to top, var(--sorteo-card), transparent);
633
+ pointer-events: none;
634
+ }
635
+
636
+ .sorteo-view-footer {
637
+ padding: 0.5rem 1rem;
638
+ border-top: 1px solid var(--sorteo-border);
639
+ font-size: 0.625rem;
640
+ color: var(--sorteo-text-muted);
641
+ display: flex;
642
+ justify-content: space-between;
643
+ }
644
+
645
+ .sorteo-settings-content {
646
+ flex: 1;
647
+ padding: 1.5rem;
648
+ overflow-y: auto;
649
+ display: flex;
650
+ flex-direction: column;
651
+ gap: 2rem;
652
+ }
653
+
654
+ .sorteo-section-title {
655
+ font-size: 0.75rem;
656
+ font-weight: 700;
657
+ text-transform: uppercase;
658
+ color: var(--sorteo-text-muted);
659
+ display: flex;
660
+ align-items: center;
661
+ gap: 0.5rem;
662
+ margin-bottom: 1rem;
663
+ }
664
+
665
+ .sorteo-options-list {
666
+ display: flex;
667
+ flex-direction: column;
668
+ gap: 1rem;
669
+ }
670
+
671
+ .sorteo-option-item {
672
+ display: flex;
673
+ align-items: center;
674
+ justify-content: space-between;
675
+ padding: 0.75rem;
676
+ background: rgba(0,0,0,0.02);
677
+ border: 1px solid var(--sorteo-border);
678
+ border-radius: 0.75rem;
679
+ cursor: pointer;
680
+ }
681
+
682
+ :global(.theme-dark) .sorteo-option-item {
683
+ background: rgba(255,255,255,0.02);
684
+ }
685
+
686
+ .sorteo-option-label {
687
+ font-size: 0.875rem;
688
+ font-weight: 500;
689
+ color: var(--sorteo-text);
690
+ }
691
+
692
+ .sorteo-switch {
693
+ position: relative;
694
+ width: 2.25rem;
695
+ height: 1.25rem;
696
+ }
697
+
698
+ .sorteo-switch-slider {
699
+ position: absolute;
700
+ inset: 0;
701
+ background: #cbd5e1;
702
+ border-radius: 9999px;
703
+ transition: all 0.3s;
704
+ }
705
+
706
+ :global(.theme-dark) .sorteo-switch-slider {
707
+ background: #334155;
708
+ }
709
+
710
+ .sorteo-switch-slider::after {
711
+ content: "";
712
+ position: absolute;
713
+ top: 2px;
714
+ left: 2px;
715
+ width: 1rem;
716
+ height: 1rem;
717
+ background: white;
718
+ border-radius: 50%;
719
+ transition: all 0.3s;
720
+ }
721
+
722
+ .sorteo-switch input:checked + .sorteo-switch-slider {
723
+ background: var(--sorteo-primary);
724
+ }
725
+
726
+ .sorteo-switch input:checked + .sorteo-switch-slider.success {
727
+ background: var(--sorteo-success);
728
+ }
729
+
730
+ .sorteo-switch input:checked + .sorteo-switch-slider.primary {
731
+ background: var(--sorteo-secondary);
732
+ }
733
+
734
+ .sorteo-switch input:checked + .sorteo-switch-slider::after {
735
+ transform: translateX(1rem);
736
+ }
737
+
738
+ .sorteo-number-input {
739
+ width: 4rem;
740
+ text-align: center;
741
+ background: var(--sorteo-card);
742
+ border: 1px solid var(--sorteo-border);
743
+ border-radius: 0.5rem;
744
+ padding: 0.25rem;
745
+ font-weight: 700;
746
+ color: var(--sorteo-text);
747
+ outline: none;
748
+ }
749
+
750
+ .sorteo-field-group {
751
+ display: flex;
752
+ flex-direction: column;
753
+ gap: 0.5rem;
754
+ }
755
+
756
+ .sorteo-field-label {
757
+ font-size: 0.875rem;
758
+ font-weight: 500;
759
+ color: var(--sorteo-text);
760
+ }
761
+
762
+ .sorteo-textarea-small {
763
+ width: 100%;
764
+ height: 8rem;
765
+ padding: 0.75rem;
766
+ border-radius: 0.75rem;
767
+ background: rgba(0,0,0,0.02);
768
+ border: 1px solid var(--sorteo-border);
769
+ color: var(--sorteo-text);
770
+ font-size: 0.75rem;
771
+ outline: none;
772
+ resize: none;
773
+ }
774
+
775
+ .sorteo-field-info {
776
+ font-size: 0.625rem;
777
+ color: var(--sorteo-text-muted);
778
+ margin: 0;
779
+ }
780
+
781
+ .sorteo-stage {
782
+ grid-column: span 1;
783
+ height: 800px;
784
+ position: relative;
785
+ transition: all 0.5s ease-in-out;
786
+ }
787
+
788
+ @media (min-width: 1280px) {
789
+ .sorteo-stage {
790
+ grid-column: span 8;
791
+ }
792
+ }
793
+
794
+ .sorteo-stage.zen-active {
795
+ grid-column: span 12;
796
+ }
797
+
798
+ .sorteo-zen-btn {
799
+ position: absolute;
800
+ top: 1.5rem;
801
+ left: 1.5rem;
802
+ z-index: 50;
803
+ padding: 0.5rem;
804
+ border-radius: 9999px;
805
+ border: none;
806
+ background: rgba(255, 255, 255, 0.05);
807
+ color: #94a3b8;
808
+ backdrop-filter: blur(8px);
809
+ cursor: pointer;
810
+ opacity: 0;
811
+ transition: all 0.3s;
812
+ }
813
+
814
+ .sorteo-stage:hover .sorteo-zen-btn {
815
+ opacity: 1;
816
+ }
817
+
818
+ .sorteo-zen-btn:hover {
819
+ background: white;
820
+ color: var(--sorteo-primary);
821
+ }
822
+
823
+ :global(.theme-dark) .sorteo-zen-btn:hover {
824
+ background: black;
825
+ }
826
+
827
+ .sorteo-studio {
828
+ height: 100%;
829
+ background: var(--sorteo-studio-bg);
830
+ border-radius: 2rem;
831
+ border: 4px solid #1e293b;
832
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.1);
833
+ display: flex;
834
+ flex-direction: column;
835
+ overflow: hidden;
836
+ position: relative;
837
+ }
838
+
839
+ .sorteo-studio-header {
840
+ height: 3rem;
841
+ background: #020617;
842
+ display: flex;
843
+ align-items: center;
844
+ padding: 0 1.5rem;
845
+ gap: 0.5rem;
846
+ }
847
+
848
+ .sorteo-dots {
849
+ display: flex;
850
+ gap: 0.375rem;
851
+ }
852
+
853
+ .dot {
854
+ width: 0.75rem;
855
+ height: 0.75rem;
856
+ border-radius: 50%;
857
+ }
858
+
859
+ .dot.red {
860
+ background: #ef4444;
861
+ opacity: 0.5;
862
+ }
863
+ .dot.yellow {
864
+ background: #f59e0b;
865
+ opacity: 0.5;
866
+ }
867
+ .dot.green {
868
+ background: #10b981;
869
+ opacity: 0.5;
870
+ }
871
+
872
+ .sorteo-version {
873
+ margin-left: auto;
874
+ font-size: 0.75rem;
875
+ color: #475569;
876
+ text-transform: uppercase;
877
+ letter-spacing: 0.2em;
878
+ }
879
+
880
+ .sorteo-arena {
881
+ flex: 1;
882
+ position: relative;
883
+ background: radial-gradient(circle at center, #1e1b4b, #020617);
884
+ display: flex;
885
+ align-items: center;
886
+ justify-content: center;
887
+ overflow: hidden;
888
+ }
889
+
890
+ .sorteo-grid-bg {
891
+ position: absolute;
892
+ inset: 0;
893
+ background-image:
894
+ linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
895
+ linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
896
+ background-size: 4rem 4rem;
897
+ mask-image: radial-gradient(circle at center, black 40%, transparent 80%);
898
+ }
899
+
900
+ .sorteo-glow {
901
+ position: absolute;
902
+ top: 0;
903
+ left: 50%;
904
+ transform: translateX(-50%);
905
+ width: 800px;
906
+ height: 500px;
907
+ background: rgba(99, 102, 241, 0.15);
908
+ filter: blur(120px);
909
+ border-radius: 50%;
910
+ pointer-events: none;
911
+ }
912
+
913
+ .sorteo-content {
914
+ position: relative;
915
+ z-index: 10;
916
+ width: 100%;
917
+ max-width: 56rem;
918
+ text-align: center;
919
+ padding: 1rem;
920
+ }
921
+
922
+ .sorteo-state-empty {
923
+ transition: all 0.5s ease;
924
+ }
925
+
926
+ .sorteo-state-empty.hidden-anim {
927
+ opacity: 0;
928
+ transform: translateY(1rem);
929
+ pointer-events: none;
930
+ }
931
+
932
+ .sorteo-empty-icon {
933
+ width: 6rem;
934
+ height: 6rem;
935
+ background: rgba(30, 41, 59, 0.5);
936
+ border: 1px solid rgba(51, 65, 85, 0.5);
937
+ border-radius: 50%;
938
+ display: inline-flex;
939
+ align-items: center;
940
+ justify-content: center;
941
+ margin-bottom: 1.5rem;
942
+ animation: pulse 2s infinite;
943
+ }
944
+
945
+ .sorteo-empty-icon [data-icon] {
946
+ width: 2.5rem;
947
+ height: 2.5rem;
948
+ color: #64748b;
949
+ }
950
+
951
+ .sorteo-empty-title {
952
+ font-size: 1.875rem;
953
+ font-weight: 700;
954
+ color: #475569;
955
+ margin: 0;
956
+ }
957
+
958
+ .sorteo-state-countdown {
959
+ position: absolute;
960
+ inset: 0;
961
+ display: flex;
962
+ align-items: center;
963
+ justify-content: center;
964
+ z-index: 50;
965
+ pointer-events: none;
966
+ }
967
+
968
+ .sorteo-countdown-text {
969
+ font-size: 15rem;
970
+ font-weight: 900;
971
+ color: rgba(255,255,255,0.1);
972
+ transform: scale(1.5);
973
+ filter: blur(2px);
974
+ }
975
+
976
+ .sorteo-state-active {
977
+ display: flex;
978
+ flex-direction: column;
979
+ align-items: center;
980
+ gap: 2rem;
981
+ }
982
+
983
+ .sorteo-active-label {
984
+ color: #818cf8;
985
+ font-size: 0.875rem;
986
+ letter-spacing: 0.5em;
987
+ text-transform: uppercase;
988
+ opacity: 0.7;
989
+ }
990
+
991
+ .sorteo-winner-display {
992
+ padding: 3rem 0;
993
+ }
994
+
995
+ .sorteo-winner-name {
996
+ font-size: clamp(3rem, 15vw, 8rem);
997
+ font-weight: 900;
998
+ color: white;
999
+ letter-spacing: -0.02em;
1000
+ margin: 0;
1001
+ text-shadow: 0 0 50px rgba(99, 102, 241, 0.5);
1002
+ word-break: break-all;
1003
+ line-height: 1.1;
1004
+ }
1005
+
1006
+ .sorteo-winner-name.winner-success {
1007
+ color: #34d399;
1008
+ text-shadow: 0 0 40px rgba(52, 211, 153, 0.8), 0 0 80px rgba(52, 211, 153, 0.4);
1009
+ }
1010
+
1011
+ .sorteo-winner-name.scale-up {
1012
+ transform: scale(1.1);
1013
+ transition: transform 0.5s;
1014
+ }
1015
+
1016
+ .sorteo-multi-results {
1017
+ display: grid;
1018
+ grid-template-columns: 1fr;
1019
+ gap: 1rem;
1020
+ width: 100%;
1021
+ max-height: 400px;
1022
+ overflow-y: auto;
1023
+ padding: 1rem;
1024
+ }
1025
+
1026
+ @media (min-width: 768px) {
1027
+ .sorteo-multi-results { grid-template-columns: repeat(2, 1fr); }
1028
+ }
1029
+
1030
+ @media (min-width: 1024px) {
1031
+ .sorteo-multi-results { grid-template-columns: repeat(3, 1fr); }
1032
+ }
1033
+
1034
+ .sorteo-result-card {
1035
+ background: rgba(30, 41, 59, 0.8);
1036
+ border: 1px solid rgba(51, 65, 85, 0.5);
1037
+ padding: 1rem;
1038
+ border-radius: 0.75rem;
1039
+ position: relative;
1040
+ display: flex;
1041
+ align-items: center;
1042
+ justify-content: center;
1043
+ transition: all 0.3s;
1044
+ }
1045
+
1046
+ .sorteo-result-card:hover {
1047
+ background: rgba(16, 185, 129, 0.1);
1048
+ border-color: rgba(16, 185, 129, 0.3);
1049
+ }
1050
+
1051
+ .sorteo-result-name {
1052
+ font-size: 1.25rem;
1053
+ font-weight: 700;
1054
+ color: white;
1055
+ word-break: break-all;
1056
+ }
1057
+
1058
+ .sorteo-result-idx {
1059
+ position: absolute;
1060
+ top: 0.375rem;
1061
+ left: 0.375rem;
1062
+ font-size: 0.625rem;
1063
+ color: #64748b;
1064
+ }
1065
+
1066
+ .sorteo-winner-actions {
1067
+ margin-top: 3rem;
1068
+ display: flex;
1069
+ justify-content: center;
1070
+ }
1071
+
1072
+ .sorteo-reroll-btn {
1073
+ background: #1e293b;
1074
+ color: white;
1075
+ padding: 0.75rem 1.5rem;
1076
+ border-radius: 9999px;
1077
+ font-weight: 700;
1078
+ font-size: 0.875rem;
1079
+ border: 1px solid #334155;
1080
+ cursor: pointer;
1081
+ transition: background 0.2s;
1082
+ }
1083
+
1084
+ .sorteo-reroll-btn:hover {
1085
+ background: #334155;
1086
+ }
1087
+
1088
+ .sorteo-studio-footer {
1089
+ height: 6rem;
1090
+ background: #0f172a;
1091
+ border-top: 1px solid #1e293b;
1092
+ display: flex;
1093
+ align-items: center;
1094
+ justify-content: center;
1095
+ padding: 0 2rem;
1096
+ }
1097
+
1098
+ .sorteo-main-btn {
1099
+ width: 100%;
1100
+ max-width: 28rem;
1101
+ position: relative;
1102
+ border: none;
1103
+ background: transparent;
1104
+ cursor: pointer;
1105
+ padding: 0;
1106
+ outline: none;
1107
+ }
1108
+
1109
+ .sorteo-btn-glow {
1110
+ position: absolute;
1111
+ inset: 0;
1112
+ background: linear-gradient(90deg, #6366f1, #a855f7, #ec4899);
1113
+ border-radius: 0.75rem;
1114
+ filter: blur(8px);
1115
+ opacity: 0.25;
1116
+ transition: opacity 0.5s;
1117
+ }
1118
+
1119
+ .sorteo-main-btn:hover:not(:disabled) .sorteo-btn-glow {
1120
+ opacity: 0.75;
1121
+ }
1122
+
1123
+ .sorteo-main-btn:disabled .sorteo-btn-glow {
1124
+ display: none;
1125
+ }
1126
+
1127
+ .sorteo-btn-content {
1128
+ position: relative;
1129
+ height: 3.5rem;
1130
+ background: white;
1131
+ border-radius: 0.75rem;
1132
+ border: 1px solid #e2e8f0;
1133
+ display: flex;
1134
+ align-items: center;
1135
+ justify-content: center;
1136
+ gap: 0.75rem;
1137
+ transition: transform 0.1s;
1138
+ }
1139
+
1140
+ :global(.theme-dark) .sorteo-btn-content {
1141
+ background: #020617;
1142
+ border-color: #1e293b;
1143
+ }
1144
+
1145
+ .sorteo-main-btn:active:not(:disabled) .sorteo-btn-content {
1146
+ transform: scale(0.98);
1147
+ }
1148
+
1149
+ .sorteo-btn-content span {
1150
+ font-size: 1.25rem;
1151
+ font-weight: 900;
1152
+ text-transform: uppercase;
1153
+ letter-spacing: 0.05em;
1154
+ background: linear-gradient(90deg, #4f46e5, #9333ea);
1155
+ -webkit-background-clip: text;
1156
+ -webkit-text-fill-color: transparent;
1157
+ }
1158
+
1159
+ :global(.theme-dark) .sorteo-btn-content span {
1160
+ background: linear-gradient(90deg, #818cf8, #c084fc);
1161
+ -webkit-background-clip: text;
1162
+ -webkit-text-fill-color: transparent;
1163
+ }
1164
+
1165
+ .sorteo-main-btn:disabled .sorteo-btn-content span {
1166
+ background: none;
1167
+ -webkit-text-fill-color: #475569;
1168
+ color: #475569;
1169
+ }
1170
+
1171
+ .sorteo-btn-content [data-icon] {
1172
+ width: 1.5rem;
1173
+ height: 1.5rem;
1174
+ color: #a855f7;
1175
+ }
1176
+
1177
+ .sorteo-main-btn:disabled .sorteo-btn-content [data-icon] {
1178
+ color: #475569;
1179
+ }
1180
+
1181
+ .sorteo-history {
1182
+ margin-top: 3rem;
1183
+ }
1184
+
1185
+ .sorteo-history-container {
1186
+ border-top: 1px solid var(--sorteo-border);
1187
+ padding-top: 2rem;
1188
+ }
1189
+
1190
+ .sorteo-history-title {
1191
+ font-size: 1.125rem;
1192
+ font-weight: 700;
1193
+ color: var(--sorteo-text);
1194
+ display: flex;
1195
+ align-items: center;
1196
+ gap: 0.5rem;
1197
+ margin-bottom: 1.5rem;
1198
+ }
1199
+
1200
+ .sorteo-history-title [data-icon] {
1201
+ width: 1.25rem;
1202
+ height: 1.25rem;
1203
+ opacity: 0.5;
1204
+ }
1205
+
1206
+ .sorteo-history-list {
1207
+ display: flex;
1208
+ flex-wrap: wrap;
1209
+ gap: 0.75rem;
1210
+ }
1211
+
1212
+ .sorteo-no-winners {
1213
+ font-size: 0.875rem;
1214
+ font-style: italic;
1215
+ color: var(--sorteo-text-muted);
1216
+ }
1217
+
1218
+ .sorteo-history-item {
1219
+ background: var(--sorteo-card);
1220
+ border: 1px solid var(--sorteo-border);
1221
+ border-radius: 9999px;
1222
+ padding: 0.375rem 1rem;
1223
+ font-size: 0.875rem;
1224
+ font-weight: 500;
1225
+ color: var(--sorteo-text);
1226
+ display: flex;
1227
+ align-items: center;
1228
+ gap: 0.5rem;
1229
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
1230
+ animation: zoom-in 0.3s ease-out;
1231
+ }
1232
+
1233
+ .sorteo-history-dot {
1234
+ width: 0.5rem;
1235
+ height: 0.5rem;
1236
+ border-radius: 50%;
1237
+ background: var(--sorteo-success);
1238
+ }
1239
+
1240
+ .sr-only {
1241
+ position: absolute;
1242
+ width: 1px;
1243
+ height: 1px;
1244
+ padding: 0;
1245
+ margin: -1px;
1246
+ overflow: hidden;
1247
+ clip-path: inset(50%);
1248
+ white-space: nowrap;
1249
+ border-width: 0;
1250
+ }
1251
+
1252
+ .hidden { display: none; }
1253
+
1254
+ @keyframes pulse {
1255
+ 0%, 100% { opacity: 1; }
1256
+ 50% { opacity: 0.5; }
1257
+ }
1258
+
1259
+ @keyframes ping-slow {
1260
+ 0% {
1261
+ transform: scale(1);
1262
+ opacity: 0.5;
1263
+ }
1264
+ 100% {
1265
+ transform: scale(1.5);
1266
+ opacity: 0;
1267
+ }
1268
+ }
1269
+
1270
+ .animate-ping-slow {
1271
+ animation: ping-slow 1s cubic-bezier(0, 0, 0.2, 1) infinite;
1272
+ }
1273
+
1274
+ @keyframes zoom-in {
1275
+ 0% {
1276
+ opacity: 0;
1277
+ transform: scale(0.95);
1278
+ }
1279
+ 100% {
1280
+ opacity: 1;
1281
+ transform: scale(1);
1282
+ }
1283
+ }
1284
+
1285
+ .animate-zoom-in {
1286
+ animation: zoom-in 0.5s ease-out both;
1287
+ }
1288
+
1289
+ .sorteo-confetti-particle {
1290
+ position: absolute;
1291
+ width: 8px;
1292
+ height: 8px;
1293
+ border-radius: 50%;
1294
+ z-index: 50;
1295
+ left: 50%;
1296
+ top: 50%;
1297
+ opacity: 1;
1298
+ transform: translate(0, 0) rotate(0deg) scale(0.5);
1299
+ animation: confetti-fly 1.5s cubic-bezier(0.1, 1, 0.2, 1) forwards;
1300
+ }
1301
+
1302
+ @keyframes confetti-fly {
1303
+ to {
1304
+ transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1);
1305
+ opacity: 0;
1306
+ }
1307
+ }
1308
+
1309
+ .custom-scrollbar::-webkit-scrollbar {
1310
+ width: 4px;
1311
+ }
1312
+ .custom-scrollbar::-webkit-scrollbar-track {
1313
+ background: transparent;
1314
+ }
1315
+ .custom-scrollbar::-webkit-scrollbar-thumb {
1316
+ background: var(--sorteo-border);
1317
+ border-radius: 10px;
1318
+ }
1319
+ </style>