const { useState, useRef, useCallback, useEffect } = React;

/* ─── API HELPER ─────────────────────────────────────────────────────────── */
async function api(path, body, method = "POST") {
  const res = await fetch(path, {
    method,
    headers: body ? { "Content-Type": "application/json" } : undefined,
    body: body ? JSON.stringify(body) : undefined,
    credentials: "same-origin",
  });
  let data = {};
  try { data = await res.json(); } catch {}
  if (!res.ok) {
    const err = new Error(data.error || `Request failed (${res.status})`);
    err.status = res.status;
    throw err;
  }
  return data;
}

/* ─── ANALYTICS ──────────────────────────────────────────────────────────── */
const track = (event, props = {}) => {
  try {
    if (window.plausible) window.plausible(event, { props });
    if (window.gtag) window.gtag("event", event, props);
  } catch {}
};

/* ─── LOCAL REPORT STORAGE ───────────────────────────────────────────────── */
const saveReport = (report, fileName, contractText, brandInfo) => {
  try {
    const id = `report_${Date.now()}`;
    const entry = { id, fileName, date: new Date().toISOString(), report, brandInfo: brandInfo || null, contractText: (contractText || "").slice(0, 200000) };
    localStorage.setItem(id, JSON.stringify(entry));
    const index = JSON.parse(localStorage.getItem("report_index") || "[]");
    index.unshift({ id, fileName, date: entry.date, riskScore: report.riskScore, overallRisk: report.overallRisk });
    localStorage.setItem("report_index", JSON.stringify(index.slice(0, 20)));
    return id;
  } catch (e) { console.error("Save failed", e); return null; }
};
const loadReportIndex = () => { try { return JSON.parse(localStorage.getItem("report_index") || "[]"); } catch { return []; } };
const setReportStage = (id, stage) => {
  try {
    const index = loadReportIndex().map((r) => (r.id === id ? { ...r, stage } : r));
    localStorage.setItem("report_index", JSON.stringify(index));
    return index;
  } catch { return loadReportIndex(); }
};
const loadReportEntry = (id) => { try { const r = localStorage.getItem(id); return r ? JSON.parse(r) : null; } catch { return null; } };

