// ============================================================
// Beyond the Falls - TOP sections: Hero · About · MouseTrail
// ============================================================
const { useEffect: useEffectT, useRef: useRefT, useState: useStateT } = React;

// ---- shared top nav ---------------------------------------
function TopNav() {
  const links = [['Home','home'],['World','worlds'],['Story','synopsis'],['Cast','characters'],['Contact','contact']];
  const [scrolled, setScrolled] = useStateT(false);
  const [active, setActive] = useStateT('home');

  useEffectT(() => {
    const onScroll = () => setScrolled(window.scrollY > 40);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  useEffectT(() => {
    const ids = links.map(l => l[1]);
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
    }, { rootMargin: '-45% 0px -50% 0px', threshold: 0 });
    ids.forEach(id => { const el = document.getElementById(id); if (el) obs.observe(el); });
    return () => obs.disconnect();
  }, []);

  return (
    <header className={`fixed top-0 inset-x-0 z-50 transition-all duration-500 ${scrolled ? 'liquid-glass-scrolled' : 'liquid-glass-top'}`}>
      <div className="max-w-7xl mx-auto flex items-center justify-between px-6 md:px-8 py-3.5">
        <a href="#home" className="flex items-center gap-3 group shrink-0" aria-label="Beyond the Falls - home">
          <window.BTFEye className={`w-6 h-6 shrink-0 transition ${scrolled ? 'text-leaf' : 'text-biolum'}`}/>
          <window.BTFLogo className={`w-auto transition ${scrolled ? 'text-ink' : 'text-white/90 group-hover:text-white'}`} style={{ height: 30 }}/>
        </a>
        <nav className={`hidden md:flex items-center gap-1 rounded-full border px-2 py-2 transition-colors ${scrolled ? 'border-ink/10 liquid-pill' : 'border-white/15 liquid-pill-dark'}`}>
          {links.map(([l,h]) => {
            const isActive = active === h;
            return (
              <a key={l} href={`#${h}`}
                 className={`px-4 py-1.5 rounded-full text-[12px] tracking-wide font-medium transition
                   ${isActive
                     ? (scrolled ? 'bg-ink text-off' : 'bg-white text-ink')
                     : (scrolled ? 'text-ink/70 hover:text-ink hover:bg-ink/10' : 'text-white/80 hover:text-white hover:bg-white/10')}`}>{l}</a>
            );
          })}
        </nav>
        <div className="flex items-center gap-3 shrink-0">
          <a href="/studio"
             className={`group inline-flex items-center gap-2 rounded-full px-4 py-2 text-[12px] font-semibold tracking-wide transition
               ${scrolled ? 'bg-ink text-off hover:bg-leafdk' : 'bg-biolum text-ink hover:bg-acid'}`}>
            Enter the Studio
            <window.Glyph.arrow className="w-3.5 h-3.5 -rotate-45 group-hover:rotate-0 transition"/>
          </a>
        </div>
      </div>
    </header>
  );
}

