// ============================================================
// Nami Order Portal — Full Order Form PDF preview
//
// Renders a 7-section preview the AE sees on `#/pdf/<dealId>`. Structure
// mirrors legal-templates/Order_Form_Template_v1.md (Cover → Service Order
// p1 + p2 → Amendment Addendum → SLA summary → Standard Documents
// references → Signatures). The DocuSign envelope's server-side HTML
// (functions/_shared/docusign-document.js) carries the same structure so
// the AE preview and the customer's signing copy don't drift.
// ============================================================

// Pre-print pagination of long legal documents (MSA, DPA, SLA full
// text). Browsers will happily flow content across multiple sheets at
// print time, but the resulting sheets all share the same React-rendered
// header/footer/page-number, which means split sheets look wrong. By
// chunking the markdown into roughly-one-page segments BEFORE render,
// each segment becomes its own `<FullLegalPage>` with its own footer
// and slot in the global page numbering.
//
// Strategy: split at top-level (`## `) section boundaries — that's
// always a natural break point — then greedily pack consecutive
// sections into buckets sized for one letter sheet of body copy
// (`charsPerPage`). For the standard MSA/DPA/SLA the resulting bucket
// count is stable, so page numbers don't shuffle as the user toggles
// other content.
// Estimate the rendered vertical "line-units" a markdown block will
// occupy when rendered through legal-md.js into the Service Order
// package's .legal-doc styles. The print sheet has roughly 36 line-units
// of usable height (11in - 0.6in top - 0.85in bottom = 9.55in / 18.15px
// per body line ≈ 37.9). This estimator is what lets the chunker
// produce chunks that actually fit one printed sheet — char-count alone
// undercounts the vertical cost of headings, lists, and tables, which
// was why long sections like the MSA's section-4 bullet list were
// rendering off the bottom of the sheet.
// Empirically calibrated against actual print output: at 11px Gilroy on
// an 8.5×11 letter with 0.75in horizontal padding, a full-width
// paragraph line holds ~180–200 chars, not the 70 I originally
// guessed. With the smaller per-line denominator, the chunker was
// overestimating page consumption by ~2.5× and producing chunks at
// 40–50% sheet utilization. The new denominators bring the estimate
// in line with reality so the chunker can pack pages denser.
const estimateLegalUnits = (md) => {
  if (!md) return 0;
  let units = 0;
  const lines = String(md).split("\n");
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const t = line.trim();
    if (!t) {
      // Blank line — paragraph spacing.
      units += 0.3;
    } else if (/^##\s/.test(t)) {
      // Uppercase blue section heading: top margin + heading + rule.
      units += 3.2;
    } else if (/^###\s/.test(t)) {
      units += 2.1;
    } else if (/^####\s/.test(t)) {
      units += 1.6;
    } else if (/^[-*]\s+/.test(t)) {
      // List item — slightly narrower than full-width due to bullet
      // indent (~160 chars per wrapped line).
      units += Math.max(1, Math.ceil((t.length - 2) / 160)) * 1.05;
    } else if (/^\|/.test(t)) {
      // Table row. Header separator (`|---|---|`) takes no real
      // vertical, but each genuine row does.
      if (/^\s*\|?\s*[:\-\s|]+\|?\s*$/.test(t)) {
        units += 0;
      } else {
        units += 1.7;
      }
    } else {
      // Paragraph line — wraps at ~180 chars in print body.
      units += Math.max(1, Math.ceil(t.length / 180));
    }
  }
  return units;
};

