/* Sybilhunt website — kit-local primitives. These mirror the design-system components in /components so the kit renders standalone (the compiled _ds_bundle.js is built post-turn). All styling uses the real design tokens from styles.css. */ function Logo({ size = 28, showWordmark = true, onClick }) { return ( Sybilhunt {showWordmark && ( Sybilhunt )} ); } function Button({ variant = 'primary', size = 'md', fullWidth = false, disabled = false, leftIcon, rightIcon, onClick, style = {}, children }) { const sizes = { sm: { padding: '0 16px', height: 36, fontSize: 14 }, md: { padding: '0 22px', height: 46, fontSize: 15 }, lg: { padding: '0 30px', height: 56, fontSize: 17 } }; const variants = { primary: { background: 'var(--signal-500)', color: 'var(--text-on-signal)', border: '1px solid transparent', boxShadow: '0 8px 30px var(--signal-glow)' }, secondary: { background: 'transparent', color: 'var(--text-strong)', border: '1px solid var(--border-strong)' }, ghost: { background: 'transparent', color: 'var(--text-body)', border: '1px solid transparent' }, danger: { background: 'var(--coral-500)', color: 'var(--coral-ink)', border: '1px solid transparent', boxShadow: '0 8px 28px var(--coral-glow)' }, }; const s = sizes[size], v = variants[variant]; return ( ); } function Badge({ tone = 'neutral', size = 'md', dot = false, style = {}, children }) { const tones = { neutral: { bg: 'color-mix(in oklab, var(--ink-300) 14%, transparent)', fg: 'var(--text-muted)', dotc: 'var(--ink-300)' }, signal: { bg: 'color-mix(in oklab, var(--signal-500) 16%, transparent)', fg: 'var(--signal-400)', dotc: 'var(--signal-500)' }, live: { bg: 'color-mix(in oklab, var(--coral-500) 16%, transparent)', fg: 'var(--coral-300)', dotc: 'var(--coral-500)' }, info: { bg: 'color-mix(in oklab, var(--cyan-500) 15%, transparent)', fg: 'var(--cyan-300)', dotc: 'var(--cyan-500)' }, gold: { bg: 'color-mix(in oklab, var(--gold-500) 16%, transparent)', fg: 'var(--gold-400)', dotc: 'var(--gold-500)' }, }; const t = tones[tone]; const isLive = tone === 'live' || tone === 'signal'; return ( {dot && } {children} ); } function Card({ padding = 24, interactive = false, glow = false, style = {}, children, ...rest }) { return (
{ e.currentTarget.style.borderColor = 'var(--border-strong)'; e.currentTarget.style.transform = 'translateY(-3px)'; } : undefined} onMouseLeave={interactive ? (e) => { e.currentTarget.style.borderColor = 'var(--border-subtle)'; e.currentTarget.style.transform = 'translateY(0)'; } : undefined} {...rest}>{children}
); } function Avatar({ src, name = '', size = 48, ring = false, style = {} }) { const initials = name.split(' ').map((w) => w[0]).slice(0, 2).join('').toUpperCase(); return ( {src ? {name} : initials} ); } function Stat({ value, label, sublabel, tone = 'default', align = 'left', style = {} }) { const colors = { default: 'var(--text-strong)', signal: 'var(--signal-400)', gold: 'var(--gold-400)', coral: 'var(--coral-300)' }; return (
{value}
{label &&
{label}
} {sublabel &&
{sublabel}
}
); } function Countdown({ deadline, size = 'md', tone = 'coral', style = {} }) { const target = React.useMemo(() => new Date(deadline).getTime(), [deadline]); const [now, setNow] = React.useState(Date.now()); React.useEffect(() => { const id = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(id); }, []); const diff = Math.max(0, target - now); const units = [['days', Math.floor(diff / 86400000)], ['hrs', Math.floor((diff % 86400000) / 3600000)], ['min', Math.floor((diff % 3600000) / 60000)], ['sec', Math.floor((diff % 60000) / 1000)]]; const dims = size === 'lg' ? { box: 78, num: 36, gap: 12 } : size === 'sm' ? { box: 44, num: 20, gap: 6 } : { box: 58, num: 26, gap: 9 }; const accent = tone === 'signal' ? 'var(--signal-400)' : 'var(--coral-300)'; return (
{units.map(([label, val]) => (
{String(val).padStart(2, '0')}
{label}
))}
); } function PartnerChip({ name, category, accent = 'var(--signal-500)', logoUrl = null, muted = false, onClick = null, style = {} }) { const mono = name ? name.replace(/[^A-Za-zА-Яа-я0-9]/g, '').slice(0, 2).toUpperCase() : '?'; return (
{ e.currentTarget.style.borderColor = 'var(--border-strong)'; e.currentTarget.style.transform = 'translateY(-2px)'; if (onClick) e.currentTarget.style.boxShadow = '0 8px 22px rgba(0,0,0,0.08)'; }} onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'var(--border-subtle)'; e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}> {logoUrl ? {name} { e.currentTarget.style.display='none'; e.currentTarget.parentNode.innerText = mono; }} /> : mono}
{name}
{category &&
{category}
}
{onClick && }
); } function Dialog({ open, onClose, title, eyebrow, width = 'min(70vw, 920px)', footer, children }) { React.useEffect(() => { function onKey(e) { if (e.key === 'Escape' && onClose) onClose(); } if (open) document.addEventListener('keydown', onKey); return () => document.removeEventListener('keydown', onKey); }, [open, onClose]); if (!open) return null; return (
e.stopPropagation()} role="dialog" aria-modal="true" style={{ position: 'relative', width, maxWidth: 920, maxHeight: '84vh', overflowY: 'auto', background: 'var(--surface-panel)', border: '1px solid var(--border-strong)', borderRadius: 'var(--radius-xl)', boxShadow: 'var(--shadow-xl), var(--glow-signal-sm)', padding: 'clamp(28px, 4vw, 52px)', animation: 'sh-dlg-pop var(--dur-slow) var(--ease-bounce)' }}> {eyebrow &&
{eyebrow}
} {title &&

{title}

}
{children}
{footer &&
{footer}
}
); } Object.assign(window, { Logo, Button, Badge, Card, Avatar, Stat, Countdown, PartnerChip, Dialog });