function useFadeIn(ref) {
	React.useEffect(() => {
		const el = ref.current;
		if (!el) return;
		const io = new IntersectionObserver((entries) => {
			entries.forEach(e => { if (e.isIntersecting) { el.classList.add('in'); io.disconnect(); } });
		}, { threshold: 0.08 });
		io.observe(el);
		return () => io.disconnect();
	}, [ref]);
}

function SectionHeader({ eyebrow, title, note }) {
	const ref = React.useRef(null);
	useFadeIn(ref);
	return (
		<div ref={ref} className="fade-up" style={{
			display: 'grid', gridTemplateColumns: '1fr 1fr', alignItems: 'end', gap: 40,
			borderBottom: '1px solid var(--divider)', paddingBottom: 28,
		}}>
			<div>
				<div className="mono-mini" style={{ marginBottom: 18 }}>{eyebrow}</div>
				<h2 className="display" style={{
					margin: 0, fontSize: 'clamp(44px, 6.5vw, 88px)',
					lineHeight: 0.95, fontWeight: 700, letterSpacing: '-0.04em',
				}}>
					{title}
				</h2>
			</div>
			{note && (
				<p style={{ margin: 0, color: 'var(--fg-soft)', fontSize: 15, maxWidth: 420, justifySelf: 'end', textAlign: 'right' }}>
					{note}
				</p>
			)}
		</div>
	);
}

