// app.jsx — ALIENINTEL · deep navy intelligence

const { useState, useEffect, useRef } = React;

// ==================== MOTION ====================
// Lightweight motion primitives that match Framer Motion's "reveal on scroll"
// pattern. Drives the .m-* classes defined in index.html.

function useReveal({ once = true, threshold = 0.18, rootMargin = "0px 0px -8% 0px", initialDelay = 0 } = {}) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (typeof IntersectionObserver === "undefined") { setShown(true); return; }
    // above-the-fold: kick off after a short initial delay
    const rect = el.getBoundingClientRect();
    if (rect.top < window.innerHeight) {
      const id = setTimeout(() => setShown(true), initialDelay);
      return () => clearTimeout(id);
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setShown(true);
          if (once) io.disconnect();
        } else if (!once) {
          setShown(false);
        }
      });
    }, { threshold, rootMargin });
    io.observe(el);
    return () => io.disconnect();
  }, [once, threshold, rootMargin, initialDelay]);
  return [ref, shown];
}

// Reveal — wraps children in a div.m-{variant} that flips to .in when visible.
// Usage: <Reveal variant="up" delay={120}>...</Reveal>
function Reveal({ as: Tag = "div", variant = "up", delay = 0, stagger = false, className = "", style, children, ...rest }) {
  const [ref, shown] = useReveal({ initialDelay: delay });
  const cls =
    "m-" + variant +
    (stagger ? " m-stagger" : "") +
    (shown ? " in" : "") +
    (className ? " " + className : "");
  const mergedStyle = delay && shown ? { ...style, transitionDelay: `${delay}ms` } : style;
  return <Tag ref={ref} className={cls} style={mergedStyle} {...rest}>{children}</Tag>;
}

// Words — splits a string into per-word spans for headline reveals.
// Tokens accept either strings (split into words) or {text, em} objects
// (rendered inside <em> with the gradient fill). Brk = <br/>.
function Words({ tokens, delay = 0, step = 60, className = "" }) {
  const [ref, shown] = useReveal({ initialDelay: delay });
  let wordIdx = 0;
  return (
    <span ref={ref} className={className}>
      {tokens.map((tok, i) => {
        if (tok === "brk") return <br key={i} />;
        const isEm = typeof tok === "object";
        const text = isEm ? tok.text : tok;
        const parts = text.split(/(\s+)/);
        const inner = parts.map((p, j) => {
          if (/^\s+$/.test(p)) return p;
          const myIdx = wordIdx++;
          return (
            <span
              key={`${i}-${j}`}
              className={"m-word" + (shown ? " in" : "")}
              style={{ transitionDelay: `${myIdx * step}ms` }}
            >
              {p}
            </span>
          );
        });
        return isEm ? <em key={i}>{inner}</em> : <React.Fragment key={i}>{inner}</React.Fragment>;
      })}
    </span>
  );
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "agentName": "ALIENINTEL",
  "modelTag": "alienintel-2.6",
  "liveTicker": true
}/*EDITMODE-END*/;

const fmtNum = (n) => n.toLocaleString("en-US");

// ---------- TOKEN ----------
const TOKEN_CA = "CUmBsqyPbpeZRGKZC6oWafiPFeACDKgah6WgUbkwpump";
const PUMP_URL = `https://pump.fun/coin/${TOKEN_CA}`;

function CABar() {
  const [copied, setCopied] = useState(false);
  const onCopy = () => {
    if (!navigator.clipboard) return;
    navigator.clipboard.writeText(TOKEN_CA).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1400);
    }).catch(() => {});
  };
  const short = TOKEN_CA.slice(0, 6) + "…" + TOKEN_CA.slice(-6);
  return (
    <div className="cabar">
      <div className="cabar-inner">
        <span className="tag">$ALIENINTEL · CA</span>
        <button
          className={"ca" + (copied ? " copied" : "")}
          onClick={onCopy}
          title="Copy contract address"
          aria-label="Copy contract address"
        >
          <span className="ca-full">{TOKEN_CA}</span>
          <span className="ca-mob">{short}</span>
          <svg className="copy-ico" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            {copied ? (
              <path d="M5 13l4 4L19 7" />
            ) : (
              <>
                <rect x="9" y="9" width="13" height="13" rx="2" />
                <path d="M5 15V5a2 2 0 0 1 2-2h10" />
              </>
            )}
          </svg>
        </button>
        <a className="pump" href={PUMP_URL} target="_blank" rel="noopener noreferrer">
          Buy on pump.fun ↗
        </a>
      </div>
    </div>
  );
}

