/* ============================================================
NemakiWare — shared UI: logo, icons, reveal, primitives
Exposes components on window.
============================================================ */
const { useState, useEffect, useRef } = React;
/* ---- scroll reveal (scroll + fallback; IO-free for reliability) */
function Reveal({ children, as = "div", delay = 0, className = "", ...rest }) {
const ref = useRef(null);
const El = as;
useEffect(() => {
const el = ref.current;
if (!el) return;
let done = false;
const reveal = () => { if (!done) { done = true; el.classList.add("in"); cleanup(); } };
const check = () => {
const r = el.getBoundingClientRect();
if (r.top < (window.innerHeight || 800) * 0.92 && r.bottom > 0) reveal();
};
const onScroll = () => check();
function cleanup() {
window.removeEventListener("scroll", onScroll);
window.removeEventListener("resize", onScroll);
clearTimeout(t);
}
check();
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll, { passive: true });
const t = setTimeout(reveal, 1600); // hard fallback so content never stays hidden
return cleanup;
}, []);
return (
);
}
/* ---- icon set (simple line icons) ----------------------------- */
const ICONS = {
shield: "M12 3l7 3v5c0 4.5-3 7.6-7 9-4-1.4-7-4.5-7-9V6l7-3z",
search: ["M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14z", "M16.5 16.5L21 21"],
layers: ["M12 3l9 5-9 5-9-5 9-5z", "M3 13l9 5 9-5"],
plug: ["M8 3v5", "M16 3v5", "M6 8h12v2a6 6 0 0 1-12 0V8z", "M12 16v5"],
cube: ["M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z", "M12 3v18", "M4 7.5l8 4.5 8-4.5"],
cycle: ["M4 12a8 8 0 0 1 13.5-5.8L20 8", "M20 4v4h-4", "M20 12a8 8 0 0 1-13.5 5.8L4 16", "M4 20v-4h4"],
monitor: ["M3 4h18v12H3z", "M8 20h8", "M12 16v4"],
lock: ["M6 10V8a6 6 0 0 1 12 0v2", "M5 10h14v10H5z"],
tree: ["M12 4v5", "M6 20v-4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4", "M12 9v5", "M10 2h4v4h-4z", "M4 18h4v4H4z", "M16 18h4v4h-4z"],
users: ["M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z", "M2.5 20a6.5 6.5 0 0 1 13 0", "M16 4.5a3.5 3.5 0 0 1 0 7", "M17 14.2A6.5 6.5 0 0 1 21.5 20"],
eye: ["M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z", "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"],
check: ["M4 12.5l5 5 11-11"],
arrow: ["M5 12h14", "M13 6l6 6-6 6"],
arrowDown: ["M12 5v14", "M6 13l6 6 6-6"],
github: "M12 2a10 10 0 0 0-3.16 19.49c.5.09.68-.22.68-.48l-.01-1.7c-2.78.6-3.37-1.34-3.37-1.34-.45-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.61.07-.61 1 .07 1.53 1.03 1.53 1.03.9 1.53 2.36 1.09 2.94.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02a9.56 9.56 0 0 1 5 0c1.91-1.29 2.75-1.02 2.75-1.02.55 1.38.2 2.4.1 2.65.64.7 1.03 1.59 1.03 2.68 0 3.84-2.34 4.69-4.57 4.94.36.31.68.92.68 1.85l-.01 2.74c0 .27.18.58.69.48A10 10 0 0 0 12 2z",
globe: ["M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z", "M3 12h18", "M12 3c2.5 2.4 3.8 5.6 3.8 9s-1.3 6.6-3.8 9c-2.5-2.4-3.8-5.6-3.8-9S9.5 5.4 12 3z"],
spark: ["M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8L12 3z"],
doc: ["M7 3h7l4 4v14H7z", "M14 3v4h4"],
bolt: ["M13 3L5 13h6l-1 8 8-10h-6l1-8z"],
key: ["M14 7a4 4 0 1 1-5.7 3.6L3 16v3h3l1-1h2v-2h2l1.3-1.3A4 4 0 0 1 14 7z"],
link: ["M9 15l6-6", "M11 6l1-1a4 4 0 0 1 6 6l-1 1", "M13 18l-1 1a4 4 0 0 1-6-6l1-1"],
import: ["M12 3v12", "M7 10l5 5 5-5", "M4 20h16"],
database: ["M12 3c4.4 0 8 1.3 8 3s-3.6 3-8 3-8-1.3-8-3 3.6-3 8-3z", "M4 6v6c0 1.7 3.6 3 8 3s8-1.3 8-3V6", "M4 12v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"],
};
function Icon({ name, size = 22, stroke = 1.9, fill = false, style }) {
const d = ICONS[name];
const paths = Array.isArray(d) ? d : [d];
const isFill = fill || name === "github";
return (
);
}
/* ---- placeholder visual (subtle striped) ---------------------- */
function Placeholder({ label, h = 200, dark = false }) {
const stroke = dark ? "rgba(255,255,255,0.10)" : "oklch(0.55 0.06 220 / 0.14)";
return (