/* MostlyPDF web app — React (via Babel), ported faithfully from the Claude Design
   handoff (MostlyPDF.dc.html) onto the Forge/Mostly Tiny _ds + _kit. Four screens:
   Landing · Runner · Pricing · Compare, coral accent. The runner is wired to the
   real pdfProcess endpoint (window.MOSTLYPDF.endpoint) + the generated tool registry
   (window.PDF_TOOLS), replacing the design's mock data. Style strings are kept
   verbatim from the design via S(). */
(function () {
  'use strict';
  const { useState, useEffect, useRef } = React;
  const CFG = window.MOSTLYPDF || {};
  const e = React.createElement;

  // i18n runtime (the @mostly-tiny/i18n window.ForgeI18n global, installed by the
  // forge-i18n-core.js + _i18n_bundle.js script tags before this babel module evals —
  // and re-installed per-locale during the SSR prerender). The identity fallback keeps
  // the page rendering if the bundle is absent (e.g. raw dev server). SSR-safe: the
  // prerender re-evaluates THIS module once per locale with ForgeI18n forced to that
  // locale's server translator, so module-scope tr('…') calls localize correctly.
  const I18N = (typeof window !== 'undefined' && window.ForgeI18n) || {
    t: (k) => k, has: () => false, locale: 'en', dir: 'ltr',
    fmt: { number: (n) => String(n ?? ''), currency: (n) => String(n ?? ''), percent: (n) => String(n ?? ''),
           date: (d) => String(d ?? ''), time: (d) => String(d ?? ''), relative: (d) => String(d ?? '') },
  };
  const tr = I18N.t, fmt = I18N.fmt;

  // Public sign-up/sign-in gate. FALSE = closed beta (team-only): the header hides the
  // Sign in / Get started buttons and shows an "In development" pill. Flip to true at public
  // launch (alongside auth.config publicSignup:true + opening the IdP). Mirrors the backend
  // gate — magic-link send already refuses non-team emails while publicSignup is false.
  const PUBLIC_APP_OPEN = false;

  // Lightweight fuzzy matcher for the tool search: a contiguous substring wins (ranked by
  // how early it appears); otherwise an in-order subsequence match. Returns a score
  // (higher = better) or -1 for no match.
  function fuzzyScore(query, text) {
    const q = (query || '').toLowerCase().trim();
    const t = (text || '').toLowerCase();
    if (!q) return 0;
    const idx = t.indexOf(q);
    if (idx >= 0) return 1000 - idx;
    let qi = 0;
    for (let i = 0; i < t.length && qi < q.length; i++) if (t[i] === q[qi]) qi++;
    return qi === q.length ? 1 : -1;
  }

  // Parse a design inline-style string ("a:b;c:d") into a React style object,
  // preserving --custom-properties verbatim.
  function S(str) {
    const o = {};
    (str || '').split(';').forEach((decl) => {
      const i = decl.indexOf(':');
      if (i < 0) return;
      let k = decl.slice(0, i).trim();
      const v = decl.slice(i + 1).trim();
      if (!k) return;
      if (!k.startsWith('--')) k = k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
      o[k] = v;
    });
    return o;
  }

  // ── icon paths (verbatim from the design) ──
  const P = {
    layers: 'M12 2 2 7l10 5 10-5-10-5z M2 17l10 5 10-5 M2 12l10 5 10-5',
    scissors: 'M6 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6z M6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z M20 4 8.12 15.88 M14.47 14.48 20 20 M8.12 8.12 12 12',
    fileMinus: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z M14 2v7h7 M9 15h6',
    copy: 'M9 9h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V11a2 2 0 0 1 2-2z M5 15H4a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v1',
    grid: 'M3 3h7v7H3z M14 3h7v7h-7z M14 14h7v7h-7z M3 14h7v7H3z',
    rotate: 'M21 2v6h-6 M21 13a9 9 0 1 1-3-7.7L21 8',
    shrink: 'M15 3h6v6 M9 21H3v-6 M21 3l-7 7 M3 21l7-7',
    image: 'M3 3h18v18H3z M8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z M21 15l-5-5L5 21',
    image2: 'M3 3h18v18H3z M9 11a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z M21 14l-4-4L7 20',
    fileText: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z M14 2v7h7 M16 13H8 M16 17H8 M10 9H8',
    fileType: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z M14 2v7h7 M9 13v5 M7 13h4',
    scan: 'M3 7V5a2 2 0 0 1 2-2h2 M17 3h2a2 2 0 0 1 2 2v2 M21 17v2a2 2 0 0 1-2 2h-2 M7 21H5a2 2 0 0 1-2-2v-2 M7 8h8 M7 12h10 M7 16h6',
    hash: 'M4 9h16 M4 15h16 M10 3 8 21 M16 3l-2 18',
    droplet: 'M12 2.7 6.3 8.4a8 8 0 1 0 11.4 0z M9.5 14a2.5 2.5 0 0 0 2.5 2.5',
    lock: 'M5 11h14v10H5z M8 11V7a4 4 0 0 1 8 0v4',
    unlock: 'M5 11h14v10H5z M8 11V7a4 4 0 0 1 7.9-1',
    pen: 'M2 22s4-1 7-4l9.5-9.5a2.1 2.1 0 0 0-3-3L6 15c-3 3-4 7-4 7z M15 5l4 4',
    zap: 'M13 2 3 14h7l-1 8 10-12h-7z',
    code: 'M16 18l6-6-6-6 M8 6l-6 6 6 6',
  };
  function ic(name, size, sw) {
    const d = P[name] || '';
    return e('svg', { width: size || 20, height: size || 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: sw || 2, strokeLinecap: 'round', strokeLinejoin: 'round' },
      d.split(' M').map((p, i) => e('path', { key: i, d: (i ? 'M' : '') + p })));
  }
  const Logo = (sz) => (
    <svg width={sz} height={sz} viewBox="0 0 100 100" aria-hidden="true">
      <rect x="3" y="3" width="94" height="94" rx="27" fill="var(--accent)" />
      <path d="M34 22H56L70 36V74A4 4 0 0 1 66 78H34A4 4 0 0 1 30 74V26A4 4 0 0 1 34 22Z" fill="none" stroke="#fff" strokeWidth="6.5" strokeLinejoin="round" strokeLinecap="round" />
      <path d="M56 22V36H70" fill="none" stroke="#fff" strokeWidth="6.5" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx="79" cy="79" r="5" fill="#fff" />
    </svg>
  );

  // ── tool catalog: the design's display copy, reconciled with the live registry.
  // engine 'pure' tools are wired to pdfProcess; 'container' tools render as Soon. ──
  // Tool display copy is keyed by slug (mp.tool.<slug>.title/answer); category names/notes by
  // mp.cat.<key>.name/note. Slugs/icons/flags are NOT translated (they're code/registry-driven).
  const CATS = [
    { key: 'organize', name: tr('mp.cat.organize.name'), note: tr('mp.cat.organize.note'), tools: [
      { slug: 'merge-pdf', icon: 'layers', title: tr('mp.tool.merge-pdf.title'), answer: tr('mp.tool.merge-pdf.answer') },
      { slug: 'split-pdf', icon: 'scissors', title: tr('mp.tool.split-pdf.title'), answer: tr('mp.tool.split-pdf.answer') },
      { slug: 'remove-pages', icon: 'fileMinus', title: tr('mp.tool.remove-pages.title'), answer: tr('mp.tool.remove-pages.answer') },
      { slug: 'extract-pages', icon: 'copy', title: tr('mp.tool.extract-pages.title'), answer: tr('mp.tool.extract-pages.answer') },
      { slug: 'organize-pdf', icon: 'grid', title: tr('mp.tool.organize-pdf.title'), answer: tr('mp.tool.organize-pdf.answer') },
      { slug: 'rotate-pdf', icon: 'rotate', title: tr('mp.tool.rotate-pdf.title'), answer: tr('mp.tool.rotate-pdf.answer') },
    ] },
    { key: 'optimize', name: tr('mp.cat.optimize.name'), note: tr('mp.cat.optimize.note'), tools: [
      { slug: 'compress-pdf', icon: 'shrink', title: tr('mp.tool.compress-pdf.title'), answer: tr('mp.tool.compress-pdf.answer'), soon: true },
    ] },
    { key: 'convert', name: tr('mp.cat.convert.name'), note: tr('mp.cat.convert.note'), tools: [
      { slug: 'jpg-to-pdf', icon: 'image', title: tr('mp.tool.jpg-to-pdf.title'), answer: tr('mp.tool.jpg-to-pdf.answer') },
      { slug: 'pdf-to-word', icon: 'fileText', title: tr('mp.tool.pdf-to-word.title'), answer: tr('mp.tool.pdf-to-word.answer'), pro: true, soon: true },
      { slug: 'pdf-to-jpg', icon: 'image2', title: tr('mp.tool.pdf-to-jpg.title'), answer: tr('mp.tool.pdf-to-jpg.answer'), soon: true },
      { slug: 'word-to-pdf', icon: 'fileType', title: tr('mp.tool.word-to-pdf.title'), answer: tr('mp.tool.word-to-pdf.answer'), soon: true },
      { slug: 'ocr-pdf', icon: 'scan', title: tr('mp.tool.ocr-pdf.title'), answer: tr('mp.tool.ocr-pdf.answer'), pro: true, soon: true },
    ] },
    { key: 'edit', name: tr('mp.cat.edit.name'), note: tr('mp.cat.edit.note'), tools: [
      { slug: 'page-numbers', icon: 'hash', title: tr('mp.tool.page-numbers.title'), answer: tr('mp.tool.page-numbers.answer') },
      { slug: 'watermark-pdf', icon: 'droplet', title: tr('mp.tool.watermark-pdf.title'), answer: tr('mp.tool.watermark-pdf.answer') },
    ] },
    { key: 'security', name: tr('mp.cat.security.name'), note: tr('mp.cat.security.note'), tools: [
      { slug: 'protect-pdf', icon: 'lock', title: tr('mp.tool.protect-pdf.title'), answer: tr('mp.tool.protect-pdf.answer'), soon: true },
      { slug: 'unlock-pdf', icon: 'unlock', title: tr('mp.tool.unlock-pdf.title'), answer: tr('mp.tool.unlock-pdf.answer'), soon: true },
      { slug: 'sign-pdf', icon: 'pen', title: tr('mp.tool.sign-pdf.title'), answer: tr('mp.tool.sign-pdf.answer'), pro: true, soon: true },
    ] },
  ];
  // Per-tool runner copy. Prose (runLabel/workingLabel/successTitle/errorMsg/doMore.label/verb/howto/
  // genericNote/pagesLabel) is keyed mp.runner.<slug>.*; opt/accepts/min/placeholder stay as code/format.
  const META = {
    'merge-pdf': { inputs: 'multi', reorder: true, opt: 'merge', accepts: 'PDF', min: 2, runLabel: tr('mp.runner.merge-pdf.runLabel'), workingLabel: tr('mp.runner.merge-pdf.workingLabel'), successTitle: tr('mp.runner.merge-pdf.successTitle'), errorMsg: tr('mp.runner.merge-pdf.errorMsg'), doMore: { slug: 'compress-pdf', label: tr('mp.runner.merge-pdf.doMore') }, verb: tr('mp.runner.merge-pdf.verb'), howto: tr('mp.runner.merge-pdf.howto') },
    'split-pdf': { inputs: 'single', opt: 'split', accepts: 'PDF', runLabel: tr('mp.runner.split-pdf.runLabel'), workingLabel: tr('mp.runner.split-pdf.workingLabel'), successTitle: tr('mp.runner.split-pdf.successTitle'), errorMsg: tr('mp.runner.split-pdf.errorMsg'), doMore: { slug: 'merge-pdf', label: tr('mp.runner.split-pdf.doMore') }, verb: tr('mp.runner.split-pdf.verb'), howto: tr('mp.runner.split-pdf.howto') },
    'remove-pages': { inputs: 'single', opt: 'pages', pagesLabel: tr('mp.runner.remove-pages.pagesLabel'), placeholder: '2, 5-7', accepts: 'PDF', runLabel: tr('mp.runner.remove-pages.runLabel'), workingLabel: tr('mp.runner.remove-pages.workingLabel'), successTitle: tr('mp.runner.remove-pages.successTitle'), errorMsg: tr('mp.runner.remove-pages.errorMsg'), doMore: { slug: 'organize-pdf', label: tr('mp.runner.remove-pages.doMore') }, verb: tr('mp.runner.remove-pages.verb'), howto: tr('mp.runner.remove-pages.howto') },
    'extract-pages': { inputs: 'single', opt: 'pages', pagesLabel: tr('mp.runner.extract-pages.pagesLabel'), placeholder: '1, 3-4', accepts: 'PDF', runLabel: tr('mp.runner.extract-pages.runLabel'), workingLabel: tr('mp.runner.extract-pages.workingLabel'), successTitle: tr('mp.runner.extract-pages.successTitle'), errorMsg: tr('mp.runner.extract-pages.errorMsg'), doMore: { slug: 'merge-pdf', label: tr('mp.runner.extract-pages.doMore') }, verb: tr('mp.runner.extract-pages.verb'), howto: tr('mp.runner.extract-pages.howto') },
    'organize-pdf': { inputs: 'single', opt: 'order', accepts: 'PDF', runLabel: tr('mp.runner.organize-pdf.runLabel'), workingLabel: tr('mp.runner.organize-pdf.workingLabel'), successTitle: tr('mp.runner.organize-pdf.successTitle'), errorMsg: tr('mp.runner.organize-pdf.errorMsg'), doMore: { slug: 'page-numbers', label: tr('mp.runner.organize-pdf.doMore') }, verb: tr('mp.runner.organize-pdf.verb'), howto: tr('mp.runner.organize-pdf.howto') },
    'rotate-pdf': { inputs: 'single', opt: 'rotate', accepts: 'PDF', runLabel: tr('mp.runner.rotate-pdf.runLabel'), workingLabel: tr('mp.runner.rotate-pdf.workingLabel'), successTitle: tr('mp.runner.rotate-pdf.successTitle'), errorMsg: tr('mp.runner.rotate-pdf.errorMsg'), doMore: { slug: 'page-numbers', label: tr('mp.runner.rotate-pdf.doMore') }, verb: tr('mp.runner.rotate-pdf.verb'), howto: tr('mp.runner.rotate-pdf.howto') },
    'watermark-pdf': { inputs: 'single', opt: 'watermark', accepts: 'PDF', runLabel: tr('mp.runner.watermark-pdf.runLabel'), workingLabel: tr('mp.runner.watermark-pdf.workingLabel'), successTitle: tr('mp.runner.watermark-pdf.successTitle'), errorMsg: tr('mp.runner.watermark-pdf.errorMsg'), doMore: { slug: 'page-numbers', label: tr('mp.runner.watermark-pdf.doMore') }, verb: tr('mp.runner.watermark-pdf.verb'), howto: tr('mp.runner.watermark-pdf.howto') },
    'page-numbers': { inputs: 'single', opt: 'pagenum', accepts: 'PDF', runLabel: tr('mp.runner.page-numbers.runLabel'), workingLabel: tr('mp.runner.page-numbers.workingLabel'), successTitle: tr('mp.runner.page-numbers.successTitle'), errorMsg: tr('mp.runner.page-numbers.errorMsg'), doMore: { slug: 'watermark-pdf', label: tr('mp.runner.page-numbers.doMore') }, verb: tr('mp.runner.page-numbers.verb'), howto: tr('mp.runner.page-numbers.howto') },
    'jpg-to-pdf': { inputs: 'multi', opt: 'images', accepts: 'JPG, PNG', min: 1, runLabel: tr('mp.runner.jpg-to-pdf.runLabel'), workingLabel: tr('mp.runner.jpg-to-pdf.workingLabel'), successTitle: tr('mp.runner.jpg-to-pdf.successTitle'), errorMsg: tr('mp.runner.jpg-to-pdf.errorMsg'), doMore: { slug: 'merge-pdf', label: tr('mp.runner.jpg-to-pdf.doMore') }, verb: tr('mp.runner.jpg-to-pdf.verb'), howto: tr('mp.runner.jpg-to-pdf.howto'), genericNote: tr('mp.runner.jpg-to-pdf.genericNote') },
  };
  const toolMap = () => { const m = {}; CATS.forEach((c) => c.tools.forEach((t) => { m[t.slug] = Object.assign({ category: c.name, categoryKey: c.key }, t); })); return m; };
  const TM = toolMap();
  const RUNNER_TABS = ['merge-pdf', 'split-pdf', 'rotate-pdf', 'watermark-pdf'];
  const POS = ['top-left', 'top-center', 'top-right', 'center-left', 'center', 'center-right', 'bottom-left', 'bottom-center', 'bottom-right'];
  const placeMap = { 'top-left': 'start start', 'top-center': 'start center', 'top-right': 'start end', 'center-left': 'center start', center: 'center center', 'center-right': 'center end', 'bottom-left': 'end start', 'bottom-center': 'end center', 'bottom-right': 'end end' };

  const fileToB64 = (f) => new Promise((res, rej) => { const r = new FileReader(); r.onload = () => res(String(r.result).split(',')[1]); r.onerror = rej; r.readAsDataURL(f); });
  const fmtSize = (n) => (n < 1024 ? n + ' B' : n < 1048576 ? (n / 1024).toFixed(0) + ' KB' : (n / 1048576).toFixed(1) + ' MB');

  // ── shared chrome ──
  function Nav({ go }) {
    return (
      <div style={S('position:sticky;top:0;z-index:40;background:color-mix(in srgb,var(--bg) 82%,transparent);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-bottom:1px solid var(--hairline);')}>
        <div style={S('max-width:1180px;margin:0 auto;padding:0 28px;height:64px;display:flex;align-items:center;gap:26px;')}>
          <div onClick={() => go('landing')} style={S('display:inline-flex;align-items:center;gap:10px;cursor:pointer;')}>
            {Logo(30)}
            <span style={S('font-family:var(--font-display);font-weight:600;font-size:20px;letter-spacing:-0.04em;')}>Mostly<span style={S('color:var(--accent);')}>PDF</span></span>
          </div>
          <nav style={S('display:flex;gap:22px;margin-left:6px;')}>
            <span className="pdf-link" onClick={() => go('landing')} style={S('font-size:13.5px;font-weight:500;color:var(--fg-muted);')}>{tr('mp.nav.allTools')}</span>
            <span className="pdf-link" onClick={() => go('pricing')} style={S('font-size:13.5px;font-weight:500;color:var(--fg-muted);')}>{tr('mp.nav.pricing')}</span>
            <span className="pdf-link" onClick={() => go('compare')} style={S('font-size:13.5px;font-weight:500;color:var(--fg-muted);')}>{tr('mp.nav.compare')}</span>
            <span style={S('font-size:13.5px;font-weight:500;color:var(--fg-subtle);')}>{tr('mp.nav.api')}</span>
          </nav>
          <div style={S('margin-left:auto;display:flex;align-items:center;gap:10px;')}>
            <span style={S('display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border:1px solid var(--border);border-radius:999px;font-size:12.5px;font-weight:500;color:var(--fg-muted);cursor:pointer;')}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><path d="M3 12h18" /><path d="M12 3a15 15 0 0 1 0 18 M12 3a15 15 0 0 0 0 18" /></svg>
              EN
            </span>
            {PUBLIC_APP_OPEN ? (
              <>
                <button className="forge-btn forge-btn--ghost">{tr('mp.nav.signIn')}</button>
                <button className="forge-btn forge-btn--primary">{tr('mp.nav.getStarted')}</button>
              </>
            ) : (
              <span title={tr('mp.nav.betaTitle')} style={S('display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border:1px solid var(--border);border-radius:999px;font-size:12.5px;font-weight:600;color:var(--fg-muted);')}>
                <span style={S('width:7px;height:7px;border-radius:50%;background:var(--accent);')} />
                {tr('mp.nav.inDevelopment')}
              </span>
            )}
          </div>
        </div>
      </div>
    );
  }

  // The ONE shared portfolio footer template (window.ForgeKit.Footer) — same component as every
  // other Mostly Tiny product, so the footer can't drift between products. Legal links go to the
  // canonical /legal/mostlypdf/<kind> path; the Tools/Product/Company links stay in-app placeholders.
  function Footer() {
    const LEGAL = 'https://mostlyprivacy.com/legal/mostlypdf/';
    const brand = (
      <a href="#" onClick={(e) => e.preventDefault()} style={S('display:inline-flex;align-items:center;gap:9px;text-decoration:none;')}>
        {Logo(26)}
        <span style={S('font-family:var(--font-display);font-weight:600;font-size:17px;letter-spacing:-0.04em;color:var(--fg);')}>Mostly<span style={S('color:var(--accent);')}>PDF</span></span>
      </a>
    );
    const columns = [
      { heading: tr('mp.footer.tools'), links: [
        { label: tr('mp.tool.merge-pdf.title'), href: '#' },
        { label: tr('mp.tool.split-pdf.title'), href: '#' },
        { label: tr('mp.tool.compress-pdf.title'), href: '#' },
        { label: tr('mp.tool.pdf-to-word.title'), href: '#' },
      ] },
      { heading: tr('mp.footer.product'), links: [
        { label: tr('mp.nav.pricing'), href: '#/pricing' },
        { label: tr('mp.footer.apiDocs'), href: '/docs' },
        { label: tr('mp.footer.apiKeys'), href: '#/keys' }, // subtle, team-only entry while in private beta
        { label: tr('mp.nav.compare'), href: '#/compare' },
      ] },
      { heading: tr('mp.footer.company'), links: [
        { label: tr('mp.footer.about'), href: '#' },
        { label: tr('mp.footer.support'), href: '#' },
      ] },
      { heading: tr('mp.footer.legal'), links: [
        { label: tr('mp.footer.terms'), href: LEGAL + 'terms' },
        { label: tr('mp.footer.privacy'), href: LEGAL + 'privacy' },
        { label: tr('mp.footer.cookies'), href: LEGAL + 'cookie' },
      ] },
    ];
    return (
      <window.ForgeKit.Footer
        brand={brand}
        tagline={tr('mp.footer.tagline')}
        columns={columns}
        version="MostlyPDF · v1.0"
      />
    );
  }

  const check = (stroke, w) => <svg width={w || 15} height={w || 15} viewBox="0 0 24 24" fill="none" stroke={stroke} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>;

  // ── LANDING ──
  function Landing({ go, open }) {
    const trust = [tr('mp.landing.trust.free'), tr('mp.landing.trust.noSignup'), tr('mp.landing.trust.noWatermark'), tr('mp.landing.trust.noLimit'), tr('mp.landing.trust.noAds')];
    const why = [
      { icon: 'zap', title: tr('mp.landing.why.free.title'), body: tr('mp.landing.why.free.body') },
      { icon: 'fileText', title: tr('mp.landing.why.convert.title'), body: tr('mp.landing.why.convert.body') },
      { icon: 'code', title: tr('mp.landing.why.api.title'), body: tr('mp.landing.why.api.body') },
    ];
    // Fuzzy tool search: as the visitor types, match across title/answer/slug and show a
    // ranked result grid in place of the category sections (empty query = browse by category).
    const [q, setQ] = useState('');
    const query = q.trim();
    const allTools = CATS.flatMap((c) => c.tools);
    const results = query
      ? allTools
          .map((tool) => ({
            tool,
            s: Math.max(
              fuzzyScore(query, tool.title),
              fuzzyScore(query, tool.answer),
              fuzzyScore(query, tool.slug.replace(/-/g, ' ')),
            ),
          }))
          .filter((x) => x.s > 0)
          .sort((a, b) => b.s - a.s)
          .map((x) => x.tool)
      : null;
    const ToolCard = (tool) => (
      <div key={tool.slug} onClick={() => open(tool.slug)} className="forge-card forge-card--interactive" style={S('padding:18px;cursor:pointer;display:flex;flex-direction:column;')}>
        <div style={S('display:flex;align-items:flex-start;justify-content:space-between;gap:10px;')}>
          <span style={S('display:inline-grid;place-items:center;width:42px;height:42px;border-radius:12px;background:var(--accent-bg-soft);color:var(--accent);')}>{ic(tool.icon, 22)}</span>
          <div style={S('display:flex;gap:6px;')}>
            {tool.pro && <span className="forge-badge forge-badge--accent">{tr('mp.badge.pro')}</span>}
            {tool.soon && <span className="forge-badge">{tr('mp.badge.soon')}</span>}
          </div>
        </div>
        <div style={S('margin-top:14px;font-size:15px;font-weight:600;letter-spacing:-0.012em;')}>{tool.title}</div>
        <div style={S('margin-top:5px;font-size:13px;line-height:1.5;color:var(--fg-muted);text-wrap:pretty;')}>{tool.answer}</div>
      </div>
    );
    return (
      <div>
        <section style={S('max-width:1180px;margin:0 auto;padding:60px 28px 8px;text-align:center;')}>
          <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.landing.eyebrow')}</span>
          <h1 style={S('font-family:var(--font-display);font-weight:600;font-size:56px;line-height:1.03;letter-spacing:-0.045em;margin:14px auto 0;max-width:16em;text-wrap:balance;')}>{tr('mp.landing.title')}</h1>
          <p style={S('font-size:17px;line-height:1.55;color:var(--fg-muted);max-width:34em;margin:18px auto 0;text-wrap:pretty;')}>{tr('mp.landing.subtitle')}</p>
          <div style={S('display:flex;justify-content:center;flex-wrap:wrap;gap:10px 22px;margin-top:24px;')}>
            {trust.map((t) => <span key={t} style={S('display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:500;color:var(--fg-muted);')}>{check('var(--good)')}{t}</span>)}
          </div>
          <div style={S('max-width:520px;margin:30px auto 0;position:relative;')}>
            <span style={S('position:absolute;left:16px;top:50%;transform:translateY(-50%);color:var(--fg-subtle);display:grid;place-items:center;')}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8" /><path d="M21 21l-4.3-4.3" /></svg>
            </span>
            <input value={q} onChange={(ev) => setQ(ev.target.value)} placeholder={tr('mp.landing.searchPlaceholder')} style={S('width:100%;height:52px;padding:0 18px 0 46px;font-family:var(--font-sans);font-size:15px;background:var(--bg-elev);color:var(--fg);border:1px solid var(--border);border-radius:999px;box-shadow:var(--shadow-soft);outline:none;')} />
          </div>
        </section>

        <section style={S('max-width:1180px;margin:0 auto;padding:18px 28px 8px;')}>
          {results ? (
            results.length ? (
              <div style={S('margin-top:24px;')}>
                <div style={S('font-size:13px;color:var(--fg-subtle);margin-bottom:16px;')}>{tr('mp.landing.resultsCount', { count: results.length, query })}</div>
                <div style={S('display:grid;grid-template-columns:repeat(auto-fill,minmax(252px,1fr));gap:14px;')}>
                  {results.map((tool) => ToolCard(tool))}
                </div>
              </div>
            ) : (
              <div style={S('text-align:center;padding:56px 0;color:var(--fg-muted);')}>
                <div style={S('font-size:15px;font-weight:600;color:var(--fg);')}>{tr('mp.landing.noResults', { query })}</div>
                <p style={S('font-size:13.5px;margin:8px 0 0;')}>{tr('mp.landing.noResultsHint')}</p>
              </div>
            )
          ) : (
            CATS.map((cat) => (
              <div key={cat.key} style={S('margin-top:40px;')}>
                <div style={S('display:flex;align-items:baseline;gap:12px;margin-bottom:16px;')}>
                  <h2 style={S('font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:-0.022em;margin:0;')}>{cat.name}</h2>
                  <span style={S('font-size:13px;color:var(--fg-subtle);')}>{cat.note}</span>
                </div>
                <div style={S('display:grid;grid-template-columns:repeat(auto-fill,minmax(252px,1fr));gap:14px;')}>
                  {cat.tools.map((tool) => ToolCard(tool))}
                </div>
              </div>
            ))
          )}
        </section>

        <section style={S('max-width:1180px;margin:0 auto;padding:64px 28px 8px;')}>
          <div style={S('text-align:center;margin-bottom:36px;')}>
            <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.landing.whyEyebrow')}</span>
            <h2 style={S('font-family:var(--font-display);font-size:34px;font-weight:600;letter-spacing:-0.03em;margin:10px 0 0;text-wrap:balance;')}>{tr('mp.landing.whyTitle')}</h2>
          </div>
          <div style={S('display:grid;grid-template-columns:repeat(3,1fr);gap:16px;')}>
            {why.map((w) => (
              <div key={w.title} className="forge-card" style={S('padding:24px;')}>
                <span style={S('display:inline-grid;place-items:center;width:44px;height:44px;border-radius:12px;background:var(--accent-bg-soft);color:var(--accent);margin-bottom:14px;')}>{ic(w.icon, 22)}</span>
                <div style={S('font-family:var(--font-display);font-size:17px;font-weight:600;letter-spacing:-0.018em;')}>{w.title}</div>
                <p style={S('font-size:13.5px;line-height:1.56;color:var(--fg-muted);margin:8px 0 0;text-wrap:pretty;')}>{w.body}</p>
              </div>
            ))}
          </div>
        </section>

        <section style={S('max-width:1180px;margin:0 auto;padding:48px 28px 8px;')}>
          <div style={S('display:flex;align-items:center;justify-content:space-between;gap:28px;flex-wrap:wrap;padding:30px 36px;border-radius:var(--radius-xl);background:var(--brand-midnight);color:#fff;')}>
            <div>
              <div style={S('font-family:var(--font-display);font-size:24px;font-weight:600;letter-spacing:-0.025em;')}>{tr('mp.landing.ctaTitle')}</div>
              <p style={S('font-size:14px;color:rgba(255,255,255,0.62);margin:8px 0 0;max-width:40em;')}>{tr('mp.landing.ctaBody')}</p>
            </div>
            <button onClick={() => go('pricing')} className="forge-btn forge-btn--primary forge-btn--lg">{tr('mp.landing.ctaButton')}</button>
          </div>
        </section>
      </div>
    );
  }

  // ── RUNNER (wired to pdfProcess) ──
  function Runner({ slug, go, open }) {
    const tool = TM[slug] || {};
    const meta = META[slug] || { inputs: 'single', opt: 'generic', accepts: 'PDF', runLabel: tr('mp.runner.default.runLabel', { tool: tool.title || '' }), workingLabel: tr('mp.runner.default.workingLabel'), successTitle: tr('mp.runner.default.successTitle'), errorMsg: tr('mp.runner.default.errorMsg'), doMore: { slug: 'merge-pdf', label: tr('mp.runner.default.doMore') }, verb: (tool.title || '').toLowerCase(), howto: tr('mp.runner.default.howto'), genericNote: tr('mp.runner.default.genericNote') };
    const multi = meta.inputs === 'multi';
    const minFiles = meta.min || 1;

    const [files, setFiles] = useState([]);
    const [phase, setPhase] = useState('idle'); // idle | files | working | success | error
    const [dragOn, setDragOn] = useState(false);
    const [errMsg, setErrMsg] = useState(meta.errorMsg);
    const [result, setResult] = useState(null);
    const [faqOpen, setFaqOpen] = useState(0);
    const inputRef = useRef(null);
    // options
    const [rotation, setRotation] = useState(90);
    const [wmText, setWmText] = useState('CONFIDENTIAL');
    const [wmOpacity, setWmOpacity] = useState(0.18);
    const [wmPos, setWmPos] = useState('center');
    const [pnPos, setPnPos] = useState('bottom-center');
    const [pnStart, setPnStart] = useState(1);
    const [splitMode, setSplitMode] = useState('ranges');
    const [splitRanges, setSplitRanges] = useState('1-3, 5, 8-12');
    const [splitEvery, setSplitEvery] = useState(2);
    const [pagesVal, setPagesVal] = useState('');
    const [orderVal, setOrderVal] = useState('');

    useEffect(() => { setFiles([]); setPhase('idle'); setResult(null); setErrMsg(meta.errorMsg); }, [slug]);

    function addFiles(list) {
      const arr = Array.prototype.slice.call(list || []);
      if (!arr.length) return;
      setFiles((prev) => (multi ? prev.concat(arr) : arr.slice(0, 1)));
      setPhase('files');
    }
    function removeAt(i) { setFiles((prev) => { const n = prev.filter((_, j) => j !== i); if (!n.length) setPhase('idle'); return n; }); }

    function collectOptions() {
      switch (meta.opt) {
        case 'split': return splitMode === 'ranges' ? { ranges: splitRanges.split(',').map((s) => s.trim()).filter(Boolean) } : splitMode === 'every' ? { everyN: Number(splitEvery) } : {};
        case 'rotate': return { degrees: rotation };
        case 'watermark': return { text: wmText, opacity: Number(wmOpacity) };
        case 'pagenum': return { position: pnPos, start: Number(pnStart) };
        case 'pages': return { pages: pagesVal };
        case 'order': return { order: orderVal.split(',').map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n)) };
        case 'images': return {};
        default: return {};
      }
    }

    async function run() {
      if (files.length < minFiles) { setErrMsg(meta.errorMsg); setPhase('error'); return; }
      setPhase('working');
      try {
        const b64 = await Promise.all(files.map(fileToB64));
        const res = await fetch(CFG.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tool: slug, options: collectOptions(), files: b64 }) });
        const j = await res.json().catch(() => ({}));
        if (!res.ok) throw new Error(j.error || 'Processing failed');
        const dls = j.outputs.map((b, i) => { const bin = atob(b); const u = new Uint8Array(bin.length); for (let k = 0; k < bin.length; k++) u[k] = bin.charCodeAt(k); const url = URL.createObjectURL(new Blob([u], { type: j.contentType || 'application/pdf' })); return { name: (j.filenames && j.filenames[i]) || (slug + '.pdf'), size: fmtSize(u.length), url }; });
        setResult({ downloads: dls });
        setPhase('success');
      } catch (err) {
        setErrMsg(err.message + (/Failed to fetch|NetworkError/i.test(err.message) ? tr('mp.runner.networkHint') : ''));
        setPhase('error');
      }
    }

    const accentChip = 'display:inline-flex;align-items:center;gap:5px;height:30px;padding:0 13px;border-radius:999px;font-size:12.5px;font-weight:600;border:1px solid transparent;cursor:pointer;';
    const onChip = accentChip + 'background:var(--accent-bg-soft);color:var(--accent);';
    const offChip = accentChip + 'background:var(--bg-chip);color:var(--fg-muted);';
    const dropStyle = 'display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;border-radius:var(--radius-xl);border:2px dashed ' + (dragOn ? 'var(--accent)' : 'var(--border-strong)') + ';background:' + (dragOn ? 'var(--accent-bg-soft)' : 'var(--bg-elev)') + ';cursor:pointer;transition:border-color .15s,background .15s,transform .15s;transform:' + (dragOn ? 'scale(1.01)' : 'none') + ';';
    const cellBase = 'height:26px;border-radius:6px;border:1px solid var(--border);background:var(--bg);cursor:pointer;';
    const cellOn = 'height:26px;border-radius:6px;border:1px solid var(--accent);background:var(--accent-bg-soft);cursor:pointer;';

    const faqList = [
      { q: tr('mp.runner.faq.free.q', { tool: tool.title }), a: tr('mp.runner.faq.free.a', { tool: tool.title }) },
      { q: tr('mp.runner.faq.how.q', { verb: meta.verb }), a: tr('mp.runner.faq.how.a', { howto: meta.howto, runLabel: meta.runLabel }) },
      { q: tr('mp.runner.faq.safe.q'), a: tr('mp.runner.faq.safe.a') },
    ];

    const twoCol = phase === 'idle' || phase === 'files' || phase === 'error';
    const showDrop = phase === 'idle' || phase === 'error';

    return (
      <div style={S('max-width:1100px;margin:0 auto;padding:26px 28px 8px;')}>
        <div onClick={() => go('landing')} style={S('display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--fg-muted);cursor:pointer;margin-bottom:18px;')}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5" /><path d="M12 19l-7-7 7-7" /></svg>
          {tr('mp.nav.allTools')} <span style={S('color:var(--fg-subtle);')}>/</span> <span style={S('color:var(--fg);font-weight:500;')}>{tool.category}</span>
        </div>

        <div style={S('display:flex;align-items:flex-start;gap:16px;')}>
          <span style={S('display:inline-grid;place-items:center;width:54px;height:54px;border-radius:15px;background:var(--accent-bg-soft);color:var(--accent);flex:none;')}>{ic(tool.icon, 26)}</span>
          <div>
            <div style={S('display:flex;align-items:center;gap:10px;')}>
              <h1 style={S('font-family:var(--font-display);font-size:30px;font-weight:600;letter-spacing:-0.03em;margin:0;')}>{tool.title}</h1>
              {tool.pro && <span className="forge-badge forge-badge--accent">{tr('mp.badge.pro')}</span>}
              {tool.soon && <span className="forge-badge">{tr('mp.badge.soon')}</span>}
            </div>
            <p style={S('font-size:15px;line-height:1.5;color:var(--fg-muted);margin:7px 0 0;max-width:42em;text-wrap:pretty;')}>{tool.answer}</p>
          </div>
        </div>

        <div style={S('display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:22px;padding-bottom:18px;border-bottom:1px solid var(--hairline);')}>
          <span style={S('font-size:12px;font-weight:600;color:var(--fg-subtle);text-transform:uppercase;letter-spacing:0.05em;margin-right:2px;')}>{tr('mp.runner.toolLabel')}</span>
          {RUNNER_TABS.map((rt) => <button key={rt} onClick={() => open(rt)} style={S(rt === slug ? onChip : offChip)}>{TM[rt].title}</button>)}
        </div>

        {tool.soon && (
          <div style={S('display:flex;align-items:center;gap:12px;margin-top:22px;padding:16px 20px;border-radius:var(--radius);background:var(--warn-soft);border:1px solid color-mix(in srgb,var(--warn) 28%,transparent);')}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--warn)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></svg>
            <div style={S('font-size:13.5px;color:var(--fg);')}><strong style={S('font-weight:600;')}>{tr('mp.runner.soonBannerLead')}</strong> {tr('mp.runner.soonBannerBody')}</div>
          </div>
        )}

        {phase === 'working' && (
          <div className="forge-card" style={S('margin-top:26px;padding:44px;text-align:center;max-width:560px;margin-left:auto;margin-right:auto;')}>
            <div style={S('font-family:var(--font-display);font-size:19px;font-weight:600;letter-spacing:-0.02em;')}>{meta.workingLabel}</div>
            <div style={S('height:8px;border-radius:999px;background:var(--bg-chip);overflow:hidden;margin:22px 0 12px;')}>
              <div style={S('height:100%;border-radius:999px;background:var(--accent-grad);animation:pdf-bar 1.4s var(--ease-out) forwards;')}></div>
            </div>
            <div style={S('font-size:12.5px;color:var(--fg-subtle);')}>{tr('mp.runner.processing')}</div>
          </div>
        )}

        {phase === 'success' && result && (
          <div className="forge-card" style={S('margin-top:26px;padding:36px;max-width:620px;margin-left:auto;margin-right:auto;animation:pdf-rise .3s var(--ease-out);')}>
            <div style={S('display:flex;flex-direction:column;align-items:center;text-align:center;')}>
              <span style={S('display:grid;place-items:center;width:56px;height:56px;border-radius:50%;background:var(--good-soft);color:var(--good);animation:pdf-pop .32s var(--ease-spring);')}>{check('currentColor', 28)}</span>
              <div style={S('font-family:var(--font-display);font-size:22px;font-weight:600;letter-spacing:-0.02em;margin-top:14px;')}>{meta.successTitle}</div>
              <div style={S('font-size:13.5px;color:var(--fg-muted);margin-top:5px;')}>{tr('mp.runner.filesReady', { count: result.downloads.length })}</div>
            </div>
            <div style={S('display:flex;flex-direction:column;gap:10px;margin-top:24px;')}>
              {result.downloads.map((dl, i) => (
                <div key={i} style={S('display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:var(--radius);border:1px solid var(--border);background:var(--bg);')}>
                  <span style={S('display:inline-grid;place-items:center;width:34px;height:34px;border-radius:8px;background:var(--accent-bg-soft);color:var(--accent);flex:none;')}>
                    <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" /><path d="M14 2v7h7" /></svg>
                  </span>
                  <div style={S('flex:1;min-width:0;')}>
                    <div style={S('font-size:13.5px;font-weight:600;')}>{dl.name}</div>
                    <div style={S('font-size:11.5px;color:var(--fg-subtle);')}>{dl.size}</div>
                  </div>
                  <a href={dl.url} download={dl.name} className="forge-btn forge-btn--primary forge-btn--sm">
                    <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="M7 10l5 5 5-5" /><path d="M12 15V3" /></svg>
                    <span>{tr('mp.runner.download')}</span>
                  </a>
                </div>
              ))}
            </div>
            <div style={S('display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:20px;padding-top:18px;border-top:1px solid var(--hairline);')}>
              <button onClick={() => open(meta.doMore.slug)} style={S('display:inline-flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--accent);background:none;border:none;cursor:pointer;')}>
                {meta.doMore.label}
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14" /><path d="M12 5l7 7-7 7" /></svg>
              </button>
              <button onClick={() => { setFiles([]); setResult(null); setPhase('idle'); }} className="forge-btn forge-btn--secondary forge-btn--sm">{tr('mp.runner.startOver')}</button>
            </div>
          </div>
        )}

        {twoCol && (
          <div style={S('display:grid;grid-template-columns:1.45fr 1fr;gap:20px;margin-top:24px;align-items:start;')}>
            <div>
              {showDrop ? (
                <div>
                  <div onClick={() => inputRef.current && inputRef.current.click()}
                    onDragOver={(ev) => { ev.preventDefault(); setDragOn(true); }}
                    onDragLeave={() => setDragOn(false)}
                    onDrop={(ev) => { ev.preventDefault(); setDragOn(false); addFiles(ev.dataTransfer.files); }}
                    style={S(dropStyle)}>
                    <span style={S('display:grid;place-items:center;width:60px;height:60px;border-radius:16px;background:var(--accent-bg-soft);color:var(--accent);margin-bottom:16px;')}>
                      <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="M17 8l-5-5-5 5" /><path d="M12 3v12" /></svg>
                    </span>
                    <div style={S('font-family:var(--font-display);font-size:18px;font-weight:600;letter-spacing:-0.018em;')}>{dragOn ? tr('mp.runner.dropActive') : tr('mp.runner.dropIdle')}</div>
                    <div style={S('font-size:13.5px;color:var(--fg-muted);margin-top:5px;')}>{tr('mp.runner.orBrowsePre')}<span style={S('color:var(--accent);font-weight:600;')}>{tr('mp.runner.browseFiles')}</span></div>
                    <div style={S('font-size:12px;color:var(--fg-subtle);margin-top:14px;')}>{tr('mp.runner.acceptsLimit', { accepts: meta.accepts })}</div>
                  </div>
                  {phase === 'error' && (
                    <div style={S('display:flex;align-items:center;gap:10px;margin-top:12px;padding:12px 15px;border-radius:var(--radius);background:var(--bad-soft);border:1px solid color-mix(in srgb,var(--bad) 24%,transparent);')}>
                      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--bad)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9" /><path d="M12 8v5" /><path d="M12 16h.01" /></svg>
                      <div style={S('font-size:13px;color:var(--bad);font-weight:500;')}>{errMsg}</div>
                    </div>
                  )}
                </div>
              ) : (
                <div>
                  <div className="forge-card" style={S('padding:8px;')}>
                    <div style={S('display:flex;align-items:center;justify-content:space-between;padding:10px 12px 8px;')}>
                      <span style={S('font-size:12px;font-weight:600;color:var(--fg-subtle);text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;')}>{tr('mp.runner.fileCount', { count: files.length })}</span>
                    </div>
                    <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                      {files.map((f, i) => (
                        <div key={i} style={S('display:flex;align-items:center;gap:11px;padding:9px 10px;border-radius:var(--radius);background:var(--bg);')}>
                          <span style={S('display:inline-grid;place-items:center;width:36px;height:44px;border-radius:6px;background:#fff;border:1px solid var(--border);font-size:8px;font-weight:700;letter-spacing:0.02em;color:var(--accent);flex:none;')}>{(f.name.split('.').pop() || 'PDF').toUpperCase().slice(0, 4)}</span>
                          <div style={S('flex:1;min-width:0;')}>
                            <div style={S('font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;')}>{f.name}</div>
                            <div style={S('font-size:11.5px;color:var(--fg-subtle);')}>{fmtSize(f.size)}</div>
                          </div>
                          <button onClick={() => removeAt(i)} className="forge-iconbtn forge-iconbtn--sm" aria-label={tr('mp.runner.remove')}>
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18" /><path d="M6 6l12 12" /></svg>
                          </button>
                        </div>
                      ))}
                    </div>
                    {multi && (
                      <button onClick={() => inputRef.current && inputRef.current.click()} style={S('display:flex;align-items:center;justify-content:center;gap:8px;width:100%;margin-top:6px;padding:11px;border-radius:var(--radius);border:1px dashed var(--border-strong);background:transparent;color:var(--fg-muted);font-size:13px;font-weight:500;cursor:pointer;')}>
                        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14" /><path d="M5 12h14" /></svg>
                        {tr('mp.runner.addMore')}
                      </button>
                    )}
                  </div>
                  <div style={S('display:flex;align-items:center;gap:8px;margin-top:12px;font-size:12px;color:var(--fg-subtle);')}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /></svg>
                    {tr('mp.runner.encryptionNote')}
                  </div>
                </div>
              )}
            </div>

            <div className="forge-card" style={S('padding:20px;position:sticky;top:84px;')}>
              <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-0.016em;margin-bottom:16px;')}>{tr('mp.opt.options')}</div>

              {meta.opt === 'merge' && <p style={S('font-size:13px;line-height:1.55;color:var(--fg-muted);margin:0 0 4px;')}>{tr('mp.opt.mergeNote')}</p>}

              {meta.opt === 'split' && (
                <div>
                  <div style={S('display:flex;flex-direction:column;gap:6px;margin-bottom:14px;')}>
                    <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.splitMode')}</span>
                    <div className="forge-select-wrap">
                      <select value={splitMode} onChange={(ev) => setSplitMode(ev.target.value)} className="forge-select">
                        <option value="ranges">{tr('mp.opt.splitRangesOpt')}</option>
                        <option value="each">{tr('mp.opt.splitEachOpt')}</option>
                        <option value="every">{tr('mp.opt.splitEveryOpt')}</option>
                      </select>
                      <span className="forge-select-wrap__chev"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6" /></svg></span>
                    </div>
                  </div>
                  {splitMode === 'ranges' && (
                    <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                      <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.pageRanges')}</span>
                      <input value={splitRanges} onChange={(ev) => setSplitRanges(ev.target.value)} className="forge-input" placeholder="1-3, 5, 8-12" />
                      <span style={S('font-size:11.5px;color:var(--fg-subtle);')}>{tr('mp.opt.separateRanges')}</span>
                    </div>
                  )}
                  {splitMode === 'every' && (
                    <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                      <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.pagesPerFile')}</span>
                      <input value={splitEvery} onChange={(ev) => setSplitEvery(ev.target.value)} type="number" className="forge-input" />
                    </div>
                  )}
                </div>
              )}

              {meta.opt === 'pages' && (
                <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                  <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{meta.pagesLabel}</span>
                  <input value={pagesVal} onChange={(ev) => setPagesVal(ev.target.value)} className="forge-input" placeholder={meta.placeholder} />
                  <span style={S('font-size:11.5px;color:var(--fg-subtle);')}>{tr('mp.opt.pagesHint', { example: meta.placeholder })}</span>
                </div>
              )}

              {meta.opt === 'order' && (
                <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                  <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.newOrder')}</span>
                  <input value={orderVal} onChange={(ev) => setOrderVal(ev.target.value)} className="forge-input" placeholder="3, 1, 2, 4" />
                  <span style={S('font-size:11.5px;color:var(--fg-subtle);')}>{tr('mp.opt.newOrderHint')}</span>
                </div>
              )}

              {meta.opt === 'rotate' && (
                <div>
                  <div style={S('display:flex;flex-direction:column;gap:8px;margin-bottom:16px;')}>
                    <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.rotation')}</span>
                    <div style={S('display:flex;gap:8px;')}>
                      {[90, 180, 270].map((a) => <button key={a} onClick={() => setRotation(a)} style={S((a === rotation ? onChip : offChip) + 'min-width:54px;justify-content:center;')}>{a}°</button>)}
                    </div>
                  </div>
                  <div style={S('display:flex;flex-direction:column;align-items:center;gap:8px;padding:18px;border-radius:var(--radius);background:var(--bg);border:1px solid var(--hairline);')}>
                    <div style={S('width:66px;height:84px;background:#fff;border:1px solid var(--border);border-radius:4px;box-shadow:var(--shadow-xs);transition:transform .25s var(--ease-out);transform:rotate(' + rotation + 'deg);')}>
                      <div style={S('font-size:8px;color:var(--fg-subtle);line-height:1.6;padding:8px;')}>
                        <div style={S('width:60%;height:3px;background:var(--fg-subtle);opacity:.4;border-radius:2px;margin-bottom:4px;')}></div>
                        <div style={S('width:90%;height:3px;background:var(--fg-subtle);opacity:.25;border-radius:2px;margin-bottom:3px;')}></div>
                        <div style={S('width:80%;height:3px;background:var(--fg-subtle);opacity:.25;border-radius:2px;')}></div>
                      </div>
                    </div>
                    <span style={S('font-size:11.5px;color:var(--fg-subtle);')}>{tr('mp.opt.rotatePreview', { deg: rotation })}</span>
                  </div>
                </div>
              )}

              {meta.opt === 'watermark' && (
                <div>
                  <div style={S('display:flex;flex-direction:column;gap:6px;margin-bottom:14px;')}>
                    <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.watermarkText')}</span>
                    <input value={wmText} onChange={(ev) => setWmText(ev.target.value)} className="forge-input" />
                  </div>
                  <div style={S('display:flex;flex-direction:column;gap:6px;margin-bottom:14px;')}>
                    <div style={S('display:flex;justify-content:space-between;')}><span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.opacity')}</span><span style={S('font-size:12px;color:var(--fg-muted);font-variant-numeric:tabular-nums;')}>{Math.round(wmOpacity * 100)}%</span></div>
                    <input type="range" min="0" max="100" value={Math.round(wmOpacity * 100)} onChange={(ev) => setWmOpacity(ev.target.value / 100)} style={S('width:100%;accent-color:var(--accent);')} />
                  </div>
                  <div style={S('position:relative;display:grid;place-items:' + placeMap[wmPos] + ';padding:14px;border-radius:var(--radius);background:#fff;border:1px solid var(--hairline);min-height:104px;overflow:hidden;')}>
                    <span style={S('font-family:var(--font-display);font-weight:700;font-size:20px;letter-spacing:0.04em;color:var(--accent);transform:rotate(-24deg);opacity:' + wmOpacity + ';white-space:nowrap;')}>{wmText}</span>
                  </div>
                </div>
              )}

              {meta.opt === 'pagenum' && (
                <div>
                  <div style={S('display:flex;flex-direction:column;gap:6px;margin-bottom:14px;')}>
                    <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.position')}</span>
                    <div style={S('display:grid;grid-template-columns:repeat(3,1fr);gap:5px;width:108px;')}>
                      {POS.map((k) => <button key={k} onClick={() => setPnPos(k)} style={S(k === pnPos ? cellOn : cellBase)} aria-label={k}></button>)}
                    </div>
                  </div>
                  <div style={S('display:flex;flex-direction:column;gap:6px;')}>
                    <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.opt.startAt')}</span>
                    <input value={pnStart} onChange={(ev) => setPnStart(ev.target.value)} type="number" className="forge-input" />
                  </div>
                </div>
              )}

              {(meta.opt === 'images' || meta.opt === 'generic') && <p style={S('font-size:13px;line-height:1.55;color:var(--fg-muted);margin:0;')}>{meta.genericNote || tr('mp.runner.default.genericNote')}</p>}

              <div style={S('margin-top:18px;padding-top:16px;border-top:1px solid var(--hairline);')}>
                <button onClick={run} disabled={tool.soon || files.length < minFiles} className="forge-btn forge-btn--primary forge-btn--lg forge-btn--block"><span>{meta.runLabel}</span></button>
              </div>
            </div>
          </div>
        )}

        <input ref={inputRef} type="file" accept={slug === 'jpg-to-pdf' ? 'image/jpeg,image/png' : 'application/pdf'} multiple={multi} onChange={(ev) => addFiles(ev.target.files)} />

        <section style={S('max-width:760px;margin:56px auto 0;')}>
          <div style={S('text-align:center;margin-bottom:24px;')}>
            <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.runner.goodToKnow')}</span>
            <h2 style={S('font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-0.028em;margin:8px 0 0;')}>{tr('mp.runner.questionsHeading', { tool: tool.title })}</h2>
          </div>
          <div style={S('display:flex;flex-direction:column;gap:10px;')}>
            {faqList.map((f, i) => (
              <div key={i} className="forge-card" style={S('padding:0;overflow:hidden;')}>
                <button onClick={() => setFaqOpen(faqOpen === i ? -1 : i)} style={S('display:flex;align-items:center;justify-content:space-between;gap:14px;width:100%;padding:16px 20px;background:none;border:none;cursor:pointer;text-align:left;')}>
                  <span style={S('font-size:14.5px;font-weight:600;letter-spacing:-0.01em;')}>{f.q}</span>
                  <span style={S('display:grid;place-items:center;color:var(--fg-subtle);transition:transform .18s;flex:none;transform:rotate(' + (faqOpen === i ? '180deg' : '0deg') + ');')}><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6" /></svg></span>
                </button>
                {faqOpen === i && <p style={S('font-size:13.5px;line-height:1.6;color:var(--fg-muted);margin:0;padding:0 20px 18px;text-wrap:pretty;')}>{f.a}</p>}
              </div>
            ))}
          </div>
        </section>
      </div>
    );
  }

  // ── PRICING ──
  function Pricing() {
    const [annual, setAnnual] = useState(true);
    const seg = 'border:none;background:transparent;padding:8px 18px;border-radius:999px;font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--fg-muted);cursor:pointer;';
    const segSel = 'background:var(--bg-elev);padding:8px 18px;border:none;border-radius:999px;font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--fg);box-shadow:var(--shadow-xs);cursor:pointer;';
    const planCard = 'position:relative;background:var(--bg-elev);border:1px solid var(--border);border-radius:var(--radius-card);box-shadow:var(--shadow-soft);padding:26px;display:flex;flex-direction:column;';
    const planCardFeat = 'position:relative;background:var(--bg-elev);border:1px solid color-mix(in srgb,var(--accent) 40%,transparent);border-radius:var(--radius-card);box-shadow:0 1px 3px rgba(10,10,26,.04),0 18px 44px color-mix(in srgb,var(--accent) 16%,transparent);padding:26px;display:flex;flex-direction:column;';
    const ctaPrimary = 'margin-top:18px;height:42px;border:1px solid transparent;border-radius:999px;background:var(--accent);color:var(--accent-fg);font-family:var(--font-sans);font-size:14px;font-weight:600;cursor:pointer;box-shadow:0 1px 4px color-mix(in srgb,var(--accent) 28%,transparent);';
    const ctaSecondary = 'margin-top:18px;height:42px;border:1px solid var(--border-strong);border-radius:999px;background:var(--bg-elev);color:var(--fg);font-family:var(--font-sans);font-size:14px;font-weight:500;cursor:pointer;';
    const plans = [
      { name: tr('mp.pricing.free.name'), amt: '$0', per: tr('mp.pricing.free.per'), desc: tr('mp.pricing.free.desc'), cta: tr('mp.pricing.free.cta'), feat: false, feats: [tr('mp.pricing.free.feat.0'), tr('mp.pricing.free.feat.1'), tr('mp.pricing.free.feat.2'), tr('mp.pricing.free.feat.3'), tr('mp.pricing.free.feat.4'), tr('mp.pricing.free.feat.5')] },
      { name: tr('mp.pricing.pro.name'), amt: annual ? '$36' : '$5', per: annual ? tr('mp.pricing.perYear') : tr('mp.pricing.perMonth'), desc: tr('mp.pricing.pro.desc'), cta: tr('mp.pricing.pro.cta'), feat: true, feats: [tr('mp.pricing.pro.feat.0'), tr('mp.pricing.pro.feat.1'), tr('mp.pricing.pro.feat.2'), tr('mp.pricing.pro.feat.3'), tr('mp.pricing.pro.feat.4'), tr('mp.pricing.pro.feat.5')] },
      { name: tr('mp.pricing.business.name'), amt: '$4', per: tr('mp.pricing.perUserMonth'), desc: tr('mp.pricing.business.desc'), cta: tr('mp.pricing.business.cta'), feat: false, feats: [tr('mp.pricing.business.feat.0'), tr('mp.pricing.business.feat.1'), tr('mp.pricing.business.feat.2'), tr('mp.pricing.business.feat.3'), tr('mp.pricing.business.feat.4')] },
      { name: tr('mp.pricing.api.name'), amt: tr('mp.pricing.api.amt'), per: tr('mp.pricing.api.per'), desc: tr('mp.pricing.api.desc'), cta: tr('mp.pricing.api.cta'), feat: false, feats: [tr('mp.pricing.api.feat.0'), tr('mp.pricing.api.feat.1'), tr('mp.pricing.api.feat.2'), tr('mp.pricing.api.feat.3'), tr('mp.pricing.api.feat.4')] },
    ];
    const entFeats = [tr('mp.pricing.ent.feat.0'), tr('mp.pricing.ent.feat.1'), tr('mp.pricing.ent.feat.2'), tr('mp.pricing.ent.feat.3')];
    const noTricks = [tr('mp.pricing.noTricks.0'), tr('mp.pricing.noTricks.1'), tr('mp.pricing.noTricks.2')];
    return (
      <div style={S('max-width:1180px;margin:0 auto;padding:48px 28px 8px;')}>
        <div style={S('text-align:center;')}>
          <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.nav.pricing')}</span>
          <h1 style={S('font-family:var(--font-display);font-size:42px;font-weight:600;letter-spacing:-0.038em;margin:12px 0 0;text-wrap:balance;')}>{tr('mp.pricing.title')}</h1>
          <p style={S('font-size:16px;line-height:1.55;color:var(--fg-muted);max-width:34em;margin:14px auto 0;')}>{tr('mp.pricing.subtitle')}</p>
          <div style={S('display:inline-flex;align-items:center;gap:4px;padding:4px;border-radius:999px;background:var(--bg-chip);margin-top:24px;')}>
            <button onClick={() => setAnnual(false)} style={S(annual ? seg : segSel)}>{tr('mp.pricing.monthly')}</button>
            <button onClick={() => setAnnual(true)} style={S(annual ? segSel : seg)}>{tr('mp.pricing.annual')} <span style={S('color:var(--good);font-weight:600;')}>−40%</span></button>
          </div>
        </div>
        <div style={S('display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:40px;align-items:start;')}>
          {plans.map((p) => (
            <div key={p.name} style={S(p.feat ? planCardFeat : planCard)}>
              {p.feat && <span style={S('position:absolute;top:-11px;left:28px;padding:4px 11px;border-radius:999px;background:var(--accent);color:var(--accent-fg);font-size:10.5px;font-weight:700;letter-spacing:0.04em;text-transform:uppercase;')}>{tr('mp.pricing.mostPopular')}</span>}
              <div style={S('font-family:var(--font-display);font-size:17px;font-weight:600;')}>{p.name}</div>
              <div style={S('display:flex;align-items:baseline;gap:5px;margin-top:10px;')}>
                <span style={S('font-family:var(--font-display);font-size:40px;font-weight:600;letter-spacing:-0.04em;line-height:1;')}>{p.amt}</span>
                <span style={S('font-size:13px;color:var(--fg-subtle);')}>{p.per}</span>
              </div>
              <div style={S('font-size:12.5px;color:var(--fg-muted);line-height:1.5;margin-top:8px;min-height:36px;')}>{p.desc}</div>
              <button style={S(p.feat ? ctaPrimary : ctaSecondary)}><span>{p.cta}</span></button>
              <div style={S('height:1px;background:var(--hairline);margin:18px 0;')}></div>
              <ul style={S('list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:11px;')}>
                {p.feats.map((ft) => <li key={ft} style={S('display:flex;align-items:flex-start;gap:9px;font-size:13px;line-height:1.4;color:var(--fg);')}><span style={S('flex:none;margin-top:1px;')}>{check('var(--accent)')}</span>{ft}</li>)}
              </ul>
            </div>
          ))}
        </div>
        <div style={S('display:flex;align-items:center;justify-content:space-between;gap:32px;flex-wrap:wrap;margin-top:18px;padding:28px 32px;border-radius:var(--radius-xl);background:var(--bg-elev);border:1px solid var(--border);box-shadow:var(--shadow-soft);')}>
          <div style={S('flex:1;min-width:280px;')}>
            <span style={S('display:inline-block;font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:var(--accent);background:var(--accent-bg-soft);padding:3px 9px;border-radius:999px;margin-bottom:10px;')}>{tr('mp.pricing.enterprise')}</span>
            <div style={S('font-family:var(--font-display);font-size:22px;font-weight:600;')}>{tr('mp.pricing.entTitle')}</div>
            <p style={S('font-size:14px;color:var(--fg-muted);margin:6px 0 14px;max-width:46em;line-height:1.5;')}>{tr('mp.pricing.entBody')}</p>
            <div style={S('display:flex;flex-wrap:wrap;gap:9px 22px;')}>
              {entFeats.map((ef) => <span key={ef} style={S('display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:500;')}>{check('var(--good)')}{ef}</span>)}
            </div>
          </div>
          <button className="forge-btn forge-btn--secondary forge-btn--lg">{tr('mp.pricing.contactUs')}</button>
        </div>
        <div style={S('display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;margin-top:28px;')}>
          <span style={S('font-size:12.5px;color:var(--fg-subtle);')}>{tr('mp.pricing.noTricksLabel')}</span>
          {noTricks.map((nt) => <span key={nt} style={S('display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border-radius:999px;background:var(--good-soft);color:color-mix(in srgb,var(--good) 64%,var(--fg));font-size:12.5px;font-weight:600;')}>{check('currentColor', 14)}{nt}</span>)}
        </div>
      </div>
    );
  }

  // ── COMPARE ──
  function Compare() {
    const cmpRows = [
      { feat: tr('mp.compare.row.freeTier.feat'), us: tr('mp.compare.row.freeTier.us'), them: tr('mp.compare.row.freeTier.them') },
      { feat: tr('mp.compare.row.wall.feat'), us: tr('mp.compare.row.wall.us'), them: tr('mp.compare.row.wall.them') },
      { feat: tr('mp.compare.row.watermark.feat'), us: tr('mp.compare.row.watermark.us'), them: tr('mp.compare.row.watermark.them') },
      { feat: tr('mp.compare.row.quality.feat'), us: tr('mp.compare.row.quality.us'), them: tr('mp.compare.row.quality.them') },
      { feat: tr('mp.compare.row.pricing.feat'), us: tr('mp.compare.row.pricing.us'), them: tr('mp.compare.row.pricing.them') },
      { feat: tr('mp.compare.row.api.feat'), us: tr('mp.compare.row.api.us'), them: tr('mp.compare.row.api.them') },
      { feat: tr('mp.compare.row.signup.feat'), us: tr('mp.compare.row.signup.us'), them: tr('mp.compare.row.signup.them') },
    ];
    const cmpMore = [
      { letter: 'S', title: 'vs Smallpdf', tag: tr('mp.compare.more.smallpdf') },
      { letter: 'P', title: 'vs PDF24', tag: tr('mp.compare.more.pdf24') },
      { letter: 'S', title: 'vs Sejda', tag: tr('mp.compare.more.sejda') },
      { letter: 'S', title: 'vs Stirling PDF', tag: tr('mp.compare.more.stirling') },
    ];
    const rowBase = 'display:grid;grid-template-columns:1.6fr 1fr 1fr;align-items:center;padding:13px 22px;border-bottom:1px solid var(--hairline);font-size:13.5px;';
    return (
      <div style={S('max-width:1000px;margin:0 auto;padding:48px 28px 8px;')}>
        <div style={S('text-align:center;')}>
          <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.nav.compare')}</span>
          <h1 style={S('font-family:var(--font-display);font-size:40px;font-weight:600;letter-spacing:-0.036em;margin:12px 0 0;text-wrap:balance;')}>{tr('mp.compare.title')}</h1>
          <p style={S('font-size:16px;line-height:1.55;color:var(--fg-muted);max-width:36em;margin:14px auto 0;')}>{tr('mp.compare.subtitle')}</p>
        </div>
        <div style={S('display:flex;gap:16px;margin-top:36px;padding:22px 24px;border-radius:var(--radius-lg);background:var(--good-soft);border:1px solid color-mix(in srgb,var(--good) 30%,transparent);')}>
          <span style={S('width:40px;height:40px;border-radius:11px;background:var(--good);color:#fff;display:grid;place-items:center;flex:none;')}>{check('currentColor', 20)}</span>
          <div>
            <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;')}>{tr('mp.compare.leaderTitle')}</div>
            <p style={S('font-size:14px;color:var(--fg-muted);line-height:1.55;margin:6px 0 0;')}>{tr('mp.compare.leaderBody')}</p>
          </div>
        </div>
        <div style={S('display:flex;align-items:stretch;gap:0;background:var(--brand-midnight);border-radius:var(--radius-xl);padding:32px 40px;margin:18px 0 28px;flex-wrap:wrap;')}>
          <div style={S('flex:1;min-width:200px;')}>
            <span style={S('font-size:11px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:rgba(255,255,255,0.5);')}>{tr('mp.compare.proLabel')}</span>
            <div style={S('font-family:var(--font-display);font-size:44px;font-weight:700;letter-spacing:-0.04em;line-height:1.05;margin-top:10px;background:var(--accent-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;')}>$5/mo</div>
            <p style={S('font-size:13.5px;color:rgba(255,255,255,0.62);margin-top:8px;line-height:1.5;max-width:26em;')}>{tr('mp.compare.proBody')}</p>
          </div>
          <div style={S('width:1px;background:rgba(255,255,255,0.12);margin:0 36px;')}></div>
          <div style={S('flex:1;min-width:200px;')}>
            <span style={S('font-size:11px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:rgba(255,255,255,0.5);')}>{tr('mp.compare.freeLabel')}</span>
            <div style={S('font-family:var(--font-display);font-size:44px;font-weight:700;letter-spacing:-0.04em;line-height:1.05;margin-top:10px;color:#fff;')}>{tr('mp.compare.noWall')}</div>
            <p style={S('font-size:13.5px;color:rgba(255,255,255,0.62);margin-top:8px;line-height:1.5;max-width:26em;')}>{tr('mp.compare.freeBody')}</p>
          </div>
        </div>
        <div style={S('border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--bg-elev);')}>
          <div style={S('display:grid;grid-template-columns:1.6fr 1fr 1fr;align-items:center;background:var(--bg);border-bottom:1px solid var(--border);padding:14px 22px;font-size:13px;font-weight:600;')}>
            <span></span>
            <span style={S('display:inline-flex;align-items:center;gap:7px;justify-content:center;color:var(--accent);')}>{Logo(16)} MostlyPDF</span>
            <span style={S('text-align:center;color:var(--fg-muted);')}>iLovePDF</span>
          </div>
          {cmpRows.map((r, i) => (
            <div key={i} style={S(rowBase + (i % 2 ? 'background:color-mix(in srgb,var(--bg) 50%,transparent);' : ''))}>
              <span style={S('font-weight:500;')}>{r.feat}</span>
              <span style={S('display:inline-flex;align-items:center;gap:8px;justify-content:center;text-align:center;font-size:13px;font-weight:600;color:color-mix(in srgb,var(--good) 70%,var(--fg));')}>{check('var(--accent)')}{r.us}</span>
              <span style={S('text-align:center;font-size:13px;color:var(--fg-muted);')}>{r.them}</span>
            </div>
          ))}
        </div>
        <div style={S('display:flex;gap:16px;margin-top:24px;padding:22px 24px;border-radius:var(--radius-lg);background:var(--warn-soft);border:1px solid color-mix(in srgb,var(--warn) 32%,transparent);')}>
          <span style={S('width:40px;height:40px;border-radius:11px;background:var(--warn);color:#fff;display:grid;place-items:center;flex:none;')}><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 9v4" /><path d="M12 17h.01" /><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z" /></svg></span>
          <div>
            <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;')}>{tr('mp.compare.theyWinTitle')}</div>
            <p style={S('font-size:14px;color:var(--fg-muted);line-height:1.55;margin:6px 0 0;')}>{tr('mp.compare.theyWinBody')}</p>
          </div>
        </div>
        <div style={S('margin-top:36px;')}>
          <div style={S('font-size:11px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--fg-subtle);text-align:center;margin-bottom:18px;')}>{tr('mp.compare.moreComparisons')}</div>
          <div style={S('display:grid;grid-template-columns:repeat(2,1fr);gap:14px;')}>
            {cmpMore.map((cm, i) => (
              <div key={i} className="forge-card forge-card--interactive" style={S('padding:20px;cursor:pointer;')}>
                <div style={S('display:flex;align-items:center;gap:10px;')}>
                  <span style={S('display:inline-grid;place-items:center;width:28px;height:28px;border-radius:7px;background:var(--fg-subtle);color:#fff;font-size:12px;font-weight:700;flex:none;')}>{cm.letter}</span>
                  <span style={S('font-family:var(--font-display);font-size:15px;font-weight:600;letter-spacing:-0.01em;')}>{cm.title}</span>
                </div>
                <p style={S('font-size:13px;color:var(--fg-muted);line-height:1.5;margin:10px 0 0;text-wrap:pretty;')}>{cm.tag}</p>
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  // ── API-KEYS DASHBOARD (#/keys) ──
  // Team-only while PUBLIC_APP_OPEN is false: not advertised in the public Nav (a subtle footer-
  // style link from the dashboard itself is enough); the team navigates directly to #/keys.
  //
  // SSR-SAFE: this whole component is only rendered for the #/keys route, but even then it never
  // touches window/firebase at render time — all firebase/auth work happens inside useEffect, so
  // the i18n prerender (no DOM) renders the static "loading" shell without throwing.

  // Lazy-initialise the compat Firebase app + auth + functions, reading window.MOSTLYPDF.firebase.
  // Returns { auth, fns } or null if firebase/config isn't available. Idempotent (reuses the app).
  function initFirebase() {
    if (typeof window === 'undefined') return null;
    const fb = window.firebase;
    const conf = (window.MOSTLYPDF || {}).firebase;
    if (!fb || !fb.initializeApp || !conf) return null;
    try {
      const app = fb.apps && fb.apps.length ? fb.app() : fb.initializeApp(conf);
      return { auth: app.auth(), fns: app.functions('europe-west2') };
    } catch (err) {
      return null;
    }
  }

  function Keys({ go }) {
    const [ready, setReady] = useState(false);      // firebase initialised?
    const [user, setUser] = useState(null);          // signed-in user | null
    const [authPhase, setAuthPhase] = useState('idle'); // idle | sending | sent | completing | closed | error
    const [email, setEmail] = useState('');
    const [authErr, setAuthErr] = useState('');
    const [keys, setKeys] = useState(null);          // null = not loaded; [] = loaded empty
    const [keysErr, setKeysErr] = useState('');
    const [newName, setNewName] = useState('');
    const [creating, setCreating] = useState(false);
    const [createErr, setCreateErr] = useState('');
    const [secret, setSecret] = useState(null);      // the one-time-shown new secret
    const [copied, setCopied] = useState(false);
    const [busyId, setBusyId] = useState('');        // id being revoked
    const fbRef = useRef(null);                       // { auth, fns }

    // Init firebase + subscribe to auth, and complete a magic-link landing if present.
    // All of this is DOM/firebase work → inside useEffect (never at module/render top-level).
    useEffect(() => {
      const fb = initFirebase();
      fbRef.current = fb;
      if (!fb) { setReady(true); return; }
      let unsub = function () {};
      try {
        unsub = window.MostlyAuth.onAuth(fb.auth, (u) => { setUser(u); setReady(true); });
      } catch (err) { setReady(true); }
      // Returning from a magic-link email lands here with the sign-in link in the URL.
      try {
        if (window.MostlyAuth.isMagicLinkLanding(fb.auth)) {
          setAuthPhase('completing');
          window.MostlyAuth.completeMagicLink({ auth: fb.auth }).catch((err) => {
            if (window.MostlyAuth.isClosedBetaError(err)) setAuthPhase('closed');
            else { setAuthErr(String((err && err.message) || err)); setAuthPhase('error'); }
          });
        }
      } catch (err) { /* not a landing */ }
      return () => { try { unsub(); } catch (e) { /* ignore */ } };
    }, []);

    // Load the key list once signed in.
    useEffect(() => {
      const fb = fbRef.current;
      if (!user || !fb) return;
      setKeysErr('');
      fb.fns.httpsCallable('listApiKeys')({})
        .then((res) => setKeys((res && res.data && res.data.keys) || []))
        .catch((err) => setKeysErr(String((err && err.message) || err)));
    }, [user]);

    function sendLink(ev) {
      ev.preventDefault();
      const fb = fbRef.current;
      const addr = email.trim();
      if (!addr || !fb) return;
      setAuthPhase('sending'); setAuthErr('');
      window.MostlyAuth.requestMagicLink({ fns: fb.fns, email: addr, continueUrl: window.location.href })
        .then(() => setAuthPhase('sent'))
        .catch((err) => {
          if (window.MostlyAuth.isClosedBetaError(err)) setAuthPhase('closed');
          else { setAuthErr(String((err && err.message) || err)); setAuthPhase('error'); }
        });
    }

    function signOut() {
      const fb = fbRef.current;
      if (!fb) return;
      window.MostlyAuth.signOut(fb.auth).then(() => { setKeys(null); setSecret(null); });
    }

    function createKey(ev) {
      ev.preventDefault();
      const fb = fbRef.current;
      if (!fb) return;
      setCreating(true); setCreateErr(''); setCopied(false);
      fb.fns.httpsCallable('createApiKey')({ name: newName.trim() || 'API key', scopes: ['pdf:run'] })
        .then((res) => {
          const d = (res && res.data) || {};
          setSecret(d.secret || '');
          setNewName('');
          // Optimistically add the new key to the table (revoked:false), then refresh.
          setKeys((prev) => [{ id: d.id, name: d.name, last4: d.last4, prefix: 'sk', scopes: d.scopes || ['pdf:run'], revoked: false }].concat(prev || []));
        })
        .catch((err) => setCreateErr(String((err && err.message) || err)))
        .finally(() => setCreating(false));
    }

    function revoke(id) {
      const fb = fbRef.current;
      if (!fb) return;
      setBusyId(id);
      fb.fns.httpsCallable('revokeApiKey')({ id })
        .then(() => setKeys((prev) => (prev || []).map((k) => (k.id === id ? Object.assign({}, k, { revoked: true }) : k))))
        .catch((err) => setKeysErr(String((err && err.message) || err)))
        .finally(() => setBusyId(''));
    }

    function copySecret() {
      try {
        if (navigator.clipboard && secret) {
          navigator.clipboard.writeText(secret).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1800); });
        }
      } catch (err) { /* clipboard blocked */ }
    }

    const wrap = 'max-width:860px;margin:0 auto;padding:42px 28px 8px;';
    const headBlock = (
      <div style={S('margin-bottom:26px;')}>
        <span style={S('display:inline-block;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--accent);')}>{tr('mp.keys.developers')}</span>
        <h1 style={S('font-family:var(--font-display);font-size:34px;font-weight:600;letter-spacing:-0.034em;margin:10px 0 0;')}>{tr('mp.keys.title')}</h1>
        <p style={S('font-size:15px;line-height:1.55;color:var(--fg-muted);max-width:40em;margin:10px 0 0;text-wrap:pretty;')}>{tr('mp.keys.introPre')} <a href="/docs" style={S('color:var(--accent);font-weight:600;text-decoration:none;')}>{tr('mp.keys.apiReference')}</a> {tr('mp.keys.introPost')}</p>
      </div>
    );

    // 1) Booting firebase (also the SSR/prerender render: ready=false, no DOM touched).
    if (!ready) {
      return (
        <div style={S(wrap)}>
          {headBlock}
          <div className="forge-card" style={S('padding:40px;text-align:center;color:var(--fg-muted);font-size:14px;')}>{tr('mp.keys.loading')}</div>
        </div>
      );
    }

    // 2) Firebase unavailable (misconfigured / SDK blocked).
    if (!fbRef.current) {
      return (
        <div style={S(wrap)}>
          {headBlock}
          <div className="forge-card" style={S('padding:28px;')}>
            <div style={S('font-size:14px;color:var(--fg);font-weight:600;')}>{tr('mp.keys.unavailableTitle')}</div>
            <p style={S('font-size:13.5px;color:var(--fg-muted);margin:8px 0 0;line-height:1.55;')}>{tr('mp.keys.unavailablePre')} <a href="/docs" style={S('color:var(--accent);font-weight:600;text-decoration:none;')}>{tr('mp.keys.apiDocs')}</a> {tr('mp.keys.unavailablePost')}</p>
          </div>
        </div>
      );
    }

    // 3) Signed out → sign-in panel (magic link), with the private-beta case handled calmly.
    if (!user) {
      const card = 'forge-card';
      const cardStyle = S('padding:30px;max-width:460px;margin:0 auto;');
      let inner;
      if (authPhase === 'completing') {
        inner = (
          <div style={S('text-align:center;')}>
            <div style={S('font-family:var(--font-display);font-size:19px;font-weight:600;letter-spacing:-0.02em;')}>{tr('mp.keys.signingIn')}</div>
            <p style={S('font-size:13.5px;color:var(--fg-muted);margin:8px 0 0;')}>{tr('mp.keys.signingInBody')}</p>
          </div>
        );
      } else if (authPhase === 'closed') {
        inner = (
          <div style={S('text-align:center;')}>
            <span style={S('display:inline-grid;place-items:center;width:48px;height:48px;border-radius:50%;background:var(--accent-bg-soft);color:var(--accent);margin-bottom:6px;')}>{ic('lock', 22)}</span>
            <div style={S('font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:-0.02em;margin-top:8px;')}>{tr('mp.keys.betaTitle')}</div>
            <p style={S('font-size:13.5px;color:var(--fg-muted);margin:10px 0 0;line-height:1.6;text-wrap:pretty;')}>{tr('mp.keys.betaBody')}</p>
          </div>
        );
      } else if (authPhase === 'sent') {
        inner = (
          <div style={S('text-align:center;')}>
            <span style={S('display:inline-grid;place-items:center;width:48px;height:48px;border-radius:50%;background:var(--good-soft);color:var(--good);margin-bottom:6px;')}>{check('currentColor', 24)}</span>
            <div style={S('font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:-0.02em;margin-top:8px;')}>{tr('mp.keys.inboxTitle')}</div>
            <p style={S('font-size:13.5px;color:var(--fg-muted);margin:10px 0 0;line-height:1.6;')}>{tr('mp.keys.inboxPre')} <strong style={S('color:var(--fg);')}>{email}</strong>{tr('mp.keys.inboxPost')}</p>
            <button onClick={() => setAuthPhase('idle')} style={S('margin-top:14px;font-size:13px;font-weight:600;color:var(--accent);background:none;border:none;cursor:pointer;')}>{tr('mp.keys.differentEmail')}</button>
          </div>
        );
      } else {
        inner = (
          <div>
            <div style={S('font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:-0.02em;')}>{tr('mp.keys.signInTitle')}</div>
            <p style={S('font-size:13.5px;color:var(--fg-muted);margin:8px 0 18px;line-height:1.55;')}>{tr('mp.keys.signInBody')}</p>
            <form onSubmit={sendLink} style={S('display:flex;flex-direction:column;gap:10px;')}>
              <input type="email" value={email} onChange={(ev) => setEmail(ev.target.value)} placeholder="you@company.com" className="forge-input" autoFocus />
              {authPhase === 'error' && <div style={S('font-size:12.5px;color:var(--bad);font-weight:500;')}>{authErr || tr('mp.keys.genericError')}</div>}
              <button type="submit" disabled={authPhase === 'sending'} className="forge-btn forge-btn--primary forge-btn--lg forge-btn--block"><span>{authPhase === 'sending' ? tr('mp.keys.sending') : tr('mp.keys.emailLink')}</span></button>
            </form>
          </div>
        );
      }
      return (
        <div style={S(wrap)}>
          {headBlock}
          <div className={card} style={cardStyle}>{inner}</div>
        </div>
      );
    }

    // 4) Signed in → keys table + create form.
    const monoChip = 'font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-size:12.5px;';
    return (
      <div style={S(wrap)}>
        <div style={S('display:flex;align-items:flex-start;justify-content:space-between;gap:16px;')}>
          {headBlock}
          <button onClick={signOut} className="forge-btn forge-btn--secondary forge-btn--sm" style={S('flex:none;margin-top:4px;')}>{tr('mp.keys.signOut')}</button>
        </div>

        {/* Create-key form */}
        <div className="forge-card" style={S('padding:22px;')}>
          <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-0.016em;margin-bottom:14px;')}>{tr('mp.keys.createKey')}</div>
          <form onSubmit={createKey} style={S('display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;')}>
            <div style={S('flex:1;min-width:220px;display:flex;flex-direction:column;gap:6px;')}>
              <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.keys.keyName')}</span>
              <input value={newName} onChange={(ev) => setNewName(ev.target.value)} className="forge-input" placeholder={tr('mp.keys.keyNamePlaceholder')} />
            </div>
            <div style={S('display:flex;flex-direction:column;gap:6px;')}>
              <span style={S('font-size:12px;font-weight:500;color:var(--fg);')}>{tr('mp.keys.scope')}</span>
              <span style={S('display:inline-flex;align-items:center;height:38px;padding:0 12px;border-radius:var(--radius);background:var(--bg-chip);color:var(--fg-muted);font-size:12.5px;font-weight:600;')}>pdf:run</span>
            </div>
            <button type="submit" disabled={creating} className="forge-btn forge-btn--primary"><span>{creating ? tr('mp.keys.creating') : tr('mp.keys.createKeyBtn')}</span></button>
          </form>
          {createErr && <div style={S('font-size:12.5px;color:var(--bad);font-weight:500;margin-top:10px;')}>{createErr}</div>}
        </div>

        {/* One-time secret reveal */}
        {secret && (
          <div className="forge-card" style={S('padding:22px;margin-top:16px;border:1px solid color-mix(in srgb,var(--accent) 40%,transparent);')}>
            <div style={S('display:flex;align-items:center;gap:10px;')}>
              <span style={S('display:inline-grid;place-items:center;width:34px;height:34px;border-radius:9px;background:var(--accent-bg-soft);color:var(--accent);flex:none;')}>{ic('lock', 18)}</span>
              <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-0.016em;')}>{tr('mp.keys.secretTitle')}</div>
            </div>
            <p style={S('font-size:13px;color:var(--fg-muted);margin:12px 0 0;line-height:1.55;')}><strong style={S('color:var(--fg);')}>{tr('mp.keys.secretWarnLead')}</strong> {tr('mp.keys.secretWarnBody')}</p>
            <div style={S('display:flex;align-items:center;gap:10px;margin-top:14px;padding:12px 14px;border-radius:var(--radius);background:var(--bg);border:1px solid var(--border);')}>
              <code style={S(monoChip + 'flex:1;min-width:0;overflow-x:auto;white-space:nowrap;color:var(--fg);')}>{secret}</code>
              <button onClick={copySecret} className="forge-btn forge-btn--secondary forge-btn--sm" style={S('flex:none;')}>{copied ? tr('mp.keys.copied') : tr('mp.keys.copy')}</button>
            </div>
            <button onClick={() => setSecret(null)} style={S('margin-top:12px;font-size:12.5px;font-weight:600;color:var(--fg-muted);background:none;border:none;cursor:pointer;')}>{tr('mp.keys.dismissSaved')}</button>
          </div>
        )}

        {/* Key list */}
        <div style={S('margin-top:24px;')}>
          <div style={S('font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-0.016em;margin-bottom:12px;')}>{tr('mp.keys.yourKeys')}</div>
          {keysErr && <div style={S('font-size:12.5px;color:var(--bad);font-weight:500;margin-bottom:10px;')}>{keysErr}</div>}
          {keys === null ? (
            <div className="forge-card" style={S('padding:28px;text-align:center;color:var(--fg-muted);font-size:13.5px;')}>{tr('mp.keys.loadingKeys')}</div>
          ) : keys.length === 0 ? (
            <div className="forge-card" style={S('padding:28px;text-align:center;color:var(--fg-muted);font-size:13.5px;')}>{tr('mp.keys.noKeys')}</div>
          ) : (
            <div className="forge-card" style={S('padding:0;overflow:hidden;')}>
              <div style={S('display:grid;grid-template-columns:1.4fr 1.1fr 1fr 0.8fr;align-items:center;padding:12px 18px;background:var(--bg);border-bottom:1px solid var(--border);font-size:12px;font-weight:600;color:var(--fg-subtle);text-transform:uppercase;letter-spacing:0.04em;')}>
                <span>{tr('mp.keys.colName')}</span><span>{tr('mp.keys.colKey')}</span><span>{tr('mp.keys.colScopes')}</span><span style={S('text-align:right;')}>{tr('mp.keys.colStatus')}</span>
              </div>
              {keys.map((k) => (
                <div key={k.id} style={S('display:grid;grid-template-columns:1.4fr 1.1fr 1fr 0.8fr;align-items:center;padding:14px 18px;border-bottom:1px solid var(--hairline);font-size:13.5px;')}>
                  <span style={S('font-weight:600;' + (k.revoked ? 'color:var(--fg-subtle);text-decoration:line-through;' : ''))}>{k.name || tr('mp.keys.defaultKeyName')}</span>
                  <span style={S(monoChip + 'color:var(--fg-muted);')}>{(k.prefix || 'sk')}_•••{k.last4 || '????'}</span>
                  <span style={S('display:flex;flex-wrap:wrap;gap:5px;')}>{(k.scopes || []).map((sc) => <span key={sc} className="forge-badge">{sc}</span>)}</span>
                  <span style={S('display:flex;align-items:center;justify-content:flex-end;gap:10px;')}>
                    {k.revoked ? (
                      <span style={S('font-size:12px;font-weight:600;color:var(--fg-subtle);')}>{tr('mp.keys.revoked')}</span>
                    ) : (
                      <button onClick={() => revoke(k.id)} disabled={busyId === k.id} style={S('font-size:12.5px;font-weight:600;color:var(--bad);background:none;border:none;cursor:pointer;')}>{busyId === k.id ? tr('mp.keys.revoking') : tr('mp.keys.revoke')}</button>
                    )}
                  </span>
                </div>
              ))}
            </div>
          )}
        </div>

        <div style={S('margin-top:28px;font-size:13px;color:var(--fg-subtle);')}>
          <span className="pdf-link" onClick={() => go('landing')} style={S('color:var(--fg-muted);font-weight:500;')}>{tr('mp.keys.backToTools')}</span>
        </div>
      </div>
    );
  }

  // ── root: hash router ──
  function App() {
    const parse = () => {
      if (typeof location === 'undefined') return { screen: 'landing', slug: null }; // SSR/no-DOM safe
      const h = (location.hash || '').replace(/^#\/?/, '');
      if (h === 'pricing' || h === 'compare') return { screen: h, slug: null };
      // The team's API-keys dashboard. Not advertised in the public Nav while PUBLIC_APP_OPEN is
      // false — reachable directly at #/keys (and #/dashboard as an alias).
      if (h === 'keys' || h === 'dashboard') return { screen: 'keys', slug: null };
      if (h && TM[h]) return { screen: 'runner', slug: h };
      return { screen: 'landing', slug: null };
    };
    const [route, setRoute] = useState(parse());
    useEffect(() => { const f = () => { setRoute(parse()); window.scrollTo(0, 0); }; window.addEventListener('hashchange', f); return () => window.removeEventListener('hashchange', f); }, []);
    const go = (screen) => { location.hash = screen === 'landing' ? '#/' : '#/' + screen; };
    const open = (slug) => { location.hash = '#/' + slug; };
    let body;
    if (route.screen === 'runner') body = <Runner key={route.slug} slug={route.slug} go={go} open={open} />;
    else if (route.screen === 'pricing') body = <Pricing />;
    else if (route.screen === 'compare') body = <Compare />;
    else if (route.screen === 'keys') body = <Keys go={go} />;
    else body = <Landing go={go} open={open} />;
    // Flex column so the footer is pinned to the bottom of the viewport on short pages
    // (the body region grows to fill); on long pages it just sits after the content.
    return (
      <div style={S('display:flex;flex-direction:column;min-height:100vh;background:var(--bg);color:var(--fg);font-family:var(--font-sans);')}>
        <Nav go={go} />
        <div style={S('flex:1 0 auto;padding-bottom:72px;')}>{body}</div>
        <Footer />
      </div>
    );
  }

  // Hydrate the prerendered SSR markup when present; client-render if the shell is empty.
  const _root = document.getElementById('mostlypdf-app');
  if (_root) {
    if (_root.hasChildNodes()) ReactDOM.hydrateRoot(_root, <App />);
    else ReactDOM.createRoot(_root).render(<App />);
  }
})();
