/* ============================================================ Shared UI primitives — Icon set, Avatar, etc. Exposed on window. ============================================================ */ const { useState, useEffect, useRef, useMemo } = React; // Minimal line-icon set (stroke = currentColor). UI affordances only. const PATHS = { calendar: "M7 3v3M17 3v3M4 8h16M5 5h14a1 1 0 011 1v13a1 1 0 01-1 1H5a1 1 0 01-1-1V6a1 1 0 011-1z", clock: "M12 7v5l3 2M12 21a9 9 0 100-18 9 9 0 000 18z", flag: "M5 21V4M5 4h11l-2 3.5L16 11H5", user: "M12 12a4 4 0 100-8 4 4 0 000 8zM4 21a8 8 0 0116 0", users: "M9 11a3.5 3.5 0 100-7 3.5 3.5 0 000 7zM2 21a7 7 0 0114 0M17 11a3 3 0 100-6M22 21a6.5 6.5 0 00-5-6.3", edit: "M4 20h4L19 9l-4-4L4 16v4zM14 6l4 4", trash: "M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13", plus: "M12 5v14M5 12h14", minus: "M5 12h14", check: "M5 12l5 5L20 6", checkCircle: "M9 12l2 2 4-4M12 21a9 9 0 100-18 9 9 0 000 18z", chevR: "M9 6l6 6-6 6", chevL: "M15 6l-6 6 6 6", chevD: "M6 9l6 6 6-6", menu: "M4 7h16M4 12h16M4 17h16", x: "M6 6l12 12M18 6L6 18", logout: "M15 12H4m0 0l4-4m-4 4l4 4M14 4h5a1 1 0 011 1v14a1 1 0 01-1 1h-5", trophy: "M8 4h8v4a4 4 0 01-8 0V4zM8 6H5v1a3 3 0 003 3M16 6h3v1a3 3 0 01-3 3M10 14h4M9 20h6M12 14v6", cart: "M5 4h2l1.5 11h9L19 7H7", mail: "M4 6h16v12H4zM4 7l8 6 8-6", pin: "M12 21s7-6.3 7-11a7 7 0 10-14 0c0 4.7 7 11 7 11zM12 12a2.5 2.5 0 100-5 2.5 2.5 0 000 5z", star: "M12 4l2.4 5 5.6.5-4.2 3.7 1.3 5.3L12 16.8 6.9 18.5 8.2 13.2 4 9.5 9.6 9z", shield: "M12 3l8 3v6c0 4.5-3.4 7.7-8 9-4.6-1.3-8-4.5-8-9V6l8-3z", swap: "M7 8h11l-3-3M17 16H6l3 3", walk: "M13.6 5a1.4 1.4 0 100-2.8 1.4 1.4 0 000 2.8M13 8.2l-2.3 4.3 2.7 1.7L14.2 20M10.7 12.5L8 14.2M15.4 14.2L18 16", info: "M12 8h.01M11 12h1v5h1M12 21a9 9 0 100-18 9 9 0 000 18z", arrowR: "M5 12h14m-5-5l5 5-5 5", }; function Icon({ name, size = 18, stroke = 2, style, className }) { const d = PATHS[name]; return ( ); } function Avatar({ initials, size = 34, tone = "brand" }) { const bg = tone === "accent" ? "var(--accent)" : "var(--brand-soft)"; const fg = tone === "accent" ? "#1b1404" : "var(--brand)"; return (
{initials}
); } // striped placeholder for real imagery function Placeholder({ label, h = 140, radius = "var(--radius-sm)" }) { return (
{label}
); } // Walk / Ride transport indicator. Read-only badge, or a toggle when onToggle is given. function Transport({ mode, onToggle, size = "sm" }) { const ride = mode === "ride"; const pad = size === "sm" ? "3px 8px 3px 6px" : "5px 11px 5px 8px"; const fs = size === "sm" ? 10.5 : 12; const inner = ( <> {ride ? "Ride" : "Walk"} ); const base = { display: "inline-flex", alignItems: "center", gap: 5, padding: pad, borderRadius: 999, fontSize: fs, fontWeight: 700, letterSpacing: ".02em", whiteSpace: "nowrap", background: ride ? "color-mix(in srgb,var(--accent) 18%,var(--surface))" : "var(--brand-soft)", color: ride ? "var(--accent-deep)" : "var(--brand)", border: "1px solid " + (ride ? "color-mix(in srgb,var(--accent) 40%,transparent)" : "transparent"), }; if (!onToggle) return {inner}; return ( ); } function StatTile({ value, label, sub, accent }) { return (
{value}
{label}
{sub &&
{sub}
}
); } function Toast({ msg, onDone }) { useEffect(() => { if (!msg) return; const t = setTimeout(onDone, 2800); return () => clearTimeout(t); }, [msg]); if (!msg) return null; return (
{msg}
); } function Modal({ children, onClose, wide }) { useEffect(() => { const onKey = (e) => e.key === "Escape" && onClose(); window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []); return (
e.stopPropagation()}> {children}
); } function ModalHead({ title, sub, onClose }) { return (

{title}

{sub &&

{sub}

}
); } Object.assign(window, { Icon, Avatar, Placeholder, Transport, StatTile, Toast, Modal, ModalHead });