// Lalaluxe — components/brand.jsx
// What the brand draws by hand: the wordmark and the painted finger. Loaded by booking.html and
// admin.html before their shared primitives; hues come from the paint tokens in colors.css. The
// server shells in lib/booking-router.js and the favicons carry the same logo geometry.

/* ---------- Logo: drawn capitals, the X made with a brush ---------- */
// Custom high-contrast capitals built from stems, hairlines and one arc — nothing is typed, so the
// mark needs no font. S is the stem and h the hairline on a 100-unit cap height.
function logoGlyphs(S, h) {
	const H = 100;
	const R = (x, y, w, hh) => `M${x} ${y}h${w}v${hh}h${-w}Z`;
	const P = (...pts) => "M" + pts.map((p) => p.join(" ")).join("L") + "Z";
	const beak = (x, y, dir) => P([x, y], [x, y + dir * 31], [x - 1.5 - h * 0.25, y + dir * 31], [x - 7.5, y + dir * h]);
	const t = h + 0.5; // the thin stroke
	return {
		L: { w: 58, d: R(8, 0, S, H) + R(0, 0, S + 16, h) + R(0, H - h, 58, h) + beak(58, H, -1) },
		A: { w: 98, d: P([44, 0], [44 + t, 0], [8 + t, H], [8, H]) + P([44, 0], [44.5 + S, 0], [75.5 + S, H], [75, H]) + R(23.5, 64, 41, h) + R(0, H - h, 19 + h, h) + R(67.5, H - h, 15.5 + S, h) },
		U: { w: 82, d: `M9 0H${9 + S}V60A${(61 - S) / 2} ${39.7 - h} 0 0 0 70 60V0H${70 + t}V60A${(61 + t) / 2} 40 0 0 1 9 60Z` + R(1, 0, S + 16, h) + R(63, 0, 15 + h, h) },
		E: { w: 60, d: R(8, 0, S, H) + R(0, 0, 56, h) + beak(56, 0, 1) + R(20, 50 - h / 2, 25, h) + R(45, 39, 1.2 + h * 0.25, 22) + R(0, H - h, 58, h) + beak(58, H, -1) },
	};
}
const LOGO_TEXT = logoGlyphs(17, 4.6); // sturdy cut for small sizes
const LOGO_FINE = logoGlyphs(15, 2.3); // display cut
// the X: two passes of a loaded brush
const LOGO_X = {
	w: 92,
	a: "M3 6C8-1 20 0 26 8 41 29 62 59 88 92 92 98 88 105 80 104 74 103 71 99 68 95 49 68 27 39 6 16 2 12 1 9 3 6ZM90 101l7 5-2 3-8-5ZM84 105l5 5-3 1-5-5Z",
	b: "M79 0C85-1 90 4 87 9 69 37 46 68 21 100 17 105 8 105 7 100 6 97 8 93 11 89 35 57 57 28 73 5 75 2 77 0 79 0ZM7 104l-5 6 3 1 5-6Z",
};
function logoRow(G, word, gap, y) {
	let x = 0;
	const nodes = [];
	for (const ch of word) {
		if (ch === "X") {
			nodes.push(
				<g key={y + "-" + x} className="logo-x" transform={`translate(${x - 2} ${y - 2})`}>
					<path d={LOGO_X.a} />
					<path d={LOGO_X.b} />
				</g>,
			);
			x += LOGO_X.w - 4 + gap;
		} else {
			nodes.push(<path key={y + "-" + x} transform={`translate(${x} ${y})`} d={G[ch].d} />);
			x += G[ch].w + gap;
		}
	}
	return { nodes, width: x - gap };
}
// The logo the studio picked (Studio → Logo), as the server wrote it on <html data-brand>. Every
// logo but the drawn one is a set of files under images/brand/<id>/ — the wordmark for a light and a
// dark ground (the theme shows one), and the app icon. Twinned with BRANDS in lib/brand.js.
const BRAND_LOGOS = {
	classic: { name: "The brushed X", note: "Drawn capitals, the X in two pink brushstrokes" },
	fluffy: { name: "Fluffy", note: "Soft fur letters, pink after dark", logo: ["logo-day.webp", "logo-night.webp"] },
	chrome: { name: "Candy chrome", note: "Pink chrome with a halo", logo: ["logo-day.webp", "logo-night.webp"] },
	love: { name: "Love note", note: "Handwritten with a heart", logo: ["logo-day.svg", "logo-night.svg"] },
	halo: { name: "Pink halo", note: "Jelly letters under a halo, hearts around", logo: ["logo-day.webp", "logo-night.webp"] },
	drip: { name: "Drip", note: "Candy letters melting, cut out as a sticker", logo: ["logo-day.webp", "logo-night.webp"] },
	ransom: { name: "Ransom note", note: "Cut-out letters and a lipstick kiss", logo: ["logo-day.webp", "logo-night.webp"] },
};
const brandNow = () => {
	const id = typeof document !== "undefined" && document.documentElement.dataset.brand;
	return id && Object.hasOwn(BRAND_LOGOS, id) ? id : "classic";
};
// The drawn logo's tab icon, as the pages carry it: the X in pink on jet (the studio's: jet on pink).
function drawnTabIcon(studio) {
	const [ground, ink] = studio ? ["#FBACBE", "#0B0908"] : ["#0B0908", "#FBACBE"];
	const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100" rx="20" fill="${ground}"/><g fill="${ink}" transform="translate(50 50) scale(0.66) translate(-47 -52.5)"><path d="${LOGO_X.a}"/><path d="${LOGO_X.b}"/></g></svg>`;
	return "data:image/svg+xml," + encodeURIComponent(svg);
}
// Put a logo on the page now: the wordmarks redraw and the tab icon follows.
function setBrand(id) {
	if (!Object.hasOwn(BRAND_LOGOS, id || "") || id === brandNow()) return;
	document.documentElement.dataset.brand = id;
	const icon = document.querySelector('link[rel="icon"]');
	if (icon) {
		const studio = location.pathname.startsWith("/admin");
		icon.setAttribute("type", id === "classic" ? "image/svg+xml" : "image/png");
		if (id === "classic") icon.removeAttribute("sizes");
		icon.setAttribute("href", id === "classic" ? drawnTabIcon(studio) : `/images/brand/${id}/${studio ? "console" : "favicon"}-32.png`);
	}
	window.dispatchEvent(new CustomEvent("brandchange", { detail: id }));
}
function useBrand() {
	const [id, setId] = React.useState(brandNow);
	React.useEffect(() => {
		const on = () => setId(brandNow());
		window.addEventListener("brandchange", on);
		return () => window.removeEventListener("brandchange", on);
	}, []);
	return id;
}
// A logo's wordmark from its files, both grounds; the theme shows one.
function LogoArt({ id }) {
	const [day, night] = BRAND_LOGOS[id].logo;
	return (
		<span className={`logo logo--art logo--${id}`} role="img" aria-label="Lalaluxe">
			<img className="logo-day" src={`/images/brand/${id}/${day}`} alt="" draggable="false" />
			<img className="logo-night" src={`/images/brand/${id}/${night}`} alt="" draggable="false" />
		</span>
	);
}
// The wordmark. `fine` is the display cut, for sizes where hairlines can hold. `brand` draws a
// logo other than the one on the page (the console's picker).
function Logo({ fine = false, brand }) {
	const current = useBrand();
	const id = brand || current;
	if (id !== "classic") return <LogoArt id={id} />;
	const row = logoRow(fine ? LOGO_FINE : LOGO_TEXT, "LALALUXE", 13, 0);
	return (
		<svg className="logo" viewBox={`-2 -5 ${row.width + 8} 112`} role="img" aria-label="Lalaluxe">
			{row.nodes}
		</svg>
	);
}
// The mark on its own, where the full word cannot fit (the console's collapsed rail): the brushed X,
// or the picked logo's app icon.
function LogoX({ brand }) {
	const current = useBrand();
	const id = brand || current;
	if (id !== "classic") return <img className="logo logo--x logo--icon" src={`/images/brand/${id}/icon-192.png`} alt="Lalaluxe" draggable="false" />;
	return (
		<svg className="logo logo--x" viewBox="-6 -6 104 120" role="img" aria-label="Lalaluxe">
			<g className="logo-x">
				<path d={LOGO_X.a} />
				<path d={LOGO_X.b} />
			</g>
		</svg>
	);
}

