/* ORGULLO MILLONARIO · Landing modular — React + Tailwind · Liquid Glass iOS 26 Réplica del sitio completo. Cada sección Y cada bloque (tarjetas/banners) se prende/apaga desde el Panel SaaS (config.sections[].on + blocks[].on) y se refleja EN VIVO vía OM-DB. */ const {useState,useEffect,useRef,useMemo,useSyncExternalStore,createContext,useContext}=React; const useDB=()=>useSyncExternalStore(OMDB.subscribe,OMDB.get); /* ---- icons ---- */ const I={ home:, cal:<>, ticket:<>, chat:, user:<>, wa:, ig:<>, yt:<>, tk:, x:, arrow:, lock:<>, play:, chev:, up:, }; const Ic=({n,s=18,c=""})=>{I[n]}; /* ---- crests (imagen si existe, si no badge con iniciales) ---- */ const CRESTS={river:'assets/river.png',boca:'assets/boca.png',barracas:'assets/barracas.png',argentinos:'assets/argentinos.png',racing:'assets/racing.png',talleres:'assets/talleres.png',gimnasia:'assets/gimnasia.png',rosario:'assets/rosario.png',flamengo:'assets/flamengo.png'}; function Crest({k,name,s=32,logo}){ const src=logo||CRESTS[k]; if(src)return {name||''}; const ini=(name||'?').replace(/[^A-Za-zÁÉÍÓÚÑ ]/g,'').split(/\s+/).filter(Boolean).slice(0,2).map(w=>w[0]).join('').toUpperCase(); return {ini}; } const FORMA={G:['#2fe07a','rgba(47,224,122,.16)'],P:['#ff5a63','rgba(255,90,99,.16)'],E:['#e0a24e','rgba(224,162,78,.16)']}; const FormaBadges=({str,s=24})=>
{str.split('').map((r,i)=>{const[c,bg]=FORMA[r]||FORMA.E;return {r};})}
; /* ---- toast ---- */ const ToastCtx=createContext(()=>{}); function ToastHost({children}){ const [msg,setMsg]=useState(null);const t=useRef(); const toast=m=>{setMsg(m);clearTimeout(t.current);t.current=setTimeout(()=>setMsg(null),2400);}; return {children}
{msg}
; } /* ---- countdown ---- */ function useCountdown(iso){const [d,setD]=useState(()=>calc(iso));useEffect(()=>{const t=setInterval(()=>setD(calc(iso)),1000);return()=>clearInterval(t);},[iso]);return d;} function calc(iso){let ms=Math.max(0,new Date(iso).getTime()-Date.now());const p=n=>String(n).padStart(2,'0');const dd=Math.floor(ms/864e5);ms-=dd*864e5;const hh=Math.floor(ms/36e5);ms-=hh*36e5;const mm=Math.floor(ms/6e4);const ss=Math.floor((ms-mm*6e4)/1000);return {dd:p(dd),hh:p(hh),mm:p(mm),ss:p(ss)};} function faltan(iso){let ms=new Date(iso)-Date.now();if(ms<0)return 'Jugado';const d=Math.floor(ms/864e5);const h=Math.floor((ms%864e5)/36e5);return `Faltan ${d}d ${h}h`;} const Chip=({children,c='#ff2e3e'})=>{children}; const Eyebrow=({k,t,sub})=>(
{k}

{t}

{sub&&

{sub}

}
); const CountBoxes=({c,accent='#ffcf3e'})=>(
{[['DÍAS',c.dd],['HS',c.hh],['MIN',c.mm],['SEG',c.ss]].map(([l,v])=>(
{v}{l}
))}
); const Bar=({pct,bg})=>
; /* helper visibilidad — la modularización SOLO aplica si el panel la activó */ function useVis(){ const db=useDB();const modular=!!db.config.modular;const secs=db.config.sections||[]; const blockOn=(secId,blkId)=>{if(!modular)return true;const s=secs.find(x=>x.id===secId);if(!s)return true;const b=(s.blocks||[]).find(x=>x.id===blkId);return b?b.on:true;}; return {secs,blockOn,modular}; } /* ============ SHIRT 360 ============ */ function Shirt360({front,back,s=150}){ const [ang,setAng]=useState(0);const drag=useRef(null);const auto=useRef(true);const resume=useRef(); useEffect(()=>{let last=performance.now(),raf;const loop=t=>{const dt=t-last;last=t;if(auto.current)setAng(a=>(a+dt*0.045)%360);raf=requestAnimationFrame(loop);};raf=requestAnimationFrame(loop);return()=>cancelAnimationFrame(raf);},[]); const down=e=>{auto.current=false;clearTimeout(resume.current);drag.current={x:e.clientX,a:ang};e.currentTarget.setPointerCapture&&e.currentTarget.setPointerCapture(e.pointerId);}; const move=e=>{if(drag.current)setAng(drag.current.a+(e.clientX-drag.current.x)*0.8);}; const up=()=>{if(drag.current){drag.current=null;resume.current=setTimeout(()=>auto.current=true,2200);}}; return
↺ ARRASTRÁ PARA GIRAR 360°
; } /* ============ HERO ============ */ function Hero(){ const db=useDB();const p=db.partido;const c=useCountdown(p.fecha);const k=db.kpis; return
FILIAL RIVER · CORRIENTES

{db.config.hero_titulo}

{k.socios} en vivo | {k.visitas} visitas
● PRÓXIMO PARTIDO
{p.local}LOCAL
VS
{p.visitante}VISITANTE
📅 25 JUL🏆 {p.competencia}📍 Monumental
; } /* ============ CENTRO DE DATOS ============ */ function Centro(){ const db=useDB();const {blockOn}=useVis();const d=db.datos; const live=!!(window.OMDB&&OMDB.isLive&&OMDB.isLive()); const _xgMax=Math.max(d.xg.river,d.xg.rivalXg); return
● {live?'EN VIVO':'DEMO'} · {d.liga}
{blockOn('centro','tabla')&&
🏆 TABLA · ZONA DE RIVERLiga Prof. 2026
#EQUIPODGPTS
{d.tabla.map(t=>(
{t.pos}
{t.nombre}
{t.dg} {t.pts}
))}
}
{blockOn('centro','forma')&&
📋 FORMA RIVER · ÚLTIMOS 5
■ Ganó■ Empató■ Perdió
} {blockOn('centro','xg')&&
◎ xG · GOLES ESPERADOS
{d.xg.river}
{d.xg.rivalXg}
} {blockOn('centro','ad')&&
ESPACIO PUBLICITARIO
300 × 250 · configurable desde el panel
}
; } /* ============ PROBABILIDADES 1X2 ============ */ function Prob(){ const db=useDB();const p=db.datos.pred;const pt=db.partido; const max=Math.max(...p.scores.map(s=>s.p)); return
◈ PROBABILIDADES · PRÓXIMO PARTIDO{p.modelo}
River
VS
25/7 · 19:15
📍 Monumental
{pt.visitante}
RESULTADO FINAL (1X2)
Gana River {p.home}%Empate {p.draw}%Gana rival {p.away}%
AMBOS EQUIPOS MARCAN
Sí {p.bttsYes}%No {p.bttsNo}%
RESULTADOS MÁS PROBABLES
{p.scores.map((s,i)=>(
{s.s}{s.p}%
))}
Actualizado 04:01:19 · se refresca cada 60s
; } /* ============ CALENDARIO ============ */ const CAL=[ {dia:'25',mes:'JUL',rival:'Barracas Central',crest:'barracas',comp:'Liga Profesional · Jornada 1 · Monumental',cond:'LOCAL',iso:'2026-07-25T19:15:00-03:00'}, {dia:'29',mes:'JUL',rival:'Gimnasia La Plata',crest:'gimnasia',comp:'Liga Profesional · Jornada 2 · Visitante',cond:'VISITA',iso:'2026-07-29T19:15:00-03:00'}, {dia:'02',mes:'AGO',rival:'Rosario Central',crest:'rosario',comp:'Liga Profesional · Jornada 3 · Monumental',cond:'LOCAL',iso:'2026-08-02T19:15:00-03:00'}, {dia:'09',mes:'AGO',rival:'Tigre',crest:'tigre',comp:'Liga Profesional · Jornada 4 · Visitante',cond:'VISITA',iso:'2026-08-09T21:00:00-03:00'}, ]; function Calendario(){ const {blockOn}=useVis(); return
● Sincronizado · API fútbol
{CAL.map((m,i)=>(
{m.dia}{m.mes}
VS
River vs {m.rival}🏆 {m.comp}
{m.cond}
{faltan(m.iso)}
))} {blockOn('calendario','sponsor')&&
SPONSOR OFICIAL · RIVER PLATE Betano
}
; } /* ============ TICKETS & VIAJES ============ */ function Viajes(){ const db=useDB();const toast=useContext(ToastCtx); return
{db.viajes.map((v,i)=>{const pct=Math.round((1-v.cupos/v.total)*100);const last=v.cupos<=20&&v.cupos>0; return
VIAJE OFICIAL{v.nuevo&&NUEVO · WHATSAPP}

{v.destino}

VS{v.rival} · {v.comp}
🗓 {v.fecha}🚌 {v.salida}📍 {v.punto}👥 {v.cupos} de {v.total} cupos libres
{last?'¡Últimos lugares!':'Cupos disponibles'}
{v.precio}
SEÑA {v.sena}
{v.estado}
;})}
; } /* ============ SORTEOS & PREMIOS ============ */ function Sorteos(){ const db=useDB(); return
{db.premios.map((pr,i)=>(
{pr.kicker}{pr.badge}

{pr.titulo}

{pr.dorso?:{pr.titulo}}
{pr.precio}
))}
; } /* ============ ÚLTIMOS RESULTADOS ============ */ function Resultados(){ const db=useDB();const r=db.resultados;const [mes,setMes]=useState(r.activo); return
🗓 TEMPORADA {r.anio} {r.meses.map(([m,n])=>( ))}
{r.mesLabel} {r.anio}
{r.lista.map((m,i)=>(
{m.comp}{m.fecha}
{m.local}
{m.gl!=null?
{m.gl} - {m.gv}
{m.estado}
:
VS
{m.estado}
}
{m.visita}
))}
; } /* ============ ESTADÍSTICAS · SUPERCLÁSICO ============ */ function Stats(){ const db=useDB();const cl=db.clasico;const h=db.historial;const c=useCountdown(cl.fecha); return
● ✕ EL CLÁSICO DE CLÁSICOS
RIVERVISITANTE
VS
DOM 1 NOV
20:00 hs · Jornada 15
BOCALOCAL · La Bombonera
RIVER
FORMA RECIENTE
BOCA
; } /* ============ PLANTILLA 2026 ============ */ function Plantilla(){ const db=useDB();const {blockOn}=useVis();const f=db.formacion;const h=db.historial; const Face=({p,gk})=>(
{p.foto?{p.n}:{(p.n||'?')[0]}} {p.n}
); const Row=({arr})=>
{(arr||[]).map((p,i)=>)}
; return
👥 PLANTILLA 2026{f.esquema}
{blockOn('plantilla','historial')&&
📋 HISTORIAL SUPERCLÁSICOS
{[[h.ganoRiver,'GANÓ RIVER','#2fe07a'],[h.empates,'EMPATES','#e0a24e'],[h.ganoBoca,'GANÓ BOCA','#2f72e0']].map(([n,l,c],i)=>(
{n}{l}
))}

{h.total} clásicos oficiales · último: {h.ultimo}

ÚLTIMOS CRUCES
{h.cruces.map(([f,s,r],i)=>{const[c,bg]=FORMA[r];return
{f}{s}{r}
;})}
} {blockOn('plantilla','ad')&&
PUBLICIDAD DE SOCIO EXCLUSIVO
Betano
}
; } /* ============ SPONSORS ============ */ function Sponsors(){ const db=useDB();const {blockOn}=useVis();const TC={ORO:'#ffcf3e',PLATA:'#c0c0cb',BRONCE:'#d9915a'}; return
{blockOn('sponsors','gob')&&
APOYA
Gobierno de Corrientes
}
{[...(db.sponsors_locales||[]),...(db.sponsors_locales||[])].map((s,i)=>(
{s.tier}
{s.logo?:{s.nombre}}
))}
★ NUESTROS SPONSORS OFICIALES
; } /* ============ PRODE ============ */ function Prode(){ const db=useDB();const {blockOn}=useVis();const pr=db.prode;const pt=db.partido;const [vid,setVid]=useState(false); return
Acertá y ganá hasta {pr.descuento} en tu próximo viaje}/>
River vs {pt.visitante}
● PRÓXIMO · EN VIVO API

Registrate para jugar el Prode

Es una función exclusiva de socios. Creá tu cuenta y elegí un plan Plata, Oro o VIP para jugar cada partido y ganar descuentos reales.

{blockOn('prode','video')&&
LO ÚLTIMO DE LA BANDA
● VIDEO DESTACADO
}
{vid&&setVid(false)}/>}
; } /* ============ REELS ============ */ function ytId(u){const m=(u||'').match(/(?:youtu\.be\/|v=|shorts\/|embed\/)([\w-]{11})/);return m?m[1]:null;} function ttId(u){const m=(u||'').match(/video\/(\d+)/);return m?m[1]:null;} function VideoModal({reel,onClose}){ const yt=reel.plataforma==='YOUTUBE'&&ytId(reel.url);const tt=reel.plataforma==='TIKTOK'&&ttId(reel.url); return
e.stopPropagation()} className="glass-deep relative rounded-glass p-3 w-full max-w-[420px]" style={{animation:'sheetUp .35s cubic-bezier(.22,1,.36,1) both'}}>
{reel.titulo}
{yt?