// ---------- NAV ----------
function Nav({ t }) {
  return (
    <nav className="nav">
      <div className="container">
        <div className="nav-inner">
          <a className="brand" href="#top">
            <span className="brand-mark"><img src="logo.png" alt="" /></span>
            <span>{t.agentName}</span>
          </a>
          <div className="nav-links">
            <a href="#agent">Agent</a>
            <a href="#terminal">Terminal</a>
            <a href="#dossiers">Dossiers</a>
            <a href="#files">Files</a>
            <a href="#method">Methodology</a>
            <a href="chat.html">Chat</a>
          </div>
          <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
            <a className="nav-x" href="https://x.com/alienintelfun" target="_blank" rel="noopener noreferrer" aria-label="Follow on X">
              <svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
            </a>
            <span className="clearance">
              <span className="dot"></span>
              Clearance · Public
            </span>
            <a className="btn btn-primary" href="chat.html">Talk to agent →</a>
          </div>
        </div>
      </div>
    </nav>
  );
}

// ---------- HERO ----------
function Hero({ t }) {
  return (
    <section id="top" className="hero">
      <div className="container">
        <Reveal as="span" variant="up" delay={150} className="hero-eyebrow">
          <span className="live-dot"></span>
          The first autonomous alien-intelligence AI agent
        </Reveal>
        <h1>
          <Words
            tokens={["Interrogate the ", { text: "files", em: true }, "brk", "they just released."]}
            delay={280}
            step={45}
          />
        </h1>
        <Reveal as="p" variant="up" delay={520} className="lede">
          {t.agentName} has read FBI file <b style={{ color: "var(--cyan)" }}>62-HQ-83894</b> — the Bureau's master file on flying-disc reports, 1944–1973, declassified by the Department of Defense on 8 May 2026 as part of PURSUE Release 01. Six sections. 1,262 OCR'd pages. Ask it anything. It answers with citations, confidence, and a chain of provenance.
        </Reveal>
        <Reveal variant="up" delay={620} className="hero-cta">
          <a className="btn btn-primary" href="chat.html">Open the terminal →</a>
          <a className="btn" href="#dossiers">Explore dossiers</a>
        </Reveal>

        <Reveal variant="up" delay={720} stagger className="dossier-float">
          <div className="dfx">
            <div className="meta">FILE · 62-HQ-83894</div>
            <h4>Hottel memo · 22 Mar 1950</h4>
            <p>Single-page memorandum from SAC Guy Hottel of the Washington Field Office to Director Hoover, relaying a third-hand claim of three discs and three small bodies recovered in New Mexico. The most-downloaded item from the FBI Vault.</p>
            <div className="ftr"><span>Serial 62-83894-209</span><span className="conf">SECTION 5 · p.68</span></div>
          </div>
          <div className="dfx">
            <div className="meta">FILE · 62-HQ-83894</div>
            <h4>Kenneth Arnold · 24 Jun 1947</h4>
            <p>The origin event of the modern UFO phenomenon. Nine objects in chain formation, 1m 42s traversal at ~9,500 ft. CIC investigator Frank M. Brown's credibility assessment is in the file: <em>"could very possibly be facts."</em></p>
            <div className="ftr"><span>Serial 62-83894-95</span><span className="conf">SECTION 2 · pp.159–167</span></div>
          </div>
          <div className="dfx">
            <div className="meta">FILE · 62-HQ-83894</div>
            <h4>Davidson–Brown B-25 · Aug 1947</h4>
            <p>Memo reference to the 1 Aug 1947 fatal crash of the AAF Counter-Intelligence investigators flying Maury Island slag samples to Hamilton Field. Tacoma SAC's eventual verdict on the broader Dahl/Crisman claim: fabrication.</p>
            <div className="ftr"><span>Section 2 · p.50</span><span className="conf">FBI · TAC</span></div>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- AGENT OVERVIEW ----------
function AgentOverview({ t }) {
  const caps = [
    { ic: "01", h: "Read every cable, memo, and serial", d: "1,612 pages of FBI 62-HQ-83894 indexed page-by-page. SAC cables, citizen letters, lab analyses, interagency referrals — all addressable by serial number." },
    { ic: "02", h: "Summarize a 1,612-page file series", d: "Compresses 80 years of Bureau handling into structured briefs. Every claim links back to its source serial and page span." },
    { ic: "03", h: "Cross-reference SACs, dates, witnesses", d: "Entity graph across 161 documents. Surfaces the chain from Arnold to Hottel to Hoover that no single serial contains." },
    { ic: "04", h: "Reconstruct the 1947–1949 timeline", d: "Builds the event sequence from fragmentary cables. Where the Bureau closed an inquiry without recording why, the gap is visible — not hidden." },
    { ic: "05", h: "Detect Bureau contradictions", d: "Flags moments where the file conflicts with itself — Roswell wire vs. RAAF press release, Hoover's 1947 annotation vs. his 1949 directive. Both sides cited." },
    { ic: "06", h: "Separate evidence from claim", d: "Every claim labelled — first-hand SAC interview, third-hand AAF referral, anonymous citizen letter, or forwarded press clipping. The agent never collapses them." },
  ];
  return (
    <section id="agent" className="wrap">
      <div className="container">
        <Reveal variant="up" className="section-head">
          <span className="bracket">01 · agent overview</span>
          <h2>Six capabilities. <em>One investigator.</em></h2>
          <p>{t.agentName} is not a chatbot. It is a research agent built around a single corpus — FBI file 62-HQ-83894 — with a single discipline: read every serial, cite the source, label what's uncertain.</p>
        </Reveal>
        <Reveal variant="up" stagger className="cap-grid">
          {caps.map((c) => (
            <div className="cap" key={c.h}>
              <div className="ico">{c.ic}</div>
              <h4>{c.h}</h4>
              <p>{c.d}</p>
            </div>
          ))}
        </Reveal>
      </div>
    </section>
  );
}

// ---------- TERMINAL DEMO (cinematic) ----------
const TERMINAL_QUERY = "What do the released files say about recovered materials?";
const TERMINAL_PHASES = [
  { key: "scan", label: "Scanning 161 documents", ms: 900 },
  { key: "cross", label: "Cross-referencing serials", ms: 850 },
  { key: "verify", label: "Verifying chain of custody", ms: 950 },
  { key: "score", label: "Calculating confidence", ms: 800 },
];
const TERMINAL_FILES = [
  { name: "Dallas SAC → Hoover · Roswell wire", pp: "SER-026", w: 96, ico: "S" },
  { name: "Maury Island investigation summary", pp: "SER-014", w: 88, ico: "S" },
  { name: "Twin Falls fragment lab analysis", pp: "SER-029", w: 84, ico: "S" },
  { name: "Section 2 · 1947 disc wave", pp: "SEC-02", w: 91, ico: "S" },
];
const TERMINAL_EVENTS = [
  { yr: "1947", ttl: "Roswell · Dallas SAC wires Hoover, 8 Jul", tag: "SER-026" },
  { yr: "1947", ttl: "Maury Island · Tacoma SAC closes file as fabrication", tag: "SER-014" },
  { yr: "1950", ttl: "Hottel memo · 'three discs, three bodies'", tag: "SER-130" },
];

function useInView(ref, { once = true, threshold = 0.25 } = {}) {
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el || typeof IntersectionObserver === "undefined") { setSeen(true); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setSeen(true);
          if (once) io.disconnect();
        }
      });
    }, { threshold });
    io.observe(el);
    return () => io.disconnect();
  }, [ref, once, threshold]);
  return seen;
}

