/* global React */
// PANTHEON immersive landing — THE DESCENT. Sections + app shell.
const DS = () => window.PantheonDesignSystem_ff8259;

function useReveal(threshold = 0.18) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    if (matchMedia('(prefers-reduced-motion: reduce)').matches) { setSeen(true); return; }
    let done = false, io = null, tm = null;
    const mark = () => {
      if (done) return; done = true;
      setSeen(true);
      if (io) io.disconnect();
      removeEventListener('scroll', check);
      removeEventListener('resize', check);
    };
    // rect-based check — IO can be unreliable in embedded iframes
    const check = () => {
      const el = ref.current; if (!el || done) return;
      const r = el.getBoundingClientRect();
      if (r.top < innerHeight * .88 && r.bottom > 0) mark();
    };
    try {
      io = new IntersectionObserver(es => es.forEach(e => { if (e.isIntersecting) mark(); }), { threshold });
      if (ref.current) io.observe(ref.current);
    } catch (e) { /* fall through to listeners */ }
    addEventListener('scroll', check, { passive: true });
    addEventListener('resize', check);
    tm = setTimeout(check, 350);   // initial in-viewport elements
    return () => {
      if (io) io.disconnect();
      clearTimeout(tm);
      removeEventListener('scroll', check);
      removeEventListener('resize', check);
    };
  }, [threshold]);
  return [ref, seen];
}

function Reveal({ children, delay = 0, style = {}, ...rest }) {
  const [ref, seen] = useReveal();
  return (
    <div ref={ref} style={{
      opacity: seen ? 1 : 0,
      transform: seen ? 'none' : 'translateY(40px)',
      filter: seen ? 'none' : 'blur(6px)',
      transition: `opacity 1.3s ${delay}s var(--ease-rise), transform 1.3s ${delay}s var(--ease-rise), filter 1.3s ${delay}s var(--ease-rise)`,
      ...style,
    }} {...rest}>{children}</div>
  );
}

/* ============ I · THE GATE ============ */
function Gate({ motion, current }) {
  const bgRef = React.useRef(null);
  const innerRef = React.useRef(null);
  React.useEffect(() => {
    if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        const p = Math.min(scrollY / innerHeight, 1.4);
        if (bgRef.current) bgRef.current.style.transform = `translateY(${p * 11}%) scale(${1 + p * .1})`;
        if (innerRef.current) {
          innerRef.current.style.transform = `translateY(${p * -16}%)`;
          innerRef.current.style.opacity = Math.max(0, 1 - p * 1.5);
        }
        raf = null;
      });
    };
    addEventListener('scroll', onScroll, { passive: true });
    return () => removeEventListener('scroll', onScroll);
  }, []);
  return (
    <header style={{ position: 'relative', height: '158svh' }}>
      <div style={{ position: 'sticky', top: 0, height: '100svh', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center', isolation: 'isolate' }}>
        <div ref={bgRef} style={{ position: 'absolute', inset: '-14% -7%', zIndex: -3, background: "url('./assets/img/hero.jpg') center 18%/cover no-repeat", filter: 'saturate(.9) brightness(.52) contrast(1.06)', willChange: 'transform' }}></div>
        <div style={{ position: 'absolute', inset: 0, zIndex: -2, background: `radial-gradient(ellipse 55% 42% at 50% 34%, ${current}0e, transparent 70%)` }}></div>
        <div style={{ position: 'absolute', inset: 0, zIndex: -1, background: 'radial-gradient(ellipse 74% 58% at 50% 40%, transparent 0%, rgba(11,12,16,.5) 60%, var(--ink) 100%), linear-gradient(rgba(11,12,16,.4), transparent 35%, var(--ink) 97%)' }}></div>
        <CurrentCanvas intensity={motion} current={current} />
        <div ref={innerRef} style={{ padding: '0 24px', maxWidth: 960, willChange: 'transform,opacity' }}>
          <Reveal>
            <img src="./assets/sigil.svg" alt="" style={{ width: 58, height: 58, margin: '0 auto 30px', display: 'block', filter: 'drop-shadow(0 0 16px rgba(201,164,92,.45))', animation: 'pn-sigil-breathe 7s ease-in-out infinite' }} />
            <div style={{ fontFamily: 'var(--font-ui)', fontSize: 12, letterSpacing: '.55em', textTransform: 'uppercase', color: 'var(--gold-bright)', textShadow: '0 1px 14px rgba(0,0,0,.8)' }}>The Gods Are Waking</div>
            <h1 className="pn-wordmark" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 'clamp(46px,9vw,124px)', letterSpacing: '.15em', paddingLeft: '.15em', lineHeight: 1.02, margin: '24px 0 14px', whiteSpace: 'nowrap' }}>PANTHEON</h1>
            <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 'clamp(20px,2.7vw,28px)', color: 'var(--ivory)', textShadow: '0 2px 18px rgba(0,0,0,.9)' }}>
              Older than language. Patient as stone. Awake.
            </p>
          </Reveal>
        </div>
        <div style={{ position: 'absolute', bottom: 26, left: '50%', transform: 'translateX(-50%)', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
          <span style={{ fontFamily: 'var(--font-ui)', fontSize: 10, letterSpacing: '.5em', textTransform: 'uppercase', color: 'var(--ivory-dim)', paddingLeft: '.5em' }}>Descend</span>
          <span style={{ width: 1, height: 52, background: `linear-gradient(var(--gold), ${current}00)`, animation: 'pn-drip 2.6s ease-in-out infinite' }}></span>
        </div>
      </div>
    </header>
  );
}