// ============================================================
// 1) HERO
// ============================================================
function Hero() {
  const wrapRef = useRefT(null);
  const logoRef = useRefT(null);
  const m1 = useRefT(null), m2 = useRefT(null), m3 = useRefT(null);
  // magic-glow gradient on the front wordmark
  const gradRef = useRefT(null), gs0 = useRefT(null), gs1 = useRefT(null), gs2 = useRefT(null);
  const magic = useRefT({ tx: 670, ty: 218, cx: 670, cy: 218, act: 0, tact: 0, t: 0 });

  useEffectT(() => {
    const wrap = wrapRef.current, logo = logoRef.current;
    if (!wrap || !logo) return;
    const { hslF, lerpF } = window.fairyUtil;
    const BASE = [244, 243, 238]; // #F4F3EE
    let raf = 0, tx = 0, ty = 0, cx = 0, cy = 0;
    const onMove = (e) => {
      const r = wrap.getBoundingClientRect();
      tx = (e.clientX - r.left) / r.width - 0.5;
      ty = (e.clientY - r.top) / r.height - 0.5;
      // drifting meta corners
      if (m1.current) m1.current.style.transform = `translate(${tx*-16}px, ${ty*-16}px)`;
      if (m2.current) m2.current.style.transform = `translate(${tx*16}px, ${ty*-12}px)`;
      if (m3.current) m3.current.style.transform = `translate(${tx*10}px, ${ty*18}px)`;
      // map cursor into the wordmark's SVG user space (viewBox 1340x436)
      const lr = logo.getBoundingClientRect();
      const m = magic.current;
      m.tx = ((e.clientX - lr.left) / lr.width) * 1340;
      m.ty = ((e.clientY - lr.top) / lr.height) * 436;
      m.tact = 1;
    };
    const onLeave = () => { magic.current.tact = 0; };
    const mk = (hue, l, act) => {
      const c = hslF(hue, 0.92, l);
      return `rgb(${Math.round(lerpF(BASE[0], c[0], act))},${Math.round(lerpF(BASE[1], c[1], act))},${Math.round(lerpF(BASE[2], c[2], act))})`;
    };
    const tick = () => {
      cx += (tx - cx) * 0.08; cy += (ty - cy) * 0.08;
      logo.style.transform = `rotateY(${(cx*18).toFixed(2)}deg) rotateX(${(-cy*10).toFixed(2)}deg)`;
      // magic glow follows + decays
      const m = magic.current;
      m.cx += (m.tx - m.cx) * 0.16; m.cy += (m.ty - m.cy) * 0.16;
      m.act += (m.tact - m.act) * 0.05;
      if (m.act > 0.01) m.t += 0.012;
      if (gradRef.current) {
        gradRef.current.setAttribute('cx', m.cx.toFixed(1));
        gradRef.current.setAttribute('cy', m.cy.toFixed(1));
      }
      const h0 = 160 + 75 * Math.sin(m.t);
      const h1 = 120 + 60 * Math.sin(m.t * 0.8 + 1.7);
      if (gs0.current) gs0.current.setAttribute('stop-color', mk(h0, 0.64, m.act));
      if (gs1.current) gs1.current.setAttribute('stop-color', mk(h1, 0.72, m.act));
      if (gs2.current) gs2.current.setAttribute('stop-color', '#F4F3EE');
      raf = requestAnimationFrame(tick);
    };
    wrap.addEventListener('mousemove', onMove);
    wrap.addEventListener('mouseleave', onLeave);
    raf = requestAnimationFrame(tick);
    return () => { wrap.removeEventListener('mousemove', onMove); wrap.removeEventListener('mouseleave', onLeave); cancelAnimationFrame(raf); };
  }, []);

  const heroMagicDefs = (
    <defs>
      <radialGradient ref={gradRef} id="heroMagicGrad" gradientUnits="userSpaceOnUse" cx="670" cy="218" r="300">
        <stop ref={gs0} offset="0" stopColor="#F4F3EE"/>
        <stop ref={gs1} offset="0.5" stopColor="#F4F3EE"/>
        <stop ref={gs2} offset="1" stopColor="#F4F3EE"/>
      </radialGradient>
    </defs>
  );

  const depthLayers = Array.from({ length: 14 }).map((_, i) => {
    const z = -(i + 1) * 3;
    const shade = 6 + i * 3.4;
    return (
      <window.BTFLogo key={i} className="absolute inset-0 w-full h-auto" style={{
        transform: `translateZ(${z}px)`,
        color: `rgb(${shade}, ${Math.min(shade+8,42)}, ${Math.min(shade+4,30)})`,
        filter: i === 13 ? 'drop-shadow(0 26px 42px rgba(0,0,0,.7))' : 'none',
      }}/>
    );
  });

  return (
    <section id="home" ref={wrapRef} className="hero-bg grain relative min-h-screen text-off overflow-hidden" data-screen-label="01 Hero">

      <div ref={m1} className="absolute top-28 left-8 z-10 text-[11px] font-mono tracking-[0.18em] uppercase text-white/55 hidden md:block will-change-transform">
        <div>Fantasy AI series</div>
      </div>
      <div ref={m2} className="absolute top-28 right-8 z-10 text-[11px] font-mono tracking-[0.18em] uppercase text-white/55 text-right hidden md:block will-change-transform">
        <div>FOR YOUNG TEENS</div>
      </div>

      <window.HeroWorldGrid />

      <div className="logo3d-wrap absolute inset-0 z-20 flex items-center justify-center px-6 pointer-events-none">
        <div ref={logoRef} className="logo3d relative" style={{ width: 'min(78vw, 820px)', marginTop: '-3vh' }}>
          {depthLayers}
          <window.BTFLogo className="relative w-full h-auto" fill="url(#heroMagicGrad)" defs={heroMagicDefs} style={{ filter: 'drop-shadow(0 1px 0 rgba(255,255,255,.3))' }}/>
        </div>
      </div>


      <div className="absolute left-1/2 z-30 script-text text-biolum pointer-events-none"
           style={{ top: 'calc(50% - min(17vw, 175px))', fontSize: 'clamp(28px, 4.4vw, 64px)', transform: 'translate(-50%, -100%) rotate(-4deg)' }}>
        a journey to yourself
      </div>

      <div ref={m3} className="absolute bottom-10 inset-x-0 px-8 z-10 will-change-transform">
        <div className="max-w-7xl mx-auto flex flex-wrap items-end justify-between gap-6">
          <div className="max-w-md text-white/75 text-[15px] leading-relaxed">
            In a universe where magic is the living voice of nature, young students learn to hear their own inner voice - and restore a broken cycle of existence.
          </div>
          <div className="flex flex-wrap items-center gap-3">
            <window.Magnetic as="a" href="/studio" strength={0.4} data-magnet
               className="group inline-flex items-center gap-2 rounded-full bg-biolum text-ink px-5 py-3 text-[13px] font-semibold hover:bg-acid transition">
              Enter the Studio
              <window.Glyph.arrow className="w-4 h-4 -rotate-45 group-hover:rotate-0 transition"/>
            </window.Magnetic>
            <window.Magnetic as="a" href="#synopsis" strength={0.4} data-magnet
               className="inline-flex items-center gap-2 rounded-full border border-white/20 text-white/90 px-5 py-3 text-[13px] font-medium hover:bg-white/10 transition">
              Read the story
            </window.Magnetic>
            <window.Magnetic as="a" href="#worlds" strength={0.4} data-magnet
               className="inline-flex items-center gap-2 rounded-full border border-white/20 text-white/90 px-5 py-3 text-[13px] font-medium hover:bg-white/10 transition">
              Enter the world
            </window.Magnetic>
          </div>
        </div>
        <div className="hairline-dark mt-8"/>
        <div className="max-w-7xl mx-auto mt-4 flex items-center justify-between text-[10px] font-mono tracking-[0.2em] uppercase text-white/45">
          <span>Scroll · Down</span>
          <span>WIZARD ELEMENT STUDIO</span>
          <span>Balance · Not power</span>
        </div>
      </div>
    </section>
  );
}