/* ---------- The painting ---------- */
// Filters shared by the painted figure: a hand-drawn wobble for contours and a dragged-brush
// texture for colour fields. Rendered once at the app root.
function PaintDefs() {
	return (
		<svg className="paint-defs" aria-hidden="true">
			<defs>
				<filter id="paint-hand" x="-8%" y="-8%" width="116%" height="116%">
					<feTurbulence type="fractalNoise" baseFrequency="0.045" numOctaves="2" seed="5" result="w" />
					<feDisplacementMap in="SourceGraphic" in2="w" scale="1.7" xChannelSelector="R" yChannelSelector="G" />
				</filter>
				<filter id="paint-field" x="0" y="0" width="100%" height="100%">
					<feTurbulence type="fractalNoise" baseFrequency="0.004 0.11" numOctaves="3" seed="21" result="s" />
					<feColorMatrix in="s" type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 -2.2 1.34" result="a" />
					<feComposite in="SourceGraphic" in2="a" operator="in" />
				</filter>
				{/* a dry brush: bristle gaps along the drag, a worked edge */}
				<filter id="paint-drag" x="-4%" y="-30%" width="108%" height="160%">
					<feTurbulence type="fractalNoise" baseFrequency="0.0016 0.075" numOctaves="3" seed="8" result="s" />
					<feColorMatrix in="s" type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 -7 4.95" result="a" />
					<feComposite in="SourceGraphic" in2="a" operator="in" result="p" />
					<feTurbulence type="fractalNoise" baseFrequency="0.009" numOctaves="2" seed="3" result="w" />
					<feDisplacementMap in="p" in2="w" scale="18" xChannelSelector="R" yChannelSelector="G" />
				</filter>
			</defs>
		</svg>
	);
}

