/* global React */
const { useState, useEffect, useRef } = React;

// ============ Nav ============
function Nav({ active, onNav }) {
  const [scrolled, setScrolled] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 40);
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // Close overlay when navigating
  const handleNav = id => {
    setMenuOpen(false);
    document.body.style.overflow = "";
    onNav(id);
  };

  // Lock body scroll when overlay is open
  useEffect(() => {
    document.body.style.overflow = menuOpen ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [menuOpen]);

  const links = [
    { id: "book-one", label: "Book One" },
    { id: "series", label: "The Series" },
    { id: "world", label: "The World" },
    { id: "map", label: "Thresholds" },
    { id: "characters", label: "Characters" },
    { id: "author", label: "Author" },
  ];
  return (
    <>
      <nav className={"nav " + (scrolled ? "scrolled" : "")}>
        <a href="#top" className="nav-brand" onClick={e => { e.preventDefault(); handleNav("top"); }}>
          <img src="assets/brand/jackal-stamp.png" alt=""/>
          <span>The Jackal Court</span>
        </a>
        <div className="nav-links">
          {links.map(l => (
            <a key={l.id} href={"#" + l.id}
               className={active === l.id ? "active" : ""}
               onClick={e => { e.preventDefault(); handleNav(l.id); }}>{l.label}</a>
          ))}
        </div>
        <button className="nav-cta" onClick={() => handleNav("author")}>Notify Me</button>
        <button
          className={"nav-hamburger " + (menuOpen ? "open" : "")}
          onClick={() => setMenuOpen(o => !o)}
          aria-label={menuOpen ? "Close menu" : "Open menu"}
          aria-expanded={menuOpen}
        >
          <span className="hb-line"/>
          <span className="hb-line"/>
          <span className="hb-line"/>
        </button>
      </nav>
      {menuOpen && (
        <div className="nav-overlay" onClick={() => setMenuOpen(false)} role="dialog" aria-modal="true">
          <div className="nav-overlay-inner" onClick={e => e.stopPropagation()}>
            <div className="overlay-brand">
              <span className="overline">The Jackal Court</span>
            </div>
            {links.map(l => (
              <a key={l.id} href={"#" + l.id}
                 className={"overlay-link " + (active === l.id ? "active" : "")}
                 onClick={e => { e.preventDefault(); handleNav(l.id); }}>
                {l.label}
              </a>
            ))}
            <button className="btn-primary overlay-cta" onClick={() => handleNav("author")}>
              Notify Me at Launch
            </button>
          </div>
        </div>
      )}
    </>
  );
}

// ============ Hero ============
const BOOK_ORDINALS = ['','One','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten'];
function pillarSub(book) {
  if (book.tagline) return book.tagline;
  if (book.blurb) return book.blurb.split(/\n\n/)[0].replace(/\*\*/g,'');
  return '';
}