// Target ≈ 44 line-units per chunk.
//   Letter sheet content area:
//     11in − 0.6in top padding − 0.85in bottom padding (reserves the
//     absolute footer at bottom:28px + footer text + margin) − ~30px
//     per-page header (logo + gap + border)
//   = ~887px usable / 18.15px per body line ≈ 48.8 lines.
//   Each `<p>` also adds 10px margin-bottom on top of its line(s), and
//   the estimator can't see paragraph counts ahead of time — so we
//   target 44 (≈5 line buffer) instead of the raw 48 capacity.
const chunkLegalMarkdown = (markdown, unitsPerPage = 44) => {
  if (!markdown) return [""];
  const text = String(markdown).trim();
  // FIRST: split on author-controlled `<!-- pagebreak -->` markers.
  // Each segment between markers is then independently chunked by the
  // packing logic below. Page breaks from source are HARD — they're
  // never merged across, even if the resulting segments are short.
  const segments = text
    .split(/^\s*<!--\s*pagebreak\s*-->\s*$/m)
    .map((s) => s.trim())
    .filter((s) => s.length);

  const allPages = [];
  for (const segment of segments) {
    // Split each segment at `## ` and `### ` headings, then greedy-pack
    // sections into chunks. Same logic as before, just scoped to one
    // segment so the packer can't merge across an author's page break.
    const sections = segment.split(/(?=^#{2,3} )/m).filter((s) => s.trim().length);
    if (!sections.length) { allPages.push(segment); continue; }
    const sized = sections.map((s) => ({ md: s, units: estimateLegalUnits(s) }));

    const pages = [];
    let current = "";
    let currentU = 0;
    for (const { md: sec, units: secU } of sized) {
      if (!current) {
        current = sec;
        currentU = secU;
        continue;
      }
      const wouldBe = currentU + secU;
      const underTarget = currentU < unitsPerPage * 0.55;
      if (wouldBe <= unitsPerPage * 1.05 || underTarget) {
        current += sec;
        currentU = wouldBe;
      } else {
        pages.push(current.trim());
        current = sec;
        currentU = secU;
      }
      let safety = 20;
      while (currentU > unitsPerPage * 1.2 && safety-- > 0) {
        const paragraphs = current.split(/\n\n/);
        if (paragraphs.length < 2) break;
        let accU = 0;
        let cutAt = 0;
        for (let i = 0; i < paragraphs.length; i++) {
          const piece = (i === 0 ? "" : "\n\n") + paragraphs[i];
          const pU = estimateLegalUnits(piece);
          if (i > 0 && accU + pU > unitsPerPage * 1.0) break;
          accU += pU;
          cutAt = i + 1;
        }
        if (cutAt >= paragraphs.length) break;
        pages.push(paragraphs.slice(0, cutAt).join("\n\n").trim());
        current = paragraphs.slice(cutAt).join("\n\n");
        currentU = estimateLegalUnits(current);
      }
    }
    if (current.trim()) pages.push(current.trim());

    // Merge sparse chunks WITHIN this segment only — never across an
    // author-controlled page break.
    const TINY = unitsPerPage * 0.35;
    const MAX_MERGE = unitsPerPage * 1.15;
    for (let i = 0; i < pages.length; i++) {
      const ui = estimateLegalUnits(pages[i]);
      if (ui >= TINY) continue;
      const prevU = i > 0 ? estimateLegalUnits(pages[i - 1]) : Infinity;
      const nextU = i < pages.length - 1 ? estimateLegalUnits(pages[i + 1]) : Infinity;
      if (prevU <= nextU && i > 0 && prevU + ui <= MAX_MERGE) {
        pages[i - 1] = (pages[i - 1] + "\n\n" + pages[i]).trim();
        pages.splice(i, 1);
        i--;
      } else if (i < pages.length - 1 && nextU + ui <= MAX_MERGE) {
        pages[i + 1] = (pages[i] + "\n\n" + pages[i + 1]).trim();
        pages.splice(i, 1);
        i--;
      }
    }

    for (const p of pages) allPages.push(p);
  }

  return allPages.length ? allPages : [""];
};

// The Amendment Addendum blocks are hand-rendered (not markdown), so the
// markdown chunker above can't paginate them. We estimate each block's
// height in the same line-unit currency `estimateLegalUnits` uses (see the
// per-line notes above) and pack blocks onto pages, spilling onto
// continuation pages when a page fills. Without this, full-length clauses
// (e.g. the verbatim V13 mutual-liability / V14 IP-indemnity variants)
// overflow the single fixed-height addendum sheet. Target a touch under
// the legal chunker's 44 because every addendum page also carries the
// §N heading + section line of chrome the legal pages don't.
const AMEND_PREAMBLE_UNITS = 6;   // supplements paragraph — first page only
const AMEND_FOOTER_UNITS = 4;     // "Standard terms preserved" box — last page only
const AMEND_BLOCK_CHROME = 3.5;   // §N heading + section line + block margins, per block

const chunkAmendments = (amendments, unitsPerPage = 42) => {
  if (!amendments?.length) return [];
  const cost = (a) => AMEND_BLOCK_CHROME + estimateLegalUnits(a.text);
  const chunks = [];
  let current = [];
  let used = AMEND_PREAMBLE_UNITS;        // page 1 carries the preamble
  for (const a of amendments) {
    const c = cost(a);
    // Start a new page when the next block won't fit — but never leave a
    // page empty, so a single block larger than a page still gets its own.
    if (current.length && used + c > unitsPerPage) {
      chunks.push(current);
      current = [];
      used = 0;                           // continuation pages have no preamble
    }
    current.push(a);
    used += c;
  }
  if (current.length) chunks.push(current);
  // Reserve room for the closing box on the last page: if the final page
  // is too full to also carry the footer, push its last block onto a new
  // page (only when that leaves something behind).
  const last = chunks[chunks.length - 1];
  const lastPreamble = chunks.length === 1 ? AMEND_PREAMBLE_UNITS : 0;
  const lastUsed = lastPreamble + last.reduce((s, a) => s + cost(a), 0);
  if (last.length > 1 && lastUsed + AMEND_FOOTER_UNITS > unitsPerPage) {
    chunks.push([last.pop()]);
  }
  return chunks;
};

// Derive end-of-term from start + termYears so missing endDate fields
// (which are common — only Start Date is captured in the wizard) still
// render correctly in the Subscription Term table and cover effective
// dates line. termEnd lands on the day BEFORE the same calendar date
// N years later (e.g. start 2026-06-01 + 1y → end 2027-05-31). Local
// calendar math throughout — never let JS parse the ISO date as UTC.
const computeEndDate = (startISO, termYears) => {
  if (!startISO || !termYears) return null;
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(String(startISO));
  if (!m) return null;
  const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
  d.setFullYear(d.getFullYear() + termYears);
  d.setDate(d.getDate() - 1);
  const yyyy = d.getFullYear();
  const mm = String(d.getMonth() + 1).padStart(2, "0");
  const dd = String(d.getDate()).padStart(2, "0");
  return `${yyyy}-${mm}-${dd}`;
};

const OrderFormPDF = ({ deal: rawDeal, onBack, coverTreatment = "gradient", embedded = false }) => {
  const PRICING = window.NAMI_PRICING;
  const variants = window.NAMI_DATA.VARIANTS;
  const trims = window.NAMI_DATA.TRIM_TIERS;
  const deal = React.useMemo(() => ({
    ...rawDeal,
    endDate: rawDeal.endDate || computeEndDate(rawDeal.startDate, rawDeal.termYears || 1),
  }), [rawDeal]);
  const t = trims[deal.trim || "premier"];

  // Full legal-document text is fetched as a JSON asset so a single source
  // of truth (legal-templates/*.md → public/legal-text.json) drives both
  // the AE preview and the DocuSign envelope. Until it loads, the three
  // full-text pages render an inline placeholder; pagination counts are
  // computed against the final, post-load page list so they don't shift.
  const [legalText, setLegalText] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    fetch("legal-text.json", { cache: "no-cache" })
      .then((r) => (r.ok ? r.json() : null))
      .then((j) => { if (alive) setLegalText(j); })
      .catch(() => { if (alive) setLegalText({}); });
    return () => { alive = false; };
  }, []);

  // Memoize amendments so downstream useCallback / useEffect deps
  // (regeneratePdfmake) see a stable reference. Without this the
  // pdfmake embed re-fires generate() on every render, looping forever.
  const amendments = React.useMemo(() => variants
    .map((v) => {
      const val = (deal.variants || {})[v.id];
      if (val == null || val === false || (Array.isArray(val) && !val.length)) return null;
      const text = v.langTemplate(val);
      if (!text) return null;
      const numMatch = v.id.match(/^v(\d+)/);
      const num = numMatch ? numMatch[1] : "";
      return { id: v.id, num, category: v.category, section: v.section, text };
    })
    .filter(Boolean),
    [variants, deal.variants],
  );

  const commits = deal.commits || [t.minCommit * 1_000_000];
  const cpm = deal.cpm || t.cpmRepresentative;
  const { tcv, subscriptionTotal, conciergeTotal, carrierTotal, billingDiscountAmount, multiyrDiscountAmount, psTotal, lineItems } =
    PRICING.computeDealTcv(deal);
  const billing = deal.cadence || "annual";
  const billingLabel = billing === "usage"
    ? "Pay-as-you-go (monthly, in arrears)"
    : billing === "quarterly"
      ? "Quarterly upfront"
      : "Annual upfront";

  // Chunk each long legal doc into one-letter-sheet-sized buckets so
  // each bucket renders as its own component-level page with its own
  // header/footer/page number. The chunker preserves section
  // boundaries (`## `) so a section never starts at the end of one
  // page and continues on the next.
  const msaChunks = React.useMemo(() => chunkLegalMarkdown(legalText?.MSA), [legalText?.MSA]);
  const dpaChunks = React.useMemo(() => chunkLegalMarkdown(legalText?.DPA), [legalText?.DPA]);
  const slaChunks = React.useMemo(() => chunkLegalMarkdown(legalText?.SLA), [legalText?.SLA]);
  const amendmentChunks = React.useMemo(() => chunkAmendments(amendments), [amendments]);

  // Page count is dynamic — Amendment Addendum drops out when no variants
  // are applied, and each legal doc expands to N chunks once loaded.
  // Until legal text is fetched, the legal sections each occupy a single
  // placeholder slot so the cover's "p. X" inventory doesn't jump
  // around at mount.
  const pages = [
    "cover",
    "service-order-1",
    "service-order-2",
    ...amendmentChunks.map((_, i) => `amendment-${i}`),
    "sla",
    ...msaChunks.map((_, i) => `msa-full-${i}`),
    ...dpaChunks.map((_, i) => `dpa-full-${i}`),
    ...slaChunks.map((_, i) => `sla-full-${i}`),
    "references",
    "signatures",
  ];
  const totalPages = pages.length;
  const pageNum = (key) => pages.indexOf(key) + 1;

  // Show a DRAFT watermark on every page until the deal has been signed
  // (or the customer has explicitly approved). Anything pre-signature
  // counts as draft in customer-visible language. The watermark is
  // suppressed on the embedded preview tile in deal-detail because it's
  // already framed as a compact preview.
  const draftStates = new Set(["draft", "review", "pending_legal", "approved", "legal"]);
  const isDraft = !embedded && draftStates.has(deal.status);

  // View toggle: "html" is the existing React-rendered preview;
  // "pdfmake" embeds the pdfmake output in an iframe so the AE can
  // iterate on the pdfmake design without going through Save → open.
  const [viewMode, setViewMode] = React.useState("html");
  const [pdfUrl, setPdfUrl] = React.useState(null);
  const [pdfStatus, setPdfStatus] = React.useState("idle"); // idle | loading | error
  const [pdfError, setPdfError] = React.useState(null);

  const regeneratePdfmake = React.useCallback(async () => {
    if (!window.NAMI_PDFMAKE || !legalText) return;
    setPdfStatus("loading");
    setPdfError(null);
    try {
      const blob = await window.NAMI_PDFMAKE.generate({
        deal, amendments, legalText, isDraft, download: false,
      });
      const url = URL.createObjectURL(blob);
      setPdfUrl((prev) => {
        if (prev) URL.revokeObjectURL(prev);
        return url;
      });
      setPdfStatus("idle");
    } catch (err) {
      console.error("pdfmake preview failed:", err);
      setPdfError(err.message || String(err));
      setPdfStatus("error");
    }
  }, [deal, amendments, legalText, isDraft]);

  // Auto-generate when the user flips to pdfmake view, when the deal
  // changes while in pdfmake view, or when legal text first arrives.
  React.useEffect(() => {
    if (viewMode === "pdfmake" && legalText) regeneratePdfmake();
  }, [viewMode, legalText, regeneratePdfmake]);

  // Clean up the blob URL on unmount.
  React.useEffect(() => () => {
    if (pdfUrl) URL.revokeObjectURL(pdfUrl);
  }, [pdfUrl]);

  return (
    <div className={`pdf-viewer${embedded ? " pdf-viewer--embedded" : ""}${isDraft ? " pdf-viewer--draft" : ""}`}>
      <div className="pdf-viewer__inner">
        {!embedded && (
          <div className="pdf-toolbar">
            <button className="detail-header__back" onClick={onBack}>
              <Icon name="chevronLeft" size={14} /> Back to deal
            </button>
            <div className="pdf-toolbar__title">
              <Icon name="file" size={14} /> Order Form preview — {deal.customer}
            </div>
            <div className="pdf-toolbar__view-toggle" style={{ display: "flex", gap: 0, border: "1px solid var(--strokes)", borderRadius: 999, padding: 2, marginLeft: 12 }}>
              <button
                onClick={() => setViewMode("html")}
                style={{
                  padding: "6px 14px", borderRadius: 999, border: 0,
                  background: viewMode === "html" ? "var(--navy)" : "transparent",
                  color: viewMode === "html" ? "#fff" : "var(--dark-grey)",
                  fontWeight: 600, fontSize: 12, cursor: "pointer",
                }}
              >
                HTML
              </button>
              <button
                onClick={() => setViewMode("pdfmake")}
                disabled={!window.NAMI_PDFMAKE?.available || !legalText}
                style={{
                  padding: "6px 14px", borderRadius: 999, border: 0,
                  background: viewMode === "pdfmake" ? "var(--navy)" : "transparent",
                  color: viewMode === "pdfmake" ? "#fff" : "var(--dark-grey)",
                  fontWeight: 600, fontSize: 12, cursor: "pointer",
                  opacity: !window.NAMI_PDFMAKE?.available || !legalText ? 0.5 : 1,
                }}
                title={!legalText ? "Legal text still loading…" : "Preview pdfmake output"}
              >
                pdfmake
              </button>
            </div>
            <div className="flex gap-3">
              <button
                className="btn btn--ghost btn--sm"
                onClick={() => {
                  // Browser-print path: identical to what's rendered on
                  // screen. The chunker + @media print CSS handle pagination.
                  window.print();
                }}
              >
                <Icon name="download" size={13} /> Save as PDF (Print)
              </button>
              <button
                className="btn btn--ghost btn--sm"
                disabled={!window.NAMI_PDFMAKE?.available || !legalText}
                onClick={async () => {
                  if (!window.NAMI_PDFMAKE) return;
                  try {
                    await window.NAMI_PDFMAKE.generate({
                      deal,
                      amendments,
                      legalText,
                      isDraft,
                    });
                  } catch (err) {
                    console.error("pdfmake generation failed:", err);
                    alert(`pdfmake export failed: ${err.message || err}`);
                  }
                }}
                title={!legalText ? "Legal text still loading…" : "Generate via pdfmake"}
              >
                <Icon name="download" size={13} /> Save as PDF (pdfmake)
              </button>
              <button className="btn btn--alloy btn--sm">
                <Icon name="send" size={13} /> Send to customer
              </button>
            </div>
          </div>
        )}

        {viewMode === "pdfmake" ? (
          <div className="pdfmake-embed" style={{ flex: 1, padding: 24, background: "var(--alice-grey)", display: "flex", flexDirection: "column" }}>
            {pdfStatus === "loading" && (
              <div style={{ textAlign: "center", padding: 80, color: "var(--dark-grey)" }}>
                <div className="spinner" style={{ margin: "0 auto 18px" }} />
                Generating pdfmake preview…
              </div>
            )}
            {pdfStatus === "error" && (
              <div style={{ padding: 24, color: "var(--accent-red)", background: "#fff", borderRadius: 8, border: "1px solid var(--strokes)" }}>
                pdfmake failed: {pdfError}
                <div style={{ marginTop: 12 }}>
                  <button className="btn btn--outline btn--sm" onClick={regeneratePdfmake}>Retry</button>
                </div>
              </div>
            )}
            {pdfUrl && pdfStatus !== "loading" && (
              <>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }}>
                  <div style={{ fontSize: 12, color: "var(--dark-grey)" }}>
                    pdfmake render (iterates on every deal change)
                  </div>
                  <button className="btn btn--ghost btn--sm" onClick={regeneratePdfmake}>
                    <Icon name="refresh" size={13} /> Regenerate
                  </button>
                </div>
                <iframe
                  src={pdfUrl}
                  title="pdfmake preview"
                  style={{ flex: 1, width: "100%", minHeight: 900, border: "1px solid var(--strokes)", borderRadius: 8, background: "#fff" }}
                />
              </>
            )}
          </div>
        ) : (
          <>
        {/* ---- COVER ---- */}
        <CoverPage deal={deal} treatment={coverTreatment} amendments={amendments} pages={pages} isDraft={isDraft} />

        {/* ---- SERVICE ORDER PAGE 1 — Customer & Services ---- */}
        <ServiceOrderCustomerPage deal={deal} trim={t} pageNum={pageNum("service-order-1")} totalPages={totalPages} anchorId="anchor-service-order" />

        {/* ---- SERVICE ORDER PAGE 2 — Term, Fees, Payment ---- */}
        <ServiceOrderFeesPage
          deal={deal} trim={t} cpm={cpm} commits={commits} isDraft={isDraft}
          billingLabel={billingLabel}
          subscriptionTotal={subscriptionTotal}
          conciergeTotal={conciergeTotal}
          carrierTotal={carrierTotal}
          billingDiscountAmount={billingDiscountAmount}
          multiyrDiscountAmount={multiyrDiscountAmount}
          psTotal={psTotal}
          tcv={tcv}
          pageNum={pageNum("service-order-2")}
          totalPages={totalPages}
        />

        {/* ---- AMENDMENT ADDENDUM (paginated; long clauses spill to
             continuation pages) ---- */}
        {amendmentChunks.map((chunk, i) => {
          const startIndex = amendmentChunks
            .slice(0, i)
            .reduce((s, c) => s + c.length, 0);
          return (
            <AmendmentAddendumPage
              key={`amendment-${i}`}
              deal={deal} chunk={chunk} startIndex={startIndex}
              isFirst={i === 0} isLast={i === amendmentChunks.length - 1}
              pageNum={pageNum(`amendment-${i}`)} totalPages={totalPages}
              anchorId={i === 0 ? "anchor-amendment" : undefined}
            />
          );
        })}

        {/* ---- SERVICE LEVEL ADDENDUM (summary) ---- */}
        <SlaSummaryPage
          deal={deal}
          pageNum={pageNum("sla")} totalPages={totalPages}
          anchorId="anchor-sla-summary"
        />

        {/* ---- STANDARD DOCUMENTS (full text, inline, chunked one
             component-page per ~letter-sheet) ---- */}
        {msaChunks.map((chunk, i) => (
          <FullLegalPage
            key={`msa-${i}`}
            docLabel="Master Services Agreement"
            brand="Nami ML — Master Services Agreement"
            markdown={chunk}
            chunkIndex={i}
            chunkCount={msaChunks.length}
            pageNum={pageNum(`msa-full-${i}`)}
            totalPages={totalPages}
            anchorId={i === 0 ? "anchor-msa" : null}
          />
        ))}
        {dpaChunks.map((chunk, i) => (
          <FullLegalPage
            key={`dpa-${i}`}
            docLabel="Data Protection Addendum"
            brand="Nami ML — Data Protection Addendum"
            markdown={chunk}
            chunkIndex={i}
            chunkCount={dpaChunks.length}
            pageNum={pageNum(`dpa-full-${i}`)}
            totalPages={totalPages}
            anchorId={i === 0 ? "anchor-dpa" : null}
          />
        ))}
        {slaChunks.map((chunk, i) => (
          <FullLegalPage
            key={`sla-${i}`}
            docLabel="Service Level Addendum"
            brand="Nami ML — Service Level Addendum"
            markdown={chunk}
            chunkIndex={i}
            chunkCount={slaChunks.length}
            pageNum={pageNum(`sla-full-${i}`)}
            totalPages={totalPages}
            anchorId={i === 0 ? "anchor-sla" : null}
          />
        ))}

        {/* ---- EXTERNAL REFERENCES (Privacy + Subprocessors URLs) ---- */}
        <ExternalReferencesPage
          pageNum={pageNum("references")} totalPages={totalPages}
          anchorId="anchor-references"
        />

        {/* ---- SIGNATURES ---- */}
        <SignaturesPage
          deal={deal} amendments={amendments}
          pageNum={pageNum("signatures")} totalPages={totalPages}
          anchorId="anchor-signatures"
        />
          </>
        )}
      </div>
    </div>
  );
};