// ============================================================
// 2) ABOUT - logline + Technology + concept cards
// ============================================================
function About() {
  const [open, setOpen] = useStateT(null);
  const spot = window.useSpotlight('rgba(124,255,203,.16)', 720);
  const tech = window.TECHNOLOGY;
  return (
    <section id="about" ref={spot} className="spotlight bg-off text-ink px-6 md:px-8 pt-28 pb-24 relative overflow-hidden" data-screen-label="02 About">
      <div className="absolute inset-0 pointer-events-none" style={{ background: 'radial-gradient(820px 520px at 6% 0%, rgba(124,255,203,.20), transparent 58%), radial-gradient(720px 560px at 102% 26%, rgba(198,255,74,.16), transparent 58%), radial-gradient(760px 620px at 64% 110%, rgba(14,156,107,.16), transparent 60%)' }}/>
      <div className="max-w-7xl mx-auto relative">
        <div className="flex items-center gap-2 font-mono text-[11px] tracking-[0.2em] uppercase text-leaf reveal">
          <window.BTFEye className="w-[10px] h-[10px] text-leaf shrink-0"/> Production
        </div>
        <h2 className="mt-6 font-display font-medium tracking-tight reveal reveal-delay-1"
            style={{ fontSize: 'clamp(32px, 4.4vw, 64px)', lineHeight: 1.04, letterSpacing: '-0.02em', textWrap: 'pretty' }}>
          Magic here is not a weapon, but a way of <span className="script-text" style={{ fontSize: '1.12em', lineHeight: .7, color: '#0E9C6B' }}>knowing</span> - and the real threat is a system that sells <span className="font-semibold" style={{ background: 'linear-gradient(transparent 60%, #C6FF4A 60%)', paddingInline: '.04em' }}>fast success</span> and the <span className="font-semibold" style={{ color: '#0E9C6B' }}>refusal to think</span>.
        </h2>

        {/* Technology (left) + concept cards (right) */}
        <div className="mt-16 grid grid-cols-1 lg:grid-cols-12 gap-3 items-stretch">
          <div className="lg:col-span-4 reveal reveal-delay-2">
            <TechnologyCard c={tech} onOpen={() => setOpen(tech)} />
          </div>
          <div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-2 gap-3">
            {window.CONCEPTS.map((c, i) => (
              <ConceptCard key={c.key} c={c} idx={i + 1} onOpen={() => setOpen(c)} />
            ))}
          </div>
        </div>
      </div>

      {open && <ConceptModal c={open} onClose={() => setOpen(null)} />}
    </section>
  );
}