// The painting: one fingertip on a colour field, its nail growing with `ext`
// (free-edge length past the fingertip, in viewBox units). `marks` rules the lengths across the
// ground. Built the way a painter would block it in — a flat mid-tone, a cut shadow on the
// turned side, a plane of light, a few gestural marks, then the contour in ink.
// `look` adds what a service does to the nail, or what a piece of nail art puts on it (see
// ServiceIcon and ArtIcon), `shape` cuts the free edge, and `frame` crops the picture.
// What the nail is painted with for a look: [base, shaded side, stroke of light, shade strength].
const NAIL_FINISHES = {
	lacquer: ["var(--lacquer)", "var(--lacquer-shade)", "var(--lacquer-light)", 1],
	french: ["var(--lacquer-light)", "var(--lacquer)", "var(--chrome-light)", 0.6],
	frenchart: ["var(--lacquer-light)", "var(--lacquer)", "var(--chrome-light)", 0.6],
	cateye: ["var(--paint-berry)", "var(--art-ink)", "var(--lacquer)", 0.4],
	bling: ["var(--chrome)", "var(--chrome-shade)", "var(--chrome-light)", 0.7],
	ombre: ["var(--on-paint)", "var(--lacquer-light)", "var(--chrome-light)", 0.4],
	milkbath: ["var(--on-paint)", "var(--lacquer-light)", "var(--chrome-light)", 0.75],
	airbrush: ["var(--on-paint)", "var(--lacquer-light)", "var(--chrome-light)", 0.5],
	chrome: ["var(--chrome)", "var(--chrome-shade)", "var(--chrome-light)", 1],
	animal: ["var(--on-paint)", "var(--chrome)", "var(--chrome-light)", 0.45],
	// a nail with nothing on it yet: the bare nail, its outline dashed (Build your own's empty nail)
	bare: ["var(--nail-bare)", "var(--skin-shade)", "var(--nail-bare)", 0.3],
};
// The ground under every painted icon: two dragged passes over the colour field.
function PaintGround({ w = 300, h = 236 }) {
	return (
		<>
			<rect width={w} height={h} fill="#000" fillOpacity=".08" filter="url(#paint-field)" />
			<rect width={w} height={h} fill="#fff" fillOpacity=".1" filter="url(#paint-field)" transform={`translate(0 ${h}) scale(1 -1)`} />
		</>
	);
}
// How the free edge is cut: [corner radius, sidewall taper]. Almond, stiletto and round draw their own curve.
// Duck flares the other way: the free edge fans out past the sidewalls to a wide, square tip.
const NAIL_SHAPES = { square: [3, 0], coffin: [2.5, 9], almond: [6, 8], stiletto: [8, 9], round: [10, 0], duck: [2.5, 0] };
// how far each side of a duck tip reaches past the nail bed
const DUCK_FLARE = 6;
// Cow print: [across from the nail's centre, how far down it, turn°, size, outline].
const COW_BLOT = [
	"m-7-2c1-5 7-7 11-3 4 3 3 8-1 9-3 1-4 4-8 2-4-2-3-5-2-8z",
	"m-5-5c4-3 9-1 9 3 0 3-3 3-3 6 0 3-5 4-7 1-2-3-2-7 1-10z",
	"m-6 0c0-4 5-6 8-4 3 2 5 5 2 8-3 3-10 1-10-4z",
];
// Full bling: stones set edge to edge, each row offset from the last. [across from the centre, how far down]
const BLING_STONES = [0.08, 0.2, 0.32, 0.44, 0.56, 0.68, 0.8, 0.92].flatMap((p, row) => (row % 2 ? [-9, 0, 9] : [-13.5, -4.5, 4.5, 13.5]).map((dx) => [dx, p]));
const COW_PATCHES = [
	[13, 0.15, 0, 1.15, COW_BLOT[0]],
	[-11, 0.3, 0, 1.2, COW_BLOT[1]],
	[8, 0.48, 0, 1.25, COW_BLOT[2]],
	[-13, 0.65, 40, 1.05, COW_BLOT[0]],
	[12, 0.77, -30, 1.15, COW_BLOT[1]],
	[-2, 0.92, 0, 0.85, COW_BLOT[2]],
];
function HandStage({ ext, marks = [], label = "Nail length preview", look, shape, frame = "0 0 300 236" }) {
	const CX = 150, T = 114, BED = 50, NW = 38;
	const e = Math.max(0, ext);
	const f = (n) => Math.round(n * 100) / 100;
	const x = CX - NW / 2;
	const top = T + 4 - e; // free edge
	const cut = T + BED; // lowest point of the cuticle curve
	const c = NW * 0.3;
	const cutTo = NAIL_SHAPES[shape];
	const r = cutTo ? cutTo[0] : Math.max(3.2, 11 - e * 0.24); // soft square when short, crisp when long
	const t = cutTo ? cutTo[1] : Math.min(7, Math.max(0, (e - 10) * 0.085)); // sidewalls taper once there is length
	const yt = Math.max(T + 6, top + r); // straight over the nail bed, then the free edge
	const mid = (top + cut) / 2;
	const rise = yt - top;
	const fl = shape === "duck" ? DUCK_FLARE : 0;
	const xl = x - 3 - fl, xr = x + NW + 3 + fl; // the nail's full span, past either side, for what is painted across it
	const edge =
		shape === "duck" ? `C${x + NW} ${f(yt - rise * 0.3)} ${f(x + NW + fl * 0.7)} ${f(top + rise * 0.3)} ${x + NW + fl} ${f(top + r)}Q${x + NW + fl} ${f(top)} ${f(x + NW + fl - r)} ${f(top)}L${f(x - fl + r)} ${f(top)}Q${x - fl} ${f(top)} ${x - fl} ${f(top + r)}C${f(x - fl * 0.7)} ${f(top + rise * 0.3)} ${x} ${f(yt - rise * 0.3)} ${x} ${f(yt)}`
		: shape === "almond" ? `C${x + NW} ${f(yt - rise * 0.5)} ${CX + 11} ${f(top + 4)} ${CX} ${f(top)}C${CX - 11} ${f(top + 4)} ${x} ${f(yt - rise * 0.5)} ${x} ${f(yt)}`
		: shape === "stiletto" ? `C${x + NW - 0.5} ${f(yt - rise * 0.38)} ${CX + 5.5} ${f(top + 13)} ${CX + 1.3} ${f(top + 1.6)}Q${CX} ${f(top - 0.6)} ${CX - 1.3} ${f(top + 1.6)}C${CX - 5.5} ${f(top + 13)} ${x + 0.5} ${f(yt - rise * 0.38)} ${x} ${f(yt)}`
		: shape === "round" ? `C${x + NW} ${f(top + 3)} ${CX + 13} ${f(top)} ${CX} ${f(top)}C${CX - 13} ${f(top)} ${x} ${f(top + 3)} ${x} ${f(yt)}`
		: `L${f(x + NW - t)} ${f(top + r)}Q${f(x + NW - t)} ${f(top)} ${f(x + NW - t - r)} ${f(top)}L${f(x + t + r)} ${f(top)}Q${f(x + t)} ${f(top)} ${f(x + t)} ${f(top + r)}L${x} ${f(yt)}`;
	const nail = `M${x} ${f(cut - c)}C${x} ${f(cut + c * 0.5)} ${x + NW} ${f(cut + c * 0.5)} ${x + NW} ${f(cut - c)}L${x + NW} ${f(yt)}${edge}Z`;
	// one slender fingertip, a little asymmetric, the way a real one is
	const finger =
		`M121.5 252C121.5 238 119.5 ${T + 116} 120.5 ${T + 101}C121.5 ${T + 84} 124 ${T + 68} 123.5 ${T + 46}` +
		`C123 ${T + 17} 133.5 ${T} 149.8 ${T}C166.5 ${T} 177 ${T + 18} 176.5 ${T + 47}` +
		`C176 ${T + 68} 178.5 ${T + 84} 179.5 ${T + 101}C180.5 ${T + 116} 178.5 238 178.5 252Z`;
	// several paintings can share a page (the service list), so each keeps its own clip paths
	const id = "hs" + React.useId().replace(/[^a-zA-Z0-9]/g, "");
	const clip = (name) => `url(#${id}${name})`;
	// fill in: the grown-out gap above the cuticle, the cuticle's own curve lifted 15
	const gap = `M${x - 3} ${f(cut - c - 15)}C${x - 3} ${f(cut + c * 0.5 - 15)} ${x + NW + 3} ${f(cut + c * 0.5 - 15)} ${x + NW + 3} ${f(cut - c - 15)}`;
	// repair: where the nail has snapped
	const snapY = top + (cut - top) * 0.36;
	const snap = `M${x - 3} ${f(snapY + 3)}L${f(x + NW * 0.25)} ${f(snapY - 6)}L${CX} ${f(snapY + 4)}L${f(x + NW * 0.75)} ${f(snapY - 6)}L${x + NW + 3} ${f(snapY + 3)}`;
	const [paint, paintShade, paintLight, shadeStrength] = NAIL_FINISHES[look] || NAIL_FINISHES.lacquer;
	const ny = (p) => f(top + (cut - top) * p); // a point p of the way down the nail, tip to cuticle
	// a raised five-petal bloom, and a cut stone, set a point p of the way down the nail
	const bloom = (dx, p, size) => (
		<g key={"bloom" + p} stroke="var(--art-ink)" strokeLinejoin="round">
			{[0, 1, 2, 3, 4].map((k) => {
				const turn = ((-90 + 72 * k) * Math.PI) / 180;
				return <circle key={k} cx={f(CX + dx + Math.cos(turn) * size * 0.7)} cy={f(ny(p) + Math.sin(turn) * size * 0.7)} r={f(size * 0.6)} fill="var(--on-paint)" strokeWidth="1.4" />;
			})}
			<circle cx={CX + dx} cy={ny(p)} r={f(size * 0.4)} fill="var(--paint-ochre)" strokeWidth="1.3" />
		</g>
	);
	const stone = (dx, p, w, h) => (
		<g stroke="var(--art-ink)" strokeLinejoin="round">
			<path d={`M${CX + dx} ${f(ny(p) - h)}L${CX + dx + w} ${ny(p)}L${CX + dx} ${f(ny(p) + h)}L${CX + dx - w} ${ny(p)}Z`} fill="var(--chrome-light)" strokeWidth="1.5" />
			<path d={`M${CX + dx - w} ${ny(p)}H${CX + dx + w}M${CX + dx} ${f(ny(p) - h)}L${f(CX + dx - w * 0.4)} ${ny(p)}L${CX + dx} ${f(ny(p) + h)}L${f(CX + dx + w * 0.4)} ${ny(p)}Z`} fill="none" strokeWidth=".9" />
		</g>
	);
	const beads = (spots, r, fill) => (
		<g stroke="var(--art-ink)" strokeLinejoin="round">
			{spots.map(([dx, p], i) => <circle key={i} cx={CX + dx} cy={ny(p)} r={r} fill={fill} strokeWidth="1.15" />)}
		</g>
	);
	const lacquer = (
		<g>
			<path d={nail} fill={paint} />
			<g clipPath={clip("n")}>
				{/* french: the free edge left white, down to a smile line */}
				{(look === "french" || look === "frenchart" || look === "junk") && <path d={`M${xl} ${f(top - 6)}H${xr}V${ny(0.44)}Q${CX} ${ny(0.12)} ${xl} ${ny(0.44)}Z`} fill="var(--on-paint)" />}
				{/* ombré: colour fading from the tip down to nothing at the cuticle */}
				{look === "ombre" && <rect x={f(xl + 1)} y={f(top - 4)} width={f(xr - xl - 2)} height={f(cut - top + 12)} fill={clip("o")} />}
				{/* cat eye: a band of light drawn across dark polish by a magnet */}
				{look === "cateye" && <path d={`M${xl} ${ny(0.72)}L${xr} ${ny(0.34)}V${ny(0.52)}L${xl} ${ny(0.9)}Z`} fill="var(--lacquer)" fillOpacity=".7" />}
				{look === "cateye" && <path d={`M${xl} ${ny(0.8)}L${xr} ${ny(0.42)}`} fill="none" stroke="var(--lacquer-light)" strokeWidth="2.6" />}
				{/* the far side falls into shade */}
				<path d={`M${f(x + NW * 0.66)} ${f(top - 4)}H${f(xr + 1)}V${cut + 8}H${f(x + NW * 0.74)}C${f(x + NW * 0.82)} ${f(mid)} ${f(x + NW * 0.6)} ${f(mid - 10)} ${f(x + NW * 0.66)} ${f(top - 4)}Z`} fill={paintShade} fillOpacity={shadeStrength} />
				{/* airbrush: an aura of colour blown into the middle of the nail */}
				{look === "airbrush" && <rect x={f(xl + 1)} y={f(top - 4)} width={f(xr - xl - 2)} height={f(cut - top + 12)} fill={clip("g")} />}
				{/* one loaded stroke of light */}
				<path d={`M${f(x + NW * 0.2 + t * 0.5)} ${f(top + r + 3)}C${f(x + NW * 0.34 + t * 0.5)} ${f(top + r - 1)} ${f(x + NW * 0.4)} ${f(top + r + 6)} ${f(x + NW * 0.36)} ${f(mid)}C${f(x + NW * 0.33)} ${f(cut - c - 10)} ${f(x + NW * 0.3)} ${f(cut - c - 3)} ${f(x + NW * 0.22)} ${f(cut - c - 6)}C${f(x + NW * 0.14)} ${f(cut - c - 12)} ${f(x + NW * 0.2)} ${f(mid)} ${f(x + NW * 0.2 + t * 0.5)} ${f(top + r + 3)}Z`} fill={paintLight} />
				{/* milk bath: a milky swirl with petals and gold flake set into it */}
				{look === "milkbath" && (
					<g>
						<path d={`M${x + 7} ${ny(0.2)}C${CX + 12} ${ny(0.3)} ${x + 3} ${ny(0.48)} ${CX + 7} ${ny(0.68)}`} fill="none" stroke="var(--lacquer-light)" strokeOpacity=".75" strokeWidth="7" strokeLinecap="round" />
						{[[-7, 0.3, 24], [8, 0.46, -30], [-4, 0.62, 10], [7, 0.78, 40]].map(([dx, p, turn], i) => (
							<ellipse key={i} cx={CX + dx} cy={ny(p)} rx="3.5" ry="2.2" fill="var(--lacquer)" stroke="var(--art-ink)" strokeWidth=".9" transform={`rotate(${turn} ${CX + dx} ${ny(p)})`} />
						))}
						{[[5, 0.2], [-9, 0.5], [1, 0.84], [10, 0.62]].map(([dx, p], i) => <circle key={i} cx={CX + dx} cy={ny(p)} r="1.5" fill="var(--paint-ochre)" />)}
					</g>
				)}
				{/* full bling: stones over the whole nail, running off the edges */}
				{look === "bling" && beads(BLING_STONES, 3.4, "var(--chrome-light)")}
				{/* animal print: cow — black patches on white, running off the edges */}
				{look === "animal" && COW_PATCHES.map(([dx, p, turn, size, d], i) => (
					<path key={i} d={d} fill="var(--art-ink)" transform={`translate(${CX + dx} ${ny(p)}) rotate(${turn}) scale(${size})`} />
				))}
				{/* chrome: the room bent across a mirror */}
				{look === "chrome" && <path d={`M${f(xl + 1)} ${ny(0.42)}Q${CX} ${ny(0.6)} ${f(xr - 1)} ${ny(0.36)}V${ny(0.54)}Q${CX} ${ny(0.76)} ${f(xl + 1)} ${ny(0.6)}Z`} fill="var(--chrome-shade)" fillOpacity=".8" />}
				{look === "chrome" && <path d={`M${f(xl + 1)} ${ny(0.64)}Q${CX} ${ny(0.8)} ${f(xr - 1)} ${ny(0.58)}`} fill="none" stroke="var(--chrome-light)" strokeWidth="2.2" />}
				{/* gel: a wet band of gloss */}
				{look === "gel" && <path d={`M${f(xl + 1)} ${ny(0.2)}Q${CX} ${ny(0.04)} ${f(xr - 1)} ${ny(0.24)}V${ny(0.4)}Q${CX} ${ny(0.2)} ${f(xl + 1)} ${ny(0.36)}Z`} fill="var(--chrome-light)" fillOpacity=".72" />}
				{look === "fillin" && <path d={`${gap}V${cut + 10}H${xl}Z`} fill="var(--nail-bare)" />}
				{look === "fillin" && <path d={gap} fill="none" stroke="var(--art-ink)" strokeWidth="1.8" />}
			</g>
			<path d={nail} fill="none" stroke="var(--art-ink)" strokeWidth="2" strokeLinejoin="round" strokeDasharray={look === "bare" ? "5 4" : undefined} />
		</g>
	);
	const crack = <g clipPath={clip("n")}><path d={snap} fill="none" stroke="var(--art-ink)" strokeWidth="2" strokeLinejoin="round" /></g>;
	return (
		<svg className="hand" viewBox={frame} preserveAspectRatio="xMidYMin slice" {...(label ? { role: "img", "aria-label": label } : { "aria-hidden": true })}>
			<defs>
				<clipPath id={id + "f"}><path d={finger} /></clipPath>
				<clipPath id={id + "n"}><path d={nail} /></clipPath>
				{look === "repair" && <clipPath id={id + "l"}><path d={`${snap}V${cut + 12}H${x - 3}Z`} /></clipPath>}
				{look === "repair" && <clipPath id={id + "u"}><path d={`${snap}V${f(top - 8)}H${x - 3}Z`} /></clipPath>}
				{look === "ombre" && (
					<linearGradient id={id + "o"} gradientUnits="userSpaceOnUse" x1="0" y1={f(top)} x2="0" y2={f(cut)}>
						<stop offset="0" style={{ stopColor: "var(--paint-berry)" }} />
						<stop offset=".42" stopOpacity=".95" style={{ stopColor: "var(--lacquer)" }} />
						<stop offset=".86" stopOpacity="0" style={{ stopColor: "var(--lacquer-light)" }} />
					</linearGradient>
				)}
				{look === "airbrush" && (
					<radialGradient id={id + "g"} gradientUnits="userSpaceOnUse" cx={CX} cy={ny(0.46)} r={NW * 0.74}>
						<stop offset="0" stopOpacity=".95" style={{ stopColor: "var(--paint-berry)" }} />
						<stop offset=".5" stopOpacity=".9" style={{ stopColor: "var(--lacquer)" }} />
						<stop offset="1" stopOpacity="0" style={{ stopColor: "var(--lacquer-light)" }} />
					</radialGradient>
				)}
			</defs>
			<PaintGround />

			<g className="hand-ruler">
				{marks.map((m) => {
					const y = T + 4 - m.ext;
					return (
						<g key={m.id} className={m.on ? "on" : undefined}>
							<line x1="18" x2="282" y1={y} y2={y} />
							<text x="18" y={y - 5}>{m.label}</text>
						</g>
					);
				})}
			</g>

			<g filter="url(#paint-hand)">
				<path d={finger} fill="var(--skin)" />
				<g clipPath={clip("f")}>
					{/* shade: the turned-away side, cut like paper */}
					<path d={`M168.5 ${T + 2}C175 ${T + 22} 170.5 ${T + 42} 172.5 ${T + 64}C174.5 ${T + 88} 169.5 ${T + 106} 171.5 ${T + 132}L184 ${T + 132}L184 ${T}Z`} fill="var(--skin-shade)" />
					{/* light: a long warm plane down the lit side */}
					<path d={`M127 ${T + 50}C127.6 ${T + 38} 131.8 ${T + 31} 134.4 ${T + 37}C132.2 ${T + 60} 135.2 ${T + 82} 133 ${T + 104}C131.8 ${T + 116} 133.4 ${T + 126} 132.6 ${T + 134}L125.4 ${T + 134}C124 ${T + 108} 126.4 ${T + 78} 127 ${T + 50}Z`} fill="var(--skin-light)" />
					{/* the fingertip catches it */}
					<path d={`M130.5 ${T + 27}C134.5 ${T + 12} 142 ${T + 6} 150.5 ${T + 6.5}C143.3 ${T + 10} 137.6 ${T + 16} 134.2 ${T + 30}C132.9 ${T + 33} 129.8 ${T + 31} 130.5 ${T + 27}Z`} fill="var(--skin-glint)" />
					{/* a cool reflected edge */}
					<path d={`M175.2 ${T + 58}C176.5 ${T + 78} 177.8 ${T + 92} 178.2 ${T + 116}`} fill="none" stroke="var(--skin-cool)" strokeWidth="2.6" strokeLinecap="round" strokeOpacity=".85" />
					{/* gestural marks */}
					<path d={`M138 ${T + 74}c2.2 9 1.4 18 2.8 27`} fill="none" stroke="var(--skin-glint)" strokeWidth="2.8" strokeLinecap="round" strokeOpacity=".8" />
					<path d={`M160.5 ${T + 70}c1.5 8 0 15 2.2 24`} fill="none" stroke="var(--skin-shade)" strokeWidth="3.2" strokeLinecap="round" strokeOpacity=".7" />
					{/* knuckle: two confident tapered marks */}
					<path d={`M132 ${T + 95}Q150 ${T + 106} 169 ${T + 95}Q150 ${T + 101.5} 132 ${T + 95}Z`} fill="var(--art-ink)" />
					<path d={`M135.5 ${T + 105.5}Q150 ${T + 114} 165.5 ${T + 105.5}Q150 ${T + 110.2} 135.5 ${T + 105.5}Z`} fill="var(--art-ink)" fillOpacity=".8" />
					{/* the nail sits in the skin: fold shadow around it */}
					<path d={nail} fill="none" stroke="var(--skin-shade)" strokeWidth="7" strokeOpacity=".9" />
				</g>
				<path d={finger} fill="none" stroke="var(--art-ink)" strokeWidth="2.1" strokeLinejoin="round" />
			</g>

			{/* the nail is the one hard, straight thing in the picture: no wobble on it */}
			{look === "repair" ? (
				<g>
					<g clipPath={clip("l")}>{lacquer}</g>
					{crack}
					{/* the snapped end, knocked askew */}
					<g transform={`rotate(-13 ${CX} ${f(snapY)}) translate(-5 -9)`}>
						<g clipPath={clip("u")}>{lacquer}</g>
						{crack}
					</g>
					<path d={`M${x + NW + 13} ${f(snapY - 15)}l9-8M${x + NW + 17} ${f(snapY - 3)}h12M${x + NW + 9} ${f(snapY - 26)}l3-11`} fill="none" stroke="var(--art-ink)" strokeWidth="2.2" strokeLinecap="round" />
				</g>
			) : lacquer}
			{/* cuticle */}
			<path d={`M${x - 1} ${f(cut - c + 2)}C${x - 1} ${f(cut + c * 0.5 + 4)} ${x + NW + 1} ${f(cut + c * 0.5 + 4)} ${x + NW + 1} ${f(cut - c + 2)}`} fill="none" stroke="var(--skin-light)" strokeWidth="2.1" strokeLinecap="round" />
			{/* overlay: a second coat laid over the natural nail */}
			{look === "overlay" && (
				<g transform="translate(12 -21)">
					<path d={nail} fill="var(--lacquer-light)" fillOpacity=".86" stroke="var(--art-ink)" strokeWidth="2" strokeDasharray="5.5 5" strokeLinejoin="round" strokeLinecap="round" />
				</g>
			)}
			{/* gel: it shines */}
			{look === "gel" && (
				<g fill="var(--chrome-light)" stroke="var(--art-ink)" strokeWidth="1.2" strokeLinejoin="round">
					<path d={sparkPath(CX + 33, top + 6, 8.5)} />
					<path d={sparkPath(CX - 33, top + 30, 4.8)} />
				</g>
			)}
			{/* 3D flowers: raised blooms sitting on the lacquer */}
			{look === "flowers" && [[-1, 0.34, 11], [5, 0.7, 7.5]].map(([dx, p, size]) => bloom(dx, p, size))}
			{/* character art: a hand-painted face */}
			{look === "character" && (
				<g stroke="var(--art-ink)" strokeLinecap="round" strokeLinejoin="round">
					<circle cx={CX} cy={ny(0.4)} r="12.5" fill="var(--paint-ochre)" strokeWidth="1.9" />
					<ellipse cx={CX - 4.4} cy={f(ny(0.4) - 2.6)} rx="1.5" ry="2.3" fill="var(--art-ink)" stroke="none" />
					<ellipse cx={CX + 4.4} cy={f(ny(0.4) - 2.6)} rx="1.5" ry="2.3" fill="var(--art-ink)" stroke="none" />
					<path d={`M${CX - 6.2} ${f(ny(0.4) + 2.8)}Q${CX} ${f(ny(0.4) + 9.6)} ${CX + 6.2} ${f(ny(0.4) + 2.8)}`} fill="none" strokeWidth="1.9" />
				</g>
			)}
			{/* charms: a cut stone, gold studs, a row of pearls */}
			{look === "charms" && (
				<>
					{stone(0, 0.3, 7.5, 8.5)}
					{beads([[-8.5, 0.56], [8.5, 0.56], [0, 0.64]], 2.7, "var(--paint-ochre)")}
					{beads([[-7.5, 0.84], [0, 0.88], [7.5, 0.84]], 2.4, "var(--on-paint)")}
				</>
			)}
			{/* french with designs: a french tip, and a little painted on the bed under it */}
			{look === "frenchart" && (
				<g stroke="var(--art-ink)" strokeLinejoin="round">
					<path d={`M${CX} ${f(ny(0.7) + 6.5)}C${CX - 11} ${f(ny(0.7) - 2)} ${CX - 5} ${f(ny(0.7) - 9.5)} ${CX} ${f(ny(0.7) - 3.5)}C${CX + 5} ${f(ny(0.7) - 9.5)} ${CX + 11} ${f(ny(0.7) - 2)} ${CX} ${f(ny(0.7) + 6.5)}Z`} fill="var(--paint-berry)" strokeWidth="1.4" />
					{[[-9, 0.54], [9, 0.54], [0, 0.9]].map(([dx, p], i) => <circle key={i} cx={CX + dx} cy={ny(p)} r="1.7" fill="var(--paint-ochre)" strokeWidth="1" />)}
				</g>
			)}
			{/* junk nails: a little of everything on one nail — a french edge, a bloom, a stone, studs */}
			{look === "junk" && (
				<>
					{bloom(-4, 0.5, 8.5)}
					{stone(7, 0.74, 5.5, 6.5)}
					{beads([[-9, 0.78], [-3, 0.9]], 2.4, "var(--paint-ochre)")}
					{beads([[9, 0.32]], 2.2, "var(--on-paint)")}
				</>
			)}
			{/* chrome and full bling: they catch the light */}
			{(look === "chrome" || look === "bling") && (
				<g fill="var(--chrome-light)" stroke="var(--art-ink)" strokeWidth="1.2" strokeLinejoin="round">
					<path d={sparkPath(CX + 33, top + 20, 8.5)} />
					<path d={sparkPath(CX - 33, top + 54, 4.8)} />
				</g>
			)}
			{/* full set: new length, fresh */}
			{look === "fullset" && (
				<g fill="var(--paint-ochre)" stroke="var(--art-ink)" strokeWidth="1.2" strokeLinejoin="round">
					<path d={sparkPath(CX + 41, top + 16, 10)} />
					<path d={sparkPath(CX - 40, top + 44, 5.5)} />
				</g>
			)}
		</svg>
	);
}
// a four-point sparkle
function sparkPath(cx, cy, s) {
	const k = (n) => Math.round(n * 100) / 100;
	return `M${cx} ${k(cy - s)}C${k(cx + s * 0.16)} ${k(cy - s * 0.3)} ${k(cx + s * 0.3)} ${k(cy - s * 0.16)} ${k(cx + s)} ${cy}` +
		`C${k(cx + s * 0.3)} ${k(cy + s * 0.16)} ${k(cx + s * 0.16)} ${k(cy + s * 0.3)} ${cx} ${k(cy + s)}` +
		`C${k(cx - s * 0.16)} ${k(cy + s * 0.3)} ${k(cx - s * 0.3)} ${k(cy + s * 0.16)} ${k(cx - s)} ${cy}` +
		`C${k(cx - s * 0.3)} ${k(cy - s * 0.16)} ${k(cx - s * 0.16)} ${k(cy - s * 0.3)} ${cx} ${k(cy - s)}Z`;
}