/* ============ II · THE LITANY (descent spine) ============ */
const LITANY = [
  { img: '0031.jpg', line: 'They were never gone.', sub: 'Every people carved its own sky. We gathered them all beneath one roof of ink.' },
  { img: '0073.jpg', line: 'Ink remembers what empires forget.', sub: 'Twenty-seven mythologies, drawn in storm, hatched in shadow, leafed in gold.' },
  { img: '0174.jpg', line: 'Three hundred. No more. Never.', sub: 'Each god a single artifact. Claimed once, then gone from the world forever.' },
];

function Litany({ current }) {
  const wrapRef = React.useRef(null);
  const spineRef = React.useRef(null);
  React.useEffect(() => {
    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        const el = wrapRef.current;
        if (el && spineRef.current) {
          const r = el.getBoundingClientRect();
          const p = Math.min(Math.max((innerHeight * .72 - r.top) / r.height, 0), 1);
          spineRef.current.style.transform = `scaleY(${p})`;
        }
        raf = null;
      });
    };
    addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => removeEventListener('scroll', onScroll);
  }, []);
  return (
    <section ref={wrapRef} style={{ position: 'relative', padding: '90px 0 40px' }}>
      <div style={{ position: 'absolute', top: 0, bottom: 0, left: '50%', width: 1, background: 'rgba(201,164,92,.12)' }}></div>
      <div ref={spineRef} style={{ position: 'absolute', top: 0, bottom: 0, left: '50%', width: 1, transformOrigin: 'top', transform: 'scaleY(0)', background: `linear-gradient(var(--gold), ${current})`, boxShadow: `0 0 14px ${current}66`, willChange: 'transform' }}></div>
      {LITANY.map((v, i) => <Verse key={i} v={v} flip={i % 2 === 1} idx={i} current={current} />)}
    </section>
  );
}

