diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..74b3aa7 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,109 @@ +# Ocultar headers de servidor + + Header unset X-Powered-By + Header always unset X-Powered-By + Header unset Server + + +# Bloquear acceso a archivos sensibles + + Order allow,deny + Deny from all + + +# ============================================================ +# Compresion (Brotli si esta, Gzip como fallback) +# ============================================================ + + AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml application/atom+xml image/svg+xml font/ttf font/otf application/vnd.ms-fontobject + + + AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml application/atom+xml image/svg+xml font/ttf font/otf application/vnd.ms-fontobject + + +# ============================================================ +# Cache-Control para estaticos +# ============================================================ + + ExpiresActive On + ExpiresDefault "access plus 1 month" + + # HTML y JSON: no cachear (siempre frescos) + ExpiresByType text/html "access plus 0 seconds" + ExpiresByType application/json "access plus 0 seconds" + ExpiresByType application/manifest+json "access plus 1 day" + + # CSS y JS: 1 anio (con cache-busting via ?v= o hash de Vite) + ExpiresByType text/css "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType text/javascript "access plus 1 year" + + # Imagenes: 1 anio + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/webp "access plus 1 year" + ExpiresByType image/avif "access plus 1 year" + ExpiresByType image/svg+xml "access plus 1 year" + ExpiresByType image/x-icon "access plus 1 year" + ExpiresByType image/vnd.microsoft.icon "access plus 1 year" + + # Fuentes: 1 anio + ExpiresByType font/woff "access plus 1 year" + ExpiresByType font/woff2 "access plus 1 year" + ExpiresByType application/font-woff "access plus 1 year" + ExpiresByType application/font-woff2 "access plus 1 year" + ExpiresByType application/vnd.ms-fontobject "access plus 1 year" + + + + # Cache largo + immutable para estaticos con hash o version + + Header set Cache-Control "public, max-age=31536000, immutable" + + + # HTML siempre fresco + + Header set Cache-Control "no-cache, must-revalidate" + + + # Vary: Accept-Encoding (correcto para CDN/proxies) + + Header append Vary Accept-Encoding + + + +# ============================================================ +# Routing Laravel + seguridad +# ============================================================ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Forzar HTTPS + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + + # Bloquear acceso directo a /storage/app + RewriteRule ^storage/app/(.*)$ - [F,L] + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Handle X-XSRF-Token Header + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt new file mode 100644 index 0000000..c48a25b --- /dev/null +++ b/public/.well-known/security.txt @@ -0,0 +1,4 @@ +Contact: mailto:admin@onapb.com +Expires: 2027-04-01T00:00:00Z +Preferred-Languages: es, en +Canonical: https://onapb.com/.well-known/security.txt diff --git a/public/favicon copy.ico b/public/favicon copy.ico new file mode 100644 index 0000000..5832066 Binary files /dev/null and b/public/favicon copy.ico differ diff --git a/public/favicon-16.png b/public/favicon-16.png new file mode 100644 index 0000000..c6e2efb Binary files /dev/null and b/public/favicon-16.png differ diff --git a/public/favicon-32.png b/public/favicon-32.png new file mode 100644 index 0000000..c67bb7f Binary files /dev/null and b/public/favicon-32.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..5832066 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..cb6a92b Binary files /dev/null and b/public/favicon.png differ diff --git a/public/favicon_source.png b/public/favicon_source.png new file mode 100644 index 0000000..b68c104 Binary files /dev/null and b/public/favicon_source.png differ diff --git a/public/icons/icon-128.png b/public/icons/icon-128.png new file mode 100644 index 0000000..fcfe5a5 Binary files /dev/null and b/public/icons/icon-128.png differ diff --git a/public/icons/icon-144.png b/public/icons/icon-144.png new file mode 100644 index 0000000..1c52830 Binary files /dev/null and b/public/icons/icon-144.png differ diff --git a/public/icons/icon-152.png b/public/icons/icon-152.png new file mode 100644 index 0000000..b392f35 Binary files /dev/null and b/public/icons/icon-152.png differ diff --git a/public/icons/icon-192.png b/public/icons/icon-192.png new file mode 100644 index 0000000..7c0b4a9 Binary files /dev/null and b/public/icons/icon-192.png differ diff --git a/public/icons/icon-384.png b/public/icons/icon-384.png new file mode 100644 index 0000000..f9b535a Binary files /dev/null and b/public/icons/icon-384.png differ diff --git a/public/icons/icon-512.png b/public/icons/icon-512.png new file mode 100644 index 0000000..407bde3 Binary files /dev/null and b/public/icons/icon-512.png differ diff --git a/public/icons/icon-72.png b/public/icons/icon-72.png new file mode 100644 index 0000000..2e4cfc6 Binary files /dev/null and b/public/icons/icon-72.png differ diff --git a/public/icons/icon-96.png b/public/icons/icon-96.png new file mode 100644 index 0000000..a4314ac Binary files /dev/null and b/public/icons/icon-96.png differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..962b5c8 Binary files /dev/null and b/public/logo.png differ diff --git a/public/logo.webp b/public/logo.webp new file mode 100644 index 0000000..27d4bf6 Binary files /dev/null and b/public/logo.webp differ diff --git a/public/logoFondoBlanco.png b/public/logoFondoBlanco.png new file mode 100644 index 0000000..81da186 Binary files /dev/null and b/public/logoFondoBlanco.png differ diff --git a/public/logoFondoBlanco.webp b/public/logoFondoBlanco.webp new file mode 100644 index 0000000..60de28a Binary files /dev/null and b/public/logoFondoBlanco.webp differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..22b672d --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,88 @@ +{ + "name": "OnAPB — Asociación de Básquet Paraná", + "short_name": "OnAPB", + "description": "Seguí el básquet de Paraná: partidos, equipos, entradas y resultados.", + "start_url": "/", + "display": "standalone", + "background_color": "#0a0a0a", + "theme_color": "#b00000", + "orientation": "portrait-primary", + "lang": "es-AR", + "scope": "/", + "icons": [ + { + "src": "/icons/icon-72.png?v=4", + "sizes": "72x72", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-96.png?v=4", + "sizes": "96x96", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-128.png?v=4", + "sizes": "128x128", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-144.png?v=4", + "sizes": "144x144", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-152.png?v=4", + "sizes": "152x152", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-192.png?v=4", + "sizes": "192x192", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-384.png?v=4", + "sizes": "384x384", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-512.png?v=4", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ], + "shortcuts": [ + { + "name": "Próximos Partidos", + "short_name": "Partidos", + "description": "Ver los próximos partidos", + "url": "/eventos", + "icons": [{ "src": "/icons/icon-96.png?v=4", "sizes": "96x96" }] + }, + { + "name": "Mi Panel", + "short_name": "Mi Panel", + "description": "Acceder a mi perfil y entradas", + "url": "/panel-usuario", + "icons": [{ "src": "/icons/icon-96.png?v=4", "sizes": "96x96" }] + }, + { + "name": "Torneos", + "short_name": "Torneos", + "description": "Ver torneos activos", + "url": "/torneos", + "icons": [{ "src": "/icons/icon-96.png?v=4", "sizes": "96x96" }] + } + ], + "screenshots": [], + "categories": ["sports", "entertainment"], + "prefer_related_applications": false +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..a668c0e --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,9 @@ +User-agent: * +Disallow: /admin +Disallow: /recuperar +Disallow: /api/ +Disallow: /storage/ +Disallow: /vendor/ +Allow: / + +Sitemap: https://onapb.com/sitemap.xml diff --git a/public/static/admin-kinetic.css b/public/static/admin-kinetic.css new file mode 100644 index 0000000..ba01f0a --- /dev/null +++ b/public/static/admin-kinetic.css @@ -0,0 +1,249 @@ +/* + OnAPB Admin - Kinetic Arena Design System + "The Editorial Athlete" - Admin Extension +*/ + +:root { + --admin-sidebar-bg: #0A0A0A; + --admin-sidebar-active: #B00000; + --admin-content-bg: #F8F9FF; + --admin-surface: #FFFFFF; + --admin-primary: #B00000; + --admin-text-main: #1A1A1A; + --admin-text-muted: #666666; + --admin-outline: #E0E0E0; + + /* Typography */ + --admin-font-header: 'Space Grotesk', sans-serif; + --admin-font-body: 'Plus Jakarta Sans', sans-serif; +} + +body { + background-color: var(--admin-content-bg); + font-family: var(--admin-font-body); + color: var(--admin-text-main); + overflow-x: hidden; +} + +/* Sidebar Redesign */ +.admin-sidebar { + background: var(--admin-sidebar-bg) !important; + width: 280px; + height: 100vh; + position: fixed; + left: 0; + top: 0; + z-index: 1000; + transition: all 0.3s ease; + border-right: none !important; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: var(--admin-primary) #000; +} + +.admin-sidebar::-webkit-scrollbar { + width: 4px; +} + +.admin-sidebar::-webkit-scrollbar-track { + background: #000; +} + +.admin-sidebar::-webkit-scrollbar-thumb { + background-color: var(--admin-primary); +} + +.sidebar-header { + padding: 2rem; + background: #000; + border-bottom: 4px solid var(--admin-sidebar-active); +} + +.sidebar-logo { + height: 40px; + filter: brightness(0) invert(1); + margin-right: 10px; +} + +.sidebar-title { + font-family: var(--admin-font-header); + font-weight: 700; + font-size: 1.2rem; + color: #fff; + letter-spacing: -0.02em; +} + +.sidebar-nav { + padding: 1.5rem 0; +} + +.sidebar-link { + display: flex; + align-items: center; + padding: 0.85rem 2rem; + color: rgba(255,255,255,0.6); + text-decoration: none; + font-weight: 600; + text-transform: uppercase; + font-size: 0.8rem; + letter-spacing: 0.05em; + transition: all 0.2s; +} + +.sidebar-link i { + font-size: 1.1rem; + margin-right: 1rem; +} + +.sidebar-link:hover { + color: #fff; + background: rgba(255,255,255,0.05); +} + +.sidebar-link.active { + background: var(--admin-sidebar-active); + color: #fff; +} + +/* Main Content Area */ +.admin-main { + margin-left: 280px; + min-height: 100vh; + transition: all 0.3s ease; +} + +.admin-topbar { + background: #fff; + height: 70px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 2rem; + border-bottom: 1px solid var(--admin-outline); +} + +.admin-content { + padding: 2.5rem; +} + +/* Kinetic Admin Cards */ +.admin-card { + background: #fff; + border: none; + border-radius: 0; + box-shadow: 0 10px 30px rgba(0,0,0,0.03); + margin-bottom: 1.5rem; + padding: 2rem; +} + +.admin-card-header { + border-bottom: 2px solid var(--admin-content-bg); + margin-bottom: 1.5rem; + padding-bottom: 1rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.admin-card-header h3 { + font-family: var(--admin-font-header); + font-weight: 700; + margin-bottom: 0; + text-transform: uppercase; + font-size: 1.1rem; +} + +/* Stats Cards */ +.stat-card { + background: #000; + color: #fff; + padding: 2rem; + position: relative; + overflow: hidden; + margin-bottom: 1rem; +} + +.stat-card .stat-value { + font-family: var(--admin-font-header); + font-size: 3rem; + font-weight: 800; + line-height: 1; + margin-bottom: 0.5rem; +} + +.stat-card .stat-label { + text-transform: uppercase; + font-weight: 700; + font-size: 0.75rem; + letter-spacing: 0.1em; + color: rgba(255,255,255,0.5); +} + +/* High Contrast Table */ +.kinetic-table { + width: 100%; + border-collapse: collapse; +} + +.kinetic-table th { + background: var(--admin-content-bg); + padding: 1rem; + text-align: left; + font-weight: 700; + text-transform: uppercase; + font-size: 0.7rem; + letter-spacing: 0.05em; + color: var(--admin-text-muted); +} + +.kinetic-table td { + padding: 1.2rem 1rem; + border-bottom: 1px solid var(--admin-outline); + font-size: 0.9rem; +} + +.kinetic-table tr:hover td { + background: #fafafa; +} + +/* Admin Buttons */ +.btn-admin-primary { + background: var(--admin-primary); + color: #fff; + border: none; + padding: 0.75rem 1.5rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 0.8rem; + transition: 0.3s; +} + +.btn-admin-primary:hover { + background: #900000; + transform: translateY(-2px); +} + +.btn-admin-action { + width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 0; + margin-right: 5px; + transition: 0.2s; +} + +/* Responsive */ +@media (max-width: 991.98px) { + .admin-sidebar { + left: -280px; + } + .admin-sidebar.show { + left: 0; + } + .admin-main { + margin-left: 0; + } +} diff --git a/public/static/admin.css b/public/static/admin.css new file mode 100644 index 0000000..22e48bd --- /dev/null +++ b/public/static/admin.css @@ -0,0 +1,621 @@ +/* ══════════════════════════════════ + ADMIN PANEL STYLES - ONAPB + ══════════════════════════════════ */ + +/* ── Variables ── */ +:root { + --admin-sidebar-w: 260px; + --admin-primary: #b00000; + --admin-primary-dark: #8b0000; + --admin-bg: #f0f2f5; + --admin-sidebar-bg: #1a1a2e; + --admin-sidebar-hover: #16213e; + --admin-sidebar-active: #b00000; + --admin-card-bg: #ffffff; + --admin-topbar-h: 60px; + --admin-text: #333; + --admin-muted: #6c757d; + --admin-border: #e0e0e0; + --admin-shadow: 0 2px 12px rgba(0,0,0,0.08); + --admin-radius: 10px; +} + +/* ── Typography ── */ +body { + font-family: 'Roboto', sans-serif; + background: var(--admin-bg); + color: var(--admin-text); + margin: 0; + padding: 0; +} + +h1, h2, h3, h4 { + font-family: 'Montserrat', sans-serif; + font-weight: 700; +} + +/* ── Layout ── */ +.admin-wrapper { + display: flex; + min-height: 100vh; +} + +/* ── Sidebar ── */ +.admin-sidebar { + width: var(--admin-sidebar-w); + background: var(--admin-sidebar-bg); + color: #ccc; + position: fixed; + top: 0; + left: 0; + bottom: 0; + z-index: 1050; + overflow-y: auto; + transition: transform 0.3s ease; +} + +.sidebar-header { + padding: 20px 16px 10px; + text-align: center; + border-bottom: 1px solid rgba(255,255,255,0.08); +} + +.sidebar-logo { + max-height: 80px; + margin: 0 auto 8px; + display: block; +} + +.sidebar-title { + display: block; + font-family: 'Bebas Neue', sans-serif; + font-size: 1.3rem; + letter-spacing: 3px; + color: var(--admin-primary); + margin-top: 4px; +} + +.sidebar-nav { + padding: 12px 0; +} + +.sidebar-link { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 20px; + color: #b0b0c0; + text-decoration: none; + font-family: 'Montserrat', sans-serif; + font-size: 0.88rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + border-left: 3px solid transparent; + transition: all 0.2s ease; +} + +.sidebar-link:hover { + background: var(--admin-sidebar-hover); + color: #fff; + border-left-color: var(--admin-primary); +} + +.sidebar-link.active { + background: rgba(176, 0, 0, 0.15); + color: #fff; + border-left-color: var(--admin-primary); +} + +.sidebar-link i { + font-size: 1.15rem; + width: 22px; + text-align: center; +} + +.sidebar-divider { + border-color: rgba(255,255,255,0.08); + margin: 8px 16px; +} + +/* ── Main ── */ +.admin-main { + flex: 1; + margin-left: var(--admin-sidebar-w); + display: flex; + flex-direction: column; + min-height: 100vh; +} + +/* ── Topbar ── */ +.admin-topbar { + height: var(--admin-topbar-h); + background: var(--admin-card-bg); + border-bottom: 1px solid var(--admin-border); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 24px; + position: sticky; + top: 0; + z-index: 1020; + box-shadow: 0 1px 4px rgba(0,0,0,0.04); +} + +.sidebar-toggle { + color: var(--admin-text); + padding: 4px 8px; +} + +.topbar-greeting { + font-size: 0.95rem; + color: var(--admin-muted); +} + +/* ── Content ── */ +.admin-content { + padding: 24px; + flex: 1; +} + +/* ── Cards ── */ +.admin-card { + background: var(--admin-card-bg); + border-radius: var(--admin-radius); + box-shadow: var(--admin-shadow); + border: none; + overflow: hidden; +} + +.admin-card .card-header { + background: var(--admin-card-bg); + border-bottom: 2px solid var(--admin-border); + padding: 16px 20px; + font-family: 'Montserrat', sans-serif; + font-weight: 700; + font-size: 1rem; + text-transform: uppercase; + letter-spacing: 0.5px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.admin-card .card-body { + padding: 20px; +} + +/* ── Stat Cards ── */ +.stat-card { + background: var(--admin-card-bg); + border-radius: var(--admin-radius); + box-shadow: var(--admin-shadow); + padding: 20px; + display: flex; + align-items: center; + gap: 16px; + transition: transform 0.2s ease, box-shadow 0.2s ease; + text-decoration: none; + color: inherit; + border-left: 4px solid var(--admin-primary); +} + +.stat-card:hover { + transform: translateY(-3px); + box-shadow: 0 6px 20px rgba(0,0,0,0.12); + color: inherit; +} + +.stat-icon { + width: 56px; + height: 56px; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + color: #fff; + flex-shrink: 0; +} + +.stat-icon.clubes { background: linear-gradient(135deg, #b00000, #d32f2f); } +.stat-icon.equipos { background: linear-gradient(135deg, #1565c0, #42a5f5); } +.stat-icon.jugadores{ background: linear-gradient(135deg, #2e7d32, #66bb6a); } +.stat-icon.eventos { background: linear-gradient(135deg, #e65100, #ff9800); } +.stat-icon.promos { background: linear-gradient(135deg, #6a1b9a, #ab47bc); } +.stat-icon.noticias { background: linear-gradient(135deg, #00838f, #26c6da); } + +.stat-info h3 { + font-size: 1.8rem; + margin: 0; + font-weight: 700; + color: var(--admin-text); +} + +.stat-info p { + margin: 0; + font-size: 0.85rem; + color: var(--admin-muted); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* ── Tables ── */ +.admin-table { + width: 100%; + border-collapse: separate; + border-spacing: 0; +} + +.admin-table thead th { + background: #f8f9fa; + font-family: 'Montserrat', sans-serif; + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--admin-muted); + padding: 12px 16px; + border-bottom: 2px solid var(--admin-border); + white-space: nowrap; +} + +.admin-table tbody td { + padding: 12px 16px; + border-bottom: 1px solid #f0f0f0; + vertical-align: middle; + font-size: 0.92rem; +} + +.admin-table tbody tr:hover { + background: #fafbfc; +} + +.admin-table tbody tr:last-child td { + border-bottom: none; +} + +/* ── Forms ── */ +.admin-form .form-label { + font-family: 'Montserrat', sans-serif; + font-weight: 600; + font-size: 0.82rem; + text-transform: uppercase; + letter-spacing: 0.3px; + color: var(--admin-muted); + margin-bottom: 6px; +} + +.admin-form .form-control, +.admin-form .form-select { + border-radius: 8px; + border: 1.5px solid var(--admin-border); + padding: 10px 14px; + font-size: 0.92rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.admin-form .form-control:focus, +.admin-form .form-select:focus { + border-color: var(--admin-primary); + box-shadow: 0 0 0 3px rgba(176, 0, 0, 0.1); +} + +/* ── Buttons ── */ +.btn-admin { + background: var(--admin-primary); + color: #fff; + border: none; + padding: 10px 20px; + border-radius: 8px; + font-family: 'Montserrat', sans-serif; + font-weight: 600; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.5px; + transition: all 0.2s ease; +} + +.btn-admin:hover { + background: var(--admin-primary-dark); + color: #fff; + transform: translateY(-1px); +} + +.btn-admin-outline { + background: transparent; + color: var(--admin-primary); + border: 2px solid var(--admin-primary); + padding: 8px 16px; + border-radius: 8px; + font-family: 'Montserrat', sans-serif; + font-weight: 600; + font-size: 0.82rem; + text-transform: uppercase; + transition: all 0.2s ease; + text-decoration: none; +} + +.btn-admin-outline:hover { + background: var(--admin-primary); + color: #fff; +} + +/* Action buttons in table */ +.btn-action { + padding: 6px 10px; + border-radius: 6px; + font-size: 0.82rem; + border: none; + transition: all 0.2s ease; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 4px; +} + +.btn-action.edit { + background: #e3f2fd; + color: #1565c0; +} +.btn-action.edit:hover { + background: #1565c0; + color: #fff; +} + +.btn-action.delete { + background: #ffebee; + color: #c62828; +} +.btn-action.delete:hover { + background: #c62828; + color: #fff; +} + +/* ── Page Header ── */ +.page-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 24px; + flex-wrap: wrap; + gap: 12px; +} + +.page-header h2 { + margin: 0; + font-size: 1.5rem; + color: var(--admin-text); +} + +/* ── Badge ── */ +.badge-admin { + padding: 4px 10px; + border-radius: 20px; + font-size: 0.75rem; + font-weight: 600; +} + +/* ── Empty State ── */ +.empty-state { + text-align: center; + padding: 48px 20px; + color: var(--admin-muted); +} + +.empty-state i { + font-size: 3rem; + margin-bottom: 12px; + opacity: 0.4; +} + +.empty-state p { + font-size: 1rem; + margin: 0; +} + +/* ── Search ── */ +.search-box { + position: relative; + max-width: 320px; +} + +.search-box input { + padding-left: 40px; + border-radius: 20px; + border: 1.5px solid var(--admin-border); + font-size: 0.9rem; +} + +.search-box i { + position: absolute; + left: 14px; + top: 50%; + transform: translateY(-50%); + color: var(--admin-muted); +} + +/* ── QR Scanner ── */ +.qr-scanner-area { + max-width: 500px; + margin: 0 auto; + text-align: center; +} + +.qr-result { + margin-top: 20px; + padding: 20px; + border-radius: var(--admin-radius); + display: none; +} + +.qr-result.success { + background: #e8f5e9; + border: 2px solid #4caf50; + display: block; +} + +.qr-result.error { + background: #ffebee; + border: 2px solid #f44336; + display: block; +} + +/* ── Overlay ── */ +.sidebar-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0,0,0,0.5); + z-index: 1040; +} + +.sidebar-overlay.show { + display: block; +} + +/* ── Responsive ── */ +@media (max-width: 991px) { + .admin-sidebar { + transform: translateX(-100%); + } + + .admin-sidebar.show { + transform: translateX(0); + } + + .admin-main { + margin-left: 0; + } +} + +@media (max-width: 576px) { + .admin-content { + padding: 16px; + } + + .stat-card { + padding: 16px; + } + + .stat-info h3 { + font-size: 1.4rem; + } + + .page-header { + flex-direction: column; + align-items: flex-start; + } + + .admin-table thead { + display: none; + } + + .admin-table tbody tr { + display: block; + margin-bottom: 12px; + border: 1px solid var(--admin-border); + border-radius: 8px; + padding: 12px; + } + + .admin-table tbody td { + display: flex; + justify-content: space-between; + align-items: center; + padding: 6px 0; + border: none; + } + + .admin-table tbody td::before { + content: attr(data-label); + font-weight: 600; + font-size: 0.8rem; + color: var(--admin-muted); + text-transform: uppercase; + margin-right: 8px; + } +} + +/* ── Pagination ── */ +.pagination { + margin-bottom: 0; + gap: 4px; + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.pagination .page-link { + color: var(--admin-text); + background-color: #fff; + border: 1px solid var(--admin-border); + border-radius: 6px !important; + margin: 0; + font-size: 0.82rem; + font-weight: 500; + padding: 6px 12px; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + min-width: 36px; +} + +.pagination .page-link:hover { + background-color: var(--admin-bg); + border-color: var(--admin-primary); + color: var(--admin-primary); + z-index: 2; +} + +.pagination .page-item.active .page-link { + background-color: var(--admin-primary); + border-color: var(--admin-primary); + color: #fff; + cursor: default; +} + +.pagination .page-item.disabled .page-link { + color: #bdbdbd; + background-color: #fcfcfc; + border-color: #eee; + pointer-events: none; +} + +/* Fix huge arrows in some Laravel pagination templates */ +.pagination svg, +nav svg, +[role="navigation"] svg { + width: 20px !important; + height: 20px !important; + max-width: 20px !important; + max-height: 20px !important; + display: inline-block !important; + vertical-align: middle; +} + +/* Hide the redundant text and large flex containers from Tailwind template if it leaks */ +nav[role="navigation"] > div:first-child { + display: none !important; +} + +.pagination .flex.justify-between.flex-1 { + display: none !important; +} + +@media (max-width: 576px) { + .pagination .page-link { + padding: 4px 10px; + font-size: 0.75rem; + min-width: 32px; + } +} + +/* ── Delete form inline ── */ +.delete-form { + display: inline; +} diff --git a/public/static/asociate.css b/public/static/asociate.css new file mode 100644 index 0000000..cef25e1 --- /dev/null +++ b/public/static/asociate.css @@ -0,0 +1,130 @@ +.asociate-container { + max-width: 800px; + margin: 40px auto; + padding: 0 15px; +} + +/* Título */ +.asociate-container .page-title { + font-size: 2.4rem; + font-weight: 700; + color: var(--primary); + text-align: center; + margin-bottom: 25px; +} + +/* Cards */ +.asociate-container .card { + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--outline-variant, #e0ddd6); + background: var(--surface-container-lowest, #fff); + box-shadow: var(--shadow-sm, 0 3px 10px rgba(0,0,0,0.05)); +} + +.asociate-container h4 { + font-weight: 600; + color: var(--on-surface); +} + +.asociate-container p { + font-size: 1rem; + color: var(--on-surface-muted); +} + +/* Formularios */ +.asociate-container .form-label { + font-weight: 600; + color: var(--on-surface); +} + +.asociate-container .form-control { + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--outline-variant, #ccc); + font-size: 0.95rem; + padding: 10px; + background: var(--surface-container-lowest, #fff); + color: var(--on-surface); + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.asociate-container .form-control:focus { + border-color: var(--primary); + box-shadow: 0 0 0 0.2rem rgba(194, 0, 0, 0.15); +} + +/* Botones */ +.asociate-container .btn { + font-weight: 600; + padding: 10px 18px; + border-radius: var(--radius-sm, 4px); + transition: transform 0.1s ease, box-shadow 0.2s ease; +} + +.asociate-container .btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 10px rgba(0,0,0,0.1); +} + +.asociate-container .btn-primary { + background: var(--primary); + border-color: var(--primary); +} + +.asociate-container .btn-primary:hover { + background: var(--primary-deep, #8b0000); + border-color: var(--primary-deep, #8b0000); +} + +.asociate-container .btn-success { + background: #28a745; + border-color: #28a745; +} + +.asociate-container .btn-success:hover { + background: #218838; + border-color: #218838; +} + +/* Alertas */ +.asociate-container .alert { + border-radius: var(--radius-sm, 4px); + font-size: 0.95rem; +} + +/* Responsive */ +@media (max-width: 768px) { + .asociate-container .page-title { + font-size: 2rem; + } + .asociate-container { padding-left: 16px; padding-right: 16px; } + .asociate-container .form-control { min-height: 44px; } +} + +@media (max-width: 576px) { + .asociate-container .page-title { + font-size: 1.6rem; + } + + .asociate-container .card { + padding: 15px !important; + } + .asociate-container .btn { min-height: 44px; } +} + + +.sugerencia-email { + background: var(--surface-container-low, #f8f9fa); + border-left: 3px solid var(--primary); + padding: 4px 8px; + border-radius: var(--radius-sm, 4px); + margin-top: 4px; + color: var(--on-surface); +} +.sugerencia-email a { + color: var(--primary); + text-decoration: none; + font-weight: 500; +} +.sugerencia-email a:hover { + text-decoration: underline; +} diff --git a/public/static/base.css b/public/static/base.css new file mode 100644 index 0000000..7254c3d --- /dev/null +++ b/public/static/base.css @@ -0,0 +1,447 @@ +/* ====== GLOBAL ====== */ +:root { + --primary-color: #b00000; + --primary-dark: #8b0000; + --bg-color: #f4f7f6; + --card-bg: #ffffff; + --text-dark: #2c3e50; + --text-muted: #6c757d; + --shadow-sm: 0 4px 15px rgba(0,0,0,0.05); + --shadow-lg: 0 10px 30px rgba(0,0,0,0.12); + --radius: 4px; + --gradient-primary: linear-gradient(135deg, #b00000, #d32f2f); + --gradient-success: linear-gradient(135deg, #2e7d32, #66bb6a); + --gradient-info: linear-gradient(135deg, #0277bd, #29b6f6); +} + +html, body { + margin: 0; + padding: 0; + min-height: 100vh; + font-size: 16px; + background: var(--bg-color); + color: var(--text-dark); +} + +*, *::before, *::after { box-sizing: border-box; } +img, video, canvas, svg { max-width: 100%; height: auto; display: block; } + +/* ===== TIPOGRAFÍA — delegada a kinetic-arena.css ====== */ +/* Las familias tipográficas las define el sistema de diseño principal */ + +/* ====== NAVBAR PREMIUN ====== */ +.custom-navbar { + background-color: rgba(255, 255, 255, 0.95) !important; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-bottom: 1px solid rgba(0,0,0,0.05); + padding: 15px 20px; + box-shadow: 0 4px 20px rgba(0,0,0,0.03); + position: sticky; + top: 0; + z-index: 1030; + transition: all 0.3s ease; +} + +.custom-navbar .navbar-brand { + color: var(--primary-color); + font-size: 1.8rem; + text-shadow: 1px 1px 2px rgba(0,0,0,0.1); + transition: transform 0.3s ease; +} +.custom-navbar .navbar-brand:hover { + transform: scale(1.05); +} + +.custom-navbar .nav-link { + color: var(--text-dark) !important; + font-size: 0.95rem; + text-transform: uppercase; + letter-spacing: 0.5px; + margin: 0 5px; + padding: 8px 15px !important; + border-radius: 8px; + transition: all 0.3s ease; + position: relative; +} + +.custom-navbar .nav-link::after { + content: ''; + position: absolute; + bottom: 0; + left: 15px; + right: 15px; + height: 3px; + background-color: var(--primary-color); + border-radius: 3px; + transform: scaleX(0); + transform-origin: bottom right; + transition: transform 0.3s ease; +} + +.custom-navbar .nav-link:hover::after, +.custom-navbar .nav-link.active::after { + transform: scaleX(1); + transform-origin: bottom left; +} +.custom-navbar .nav-link:hover, .custom-navbar .nav-link.active { + color: var(--primary-color) !important; + background: rgba(176, 0, 0, 0.05); +} + +.dropdown-menu { + border-radius: var(--radius); + border: none; + box-shadow: var(--shadow-lg); + padding: 10px; + animation: fadeInDown 0.3s ease; +} + +@keyframes fadeInDown { + from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); } +} + +.dropdown-item { + border-radius: 6px; + padding: 8px 15px; + transition: all 0.2s ease; +} +.dropdown-item:hover { + background-color: rgba(176, 0, 0, 0.05); + color: var(--primary-color); + transform: translateX(5px); +} + +/* ====== HERO ====== */ +.hero { + height: 70vh; + position: relative; + overflow: hidden; +} + +.hero-img { + object-fit: cover; + width: 100%; + height: 75vh; + max-height: 800px; + filter: brightness(80%); + transition: transform 6s ease; +} + +.carousel-item.active .hero-img { + transform: scale(1.05); +} + +.hero-caption { + bottom: 50%; + transform: translateY(50%); + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(8px); + border-radius: 16px; + padding: 40px 30px; + max-width: 700px; + border: 1px solid rgba(255,255,255,0.1); + box-shadow: 0 20px 40px rgba(0,0,0,0.3); + animation: fadeInUp 1s ease; +} + +@keyframes fadeInUp { + from { opacity: 0; transform: translate(-50%, 60%); } + to { opacity: 1; transform: translate(-50%, 50%); left: 50%; } +} +.hero-caption { left: 50%; transform: translate(-50%, 50%); position: absolute; } + + +.hero-caption h1 { + color: #fff; + font-size: 4.5rem; + letter-spacing: 2px; + text-shadow: 2px 4px 10px rgba(0,0,0,0.5); + margin-bottom: 15px; +} + +.hero-caption p { + color: #f0f0f0; + font-size: 1.3rem; + margin-bottom: 25px; + font-weight: 300; +} + +/* ====== CARDS PREMIUN ====== */ +.card { + border: none; + border-radius: var(--radius); + background: var(--card-bg); + box-shadow: var(--shadow-sm); + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); + overflow: hidden; + height: auto; +} + +.card:hover { + transform: translateY(-8px); + box-shadow: var(--shadow-lg); +} + +.card-img-top { + transition: transform 0.5s ease; +} +.card:hover .card-img-top { + transform: scale(1.08); +} +.card > div:first-child:not(.card-body) { + overflow: hidden; /* For zooming images */ +} + +.card-title { + color: var(--text-dark); + font-size: 1.25rem; +} + +/* ====== BADGES ====== */ +.badge { + padding: 6px 12px; + border-radius: 20px; + font-weight: 600; + letter-spacing: 0.5px; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); +} +.badge.bg-success { background: var(--gradient-success) !important; } +.badge.bg-primary { background: var(--gradient-info) !important; } +.badge.bg-danger { background: var(--gradient-primary) !important; } + + +/* ====== BOTONES PREMIUN ====== */ +.btn { + border-radius: 8px; + padding: 10px 24px; + text-transform: uppercase; + font-size: 0.85rem; + letter-spacing: 1px; + border: none; + transition: all 0.3s ease; + box-shadow: 0 4px 10px rgba(0,0,0,0.1); +} + +.btn:active { + transform: scale(0.96); +} + +.btn-primary, .btn-danger, .btn-hero { + background: var(--gradient-primary) !important; + color: #fff; +} +.btn-primary:hover, .btn-danger:hover, .btn-hero:hover { + box-shadow: 0 8px 20px rgba(176, 0, 0, 0.3); + transform: translateY(-2px); +} + +.btn-success { + background: var(--gradient-success) !important; +} +.btn-success:hover { + box-shadow: 0 8px 20px rgba(46, 125, 50, 0.3); + transform: translateY(-2px); +} + +.btn-info { + background: var(--gradient-info) !important; + color: white !important; +} + +.btn-outline-primary, .btn-outline-danger { + background: transparent !important; + border: 2px solid var(--primary-color) !important; + color: var(--primary-color) !important; + box-shadow: none; +} +.btn-outline-primary:hover, .btn-outline-danger:hover { + background: var(--gradient-primary) !important; + color: white !important; + box-shadow: 0 8px 20px rgba(176, 0, 0, 0.2); + border-color: transparent !important; +} + +/* ====== SECTIONS & CONTAINERS ====== */ +.content { + animation: fadeIn 0.6s ease; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +/* ====== FOOTER ====== */ +.footer { + background: #1a1a2e; /* Admin sidebar color */ + color: #a0aab5; + text-align: center; + padding: 40px 0; + font-size: 0.95rem; + margin-top: 60px; +} + +/* ====== SPONSOR CAROUSEL ====== */ +.sponsor-carousel-container { + background: rgba(255, 255, 255, 1); + padding: 20px 0; + border-bottom: 1px solid rgba(0,0,0,0.08); + overflow: hidden; + position: relative; + width: 100%; +} + +.sponsor-carousel-track { + display: flex; + width: max-content; + animation: scrollSponsors 40s linear infinite; + align-items: center; +} + +/* When only 1 or 2 items (no sponsors), center instead of animate */ +.sponsor-carousel-track:has(.sponsor-item:only-of-type) { + width: 100%; + animation: none; + justify-content: center; +} + +.sponsor-item { + width: 200px; + flex-shrink: 0; + margin: 0 30px; + display: flex; + align-items: center; + justify-content: center; +} + +.sponsor-item img { + max-height: 55px; + max-width: 150px; + filter: grayscale(50%); + opacity: 0.65; + transition: all 0.4s ease; + object-fit: contain; +} + +.sponsor-item:hover img { + filter: grayscale(0%); + opacity: 1; + transform: scale(1.08); +} + +@keyframes scrollSponsors { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } +} + +/* Pause on hover */ +.sponsor-carousel-container:hover .sponsor-carousel-track { + animation-play-state: paused; +} + +/* ====== MODAL PREMIUN ====== */ +.modal-content { + border-radius: 16px; + border: none; + box-shadow: 0 25px 50px rgba(0,0,0,0.2); + overflow: hidden; +} +.modal-header { + border-bottom: 1px solid rgba(0,0,0,0.05); + background: #f8f9fa; +} +.nav-tabs .nav-link { + font-weight: 600; + text-transform: uppercase; + color: var(--text-muted); + border: none; + border-bottom: 3px solid transparent; +} +.nav-tabs .nav-link.active { + color: var(--primary-color); + border-bottom: 3px solid var(--primary-color); + background: transparent; +} + +/* ====== RESPONSIVE ====== */ +@media (max-width: 768px) { + .navbar-brand img { height: 60px; } + .custom-navbar { padding: 10px; } + .hero-caption { width: 90%; padding: 25px 20px; } + .hero-caption h1 { font-size: 3rem; } + .card:hover { transform: none; } /* Disable heavy animations on mobile */ +} + +/* ====== LOGO ====== */ +.navbar-logo { + height: auto; + max-height: 80px; + transition: max-height 0.3s ease, filter 0.3s ease; +} + +/* ======= MOBILE TABLE STACK ======= */ +@media screen and (max-width: 768px) { + .table-mobile-stack:not(.no-responsive) { display: block; width: 100%; overflow-x: hidden; } + .table-mobile-stack thead { display: none; } + .table-mobile-stack tr { + display: block; margin-bottom: 15px; background: #fff; + border-radius: var(--radius); padding: 15px; box-shadow: var(--shadow-sm); + } + .table-mobile-stack td { + display: flex; justify-content: space-between; text-align: right !important; + padding: 8px 0; border: none; align-items: center; border-bottom: 1px dashed #eee; + } + .table-mobile-stack td:last-child { border-bottom: none; } + .table-mobile-stack td::before { + content: attr(data-label); font-weight: 600; color: var(--text-muted); font-size: 0.85rem; text-transform: uppercase; + } +} + +/* ======= SPLASH SCREEN (X STYLE) ======= */ +#splash-screen { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #ffffff; + z-index: 99999; + display: flex; + align-items: center; + justify-content: center; + transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1), + visibility 0.6s cubic-bezier(0.4, 0, 0.2, 1); +} + +#splash-logo { + width: 100px; + height: 100px; + object-fit: contain; + animation: logo-entrance 1.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards, + logo-pulse 2s ease-in-out infinite 1.2s; + transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* Estado de salida */ +.splash-hidden { + opacity: 0; + visibility: hidden; + pointer-events: none; +} + +.splash-hidden #splash-logo { + transform: scale(10); /* El logo se agranda para "perforar" la pantalla estilo X */ + opacity: 0; +} + +@keyframes logo-entrance { + 0% { opacity: 0; transform: scale(0.5); } + 100% { opacity: 1; transform: scale(1); } +} + +@keyframes logo-pulse { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.08); } +} diff --git a/public/static/eventos.css b/public/static/eventos.css new file mode 100644 index 0000000..5ad0f18 --- /dev/null +++ b/public/static/eventos.css @@ -0,0 +1,23 @@ +/* OnAPB — Eventos + La vista usa kinetic-card + Bootstrap. + Este archivo conserva solo estilos de soporte. */ + +/* Barra de fechas horizontal — scroll sin scrollbar visible */ +.no-scrollbar::-webkit-scrollbar { display: none; } +.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } + +/* Pulse para badge "EN VIVO" */ +.pulse { animation: pulse-badge 2s ease-in-out infinite; } +@keyframes pulse-badge { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +/* Score display */ +.match-score-display { + font-family: var(--font-display, 'Antonio', sans-serif); + font-size: 2rem; + font-weight: 700; + letter-spacing: 0.05em; + color: var(--on-surface); +} diff --git a/public/static/index.css b/public/static/index.css new file mode 100644 index 0000000..495fe51 --- /dev/null +++ b/public/static/index.css @@ -0,0 +1,187 @@ +/* ════════════════════════════════ + HOME / WELCOME — OnAPB + Construido sobre kinetic-arena.css +════════════════════════════════ */ + +/* ── Contenedor base ── */ +.index-container { + max-width: 1100px; + margin: 40px auto; + padding: 0 15px; +} + +.index-container h2 { + font-size: 2.2rem; + color: var(--primary); + margin-bottom: 25px; +} + +/* ── Hero / Carousel principal ── */ +.hero-img { + object-fit: cover; + height: 70vh; + filter: brightness(70%); +} + +.hero-caption h1 { + font-size: clamp(2.5rem, 7vw, 5rem); + text-shadow: 0 2px 12px rgba(0,0,0,0.5); + font-family: var(--font-display) !important; +} + +.hero-caption p { + font-size: 1.1rem; + text-shadow: 0 2px 8px rgba(0,0,0,0.4); +} + +.btn-hero { + background: var(--primary); + color: #fff; + padding: 12px 28px; + border-radius: 0; + text-decoration: none; + font-family: var(--font-display) !important; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + transition: background-color 0.25s, transform 0.2s; +} + +.btn-hero:hover { + background: var(--primary-deep); + color: white; + transform: translateY(-1px); +} + +/* ── Cards de eventos / promos ── */ +.index-container .card { + border-radius: var(--radius); + border: 1px solid var(--outline-variant); + overflow: hidden; + transition: transform 0.22s ease, box-shadow 0.22s ease; + background: var(--surface-container-lowest); +} + +.index-container .card img { + width: 100%; + height: 200px; + object-fit: cover; +} + +.index-container .card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-lg); +} + +.index-container .card-body { + padding: 16px; + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.index-container .card-title { + font-size: 1rem; + font-weight: 700; + color: var(--on-surface); + margin-bottom: 8px; + font-family: var(--font-display) !important; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.index-container .card-text { + font-size: 0.9rem; + color: var(--on-surface-muted); +} + +.index-container .badge { + font-size: 0.75rem; + padding: 5px 10px; + border-radius: var(--radius-sm); +} + +.card-text i.bi { + color: var(--primary); + font-size: 1rem; +} + +/* ── Carousel de eventos (controles) ── */ +#eventosCarousel { + position: relative; + padding: 0 60px; +} + +#eventosCarousel .carousel-item { + transition: transform 0.8s ease, opacity 0.5s ease-out; +} + +#eventosCarousel .carousel-control-prev, +#eventosCarousel .carousel-control-next { + width: 44px; + height: 44px; + top: 50%; + transform: translateY(-50%); + background: rgba(26, 18, 8, 0.25); + border-radius: 50%; + transition: background 0.25s; + z-index: 10; +} + +#eventosCarousel .carousel-control-prev:hover, +#eventosCarousel .carousel-control-next:hover { + background: var(--primary); +} + +#eventosCarousel .carousel-control-prev { left: -52px; } +#eventosCarousel .carousel-control-next { right: -52px; } + +/* ── Standings Widget ── */ +#standingsCarousel { + min-height: 380px; +} + +.standings-header { + border-bottom: 1px solid rgba(255,255,255,0.1); + padding-bottom: 10px; +} + +#standingsCarousel .table td { + border-color: rgba(255,255,255,0.06); +} + +#standingsCarousel .btn-outline-light:hover { + background: var(--primary); + border-color: var(--primary); + color: white; +} + +/* ── Responsive ── */ +@media (max-width: 768px) { + #eventosCarousel { padding: 0 16px; overflow: hidden; } + #eventosCarousel .carousel-control-prev { left: 6px; } + #eventosCarousel .carousel-control-next { right: 6px; } + + .index-container .card img { height: 160px; } + .hero-caption h1 { font-size: 2rem; } + .hero-caption p { font-size: 0.95rem; } + .index-container h2 { font-size: 1.6rem; } + + #standingsCarousel { min-height: auto; } + + #promosCarousel .col-md-4, + #eventosCarousel .col-md-4 { + flex: 0 0 100%; + max-width: 100%; + } +} + +@media (max-width: 576px) { + .hero-img { height: 45vh; } + .index-container .card img { height: 140px; } + .index-container h2 { font-size: 1.4rem; } + .index-container .card-body { padding: 10px; } + + #eventosCarousel .carousel-control-prev, + #eventosCarousel .carousel-control-next { display: none; } +} diff --git a/public/static/kinetic-arena-v3.css b/public/static/kinetic-arena-v3.css new file mode 100644 index 0000000..e820cc8 --- /dev/null +++ b/public/static/kinetic-arena-v3.css @@ -0,0 +1,1686 @@ +/* ===================================================================== + ONAPB — Kinetic Arena v3 + Capa de innovación visual sobre kinetic-arena.css (sin tocar colores). + Carga DESPUÉS de base.css y kinetic-arena.css. + ===================================================================== */ + +/* ───────────────────────────────────────────────────────────────────── + 01. TOKENS DE MOTION + ───────────────────────────────────────────────────────────────────── */ +:root { + --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); + --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1); + --ease-power: cubic-bezier(0.83, 0, 0.17, 1); + --ease-arc: cubic-bezier(0.65, 0.05, 0.36, 1); + + --dur-snap: 140ms; + --dur-quick: 220ms; + --dur-base: 360ms; + --dur-soft: 560ms; + --dur-stage: 900ms; + + --primary-glow: 0 0 0 0 rgba(194, 0, 0, 0.45); + --primary-shadow-soft: 0 18px 40px -22px rgba(194, 0, 0, 0.55); + --kinetic-shadow-deep: 0 40px 80px -30px rgba(26, 18, 8, 0.35); + --kinetic-shadow-card: 0 22px 45px -28px rgba(26, 18, 8, 0.28); + + --grain-mix: multiply; +} + +@media (prefers-reduced-motion: reduce) { + + *, + *::before, + *::after { + animation-duration: 0.001ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.001ms !important; + scroll-behavior: auto !important; + } +} + +/* ───────────────────────────────────────────────────────────────────── + 02. SCROLLBAR PERSONALIZADA + ───────────────────────────────────────────────────────────────────── */ +* { + scrollbar-width: thin; + scrollbar-color: var(--primary) transparent; +} + +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: var(--surface-container-low); +} + +::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, var(--primary), var(--primary-deep)); + border-radius: 999px; + border: 2px solid var(--surface-container-low); +} + +::-webkit-scrollbar-thumb:hover { + background: var(--primary-deep); +} + +/* ───────────────────────────────────────────────────────────────────── + 03. BARRA DE PROGRESO DE LECTURA (top) + ───────────────────────────────────────────────────────────────────── */ +#kinetic-reading-bar { + position: fixed; + top: 0; + left: 0; + height: 3px; + width: 0%; + background: linear-gradient(90deg, var(--primary), #ff3232, var(--primary-deep)); + background-size: 200% 100%; + animation: barShimmer 3s linear infinite; + z-index: 2000; + transition: width 0.12s linear; + box-shadow: 0 0 12px rgba(194, 0, 0, 0.6); + pointer-events: none; +} + +@keyframes barShimmer { + from { + background-position: 0% 0; + } + + to { + background-position: 200% 0; + } +} + +/* ───────────────────────────────────────────────────────────────────── + 04. CURSOR PERSONALIZADO (sólo desktop con puntero fino) + ───────────────────────────────────────────────────────────────────── */ +@media (hover: hover) and (pointer: fine) { + + body.kinetic-cursor-on, + body.kinetic-cursor-on * { + cursor: none; + } + + body.kinetic-cursor-on input, + body.kinetic-cursor-on textarea, + body.kinetic-cursor-on select { + cursor: text; + } + + .kinetic-cursor-dot, + .kinetic-cursor-ring { + position: fixed; + top: 0; + left: 0; + pointer-events: none; + z-index: 9999; + will-change: transform; + /* sin mix-blend-mode: era el responsable de "perder" el cursor en fondos cálidos */ + } + + .kinetic-cursor-dot { + width: 10px; + height: 10px; + background: var(--primary); + border-radius: 50%; + transform: translate(-50%, -50%); + /* Doble anillo: borde negro fino para alto contraste sobre cualquier fondo */ + border: 2px solid #111; + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6), + 0 2px 8px rgba(0, 0, 0, 0.45); + transition: transform var(--dur-snap) var(--ease-spring), + width var(--dur-quick), height var(--dur-quick), + background var(--dur-quick), border-color var(--dur-quick); + } + + .kinetic-cursor-ring { + width: 38px; + height: 38px; + /* Anillo rojo grueso con outline negro para que se vea sobre claro y oscuro */ + border: 3px solid var(--primary); + outline: 2px solid #111; + outline-offset: -1px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.05); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.5), + 0 4px 14px rgba(0, 0, 0, 0.35); + transform: translate(-50%, -50%); + transition: transform 0.18s var(--ease-out-soft), + width var(--dur-quick), height var(--dur-quick), + border-color var(--dur-quick), + opacity var(--dur-quick); + } + + .kinetic-cursor-ring.is-hover { + width: 60px; + height: 60px; + border-color: var(--primary-deep); + background: rgba(194, 0, 0, 0.18); + outline-color: #000; + } + + .kinetic-cursor-dot.is-hover { + width: 6px; + height: 6px; + background: #fff; + border-color: var(--primary-deep); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 05. NAVBAR — efecto glass kinético + indicador animado + ───────────────────────────────────────────────────────────────────── */ +.custom-navbar { + transition: background-color 0.4s var(--ease-out-soft), + border-color 0.4s var(--ease-out-soft), + box-shadow 0.4s var(--ease-out-soft), + padding 0.3s var(--ease-out-soft) !important; +} + +.custom-navbar.is-scrolled { + background-color: rgba(245, 243, 239, 0.78) !important; + backdrop-filter: blur(28px) saturate(200%); + -webkit-backdrop-filter: blur(28px) saturate(200%); + border-bottom-color: rgba(194, 0, 0, 0.15) !important; + box-shadow: 0 8px 30px -20px rgba(26, 18, 8, 0.18) !important; + padding: 6px 0 !important; +} + +.custom-navbar .navbar-logo { + transition: transform 0.45s var(--ease-spring), filter 0.4s ease; +} + +.custom-navbar .navbar-brand:hover .navbar-logo { + transform: rotate(-6deg) scale(1.06); + filter: drop-shadow(0 6px 14px rgba(194, 0, 0, 0.35)); +} + +.custom-navbar .nav-link { + overflow: hidden; +} + +.custom-navbar .nav-link::before { + content: ''; + position: absolute; + left: 14px; + right: 14px; + bottom: 4px; + height: 2px; + background: var(--primary); + transform: scaleX(0); + transform-origin: right center; + transition: transform 0.42s var(--ease-arc); +} + +.custom-navbar .nav-link:hover::before, +.custom-navbar .nav-link.active::before { + transform: scaleX(1); + transform-origin: left center; +} + +/* Cuadrito decorativo en active */ +.custom-navbar .nav-link.active::after { + content: ''; + position: absolute; + top: 6px; + left: 6px; + width: 4px; + height: 4px; + background: var(--primary); + display: block !important; + animation: kineticBlink 1.6s steps(2, jump-none) infinite; +} + +@keyframes kineticBlink { + 50% { + opacity: 0.2; + } +} + +/* Bell de notificaciones */ +#notif-bell .bi-bell-fill { + transition: transform 0.35s var(--ease-spring); +} + +#notif-bell:hover .bi-bell-fill { + animation: bellShake 0.6s var(--ease-out-soft); +} + +@keyframes bellShake { + + 0%, + 100% { + transform: rotate(0); + } + + 20% { + transform: rotate(15deg); + } + + 40% { + transform: rotate(-12deg); + } + + 60% { + transform: rotate(8deg); + } + + 80% { + transform: rotate(-4deg); + } +} + +#notif-badge { + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0.7); + animation: badgeRing 1.8s var(--ease-out-soft) infinite; +} + +@keyframes badgeRing { + 0% { + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0.6); + } + + 70% { + box-shadow: 0 0 0 12px rgba(194, 0, 0, 0); + } + + 100% { + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 06. CARDS KINÉTICAS — tilt + spotlight + reveal + ───────────────────────────────────────────────────────────────────── */ +.kinetic-card { + position: relative; + overflow: hidden; + transform-style: preserve-3d; + transition: + transform 0.55s var(--ease-out-soft), + box-shadow 0.55s var(--ease-out-soft), + border-color 0.45s ease; +} + +.kinetic-card::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), + rgba(194, 0, 0, 0.08), + transparent 55%); + opacity: 0; + transition: opacity 0.45s ease; + pointer-events: none; + z-index: 1; +} + +.kinetic-card::after { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 3px; + background: linear-gradient(180deg, var(--primary), var(--primary-deep)); + transform: scaleY(0); + transform-origin: top center; + transition: transform 0.5s var(--ease-arc); + z-index: 2; +} + +.kinetic-card:hover { + transform: translateY(-6px); + box-shadow: var(--kinetic-shadow-card); + border-color: rgba(194, 0, 0, 0.3); +} + +.kinetic-card:hover::before { + opacity: 1; +} + +.kinetic-card:hover::after { + transform: scaleY(1); +} + +.kinetic-card>* { + position: relative; + z-index: 3; +} + +/* Variante 3D tilt (activado vía JS con [data-tilt]) */ +[data-tilt] { + transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); + transition: transform 0.25s var(--ease-out-soft); + will-change: transform; +} + +[data-tilt].is-tilting { + transition: transform 0.05s linear; +} + +/* ───────────────────────────────────────────────────────────────────── + 07. BOTONES KINÉTICOS — magnético + ripple + sweep + ───────────────────────────────────────────────────────────────────── */ +.btn-kinetic-primary, +.btn, +.btn-admin-primary { + position: relative; + isolation: isolate; + overflow: hidden; +} + +.btn-kinetic-primary { + transition: + background-color var(--dur-quick) ease, + color var(--dur-quick) ease, + transform var(--dur-quick) var(--ease-spring), + box-shadow var(--dur-base) var(--ease-out-soft), + letter-spacing var(--dur-quick) ease !important; +} + +.btn-kinetic-primary::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(120deg, + transparent 0%, + rgba(255, 255, 255, 0.28) 40%, + rgba(255, 255, 255, 0.55) 50%, + rgba(255, 255, 255, 0.28) 60%, + transparent 100%); + transform: translateX(-110%) skewX(-15deg); + transition: transform 0.65s var(--ease-arc); + z-index: 1; + pointer-events: none; +} + +.btn-kinetic-primary:hover { + box-shadow: var(--primary-shadow-soft); + letter-spacing: 0.16em !important; + transform: translateY(-2px) !important; +} + +.btn-kinetic-primary:hover::after { + transform: translateX(110%) skewX(-15deg); +} + +.btn-kinetic-primary>* { + position: relative; + z-index: 2; +} + +/* Ripple universal: agrega clase .kinetic-ripple */ +.kinetic-ripple-wave { + position: absolute; + border-radius: 50%; + background: rgba(255, 255, 255, 0.45); + transform: translate(-50%, -50%) scale(0); + animation: ripple 0.6s var(--ease-out-soft); + pointer-events: none; + z-index: 0; +} + +@keyframes ripple { + to { + transform: translate(-50%, -50%) scale(4); + opacity: 0; + } +} + +/* Botón magnético */ +[data-magnetic] { + transition: transform 0.22s var(--ease-out-soft); + will-change: transform; +} + +/* ───────────────────────────────────────────────────────────────────── + 08. HERO — text-reveal mask + parallax + CTA elevation + ───────────────────────────────────────────────────────────────────── */ +.hero-title { + /* Sin overflow: hidden global — el clipping del reveal lo hace cada .word. + Además agregamos padding-bottom para dar lugar a descenders (p, q, j, g, y). */ + display: inline-block; + padding-bottom: 0.18em; + line-height: 1.02 !important; +} + +.hero-title .word, +.kinetic-reveal-text .word { + display: inline-block; + overflow: hidden; + vertical-align: bottom; + /* Espacio para que los descenders no queden cortados por el overflow:hidden */ + padding-bottom: 0.22em; + line-height: 1.05; +} + +.hero-title .word>span, +.kinetic-reveal-text .word>span { + display: inline-block; + /* 130% > 100% + descender (~22%), garantiza ocultarlo completamente al inicio */ + transform: translateY(130%); + transition: transform 0.95s var(--ease-arc); +} + +/* Wrapper general del reveal-text */ +.kinetic-reveal-text { + display: inline-block; + padding-bottom: 0.18em; + line-height: 1.05 !important; +} + +/* Override global para todos los displays/headings: relajar line-height + demasiado ajustado del sistema base que recorta descenders. */ +h1, h2, h3, h4, h5, h6, +.display-1, .display-2, .display-3, +.display-4, .display-5, .display-6, +.hero-title { + line-height: 1.05 !important; + padding-bottom: 0.08em; +} + +/* Caso especial Antonio (font display) — necesita un poco más de aire */ +.display-1, .display-2, .display-3, .hero-title { + padding-bottom: 0.12em; +} + +.hero-title.is-in .word>span, +.kinetic-reveal-text.is-in .word>span { + transform: translateY(0); +} + +.hero-title.is-in .word:nth-child(2)>span { + transition-delay: 0.08s; +} + +.hero-title.is-in .word:nth-child(3)>span { + transition-delay: 0.16s; +} + +.hero-title.is-in .word:nth-child(4)>span { + transition-delay: 0.24s; +} + +.hero-title.is-in .word:nth-child(5)>span { + transition-delay: 0.32s; +} + +.hero-title.is-in .word:nth-child(6)>span { + transition-delay: 0.40s; +} + +.hero-title.is-in .word:nth-child(7)>span { + transition-delay: 0.48s; +} + +.hero-title.is-in .word:nth-child(8)>span { + transition-delay: 0.56s; +} + +/* Highlight con barrido tras el texto */ +.kinetic-highlight { + position: relative; + display: inline-block; + color: var(--primary); + isolation: isolate; +} + +.kinetic-highlight::before { + content: ''; + position: absolute; + inset: 8% -4% 8% -4%; + background: rgba(194, 0, 0, 0.12); + transform: scaleX(0); + transform-origin: left center; + transition: transform 0.7s var(--ease-arc) 0.4s; + z-index: -1; + border-radius: 2px; +} + +.kinetic-highlight.is-in::before { + transform: scaleX(1); +} + +/* Hero parallax (clip-path) */ +.hero-clip, +img.hero-clip { + transition: clip-path 1.2s var(--ease-arc), transform 6s var(--ease-out-soft); + will-change: transform; +} + +.carousel-item.active img.hero-clip { + transform: scale(1.04); +} + +/* ───────────────────────────────────────────────────────────────────── + 09. REVEAL ON SCROLL — variantes + ───────────────────────────────────────────────────────────────────── */ +.kfx-reveal { + opacity: 0; + transition: opacity 0.7s var(--ease-out-soft), + transform 0.7s var(--ease-out-soft), + filter 0.7s var(--ease-out-soft), + clip-path 0.9s var(--ease-arc); + will-change: transform, opacity; +} + +.kfx-reveal[data-fx="up"] { + transform: translateY(28px); +} + +.kfx-reveal[data-fx="down"] { + transform: translateY(-28px); +} + +.kfx-reveal[data-fx="left"] { + transform: translateX(-28px); +} + +.kfx-reveal[data-fx="right"] { + transform: translateX(28px); +} + +.kfx-reveal[data-fx="zoom"] { + transform: scale(0.92); +} + +.kfx-reveal[data-fx="blur"] { + filter: blur(14px); + transform: translateY(12px); +} + +.kfx-reveal[data-fx="curtain"] { + clip-path: inset(0 100% 0 0); +} + +.kfx-reveal[data-fx="rise"] { + clip-path: inset(100% 0 0 0); + transform: translateY(20px); +} + +.kfx-reveal.is-in { + opacity: 1; + transform: none; + filter: none; + clip-path: inset(0 0 0 0); +} + +/* Stagger para hijos */ +[data-stagger]>* { + opacity: 0; + transform: translateY(22px); + transition: opacity 0.65s var(--ease-out-soft), transform 0.65s var(--ease-out-soft); +} + +[data-stagger].is-in>* { + opacity: 1; + transform: none; +} + +[data-stagger].is-in>*:nth-child(1) { + transition-delay: 0.04s; +} + +[data-stagger].is-in>*:nth-child(2) { + transition-delay: 0.10s; +} + +[data-stagger].is-in>*:nth-child(3) { + transition-delay: 0.16s; +} + +[data-stagger].is-in>*:nth-child(4) { + transition-delay: 0.22s; +} + +[data-stagger].is-in>*:nth-child(5) { + transition-delay: 0.28s; +} + +[data-stagger].is-in>*:nth-child(6) { + transition-delay: 0.34s; +} + +[data-stagger].is-in>*:nth-child(7) { + transition-delay: 0.40s; +} + +[data-stagger].is-in>*:nth-child(8) { + transition-delay: 0.46s; +} + +[data-stagger].is-in>*:nth-child(9) { + transition-delay: 0.52s; +} + +[data-stagger].is-in>*:nth-child(10) { + transition-delay: 0.58s; +} + +/* Compatibilidad con animate-on-scroll original (mejorado) */ +.animate-on-scroll { + transition: + opacity 0.75s var(--ease-out-soft), + transform 0.75s var(--ease-out-soft) !important; +} + +/* ───────────────────────────────────────────────────────────────────── + 10. CONTADORES Y MARCADOR LIVE + ───────────────────────────────────────────────────────────────────── */ +.kfx-counter { + font-family: var(--font-display) !important; + font-feature-settings: "tnum" 1, "lnum" 1; + font-variant-numeric: tabular-nums lining-nums; + display: inline-block; +} + +.kfx-live-pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + background: rgba(194, 0, 0, 0.08); + border: 1px solid rgba(194, 0, 0, 0.3); + border-radius: 999px; + color: var(--primary); + font-family: var(--font-body); + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.18em; +} + +.kfx-live-pill::before { + content: ''; + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--primary); + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0.6); + animation: livePulseRing 1.8s ease-out infinite; +} + +@keyframes livePulseRing { + 0% { + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0.6); + } + + 70% { + box-shadow: 0 0 0 12px rgba(194, 0, 0, 0); + } + + 100% { + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 11. MARQUEE / TICKER (ej: sponsors, headlines) + ───────────────────────────────────────────────────────────────────── */ +.kfx-marquee { + overflow: hidden; + position: relative; + --marquee-speed: 40s; + -webkit-mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent); + mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent); +} + +.kfx-marquee__track { + display: inline-flex; + gap: 4rem; + white-space: nowrap; + animation: marqueeSlide var(--marquee-speed) linear infinite; +} + +.kfx-marquee:hover .kfx-marquee__track { + animation-play-state: paused; +} + +@keyframes marqueeSlide { + from { + transform: translateX(0); + } + + to { + transform: translateX(-50%); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 12. INPUTS — focus glow + label flotante (opcional) + ───────────────────────────────────────────────────────────────────── */ +.form-control, +.form-select { + transition: + border-color 0.25s ease, + box-shadow 0.3s ease, + background-color 0.25s ease, + transform 0.2s ease !important; +} + +.form-control:focus, +.form-select:focus { + box-shadow: 0 0 0 4px rgba(194, 0, 0, 0.10), + 0 8px 22px -16px rgba(194, 0, 0, 0.6) !important; + transform: translateY(-1px); +} + +/* Floating label compatible (envolver con .kfx-float) */ +.kfx-float { + position: relative; +} + +.kfx-float>.form-control { + padding-top: 1.4rem; + padding-bottom: 0.5rem; +} + +.kfx-float>label { + position: absolute; + top: 0.85rem; + left: 0.95rem; + color: var(--on-surface-muted); + pointer-events: none; + transition: transform 0.2s var(--ease-out-soft), color 0.2s ease, font-size 0.2s ease; + font-size: 0.95rem; + transform-origin: left center; +} + +.kfx-float>.form-control:focus+label, +.kfx-float>.form-control:not(:placeholder-shown)+label { + transform: translateY(-12px) scale(0.78); + color: var(--primary); +} + +/* ───────────────────────────────────────────────────────────────────── + 13. DIVIDERS Y SECCIONES KINÉTICAS + ───────────────────────────────────────────────────────────────────── */ +.kfx-section-tag { + display: inline-flex; + align-items: center; + gap: 0.75rem; + font-family: var(--font-body) !important; + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.22em; + color: var(--primary); + margin-bottom: 0.75rem; +} + +.kfx-section-tag::before { + content: ''; + width: 32px; + height: 2px; + background: var(--primary); + transform-origin: left; + transform: scaleX(0); + transition: transform 0.7s var(--ease-arc); +} + +.kfx-section-tag.is-in::before, +.kfx-reveal.is-in .kfx-section-tag::before { + transform: scaleX(1); +} + +.kfx-divider-sweep { + position: relative; + height: 1px; + background: var(--outline-variant); + overflow: hidden; + margin: 3rem 0; +} + +.kfx-divider-sweep::after { + content: ''; + position: absolute; + inset: 0; + width: 60%; + background: linear-gradient(90deg, transparent, var(--primary), transparent); + animation: sweep 3.5s ease-in-out infinite; +} + +@keyframes sweep { + 0% { + transform: translateX(-110%); + } + + 100% { + transform: translateX(220%); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 14. TABLAS — hover slide + zebra suave + ───────────────────────────────────────────────────────────────────── */ +.table tbody tr { + transition: background 0.2s ease, transform 0.25s var(--ease-out-soft); +} + +.table tbody tr:hover { + background: rgba(194, 0, 0, 0.04); +} + +.table tbody tr:hover td:first-child { + box-shadow: inset 3px 0 0 var(--primary); +} + +.table-dark tbody tr:hover { + background: rgba(194, 0, 0, 0.18) !important; +} + +/* Standings rank top-3 con resaltado */ +#standingsCarousel tbody tr:nth-child(1) td:first-child { + color: #ffd34a !important; + font-weight: 800; +} + +#standingsCarousel tbody tr:nth-child(2) td:first-child { + color: #d8d8d8 !important; + font-weight: 700; +} + +#standingsCarousel tbody tr:nth-child(3) td:first-child { + color: #d28a4a !important; + font-weight: 700; +} + +/* ───────────────────────────────────────────────────────────────────── + 15. BADGES MEJORADOS + ───────────────────────────────────────────────────────────────────── */ +.badge { + transition: transform 0.2s var(--ease-spring), box-shadow 0.2s ease; +} + +.badge:hover { + transform: scale(1.06); +} + +.badge.bg-primary { + background: linear-gradient(135deg, var(--primary), var(--primary-deep)) !important; + box-shadow: 0 4px 12px -6px rgba(194, 0, 0, 0.45); +} + +/* ───────────────────────────────────────────────────────────────────── + 16. MODALES — entrada elegante + ───────────────────────────────────────────────────────────────────── */ +.modal.fade .modal-dialog { + transform: translateY(40px) scale(0.96); + transition: transform 0.45s var(--ease-spring), opacity 0.4s ease !important; +} + +.modal.show .modal-dialog { + transform: translateY(0) scale(1); +} + +.modal-backdrop.show { + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); +} + +.modal-content { + border: 1px solid var(--outline-variant); + border-radius: var(--radius) !important; + box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.45); + animation: modalGlow 0.6s ease; +} + +@keyframes modalGlow { + from { + box-shadow: 0 0 0 rgba(194, 0, 0, 0); + } + + to { + box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.45); + } +} + +.nav-tabs .nav-link { + position: relative; + transition: color 0.25s ease; +} + +.nav-tabs .nav-link::after { + content: ''; + position: absolute; + left: 10%; + right: 10%; + bottom: -1px; + height: 3px; + background: var(--primary); + transform: scaleX(0); + transform-origin: left center; + transition: transform 0.4s var(--ease-arc); +} + +.nav-tabs .nav-link.active::after { + transform: scaleX(1); +} + +/* ───────────────────────────────────────────────────────────────────── + 17. SPLASH — cinemático + ───────────────────────────────────────────────────────────────────── */ +#splash-screen { + background: radial-gradient(ellipse at center, #1a1a18 0%, #0a0a0a 100%); +} + +#splash-screen::before { + content: ''; + position: absolute; + inset: -50%; + background: + repeating-linear-gradient(45deg, + rgba(194, 0, 0, 0.04) 0, + rgba(194, 0, 0, 0.04) 1px, + transparent 1px, + transparent 12px); + animation: splashSweep 8s linear infinite; + pointer-events: none; +} + +@keyframes splashSweep { + from { + transform: translate(-25%, -25%) rotate(0deg); + } + + to { + transform: translate(-25%, -25%) rotate(360deg); + } +} + +#splash-logo { + position: relative; + filter: drop-shadow(0 12px 30px rgba(194, 0, 0, 0.55)); +} + +/* ───────────────────────────────────────────────────────────────────── + 18. PWA banner — refinado + ───────────────────────────────────────────────────────────────────── */ +#pwa-install-banner { + border-top: 1px solid var(--outline-variant) !important; + background: rgba(255, 255, 255, 0.96) !important; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + animation: bannerRise 0.5s var(--ease-spring); +} + +@keyframes bannerRise { + from { + transform: translateY(110%); + } + + to { + transform: translateY(0); + } +} + +#pwa-install-btn { + background: linear-gradient(135deg, var(--primary), var(--primary-deep)) !important; + color: white !important; + border: none !important; + box-shadow: 0 8px 24px -10px rgba(194, 0, 0, 0.55); + transition: transform 0.25s var(--ease-spring), box-shadow 0.25s ease !important; +} + +#pwa-install-btn:hover { + transform: translateY(-2px); + box-shadow: 0 14px 30px -10px rgba(194, 0, 0, 0.65); +} + +/* ───────────────────────────────────────────────────────────────────── + 19. SKELETON / SHIMMER + ───────────────────────────────────────────────────────────────────── */ +.kfx-skeleton { + position: relative; + overflow: hidden; + background: var(--surface-container); + border-radius: var(--radius-sm); +} + +.kfx-skeleton::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(90deg, + transparent, + rgba(255, 255, 255, 0.5), + transparent); + animation: shimmer 1.6s linear infinite; +} + +@keyframes shimmer { + from { + transform: translateX(-100%); + } + + to { + transform: translateX(100%); + } +} + +/* ───────────────────────────────────────────────────────────────────── + 20. SPONSORS CAROUSEL — fade edges + hover lift + ───────────────────────────────────────────────────────────────────── */ +.sponsor-carousel-container { + -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent); + mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent); +} + +.sponsor-item { + transition: transform 0.4s var(--ease-out-soft); +} + +.sponsor-item:hover { + transform: translateY(-3px); +} + +/* ───────────────────────────────────────────────────────────────────── + 21. FOOTER — refinado + ───────────────────────────────────────────────────────────────────── */ +footer.footer { + position: relative; + overflow: hidden; + background: var(--arena-dark) !important; + color: rgba(255, 255, 255, 0.65) !important; +} + +footer.footer::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--primary), transparent); + animation: sweep 5s ease-in-out infinite; +} + +/* ───────────────────────────────────────────────────────────────────── + 22. UTILIDADES INNOVADORAS + ───────────────────────────────────────────────────────────────────── */ + +/* Texto con gradiente animado */ +.kfx-text-gradient { + background: linear-gradient(120deg, var(--primary) 0%, #ff3232 35%, var(--primary-deep) 70%, var(--primary) 100%); + background-size: 250% 100%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + color: transparent; + animation: textShift 6s ease-in-out infinite; +} + +@keyframes textShift { + + 0%, + 100% { + background-position: 0% 50%; + } + + 50% { + background-position: 100% 50%; + } +} + +/* Borde animado */ +.kfx-border-glow { + position: relative; + isolation: isolate; +} + +.kfx-border-glow::before { + content: ''; + position: absolute; + inset: -1px; + border-radius: inherit; + background: conic-gradient(from 0deg, transparent 0%, var(--primary) 25%, transparent 50%); + animation: borderSpin 4s linear infinite; + z-index: -1; +} + +.kfx-border-glow::after { + content: ''; + position: absolute; + inset: 1px; + background: var(--surface-container-lowest); + border-radius: inherit; + z-index: -1; +} + +@keyframes borderSpin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +/* Underline kinético en links */ +.kfx-link { + position: relative; + text-decoration: none; + color: inherit; + background-image: linear-gradient(currentColor, currentColor); + background-position: 0% 100%; + background-repeat: no-repeat; + background-size: 0% 1.5px; + transition: background-size 0.45s var(--ease-arc), color 0.25s ease; +} + +.kfx-link:hover { + background-size: 100% 1.5px; + color: var(--primary); +} + +/* Imagen con zoom suave en hover y mask reveal */ +.kfx-img-cover { + overflow: hidden; + position: relative; +} + +.kfx-img-cover img { + transition: transform 0.9s var(--ease-out-soft), filter 0.5s ease; + will-change: transform; +} + +.kfx-img-cover:hover img { + transform: scale(1.06); + filter: saturate(1.1) contrast(1.05); +} + +.kfx-img-cover::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(180deg, transparent 50%, rgba(0, 0, 0, 0.45)); + opacity: 0; + transition: opacity 0.45s ease; + pointer-events: none; +} + +.kfx-img-cover:hover::after { + opacity: 1; +} + +/* Spotlight: contenido sobre imagen */ +.kfx-img-spotlight { + position: relative; + overflow: hidden; +} + +.kfx-img-spotlight::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(500px circle at var(--mx, 50%) var(--my, 50%), + rgba(194, 0, 0, 0.18), + transparent 60%); + opacity: 0; + transition: opacity 0.4s ease; + z-index: 1; + pointer-events: none; +} + +.kfx-img-spotlight:hover::before { + opacity: 1; +} + +/* Etiqueta numerada estilo deportivo */ +.kfx-jersey { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + background: var(--arena-dark); + color: var(--primary); + font-family: var(--font-display); + font-weight: 800; + font-size: 1.1rem; + border-radius: 4px; + box-shadow: inset 0 0 0 2px var(--primary); + transition: transform 0.3s var(--ease-spring); +} + +.kfx-jersey:hover { + transform: rotate(-4deg) scale(1.05); +} + +/* Badge dot pulsante */ +.kfx-dot { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--primary); + box-shadow: 0 0 0 0 rgba(194, 0, 0, 0.7); + animation: badgeRing 1.6s ease-out infinite; + vertical-align: middle; +} + +/* No-grain (en superficies oscuras) */ +.no-grain::after { + display: none !important; +} + +/* Página entrada */ +@keyframes pageIn { + from { + opacity: 0; + transform: translateY(8px); + } + + to { + opacity: 1; + transform: none; + } +} + +.content { + animation: pageIn 0.5s var(--ease-out-soft); +} + +/* Fix para evitar que las letras con "pancita" (p, g, y, q) se corten abajo */ +.texto-sin-cortar, +h1, +h2, +h3, +h4, +h5, +h6, +.fc-toolbar-title { + line-height: 1.3 !important; + padding-bottom: 2px !important; +} + +/* ───────────────────────────────────────────────────────────────────── + 23. ADMIN — sidebar premium e interacciones + ───────────────────────────────────────────────────────────────────── */ +.admin-sidebar { + background: + linear-gradient(180deg, rgba(194, 0, 0, 0.05), transparent 30%), + var(--admin-sidebar-bg, #0A0A0A) !important; +} + +.admin-sidebar::before { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 1px; + height: 100%; + background: linear-gradient(180deg, transparent, rgba(194, 0, 0, 0.3) 50%, transparent); + pointer-events: none; +} + +.sidebar-link { + position: relative; + overflow: hidden; +} + +.sidebar-link::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 3px; + background: var(--primary); + transform: scaleY(0); + transition: transform 0.35s var(--ease-arc); +} + +.sidebar-link:hover::before, +.sidebar-link.active::before { + transform: scaleY(1); +} + +.sidebar-link i { + transition: transform 0.35s var(--ease-spring), color 0.25s ease; +} + +.sidebar-link:hover i { + transform: translateX(3px) scale(1.08); + color: var(--primary); +} + +.sidebar-link.active { + background: + linear-gradient(90deg, + rgba(194, 0, 0, 0.95), + rgba(138, 0, 0, 0.85)) !important; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06); +} + +.sidebar-link.active i { + color: white !important; + transform: none; +} + +/* Stat-card admin: número con tick + glow */ +.stat-card { + background: linear-gradient(135deg, #0a0a0a, #1a1a1a) !important; + transition: transform 0.45s var(--ease-out-soft), box-shadow 0.45s ease; + overflow: hidden; + position: relative; +} + +.stat-card::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle at 100% 0%, rgba(194, 0, 0, 0.25), transparent 60%); + opacity: 0; + transition: opacity 0.4s ease; +} + +.stat-card:hover { + transform: translateY(-4px); + box-shadow: 0 24px 40px -20px rgba(0, 0, 0, 0.55); +} + +.stat-card:hover::before { + opacity: 1; +} + +.stat-card .stat-value { + background: linear-gradient(135deg, #fff, #ffb4b4); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +/* Admin card hover */ +.admin-card { + border-radius: 4px !important; + transition: transform 0.35s var(--ease-out-soft), box-shadow 0.35s ease; +} + +.admin-card:hover { + transform: translateY(-2px); + box-shadow: 0 18px 40px -22px rgba(0, 0, 0, 0.18); +} + +/* Botones admin con sweep */ +.btn-admin-primary { + position: relative; + overflow: hidden; + transition: transform 0.25s var(--ease-spring), box-shadow 0.3s ease, background 0.25s ease !important; +} + +.btn-admin-primary::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.25), transparent); + transform: translateX(-110%) skewX(-15deg); + transition: transform 0.6s var(--ease-arc); +} + +.btn-admin-primary:hover::after { + transform: translateX(110%) skewX(-15deg); +} + +.btn-admin-primary:hover { + box-shadow: 0 14px 28px -12px rgba(194, 0, 0, 0.55); + transform: translateY(-2px); +} + +/* Topbar admin con glass */ +.admin-topbar { + background: rgba(255, 255, 255, 0.85) !important; + backdrop-filter: blur(18px) saturate(180%); + -webkit-backdrop-filter: blur(18px) saturate(180%); + position: sticky; + top: 0; + z-index: 100; +} + +/* Avatar con anillo */ +.admin-topbar .bg-primary { + background: linear-gradient(135deg, var(--primary), var(--primary-deep)) !important; + box-shadow: + 0 0 0 3px rgba(194, 0, 0, 0.15), + 0 6px 18px -6px rgba(194, 0, 0, 0.5); + transition: transform 0.3s var(--ease-spring); +} + +.admin-topbar .bg-primary:hover { + transform: rotate(-6deg) scale(1.05); +} + +/* Mejor scroll en sidebar (móvil overlay) */ +.sidebar-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; + z-index: 999; +} + +.sidebar-overlay.show { + opacity: 1; + visibility: visible; +} + +/* Tablas admin con accent */ +.kinetic-table tr { + transition: background 0.2s ease; +} + +.kinetic-table tr:hover td { + background: rgba(194, 0, 0, 0.04); + box-shadow: inset 3px 0 0 var(--primary); +} + +/* ───────────────────────────────────────────────────────────────────── + 24. NOTICIAS / EVENTOS — micro UI + ───────────────────────────────────────────────────────────────────── */ +.kinetic-news-item { + position: relative; + transition: background 0.3s var(--ease-out-soft), padding-left 0.3s var(--ease-out-soft); +} + +.kinetic-news-item::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + width: 0; + height: 2px; + background: var(--primary); + transition: width 0.4s var(--ease-arc); + transform: translateY(-50%); +} + +.kinetic-news-item:hover { + background: rgba(194, 0, 0, 0.03); + padding-left: 12px; +} + +.kinetic-news-item:hover::before { + width: 8px; +} + +/* Eventos – tarjeta con flecha animada */ +.kfx-event-cta { + display: inline-flex; + align-items: center; + gap: 8px; + overflow: hidden; +} + +.kfx-event-cta::after { + content: '→'; + transition: transform 0.35s var(--ease-arc); + display: inline-block; +} + +.kinetic-card:hover .kfx-event-cta::after { + transform: translateX(6px); +} + +/* ───────────────────────────────────────────────────────────────────── + 25. RESPONSIVE — desactivar efectos pesados en móvil + ───────────────────────────────────────────────────────────────────── */ +@media (max-width: 768px) { + .kinetic-card:hover { + transform: none; + } + + .kinetic-card::before { + display: none; + } + + [data-tilt] { + transform: none !important; + } + + .kinetic-cursor-dot, + .kinetic-cursor-ring { + display: none !important; + } + + body.kinetic-cursor-on, + body.kinetic-cursor-on * { + cursor: auto; + } +} + +/* ───────────────────────────────────────────────────────────────────── + 26. SELECCIÓN DE TEXTO Y FOCUS GLOBAL + ───────────────────────────────────────────────────────────────────── */ +/* IMPORTANTE: ::selection sólo soporta `color` y `background-color`, + NO el shorthand `background`. Usar shorthand causa que la regla se ignore + silenciosamente en Chrome/Edge → quedaba selección invisible (blanco/blanco). */ +::selection { + background-color: var(--primary) !important; + color: #ffffff !important; +} + +::-moz-selection { + background-color: var(--primary) !important; + color: #ffffff !important; +} + +/* Override específico para que la selección dentro de modales SweetAlert + también respete los colores de marca (algunas reglas internas del SWAL + quedan más específicas y pisan la global). */ +.swal2-popup ::selection, +.swal2-popup *::selection { + background-color: var(--primary) !important; + color: #ffffff !important; +} + +.swal2-popup ::-moz-selection, +.swal2-popup *::-moz-selection { + background-color: var(--primary) !important; + color: #ffffff !important; +} + +:focus-visible { + outline: 2px solid var(--primary); + outline-offset: 2px; + border-radius: 2px; +} + +/* ───────────────────────────────────────────────────────────────────── + 27. SWEETALERT2 — afinado de marca + ───────────────────────────────────────────────────────────────────── */ +.swal2-popup { + border-radius: var(--radius) !important; + font-family: var(--font-body) !important; + border: 1px solid var(--outline-variant); + box-shadow: 0 25px 60px -25px rgba(26, 18, 8, 0.4) !important; +} + +.swal2-title { + font-family: var(--font-display) !important; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.swal2-toast { + border-left: 4px solid var(--primary) !important; +} + +/* Botón CONFIRMAR de SweetAlert. + SWAL aplica `style="background-color: rgb(...)"` inline desde JS + (vía confirmButtonColor). Usamos background-color + background-image por + separado con !important para que el inline NO gane. Antes usábamos + shorthand `background:` que en algunos casos no se aplicaba como esperado. */ +.swal2-styled.swal2-confirm, +.swal2-popup .swal2-actions .swal2-styled.swal2-confirm, +button.swal2-confirm.swal2-styled { + background-color: var(--primary) !important; + background-image: linear-gradient(135deg, var(--primary), var(--primary-deep)) !important; + color: #ffffff !important; + border: none !important; + border-radius: var(--radius-sm) !important; + text-transform: uppercase !important; + letter-spacing: 0.08em !important; + font-weight: 700 !important; + box-shadow: 0 6px 18px -8px rgba(194, 0, 0, 0.55); + transition: transform 0.2s var(--ease-spring), box-shadow 0.25s ease, filter 0.2s ease; +} + +.swal2-styled.swal2-confirm:hover, +.swal2-popup .swal2-actions .swal2-styled.swal2-confirm:hover, +button.swal2-confirm.swal2-styled:hover { + background-color: var(--primary-deep) !important; + background-image: linear-gradient(135deg, var(--primary-deep), var(--primary)) !important; + color: #ffffff !important; + transform: translateY(-1px); + box-shadow: 0 10px 24px -10px rgba(194, 0, 0, 0.65); + filter: brightness(1.05); +} + +.swal2-styled.swal2-confirm:focus, +button.swal2-confirm.swal2-styled:focus { + box-shadow: 0 0 0 3px rgba(194, 0, 0, 0.35), + 0 6px 18px -8px rgba(194, 0, 0, 0.55) !important; + outline: none !important; +} + +/* Botón CANCELAR de SweetAlert: gris consistente, texto blanco legible. */ +.swal2-styled.swal2-cancel, +.swal2-popup .swal2-actions .swal2-styled.swal2-cancel, +button.swal2-cancel.swal2-styled { + background-color: #6c757d !important; + background-image: none !important; + color: #ffffff !important; + border: none !important; + border-radius: var(--radius-sm) !important; + text-transform: uppercase !important; + letter-spacing: 0.08em !important; + font-weight: 700 !important; +} + +.swal2-styled.swal2-cancel:hover, +button.swal2-cancel.swal2-styled:hover { + background-color: #5a6268 !important; + color: #ffffff !important; +} + +/* Botón DENY (cuando exista) */ +.swal2-styled.swal2-deny, +button.swal2-deny.swal2-styled { + background-color: #b91c1c !important; + background-image: none !important; + color: #ffffff !important; + border: none !important; + border-radius: var(--radius-sm) !important; + text-transform: uppercase !important; + letter-spacing: 0.08em !important; + font-weight: 700 !important; +} \ No newline at end of file diff --git a/public/static/kinetic-arena-v3.min.css b/public/static/kinetic-arena-v3.min.css new file mode 100644 index 0000000..7e49fa5 --- /dev/null +++ b/public/static/kinetic-arena-v3.min.css @@ -0,0 +1 @@ +:root{--ease-spring:cubic-bezier(0.34,1.56,0.64,1);--ease-out-soft:cubic-bezier(0.16,1,0.3,1);--ease-power:cubic-bezier(0.83,0,0.17,1);--ease-arc:cubic-bezier(0.65,0.05,0.36,1);--dur-snap:140ms;--dur-quick:220ms;--dur-base:360ms;--dur-soft:560ms;--dur-stage:900ms;--primary-glow:0 0 0 0 rgba(194,0,0,0.45);--primary-shadow-soft:0 18px 40px -22px rgba(194,0,0,0.55);--kinetic-shadow-deep:0 40px 80px -30px rgba(26,18,8,0.35);--kinetic-shadow-card:0 22px 45px -28px rgba(26,18,8,0.28);--grain-mix:multiply}@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.001ms !important;animation-iteration-count:1 !important;transition-duration:0.001ms !important;scroll-behavior:auto !important}}*{scrollbar-width:thin;scrollbar-color:var(--primary) transparent}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:var(--surface-container-low)}::-webkit-scrollbar-thumb{background:linear-gradient(180deg,var(--primary),var(--primary-deep));border-radius:999px;border:2px solid var(--surface-container-low)}::-webkit-scrollbar-thumb:hover{background:var(--primary-deep)}#kinetic-reading-bar{position:fixed;top:0;left:0;height:3px;width:0%;background:linear-gradient(90deg,var(--primary),#ff3232,var(--primary-deep));background-size:200% 100%;animation:barShimmer 3s linear infinite;z-index:2000;transition:width 0.12s linear;box-shadow:0 0 12px rgba(194,0,0,0.6);pointer-events:none}@keyframes barShimmer{from{background-position:0% 0}to{background-position:200% 0}}@media (hover:hover) and (pointer:fine){body.kinetic-cursor-on,body.kinetic-cursor-on *{cursor:none}body.kinetic-cursor-on input,body.kinetic-cursor-on textarea,body.kinetic-cursor-on select{cursor:text}.kinetic-cursor-dot,.kinetic-cursor-ring{position:fixed;top:0;left:0;pointer-events:none;z-index:9999;will-change:transform}.kinetic-cursor-dot{width:10px;height:10px;background:var(--primary);border-radius:50%;transform:translate(-50%,-50%);border:2px solid #111;box-shadow:0 0 0 1px rgba(255,255,255,0.6),0 2px 8px rgba(0,0,0,0.45);transition:transform var(--dur-snap) var(--ease-spring),width var(--dur-quick),height var(--dur-quick),background var(--dur-quick),border-color var(--dur-quick)}.kinetic-cursor-ring{width:38px;height:38px;border:3px solid var(--primary);outline:2px solid #111;outline-offset:-1px;border-radius:50%;background:rgba(255,255,255,0.05);box-shadow:0 0 0 1px rgba(255,255,255,0.5),0 4px 14px rgba(0,0,0,0.35);transform:translate(-50%,-50%);transition:transform 0.18s var(--ease-out-soft),width var(--dur-quick),height var(--dur-quick),border-color var(--dur-quick),opacity var(--dur-quick)}.kinetic-cursor-ring.is-hover{width:60px;height:60px;border-color:var(--primary-deep);background:rgba(194,0,0,0.18);outline-color:#000}.kinetic-cursor-dot.is-hover{width:6px;height:6px;background:#fff;border-color:var(--primary-deep)}}.custom-navbar{transition:background-color 0.4s var(--ease-out-soft),border-color 0.4s var(--ease-out-soft),box-shadow 0.4s var(--ease-out-soft),padding 0.3s var(--ease-out-soft) !important}.custom-navbar.is-scrolled{background-color:rgba(245,243,239,0.78) !important;backdrop-filter:blur(28px) saturate(200%);-webkit-backdrop-filter:blur(28px) saturate(200%);border-bottom-color:rgba(194,0,0,0.15) !important;box-shadow:0 8px 30px -20px rgba(26,18,8,0.18) !important;padding:6px 0 !important}.custom-navbar .navbar-logo{transition:transform 0.45s var(--ease-spring),filter 0.4s ease}.custom-navbar .navbar-brand:hover .navbar-logo{transform:rotate(-6deg) scale(1.06);filter:drop-shadow(0 6px 14px rgba(194,0,0,0.35))}.custom-navbar .nav-link{overflow:hidden}.custom-navbar .nav-link::before{content:'';position:absolute;left:14px;right:14px;bottom:4px;height:2px;background:var(--primary);transform:scaleX(0);transform-origin:right center;transition:transform 0.42s var(--ease-arc)}.custom-navbar .nav-link:hover::before,.custom-navbar .nav-link.active::before{transform:scaleX(1);transform-origin:left center}.custom-navbar .nav-link.active::after{content:'';position:absolute;top:6px;left:6px;width:4px;height:4px;background:var(--primary);display:block !important;animation:kineticBlink 1.6s steps(2,jump-none) infinite}@keyframes kineticBlink{50%{opacity:0.2}}#notif-bell .bi-bell-fill{transition:transform 0.35s var(--ease-spring)}#notif-bell:hover .bi-bell-fill{animation:bellShake 0.6s var(--ease-out-soft)}@keyframes bellShake{0%,100%{transform:rotate(0)}20%{transform:rotate(15deg)}40%{transform:rotate(-12deg)}60%{transform:rotate(8deg)}80%{transform:rotate(-4deg)}}#notif-badge{box-shadow:0 0 0 0 rgba(194,0,0,0.7);animation:badgeRing 1.8s var(--ease-out-soft) infinite}@keyframes badgeRing{0%{box-shadow:0 0 0 0 rgba(194,0,0,0.6)}70%{box-shadow:0 0 0 12px rgba(194,0,0,0)}100%{box-shadow:0 0 0 0 rgba(194,0,0,0)}}.kinetic-card{position:relative;overflow:hidden;transform-style:preserve-3d;transition:transform 0.55s var(--ease-out-soft),box-shadow 0.55s var(--ease-out-soft),border-color 0.45s ease}.kinetic-card::before{content:'';position:absolute;inset:0;background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),rgba(194,0,0,0.08),transparent 55%);opacity:0;transition:opacity 0.45s ease;pointer-events:none;z-index:1}.kinetic-card::after{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(180deg,var(--primary),var(--primary-deep));transform:scaleY(0);transform-origin:top center;transition:transform 0.5s var(--ease-arc);z-index:2}.kinetic-card:hover{transform:translateY(-6px);box-shadow:var(--kinetic-shadow-card);border-color:rgba(194,0,0,0.3)}.kinetic-card:hover::before{opacity:1}.kinetic-card:hover::after{transform:scaleY(1)}.kinetic-card>*{position:relative;z-index:3}[data-tilt]{transform:perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));transition:transform 0.25s var(--ease-out-soft);will-change:transform}[data-tilt].is-tilting{transition:transform 0.05s linear}.btn-kinetic-primary,.btn,.btn-admin-primary{position:relative;isolation:isolate;overflow:hidden}.btn-kinetic-primary{transition:background-color var(--dur-quick) ease,color var(--dur-quick) ease,transform var(--dur-quick) var(--ease-spring),box-shadow var(--dur-base) var(--ease-out-soft),letter-spacing var(--dur-quick) ease !important}.btn-kinetic-primary::after{content:'';position:absolute;inset:0;background:linear-gradient(120deg,transparent 0%,rgba(255,255,255,0.28) 40%,rgba(255,255,255,0.55) 50%,rgba(255,255,255,0.28) 60%,transparent 100%);transform:translateX(-110%) skewX(-15deg);transition:transform 0.65s var(--ease-arc);z-index:1;pointer-events:none}.btn-kinetic-primary:hover{box-shadow:var(--primary-shadow-soft);letter-spacing:0.16em !important;transform:translateY(-2px) !important}.btn-kinetic-primary:hover::after{transform:translateX(110%) skewX(-15deg)}.btn-kinetic-primary>*{position:relative;z-index:2}.kinetic-ripple-wave{position:absolute;border-radius:50%;background:rgba(255,255,255,0.45);transform:translate(-50%,-50%) scale(0);animation:ripple 0.6s var(--ease-out-soft);pointer-events:none;z-index:0}@keyframes ripple{to{transform:translate(-50%,-50%) scale(4);opacity:0}}[data-magnetic]{transition:transform 0.22s var(--ease-out-soft);will-change:transform}.hero-title{display:inline-block;padding-bottom:0.18em;line-height:1.02 !important}.hero-title .word,.kinetic-reveal-text .word{display:inline-block;overflow:hidden;vertical-align:bottom;padding-bottom:0.22em;line-height:1.05}.hero-title .word>span,.kinetic-reveal-text .word>span{display:inline-block;transform:translateY(130%);transition:transform 0.95s var(--ease-arc)}.kinetic-reveal-text{display:inline-block;padding-bottom:0.18em;line-height:1.05 !important}h1,h2,h3,h4,h5,h6,.display-1,.display-2,.display-3,.display-4,.display-5,.display-6,.hero-title{line-height:1.05 !important;padding-bottom:0.08em}.display-1,.display-2,.display-3,.hero-title{padding-bottom:0.12em}.hero-title.is-in .word>span,.kinetic-reveal-text.is-in .word>span{transform:translateY(0)}.hero-title.is-in .word:nth-child(2)>span{transition-delay:0.08s}.hero-title.is-in .word:nth-child(3)>span{transition-delay:0.16s}.hero-title.is-in .word:nth-child(4)>span{transition-delay:0.24s}.hero-title.is-in .word:nth-child(5)>span{transition-delay:0.32s}.hero-title.is-in .word:nth-child(6)>span{transition-delay:0.40s}.hero-title.is-in .word:nth-child(7)>span{transition-delay:0.48s}.hero-title.is-in .word:nth-child(8)>span{transition-delay:0.56s}.kinetic-highlight{position:relative;display:inline-block;color:var(--primary);isolation:isolate}.kinetic-highlight::before{content:'';position:absolute;inset:8% -4% 8% -4%;background:rgba(194,0,0,0.12);transform:scaleX(0);transform-origin:left center;transition:transform 0.7s var(--ease-arc) 0.4s;z-index:-1;border-radius:2px}.kinetic-highlight.is-in::before{transform:scaleX(1)}.hero-clip,img.hero-clip{transition:clip-path 1.2s var(--ease-arc),transform 6s var(--ease-out-soft);will-change:transform}.carousel-item.active img.hero-clip{transform:scale(1.04)}.kfx-reveal{opacity:0;transition:opacity 0.7s var(--ease-out-soft),transform 0.7s var(--ease-out-soft),filter 0.7s var(--ease-out-soft),clip-path 0.9s var(--ease-arc);will-change:transform,opacity}.kfx-reveal[data-fx="up"]{transform:translateY(28px)}.kfx-reveal[data-fx="down"]{transform:translateY(-28px)}.kfx-reveal[data-fx="left"]{transform:translateX(-28px)}.kfx-reveal[data-fx="right"]{transform:translateX(28px)}.kfx-reveal[data-fx="zoom"]{transform:scale(0.92)}.kfx-reveal[data-fx="blur"]{filter:blur(14px);transform:translateY(12px)}.kfx-reveal[data-fx="curtain"]{clip-path:inset(0 100% 0 0)}.kfx-reveal[data-fx="rise"]{clip-path:inset(100% 0 0 0);transform:translateY(20px)}.kfx-reveal.is-in{opacity:1;transform:none;filter:none;clip-path:inset(0 0 0 0)}[data-stagger]>*{opacity:0;transform:translateY(22px);transition:opacity 0.65s var(--ease-out-soft),transform 0.65s var(--ease-out-soft)}[data-stagger].is-in>*{opacity:1;transform:none}[data-stagger].is-in>*:nth-child(1){transition-delay:0.04s}[data-stagger].is-in>*:nth-child(2){transition-delay:0.10s}[data-stagger].is-in>*:nth-child(3){transition-delay:0.16s}[data-stagger].is-in>*:nth-child(4){transition-delay:0.22s}[data-stagger].is-in>*:nth-child(5){transition-delay:0.28s}[data-stagger].is-in>*:nth-child(6){transition-delay:0.34s}[data-stagger].is-in>*:nth-child(7){transition-delay:0.40s}[data-stagger].is-in>*:nth-child(8){transition-delay:0.46s}[data-stagger].is-in>*:nth-child(9){transition-delay:0.52s}[data-stagger].is-in>*:nth-child(10){transition-delay:0.58s}.animate-on-scroll{transition:opacity 0.75s var(--ease-out-soft),transform 0.75s var(--ease-out-soft) !important}.kfx-counter{font-family:var(--font-display) !important;font-feature-settings:"tnum" 1,"lnum" 1;font-variant-numeric:tabular-nums lining-nums;display:inline-block}.kfx-live-pill{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background:rgba(194,0,0,0.08);border:1px solid rgba(194,0,0,0.3);border-radius:999px;color:var(--primary);font-family:var(--font-body);font-size:0.7rem;font-weight:700;text-transform:uppercase;letter-spacing:0.18em}.kfx-live-pill::before{content:'';width:7px;height:7px;border-radius:50%;background:var(--primary);box-shadow:0 0 0 0 rgba(194,0,0,0.6);animation:livePulseRing 1.8s ease-out infinite}@keyframes livePulseRing{0%{box-shadow:0 0 0 0 rgba(194,0,0,0.6)}70%{box-shadow:0 0 0 12px rgba(194,0,0,0)}100%{box-shadow:0 0 0 0 rgba(194,0,0,0)}}.kfx-marquee{overflow:hidden;position:relative;--marquee-speed:40s;-webkit-mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent);mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent)}.kfx-marquee__track{display:inline-flex;gap:4rem;white-space:nowrap;animation:marqueeSlide var(--marquee-speed) linear infinite}.kfx-marquee:hover .kfx-marquee__track{animation-play-state:paused}@keyframes marqueeSlide{from{transform:translateX(0)}to{transform:translateX(-50%)}}.form-control,.form-select{transition:border-color 0.25s ease,box-shadow 0.3s ease,background-color 0.25s ease,transform 0.2s ease !important}.form-control:focus,.form-select:focus{box-shadow:0 0 0 4px rgba(194,0,0,0.10),0 8px 22px -16px rgba(194,0,0,0.6) !important;transform:translateY(-1px)}.kfx-float{position:relative}.kfx-float>.form-control{padding-top:1.4rem;padding-bottom:0.5rem}.kfx-float>label{position:absolute;top:0.85rem;left:0.95rem;color:var(--on-surface-muted);pointer-events:none;transition:transform 0.2s var(--ease-out-soft),color 0.2s ease,font-size 0.2s ease;font-size:0.95rem;transform-origin:left center}.kfx-float>.form-control:focus+label,.kfx-float>.form-control:not(:placeholder-shown)+label{transform:translateY(-12px) scale(0.78);color:var(--primary)}.kfx-section-tag{display:inline-flex;align-items:center;gap:0.75rem;font-family:var(--font-body) !important;font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.22em;color:var(--primary);margin-bottom:0.75rem}.kfx-section-tag::before{content:'';width:32px;height:2px;background:var(--primary);transform-origin:left;transform:scaleX(0);transition:transform 0.7s var(--ease-arc)}.kfx-section-tag.is-in::before,.kfx-reveal.is-in .kfx-section-tag::before{transform:scaleX(1)}.kfx-divider-sweep{position:relative;height:1px;background:var(--outline-variant);overflow:hidden;margin:3rem 0}.kfx-divider-sweep::after{content:'';position:absolute;inset:0;width:60%;background:linear-gradient(90deg,transparent,var(--primary),transparent);animation:sweep 3.5s ease-in-out infinite}@keyframes sweep{0%{transform:translateX(-110%)}100%{transform:translateX(220%)}}.table tbody tr{transition:background 0.2s ease,transform 0.25s var(--ease-out-soft)}.table tbody tr:hover{background:rgba(194,0,0,0.04)}.table tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--primary)}.table-dark tbody tr:hover{background:rgba(194,0,0,0.18) !important}#standingsCarousel tbody tr:nth-child(1) td:first-child{color:#ffd34a !important;font-weight:800}#standingsCarousel tbody tr:nth-child(2) td:first-child{color:#d8d8d8 !important;font-weight:700}#standingsCarousel tbody tr:nth-child(3) td:first-child{color:#d28a4a !important;font-weight:700}.badge{transition:transform 0.2s var(--ease-spring),box-shadow 0.2s ease}.badge:hover{transform:scale(1.06)}.badge.bg-primary{background:linear-gradient(135deg,var(--primary),var(--primary-deep)) !important;box-shadow:0 4px 12px -6px rgba(194,0,0,0.45)}.modal.fade .modal-dialog{transform:translateY(40px) scale(0.96);transition:transform 0.45s var(--ease-spring),opacity 0.4s ease !important}.modal.show .modal-dialog{transform:translateY(0) scale(1)}.modal-backdrop.show{backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}.modal-content{border:1px solid var(--outline-variant);border-radius:var(--radius) !important;box-shadow:0 30px 80px -20px rgba(0,0,0,0.45);animation:modalGlow 0.6s ease}@keyframes modalGlow{from{box-shadow:0 0 0 rgba(194,0,0,0)}to{box-shadow:0 30px 80px -20px rgba(0,0,0,0.45)}}.nav-tabs .nav-link{position:relative;transition:color 0.25s ease}.nav-tabs .nav-link::after{content:'';position:absolute;left:10%;right:10%;bottom:-1px;height:3px;background:var(--primary);transform:scaleX(0);transform-origin:left center;transition:transform 0.4s var(--ease-arc)}.nav-tabs .nav-link.active::after{transform:scaleX(1)}#splash-screen{background:radial-gradient(ellipse at center,#1a1a18 0%,#0a0a0a 100%)}#splash-screen::before{content:'';position:absolute;inset:-50%;background:repeating-linear-gradient(45deg,rgba(194,0,0,0.04) 0,rgba(194,0,0,0.04) 1px,transparent 1px,transparent 12px);animation:splashSweep 8s linear infinite;pointer-events:none}@keyframes splashSweep{from{transform:translate(-25%,-25%) rotate(0deg)}to{transform:translate(-25%,-25%) rotate(360deg)}}#splash-logo{position:relative;filter:drop-shadow(0 12px 30px rgba(194,0,0,0.55))}#pwa-install-banner{border-top:1px solid var(--outline-variant) !important;background:rgba(255,255,255,0.96) !important;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);animation:bannerRise 0.5s var(--ease-spring)}@keyframes bannerRise{from{transform:translateY(110%)}to{transform:translateY(0)}}#pwa-install-btn{background:linear-gradient(135deg,var(--primary),var(--primary-deep)) !important;color:white !important;border:none !important;box-shadow:0 8px 24px -10px rgba(194,0,0,0.55);transition:transform 0.25s var(--ease-spring),box-shadow 0.25s ease !important}#pwa-install-btn:hover{transform:translateY(-2px);box-shadow:0 14px 30px -10px rgba(194,0,0,0.65)}.kfx-skeleton{position:relative;overflow:hidden;background:var(--surface-container);border-radius:var(--radius-sm)}.kfx-skeleton::after{content:'';position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.5),transparent);animation:shimmer 1.6s linear infinite}@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}.sponsor-carousel-container{-webkit-mask-image:linear-gradient(90deg,transparent,black 6%,black 94%,transparent);mask-image:linear-gradient(90deg,transparent,black 6%,black 94%,transparent)}.sponsor-item{transition:transform 0.4s var(--ease-out-soft)}.sponsor-item:hover{transform:translateY(-3px)}footer.footer{position:relative;overflow:hidden;background:var(--arena-dark) !important;color:rgba(255,255,255,0.65) !important}footer.footer::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--primary),transparent);animation:sweep 5s ease-in-out infinite}.kfx-text-gradient{background:linear-gradient(120deg,var(--primary) 0%,#ff3232 35%,var(--primary-deep) 70%,var(--primary) 100%);background-size:250% 100%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;animation:textShift 6s ease-in-out infinite}@keyframes textShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}.kfx-border-glow{position:relative;isolation:isolate}.kfx-border-glow::before{content:'';position:absolute;inset:-1px;border-radius:inherit;background:conic-gradient(from 0deg,transparent 0%,var(--primary) 25%,transparent 50%);animation:borderSpin 4s linear infinite;z-index:-1}.kfx-border-glow::after{content:'';position:absolute;inset:1px;background:var(--surface-container-lowest);border-radius:inherit;z-index:-1}@keyframes borderSpin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.kfx-link{position:relative;text-decoration:none;color:inherit;background-image:linear-gradient(currentColor,currentColor);background-position:0% 100%;background-repeat:no-repeat;background-size:0% 1.5px;transition:background-size 0.45s var(--ease-arc),color 0.25s ease}.kfx-link:hover{background-size:100% 1.5px;color:var(--primary)}.kfx-img-cover{overflow:hidden;position:relative}.kfx-img-cover img{transition:transform 0.9s var(--ease-out-soft),filter 0.5s ease;will-change:transform}.kfx-img-cover:hover img{transform:scale(1.06);filter:saturate(1.1) contrast(1.05)}.kfx-img-cover::after{content:'';position:absolute;inset:0;background:linear-gradient(180deg,transparent 50%,rgba(0,0,0,0.45));opacity:0;transition:opacity 0.45s ease;pointer-events:none}.kfx-img-cover:hover::after{opacity:1}.kfx-img-spotlight{position:relative;overflow:hidden}.kfx-img-spotlight::before{content:'';position:absolute;inset:0;background:radial-gradient(500px circle at var(--mx,50%) var(--my,50%),rgba(194,0,0,0.18),transparent 60%);opacity:0;transition:opacity 0.4s ease;z-index:1;pointer-events:none}.kfx-img-spotlight:hover::before{opacity:1}.kfx-jersey{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;background:var(--arena-dark);color:var(--primary);font-family:var(--font-display);font-weight:800;font-size:1.1rem;border-radius:4px;box-shadow:inset 0 0 0 2px var(--primary);transition:transform 0.3s var(--ease-spring)}.kfx-jersey:hover{transform:rotate(-4deg) scale(1.05)}.kfx-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--primary);box-shadow:0 0 0 0 rgba(194,0,0,0.7);animation:badgeRing 1.6s ease-out infinite;vertical-align:middle}.no-grain::after{display:none !important}@keyframes pageIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.content{animation:pageIn 0.5s var(--ease-out-soft)}.texto-sin-cortar,h1,h2,h3,h4,h5,h6,.fc-toolbar-title{line-height:1.3 !important;padding-bottom:2px !important}.admin-sidebar{background:linear-gradient(180deg,rgba(194,0,0,0.05),transparent 30%),var(--admin-sidebar-bg,#0A0A0A) !important}.admin-sidebar::before{content:'';position:absolute;top:0;right:0;width:1px;height:100%;background:linear-gradient(180deg,transparent,rgba(194,0,0,0.3) 50%,transparent);pointer-events:none}.sidebar-link{position:relative;overflow:hidden}.sidebar-link::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--primary);transform:scaleY(0);transition:transform 0.35s var(--ease-arc)}.sidebar-link:hover::before,.sidebar-link.active::before{transform:scaleY(1)}.sidebar-link i{transition:transform 0.35s var(--ease-spring),color 0.25s ease}.sidebar-link:hover i{transform:translateX(3px) scale(1.08);color:var(--primary)}.sidebar-link.active{background:linear-gradient(90deg,rgba(194,0,0,0.95),rgba(138,0,0,0.85)) !important;box-shadow:inset 0 0 0 1px rgba(255,255,255,0.06)}.sidebar-link.active i{color:white !important;transform:none}.stat-card{background:linear-gradient(135deg,#0a0a0a,#1a1a1a) !important;transition:transform 0.45s var(--ease-out-soft),box-shadow 0.45s ease;overflow:hidden;position:relative}.stat-card::before{content:'';position:absolute;inset:0;background:radial-gradient(circle at 100% 0%,rgba(194,0,0,0.25),transparent 60%);opacity:0;transition:opacity 0.4s ease}.stat-card:hover{transform:translateY(-4px);box-shadow:0 24px 40px -20px rgba(0,0,0,0.55)}.stat-card:hover::before{opacity:1}.stat-card .stat-value{background:linear-gradient(135deg,#fff,#ffb4b4);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}.admin-card{border-radius:4px !important;transition:transform 0.35s var(--ease-out-soft),box-shadow 0.35s ease}.admin-card:hover{transform:translateY(-2px);box-shadow:0 18px 40px -22px rgba(0,0,0,0.18)}.btn-admin-primary{position:relative;overflow:hidden;transition:transform 0.25s var(--ease-spring),box-shadow 0.3s ease,background 0.25s ease !important}.btn-admin-primary::after{content:'';position:absolute;inset:0;background:linear-gradient(120deg,transparent,rgba(255,255,255,0.25),transparent);transform:translateX(-110%) skewX(-15deg);transition:transform 0.6s var(--ease-arc)}.btn-admin-primary:hover::after{transform:translateX(110%) skewX(-15deg)}.btn-admin-primary:hover{box-shadow:0 14px 28px -12px rgba(194,0,0,0.55);transform:translateY(-2px)}.admin-topbar{background:rgba(255,255,255,0.85) !important;backdrop-filter:blur(18px) saturate(180%);-webkit-backdrop-filter:blur(18px) saturate(180%);position:sticky;top:0;z-index:100}.admin-topbar .bg-primary{background:linear-gradient(135deg,var(--primary),var(--primary-deep)) !important;box-shadow:0 0 0 3px rgba(194,0,0,0.15),0 6px 18px -6px rgba(194,0,0,0.5);transition:transform 0.3s var(--ease-spring)}.admin-topbar .bg-primary:hover{transform:rotate(-6deg) scale(1.05)}.sidebar-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.5);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);opacity:0;visibility:hidden;transition:opacity 0.3s ease,visibility 0.3s ease;z-index:999}.sidebar-overlay.show{opacity:1;visibility:visible}.kinetic-table tr{transition:background 0.2s ease}.kinetic-table tr:hover td{background:rgba(194,0,0,0.04);box-shadow:inset 3px 0 0 var(--primary)}.kinetic-news-item{position:relative;transition:background 0.3s var(--ease-out-soft),padding-left 0.3s var(--ease-out-soft)}.kinetic-news-item::before{content:'';position:absolute;left:0;top:50%;width:0;height:2px;background:var(--primary);transition:width 0.4s var(--ease-arc);transform:translateY(-50%)}.kinetic-news-item:hover{background:rgba(194,0,0,0.03);padding-left:12px}.kinetic-news-item:hover::before{width:8px}.kfx-event-cta{display:inline-flex;align-items:center;gap:8px;overflow:hidden}.kfx-event-cta::after{content:'→';transition:transform 0.35s var(--ease-arc);display:inline-block}.kinetic-card:hover .kfx-event-cta::after{transform:translateX(6px)}@media (max-width:768px){.kinetic-card:hover{transform:none}.kinetic-card::before{display:none}[data-tilt]{transform:none !important}.kinetic-cursor-dot,.kinetic-cursor-ring{display:none !important}body.kinetic-cursor-on,body.kinetic-cursor-on *{cursor:auto}}::selection{background-color:var(--primary) !important;color:#ffffff !important}::-moz-selection{background-color:var(--primary) !important;color:#ffffff !important}.swal2-popup ::selection,.swal2-popup *::selection{background-color:var(--primary) !important;color:#ffffff !important}.swal2-popup ::-moz-selection,.swal2-popup *::-moz-selection{background-color:var(--primary) !important;color:#ffffff !important}:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:2px}.swal2-popup{border-radius:var(--radius) !important;font-family:var(--font-body) !important;border:1px solid var(--outline-variant);box-shadow:0 25px 60px -25px rgba(26,18,8,0.4) !important}.swal2-title{font-family:var(--font-display) !important;text-transform:uppercase;letter-spacing:0.04em}.swal2-toast{border-left:4px solid var(--primary) !important}.swal2-styled.swal2-confirm,.swal2-popup .swal2-actions .swal2-styled.swal2-confirm,button.swal2-confirm.swal2-styled{background-color:var(--primary) !important;background-image:linear-gradient(135deg,var(--primary),var(--primary-deep)) !important;color:#ffffff !important;border:none !important;border-radius:var(--radius-sm) !important;text-transform:uppercase !important;letter-spacing:0.08em !important;font-weight:700 !important;box-shadow:0 6px 18px -8px rgba(194,0,0,0.55);transition:transform 0.2s var(--ease-spring),box-shadow 0.25s ease,filter 0.2s ease}.swal2-styled.swal2-confirm:hover,.swal2-popup .swal2-actions .swal2-styled.swal2-confirm:hover,button.swal2-confirm.swal2-styled:hover{background-color:var(--primary-deep) !important;background-image:linear-gradient(135deg,var(--primary-deep),var(--primary)) !important;color:#ffffff !important;transform:translateY(-1px);box-shadow:0 10px 24px -10px rgba(194,0,0,0.65);filter:brightness(1.05)}.swal2-styled.swal2-confirm:focus,button.swal2-confirm.swal2-styled:focus{box-shadow:0 0 0 3px rgba(194,0,0,0.35),0 6px 18px -8px rgba(194,0,0,0.55) !important;outline:none !important}.swal2-styled.swal2-cancel,.swal2-popup .swal2-actions .swal2-styled.swal2-cancel,button.swal2-cancel.swal2-styled{background-color:#6c757d !important;background-image:none !important;color:#ffffff !important;border:none !important;border-radius:var(--radius-sm) !important;text-transform:uppercase !important;letter-spacing:0.08em !important;font-weight:700 !important}.swal2-styled.swal2-cancel:hover,button.swal2-cancel.swal2-styled:hover{background-color:#5a6268 !important;color:#ffffff !important}.swal2-styled.swal2-deny,button.swal2-deny.swal2-styled{background-color:#b91c1c !important;background-image:none !important;color:#ffffff !important;border:none !important;border-radius:var(--radius-sm) !important;text-transform:uppercase !important;letter-spacing:0.08em !important;font-weight:700 !important} \ No newline at end of file diff --git a/public/static/kinetic-arena.css b/public/static/kinetic-arena.css new file mode 100644 index 0000000..3136558 --- /dev/null +++ b/public/static/kinetic-arena.css @@ -0,0 +1,569 @@ +/* + ONAPB — "Constructivismo de Cancha" + Design System v2.0 — 2026 + ───────────────────────────────────── + Display: Antonio (condensed, impactful) + Body: DM Sans (warm, clean, modern) +*/ + +@import url('https://fonts.googleapis.com/css2?family=Antonio:wght@400;500;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap'); + +/* ══════════════════════════════ + TOKENS +══════════════════════════════ */ +:root { + /* Superficies — base cálida */ + --surface: #f5f3ef; + --surface-bright: #faf9f6; + --surface-container-low: #ede9e2; + --surface-container: #e5e1d9; + --surface-container-high: #dbd5cc; + --surface-container-lowest: #ffffff; + --surface-dim: #c9c3b9; + + /* Oscuro */ + --arena-dark: #111111; + --arena-dark-surface: #1a1a18; + --arena-mid: #2c2c2a; + + /* Primario — rojo carmesí */ + --primary: #c20000; + --primary-deep: #8a0000; + --primary-container: #c20000; + --on-primary: #ffffff; + --on-primary-container: #ffe4e1; + + /* Alias legacy (vistas antiguas) */ + --primary-color: #c20000; + --primary-dark: #8a0000; + --bg-color: #f5f3ef; + --card-bg: #ffffff; + + /* Texto */ + --on-surface: #1a1208; + --on-surface-variant: #524840; + --on-surface-muted: #7a6e65; + --text-dark: #1a1208; + --text-muted: #7a6e65; + + /* Bordes */ + --outline: #9e8f85; + --outline-variant: rgba(158, 143, 133, 0.18); + + /* Tipografía */ + --font-display: 'Antonio', sans-serif; + --font-body: 'DM Sans', sans-serif; + + /* Espaciado */ + --spacing-1: 0.25rem; + --spacing-2: 0.5rem; + --spacing-3: 0.75rem; + --spacing-4: 1rem; + --spacing-6: 1.5rem; + --spacing-8: 2rem; + --spacing-12: 3rem; + --spacing-16: 4rem; + + /* Radio — editorial, cuadrado */ + --radius-sm: 2px; + --radius: 4px; + --radius-lg: 8px; + + /* Sombras */ + --shadow-sm: 0 2px 8px rgba(26, 18, 8, 0.07); + --shadow-lg: 0 8px 32px rgba(26, 18, 8, 0.12); + + /* Gradients */ + --gradient-primary: linear-gradient(135deg, #c20000, #8a0000); +} + +/* ══════════════════════════════ + BASE +══════════════════════════════ */ +*, *::before, *::after { box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + background-color: var(--surface) !important; + color: var(--on-surface) !important; + font-family: var(--font-body) !important; + font-size: 16px; + line-height: 1.65; + margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +img, video, canvas, svg { max-width: 100%; height: auto; } + +/* ══════════════════════════════ + GRANO DE TEXTURA +══════════════════════════════ */ +body::after { + content: ''; + position: fixed; + inset: 0; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n' x='0' y='0'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E"); + background-size: 250px 250px; + pointer-events: none; + z-index: 9998; + mix-blend-mode: multiply; +} + +/* ══════════════════════════════ + TIPOGRAFÍA +══════════════════════════════ */ +h1, h2, h3, h4, h5, h6, +.display-1, .display-2, .display-3, +.display-4, .display-5, .display-6, +.navbar-brand, .hero-title { + font-family: var(--font-display) !important; + font-weight: 700 !important; + letter-spacing: 0.03em !important; + text-transform: uppercase; + line-height: 0.93 !important; + color: var(--on-surface); +} + +p, td, li, .form-control, .form-label, +.nav-link, .dropdown-item, .btn, +body, small { + font-family: var(--font-body) !important; +} + +.card-title { + font-family: var(--font-display) !important; +} + +/* ══════════════════════════════ + NAVBAR +══════════════════════════════ */ +.custom-navbar { + background-color: rgba(245, 243, 239, 0.93) !important; + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border-bottom: 1px solid var(--outline-variant) !important; + padding: 10px 0; + position: sticky; + top: 0; + z-index: 1030; + box-shadow: none !important; + transition: background 0.3s; +} + +.custom-navbar .navbar-logo { + height: 36px; + width: auto; +} + +.custom-navbar .navbar-brand { + font-family: var(--font-display) !important; + letter-spacing: 0.1em; + color: var(--primary) !important; + font-size: 1.5rem; + font-weight: 700; + transition: opacity 0.2s; +} +.custom-navbar .navbar-brand:hover { opacity: 0.8; } + +/* Remove old underline effect */ +.custom-navbar .nav-link::after { display: none !important; } + +.custom-navbar .nav-link { + font-family: var(--font-body) !important; + font-weight: 600 !important; + font-size: 0.8rem !important; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--on-surface) !important; + padding: 6px 14px !important; + border-radius: var(--radius-sm); + transition: color 0.2s, background 0.2s; + position: relative; +} + +.custom-navbar .nav-link:hover, +.custom-navbar .nav-link.active { + color: var(--primary) !important; + background: rgba(194, 0, 0, 0.06) !important; +} + +.navbar-toggler { + border: 1px solid var(--outline-variant); + border-radius: var(--radius-sm); + padding: 6px 10px; +} +.navbar-toggler:focus { box-shadow: none; } + +/* ══════════════════════════════ + DROPDOWN +══════════════════════════════ */ +.dropdown-menu { + background: var(--surface-container-lowest); + border: 1px solid var(--outline-variant); + border-radius: var(--radius); + box-shadow: var(--shadow-lg); + padding: 6px; + animation: menuIn 0.18s ease; + min-width: 200px; +} + +@keyframes menuIn { + from { opacity: 0; transform: translateY(-6px); } + to { opacity: 1; transform: translateY(0); } +} + +.dropdown-item { + font-family: var(--font-body) !important; + font-size: 0.875rem; + border-radius: var(--radius-sm); + padding: 8px 14px; + color: var(--on-surface); + transition: background 0.15s, color 0.15s; +} +.dropdown-item:hover, +.dropdown-item:focus { + background: var(--surface-container); + color: var(--primary); +} + +.dropdown-divider { border-color: var(--outline-variant); } +.dropdown-header { + font-family: var(--font-body) !important; + font-size: 0.7rem; + letter-spacing: 0.12em; + color: var(--on-surface-muted); + padding: 6px 14px; +} + +/* ══════════════════════════════ + CARDS +══════════════════════════════ */ +.kinetic-card { + background-color: var(--surface-container-lowest); + border-radius: var(--radius); + border: 1px solid var(--outline-variant); + transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease; +} + +.kinetic-card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-lg); + border-color: rgba(194, 0, 0, 0.2); +} + +/* ══════════════════════════════ + BOTONES +══════════════════════════════ */ +.btn-kinetic-primary { + background-color: var(--primary) !important; + color: white !important; + border: none !important; + border-radius: 0 !important; + padding: var(--spacing-3) var(--spacing-8) !important; + font-family: var(--font-display) !important; + font-weight: 700; + font-size: 1rem; + letter-spacing: 0.12em; + text-transform: uppercase; + display: inline-block; + text-align: center; + text-decoration: none; + cursor: pointer; + transition: background-color 0.2s, transform 0.18s; + position: relative; +} + +.btn-kinetic-primary:hover { + background-color: var(--primary-deep) !important; + color: white !important; + transform: translateY(-1px); + text-decoration: none; +} + +.btn-kinetic-primary:active { + transform: translateY(0); +} + +/* ══════════════════════════════ + HERO +══════════════════════════════ */ +.hero-title { + font-family: var(--font-display) !important; + font-size: clamp(3.5rem, 11vw, 8rem); + line-height: 0.88 !important; + letter-spacing: 0.02em !important; + text-transform: uppercase; + font-weight: 700 !important; + margin-bottom: var(--spacing-4); +} + +.hero-caption { + background: transparent !important; + backdrop-filter: none !important; + border: none !important; +} + +/* Clip-path diagonal en imagen hero */ +.hero-clip { + clip-path: polygon(8% 0, 100% 0, 100% 100%, 0% 100%); +} + +/* ══════════════════════════════ + BADGES / TAGS +══════════════════════════════ */ +.kinetic-tag-live { + background-color: var(--primary); + color: white; + padding: 3px 10px; + border-radius: 0; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.1em; + font-family: var(--font-body) !important; + display: inline-flex; + align-items: center; + gap: 5px; + text-transform: uppercase; +} + +.kinetic-tag-live::before { + content: ''; + width: 6px; + height: 6px; + background: white; + border-radius: 50%; + flex-shrink: 0; + animation: livePulse 1.3s infinite; +} + +@keyframes livePulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.3; transform: scale(0.65); } +} + +/* Bootstrap badge override */ +.badge { + border-radius: var(--radius-sm) !important; + font-family: var(--font-body) !important; + font-weight: 600 !important; + letter-spacing: 0.05em; +} + +/* ══════════════════════════════ + ETIQUETAS DE SECCIÓN +══════════════════════════════ */ +.section-label { + font-family: var(--font-body) !important; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--primary); + display: block; + margin-bottom: var(--spacing-2); +} + +/* Acento izquierdo para secciones */ +.accent-left { + border-left: 5px solid var(--primary); + padding-left: var(--spacing-4); +} + +/* ══════════════════════════════ + LÍNEA DIVISORIA CON ACENTO +══════════════════════════════ */ +.kinetic-divider { + display: flex; + align-items: center; + gap: var(--spacing-4); + margin: var(--spacing-8) 0; +} +.kinetic-divider::before, +.kinetic-divider::after { + content: ''; + flex: 1; + height: 1px; + background: var(--outline-variant); +} +.kinetic-divider::before { background: var(--primary); max-width: 40px; } + +/* ══════════════════════════════ + ANIMACIONES AL SCROLL +══════════════════════════════ */ +.animate-on-scroll { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.55s cubic-bezier(0.25, 0.46, 0.45, 0.94), + transform 0.55s cubic-bezier(0.25, 0.46, 0.45, 0.94); +} + +.animate-on-scroll.visible { + opacity: 1; + transform: translateY(0); +} + +.animate-on-scroll[data-delay="1"] { transition-delay: 0.08s; } +.animate-on-scroll[data-delay="2"] { transition-delay: 0.16s; } +.animate-on-scroll[data-delay="3"] { transition-delay: 0.24s; } +.animate-on-scroll[data-delay="4"] { transition-delay: 0.32s; } +.animate-on-scroll[data-delay="5"] { transition-delay: 0.40s; } + +/* Variante: slide desde izquierda */ +.animate-slide-left { + opacity: 0; + transform: translateX(-20px); + transition: opacity 0.5s ease, transform 0.5s ease; +} +.animate-slide-left.visible { + opacity: 1; + transform: translateX(0); +} + +/* ══════════════════════════════ + FORMULARIOS +══════════════════════════════ */ +.form-control { + border: 1px solid var(--outline-variant); + border-radius: var(--radius-sm) !important; + background: var(--surface-container-lowest); + color: var(--on-surface); + font-family: var(--font-body) !important; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.form-control:focus { + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(194, 0, 0, 0.1); + background: var(--surface-container-lowest); + color: var(--on-surface); +} + +/* ══════════════════════════════ + TABLAS +══════════════════════════════ */ +.table { + font-family: var(--font-body) !important; + font-size: 0.9rem; +} + +.table th { + font-family: var(--font-body) !important; + font-weight: 700; + text-transform: uppercase; + font-size: 0.75rem; + letter-spacing: 0.08em; + color: var(--on-surface-muted); + border-bottom: 2px solid var(--outline-variant); +} + +/* ══════════════════════════════ + NOTICIAS — ITEM +══════════════════════════════ */ +.kinetic-news-item { + transition: background 0.2s; + border-radius: var(--radius-sm); + padding: var(--spacing-2) 0; +} +.kinetic-news-item:hover { background: var(--surface-container-low); } + +.hover-primary:hover { color: var(--primary) !important; } + +/* ══════════════════════════════ + SPLASH SCREEN +══════════════════════════════ */ +#splash-screen { + position: fixed; + inset: 0; + background: var(--arena-dark); + display: flex; + align-items: center; + justify-content: center; + z-index: 99999; + transition: opacity 0.4s ease, visibility 0.4s ease; +} + +#splash-screen.hidden { + opacity: 0; + visibility: hidden; +} + +#splash-logo { + width: 80px; + height: 80px; + animation: splashPulse 0.8s ease-in-out infinite alternate; +} + +@keyframes splashPulse { + from { transform: scale(0.9); opacity: 0.7; } + to { transform: scale(1.05); opacity: 1; } +} + +/* ══════════════════════════════ + UTILIDADES +══════════════════════════════ */ +.no-line { border: none !important; } +.no-scrollbar::-webkit-scrollbar { display: none; } +.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } +.text-kinetic-muted { color: var(--on-surface-muted) !important; } +.bg-primary-container { background-color: rgba(194, 0, 0, 0.1) !important; } +.text-primary { color: var(--primary) !important; } + +.tracking-widest { letter-spacing: 0.2em; } +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* ══════════════════════════════ + PULSE (badges en vivo) +══════════════════════════════ */ +.pulse { + animation: badgePulse 2s infinite; +} +@keyframes badgePulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +/* ══════════════════════════════ + FOOTER +══════════════════════════════ */ +footer, .footer-section { + font-family: var(--font-body) !important; + font-size: 0.875rem; + background: var(--arena-dark) !important; + color: rgba(255,255,255,0.6) !important; +} + +/* ══════════════════════════════ + RESPONSIVE +══════════════════════════════ */ +@media (max-width: 991px) { + .custom-navbar .navbar-collapse { + background: var(--surface-container-lowest); + border: 1px solid var(--outline-variant); + border-radius: var(--radius); + padding: var(--spacing-2); + margin-top: var(--spacing-2); + } + + .custom-navbar .nav-link { + padding: 10px 16px !important; + border-radius: var(--radius-sm); + } +} + +@media (max-width: 768px) { + .hero-title { + font-size: clamp(3rem, 15vw, 5rem); + line-height: 0.9 !important; + } + + .kinetic-card:hover { + transform: none; + } +} diff --git a/public/static/kinetic-fx.js b/public/static/kinetic-fx.js new file mode 100644 index 0000000..6ce00be --- /dev/null +++ b/public/static/kinetic-fx.js @@ -0,0 +1,480 @@ +/* ===================================================================== + ONAPB — Kinetic FX + Capa de interacciones del frontend. + Vanilla JS, sin dependencias. Cargar al final de con defer. + ===================================================================== */ +(function () { + 'use strict'; + + var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + var hasFinePointer = window.matchMedia('(hover: hover) and (pointer: fine)').matches; + var isTouch = !hasFinePointer || ('ontouchstart' in window) || (navigator.maxTouchPoints > 0); + + function ready(fn) { + if (document.readyState !== 'loading') fn(); + else document.addEventListener('DOMContentLoaded', fn); + } + + /* ───────────────────────────────────────────────────────────────── + 1. Reveal on scroll (.kfx-reveal, [data-stagger], .kfx-section-tag) + ───────────────────────────────────────────────────────────────── */ + function initReveal() { + if (!('IntersectionObserver' in window)) { + document.querySelectorAll('.kfx-reveal, [data-stagger], .kfx-section-tag, .hero-title, .kinetic-reveal-text, .kinetic-highlight') + .forEach(function (el) { el.classList.add('is-in'); }); + return; + } + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (e.isIntersecting) { + e.target.classList.add('is-in'); + io.unobserve(e.target); + } + }); + }, { threshold: 0.12, rootMargin: '0px 0px -60px 0px' }); + + document.querySelectorAll('.kfx-reveal, [data-stagger], .kfx-section-tag, .hero-title, .kinetic-reveal-text, .kinetic-highlight') + .forEach(function (el) { io.observe(el); }); + } + + /* ───────────────────────────────────────────────────────────────── + 2. Word splitter para reveal de títulos (hero-title, kinetic-reveal-text) + ───────────────────────────────────────────────────────────────── */ + function splitWords() { + document.querySelectorAll('.hero-title:not([data-split]), .kinetic-reveal-text:not([data-split])').forEach(function (el) { + if (el.children.length > 0 && el.querySelector('.word')) return; + var text = el.textContent.trim(); + if (!text) return; + var words = text.split(/\s+/); + el.innerHTML = words.map(function (w) { + return '' + w + ''; + }).join(' '); + el.setAttribute('data-split', 'true'); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 3. Reading progress bar (top) + ───────────────────────────────────────────────────────────────── */ + function initReadingBar() { + if (prefersReduced) return; + var bar = document.getElementById('kinetic-reading-bar'); + if (!bar) { + bar = document.createElement('div'); + bar.id = 'kinetic-reading-bar'; + document.body.appendChild(bar); + } + var ticking = false; + function update() { + var scrollTop = window.scrollY || document.documentElement.scrollTop; + var docHeight = document.documentElement.scrollHeight - window.innerHeight; + var pct = docHeight > 0 ? Math.min(100, (scrollTop / docHeight) * 100) : 0; + bar.style.width = pct + '%'; + ticking = false; + } + window.addEventListener('scroll', function () { + if (!ticking) { + window.requestAnimationFrame(update); + ticking = true; + } + }, { passive: true }); + update(); + } + + /* ───────────────────────────────────────────────────────────────── + 4. Navbar scroll state + ───────────────────────────────────────────────────────────────── */ + function initNavbarScroll() { + var nav = document.querySelector('.custom-navbar'); + if (!nav) return; + function update() { + if (window.scrollY > 30) nav.classList.add('is-scrolled'); + else nav.classList.remove('is-scrolled'); + } + window.addEventListener('scroll', update, { passive: true }); + update(); + } + + /* ───────────────────────────────────────────────────────────────── + 5. Spotlight para .kinetic-card y .kfx-img-spotlight + ───────────────────────────────────────────────────────────────── */ + function initSpotlight() { + if (isTouch) return; + var els = document.querySelectorAll('.kinetic-card, .kfx-img-spotlight'); + els.forEach(function (el) { + el.addEventListener('mousemove', function (e) { + var rect = el.getBoundingClientRect(); + var x = ((e.clientX - rect.left) / rect.width) * 100; + var y = ((e.clientY - rect.top) / rect.height) * 100; + el.style.setProperty('--mx', x + '%'); + el.style.setProperty('--my', y + '%'); + }); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 6. Tilt 3D (data-tilt) + ───────────────────────────────────────────────────────────────── */ + function initTilt() { + if (isTouch || prefersReduced) return; + document.querySelectorAll('[data-tilt]').forEach(function (el) { + var max = parseFloat(el.getAttribute('data-tilt-max') || '8'); + el.addEventListener('mousemove', function (e) { + var rect = el.getBoundingClientRect(); + var x = (e.clientX - rect.left) / rect.width - 0.5; + var y = (e.clientY - rect.top) / rect.height - 0.5; + el.classList.add('is-tilting'); + el.style.setProperty('--ry', (x * max) + 'deg'); + el.style.setProperty('--rx', (-y * max) + 'deg'); + }); + el.addEventListener('mouseleave', function () { + el.classList.remove('is-tilting'); + el.style.setProperty('--rx', '0deg'); + el.style.setProperty('--ry', '0deg'); + }); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 7. Magnetic buttons (data-magnetic) + ───────────────────────────────────────────────────────────────── */ + function initMagnetic() { + if (isTouch || prefersReduced) return; + document.querySelectorAll('[data-magnetic]').forEach(function (el) { + var strength = parseFloat(el.getAttribute('data-magnetic-strength') || '0.25'); + el.addEventListener('mousemove', function (e) { + var rect = el.getBoundingClientRect(); + var x = e.clientX - rect.left - rect.width / 2; + var y = e.clientY - rect.top - rect.height / 2; + el.style.transform = 'translate(' + (x * strength) + 'px, ' + (y * strength) + 'px)'; + }); + el.addEventListener('mouseleave', function () { + el.style.transform = ''; + }); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 8. Ripple en clicks (cualquier .btn, .btn-kinetic-primary) + ───────────────────────────────────────────────────────────────── */ + function initRipple() { + document.addEventListener('click', function (e) { + var btn = e.target.closest('.btn, .btn-kinetic-primary, .btn-admin-primary, .sidebar-link'); + if (!btn || btn.classList.contains('no-ripple')) return; + var rect = btn.getBoundingClientRect(); + var size = Math.max(rect.width, rect.height); + var wave = document.createElement('span'); + wave.className = 'kinetic-ripple-wave'; + wave.style.width = wave.style.height = size + 'px'; + wave.style.left = (e.clientX - rect.left) + 'px'; + wave.style.top = (e.clientY - rect.top) + 'px'; + // Posición relativa para contener el ripple + var pos = window.getComputedStyle(btn).position; + if (pos === 'static') btn.style.position = 'relative'; + btn.style.overflow = 'hidden'; + btn.appendChild(wave); + setTimeout(function () { wave.remove(); }, 650); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 9. Counter animado (.kfx-counter con data-target) + ───────────────────────────────────────────────────────────────── */ + function initCounters() { + if (!('IntersectionObserver' in window)) return; + var counters = document.querySelectorAll('.kfx-counter[data-target]'); + if (!counters.length) return; + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (entry) { + if (!entry.isIntersecting) return; + var el = entry.target; + var target = parseFloat(el.getAttribute('data-target')) || 0; + var duration = parseInt(el.getAttribute('data-duration') || '1400', 10); + var decimals = parseInt(el.getAttribute('data-decimals') || '0', 10); + var prefix = el.getAttribute('data-prefix') || ''; + var suffix = el.getAttribute('data-suffix') || ''; + var start = 0; + var startTime = null; + if (prefersReduced) { + el.textContent = prefix + target.toFixed(decimals) + suffix; + io.unobserve(el); + return; + } + function tick(ts) { + if (!startTime) startTime = ts; + var progress = Math.min(1, (ts - startTime) / duration); + var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic + var current = start + (target - start) * eased; + el.textContent = prefix + current.toFixed(decimals) + suffix; + if (progress < 1) requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + io.unobserve(el); + }); + }, { threshold: 0.4 }); + counters.forEach(function (c) { io.observe(c); }); + } + + /* ───────────────────────────────────────────────────────────────── + 10. Parallax suave (data-parallax="speed") + ───────────────────────────────────────────────────────────────── */ + function initParallax() { + if (prefersReduced) return; + var els = Array.prototype.slice.call(document.querySelectorAll('[data-parallax]')); + if (!els.length) return; + var ticking = false; + function update() { + var vh = window.innerHeight; + els.forEach(function (el) { + var rect = el.getBoundingClientRect(); + if (rect.bottom < 0 || rect.top > vh) return; + var speed = parseFloat(el.getAttribute('data-parallax')) || 0.2; + var offset = (rect.top - vh / 2) * speed * -1; + el.style.transform = 'translate3d(0, ' + offset.toFixed(1) + 'px, 0)'; + }); + ticking = false; + } + window.addEventListener('scroll', function () { + if (!ticking) { + requestAnimationFrame(update); + ticking = true; + } + }, { passive: true }); + update(); + } + + /* ───────────────────────────────────────────────────────────────── + 11. Marquee duplicador (.kfx-marquee con un solo track) + ───────────────────────────────────────────────────────────────── */ + function initMarquee() { + document.querySelectorAll('.kfx-marquee').forEach(function (el) { + var track = el.querySelector('.kfx-marquee__track'); + if (!track || track.dataset.cloned === '1') return; + track.dataset.cloned = '1'; + track.innerHTML += track.innerHTML; // duplicar para loop seamless + }); + } + + /* ───────────────────────────────────────────────────────────────── + 12. Cursor personalizado (sólo desktop hover-fino) + ───────────────────────────────────────────────────────────────── */ + function initCustomCursor() { + if (!hasFinePointer || isTouch || prefersReduced) return; + if (document.querySelector('.kinetic-cursor-dot')) return; + + var dot = document.createElement('div'); + var ring = document.createElement('div'); + dot.className = 'kinetic-cursor-dot'; + ring.className = 'kinetic-cursor-ring'; + document.body.appendChild(dot); + document.body.appendChild(ring); + document.body.classList.add('kinetic-cursor-on'); + + var mx = window.innerWidth / 2, my = window.innerHeight / 2; + var rx = mx, ry = my; + + document.addEventListener('mousemove', function (e) { + mx = e.clientX; my = e.clientY; + dot.style.transform = 'translate(' + mx + 'px, ' + my + 'px) translate(-50%, -50%)'; + }, { passive: true }); + + function loop() { + rx += (mx - rx) * 0.18; + ry += (my - ry) * 0.18; + ring.style.transform = 'translate(' + rx + 'px, ' + ry + 'px) translate(-50%, -50%)'; + requestAnimationFrame(loop); + } + loop(); + + // Hover en interactivos + var hoverSel = 'a, button, .btn, .kinetic-card, [role="button"], [data-tilt], [data-magnetic], .nav-link, input[type="submit"]'; + document.addEventListener('mouseover', function (e) { + if (e.target.closest(hoverSel)) { + ring.classList.add('is-hover'); + dot.classList.add('is-hover'); + } + }); + document.addEventListener('mouseout', function (e) { + if (e.target.closest(hoverSel)) { + ring.classList.remove('is-hover'); + dot.classList.remove('is-hover'); + } + }); + document.addEventListener('mouseleave', function () { + ring.style.opacity = '0'; + dot.style.opacity = '0'; + }); + document.addEventListener('mouseenter', function () { + ring.style.opacity = '1'; + dot.style.opacity = '1'; + }); + } + + /* ───────────────────────────────────────────────────────────────── + 13. Auto-aplicar reveal a tarjetas / encabezados (best-effort) + ───────────────────────────────────────────────────────────────── */ + function autoTagReveal() { + // Tarjetas comunes en home/eventos + document.querySelectorAll('.kinetic-card:not(.kfx-reveal)').forEach(function (el) { + el.classList.add('kfx-reveal'); + if (!el.hasAttribute('data-fx')) el.setAttribute('data-fx', 'up'); + }); + + // Display headings (h1.display-* / h2.display-*) + document.querySelectorAll('h1.display-1, h1.display-2, h1.display-3, h1.display-4, h2.display-3, h2.display-4, h2.display-5') + .forEach(function (el) { + if (!el.classList.contains('kfx-reveal') && !el.classList.contains('hero-title')) { + el.classList.add('kfx-reveal'); + el.setAttribute('data-fx', 'up'); + } + }); + } + + /* ───────────────────────────────────────────────────────────────── + 14. Smooth anchor scroll + ───────────────────────────────────────────────────────────────── */ + function initAnchorSmooth() { + document.addEventListener('click', function (e) { + var a = e.target.closest('a[href^="#"]'); + if (!a) return; + var href = a.getAttribute('href'); + if (!href || href === '#' || href.length < 2) return; + var target = document.querySelector(href); + if (!target) return; + e.preventDefault(); + target.scrollIntoView({ behavior: prefersReduced ? 'auto' : 'smooth', block: 'start' }); + }); + } + + /* ───────────────────────────────────────────────────────────────── + 15. SweetAlert2 patcher (a prueba de cache) + Detecta cuando aparece un .swal2-popup y fuerza inline styles en + los botones para garantizar fondo rojo en confirm y gris en cancel, + sin importar el orden/cache del CSS o el confirmButtonColor del JS. + ───────────────────────────────────────────────────────────────── */ + function initSwalPatcher() { + if (!('MutationObserver' in window)) return; + + var BRAND_RED = '#c20000'; + var BRAND_RED_DEEP = '#8a0000'; + var BRAND_GRAY = '#6c757d'; + + // Inyectar reglas críticas como