/* ─── FILE TEXT EXTRACTION (in-browser) ──────────────────────────────────── */
async function extractDocxText(file) {
  if (!window.JSZip) throw new Error("Document reader not available. Try converting to PDF first.");
  const buf = await file.arrayBuffer();
  const zip = await window.JSZip.loadAsync(buf);
  const xmlFile = zip.file("word/document.xml");
  if (!xmlFile) throw new Error("This doesn't look like a valid Word document (.docx).");
  const xmlText = await xmlFile.async("string");
  const withParaBreaks = xmlText.replace(/<w:p(?:\s[^>]*)?>/g, "\n");
  const noDeletes = withParaBreaks.replace(/<w:del(?:\s|>)[\s\S]*?<\/w:del>/g, "");
  let fullText = noDeletes.split("\n").map((line) => {
    const parts = []; let m;
    const re = /<w:t(?:\s[^>]*)?>([^<]*)<\/w:t>/g;
    while ((m = re.exec(line)) !== null) { if (m[1]) parts.push(m[1]); }
    return parts.join("");
  }).filter((l) => l.trim()).join("\n");
  return fullText
    .replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">")
    .replace(/&nbsp;/g, " ").replace(/&apos;/g, "'").replace(/&quot;/g, '"')
    .replace(/&#x([0-9A-Fa-f]+);/g, (_, h) => String.fromCharCode(parseInt(h, 16)))
    .replace(/&#(\d+);/g, (_, d) => String.fromCharCode(parseInt(d, 10)))
    .replace(/[ \t]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
}
async function extractPdfText(file) {
  if (!window.pdfjsLib) throw new Error("PDF reader not available. Try a .docx file instead.");
  window.pdfjsLib.GlobalWorkerOptions.workerSrc = "";
  const arrayBuffer = await file.arrayBuffer();
  const pdf = await window.pdfjsLib.getDocument({ data: arrayBuffer, useWorkerFetch: false, isEvalSupported: false, useSystemFonts: true }).promise;
  let text = "";
  for (let i = 1; i <= pdf.numPages; i++) {
    const page = await pdf.getPage(i);
    const content = await page.getTextContent();
    text += `\n--- PAGE ${i} ---\n` + content.items.map((it) => it.str).join(" ");
  }
  return text.trim();
}
async function extractText(file) {
  const isDocx = file.name?.toLowerCase().endsWith(".docx") || file.type?.includes("wordprocessingml");
  const text = isDocx ? await extractDocxText(file) : await extractPdfText(file);
  if (!text || text.replace(/\s/g, "").length < 200) {
    throw new Error(isDocx
      ? "Couldn't extract text from this Word document. Make sure it isn't corrupted or password-protected."
      : "This PDF doesn't appear to contain readable text, it may be a scanned document. Try the original Word doc instead.");
  }
  return text;
}

/* ─── SAMPLE REPORT (shown before signup, see the goods before the ask) ── */
const SAMPLE_REPORT = {
  overallRisk: "MEDIUM",
  riskScore: 61,
  alexSays: "Most of this contract is standard and perfectly fair. The operational clauses are fine. But the 36-month term, the uncapped price rises and the 7-day claims window are all below market for a brand your size, and all three are winnable.",
  crossContractIssues: [
    "The contract references a 'Schedule of Charges' that isn't included in the document, request it before signing, because that's where the real costs live.",
  ],
  summaryStats: { totalSections: 9, mustChange: 2, pushBack: 2, headsUp: 2, fine: 3 },
  beforeYouSign: [
    { rank: 1, issue: "Cut the 36-month term to 12 months", alexSays: "Ask for a 12-month rolling contract, or a 1+1 where year two only kicks in if they hit their KPIs.", likelyToWin: true },
    { rank: 2, issue: "Extend the 7-day claims window", alexSays: "Ask for 14 days from discovery, 7 days from dispatch means most damage is found too late to claim.", likelyToWin: true },
    { rank: 3, issue: "Cap the annual price increase", alexSays: "Ask for CPI plus 1%, capped at 6% in any 12-month period, with the index named.", likelyToWin: true },
  ],
  sections: [
    { id: "s1", title: "How long are you tied in?", emoji: "", status: "MUST_CHANGE",
      originalText: "This Agreement shall commence on the Commencement Date and shall continue for an initial term of thirty-six (36) months, and thereafter shall automatically renew for successive twelve (12) month periods unless either party gives not less than six (6) months' written notice…",
      plainEnglish: "You're locked in for 3 years, and it auto-renews for another year if you miss a 6-month notice window. For a brand doing under 2,000 orders a month, that's well over market.",
      alexNote: { vibe: "This is the one to fight.", whatItReallyMeans: "If the service disappoints in month 4, you still pay for 32 more months.", personalised: "At your volume, 12-month rolling contracts are absolutely achievable, 3PLs sign them for brands your size every week.", willTheyBudge: "YES_LIKELY", willTheyBudgeReason: "Term length is the most commonly conceded clause there is.", whatToSay: "We're excited to get started, but we can't commit to 36 months before we've seen the service. Can we do 12 months initial, and we'll happily extend for another 12 once the KPIs are being hit? That way the long deal is earned, not assumed.", ifTheyRefuse: "Offer 18 months with a 6-month break clause tied to the dispatch SLA.", reassurance: null } },
    { id: "s2", title: "What do they owe you if stock is lost or damaged?", emoji: "", status: "PUSH_BACK",
      originalText: "The Company's liability for loss of or damage to Goods shall be limited to the replacement cost or invoice value of the Goods, whichever is the lower…",
      plainEnglish: "If they lose your stock, they pay your cost price, not what you'd have sold it for. On a £60 retail item that cost you £18, you'd get £18.",
      alexNote: { vibe: "Standard opener, worth improving.", whatItReallyMeans: "Every lost unit costs you the margin as well as the stock.", personalised: null, willTheyBudge: "MAYBE", willTheyBudgeReason: "Many will move to retail value for damage they cause.", whatToSay: "On liability, 'whichever is lower' means we lose our margin every time something goes wrong on your side. Can we set it at retail replacement value where the loss is caused by handling, and keep invoice value for everything else?", ifTheyRefuse: "Ask for a stock-throughput insurance quote instead and price it into your margins.", reassurance: null } },
    { id: "s3", title: "How fast do orders actually go out?", emoji: "", status: "HEADS_UP",
      originalText: "The Company shall use reasonable endeavours to despatch 99% of compliant orders received before the Cut-Off Time on the same Business Day…",
      plainEnglish: "The 99% number looks good, but 'reasonable endeavours' makes it a target, not a promise. There's no consequence if they miss it.",
      alexNote: { vibe: "Fine number, weak teeth.", whatItReallyMeans: "A target with no consequence is a hope, not an SLA.", personalised: null, willTheyBudge: "MAYBE", willTheyBudgeReason: "Few grant credits, but sustained-failure exit rights are winnable.", whatToSay: "The 99% target works for us, but can we add that if it's missed for any rolling 6-month period, we can exit without penalty? We're not asking for credits, just the right to leave if it's consistently not working.", ifTheyRefuse: "Ask for quarterly SLA review meetings with the numbers in writing.", reassurance: null } },
    { id: "s4", title: "How much can prices rise each year?", emoji: "", status: "PUSH_BACK",
      originalText: "The Company may increase its charges upon thirty (30) days' written notice to reflect increases in operating costs…",
      plainEnglish: "They can raise prices by any amount with 30 days' notice. There's no cap and no index, that's an open door.",
      alexNote: { vibe: "Uncapped increases, always push.", whatItReallyMeans: "Your fulfilment cost per order can jump mid-contract with no ceiling.", personalised: null, willTheyBudge: "YES_LIKELY", willTheyBudgeReason: "A CPI-linked cap is a very normal ask.", whatToSay: "Totally understand costs move, can we link increases to CPI plus 1%, capped at 6% in any 12 months, with the ONS index named? Just so we can model our unit economics with confidence.", ifTheyRefuse: "Ask for the right to exit without penalty if any increase exceeds 6%.", reassurance: null } },
    { id: "s5", title: "How long do you have to claim for damage?", emoji: "", status: "MUST_CHANGE",
      originalText: "Claims for loss or damage must be notified in writing within seven (7) days of despatch, failing which the Company shall have no liability…",
      plainEnglish: "Seven days from dispatch is very short, customer returns and damage reports usually surface later than that. Miss it and they owe you nothing.",
      alexNote: { vibe: "Quietly brutal. Change it.", whatItReallyMeans: "Most real-world damage is discovered after the window has already shut.", personalised: null, willTheyBudge: "YES_LIKELY", willTheyBudgeReason: "14 days from discovery is a standard concession.", whatToSay: "The 7-day claims window from dispatch doesn't reflect how damage actually surfaces, customers report it days later. Can we make it 14 days from discovery? That's the norm we've seen elsewhere.", ifTheyRefuse: "Get it to 14 days from delivery as a minimum.", reassurance: null } },
    { id: "s6", title: "What's in the rate card you haven't seen?", emoji: "", status: "PUSH_BACK",
      originalText: "Storage and ancillary services shall be charged in accordance with the Company's Schedule of Charges, as amended from time to time…",
      plainEnglish: "Charges live in a separate schedule 'as amended from time to time', meaning they can change it, and it isn't in this document.",
      alexNote: { vibe: "The real prices aren't in this contract.", whatItReallyMeans: "You're agreeing to prices you haven't seen and that can change under you.", personalised: null, willTheyBudge: "YES_LIKELY", willTheyBudgeReason: "Fixing the rate card to the contract is reasonable and usually accepted.", whatToSay: "Could you send over the current Schedule of Charges, and can we attach it to the contract as a fixed appendix, with changes following the same notice-and-cap rules as the main pricing clause?", ifTheyRefuse: "Ask for 60 days' notice of any rate card change plus an exit right if you don't accept it.", reassurance: null } },
    { id: "s7", title: "Can they hold your stock if there's a dispute?", emoji: "", status: "HEADS_UP",
      originalText: "The Company shall have a general lien on all Goods in its possession for all sums due from the Customer on any account…",
      plainEnglish: "A 'general lien' means they can hold all your stock over any unpaid invoice, even a disputed one. Standard in the industry, but know it's there.",
      alexNote: { vibe: "Standard, but know the exit plan.", whatItReallyMeans: "In a billing dispute, your inventory is their leverage.", personalised: null, willTheyBudge: "PROBABLY_NOT", willTheyBudgeReason: "Liens are near-universal in 3PL standard terms.", whatToSay: "We're fine with the lien in principle, can we add that it only applies to undisputed sums, and agree the offboarding process now: stock handover within 14 days of termination at a named cost per pallet, with our order data exported?", ifTheyRefuse: "Keep invoices current and dispute in writing fast, the paper trail is your protection.", reassurance: "This clause is in almost every 3PL contract, it's not a red flag about this provider." } },
    { id: "s8", title: "When do you have to pay?", emoji: "", status: "FINE",
      originalText: "Invoices are payable within fourteen (14) days of the invoice date by direct debit…",
      plainEnglish: "14-day terms by direct debit is normal for your size. Nothing to fight here.", alexNote: null },
    { id: "s9", title: "Is your customer data protected?", emoji: "", status: "FINE",
      originalText: "The parties shall comply with the Data Protection Legislation as set out in the Data Processing Agreement at Schedule 3…",
      plainEnglish: "A proper DPA is referenced and attached. This is exactly what you want to see.", alexNote: null },
  ],
};

/* ─── CONSTANTS ──────────────────────────────────────────────────────────── */
const STATUS = {
  FINE:        { color: "#16A34A", bg: "#F0FDF4", border: "#BBF7D0", label: "All good",    barColor: "#16A34A" },
  HEADS_UP:    { color: "#92400E", bg: "#FFFBEB", border: "#FCD34D", label: "Heads up",    barColor: "#F59E0B" },
  PUSH_BACK:   { color: "#1E40AF", bg: "#EFF6FF", border: "#93C5FD", label: "Push back",   barColor: "#3B82F6" },
  MUST_CHANGE: { color: "#991B1B", bg: "#FEF2F2", border: "#FCA5A5", label: "Change this", barColor: "#EF4444" },
};
const BUDGE = {
  YES_LIKELY:   { label: "They'll move on this ✓", color: "#16A34A", bg: "#F0FDF4", border: "#BBF7D0" },
  MAYBE:        { label: "Worth asking",            color: "#92400E", bg: "#FFFBEB", border: "#FCD34D" },
  PROBABLY_NOT: { label: "Unlikely to budge",       color: "#6B7280", bg: "#F9FAFB", border: "#E5E7EB" },
};
const PRICE_LABEL = "£19.99/month";

/* ─── PDF EXPORT (client-side print view) ────────────────────────────────── */
const exportPDF = (report, fileName) => {
  const w = window.open("", "_blank");
  if (!w) { alert("Please allow pop-ups to export the PDF."); return; }
  const date = new Date().toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" });
  const riskColor = report.overallRisk === "HIGH" ? "#DC2626" : report.overallRisk === "MEDIUM" ? "#D97706" : "#16A34A";
  const statusColors = { FINE: "#16A34A", HEADS_UP: "#D97706", PUSH_BACK: "#1D4ED8", MUST_CHANGE: "#DC2626" };
  const statusLabels = { FINE: "All good", HEADS_UP: "Heads up", PUSH_BACK: "Push back", MUST_CHANGE: "Change this" };
  const esc = (s) => String(s || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

  const sectionsHTML = (report.sections || []).map((s) => {
    const sc = statusColors[s.status] || "#374151";
    const note = s.alexNote;
    return `
      <div style="margin-bottom:24px;border:1px solid #E3E6EA;border-radius:10px;overflow:hidden;page-break-inside:avoid;">
        <div style="background:${s.status !== "FINE" ? "#FFF8F0" : "#FAFBFC"};padding:12px 16px;border-bottom:1px solid #E3E6EA;display:flex;align-items:center;justify-content:space-between;">
          <div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;font-weight:700;color:#16212E;">${esc(s.title)}</div>
          ${s.status !== "FINE" ? `<span style="font-size:10px;font-weight:700;color:${sc};border:1.5px solid ${sc}33;padding:2px 10px;border-radius:20px;font-family:monospace;">${(statusLabels[s.status] || "").toUpperCase()}</span>` : ""}
        </div>
        <div style="padding:14px 16px;">
          <div style="font-size:13px;color:#222B36;line-height:1.85;font-family:Arial,Helvetica,sans-serif;margin-bottom:${note ? "14px" : "0"};">${esc(s.plainEnglish)}</div>
          ${note ? `
            <div style="background:#FAFBFC;border:1px solid ${sc}33;border-radius:8px;padding:13px 14px;">
              <div style="font-size:13px;font-weight:700;color:#16212E;margin-bottom:8px;font-family:Arial,Helvetica,sans-serif;">${esc(note.vibe)}</div>
              <div style="font-size:12px;color:#374151;line-height:1.8;margin-bottom:10px;">${esc(note.whatItReallyMeans)}</div>
              ${note.whatToSay ? `<div style="background:#16212E;border-radius:6px;padding:11px 13px;"><div style="font-size:9px;color:#6B7280;letter-spacing:0.1em;margin-bottom:6px;font-family:monospace;">WHAT TO SAY</div><div style="font-size:12px;color:#E5E7EB;line-height:1.85;white-space:pre-wrap;font-family:Arial,Helvetica,sans-serif;">${esc(note.whatToSay)}</div></div>` : ""}
            </div>` : ""}
        </div>
      </div>`;
  }).join("");

  const prioritiesHTML = (report.beforeYouSign || []).map((p) => `
    <div style="display:flex;gap:12px;align-items:flex-start;padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid #EDF0F3;">
      <div style="width:24px;height:24px;border-radius:50%;background:#16212E;color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-family:monospace;flex-shrink:0;">${p.rank}</div>
      <div><div style="font-size:13px;font-weight:700;color:#16212E;margin-bottom:3px;font-family:Arial,Helvetica,sans-serif;">${esc(p.issue)}</div><div style="font-size:12px;color:#6B7280;line-height:1.7;">${esc(p.alexSays)}</div></div>
      ${p.likelyToWin ? `<span style="font-size:9px;color:#16A34A;background:#F0FDF4;border:1px solid #BBF7D0;padding:2px 8px;border-radius:20px;font-family:monospace;flex-shrink:0;">Likely to win ✓</span>` : ""}
    </div>`).join("");

  w.document.write(`<!DOCTYPE html><html><head><title>Clause Report</title>
  <style>@page{margin:20mm 18mm}body{font-family:Arial,Helvetica,sans-serif;color:#16212E;background:#fff;max-width:700px;margin:0 auto;padding:20px}h1{font-size:28px;margin:0}@media print{.no-print{display:none}}</style>
  </head><body>
  <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:28px;padding-bottom:20px;border-bottom:2px solid #16212E;">
    <div>
      <div style="font-family:monospace;font-size:10px;color:#667079;letter-spacing:0.12em;margin-bottom:6px;">CLAUSE</div>
      <h1>Contract Analysis Report</h1>
      <div style="font-size:12px;color:#414B56;margin-top:6px;">${esc(fileName)} · ${date}</div>
    </div>
    <div style="text-align:right;">
      <div style="font-size:48px;font-weight:700;color:${riskColor};line-height:1;">${report.riskScore}</div>
      <div style="font-size:10px;color:#667079;font-family:monospace;letter-spacing:0.1em;">/ 100 RISK SCORE</div>
      <div style="font-size:11px;font-weight:700;color:${riskColor};margin-top:4px;">${report.overallRisk} RISK</div>
    </div>
  </div>
  <div style="background:#16212E;border-radius:12px;padding:18px 20px;margin-bottom:24px;">
    <div style="font-size:9px;color:#4B5563;letter-spacing:0.12em;margin-bottom:6px;font-family:monospace;">THE VERDICT</div>
    <div style="font-size:13px;color:#F9FAFB;line-height:1.85;">${esc(report.alexSays)}</div>
  </div>
  <div style="margin-bottom:24px;"><div style="font-family:monospace;font-size:10px;color:#667079;letter-spacing:0.1em;margin-bottom:14px;">BEFORE YOU SIGN</div>${prioritiesHTML}</div>
  <div style="font-family:monospace;font-size:10px;color:#667079;letter-spacing:0.1em;margin-bottom:16px;">FULL CONTRACT BREAKDOWN</div>
  ${sectionsHTML}
  <div style="margin-top:28px;padding:12px 16px;background:#F4F5F7;border-radius:8px;font-size:10px;color:#667079;text-align:center;line-height:1.8;font-family:monospace;">
    Guidance from industry experience, not legal advice. For complex situations, consult a solicitor.<br>
    Generated by Clause · ${date}
  </div>
  <div class="no-print" style="text-align:center;margin-top:20px;"><button onclick="window.print()" style="background:#16212E;color:#fff;border:none;padding:12px 32px;border-radius:8px;cursor:pointer;font-size:13px;">Print / Save as PDF</button></div>
  </body></html>`);
  w.document.close();
};

/* ─── PRIVACY POLICY ─────────────────────────────────────────────────────── */
const PRIVACY_SECTIONS = [
  { title: "The short version",
    body: "Your contract is read in your browser, sent to our server for analysis, passed to our AI analysis provider, and then discarded. We don't keep a copy of it. We do keep your contact details (from the report screen and checkout) and anonymised benchmark data about each analysis, never the contract text itself. Payments are handled entirely by Stripe; subscriptions can be cancelled any time from the billing portal. Your reports are stored in your own browser, not in a database of ours." },
  { title: "What we process and why",
    items: [
      ["Your contract document", "Text is extracted in your browser and sent to our server, which forwards it to our AI analysis provider to generate the analysis. We do not store the document or its text after the response is returned."],
      ["Anonymous benchmark data", "For each analysis we keep anonymised metadata: your business profile bands (market, order-volume band, product category, AOV band), the overall risk score, and which clause types were flagged. This keeps our market benchmarks sharp. It never includes contract text, company names, or anything that identifies you or your 3PL."],
      ["Your contact details", "We collect your work email (and company, if you give it) when you open your first report, and your name, phone number and company at checkout via Stripe. We use these to keep your report and subscription linked to you, and to send occasional emails about your report and Clause. You can unsubscribe from those anytime, and we never sell or share your details with third parties, including 3PLs."],
      ["Payment information", "Handled entirely by Stripe on their PCI-compliant checkout page. We never see your card details."],
      ["Access cookie", "After payment we set a signed cookie in your browser granting access. It contains your email and sign-in date, nothing else."],
      ["Your analysis results", "Stored locally in your browser's localStorage. Export a PDF to keep a permanent copy."],
      ["Basic analytics", "Anonymised usage events, such as an analysis starting or a checkout completing, logged against your email so we can support you. No contract content attached."],
    ] },
  { title: "Third parties we use",
    items: [
      ["AI analysis provider", "Your contract text is processed by our AI provider under a commercial API agreement to generate the report. It is not used to train their models and is not retained by them after processing."],
      ["Stripe", "Payment processing and payment records."],
      ["Database provider", "Hosts your contact details, subscription status, and the anonymised benchmark and usage data described above."],
      ["Hosting provider", "Hosts the website and runs the server-side code that talks to the above providers."],
      ["Google Fonts", "Font files loaded from Google's CDN."],
    ] },
  { title: "International transfers",
    body: "Some of our providers (including our AI analysis provider and our hosting provider) are based in, or may process data in, the United States. Where that happens, we rely on their standard contractual clauses or equivalent safeguards recognised under UK and EU data protection law." },
  { title: "Cancelling",
    body: "Your subscription is billed monthly by Stripe and can be cancelled any time from your dashboard (Manage subscription), it takes two clicks and access runs to the end of the billing period." },
  { title: "Your rights (UK/EU)",
    body: "Under UK and EU GDPR you can access, correct, or delete your personal data. Your reports live in your browser (clear localStorage to delete them); your contact and benchmark records live with us, with our database provider, and can be deleted on request; your payment record lives with Stripe. For anything else, use the Help option in the site footer." },
  { title: "Cookies", body: "One functional cookie (your access grant after payment). No advertising cookies. Third parties (Stripe, Google Fonts) may set their own." },
  { title: "Contact", body: "Use the Help option in the site footer. Every message is logged with your email address and read." },
];

const TERMS_SECTIONS = [
  { title: "What Clause is", body: "Clause analyses UK and EU third-party-logistics (3PL) contracts and gives commercial guidance: what's standard, what's below market, and what to raise with your provider. It is operated from the United Kingdom." },
  { title: "Not legal advice", body: "Clause provides commercial guidance based on fulfilment industry experience, not legal advice, and no solicitor-client relationship is created. Reports can contain errors and are not a substitute for professional review of high-value or unusual contracts. You remain responsible for what you sign." },
  { title: "Your subscription", body: "Full access costs £19.99 per month, billed by Stripe, and renews monthly until cancelled. You can cancel any time from your dashboard (Manage subscription); access continues to the end of the paid period. By purchasing you request immediate access to digital content and acknowledge that, once the service has been supplied, the statutory 14-day cooling-off refund may no longer apply. If something's gone wrong, contact us via the Help option and we'll be reasonable." },
  { title: "Fair use", body: "Subscriptions are for one business. Reasonable-use limits apply to analyses and report tools to keep the service fast for everyone; we'll contact you before restricting anything." },
  { title: "Your content", body: "You confirm you're entitled to upload the contracts you analyse. Your documents are processed as described in the Privacy Policy and are not stored after analysis. Reports are for your business use; the benchmark methodology and software remain ours." },
  { title: "Liability", body: "To the extent permitted by law, our total liability arising from the service is limited to the amount you paid us in the 12 months before the claim. Nothing excludes liability that cannot lawfully be excluded. We are not liable for decisions made, or contracts signed, on the basis of a report." },
  { title: "Governing law", body: "These terms are governed by the laws of England and Wales, and disputes belong to the courts of England and Wales. If you're a consumer elsewhere in the UK or EU, your mandatory local rights are unaffected." },
  { title: "Contact", body: "Via the Help option in the site footer." },
];

function TermsOfService({ onClose }) {
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.6)", zIndex: 2000, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: 10, width: "100%", maxWidth: 560, maxHeight: "85vh", overflow: "hidden", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid #E3E6EA", display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0 }}>
          <div>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 20, color: "#16212E", marginBottom: 2 }}>Terms of Service</div>
            <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.08em" }}>CLAUSE · LAST UPDATED JULY 2026</div>
          </div>
          <button onClick={onClose} style={{ background: "transparent", border: "none", fontSize: 20, color: "#7C858E", cursor: "pointer" }}>✕</button>
        </div>
        <div style={{ overflowY: "auto", padding: "20px 24px 28px" }}>
          {TERMS_SECTIONS.map(({ title, body }) => (
            <div key={title} style={{ marginBottom: 20 }}>
              <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 15, fontWeight: 600, color: "#16212E", marginBottom: 6 }}>{title}</div>
              <div style={{ fontSize: 13, color: "#333D4A", lineHeight: 1.85 }}>{body}</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function PrivacyPolicy({ onClose }) {
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.6)", zIndex: 2000, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: 10, width: "100%", maxWidth: 560, maxHeight: "85vh", overflow: "hidden", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid #E3E6EA", display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0 }}>
          <div>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 20, color: "#16212E", marginBottom: 2 }}>Privacy Policy</div>
            <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.08em" }}>CLAUSE · LAST UPDATED JULY 2026</div>
          </div>
          <button onClick={onClose} style={{ background: "transparent", border: "none", fontSize: 20, color: "#7C858E", cursor: "pointer" }}>✕</button>
        </div>
        <div style={{ overflowY: "auto", padding: "20px 24px 28px" }}>
          {PRIVACY_SECTIONS.map(({ title, body, items }) => (
            <div key={title} style={{ marginBottom: 22 }}>
              <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 15, fontWeight: 600, color: "#16212E", marginBottom: 8 }}>{title}</div>
              {body && <div style={{ fontSize: 13, color: "#333D4A", lineHeight: 1.85 }}>{body}</div>}
              {items && (
                <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                  {items.map(([label, desc]) => (
                    <div key={label} style={{ paddingLeft: 12, borderLeft: "2px solid #E3E6EA" }}>
                      <div style={{ fontSize: 12.5, fontWeight: 600, color: "#16212E", fontFamily: "'Archivo', sans-serif", marginBottom: 2 }}>{label}</div>
                      <div style={{ fontSize: 12, color: "#6B7280", lineHeight: 1.75 }}>{desc}</div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ─── SECTION CARD ───────────────────────────────────────────────────────── */
function SectionCard({ section, isNew }) {
  const [showOriginal, setShowOriginal] = useState(false);
  const [showScript, setShowScript] = useState(false);
  const [copied, setCopied] = useState(false);
  const cfg = STATUS[section.status] || STATUS.FINE;
  const note = section.alexNote;
  const hasNote = !!note && section.status !== "FINE";
  const isFine = section.status === "FINE";
  const isActionable = ["MUST_CHANGE", "PUSH_BACK", "HEADS_UP"].includes(section.status);

  return (
    <div style={{ background: "#fff", borderRadius: 8, border: `1px solid ${hasNote ? cfg.border : "#E7EAEE"}`, marginBottom: 10, overflow: "hidden", animation: isNew ? "popIn 0.3s cubic-bezier(0.34,1.56,0.64,1) forwards" : "none" }}>
      <div style={{ display: "flex" }}>
        <div style={{ width: 3, background: isFine ? "#E3E6EA" : cfg.barColor, flexShrink: 0 }} />
        <div style={{ flex: 1, padding: "14px 18px 16px" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: isFine ? 0 : 10 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span style={{ fontSize: 13, fontWeight: 600, color: "#16212E", fontFamily: "'Archivo', sans-serif" }}>{section.title}</span>
            </div>
            <div style={{ display: "flex", gap: 6, alignItems: "center", flexShrink: 0 }}>
              {!isFine && (
                <span
                  style={{ fontSize: 9, color: cfg.color, background: cfg.bg, border: `1px solid ${cfg.border}`, padding: "3px 10px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.06em", display: "flex", alignItems: "center", gap: 4 }}
                >
                  {cfg.label}
                </span>
              )}
              <button onClick={() => setShowOriginal((v) => !v)} style={{ background: "transparent", border: "none", color: "#7C858E", cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif", padding: "2px 0" }}>
                {showOriginal ? "hide" : "original"}
              </button>
            </div>
          </div>

          {showOriginal && (
            <div style={{ background: "#F2F4F6", borderRadius: 5, padding: "10px 13px", marginBottom: 12, fontSize: 11, color: "#414B56", lineHeight: 1.85, fontFamily: "'IBM Plex Mono', monospace", letterSpacing: 0 }}>
              {section.originalText}
            </div>
          )}

          {!isFine && (
            <div style={{ fontSize: 13.5, color: "#333D4A", lineHeight: 1.8, fontFamily: "'Archivo', sans-serif", marginBottom: hasNote ? 14 : 0 }}>{section.plainEnglish}</div>
          )}
          {isFine && (
            <div style={{ fontSize: 12.5, color: "#9CA3AF", lineHeight: 1.7, fontFamily: "'Archivo', sans-serif", marginTop: 6 }}>{section.plainEnglish}</div>
          )}

          {hasNote && (
            <div style={{ background: cfg.bg, borderRadius: 6, padding: "12px 14px", border: `1px solid ${cfg.border}` }}>
              <div style={{ fontSize: 13, fontWeight: 600, color: "#16212E", fontFamily: "'Archivo', sans-serif", marginBottom: 6, lineHeight: 1.4 }}>{note.vibe}</div>
              {note.whatItReallyMeans && <div style={{ fontSize: 12.5, color: "#6B7280", lineHeight: 1.7, marginBottom: 10 }}>{note.whatItReallyMeans}</div>}
              {note.personalised && (
                <div style={{ fontSize: 12, color: "#374151", background: "rgba(255,255,255,0.6)", borderRadius: 6, padding: "7px 10px", marginBottom: 10 }}><span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, letterSpacing: "0.08em", color: "#9CA3AF" }}>FOR YOUR BUSINESS · </span>{note.personalised}</div>
              )}
              {note.reassurance && <div style={{ fontSize: 12, color: "#16A34A", marginBottom: 10 }}>✓ {note.reassurance}</div>}
              {note.willTheyBudge && (
                <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: note.whatToSay ? 12 : 0 }}>
                  <span style={{ fontSize: 9, fontFamily: "'IBM Plex Mono', monospace", color: BUDGE[note.willTheyBudge]?.color, background: "rgba(255,255,255,0.7)", border: `1px solid ${BUDGE[note.willTheyBudge]?.border}`, padding: "2px 8px", borderRadius: 4, flexShrink: 0 }}>
                    {BUDGE[note.willTheyBudge]?.label}
                  </span>
                  <span style={{ fontSize: 12, color: "#9CA3AF" }}>{note.willTheyBudgeReason}</span>
                </div>
              )}
              {note.whatToSay && (
                <div>
                  <button onClick={() => setShowScript((v) => !v)} style={{ background: "transparent", border: "none", color: "#16212E", cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif", padding: 0, display: "flex", alignItems: "center", gap: 5, textDecoration: "underline", textUnderlineOffset: 3 }}>
                    {showScript ? "hide message ▲" : "what to say ▼"}
                  </button>
                  {showScript && (
                    <div style={{ marginTop: 10, background: "#16212E", borderRadius: 8, padding: "13px 15px" }}>
                      <div style={{ fontSize: 13, color: "#D1D5DB", lineHeight: 1.9, whiteSpace: "pre-wrap", fontFamily: "'Archivo', sans-serif" }}>{note.whatToSay}</div>
                      {note.ifTheyRefuse && (
                        <div style={{ marginTop: 10, paddingTop: 10, borderTop: "1px solid rgba(255,255,255,0.06)", fontSize: 11.5, color: "#6B7280", lineHeight: 1.7 }}>
                          If they say no: {note.ifTheyRefuse}
                        </div>
                      )}
                      <button onClick={() => { navigator.clipboard?.writeText(note.whatToSay); setCopied(true); setTimeout(() => setCopied(false), 2000); }} style={{ marginTop: 10, background: "transparent", color: copied ? "#4ADE80" : "#6B7280", border: "none", padding: 0, cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif" }}>
                        {copied ? "✓ copied" : "copy"}
                      </button>
                    </div>
                  )}
                </div>
              )}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ─── ASK ALEX (chat) ────────────────────────────────────────────────────── */
function AskAlex({ report, brandInfo }) {
  const [messages, setMessages] = useState([{ role: "alex", text: "Got any questions about this contract? Ask me anything, I'll give you a straight answer." }]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const bottomRef = useRef();

  useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]);

  const send = async () => {
    if (!input.trim() || loading) return;
    const q = input.trim(); setInput(""); setLoading(true);
    setMessages((prev) => [...prev, { role: "user", text: q }]);
    try {
      const { reply } = await api("/api/assist", { type: "chat", report, brandInfo, history: messages.slice(1), question: q });
      setMessages((prev) => [...prev, { role: "alex", text: reply }]);
    } catch (e) {
      setMessages((prev) => [...prev, { role: "alex", text: e.message || "Something went wrong. Try again." }]);
    } finally { setLoading(false); }
  };

  return (
    <div style={{ background: "#fff", border: "1px solid #E7EAEE", borderRadius: 8, overflow: "hidden", marginBottom: 14 }}>
      <div style={{ padding: "13px 18px 11px", background: "#FAFBFC", borderBottom: "1px solid #EDF0F3" }}>
        <span style={{ fontSize: 13.5, fontWeight: 700, color: "#16212E", fontFamily: "'Archivo', sans-serif" }}>Ask about this contract</span>
      </div>
      <div style={{ padding: "14px 16px", maxHeight: 280, overflowY: "auto" }}>
        {messages.map((m, i) => (
          <div key={i} style={{ display: "flex", gap: 9, alignItems: "flex-start", marginBottom: 12, flexDirection: m.role === "user" ? "row-reverse" : "row" }}>
            <div style={{ maxWidth: "80%", background: m.role === "user" ? "#16212E" : "#F2F4F6", color: m.role === "user" ? "#F9FAFB" : "#222B36", padding: "9px 13px", borderRadius: m.role === "user" ? "12px 12px 3px 12px" : "12px 12px 12px 3px", fontSize: 13, lineHeight: 1.8, fontFamily: "'Archivo', sans-serif" }}>
              {m.text}
            </div>
          </div>
        ))}
        {loading && (
          <div style={{ display: "flex", gap: 9, alignItems: "flex-start" }}>
            <div style={{ background: "#F2F4F6", padding: "9px 13px", borderRadius: "12px 12px 12px 3px", display: "flex", gap: 4, alignItems: "center" }}>
              {[0, 1, 2].map((i) => <div key={i} className="dot" style={{ width: 6, height: 6, animationDelay: `${i * 0.15}s` }} />)}
            </div>
          </div>
        )}
        <div ref={bottomRef} />
      </div>
      <div style={{ padding: "10px 14px", borderTop: "1px solid #EDF0F3", display: "flex", gap: 8 }}>
        <input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} placeholder="e.g. What does the liability cap mean for me?" style={{ flex: 1, border: "1px solid #D5D9DF", borderRadius: 8, padding: "9px 13px", fontSize: 13, fontFamily: "'Archivo', sans-serif", color: "#16212E", outline: "none", background: "#FAFBFC" }} />
        <button onClick={send} disabled={!input.trim() || loading} style={{ background: "#16212E", color: "#F4F5F7", border: "none", padding: "9px 16px", borderRadius: 8, cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif", opacity: !input.trim() || loading ? 0.4 : 1 }}>Send</button>
      </div>
      {messages.length <= 1 && (
        <div style={{ padding: "0 14px 12px", display: "flex", gap: 6, flexWrap: "wrap" }}>
          {["What's the worst clause in this contract?", "How do I bring up the termination clause?", "Is this normal for a brand my size?"].map((q) => (
            <button key={q} onClick={() => setInput(q)} style={{ background: "#F4F5F7", border: "1px solid #E3E6EA", color: "#414B56", padding: "5px 11px", borderRadius: 4, cursor: "pointer", fontSize: 11, fontFamily: "'Archivo', sans-serif", lineHeight: 1.4 }}>
              {q}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

/* ─── EMAIL COMPOSER ─────────────────────────────────────────────────────── */
function EmailComposer({ report, brandInfo, onClose }) {
  const [state, setState] = useState("loading");
  const [email, setEmail] = useState({ subject: "", body: "" });
  const [copied, setCopied] = useState(false);

  useEffect(() => { generate(); }, []);

  const generate = async () => {
    setState("loading");
    try {
      const data = await api("/api/assist", { type: "email", report, brandInfo });
      setEmail(data.email);
      setState("done");
    } catch (e) { setState("error"); setEmail({ subject: "", body: e.message || "" }); }
  };

  const copy = () => {
    navigator.clipboard?.writeText(`Subject: ${email.subject}\n\n${email.body}`);
    setCopied(true); setTimeout(() => setCopied(false), 2200);
  };

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.52)", zIndex: 1000, display: "flex", alignItems: "flex-end", justifyContent: "center" }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: "20px 20px 0 0", width: "100%", maxWidth: 760, maxHeight: "88vh", overflow: "hidden", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid #E3E6EA", display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 20, color: "#16212E", marginBottom: 3 }}>Negotiation email</div>
            <div style={{ fontSize: 12.5, color: "#414B56" }}>Drafted from every clause we flagged. Edit before sending.</div>
          </div>
          <button onClick={onClose} style={{ background: "transparent", border: "none", fontSize: 20, color: "#7C858E", cursor: "pointer", padding: "0 0 0 16px" }}>✕</button>
        </div>
        <div style={{ flex: 1, overflowY: "auto", padding: "20px 24px" }}>
          {state === "loading" && (
            <div style={{ textAlign: "center", padding: "44px 0" }}>
              <div style={{ display: "flex", justifyContent: "center", gap: 6, marginBottom: 16 }}>
                <div className="dot" /><div className="dot" /><div className="dot" />
              </div>
              <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 17, color: "#16212E", marginBottom: 5 }}>Drafting your email…</div>
              <div style={{ fontSize: 12, color: "#9CA3AF" }}>Turning every flagged clause into a single, sendable message.</div>
            </div>
          )}
          {state === "error" && (
            <div style={{ textAlign: "center", padding: "32px 0" }}>
              <div style={{ fontSize: 13, color: "#DC2626", marginBottom: 14 }}>{email.body || "Something went wrong."}</div>
              <button className="btn" onClick={generate}>Try again</button>
            </div>
          )}
          {state === "done" && (
            <div>
              <div style={{ marginBottom: 14 }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.1em", marginBottom: 7 }}>SUBJECT</div>
                <div style={{ background: "#F2F4F6", borderRadius: 8, padding: "10px 14px", fontSize: 13, color: "#16212E", fontFamily: "'Archivo', sans-serif" }}>{email.subject}</div>
              </div>
              <div style={{ marginBottom: 20 }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.1em", marginBottom: 7 }}>EMAIL</div>
                <div style={{ background: "#F2F4F6", borderRadius: 8, padding: 16, fontSize: 13, color: "#222B36", lineHeight: 1.95, fontFamily: "'Archivo', sans-serif", whiteSpace: "pre-wrap" }}>{email.body}</div>
              </div>
              <div style={{ display: "flex", gap: 10 }}>
                <button className="btn" style={{ flex: 1 }} onClick={copy}>{copied ? "Copied to clipboard" : "Copy email"}</button>
                <button onClick={generate} style={{ background: "transparent", border: "1px solid #D5D9DF", color: "#414B56", padding: "10px 18px", borderRadius: 8, cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif", whiteSpace: "nowrap" }}>Regenerate</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ─── COMPARE MODAL ──────────────────────────────────────────────────────── */
function CompareModal({ report, originalText, onClose }) {
  const [state, setState] = useState("upload");
  const [revised, setRevised] = useState(null);
  const [comparison, setComparison] = useState(null);
  const [errorMsg, setErrorMsg] = useState("");
  const [dragging, setDragging] = useState(false);
  const fileRef = useRef();

  const handleFile = (f) => {
    if (!f) return;
    const ok = f.type === "application/pdf" || f.name?.toLowerCase().endsWith(".pdf") || f.name?.toLowerCase().endsWith(".docx") || f.type?.includes("wordprocessingml");
    if (ok) setRevised(f);
  };
  const onDrop = useCallback((e) => { e.preventDefault(); setDragging(false); handleFile(e.dataTransfer.files[0]); }, []);

  const compare = async () => {
    if (!revised) return;
    setState("loading");
    try {
      const revisedText = await extractText(revised);
      const { comparison: comp } = await api("/api/assist", { type: "compare", report, originalText, revisedText });
      setComparison(comp);
      setState("done");
    } catch (e) { setErrorMsg(e.message); setState("error"); }
  };

  const Group = ({ items, label, color, bg, border, icon }) => {
    if (!items?.length) return null;
    return (
      <div style={{ marginBottom: 18 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 9 }}>
          <span style={{ fontSize: 9, color, background: bg, border: `1px solid ${border}`, padding: "2px 9px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.08em" }}>{label}</span>
        </div>
        {items.map((item, i) => (
          <div key={i} style={{ background: bg, border: `1px solid ${border}`, borderRadius: 6, padding: "11px 14px", marginBottom: 7 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: "#16212E", fontFamily: "'Archivo', sans-serif", marginBottom: 3 }}>{item.title}</div>
            <div style={{ fontSize: 12.5, color: "#333D4A", lineHeight: 1.7 }}>{item.what}</div>
            {item.stillNeeded && <div style={{ fontSize: 12, color, marginTop: 5 }}>Still needed: {item.stillNeeded}</div>}
          </div>
        ))}
      </div>
    );
  };

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.52)", zIndex: 1000, display: "flex", alignItems: "flex-end", justifyContent: "center" }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: "20px 20px 0 0", width: "100%", maxWidth: 760, maxHeight: "90vh", overflow: "hidden", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid #E3E6EA", display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 20, color: "#16212E", marginBottom: 3 }}>Compare revisions</div>
            <div style={{ fontSize: 12.5, color: "#414B56" }}>
              {state === "done" ? "Here's what they changed, and what they ignored." : "Upload the revised contract they sent back."}
            </div>
          </div>
          <button onClick={onClose} style={{ background: "transparent", border: "none", fontSize: 20, color: "#7C858E", cursor: "pointer", padding: "0 0 0 16px" }}>✕</button>
        </div>
        <div style={{ flex: 1, overflowY: "auto", padding: "20px 24px" }}>
          {state === "upload" && (
            <div>
              <div className={`drop${dragging ? " drag" : ""}`}
                onClick={() => fileRef.current?.click()}
                onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
                onDragLeave={() => setDragging(false)}
                onDrop={onDrop}
                style={{ marginBottom: 14 }}>
                <input ref={fileRef} type="file" accept=".pdf,.docx" style={{ display: "none" }} onChange={(e) => handleFile(e.target.files[0])} />
                {revised ? (
                  <div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 12, color: "#16212E", marginBottom: 2 }}>{revised.name}</div>
                    <div style={{ fontSize: 11, color: "#667079" }}>{(revised.size / 1024).toFixed(0)} KB · tap to change</div>
                  </div>
                ) : (
                  <div>
                    <div style={{ fontSize: 14, color: "#374151", marginBottom: 4 }}>Drop the revised contract here</div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, color: "#667079" }}>PDF or Word doc · tap to browse</div>
                  </div>
                )}
              </div>
              <button className="btn" style={{ width: "100%", opacity: revised ? 1 : 0.4 }} disabled={!revised} onClick={compare}>
                Compare contracts
              </button>
            </div>
          )}
          {state === "loading" && (
            <div style={{ textAlign: "center", padding: "48px 0" }}>
              <div style={{ display: "flex", justifyContent: "center", gap: 6, marginBottom: 18 }}>
                <div className="dot" /><div className="dot" /><div className="dot" />
              </div>
              <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 18, color: "#16212E", marginBottom: 6 }}>Comparing the two contracts…</div>
              <div style={{ fontSize: 12.5, color: "#9CA3AF" }}>Checking what they agreed to and what they quietly ignored.</div>
            </div>
          )}
          {state === "error" && (
            <div style={{ textAlign: "center", padding: "32px 0" }}>
              <div style={{ fontSize: 13, color: "#DC2626", marginBottom: 14 }}>{errorMsg || "Something went wrong."}</div>
              <button className="btn" onClick={compare}>Try again</button>
            </div>
          )}
          {state === "done" && comparison && (
            <div>
              <div style={{ background: "#16212E", borderRadius: 6, padding: "14px 16px", marginBottom: 20 }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.12em", marginBottom: 7 }}>THE VERDICT</div>
                <div style={{ fontSize: 13.5, color: "#F9FAFB", lineHeight: 1.85, fontFamily: "'Archivo', sans-serif" }}>{comparison.summary}</div>
              </div>
              <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 22 }}>
                {[
                  [comparison.accepted?.length, "Accepted", "#16A34A", "#F0FDF4", "#BBF7D0"],
                  [comparison.partial?.length, "Partial", "#92400E", "#FFFBEB", "#FCD34D"],
                  [comparison.ignored?.length, "Ignored", "#991B1B", "#FEF2F2", "#FCA5A5"],
                  [comparison.newIssues?.length, "New issues", "#374151", "#F9FAFB", "#E5E7EB"],
                ].filter(([n]) => n > 0).map(([n, label, color, bg, border]) => (
                  <div key={label} style={{ background: bg, border: `1px solid ${border}`, borderRadius: 6, padding: "8px 14px", display: "flex", alignItems: "center", gap: 7 }}>
                    <span style={{ fontFamily: "'Archivo', sans-serif", fontSize: 20, fontWeight: 600, color, lineHeight: 1 }}>{n}</span>
                    <span style={{ fontSize: 12, color: "#374151" }}>{label}</span>
                  </div>
                ))}
              </div>
              <Group items={comparison.accepted} label="ACCEPTED" color="#16A34A" bg="#F0FDF4" border="#BBF7D0" />
              <Group items={comparison.partial} label="PARTIAL WIN" color="#92400E" bg="#FFFBEB" border="#FCD34D" />
              <Group items={comparison.ignored} label="IGNORED" color="#991B1B" bg="#FEF2F2" border="#FCA5A5" />
              <Group items={comparison.newIssues} label="NEW ISSUES" color="#374151" bg="#F9FAFB" border="#E5E7EB" />

              <div style={{ marginTop: 20, background: "#16212E", borderRadius: 8, padding: 20 }}>
                <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 17, color: "#F9FAFB", marginBottom: 8, lineHeight: 1.3 }}>
                  {comparison.ignored?.length > 0
                    ? `They ignored ${comparison.ignored.length} point${comparison.ignored.length !== 1 ? "s" : ""}. Worth one more round.`
                    : "Good progress. Keep pushing on the partial wins."}
                </div>
                <div style={{ fontSize: 12.5, color: "#6B7280", lineHeight: 1.7, marginBottom: 16 }}>
                  Go back to your report, update your negotiation email to focus on what they didn't move on, and send it again. Most 3PLs give more ground in round two.
                </div>
                <button onClick={onClose} style={{ background: "#F4F5F7", color: "#16212E", border: "none", padding: "11px 22px", borderRadius: 8, cursor: "pointer", fontFamily: "'Archivo', sans-serif", fontSize: 13, fontWeight: 700, width: "100%" }}>
                  Back to my report
                </button>
              </div>
              <button onClick={() => { setRevised(null); setState("upload"); }} style={{ marginTop: 10, background: "transparent", border: "1px solid #D5D9DF", color: "#414B56", padding: "9px 18px", borderRadius: 8, cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif", width: "100%" }}>
                Upload another revision
              </button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ─── READING SCREEN (progress only, profile is captured up front now) ──── */
const STEPS = [
  "Reading your contract…",
  "Breaking down the clauses…",
  "Checking what's standard vs what's not…",
  "Working out what's worth raising…",
  "Almost there, writing up your report…",
];
const WAIT_TIPS = [
  ["WHAT WE CHECK", "Around 30 clause areas", "Termination, liability, SLAs, price rises, returns, claims windows, exit terms and more, against real market benchmarks for your size."],
  ["WORTH KNOWING", "The rate card matters too", "The contract sets the rules, but the rate card sets the prices. If yours wasn't in the document, we'll remind you to request it."],
  ["WORTH KNOWING", "Most 3PLs expect pushback", "A first-draft contract is an opening position, not a final offer. Asking is normal, and your report says what they'll actually move on."],
];

function ReadingScreen({ step, onCancel }) {
  const [elapsed, setElapsed] = useState(0);
  const [tipIdx, setTipIdx] = useState(0);

  useEffect(() => {
    const t = setInterval(() => setElapsed((s) => s + 1), 1000);
    const tips = setInterval(() => setTipIdx((i) => (i + 1) % WAIT_TIPS.length), 9000);
    return () => { clearInterval(t); clearInterval(tips); };
  }, []);

  const mins = Math.floor(elapsed / 60);
  const secs = elapsed % 60;
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
  const [icon, title, desc] = WAIT_TIPS[tipIdx];

  return (
    <div style={{ textAlign: "center", padding: "60px 24px" }}>
      <div style={{ display: "flex", justifyContent: "center", gap: 6, marginBottom: 24 }}>
        <div className="dot" /><div className="dot" /><div className="dot" />
      </div>
      <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 22, color: "#16212E", marginBottom: 6, minHeight: 30 }}>
        {STEPS[Math.min(step, STEPS.length - 1)]}
      </div>
      <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, color: "#667079", letterSpacing: "0.08em", marginBottom: 28 }}>
        {timeStr}, a thorough read takes a couple of minutes
      </div>
      <div style={{ maxWidth: 320, margin: "0 auto 40px", background: "#E3E6EA", borderRadius: 4, height: 3, overflow: "hidden" }}>
        <div style={{ height: "100%", borderRadius: 4, background: "#16212E", width: `${Math.min(((step + 1) / STEPS.length) * 100, 90)}%`, transition: "width 0.8s ease" }} />
      </div>

      <div key={tipIdx} className="fade-in" style={{ maxWidth: 420, margin: "0 auto", background: "#fff", borderRadius: 10, border: "1px solid #E3E6EA", padding: "24px", textAlign: "left" }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 10 }}>{icon}</div>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 16, color: "#16212E", marginBottom: 8 }}>{title}</div>
        <div style={{ fontSize: 13, color: "#414B56", lineHeight: 1.8 }}>{desc}</div>
      </div>

      {elapsed >= 45 && (
        <div style={{ marginTop: 28, animation: "fadeUp 0.4s ease forwards" }}>
          <div style={{ fontSize: 12.5, color: "#9CA3AF", marginBottom: 10, fontFamily: "'Archivo', sans-serif" }}>Taking longer than expected?</div>
          <button onClick={onCancel} style={{ background: "transparent", border: "1px solid #D5D9DF", color: "#414B56", padding: "8px 20px", borderRadius: 5, cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif" }}>
            CANCEL
          </button>
        </div>
      )}
      <div style={{ marginTop: 36, fontSize: 11, color: "#7C858E", fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.04em" }}>
        Your document is analysed and discarded, never stored on our servers
      </div>
    </div>
  );
}

/* ─── ONBOARDING, full profile BEFORE analysis (fixes the tier bug) ─────── */
const QUESTIONS = [
  { key: "market", q: "Where is this contract based?", sub: "This sets which legal standards and market benchmarks we apply.", options: [["UK", "UK"], ["EU", "EU"], ["UK & EU", "OTHER"]] },
  { key: "orders", q: "Orders per month?", sub: "This decides which contract terms are realistic for you to push for.", options: [["Under 500", "under500"], ["500-2k", "500-2000"], ["2k-5k", "2000-5000"], ["5k+", "5000plus"]] },
  { key: "productType", q: "What do you sell?", options: [["General / mixed", "general"], ["Apparel & fashion", "apparel"], ["Fragile / high-value", "fragile"], ["Food & bev", "food"]] },
  { key: "aov", q: "Average order value?", options: [["Under £50", "under50"], ["£50-150", "50-150"], ["£150-500", "150-500"], ["£500+", "500plus"]] },
  { key: "role", q: "What's your role?", sub: "So the report talks about what you care about.", options: [["Founder / owner", "founder"], ["Operations", "operations"], ["Finance", "finance"], ["Something else", "other"]] },
];

function Onboarding({ onComplete }) {
  const [step, setStep] = useState(0);
  const [answers, setAnswers] = useState({});
  const q = QUESTIONS[step];

  const select = (val) => {
    const next = { ...answers, [q.key]: val };
    setAnswers(next);
    setTimeout(() => {
      if (step >= QUESTIONS.length - 1) onComplete(next);
      else setStep((s) => s + 1);
    }, 180);
  };

  return (
    <div className="fade-in" style={{ maxWidth: 520, margin: "0 auto" }}>
      <div style={{ textAlign: "center", marginBottom: 32 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.1em", marginBottom: 14 }}>
          {step + 1} OF {QUESTIONS.length} · 15 SECONDS, THEN UPLOAD
        </div>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: "clamp(24px,3.5vw,32px)", color: "#16212E", lineHeight: 1.2, letterSpacing: "-0.02em", marginBottom: 10 }}>
          {q.q}
        </div>
        {q.sub && <div style={{ fontSize: 13.5, color: "#414B56", lineHeight: 1.75 }}>{q.sub}</div>}
      </div>

      <div key={step} className="fade-in" style={{ display: "grid", gridTemplateColumns: q.options.length === 3 ? "1fr 1fr 1fr" : "1fr 1fr", gap: 12, marginBottom: 24 }}>
        {q.options.map(([label, val]) => (
          <button key={val} onClick={() => select(val)}
            style={{ padding: "18px 14px", borderRadius: 8, border: `1.5px solid ${answers[q.key] === val ? "#16212E" : "#D5D9DF"}`, background: answers[q.key] === val ? "#16212E" : "#fff", color: answers[q.key] === val ? "#F4F5F7" : "#374151", cursor: "pointer", fontSize: 14.5, fontFamily: "'Archivo', sans-serif", transition: "all 0.15s", textAlign: "center" }}>
            {label}
          </button>
        ))}
      </div>

      <div style={{ display: "flex", justifyContent: "center", gap: 5 }}>
        {QUESTIONS.map((_, i) => (
          <span key={i} style={{ width: 6, height: 6, borderRadius: "50%", background: i <= step ? "#16212E" : "#D5D9DF", display: "inline-block" }} />
        ))}
      </div>
      {step > 0 && (
        <div style={{ textAlign: "center", marginTop: 16 }}>
          <button onClick={() => setStep((s) => s - 1)} style={{ background: "none", border: "none", color: "#667079", cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif" }}>Back</button>
        </div>
      )}
    </div>
  );
}

/* ─── HELP MODAL — self-serve first, message form second, no dead inbox ──── */
function HelpModal({ paid, onClose, onRestore }) {
  const [email, setEmail] = useState("");
  const [message, setMessage] = useState("");
  const [state, setState] = useState("idle"); // idle | sending | sent | error
  const [errMsg, setErrMsg] = useState("");

  const send = async () => {
    if (!email.includes("@") || message.trim().length < 5) { setErrMsg("Add your email and a short message."); return; }
    setState("sending"); setErrMsg("");
    try {
      await api("/api/support", { email: email.trim(), message: message.trim() });
      setState("sent");
    } catch (e) { setState("error"); setErrMsg(e.message || "Couldn't send. Try again."); }
  };

  const openPortal = async () => {
    try { const { url } = await api("/api/portal", {}); window.location.href = url; }
    catch (e) { setErrMsg(e.message); }
  };

  const Row = ({ title, desc, action, onClick }) => (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: "12px 0", borderBottom: "1px solid #EDF0F3" }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 13, fontWeight: 600, color: "#16212E", marginBottom: 2 }}>{title}</div>
        <div style={{ fontSize: 12, color: "#414B56", lineHeight: 1.6 }}>{desc}</div>
      </div>
      {action && <button onClick={onClick} className="btn-ghost" style={{ flexShrink: 0 }}>{action}</button>}
    </div>
  );

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.55)", zIndex: 1500, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: 10, width: "100%", maxWidth: 480, maxHeight: "88vh", overflowY: "auto", padding: "24px" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
          <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 19, color: "#16212E" }}>Help</div>
          <button onClick={onClose} style={{ background: "transparent", border: "none", fontSize: 20, color: "#7C858E", cursor: "pointer" }}>✕</button>
        </div>
        <div style={{ fontSize: 12.5, color: "#414B56", lineHeight: 1.7, marginBottom: 12 }}>
          Almost everything is instant and self-serve. Start with the buttons; the form is for anything they don't cover.
        </div>

        <Row title="Unlock paid features on this device" desc="Subscribed on another browser or phone? Restore with your checkout email." action="RESTORE" onClick={() => { onClose(); onRestore(); }} />
        <Row title="Cancel or change your subscription" desc={paid ? "Opens your secure Stripe billing page. Two clicks to cancel." : "Restore access first, then manage billing from your dashboard."} action={paid ? "BILLING" : null} onClick={openPortal} />
        <Row title="Receipts and invoices" desc="Stripe emails a receipt for every payment automatically. Check the inbox you used at checkout." action={null} />

        <div style={{ marginTop: 16 }}>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 8 }}>ANYTHING ELSE</div>
          {state === "sent" ? (
            <div style={{ background: "#F0FDF4", border: "1px solid #BBF7D0", borderRadius: 6, padding: "13px 16px", fontSize: 13, color: "#166534", lineHeight: 1.7 }}>
              Got it. Your message is logged with your email attached, and we read every one. If it needs action, you'll hear back at {email}.
            </div>
          ) : (
            <>
              <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@yourbrand.com"
                style={{ width: "100%", padding: "11px 13px", border: "1px solid #D5D9DF", borderRadius: 6, fontSize: 14, fontFamily: "'Archivo', sans-serif", background: "#FAFBFC", outline: "none", marginBottom: 8, boxSizing: "border-box" }} />
              <textarea value={message} onChange={(e) => setMessage(e.target.value)} placeholder="What's up? Include your order of events if something broke." rows={4}
                style={{ width: "100%", padding: "11px 13px", border: "1px solid #D5D9DF", borderRadius: 6, fontSize: 14, fontFamily: "'Archivo', sans-serif", background: "#FAFBFC", outline: "none", marginBottom: 8, boxSizing: "border-box", resize: "vertical" }} />
              {errMsg && <div style={{ fontSize: 12, color: "#DC2626", marginBottom: 8 }}>{errMsg}</div>}
              <button className="btn" style={{ width: "100%" }} onClick={send} disabled={state === "sending"}>
                {state === "sending" ? "Sending…" : "Send message"}
              </button>
              <div style={{ marginTop: 8, fontSize: 11, color: "#667079", lineHeight: 1.6 }}>
                Clause is a small operation. Billing and access issues are fixed instantly by the buttons above; messages are for everything else and get a reply when action is needed.
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

/* ─── RESTORE ACCESS MODAL ───────────────────────────────────────────────── */
function RestoreModal({ onClose, onRestored }) {
  const [email, setEmail] = useState("");
  const [state, setState] = useState("idle");
  const [msg, setMsg] = useState("");

  const restore = async () => {
    if (!email.includes("@")) { setMsg("Enter the email you used at checkout."); return; }
    setState("loading"); setMsg("");
    try {
      const data = await api("/api/verify", { email: email.trim() });
      onRestored(data);
    } catch (e) {
      setState("idle");
      setMsg(e.message || "No payment found for that email.");
    }
  };

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.55)", zIndex: 1500, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: "#fff", borderRadius: 10, width: "100%", maxWidth: 400, padding: "26px 24px" }}>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 19, color: "#16212E", marginBottom: 6 }}>Restore your access</div>
        <div style={{ fontSize: 13, color: "#414B56", lineHeight: 1.7, marginBottom: 16 }}>
          Already subscribed? Enter the email you used at checkout and we'll unlock this browser.
        </div>
        <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} onKeyDown={(e) => e.key === "Enter" && restore()} placeholder="you@yourbrand.com"
          style={{ width: "100%", padding: "12px 14px", border: "1px solid #D5D9DF", borderRadius: 8, fontSize: 14, fontFamily: "'Archivo', sans-serif", background: "#FAFBFC", outline: "none", marginBottom: 12, boxSizing: "border-box" }} />
        {msg && <div style={{ fontSize: 12, color: "#DC2626", marginBottom: 12 }}>{msg}</div>}
        <button className="btn" style={{ width: "100%" }} onClick={restore} disabled={state === "loading"}>
          {state === "loading" ? "Checking…" : "Restore access"}
        </button>
        <div style={{ textAlign: "center", marginTop: 12 }}>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "#667079", cursor: "pointer", fontSize: 13, fontFamily: "'Archivo', sans-serif" }}>Cancel</button>
        </div>
      </div>
    </div>
  );
}

/* ─── DASHBOARD — a negotiation pipeline, not a greeting card ────────────── */
const STAGES = [
  ["analysed", "Just analysed"],
  ["sent", "Sent to 3PL"],
  ["waiting", "Waiting on reply"],
  ["revision", "Revision received"],
  ["signed", "Agreed & signed"],
];
const daysAgo = (iso) => Math.max(0, Math.floor((Date.now() - new Date(iso).getTime()) / (1000 * 60 * 60 * 24)));

function stageNudge(stage, days) {
  if (stage === "signed") return { tone: "ok", text: "Done. Diarise the renewal notice window now, so the auto-renewal clause never catches you." };
  if (stage === "revision") return { tone: "act", text: "Upload their revision to see what they accepted, what they ignored, and whether round two is worth it." };
  if ((stage === "sent" || stage === "waiting") && days >= 5) return { tone: "warn", text: `${days} days without a reply. Chase politely: most 3PLs respond in 3 to 5 days, and silence is a negotiating tactic.` };
  if (stage === "sent" || stage === "waiting") return { tone: "ok", text: "Most 3PLs reply within 3 to 5 days. Sit tight for now." };
  return { tone: "act", text: "Send the negotiation email back. Momentum matters: 3PLs prioritise brands that push." };
}

function Dashboard({ access, onContinue, onNewContract, onUploadRevision, onManage }) {
  const [reports, setReports] = useState(loadReportIndex);
  const paid = !!access?.paid;

  const changeStage = (id, stage) => setReports(setReportStage(id, stage));

  return (
    <div style={{ maxWidth: 720, margin: "0 auto", padding: "32px 24px 60px" }}>

      {/* Header row: title left, status + actions right */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap", marginBottom: 6 }}>
        <div>
          <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 24, color: "#16212E" }}>Negotiations</div>
          <div style={{ fontSize: 12.5, color: "#667079", marginTop: 2 }}>
            {paid
              ? <span>Subscription active{access.email ? ` · ${access.email}` : ""} · <button onClick={onManage} style={{ background: "none", border: "none", padding: 0, cursor: "pointer", fontSize: 12.5, color: "#414B56", textDecoration: "underline", textUnderlineOffset: 3 }}>Manage billing</button></span>
              : "Free plan · your first findings are free on every contract"}
          </div>
        </div>
        <button className="btn" onClick={onNewContract}>New contract</button>
      </div>

      {/* Pipeline */}
      <div style={{ marginTop: 18 }}>
        {reports.length === 0 ? (
          <div style={{ background: "#fff", border: "2px dashed #E3E6EA", borderRadius: 10, padding: "40px 24px", textAlign: "center" }}>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 17, color: "#16212E", marginBottom: 8 }}>No contracts analysed yet</div>
            <div style={{ fontSize: 13, color: "#667079", marginBottom: 20, lineHeight: 1.7 }}>Upload your 3PL contract to get started. Takes about two minutes.</div>
            <button className="btn" onClick={onNewContract}>Upload my contract</button>
          </div>
        ) : (
          <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, overflow: "hidden" }}>
            {reports.map((item, i) => {
              const stage = item.stage || "analysed";
              const days = daysAgo(item.date);
              const nudge = stageNudge(stage, days);
              const rColor = item.overallRisk === "HIGH" ? "#EF4444" : item.overallRisk === "MEDIUM" ? "#F59E0B" : "#16A34A";
              const nudgeColor = nudge.tone === "warn" ? "#92400E" : nudge.tone === "act" ? "#414B56" : "#667079";
              const nudgeBg = nudge.tone === "warn" ? "#FFFBEB" : "#FAFBFC";
              return (
                <div key={item.id} style={{ borderBottom: i < reports.length - 1 ? "1px solid #EDF0F3" : "none" }}>
                  <div style={{ padding: "16px 18px 12px", display: "flex", alignItems: "flex-start", gap: 14, flexWrap: "wrap" }}>
                    <div style={{ flex: "1 1 220px", minWidth: 0 }}>
                      <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 600, fontSize: 14.5, color: "#16212E", marginBottom: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{item.fileName}</div>
                      <div style={{ fontSize: 12, color: "#667079" }}>
                        Analysed {days === 0 ? "today" : days === 1 ? "yesterday" : `${days} days ago`}
                        <span style={{ margin: "0 6px", color: "#D5D9DF" }}>·</span>
                        Risk <span style={{ color: rColor, fontWeight: 600 }}>{item.riskScore ?? "?"}</span>
                      </div>
                    </div>
                    <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                      <select value={stage} onChange={(e) => changeStage(item.id, e.target.value)}
                        style={{ fontFamily: "'Archivo', sans-serif", fontSize: 12, color: "#414B56", padding: "7px 8px", border: "1px solid #E3E6EA", borderRadius: 5, background: "#FAFBFC", cursor: "pointer" }}>
                        {STAGES.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
                      </select>
                      {stage === "revision" ? (
                        <button className="btn" style={{ padding: "9px 16px", fontSize: 12.5 }} onClick={() => onUploadRevision(item.id)}>Upload revision</button>
                      ) : (
                        <button className="btn" style={{ padding: "9px 16px", fontSize: 12.5 }} onClick={() => onContinue(item.id)}>Open</button>
                      )}
                    </div>
                  </div>
                  {nudge.tone !== "ok" && (
                    <div style={{ margin: "0 18px 14px", padding: "9px 12px", background: nudgeBg, border: `1px solid ${nudge.tone === "warn" ? "#FCD34D" : "#EDF0F3"}`, borderRadius: 6, fontSize: 12, color: nudgeColor, lineHeight: 1.65 }}>
                      {nudge.text}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </div>

      {reports.length > 0 && (
        <div style={{ marginTop: 14, fontSize: 11.5, color: "#98A1AB", lineHeight: 1.65, textAlign: "center" }}>
          Reports are saved in this browser. Export a PDF for a permanent copy; paid access works on any device via Restore access.
        </div>
      )}
    </div>
  );
}

/* ─── SAMPLE REPORT SCREEN ───────────────────────────────────────────────── */
function SampleReport({ onStart, onBack }) {
  const r = SAMPLE_REPORT;
  return (
    <div className="fade-in" style={{ maxWidth: 760, margin: "0 auto" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 16, flexWrap: "wrap" }}>
        <button onClick={onBack} style={{ background: "none", border: "1px solid #D5D9DF", borderRadius: 5, padding: "8px 14px", cursor: "pointer", fontSize: 13, color: "#414B56", fontFamily: "'Archivo', sans-serif" }}>Back</button>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontSize: 9, color: "#92400E", background: "#FFFBEB", border: "1px solid #FCD34D", padding: "3px 10px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.08em" }}>SAMPLE REPORT</span>
          <span style={{ fontSize: 11.5, color: "#667079" }}>UK apparel brand · ~1,400 orders/month · real clause wording, anonymised</span>
        </div>
      </div>

      <div style={{ background: "#16212E", borderRadius: 8, padding: "20px 22px", marginBottom: 16, display: "flex", gap: 14, alignItems: "flex-start" }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.12em", marginBottom: 7 }}>THE VERDICT</div>
          <div style={{ fontSize: 14.5, color: "#F9FAFB", lineHeight: 1.9 }}>{r.alexSays}</div>
        </div>
        <div style={{ textAlign: "right", flexShrink: 0 }}>
          <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 38, fontWeight: 700, lineHeight: 1, color: "#F59E0B" }}>{r.riskScore}</div>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.1em" }}>/ 100 RISK</div>
        </div>
      </div>

      <div style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" }}>
        {[[r.summaryStats.mustChange, "Change this", "#EF4444", "#FEF2F2", "#FCA5A5"], [r.summaryStats.pushBack, "Push back", "#1E40AF", "#EFF6FF", "#93C5FD"], [r.summaryStats.headsUp, "Heads up", "#92400E", "#FFFBEB", "#FCD34D"], [r.summaryStats.fine, "Looking good", "#16A34A", "#F0FDF4", "#BBF7D0"]].map(([n, label, color, bg, border]) => (
          <div key={label} style={{ background: bg, border: `1px solid ${border}`, borderRadius: 6, padding: "8px 13px", display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ fontFamily: "'Archivo', sans-serif", fontSize: 20, fontWeight: 600, color, lineHeight: 1 }}>{n}</span>
            <span style={{ fontSize: 12, color: "#374151" }}>{label}</span>
          </div>
        ))}
      </div>

      <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 8, padding: "17px 20px", marginBottom: 16 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.1em", marginBottom: 14 }}>BEFORE YOU SIGN · START HERE</div>
        {r.beforeYouSign.map((p, i) => (
          <div key={i} style={{ display: "flex", gap: 12, alignItems: "flex-start", paddingBottom: i < r.beforeYouSign.length - 1 ? 13 : 0, marginBottom: i < r.beforeYouSign.length - 1 ? 13 : 0, borderBottom: i < r.beforeYouSign.length - 1 ? "1px solid #EDF0F3" : "none" }}>
            <div style={{ width: 24, height: 24, borderRadius: "50%", background: "#16212E", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, flexShrink: 0, marginTop: 1 }}>{p.rank}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13.5, fontWeight: 600, color: "#16212E", marginBottom: 3, fontFamily: "'Archivo', sans-serif" }}>{p.issue}</div>
              <div style={{ fontSize: 13, color: "#6B7280", lineHeight: 1.75 }}>{p.alexSays}</div>
            </div>
            <span style={{ fontSize: 9, color: "#16A34A", background: "#F0FDF4", border: "1px solid #BBF7D0", padding: "2px 9px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace", flexShrink: 0, marginTop: 3 }}>Likely to win</span>
          </div>
        ))}
      </div>

      {r.sections.map((s) => (
        <SectionCard key={s.id} section={s} isNew={false} />
      ))}

      <div style={{ background: "#16212E", borderRadius: 8, padding: "28px", marginTop: 8, textAlign: "center" }}>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 22, color: "#F9FAFB", lineHeight: 1.25, marginBottom: 10 }}>This is what you get for your own contract.</div>
        <div style={{ fontSize: 13, color: "#9CA3AF", lineHeight: 1.8, marginBottom: 20, maxWidth: 420, margin: "0 auto 20px" }}>
          Upload yours and see your first findings free. No account, no card, the analysis runs and you read the top of your report before deciding anything.
        </div>
        <button className="btn" style={{ background: "#F4F5F7", color: "#16212E", padding: "15px 40px" }} onClick={onStart}>
          Analyse my contract free
        </button>
      </div>
    </div>
  );
}

/* ─── ABOUT PAGE ─────────────────────────────────────────────────────────── */
const FAQ_ITEMS = [
  ["Is my contract confidential?", "Yes. The text is extracted in your browser, analysed, and discarded. We never store your document, and nothing you upload is shared with anyone, including your 3PL. We keep only anonymised statistics (for example, how many contracts of your size have a 36-month term)."],
  ["Is this legal advice?", "No. It's commercial guidance from fulfilment industry experience: what's normal, what's below market, and what 3PLs will realistically concede. Where a clause genuinely needs a solicitor, the report tells you so instead of guessing."],
  ["What do I get free, and what's paid?", "The analysis runs free and you read the top of your report, the verdict, risk score, and first findings, before deciding anything. Full access is £19.99 a month: every clause explained with exactly what to say, the negotiation email, and revision comparison. Cancel any time from your dashboard."],
  ["Which contracts does it work on?", "UK and EU fulfilment and 3PL agreements: MSAs, warehousing and fulfilment T&Cs, and renewals. Upload the Word document your 3PL sent for the best results; PDF works too."],
  ["What if my 3PL just says no?", "Some clauses they won't move on, and the report says so honestly. But most first-draft contracts are opening positions: term length, claims windows and price caps are conceded every week. The report tells you which battles are winnable before you pick them."],
];

function AboutPage({ onStart }) {
  return (
    <div className="fade-in" style={{ maxWidth: 680, margin: "0 auto" }}>
      <div style={{ textAlign: "center", marginBottom: 28 }}>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 30, color: "#16212E", marginBottom: 8 }}>About Clause</div>
        <div style={{ fontSize: 14, color: "#414B56", lineHeight: 1.75 }}>What it checks, where the benchmarks come from, and the questions everyone asks.</div>
      </div>

      <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "22px", marginBottom: 14 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 6 }}>WHERE THE BENCHMARKS COME FROM</div>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 16, fontWeight: 700, color: "#16212E", marginBottom: 10 }}>Built from the other side of the table.</div>
        <div style={{ fontSize: 13, color: "#414B56", lineHeight: 1.9 }}>
          Clause was built by people who've spent their careers inside 3PLs across the UK and Europe, writing these contracts, negotiating them, and watching brands sign terms they didn't need to accept. We know which clauses a 3PL will quietly drop if you ask, which ones they'll fight for, and which ones they slip in hoping you won't notice. That knowledge is the benchmark library your contract gets checked against, and when something genuinely needs a solicitor, the report says so.
        </div>
      </div>

      <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "20px 22px", marginBottom: 14 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 6 }}>WHAT GETS CHECKED</div>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 15, fontWeight: 700, color: "#16212E", marginBottom: 12 }}>Every clause, against market benchmarks for your size and market.</div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(170px, 1fr))", gap: "6px 14px" }}>
          {[
            "Contract term & lock-in", "Auto-renewal traps", "Termination & notice", "Liability caps", "Claims windows", "Dispatch SLAs & teeth",
            "Price increase caps", "Rate card & hidden charges", "Minimum volume commitments", "Storage & peak surcharges", "Returns handling SLAs", "Lien & exit terms",
            "Insurance obligations", "Shrinkage allowances", "Carrier selection rights", "Exclusivity scope", "Sub-contracting consent", "GDPR / data processing",
          ].map((t) => (
            <div key={t} style={{ fontSize: 12, color: "#414B56", display: "flex", alignItems: "center", gap: 7, padding: "3px 0" }}>
              <span style={{ width: 4, height: 4, background: "#16212E", display: "inline-block", flexShrink: 0 }} />{t}
            </div>
          ))}
        </div>
      </div>

      <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "20px 22px", marginBottom: 14 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 14 }}>COMMON QUESTIONS</div>
        {FAQ_ITEMS.map(([q, a], i, arr) => (
          <div key={q} style={{ paddingBottom: i < arr.length - 1 ? 14 : 0, marginBottom: i < arr.length - 1 ? 14 : 0, borderBottom: i < arr.length - 1 ? "1px solid #EDF0F3" : "none" }}>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 13.5, fontWeight: 600, color: "#16212E", marginBottom: 5 }}>{q}</div>
            <div style={{ fontSize: 12.5, color: "#414B56", lineHeight: 1.85 }}>{a}</div>
          </div>
        ))}
      </div>

      <div style={{ padding: "12px 16px", border: "1px solid #E3E6EA", borderRadius: 6, marginBottom: 20 }}>
        <div style={{ fontSize: 11, color: "#667079", lineHeight: 1.75, textAlign: "center", fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.02em" }}>
          Clause provides guidance based on industry experience, not legal advice. Analysis is software-assisted, built on our own negotiation benchmarks. For complex or high-value contracts, involve a solicitor.
        </div>
      </div>

      <div style={{ textAlign: "center", marginBottom: 8 }}>
        <button className="btn" onClick={onStart}>Analyse my contract free</button>
      </div>
    </div>
  );
}