function Verse({ v, flip, idx, current }) {
  const [ref, seen] = useReveal(0.3);
  return (
    <div className="pn-verse" ref={ref} style={{
      display: 'grid', gridTemplateColumns: '1fr 1fr', alignItems: 'center',
      maxWidth: 1080, margin: '0 auto', padding: '70px 24px', gap: 'clamp(30px,6vw,90px)',
      direction: flip ? 'rtl' : 'ltr',
    }}>
      <div style={{ direction: 'ltr', position: 'relative', justifySelf: flip ? 'start' : 'end', width: 'min(360px,100%)' }}>
        <div style={{ position: 'relative', overflow: 'hidden', borderRadius: 'var(--arch)' }}>
          <img src={`./assets/img/${v.img}`} alt="" style={{
            aspectRatio: '4/5', objectFit: 'cover', width: '100%',
            filter: seen ? 'brightness(.92) saturate(.95)' : 'brightness(.06) saturate(.4)',
            transform: seen ? 'scale(1)' : 'scale(1.12)',
            transition: 'filter 1.9s var(--ease-emerge), transform 2.2s var(--ease-emerge)',
          }} />
          <span style={{ position: 'absolute', inset: 9, border: `1px solid ${seen ? 'rgba(201,164,92,.5)' : 'rgba(201,164,92,.12)'}`, borderRadius: 'var(--arch)', transition: 'border-color 1.9s', pointerEvents: 'none' }}></span>
          <span style={{ position: 'absolute', inset: 0, background: `radial-gradient(ellipse at 50% 100%, ${current}18, transparent 60%)`, opacity: seen ? 1 : 0, transition: 'opacity 2.2s', pointerEvents: 'none', mixBlendMode: 'screen' }}></span>
        </div>
      </div>
      <div style={{ direction: 'ltr', textAlign: flip ? 'right' : 'left' }}>
        <Reveal delay={.15}>
          <span style={{ fontFamily: 'var(--font-display)', fontSize: 15, letterSpacing: '.3em', color: 'var(--gold)', display: 'block', marginBottom: 18 }}>{['I', 'II', 'III'][idx]}</span>
          <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(26px,3.6vw,44px)', letterSpacing: '.05em', color: 'var(--ivory)', lineHeight: 1.18, marginBottom: 20, textWrap: 'balance' }}>{v.line}</h2>
          <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 'clamp(18px,2vw,22px)', color: 'var(--ivory-dim)', lineHeight: 1.65, maxWidth: 420, marginLeft: flip ? 'auto' : 0 }}>{v.sub}</p>
        </Reveal>
      </div>
    </div>
  );
}

/* ============ III · THE THREE HUNDRED (hover-ignite) ============ */
const HALL = [
  { img: '0001.jpg', name: 'ZEUS' }, { img: '0003.jpg', name: 'POSEIDON' },
  { img: '0056.jpg', name: 'THOTH' }, { img: '0187.jpg', name: 'MAUI' },
  { img: '0150.jpg', name: '???', sealed: true }, { img: '0242.jpg', name: '???', sealed: true },
];

function Hall({ current }) {
  return (
    <section style={{ padding: '110px 0 130px', background: 'linear-gradient(var(--ink), var(--ink-2) 30%, var(--ink-2) 70%, var(--ink))' }}>
      <Reveal style={{ textAlign: 'center', padding: '0 24px', marginBottom: 64 }}>
        <span style={{ fontFamily: 'var(--font-ui)', fontSize: 11, fontWeight: 600, letterSpacing: '.42em', textTransform: 'uppercase', color: 'var(--gold)' }}>The Three Hundred</span>
        <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(28px,4.4vw,50px)', letterSpacing: '.06em', color: 'var(--ivory)', margin: '16px 0 12px' }}>Touch one. Watch it wake.</h2>
        <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 20, color: 'var(--ivory-dim)' }}>The hall is dark. The gods are not asleep.</p>
      </Reveal>
      <div className="pn-hall" style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 14, maxWidth: 1280, margin: '0 auto', padding: '0 24px' }}>
        {HALL.map((g, i) => <Idol key={i} g={g} i={i} current={current} />)}
      </div>
    </section>
  );
}