/* ---------- Service icons: the same painting, cropped to the fingertip, showing what the service does ---------- */
// So nobody has to read: a long nail and a sparkle is new length; a gold band at the cuticle is the
// grown-out gap being filled; a second coat hovering over a short nail is an overlay; a snapped
// nail is a repair; a short round nail with a wet shine is gel polish. The value is each icon's
// nail length. Mirrors SERVICE_ICONS in lib/site-config.js.
const SERVICE_ICONS = { fullset: 56, fillin: 56, overlay: 6, repair: 44, gel: 10, plain: 30 };
function ServiceIcon({ kind }) {
	const look = SERVICE_ICONS[kind] === undefined ? "plain" : kind;
	return (
		<span className="svc-ico">
			<HandStage ext={SERVICE_ICONS[look]} look={look} shape={look === "gel" ? "round" : undefined} frame="95 50 110 131" label="" />
		</span>
	);
}

/* ---------- Nail art icons: the same painting, a little closer, wearing the art ---------- */
// A french tip is a white free edge, and with designs it carries a heart under it; cat eye is a
// band of light across dark polish; ombré fades from the tip; charms, 3D art and a face sit on the
// lacquer; chrome is a mirror; airbrush is an aura of colour; full bling is a nail paved in stones;
// junk nails wear a little of everything. Milk bath (a milky nail with petals in it) and animal
// print (cow) are drawn too, for a studio that offers them. `shape` cuts the nail the way the
// customer has chosen hers. Mirrors ART_ICONS in lib/site-config.js.
const ART_ICONS = ["french", "frenchart", "cateye", "ombre", "charms", "chrome", "flowers", "character", "airbrush", "bling", "junk", "milkbath", "animal", "plain"];
function ArtIcon({ kind, shape }) {
	return (
		<span className="svc-ico art-ico">
			<HandStage ext={48} look={kind === "bare" || ART_ICONS.includes(kind) ? kind : "plain"} shape={shape} frame="104 56 92 110" label="" />
		</span>
	);
}

