/* ============================================================
   core.jsx, Lucide icon set, shared atoms, and report data.
   Exports everything to window for the other Babel scripts.
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- Lucide icon paths (stroke, currentColor) ---- */
const ICONS = {
  terminal: '<polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/>',
  fileCode: '<path d="M10 12.5 8 15l2 2.5"/><path d="m14 12.5 2 2.5-2 2.5"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M4 6a2 2 0 0 1 2-2h8l6 6v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/>',
  database: '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>',
  gitBranch: '<line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',
  save: '<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/>',
  shieldCheck: '<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/>',
  search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
  listTree: '<path d="M21 12h-8"/><path d="M21 6H8"/><path d="M21 18h-8"/><path d="M3 6v4c0 1.1.9 2 2 2h3"/><path d="M3 10v6c0 1.1.9 2 2 2h3"/>',
  penLine: '<path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/>',
  scanSearch: '<path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><circle cx="12" cy="12" r="3"/><path d="m16 16-1.9-1.9"/>',
  sparkles: '<path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .962 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.962 0z"/>',
  mic: '<path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/>',
  send: '<path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"/><path d="m21.854 2.147-10.94 10.939"/>',
  play: '<polygon points="6 3 20 12 6 21 6 3"/>',
  pause: '<rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/>',
  rotate: '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/>',
  check: '<polyline points="20 6 9 17 4 12"/>',
  plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
  x: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
  arrowUpRight: '<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',
  info: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
  trendingUp: '<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/>',
  layers: '<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',
  users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
  globe: '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
  clock: '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
  fileCheck: '<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/><path d="M14 2v6h6"/><path d="m9 15 2 2 4-4"/>',
  zap: '<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>',
  wrench: '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>',
  cpu: '<rect width="16" height="16" x="4" y="4" rx="2"/><rect width="6" height="6" x="9" y="9" rx="1"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/>',
  fileText: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v5h5"/><path d="M16 13H8"/><path d="M16 17H8"/><path d="M10 9H8"/>',
  cornerDownRight: '<polyline points="15 10 20 15 15 20"/><path d="M4 4v7a4 4 0 0 0 4 4h12"/>'
};

function Icon({ name, className, style }) {
  const d = ICONS[name] || '';
  return (
    <svg className={className} style={style} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
      dangerouslySetInnerHTML={{ __html: d }} />
  );
}

/* ---- Free Trial CTA cluster ---- */
const FREE_TRIAL_URL = "https://pseo.nl/builder";
function FreeTrial({ size = "", dark = false, center = false, sub = true }) {
  return (
    <div className={"cta-stack" + (center ? " center" : "")}>
      <a className={"btn btn-primary " + size} href={FREE_TRIAL_URL} target="_blank" rel="noopener">
        Free Trial <Icon name="arrowUpRight" />
      </a>
      {sub && (
        <span className={"cta-sub" + (dark ? " on-dark" : "")}>
          <b>1-min set-up</b>, get your brand voice &amp; first 10 high-quality articles.
        </span>
      )}
    </div>
  );
}

/* ---- Section header ---- */
function SectionHead({ part, label, title, intro, center, dark }) {
  return (
    <div className={"section-head" + (center ? " center" : "")}>
      <div className="part-label">
        {part && <span className="pnum">{part}</span>}
        <span>{label}</span>
      </div>
      <h2 className="sec-title" dangerouslySetInnerHTML={{ __html: title }} />
      {intro && <p className="sec-intro" dangerouslySetInnerHTML={{ __html: intro }} />}
    </div>
  );
}

/* ---- Scroll reveal hook ---- */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
    }, { threshold: 0.12 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  });
}

/* ============================================================
   DATA
   ============================================================ */

