// Anastasia & Daniil — A Wedding Story
// Page-turning book with realistic 3D flip, soft paper pages, cool stone palette.

const { useState, useEffect, useRef, useCallback, useMemo } = React;

const PAGE_W = 540;
const PAGE_H = 740;

// ─────────────────────────────────────────────────────────────
// PAGE CONTENT RENDERERS
// ─────────────────────────────────────────────────────────────

function PhotoFull({ photo, caption }) {
  return (
    <div className="pg-photo-full">
      <div className="pg-photo-frame">
        <img src={window.photoPath(photo)} alt="" loading="lazy" draggable="false" />
      </div>
      {caption && <div className="pg-photo-caption">{caption}</div>}
    </div>
  );
}

function Mosaic2({ photos }) {
  return (
    <div className="pg-mosaic-2">
      {photos.map((n, i) => (
        <div key={i} className="pg-mosaic-item">
          <img src={window.photoPath(n)} alt="" loading="lazy" draggable="false" />
        </div>
      ))}
    </div>
  );
}

function Mosaic3Stack({ photos }) {
  return (
    <div className="pg-mosaic-3">
      <div className="pg-mosaic-3-top">
        <img src={window.photoPath(photos[0])} alt="" loading="lazy" draggable="false" />
      </div>
      <div className="pg-mosaic-3-bottom">
        <div className="pg-mosaic-item">
          <img src={window.photoPath(photos[1])} alt="" loading="lazy" draggable="false" />
        </div>
        <div className="pg-mosaic-item">
          <img src={window.photoPath(photos[2])} alt="" loading="lazy" draggable="false" />
        </div>
      </div>
    </div>
  );
}

function TextBlock({ script, heading, body, align }) {
  return (
    <div className={`pg-text ${align === 'center' ? 'pg-text-center' : ''}`}>
      <div className="pg-text-inner">
        {script && <div className="pg-script">{script}</div>}
        {heading && <h2 className="pg-heading">{heading}</h2>}
        <div className="pg-ornament">
          <svg viewBox="0 0 120 12" width="100" height="10">
            <line x1="0" y1="6" x2="44" y2="6" stroke="currentColor" strokeWidth="0.6"/>
            <circle cx="60" cy="6" r="2" fill="none" stroke="currentColor" strokeWidth="0.6"/>
            <circle cx="52" cy="6" r="1" fill="currentColor"/>
            <circle cx="68" cy="6" r="1" fill="currentColor"/>
            <line x1="76" y1="6" x2="120" y2="6" stroke="currentColor" strokeWidth="0.6"/>
          </svg>
        </div>
        {body && body.map((para, i) => <p key={i} className="pg-body">{para}</p>)}
      </div>
    </div>
  );
}

function TitlePage({ monogram, title, subtitle, date, place }) {
  return (
    <div className="pg-title">
      <div className="pg-title-monogram">{monogram}</div>
      <div className="pg-title-rule" />
      <h1 className="pg-title-main">{title}</h1>
      <div className="pg-title-sub">{subtitle}</div>
      <div className="pg-title-flourish">
        <svg viewBox="0 0 160 30" width="140" height="26">
          <path d="M5 15 Q40 5 80 15 T155 15" fill="none" stroke="currentColor" strokeWidth="0.5"/>
          <circle cx="80" cy="15" r="2" fill="currentColor"/>
          <circle cx="80" cy="15" r="5" fill="none" stroke="currentColor" strokeWidth="0.4"/>
        </svg>
      </div>
      <div className="pg-title-date">{date}</div>
      <div className="pg-title-place">{place}</div>
    </div>
  );
}

