@golstats/gsc-reports 1.0.72 → 1.0.74

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 (29) hide show
  1. package/README.md +2 -2
  2. package/dist/{FilterConditions-55d68355-DMqzcKBO-BDPZ_sNw-Ckfw9Gtc.js → FilterConditions-55d68355-DMqzcKBO-BUsV1uff-BqhmhIO7.js} +11 -11
  3. package/dist/{FilterField-59a73e38-CNaE03Ge-CLG54zqa-C4gBnorS.js → FilterField-59a73e38-CNaE03Ge-5Ufd6Qjm-CLmzz8wD.js} +4 -4
  4. package/dist/{FilterSubcategories-a9b32cc9-_h5FCZ4r-DONMEjqg-DuVYNg8C.js → FilterSubcategories-a9b32cc9-_h5FCZ4r-DcLxx26Q-CEyuCb0o.js} +1 -1
  5. package/dist/css/fonts.css +83 -83
  6. package/dist/gsc-reports.css +1 -1
  7. package/dist/gsc-reports.es.js +1 -1
  8. package/dist/gsc-reports.umd.js +340 -318
  9. package/dist/{index-SP9XZkDu.js → index-BlybwR5p.js} +117226 -103273
  10. package/package.json +3 -3
  11. package/src/App.vue +28 -0
  12. package/src/components/TemplatesSection.vue +113 -0
  13. package/src/components/elementsTemplates/FortalezasView.vue +1193 -0
  14. package/src/components/elementsTemplates/ModalConfigurarContenido.vue +1229 -0
  15. package/src/components/elementsTemplates/ModalDeleteTemplate.vue +249 -249
  16. package/src/components/elementsTemplates/ModalGenerarReporte.vue +39 -1
  17. package/src/components/elementsTemplates/ModalSoloEscritorio.vue +83 -83
  18. package/src/components/elementsTemplates/ModalduplicateTemplate.vue +300 -300
  19. package/src/components/elementsTemplates/TirosEsquinaView.vue +1071 -0
  20. package/src/components/elementsTemplates/TooltipReportOptions.vue +97 -97
  21. package/src/components/elementsTemplates/TooltipTemplateOptions.vue +168 -168
  22. package/src/components/filters.vue +935 -935
  23. package/src/components/thumbnails-reports/AnalisisPostMatchType1.vue +741 -741
  24. package/src/components/thumbnails-reports/AnalisisPostMatchType2.vue +743 -743
  25. package/src/components/thumbnails-reports/AnalisisPrematchType3.vue +173 -173
  26. package/src/components/thumbnails-reports/AnalisisPrematchType4.vue +173 -173
  27. package/src/index.js +4 -4
  28. package/src/types.d.ts +45 -45
  29. package/src/utils/dateUtils.js +52 -52