function Hero({ onNav, onOpen }) {
  const books = window.JACKAL_COURT_BOOKS;
  const available = books.filter(b => b.status === 'available').sort((a,b) => a.n - b.n);
  const startHere = available[0];
  const latest    = available[available.length - 1];
  const showTwin  = available.length >= 2 && startHere.n !== latest.n;

  if (showTwin) {
    return (
      <section className="hero hero-twin" id="top">
        <div className="hero-bg-abstract">
          <div className="hero-grain"/>
          <div className="hero-glyph"/>
          <div className="hero-mist"/>
        </div>
        <div className="hero-inner">
          <div className="hero-head">
            <span className="overline">S. J. Kemet presents</span>
            <h1>The Jackal<br/><span className="gold">Court</span></h1>
            <p className="hero-tagline twin-tagline">
              A hidden world ruled by ancient beast-kin.<br/>
              Ten books. One woman who sees the pattern.
            </p>
          </div>
          <div className="twin">
            {/* Left pillar: Start Here */}
            <div className="pillar">
              <div className="pillar-label">Start Here</div>
              <div className="cover-frame pillar-cover-wrap">
                <div className="pillar-cover" style={{ backgroundImage: `url(${startHere.cover})` }}/>
              </div>
              <div className="pillar-meta">
                <div className="pillar-numeral">Book {BOOK_ORDINALS[startHere.n]}</div>
                <h2 className="pillar-title">{startHere.title}</h2>
                <p className="pillar-sub">{pillarSub(startHere)}</p>
                <button className="btn-primary pillar-btn" onClick={() => onOpen(startHere)}>Begin the Series</button>
              </div>
            </div>
            <div className="twin-divider"/>
            {/* Right pillar: Latest Release */}
            <div className="pillar pillar-latest">
              <div className="latest-ribbon">Just Released</div>
              <div className="pillar-label">Latest Release</div>
              <div className="cover-frame pillar-cover-wrap">
                <div className="pillar-cover" style={{ backgroundImage: `url(${latest.cover})` }}/>
              </div>
              <div className="pillar-meta">
                <div className="pillar-numeral">Book {BOOK_ORDINALS[latest.n]}</div>
                <h2 className="pillar-title">{latest.title}</h2>
                <p className="pillar-sub">{pillarSub(latest)}</p>
                <button className="btn-ghost pillar-btn" onClick={() => onOpen(latest)}>Read Book {BOOK_ORDINALS[latest.n]}</button>
              </div>
            </div>
          </div>
          <div className="hero-meta twin-meta">
            <span><i className="dot"/>Monster Romance</span>
            <span><i className="dot"/>Egyptian Mythology</span>
            <span><i className="dot"/>Neurodivergent Leads</span>
          </div>
        </div>
        <div className="scroll-cue"><span>Scroll</span><div className="line"/></div>
      </section>
    );
  }

  // Single hero (only book 1 available)
  return (
    <section className="hero" id="top">
      <div className="hero-bg-abstract">
        <div className="hero-grain"/>
        <div className="hero-glyph"/>
        <div className="hero-mist"/>
      </div>
      <div className="hero-content">
        <div className="hero-copy">
          <span className="overline">S. J. Kemet presents</span>
          <h1>
            The Jackal<br/>
            <span className="gold">Court</span>
          </h1>
          <p className="hero-tagline">
            A hidden world ruled by ancient beast-kin.<br/>
            Ten books. One woman who sees the pattern.
          </p>
          <div className="hero-meta">
            <span><i className="dot"/>Monster Romance</span>
            <span><i className="dot"/>Egyptian Mythology</span>
            <span><i className="dot"/>Neurodivergent Leads</span>
          </div>
          <div className="hero-ctas">
            <a className="btn-primary" href="#book-one" onClick={e => { e.preventDefault(); onNav("book-one"); }}>
              Begin with Book One
            </a>
            <a className="btn-ghost" href="#series" onClick={e => { e.preventDefault(); onNav("series"); }}>
              The Full Series
            </a>
          </div>
        </div>
        <div className="hero-cover-frame cover-frame">
          <div className="hero-cover" style={{ backgroundImage: `url(${window.JACKAL_COURT_BOOKS[0].cover})` }}/>
        </div>
      </div>
      <div className="scroll-cue">
        <span>Scroll</span>
        <div className="line"/>
      </div>
    </section>
  );
}