/* ---------- Shape icons: the same nail, cut each way ---------- */
// For the look screen's shape picker: each cut and how long the nail is drawn at it. The cut is also
// what ArtIcon takes as `shape`. Which cut a shape wears is `content.shapeIcon[id]`, picked in the
// console; mirror SHAPE_ICONS in lib/site-config.js.
const SHAPE_ICONS = { square: 38, coffin: 46, almond: 46, stiletto: 56, round: 10, duck: 42 };
function ShapeIcon({ cut }) {
	const at = cut in SHAPE_ICONS ? cut : "square";
	return (
		<span className="svc-ico shape-ico">
			<HandStage ext={SHAPE_ICONS[at]} shape={at} frame="95 50 110 131" label="" />
		</span>
	);
}

/* ---------- Visit icons: a calendar page with one day ticked, or three ---------- */
// How many visits she is booking, without a word: a single appointment is one date, a plan is three.
const VISIT_DAYS = { cols: [38, 52, 66, 80], rows: [54, 67, 80], one: [[66, 67]], three: [[38, 54], [66, 67], [52, 80]] };
function VisitIcon({ count }) {
	const ticked = count === 1 ? VISIT_DAYS.one : VISIT_DAYS.three;
	const is = (x, y) => ticked.some(([tx, ty]) => tx === x && ty === y);
	return (
		<span className="svc-ico visit-ico">
			<svg className="hand" viewBox="0 0 120 110" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
				<PaintGround w={120} h={110} />
				<g filter="url(#paint-hand)" stroke="var(--art-ink)" strokeWidth="2.4" strokeLinejoin="round">
					<rect x="25" y="22" width="70" height="72" rx="3" fill="var(--on-paint)" />
					<path d="M25 42H95V25Q95 22 92 22H28Q25 22 25 25Z" fill="var(--paint-ochre)" />
					<path d="M43 14v14M77 14v14" fill="none" strokeWidth="3.4" strokeLinecap="round" />
				</g>
				{VISIT_DAYS.rows.map((y) => VISIT_DAYS.cols.map((x) => !is(x, y) && <circle key={x + "-" + y} cx={x} cy={y} r="2.1" fill="var(--art-ink)" fillOpacity=".5" />))}
				{ticked.map(([x, y]) => (
					<g key={x + "-" + y}>
						<circle cx={x} cy={y} r="7.6" fill="var(--lacquer)" stroke="var(--art-ink)" strokeWidth="1.8" />
						<path d={`M${x - 3.4} ${y + 0.2}l2.4 2.6 4.6-5.4`} fill="none" stroke="var(--on-paint)" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" />
					</g>
				))}
			</svg>
		</span>
	);
}

