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