function TechnologyCard({ c, onOpen }) {
  return (
    <window.Tilt max={6}
      className="rounded-2xl overflow-hidden relative cursor-pointer group h-full min-h-[420px] lg:min-h-full"
      style={{ background: '#0A0A0A', color: '#F4F3EE' }}>
      <button onClick={onOpen} className="text-left w-full h-full p-8 flex flex-col justify-between focus:outline-none">
        <div>
          <div className="flex items-center justify-between text-[10px] font-mono tracking-[0.2em] uppercase text-white/55">
            <span>{c.tag}</span><span>01</span>
          </div>
          <div className="mt-8 font-display font-bold tracking-tight" style={{ fontSize: 'clamp(36px, 4vw, 52px)', lineHeight: .95 }}>
            {c.title}
          </div>
          <div className="mt-4 script-text text-biolum" style={{ fontSize: 'clamp(22px, 2.4vw, 30px)', transform: 'rotate(-3deg)', transformOrigin: 'left center' }}>
            {c.script}
          </div>
          <p className="mt-6 text-[14px] leading-relaxed text-white/70 max-w-sm">{c.short}</p>
        </div>
        <div className="mt-8">
          <div className="flex flex-wrap gap-2 mb-6">
            {(c.facts || []).map(f => (
              <span key={f} className="rounded-full border border-white/15 px-3 py-1 text-[10px] font-mono tracking-[0.14em] uppercase text-biolum/90">{f}</span>
            ))}
          </div>
          <div className="inline-flex items-center gap-2 text-[11px] font-mono tracking-[0.16em] uppercase text-white/80 group-hover:gap-3 transition-all">
            Read more <window.Glyph.arrow className="w-4 h-4 -rotate-45 text-biolum"/>
          </div>
        </div>
      </button>
    </window.Tilt>
  );
}

const CONCEPT_THEMES = [
  { bg: '#062016', fg: '#F4F3EE', accent: '#7CFFCB' },
  { bg: '#7CFFCB', fg: '#06140F', accent: '#062016' },
  { bg: '#0E9C6B', fg: '#F4F3EE', accent: '#C6FF4A' },
];
function ConceptCard({ c, idx, onOpen }) {
  const t = CONCEPT_THEMES[idx % CONCEPT_THEMES.length];
  return (
    <window.Tilt max={7}
      className={`reveal reveal-delay-${(idx%4)+1} rounded-2xl overflow-hidden relative cursor-pointer group`}
      style={{ background: t.bg, color: t.fg }}>
      <button onClick={onOpen} className="text-left w-full h-full p-7 min-h-[200px] flex flex-col justify-between focus:outline-none">
        <div className="flex items-center justify-between text-[10px] font-mono tracking-[0.2em] uppercase opacity-70">
          <span>{c.tag}</span><span>0{idx+1}</span>
        </div>
        <div>
          <div className="font-display font-bold tracking-tight" style={{ fontSize: 'clamp(26px,2.4vw,34px)', lineHeight: 1 }}>{c.title}</div>
          <div className="mt-2 text-[13px] opacity-75 leading-snug">{c.short}</div>
          <div className="mt-4 inline-flex items-center gap-2 text-[11px] font-mono tracking-[0.16em] uppercase opacity-90 group-hover:gap-3 transition-all">
            Read more <window.Glyph.arrow className="w-4 h-4 -rotate-45" style={{ color: t.accent }}/>
          </div>
        </div>
      </button>
    </window.Tilt>
  );
}