function Gallery() {
	const [lightbox, setLightbox] = React.useState(null);
	const scrollerRef = React.useRef(null);
	const baseWorks = window.WORKS;
	const loop = [...baseWorks, ...baseWorks, ...baseWorks];
	const N = baseWorks.length;

	const openAt = (i) => setLightbox(i % N);
	const close = () => setLightbox(null);
	const prevLb = (e) => { e?.stopPropagation(); setLightbox(i => (i - 1 + N) % N); };
	const nextLb = (e) => { e?.stopPropagation(); setLightbox(i => (i + 1) % N); };

	React.useEffect(() => {
		if (lightbox === null) return;
		const onKey = (e) => {
			if (e.key === 'Escape') close();
			if (e.key === 'ArrowLeft') prevLb();
			if (e.key === 'ArrowRight') nextLb();
		};
		window.addEventListener('keydown', onKey);
		return () => window.removeEventListener('keydown', onKey);
	}, [lightbox]);

	const centerOnMiddle = React.useCallback(() => {
		const el = scrollerRef.current;
		if (!el) return;
		const panels = el.querySelectorAll('.h-cell');
		if (!panels.length) return;
		const target = panels[N];
		if (!target) return;
		const center = target.offsetLeft - (el.clientWidth - target.offsetWidth) / 2;
		el.scrollLeft = center;
	}, [N]);

	React.useEffect(() => {
		const t = setTimeout(centerOnMiddle, 60);
		window.addEventListener('resize', centerOnMiddle);
		return () => { clearTimeout(t); window.removeEventListener('resize', centerOnMiddle); };
	}, [centerOnMiddle]);

	React.useEffect(() => {
		const el = scrollerRef.current;
		if (!el) return;
		let rafId;
		const onScroll = () => {
			if (rafId) return;
			rafId = requestAnimationFrame(() => {
				rafId = null;
				const panels = Array.from(el.querySelectorAll('.h-cell'));
				if (!panels.length) return;


				const firstMidLeft = panels[N]?.offsetLeft ?? 0;
				const firstLastCopyLeft = panels[N * 2]?.offsetLeft ?? 0;
				const copyWidth = firstLastCopyLeft - firstMidLeft;
				if (copyWidth > 0) {
					if (el.scrollLeft < firstMidLeft - copyWidth * 0.5) el.scrollLeft += copyWidth;
					else if (el.scrollLeft > firstLastCopyLeft + copyWidth * 0.5) el.scrollLeft -= copyWidth;
				}

				const vpCenter = window.innerWidth / 2;
				let nearest = 0, nearestDist = Infinity;
				panels.forEach((p, i) => {
					const r = p.getBoundingClientRect();
					const center = r.left + r.width / 2;
					const dist = Math.abs(center - vpCenter);
					if (dist < nearestDist) { nearestDist = dist; nearest = i; }
					const offset = (center - vpCenter) / window.innerWidth;
					const img = p.querySelector('img');
					if (img) img.style.transform = `translate3d(${-offset * 36}px, 0, 0)`;
				});
				panels.forEach((p, i) => p.classList.toggle('active', i === nearest));
			});
		};
		// Delay initial highlight until after centerOnMiddle's 60ms timeout settles
		const initT = setTimeout(onScroll, 80);
		el.addEventListener('scroll', onScroll, { passive: true });
		return () => { clearTimeout(initT); el.removeEventListener('scroll', onScroll); };
	}, [N]);

	const scrollByDir = (dir) => {
		const el = scrollerRef.current;
		if (!el) return;
		const panels = Array.from(el.querySelectorAll('.h-cell'));
		if (!panels.length) return;
		const vpCenter = window.innerWidth / 2;
		let nearestIdx = 0, nearestDist = Infinity;
		panels.forEach((p, i) => {
			const r = p.getBoundingClientRect();
			const c = r.left + r.width / 2;
			const d = Math.abs(c - vpCenter);
			if (d < nearestDist) { nearestDist = d; nearestIdx = i; }
		});
		// Always target within middle copy to avoid loop-correction jumps
		const nearestSlot = nearestIdx % N;
		const targetSlot = ((nearestSlot + dir) % N + N) % N;
		const target = panels[N + targetSlot];
		if (!target) return;
		el.scrollTo({ left: target.offsetLeft + target.offsetWidth / 2 - el.clientWidth / 2, behavior: 'smooth' });
	};

	return (
		<section id="work" style={{ padding: '100px 0', position: 'relative', overflow: 'hidden' }}>
			<div className="h-wrap" style={{ position: 'relative' }}>
				<div ref={scrollerRef} className="h-scroller">
					<div className="h-spacer-l"/>
					{loop.map((w, i) => (
						<HCell key={i} work={w} index={i % N} onOpen={() => openAt(i)}/>
					))}
					<div className="h-spacer-r"/>
				</div>

				<button aria-label="Previous" onClick={() => scrollByDir(-1)} className="h-nav h-nav-l">
					<svg width="22" height="22" viewBox="0 0 22 22" fill="none"><path d="M14 4L7 11L14 18" stroke="currentColor" strokeWidth="1.8" strokeLinecap="square" strokeLinejoin="miter"/></svg>
				</button>
				<button aria-label="Next" onClick={() => scrollByDir(1)} className="h-nav h-nav-r">
					<svg width="22" height="22" viewBox="0 0 22 22" fill="none"><path d="M8 4L15 11L8 18" stroke="currentColor" strokeWidth="1.8" strokeLinecap="square" strokeLinejoin="miter"/></svg>
				</button>
			</div>

			{lightbox !== null && (
				<div role="dialog" aria-modal="true" onClick={close}
					style={{
						position: 'fixed', inset: 0, zIndex: 100,
						background: 'rgba(6,8,16,0.94)', backdropFilter: 'blur(6px)',
						display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40,
					}}>
					<button aria-label="Close" onClick={close} style={lbBtn(20, 20)}>✕</button>
					<button aria-label="Previous" onClick={prevLb} style={lbBtn('auto', 24, 'left')}>‹</button>
					<button aria-label="Next" onClick={nextLb} style={lbBtn('auto', 24, 'right')}>›</button>
					<figure onClick={e => e.stopPropagation()} style={{ margin: 0, maxWidth: 'min(1400px, 92vw)', maxHeight: '88vh' }}>
						<img src={baseWorks[lightbox].src} alt={baseWorks[lightbox].title}
							style={{ width: '100%', maxHeight: '84vh', objectFit: 'contain' }}/>
						<figcaption className="mono-mini" style={{ color: 'rgba(255,255,255,0.55)', marginTop: 14, textAlign: 'center' }}>
							{lightbox + 1} / {N}
						</figcaption>
					</figure>
				</div>
			)}

			<style>{`
				.h-scroller {
					display: flex; align-items: center; gap: 14px;
					overflow-x: auto; overflow-y: hidden; scroll-behavior: auto;
					padding: 40px 0 56px;
					-webkit-overflow-scrolling: touch; scrollbar-width: none;
					user-select: none; overscroll-behavior-x: contain;
				}
				.h-scroller::-webkit-scrollbar { display: none; }
				.h-spacer-l, .h-spacer-r { flex: 0 0 30vw; }
				@media (max-width: 720px) { .h-spacer-l, .h-spacer-r { flex: 0 0 12vw; } }

				.h-cell {
					flex: 0 0 auto; height: 62vh; min-height: 420px; max-height: 720px;
					position: relative; cursor: pointer; overflow: hidden;
					transition: opacity .5s ease, transform .5s cubic-bezier(.2,.7,.2,1);
					opacity: 0.5; display: flex; align-items: center; justify-content: center;
				}
				.h-cell.active { opacity: 1; transform: translateY(-6px); }
				.h-cell img {
					height: 100%; width: auto; max-width: none; display: block;
					object-fit: contain; transition: transform .1s linear, filter .5s ease; will-change: transform;
				}
				.h-cell:not(.active) img { filter: saturate(0.6) brightness(0.68); }

				.h-cell-num {
					position: absolute; top: 12px; left: 12px; z-index: 2;
					font-family: ui-monospace, Menlo, monospace; font-size: 11px; letter-spacing: 0.14em;
					color: rgba(255,255,255,0.88); width: 28px; height: 28px; border-radius: 999px;
					border: 1px solid rgba(255,255,255,0.45);
					display: flex; align-items: center; justify-content: center;
					background: rgba(0,0,0,0.25); backdrop-filter: blur(6px);
				}
				.h-cell-meta {
					position: absolute; left: 16px; right: 16px; bottom: 16px; z-index: 2;
					color: #fff; display: flex; flex-direction: column; gap: 4px;
					text-shadow: 0 2px 20px rgba(0,0,0,0.6); pointer-events: none;
					opacity: 0; transform: translateY(8px); transition: opacity .4s ease, transform .4s ease;
				}
				.h-cell.active .h-cell-meta { opacity: 1; transform: none; }
				.h-cell-title {
					font-family: 'Space Grotesk', sans-serif; font-weight: 700;
					letter-spacing: -0.03em; font-size: 22px; line-height: 1.05;
				}
				.h-cell-sub {
					font-family: ui-monospace, Menlo, monospace; font-size: 10.5px;
					letter-spacing: 0.14em; color: rgba(255,255,255,0.82); text-transform: uppercase;
				}
				@media (max-width: 900px) { .h-cell { height: 54vh; min-height: 360px; } }

				.h-nav {
					position: absolute; top: 50%; transform: translateY(-50%);
					width: 64px; height: 64px; border-radius: 999px;
					background: var(--bg); color: var(--fg); border: 1.5px solid var(--fg);
					cursor: pointer; display: flex; align-items: center; justify-content: center;
					z-index: 5; transition: background .2s ease, color .2s ease, transform .2s ease, box-shadow .2s ease;
					box-shadow: 0 10px 30px -10px rgba(0,0,0,0.35);
				}
				.h-nav:hover { background: var(--fg); color: var(--bg); transform: translateY(-50%) scale(1.06); }
				.h-nav:active { transform: translateY(-50%) scale(0.98); }
				.h-nav-l { left: 36px; }
				.h-nav-r { right: 36px; }
				@media (max-width: 720px) {
					.h-nav { width: 52px; height: 52px; }
					.h-nav-l { left: 16px; } .h-nav-r { right: 16px; }
				}
			`}</style>
		</section>
	);
}