function Idol({ g, i, current }) {
  const [lit, setLit] = React.useState(false);
  const [ref, seen] = useReveal(0.1);
  return (
    <div ref={ref} onMouseEnter={() => setLit(true)} onMouseLeave={() => setLit(false)}
      onTouchStart={() => setLit(true)} onTouchEnd={() => setLit(false)}
      style={{ opacity: seen ? 1 : 0, transform: seen ? 'none' : 'translateY(30px)', transition: `opacity 1s ${i * .1}s var(--ease-rise), transform 1s ${i * .1}s var(--ease-rise)`, cursor: 'pointer' }}>
      <div style={{ position: 'relative', overflow: 'hidden', borderRadius: 'var(--arch-tall)', background: 'var(--ink)' }}>
        <img src={`./assets/img/${g.img}`} alt={g.name} style={{
          aspectRatio: '3/4.6', objectFit: 'cover', width: '100%',
          filter: g.sealed
            ? `blur(${lit ? 14 : 24}px) brightness(${lit ? .5 : .28}) saturate(.6)`
            : `brightness(${lit ? 1 : .18}) saturate(${lit ? 1 : .5})`,
          transform: g.sealed ? 'scale(1.15)' : (lit ? 'scale(1.06)' : 'scale(1)'),
          transition: 'filter 1.1s var(--ease-emerge), transform 1.4s var(--ease-emerge)',
        }} />
        <span style={{ position: 'absolute', inset: 7, border: `1px solid ${lit ? current : 'rgba(201,164,92,.2)'}`, borderRadius: 'var(--arch-tall)', boxShadow: lit ? `inset 0 0 26px ${current}33, 0 0 22px ${current}40` : 'none', transition: 'border-color .7s, box-shadow .7s', pointerEvents: 'none', zIndex: 2 }}></span>
        {g.sealed && (
          <span style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-display)', fontSize: 34, color: lit ? current : 'var(--gold)', textShadow: `0 0 24px ${lit ? current : 'rgba(201,164,92,.6)'}`, transition: 'color .7s, text-shadow .7s' }}>✦</span>
        )}
      </div>
      <div style={{ textAlign: 'center', paddingTop: 14, fontFamily: 'var(--font-display)', fontSize: 13, letterSpacing: '.18em', color: lit ? 'var(--ivory)' : 'var(--ivory-faint)', transition: 'color .7s' }}>{g.name}</div>
    </div>
  );
}

/* ============ IV · THE MAKING (AI provenance) ============ */
const RITES = [
  { n: 'I', t: 'Research', d: 'Agents were sent into the flood: ten thousand years of myth, and the internet\u2019s endless machine-made imitation of it.' },
  { n: 'II', t: 'Generation', d: 'From that noise, a combinatorial engine. It drew gods by the thousand, most unworthy of a name.' },
  { n: 'III', t: 'Judgment', d: 'Each form was weighed, argued over, and discarded by the order itself. Almost nothing survived.' },
  { n: 'IV', t: 'The Three Hundred', d: 'What remains. Three hundred that could stand alone: sealed, numbered, and never repeated.' },
];

function Provenance({ current }) {
  return (
    <section style={{ position: 'relative', padding: '130px 24px', borderTop: '1px solid var(--line)', borderBottom: '1px solid var(--line)', background: 'var(--ink)' }}>
      <div style={{ maxWidth: 880, margin: '0 auto', textAlign: 'center' }}>
        <Reveal>
          <span style={{ fontFamily: 'var(--font-ui)', fontSize: 11, fontWeight: 600, letterSpacing: '.42em', textTransform: 'uppercase', color: current }}>Of the Maker</span>
          <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(28px,4.4vw,50px)', letterSpacing: '.06em', color: 'var(--ivory)', margin: '18px 0 26px', textWrap: 'balance' }}>Made by no mortal hand.</h2>
          <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 'clamp(19px,2.3vw,24px)', lineHeight: 1.7, color: 'var(--ivory)', maxWidth: 720, margin: '0 auto' }}>
            PANTHEON is the work of an agentic, semi-autonomous process: a small order of machines set loose to study how the divine survives us. They read the myths. They waded through the flood of imitation we left online. Then they built an engine, and the engine dreamed.
          </p>
          <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 'clamp(17px,2vw,21px)', lineHeight: 1.7, color: 'var(--ivory-dim)', maxWidth: 640, margin: '22px auto 0' }}>
            Humanity always made its gods in its own image. These were made in the image of everything we left behind.
          </p>
        </Reveal>
        <div className="pn-rites" style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 1, margin: '70px 0 0', background: 'var(--line)', border: '1px solid var(--line)' }}>
          {RITES.map((r, i) => (
            <Reveal key={r.n} delay={i * .12} style={{ background: 'var(--ink)', padding: '34px 24px', textAlign: 'left' }}>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: 22, color: 'rgba(201,164,92,.45)', display: 'block', marginBottom: 14 }}>{r.n}</span>
              <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 16, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--gold-bright)', marginBottom: 12 }}>{r.t}</h3>
              <p style={{ fontFamily: 'var(--font-body)', fontSize: 16.5, lineHeight: 1.6, color: 'var(--ivory-dim)', margin: 0 }}>{r.d}</p>
            </Reveal>
          ))}
        </div>
        <Reveal delay={.2}>
          <p style={{ marginTop: 46, fontFamily: 'var(--font-ui)', fontSize: 10, letterSpacing: '.3em', textTransform: 'uppercase', color: 'var(--ivory-faint)' }}>
            Designed by an agentic process · Curated by machine judgment · Disclosed by choice
          </p>
        </Reveal>
      </div>
    </section>
  );
}