function ConceptModal({ c, onClose }) {
  return (
    <window.Modal onClose={onClose} accent="#7CFFCB" bg="#062016" fg="#F4F3EE"
      tag={c.tag} title={c.title} script={c.script} file={c.file || `/about/${c.key}.md`}>
      {c.body && (
        <div className="space-y-4 max-w-2xl text-[15px] leading-relaxed" style={{ color: '#F4F3EEcc' }}>
          {c.body.map((p, i) => <p key={i}>{p}</p>)}
        </div>
      )}
      {c.list && (
        <div className="grid md:grid-cols-2 gap-3">
          {c.list.map(([t, d], i) => (
            <div key={i} className="rounded-2xl p-5 border" style={{ borderColor: '#F4F3EE22', background: '#F4F3EE08' }}>
              <div className="flex items-start gap-2">
                <window.Glyph.spark className="w-4 h-4 mt-0.5 shrink-0 text-biolum"/>
                <div>
                  <div className="font-display font-semibold" style={{ fontSize: 17 }}>{t}</div>
                  <div className="mt-1 text-[13.5px] leading-snug" style={{ color: '#F4F3EEb0' }}>{d}</div>
                </div>
              </div>
            </div>
          ))}
        </div>
      )}
      {c.facts && (
        <div className="mt-6 flex flex-wrap gap-2">
          {c.facts.map(f => <window.Pill key={f}>{f}</window.Pill>)}
        </div>
      )}
    </window.Modal>
  );
}

