This commit is contained in:
Laucha1312
2026-06-04 15:19:42 -03:00
parent 90c5f85512
commit fdd0fef3f0
37 changed files with 4912 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
# Ocultar headers de servidor
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
Header unset Server
</IfModule>
# Bloquear acceso a archivos sensibles
<FilesMatch "\.(env|log|git|gitignore|htpasswd|DS_Store)$">
Order allow,deny
Deny from all
</FilesMatch>
# ============================================================
# Compresion (Brotli si esta, Gzip como fallback)
# ============================================================
<IfModule mod_brotli.c>
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
</IfModule>
<IfModule mod_deflate.c>
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
</IfModule>
# ============================================================
# Cache-Control para estaticos
# ============================================================
<IfModule mod_expires.c>
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"
</IfModule>
<IfModule mod_headers.c>
# Cache largo + immutable para estaticos con hash o version
<FilesMatch "\.(css|js|woff2?|ttf|eot|otf|svg|png|jpe?g|webp|avif|ico)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
# HTML siempre fresco
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>
# Vary: Accept-Encoding (correcto para CDN/proxies)
<FilesMatch "\.(css|js|html|svg|json)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
# ============================================================
# Routing Laravel + seguridad
# ============================================================
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
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]
</IfModule>
+4
View File
@@ -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
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