// ============ Featured Book ============
function Featured({ onOpen }) {
  const settings = window.JACKAL_COURT_SETTINGS || {};
  const featuredN = settings.featuredBookNumber || 1;
  const book = window.JACKAL_COURT_BOOKS.find(b => b.n === featuredN) || window.JACKAL_COURT_BOOKS[0];
  const ordinal = BOOK_ORDINALS[book.n] || String(book.n);
  return (
    <section className="featured" id="book-one">
      <div className="section-inner">
        <div className="section-header" style={{ marginBottom: 56 }}>
          <div className="ornament"><span className="diamond"/></div>
          <span className="overline">Begin Here</span>
          <h2>Book {ordinal}</h2>
          <p>The first binding in four thousand years of guild record.</p>
        </div>
        <div className="featured-grid">
          <div className="featured-cover" style={{ backgroundImage: `url(${book.cover})` }}/>
          <div className="featured-copy">
            <span className="overline">Book {ordinal} · The Jackal Court</span>
            <h2>{book.title}</h2>
            <p className="featured-tagline">{book.tagline}</p>

            <div className="meta-grid">
              <div className="meta-item">
                <span className="ui-label">Setting</span>
                <span className="v">{book.setting}</span>
              </div>
              <div className="meta-item">
                <span className="ui-label">Heat</span>
                <span className="v">{book.heat}</span>
              </div>
              <div className="meta-item">
                <span className="ui-label">Neurotype</span>
                <span className="v">{book.nd}</span>
              </div>
              <div className="meta-item">
                <span className="ui-label">Length</span>
                <span className="v">{book.length}</span>
              </div>
            </div>

            <div className="blurb">
              {book.blurb.split(/\n\n+/).map((para, i) => <p key={i}>{para}</p>)}
            </div>

            <div className="tropes">
              {book.tropes.map(t => <span key={t} className="trope">{t}</span>)}
            </div>

            <details className="warnings">
              <summary>Content & Trigger Warnings</summary>
              <ul>
                {book.warnings.map((w, i) => <li key={i}>{w}</li>)}
              </ul>
            </details>

            <div className="hero-ctas" style={{ marginTop: 40 }}>
              {book.retailers?.amazon ? (
                <a className="btn-primary" href={book.retailers.amazon} target="_blank" rel="noopener noreferrer">Buy on Amazon</a>
              ) : (
                <a className="btn-primary" href="#notify" onClick={e => { e.preventDefault(); document.getElementById("author").scrollIntoView({behavior:"smooth"}); }}>Notify Me at Launch</a>
              )}
              <button className="btn-ghost" onClick={() => onOpen(book)}>Read Excerpt</button>
            </div>
            {book.retailers && (book.retailers.kobo || book.retailers.apple || book.retailers.bol) && (
              <div className="retailer-links">
                {book.retailers.kobo  && <a href={book.retailers.kobo}  target="_blank" rel="noopener noreferrer">Kobo</a>}
                {book.retailers.apple && <a href={book.retailers.apple} target="_blank" rel="noopener noreferrer">Apple Books</a>}
                {book.retailers.bol   && <a href={book.retailers.bol}   target="_blank" rel="noopener noreferrer">Bol.com</a>}
              </div>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

// ============ Series grid ============
function Series({ onOpen }) {
  const verbLine = window.JACKAL_COURT_BOOKS.map(b =>
    b.status === "veiled" ? "…" : (b.verb || "…")
  ).join(". ") + ".";
  return (
    <section className="books" id="series">
      <div className="section-inner">
        <div className="section-header">
          <div className="ornament"><span className="diamond"/></div>
          <span className="overline">The Complete Ten</span>
          <h2>A Ladder of Emotional Intensity</h2>
          <p>{verbLine}<br/>
            Each book stands alone. Together they carry a three-thousand-year reckoning.</p>
        </div>
        <div className="books-grid">
          {window.JACKAL_COURT_BOOKS.map(b => <BookCard key={b.n} book={b} onOpen={onOpen}/>)}
        </div>
      </div>
    </section>
  );
}

function BookCard({ book, onOpen }) {
  const isVeiled    = book.status === "veiled";
  const isAnnounced = book.status === "announced";
  const isAvailable = book.status === "available";
  const sealed = book.status === "coming" || isVeiled;
  const cls = "book-card " + (sealed ? "sealed " : "open ") + (isVeiled ? "veiled " : "") + (isAnnounced ? "announced" : "");
  return (
    <button className={cls} onClick={() => onOpen(book)}>
      <div className="book-cover-wrap">
        {sealed ? (
          <div className="sealed-file">
            <div className="sealed-grain"/>
            <div className="sealed-corner tl"/>
            <div className="sealed-corner tr"/>
            <div className="sealed-corner bl"/>
            <div className="sealed-corner br"/>
            <div className="sealed-body">
              <div className="sealed-roman">{book.numeral}</div>
              {!isVeiled && (
                <div className="sealed-verb">{book.verb || "Sealed"}</div>
              )}
              <div className="sealed-rule"/>
              <div className="sealed-status">{isVeiled ? "Finale · Veiled" : book.statusLabel}</div>
            </div>
            <div className="wax-seal">
              <div className="wax-ring">
                <div className="wax-glyph">JC</div>
              </div>
            </div>
          </div>
        ) : (
          <div className="book-cover-img" style={{ backgroundImage: `url(${book.cover})` }}/>
        )}
      </div>
      <div className="book-info">
        <div className="book-num">
          Book {book.numeral}
          {isAvailable  && <span className="book-num-badge">Available</span>}
          {isAnnounced  && <span className="book-num-badge announced-badge">Coming Soon</span>}
        </div>
        <div className="book-title">
          {isVeiled
            ? <span className="muted-it">— sealed —</span>
            : (sealed ? null : book.title)}
        </div>
        <div className="book-meta">
          {isVeiled ? "Revealed upon release" : (sealed ? null : `${book.setting} · ${book.nd}`)}
        </div>
      </div>
    </button>
  );
}

// ============ World ============
function World() {
  const codex = window.JACKAL_COURT_CODEX || [];
  if (codex.length === 0) return null;
  return (
    <section className="world" id="world">
      <div className="section-inner">
        <div className="section-header">
          <div className="ornament"><span className="diamond"/></div>
          <span className="overline">The Hidden World</span>
          <h2>Codex of the Guild</h2>
          <p>The gods did not vanish. They stepped sideways, and stayed.</p>
        </div>
        <div className="codex-grid">
          {codex.map((c, i) => (
            <div className="codex-card" key={c.slug}>
              <div className="num">{String(i+1).padStart(2,"0")}</div>
              <h3>{c.title}</h3>
              <div className="short">{c.short}</div>
              <div className="body">{c.body}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ============ Characters ============
function Characters() {
  // Only show cast whose book is already available — avoid spoilers.
  const maxBook = Math.max(...window.JACKAL_COURT_BOOKS.filter(b => b.status === "available" || b.status === "announced").map(b => b.n));
  const cast = window.JACKAL_COURT_CAST.filter(c => c.book <= maxBook);
  return (
    <section className="characters" id="characters">
      <div className="section-inner">
        <div className="section-header">
          <div className="ornament"><span className="diamond"/></div>
          <span className="overline">The Court · Book One Roster</span>
          <h2>Those You Meet First</h2>
          <p>The cast seen, or glimpsed, in Book One. More names will be added to this page as the series releases.</p>
        </div>
        <div className="cast-grid">
          {cast.map(c => (
            <div className="cast-card" key={c.name}>
              <h3 className="cast-name">{c.name}</h3>
              <div className="cast-line">{c.line}</div>
              <div className="cast-meta">
                <span>{c.age}</span>
                <span>{c.role}</span>
              </div>
              <p className="cast-desc">{c.desc}</p>
            </div>
          ))}
          <div className="cast-card cast-card--placeholder">
            <h3 className="cast-name" style={{ opacity: 0.35 }}>· · ·</h3>
            <div className="cast-line" style={{ opacity: 0.4 }}>More to come</div>
            <p className="cast-desc" style={{ opacity: 0.35, fontStyle: "italic" }}>
              New names are added to this page with each book in the series.
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

// ============ Author / Signup ============
function Author() {
  const kitRef = useRef(null);

  useEffect(() => {
    if (!kitRef.current) return;
    // Load ck.5.js once
    if (!document.querySelector('script[src*="ckjs/ck.5.js"]')) {
      const ck = document.createElement("script");
      ck.src = "https://f.convertkit.com/ckjs/ck.5.js";
      document.head.appendChild(ck);
    }
    // Load the form script (self-renders into kitRef container)
    const s = document.createElement("script");
    s.async = true;
    s.setAttribute("data-uid", "02e9712c08");
    s.src = "https://s-j-kemet.kit.com/02e9712c08/index.js";
    kitRef.current.appendChild(s);
  }, []);

  return (
    <section className="author" id="author">
      <div className="section-inner author-inner">
        <div className="author-wordmark">
          <span className="aw-initials">S. J.</span>
          <span className="aw-name">Kemet</span>
        </div>
        <p className="statement">
          "I write the women who notice what others cannot. The ancient beings who have spent too long alone. The love that arrives the way it was always going to."
        </p>
        <p className="note">
          I started The Jackal Court because I wanted monster romance that took its heroines seriously —
          not in spite of their minds, but entirely because of them. Nadia is autistic.
          The second heroine has ADHD. Every heroine in this series thinks differently,
          and that difference is the reason she matters.
        </p>
        <p className="note">
          Ten books. One hidden world that has been waiting for exactly them.
        </p>
        <div ref={kitRef} className="kit-form-wrap"/>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer>
      <div className="row"><strong>The Jackal Court</strong> · by S. J. Kemet</div>
      <div className="row">Ten books · Spicy monster romance · Egyptian mythology · Neurodivergent heroines</div>
      <div className="footer-social">
        <a href="https://www.instagram.com/sj.kemet/" target="_blank" rel="noopener noreferrer" aria-label="Instagram">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <rect x="2" y="2" width="20" height="20" rx="5" ry="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="0.5" fill="currentColor" stroke="none"/>
          </svg>
          Instagram
        </a>
        <a href="https://www.pinterest.com/sjkemet/" target="_blank" rel="noopener noreferrer" aria-label="Pinterest">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 0C5.373 0 0 5.373 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 0 1 .083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.632-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12S18.627 0 12 0z"/>
          </svg>
          Pinterest
        </a>
        <a href="https://www.tiktok.com/@sjkemet" target="_blank" rel="noopener noreferrer" aria-label="TikTok">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
            <path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.33 6.33 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.69a8.18 8.18 0 0 0 4.78 1.52V6.75a4.85 4.85 0 0 1-1.01-.06z"/>
          </svg>
          TikTok
        </a>
      </div>
      <div className="row" style={{ marginTop: 24 }}>© 2026 S. J. Kemet · All rights reserved</div>
    </footer>
  );
}

// ============ Modal ============
function BookModal({ book, onClose }) {
  useEffect(() => {
    const onEsc = e => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onEsc);
    document.body.style.overflow = "hidden";
    return () => {
      document.removeEventListener("keydown", onEsc);
      document.body.style.overflow = "";
    };
  }, [onClose]);
  if (!book) return null;

  const isVeiled    = book.status === "veiled";
  const isAnnounced = book.status === "announced";
  const isAvailable = book.status === "available";
  const sealed = book.status === "coming" || isVeiled;

  // Sealed view: minimal spoiler-free display
  if (sealed) {
    return (
      <div className="modal-backdrop" onClick={onClose}>
        <div className="modal" onClick={e => e.stopPropagation()}>
          <button className="modal-close" onClick={onClose}>×</button>
          <div className="modal-grid">
            <div>
              <div className="modal-cover" style={{ background: "radial-gradient(circle at center, #1a120a, #0a0604)", display:"flex", alignItems:"center", justifyContent:"center" }}>
                <div style={{ textAlign:"center", color:"var(--gold)", fontFamily:"Cinzel", letterSpacing:"0.25em" }}>
                  <div style={{ fontSize: 36, marginBottom: 12 }}>{book.numeral}</div>
                  {isVeiled && <div style={{ fontSize: 11, opacity: 0.6 }}>VEILED</div>}
                </div>
              </div>
            </div>
            <div>
              <div className="modal-num">Book {book.numeral} · The Jackal Court</div>
              <h2 style={{ fontFamily:"Cinzel", color:"var(--gold)" }}>{book.numeral}</h2>
              <div className="meta-grid" style={{ marginTop: 16 }}>
                <div className="meta-item">
                  <span className="ui-label">Status</span>
                  <span className="v" style={{ color: "var(--paper)" }}>{book.statusLabel}</span>
                </div>
              </div>
              <p style={{ marginTop: 28, fontStyle: "italic", opacity: 0.65, lineHeight: 1.7 }}>
                Details revealed closer to release.
              </p>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // Full view: available books
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()}>
        <button className="modal-close" onClick={onClose}>×</button>
        <div className="modal-grid">
          <div>
            <div className="modal-cover" style={{ backgroundImage: `url(${book.cover})` }}/>
          </div>
          <div>
            <div className="modal-num">Book {book.numeral} · The Jackal Court</div>
            <h2>{book.title}</h2>
            <div className="fmc-line">{book.mmc} × {book.fmc}</div>
            <div className="meta-grid" style={{ marginTop: 8 }}>
              <div className="meta-item"><span className="ui-label">Status</span><span className="v" style={{ color: isAvailable ? "var(--amber)" : "var(--gold)" }}>{book.statusLabel}</span></div>
              <div className="meta-item"><span className="ui-label">Setting</span><span className="v">{book.setting}</span></div>
              <div className="meta-item"><span className="ui-label">Neurotype</span><span className="v">{book.nd}</span></div>
              <div className="meta-item"><span className="ui-label">Heat</span><span className="v">{book.heat}</span></div>
            </div>
            <p className="featured-tagline" style={{ fontSize: 20, marginTop: 24 }}>{book.tagline}</p>
            {book.blurb ? (
              <div className="blurb">
                {book.blurb.split(/\n\n+/).map((para, i) => <p key={i}>{para}</p>)}
              </div>
            ) : (
              <div className="blurb" style={{ color: "var(--paper-mute)" }}>{book.logline}</div>
            )}
            {book.tropes && (
              <div className="tropes">
                {book.tropes.map(t => <span key={t} className="trope">{t}</span>)}
              </div>
            )}
            {book.excerpt && (
              <div className="excerpt-block">
                <div className="excerpt-divider"><span>· First Pages ·</span></div>
                <div className="excerpt-body">
                  {book.excerpt.split(/\n\n+/).map((para, i) => {
                    const isHeading = para.startsWith("**") && para.endsWith("**");
                    const isAside = para.startsWith("*[") && para.endsWith("]*");
                    if (isHeading) {
                      return <h4 key={i} className="excerpt-heading">{para.replace(/\*\*/g, "")}</h4>;
                    }
                    if (isAside) {
                      return <p key={i} className="excerpt-aside">{para.replace(/^\*\[|\]\*$/g, "")}</p>;
                    }
                    // Inline italic *x*
                    const parts = para.split(/(\*[^*]+\*)/g);
                    return (
                      <p key={i}>
                        {parts.map((p, j) =>
                          p.startsWith("*") && p.endsWith("*")
                            ? <em key={j}>{p.slice(1, -1)}</em>
                            : p
                        )}
                      </p>
                    );
                  })}
                </div>
              </div>
            )}
            {book.retailers && (book.retailers.amazon || book.retailers.kobo || book.retailers.apple || book.retailers.bol) && (
              <div className="retailer-links" style={{ marginTop: 28 }}>
                {book.retailers.amazon && <a className="btn-primary" href={book.retailers.amazon} target="_blank" rel="noopener noreferrer">Buy on Amazon</a>}
                {book.retailers.kobo   && <a className="btn-ghost"   href={book.retailers.kobo}   target="_blank" rel="noopener noreferrer">Kobo</a>}
                {book.retailers.apple  && <a className="btn-ghost"   href={book.retailers.apple}  target="_blank" rel="noopener noreferrer">Apple Books</a>}
                {book.retailers.bol    && <a className="btn-ghost"   href={book.retailers.bol}    target="_blank" rel="noopener noreferrer">Bol.com</a>}
              </div>
            )}
            {book.warnings && (
              <details className="warnings">
                <summary>Content & Trigger Warnings</summary>
                <ul>{book.warnings.map((w,i) => <li key={i}>{w}</li>)}</ul>
              </details>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

// ============ If You Loved ============
function IfYouLoved() {
  return (
    <section className="loved" id="loved">
      <div className="section-inner">
        <div className="loved-statement">
          <div className="ornament"><span className="diamond"/></div>
          <p className="loved-lede">
            For readers of <em>Sarah&nbsp;J.&nbsp;Maas</em>, <em>Jennifer&nbsp;L.&nbsp;Armentrout</em>, and <em>Ruby&nbsp;Dixon</em>.
          </p>
          <p className="loved-tail">
            Monster romance written with reverence. Fated binding. Touch-starved guardians four thousand years old. Heroines the world already gave up on.
          </p>
        </div>
      </div>
    </section>
  );
}

// ============ Threshold Map ============
function ThresholdMap() {
  const thresholds = window.JACKAL_COURT_THRESHOLDS || [];
  const [active, setActive] = useState(null);
  const activeT = thresholds.find(t => t.n === active) || null;

  return (
    <section className="thresholds" id="map">
      <div className="section-inner">
        <div className="section-header">
          <div className="ornament"><span className="diamond"/></div>
          <span className="overline">Guild Cartography</span>
          <h2>Eight Thresholds. Six Known.</h2>
          <p>Specific places in the world where the boundary between the hidden world and the human one grows thin. They look like ordinary places. They are not.</p>
        </div>
        <div className="threshold-layout">
          <div className="map-frame">
            <div className="map-inner">
              <img src="assets/brand/map-mediterranean.png" alt="" className="map-bg" draggable="false"/>
              {thresholds.map(t => (
                <button
                  key={t.n}
                  className={`threshold-pin ${t.status} ${active === t.n ? "active" : ""}`}
                  style={{ left: `${t.x}%`, top: `${t.y}%` }}
                  onClick={() => setActive(active === t.n ? null : t.n)}
                  aria-label={`Threshold ${t.n}, ${t.city}`}
                >
                  <span className="pin-core"/>
                  <span className="pin-ring"/>
                  <span className="pin-label">{String(t.n).padStart(2,"0")}</span>
                </button>
              ))}
            </div>
          </div>
          <div className="threshold-panel">
            <div className="panel-head">
              <span className="overline">Current Status</span>
              <div className="legend">
                <span className="l-item"><i className="l-dot intact"/>Intact</span>
                <span className="l-item"><i className="l-dot unrecorded"/>Unrecorded</span>
              </div>
              <p className="legend-note">More statuses — <em>contested</em>, <em>lost</em> — will appear on this map as the series releases.</p>
            </div>
            {activeT ? (
              <div className="panel-active">
                <div className="panel-n">Threshold {String(activeT.n).padStart(2,"0")}</div>
                <h3 className="panel-city">{activeT.city}</h3>
                <div className={`panel-status ${activeT.status}`}>
                  {activeT.status === "unrecorded" ? "Unrecorded in any Guild archive" : activeT.status.charAt(0).toUpperCase() + activeT.status.slice(1)}
                </div>
                <p className="panel-disg">{activeT.disguise}</p>
                <button className="panel-back" onClick={() => setActive(null)}>← All thresholds</button>
              </div>
            ) : (
              <ul className="panel-list">
                {thresholds.map(t => (
                  <li key={t.n}>
                    <button onClick={() => setActive(t.n)}>
                      <span className={`l-dot ${t.status}`}/>
                      <span className="p-n">{String(t.n).padStart(2,"0")}</span>
                      <span className="p-city">{t.city}</span>
                      <span className={`p-status ${t.status}`}>
                        {t.status === "unrecorded" ? "unrecorded" : t.status}
                      </span>
                    </button>
                  </li>
                ))}
              </ul>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Nav, Hero, Featured, IfYouLoved, Series, World, ThresholdMap, Characters, Author, Footer, BookModal });
