// admin-markdown-to-figures.jsx — "Markdown → Figures" generator
//
// Paste a blog-post markdown file → the figures-plan edge function asks Claude for a
// compact JSON plan → the PORTED deterministic renderer below turns that plan into
// self-contained HTML for the cover package + in-article figures, each with a Copy
// button. The renderer is 100% client-side and pure (no LLM); only the markdown→plan
// step calls the server.
(function () {
  const { useState, useRef } = React;
  const Icon = window.Icon;

  const SUPABASE_URL      = 'https://iwvlmpgeodctctmaacja.supabase.co';
  const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml3dmxtcGdlb2RjdGN0bWFhY2phIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjYwMzY3MTUsImV4cCI6MjA4MTYxMjcxNX0.hMs9OGPTdhPAs0lSKzDWE1Cc-K27NoW11--niolkoWY';

  async function planFigures(markdown) {
    const db = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
    const { data, error } = await db.functions.invoke('figures-plan', { body: { markdown } });
    // Edge function returns 422 with { ok:false, error, raw } on validation failure.
    // supabase-js surfaces non-2xx as `error`, but the JSON body still rides along.
    if (error && !data) {
      let detail = error.message;
      try { detail = (await error.context.json())?.error || detail; } catch (_e) {}
      throw new Error(detail || 'Planner failed');
    }
    if (!data?.ok) throw new Error(data?.error || 'Planner returned no usable plan');
    return data.plan;
  }

  // ── Sample markdown (the acceptance-test post) ───────────────────────────
  const SAMPLE_MD = `# Exclusive vs Shared Leads: Which Model Makes More Money?

Exclusive leads go to one buyer. Shared leads go to several at once — usually 3 to 5. That single difference decides your close rate and your margin.

## At a glance
Exclusive leads close 2–3x higher than shared in the same niche. A typical shared lead is sold to 3–5 buyers. With exclusive delivery there are 0 duplicate-outreach disputes.

## The real cost math
Per 100 leads: exclusive costs $45/lead and closes at 25%; shared costs $18/lead and closes at 9%. Profit per lead lands at $255 exclusive vs $90 shared. The cheaper lead made the more expensive customer.

## How to decide
First, is the deal high-ticket or retainer-based? If one close is worth four figures, go exclusive. Second, can you respond in under 60 seconds every time? Shared only works with instant speed-to-lead. Third, is the client judging you on quality or volume?

## Common mistakes
Buying on cost-per-lead alone — the cheapest lead is rarely the cheapest customer. Running shared without speed-to-lead — slow follow-up turns shared leads into expensive noise.

> You don't lose money on shared leads at the point of sale. You lose it ten minutes later, on the call that never connects.`;

  // =====================================================================
  // PORTED RENDERER — pure string builders. Methods call each other via R.*
  // Copied verbatim from the "Markdown to Figures" prototype; the only change
  // is buildFigures(plan) takes the plan as an argument instead of this.state.
  // =====================================================================
  const R = {
    esc(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); },
    emph(s, color) { return this.esc(s).replace(/\[\[(.+?)\]\]/g, '<span style="color:' + color + '">$1</span>'); },
    bodyEmph(s) { return this.esc(s).replace(/\[\[(.+?)\]\]/g, '<strong style="font-weight:600;color:var(--ink)">$1</strong>'); },

    varMap: {
      'var(--paper3)': '#E9E2CE', 'var(--paper2)': '#F4EFE2', 'var(--paper)': '#FCFAF2',
      'var(--ink)': '#1A2B3B', 'var(--body)': '#2c2a24', 'var(--muted)': '#7A715A',
      'var(--border2)': '#D6CFB8', 'var(--border)': '#E5E0CC',
      'var(--orange-deep)': '#C7501A', 'var(--orange-soft)': '#FFE4C2', 'var(--orange)': '#F97316',
      'var(--emerald-deep)': '#0F8F66', 'var(--emerald-soft)': '#D5F1E5', 'var(--emerald)': '#10B981',
      'var(--red-soft)': '#FBE2E0', 'var(--red-deep)': '#B0301F', 'var(--red)': '#EF4444',
      'var(--sans)': "'Inter',system-ui,sans-serif", 'var(--serif)': "'Source Serif 4',Georgia,serif", 'var(--mono)': "'JetBrains Mono',ui-monospace,monospace",
    },
    resolveVars(html) { let out = String(html); for (const k in this.varMap) { out = out.split(k).join(this.varMap[k]); } return out; },

    ckSm(c) { return '<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="' + (c || '#fff') + '" stroke-width="3.6" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 6"/></svg>'; },
    xSm(c) { return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="' + (c || '#fff') + '" stroke-width="3.6" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>'; },
    arrowSm(c) { return '<svg width="28" height="20" viewBox="0 0 28 20"><path d="M2 10 H22" stroke="' + c + '" stroke-width="2" stroke-dasharray="4 4" stroke-linecap="round"/><path d="M18 5 L24 10 L18 15" fill="none" stroke="' + c + '" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'; },

    renderFigure(f) {
      switch (f.element) {
        case 'hero': return this.bHero(f);
        case 'og': return this.bOg(f);
        case 'key-takeaway': return this.bKey(f);
        case 'note-callout': return this.bNote(f);
        case 'comparison-split': return this.bSplit(f);
        case 'stat-trio': return this.bStat(f);
        case 'cost-table': return this.bCost(f);
        case 'comparison-table': return this.bCmp(f);
        case 'pull-quote': return this.bQuote(f);
        case 'process-flow': return this.bFlow(f);
        case 'before-after': return this.bBeforeAfter(f);
        case 'decision-steps': return this.bSteps(f);
        case 'pitfall-grid': return this.bPitfall(f);
        case 'link-card': return this.bLink(f);
        case 'cta': return this.bCta(f);
        case 'concept-cover': return this.bConceptCoverFeatured(f);
        case 'faq': case 'faq-accordion': return this.bFaq(f);
        default: return this.bUnknown(f);
      }
    },
    paddedFor(el) { return !(el === 'hero' || el === 'og' || el === 'pull-quote' || el === 'comparison-split' || el === 'process-flow'); },

    bUnknown(f) { return '<div style="font:500 13px/1.5 var(--mono);color:var(--muted);padding:8px;">Element &ldquo;' + this.esc(f.element) + '&rdquo; isn’t in the registry — skipped.</div>'; },

    bHero(h) { const m = h.meta || {};
      return '<div style="width:600px;height:315px;max-width:100%;overflow:hidden;border-radius:12px;box-shadow:0 18px 38px -22px rgba(15,23,42,.3);">'
        + '<div style="width:1200px;height:630px;transform:scale(.5);transform-origin:top left;background:var(--paper2);position:relative;overflow:hidden;padding:72px;display:flex;flex-direction:column;justify-content:space-between;box-sizing:border-box;">'
        + '<div style="background-image:linear-gradient(rgba(26,43,59,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.04) 1px,transparent 1px);background-size:48px 48px;position:absolute;inset:0;"></div>'
        + '<div style="position:absolute;right:-160px;top:-160px;width:560px;height:560px;border-radius:50%;background:radial-gradient(circle,rgba(249,115,22,.16) 0%,rgba(249,115,22,0) 65%);"></div>'
        + '<div style="position:relative;display:inline-flex;align-items:center;gap:14px;font:700 19px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--orange-deep);"><span style="width:12px;height:12px;border-radius:50%;background:var(--orange);box-shadow:0 0 0 6px rgba(249,115,22,.18);"></span>' + this.esc(h.category) + '</div>'
        + '<h1 style="position:relative;font-family:var(--serif);font-weight:600;font-size:' + ((h.headline || '').length > 60 ? 60 : 70) + 'px;line-height:1.06;letter-spacing:-.02em;color:var(--ink);margin:0;max-width:980px;text-wrap:balance;">' + this.emph(h.headline, 'var(--orange-deep)').replace(/(<span[^>]*>)/, '$1<em style="font-style:italic;font-weight:500;">').replace(/<\/span>/, '</em></span>') + '</h1>'
        + '<div style="position:relative;display:flex;align-items:center;gap:20px;font:700 20px/1 var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--muted);"><span>' + this.esc(m.read || '') + '</span><span style="width:6px;height:6px;border-radius:50%;background:var(--border2);"></span><span>' + this.esc(m.tag || '') + '</span></div>'
        + '</div></div>'; },

    bOg(o) { return '<div style="width:600px;height:315px;max-width:100%;overflow:hidden;border-radius:12px;box-shadow:0 18px 38px -22px rgba(15,23,42,.45);">'
      + '<div style="width:1200px;height:630px;transform:scale(.5);transform-origin:top left;background:var(--ink);position:relative;overflow:hidden;padding:76px;display:flex;flex-direction:column;justify-content:space-between;box-sizing:border-box;">'
      + '<div style="background-image:linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);background-size:48px 48px;position:absolute;inset:0;"></div>'
      + '<div style="position:absolute;right:-140px;bottom:-180px;width:600px;height:600px;border-radius:50%;background:radial-gradient(circle,rgba(249,115,22,.28) 0%,rgba(249,115,22,0) 62%);"></div>'
      + '<div style="position:relative;align-self:flex-start;display:inline-flex;align-items:center;gap:12px;background:rgba(249,115,22,.16);border:1.5px solid rgba(249,115,22,.5);border-radius:9999px;padding:12px 22px;font:800 18px/1 var(--sans);letter-spacing:.08em;text-transform:uppercase;color:var(--orange);">' + this.esc(o.category) + '</div>'
      + '<h2 style="position:relative;font-family:var(--sans);font-weight:900;font-size:76px;line-height:1.04;letter-spacing:-.03em;color:#fff;margin:0;max-width:1020px;text-wrap:balance;">' + this.emph(o.headline, 'var(--orange)') + '</h2>'
      + '<div style="position:relative;display:flex;align-items:center;gap:16px;"><span style="width:40px;height:3px;background:var(--orange);border-radius:2px;"></span><span style="font:600 24px/1.3 var(--serif);color:rgba(255,255,255,.66);">' + this.esc(o.hook) + '</span></div>'
      + '</div></div>'; },

    bKey(f) { return '<div style="position:relative;background:#fff;border:1px solid var(--border);border-radius:14px;padding:22px 24px 22px 26px;box-shadow:0 4px 16px -10px rgba(15,23,42,.14);overflow:hidden;">'
      + '<span style="position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--orange);"></span>'
      + '<div style="display:flex;align-items:center;gap:8px;margin-bottom:10px;"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2 3 14h7l-1 8 10-12h-7l1-8z"/></svg><span style="font:800 11px/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:var(--orange-deep);">' + this.esc(f.eyebrow || 'The short answer') + '</span></div>'
      + '<p style="font-family:var(--serif);font-size:18px;line-height:1.62;color:var(--body);margin:0;text-wrap:pretty;">' + this.bodyEmph(f.body) + '</p></div>'; },

    bNote(f) { return '<div style="position:relative;background:rgba(249,115,22,.06);border:1px solid rgba(249,115,22,.28);border-radius:14px;padding:20px 22px;">'
      + '<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--orange-deep)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/></svg><span style="font:800 11px/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:var(--orange-deep);">' + this.esc(f.kicker || 'Rule of thumb') + '</span></div>'
      + '<p style="font-family:var(--serif);font-size:17px;line-height:1.6;color:var(--ink);margin:0;text-wrap:pretty;">' + this.bodyEmph(f.body) + '</p></div>'; },

    bQuote(f) { return '<figure style="margin:0;padding:6px 0 6px 26px;border-left:3px solid var(--orange);"><blockquote style="margin:0;font-family:var(--serif);font-style:italic;font-size:25px;line-height:1.4;color:var(--ink);letter-spacing:-.01em;text-wrap:balance;">&ldquo;' + this.esc(f.quote) + '&rdquo;</blockquote></figure>'; },

    bStat(f) { const cols = ['var(--orange-deep)', 'var(--ink)', 'var(--emerald-deep)'];
      const cards = (f.stats || []).slice(0, 3).map((s, i) => '<div style="background:#fff;border:1px solid var(--border);border-radius:12px;padding:18px 16px;box-shadow:0 2px 6px -2px rgba(15,23,42,.05);">'
        + '<div style="font:900 34px/1 var(--sans);font-variant-numeric:tabular-nums;letter-spacing:-.03em;color:' + (cols[i] || 'var(--ink)') + ';">' + this.esc(s.value) + '</div>'
        + '<div style="font:600 12.5px/1.4 var(--sans);color:var(--muted);margin-top:8px;">' + this.esc(s.label) + (s.cite ? '<sup style="color:var(--orange);font-weight:700;">' + this.esc(s.cite) + '</sup>' : '') + '</div></div>').join('');
      return '<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px;">' + cards + '</div>'; },

    bCost(f) { const rows = (f.rows || []); const last = rows.length - 1;
      let cells = '<div style="padding:13px 18px;font:700 10px/1.2 var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--muted);background:var(--paper2);border-bottom:1px solid var(--border);">' + this.esc(f.corner || '') + '</div>'
        + '<div style="padding:13px 16px;font:800 11px/1.2 var(--sans);letter-spacing:.05em;text-transform:uppercase;color:var(--orange-deep);background:rgba(249,115,22,.08);border-bottom:1px solid rgba(249,115,22,.24);display:flex;align-items:center;gap:7px;"><span style="width:8px;height:8px;border-radius:50%;background:var(--orange);box-shadow:0 0 0 3px rgba(249,115,22,.2);"></span>' + this.esc(f.colA) + '</div>'
        + '<div style="padding:13px 16px;font:800 11px/1.2 var(--sans);letter-spacing:.05em;text-transform:uppercase;color:var(--muted);background:var(--paper2);border-bottom:1px solid var(--border);">' + this.esc(f.colB) + '</div>';
      rows.forEach((r, i) => { const fin = i === last; const bb = i < last ? 'border-bottom:1px solid var(--border);' : '';
        cells += '<div style="padding:' + (fin ? '14px 18px' : '12px 18px') + ';font:' + (fin ? '800' : '600') + ' 14px/1.3 var(--sans);color:var(--ink);' + (fin ? 'background:var(--paper2);' : '') + bb + '">' + this.esc(r.label) + '</div>'
          + '<div style="padding:' + (fin ? '14px 16px' : '12px 16px') + ';font:' + (fin ? '900 18px' : '600 14px') + '/1 var(--sans);font-variant-numeric:tabular-nums;color:var(--orange-deep);background:' + (fin ? 'rgba(249,115,22,.12)' : 'rgba(249,115,22,.04)') + ';' + bb + '">' + this.esc(r.a) + '</div>'
          + '<div style="padding:' + (fin ? '14px 16px' : '12px 16px') + ';font:' + (fin ? '800 16px' : '600 14px') + '/1 var(--sans);font-variant-numeric:tabular-nums;color:' + (fin ? 'var(--ink)' : 'var(--muted)') + ';' + (fin ? 'background:var(--paper2);' : '') + bb + '">' + this.esc(r.b) + '</div>'; });
      const ft = f.footnote ? '<p style="font:500 11.5px/1.5 var(--mono);color:var(--muted);margin:12px 0 0;">' + this.esc(f.footnote) + '</p>' : '';
      return '<div style="background:#fff;border:1px solid var(--border);border-radius:14px;overflow:hidden;box-shadow:0 4px 16px -10px rgba(15,23,42,.14);"><div style="display:grid;grid-template-columns:1.5fr 1fr 1fr;">' + cells + '</div></div>' + ft; },

    bCmp(f) { const rows = (f.rows || []);
      let cells = '<div style="padding:13px 18px;font:700 10px/1.2 var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--muted);background:var(--paper2);border-bottom:1px solid var(--border);">Dimension</div>'
        + '<div style="padding:13px 16px;font:800 11px/1.2 var(--sans);letter-spacing:.05em;text-transform:uppercase;color:var(--orange-deep);background:rgba(249,115,22,.08);border-bottom:1px solid rgba(249,115,22,.24);display:flex;align-items:center;gap:7px;"><span style="width:8px;height:8px;border-radius:50%;background:var(--orange);box-shadow:0 0 0 3px rgba(249,115,22,.2);"></span>' + this.esc(f.colA) + '</div>'
        + '<div style="padding:13px 16px;font:800 11px/1.2 var(--sans);letter-spacing:.05em;text-transform:uppercase;color:var(--muted);background:var(--paper2);border-bottom:1px solid var(--border);">' + this.esc(f.colB) + '</div>';
      const chip = (state, color, bg) => state ? '<span style="width:20px;height:20px;border-radius:50%;background:' + bg + ';color:' + color + ';display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + (state === 'win' ? '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 6"/></svg>' : '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.4" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>') + '</span>' : '';
      rows.forEach((r) => {
        const aCol = r.aState === 'lose' ? 'var(--muted)' : (r.aState === 'win' ? 'var(--emerald-deep)' : 'var(--ink)');
        const bCol = r.bState === 'win' ? 'var(--emerald-deep)' : (r.bState === 'lose' ? 'var(--muted)' : 'var(--muted)');
        cells += '<div style="padding:13px 18px;font:600 13.5px/1.3 var(--sans);color:var(--ink);border-bottom:1px solid var(--border);background:#fff;">' + this.esc(r.dim) + '</div>'
          + '<div style="padding:13px 16px;font:' + (r.aState === 'win' ? '600' : '500') + ' 13px/1.35 var(--sans);color:' + aCol + ';background:rgba(249,115,22,.05);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:9px;">' + chip(r.aState, 'var(--emerald-deep)', 'rgba(16,185,129,.16)').replace('var(--emerald-deep)', r.aState === 'lose' ? 'var(--red)' : 'var(--emerald-deep)').replace('rgba(16,185,129,.16)', r.aState === 'lose' ? 'rgba(239,68,68,.12)' : 'rgba(16,185,129,.16)') + this.esc(r.a) + '</div>'
          + '<div style="padding:13px 16px;font:500 13px/1.35 var(--sans);color:' + bCol + ';border-bottom:1px solid var(--border);background:#fff;display:flex;align-items:center;gap:9px;">' + chip(r.bState, r.bState === 'lose' ? 'var(--red)' : 'var(--emerald-deep)', r.bState === 'lose' ? 'rgba(239,68,68,.12)' : 'rgba(16,185,129,.16)') + this.esc(r.b) + '</div>'; });
      return '<div style="border:1px solid var(--border);border-radius:14px;overflow:hidden;box-shadow:0 4px 16px -10px rgba(15,23,42,.14);"><div style="display:grid;grid-template-columns:1.25fr 1fr 1fr;">' + cells + '</div></div>'; },

    bSplit(f) { const L = f.left || {}, Rr = f.right || {};
      const rrows = (Rr.results || []).map(r => { const win = r.state === 'win';
        return '<div style="display:flex;align-items:center;gap:9px;padding:8px 11px;border-radius:10px;border:1px solid ' + (win ? 'var(--emerald-soft)' : 'var(--red-soft)') + ';background:' + (win ? '#F5FBF8' : '#FCF1F0') + ';">'
          + '<span style="width:18px;height:18px;border-radius:50%;background:' + (win ? 'var(--emerald)' : 'var(--red)') + ';display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + (win ? this.ckSm() : this.xSm()) + '</span>'
          + '<span style="font:600 12px/1 var(--sans);color:' + (win ? 'var(--ink)' : '#8A2F26') + ';flex:1;text-align:left;' + (win ? '' : 'text-decoration:line-through;') + '">' + this.esc(r.text) + '</span>' + (win ? '<span style="font:700 9px/1 var(--mono);color:var(--emerald-deep);">WON</span>' : '') + '</div>'; }).join('');
      return '<figure style="margin:0;"><div style="background:var(--paper2);border:1px solid var(--border);border-radius:18px;padding:24px;box-shadow:0 18px 38px -22px rgba(15,23,42,.22);position:relative;overflow:hidden;">'
        + '<div style="background-image:linear-gradient(rgba(26,43,59,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.04) 1px,transparent 1px);background-size:34px 34px;position:absolute;inset:0;pointer-events:none;"></div>'
        + '<div style="position:relative;display:grid;grid-template-columns:1fr 1px 1fr;gap:22px;">'
        + '<div style="display:flex;flex-direction:column;align-items:center;text-align:center;">'
        + '<div style="font:700 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--orange-deep);margin-bottom:14px;">' + this.esc(L.label) + '</div>'
        + '<div style="display:inline-flex;align-items:center;gap:8px;background:#fff;border:1.5px solid var(--orange);border-radius:10px;padding:8px 13px;box-shadow:0 12px 24px -10px rgba(249,115,22,.4);font:700 11px/1 var(--mono);color:var(--orange-deep);"><span style="width:6px;height:6px;border-radius:50%;background:var(--orange);"></span>' + this.esc(L.badge) + '</div>'
        + '<svg width="22" height="38" viewBox="0 0 22 38" style="display:block;"><path d="M11 2 V30" stroke="var(--orange)" stroke-width="2" stroke-dasharray="4 4" stroke-linecap="round"/><path d="M5 26 L11 33 L17 26" fill="none" stroke="var(--orange)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
        + '<div style="width:100%;display:flex;align-items:center;gap:10px;padding:11px 13px;border-radius:12px;border:1px solid var(--emerald-soft);background:#F5FBF8;"><span style="width:24px;height:24px;border-radius:50%;background:var(--emerald);display:flex;align-items:center;justify-content:center;flex-shrink:0;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 6"/></svg></span><span style="font:700 13px/1.2 var(--sans);color:var(--ink);text-align:left;flex:1;">' + this.esc(L.result) + '</span><span style="font:700 9.5px/1 var(--mono);letter-spacing:.08em;color:var(--emerald-deep);background:var(--emerald-soft);padding:4px 7px;border-radius:6px;">WON</span></div>'
        + '<div style="font-family:var(--serif);font-style:italic;font-size:13px;color:var(--muted);margin-top:12px;line-height:1.4;">' + this.esc(L.subnote) + '</div>'
        + '</div>'
        + '<div style="background:var(--border);"></div>'
        + '<div style="display:flex;flex-direction:column;align-items:center;text-align:center;">'
        + '<div style="font:700 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin-bottom:14px;">' + this.esc(Rr.label) + '</div>'
        + '<div style="display:inline-flex;align-items:center;gap:8px;background:#fff;border:1.5px solid var(--border2);border-radius:10px;padding:8px 13px;box-shadow:0 8px 18px -10px rgba(15,23,42,.2);font:700 11px/1 var(--mono);color:var(--muted);"><span style="width:6px;height:6px;border-radius:50%;background:var(--muted);"></span>' + this.esc(Rr.badge) + '</div>'
        + '<svg width="180" height="38" viewBox="0 0 180 38" style="display:block;"><path d="M90 2 V14 M90 14 H24 V30 M90 14 H68 V30 M90 14 H112 V30 M90 14 H156 V30" fill="none" stroke="var(--border2)" stroke-width="2" stroke-dasharray="4 4" stroke-linecap="round" stroke-linejoin="round"/></svg>'
        + '<div style="width:100%;display:flex;flex-direction:column;gap:6px;">' + rrows + '</div>'
        + '<div style="font-family:var(--serif);font-style:italic;font-size:13px;color:var(--muted);margin-top:12px;line-height:1.4;">' + this.esc(Rr.subnote) + '</div>'
        + '</div>'
        + '</div></div>'
        + '<figcaption style="font:500 12.5px/1.5 var(--sans);color:var(--muted);margin-top:12px;text-align:center;">' + this.esc(f.caption) + '</figcaption></figure>'; },

    bFlow(f) { const steps = (f.steps || []).slice(0, 4); const last = steps.length - 1;
      let inner = '';
      steps.forEach((s, i) => { const win = i === last;
        inner += '<div style="flex:1;background:' + (win ? '#F5FBF8' : '#fff') + ';border:1px solid ' + (win ? 'var(--emerald-soft)' : 'var(--border)') + ';border-radius:12px;padding:14px 12px;text-align:center;box-shadow:0 6px 16px -10px ' + (win ? 'rgba(16,185,129,.25)' : 'rgba(15,23,42,.2)') + ';">'
          + '<span style="display:inline-flex;width:26px;height:26px;border-radius:8px;background:' + (win ? 'var(--emerald)' : 'var(--orange-soft)') + ';color:' + (win ? '#fff' : 'var(--orange-deep)') + ';align-items:center;justify-content:center;font:800 12px/1 var(--mono);margin-bottom:9px;">' + (win ? '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 6"/></svg>' : (i + 1)) + '</span>'
          + '<div style="font:700 12.5px/1.25 var(--sans);color:var(--ink);">' + this.esc(s.label) + '</div>'
          + '<div style="font:400 11px/1.35 var(--serif);color:var(--muted);margin-top:4px;">' + this.esc(s.caption) + '</div></div>';
        if (i < last) { inner += '<div style="display:flex;align-items:center;flex-shrink:0;">' + this.arrowSm(i === last - 1 ? 'var(--emerald)' : 'var(--orange)') + '</div>'; }
      });
      return '<figure style="margin:0;"><div style="background:var(--paper2);border:1px solid var(--border);border-radius:18px;padding:26px 22px;box-shadow:0 18px 38px -22px rgba(15,23,42,.22);position:relative;overflow:hidden;">'
        + '<div style="background-image:linear-gradient(rgba(26,43,59,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.04) 1px,transparent 1px);background-size:34px 34px;position:absolute;inset:0;pointer-events:none;"></div>'
        + '<div style="position:relative;display:flex;align-items:stretch;justify-content:space-between;gap:6px;">' + inner + '</div></div>'
        + (f.caption ? '<figcaption style="font:500 12.5px/1.5 var(--sans);color:var(--muted);margin-top:12px;text-align:center;">' + this.esc(f.caption) + '</figcaption>' : '') + '</figure>'; },

    bBeforeAfter(f) { const before = (f.before || []), after = (f.after || []);
      const bRows = before.map(t => '<div style="display:flex;align-items:center;gap:9px;"><span style="width:18px;height:18px;border-radius:50%;background:rgba(239,68,68,.12);color:var(--red);display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + this.xSm('currentColor') + '</span><span style="font:500 13px/1.3 var(--sans);color:#8A2F26;text-decoration:line-through;">' + this.esc(t) + '</span></div>').join('');
      const aRows = after.map(t => '<div style="display:flex;align-items:center;gap:9px;"><span style="width:18px;height:18px;border-radius:50%;background:var(--emerald);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + this.ckSm() + '</span><span style="font:600 13px/1.3 var(--sans);color:var(--ink);">' + this.esc(t) + '</span></div>').join('');
      return '<div style="display:grid;grid-template-columns:1fr 44px 1fr;align-items:center;gap:0;">'
        + '<div style="background:#fff;border:1px solid var(--red-soft);border-radius:14px;padding:18px 18px 20px;box-shadow:0 2px 8px -4px rgba(15,23,42,.08);"><div style="font:700 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--red-deep);margin-bottom:14px;">' + this.esc(f.beforeLabel || 'Before') + '</div><div style="display:flex;flex-direction:column;gap:9px;">' + bRows + '</div></div>'
        + '<div style="display:flex;align-items:center;justify-content:center;">' + this.arrowSm('var(--orange)') + '</div>'
        + '<div style="background:#F5FBF8;border:1px solid var(--emerald-soft);border-radius:14px;padding:18px 18px 20px;box-shadow:0 10px 24px -14px rgba(16,185,129,.4);"><div style="font:700 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--emerald-deep);margin-bottom:14px;">' + this.esc(f.afterLabel || 'After') + '</div><div style="display:flex;flex-direction:column;gap:9px;">' + aRows + '</div></div>'
        + '</div>'; },

    bSteps(f) { const steps = (f.steps || []).slice(0, 5);
      const items = steps.map((s, i) => '<div style="display:flex;gap:16px;align-items:flex-start;padding:18px 20px;background:#fff;border:1px solid var(--border);border-radius:13px;box-shadow:0 2px 6px -2px rgba(15,23,42,.05);">'
        + '<span style="flex-shrink:0;width:30px;height:30px;border-radius:9px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font:800 14px/1 var(--mono);">' + (i + 1) + '</span>'
        + '<div><div style="font:700 16px/1.3 var(--sans);color:var(--ink);">' + this.esc(s.title) + '</div><p style="font-family:var(--serif);font-size:16px;line-height:1.6;color:var(--body);margin:6px 0 0;">' + this.esc(s.body) + '</p></div></div>').join('');
      return '<div style="display:flex;flex-direction:column;gap:12px;">' + items + '</div>'; },

    bPitfall(f) { const cards = (f.cards || []).slice(0, 4);
      const cell = c => '<div style="background:#fff;border:1px solid var(--border);border-radius:13px;padding:18px;box-shadow:0 2px 6px -2px rgba(15,23,42,.05);">'
        + '<span style="display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:8px;background:var(--red-soft);color:var(--red-deep);margin-bottom:12px;"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg></span>'
        + '<div style="font:700 15px/1.3 var(--sans);color:var(--ink);">' + this.esc(c.title) + '</div><p style="font-family:var(--serif);font-size:15px;line-height:1.6;color:var(--body);margin:6px 0 0;">' + this.esc(c.body) + '</p></div>';
      return '<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;">' + cards.map(cell).join('') + '</div>'; },

    bLink(f) { return '<div style="display:flex;align-items:center;gap:16px;padding:16px 18px;background:var(--paper2);border:1px solid var(--border);border-radius:13px;">'
      + '<span style="flex-shrink:0;width:38px;height:38px;border-radius:10px;background:var(--orange-soft);display:flex;align-items:center;justify-content:center;"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--orange-deep)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>'
      + '<span style="flex:1;min-width:0;"><span style="display:block;font:700 10px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--orange-deep);margin-bottom:5px;">' + this.esc(f.kicker || 'Keep reading') + '</span><span style="display:block;font:700 15px/1.3 var(--sans);color:var(--ink);">' + this.esc(f.title) + '</span><span style="display:block;font:400 13px/1.4 var(--serif);color:var(--muted);margin-top:3px;">' + this.esc(f.teaser) + '</span></span></div>'; },

    bCta(f) { return '<div style="position:relative;background:var(--paper2);border:1px solid var(--border2);border-radius:20px;padding:34px 34px 30px;overflow:hidden;">'
      + '<div style="position:absolute;inset:0;background-image:linear-gradient(rgba(26,43,59,.035) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.035) 1px,transparent 1px);background-size:34px 34px;pointer-events:none;"></div>'
      + '<div style="position:absolute;right:-120px;bottom:-150px;width:380px;height:380px;border-radius:50%;background:radial-gradient(circle,rgba(249,115,22,.14) 0%,rgba(249,115,22,0) 65%);pointer-events:none;"></div>'
      + '<div style="position:relative;max-width:520px;"><h2 style="font-family:var(--serif);font-weight:600;font-size:28px;line-height:1.15;letter-spacing:-.015em;color:var(--ink);margin:0;text-wrap:balance;">' + this.esc(f.headline) + '</h2>'
      + '<p style="font-family:var(--serif);font-size:16px;line-height:1.6;color:var(--muted);margin:12px 0 0;text-wrap:pretty;">' + this.esc(f.sub) + '</p>'
      + '<div style="display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:22px;"><a href="#" style="display:inline-flex;align-items:center;gap:8px;padding:14px 22px;background:var(--orange);color:#fff;border-radius:13px;font:700 15px/1 var(--sans);text-decoration:none;box-shadow:0 12px 26px -8px rgba(249,115,22,.5);">' + this.esc(f.primary || 'Start free trial') + '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>'
      + (f.secondary ? '<a href="#" style="display:inline-flex;align-items:center;gap:7px;font:700 14px/1 var(--sans);color:var(--ink);text-decoration:none;">' + this.esc(f.secondary) + '</a>' : '') + '</div></div></div>'; },

    bFaq(f) { const items = (f.items || []).slice(0, 6);
      const rows = items.map((it, i) => '<div style="border-bottom:1px solid var(--border);"><div style="display:flex;align-items:flex-start;justify-content:space-between;gap:18px;padding:20px 2px;"><span style="font:700 17px/1.4 var(--sans);color:var(--ink);">' + this.esc(it.q) + '</span><span style="flex-shrink:0;width:26px;height:26px;display:flex;align-items:center;justify-content:center;font:300 24px/1 var(--sans);color:' + (i === 0 ? 'var(--orange)' : 'var(--ink)') + ';transform:rotate(' + (i === 0 ? '135deg' : '0') + ');">+</span></div>' + (i === 0 ? '<p style="font-family:var(--serif);font-size:16px;line-height:1.7;color:var(--body);margin:0 0 20px;max-width:620px;text-wrap:pretty;">' + this.esc(it.a) + '</p>' : '') + '</div>').join('');
      return '<div style="border-top:1px solid var(--border);">' + rows + '</div>'; },

    coverDiagramFull(cov) {
      const t = cov.type || 'spread', e = this.esc.bind(this), s = cov.spread || {};
      if (t === 'spread') {
        const m = s.midpoint;
        const mark = m ? '<div style="position:relative;height:38px;"><div style="position:absolute;bottom:0;left:' + e(m.pct || 50) + '%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:flex-start;"><span style="font:700 11px/1 var(--mono);color:#fff;background:var(--ink);padding:5px 9px;border-radius:6px;white-space:nowrap;">' + e(m.value || '') + '</span><span style="width:2px;height:8px;background:var(--ink);margin-left:12px;"></span></div></div>' : '';
        return '<div style="background:#fff;border:1px solid var(--border);border-radius:16px;padding:22px;box-shadow:0 10px 28px -16px rgba(15,23,42,.2);">'
          + '<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:18px;"><div><div style="font:700 11px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);">' + e(s.label || 'The spread') + '</div><div style="font-family:var(--serif);font-style:italic;font-size:12px;color:var(--muted);margin-top:5px;">' + e(s.subtitle || '') + '</div></div><div style="font:900 38px/.9 var(--sans);letter-spacing:-.04em;color:var(--orange-deep);">' + e(s.multiplier || '') + '</div></div>'
          + mark
          + '<div style="height:12px;border-radius:999px;background:linear-gradient(90deg,var(--emerald) 0%,var(--orange) 55%,var(--red) 100%);margin-bottom:16px;"></div>'
          + '<div style="display:flex;justify-content:space-between;"><div style="display:flex;align-items:center;gap:8px;"><div style="width:10px;height:10px;border-radius:50%;background:var(--emerald);box-shadow:0 0 0 4px rgba(16,185,129,.16);flex-shrink:0;"></div><div><div style="font:900 24px/1 var(--sans);color:var(--ink);">' + e((s.lo || {}).value || '') + '</div><div style="font:600 11px/1.3 var(--sans);color:var(--muted);margin-top:4px;">' + e((s.lo || {}).label || '') + '</div></div></div>'
          + '<div style="display:flex;flex-direction:row-reverse;align-items:center;gap:8px;text-align:right;"><div style="width:10px;height:10px;border-radius:50%;background:var(--red);box-shadow:0 0 0 4px rgba(239,68,68,.16);flex-shrink:0;"></div><div><div style="font:900 24px/1 var(--sans);color:var(--ink);">' + e((s.hi || {}).value || '') + '</div><div style="font:600 11px/1.3 var(--sans);color:var(--muted);margin-top:4px;">' + e((s.hi || {}).label || '') + '</div></div></div></div></div>';
      }
      const v = cov.versus || {}, L = v.left || {}, Rr = v.right || {};
      if (t === 'versus') {
        return '<div style="background:#fff;border:1px solid var(--border);border-radius:16px;padding:20px 22px;box-shadow:0 10px 28px -16px rgba(15,23,42,.2);display:grid;grid-template-columns:1fr 1px 1fr;gap:16px;align-items:center;">'
          + '<div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:6px;"><span style="font:700 9px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;background:#fff;color:var(--orange-deep);border:1.5px solid var(--orange);padding:3px 7px;border-radius:6px;">' + e(L.badge || 'A') + '</span><div style="font:900 40px/.9 var(--sans);letter-spacing:-.04em;color:var(--emerald-deep);">' + e(L.value || '') + '</div><div style="font:600 11px/1.2 var(--sans);color:var(--muted);">' + e(L.sub || '') + '</div></div>'
          + '<div style="background:var(--border);height:72px;"></div>'
          + '<div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:6px;"><span style="font:700 9px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;background:#fff;color:var(--muted);border:1.5px solid var(--border2);padding:3px 7px;border-radius:6px;">' + e(Rr.badge || 'B') + '</span><div style="font:900 40px/.9 var(--sans);letter-spacing:-.04em;color:var(--red-deep);">' + e(Rr.value || '') + '</div><div style="font:600 11px/1.2 var(--sans);color:var(--muted);">' + e(Rr.sub || '') + '</div></div>'
          + '</div>';
      }
      if (t === 'steps') {
        const steps = (cov.stepsData || []).slice(0, 6);
        const dots = steps.map((st, i) => { const on = i === steps.length - 1; return '<span style="width:28px;height:28px;border-radius:50%;background:' + (on ? 'var(--orange)' : '#fff') + ';border:1.5px solid ' + (on ? 'var(--orange)' : 'var(--border2)') + ';font:800 12px/1 var(--sans);color:' + (on ? '#fff' : 'var(--muted)') + ';display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:' + (on ? '0 8px 18px -8px rgba(249,115,22,.5)' : 'none') + ';">' + (i + 1) + '</span>' + (i < steps.length - 1 ? '<span style="flex:1;height:2px;background:repeating-linear-gradient(90deg,var(--border2) 0 4px,transparent 4px 8px);min-width:10px;"></span>' : ''); }).join('');
        const labels = steps.map(st => '<div style="flex:1;text-align:center;font:600 10px/1.3 var(--sans);color:var(--muted);padding:0 2px;">' + e(st.label || '') + '</div>').join('');
        return '<div style="background:#fff;border:1px solid var(--border);border-radius:16px;padding:22px;box-shadow:0 10px 28px -16px rgba(15,23,42,.2);"><div style="display:flex;align-items:center;">' + dots + '</div><div style="display:flex;margin-top:10px;">' + labels + '</div>' + (cov.stepsCaption ? '<div style="font:600 12px/1.3 var(--sans);color:var(--muted);margin-top:14px;">' + e(cov.stepsCaption) + '</div>' : '') + '</div>';
      }
      if (t === 'bars') {
        const bars = (cov.barsData || []).slice(0, 5);
        const bItems = bars.map(b => '<div style="flex:1;height:' + e(b.height || 50) + '%;border-radius:5px 5px 0 0;background:' + (b.highlight ? 'linear-gradient(180deg,var(--emerald) 0%,var(--emerald-deep) 100%)' : 'var(--paper3)') + ';position:relative;"><span style="position:absolute;top:-18px;left:0;right:0;text-align:center;font:800 11px/1 var(--sans);color:var(--ink);">' + e(b.value || '') + '</span><span style="position:absolute;bottom:-18px;left:0;right:0;text-align:center;font:600 9px/1 var(--sans);color:var(--muted);">' + e(b.label || '') + '</span></div>').join('');
        return '<div style="background:#fff;border:1px solid var(--border);border-radius:16px;padding:22px 22px 34px;box-shadow:0 10px 28px -16px rgba(15,23,42,.2);"><div style="display:flex;align-items:flex-end;gap:10px;height:88px;">' + bItems + '</div>' + (cov.barsCaption ? '<div style="font:600 11px/1.3 var(--sans);color:var(--muted);margin-top:22px;">' + e(cov.barsCaption) + '</div>' : '') + '</div>';
      }
      return '';
    },

    coverDiagramMini(cov) {
      const t = cov.type || 'spread', e = this.esc.bind(this), s = cov.spread || {};
      if (t === 'spread') {
        return '<div style="margin-top:auto;background:#fff;border:1px solid var(--border);border-radius:10px;padding:11px;"><div style="display:flex;justify-content:space-between;margin-bottom:8px;"><div style="font:700 9px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--muted);">' + e(s.label || '') + '</div><div style="font:900 20px/.9 var(--sans);color:var(--orange-deep);">' + e(s.multiplier || '') + '</div></div><div style="height:7px;border-radius:999px;background:linear-gradient(90deg,var(--emerald),var(--orange) 55%,var(--red));margin-bottom:9px;"></div><div style="display:flex;justify-content:space-between;"><div><div style="font:900 13px/1 var(--sans);color:var(--ink);">' + e((s.lo || {}).value || '') + '</div><div style="font:500 9px/1.2 var(--sans);color:var(--muted);margin-top:2px;">' + e((s.lo || {}).label || '') + '</div></div><div style="text-align:right;"><div style="font:900 13px/1 var(--sans);color:var(--ink);">' + e((s.hi || {}).value || '') + '</div><div style="font:500 9px/1.2 var(--sans);color:var(--muted);margin-top:2px;">' + e((s.hi || {}).label || '') + '</div></div></div></div>';
      }
      const v = cov.versus || {}, L = v.left || {}, Rr = v.right || {};
      if (t === 'versus') {
        return '<div style="margin-top:auto;display:grid;grid-template-columns:1fr 1px 1fr;gap:11px;align-items:center;"><div style="text-align:center;"><span style="display:inline-flex;font:700 8px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;background:#fff;color:var(--orange-deep);border:1.5px solid var(--orange);padding:3px 6px;border-radius:5px;">' + e(L.badge || 'A') + '</span><div style="font:900 34px/.9 var(--sans);color:var(--emerald-deep);margin-top:7px;">' + e(L.value || '') + '</div><div style="font:600 10px/1.2 var(--sans);color:var(--muted);margin-top:3px;">' + e(L.sub || '') + '</div></div><div style="background:var(--border);height:54px;"></div><div style="text-align:center;"><span style="display:inline-flex;font:700 8px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;background:#fff;color:var(--muted);border:1.5px solid var(--border2);padding:3px 6px;border-radius:5px;">' + e(Rr.badge || 'B') + '</span><div style="font:900 34px/.9 var(--sans);color:var(--red-deep);margin-top:7px;">' + e(Rr.value || '') + '</div><div style="font:600 10px/1.2 var(--sans);color:var(--muted);margin-top:3px;">' + e(Rr.sub || '') + '</div></div></div>';
      }
      if (t === 'steps') {
        const steps = (cov.stepsData || []).slice(0, 6);
        const dots = steps.map((st, i) => { const on = i === steps.length - 1; return '<span style="width:26px;height:26px;border-radius:50%;background:' + (on ? 'var(--orange)' : '#fff') + ';border:1.5px solid ' + (on ? 'var(--orange)' : 'var(--border2)') + ';font:800 10px/1 var(--sans);color:' + (on ? '#fff' : 'var(--muted)') + ';display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:' + (on ? '0 5px 12px -5px rgba(249,115,22,.5)' : 'none') + ';">' + (i + 1) + '</span>' + (i < steps.length - 1 ? '<span style="flex:1;height:2px;background:repeating-linear-gradient(90deg,var(--border2) 0 4px,transparent 4px 8px);min-width:5px;"></span>' : ''); }).join('');
        return '<div style="margin-top:auto;"><div style="display:flex;align-items:center;">' + dots + '</div>' + (cov.stepsCaption ? '<div style="font:600 11px/1.3 var(--sans);color:var(--muted);margin-top:9px;">' + e(cov.stepsCaption) + '</div>' : '') + '</div>';
      }
      if (t === 'bars') {
        const bars = (cov.barsData || []).slice(0, 5);
        const bItems = bars.map(b => '<div style="flex:1;height:' + e(b.height || 50) + '%;border-radius:4px 4px 0 0;background:' + (b.highlight ? 'linear-gradient(180deg,var(--emerald) 0%,var(--emerald-deep) 100%)' : 'var(--paper3)') + ';position:relative;"><span style="position:absolute;top:-14px;left:0;right:0;text-align:center;font:800 9px/1 var(--sans);color:var(--ink);">' + e(b.value || '') + '</span><span style="position:absolute;bottom:-14px;left:0;right:0;text-align:center;font:600 8px/1 var(--sans);color:var(--muted);">' + e(b.label || '') + '</span></div>').join('');
        return '<div style="margin-top:auto;display:flex;align-items:flex-end;gap:7px;height:80px;">' + bItems + '</div>';
      }
      return '';
    },

    bConceptCoverFeatured(cov) {
      const e = this.esc.bind(this);
      const hl = this.emph(cov.headline || '', 'var(--orange-deep)').replace(/(<span[^>]*>)/, '$1<em style="font-style:italic;font-weight:500;">').replace(/<[/]span>/, '</em></span>');
      return '<div style="position:relative;overflow:hidden;background:var(--paper2);border:1px solid var(--border);border-radius:20px;padding:32px 36px;box-shadow:0 18px 40px -28px rgba(15,23,42,.24);"><div style="position:absolute;inset:0;pointer-events:none;background-image:linear-gradient(rgba(26,43,59,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.04) 1px,transparent 1px);background-size:34px 34px;"></div><div style="position:relative;display:grid;grid-template-columns:1.04fr 1fr;gap:36px;align-items:center;">'
        + '<div><div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;"><span style="font:800 10px/1 var(--sans);letter-spacing:.06em;text-transform:uppercase;color:#fff;background:var(--orange);padding:5px 9px;border-radius:6px;box-shadow:0 8px 18px -8px rgba(249,115,22,.5);">' + e(cov.badge || 'Guide') + '</span><span style="font:700 11px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);">' + e(cov.category || '') + '</span></div>'
        + '<h2 style="font:800 34px/1.08 var(--sans);letter-spacing:-.025em;color:var(--ink);margin:0 0 14px;text-wrap:balance;">' + hl + '</h2>'
        + '<p style="font-family:var(--serif);font-size:16px;line-height:1.55;color:var(--muted);margin:0 0 18px;">' + e(cov.dek || '') + '</p>'
        + '<div style="display:flex;align-items:center;gap:12px;"><span style="font:700 13px/1 var(--sans);color:var(--orange-deep);">Read &#8594;</span><span style="width:3px;height:3px;border-radius:50%;background:var(--border2);"></span><span style="font:600 12px/1 var(--sans);color:var(--muted);">' + e(cov.read || '') + '</span></div></div>'
        + this.coverDiagramFull(cov)
        + '</div></div>';
    },

    bConceptCoverCard(cov) {
      const e = this.esc.bind(this);
      const hl = (cov.headline || '').replace(/\[\[(.+?)\]\]/g, '$1');
      return '<div style="max-width:280px;background:#fff;border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 12px 30px -20px rgba(15,23,42,.28);"><div style="position:relative;height:188px;background:var(--paper2);border-bottom:1px solid var(--border);padding:16px;overflow:hidden;"><div style="position:absolute;inset:0;pointer-events:none;background-image:linear-gradient(rgba(26,43,59,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(26,43,59,.04) 1px,transparent 1px);background-size:26px 26px;"></div><div style="position:relative;height:100%;display:flex;flex-direction:column;"><div style="font:700 9px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);">' + e(cov.category || '') + '</div>'
        + this.coverDiagramMini(cov)
        + '</div></div><div style="padding:13px 15px 15px;"><div style="display:flex;align-items:center;gap:9px;"><span style="font:700 10px/1 var(--sans);color:var(--orange-deep);background:var(--orange-soft);border:1px solid #FFD9AE;padding:4px 8px;border-radius:999px;">' + e(cov.category || '') + '</span><span style="font:600 11px/1 var(--sans);color:var(--muted);">' + e(cov.read || '') + '</span></div><h3 style="font:800 15px/1.25 var(--sans);letter-spacing:-.02em;color:var(--ink);margin:9px 0 5px;">' + e(hl) + '</h3><p style="font-family:var(--serif);font-size:12.5px;line-height:1.5;color:var(--muted);margin:0;">' + e(cov.dek || '') + '</p><div style="display:flex;align-items:center;gap:7px;margin-top:11px;"><span style="width:22px;height:22px;border-radius:50%;background:var(--ink);color:#fff;font:800 8px/1 var(--sans);display:flex;align-items:center;justify-content:center;">LC</span><span style="font:600 10px/1 var(--sans);color:var(--ink);">Leandro Campos</span><span style="width:3px;height:3px;border-radius:50%;background:var(--border2);"></span><span style="font:500 10px/1 var(--sans);color:var(--muted);">Jun 2026</span></div></div></div>';
    },

    // Assemble the ordered output list: cover package → in-article figures.
    buildFigures(plan) {
      if (!plan) return [];
      const out = [];
      if (plan.cover || plan.hero) {
        out.push({ slug: '_sec', label: 'COVER PACKAGE · 3 ASSETS', html: '', isSec: true });
      }
      if (plan.cover) {
        out.push({ slug: 'SIZE A · featured cover (.bp-cover)', html: this.bConceptCoverFeatured(plan.cover), padded: false });
        out.push({ slug: 'SIZE B · card thumbnail (.bx-card)', html: this.bConceptCoverCard(plan.cover), padded: false });
      }
      if (plan.hero) out.push({ slug: 'SIZE C · social image 1200x630', html: this.bHero(plan.hero), padded: false });
      if (plan.og || (plan.figures && plan.figures.length)) {
        out.push({ slug: '_sec', label: 'IN-ARTICLE FIGURES', html: '', isSec: true });
      }
      if (plan.og) out.push({ slug: 'og-card', html: this.bOg(plan.og), padded: false });
      (plan.figures || []).forEach(f => out.push({ slug: f.element, html: this.renderFigure(f), padded: this.paddedFor(f.element) }));
      return out;
    },
  };

  // =====================================================================
  // React page
  // =====================================================================
  function MarkdownToFiguresPage() {
    const [md, setMd]         = useState(SAMPLE_MD);
    const [phase, setPhase]   = useState('idle'); // idle | loading | done | error
    const [plan, setPlan]     = useState(null);
    const [status, setStatus] = useState('Paste a post and click Generate, or load the sample.');
    const [warnings, setWarnings] = useState([]);
    const [copiedSlug, setCopiedSlug] = useState(null);
    const [dragOver, setDragOver] = useState(false);
    const fileRef = useRef(null);

    const items = plan ? R.buildFigures(plan) : [];

    const computeWarnings = (p) => {
      const w = [];
      if (!p.cover) w.push('Cover is missing — the planner must always return a concept cover.');
      const known = new Set(['hero', 'og', 'key-takeaway', 'note-callout', 'comparison-split', 'stat-trio', 'cost-table', 'comparison-table', 'pull-quote', 'process-flow', 'before-after', 'decision-steps', 'pitfall-grid', 'link-card', 'cta', 'concept-cover', 'faq', 'faq-accordion']);
      (p.figures || []).forEach(f => { if (!known.has(f.element)) w.push(`Unknown element "${f.element}" — skipped.`); });
      return w;
    };

    const generate = async () => {
      if (phase === 'loading') return;
      if (!md.trim()) { setStatus('Paste some markdown first.'); return; }
      setPhase('loading');
      setStatus('Reading the post and planning figures with Claude…');
      setWarnings([]);
      try {
        const p = await planFigures(md);
        const w = computeWarnings(p);
        setPlan(p);
        setWarnings(w);
        setPhase('done');
        const n = (p.figures || []).length;
        setStatus(`Generated cover + hero + OG + ${n} in-article figure${n === 1 ? '' : 's'}. Copy any block's HTML.`);
      } catch (e) {
        setPhase('error');
        setStatus(e.message || 'Generation failed.');
      }
    };

    const copy = (html, slug) => {
      const out = R.resolveVars(html);
      const done = () => { setCopiedSlug(slug); setStatus(`Copied "${slug}" HTML to clipboard.`); setTimeout(() => setCopiedSlug(null), 1600); };
      try {
        if (navigator.clipboard && navigator.clipboard.writeText) {
          navigator.clipboard.writeText(out).then(done, () => fallbackCopy(out, done));
        } else fallbackCopy(out, done);
      } catch (_e) { fallbackCopy(out, done); }
    };
    const fallbackCopy = (text, done) => {
      try { const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); done && done(); }
      catch (_e) { setStatus('Copy failed — select the HTML manually.'); }
    };

    const copyAll = () => {
      if (!items.length) return;
      const joined = items.filter(it => !it.isSec).map(it => '<!-- ' + it.slug + ' -->\n' + R.resolveVars(it.html)).join('\n\n');
      copy(joined, `all ${items.filter(it => !it.isSec).length} blocks`);
    };

    const readFile = (file) => {
      if (!file) return;
      const reader = new FileReader();
      reader.onload = () => { setMd(String(reader.result || '')); setStatus(`Loaded ${file.name}.`); };
      reader.readAsText(file);
    };

    // ── styles ──────────────────────────────────────────────────────────
    const ink = '#1A2B3B', orange = '#F97316', paper = '#EDE7D6', muted = '#7A715A';
    const s = {
      root: { display: 'flex', gap: 16, height: 'calc(100vh - 130px)', minHeight: 560, margin: '-24px', padding: 24 },
      // LEFT
      left: { width: 380, flexShrink: 0, background: ink, color: '#fff', display: 'flex', flexDirection: 'column', padding: 24, borderRadius: 14, overflow: 'hidden' },
      eyebrow: { display: 'inline-flex', alignItems: 'center', gap: 8, font: '700 10px/1 ui-monospace,monospace', letterSpacing: '.16em', textTransform: 'uppercase', color: orange, marginBottom: 14 },
      dot: { width: 6, height: 6, borderRadius: '50%', background: orange },
      h1: { fontSize: 22, fontWeight: 800, lineHeight: 1.15, letterSpacing: '-.02em', margin: '0 0 8px' },
      lead: { fontSize: 12.5, lineHeight: 1.55, color: 'rgba(255,255,255,.6)', margin: '0 0 16px' },
      labelRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 },
      smallLabel: { font: '700 9.5px/1 ui-monospace,monospace', letterSpacing: '.14em', textTransform: 'uppercase', color: 'rgba(255,255,255,.5)' },
      sample: { background: 'none', border: 'none', color: 'rgba(255,255,255,.55)', font: '600 11px/1 ui-monospace,monospace', cursor: 'pointer', textDecoration: 'underline', textUnderlineOffset: 2, padding: 0 },
      ta: { flex: 1, minHeight: 0, resize: 'none', width: '100%', background: '#0f1822', border: '1px solid ' + (dragOver ? orange : '#243240'), borderRadius: 10, color: '#c9d6e3', fontSize: 12, lineHeight: 1.6, padding: 14, outline: 'none', fontFamily: 'ui-monospace,SFMono-Regular,monospace', transition: 'border-color .15s' },
      genBtn: { marginTop: 14, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, padding: 13, background: orange, color: '#fff', border: 'none', borderRadius: 11, font: '700 14px/1 inherit', cursor: phase === 'loading' ? 'wait' : 'pointer', boxShadow: '0 12px 26px -10px rgba(249,115,22,.6)', opacity: phase === 'loading' ? 0.8 : 1 },
      statusLine: { font: '500 11.5px/1.5 ui-monospace,monospace', color: phase === 'error' ? '#FCA5A5' : 'rgba(255,255,255,.55)', marginTop: 11, minHeight: 18 },
      // RIGHT
      right: { flex: 1, minWidth: 0, overflow: 'auto', background: paper, borderRadius: 14, padding: '24px 28px 60px', position: 'relative' },
      rightInner: { maxWidth: 680, margin: '0 auto' },
      topbar: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginBottom: 18, position: 'sticky', top: -24, zIndex: 5, background: paper, padding: '6px 0 10px' },
      topLabel: { font: '700 10px/1 ui-monospace,monospace', letterSpacing: '.14em', textTransform: 'uppercase', color: muted },
      copyAllBtn: { display: 'inline-flex', alignItems: 'center', gap: 7, background: '#fff', border: '1px solid #D6CFB8', borderRadius: 8, padding: '7px 11px', font: '600 11px/1 ui-monospace,monospace', color: ink, cursor: 'pointer' },
      warnBox: { background: '#FFF7ED', border: '1px solid #FED7AA', borderRadius: 10, padding: '10px 12px', marginBottom: 16 },
      warnLine: { display: 'flex', gap: 7, alignItems: 'flex-start', font: '600 11.5px/1.45 inherit', color: '#9A3412' },
      emptyWrap: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', height: '70%', color: muted },
    };

    const SecHeader = (it, idx) => React.createElement('div', { key: idx, style: { padding: idx === 0 ? '0 0 10px' : '20px 0 10px', borderTop: idx === 0 ? 'none' : '1px solid #D6CFB8', marginTop: idx === 0 ? 0 : 12 } },
      React.createElement('span', { style: { font: '700 10px/1 ui-monospace,monospace', letterSpacing: '.16em', textTransform: 'uppercase', color: muted } }, it.label));

    const FigureCard = (it, idx) => {
      if (it.isSec) return SecHeader(it, idx);
      const body = React.createElement('div', {
        style: it.padded === false ? {} : { background: '#FCFAF2', border: '1px solid #D6CFB8', borderRadius: 16, padding: 24 },
        dangerouslySetInnerHTML: { __html: R.resolveVars(it.html) },
      });
      const header = React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, marginBottom: 9 } },
        React.createElement('span', { style: { font: '600 11px/1 ui-monospace,monospace', background: ink, color: '#fff', padding: '5px 9px', borderRadius: 5, whiteSpace: 'nowrap' } }, it.slug),
        React.createElement('button', {
          onClick: () => copy(it.html, it.slug),
          style: { display: 'inline-flex', alignItems: 'center', gap: 6, background: '#fff', border: '1px solid #D6CFB8', borderRadius: 7, padding: '5px 9px', font: '600 10px/1 ui-monospace,monospace', color: copiedSlug === it.slug ? '#0F8F66' : muted, cursor: 'pointer' },
        },
          React.createElement('span', { dangerouslySetInnerHTML: { __html: '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>' } }),
          copiedSlug === it.slug ? 'Copied' : 'Copy HTML'));
      return React.createElement('div', { key: idx, style: { marginBottom: 22 } }, header, body);
    };

    return (
      <div className="page-content" style={s.root}>
        {/* LEFT — input */}
        <div style={s.left}>
          <div style={s.eyebrow}><span style={s.dot} />Live · Markdown → Figures</div>
          <h1 style={s.h1}>Paste a post. Get on-brand figures.</h1>
          <p style={s.lead}>Claude reads your markdown, picks the right element for each block from the locked house registry, and renders the cover, OG card and in-article figures. Copy any block's HTML straight into your post.</p>

          <div style={s.labelRow}>
            <span style={s.smallLabel}>Post markdown</span>
            <div style={{ display: 'flex', gap: 12 }}>
              <button style={s.sample} onClick={() => fileRef.current && fileRef.current.click()}>upload .md</button>
              <button style={s.sample} onClick={() => { setMd(SAMPLE_MD); setStatus('Sample markdown loaded.'); }}>load sample</button>
            </div>
          </div>
          <input ref={fileRef} type="file" accept=".md,.markdown,.txt,text/markdown" style={{ display: 'none' }} onChange={e => readFile(e.target.files && e.target.files[0])} />

          <textarea
            value={md}
            onChange={e => setMd(e.target.value)}
            spellCheck={false}
            placeholder="# Paste your article markdown here…"
            style={s.ta}
            onDragOver={e => { e.preventDefault(); setDragOver(true); }}
            onDragLeave={() => setDragOver(false)}
            onDrop={e => { e.preventDefault(); setDragOver(false); const f = e.dataTransfer.files && e.dataTransfer.files[0]; if (f) readFile(f); }}
          />

          <button style={s.genBtn} onClick={generate} disabled={phase === 'loading'}>
            <Icon name={phase === 'loading' ? 'Loader' : 'Zap'} size={15} color="#fff" fill={phase === 'loading' ? 'none' : '#fff'} />
            {phase === 'loading' ? 'Generating…' : 'Generate figures'}
          </button>
          <div style={s.statusLine}>{status}</div>
        </div>

        {/* RIGHT — output */}
        <div style={s.right}>
          <div style={s.rightInner}>
            <div style={s.topbar}>
              <span style={s.topLabel}>{items.length ? `Generated figures · ${items.filter(it => !it.isSec).length} blocks` : 'Generated figures'}</span>
              <button style={s.copyAllBtn} onClick={copyAll} disabled={!items.length}>
                <span dangerouslySetInnerHTML={{ __html: '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>' }} />
                Copy all HTML
              </button>
            </div>

            {warnings.length > 0 && (
              <div style={s.warnBox}>
                {warnings.map((w, i) => (
                  <div key={i} style={{ ...s.warnLine, marginTop: i ? 6 : 0 }}>
                    <Icon name="ShieldAlert" size={13} color="#9A3412" />
                    <span>{w}</span>
                  </div>
                ))}
              </div>
            )}

            {items.length
              ? items.map((it, i) => FigureCard(it, i))
              : (
                <div style={s.emptyWrap}>
                  <Icon name="Image" size={28} color="#C9BFA3" />
                  <div style={{ fontSize: 13, fontWeight: 700, marginTop: 12, color: '#9C9176' }}>No figures yet</div>
                  <div style={{ fontSize: 12, marginTop: 4, maxWidth: 320, lineHeight: 1.5, color: '#B0A687' }}>Paste a markdown post on the left and click Generate. You'll get a cover package plus in-article figures, each copy-paste clean.</div>
                </div>
              )}
          </div>
        </div>
      </div>
    );
  }

  window.MarkdownToFiguresPage = MarkdownToFiguresPage;
  window.__figuresRenderer = R; // exposed for debugging / preview verification
})();