function HCell({ work, index, onOpen }) {
	return (
		<figure
			className="h-cell"
			onClick={onOpen}
			tabIndex={0}
			aria-label={work.title}
			onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onOpen()}
			style={{ margin: 0 }}
		>
			<img src={work.src} alt={work.title} loading="lazy"/>
			<div className="h-cell-num">{String(index + 1).padStart(2, '0')}</div>
			<figcaption className="h-cell-meta">
				<div className="h-cell-sub">{work.year}</div>
				<div className="h-cell-title">{work.title}</div>
			</figcaption>
		</figure>
	);
}

function lbBtn(top, side, edge) {
	const s = {
		position: 'absolute',
		top: top === 'auto' ? '50%' : top, transform: top === 'auto' ? 'translateY(-50%)' : 'none',
		background: 'rgba(255,255,255,0.08)', color: '#fff',
		border: '1px solid rgba(255,255,255,0.18)', width: 44, height: 44, borderRadius: 999,
		fontSize: 20, cursor: 'pointer', zIndex: 2,
	};
	if (edge === 'left') s.left = 24;
	else if (edge === 'right') s.right = 24;
	else s.right = 24;
	return s;
}

window.Gallery = Gallery;
window.SectionHeader = SectionHeader;
window.useFadeIn = useFadeIn;