@@ -0,0 +1,1193 @@
1
+ <template>
2
+ <div class="fortalezas-view">
3
+ <div class="fortalezas-header">
4
+ <div class="team-logo-container">
5
+ <img
6
+ :src="computedTeamLogoUrl"
7
+ :alt="`Logo ${teamInitials}`"
8
+ class="team-logo"
9
+ @error="onLogoError"
10
+ />
11
+ </div>
12
+ <div class="header-content">
13
+ <h3 class="fortalezas-title">{{ title }}</h3>
14
+ <p class="fortalezas-description">
15
+ Este template contiene {{ totalFortalezas }} visualizaciones de Fortalezas. Selecciona las
16
+ deseadas.
17
+ </p>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="fortalezas-container">
22
+ <!-- Categorías - Segmented control -->
23
+ <div class="categorias-tabs segmented">
24
+ <div
25
+ class="segmented-highlight"
26
+ :style="{
27
+ width: `calc(100% / ${categorias.length})`,
28
+ left: `calc(${categorias.indexOf(categoriaActiva)} * (100% / ${categorias.length}))`,
29
+ }"
30
+ ></div>
31
+ <button
32
+ v-for="categoria in categorias"
33
+ :key="categoria"
34
+ class="categoria-tab"
35
+ :class="{ active: categoriaActiva === categoria }"
36
+ @click="selectCategoria(categoria)"
37
+ >
38
+ {{ categoria }}
39
+ </button>
40
+ </div>
41
+
42
+ <!-- Lista de fortalezas -->
43
+ <div class="fortalezas-list">
44
+ <!-- Estado de carga -->
45
+ <div v-if="isLoading" class="loading-state">
46
+ <div class="loading-spinner"></div>
47
+ <p class="loading-text">Cargando fortalezas...</p>
48
+ </div>
49
+
50
+ <!-- Estado de error -->
51
+ <div v-else-if="error" class="error-state">
52
+ <p class="error-text">Error al cargar las fortalezas: {{ error }}</p>
53
+ <button @click="fetchFortalezas" class="retry-button">Reintentar</button>
54
+ </div>
55
+
56
+ <!-- Lista de fortalezas -->
57
+ <div
58
+ v-else
59
+ v-for="fortaleza in fortalezasFiltradas"
60
+ :key="fortaleza.id"
61
+ class="fortaleza-item"
62
+ :class="{
63
+ selected: selectedFortalezas.includes(fortaleza.id),
64
+ disabled:
65
+ !selectedFortalezas.includes(fortaleza.id) &&
66
+ selectedFortalezas.length >= totalFortalezas,
67
+ }"
68
+ @click="toggleFortaleza(fortaleza.id)"
69
+ >
70
+ <div
71
+ class="fortaleza-checkbox"
72
+ @click.stop="
73
+ !selectedFortalezas.includes(fortaleza.id) &&
74
+ selectedFortalezas.length >= totalFortalezas
75
+ ? null
76
+ : toggleFortaleza(fortaleza.id)
77
+ "
78
+ >
79
+ <input
80
+ type="checkbox"
81
+ :checked="selectedFortalezas.includes(fortaleza.id)"
82
+ :disabled="
83
+ !selectedFortalezas.includes(fortaleza.id) &&
84
+ selectedFortalezas.length >= totalFortalezas
85
+ "
86
+ class="checkbox-input"
87
+ @click.stop="
88
+ !selectedFortalezas.includes(fortaleza.id) &&
89
+ selectedFortalezas.length >= totalFortalezas
90
+ ? null
91
+ : toggleFortaleza(fortaleza.id)
92
+ "
93
+ />
94
+ <span v-if="selectedFortalezas.includes(fortaleza.id)" class="selection-number">
95
+ {{ selectionOrderMap[fortaleza.id] }}
96
+ </span>
97
+ </div>
98
+ <div class="fortaleza-badge">{{ fortaleza.value }}</div>
99
+ <div class="fortaleza-content">
100
+ <div class="fortaleza-name">{{ fortaleza.name }}</div>
101
+ <div class="fortaleza-ranking">
102
+ <span>{{ fortaleza.ranking }}</span>
103
+ <img
104
+ src="https://golstatsimages.blob.core.windows.net/golstats2-tournaments/1.png"
105
+ alt="Liga"
106
+ class="league-logo"
107
+ @error="onLeagueLogoError"
108
+ />
109
+ <div class="separator"></div>
110
+ <div class="category-indicator">
111
+ <div class="category-dot" :style="{ backgroundColor: fortaleza.color }"></div>
112
+ <span>{{ fortaleza.category }}</span>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+
120
+ <!-- Footer con contador y carrusel -->
121
+ <div class="fortalezas-footer">
122
+ <!-- Contador izquierdo - solo si hay fortalezas seleccionadas -->
123
+ <div v-if="selectedFortalezas.length > 0" class="counter-section">
124
+ <div class="counter-text">{{ selectedFortalezas.length }}/{{ totalFortalezas }}</div>
125
+ </div>
126
+
127
+ <!-- Carrusel derecho - solo si hay fortalezas seleccionadas -->
128
+ <div v-if="selectedFortalezas.length > 0" class="carousel-section">
129
+ <div class="carousel-container" ref="carouselContainerRef">
130
+ <button v-if="showLeftArrow" class="carousel-arrow left" @click="scrollLeft">‹</button>
131
+ <div class="carousel-track" ref="carouselTrackRef" :style="carouselTrackStyle">
132
+ <div
133
+ v-for="fortaleza in selectedFortalezasData"
134
+ :key="fortaleza.id"
135
+ class="footer-pill"
136
+ >
137
+ <div class="footer-badge">{{ fortaleza.value }}</div>
138
+ <div class="footer-content">
139
+ <div class="footer-name">{{ fortaleza.name }}</div>
140
+ <div class="footer-ranking">
141
+ <span>{{ fortaleza.ranking }}</span>
142
+ <img
143
+ src="https://golstatsimages.blob.core.windows.net/golstats2-tournaments/1.png"
144
+ alt="Liga"
145
+ class="footer-league-logo"
146
+ @error="onLeagueLogoError"
147
+ />
148
+ <div class="footer-separator"></div>
149
+ <div class="footer-category-indicator">
150
+ <div
151
+ class="footer-category-dot"
152
+ :style="{ backgroundColor: fortaleza.color }"
153
+ ></div>
154
+ <span>{{ fortaleza.category }}</span>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ <button class="pill-remove-btn" @click="removeFortaleza(fortaleza.id)">×</button>
159
+ </div>
160
+ </div>
161
+ <!-- Flecha derecha -->
162
+ <button v-if="showRightArrow" class="carousel-arrow right" @click="scrollRight">›</button>
163
+ </div>
164
+ </div>
165
+
166
+ <!-- Mensaje cuando no hay fortalezas seleccionadas - full width -->
167
+ <div v-else class="empty-message-full">
168
+ <span class="empty-text"
169
+ >{{ selectedFortalezas.length }} de {{ totalFortalezas }} Fortalezas agregadas</span
170
+ >
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </template>
175
+
176
+ <script setup>
177
+ import { ref, computed, reactive, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
178
+
179
+ const props = defineProps({
180
+ teamInitials: {
181
+ type: String,
182
+ default: 'CA',
183
+ },
184
+ title: {
185
+ type: String,
186
+ default: 'Fortalezas a favor de mi equipo',
187
+ },
188
+ modelValue: {
189
+ type: Array,
190
+ default: () => [],
191
+ },
192
+ teamLogoUrl: {
193
+ type: String,
194
+ required: false,
195
+ default: null,
196
+ },
197
+ seasonId: {
198
+ type: [String, Number],
199
+ required: true,
200
+ },
201
+ teamId: {
202
+ type: [String, Number],
203
+ required: true,
204
+ },
205
+ token: {
206
+ type: String,
207
+ required: true,
208
+ },
209
+ totalFortalezas: {
210
+ type: Number,
211
+ default: 15,
212
+ },
213
+ rivalTeamId: {
214
+ type: [String, Number],
215
+ required: false,
216
+ default: null,
217
+ },
218
+ })
219
+
220
+ const emit = defineEmits(['update:modelValue'])
221
+
222
+ // Computed para generar la URL del logo basándose en teamId
223
+ const computedTeamLogoUrl = computed(() => {
224
+ // Si se proporciona teamLogoUrl explícitamente, usarlo
225
+ if (props.teamLogoUrl) {
226
+ return props.teamLogoUrl
227
+ }
228
+ // Si no, generar la URL basándose en teamId
229
+ if (props.teamId) {
230
+ return `https://golstatsimages.blob.core.windows.net/teams-80/${props.teamId}.png`
231
+ }
232
+ // Fallback
233
+ return 'https://golstatsimages.blob.core.windows.net/teams-80/2.png'
234
+ })
235
+
236
+ // Fortalezas seleccionadas
237
+ const selectedFortalezas = ref([...props.modelValue])
238
+ const selectionOrderMap = reactive({})
239
+
240
+ // Estados para la carga de datos
241
+ const isLoading = ref(false)
242
+ const error = ref(null)
243
+
244
+ // Watch para sincronizar modelValue con selectedFortalezas
245
+ watch(
246
+ () => props.modelValue,
247
+ (newValue) => {
248
+ // Asegurarse de que sea un array válido
249
+ if (Array.isArray(newValue)) {
250
+ // Solo actualizar si hay cambios para evitar loops
251
+ const currentIds = JSON.stringify([...selectedFortalezas.value].sort())
252
+ const newIds = JSON.stringify([...newValue].sort())
253
+
254
+ if (currentIds !== newIds) {
255
+ selectedFortalezas.value = [...newValue]
256
+ // Reiniciar el mapa de orden
257
+ Object.keys(selectionOrderMap).forEach((key) => delete selectionOrderMap[key])
258
+ // Inicializar mapa de orden con las selecciones
259
+ selectedFortalezas.value.forEach((id, idx) => {
260
+ selectionOrderMap[id] = idx + 1
261
+ })
262
+ }
263
+ }
264
+ },
265
+ { immediate: true, deep: true },
266
+ )
267
+
268
+ // Carrusel de fortalezas seleccionadas
269
+ const carouselScrollLeft = ref(0)
270
+ const carouselContainerRef = ref(null)
271
+ const carouselTrackRef = ref(null)
272
+ const containerWidth = ref(0)
273
+ const trackWidth = ref(0)
274
+
275
+ // Medir tamaños para overflow
276
+ function measureCarousel() {
277
+ const container = carouselContainerRef.value
278
+ const track = carouselTrackRef.value
279
+ containerWidth.value = container ? container.clientWidth : 0
280
+ trackWidth.value = track ? track.scrollWidth : 0
281
+ }
282
+
283
+ // Calcular overflow y mostrar flechas
284
+ const maxScroll = computed(() => Math.max(0, trackWidth.value - containerWidth.value))
285
+
286
+ const showLeftArrow = computed(() => carouselScrollLeft.value > 0)
287
+ const showRightArrow = computed(() => carouselScrollLeft.value < maxScroll.value)
288
+
289
+ // Función para scroll hacia la derecha
290
+ function scrollRight() {
291
+ const next = Math.min(maxScroll.value, carouselScrollLeft.value + 200)
292
+ carouselScrollLeft.value = next
293
+ }
294
+
295
+ function scrollLeft() {
296
+ const next = Math.max(0, carouselScrollLeft.value - 200)
297
+ carouselScrollLeft.value = next
298
+ }
299
+
300
+ let carouselResizeHandler = null
301
+
302
+ onMounted(() => {
303
+ measureCarousel()
304
+ const onResize = () => measureCarousel()
305
+ window.addEventListener('resize', onResize)
306
+ carouselResizeHandler = onResize
307
+ console.log('FetchFortalezas')
308
+ // Cargar fortalezas al montar el componente
309
+ fetchFortalezas()
310
+ })
311
+
312
+ onBeforeUnmount(() => {
313
+ if (carouselResizeHandler) {
314
+ window.removeEventListener('resize', carouselResizeHandler)
315
+ carouselResizeHandler = null
316
+ }
317
+ })
318
+
319
+ // Re-medir cuando cambia el contenido seleccionado
320
+ watch(
321
+ () => selectedFortalezas.value.slice(),
322
+ async () => {
323
+ await nextTick()
324
+ measureCarousel()
325
+ },
326
+ { deep: true },
327
+ )
328
+
329
+ // Recargar fortalezas cuando cambien seasonId, teamId o token
330
+ watch(
331
+ () => [props.seasonId, props.teamId, props.token],
332
+ () => {
333
+ fetchFortalezas()
334
+ },
335
+ { immediate: false },
336
+ )
337
+
338
+ // Datos de fortalezas seleccionadas ordenadas por número
339
+ const selectedFortalezasData = computed(() => {
340
+ return selectedFortalezas.value
341
+ .map((id) => fortalezasData.value.find((f) => f.id === id))
342
+ .filter(Boolean)
343
+ .sort((a, b) => selectionOrderMap[a.id] - selectionOrderMap[b.id])
344
+ })
345
+
346
+ // Estilo del track del carrusel
347
+ const carouselTrackStyle = computed(() => {
348
+ return {
349
+ transform: `translateX(-${carouselScrollLeft.value}px)`,
350
+ }
351
+ })
352
+
353
+ // Datos de fortalezas obtenidos del API (formato transformado para el componente)
354
+ const fortalezasData = ref([])
355
+ // Datos originales del API para enviar al endpoint
356
+ const fortalezasRawData = ref([])
357
+
358
+ // Función para obtener fortalezas desde el endpoint
359
+ async function fetchFortalezas() {
360
+ if (!props.seasonId || !props.teamId) {
361
+ console.warn('seasonId y teamId son requeridos para obtener las fortalezas')
362
+ return
363
+ }
364
+
365
+ isLoading.value = true
366
+ error.value = null
367
+
368
+ try {
369
+ const url = `https://5c9xc3gwh2.execute-api.us-east-2.amazonaws.com/prod/strengths/seasons/${props.seasonId}/teams/${props.teamId}`
370
+ const response = await fetch(url, {
371
+ method: 'GET',
372
+ headers: {
373
+ Authorization: `${props.token}`,
374
+ 'Content-Type': 'application/json',
375
+ },
376
+ })
377
+
378
+ if (!response.ok) {
379
+ throw new Error(`Error al obtener fortalezas: ${response.status} ${response.statusText}`)
380
+ }
381
+
382
+ const data = await response.json()
383
+ console.log('data: ', data)
384
+
385
+ // Guardar los datos originales del API
386
+ fortalezasRawData.value = data.strengths || []
387
+
388
+ // Mapear los datos del API al formato esperado por el componente
389
+ fortalezasData.value = data.strengths.map((item) => ({
390
+ id: item.categories,
391
+ name: item.name,
392
+ value: item.total,
393
+ category:
394
+ item.category_type == 1 ? 'Ofensiva' : item.category_type == 2 ? 'Posesion' : 'Defensiva',
395
+ ranking: `#${item.league_ranking} en la liga`,
396
+ color: getCategoryColor(item.category_type || 'General'),
397
+ }))
398
+
399
+ // Actualizar categorías después de cargar los datos
400
+ updateCategorias()
401
+ } catch (err) {
402
+ console.error('Error al cargar fortalezas:', err)
403
+ error.value = err.message
404
+ // Mantener datos vacíos en caso de error
405
+ fortalezasData.value = []
406
+ } finally {
407
+ isLoading.value = false
408
+ }
409
+ }
410
+
411
+ // Función para obtener color según la categoría
412
+ function getCategoryColor(category) {
413
+ const colorMap = {
414
+ 1: '#4CAF50',
415
+ 3: '#2196F3',
416
+ 2: '#00BCD4',
417
+ General: '#9C27B0',
418
+ }
419
+ return colorMap[category] || '#9C27B0'
420
+ }
421
+
422
+ // Categorías dinámicas basadas en los datos del API
423
+ const categorias = ref(['Todos'])
424
+ const categoriaActiva = ref('Todos')
425
+
426
+ // Actualizar categorías cuando se cargan los datos
427
+ function updateCategorias() {
428
+ const uniqueCategories = [...new Set(fortalezasData.value.map((f) => f.category))]
429
+ categorias.value = ['Todos', ...uniqueCategories]
430
+ }
431
+
432
+ // Filtrar fortalezas por categoría
433
+ const fortalezasFiltradas = computed(() => {
434
+ if (categoriaActiva.value === 'Todos') {
435
+ return fortalezasData.value
436
+ }
437
+ return fortalezasData.value.filter((f) => f.category === categoriaActiva.value)
438
+ })
439
+
440
+ function toggleFortaleza(fortalezaId) {
441
+ const index = selectedFortalezas.value.indexOf(fortalezaId)
442
+ if (index > -1) {
443
+ // deseleccionar: quitar del array y mantener números sin reordenar
444
+ selectedFortalezas.value.splice(index, 1)
445
+ delete selectionOrderMap[fortalezaId]
446
+ } else {
447
+ // Validar que no se exceda el máximo de visualizaciones permitidas
448
+ if (selectedFortalezas.value.length >= props.totalFortalezas) {
449
+ return // No permitir seleccionar más del máximo
450
+ }
451
+
452
+ // seleccionar: asignar el número más bajo disponible
453
+ const total = fortalezasData.value.length
454
+ const usedNumbers = new Set(Object.values(selectionOrderMap))
455
+
456
+ // encontrar el primer número disponible (1, 2, 3, ...)
457
+ let nextNumber = 1
458
+ while (usedNumbers.has(nextNumber) && nextNumber <= total) {
459
+ nextNumber++
460
+ }
461
+
462
+ selectionOrderMap[fortalezaId] = nextNumber
463
+ selectedFortalezas.value.push(fortalezaId)
464
+ }
465
+ emit('update:modelValue', selectedFortalezas.value)
466
+ }
467
+
468
+ function selectCategoria(categoria) {
469
+ categoriaActiva.value = categoria
470
+ }
471
+
472
+ function removeFortaleza(fortalezaId) {
473
+ const index = selectedFortalezas.value.indexOf(fortalezaId)
474
+ if (index > -1) {
475
+ selectedFortalezas.value.splice(index, 1)
476
+ delete selectionOrderMap[fortalezaId]
477
+ emit('update:modelValue', selectedFortalezas.value)
478
+ }
479
+ }
480
+
481
+ function autocompletar() {
482
+ const total = fortalezasData.value.length
483
+ const alreadySelected = new Set(selectedFortalezas.value)
484
+ const usedNumbers = new Set(Object.values(selectionOrderMap))
485
+
486
+ // números faltantes 1..total que no están usados
487
+ const missingNumbers = []
488
+ for (let n = 1; n <= total; n++) {
489
+ if (!usedNumbers.has(n)) missingNumbers.push(n)
490
+ }
491
+ // orden ascendente para asignar secuencialmente
492
+ missingNumbers.sort((a, b) => a - b)
493
+
494
+ // ids que faltan por seleccionar, en el orden ACTUAL visible (arriba -> abajo)
495
+ const remainingIds = fortalezasFiltradas.value
496
+ .map((f) => f.id)
497
+ .filter((id) => !alreadySelected.has(id))
498
+
499
+ // Calcular cuántos se pueden agregar sin exceder el máximo
500
+ const maxPermitido = props.totalFortalezas
501
+
502
+ for (const id of remainingIds) {
503
+ // Verificar que no se exceda el máximo
504
+ if (selectedFortalezas.value.length >= maxPermitido) {
505
+ break
506
+ }
507
+
508
+ const num = missingNumbers.shift()
509
+ if (num === undefined) break
510
+ selectionOrderMap[id] = num
511
+ selectedFortalezas.value.push(id)
512
+ }
513
+
514
+ emit('update:modelValue', selectedFortalezas.value)
515
+ }
516
+
517
+ function onLogoError() {
518
+ console.warn('Error loading team logo, falling back to initials')
519
+ }
520
+
521
+ function onLeagueLogoError() {
522
+ console.warn('Error loading league logo')
523
+ }
524
+
525
+ // Exponer función autocompletar para uso externo
526
+ // Exponer datos para que el componente padre pueda acceder
527
+ defineExpose({
528
+ fortalezasData,
529
+ fortalezasRawData,
530
+ selectedFortalezas,
531
+ selectionOrderMap,
532
+ autocompletar,
533
+ })
534
+ </script>
535
+
536
+ <style scoped>
537
+ .fortalezas-view {
538
+ width: 100%;
539
+ }
540
+
541
+ .fortalezas-header {
542
+ display: flex;
543
+ align-items: flex-start;
544
+ gap: 16px;
545
+ margin-bottom: 20px;
546
+ }
547
+
548
+ .team-logo-container {
549
+ width: 64px;
550
+ height: 64px;
551
+ border-radius: 12px;
552
+ background-color: rgba(255, 255, 255, 0.05);
553
+ display: flex;
554
+ align-items: center;
555
+ justify-content: center;
556
+ padding: 6px;
557
+ flex-shrink: 0;
558
+ }
559
+
560
+ .team-logo {
561
+ width: 40px;
562
+ height: 40px;
563
+ border-radius: 4px;
564
+ object-fit: contain;
565
+ background: transparent;
566
+ }
567
+
568
+ .header-content {
569
+ flex: 1;
570
+ display: flex;
571
+ flex-direction: column;
572
+ gap: 6px;
573
+ }
574
+
575
+ .fortalezas-title {
576
+ font-family: Poppins-Medium;
577
+ font-size: 14px;
578
+ font-weight: 500;
579
+ opacity: 0.8;
580
+ color: #fff;
581
+ margin: 0;
582
+ }
583
+
584
+ .fortalezas-description {
585
+ font-family: Poppins-Regular;
586
+ font-size: 13px;
587
+ color: rgba(255, 255, 255, 0.5);
588
+ margin: 0;
589
+ line-height: 1.4;
590
+ }
591
+
592
+ .fortalezas-container {
593
+ border-radius: 8px;
594
+ border: solid 1px rgba(224, 231, 240, 0.3);
595
+ padding-left: 10px;
596
+ padding-right: 10px;
597
+ padding-top: 10px;
598
+ }
599
+
600
+ /* Segmented control styles */
601
+ .categorias-tabs.segmented {
602
+ position: relative;
603
+ display: flex;
604
+ align-items: center;
605
+ gap: 0;
606
+ border: 1px solid rgba(224, 231, 240, 0.3);
607
+ border-radius: 999px;
608
+ padding: 0;
609
+ overflow: hidden;
610
+ }
611
+
612
+ .segmented-highlight {
613
+ position: absolute;
614
+ top: 0;
615
+ bottom: 0;
616
+ left: 0;
617
+ border-radius: 999px;
618
+ border: 1px solid #cbee6b;
619
+ pointer-events: none;
620
+ transition:
621
+ left 220ms ease,
622
+ width 220ms ease;
623
+ }
624
+
625
+ .categorias-tabs.segmented .categoria-tab {
626
+ position: relative;
627
+ flex: 1 1 0;
628
+ background: transparent;
629
+ border: none;
630
+ color: rgba(255, 255, 255, 0.6);
631
+ padding: 8px 12px;
632
+ font-family: Poppins-Regular;
633
+ font-size: 12px;
634
+ cursor: pointer;
635
+ z-index: 1;
636
+ }
637
+
638
+ .categorias-tabs.segmented .categoria-tab.active {
639
+ color: #fff;
640
+ }
641
+
642
+ .categorias-tabs {
643
+ display: flex;
644
+ gap: 8px;
645
+ margin-bottom: 20px;
646
+ }
647
+
648
+ .categoria-tab {
649
+ padding: 8px 16px;
650
+ border-radius: 20px;
651
+ border: 1px solid rgba(255, 255, 255, 0.3);
652
+ background: transparent;
653
+ color: rgba(255, 255, 255, 0.7);
654
+ font-family: Poppins-Regular;
655
+ font-size: 12px;
656
+ cursor: pointer;
657
+ transition: all 0.2s ease;
658
+ }
659
+
660
+ .categoria-tab.active {
661
+ border-color: #cbee6b;
662
+ background: rgba(203, 238, 107, 0.1);
663
+ color: #cbee6b;
664
+ }
665
+
666
+ .categoria-tab:hover {
667
+ border-color: #cbee6b;
668
+ color: #cbee6b;
669
+ }
670
+
671
+ .fortalezas-list {
672
+ max-height: 260px;
673
+ overflow-y: auto;
674
+ margin-bottom: 20px;
675
+ scrollbar-width: thin;
676
+ scrollbar-color: rgba(255, 255, 255, 0.3) #2e3b46;
677
+ }
678
+
679
+ .fortalezas-list::-webkit-scrollbar {
680
+ width: 6px;
681
+ }
682
+
683
+ .fortalezas-list::-webkit-scrollbar-track {
684
+ background: #2e3b46;
685
+ border-radius: 3px;
686
+ }
687
+
688
+ .fortalezas-list::-webkit-scrollbar-thumb {
689
+ background: rgba(255, 255, 255, 0.3);
690
+ border-radius: 3px;
691
+ }
692
+
693
+ .fortaleza-item {
694
+ display: flex;
695
+ align-items: center;
696
+ gap: 12px;
697
+ padding: 12px;
698
+ cursor: pointer;
699
+ transition: background 0.2s ease;
700
+ margin-bottom: 8px;
701
+ border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
702
+ }
703
+
704
+ /* Opacidad por defecto cuando no está seleccionado */
705
+ .fortaleza-item :is(.fortaleza-name, .fortaleza-ranking, .fortaleza-badge) {
706
+ opacity: 0.7;
707
+ }
708
+
709
+ /* Al seleccionar se restaura a 1 */
710
+ .fortaleza-item.selected :is(.fortaleza-name, .fortaleza-ranking, .fortaleza-badge) {
711
+ opacity: 1;
712
+ }
713
+
714
+ .fortaleza-item:last-child {
715
+ border-bottom: none;
716
+ }
717
+
718
+ .fortaleza-item.disabled {
719
+ opacity: 0.4;
720
+ cursor: not-allowed;
721
+ pointer-events: none;
722
+ }
723
+
724
+ .fortaleza-item.disabled .fortaleza-checkbox {
725
+ cursor: not-allowed;
726
+ pointer-events: none;
727
+ }
728
+
729
+ .fortaleza-item.disabled .checkbox-input {
730
+ cursor: not-allowed;
731
+ }
732
+
733
+ .fortaleza-item.selected {
734
+ background: transparent;
735
+ border: 1px solid rgba(255, 255, 255, 0.2);
736
+ }
737
+
738
+ .fortaleza-checkbox {
739
+ position: relative;
740
+ width: 20px;
741
+ height: 20px;
742
+ flex-shrink: 0;
743
+ }
744
+
745
+ .checkbox-input {
746
+ width: 20px;
747
+ height: 20px;
748
+ border: 2px solid rgba(255, 255, 255, 0.3);
749
+ border-radius: 4px;
750
+ background: transparent;
751
+ cursor: pointer;
752
+ position: relative;
753
+ transition: all 0.2s ease;
754
+ appearance: none;
755
+ -webkit-appearance: none;
756
+ -moz-appearance: none;
757
+ }
758
+
759
+ .checkbox-input:checked {
760
+ background: #cbee6b;
761
+ border-color: #cbee6b;
762
+ }
763
+
764
+ .selection-number {
765
+ position: absolute;
766
+ top: 50%;
767
+ left: 50%;
768
+ transform: translate(-50%, -50%);
769
+ color: #000;
770
+ font-size: 12px;
771
+ font-weight: bold;
772
+ font-family: Poppins-Bold;
773
+ pointer-events: none;
774
+ }
775
+
776
+ .fortaleza-badge {
777
+ width: 54px;
778
+ height: 54px;
779
+ padding: 6px 8px;
780
+ box-shadow: 0 12.4px 49.8px 0 rgba(0, 0, 0, 0.08);
781
+ border-style: solid;
782
+ border-width: 1px;
783
+ border: 8px;
784
+ border-image-source: linear-gradient(
785
+ 138deg,
786
+ rgba(255, 255, 255, 0.2) 2%,
787
+ rgba(255, 255, 255, 0.1) 14%,
788
+ rgba(255, 255, 255, 0) 77%,
789
+ rgba(255, 255, 255, 0.2) 100%
790
+ );
791
+ border-image-slice: 1;
792
+ background-blend-mode: color-dodge;
793
+ background-image:
794
+ linear-gradient(to bottom, rgba(50, 50, 50, 0), rgba(50, 50, 50, 0)),
795
+ linear-gradient(
796
+ 138deg,
797
+ rgba(255, 255, 255, 0.2) 2%,
798
+ rgba(255, 255, 255, 0.1) 14%,
799
+ rgba(255, 255, 255, 0) 77%,
800
+ rgba(255, 255, 255, 0.2) 100%
801
+ );
802
+ background-origin: border-box;
803
+ background-clip: content-box, border-box;
804
+ display: flex;
805
+ align-items: center;
806
+ justify-content: center;
807
+ font-family: Poppins-SemiBold;
808
+ border-radius: 10.4px;
809
+ font-size: 20.7px;
810
+ font-weight: 600;
811
+ color: #fff;
812
+ flex-shrink: 0;
813
+ }
814
+
815
+ .fortaleza-content {
816
+ flex: 1;
817
+ min-width: 0;
818
+ }
819
+
820
+ .fortaleza-name {
821
+ font-family: Poppins-Regular;
822
+ font-size: 13px;
823
+ color: #fff;
824
+ margin-bottom: 4px;
825
+ line-height: 1.3;
826
+ }
827
+
828
+ .fortaleza-ranking {
829
+ font-family: Poppins-Regular;
830
+ font-size: 11px;
831
+ color: rgba(255, 255, 255, 0.6);
832
+ display: flex;
833
+ align-items: center;
834
+ gap: 6px;
835
+ }
836
+
837
+ .league-logo {
838
+ width: 16px;
839
+ height: 16px;
840
+ border-radius: 2px;
841
+ object-fit: contain;
842
+ }
843
+
844
+ .separator {
845
+ width: 1px;
846
+ height: 12px;
847
+ background-color: rgba(255, 255, 255, 0.3);
848
+ margin: 0 6px;
849
+ }
850
+
851
+ .category-indicator {
852
+ display: flex;
853
+ align-items: center;
854
+ gap: 4px;
855
+ }
856
+
857
+ .category-dot {
858
+ width: 6px;
859
+ height: 6px;
860
+ border-radius: 50%;
861
+ }
862
+
863
+ .category-indicator span {
864
+ font-family: Poppins-Regular;
865
+ font-size: 10px;
866
+ color: rgba(255, 255, 255, 0.7);
867
+ }
868
+
869
+ /* Footer con contador y carrusel */
870
+ .fortalezas-footer {
871
+ display: flex;
872
+ gap: 16px;
873
+ margin-top: 20px;
874
+ width: 100%;
875
+ }
876
+
877
+ .counter-section {
878
+ width: 59px;
879
+ height: 68px;
880
+ flex-grow: 0;
881
+ display: flex;
882
+ flex-direction: row;
883
+ justify-content: center;
884
+ align-items: center;
885
+ gap: 16px;
886
+ padding: 12px;
887
+ border-radius: 8px;
888
+ border: solid 1px rgba(255, 255, 255, 0.1);
889
+ background-color: rgba(255, 255, 255, 0.02);
890
+ }
891
+
892
+ .counter-text {
893
+ font-family: Poppins-Regular;
894
+ font-size: 12px;
895
+ font-weight: normal;
896
+ font-stretch: normal;
897
+ font-style: normal;
898
+ line-height: 1.33;
899
+ letter-spacing: 1.2px;
900
+ text-align: center;
901
+ color: #fff;
902
+ }
903
+
904
+ .carousel-section {
905
+ flex: 1;
906
+ width: 332px;
907
+ height: 72px;
908
+ flex-grow: 0;
909
+ display: flex;
910
+ flex-direction: row;
911
+ justify-content: flex-start;
912
+ align-items: center;
913
+ gap: 16px;
914
+ border-radius: 8px;
915
+ position: relative;
916
+ }
917
+
918
+ .carousel-container {
919
+ overflow: hidden;
920
+ width: 100%;
921
+ height: 100%;
922
+ position: relative;
923
+ display: flex;
924
+ align-items: center;
925
+ }
926
+
927
+ .carousel-track {
928
+ display: flex;
929
+ gap: 8px;
930
+ transition: transform 0.3s ease;
931
+ min-width: max-content;
932
+ height: 100%;
933
+ align-items: center;
934
+ z-index: 1;
935
+ }
936
+
937
+ .footer-pill {
938
+ display: flex;
939
+ align-items: center;
940
+ gap: 12px;
941
+ padding: 12px;
942
+ padding-left: 12px;
943
+ padding-right: 12px;
944
+ padding-top: 12px;
945
+ padding-bottom: 12px;
946
+ border-radius: 8px;
947
+ cursor: pointer;
948
+ transition: background 0.2s ease;
949
+ background: rgba(255, 255, 255, 0.05);
950
+ flex-shrink: 0;
951
+ height: fit-content;
952
+ min-width: 250px;
953
+ position: relative;
954
+ }
955
+
956
+ .footer-pill:hover {
957
+ background: rgba(255, 255, 255, 0.1);
958
+ }
959
+
960
+ .footer-pill .footer-badge {
961
+ width: 54px;
962
+ height: 54px;
963
+ padding: 6px 8px;
964
+ border-radius: 10.4px;
965
+ box-shadow: 0 12.4px 49.8px 0 rgba(0, 0, 0, 0.08);
966
+ border-image-slice: 1;
967
+ background-blend-mode: color-dodge;
968
+ background-image:
969
+ linear-gradient(to bottom, rgba(50, 50, 50, 0), rgba(50, 50, 50, 0)),
970
+ linear-gradient(
971
+ 138deg,
972
+ rgba(255, 255, 255, 0.2) 2%,
973
+ rgba(255, 255, 255, 0.1) 14%,
974
+ rgba(255, 255, 255, 0) 77%,
975
+ rgba(255, 255, 255, 0.2) 100%
976
+ );
977
+ background-origin: border-box;
978
+ background-clip: content-box, border-box;
979
+ display: flex;
980
+ align-items: center;
981
+ justify-content: center;
982
+ font-family: Poppins-SemiBold;
983
+ font-size: 20.7px;
984
+ font-weight: 600;
985
+ color: #fff;
986
+ flex-shrink: 0;
987
+ }
988
+
989
+ .footer-pill .footer-content {
990
+ flex: 1;
991
+ display: flex;
992
+ flex-direction: column;
993
+ gap: 4px;
994
+ }
995
+
996
+ .footer-pill .footer-name {
997
+ font-family: Poppins-Medium;
998
+ font-size: 14px;
999
+ font-weight: 500;
1000
+ color: #fff;
1001
+ margin-bottom: 4px;
1002
+ line-height: 1.3;
1003
+ }
1004
+
1005
+ .footer-pill .footer-ranking {
1006
+ font-family: Poppins-Regular;
1007
+ font-size: 11px;
1008
+ color: rgba(255, 255, 255, 0.6);
1009
+ display: flex;
1010
+ align-items: center;
1011
+ gap: 6px;
1012
+ }
1013
+
1014
+ .footer-pill .footer-league-logo {
1015
+ width: 16px;
1016
+ height: 16px;
1017
+ border-radius: 2px;
1018
+ object-fit: contain;
1019
+ }
1020
+
1021
+ .footer-pill .footer-separator {
1022
+ width: 1px;
1023
+ height: 12px;
1024
+ background-color: rgba(255, 255, 255, 0.3);
1025
+ margin: 0 6px;
1026
+ }
1027
+
1028
+ .footer-pill .footer-category-indicator {
1029
+ display: flex;
1030
+ align-items: center;
1031
+ gap: 4px;
1032
+ }
1033
+
1034
+ .footer-pill .footer-category-dot {
1035
+ width: 6px;
1036
+ height: 6px;
1037
+ border-radius: 50%;
1038
+ }
1039
+
1040
+ .footer-pill .footer-category-indicator span {
1041
+ font-family: Poppins-Regular;
1042
+ font-size: 10px;
1043
+ color: rgba(255, 255, 255, 0.7);
1044
+ }
1045
+
1046
+ .pill-remove-btn {
1047
+ background: none;
1048
+ border: none;
1049
+ color: rgba(255, 255, 255, 0.7);
1050
+ font-size: 18px;
1051
+ font-weight: bold;
1052
+ cursor: pointer;
1053
+ padding: 0;
1054
+ margin-left: auto;
1055
+ line-height: 1;
1056
+ opacity: 0.7;
1057
+ transition: opacity 0.2s ease;
1058
+ width: 20px;
1059
+ height: 20px;
1060
+ margin-top: -40px;
1061
+ margin-right: -8px;
1062
+ display: flex;
1063
+ align-items: center;
1064
+ justify-content: center;
1065
+ }
1066
+
1067
+ .pill-remove-btn:hover {
1068
+ opacity: 1;
1069
+ color: #fff;
1070
+ }
1071
+
1072
+ .carousel-arrow {
1073
+ position: absolute;
1074
+ top: 50%;
1075
+ transform: translateY(-50%);
1076
+ background: rgba(255, 255, 255, 0.1);
1077
+ border: 1px solid rgba(255, 255, 255, 0.2);
1078
+ color: #fff;
1079
+ width: 32px;
1080
+ height: 32px;
1081
+ border-radius: 50%;
1082
+ display: flex;
1083
+ align-items: center;
1084
+ justify-content: center;
1085
+ cursor: pointer;
1086
+ font-size: 18px;
1087
+ font-weight: bold;
1088
+ transition: all 0.2s ease;
1089
+ z-index: 2;
1090
+ }
1091
+
1092
+ .carousel-arrow:hover {
1093
+ background: rgba(255, 255, 255, 0.2);
1094
+ border-color: rgba(255, 255, 255, 0.3);
1095
+ }
1096
+
1097
+ .carousel-arrow.right {
1098
+ right: 8px;
1099
+ }
1100
+ .carousel-arrow.left {
1101
+ left: 8px;
1102
+ }
1103
+
1104
+ .empty-message-full {
1105
+ width: 100%;
1106
+ height: 72px;
1107
+ display: flex;
1108
+ flex-direction: row;
1109
+ justify-content: center;
1110
+ align-items: center;
1111
+ padding: 12px;
1112
+ border-radius: 8px;
1113
+ background-color: rgba(255, 255, 255, 0.05);
1114
+ position: relative;
1115
+ }
1116
+
1117
+ .empty-text {
1118
+ font-family: Poppins-Regular;
1119
+ font-size: 12px;
1120
+ color: rgba(255, 255, 255, 0.7);
1121
+ text-align: center;
1122
+ width: 100%;
1123
+ }
1124
+
1125
+ /* Estados de carga y error */
1126
+ .loading-state {
1127
+ display: flex;
1128
+ flex-direction: column;
1129
+ align-items: center;
1130
+ justify-content: center;
1131
+ padding: 40px 20px;
1132
+ gap: 16px;
1133
+ }
1134
+
1135
+ .loading-spinner {
1136
+ width: 32px;
1137
+ height: 32px;
1138
+ border: 3px solid rgba(255, 255, 255, 0.3);
1139
+ border-top: 3px solid #cbee6b;
1140
+ border-radius: 50%;
1141
+ animation: spin 1s linear infinite;
1142
+ }
1143
+
1144
+ @keyframes spin {
1145
+ 0% {
1146
+ transform: rotate(0deg);
1147
+ }
1148
+ 100% {
1149
+ transform: rotate(360deg);
1150
+ }
1151
+ }
1152
+
1153
+ .loading-text {
1154
+ font-family: Poppins-Regular;
1155
+ font-size: 14px;
1156
+ color: rgba(255, 255, 255, 0.7);
1157
+ margin: 0;
1158
+ }
1159
+
1160
+ .error-state {
1161
+ display: flex;
1162
+ flex-direction: column;
1163
+ align-items: center;
1164
+ justify-content: center;
1165
+ padding: 40px 20px;
1166
+ gap: 16px;
1167
+ }
1168
+
1169
+ .error-text {
1170
+ font-family: Poppins-Regular;
1171
+ font-size: 14px;
1172
+ color: #ff6b6b;
1173
+ margin: 0;
1174
+ text-align: center;
1175
+ }
1176
+
1177
+ .retry-button {
1178
+ background: #cbee6b;
1179
+ color: #000;
1180
+ border: none;
1181
+ padding: 8px 16px;
1182
+ border-radius: 6px;
1183
+ font-family: Poppins-Medium;
1184
+ font-size: 12px;
1185
+ font-weight: 500;
1186
+ cursor: pointer;
1187
+ transition: background 0.2s ease;
1188
+ }
1189
+
1190
+ .retry-button:hover {
1191
+ background: #b8d85a;
1192
+ }
1193
+ </style>