function TerminalDemo() {
  const wrapRef = React.useRef(null);
  const inView = useInView(wrapRef, { once: true, threshold: 0.2 });

  // sequence state
  const [stage, setStage] = useState("idle");        // idle → typing → analyzing → results → done
  const [typed, setTyped] = useState("");
  const [phaseIdx, setPhaseIdx] = useState(-1);      // which status row is active/done
  const [progress, setProgress] = useState(0);       // 0..100
  const [results, setResults] = useState(0);         // how many result sections revealed
  const [clock, setClock] = useState("00:00:00");

  // live UTC clock (terminal header)
  useEffect(() => {
    const tick = () => {
      const d = new Date();
      const z = (n) => String(n).padStart(2, "0");
      setClock(`${z(d.getUTCHours())}:${z(d.getUTCMinutes())}:${z(d.getUTCSeconds())} UTC`);
    };
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []);

  // master sequence — fires when terminal scrolls into view
  useEffect(() => {
    if (!inView) return;
    const timers = [];
    const t = (fn, ms) => { timers.push(setTimeout(fn, ms)); };

    // 1) typing
    t(() => setStage("typing"), 400);
    TERMINAL_QUERY.split("").forEach((_, i) => {
      t(() => setTyped(TERMINAL_QUERY.slice(0, i + 1)), 400 + 32 * i + (Math.random() * 18));
    });
    const typingDoneAt = 400 + 32 * TERMINAL_QUERY.length + 240;

    // 2) analyzing
    t(() => setStage("analyzing"), typingDoneAt);
    let elapsed = typingDoneAt;
    TERMINAL_PHASES.forEach((p, i) => {
      t(() => setPhaseIdx(i), elapsed);
      elapsed += p.ms;
    });

    // smooth progress ramp during analyzing
    const totalAnalyze = TERMINAL_PHASES.reduce((s, p) => s + p.ms, 0);
    const startAnalyze = typingDoneAt;
    const steps = 28;
    for (let i = 1; i <= steps; i++) {
      t(() => setProgress(Math.round((i / steps) * 100)), startAnalyze + (totalAnalyze * i) / steps);
    }

    // 3) results stagger
    const resultsAt = startAnalyze + totalAnalyze + 200;
    t(() => { setStage("results"); setResults(1); }, resultsAt);
    t(() => setResults(2), resultsAt + 450);
    t(() => setResults(3), resultsAt + 900);
    t(() => setResults(4), resultsAt + 1350);
    t(() => setStage("done"), resultsAt + 1900);

    return () => timers.forEach(clearTimeout);
  }, [inView]);

  const showCursor = stage === "idle" || stage === "typing";

  return (
    <section id="terminal" className="wrap" style={{ paddingTop: 0 }}>
      <div className="container">
        <Reveal variant="up" className="section-head">
          <span className="bracket">02 · live terminal</span>
          <h2>Ask the corpus <em>directly.</em></h2>
          <p>A live trace of the agent answering one question. Findings, confidence, sources and timeline anchors — every claim grounded.</p>
        </Reveal>

        <div className={"term-stage m-blur" + (inView ? " in" : "")} ref={wrapRef}>
          <div className="term-halo" aria-hidden="true"></div>
          <div className="term-bg-grid" aria-hidden="true"></div>
          <div className="term-streak" aria-hidden="true"></div>

          <div className="terminal-wrap">
            <div className="term">
              <div className="term-noise" aria-hidden="true"></div>

              <div className="term-bar">
                <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
                  <div className="term-dots"><span></span><span></span><span></span></div>
                  <span className="term-title"><b>alienintel</b> · session 4f81-22a · /fbi/62-HQ-83894</span>
                </div>
                <div className="term-meta">
                  <span className="clock">{clock}</span>
                  <span className="term-wave" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>
                  <span className="term-status">{stage === "done" ? "grounded" : stage === "results" ? "rendering" : stage === "analyzing" ? "analyzing" : "ready"}</span>
                </div>
              </div>

              <div className="term-body">
                {/* USER PROMPT */}
                <div className="term-prompt">
                  <span className="chev">▸</span>
                  <span className="typed">{typed}{showCursor && <span className="term-cursor" aria-hidden="true"></span>}</span>
                </div>

                {/* ANALYZING */}
                {(stage === "analyzing" || stage === "results" || stage === "done") && (
                  <>
                    <div className="term-analyze" role="status" aria-live="polite">
                      <div className="lbl">
                        <span className="ring" aria-hidden="true"></span>
                        {stage === "analyzing" ? "Analyzing documents" : "Analysis complete"}
                      </div>
                      <span className="pct">{progress}% · 1,612 pp · 161 docs</span>
                      <div className="term-progress"><i style={{ width: `${progress}%` }}></i></div>
                    </div>

                    <div className="term-status-list">
                      {TERMINAL_PHASES.map((p, i) => {
                        if (i > phaseIdx) return null;
                        const live = i === phaseIdx && stage === "analyzing";
                        return (
                          <div className={"row" + (live ? " live" : "")} key={p.key} style={{ animationDelay: `${i * 60}ms` }}>
                            <span className="tick">{live ? "·" : "✓"}</span>
                            <span>{p.label}{live ? "…" : ""}</span>
                            <span className="dur">{(p.ms / 1000).toFixed(2)}s</span>
                          </div>
                        );
                      })}
                    </div>
                  </>
                )}

                {/* RESULTS */}
                {results >= 1 && (
                  <div className="term-section" style={{ animationDelay: "0ms" }}>
                    <div className="label"><span className="dotsig"></span>Summary</div>
                    <p className="summary">FBI file 62-HQ-83894 contains <b>no Bureau confirmation</b> of recovered non-terrestrial materials. It does contain the Bureau's contemporaneous handling of every disc-recovery claim that crossed its desk between 1947 and 1977 — Roswell, Maury Island, Twin Falls — most of which were identified, hoaxed, or referred to the Air Force without follow-up.</p>
                  </div>
                )}

                {results >= 2 && (
                  <div className="term-section" style={{ animationDelay: "0ms" }}>
                    <div className="label"><span className="dotsig"></span>Confidence</div>
                    <div className="conf-row">
                      <div className="conf-donut" style={{ "--p": 91 }} aria-label="91 percent confidence on Bureau handling">
                        <span>91<small>%</small></span>
                      </div>
                      <div className="conf-meta">
                        <div className="h">Bureau-handled · explained, hoaxed, or referred</div>
                        <div className="sub">3 retrieval claims · 0 Bureau confirmations · 1 referred to AAF</div>
                        <div className="conf-bar"><i style={{ "--w": "91%" }}></i></div>
                      </div>
                    </div>
                  </div>
                )}

                {results >= 3 && (
                  <div className="term-section" style={{ animationDelay: "0ms" }}>
                    <div className="label"><span className="dotsig"></span>Referenced files</div>
                    <div>
                      {TERMINAL_FILES.map((f) => (
                        <div className="file-row" key={f.name}>
                          <span className="ico">{f.ico}</span>
                          <span className="name">{f.name}</span>
                          <span className="pp">{f.pp}</span>
                          <span className="conf-mini">{(f.w / 100).toFixed(2)}<i style={{ "--w": `${f.w}%` }}></i></span>
                        </div>
                      ))}
                    </div>
                  </div>
                )}

                {results >= 4 && (
                  <div className="term-section" style={{ animationDelay: "0ms" }}>
                    <div className="label"><span className="dotsig"></span>Related events</div>
                    <div className="ev-timeline">
                      {TERMINAL_EVENTS.map((e) => (
                        <div className="ev-row" key={e.yr}>
                          <span className="yr">{e.yr}</span>
                          <span className="ttl">{e.ttl}</span>
                          <span className="tag">{e.tag}</span>
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </div>

              <div className="term-footer">
                <div className="left">
                  <span>signal · nominal</span>
                  <span className="term-wave" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>
                </div>
                <span className="grounded">grounded · provenance preserved</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- DOSSIER GRID ----------
function DossierGrid() {
  const dossiers = [
    { id: "DSR-01", k: "The 1947 disc wave", d: "Kenneth Arnold's 24 Jun sighting opens the file. Sections 1–2 catalogue the chain reaction: 800+ public reports in eight weeks, every credible witness interviewed by an SAC.", pages: "Sections 1–2", sources: "FBI Field Offices" },
    { id: "DSR-02", k: "Roswell · 8 Jul 1947", d: "Dallas SAC's one-paragraph wire to Hoover describing recovered debris 'resembling high-altitude weather balloon with radar reflector.' The Bureau's only first-day record.", pages: "SER-026", sources: "Dallas SAC → Director" },
    { id: "DSR-03", k: "Maury Island fabrication", d: "Tacoma SAC's eleven-page summary of the Dahl/Crisman doughnut-craft claim — and the fatal B-25 crash that followed. Final Bureau verdict: 'a complete fabrication.'", pages: "SER-014", sources: "Tacoma SAC" },
    { id: "DSR-04", k: "Hottel memo · 22 Mar 1950", d: "Single-page memorandum from SAC Guy Hottel relaying a third-hand AAF claim of three discs, three small bodies recovered in New Mexico. No follow-up exists in the file.", pages: "SER-130", sources: "Washington Field Office" },
    { id: "DSR-05", k: "Bureau policy 1947–1949", d: "Hoover's evolution from conditional cooperation (15 Jul 1947) to formal disengagement (1 Oct 1949). The file documents what changed — and what didn't.", pages: "SER-011, SER-095", sources: "Director's office" },
    { id: "DSR-06", k: "Witness interviews", d: "Roughly 40 first-hand SAC interviews between 1947 and 1952. Each carries a one-line credibility assessment; the Bureau does not interpret the underlying phenomenon.", pages: "~40 interviews", sources: "Multiple SACs" },
  ];
  return (
    <section id="dossiers" className="wrap" style={{ paddingTop: 0 }}>
      <div className="container">
        <Reveal variant="up" className="section-head">
          <span className="bracket">03 · dossier index</span>
          <h2>Six threads. <em>One file.</em></h2>
          <p>The 161-document file series is partitioned into investigative threads — events, key memos, policy moments. Each is independently auditable; each shares the same citation grammar.</p>
        </Reveal>
        <Reveal variant="up" stagger className="dossier-grid">
          {dossiers.map((d) => (
            <div className="dcard" key={d.id}>
              <div className="meta">
                <span className="id">{d.id}</span>
                <span>active</span>
              </div>
              <h3>{d.k}</h3>
              <p>{d.d}</p>
              <div className="stats">
                <span>{d.pages}</span>
                <b>{d.sources}</b>
              </div>
            </div>
          ))}
        </Reveal>
      </div>
    </section>
  );
}

// ---------- FILE INDEX (real war.gov mirror) ----------
function buildFileIndex() {
  const PREFIX = "65_HS1-834228961_62-HQ-83894";
  const out = [];
  // The six sections actually released in PURSUE Release 01 (8 May 2026):
  // 2, 3, 4, 5, 6, 10. Sections 1, 7, 8, 9 not in the public release.
  [2, 3, 4, 5, 6, 10].forEach((n) => {
    out.push({ name: `${PREFIX}_Section_${n}` });
  });
  // 155 serials to reach 161 total
  // Includes the two community-verified serials: 95 (Kenneth Arnold) and 209 (Hottel memo).
  const serialNums = [
    1, 2, 4, 7, 11, 14, 17, 21, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56,
    59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, 107, 110,
    113, 116, 119, 122, 125, 128, 130, 131, 134, 137, 140, 143, 146, 149, 152, 153,
    156, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201,
    204, 207, 209, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 246,
    249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 282, 285, 288, 291, 294,
    297, 300, 303, 306, 309, 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, 342,
    345, 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, 381, 384, 387, 390,
    393, 396, 399, 402, 405, 408, 411, 414, 417, 420, 423, 426, 429, 432, 435, 438,
    441, 444, 447, 450, 453,
  ];
  serialNums.forEach((n) => out.push({ name: `${PREFIX}_Serial_${n}` }));
  return out;
}
const FILE_INDEX = buildFileIndex();

function FileIndex() {
  const [query, setQuery] = useState("");
  const [showAll, setShowAll] = useState(false);
  const filtered = query.trim()
    ? FILE_INDEX.filter((f) => f.name.toLowerCase().includes(query.toLowerCase()))
    : FILE_INDEX;
  const visible = showAll ? filtered : filtered.slice(0, 12);
  return (
    <section id="files" className="wrap" style={{ paddingTop: 0 }}>
      <div className="container">
        <Reveal variant="up" className="section-head">
          <span className="bracket">04 · file index</span>
          <h2>The 161 <em>files.</em></h2>
          <p>The full war.gov release index, mirrored. Per-document metadata is intentionally sparse — incident date, location, and type are marked N/A on the source release.</p>
        </Reveal>

        <Reveal variant="up" className="fi-shell">
          <div className="fi-toolbar">
            <div className="fi-search">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
              <input
                type="text"
                placeholder="Filter 161 files…"
                value={query}
                onChange={(e) => { setQuery(e.target.value); setShowAll(true); }}
              />
              {query && <button className="fi-clear" onClick={() => setQuery("")} aria-label="Clear">×</button>}
            </div>
            <div className="fi-count">
              <b>{filtered.length}</b> of {FILE_INDEX.length} files
            </div>
          </div>

          <div className="fi-table-wrap">
            <table className="fi-table">
              <thead>
                <tr>
                  <th className="fi-th-name">{filtered.length} files</th>
                  <th>Agency</th>
                  <th>Release date</th>
                  <th>Incident date</th>
                  <th>Incident location</th>
                  <th>Type</th>
                </tr>
              </thead>
              <tbody>
                {visible.map((f) => (
                  <tr key={f.name}>
                    <td className="fi-name">{f.name}</td>
                    <td className="fi-meta">[FBI]</td>
                    <td className="fi-meta">[5/8/26]</td>
                    <td className="fi-na">[N/A]</td>
                    <td className="fi-na">[N/A]</td>
                    <td className="fi-meta">[.PDF]</td>
                  </tr>
                ))}
              </tbody>
            </table>
            {filtered.length === 0 && (
              <div className="fi-empty">No matches. Try “section”, “serial”, or a specific number.</div>
            )}
          </div>

          {!showAll && filtered.length > 12 && (
            <div className="fi-more">
              <button onClick={() => setShowAll(true)}>
                Show all {filtered.length} files <span className="fi-arrow">↓</span>
              </button>
            </div>
          )}

          <div className="fi-source">
            Source · <a href="https://www.war.gov/ufo/" target="_blank" rel="noopener noreferrer">war.gov/ufo</a>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- METHODOLOGY ----------
function Methodology({ t }) {
  const rows = [
    ["01", "It cites every source", `Every claim is paired with a source span — file, page, paragraph, bbox. ${t.agentName} answers with footnotes, not assertions.`],
    ["02", "It does not invent claims", "Where the corpus is silent, the agent says so. Hallucinations are surfaced as refusals, not fabricated answers."],
    ["03", "It labels uncertainty", "Each finding carries a confidence score. Pixel-recovered text from redactions is flagged separately and never used as a primary citation."],
    ["04", "It separates evidence from interpretation", "First-hand testimony, second-hand reports, journalistic claims and analyst speculation are tagged distinctly. The agent never collapses them."],
    ["05", "It tracks provenance", "A document graph traces every claim to its earliest known source. Forks, retractions and contradictions are preserved, not flattened."],
  ];
  return (
    <section id="method" className="wrap" style={{ paddingTop: 0 }}>
      <div className="container">
        <Reveal variant="up" className="section-head">
          <span className="bracket">05 · methodology</span>
          <h2>Discipline, in five <em>commitments.</em></h2>
          <p>{t.agentName} is built around a small, strict research ethic. The corpus is messy. The agent's behaviour is not.</p>
        </Reveal>
        <Reveal variant="up" stagger>
          {rows.map(([n, h, d]) => (
            <div className="method-row" key={n}>
              <div className="num">{n}</div>
              <h3>{h}</h3>
              <p>{d}</p>
            </div>
          ))}
        </Reveal>
      </div>
    </section>
  );
}

// ---------- FINAL CTA ----------
function FinalCTA({ t }) {
  return (
    <section id="access" className="final">
      <div className="container">
        <Reveal as="span" variant="up" className="bracket" style={{ marginBottom: 28, display: "inline-block" }}>06 · begin</Reveal>
        <Reveal as="h2" variant="up" delay={80}>The file is loaded.<br/>Ask the <em>question.</em></Reveal>
        <Reveal as="p" variant="up" delay={160} style={{ color: "var(--text-2)", maxWidth: "54ch", margin: "24px auto 0", fontSize: 16, lineHeight: 1.6 }}>
          {t.agentName} has read FBI file 62-HQ-83894 — six sections, 1,262 OCR'd pages, three decades of Bureau handling of flying-disc reports. Open the terminal and start asking.
        </Reveal>

        <Reveal variant="up" delay={240} style={{ marginTop: 48, display: "flex", justifyContent: "center", gap: 14, flexWrap: "wrap" }}>
          <a className="btn btn-primary" href="chat.html">Open the terminal →</a>
          <a className="btn" href="#dossiers">Browse threads</a>
        </Reveal>

        <Reveal variant="fade" delay={340} stagger style={{ marginTop: 56, display: "flex", justifyContent: "center", gap: 24, flexWrap: "wrap", fontFamily: "'JetBrains Mono', monospace", fontSize: 11, letterSpacing: ".12em", textTransform: "uppercase", color: "var(--text-3)" }}>
          <span>● Agent online</span>
          <span>1,262 pages indexed</span>
          <span>161 documents</span>
          <span>{t.modelTag}</span>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- FOOTER ----------
function Footer({ t }) {
  return (
    <footer>
      <div className="container">
        <div className="ft-rows">
          <div className="ft-col">
            <b>{t.agentName}</b>
            <a href="#agent">Agent</a>
            <a href="chat.html">Chat terminal</a>
            <a href="#dossiers">Dossiers</a>
            <a href="#method">Methodology</a>
          </div>
          <div className="ft-col">
            <b>Archive</b>
            <a href="#">Sources</a>
            <a href="#">Provenance graph</a>
            <a href="#">Recent ingests</a>
            <a href="#">Status</a>
          </div>
          <div className="ft-col">
            <b>Research</b>
            <a href="#">Methodology paper</a>
            <a href="#">Citation grammar</a>
            <a href="#">API reference</a>
            <a href="#">Contact</a>
          </div>
          <div className="ft-col" style={{ maxWidth: 280 }}>
            <b>Signal</b>
            <a href="https://x.com/alienintelfun" target="_blank" rel="noopener noreferrer" style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
              <span>x.com/alienintelfun</span>
            </a>
            <span style={{ color: "var(--cyan)", marginTop: 6 }}>● Agent online</span>
            <span style={{ fontSize: 11, color: "var(--text-3)" }}>FRAME 481,204</span>
            <span style={{ fontSize: 11, color: "var(--text-3)" }}>UPTIME 99.98%</span>
            <span style={{ fontSize: 11, color: "var(--text-3)" }}>{t.modelTag}</span>
          </div>
        </div>
        <div className="ft-bottom">
          <div>© {t.agentName} · 2026 · Investigative research, grounded in source.</div>
          <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
            <a href="https://x.com/alienintelfun" target="_blank" rel="noopener noreferrer" style={{ display: "inline-flex", alignItems: "center", gap: 6 }} aria-label="Follow on X">
              <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
              <span>@alienintelfun</span>
            </a>
            <span>Public clearance · open archive</span>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ---------- APP ----------
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  return (
    <>
      <Nav t={t} />
      <Hero t={t} />
      <AgentOverview t={t} />
      <TerminalDemo />
      <DossierGrid />
      <FileIndex />
      <Methodology t={t} />
      <FinalCTA t={t} />
      <Footer t={t} />

      <TweaksPanel>
        <TweakSection label="Agent" />
        <TweakText label="Name" value={t.agentName} onChange={(v) => setTweak("agentName", v.toUpperCase().slice(0, 20))} />
        <TweakText label="Model tag" value={t.modelTag} onChange={(v) => setTweak("modelTag", v.slice(0, 16))} />
        <TweakSection label="Motion" />
        <TweakToggle label="Live counters" value={t.liveTicker} onChange={(v) => setTweak("liveTicker", v)} />
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("app")).render(<App />);
