// V2 — Brutalista / Dorsal de carrera // Crema + rojo dorsal, tipo condensada masiva, bordes negros gruesos, // elementos rotados, numeración tipo BIB. const v2c = { paper: '#f1ead8', ink: '#0e0e0c', red: 'var(--v2-accent, #e8201f)', red2: '#c81817', shadow: '#0e0e0c', warn: '#fff4a0', cond: '"Anton", "Bebas Neue", Impact, safns-serif', body: '"Space Grotesk", system-ui, sans-serif', mono: '"JetBrains Mono", ui-monospace, monospace', }; function V2Brutalist({ tweaks }) { const t = tweaks || V2_DEFAULTS; return (
); } /* ───────── Tweaks context ───────── */ const V2_DEFAULTS = { accent: '#e8201f', highlight: 'TLÓN', prefix: 'DUA', dateLine1: 'DOM · 02', dateLine2: 'AGO 2026', subtitle: 'YAGUARCOCHA', daysLeft: 40, }; const V2Ctx = React.createContext(V2_DEFAULTS); const useV2 = () => React.useContext(V2Ctx); /* ───────── Hero ───────── */ function V2Hero() { const t = useV2(); return (
{/* nav */}
DYR · 2026 ES·EN
{/* Massive numeric BIB */}
{/* date stamp top-right rotated */}
{t.dateLine1}
{t.dateLine2}
{t.prefix}
{t.highlight}
{/* Sub-event line */}
DE RUTA {t.subtitle}
{/* Image slot — race style, hero.svg as default bg */}
{/* bib number overlay */}
0026
IBARRA · ECUADOR · 2.225m
{/* CTA + countdown row */}
INSCRIBIRSE →
FALTAN
{useDaysLeft()}
DÍAS
); } /* ───────── Días reales restantes ───────── */ const V2_RACE_DATE = new Date(2026, 7, 2, 0, 0, 0); // 02 AGO 2026 function useDaysLeft() { const calc = () => Math.max(0, Math.ceil((V2_RACE_DATE - new Date()) / 86_400_000)); const [days, setDays] = React.useState(calc); React.useEffect(() => { const id = setInterval(() => setDays(calc()), 60 * 60 * 1000); return () => clearInterval(id); }, []); return days; } /* ───────── Ticker ───────── */ function V2Ticker() { const items = ['CORRE', 'PEDALEA', 'CORRE', 'RUTA', 'IBARRA', '02·08·26', 'YAGUARCOCHA']; const seq = [...items, ...items, ...items, ...items]; return (
{seq.map((t, i) => ( {t} {i % 3 === 1 && } ))}
); } /* ───────── Distancias ───────── */ function V2Distancias() { const formats = [ { code: 'SPR', name: 'SPRINT', bk: 36, rn: 7, tag: 'CATEGORÍA COMPETITIVA' }, { code: 'NOV', name: 'NOVATOS', bk: 16, rn: 3.6, tag: 'DEBUT · INICIACIÓN' }, ]; return (

DOS
DISTANCIAS
UNA META.

{formats.map((f, i) => (
{f.name}
{f.code}-26
{f.tag} {f.bk + f.rn} KM TOTAL
))} {/* POSTAS — relay card */}
POSTAS
PST-26
EQUIPOS DE 2 · BIKE + RUN
{['SOLO H', 'SOLO M', 'MIXTAS'].map((t, i) => (
{t}
EQUIPO
))}
FORMATO RELEVO UN ATLETA · UNA POSTA
); } function V2Leg({ n, label }) { return (
{n}km
{label}
); } /* ───────── Mapa ───────── */ function V2Mapa() { return (
03 EL CIRCUITO

VUELTA A
LA PISTA.

AUTÓDROMO INTERNACIONAL DE YAGUARCOCHA · ASFALTO CERRADO

{/* Track card */}
{/* dashed stripe overlay for racing kerb feel */} {/* Race track silhouette — kidney-shaped circuit */} {/* center dashed racing line */} {/* Start/finish line (checkered) */} {[0,1,2,3,4,5].map(i => ( ))} SALIDA META {/* Transition zone */} T1·T2 {/* Corner numbers (turns) */} {[ [86, 38, '1'], [186, 36, '2'], [240, 60, '3'], [292, 124, '4'], [228, 168, '5'], [130, 168, '6'], [62, 168, '7'], [32, 118, '8'], ].map(([x, y, n], i) => ( {n} ))} {/* Track name */} AUTÓDROMO {/* Legend tape */}
ASFALTO · CERRADO AL TRÁFICO
{/* Stats */}
{[ ['3,6', 'KM / VUELTA'], ['8', 'CURVAS'], ['2.225', 'm s.n.m.'], ].map(([n, l], i) => (
{n}
{l}
))}
{/* Vueltas por categoría */}
{[ { name: 'SPRINT · BIKE', laps: 10, km: 36 }, { name: 'SPRINT · RUN', laps: 2, km: 7 }, { name: 'NOVATOS · BIKE', laps: 4, km: 16 }, { name: 'NOVATOS · RUN', laps: 1, km: 3.6 }, ].map((v, i) => (
{v.name} {v.laps}vueltas ≈ {v.km}km
))}
); } /* ───────── Categorías ───────── */ function V2Categorias() { // Categorías por edad — aplican en Sprint y Novatos, hombres y mujeres. const cats = [ ['PREJUVENIL', '13 — 16 AÑOS'], ['SUB-23', '16 — 22 AÑOS'], ['SÉNIOR A', '23 — 30 AÑOS'], ['SÉNIOR B', '31 — 39 AÑOS'], ['MASTER A', '40 — 49 AÑOS'], ['MASTER B', '50 — 55 AÑOS'], ['MASTER C', '56 EN ADELANTE'], ]; return (
{/* table */}
CATEGORÍAEDAD
{cats.map(([n, who], i) => (
{n}
{who}
))}
{/* Categorías abiertas MTB */}
CATEGORÍAS ABIERTAS · MTB
GENERAL SIN
LÍMITE DE EDAD MTB
{['SPRINT', 'NOVATOS', 'POSTAS'].map((t, i) => (
{t}
ABIERTA
))}
⚠ Una categoría se abre con mínimo 6 participantes; caso contrario, se suma a la categoría superior.

PREMIACIÓN.

SPRINT & NOVATOS · HOMBRES Y MUJERES
PODIO 1·2·3 POR CATEGORÍA · MEDALLA FINISHER

{/* Foto premiación */}
Premiación Duatlón Yaguarcocha
PREMIACIÓN · EDICIÓN ANTERIOR
{/* Premios por categoría */}
PREMIOS POR CATEGORÍA
TROFEO + KIT DE
AUSPICIANTES
1º · 2º · 3º DE CADA CATEGORÍA · SPRINT Y NOVATOS · HOMBRES Y MUJERES
); } /* ───────── Precios ───────── */ function V2Precios() { const price = { sprint: 34, novatos: 27, postas: 25 }; return (

VALOR
POR
PERSONA.

INSCRIPCIÓN 2026
PRECIOS POR PERSONA
ASEGURA TU DORSAL →
▶ INCLUYE
    {[ 'Dorsal + chip de cronometraje', 'Camiseta técnica LAFTECH', 'Correa de control', 'Kit de hidratación', 'Seguro del evento', 'Medalla finisher', ].map((it, i) => (
  • · {it}
  • ))}
Kit de la competencia
); } /* ───────── Countdown 48h loop ───────── */ function V2Countdown() { // Cycle: 2 days (48h). Counts down to the next midnight that is at // least one full day away, then loops back to ~48h automatically. const CYCLE_MS = 2 * 24 * 60 * 60 * 1000; const getRemaining = () => { const now = new Date(); const anchor = new Date(now); anchor.setHours(24, 0, 0, 0); // tonight's midnight anchor.setDate(anchor.getDate() + 1); // → tomorrow's midnight (≈ 24-48h ahead) let diff = anchor - now; while (diff <= 0) diff += CYCLE_MS; const d = Math.floor(diff / 86_400_000); const h = Math.floor((diff % 86_400_000) / 3_600_000); const m = Math.floor((diff % 3_600_000) / 60_000); const s = Math.floor((diff % 60_000) / 1000); return { d, h, m, s }; }; const [t, setT] = React.useState(getRemaining); React.useEffect(() => { const id = setInterval(() => setT(getRemaining()), 1000); return () => clearInterval(id); }, []); const pad = (n) => String(n).padStart(2, '0'); const cell = (n, l) => (
{pad(n)}
{l}
); return (
{/* live pulse dot */}
EN VIVO
CUPOS LIMITADOS
TIEMPO APROXIMADO PARA TERMINAR REGISTROS
{cell(t.d, 'DÍAS')} {cell(t.h, 'HORAS')} {cell(t.m, 'MIN')} {cell(t.s, 'SEG')}
); } function V2Sep() { return (
:
); } /* ───────── Inscripción form (embed) ───────── */ function V2Form() { // Load the embed script once. React.useEffect(() => { const SRC = 'https://link.centralize.es/js/form_embed.js'; if (document.querySelector(`script[src="${SRC}"]`)) return; const s = document.createElement('script'); s.src = SRC; s.async = true; document.body.appendChild(s); }, []); return (
{/* Header bar — matches the brutalist tabs/labels above */}
▶ COMPLETA TUS DATOS
FORMULARIO DE
INSCRIPCIÓN
PASO 01
{/* Iframe container — tall enough for typical multi-field forms. The embed script auto-resizes when it can. */}
PAGO SEGURO · CUPOS LIMITADOS · CONFIRMACIÓN INMEDIATA
); } function V2PriceBlock({ label, price, invert }) { const fg = invert ? v2c.paper : v2c.ink; const bg = invert ? 'rgba(14,14,12,.2)' : 'rgba(14,14,12,.06)'; return (
{label}
${price}
); } /* ───────── Video ───────── */ function V2Video() { return (
); } /* ───────── Auspiciantes ───────── */ function V2Auspiciantes() { const logos = [ 'https://i.postimg.cc/gkXhMmsw/Whats-App-Image-2026-01-16-at-3-13-10-PM.jpg', 'https://i.postimg.cc/tCY3Lhqz/Whats-App-Image-2026-03-31-at-10-16-01.jpg', 'https://i.postimg.cc/mrNCQjw8/NIKKY.jpg', ]; return (
{logos.map((src, i) => (
Auspiciante
))}
); } /* ───────── Footer ───────── */ function V2Footer() { return ( ); } /* ───────── helper ───────── */ function V2Eyebrow({ num, label }) { return (
{num} {label}
); } window.V2Brutalist = V2Brutalist;