function Prologue({ script, body }) {
  return (
    <div className="pg-prologue">
      <div className="pg-prologue-inner">
        <div className="pg-script pg-script-large">{script}</div>
        <div className="pg-drop">
          <svg viewBox="0 0 60 20" width="60" height="16">
            <line x1="0" y1="10" x2="22" y2="10" stroke="currentColor" strokeWidth="0.5"/>
            <circle cx="30" cy="10" r="3" fill="none" stroke="currentColor" strokeWidth="0.5"/>
            <circle cx="30" cy="10" r="1" fill="currentColor"/>
            <line x1="38" y1="10" x2="60" y2="10" stroke="currentColor" strokeWidth="0.5"/>
          </svg>
        </div>
        {body && body.map((p, i) => <p key={i} className="pg-prologue-body">{p}</p>)}
      </div>
    </div>
  );
}

function ChapterOpener({ numeral, name, epigraph }) {
  return (
    <div className="pg-chapter">
      <div className="pg-chapter-inner">
        <div className="pg-chapter-eyebrow">Chapter</div>
        <div className="pg-chapter-numeral">{numeral}</div>
        <div className="pg-chapter-rule"><span/></div>
        <h2 className="pg-chapter-name">{name}</h2>
        <div className="pg-chapter-epigraph">{epigraph}</div>
        <div className="pg-chapter-ornament">
          <svg viewBox="0 0 80 60" width="80" height="60">
            <path d="M40 8 C 30 22, 30 38, 40 52 C 50 38, 50 22, 40 8 Z" fill="none" stroke="currentColor" strokeWidth="0.6"/>
            <path d="M40 14 C 34 24, 34 36, 40 46 C 46 36, 46 24, 40 14 Z" fill="none" stroke="currentColor" strokeWidth="0.4"/>
            <circle cx="40" cy="30" r="1.5" fill="currentColor"/>
          </svg>
        </div>
      </div>
    </div>
  );
}

function MonogramPage({ text }) {
  return (
    <div className="pg-monogram">
      <div className="pg-monogram-inner">
        <div className="pg-monogram-rule" />
        <div className="pg-monogram-text">{text}</div>
        <div className="pg-monogram-rule" />
        <div className="pg-monogram-script">forever</div>
      </div>
    </div>
  );
}

function BlankPage() {
  return <div className="pg-blank" />;
}

// ─────────────────────────────────────────────────────────────
// SIGNATURE PAGE
// ─────────────────────────────────────────────────────────────

function SignaturePage() {
  const [name, setName] = useState('');
  const [note, setNote] = useState('');
  const [entries, setEntries] = useState([]);
  const [submitting, setSubmitting] = useState(false);

  useEffect(() => {
    try {
      const saved = JSON.parse(localStorage.getItem('ad-signatures') || '[]');
      setEntries(saved);
    } catch (e) { setEntries([]); }
  }, []);

  const submit = (e) => {
    e.preventDefault();
    if (!name.trim() || !note.trim()) return;
    setSubmitting(true);
    setTimeout(() => {
      const newEntry = { name: name.trim(), note: note.trim(), at: Date.now() };
      const updated = [...entries, newEntry];
      setEntries(updated);
      try { localStorage.setItem('ad-signatures', JSON.stringify(updated)); } catch (e) {}
      setName(''); setNote('');
      setSubmitting(false);
    }, 350);
  };

  // Show entries on left, form on right. If many entries, scroll within left.
  return (
    <>
      <div className="pg-signature-left">
        <div className="pg-script">guest book</div>
        <h2 className="pg-heading" style={{marginBottom: 8}}>With Love</h2>
        <div className="pg-ornament">
          <svg viewBox="0 0 80 8" width="70" height="8">
            <line x1="0" y1="4" x2="30" y2="4" stroke="currentColor" strokeWidth="0.5"/>
            <circle cx="40" cy="4" r="1.5" fill="currentColor"/>
            <line x1="50" y1="4" x2="80" y2="4" stroke="currentColor" strokeWidth="0.5"/>
          </svg>
        </div>
        <div className="pg-signature-entries">
          {entries.length === 0 && (
            <div className="pg-signature-empty">
              <em>This page is waiting for its first note.</em>
            </div>
          )}
          {entries.map((e, i) => (
            <div key={i} className="pg-signature-entry">
              <div className="pg-signature-note">"{e.note}"</div>
              <div className="pg-signature-name">— {e.name}</div>
            </div>
          ))}
        </div>
      </div>

      <div className="pg-signature-right">
        <div className="pg-script">leave a note</div>
        <h2 className="pg-heading" style={{marginBottom: 8}}>For Anastasia & Daniil</h2>
        <div className="pg-ornament">
          <svg viewBox="0 0 80 8" width="70" height="8">
            <line x1="0" y1="4" x2="30" y2="4" stroke="currentColor" strokeWidth="0.5"/>
            <circle cx="40" cy="4" r="1.5" fill="currentColor"/>
            <line x1="50" y1="4" x2="80" y2="4" stroke="currentColor" strokeWidth="0.5"/>
          </svg>
        </div>
        <p className="pg-body" style={{marginTop: 4}}>
          A wedding album asks one thing of its readers — that you sign your name to the day. A line, a memory, a small good wish.
        </p>
        <form className="pg-signature-form" onSubmit={submit}>
          <label>
            <span>Your name</span>
            <input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Aunt Margaret"
              maxLength={40}
            />
          </label>
          <label>
            <span>A note</span>
            <textarea
              value={note}
              onChange={(e) => setNote(e.target.value)}
              placeholder="Something you want them to remember…"
              maxLength={240}
              rows={4}
            />
          </label>
          <button type="submit" disabled={submitting || !name.trim() || !note.trim()}>
            {submitting ? 'Pressing the ink…' : 'Sign the book'}
          </button>
        </form>
      </div>
    </>
  );
}