/* The 6 architecture components Ryan Law built */
const ARCHITECTURE = [
  { k: "orchestration", icon: "terminal", title: "Claude Code", desc: "The orchestration engine. Runs from the terminal and coordinates every step of the pipeline." },
  { k: "prompts", icon: "fileCode", title: "23 custom skill files", desc: "Structured prompts for each stage: research, outline, draft, fact-check, edit, voice-check." },
  { k: "data", icon: "database", title: "Ahrefs MCP", desc: "The data layer. Gives the model access to live keyword, SERP and competitor data." },
  { k: "tenancy", icon: "gitBranch", title: "Per-writer forks", desc: "Each writer maintains their own forked version of the pipeline, tuned to their voice and beat." },
  { k: "artifacts", icon: "save", title: "Step-by-step artifacts", desc: "Every stage saves its output to disk. Nothing happens in one shot, every step is inspectable." },
  { k: "gates", icon: "shieldCheck", title: "Quality gates", desc: "The pipeline halts between stages for human review. Slop never propagates downstream." }
];

/* The animated pipeline, stages + gates */
const STAGES = [
  { id: 1, name: "Research", icon: "search", artifact: "brief.json",
    status: ["Querying Ahrefs MCP for keyword + SERP data…", "Analyzing competitor coverage…", "Saving artifact → brief.json"],
    principle: "Research first, write last. The pipeline starts by pulling SERP data, analyzing competitor coverage and identifying angle gaps, before a single sentence is drafted.",
    builder: "Every run begins with a research stage powered by live data: Ahrefs MCP, SERP scrape and internal data matrices. Drafting without research is not an option." },
  { id: 2, name: "Outline", icon: "listTree", artifact: "outline.md",
    status: ["Structuring sections from the brief…", "Mapping intent to headings…", "Saving artifact → outline.md"],
    principle: "A structured brief becomes a structured outline. Each heading maps to a specific search intent surfaced in research, no filler sections.",
    builder: "The outline is generated from the research artifact, not from a blank prompt. You can edit it before drafting ever starts." },
  { id: 3, name: "Draft", icon: "penLine", artifact: "draft-v1.md",
    status: ["Drafting against the approved outline…", "Pulling supporting data points…", "Saving artifact → draft-v1.md"],
    principle: "Drafting only happens against an approved outline and a researched brief, never as the first move. The model writes into structure, not into a void.",
    builder: "Drafting reads the outline + brief artifacts as context. Because earlier steps are saved, the draft stage stays focused instead of losing the plot by step four." },
  { id: 4, name: "Fact-check", icon: "scanSearch", artifact: "claims.json",
    status: ["Extracting every factual claim…", "Verifying against source material…", "Saving artifact → claims.json"],
    principle: "Each claim in the draft is checked against source material as its own discrete step, not assumed correct because the prose reads well.",
    builder: "A built-in factuality gate verifies claims against the research sources and flags anything unsupported before it can reach the edit stage." },
  { id: 5, name: "Edit", icon: "sparkles", artifact: "draft-v2.md",
    status: ["Tightening structure and flow…", "Removing redundancy…", "Saving artifact → draft-v2.md"],
    principle: "Editing is a separate stage with its own prompt and its own saved artifact, so you can compare draft-v1 to draft-v2 and roll back if the edit overreached.",
    builder: "Readability and NLP topical-coverage checks run here. Every edit produces a new versioned artifact you can diff against the previous one." },
  { id: 6, name: "Voice-check", icon: "mic", artifact: "final.md",
    status: ["Matching against the voice corpus…", "Adjusting sentence rhythm…", "Saving artifact → final.md"],
    principle: "Voice is never compressed into a bullet list of rules. The piece is pattern-matched against dozens of real examples, the source material itself.",
    builder: "Voice is captured as a corpus, not a rulebook. Upload existing pieces and the platform applies tone, sentence rhythm and structural fingerprints automatically." },
  { id: 7, name: "Publish", icon: "send", artifact: "published",
    status: ["Generating schema + internal links…", "Pushing to CMS…", "Published ✓, page is live."],
    principle: "Publishing is the final gated step. Ryan's setup pushes to one CMS with schema and internal linking handled separately.",
    builder: "Multi-CMS publishing with schema, sitemaps, internal links and image generation built into the publish step, across as many brands as you run." }
];