// ----- Cover -----
const CoverPage = ({ deal, treatment, amendments, pages, isDraft = false }) => {
  const PRICING = window.NAMI_PRICING;
  const trims = window.NAMI_DATA.TRIM_TIERS;
  const t = trims[deal.trim || "premier"];
  const isGrad = treatment === "gradient";
  const govLaw = (deal.variants || {})["v1-governing-law"];
  const govLawLabel = {
    NY: "New York", CA: "California", DE: "Delaware", other: "—",
  }[govLaw] || "New York (standard)";
  const commits = deal.commits || [t.minCommit * 1_000_000];

  // Document inventory: which sections will appear and on what page.
  const inventory = [
    { label: "Service Order", sub: "Customer-specific commercial terms", anchor: "anchor-service-order" },
    ...(amendments.length ? [{
      label: "Amendment Addendum",
      sub: `${amendments.length} pre-approved modification${amendments.length === 1 ? "" : "s"} to the standard MSA`,
      anchor: "anchor-amendment",
    }] : []),
    { label: "Service Level Summary",
      sub: `${(deal.support || "Standard")[0].toUpperCase() + (deal.support || "standard").slice(1)} tier — full SLA follows`,
      anchor: "anchor-sla-summary" },
    { label: "Master Services Agreement",
      sub: "Standard Nami enterprise MSA",
      anchor: "anchor-msa" },
    { label: "Data Protection Addendum",
      sub: "SCCs, UK IDTA, CCPA/CPRA",
      anchor: "anchor-dpa" },
    { label: "Service Level Addendum",
      sub: "Standard and Concierge",
      anchor: "anchor-sla" },
    { label: "Reference Documents",
      sub: "Privacy Policy, Subprocessor List",
      anchor: "anchor-references" },
    { label: "Signatures",
      sub: "Execution page for the entire Agreement package",
      anchor: "anchor-signatures" },
  ];

  return (
    <div className={`pdf-page pdf-page--cover ${isGrad ? "cover--gradient" : "cover--smoke"}`}>
      <div className="cover-inner">
        <div className="cover__logo">
          <img src={isGrad ? "assets/nami-wordmark-white.svg" : "assets/nami-wordmark-navy.svg"} alt="Nami" />
        </div>

        <div className="cover__eyebrow">Service Order Package</div>
        <h1 className="cover__title">Subscription Services Agreement</h1>
        <div className="cover__customer" style={{ fontSize: 18, fontWeight: 600, marginTop: -12, marginBottom: 6 }}>
          {deal.customer}
        </div>
        <p className="cover__sub">
          {isDraft
            ? <>Effective TBD — TBD. </>
            : deal.endDate
              ? <>Effective {fmtDate(deal.startDate)} — {fmtDate(deal.endDate)}. </>
              : <>Effective {fmtDate(deal.startDate)}. </>}
          Prepared by Nami ML Inc.
        </p>

        <div className="cover__card">
          <div className="cover__kv">
            <div className="l">Plan</div>
            <div className="v">{t.name}</div>
          </div>
          <div className="cover__kv">
            <div className="l">Term</div>
            <div className="v">{deal.termYears || 1} year{(deal.termYears || 1) === 1 ? "" : "s"}</div>
          </div>
          <div className="cover__kv">
            <div className="l">Total contract value</div>
            <div className="v">{money(deal.tcv || 0)}</div>
          </div>
          <div className="cover__kv">
            <div className="l">Volume commit</div>
            <div className="v">{fmtImpressions(commits[0])}</div>
          </div>
          <div className="cover__kv">
            <div className="l">Support level</div>
            <div className="v" style={{ textTransform: "capitalize" }}>{deal.support || "standard"}</div>
          </div>
          <div className="cover__kv">
            <div className="l">Governing law</div>
            <div className="v">{govLawLabel}</div>
          </div>
        </div>

        <div className="doc-inventory">
          <div className="doc-inventory__title">Documents in this package</div>
          <div className="doc-inventory__list">
            {inventory.map((doc, i) => (
              <div className="doc-inventory__row" key={i}>
                <div>
                  <div className="doc-inventory__name">{doc.label}</div>
                  <div className="doc-inventory__sub">{doc.sub}</div>
                </div>
                {/* Internal fragment link. We keep `href` so browser
                    "Save as PDF" preserves it as a real PDF anchor —
                    but in the live app we have to onClick-handle it,
                    because hash-based routing (`#/pdf/...`) would
                    otherwise intercept the hash change and treat
                    `#anchor-service-order` as a route. */}
                <a
                  className="doc-inventory__link"
                  href={`#${doc.anchor}`}
                  onClick={(e) => {
                    e.preventDefault();
                    const el = document.getElementById(doc.anchor);
                    if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
                  }}
                >
                  →
                </a>
              </div>
            ))}
          </div>
        </div>

        <div className="cover__footer">
          <span>Confidential — Nami ML Inc.</span>
          <span></span>
        </div>
      </div>
    </div>
  );
};