// ─────────────────────────────────────────────────────────────
// PAGE CONTENT DISPATCHER
// ─────────────────────────────────────────────────────────────

function PageContent({ content }) {
  if (!content) return <BlankPage/>;
  switch (content.type) {
    case 'photo-full': return <PhotoFull photo={content.photo} caption={content.caption}/>;
    case 'mosaic-2': return <Mosaic2 photos={content.photos}/>;
    case 'mosaic-3-stack': return <Mosaic3Stack photos={content.photos}/>;
    case 'text-block': return <TextBlock {...content}/>;
    case 'title-page': return <TitlePage {...content}/>;
    case 'prologue': return <Prologue {...content}/>;
    case 'monogram-page': return <MonogramPage {...content}/>;
    case 'blank': return <BlankPage/>;
    default: return <BlankPage/>;
  }
}

// ─────────────────────────────────────────────────────────────
// SPREAD RENDERER (renders a whole spread including chapter / signature / covers)
// ─────────────────────────────────────────────────────────────

function SpreadFace({ spread, side }) {
  // side = 'left' | 'right'
  if (!spread) return <div className="page-content"/>;

  if (spread.kind === 'front-cover') {
    if (side === 'left') return <div className="page-content cover-inside"/>;
    return (
      <div className="page-content cover-front">
        <div className="cover-frame">
          <div className="cover-eyebrow">A Wedding Album</div>
          <div className="cover-monogram">
            <span>A</span>
            <span className="cover-amp">&amp;</span>
            <span>D</span>
          </div>
          <div className="cover-names">
            <div>Anastasia</div>
            <div className="cover-and"><em>and</em></div>
            <div>Daniil</div>
          </div>
          <div className="cover-ornament">
            <svg viewBox="0 0 160 30" width="150" height="28">
              <path d="M5 15 Q40 4 80 15 T155 15" fill="none" stroke="currentColor" strokeWidth="0.5"/>
              <circle cx="80" cy="15" r="2" fill="currentColor"/>
            </svg>
          </div>
          <div className="cover-date">XI · X · MMXXVI</div>
          <div className="cover-place">By the Sea</div>
        </div>
      </div>
    );
  }

  if (spread.kind === 'back-cover') {
    if (side === 'right') return <div className="page-content cover-inside"/>;
    return (
      <div className="page-content cover-back">
        <div className="cover-back-mark">
          <svg viewBox="0 0 60 60" width="44" height="44">
            <circle cx="30" cy="30" r="22" fill="none" stroke="currentColor" strokeWidth="0.5"/>
            <text x="30" y="36" textAnchor="middle" fontFamily="'Cormorant Garamond', serif" fontSize="14" fill="currentColor" letterSpacing="2">A&amp;D</text>
          </svg>
        </div>
        <div className="cover-back-note">— fin —</div>
      </div>
    );
  }

  if (spread.kind === 'chapter-opener') {
    // Chapter opener spans both pages: numeral on left, name + epigraph on right
    if (side === 'left') {
      return (
        <div className="page-content chapter-left">
          <div className="chapter-numeral-huge">{spread.numeral}</div>
        </div>
      );
    }
    return (
      <div className="page-content chapter-right">
        <ChapterOpener numeral="" name={spread.name} epigraph={spread.epigraph}/>
      </div>
    );
  }

  if (spread.kind === 'signature') {
    return (
      <div className={`page-content signature-page signature-${side}`}>
        {side === 'left' ? <SignatureLeft/> : <SignatureRight/>}
      </div>
    );
  }

  // default: photo / text spread, title spread, dedication, colophon — use .left and .right content
  const content = side === 'left' ? spread.left : spread.right;
  return (
    <div className="page-content">
      <div className="page-inner">
        <PageContent content={content}/>
      </div>
    </div>
  );
}