/* The 5 principles */
const PRINCIPLES = [
  { n: "01", title: "Research first, write last.",
    problem: "Most failing AI content systems start by asking the model to write. Ryan's starts by asking it to research, pull SERP data, analyze competitor coverage, identify angle gaps, and build a structured brief before a single sentence is drafted.",
    solution: "Every PSEO Builder run starts with a research stage powered by live data (Ahrefs, SERP scrape, internal data matrices) before any drafting prompt is reached. Drafting without research is not an option." },
  { n: "02", title: "Every step saves its output.",
    problem: "The single most important point in the podcast, and the one most teams skip. 'AI slop' almost always comes from chained prompts in a single context window: the model loses focus and quality collapses by step four. Saving every step as an artifact lets you inspect, audit, fork and improve any stage.",
    solution: "Every stage produces a discrete, inspectable artifact stored to the project. You can roll back, branch, replay or edit any stage independently. The pipeline is a directed graph of artifacts, not a single mega-prompt." },
  { n: "03", title: "Never compress voice into a list of rules.",
    problem: "Ryan calls this the single biggest mistake content teams make. 'Write in our voice, short sentences, be punchy, avoid jargon' is a list. Real voice is captured by showing the model dozens of real examples and letting it pattern-match against the source directly.",
    solution: "Voice is captured as a corpus, not a rulebook. Upload existing pieces; the platform extracts and applies tone, sentence rhythm, and structural fingerprints. No 'voice guidelines' required." },
  { n: "04", title: "One forked workflow per writer or brand.",
    problem: "Ryan's team doesn't share a pipeline, every writer maintains their own forked version, tuned to their beat. The shared-pipeline approach fails because no two writers' research, drafting and editing needs are identical.",
    solution: "Native multi-tenant architecture. One admin sets the template; each writer, brand or client gets a forked workflow they tune without affecting anyone else's. Agencies run dozens of brands in parallel." },
  { n: "05", title: "Quality gates between every stage.",
    problem: "The pipeline never runs end-to-end without checkpoints. A human (or automated check) approves the brief before drafting, the draft before editing, the final piece before publishing. This discipline is what makes the 8-minute claim believable, most of that time is human review, not generation.",
    solution: "Configurable quality gates between every stage: plagiarism, readability, NLP scoring, brand-voice match, factuality. Auto-pass or require human approval per gate, per workflow." }
];

/* Part 3, what you actually need in-house */
const REQUIREMENTS = [
  "Someone who can install, configure and debug Claude Code from the terminal, and keep it working through every model update.",
  "An engineering team capable of building or integrating an MCP server for your data layer (keyword data, internal product data, competitor intelligence).",
  "Time to write, version-control and maintain ~20+ skill files, and then fork them per writer.",
  "A workflow for non-technical writers to safely interact with a code-first pipeline without breaking it.",
  "Internal tooling to publish to your CMS, handling schema, internal linking, sitemap updates and image generation.",
  "Quality-assurance layers (plagiarism, readability, factuality) bolted on top, Claude Code doesn't ship with them.",
  "Six to twelve months of iteration to get the pipeline producing publish-ready output reliably."
];

/* Part 4, comparison rows */
const COMPARE = [
  { crit: "Who can operate it", inhouse: "Technical writers comfortable with terminal &amp; code.", builder: "<b>Anyone with a browser.</b> Non-technical writers run the full pipeline." },
  { crit: "Time to first publish-ready output", inhouse: "3–12 months of pipeline iteration.", builder: "<b>Day one.</b> Pre-built workflows ship with the platform." },
  { crit: "Data layer", inhouse: "Ahrefs MCP only. Custom MCPs require engineering.", builder: "Ahrefs MCP + structured data matrix + scraping + news automation, built in." },
  { crit: "Scale", inhouse: "One article at a time, manually triggered.", builder: "<b>Hundreds to thousands</b> of pages, batched and scheduled." },
  { crit: "Multi-brand support", inhouse: "One forked pipeline per writer. Multi-brand needs custom infra.", builder: "<b>Multi-tenant by default.</b> Unlimited brands or clients in parallel." },
  { crit: "Publishing", inhouse: "Manual, single CMS. Schema &amp; internal linking handled separately.", builder: "Multi-CMS publishing. Schema, sitemaps, internal links &amp; images included." },
  { crit: "Quality controls", inhouse: "Built manually per pipeline.", builder: "Plagiarism, readability, NLP scoring, voice &amp; factuality checks built in." },
  { crit: "Per-writer customisation", inhouse: "Yes, each writer maintains their own fork.", builder: "Yes, admin sets the template, writers fork and tune their own." },
  { crit: "Programmatic SEO at scale", inhouse: "Not the design goal. Built for one blog post at a time.", builder: "<b>First-class feature.</b> Thousands of intent-matched pages from a data matrix." },
  { crit: "Total cost of ownership (year 1)", inhouse: "1 senior content engineer + eng support + iteration time.", builder: "<b>A fraction of a single hire.</b> Predictable monthly cost." }
];