// ----- Service Order — Customer & Services Description -----
const ServiceOrderCustomerPage = ({ deal, trim, pageNum, totalPages, anchorId }) => {
  const PRICING = window.NAMI_PRICING;
  const features = PRICING.featuresForTrim(trim.key);
  const supportFeatures = PRICING.SUPPORT_FEATURES[deal.support || "standard"] || [];
  const supportLabel = (deal.support || "standard")[0].toUpperCase() + (deal.support || "standard").slice(1);

  return (
    <div className="pdf-page" id={anchorId || undefined}>
      <div className="pdf-page__header">
        <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
        <span className="pdf-page__doc-label">Service Order</span>
      </div>

      <h1 className="pdf-h1">Service Order</h1>
      <div className="pdf-rule" />
      <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 18 }}>
        Customer subscribes to Nami Services for the Subscription Term and Fees specified below,
        and Nami agrees to provide the Nami Services specified pursuant to the Nami Master Services
        Agreement (the "MSA") as modified by the Amendment Addendum attached hereto. In the event
        of conflict between this Service Order and the MSA, the MSA shall govern except as modified
        by the Amendment Addendum.
      </p>

      <h2 className="pdf-h2">Customer</h2>
      <table className="pdf-tbl">
        <tbody>
          <tr><td style={{ width: "30%", color: "var(--dark-grey)" }}>Legal Entity</td><td>{deal.customerLegal || deal.customer}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Address</td><td>{deal.customerAddress || "—"}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Primary Contact</td><td>{deal.primaryContact?.name || "—"}{deal.primaryContact?.email ? ` — ${deal.primaryContact.email}` : ""}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>A/P Email</td><td>{deal.billingContact?.email || "—"}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Authorized Signer</td><td>{deal.contractAdmin?.name || "—"}{deal.contractAdmin?.title ? ` — ${deal.contractAdmin.title}` : ""}{deal.contractAdmin?.email ? ` — ${deal.contractAdmin.email}` : ""}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Legal Notices</td><td>{deal.noticeAddress || "—"}</td></tr>
        </tbody>
      </table>

      <h2 className="pdf-h2">Services Description</h2>
      <div style={{ fontSize: 11, lineHeight: 1.65 }}>
        <h3 className="pdf-h3" style={{ marginTop: 4 }}>Nami {trim.name} — Subscription Services</h3>
        <ul style={{ margin: "8px 0 14px", paddingLeft: 18, columns: 2, columnGap: 24 }}>
          {features.map((f, i) => <li key={i} style={{ marginBottom: 3 }}>{f}</li>)}
        </ul>

        <h3 className="pdf-h3" style={{ marginTop: 16 }}>{supportLabel} - Service Level</h3>
        <ul style={{ margin: "6px 0 0", paddingLeft: 18, columns: 2, columnGap: 24 }}>
          {supportFeatures.map((f, i) => <li key={i} style={{ marginBottom: 3 }}>{f}</li>)}
        </ul>
      </div>

      <div className="pdf-page__num"></div>
      <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
    </div>
  );
};