/* ─── PRICING PAGE ───────────────────────────────────────────────────────── */
function PricingPage({ onStart, onCheckout, paid, onTerms }) {
  return (
    <div className="fade-in" style={{ maxWidth: 680, margin: "0 auto" }}>
      <div style={{ textAlign: "center", marginBottom: 28 }}>
        <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 30, color: "#16212E", marginBottom: 8 }}>Simple pricing</div>
        <div style={{ fontSize: 14, color: "#414B56", lineHeight: 1.75 }}>Try it free on your own contract. Pay only if the findings are worth acting on.</div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(260px, 1fr))", gap: 14, marginBottom: 14 }}>
        <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "24px" }}>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 10 }}>FREE</div>
          <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 800, fontSize: 28, color: "#16212E", marginBottom: 2 }}>£0</div>
          <div style={{ fontSize: 12, color: "#667079", marginBottom: 16 }}>No account. No card.</div>
          {["Full analysis of your contract", "The verdict and risk score", "Your first findings", "The complete sample report"].map((t) => (
            <div key={t} style={{ fontSize: 13, color: "#414B56", padding: "5px 0", display: "flex", gap: 8, alignItems: "center" }}>
              <span style={{ width: 4, height: 4, background: "#16212E", flexShrink: 0, display: "inline-block" }} />{t}
            </div>
          ))}
          <button className="btn" style={{ width: "100%", marginTop: 16, background: "#fff", color: "#16212E", border: "1.5px solid #16212E" }} onClick={onStart}>Start free</button>
        </div>

        <div style={{ background: "#16212E", borderRadius: 10, padding: "24px" }}>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#6B7280", letterSpacing: "0.12em", marginBottom: 10 }}>FULL ACCESS</div>
          <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 800, fontSize: 28, color: "#F9FAFB", marginBottom: 2 }}>£19.99<span style={{ fontSize: 14, fontWeight: 400, color: "#9CA3AF" }}>/month</span></div>
          <div style={{ fontSize: 12, color: "#9CA3AF", marginBottom: 16 }}>Cancel anytime, self-serve. Billed by Stripe.</div>
          {["Everything in free", "Every clause explained, with what to say", "Negotiation email, written for you", "Revision comparison, round after round", "Report Q&A"].map((t) => (
            <div key={t} style={{ fontSize: 13, color: "#D1D5DB", padding: "5px 0", display: "flex", gap: 8, alignItems: "center" }}>
              <span style={{ width: 4, height: 4, background: "#F4F5F7", flexShrink: 0, display: "inline-block" }} />{t}
            </div>
          ))}
          <button className="btn" style={{ width: "100%", marginTop: 16, background: "#F4F5F7", color: "#16212E" }} onClick={paid ? onStart : onCheckout}>
            {paid ? "You have full access" : "Get full access"}
          </button>
          {!paid && (
            <div style={{ marginTop: 10, fontSize: 11, color: "#6B7280", textAlign: "center" }}>
              By subscribing you agree to the <button onClick={onTerms} style={{ background: "none", border: "none", padding: 0, cursor: "pointer", color: "#9CA3AF", textDecoration: "underline", textUnderlineOffset: 3, fontSize: 11 }}>Terms</button>.
            </div>
          )}
        </div>
      </div>

      <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "20px 22px", marginBottom: 20 }}>
        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 14 }}>BILLING QUESTIONS</div>
        {[
          ["How do I cancel?", "From your dashboard: Manage subscription opens your secure Stripe billing page. Two clicks, no emails, no retention flow. Access runs to the end of the paid period."],
          ["Why a subscription and not a one-off?", "Because a negotiation isn't one-off. You send your changes, the 3PL replies, you compare their revision, and you push again. Most brands run two or three rounds; the subscription covers all of them, on every contract you're working."],
          ["Do I get receipts?", "Stripe emails a receipt for every payment automatically, to the email you used at checkout."],
        ].map(([q, a], i, arr) => (
          <div key={q} style={{ paddingBottom: i < arr.length - 1 ? 14 : 0, marginBottom: i < arr.length - 1 ? 14 : 0, borderBottom: i < arr.length - 1 ? "1px solid #EDF0F3" : "none" }}>
            <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 13.5, fontWeight: 600, color: "#16212E", marginBottom: 5 }}>{q}</div>
            <div style={{ fontSize: 12.5, color: "#414B56", lineHeight: 1.85 }}>{a}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ─── ROUTING (public pages get real URLs; the app flow stays stateful) ──── */
const PUBLIC_ROUTES = { "/": "home", "/sample": "sample", "/pricing": "pricing", "/about": "about" };
const ROUTE_FOR = { home: "/", sample: "/sample", pricing: "/pricing", about: "/about" };
const screenFromPath = () => PUBLIC_ROUTES[window.location.pathname] || "home";

/* ─── MAIN APP ───────────────────────────────────────────────────────────── */
function App() {
  const [screen, setScreen] = useState(screenFromPath);
  const [access, setAccess] = useState(null); // { paid, email, daysLeft }
  const [brandInfo, setBrandInfo] = useState(null);
  const [showFooterPrivacy, setShowFooterPrivacy] = useState(false);
  const [showTerms, setShowTerms] = useState(false);
  const [showHelp, setShowHelp] = useState(false);
  const [leadEmail, setLeadEmail] = useState(() => { try { return localStorage.getItem("clause_lead") || ""; } catch { return ""; } });
  const [gateEmail, setGateEmail] = useState("");
  const [gateCompany, setGateCompany] = useState("");
  const [gateError, setGateError] = useState("");
  const [gateBusy, setGateBusy] = useState(false);

  const submitGate = async () => {
    const email = gateEmail.trim().toLowerCase();
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) { setGateError("Enter a valid work email."); return; }
    setGateBusy(true); setGateError("");
    try {
      await api("/api/lead", { email, company: gateCompany.trim(), brandInfo, source: "report_gate" });
      try { localStorage.setItem("clause_lead", email); } catch {}
      setLeadEmail(email);
      track("lead_captured", { source: "report_gate" });
    } catch (e) {
      // Never block the report on a capture failure; let them through.
      try { localStorage.setItem("clause_lead", email); } catch {}
      setLeadEmail(email);
    } finally { setGateBusy(false); }
  };
  const [file, setFile] = useState(null);
  const [dragging, setDragging] = useState(false);
  const [report, setReport] = useState(null);
  const [streamedSections, setStreamedSections] = useState([]);
  const [filter, setFilter] = useState("ALL");
  const [error, setError] = useState(null);
  const [savedId, setSavedId] = useState(null);
  const [readingStep, setReadingStep] = useState(0);
  const [contractText, setContractText] = useState("");
  const [showEmail, setShowEmail] = useState(false);
  const [showCompare, setShowCompare] = useState(false);
  const [showRestore, setShowRestore] = useState(false);
  const [payMsg, setPayMsg] = useState("");
  const abortRef = useRef({ cancelled: false });

  const hasPaid = !!access?.paid;
  const fileRef = useRef();

  // Navigate to a public page (real URL); internal flow screens use setScreen only.
  const go = (name) => {
    const path = ROUTE_FOR[name];
    if (path && window.location.pathname !== path) window.history.pushState({}, "", path);
    setScreen(name);
    window.scrollTo(0, 0);
  };
  useEffect(() => {
    const onPop = () => setScreen(screenFromPath());
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, []);

  // On load: check access + handle Stripe return (?session_id=...)
  useEffect(() => {
    (async () => {
      const params = new URLSearchParams(window.location.search);
      const sessionId = params.get("session_id");
      if (sessionId) {
        try {
          const data = await api("/api/verify", { session_id: sessionId });
          setAccess(data);
          setPayMsg("✓ Payment confirmed, your subscription is active and full access is unlocked.");
          track("payment_complete");
        } catch (e) {
          setPayMsg(e.message || "We couldn't confirm that payment. Try Restore access, or send us a message via Help in the footer.");
        }
        window.history.replaceState({}, "", window.location.pathname);
        // Reopen the latest report if one exists
        const latest = loadReportIndex()[0];
        if (latest) { openSavedReport(latest.id); return; }
        setScreen("dashboard");
        return;
      }
      if (params.get("canceled")) window.history.replaceState({}, "", window.location.pathname);
      try { setAccess(await api("/api/access", null, "GET")); } catch { setAccess({ paid: false }); }
    })();
  }, []);

  const startCheckout = async (source) => {
    track("paywall_cta_clicked", { source });
    try {
      const { url } = await api("/api/checkout", { source });
      window.location.href = url;
    } catch (e) {
      alert(e.message || "Could not start checkout.");
    }
  };

  const ACCEPT_FILE = (f) => {
    if (!f) return;
    const isDocx = f.name?.toLowerCase().endsWith(".docx") || f.type?.includes("wordprocessingml");
    const isPdf = f.type === "application/pdf" || f.name?.toLowerCase().endsWith(".pdf");
    if (isDocx || isPdf) { setFile(f); setError(null); }
    else setError("Please upload a Word document (.docx) or PDF.");
  };
  const onDrop = useCallback((e) => { e.preventDefault(); setDragging(false); ACCEPT_FILE(e.dataTransfer.files[0]); }, []);

  const analyse = async () => {
    if (!file) return;
    track("analysis_started", { fileType: file.name?.endsWith(".docx") ? "docx" : "pdf", market: brandInfo?.market });
    setScreen("reading"); setError(null); setReadingStep(0);
    setStreamedSections([]); setReport(null);
    abortRef.current = { cancelled: false };
    const run = abortRef.current;

    let stepTimer;
    try {
      const fullText = await extractText(file);
      setContractText(fullText);
      let stepIdx = 1;
      setReadingStep(1);
      stepTimer = setInterval(() => { stepIdx = Math.min(stepIdx + 1, 4); setReadingStep(stepIdx); }, 20000);

      const { report: parsed } = await api("/api/analyze", { contractText: fullText, brandInfo, fileType: file.name?.toLowerCase().endsWith(".docx") ? "docx" : "pdf" });
      if (run.cancelled) return;

      setReport(parsed);
      setScreen("streaming");
      const id = saveReport(parsed, file.name, fullText, brandInfo);
      setSavedId(id);

      const sections = parsed.sections || [];
      for (let i = 0; i < sections.length; i++) {
        await new Promise((r) => setTimeout(r, i === 0 ? 0 : 155));
        if (run.cancelled) return;
        setStreamedSections((prev) => [...prev, { ...sections[i], _isNew: true }]);
        setTimeout(() => setStreamedSections((prev) => prev.map((s, idx) => (idx === i ? { ...s, _isNew: false } : s))), 450);
      }
      setScreen("report");
      track("analysis_complete", { riskScore: parsed.riskScore, overallRisk: parsed.overallRisk, market: brandInfo?.market, sectionCount: sections.length });
    } catch (e) {
      if (run.cancelled) return;
      console.error("analysis error:", e);
      setError(e.message || "Something went wrong. Please try again.");
      setScreen("upload");
    } finally {
      clearInterval(stepTimer);
    }
  };

  const openSavedReport = (id) => {
    const entry = loadReportEntry(id);
    if (!entry) return;
    setReport(entry.report);
    setStreamedSections(entry.report.sections || []);
    setContractText(entry.contractText || "");
    setBrandInfo(entry.brandInfo || null);
    setFilter("ALL");
    setFile({ name: entry.fileName });
    setSavedId(id);
    setScreen("report");
  };

  const reset = () => {
    setFile(null); setReport(null); setStreamedSections([]); setBrandInfo(null); setSavedId(null);
    setError(null); setFilter("ALL"); setContractText("");
    go("home");
  };

  const isReport = screen === "streaming" || screen === "report";
  const filtered = streamedSections.filter((s) => filter === "ALL" || s.status === filter);
  const summaryStats = report?.summaryStats;
  const beforeYouSign = report?.beforeYouSign || [];
  const crossIssues = report?.crossContractIssues || [];

  return (
    <>
      <div style={{ minHeight: "100vh", background: "#F4F5F7", fontFamily: "'Archivo', Arial, sans-serif" }}>
        {/* Nav */}
        <div style={{ background: "#fff", borderBottom: "1px solid #E3E6EA", padding: "13px 24px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <div onClick={reset} style={{ display: "flex", alignItems: "center", gap: 11, cursor: "pointer" }}>
            <div style={{ width: 32, height: 32, background: "#16212E", borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "'Archivo', sans-serif", fontSize: 17, color: "#F4F5F7", fontWeight: 700 }}>C</div>
            <div>
              <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 17, color: "#16212E", letterSpacing: "-0.01em", lineHeight: 1.1 }}>Clause</div>
              <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em" }}>YOUR 3PL CONTRACT, DECODED</div>
            </div>
          </div>
          <div className="nav-actions" style={{ display: "flex", gap: 8, alignItems: "center" }}>
            {["sample", "pricing", "about"].map((p) => (
              <button key={p} onClick={() => go(p)} style={{ background: "none", border: "none", cursor: "pointer", padding: "6px 6px", fontFamily: "'Archivo', sans-serif", fontSize: 13, color: screen === p ? "#16212E" : "#667079", fontWeight: screen === p ? 600 : 400, textDecoration: screen === p ? "underline" : "none", textUnderlineOffset: 4 }}>
                {p === "sample" ? "Sample" : p === "pricing" ? "Pricing" : "About"}
              </button>
            ))}
            <span style={{ width: 1, height: 16, background: "#E3E6EA", display: "inline-block" }} />
            {hasPaid ? (
              <span style={{ fontSize: 10, color: "#16A34A", fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.05em" }}>FULL ACCESS</span>
            ) : (
              <button className="btn-ghost" onClick={() => setShowRestore(true)}>Restore access</button>
            )}
            {loadReportIndex().length > 0 && screen !== "dashboard" && (
              <button className="btn-ghost" onClick={() => setScreen("dashboard")}>Dashboard</button>
            )}
            {isReport && (
              <>
                {hasPaid && <button className="btn-ghost" onClick={() => exportPDF(report, file?.name || "Contract")}>Export PDF</button>}
                {screen === "report" && hasPaid && (
                  <>
                    <button className="btn-ghost" onClick={() => setShowEmail(true)}>Draft email</button>
                    <button className="btn-ghost" onClick={() => setShowCompare(true)}>Compare</button>
                  </>
                )}
                <button className="btn-ghost" onClick={() => { if (window.confirm("Start a new analysis? Your current report is saved to your dashboard.")) reset(); }}>New</button>
              </>
            )}
          </div>
        </div>

        {payMsg && (
          <div style={{ maxWidth: 760, margin: "12px auto 0", padding: "0 18px" }}>
            <div style={{ background: payMsg.startsWith("✓") ? "#F0FDF4" : "#FEF2F2", border: `1px solid ${payMsg.startsWith("✓") ? "#BBF7D0" : "#FECACA"}`, borderRadius: 6, padding: "11px 16px", fontSize: 13, color: payMsg.startsWith("✓") ? "#166534" : "#DC2626", display: "flex", justifyContent: "space-between", gap: 10 }}>
              <span>{payMsg}</span>
              <button onClick={() => setPayMsg("")} style={{ background: "none", border: "none", cursor: "pointer", color: "inherit" }}>✕</button>
            </div>
          </div>
        )}

        {screen === "dashboard" ? (
          <Dashboard
            access={access}
            onContinue={openSavedReport}
            onNewContract={() => setScreen("onboarding")}
            onUploadRevision={(id) => { openSavedReport(id); setShowCompare(true); }}
            onManage={async () => {
              try { const { url } = await api("/api/portal", {}); window.location.href = url; }
              catch (e) { alert(e.message); }
            }}
          />
        ) : (
        <div style={{ maxWidth: 760, margin: "0 auto", padding: "40px 18px" }}>

          {/* HOME */}
          {screen === "home" && (
            <div className="fade-in">

              {/* Hero: one job, one primary action */}
              <div style={{ textAlign: "center", padding: "40px 0 56px" }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.1em", marginBottom: 20 }}>FOR UK &amp; EU BRANDS</div>
                <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 800, fontSize: "clamp(34px,6vw,58px)", color: "#16212E", lineHeight: 1.06, letterSpacing: "-0.02em", marginBottom: 18 }}>
                  Your 3PL sent you a contract.<br /><span style={{ color: "#7C858E" }}>Most brands just sign it.</span>
                </div>
                <div style={{ fontSize: 16, color: "#414B56", maxWidth: 430, margin: "0 auto 30px", lineHeight: 1.8 }}>
                  Upload yours. We'll tell you what's below market, what your 3PL will actually move on, and exactly what to say.
                </div>
                <button className="btn" style={{ padding: "17px 44px" }} onClick={() => { setScreen("onboarding"); track("homepage_cta_clicked"); }}>
                  Analyse my contract free
                </button>
                <div style={{ marginTop: 16 }}>
                  <button onClick={() => go("sample")} style={{ background: "none", border: "none", cursor: "pointer", fontSize: 13, color: "#16212E", textDecoration: "underline", textUnderlineOffset: 4, fontFamily: "'Archivo', sans-serif" }}>
                    or read a sample report first
                  </button>
                </div>
                <div style={{ marginTop: 20, fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E", letterSpacing: "0.05em" }}>
                  No account needed · Your contract is never stored
                </div>
              </div>

              {/* Example analysis */}
              <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, overflow: "hidden", marginBottom: 14 }}>
                <div style={{ padding: "14px 20px 12px", borderBottom: "1px solid #EDF0F3", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                  <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#7C858E", letterSpacing: "0.12em" }}>WHAT A REPORT LOOKS LIKE</span>
                  <button onClick={() => go("sample")} style={{ background: "none", border: "none", cursor: "pointer", fontFamily: "'Archivo', sans-serif", fontSize: 13, color: "#16212E", textDecoration: "underline", textUnderlineOffset: 3 }}>Full sample</button>
                </div>
                <div style={{ padding: "16px 20px 14px", background: "#FAFBFC", borderBottom: "1px solid #EDF0F3" }}>
                  <div style={{ fontSize: 13, color: "#333D4A", lineHeight: 1.85, fontFamily: "'Archivo', sans-serif" }}>
                    "We've seen this contract before. The lock-in is 3 years, that's aggressive. And that liability clause means if they lose your stock, they'll pay you cost price, not what you sell it for. Both are worth pushing back on."
                  </div>
                </div>
                <div style={{ padding: "14px 20px", display: "flex", flexDirection: "column", gap: 8 }}>
                  {[
                    { badge: "MUST CHANGE", color: "#EF4444", bg: "#FEF2F2", border: "#FCA5A5", bar: "#EF4444", title: "Termination clause", note: "36-month lock-in with no early exit. At your volume, 12 months is absolutely achievable." },
                    { badge: "PUSH BACK", color: "#1E40AF", bg: "#EFF6FF", border: "#93C5FD", bar: "#3B82F6", title: "Liability cap", note: "They'll pay invoice cost if your stock is damaged, not retail. That gap could be significant." },
                    { badge: "ALL GOOD", color: "#166534", bg: "#F0FDF4", border: "#BBF7D0", bar: "#E3E6EA", title: "Dispatch SLA", note: "99.5% with financial penalties attached. This is exactly where it should be." },
                  ].map(({ badge, color, bg, border, bar, title, note }) => (
                    <div key={title} style={{ display: "flex", borderRadius: 6, border: `1px solid ${border}`, overflow: "hidden" }}>
                      <div style={{ width: 3, background: bar, flexShrink: 0 }} />
                      <div style={{ flex: 1, padding: "9px 13px", background: bg, display: "flex", gap: 10, alignItems: "flex-start" }}>
                        <span style={{ fontSize: 8, color, background: "#fff", border: `1px solid ${border}`, padding: "2px 8px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace", flexShrink: 0, marginTop: 2, letterSpacing: "0.06em", whiteSpace: "nowrap" }}>{badge}</span>
                        <div>
                          <div style={{ fontSize: 12.5, fontWeight: 600, color: "#16212E", fontFamily: "'Archivo', sans-serif", marginBottom: 2 }}>{title}</div>
                          <div style={{ fontSize: 11.5, color: "#414B56", lineHeight: 1.65 }}>{note}</div>
                        </div>
                      </div>
                    </div>
                  ))}
                </div>
              </div>

              {/* How it works */}
              <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "20px 22px", marginBottom: 14 }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 16 }}>HOW IT WORKS</div>
                {[
                  ["1", "Upload your contract", "Word doc or PDF. Five quick taps first so the benchmarks match your size and market."],
                  ["2", "Read your first findings free", "The verdict, the risk score, and the top clauses. No account, no card."],
                  ["3", "Unlock the full report when you're ready", "Every clause, the negotiation email, and revision comparison. £19.99 a month, cancel anytime."],
                ].map(([n, title, desc], i, arr) => (
                  <div key={n} style={{ display: "flex", gap: 14, paddingBottom: i < arr.length - 1 ? 14 : 0, marginBottom: i < arr.length - 1 ? 14 : 0, borderBottom: i < arr.length - 1 ? "1px solid #EDF0F3" : "none" }}>
                    <div style={{ width: 26, height: 26, borderRadius: "50%", background: "#16212E", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, flexShrink: 0, marginTop: 2 }}>{n}</div>
                    <div>
                      <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 14, fontWeight: 600, color: "#16212E", marginBottom: 2 }}>{title}</div>
                      <div style={{ fontSize: 12.5, color: "#414B56", lineHeight: 1.7 }}>{desc}</div>
                    </div>
                  </div>
                ))}
              </div>

              {/* Closing CTA band */}
              <div style={{ background: "#16212E", borderRadius: 10, padding: "26px 24px", textAlign: "center" }}>
                <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 20, color: "#F9FAFB", marginBottom: 14 }}>See what's in your contract.</div>
                <button className="btn" style={{ background: "#F4F5F7", color: "#16212E", padding: "14px 36px" }} onClick={() => { setScreen("onboarding"); track("homepage_cta_clicked", { source: "footer-band" }); }}>
                  Analyse my contract free
                </button>
                <div style={{ marginTop: 12, fontSize: 12, color: "#6B7280" }}>
                  Questions first? <button onClick={() => go("about")} style={{ background: "none", border: "none", cursor: "pointer", color: "#9CA3AF", textDecoration: "underline", textUnderlineOffset: 3, fontSize: 12, padding: 0 }}>Read about how it works</button>
                </div>
              </div>
            </div>
          )}

          {/* SAMPLE REPORT */}
          {screen === "sample" && (
            <SampleReport onStart={() => { setScreen("onboarding"); track("homepage_cta_clicked", { source: "sample" }); }} onBack={() => go("home")} />
          )}

          {/* ABOUT */}
          {screen === "about" && (
            <AboutPage onStart={() => { setScreen("onboarding"); track("homepage_cta_clicked", { source: "about" }); }} />
          )}

          {/* PRICING */}
          {screen === "pricing" && (
            <PricingPage paid={hasPaid} onStart={() => { setScreen("onboarding"); track("homepage_cta_clicked", { source: "pricing" }); }} onCheckout={() => startCheckout("pricing-page")} onTerms={() => setShowTerms(true)} />
          )}

          {/* ONBOARDING */}
          {screen === "onboarding" && (
            <Onboarding onComplete={(info) => { setBrandInfo(info); setScreen("upload"); track("onboarding_complete", { market: info.market }); }} />
          )}

          {/* UPLOAD */}
          {screen === "upload" && (
            <div className="fade-in">
              <div style={{ textAlign: "center", marginBottom: 28 }}>
                <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 28, color: "#16212E", lineHeight: 1.15, marginBottom: 8 }}>Upload your contract</div>
                <div style={{ fontSize: 14, color: "#414B56", lineHeight: 1.7 }}>Your file is read in your browser, analysed, and discarded.<br />We never store a copy.</div>
              </div>

              <div style={{ background: "#F0FDF4", border: "1px solid #BBF7D0", borderRadius: 6, padding: "11px 16px", marginBottom: 10 }}>
                <div style={{ fontSize: 12.5, color: "#166534", lineHeight: 1.75 }}>
                  <strong>Upload the Word doc your 3PL sent you for best results.</strong> Word documents extract more cleanly than PDFs, so the analysis reads exactly what they wrote.
                </div>
              </div>
              <div style={{ background: "#FFFBEB", border: "1px solid #FCD34D", borderRadius: 6, padding: "11px 16px", marginBottom: 16 }}>
                <div style={{ fontSize: 12.5, color: "#92400E", lineHeight: 1.75 }}>
                  <strong>Got the rate card or schedule of charges?</strong> If it's a separate document, paste or merge it into the same file, the rate card is where most of the real cost hides.
                </div>
              </div>

              <div className={`drop ${dragging ? "drag" : ""}`} onClick={() => fileRef.current.click()}
                onDragOver={(e) => { e.preventDefault(); setDragging(true); }} onDragLeave={() => setDragging(false)} onDrop={onDrop}>
                <input ref={fileRef} type="file" accept=".docx,.pdf,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document" style={{ display: "none" }} onChange={(e) => ACCEPT_FILE(e.target.files[0])} />
                {file ? (
                  <div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, color: "#667079", letterSpacing: "0.08em", marginBottom: 10 }}>{file.name?.toLowerCase().endsWith(".docx") ? ".DOCX" : ".PDF"}</div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 12, color: "#16212E", marginBottom: 3 }}>{file.name}</div>
                    <div style={{ fontSize: 11, color: "#667079", marginBottom: 8 }}>{(file.size / 1024).toFixed(0)} KB · tap to swap</div>
                    {file.name?.toLowerCase().endsWith(".docx") && (
                      <div style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11, color: "#166534", background: "#F0FDF4", border: "1px solid #BBF7D0", borderRadius: 4, padding: "3px 10px" }}>
                        Word doc, tracked changes will work perfectly
                      </div>
                    )}
                    {file.name?.toLowerCase().endsWith(".pdf") && (
                      <div style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11, color: "#92400E", background: "#FFFBEB", border: "1px solid #FCD34D", borderRadius: 4, padding: "3px 10px" }}>
                        PDF works, but a Word doc reads more accurately
                      </div>
                    )}
                  </div>
                ) : (
                  <div>
                    <div style={{ display: "flex", justifyContent: "center", gap: 12, marginBottom: 14, alignItems: "baseline" }}>
                      <div style={{ textAlign: "center" }}>
                        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 13, color: "#374151", letterSpacing: "0.08em" }}>.DOCX</div>
                        <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 7, color: "#16A34A", letterSpacing: "0.06em", marginTop: 2 }}>RECOMMENDED</div>
                      </div>
                      <div style={{ fontSize: 13, color: "#D5D9DF" }}>or</div>
                      <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 13, color: "#9CA3AF", letterSpacing: "0.08em" }}>.PDF</div>
                    </div>
                    <div style={{ fontSize: 14, color: "#374151", marginBottom: 5 }}>Drop your contract here</div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, color: "#667079" }}>or tap to browse</div>
                  </div>
                )}
              </div>

              {error && (
                <div style={{ background: "#FEF2F2", border: "1px solid #FECACA", borderRadius: 6, padding: "13px 16px", marginTop: 13 }}>
                  <div style={{ fontSize: 13, color: "#DC2626", marginBottom: 4, fontWeight: 600 }}>⚠ {error}</div>
                  <div style={{ fontSize: 12, color: "#9CA3AF", lineHeight: 1.75 }}>
                    Make sure the file is a .docx or PDF with selectable text (not a scanned image), and under 10MB.
                  </div>
                </div>
              )}

              <div style={{ textAlign: "center", marginTop: 20 }}>
                <button className="btn" onClick={analyse} disabled={!file}>Read my contract</button>
                <div style={{ marginTop: 9, fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.05em" }}>A thorough read takes a couple of minutes · your file is never stored</div>
              </div>
            </div>
          )}

          {/* READING */}
          {screen === "reading" && (
            <ReadingScreen
              step={readingStep}
              onCancel={() => { abortRef.current.cancelled = true; setScreen("upload"); setError("Cancelled."); }}
            />
          )}

          {/* REPORT */}
          {/* REPORT EMAIL GATE (free users, once) */}
          {isReport && report && !hasPaid && !leadEmail && (
            <div className="fade-in" style={{ maxWidth: 440, margin: "40px auto" }}>
              <div style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 10, padding: "26px" }}>
                <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.12em", marginBottom: 8 }}>ANALYSIS COMPLETE</div>
                <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 22, color: "#16212E", marginBottom: 8 }}>Your report is ready.</div>
                <div style={{ fontSize: 13, color: "#414B56", lineHeight: 1.8, marginBottom: 16 }}>
                  Enter your work email to open it. We use it to keep your report linked to you and to send occasional Clause updates. Unsubscribe anytime; never sold or shared.
                </div>
                <input type="email" value={gateEmail} onChange={(e) => setGateEmail(e.target.value)} onKeyDown={(e) => e.key === "Enter" && submitGate()} placeholder="you@yourbrand.com"
                  style={{ width: "100%", padding: "12px 14px", border: "1px solid #D5D9DF", borderRadius: 6, fontSize: 15, fontFamily: "'Archivo', sans-serif", background: "#FAFBFC", outline: "none", marginBottom: 8, boxSizing: "border-box" }} />
                <input type="text" value={gateCompany} onChange={(e) => setGateCompany(e.target.value)} placeholder="Company (optional)"
                  style={{ width: "100%", padding: "12px 14px", border: "1px solid #D5D9DF", borderRadius: 6, fontSize: 15, fontFamily: "'Archivo', sans-serif", background: "#FAFBFC", outline: "none", marginBottom: 10, boxSizing: "border-box" }} />
                {gateError && <div style={{ fontSize: 12, color: "#DC2626", marginBottom: 10 }}>{gateError}</div>}
                <button className="btn" style={{ width: "100%" }} onClick={submitGate} disabled={gateBusy}>
                  {gateBusy ? "One moment…" : "Open my report"}
                </button>
              </div>
            </div>
          )}

          {isReport && report && (hasPaid || !!leadEmail) && (
            <div>
              {/* Verdict card */}
              <div className="fade-in" style={{ background: "#16212E", borderRadius: 8, padding: "20px 22px", marginBottom: 16, display: "flex", gap: 14, alignItems: "flex-start" }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.12em", marginBottom: 7 }}>THE VERDICT</div>
                  <div style={{ fontSize: 14.5, color: "#F9FAFB", lineHeight: 1.9, fontFamily: "'Archivo', sans-serif" }}>{report.alexSays}</div>
                </div>
                {report.riskScore != null && (
                  <div style={{ textAlign: "right", flexShrink: 0 }}>
                    <div style={{ fontFamily: "'Archivo', sans-serif", fontSize: 38, fontWeight: 600, lineHeight: 1, color: report.overallRisk === "HIGH" ? "#EF4444" : report.overallRisk === "MEDIUM" ? "#F59E0B" : "#22C55E" }}>{report.riskScore}</div>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.1em" }}>/ 100 RISK</div>
                    <div style={{ fontSize: 9, color: "#6B7280", marginTop: 2 }}>higher = more to negotiate</div>
                  </div>
                )}
              </div>

              {/* Stats */}
              {summaryStats && (
                <div className="fade-in" style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap", alignItems: "center" }}>
                  {[[summaryStats.mustChange, "Change this", "#EF4444", "#FEF2F2", "#FCA5A5"], [summaryStats.pushBack, "Push back", "#1E40AF", "#EFF6FF", "#93C5FD"], [summaryStats.headsUp, "Heads up", "#92400E", "#FFFBEB", "#FCD34D"], [summaryStats.fine, "Looking good", "#16A34A", "#F0FDF4", "#BBF7D0"]].filter(([n]) => n > 0).map(([n, label, color, bg, border]) => (
                    <div key={label} style={{ background: bg, border: `1px solid ${border}`, borderRadius: 6, padding: "8px 13px", display: "flex", alignItems: "center", gap: 8 }}>
                      <span style={{ fontFamily: "'Archivo', sans-serif", fontSize: 20, fontWeight: 600, color, lineHeight: 1 }}>{n}</span>
                      <span style={{ fontSize: 12, color: "#374151" }}>{label}</span>
                    </div>
                  ))}
                  {savedId && <span style={{ fontSize: 10, color: "#16A34A", fontFamily: "'IBM Plex Mono', monospace", letterSpacing: "0.05em", marginLeft: 4 }}>✓ Saved</span>}
                  {screen === "streaming" && <div style={{ display: "flex", alignItems: "center", gap: 5 }}><div className="dot" style={{ width: 5, height: 5 }} /><div className="dot" style={{ width: 5, height: 5 }} /><div className="dot" style={{ width: 5, height: 5 }} /><span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.07em" }}>still reading…</span></div>}
                </div>
              )}

              {/* Action button */}
              {screen === "report" && streamedSections.some((s) => ["MUST_CHANGE", "PUSH_BACK", "HEADS_UP"].includes(s.status)) && (
                <div className="fade-in" style={{ marginBottom: 16 }}>
                  <button onClick={() => hasPaid ? setShowEmail(true) : startCheckout("email-cta")} style={{ width: "100%", background: "#16212E", border: "none", borderRadius: 8, padding: "16px 18px", cursor: "pointer", textAlign: "left", transition: "background 0.15s" }}
                    onMouseEnter={(e) => (e.currentTarget.style.background = "#243040")}
                    onMouseLeave={(e) => (e.currentTarget.style.background = "#16212E")}>
                    <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 600, fontSize: 14, color: "#F9FAFB", marginBottom: 4, lineHeight: 1.3 }}>Draft the negotiation email</div>
                    <div style={{ fontSize: 11.5, color: "#6B7280", lineHeight: 1.6 }}>One message covering every issue worth raising, in your voice, ready to edit and send.</div>
                  </button>
                </div>
              )}

              {/* Cross-contract issues */}
              {crossIssues.length > 0 && (
                <div className="fade-in" style={{ background: "#FFF7ED", border: "1px solid #FED7AA", borderRadius: 8, padding: "14px 18px", marginBottom: 16 }}>
                  <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#C2410C", letterSpacing: "0.1em", marginBottom: 10 }}>CROSS-CONTRACT ISSUES SPOTTED</div>
                  {crossIssues.map((issue, i) => (
                    <div key={i} style={{ fontSize: 13, color: "#7C2D12", lineHeight: 1.75, marginBottom: i < crossIssues.length - 1 ? 7 : 0 }}>→ {issue}</div>
                  ))}
                </div>
              )}

              {/* Ask Alex */}
              {screen === "report" && hasPaid && (
                <div className="fade-in">
                  <AskAlex report={report} brandInfo={brandInfo || {}} />
                </div>
              )}

              {/* Before you sign */}
              {beforeYouSign.length > 0 && screen === "report" && (
                <div className="fade-in" style={{ background: "#fff", border: "1px solid #E3E6EA", borderRadius: 8, padding: "17px 20px", marginBottom: 16 }}>
                  <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#667079", letterSpacing: "0.1em", marginBottom: 14 }}>BEFORE YOU SIGN · START HERE</div>
                  {beforeYouSign.map((p, i) => (
                    <div key={i} style={{ display: "flex", gap: 12, alignItems: "flex-start", paddingBottom: i < beforeYouSign.length - 1 ? 13 : 0, marginBottom: i < beforeYouSign.length - 1 ? 13 : 0, borderBottom: i < beforeYouSign.length - 1 ? "1px solid #EDF0F3" : "none" }}>
                      <div style={{ width: 24, height: 24, borderRadius: "50%", background: "#16212E", color: "#F4F5F7", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, flexShrink: 0, marginTop: 1 }}>{p.rank}</div>
                      <div style={{ flex: 1 }}>
                        <div style={{ fontSize: 13.5, fontWeight: 600, color: "#16212E", marginBottom: 3, fontFamily: "'Archivo', sans-serif" }}>{p.issue}</div>
                        <div style={{ fontSize: 13, color: "#6B7280", lineHeight: 1.75 }}>{p.alexSays}</div>
                      </div>
                      <div style={{ flexShrink: 0, marginTop: 3 }}>
                        {p.likelyToWin
                          ? <span style={{ fontSize: 9, color: "#16A34A", background: "#F0FDF4", border: "1px solid #BBF7D0", padding: "2px 9px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace" }}>Likely to win ✓</span>
                          : <span style={{ fontSize: 9, color: "#92400E", background: "#FFFBEB", border: "1px solid #FCD34D", padding: "2px 9px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace" }}>Worth raising</span>}
                      </div>
                    </div>
                  ))}
                </div>
              )}

              {/* Filter */}
              {streamedSections.length > 0 && (
                <div style={{ marginBottom: 16 }}>
                  <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#667079", letterSpacing: "0.1em", marginBottom: 10 }}>FILTER YOUR RESULTS</div>
                  <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                    {[
                      ["ALL", `All ${streamedSections.length}`, null, null, null],
                      ["MUST_CHANGE", `${streamedSections.filter((s) => s.status === "MUST_CHANGE").length} Change this`, "#EF4444", "#FEF2F2", "#FCA5A5"],
                      ["PUSH_BACK", `${streamedSections.filter((s) => s.status === "PUSH_BACK").length} Push back`, "#1E40AF", "#EFF6FF", "#93C5FD"],
                      ["HEADS_UP", `${streamedSections.filter((s) => s.status === "HEADS_UP").length} Heads up`, "#92400E", "#FFFBEB", "#FCD34D"],
                      ["FINE", `${streamedSections.filter((s) => s.status === "FINE").length} All good`, "#16A34A", "#F0FDF4", "#BBF7D0"],
                    ].filter(([val]) => val === "ALL" || streamedSections.some((s) => s.status === val)).map(([val, lbl, color, bg, border]) => {
                      const isOn = filter === val;
                      return (
                        <button key={val} onClick={() => setFilter(val)} style={{ padding: "8px 16px", borderRadius: 5, cursor: "pointer", fontFamily: "'Archivo', sans-serif", fontSize: 13, border: `1.5px solid ${isOn ? (color || "#16212E") : (border || "#7C858E")}`, background: isOn ? (color || "#16212E") : (bg || "#fff"), color: isOn ? "#fff" : (color || "#414B56"), fontWeight: isOn ? 600 : 400, transition: "all 0.15s" }}>
                          {lbl}
                        </button>
                      );
                    })}
                  </div>
                </div>
              )}

              {/* Sections, teaser for unpaid */}
              {(hasPaid ? filtered : filtered.slice(0, 2)).map((s, i) => (
                <SectionCard key={s.id || i} section={s} isNew={s._isNew} />
              ))}

              {/* Paywall */}
              {!hasPaid && streamedSections.length > 2 && screen === "report" && (
                <div style={{ position: "relative", marginTop: -40 }}>
                  <div style={{ height: 120, background: "linear-gradient(to bottom, transparent, #F4F5F7)", marginBottom: -2, position: "relative", zIndex: 1 }} />
                  <div style={{ background: "#16212E", borderRadius: 10, padding: "32px 28px", textAlign: "center", position: "relative", zIndex: 2 }}>
                    <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.14em", marginBottom: 10 }}>
                      {streamedSections.length - 2} MORE CLAUSE{streamedSections.length - 2 !== 1 ? "S" : ""} IN YOUR REPORT
                    </div>
                    <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 24, color: "#F9FAFB", lineHeight: 1.25, marginBottom: 10 }}>
                      There's more here worth knowing.
                    </div>
                    <div style={{ fontSize: 13.5, color: "#9CA3AF", lineHeight: 1.85, maxWidth: 360, margin: "0 auto 24px" }}>
                      Full access includes every clause explained with exactly what to say, a negotiation email ready to go, and revision comparison for every round, on every contract you're negotiating.
                    </div>
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 8, justifyContent: "center", marginBottom: 26 }}>
                      {["Every clause explained", "Negotiation email written", "Revision comparison", "Report Q&A", "Cancel anytime"].map((v) => (
                        <span key={v} style={{ fontSize: 11, color: "#D1D5DB", background: "#243040", border: "1px solid #374151", padding: "4px 12px", borderRadius: 4, fontFamily: "'IBM Plex Mono', monospace" }}>{v}</span>
                      ))}
                    </div>
                    <button className="btn" style={{ background: "#F4F5F7", color: "#16212E", padding: "15px 40px", marginBottom: 12 }}
                      onClick={() => startCheckout("paywall")}>
                      Get full access for £19.99/month
                    </button>
                    <div style={{ fontSize: 11, color: "#6B7280", fontFamily: "'IBM Plex Mono', monospace", marginBottom: 8 }}>Billed monthly via Stripe · cancel anytime in two clicks</div>
                    <div style={{ fontSize: 11, color: "#4B5563" }}>
                      By subscribing you agree to the <button onClick={() => setShowTerms(true)} style={{ background: "none", border: "none", padding: 0, cursor: "pointer", color: "#9CA3AF", textDecoration: "underline", textUnderlineOffset: 3, fontSize: 11 }}>Terms</button>.
                    </div>
                    <div style={{ fontSize: 10.5, color: "#4B5563", fontFamily: "'Archivo', sans-serif" }}>Questions? Help is in the footer.</div>
                  </div>
                </div>
              )}

              {/* Closing card */}
              {screen === "report" && hasPaid && streamedSections.length > 0 && (
                <div className="fade-in" style={{ background: "#16212E", borderRadius: 10, padding: "28px", marginTop: 8, marginBottom: 8 }}>
                  <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 8, color: "#4B5563", letterSpacing: "0.14em", marginBottom: 8 }}>THAT'S EVERYTHING</div>
                  <div style={{ fontFamily: "'Archivo', sans-serif", fontWeight: 700, fontSize: 22, color: "#F9FAFB", lineHeight: 1.25, marginBottom: 10 }}>Ready to push back?</div>
                  <div style={{ fontSize: 13, color: "#9CA3AF", lineHeight: 1.8, marginBottom: 22 }}>
                    You've got {streamedSections.filter((s) => ["MUST_CHANGE", "PUSH_BACK"].includes(s.status)).length} clauses worth raising. Start with the negotiation email, it covers everything in one message.
                  </div>
                  <button onClick={() => setShowEmail(true)} style={{ width: "100%", background: "#F4F5F7", color: "#16212E", border: "none", borderRadius: 6, padding: "13px 16px", cursor: "pointer", fontFamily: "'Archivo', sans-serif", fontSize: 13, fontWeight: 700 }}>
                    Draft the email
                  </button>
                </div>
              )}
            </div>
          )}
        </div>
        )}

        {/* Modals */}
        {showRestore && (
          <RestoreModal onClose={() => setShowRestore(false)} onRestored={(data) => { setAccess(data); setShowRestore(false); setPayMsg("✓ Access restored on this device."); }} />
        )}
        {showEmail && report && <EmailComposer report={report} brandInfo={brandInfo || {}} onClose={() => setShowEmail(false)} />}
        {showCompare && report && <CompareModal report={report} originalText={contractText} onClose={() => setShowCompare(false)} />}
      </div>

      {/* Footer */}
      {screen !== "reading" && (
        <div style={{ borderTop: "1px solid #E3E6EA", padding: "20px 24px", display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 12, background: "#F4F5F7" }}>
          <div style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E", letterSpacing: "0.08em" }}>
            © {new Date().getFullYear()} CLAUSE · MADE IN THE UK · GUIDANCE, NOT LEGAL ADVICE
          </div>
          <div style={{ display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
            <button onClick={() => setShowFooterPrivacy(true)} style={{ background: "none", border: "none", fontFamily: "'Archivo', sans-serif", fontSize: 13, color: "#9CA3AF", cursor: "pointer", textDecoration: "underline", padding: 0 }}>Privacy Policy</button>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E" }}>·</span>
            <button onClick={() => setShowTerms(true)} style={{ background: "none", border: "none", fontFamily: "'Archivo', sans-serif", fontSize: 13, color: "#9CA3AF", cursor: "pointer", textDecoration: "underline", padding: 0 }}>Terms</button>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E" }}>·</span>
            <button onClick={() => setShowHelp(true)} style={{ background: "none", border: "none", fontFamily: "'Archivo', sans-serif", fontSize: 13, color: "#9CA3AF", cursor: "pointer", textDecoration: "underline", padding: 0 }}>Help</button>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E" }}>·</span>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 9, color: "#7C858E", letterSpacing: "0.06em" }}>Your documents are never stored</span>
          </div>
        </div>
      )}
      {showFooterPrivacy && <PrivacyPolicy onClose={() => setShowFooterPrivacy(false)} />}
      {showTerms && <TermsOfService onClose={() => setShowTerms(false)} />}
      {showHelp && <HelpModal paid={hasPaid} onClose={() => setShowHelp(false)} onRestore={() => setShowRestore(true)} />}
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