// Signature halves are split for layout — but it's one stateful page that needs shared state.
// To keep state shared, we render <SignaturePage/> twice with the same component lifting state via context.
// Simpler approach: a single global signature state via window so both halves stay in sync.
function SignatureLeft() {
  const [, force] = useState(0);
  useEffect(() => {
    const f = () => force(x => x + 1);
    window.addEventListener('ad-signatures-changed', f);
    return () => window.removeEventListener('ad-signatures-changed', f);
  }, []);
  const entries = (() => {
    try { return JSON.parse(localStorage.getItem('ad-signatures') || '[]'); }
    catch (e) { return []; }
  })();
  return (
    <div className="pg-signature-left">
      <div className="pg-script">guest book</div>
      <h2 className="pg-heading" style={{marginBottom: 8}}>With Love</h2>
      <div className="pg-ornament">
        <svg viewBox="0 0 80 8" width="70" height="8">
          <line x1="0" y1="4" x2="30" y2="4" stroke="currentColor" strokeWidth="0.5"/>
          <circle cx="40" cy="4" r="1.5" fill="currentColor"/>
          <line x1="50" y1="4" x2="80" y2="4" stroke="currentColor" strokeWidth="0.5"/>
        </svg>
      </div>
      <div className="pg-signature-entries">
        {entries.length === 0 && (
          <div className="pg-signature-empty">
            <em>This page is waiting for its first note.</em>
          </div>
        )}
        {entries.map((e, i) => (
          <div key={i} className="pg-signature-entry">
            <div className="pg-signature-note">&ldquo;{e.note}&rdquo;</div>
            <div className="pg-signature-name">— {e.name}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

function SignatureRight() {
  const [name, setName] = useState('');
  const [note, setNote] = useState('');
  const [submitting, setSubmitting] = useState(false);

  const submit = (e) => {
    e.preventDefault();
    if (!name.trim() || !note.trim()) return;
    setSubmitting(true);
    setTimeout(() => {
      let existing = [];
      try { existing = JSON.parse(localStorage.getItem('ad-signatures') || '[]'); } catch (er) {}
      existing.push({ name: name.trim(), note: note.trim(), at: Date.now() });
      try { localStorage.setItem('ad-signatures', JSON.stringify(existing)); } catch (er) {}
      window.dispatchEvent(new Event('ad-signatures-changed'));
      setName(''); setNote('');
      setSubmitting(false);
    }, 300);
  };

  return (
    <div className="pg-signature-right">
      <div className="pg-script">leave a note</div>
      <h2 className="pg-heading" style={{marginBottom: 8}}>For Anastasia &amp; Daniil</h2>
      <div className="pg-ornament">
        <svg viewBox="0 0 80 8" width="70" height="8">
          <line x1="0" y1="4" x2="30" y2="4" stroke="currentColor" strokeWidth="0.5"/>
          <circle cx="40" cy="4" r="1.5" fill="currentColor"/>
          <line x1="50" y1="4" x2="80" y2="4" stroke="currentColor" strokeWidth="0.5"/>
        </svg>
      </div>
      <p className="pg-body" style={{marginTop: 4}}>
        A wedding album asks one thing of its readers — that you sign your name to the day. A line, a memory, a small good wish.
      </p>
      <form className="pg-signature-form" onSubmit={submit}>
        <label>
          <span>Your name</span>
          <input type="text" value={name} onChange={e => setName(e.target.value)} placeholder="Aunt Margaret" maxLength={40}/>
        </label>
        <label>
          <span>A note</span>
          <textarea value={note} onChange={e => setNote(e.target.value)} placeholder="Something you want them to remember…" maxLength={240} rows={4}/>
        </label>
        <button type="submit" disabled={submitting || !name.trim() || !note.trim()}>
          {submitting ? 'Pressing the ink…' : 'Sign the book'}
        </button>
      </form>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// AMBIENT MUSIC (Web Audio synth — gentle piano-ish chord pad)
// ─────────────────────────────────────────────────────────────

function useAmbientMusic() {
  const ctxRef = useRef(null);
  const nodesRef = useRef(null);
  const [playing, setPlaying] = useState(false);

  const stop = useCallback(() => {
    if (nodesRef.current) {
      try {
        nodesRef.current.master.gain.cancelScheduledValues(0);
        nodesRef.current.master.gain.setValueAtTime(nodesRef.current.master.gain.value, ctxRef.current.currentTime);
        nodesRef.current.master.gain.linearRampToValueAtTime(0, ctxRef.current.currentTime + 0.8);
        setTimeout(() => {
          if (nodesRef.current) {
            try { nodesRef.current.oscs.forEach(o => o.stop()); } catch (e) {}
            try { nodesRef.current.lfos.forEach(o => o.stop()); } catch (e) {}
            nodesRef.current = null;
          }
        }, 900);
      } catch (e) {}
    }
    setPlaying(false);
  }, []);

  const start = useCallback(() => {
    if (playing) return;
    if (!ctxRef.current) {
      const AC = window.AudioContext || window.webkitAudioContext;
      if (!AC) return;
      ctxRef.current = new AC();
    }
    const ctx = ctxRef.current;
    if (ctx.state === 'suspended') ctx.resume();

    // Master gain
    const master = ctx.createGain();
    master.gain.value = 0;
    master.connect(ctx.destination);

    // A soft reverb-ish convolution? Skip — use lowpass for warmth.
    const lp = ctx.createBiquadFilter();
    lp.type = 'lowpass';
    lp.frequency.value = 1800;
    lp.Q.value = 0.4;
    lp.connect(master);

    // Chord: Cmaj9-ish — C E G B D, low octave, gentle
    // Frequencies (Hz):
    const notes = [
      130.81, // C3
      164.81, // E3
      196.00, // G3
      246.94, // B3
      293.66, // D4
      329.63, // E4
    ];

    const oscs = [];
    const lfos = [];
    notes.forEach((freq, i) => {
      const osc = ctx.createOscillator();
      osc.type = i < 2 ? 'sine' : 'triangle';
      osc.frequency.value = freq;
      const g = ctx.createGain();
      g.gain.value = 0.018 + (i % 2) * 0.008;
      // LFO for slow swell
      const lfo = ctx.createOscillator();
      lfo.frequency.value = 0.05 + i * 0.013; // very slow
      const lfoGain = ctx.createGain();
      lfoGain.gain.value = 0.012;
      lfo.connect(lfoGain).connect(g.gain);
      osc.connect(g).connect(lp);
      osc.start();
      lfo.start();
      oscs.push(osc);
      lfos.push(lfo);
    });

    // Slight detune drift
    oscs.forEach((o, i) => {
      const drift = ctx.createOscillator();
      drift.frequency.value = 0.07 + i * 0.011;
      const driftGain = ctx.createGain();
      driftGain.gain.value = 1.4;
      drift.connect(driftGain).connect(o.detune);
      drift.start();
      lfos.push(drift);
    });

    master.gain.linearRampToValueAtTime(0.55, ctx.currentTime + 2.0);
    nodesRef.current = { master, oscs, lfos };
    setPlaying(true);
  }, [playing]);

  return { playing, start, stop, toggle: () => playing ? stop() : start() };
}

// ─────────────────────────────────────────────────────────────
// THE BOOK
// ─────────────────────────────────────────────────────────────

function Book() {
  const spreads = window.SPREADS;
  const total = spreads.length;
  const [idx, setIdx] = useState(0);
  const [flip, setFlip] = useState(null); // { dir: 'next'|'prev', from, to, t: 0..1 }
  const [scale, setScale] = useState(1);
  const [hover, setHover] = useState(null); // 'next' | 'prev' | null
  const stageRef = useRef(null);
  const music = useAmbientMusic();

  // Responsive scaling
  useEffect(() => {
    const fit = () => {
      const w = window.innerWidth;
      const h = window.innerHeight;
      const padX = w > 800 ? 100 : 40;
      const padY = w > 800 ? 140 : 100;
      const sw = (w - padX) / (PAGE_W * 2 + 16);
      const sh = (h - padY) / PAGE_H;
      const s = Math.min(sw, sh, 1.2);
      setScale(Math.max(0.4, s));
    };
    fit();
    window.addEventListener('resize', fit);
    return () => window.removeEventListener('resize', fit);
  }, []);

  const goTo = useCallback((targetIdx, direction) => {
    if (flip) return;
    if (targetIdx < 0 || targetIdx >= total) return;
    setFlip({ dir: direction, from: idx, to: targetIdx });
    setTimeout(() => {
      setIdx(targetIdx);
      setFlip(null);
    }, 950);
  }, [flip, idx, total]);

  const next = useCallback(() => goTo(idx + 1, 'next'), [goTo, idx]);
  const prev = useCallback(() => goTo(idx - 1, 'prev'), [goTo, idx]);

  // Keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'ArrowRight' || e.key === ' ') { e.preventDefault(); next(); }
      else if (e.key === 'ArrowLeft') { e.preventDefault(); prev(); }
      else if (e.key === 'Home') { e.preventDefault(); setIdx(0); }
      else if (e.key === 'End') { e.preventDefault(); setIdx(total - 1); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [next, prev, total]);

  const cur = spreads[idx];
  const nextSpread = spreads[idx + 1];
  const prevSpread = spreads[idx - 1];

  // Chapter awareness for header / status bar
  const chapterName = useMemo(() => {
    // Find most recent chapter-opener at or before idx
    for (let i = idx; i >= 0; i--) {
      if (spreads[i].kind === 'chapter-opener') return spreads[i].name;
    }
    return null;
  }, [idx, spreads]);

  // Progress
  const progress = ((idx + 1) / total) * 100;

  return (
    <div className="album-root">
      {/* Top bar */}
      <div className="top-bar">
        <div className="top-bar-left">
          <div className="top-mono">A · D</div>
          <div className="top-divider"/>
          <div className="top-title">A Wedding Story</div>
        </div>
        <div className="top-bar-right">
          {chapterName && <div className="top-chapter">{chapterName}</div>}
          <button
            className={`music-btn ${music.playing ? 'on' : ''}`}
            onClick={music.toggle}
            aria-label="Toggle music"
            title={music.playing ? 'Mute ambient music' : 'Play ambient music'}
          >
            <svg viewBox="0 0 20 20" width="14" height="14">
              {music.playing ? (
                <>
                  <path d="M3 7 L7 7 L11 3 L11 17 L7 13 L3 13 Z" fill="currentColor"/>
                  <path d="M13 6 Q16 10 13 14" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/>
                  <path d="M15 4 Q19 10 15 16" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/>
                </>
              ) : (
                <>
                  <path d="M3 7 L7 7 L11 3 L11 17 L7 13 L3 13 Z" fill="currentColor"/>
                  <line x1="13" y1="6" x2="18" y2="14" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/>
                  <line x1="18" y1="6" x2="13" y2="14" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/>
                </>
              )}
            </svg>
            <span>{music.playing ? 'Sound on' : 'Sound off'}</span>
          </button>
        </div>
      </div>

      {/* Stage */}
      <div className="stage-wrap">
        <div
          className="stage"
          ref={stageRef}
          style={{ transform: `translate(-50%, -50%) scale(${scale})` }}
        >
          <Book3D
            cur={cur}
            nextSpread={nextSpread}
            prevSpread={prevSpread}
            flip={flip}
            onNextClick={next}
            onPrevClick={prev}
            hover={hover}
            setHover={setHover}
            idx={idx}
            total={total}
          />
        </div>
      </div>

      {/* Bottom navigation */}
      <div className="bottom-bar">
        <button
          className="nav-btn nav-prev"
          onClick={prev}
          disabled={idx === 0 || !!flip}
          aria-label="Previous page"
        >
          <svg viewBox="0 0 20 20" width="14" height="14"><path d="M13 4 L7 10 L13 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>
          <span>Previous</span>
        </button>
        <div className="page-counter">
          <span className="counter-cur">{String(idx + 1).padStart(2, '0')}</span>
          <span className="counter-sep">/</span>
          <span className="counter-total">{String(total).padStart(2, '0')}</span>
          <div className="counter-bar"><div className="counter-fill" style={{width: `${progress}%`}}/></div>
        </div>
        <button
          className="nav-btn nav-next"
          onClick={next}
          disabled={idx === total - 1 || !!flip}
          aria-label="Next page"
        >
          <span>Next</span>
          <svg viewBox="0 0 20 20" width="14" height="14"><path d="M7 4 L13 10 L7 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 3D BOOK with flip animation
// ─────────────────────────────────────────────────────────────

function Book3D({ cur, nextSpread, prevSpread, flip, onNextClick, onPrevClick, hover, setHover, idx, total }) {
  // Layers:
  //   - bottom: static left page (cur.left during forward flip; cur.left during static)
  //   - bottom: static right page (when flipping forward: nextSpread.right; when flipping backward: prevSpread.left... wait)
  //   - flipping page (during animation)
  //
  // Static state: just render cur.left and cur.right.
  // Forward flip from cur=A to next=B:
  //   - Static left: A.left (stays)
  //   - Static right: B.right (revealed underneath)
  //   - Flipping page: front=A.right, back=B.left, rotates 0 → -180 around its LEFT edge (spine).
  // Backward flip from cur=A to prev=Z:
  //   - Static left: Z.left (revealed underneath)
  //   - Static right: A.right (stays)
  //   - Flipping page: front=A.left, back=Z.right, rotates 0 → +180 around its RIGHT edge (spine).
  //   (More naturally: we render it as if it starts on left and rotates to right.)
  //   - But for sympathy with the forward path, we'll do: flipping page sits on LEFT side initially showing A.left (its "front"), then rotates from 0 to +180 around its RIGHT edge.
  //   - Back face = Z.right (visible after rotation).

  const isFlipping = !!flip;
  const isCover = cur.kind === 'front-cover';
  const isBackCover = cur.kind === 'back-cover';

  // Static layers
  let staticLeftSpread = cur;
  let staticRightSpread = cur;
  if (flip && flip.dir === 'next') {
    staticLeftSpread = cur; // current spread's left stays
    staticRightSpread = nextSpread; // next spread's right is being revealed
  } else if (flip && flip.dir === 'prev') {
    staticLeftSpread = prevSpread; // prev spread's left is being revealed
    staticRightSpread = cur; // current spread's right stays
  }

  // Flip page content
  let flipFront = null, flipBack = null;
  if (flip && flip.dir === 'next') {
    flipFront = { spread: cur, side: 'right' };
    flipBack = { spread: nextSpread, side: 'left' };
  } else if (flip && flip.dir === 'prev') {
    flipFront = { spread: cur, side: 'left' };
    flipBack = { spread: prevSpread, side: 'right' };
  }

  // Whether arrow zones are active (hide on covers)
  const showNextZone = idx < total - 1 && !isFlipping;
  const showPrevZone = idx > 0 && !isFlipping;

  return (
    <div className={`book ${isCover ? 'book-closed' : ''} ${isBackCover ? 'book-end' : ''}`}>
      {/* Page-edge depth (book thickness) */}
      <div className="book-edges book-edges-left" style={{width: `${Math.max(2, idx * 0.4)}px`}}/>
      <div className="book-edges book-edges-right" style={{width: `${Math.max(2, (total - idx - 1) * 0.4)}px`}}/>

      {/* Cover binding for front cover */}
      {isCover && <div className="book-binding"/>}

      {/* Left page (static) */}
      <div className="page page-left">
        <div className="page-paper">
          <SpreadFace spread={staticLeftSpread} side="left"/>
          <div className="page-shadow-inner-left"/>
        </div>
      </div>

      {/* Right page (static) */}
      <div className="page page-right">
        <div className="page-paper">
          <SpreadFace spread={staticRightSpread} side="right"/>
          <div className="page-shadow-inner-right"/>
        </div>
      </div>

      {/* Spine */}
      <div className="book-spine"/>

      {/* Flipping page */}
      {flip && (
        <div className={`flip-page flip-${flip.dir}`}>
          <div className="flip-face flip-front">
            <div className="page-paper">
              <SpreadFace spread={flipFront.spread} side={flipFront.side}/>
              {flip.dir === 'next' && <div className="page-shadow-inner-left"/>}
              {flip.dir === 'prev' && <div className="page-shadow-inner-right"/>}
            </div>
          </div>
          <div className="flip-face flip-back">
            <div className="page-paper">
              <SpreadFace spread={flipBack.spread} side={flipBack.side}/>
              {flip.dir === 'next' && <div className="page-shadow-inner-right"/>}
              {flip.dir === 'prev' && <div className="page-shadow-inner-left"/>}
            </div>
          </div>
        </div>
      )}

      {/* Click zones for nav */}
      {showPrevZone && (
        <div
          className={`nav-zone nav-zone-left ${hover === 'prev' ? 'hover' : ''}`}
          onClick={onPrevClick}
          onMouseEnter={() => setHover('prev')}
          onMouseLeave={() => setHover(null)}
        >
          <div className="nav-zone-hint">
            <svg viewBox="0 0 20 20" width="22" height="22"><path d="M13 4 L7 10 L13 16" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </div>
        </div>
      )}
      {showNextZone && (
        <div
          className={`nav-zone nav-zone-right ${hover === 'next' ? 'hover' : ''}`}
          onClick={onNextClick}
          onMouseEnter={() => setHover('next')}
          onMouseLeave={() => setHover(null)}
        >
          <div className="nav-zone-hint">
            <svg viewBox="0 0 20 20" width="22" height="22"><path d="M7 4 L13 10 L7 16" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// MOUNT
// ─────────────────────────────────────────────────────────────

ReactDOM.createRoot(document.getElementById('root')).render(<Book/>);