// ----- Service Order — Term, Fees, Payment -----
const ServiceOrderFeesPage = ({
  deal, trim, cpm, commits, billingLabel, isDraft = false,
  subscriptionTotal, conciergeTotal, carrierTotal,
  billingDiscountAmount, multiyrDiscountAmount, psTotal, tcv,
  pageNum, totalPages,
}) => {
  const carrierPerYear = (deal.addons || []).includes("carrier-grade")
    ? window.NAMI_PRICING.CARRIER_PRICE : 0;
  const conciergePerYearMap = commits.map((c) => {
    const sub = (c / 1000) * cpm;
    return window.NAMI_PRICING.conciergePriceFor(sub, deal);
  });

  // Net-terms variant override (v11-payment-terms)
  const v11 = (deal.variants || {})["v11-payment-terms"];
  const netTerms = deal.netTerms || (v11 === "net45" ? "Net 45" : v11 === "net60" ? "Net 60" : "Net 30");

  return (
    <div className="pdf-page">
      <div className="pdf-page__header">
        <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
        <span className="pdf-page__doc-label">Service Order — Fees &amp; Terms</span>
      </div>

      <h2 className="pdf-h2" style={{ marginTop: 0 }}>Subscription Term</h2>
      <table className="pdf-tbl">
        <tbody>
          <tr><td style={{ width: "30%", color: "var(--dark-grey)" }}>Term length</td><td>{deal.termYears || 1} year{(deal.termYears || 1) === 1 ? "" : "s"}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Start date</td><td>{isDraft ? "TBD" : fmtDate(deal.startDate)}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>End date</td><td>{isDraft ? "TBD" : fmtDate(deal.endDate)}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Renewal</td><td>Auto-renew for successive 12-month period per MSA §8.1.</td></tr>
        </tbody>
      </table>

      <h2 className="pdf-h2">Volume Commitment &amp; Subscription Fees</h2>
      <table className="pdf-tbl">
        <thead>
          <tr>
            <th>Year</th>
            <th>Volume commit</th>
            <th>Subscription</th>
            {conciergeTotal > 0 && <th>Concierge</th>}
            {carrierTotal > 0 && <th>Carrier-grade</th>}
            <th className="num">Subtotal</th>
          </tr>
        </thead>
        <tbody>
          {commits.map((c, i) => {
            const sub = (c / 1000) * cpm;
            const conc = conciergePerYearMap[i];
            const carr = carrierPerYear;
            const subtotal = sub + conc + carr;
            return (
              <tr key={i}>
                <td>Year {i + 1}</td>
                <td>{fmtImpressions(c)}</td>
                <td>{money(sub)}</td>
                {conciergeTotal > 0 && <td>{money(conc)}</td>}
                {carrierTotal > 0 && <td>{money(carr)}</td>}
                <td className="num">{money(subtotal)}</td>
              </tr>
            );
          })}
          <tr style={{ background: "var(--alice-grey)" }}>
            <td colSpan={2 + (conciergeTotal > 0 ? 1 : 0) + (carrierTotal > 0 ? 1 : 0) + 1} style={{ fontWeight: 600 }}>
              Subtotal before discounts
            </td>
            <td className="num" style={{ fontWeight: 600 }}>
              {money(subscriptionTotal + conciergeTotal + carrierTotal)}
            </td>
          </tr>
          {billingDiscountAmount > 0 && (
            <tr>
              <td colSpan={2 + (conciergeTotal > 0 ? 1 : 0) + (carrierTotal > 0 ? 1 : 0) + 1}>
                {billingLabel.includes("Annual") ? "Commit-upfront savings (25% off)"
                  : billingLabel.includes("Quarterly") ? "Quarterly billing (10% off)"
                  : "Billing discount"}
              </td>
              <td className="num">−{money(billingDiscountAmount)}</td>
            </tr>
          )}
          {multiyrDiscountAmount > 0 && (
            <tr>
              <td colSpan={2 + (conciergeTotal > 0 ? 1 : 0) + (carrierTotal > 0 ? 1 : 0) + 1}>
                Three-year term (5% off)
              </td>
              <td className="num">−{money(multiyrDiscountAmount)}</td>
            </tr>
          )}
          {psTotal > 0 && (
            <tr>
              <td colSpan={2 + (conciergeTotal > 0 ? 1 : 0) + (carrierTotal > 0 ? 1 : 0) + 1}>
                Professional Services (full price)
              </td>
              <td className="num">{money(psTotal)}</td>
            </tr>
          )}
        </tbody>
        <tfoot>
          <tr style={{ borderTop: "2px solid var(--navy)" }}>
            <td colSpan={2 + (conciergeTotal > 0 ? 1 : 0) + (carrierTotal > 0 ? 1 : 0) + 1} style={{ fontWeight: 700 }}>
              Total Contract Value
            </td>
            <td className="num" style={{ fontWeight: 700 }}>{money(tcv)}</td>
          </tr>
        </tfoot>
      </table>
      <div style={{ fontSize: 10, color: "var(--dark-grey)", marginTop: 6 }}>
        CPM rate: ${cpm.toFixed(2)} per 1,000 impressions. Usage above the committed
        volume is invoiced monthly in arrears at the same CPM.
      </div>

      <h2 className="pdf-h2">Payment Terms</h2>
      {(() => {
        const netDays = parseInt((netTerms || "").replace(/\D/g, ""), 10) || 30;
        const netWords = netDays === 30 ? "thirty (30)" : netDays === 45 ? "forty-five (45)" : netDays === 60 ? "sixty (60)" : `${netDays}`;
        const termYears = deal.termYears || 1;
        const startStr = fmtDate(deal.startDate);
        const isAnnual = (deal.cadence || "annual") === "annual";
        const isQuarterly = (deal.cadence || "annual") === "quarterly";
        const isUsage = (deal.cadence || "annual") === "usage";
        const currency = deal.currency || "USD";
        return (
          <>
            {isUsage ? (
              <p style={{ fontSize: 10, lineHeight: 1.65, margin: "0 0 12px" }}>
                Fees will be invoiced monthly in arrears based on actual measured impressions during
                the preceding calendar month at the CPM rate of ${cpm.toFixed(2)} per 1,000
                impressions set forth above, and are payable Net {netWords} days from the date of
                invoice. All Fees are denominated in {currency === "USD" ? "United States Dollars" : currency}.
              </p>
            ) : isQuarterly ? (
              <p style={{ fontSize: 10, lineHeight: 1.65, margin: "0 0 12px" }}>
                The Total Contract Value set forth above will be divided into four (4) equal
                quarterly installments {termYears > 1 ? "per year of the Subscription Term " : ""}
                and invoiced quarterly in advance. The first installment will be invoiced on the
                Start Date ({startStr}); each subsequent installment will be invoiced no less than
                thirty (30) days prior to the start of the next calendar quarter. Each installment
                is payable Net {netWords} days from the date of invoice. Usage in excess of the
                annual committed volume in any year will be invoiced monthly in arrears at the CPM
                rate of ${cpm.toFixed(2)} per 1,000 impressions set forth above and is payable Net
                {" "}{netWords} days from the date of invoice. All Fees are denominated in
                {" "}{currency === "USD" ? "United States Dollars" : currency}.
              </p>
            ) : (
              <p style={{ fontSize: 10, lineHeight: 1.65, margin: "0 0 12px" }}>
                Year 1 Subscription Fees will be invoiced on the Start Date ({startStr}) and are
                payable Net {netWords} days from the date of invoice.{termYears > 1 ? (
                  <> Subscription Fees for {termYears === 3 ? "Year 2 and Year 3" : "Year 2"} will
                  {termYears === 3 ? " each" : ""} be invoiced no less than thirty (30) days prior
                  to the applicable anniversary of the Start Date and are payable Net {netWords}
                  {" "}days from the date of invoice.</>
                ) : null} Usage in excess of the annual committed volume in any year will be
                invoiced monthly in arrears at the CPM rate of ${cpm.toFixed(2)} per 1,000
                impressions set forth above and is payable Net {netWords} days from the date of
                invoice. All Fees are denominated in {currency === "USD" ? "United States Dollars" : currency}.
              </p>
            )}
            <p style={{ fontSize: 10, lineHeight: 1.65, margin: "0 0 12px" }}>
              Customer shall pay undisputed invoices within Net {netWords} days of receipt. In the
              event Customer disputes any portion of an invoice, Customer shall notify Nami in
              writing of the disputed items prior to the due date and shall pay all undisputed
              amounts in accordance with this Service Order. The parties shall use commercially
              reasonable efforts to resolve any disputed items promptly.
            </p>
            <p style={{ fontSize: 10, lineHeight: 1.65, margin: 0 }}>
              Past-due amounts accrue interest at the lesser of 1.5% per month or the maximum rate
              permitted by applicable law, calculated from the original due date until paid in full,
              as set forth in MSA §1.3.
            </p>
          </>
        );
      })()}

      <div className="pdf-page__num"></div>
      <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
    </div>
  );
};

