// Lalaluxe booking — components/intro.jsx (split from app.jsx; load before app.jsx — see CLAUDE.md "multi-file Babel contract")
function Intro({ cfg, onStart }) {
	const GALLERY = getGallery(cfg);
	const [lightbox, setLightbox] = useState(null);
	const trackRef = useRef(null);
	const closeRef = useRef(null);
	const gestureRef = useRef({
		x0: 0,
		y0: 0,
		locked: null,
		dx: 0,
		animating: false,
	});

	const nextImg = useCallback(
		() => setLightbox((i) => (i + 1) % GALLERY.length),
		[GALLERY.length],
	);
	const prevImg = useCallback(
		() => setLightbox((i) => (i - 1 + GALLERY.length) % GALLERY.length),
		[GALLERY.length],
	);

	useEffect(() => {
		if (lightbox === null) return;
		const onKey = (e) => {
			if (e.key === "Escape") setLightbox(null);
			else if (e.key === "ArrowRight") nextImg();
			else if (e.key === "ArrowLeft") prevImg();
		};
		window.addEventListener("keydown", onKey);
		return () => window.removeEventListener("keydown", onKey);
	}, [lightbox, nextImg, prevImg]);

	// Modal contract (keyed on open/closed, not the image index): move focus into
	// the dialog, lock the page scroller behind the scrim, restore both on close.
	const open = lightbox !== null;
	useEffect(() => {
		if (!open) return;
		const opener = document.activeElement;
		closeRef.current && closeRef.current.focus();
		const wrap = document.querySelector(".screen-wrap");
		const prevOverflow = wrap ? wrap.style.overflowY : "";
		if (wrap) wrap.style.overflowY = "hidden";
		return () => {
			if (wrap) wrap.style.overflowY = prevOverflow;
			opener && opener.focus && opener.focus();
		};
	}, [open]);

	// Trap Tab inside the dialog (focusables queried at keydown time)
	const onDialogKeyDown = (e) => {
		if (e.key !== "Tab") return;
		const f = e.currentTarget.querySelectorAll("button");
		if (!f.length) return;
		const first = f[0],
			last = f[f.length - 1];
		if (e.shiftKey && document.activeElement === first) {
			e.preventDefault();
			last.focus();
		} else if (!e.shiftKey && document.activeElement === last) {
			e.preventDefault();
			first.focus();
		}
	};

	// Reset track position whenever the active image changes
	useEffect(() => {
		if (lightbox === null || !trackRef.current) return;
		trackRef.current.style.transition = "none";
		trackRef.current.style.transform = "translate3d(-33.3333%, 0, 0)";
		// force reflow so subsequent transitions work
		void trackRef.current.offsetWidth;
	}, [lightbox]);

	const onTouchStart = (e) => {
		if (gestureRef.current.animating) return;
		const t = e.touches[0];
		gestureRef.current = {
			x0: t.clientX,
			y0: t.clientY,
			locked: null,
			dx: 0,
			animating: false,
		};
		if (trackRef.current) trackRef.current.style.transition = "none";
	};
	const onTouchMove = (e) => {
		const g = gestureRef.current;
		if (g.animating) return;
		const t = e.touches[0];
		const dx = t.clientX - g.x0;
		const dy = t.clientY - g.y0;
		if (g.locked === null) {
			if (Math.abs(dx) > 6 || Math.abs(dy) > 6) {
				g.locked = Math.abs(dx) > Math.abs(dy) ? "x" : "y";
			}
		}
		if (g.locked === "x") {
			if (e.cancelable) e.preventDefault();
			g.dx = dx;
			if (trackRef.current) {
				const w = trackRef.current.parentElement.clientWidth;
				const pct = -33.3333 + (dx / (w * 3)) * 100;
				trackRef.current.style.transform = `translate3d(${pct}%, 0, 0)`;
			}
		}
	};
	const onTouchEnd = () => {
		const g = gestureRef.current;
		if (!trackRef.current) return;
		if (g.locked !== "x") {
			gestureRef.current = {
				x0: 0,
				y0: 0,
				locked: null,
				dx: 0,
				animating: false,
			};
			return;
		}
		const w = trackRef.current.parentElement.clientWidth;
		const threshold = Math.min(60, w * 0.18);
		const tr = trackRef.current;
		tr.style.transition = "transform 0.32s cubic-bezier(0.22, 0.8, 0.28, 1)";

		if (g.dx < -threshold) {
			g.animating = true;
			tr.style.transform = "translate3d(-66.6666%, 0, 0)";
			const done = () => {
				tr.removeEventListener("transitionend", done);
				tr.style.transition = "none";
				tr.style.transform = "translate3d(-33.3333%, 0, 0)";
				nextImg();
				gestureRef.current = {
					x0: 0,
					y0: 0,
					locked: null,
					dx: 0,
					animating: false,
				};
			};
			tr.addEventListener("transitionend", done);
		} else if (g.dx > threshold) {
			g.animating = true;
			tr.style.transform = "translate3d(0%, 0, 0)";
			const done = () => {
				tr.removeEventListener("transitionend", done);
				tr.style.transition = "none";
				tr.style.transform = "translate3d(-33.3333%, 0, 0)";
				prevImg();
				gestureRef.current = {
					x0: 0,
					y0: 0,
					locked: null,
					dx: 0,
					animating: false,
				};
			};
			tr.addEventListener("transitionend", done);
		} else {
			tr.style.transform = "translate3d(-33.3333%, 0, 0)";
			gestureRef.current = {
				x0: 0,
				y0: 0,
				locked: null,
				dx: 0,
				animating: false,
			};
		}
	};

	const prevIdx =
		lightbox === null ? 0 : (lightbox - 1 + GALLERY.length) % GALLERY.length;
	const nextIdx = lightbox === null ? 0 : (lightbox + 1) % GALLERY.length;

	return (
		<div className="screen hero-screen" data-screen-label="Landing">
			<section className="hero">
				<div className="hero__bar">
					<ThemeToggle />
				</div>

				<span className="hero__edge-label" aria-hidden="true">
					Nails Reimagined
				</span>

				<div className="hero__top">
					<h1 className="wordmark">
						<span className="roman">Lala</span>
						<span className="italic">luxe</span>
					</h1>
					<p className="tagline">Nails for girls that don't blend in.</p>
					<button className="cta startBtn" onClick={onStart}>
						<span className="startBtn__label">start booking</span>
						<span className="startBtn__arrow" aria-hidden="true"></span>
					</button>
				</div>

				<div className="hero__photo">
					<span className="hero__arch" aria-hidden="true"></span>
					<img
						src="images/hero-elements/new-base.png"
						alt="Hands with custom long nail art resting on braided hair"
					/>
				</div>

				<RecentWork gallery={GALLERY} onOpen={setLightbox} title="Recent Sets" />
			</section>

			{lightbox !== null && (
				<div
					className="lightbox"
					onClick={() => setLightbox(null)}
					onKeyDown={onDialogKeyDown}
					role="dialog"
					aria-modal="true"
					aria-label={GALLERY[lightbox].label + " — enlarged photo"}
				>
					<button
						className="lb-close"
						ref={closeRef}
						onClick={(e) => {
							e.stopPropagation();
							setLightbox(null);
						}}
						aria-label="Close photo"
					>
						×
					</button>
					<div className="lb-stage" onClick={(e) => e.stopPropagation()}>
						<div
							className="lb-viewport"
							onTouchStart={onTouchStart}
							onTouchMove={onTouchMove}
							onTouchEnd={onTouchEnd}
							onTouchCancel={onTouchEnd}
						>
							<div className="lb-track" ref={trackRef}>
								<div className="lb-slide">
									<img
										className="lb-img"
										src={GALLERY[prevIdx].src}
										alt=""
										draggable={false}
									/>
								</div>
								<div className="lb-slide">
									<img
										className="lb-img"
										src={GALLERY[lightbox].src}
										alt={GALLERY[lightbox].label}
										draggable={false}
									/>
								</div>
								<div className="lb-slide">
									<img
										className="lb-img"
										src={GALLERY[nextIdx].src}
										alt=""
										draggable={false}
									/>
								</div>
							</div>
						</div>
						<div className="lb-nav">
							<button className="lb-arrow" onClick={prevImg} aria-label="Previous look">
								‹
							</button>
							<div className="lb-count" aria-live="polite">
								{GALLERY[lightbox].label}
								<span className="sr-only">
									{` — ${lightbox + 1} of ${GALLERY.length}`}
								</span>
								<span className="dots" aria-hidden="true">
									{GALLERY.map((_, i) => (
										<span
											key={i}
											className={"d " + (i === lightbox ? "on" : "")}
										></span>
									))}
								</span>
							</div>
							<button className="lb-arrow" onClick={nextImg} aria-label="Next look">
								›
							</button>
						</div>
					</div>
				</div>
			)}
		</div>
	);
}

/* ---------- Visit step ---------- */