// ============================================================
// 3) MOUSE TRAIL interstitial
// Brand-green logo with a soft, magical iridescent shimmer that follows the
// cursor - painted as the SVG fill, so the color can never spill past the letters.
function LiquidLogo() {
  const wrapRef = useRefT(null);
  const gradRef = useRefT(null);
  const s0 = useRefT(null), s1 = useRefT(null), s2 = useRefT(null);
  const st = useRefT({ tx: 0.5, ty: 0.5, cx: 0.5, cy: 0.5, act: 0, tact: 0, t: 0 });

  useEffectT(() => {
    const wrap = wrapRef.current; if (!wrap) return;
    const sec = wrap.closest('section') || wrap;
    const svg = wrap.querySelector('svg');

    const onMove = (e) => {
      const r = svg.getBoundingClientRect();
      const s = st.current;
      s.tx = (e.clientX - r.left) / r.width;
      s.ty = (e.clientY - r.top) / r.height;
      s.tact = 1;
    };
    const onLeave = () => { st.current.tact = 0; };
    sec.addEventListener('mousemove', onMove);
    sec.addEventListener('mouseleave', onLeave);

    const GREEN = [124, 255, 203]; // #7CFFCB
    const lerp = (a, b, t) => a + (b - a) * t;
    const hsl = (h, s, l) => {
      h = ((h % 360) + 360) % 360; const c = (1 - Math.abs(2 * l - 1)) * s;
      const x = c * (1 - Math.abs(((h / 60) % 2) - 1)); const m = l - c / 2;
      let r = 0, g = 0, b = 0;
      if (h < 60) [r, g, b] = [c, x, 0]; else if (h < 120) [r, g, b] = [x, c, 0];
      else if (h < 180) [r, g, b] = [0, c, x]; else if (h < 240) [r, g, b] = [0, x, c];
      else if (h < 300) [r, g, b] = [x, 0, c]; else [r, g, b] = [c, 0, x];
      return [(r + m) * 255, (g + m) * 255, (b + m) * 255];
    };

    let raf = 0;
    const tick = () => {
      const s = st.current;
      s.cx += (s.tx - s.cx) * 0.07;
      s.cy += (s.ty - s.cy) * 0.07;
      s.act += (s.tact - s.act) * 0.045;
      if (s.act > 0.01) s.t += 0.005; // only drift while colourful

      if (gradRef.current) {
        gradRef.current.setAttribute('cx', (s.cx * 1340).toFixed(1));
        gradRef.current.setAttribute('cy', (s.cy * 436).toFixed(1));
      }
      const mk = (hue, l) => {
        const c = hsl(hue, 0.92, l);
        return `rgb(${Math.round(lerp(GREEN[0], c[0], s.act))},${Math.round(lerp(GREEN[1], c[1], s.act))},${Math.round(lerp(GREEN[2], c[2], s.act))})`;
      };
      // gentle iridescence - greens → cyans → soft blue, on-brand & magical
      const h0 = 168 + 48 * Math.sin(s.t);
      const h1 = 150 + 42 * Math.sin(s.t * 0.8 + 2.1);
      if (s0.current) s0.current.setAttribute('stop-color', mk(h0, 0.80));
      if (s1.current) s1.current.setAttribute('stop-color', mk(h1, 0.73));
      // outer stop always settles to brand green
      if (s2.current) s2.current.setAttribute('stop-color', 'rgb(124,255,203)');
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => { cancelAnimationFrame(raf); sec.removeEventListener('mousemove', onMove); sec.removeEventListener('mouseleave', onLeave); };
  }, []);

  const defs = (
    <defs>
      <radialGradient ref={gradRef} id="liquidLogoGrad" gradientUnits="userSpaceOnUse" cx="670" cy="218" r="470">
        <stop ref={s0} offset="0" stopColor="#7CFFCB"/>
        <stop ref={s1} offset="0.45" stopColor="#7CFFCB"/>
        <stop ref={s2} offset="1" stopColor="#7CFFCB"/>
      </radialGradient>
    </defs>
  );
  return (
    <div ref={wrapRef} className="w-full max-w-[980px]">
      <window.BTFLogo fill="url(#liquidLogoGrad)" defs={defs} className="w-full h-auto select-none" style={{ filter: 'drop-shadow(0 0 26px rgba(124,255,203,.16))' }}/>
    </div>
  );
}

// ============================================================
const TRAIL_FRAMES = (window.CHAR_GROUPS || []).flatMap((g) =>
  (g.people || [])
    .filter((p) => p.img)
    .map((p) => ({
      img: p.img,
      label: String(p.name || '').toUpperCase(),
      bg: g.bg || '#062016',
      fg: g.accent || '#7CFFCB',
    }))
);

function MouseTrail() {
  const sectionRef = useRefT(null);
  const lastSpawn = useRefT(0);
  const idRef = useRefT(0);
  const [items, setItems] = useStateT([]);
  const frames = TRAIL_FRAMES.length
    ? TRAIL_FRAMES
    : [{ img: '/beyond-the-falls/uploads/hero/div.webp', label: 'DIV', bg: '#062016', fg: '#7CFFCB' }];

  useEffectT(() => {
    const el = sectionRef.current; if (!el) return;
    const onMove = (e) => {
      const now = performance.now();
      if (now - lastSpawn.current < 90) return;
      lastSpawn.current = now;
      const r = el.getBoundingClientRect();
      const id = ++idRef.current;
      const f = frames[id % frames.length];
      setItems(prev => [...prev, { id, x: e.clientX - r.left, y: e.clientY - r.top, frame: f }]);
      setTimeout(() => setItems(prev => prev.filter(p => p.id !== id)), 1200);
    };
    el.addEventListener('mousemove', onMove);
    return () => el.removeEventListener('mousemove', onMove);
  }, []);

  return (
    <section ref={sectionRef} className="relative bg-off text-ink overflow-hidden cursor-none" style={{ minHeight: '85vh' }} data-screen-label="03 Faces">
      <div className="max-w-7xl mx-auto px-8 pt-16 flex items-center justify-between text-[11px] font-mono tracking-[0.2em] uppercase text-ink/55">
        <span className="inline-flex items-center gap-1.5"><window.BTFEye className="w-[10px] h-[10px] text-noble"/> Faces</span>
        <span>Move your cursor</span>
      </div>
      <div className="absolute inset-0 flex items-center justify-center pointer-events-none px-10">
        <LiquidLogo/>
      </div>
      {items.map(it => <TrailItem key={it.id} item={it} />)}
      <div className="absolute bottom-8 inset-x-0 px-8 max-w-7xl mx-auto flex items-end justify-between text-[11px] font-mono tracking-[0.2em] uppercase text-ink/55">
        <span>Cast trail</span><span>{frames.length} faces</span>
      </div>
    </section>
  );
}

function TrailItem({ item }) {
  const [show, setShow] = useStateT(false);
  useEffectT(() => {
    const t = setTimeout(() => setShow(true), 10);
    const t2 = setTimeout(() => setShow(false), 800);
    return () => { clearTimeout(t); clearTimeout(t2); };
  }, []);
  const [bg, fg] = [item.frame.bg, item.frame.fg];
  return (
    <div className={`trail-img ${show ? 'show' : ''}`} style={{ left: item.x, top: item.y, background: bg, color: fg }}>
      <img src={item.frame.img} alt="" draggable="false"
           style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center' }} />
      <div className="absolute inset-0 flex flex-col justify-between p-3" style={{ background: 'linear-gradient(180deg, rgba(0,0,0,.28) 0%, rgba(0,0,0,0) 32%, rgba(0,0,0,.45) 100%)' }}>
        <div className="text-[9px] font-mono tracking-[0.2em] uppercase" style={{ color: '#fff', opacity: .9 }}>Asset · {item.id.toString().padStart(3,'0')}</div>
        <div className="font-display font-bold tracking-tight" style={{ fontSize: 28, color: fg }}>{item.frame.label}</div>
      </div>
    </div>
  );
}

Object.assign(window, { TopNav, Hero, About, MouseTrail });