// ----- Amendment Addendum -----
// Renders one page's worth of amendment blocks. `chunk` is the slice of
// amendments for this page (see chunkAmendments); `startIndex` keeps the
// Amendment §N numbering continuous across continuation pages. The
// preamble shows only on the first page, the "Standard terms preserved"
// box only on the last.
const AmendmentAddendumPage = ({ deal, chunk, startIndex = 0, isFirst = true, isLast = true, pageNum, totalPages, anchorId }) => (
  <div className="pdf-page" id={anchorId || undefined}>
    <div className="pdf-page__header">
      <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
      <span className="pdf-page__doc-label">Amendment Addendum</span>
    </div>

    <h1 className="pdf-h1">Amendment Addendum{isFirst ? "" : " (continued)"}</h1>
    <div className="pdf-rule" />
    {isFirst && (
      <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 18 }}>
        This Amendment Addendum supplements the Nami Master Services Agreement entered into between
        Nami ML Inc. and {deal.customerLegal || deal.customer} effective {fmtDate(deal.startDate)}.
        Capitalized terms not defined here carry the meanings in the MSA. In the event of conflict
        between this Amendment Addendum and the MSA, this Amendment Addendum prevails. All other
        provisions of the MSA remain in full force and effect.
      </p>
    )}

    {chunk.map((a, i) => (
      <div className="amendment-block" key={a.id}>
        <div className="amend-h">
          Amendment §{startIndex + i + 1} — {a.category}
        </div>
        <div className="amend-sec">{a.section}</div>
        <div className="amend-text">"{a.text}"</div>
      </div>
    ))}

    {isLast && (
      <div style={{ marginTop: 24, padding: 14, background: "var(--alice-grey)", borderRadius: 8, fontSize: 11, lineHeight: 1.55, color: "var(--navy)" }}>
        <strong>Standard terms preserved.</strong> Apart from the modifications set forth above,
        all terms of the Nami Master Services Agreement, the Data Protection Addendum, and the
        Service Level Addendum remain in full force and effect.
      </div>
    )}

    <div className="pdf-page__num"></div>
    <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
  </div>
);

