/* ============================================================ UI · iconos + componentes compartidos ============================================================ */ const ICONS = { coffee:'M17 8h1a3 3 0 0 1 0 6h-1M3 8h14v6a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V8zM6 2v2M10 2v2M14 2v2', utensils:'M4 3v7a2 2 0 0 0 2 2h0a2 2 0 0 0 2-2V3M6 12v9M18 3c-1.5 0-3 1.5-3 5s1.5 4 3 4M18 3v18', wine:'M8 22h8M12 15v7M5 3h14l-1 7a6 6 0 0 1-12 0L5 3zM5.6 8h12.8', star:'M12 2.5l2.9 5.9 6.5.9-4.7 4.6 1.1 6.5L12 17.8 6.2 20.9l1.1-6.5L2.6 9.8l6.5-.9L12 2.5z', search:'M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM21 21l-4.3-4.3', phone:'M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L16 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z', mail:'M3 5h18v14H3zM3 6l9 7 9-7', whatsapp:'M12 3a9 9 0 0 0-7.7 13.6L3 21l4.5-1.2A9 9 0 1 0 12 3zM8.5 8c.3 0 .6.5.8 1s.4.9.2 1.2-.5.6-.3 1 .9 1.4 1.8 2 1.6.7 1.9.5.7-.8 1-1 .9 0 1.4.3.9.5 1 .8-.2 1.6-1.4 1.7-1.4.1-2.9-.4a8 8 0 0 1-4.4-4.4c-.5-1.5-.4-2.8.3-3.4z', instagram:'M4 8a4 4 0 0 1 4-4h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V8zM12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM16.5 7.5h.01', facebook:'M14 8h2V5h-2a3 3 0 0 0-3 3v2H9v3h2v6h3v-6h2l1-3h-3V8a1 1 0 0 1 1-1z', clock:'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 7v5l3 2', pin:'M12 21s7-6 7-11a7 7 0 0 0-14 0c0 5 7 11 7 11zM12 10a1.8 1.8 0 1 0 0-3.6 1.8 1.8 0 0 0 0 3.6z', calendar:'M3 6a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6zM3 9h18M8 3v4M16 3v4', users:'M16 19v-1a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v1M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM22 19v-1a4 4 0 0 0-3-3.8M16 4.2A3.5 3.5 0 0 1 16 11', plus:'M12 5v14M5 12h14', minus:'M5 12h14', edit:'M4 20h4l10.5-10.5a2.1 2.1 0 0 0-3-3L5 17v3zM13.5 6.5l3 3', trash:'M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13M10 11v6M14 11v6', chevup:'M6 15l6-6 6 6', chevdown:'M6 9l6 6 6-6', chevleft:'M15 6l-6 6 6 6', chevright:'M9 6l6 6-6 6', x:'M6 6l12 12M18 6L6 18', lock:'M6 11h12a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1zM8 11V8a4 4 0 0 1 8 0v3', gear:'M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM19.4 13a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-2.9 1.2V21a2 2 0 0 1-4 0v-.1A1.7 1.7 0 0 0 7 19.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0-1.2-2.9H3a2 2 0 0 1 0-4h.1A1.7 1.7 0 0 0 4.7 7l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.9.3H9.5A1.7 1.7 0 0 0 11 3.1V3a2 2 0 0 1 4 0v.1a1.7 1.7 0 0 0 2.9 1.2l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.9v.2a1.7 1.7 0 0 0 1.6 1H21a2 2 0 0 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z', chart:'M4 20V10M10 20V4M16 20v-7M22 20H2', trend:'M3 17l6-6 4 4 7-8M16 7h5v5', grid:'M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z', list:'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01', image:'M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5zM8 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM21 16l-5-5L5 21', save:'M5 3h11l3 3v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zM8 3v6h8M8 21v-6h8v6', download:'M12 3v12M7 11l5 5 5-5M5 20h14', upload:'M12 21V9M7 13l5-5 5 5M5 4h14', arrowleft:'M19 12H5M11 18l-6-6 6-6', menu:'M3 6h18M3 12h18M3 18h18', check:'M5 12l5 5L20 6', alert:'M12 3l9 16H3l9-16zM12 10v4M12 17h.01', eye:'M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z', eyeoff:'M3 3l18 18M10.6 10.6a3 3 0 0 0 4.2 4.2M9.4 5.4A9.6 9.6 0 0 1 12 5c6.5 0 10 7 10 7a18 18 0 0 1-3 3.8M6.1 6.1A18 18 0 0 0 2 12s3.5 7 10 7a9.6 9.6 0 0 0 2.6-.4', book:'M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2V5zM4 19a2 2 0 0 0 2 2h13M8 7h7M8 11h7', tag:'M3 11l8-8 9 9-8 8-9-9zM7.5 7.5h.01', dollar:'M12 2v20M16 6.5C16 5 14 4 12 4S8 5 8 7s2 3 4 3.5 4 1.5 4 3.5-2 3-4 3-4-1-4-2.5', reset:'M3 12a9 9 0 1 0 3-6.7L3 8M3 3v5h5', home:'M4 11l8-7 8 7M6 10v9a1 1 0 0 0 1 1h3v-6h4v6h3a1 1 0 0 0 1-1v-9', logout:'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9', sparkle:'M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8L12 3z', info:'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 8h.01M11 12h1v4h1', filter:'M3 5h18l-7 8v6l-4-2v-4L3 5z', copy:'M9 9h11v11H9zM5 15H4V4h11v1', arrowright:'M5 12h14M13 6l6 6-6 6', }; function Icon({ name, size = 18, fill = false, style, className }) { const d = ICONS[name]; if (!d) return null; return ( ); } /* ---- Modal ---- */ function Modal({ title, onClose, children, footer, wide }) { useEffect(() => { const h = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [onClose]); return (
{ if (e.target === e.currentTarget) onClose(); }}>

{title}

{children}
{footer &&
{footer}
}
); } /* ---- Confirm dialog ---- */ function useConfirm() { const [state, setState] = useState(null); const ask = (opts) => new Promise((resolve) => setState({ ...opts, resolve })); const node = state ? ( { state.resolve(false); setState(null); }} footer={<> }>

{state.message}

) : null; return [ask, node]; } /* ---- Field building blocks ---- */ function Field({ label, hint, children }) { return (
{label && } {children}
); } function Toggle({ on, onChange, label }) { return ( ); } Object.assign(window, { Icon, Modal, useConfirm, Field, Toggle });