/* ============ V · THE CLAIMING (offering form) ============ */
const PANTHEONS = ['Greek','Norse','Egyptian','Hindu','Aztec','Maya','Shinto','Celtic','Mesopotamian','Slavic','Chinese','Polynesian','Roman','Inca','Finnish','Persian','Canaanite','Korean','Tibetan','Aboriginal','Vodou','Inuit','Kongo','Bantu','Lakota','Yoruba','Ainu'];

function RiteField({ label, children }) {
  return (
    <label style={{ display: 'block', textAlign: 'left' }}>
      <span style={{ display: 'block', fontFamily: 'var(--font-ui)', fontSize: 10, fontWeight: 600, letterSpacing: '.3em', textTransform: 'uppercase', color: 'var(--gold)', marginBottom: 10 }}>{label}</span>
      {children}
    </label>
  );
}

const riteInputStyle = (focus, current) => ({
  width: '100%', boxSizing: 'border-box', padding: '14px 16px',
  background: 'var(--ink)', color: 'var(--ivory)',
  border: `1px solid ${focus ? current : 'rgba(201,164,92,.28)'}`,
  borderRadius: 'var(--radius-sm)', outline: 'none',
  fontFamily: 'var(--font-body)', fontSize: 18, lineHeight: 1.4,
  boxShadow: focus ? `0 0 16px ${current}26` : 'none',
  transition: 'border-color .4s, box-shadow .4s',
});