// ----- Service Level Addendum (summary) -----
const SlaSummaryPage = ({ deal, pageNum, totalPages, anchorId }) => {
  const support = deal.support || "standard";
  const isConcierge = support === "concierge";
  const supportLabel = isConcierge ? "Concierge" : "Standard";

  return (
    <div className="pdf-page" id={anchorId || undefined}>
      <div className="pdf-page__header">
        <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
        <span className="pdf-page__doc-label">Service Level Summary</span>
      </div>

      <h1 className="pdf-h1">Service Level Summary</h1>
      <div className="pdf-rule" />
      <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 18 }}>
        Customer's Service Level under the Nami Service Level Addendum is <strong>{supportLabel}</strong>.
        The {supportLabel} Service Level provides 24×7×365 support with the response-time
        commitments and uptime guarantees set forth below. This Service Level Addendum is
        incorporated into and forms part of the Agreement.
      </p>

      <h2 className="pdf-h2" style={{ marginTop: 0 }}>Initial Response Times</h2>
      <table className="pdf-tbl">
        <thead>
          <tr><th>Priority</th><th>Description</th><th>Initial Response</th></tr>
        </thead>
        <tbody>
          <tr><td><strong>P1</strong></td><td>Catastrophic — production down, no workaround</td><td>{isConcierge ? "15 minutes" : "2 hours"}</td></tr>
          <tr><td><strong>P2</strong></td><td>Major — significant impact, reduced capacity</td><td>{isConcierge ? "1 hour" : "4 hours"}</td></tr>
          <tr><td><strong>P3</strong></td><td>Medium — partial or non-critical functions impaired</td><td>{isConcierge ? "8 hours" : "1 business day"}</td></tr>
          <tr><td><strong>P4</strong></td><td>Minor — cosmetic, documentation, enhancement</td><td>{isConcierge ? "1 business day" : "3 business days"}</td></tr>
        </tbody>
      </table>

      <h2 className="pdf-h2">Uptime &amp; Service Credits</h2>
      <table className="pdf-tbl">
        <tbody>
          <tr><td style={{ width: "40%", color: "var(--dark-grey)" }}>Minimum uptime percentage</td><td>{isConcierge ? "99.999% per calendar month" : "99.99% per calendar month"}</td></tr>
          <tr><td style={{ color: "var(--dark-grey)" }}>Service credit cap</td><td>Up to {isConcierge ? "50%" : "25%"} of fees attributable to a calendar month</td></tr>
          {isConcierge && (
            <tr><td style={{ color: "var(--dark-grey)" }}>CSM model</td><td>Dedicated — single point of contact, named individual</td></tr>
          )}
          {isConcierge && (
            <tr><td style={{ color: "var(--dark-grey)" }}>Kickstart Pro Services</td><td>100 hours included annually</td></tr>
          )}
          {isConcierge && (
            <tr><td style={{ color: "var(--dark-grey)" }}>Quarterly business reviews</td><td>Yes — with Nami leadership</td></tr>
          )}
        </tbody>
      </table>

      <p style={{ fontSize: 10, color: "var(--dark-grey)", marginTop: 18, lineHeight: 1.55 }}>
        The summary above is for reference. The full text of the Nami Service Level Addendum
        (included in this package) is the authoritative version and governs in the event of any
        conflict with this summary.
      </p>

      <div className="pdf-page__num"></div>
      <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
    </div>
  );
};

