/* global React */
const { useState } = React;
/* ---------- Icon set (Lucide-style) ---------- */
function Icon({ name, size = 18, stroke = 1.75 }) {
const paths = {
arrow: ,
arrowDown: ,
check: ,
plus: ,
minus: ,
x: ,
chevron: ,
chevronr: ,
globe: ,
calendar: ,
clock: ,
users: ,
user: ,
euro: ,
factory: ,
flask: ,
book: ,
bolt: ,
chart: ,
cpu: ,
shield: ,
droplet: ,
wrench: ,
play: ,
mail: ,
linkedin: ,
youtube: ,
download: ,
grid: ,
list: ,
};
return (
);
}
/* ---------- Logo (LH brand) ---------- */
function Logo({ variant = "color", height = 28 }) {
const src = variant === "white" ? "assets/logo-white.svg"
: variant === "mark" ? "assets/logo-mark.svg"
: variant === "black" ? "assets/logo-black.svg"
: "assets/logo-color.svg";
return
;
}
/* ---------- Wordmark for "Escuela de Protones" ----------
Lockup: custom isotype (proton-arrow inside electron orbit, with
electron dot) + wordmark in display type. The isotype is supplied
as a PNG asset — variants navy (default) / white (for dark bg). */
function EPMark({ height = 28, color = "var(--lh-navy)", accent = "var(--lh-cyan)", variant }) {
const isDark = variant === 'white' ||
(typeof color === 'string' && (color === '#fff' || color === 'white'));
const markSrc = isDark ? 'assets/ep-logo-white.png' : 'assets/ep-logo.png';
return (
Escuela
de
Protones
);
}
/* ---------- Pictographic mark — just the proton/orbit glyph ---------- */
function ProtonGlyph({ size = 48, color = "var(--lh-navy)", accent = "var(--lh-cyan)", strokeWidth = 1.5 }) {
return (
);
}
/* ---------- Badge / chip ---------- */
function Badge({ children, variant = "default", style }) {
const variants = {
default: { background:'#E8F1FC', color:'#001A70', border:'1px solid transparent' },
onDark: { background:'rgba(255,255,255,.08)', color:'#fff', border:'1px solid rgba(255,255,255,.18)' },
cyan: { background:'rgba(0,181,226,.15)', color:'#00B5E2', border:'1px solid rgba(0,181,226,.35)' },
yellow: { background:'rgba(224,231,34,.22)', color:'#6B6F00', border:'1px solid rgba(224,231,34,.6)' },
outline: { background:'#fff', color:'#001A70', border:'1px solid #DDE4ED' },
soft: { background:'#F6F8FB', color:'#4A5668', border:'1px solid #EEF2F7' },
};
return (
{children}
);
}
/* ---------- Button ---------- */
function Button({ children, variant = "primary", size = "md", icon, iconAfter, onClick, type = "button", disabled, full, href, target, download, style }) {
const base = {
display:'inline-flex', alignItems:'center', justifyContent:'center', gap:8,
fontFamily:'inherit', fontWeight:600, cursor: disabled?'not-allowed':'pointer',
border:'1px solid transparent', borderRadius:8,
transition:'all 200ms cubic-bezier(.2,.8,.2,1)',
textDecoration:'none',
width: full ? '100%' : 'auto',
opacity: disabled ? 0.4 : 1,
};
const sizes = {
sm:{ padding:'7px 14px', fontSize:13 },
md:{ padding:'10px 18px', fontSize:14 },
lg:{ padding:'14px 22px', fontSize:15 },
};
const variants = {
primary: { background:'#001A70', color:'#fff' },
secondary: { background:'#fff', color:'#001A70', borderColor:'#DDE4ED' },
tertiary: { background:'transparent', color:'#307FE2', padding:'10px 4px' },
accent: { background:'#E0E722', color:'#001A70' },
ghost: { background:'transparent', color:'#001A70' },
onDark: { background:'#fff', color:'#001A70' },
onDarkGhost: { background:'transparent', color:'#fff', borderColor:'rgba(255,255,255,.25)' },
cyan: { background:'#00B5E2', color:'#001A70' },
};
const hoverStyles = {
primary: { background:'#1A3180' },
secondary: { background:'#F6F8FB', borderColor:'#C2CCD8' },
tertiary: { color:'#001A70' },
accent: { background:'#d6dd1f' },
ghost: { background:'#F6F8FB' },
onDark: { background:'#F6F8FB' },
onDarkGhost: { background:'rgba(255,255,255,.08)', borderColor:'rgba(255,255,255,.4)' },
cyan: { background:'#16C2EB' },
};
const [hover, setHover] = useState(false);
const merged = {...base, ...sizes[size], ...variants[variant], ...(hover && !disabled ? hoverStyles[variant] : {}), ...style};
if (href) {
return (
setHover(true)} onMouseLeave={()=>setHover(false)} style={merged}>
{icon && }
{children}
{iconAfter && }
);
}
return (
);
}
/* ---------- Card ---------- */
function Card({ children, hover = true, padding = 24, onClick, style }) {
const [h, setH] = useState(false);
return (
setH(true)} onMouseLeave={()=>setH(false)} onClick={onClick}
style={{
background:'#fff', border:'1px solid #EEF2F7', borderRadius:12,
padding, cursor: onClick?'pointer':'auto',
boxShadow: hover && h
? '0 12px 32px rgba(0,26,112,.08), 0 4px 12px rgba(0,26,112,.05)'
: '0 1px 2px rgba(0,26,112,.06), 0 1px 3px rgba(0,26,112,.04)',
transform: hover && h ? 'translateY(-2px)' : 'none',
transition:'all 200ms cubic-bezier(.2,.8,.2,1)',
...style,
}}>
{children}
);
}
/* ---------- Eyebrow ---------- */
function Eyebrow({ children, color = '#00B5E2', mono = true }) {
return {children}
;
}
/* ---------- Level chip ---------- */
function LevelChip({ level, size = 28, withLabel = false }) {
const labels = { i: 'Introductorio', a: 'Avanzado', e: 'Experto' };
const colors = {
i: { bg:'rgba(0,181,226,.14)', fg:'var(--lh-cyan)', border:'rgba(0,181,226,.35)' },
a: { bg:'rgba(48,127,226,.14)', fg:'var(--lh-blue)', border:'rgba(48,127,226,.4)' },
e: { bg:'rgba(224,231,34,.22)', fg:'#6B6F00', border:'rgba(224,231,34,.7)' },
};
const c = colors[level];
return (
{level}
{withLabel && {labels[level]}}
);
}
Object.assign(window, { Icon, Logo, EPMark, ProtonGlyph, Badge, Button, Card, Eyebrow, LevelChip });