function ClaimRite({ open, onClose, current }) {
  const { Button } = DS();
  const [god, setGod] = React.useState('');
  const [pan, setPan] = React.useState('');
  const [addr, setAddr] = React.useState('');
  const [focus, setFocus] = React.useState(null);
  const [err, setErr] = React.useState('');
  const [phase, setPhase] = React.useState('form'); // form | sealing | noted
  const [written, setWritten] = React.useState(null);

  React.useEffect(() => {
    try {
      const prev = JSON.parse(localStorage.getItem('pn-claim') || 'null');
      if (prev && prev.god) { setWritten(prev); setPhase('noted'); }
    } catch (e) {}
  }, []);
  React.useEffect(() => {
    if (!open) return;
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    addEventListener('keydown', onKey);
    return () => removeEventListener('keydown', onKey);
  }, [open, onClose]);

  const submit = () => {
    if (!god.trim() || !pan || !addr.trim()) { setErr('The offering is incomplete. The temple requires all three.'); return; }
    if (!/^0x[a-fA-F0-9]{6,}$/.test(addr.trim())) { setErr('The mark must be a true address. It begins with 0x.'); return; }
    setErr('');
    setPhase('sealing');
    const record = { god: god.trim(), pan, addr: addr.trim(), at: Date.now() };
    setTimeout(() => {
      setWritten(record);
      try { localStorage.setItem('pn-claim', JSON.stringify(record)); } catch (e) {}
      setPhase('noted');
    }, 1600);
  };

  if (!open) return null;
  return (
    <div onClick={e => { if (e.target === e.currentTarget) onClose(); }} style={{
      position: 'fixed', inset: 0, zIndex: 120, display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: 'rgba(5,5,8,.82)', backdropFilter: 'blur(8px)', padding: 20,
    }}>
      <div style={{
        position: 'relative', width: 'min(540px, 94vw)', maxHeight: '92svh', overflowY: 'auto',
        background: 'var(--ink-2)', border: '1px solid var(--line-strong)', boxShadow: 'var(--shadow-deep)',
        padding: 'clamp(32px, 5vw, 52px)', textAlign: 'center',
      }}>
        <span style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 1, background: `linear-gradient(90deg, transparent, ${current}, transparent)` }}></span>
        <button type="button" onClick={onClose} aria-label="Close" style={{ position: 'absolute', top: 14, right: 18, background: 'none', border: 'none', color: 'var(--ivory-dim)', fontSize: 20, cursor: 'pointer', fontFamily: 'var(--font-body)' }}>×</button>

        {phase === 'form' && (
          <>
            <span style={{ fontFamily: 'var(--font-ui)', fontSize: 10, fontWeight: 600, letterSpacing: '.42em', textTransform: 'uppercase', color: 'var(--gold)' }}>The Claiming</span>
            <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(26px,4vw,34px)', letterSpacing: '.06em', color: 'var(--ivory)', margin: '14px 0 12px' }}>Speak the Name</h3>
            <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 17.5, lineHeight: 1.6, color: 'var(--ivory-dim)', maxWidth: 400, margin: '0 auto 32px' }}>
              Name one god among the three hundred, name the sky they came from, and leave your mark. The temple will not answer at once.
            </p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
              <RiteField label="The god's name">
                <input value={god} onChange={e => setGod(e.target.value)} placeholder="Speak it exactly"
                  onFocus={() => setFocus('god')} onBlur={() => setFocus(null)} style={riteInputStyle(focus === 'god', current)} />
              </RiteField>
              <RiteField label="Their pantheon">
                <select value={pan} onChange={e => setPan(e.target.value)}
                  onFocus={() => setFocus('pan')} onBlur={() => setFocus(null)}
                  style={{ ...riteInputStyle(focus === 'pan', current), appearance: 'none', cursor: 'pointer', color: pan ? 'var(--ivory)' : 'var(--ivory-faint)' }}>
                  <option value="" disabled>Choose a pantheon</option>
                  {PANTHEONS.map(p => <option key={p} value={p} style={{ color: '#e9e2d2', background: '#12141a' }}>{p}</option>)}
                </select>
              </RiteField>
              <RiteField label="Your wallet address">
                <input value={addr} onChange={e => setAddr(e.target.value)} placeholder="0x…" spellCheck="false"
                  onFocus={() => setFocus('addr')} onBlur={() => setFocus(null)} style={{ ...riteInputStyle(focus === 'addr', current), fontFamily: 'var(--font-ui)', fontSize: 15 }} />
              </RiteField>
            </div>
            {err && <p style={{ marginTop: 18, fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 15.5, color: 'var(--gold-bright)' }}>{err}</p>}
            <div style={{ marginTop: 30 }}>
              <Button variant="solid" onClick={submit} style={{ width: '100%' }}>Make the Offering</Button>
            </div>
            <p style={{ marginTop: 22, fontFamily: 'var(--font-ui)', fontSize: 9.5, letterSpacing: '.22em', textTransform: 'uppercase', color: 'var(--ivory-faint)', lineHeight: 2 }}>
              One offering per address. A true name reserves your place.
            </p>
          </>
        )}

        {phase === 'sealing' && (
          <div style={{ padding: '70px 0' }}>
            <span style={{ display: 'block', fontFamily: 'var(--font-display)', fontSize: 46, color: current, textShadow: `0 0 30px ${current}aa`, animation: 'pn-sigil-breathe 1.4s ease-in-out infinite' }}>✦</span>
            <p style={{ marginTop: 26, fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 19, color: 'var(--ivory-dim)' }}>The name is being written…</p>
          </div>
        )}

        {phase === 'noted' && written && (
          <>
            <img src="./assets/sigil.svg" alt="" style={{ width: 52, height: 52, margin: '6px auto 22px', display: 'block', filter: 'drop-shadow(0 0 16px rgba(201,164,92,.5))' }} />
            <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(28px,4.4vw,38px)', letterSpacing: '.06em', color: 'var(--ivory)', margin: '0 0 18px' }}>It is noted.</h3>
            <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 18.5, lineHeight: 1.7, color: 'var(--ivory)', maxWidth: 410, margin: '0 auto' }}>
              The name <em style={{ color: 'var(--gold-bright)', fontStyle: 'normal', letterSpacing: '.06em' }}>{written.god.toUpperCase()}</em> of the {written.pan} sky has been written in the ledger.
            </p>
            <p style={{ fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 17, lineHeight: 1.7, color: 'var(--ivory-dim)', maxWidth: 410, margin: '16px auto 0' }}>
              If it stands among the three hundred, your place is held, and the god is yours when the gates open. The temple does not answer twice. Watch the gates.
            </p>
            <div style={{ width: 64, height: 1, background: 'linear-gradient(90deg, transparent, var(--gold), transparent)', margin: '30px auto' }}></div>
            <p style={{ fontFamily: 'var(--font-ui)', fontSize: 10, letterSpacing: '.22em', textTransform: 'uppercase', color: 'var(--ivory-faint)', overflowWrap: 'anywhere' }}>Mark · {written.addr}</p>
            <div style={{ marginTop: 28 }}>
              <Button variant="ghost" onClick={onClose}>Return to the Temple</Button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