/* ---------- Toe icons: one big toe, close up, painted the same way ---------- */
// For the toes screen: sculpted acrylic is square and a touch long, gel is rounded with a wet shine,
// solid is the plain nail, french has the white free edge. One toe only, cropped close, the nail
// most of its width — the owner's call after trying a row of toes and a smaller nail.
// `art` paints a piece of nail art (one of ART_ICONS) on the toenail instead, for the toe art ladder,
// drawn as ArtIcon draws it on a finger but laid out for the short, wide nail of a big toe; "bare" is
// a toe built toe by toe that wears nothing yet, its nail bare and dashed. `base` cuts the nail as
// acrylic or gel under the art, for a toe built toe by toe.
const TOE_LOOKS = ["acrylic", "gel", "solid", "french"];
function ToeIcon({ kind, art, base }) {
	const pick = art === undefined ? null : art === "bare" || ART_ICONS.includes(art) ? art : "plain";
	const look = pick ? (pick === "french" || pick === "frenchart" || pick === "junk" ? "french" : "solid") : TOE_LOOKS.includes(kind) ? kind : "solid";
	const cut = TOE_LOOKS.slice(0, 2).includes(base) ? base : look;
	const acrylic = cut === "acrylic", gel = cut === "gel";
	const f = (n) => Math.round(n * 100) / 100;
	const id = "toe" + React.useId().replace(/[^a-zA-Z0-9]/g, "");
	const cx = 66, w = 96, tip = 24, x0 = cx - w / 2, x1 = cx + w / 2;
	// a toe is widest at the pad and rounds over at the tip
	const outline =
		`M${f(x0 + w * 0.05)} 176C${f(x0 - w * 0.02)} 152 ${f(x0 - w * 0.06)} ${f(tip + w * 0.86)} ${f(x0 - w * 0.02)} ${f(tip + w * 0.46)}` +
		`C${f(x0 + w * 0.03)} ${f(tip + w * 0.12)} ${f(x0 + w * 0.24)} ${tip} ${cx} ${tip}` +
		`C${f(x1 - w * 0.24)} ${tip} ${f(x1 - w * 0.03)} ${f(tip + w * 0.12)} ${f(x1 + w * 0.02)} ${f(tip + w * 0.46)}` +
		`C${f(x1 + w * 0.06)} ${f(tip + w * 0.86)} ${f(x1 + w * 0.02)} 152 ${f(x1 - w * 0.05)} 176`;
	const nw = w * 0.76, nh = nw * 0.86;
	const h = nh * (acrylic ? 1.1 : gel ? 0.88 : 1);
	const ny = tip + w * (acrylic ? 0.06 : gel ? 0.15 : 0.1), nx = cx - nw / 2;
	const r = gel ? nw * 0.3 : acrylic ? nw * 0.07 : nw * 0.13, c = nw * 0.26, flare = gel ? 0 : nw * 0.03;
	const nail =
		`M${f(nx)} ${f(ny + h - c)}C${f(nx)} ${f(ny + h + c * 0.5)} ${f(nx + nw)} ${f(ny + h + c * 0.5)} ${f(nx + nw)} ${f(ny + h - c)}` +
		`L${f(nx + nw + flare)} ${f(ny + r)}Q${f(nx + nw + flare)} ${f(ny)} ${f(nx + nw + flare - r)} ${f(ny)}` +
		`L${f(nx - flare + r)} ${f(ny)}Q${f(nx - flare)} ${f(ny)} ${f(nx - flare)} ${f(ny + r)}Z`;
	const crease = ny + h + w * 0.2;
	// the art, set out on the toenail: across from its centre (in finger-nail units, widened to this
	// nail) and a point p of the way down it, tip to cuticle
	const k = nw / 38, s = 1.45;
	const X = (dx) => f(cx + dx * k), Y = (p) => f(ny + h * p);
	const [paint, paintShade, paintLight, shadeStrength] = (look === "solid" && NAIL_FINISHES[pick]) || NAIL_FINISHES.lacquer;
	const bloom = (dx, p, size) => (
		<g key={"bloom" + p} stroke="var(--art-ink)" strokeLinejoin="round">
			{[0, 1, 2, 3, 4].map((n) => {
				const turn = ((-90 + 72 * n) * Math.PI) / 180;
				return <circle key={n} cx={f(X(dx) + Math.cos(turn) * size * 0.7)} cy={f(Y(p) + Math.sin(turn) * size * 0.7)} r={f(size * 0.6)} fill="var(--on-paint)" strokeWidth="1.4" />;
			})}
			<circle cx={X(dx)} cy={Y(p)} r={f(size * 0.4)} fill="var(--paint-ochre)" strokeWidth="1.3" />
		</g>
	);
	const stone = (dx, p, sw, sh) => (
		<g stroke="var(--art-ink)" strokeLinejoin="round">
			<path d={`M${X(dx)} ${f(Y(p) - sh)}L${f(X(dx) + sw)} ${Y(p)}L${X(dx)} ${f(Y(p) + sh)}L${f(X(dx) - sw)} ${Y(p)}Z`} fill="var(--chrome-light)" strokeWidth="1.5" />
			<path d={`M${f(X(dx) - sw)} ${Y(p)}H${f(X(dx) + sw)}M${X(dx)} ${f(Y(p) - sh)}L${f(X(dx) - sw * 0.4)} ${Y(p)}L${X(dx)} ${f(Y(p) + sh)}L${f(X(dx) + sw * 0.4)} ${Y(p)}Z`} fill="none" strokeWidth=".9" />
		</g>
	);
	const beads = (spots, rad, fill) => (
		<g stroke="var(--art-ink)" strokeLinejoin="round">
			{spots.map(([dx, p], i) => <circle key={i} cx={X(dx)} cy={Y(p)} r={rad} fill={fill} strokeWidth="1.15" />)}
		</g>
	);
	return (
		<span className="svc-ico toe-ico">
			<svg className="hand" viewBox="16 12 100 119" preserveAspectRatio="xMidYMin slice" aria-hidden="true">
				<defs>
					<clipPath id={id + "t"}><path d={outline + "Z"} /></clipPath>
					<clipPath id={id + "n"}><path d={nail} /></clipPath>
					{pick === "ombre" && (
						<linearGradient id={id + "o"} gradientUnits="userSpaceOnUse" x1="0" y1={f(ny)} x2="0" y2={f(ny + h)}>
							<stop offset="0" style={{ stopColor: "var(--paint-berry)" }} />
							<stop offset=".42" stopOpacity=".95" style={{ stopColor: "var(--lacquer)" }} />
							<stop offset=".86" stopOpacity="0" style={{ stopColor: "var(--lacquer-light)" }} />
						</linearGradient>
					)}
					{pick === "airbrush" && (
						<radialGradient id={id + "g"} gradientUnits="userSpaceOnUse" cx={cx} cy={Y(0.46)} r={f(nw * 0.6)}>
							<stop offset="0" stopOpacity=".95" style={{ stopColor: "var(--paint-berry)" }} />
							<stop offset=".5" stopOpacity=".9" style={{ stopColor: "var(--lacquer)" }} />
							<stop offset="1" stopOpacity="0" style={{ stopColor: "var(--lacquer-light)" }} />
						</radialGradient>
					)}
				</defs>
				<PaintGround w={132} h={157} />
				<g filter="url(#paint-hand)">
					<path d={outline + "Z"} fill="var(--skin)" />
					<g clipPath={`url(#${id}t)`}>
						{/* the turned side in shade, light down the other */}
						<path d={`M${f(x1 - w * 0.2)} ${tip - 4}C${f(x1 - w * 0.06)} ${f(tip + w * 0.3)} ${f(x1 - w * 0.12)} ${f(tip + w * 0.8)} ${f(x1 - w * 0.16)} 180H${f(x1 + w * 0.2)}V${tip - 4}Z`} fill="var(--skin-shade)" />
						<path d={`M${f(x0 + w * 0.1)} ${f(tip + w * 0.36)}C${f(x0 + w * 0.05)} ${f(tip + w * 0.7)} ${f(x0 + w * 0.1)} ${f(tip + w * 1.1)} ${f(x0 + w * 0.08)} 170`} fill="none" stroke="var(--skin-light)" strokeWidth={f(w * 0.075)} strokeLinecap="round" />
					</g>
					{/* the fold of skin the nail sits in, then the creases of the joint */}
					<path d={nail} fill="none" stroke="var(--skin-shade)" strokeWidth={f(w * 0.07)} strokeOpacity=".85" />
					<path d={`M${f(cx - w * 0.3)} ${f(crease)}Q${cx} ${f(crease + w * 0.1)} ${f(cx + w * 0.3)} ${f(crease)}`} fill="none" stroke="var(--art-ink)" strokeWidth="1.7" strokeLinecap="round" strokeOpacity=".75" />
					<path d={`M${f(cx - w * 0.22)} ${f(crease + w * 0.13)}Q${cx} ${f(crease + w * 0.2)} ${f(cx + w * 0.22)} ${f(crease + w * 0.13)}`} fill="none" stroke="var(--art-ink)" strokeWidth="1.4" strokeLinecap="round" strokeOpacity=".5" />
					<path d={outline} fill="none" stroke="var(--art-ink)" strokeWidth="2.2" strokeLinejoin="round" strokeLinecap="round" />
				</g>
				{/* the nail is the one hard, straight thing in the picture: no wobble on it */}
				<path d={nail} fill={look === "french" ? "var(--on-paint)" : paint} />
				<g clipPath={`url(#${id}n)`}>
					{/* french: pink behind a smile line, the free edge left white */}
					{look === "french" && <path d={`M${f(nx - 3)} ${f(ny + h + 6)}V${f(ny + h * 0.6)}Q${cx} ${f(ny - h * 0.1)} ${f(nx + nw + 3)} ${f(ny + h * 0.6)}V${f(ny + h + 6)}Z`} fill="var(--lacquer)" />}
					{/* ombré: colour fading from the tip down to nothing at the cuticle */}
					{pick === "ombre" && <rect x={f(nx - 4)} y={f(ny - 4)} width={f(nw + 8)} height={f(h + 12)} fill={`url(#${id}o)`} />}
					{/* cat eye: a band of light drawn across dark polish by a magnet */}
					{pick === "cateye" && <path d={`M${f(nx - 3)} ${Y(0.74)}L${f(nx + nw + 3)} ${Y(0.3)}V${Y(0.5)}L${f(nx - 3)} ${Y(0.94)}Z`} fill="var(--lacquer)" fillOpacity=".7" />}
					{pick === "cateye" && <path d={`M${f(nx - 3)} ${Y(0.84)}L${f(nx + nw + 3)} ${Y(0.4)}`} fill="none" stroke="var(--lacquer-light)" strokeWidth="3.4" />}
					<path d={`M${f(nx + nw * 0.72)} ${f(ny + (look === "french" ? h * 0.5 : -4))}H${f(nx + nw + 6)}V${f(ny + h + 6)}H${f(nx + nw * 0.78)}Z`} fill={paintShade} fillOpacity={look === "french" ? 0.8 : shadeStrength} />
					{/* airbrush: an aura of colour blown into the middle of the nail */}
					{pick === "airbrush" && <rect x={f(nx - 4)} y={f(ny - 4)} width={f(nw + 8)} height={f(h + 12)} fill={`url(#${id}g)`} />}
					<path d={`M${f(nx + nw * 0.2)} ${f(ny + (look === "french" ? h * 0.52 : r + 2.5))}V${f(ny + h * (look === "french" ? 0.76 : 0.68))}`} stroke={look === "french" ? "var(--lacquer-light)" : paintLight} strokeWidth={f(nw * (look === "french" ? 0.1 : 0.13))} strokeLinecap="round" />
					{/* milk bath: a milky swirl with petals and gold flake set into it */}
					{pick === "milkbath" && (
						<g>
							<path d={`M${f(nx + 10)} ${Y(0.18)}C${X(14)} ${Y(0.3)} ${f(nx + 6)} ${Y(0.5)} ${X(8)} ${Y(0.74)}`} fill="none" stroke="var(--lacquer-light)" strokeOpacity=".75" strokeWidth="10" strokeLinecap="round" />
							{[[-8, 0.3, 24], [9, 0.44, -30], [-4, 0.62, 10], [8, 0.78, 40]].map(([dx, p, turn], i) => (
								<ellipse key={i} cx={X(dx)} cy={Y(p)} rx="5" ry="3.2" fill="var(--lacquer)" stroke="var(--art-ink)" strokeWidth=".9" transform={`rotate(${turn} ${X(dx)} ${Y(p)})`} />
							))}
							{[[5, 0.2], [-10, 0.5], [1, 0.86], [12, 0.62]].map(([dx, p], i) => <circle key={i} cx={X(dx)} cy={Y(p)} r="2" fill="var(--paint-ochre)" />)}
						</g>
					)}
					{/* full bling: stones over the whole nail, running off the edges */}
					{pick === "bling" && beads(BLING_STONES, 4.2, "var(--chrome-light)")}
					{/* animal print: cow — black patches on white, running off the edges */}
					{pick === "animal" && COW_PATCHES.map(([dx, p, turn, size, d], i) => (
						<path key={i} d={d} fill="var(--art-ink)" transform={`translate(${X(dx)} ${Y(p)}) rotate(${turn}) scale(${f(size * s)})`} />
					))}
					{/* chrome: the room bent across a mirror */}
					{pick === "chrome" && <path d={`M${f(nx - 2)} ${Y(0.38)}Q${cx} ${Y(0.6)} ${f(nx + nw + 2)} ${Y(0.32)}V${Y(0.52)}Q${cx} ${Y(0.78)} ${f(nx - 2)} ${Y(0.58)}Z`} fill="var(--chrome-shade)" fillOpacity=".8" />}
					{pick === "chrome" && <path d={`M${f(nx - 2)} ${Y(0.66)}Q${cx} ${Y(0.84)} ${f(nx + nw + 2)} ${Y(0.6)}`} fill="none" stroke="var(--chrome-light)" strokeWidth="2.8" />}
					{/* gel: a wet band of gloss */}
					{gel && <path d={`M${f(nx - 3)} ${f(ny + h * 0.22)}Q${cx} ${f(ny + h * 0.04)} ${f(nx + nw + 3)} ${f(ny + h * 0.26)}V${f(ny + h * 0.46)}Q${cx} ${f(ny + h * 0.24)} ${f(nx - 3)} ${f(ny + h * 0.42)}Z`} fill="var(--chrome-light)" fillOpacity=".75" />}
				</g>
				<path d={nail} fill="none" stroke="var(--art-ink)" strokeWidth="2" strokeLinejoin="round" strokeDasharray={pick === "bare" ? "5 4" : undefined} />
				{/* 3D flowers: raised blooms sitting on the lacquer */}
				{pick === "flowers" && [[-6, 0.36, 15], [8, 0.72, 10]].map(([dx, p, size]) => bloom(dx, p, size))}
				{/* character art: a hand-painted face */}
				{pick === "character" && (
					<g stroke="var(--art-ink)" strokeLinecap="round" strokeLinejoin="round">
						<circle cx={cx} cy={Y(0.48)} r="17" fill="var(--paint-ochre)" strokeWidth="1.9" />
						<ellipse cx={cx - 6} cy={f(Y(0.48) - 3.5)} rx="2" ry="3.1" fill="var(--art-ink)" stroke="none" />
						<ellipse cx={cx + 6} cy={f(Y(0.48) - 3.5)} rx="2" ry="3.1" fill="var(--art-ink)" stroke="none" />
						<path d={`M${cx - 8.4} ${f(Y(0.48) + 3.8)}Q${cx} ${f(Y(0.48) + 13)} ${cx + 8.4} ${f(Y(0.48) + 3.8)}`} fill="none" strokeWidth="1.9" />
					</g>
				)}
				{/* charms: a cut stone, gold studs, a row of pearls */}
				{pick === "charms" && (
					<>
						{stone(0, 0.3, 10, 11.5)}
						{beads([[-10, 0.58], [10, 0.58], [0, 0.66]], 3.6, "var(--paint-ochre)")}
						{beads([[-8, 0.86], [0, 0.9], [8, 0.86]], 3.2, "var(--on-paint)")}
					</>
				)}
				{/* french with designs: a french tip, and a little painted on the bed under it */}
				{pick === "frenchart" && (
					<g stroke="var(--art-ink)" strokeLinejoin="round">
						<path d={`M${cx} ${f(Y(0.74) + 9)}C${cx - 15} ${f(Y(0.74) - 3)} ${cx - 7} ${f(Y(0.74) - 13)} ${cx} ${f(Y(0.74) - 5)}C${cx + 7} ${f(Y(0.74) - 13)} ${cx + 15} ${f(Y(0.74) - 3)} ${cx} ${f(Y(0.74) + 9)}Z`} fill="var(--paint-berry)" strokeWidth="1.4" />
						{[[-10, 0.62], [10, 0.62], [-6, 0.92], [6, 0.92]].map(([dx, p], i) => <circle key={i} cx={X(dx)} cy={Y(p)} r="2.3" fill="var(--paint-ochre)" strokeWidth="1" />)}
					</g>
				)}
				{/* junk nails: a little of everything on one nail — a french edge, a bloom, a stone, studs */}
				{pick === "junk" && (
					<>
						{bloom(-6, 0.62, 12)}
						{stone(8, 0.72, 7.5, 9)}
						{beads([[-11, 0.9], [2, 0.92]], 3.2, "var(--paint-ochre)")}
						{beads([[10, 0.24]], 3, "var(--on-paint)")}
					</>
				)}
				{(gel || pick === "chrome" || pick === "bling") && (
					<g fill="var(--chrome-light)" stroke="var(--art-ink)" strokeWidth="1.1" strokeLinejoin="round">
						<path d={sparkPath(106, 23, 7)} />
						<path d={sparkPath(26, 27, 4)} />
					</g>
				)}
			</svg>
		</span>
	);
}