/* Part 5, beyond replication */
const BEYOND = [
  { icon: "layers", tag: "AT SCALE", title: "Programmatic SEO at real scale",
    desc: "Most companies have thousands of high-intent queries one layer below their content, trade × city, product × use-case, comparison × competitor. Builder generates those pages by the hundred or thousand from a structured data matrix, each tuned to its intent. This is not what Claude Code is for." },
  { icon: "users", tag: "MULTI-TENANT", title: "Multi-tenant for agencies & multi-brand operators",
    desc: "Run content for more than one brand and a single-instance pipeline becomes a maintenance burden fast. Builder treats each brand as a tenant with its own voice corpus, data matrix and publishing target, all governed by one admin layer." },
  { icon: "globe", tag: "PUBLISHING", title: "Native publishing across CMSes",
    desc: "Most teams publish to several destinations, marketing site, help centre, regional sub-brand, partner portal. Builder ships native integrations for the major CMSes, plus schema, internal linking, image generation and sitemap handling in the publish step." },
  { icon: "rotate", tag: "REFRESH", title: "News automation & content refresh",
    desc: "Ryan's team also updated ~30 existing articles with the pipeline, an underrated use-case. Builder includes scheduled refresh workflows that re-run research, detect SERP drift and refresh on-page content automatically, keeping evergreen pages competitive." },
  { icon: "shieldCheck", tag: "QUALITY", title: "Quality checks that ship with the platform",
    desc: "Plagiarism scanning, readability scoring, NLP topical coverage, brand-voice match, factuality verification against source, all built in, all configurable per workflow. You don't bolt them on after; they're part of the default gate set." }
];

/* Part 6, three paths */
const PATHS = [
  { no: "Path 01", title: "Build it yourself", featured: false,
    good: "You have a senior content lead who can ship code, engineering support for an MCP server, and 6–12 months to iterate. You want maximum control and the IP to stay in-house.",
    bad: "You don't have all three of those things. The pipeline is the visible part, the year of iteration around it is the invisible part, and it's where most attempts quietly die." },
  { no: "Path 02", title: "Hire an AI content agency", featured: false,
    good: "You want to outsource the whole problem and you're willing to pay the agency margin in exchange for not learning the pipeline yourself.",
    bad: "You want the workflow, voice corpus, data matrix and quality gates to live in your own systems and be tunable by your team. With an agency, the engine stays with them." },
  { no: "Path 03", title: "Use PSEO Builder", featured: true,
    good: "You want the same principles Ryan describes, productised. Pipeline, quality gates, multi-tenant architecture and native publishing, running in your browser with your team in control. Ship on day one, not month nine.",
    bad: "You only need one article a week and a single CMS. Honestly, ChatGPT and a careful editor will do. Builder makes sense when scale, multiple brands, or programmatic SEO are in the picture." }
];

/* Three ways to start (next steps) */
const WAYS = [
  { n: "1", title: "15-minute live walkthrough", desc: "We run PSEO Builder against your actual site on a screenshare. You see the data matrix, a live page produced end-to-end, and the comparison vs. building it in-house. No slides." },
  { n: "2", title: "Async quick-scan (5-min Loom)", desc: "Send us your URL. We send back a recorded Loom showing what the pipeline would produce for your site and the specific PSEO opportunity we see, no call required." },
  { n: "3", title: "Self-serve trial", desc: "Skip the conversation and just try it. One-minute set-up gets your brand voice and your first 10 high-quality articles. Bring your own URL and data matrix." }
];

Object.assign(window, {
  Icon, FreeTrial, SectionHead, useReveal, FREE_TRIAL_URL,
  ARCHITECTURE, STAGES, PRINCIPLES, REQUIREMENTS, COMPARE, BEYOND, PATHS, WAYS,
  React, useState, useEffect, useRef, useCallback
});