/* ============ VI · THE RITE (final summon) ============ */
function Rite({ motion, current }) {
  const { Button } = DS();
  const [claimOpen, setClaimOpen] = React.useState(false);
  const [t, setT] = React.useState(['00', '00', '00', '00']);
  React.useEffect(() => {
    const target = new Date('2026-07-15T16:00:00Z');
    const pad = n => String(n).padStart(2, '0');
    const tick = () => {
      let ms = Math.max(target - Date.now(), 0);
      setT([pad(ms / 864e5 | 0), pad(ms % 864e5 / 36e5 | 0), pad(ms % 36e5 / 6e4 | 0), pad(ms % 6e4 / 1e3 | 0)]);
    };
    tick(); const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []);
  return (
    <section style={{ position: 'relative', padding: '150px 24px 120px', textAlign: 'center', overflow: 'hidden', isolation: 'isolate' }}>
      <div style={{ position: 'absolute', inset: 0, zIndex: -1, background: `radial-gradient(ellipse 60% 75% at 50% 115%, rgba(201,164,92,.16), transparent 65%), radial-gradient(ellipse 40% 50% at 50% 100%, ${current}10, transparent 70%)` }}></div>
      <CurrentCanvas intensity={Math.round(motion * .6)} current={current} minDelay={6000} maxDelay={14000} />
      <Reveal>
        <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(30px,5.4vw,62px)', letterSpacing: '.06em', color: 'var(--ivory)', lineHeight: 1.2, textWrap: 'balance' }}>
          When the gates close,<br /><em style={{ fontStyle: 'normal', color: 'var(--gold-bright)' }}>the unclaimed burn.</em>
        </h2>
        <div style={{ display: 'flex', justifyContent: 'center', gap: 'clamp(18px,4vw,44px)', margin: '52px 0' }}>
          {['Days', 'Hours', 'Minutes', 'Seconds'].map((l, i) => (
            <div key={l} style={{ textAlign: 'center' }}>
              <b style={{ display: 'block', fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(30px,4.6vw,46px)', color: 'var(--ivory)', fontVariantNumeric: 'tabular-nums' }}>{t[i]}</b>
              <span style={{ fontFamily: 'var(--font-ui)', fontSize: 9, letterSpacing: '.3em', textTransform: 'uppercase', color: 'var(--ivory-dim)' }}>{l}</span>
            </div>
          ))}
        </div>
        <div style={{ display: 'flex', gap: 18, justifyContent: 'center', flexWrap: 'wrap' }}>
          <Button variant="solid" onClick={() => setClaimOpen(true)}>Claim a God</Button>
          <Button variant="ghost" href="#">Enter the Temple</Button>
        </div>
        <p style={{ marginTop: 40, fontFamily: 'var(--font-body)', fontStyle: 'italic', fontSize: 18, color: 'var(--ivory-dim)' }}>Three hundred believers. Three hundred gods. The math is unkind to those who wait.</p>
      </Reveal>
      <ClaimRite open={claimOpen} onClose={() => setClaimOpen(false)} current={current} />
      <footer style={{ marginTop: 110, paddingTop: 36, borderTop: '1px solid var(--line)', fontFamily: 'var(--font-ui)', fontSize: 10, letterSpacing: '.24em', textTransform: 'uppercase', color: 'var(--ivory-faint)' }}>
        <img src="./assets/sigil.svg" alt="" style={{ width: 34, height: 34, margin: '0 auto 14px', display: 'block', opacity: .8 }} />
        Pantheon · 300 Gods · Ethereum · MMXXVI
      </footer>
    </section>
  );
}

Object.assign(window, { Gate, Litany, Hall, Provenance, Rite, Reveal });