/* ---------- The wall: what hangs either side of the page on a wide screen ---------- */
// One loaded brush pass — the mark that underlines a headline — stretched to w × h.
const BRUSH_PASS = "M4 13C3 8 8 5 16 6c44-3 104-1 154-1.5 40-.5 80 1 113-.5 7-.2 13 1 12 3-1 1.6-9 1.4-16 2 7 .6 14 1.5 13 3.4-1 1.6-11 1-20 1.2 6 .8 12 2 11 3.4-1.5 1.8-13 .6-25 .4-58-.4-138 2.2-198 1.6-20-.2-40 1.5-50-.5-4-.9-5.5-2.5-6-5.5Z";
function brushPass(w, h) {
	let i = 0;
	return BRUSH_PASS.replace(/-?\d*\.?\d+/g, (n) => Math.round(Number(n) * (i++ % 2 ? h / 24 : w / 300) * 10) / 10);
}
// The logo's brushed X at the scale of the room: two passes cross behind the page, so each wall
// shows two arms. [centre x, centre y, length, width, lean°, paint] on a 1440 × 900 wall.
const WALL_PASSES = [
	[704, 474, 1780, 236, -33, "var(--paint-rose)"],
	[742, 426, 1720, 150, 31, "var(--paint-ochre)"],
];
function WallArt() {
	return (
		<div className="wall" aria-hidden="true">
			<svg viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice">
				{WALL_PASSES.map(([cx, cy, w, h, lean, paint], i) => (
					<path
						key={i}
						d={brushPass(w, h)}
						fill={paint}
						filter="url(#paint-drag)"
						transform={`translate(${cx} ${cy}) rotate(${lean}) translate(${-w / 2} ${-h / 2})`}
						style={{ animationDelay: 0.15 + i * 0.25 + "s" }}
					/>
				))}
			</svg>
		</div>
	);
}