+20
View File
@@ -0,0 +1,20 @@
<?php
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
// Bootstrap Laravel and handle the request...
/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';
$app->handleRequest(Request::capture());
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+88
View File
@@ -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
}
+9
View File
@@ -0,0 +1,9 @@
User-agent: *
Disallow: /admin
Disallow: /recuperar
Disallow: /api/
Disallow: /storage/
Disallow: /vendor/
Allow: /
Sitemap: https://onapb.com/sitemap.xml
+249
View File
@@ -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;
}
}
+621
View File
@@ -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;
}
+130
View File
@@ -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;
}
+447
View File
@@ -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); }
}
+23
View File
@@ -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);
}
+187
View File
@@ -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; }
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+569
View File
@@ -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;
}
}
+480
View File
@@ -0,0 +1,480 @@
/* =====================================================================
ONAPB Kinetic FX
Capa de interacciones del frontend.
Vanilla JS, sin dependencias. Cargar al final de <body> 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 '<span class="word"><span>' + w + '</span></span>';
}).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 <style> en runtime para evitar
// problemas de caché del archivo .css (LiteSpeed/Cloudflare).
if (!document.getElementById('kfx-swal-runtime-style')) {
var s = document.createElement('style');
s.id = 'kfx-swal-runtime-style';
s.textContent = [
/* Selección visible dentro del modal SweetAlert (rojo + texto blanco). */
'.swal2-popup ::selection,.swal2-popup *::selection{background-color:' + BRAND_RED + ' !important;color:#fff !important;}',
'.swal2-popup ::-moz-selection,.swal2-popup *::-moz-selection{background-color:' + BRAND_RED + ' !important;color:#fff !important;}',
/* Selección global (failsafe por si el CSS principal cachea viejo). */
'::selection{background-color:' + BRAND_RED + ' !important;color:#fff !important;}',
'::-moz-selection{background-color:' + BRAND_RED + ' !important;color:#fff !important;}',
/* Botones de SweetAlert (failsafe). */
'body .swal2-popup .swal2-actions .swal2-styled.swal2-confirm{' +
'background-color:' + BRAND_RED + ' !important;' +
'background-image:linear-gradient(135deg,' + BRAND_RED + ',' + BRAND_RED_DEEP + ') !important;' +
'color:#fff !important;border:none !important;' +
'}',
'body .swal2-popup .swal2-actions .swal2-styled.swal2-cancel{' +
'background-color:' + BRAND_GRAY + ' !important;' +
'background-image:none !important;' +
'color:#fff !important;border:none !important;' +
'}'
].join('\n');
document.head.appendChild(s);
}
function styleConfirm(btn) {
if (!btn) return;
btn.style.setProperty('background-color', BRAND_RED, 'important');
btn.style.setProperty('background-image',
'linear-gradient(135deg, ' + BRAND_RED + ', ' + BRAND_RED_DEEP + ')', 'important');
btn.style.setProperty('color', '#ffffff', 'important');
btn.style.setProperty('border', 'none', 'important');
btn.style.setProperty('text-shadow', 'none', 'important');
btn.style.setProperty('font-weight', '700', 'important');
btn.style.setProperty('text-transform', 'uppercase', 'important');
btn.style.setProperty('letter-spacing', '0.08em', 'important');
}
function styleCancel(btn) {
if (!btn) return;
btn.style.setProperty('background-color', BRAND_GRAY, 'important');
btn.style.setProperty('background-image', 'none', 'important');
btn.style.setProperty('color', '#ffffff', 'important');
btn.style.setProperty('border', 'none', 'important');
btn.style.setProperty('font-weight', '700', 'important');
btn.style.setProperty('text-transform', 'uppercase', 'important');
btn.style.setProperty('letter-spacing', '0.08em', 'important');
}
function styleDeny(btn) {
if (!btn) return;
btn.style.setProperty('background-color', '#b91c1c', 'important');
btn.style.setProperty('color', '#ffffff', 'important');
}
function patch(popup) {
if (!popup || popup.dataset.kfxPatched === '1') return;
popup.dataset.kfxPatched = '1';
styleConfirm(popup.querySelector('.swal2-confirm'));
styleCancel(popup.querySelector('.swal2-cancel'));
styleDeny(popup.querySelector('.swal2-deny'));
}
// Patch popups que ya estén en el DOM al cargar
document.querySelectorAll('.swal2-popup').forEach(patch);
// Observa nuevos popups (SWAL los agrega/quita dinámicamente)
var obs = new MutationObserver(function (mutations) {
mutations.forEach(function (m) {
m.addedNodes && m.addedNodes.forEach(function (n) {
if (!(n instanceof HTMLElement)) return;
if (n.classList && n.classList.contains('swal2-popup')) {
patch(n);
} else {
// Por si el contenedor agrega un wrapper antes del popup
var inner = n.querySelector && n.querySelector('.swal2-popup');
if (inner) patch(inner);
}
});
});
});
obs.observe(document.body, { childList: true, subtree: true });
}
/*
Init
*/
ready(function () {
try { splitWords(); } catch (e) { console.warn('kinetic-fx splitWords:', e); }
try { autoTagReveal(); } catch (e) { console.warn('kinetic-fx autoTagReveal:', e); }
try { initReveal(); } catch (e) { console.warn('kinetic-fx reveal:', e); }
try { initReadingBar(); } catch (e) { console.warn('kinetic-fx readingBar:', e); }
try { initNavbarScroll(); } catch (e) { console.warn('kinetic-fx navbarScroll:', e); }
try { initSpotlight(); } catch (e) { console.warn('kinetic-fx spotlight:', e); }
try { initTilt(); } catch (e) { console.warn('kinetic-fx tilt:', e); }
try { initMagnetic(); } catch (e) { console.warn('kinetic-fx magnetic:', e); }
try { initRipple(); } catch (e) { console.warn('kinetic-fx ripple:', e); }
try { initCounters(); } catch (e) { console.warn('kinetic-fx counters:', e); }
try { initParallax(); } catch (e) { console.warn('kinetic-fx parallax:', e); }
try { initMarquee(); } catch (e) { console.warn('kinetic-fx marquee:', e); }
try { initCustomCursor(); } catch (e) { console.warn('kinetic-fx cursor:', e); }
try { initAnchorSmooth(); } catch (e) { console.warn('kinetic-fx anchor:', e); }
try { initSwalPatcher(); } catch (e) { console.warn('kinetic-fx swalPatcher:', e); }
});
// API pública mínima (por si una vista necesita re-inicializar tras AJAX)
window.KineticFX = {
rescan: function () {
splitWords();
autoTagReveal();
initReveal();
initSpotlight();
initTilt();
initMagnetic();
initCounters();
initMarquee();
}
};
})();
+155
View File
@@ -0,0 +1,155 @@
/* OnAPB Lugares / Promociones
Actualizado para usar el sistema de diseño kinetic-arena.css */
.lugares-container {
max-width: 1100px;
margin: 40px auto;
padding: 0 15px;
}
.lugares-container h1 {
font-size: 2.4rem;
font-weight: 700;
color: var(--primary);
margin-bottom: 15px;
text-align: center;
}
.lugares-container p {
font-size: 1.1rem;
margin-bottom: 25px;
text-align: center;
color: var(--on-surface-muted);
}
/* Barra de filtro */
.filter-bar {
background: var(--surface-container-low);
border-radius: var(--radius-sm);
border: 1px solid var(--outline-variant);
padding: 15px;
}
.filter-bar label {
font-weight: 600;
margin-bottom: 8px;
display: block;
}
.filter-bar select {
border-radius: var(--radius-sm);
}
/* Container de promo (solo para filtrado, no visual) */
.promo-card {
cursor: pointer;
}
/* Detalle */
#promo-detail {
border-radius: var(--radius);
background: var(--surface-container-lowest);
border: 1px solid var(--outline-variant);
}
#promo-detail h3 {
color: var(--primary);
font-weight: 700;
margin-bottom: 15px;
}
#promo-detail p {
font-size: 1rem;
color: var(--on-surface-muted);
margin-bottom: 8px;
}
#promo-detail a {
display: inline-block;
text-align: center;
margin-top: 12px;
padding: 8px 14px;
border-radius: var(--radius-sm);
border: 1px solid var(--primary);
color: var(--primary);
text-decoration: none;
transition: all 0.2s ease;
}
#promo-detail a:hover {
background: var(--primary);
color: #fff;
}
/* Mapa */
.map-container {
height: 450px;
border-radius: var(--radius);
margin-top: 30px;
border: 1px solid var(--outline-variant);
box-shadow: var(--shadow-sm, 0 2px 8px rgba(0,0,0,0.08));
}
/* Mapa fluido sin desbordes */
.map-container, #map { width: 100%; max-width: 100%; }
.map-container { overflow: hidden; }
#map, .leaflet-container { width: 100% !important; }
/* Pines marcador */
.custom-pin .pin {
position: relative;
width: 36px;
height: 36px;
background: gray;
border-radius: 50%;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
--pin-color: gray;
}
.custom-pin .pin i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 16px;
color: white;
}
.custom-pin .pin::after {
content: "";
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 10px solid;
border-top-color: var(--pin-color);
}
/* Responsive */
@media (max-width: 768px) {
.lugares-container h1 { font-size: 2rem; }
.map-container { height: 350px; }
.lugares-container { padding-left: 16px; padding-right: 16px; }
}
@media (max-width: 576px) {
.lugares-container h1 { font-size: 1.6rem; }
.map-container { height: 300px; }
.map-container, #map { width: 100%; }
.custom-pin .pin {
width: 26px;
height: 26px;
}
.custom-pin .pin i { font-size: 14px; }
.custom-pin .pin::after {
bottom: -6px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 8px solid;
}
}
Binary file not shown.
Binary file not shown.
+134
View File
@@ -0,0 +1,134 @@
const CACHE_NAME = 'onapb-v4';
// Recursos estáticos que se cachean en la instalación
const STATIC_ASSETS = [
'/',
'/eventos',
'/torneos',
'/offline',
'/manifest.json',
];
// ── Install: pre-cachear recursos estáticos ──
self.addEventListener('install', (event) => {
self.skipWaiting();
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(STATIC_ASSETS).catch(() => {
// Si algún recurso falla, no bloquear la instalación
console.warn('[SW] Algún recurso estático no pudo cachearse.');
});
})
);
});
// ── Activate: limpiar caches viejas ──
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys
.filter((key) => key !== CACHE_NAME)
.map((key) => caches.delete(key))
)
).then(() => self.clients.claim())
);
});
// ── Fetch: Network-first para páginas, Cache-first para assets ──
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Solo manejar peticiones del mismo origen
if (url.origin !== location.origin) return;
// Ignorar peticiones POST, PUT, DELETE, admin, notificaciones en tiempo real
if (request.method !== 'GET') return;
if (url.pathname.startsWith('/admin')) return;
if (url.pathname.startsWith('/notificaciones/count')) return;
// Assets estáticos (JS, CSS, imágenes, fuentes): Cache-first
if (
url.pathname.match(/\.(js|css|png|jpg|jpeg|gif|svg|webp|woff2?|ico)$/)
) {
event.respondWith(
caches.match(request).then((cached) => {
if (cached) return cached;
return fetch(request).then((response) => {
if (response && response.status === 200) {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(request, clone));
}
return response;
});
})
);
return;
}
// Páginas HTML: Network-first, fallback a cache, luego /offline
event.respondWith(
fetch(request)
.then((response) => {
if (response && response.status === 200) {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(request, clone));
}
return response;
})
.catch(() =>
caches.match(request).then(
(cached) => cached || caches.match('/offline')
)
)
);
});
// ── Web Push Notifications ──
self.addEventListener('push', (event) => {
let data = { title: 'OnAPB', body: 'Tenés una nueva notificación' };
if (event.data) {
try {
data = event.data.json();
} catch (e) {
data.body = event.data.text();
}
}
const options = {
body: data.body,
icon: '/icons/icon-192.png?v=4',
badge: '/icons/icon-72.png?v=4',
data: {
url: data.url || '/'
},
vibrate: [100, 50, 100]
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const targetUrl = event.notification.data.url || '/';
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
// Si ya hay una ventana abierta con la misma URL, enfocarla
for (const client of clientList) {
if (client.url === targetUrl && 'focus' in client) {
return client.focus();
}
}
// Si no, abrir una nueva
if (clients.openWindow) {
return clients.openWindow(targetUrl);
}
})
);
});