// ---- Shared UI primitives -------------------------------------------
const { useState, useEffect, useRef } = React;
// Thin, elegant line icons (1.6 stroke), inherit currentColor
const ICONS = {
feather: "M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5zM16 8 2 22M17.5 15H9",
calendar:"M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z",
home: "M3 9.5 12 3l9 6.5V20a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1z",
sparkle: "M12 3l1.9 5.6L19.5 10l-5.6 1.9L12 17l-1.9-5.1L4.5 10l5.6-1.4zM19 4v3M5 18v2.5M18 18v2",
heart: "M20.8 5.6a5.5 5.5 0 0 0-7.8 0L12 6.6l-1-1a5.5 5.5 0 1 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8z",
leaf: "M11 20A7 7 0 0 1 4 13c0-5 5-9 16-9 0 9-4 14-9 14zM4 21c2-5 6-9 11-11",
truck: "M1 4h13v12H1zM14 8h4l3 3v5h-7M5.5 19a2 2 0 1 0 0-.1M17.5 19a2 2 0 1 0 0-.1",
cart: "M2 3h2.2l2 13h11.6l2-9H6M9 21a1 1 0 1 0 0-.1M18 21a1 1 0 1 0 0-.1",
star: "M12 2.5l2.9 6.1 6.6.9-4.8 4.6 1.2 6.6L12 18.6 6.1 21.3l1.2-6.6L2.5 9.5l6.6-.9z",
check: "M20 6 9 17l-5-5",
chevron: "M9 18l6-6-6-6",
chevronD:"M6 9l6 6 6-6",
search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3",
user: "M20 21a8 8 0 0 0-16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z",
close: "M18 6 6 18M6 6l12 12",
plus: "M12 5v14M5 12h14",
minus: "M5 12h14",
arrow: "M5 12h14M13 6l6 6-6 6",
moon: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z",
sun: "M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z",
book: "M4 4.5A2.5 2.5 0 0 1 6.5 2H20v18H6.5A2.5 2.5 0 0 0 4 22.5zM4 19.5A2.5 2.5 0 0 1 6.5 17H20",
bookmark:"M6 3h12a1 1 0 0 1 1 1v17l-7-4-7 4V4a1 1 0 0 1 1-1z",
users: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM22 21v-2a4 4 0 0 0-3-3.87M16 3.13A4 4 0 0 1 16 11",
ruler: "M3 8l5-5 13 13-5 5zM8 7l2 2M11 4l3 3M5 10l3 3",
heartline:"M19.5 5.5a4.5 4.5 0 0 0-7 .5l-.5.6-.5-.6a4.5 4.5 0 1 0-6.8 5.9L12 20l7.3-7.6a4.5 4.5 0 0 0 .2-6.9z",
quote: "M7 7H4a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h3v3a3 3 0 0 1-3 3M20 7h-3a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h3v3a3 3 0 0 1-3 3",
arrowUpRight:"M7 17 17 7M8 7h9v9",
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-2zM8.5 11a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM21 16l-4.5-4.5L7 21",
};
function Icon({ name, size = 22, stroke = 1.6, fill = false, style }) {
const d = ICONS[name] || "";
return (
);
}
// Brand logos (recolored asset variants live in /assets). brandAsset() resolves
// to a bundled blob URL (window.__resources) when present, else the file path —
// so the same code works in normal preview and in the standalone export.
function brandAsset(type, variant) {
const id = (type === "mark" ? "logoMark_" : "logoWord_") + variant;
return (window.__resources && window.__resources[id]) || ("assets/logo-" + type + "-" + variant + ".svg");
}
function LogoMark({ color = "brown", height = 40, style }) {
return ;
}
function LogoWord({ color = "brown", height = 26, style }) {
return
;
}
function Stars({ value = 5, size = 16, color = "var(--gold-deep)" }) {
return (
{[0,1,2,3,4].map(i => (
))}
);
}
function Button({ children, variant = "primary", size = "md", onClick, type = "button", style, disabled, full }) {
const base = {
fontFamily: "var(--ui)", fontWeight: 600, letterSpacing: ".01em",
border: "1px solid transparent", borderRadius: 999, cursor: disabled ? "default" : "pointer",
display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 9,
transition: "transform .18s var(--ease), background .2s, color .2s, border-color .2s, box-shadow .2s",
width: full ? "100%" : "auto", opacity: disabled ? 0.5 : 1,
whiteSpace: "nowrap",
};
const sizes = {
sm: { padding: "9px 18px", fontSize: 13 },
md: { padding: "14px 28px", fontSize: 15 },
lg: { padding: "18px 38px", fontSize: 16 },
};
const variants = {
primary: { background: "var(--espresso)", color: "var(--cream)" },
terracotta:{ background: "var(--terracotta)", color: "var(--cream)" },
outline: { background: "transparent", color: "var(--espresso)", borderColor: "var(--espresso)" },
ghost: { background: "var(--cream-2)", color: "var(--espresso)", borderColor: "transparent" },
};
return (
);
}
// Marquee strip — gentle scrolling text, like the reference shop's ribbon
function Marquee({ items, speed = 38, style }) {
const content = items.concat(items);
return (
{sub}
}