// ----- Full Legal Document (MSA / DPA / SLA, embedded inline) -----
// Each instance renders ONE chunk of the document — the chunker upstream
// has already split long docs into one-letter-sheet-sized buckets.
// `chunkIndex === 0` is the first page of a doc and gets the pdf-h1
// title + gradient rule; subsequent chunks render only body so the
// reader sees the doc as a continuous flow across sheets.
const FullLegalPage = ({ docLabel, brand, markdown, pageNum, totalPages, chunkIndex = 0, chunkCount = 1, anchorId }) => {
  const isFirst = chunkIndex === 0;
  // On the FIRST chunk only, strip the leading `## <Doc Name>` and any
  // `**Effective Date:**` stub — they're scaffolding that the Service
  // Order already establishes. Later chunks are pure body.
  const cleaned = React.useMemo(() => {
    if (!markdown) return "";
    let s = String(markdown);
    if (isFirst) {
      s = s
        .replace(/^\s*##\s+[^\n]+\n+/, "")
        .replace(/^\s*\*\*Effective Date:?\*\*[^\n]*\n+/i, "");
    }
    return s;
  }, [markdown, isFirst]);
  const html = cleaned && window.NAMI_LEGAL_MD
    ? window.NAMI_LEGAL_MD.renderMarkdown(cleaned)
    : "";
  return (
    <div className="pdf-page pdf-page--legal" id={anchorId || undefined}>
      <div className="pdf-page__header">
        <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
        <span className="pdf-page__doc-label">{docLabel}</span>
      </div>

      {isFirst && (
        <>
          <h1 className="pdf-h1">{docLabel}</h1>
          <div className="pdf-rule" />
        </>
      )}

      {html ? (
        <div className="legal-doc" dangerouslySetInnerHTML={{ __html: html }} />
      ) : (
        <div className="legal-doc legal-doc--loading" style={{ color: "var(--dark-grey)", fontSize: 11, padding: "32px 0" }}>
          Loading {docLabel}…
        </div>
      )}

      <div className="pdf-page__num"></div>
      <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
    </div>
  );
};

// ----- External References (Privacy + Subprocessors URLs) -----
const ExternalReferencesPage = ({ pageNum, totalPages, anchorId }) => (
  <div className="pdf-page" id={anchorId || undefined}>
    <div className="pdf-page__header">
      <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
      <span className="pdf-page__doc-label">Reference Documents</span>
    </div>

    <h1 className="pdf-h1">Reference Documents</h1>
    <div className="pdf-rule" />
    <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 18 }}>
      The following Nami reference documents are incorporated into this contract package by
      reference at their published URLs and are subject to the change-notification mechanics
      described in the MSA and DPA respectively. Customer's contractual rights with respect to
      these documents are governed by the Master Services Agreement and Data Protection Addendum
      included in this package.
    </p>

    <div className="reference-list">
      <div className="reference-item">
        <div className="reference-name">Nami Privacy Policy</div>
        <div className="reference-meta">
          Referenced in MSA §5 (Security and Privacy). Published at{" "}
          <a href="https://www.nami.ml/privacy" target="_blank" rel="noopener">www.nami.ml/privacy</a>
        </div>
      </div>

      <div className="reference-item">
        <div className="reference-name">Nami Subprocessor List</div>
        <div className="reference-meta">
          Referenced in DPA §6 (Subprocessors). Published at{" "}
          <a href="https://www.nami.ml/legal/subprocessors/" target="_blank" rel="noopener">www.nami.ml/legal/subprocessors/</a>
        </div>
      </div>
    </div>

    <div className="pdf-page__num"></div>
    <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
  </div>
);

// ----- Signatures -----
const SignaturesPage = ({ deal, amendments, pageNum, totalPages, anchorId }) => (
  <div className="pdf-page" id={anchorId || undefined}>
    <div className="pdf-page__header">
      <img src="assets/nami-wordmark-navy.svg" alt="Nami" style={{ height: 14 }} />
      <span className="pdf-page__doc-label">Signatures</span>
    </div>

    <h1 className="pdf-h1">Signatures</h1>
    <div className="pdf-rule" />
    <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 14 }}>
      IN WITNESS WHEREOF, the parties have caused this Agreement to be duly executed as of the
      Effective Date. Each party represents and warrants that the signatory below has authority
      to bind the party to the Agreement.
    </p>
    <p style={{ color: "var(--dark-grey)", fontSize: 11, lineHeight: 1.6, marginBottom: 24 }}>
      By signing below, each party agrees to be bound by this Service Order, the Master Services
      Agreement, Data Protection Addendum, and Service Level Addendum included in this package,
      {amendments.length ? " the Amendment Addendum," : ""} and the reference documents identified
      herein, as a single integrated Agreement.
    </p>

    {/* AE-facing preview: visible signature lines without DocuSign anchor
        markers. The worker-side renderSignatures() keeps the literal `\sig1\`
        anchor strings so DocuSign's tab placement still works at signing
        time — they're only hidden from this preview. */}
    <div className="sig-block">
      <div className="sig-box">
        <div className="role">Customer — {deal.customer}</div>
        <div className="sig-line" style={{ borderBottom: "1px solid var(--navy)", height: 32, marginBottom: 8 }} />
        <div className="pdf-kv-grid" style={{ gridTemplateColumns: "80px 1fr", gap: 2 }}>
          <div className="k">Name:</div><div className="v">{deal.contractAdmin?.name || "_______________________"}</div>
          <div className="k">Title:</div><div className="v">{deal.contractAdmin?.title || "_______________________"}</div>
          <div className="k">Date:</div><div className="v">_______________________</div>
        </div>
      </div>
      <div className="sig-box">
        <div className="role">Nami ML Inc.</div>
        <div className="sig-line" style={{ borderBottom: "1px solid var(--navy)", height: 32, marginBottom: 8 }} />
        <div className="pdf-kv-grid" style={{ gridTemplateColumns: "80px 1fr", gap: 2 }}>
          <div className="k">Name:</div><div className="v">_______________________</div>
          <div className="k">Title:</div><div className="v">_______________________</div>
          <div className="k">Date:</div><div className="v">_______________________</div>
        </div>
      </div>
    </div>

    <div className="pdf-page__num"></div>
    <div className="pdf-page__brand">Confidential — Nami ML Inc.</div>
  </div>
);

window.OrderFormPDF = OrderFormPDF;
