/* Artifact preview renderers — each takes the artifact JSON and returns
   JSX. They use the ContentEditable wrapper so each field is inline-editable.
   onEdit(fieldKey, newValue) is called whenever a field is changed.

   Fields can be: scalar (string) or arrays/nested objects we encode as paths.
*/

const { useState, useEffect, useRef, useMemo } = React;

// ---------- Editable text ----------
// Includes live brand QA: banned words highlighted via dotted-red underline,
// with a hover tooltip explaining why.
const BANNED_RE = (() => {
  const terms = (window.VENTUM_BRAND?.banned || []).filter(Boolean);
  if (!terms.length) return null;
  // word-boundary-ish match. The trailing \b doesn't work if a term ends in
  // a non-word char like "%" — so we only require a boundary at the START,
  // and let the END float. Case-insensitive.
  const escaped = terms.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
  return new RegExp('\\b(' + escaped.join('|') + ')', 'gi');
})();

function flagBannedInElement(el) {
  if (!el || !BANNED_RE) return;
  // remove old marks (preserving caret-safe approach: only when not focused)
  if (document.activeElement === el) return;
  // strip prior highlights
  el.querySelectorAll('mark.banned-word').forEach((m) => {
    const t = document.createTextNode(m.textContent);
    m.parentNode.replaceChild(t, m);
  });
  el.normalize();
  // find textnodes & wrap matches
  const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null);
  const tnodes = [];
  let n; while ((n = walker.nextNode())) tnodes.push(n);
  tnodes.forEach((node) => {
    const text = node.nodeValue;
    if (!text) return;
    BANNED_RE.lastIndex = 0;
    if (!BANNED_RE.test(text)) return;
    BANNED_RE.lastIndex = 0;
    const frag = document.createDocumentFragment();
    let last = 0, m;
    while ((m = BANNED_RE.exec(text))) {
      if (m.index > last) frag.appendChild(document.createTextNode(text.slice(last, m.index)));
      const mark = document.createElement('mark');
      mark.className = 'banned-word';
      mark.title = `"${m[1]}" is in the brand banned-phrases list — soften or replace.`;
      mark.textContent = m[1];
      frag.appendChild(mark);
      last = m.index + m[1].length;
    }
    if (last < text.length) frag.appendChild(document.createTextNode(text.slice(last)));
    node.parentNode.replaceChild(frag, node);
  });
}

// Account logo with onError cascade — tries the full VENTUM_LOGO source
// stack (logo.dev → clearbit → duckduckgo → google favicon) until one
// loads. Without this cascade, a 404 on the primary source leaves a
// broken/empty image in the slide. Accepts standard <img> styling.
//
// The `filter` prop carries the slide context's "preferred treatment"
// for dark backgrounds (typically "brightness(0) invert(1)" to render
// any logo as a clean white silhouette). intake.logo_color_mode lets
// the operator override the default per brief:
//   'auto'  — apply the passed filter if any (current behavior)
//   'mono'  — always apply brightness(0) invert(1), regardless of context
//   'color' — never apply a filter; show the logo in full color
function AccountLogoImg({ intake, style, alt = '', filter }) {
  const cascade = React.useMemo(
    () => (window.VENTUM_IMAGERY?.customerLogoCascade?.(intake) || []),
    [intake?.account_logo_url, intake?.account_domain]
  );
  const [idx, setIdx] = useState(0);
  const [failed, setFailed] = useState(false);
  if (failed || !cascade.length) return null;

  const mode = intake?.logo_color_mode || 'auto';
  const effectiveFilter = mode === 'color' ? null
                        : mode === 'mono'  ? 'brightness(0) invert(1)'
                        : (filter || null);

  return (
    <img
      src={cascade[idx]}
      alt={alt}
      onError={() => {
        if (idx + 1 < cascade.length) setIdx(idx + 1);
        else setFailed(true);
      }}
      style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain', ...(effectiveFilter ? { filter: effectiveFilter } : {}), ...style }}
    />
  );
}

function Editable({ value, onChange, tag = 'span', className = '', multiline = false, placeholder = '', style = {}, scaleKey }) {
  const ref = useRef(null);
  const debounceRef = useRef(null);
  const userTypingRef = useRef(false);

  // Per-field zoom. persistKeyRef.current identifies which scale slot in
  // window.__ventumEditableScales this Editable owns. The key needs to
  // survive text edits (the old value-based key reshuffled when the
  // operator changed a headline, losing the scale).
  //
  // Identity strategy:
  //   1. Caller-provided scaleKey prop — preferred, completely stable.
  //   2. DOM path fingerprint (tag chain back to the nearest data-slide-idx
  //      / data-artifact ancestor, plus sibling indices) — stable across
  //      text edits because it depends only on structure, not content.
  //      Recomputed once after mount because useMemo runs before ref attaches.
  //   3. Last-resort value-based key — for backward-compat with scales
  //      already saved under the old scheme.
  const initialKey = useMemo(() => {
    if (scaleKey) return 'k|' + scaleKey;
    const txt = (value || '').slice(0, 80);
    return 'v|' + tag + '|' + (className || '') + '|' + txt;
  }, []);
  const persistKeyRef = useRef(initialKey);
  if (!window.__ventumEditableScales) window.__ventumEditableScales = {};
  const [scale, _setScale] = useState(() => window.__ventumEditableScales[initialKey] || 1);

  // After mount, compute the structural path key and migrate any scale
  // sitting on the legacy value-based key onto the new path key.
  useEffect(() => {
    if (scaleKey) return; // caller-provided key already stable
    if (!ref.current) return;
    const parts = [];
    let node = ref.current;
    let depth = 0;
    while (node && depth < 12) {
      const idx = node.parentElement
        ? Array.prototype.indexOf.call(node.parentElement.children, node)
        : 0;
      parts.push((node.tagName || 'X') + idx);
      if (node.dataset && (node.dataset.slideIdx != null || node.dataset.artifact != null)) break;
      node = node.parentElement;
      depth++;
    }
    if (!parts.length) return;
    const pathKey = 'p|' + parts.reverse().join('>');
    if (pathKey === persistKeyRef.current) return;
    const cache = window.__ventumEditableScales;
    // Migrate any prior scale from the legacy key to the new path key.
    if (cache[persistKeyRef.current] != null && cache[pathKey] == null) {
      cache[pathKey] = cache[persistKeyRef.current];
    }
    persistKeyRef.current = pathKey;
    const stored = cache[pathKey];
    if (stored != null && stored !== scale) _setScale(stored);
  }, []);
  const setScale = (next) => {
    const n = typeof next === 'function' ? next(scale) : next;
    const k = persistKeyRef.current;
    window.__ventumEditableScales[k] = n;
    _setScale(n);
    // Notify app-level state so the scales get folded into intake._field_scales
    // and ride along with cloud autosave to Supabase. Without this, A−/A+
    // changes lived only in the browser session and reverted on refresh.
    try { window.dispatchEvent(new CustomEvent('ventum-scale-changed', { detail: { key: k, scale: n } })); } catch (_) {}
  };

  const [focused, setFocused] = useState(false);
  const [rect, setRect] = useState(null);

  useEffect(() => {
    // Skip reset if the change came from the user typing — would kill the caret.
    if (userTypingRef.current) {
      userTypingRef.current = false;
      return;
    }
    if (ref.current && ref.current.innerText !== (value || '')) {
      ref.current.innerText = value || '';
      flagBannedInElement(ref.current);
    }
  }, [value]);

  // Flush any pending text to onChange. Called on input (debounced via
  // onInput handler), on blur (immediate), and on unmount (immediate)
  // so a user typing then navigating to Room 6 without blurring doesn't
  // lose their edit.
  const flushText = () => {
    if (debounceRef.current) {
      clearTimeout(debounceRef.current);
      debounceRef.current = null;
    }
    if (!ref.current) return;
    const text = ref.current.innerText;
    if (text !== value) {
      userTypingRef.current = true;
      onChange(text);
    }
  };

  // Flush on unmount — critical for the Room 5 → Room 6 navigation case
  // where the user typed but didn't click out of the field first.
  useEffect(() => () => flushText(), []);

  // Keep toolbar pinned to the element while focused (handles scroll +
  // window resize). Read getBoundingClientRect on every animation frame
  // while focus is active.
  useEffect(() => {
    if (!focused) return;
    let raf;
    const tick = () => {
      if (ref.current) setRect(ref.current.getBoundingClientRect());
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, [focused]);

  const bump = (delta) => setScale(s => Math.max(0.4, Math.min(3, Number((s + delta).toFixed(2)))));
  const resetScale = () => setScale(1);

  const Tag = tag;
  return (
    <>
      <Tag
        ref={ref}
        contentEditable
        suppressContentEditableWarning
        className={"editable " + className}
        style={{ ...style, ...(scale !== 1 ? { zoom: scale } : {}) }}
        data-placeholder={placeholder}
        onFocus={(e) => {
          // strip highlights while editing so caret is stable
          e.currentTarget.querySelectorAll('mark.banned-word').forEach((m) => {
            const t = document.createTextNode(m.textContent);
            m.parentNode.replaceChild(t, m);
          });
          e.currentTarget.normalize();
          setFocused(true);
        }}
        onInput={() => {
          // Debounce writes back so React state doesn't churn per keystroke.
          if (debounceRef.current) clearTimeout(debounceRef.current);
          debounceRef.current = setTimeout(flushText, 250);
        }}
        onBlur={(e) => {
          flushText();
          flagBannedInElement(e.currentTarget);
          // Delay hiding so a click on the toolbar registers first
          setTimeout(() => setFocused(false), 180);
        }}
        onKeyDown={(e) => {
          if (e.metaKey || e.ctrlKey) {
            if (e.key === '=' || e.key === '+') { e.preventDefault(); bump(0.1); }
            else if (e.key === '-' || e.key === '_') { e.preventDefault(); bump(-0.1); }
            else if (e.key === '0') { e.preventDefault(); resetScale(); }
          }
        }}
      />
      {focused && rect && ReactDOM.createPortal(
        <div
          className="editable-fz-ctl"
          data-editor-only="true"
          // Position above the element. Falls below if too close to the top.
          style={{
            position: 'fixed',
            zIndex: 9999,
            top: rect.top > 36 ? rect.top - 32 : rect.bottom + 6,
            left: Math.max(8, Math.min(window.innerWidth - 180, rect.left)),
            display: 'flex',
            alignItems: 'center',
            gap: 2,
            padding: '4px 6px',
            background: 'var(--navy, #0B1F33)',
            color: 'white',
            borderRadius: 3,
            boxShadow: '0 4px 16px -4px rgba(0,0,0,0.35)',
            fontFamily: 'var(--mono)',
            fontSize: 10,
            letterSpacing: '0.1em',
            userSelect: 'none'
          }}
          // Don't blur the editable when clicking the toolbar
          onMouseDown={(e) => e.preventDefault()}
        >
          <button
            onClick={() => bump(-0.1)}
            title="Smaller (⌘−)"
            style={{ background: 'transparent', border: 'none', color: 'white', padding: '2px 8px', cursor: 'pointer', fontSize: 14, lineHeight: 1, fontFamily: 'inherit' }}
          >A−</button>
          <span style={{ minWidth: 36, textAlign: 'center', opacity: 0.85, fontSize: 9.5 }}>
            {Math.round(scale * 100)}%
          </span>
          <button
            onClick={() => bump(0.1)}
            title="Bigger (⌘+)"
            style={{ background: 'transparent', border: 'none', color: 'white', padding: '2px 8px', cursor: 'pointer', fontSize: 14, lineHeight: 1, fontFamily: 'inherit' }}
          >A+</button>
          {scale !== 1 && (
            <button
              onClick={resetScale}
              title="Reset (⌘0)"
              style={{ background: 'transparent', border: '1px solid rgba(255,255,255,0.25)', color: 'white', padding: '2px 6px', cursor: 'pointer', fontSize: 9, lineHeight: 1, fontFamily: 'inherit', borderRadius: 2, marginLeft: 4 }}
            >Reset</button>
          )}
        </div>,
        document.body
      )}
    </>
  );
}

// ---------- Editable image ----------
// Click "Replace" → popover with library tiles + upload button + position/zoom/crop adjusts.
// Stores src via onChange(slot, dataUrl), adjustments via onChangeAdjust(slot, adj).
function EditableImage({
  src,
  slot = 'hero',
  overrides = {},
  adjustments = {},
  onChange,
  onChangeAdjust,
  alt = '',
  label = 'Replace',
  fit: defaultFit = 'cover',
  className = '',
  imgStyle = {},
  containerStyle = {}
}) {
  const inputRef = useRef(null);
  const libraryInputRef = useRef(null);
  const menuRef = useRef(null);
  const btnRef = useRef(null);
  const [open, setOpen] = useState(false);
  const [anchor, setAnchor] = useState(null); // viewport-relative coords for the portal'd menu
  const [teamLibrary, setTeamLibrary] = useState([]);
  const [teamLibLoading, setTeamLibLoading] = useState(false);
  // An override is "usable" only if it's a real URL. The localStorage
  // autosave used to replace oversized data URLs with the literal string
  // `[stripped:dataurl]`; if that gets restored into image_overrides it
  // becomes the IMG src and 404s. Treat any non-URL-looking value as
  // missing so the prop `src` (vertical/product default) takes over.
  const rawOverride = overrides[slot];
  const overrideUsable = typeof rawOverride === 'string'
    && rawOverride.length > 0
    && !rawOverride.startsWith('[')
    && (rawOverride.startsWith('http') || rawOverride.startsWith('data:') || rawOverride.startsWith('assets/') || rawOverride.startsWith('/'));
  const effective = overrideUsable ? rawOverride : src;
  const adj = adjustments[slot] || {};
  const fit = adj.fit || defaultFit;
  // position can be 'X% Y%' (string from anchor grid) OR { x, y } (from sliders/drag)
  // Normalize to { x, y } numbers in 0..100.
  let posX = 50, posY = 50;
  if (typeof adj.position === 'string') {
    const m = adj.position.match(/(-?[\d.]+)%\s+(-?[\d.]+)%/);
    if (m) { posX = parseFloat(m[1]); posY = parseFloat(m[2]); }
  } else if (adj.position && typeof adj.position === 'object') {
    posX = adj.position.x ?? 50;
    posY = adj.position.y ?? 50;
  }
  if (typeof adj.x === 'number') posX = adj.x;
  if (typeof adj.y === 'number') posY = adj.y;
  const position = `${posX}% ${posY}%`;
  const zoom = Number(adj.zoom) > 1 ? Number(adj.zoom) : 1;

  // ---- Photo-style filter adjustments ----
  // Each is 0..200 with 100 = neutral (CSS filter percent semantics).
  const brightness = adj.brightness != null ? adj.brightness : 100;
  const contrast   = adj.contrast   != null ? adj.contrast   : 100;
  const saturation = adj.saturation != null ? adj.saturation : 100;
  const tintMode   = adj.tint || 'none'; // 'none' | 'navy' | 'teal'
  const filterStr = `brightness(${brightness}%) contrast(${contrast}%) saturate(${saturation}%)`;

  // ---- Drag-to-pan on the live preview ----
  const dragRef = useRef(null);
  const dragState = useRef(null);
  useEffect(() => {
    const el = dragRef.current;
    if (!el || !onChangeAdjust) return;
    const onDown = (e) => {
      const rect = el.getBoundingClientRect();
      dragState.current = {
        startClientX: e.clientX,
        startClientY: e.clientY,
        startX: posX,
        startY: posY,
        rect
      };
      el.style.cursor = 'grabbing';
      e.preventDefault();
    };
    const onMove = (e) => {
      const st = dragState.current;
      if (!st) return;
      const dx = e.clientX - st.startClientX;
      const dy = e.clientY - st.startClientY;
      // Translate movement into percent — drag right -> show more of right edge -> X decreases
      const xPct = Math.max(0, Math.min(100, st.startX - (dx / st.rect.width) * 100));
      const yPct = Math.max(0, Math.min(100, st.startY - (dy / st.rect.height) * 100));
      setAdj({ x: xPct, y: yPct });
    };
    const onUp = () => {
      if (dragState.current && el) el.style.cursor = 'grab';
      dragState.current = null;
    };
    el.addEventListener('mousedown', onDown);
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    return () => {
      el.removeEventListener('mousedown', onDown);
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    };
  }, [posX, posY, onChangeAdjust]);

  // close on outside click + reposition on scroll/resize
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {
      if (
        (menuRef.current && menuRef.current.contains(e.target)) ||
        (btnRef.current && btnRef.current.contains(e.target))
      ) return;
      setOpen(false);
    };
    const reposition = () => {
      if (!btnRef.current) return;
      const r = btnRef.current.getBoundingClientRect();
      setAnchor({ top: r.top, right: r.right, bottom: r.bottom, left: r.left });
    };
    document.addEventListener('mousedown', onDoc);
    window.addEventListener('scroll', reposition, true);
    window.addEventListener('resize', reposition);
    return () => {
      document.removeEventListener('mousedown', onDoc);
      window.removeEventListener('scroll', reposition, true);
      window.removeEventListener('resize', reposition);
    };
  }, [open]);

  const openMenu = (e) => {
    e.stopPropagation();
    if (btnRef.current) {
      const r = btnRef.current.getBoundingClientRect();
      setAnchor({ top: r.top, right: r.right, bottom: r.bottom, left: r.left });
    }
    setOpen((o) => !o);
  };

  // Load team-uploaded library entries when the menu opens. Refresh on
  // every open so a colleague's new upload shows up immediately without
  // a page reload.
  useEffect(() => {
    if (!open) return;
    if (!window.VentumStorage?.listLibraryAssets) return;
    let cancelled = false;
    setTeamLibLoading(true);
    window.VentumStorage.listLibraryAssets()
      .then((rows) => { if (!cancelled) setTeamLibrary(rows || []); })
      .catch(() => { if (!cancelled) setTeamLibrary([]); })
      .finally(() => { if (!cancelled) setTeamLibLoading(false); });
    return () => { cancelled = true; };
  }, [open]);

  const pickUpload = (e) => {
    e.stopPropagation();
    e.preventDefault();
    inputRef.current?.click();
  };
  const pickLibraryUpload = (e) => {
    e.stopPropagation();
    e.preventDefault();
    libraryInputRef.current?.click();
  };
  const handleLibraryFile = async (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    e.target.value = '';
    if (!window.VentumStorage?.addLibraryAsset) {
      window.__toast && window.__toast('Library not available');
      return;
    }
    // Pre-fill the label with the file's basename for speed.
    const defaultLabel = (f.name || 'image').replace(/\.[^.]+$/, '').replace(/[-_]+/g, ' ');
    const label = window.prompt('Photo label (shown on hover)', defaultLabel);
    if (label === null) return; // cancel
    const tagsRaw = window.prompt('Tags (comma-separated — e.g. hospitality, hotel, lobby)', '');
    if (tagsRaw === null) return;
    const tags = tagsRaw.split(',').map(t => t.trim()).filter(Boolean);
    try {
      window.__toast && window.__toast('Adding to library…');
      const row = await window.VentumStorage.addLibraryAsset(f, { label, tags, suggestedName: f.name });
      setTeamLibrary((cur) => [row, ...cur]);
      if (onChange) onChange(slot, row.url); // immediately use it on this artifact
      window.__toast && window.__toast('Added to library');
    } catch (err) {
      console.warn('[library] add failed', err);
      window.__toast && window.__toast('Failed to add to library');
    }
  };
  const removeFromLibrary = async (asset) => {
    if (!window.VentumStorage?.deleteLibraryAsset) return;
    const ok = window.confirm(`Remove "${asset.label || 'this image'}" from the team library?`);
    if (!ok) return;
    try {
      await window.VentumStorage.deleteLibraryAsset(asset.id);
      setTeamLibrary((cur) => cur.filter(a => a.id !== asset.id));
      window.__toast && window.__toast('Removed from library');
    } catch (err) {
      console.warn('[library] delete failed', err);
      window.__toast && window.__toast('Failed to remove');
    }
  };
  const handleFile = async (e) => {
    const f = e.target.files?.[0];
    if (!f || !onChange) return;
    e.target.value = '';
    // Upload to Supabase Storage and store the resulting public URL —
    // keeps the artifact JSON tiny instead of embedding a base64
    // megablob. Falls back to a data URL only if Storage is unavailable
    // (offline / Supabase down) so the operator's workflow doesn't stall.
    if (window.VentumStorage?.uploadBriefImage) {
      try {
        window.__toast && window.__toast('Uploading image…');
        const url = await window.VentumStorage.uploadBriefImage(f, f.name || 'image');
        onChange(slot, url);
        setOpen(false);
        window.__toast && window.__toast('Image uploaded');
        return;
      } catch (err) {
        console.warn('[upload] Storage upload failed, falling back to data URL', err?.message || err);
        // Loud, blocking notice — a replaced image that only lives on this
        // device is a data-integrity risk (teammates won't see it, and it must
        // be re-uploaded to share). It is NOT lost on reload (kept in the
        // durable IndexedDB shadow copy), but the operator must know.
        window.alert(
          'This image could NOT be uploaded to the cloud (likely a connection issue or the "brief-images" Storage bucket isn\'t set up yet).\n\n' +
          'It has been kept on THIS device, so it will not be lost when you reload — but teammates won\'t see it until you re-upload it. ' +
          'Retry the upload before sharing this brief.'
        );
      }
    }
    // Fallback: encode as data URL (kept locally; the durable IndexedDB shadow
    // copy preserves it across reloads even though localStorage strips it).
    const reader = new FileReader();
    reader.onload = () => {
      onChange(slot, reader.result);
      setOpen(false);
    };
    reader.readAsDataURL(f);
  };
  const pickLibrary = (url) => {
    onChange && onChange(slot, url);
    setOpen(false);
  };
  const setAdj = (patch) => {
    if (!onChangeAdjust) return;
    onChangeAdjust(slot, { ...adj, ...patch });
  };

  const library = (window.VENTUM_IMAGERY?.library || []);
  const posGrid = [
    ['0% 0%', '50% 0%', '100% 0%'],
    ['0% 50%', '50% 50%', '100% 50%'],
    ['0% 100%', '50% 100%', '100% 100%']
  ];

  // Portal positioning — menu sits above-and-left of the Replace button,
  // flips below if it can't fit above. Compact ~440px so it lands cleanly.
  let menuStyle = { display: 'none' };
  if (open && anchor) {
    const MENU_W = Math.min(1280, window.innerWidth - 48);
    const MENU_H = window.innerHeight - 48;
    menuStyle = {
      position: 'fixed',
      top: '50%',
      left: '50%',
      transform: 'translate(-50%, -50%)',
      width: MENU_W,
      height: MENU_H,
      overflow: 'hidden',
      zIndex: 9999,
      display: 'grid',
      gridTemplateColumns: '380px 1fr'
    };
  }

  // Tell the rest of the page that an image-replace menu is open so
  // the layout switcher / deck nav can step out of the way.
  useEffect(() => {
    document.body.classList.toggle('img-menu-open', open);
    return () => document.body.classList.remove('img-menu-open');
  }, [open]);

  const menuNode = open ? (
    <>
      <div className="editable-img__backdrop" onClick={() => setOpen(false)} />
      <div ref={menuRef} className="editable-img__menu editable-img__menu--portal" style={menuStyle} onClick={(e) => e.stopPropagation()}>
        {/* LEFT pane — live preview, drag to pan */}
        <div className="editable-img__previewpane">
          <div
            className="editable-img__previewframe"
            ref={dragRef}
            style={{ cursor: onChangeAdjust ? 'grab' : 'default' }}
          >
            <img
              src={effective}
              alt=""
              draggable={false}
              onError={(e) => {
                const fb = window.VENTUM_IMAGERY?.fallbackFor?.(effective);
                if (fb && e.target.src !== fb) e.target.src = fb;
              }}
              style={{
                position: 'absolute', inset: 0,
                width: '100%', height: '100%',
                objectFit: fit,
                objectPosition: position,
                transform: zoom > 1 ? `scale(${zoom})` : 'none',
                transformOrigin: position,
                filter: filterStr,
                pointerEvents: 'none',
                userSelect: 'none'
              }}
            />
            {tintMode !== 'none' && (
              <div style={{
                position: 'absolute', inset: 0,
                background: tintMode === 'navy' ? 'rgba(11,31,51,0.35)' : 'rgba(34,184,167,0.30)',
                mixBlendMode: 'multiply',
                pointerEvents: 'none'
              }} />
            )}
          </div>
          <div className="editable-img__previewmeta">
            <span className="mono">{onChangeAdjust ? 'Drag to pan · live preview' : 'Live preview · matches artifact'}</span>
          </div>
        </div>
        {/* RIGHT pane — picker + adjust controls */}
        <div className="editable-img__rightpane">
      <div className="editable-img__menu-head">
        <span className="mono">Replace image</span>
        <button className="editable-img__close" onClick={() => setOpen(false)} aria-label="Close">×</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
        <button className="editable-img__upload mono" onClick={pickUpload}>
          <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" style={{ marginRight: 8 }}>
            <path d="M8 11V2M4 6l4-4 4 4" strokeLinecap="round" strokeLinejoin="round" />
            <path d="M2 11v2a1 1 0 001 1h10a1 1 0 001-1v-2" strokeLinecap="round" />
          </svg>
          Upload one-off
        </button>
        <button className="editable-img__upload mono" onClick={pickLibraryUpload} title="Upload an image and add it to the team library so it's available on every artifact">
          <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" style={{ marginRight: 8 }}>
            <rect x="1.5" y="3" width="13" height="10" rx="1" />
            <path d="M8 6v4M6 8h4" strokeLinecap="round" />
          </svg>
          Add to library
        </button>
      </div>
      {teamLibrary.length > 0 && (
        <>
          <div className="editable-img__menu-sep mono">
            Team library
            <span style={{ float: 'right', opacity: 0.6, textTransform: 'none', letterSpacing: 0 }}>{teamLibrary.length}</span>
          </div>
          <div className="editable-img__library">
            {teamLibrary.map((item) => (
              <div
                key={item.id}
                className={"editable-img__tile" + (effective === item.url ? ' is-active' : '')}
                style={{ position: 'relative', padding: 0 }}
                title={item.label || ''}
              >
                <button
                  style={{ position: 'absolute', inset: 0, background: 'none', border: 0, padding: 0, cursor: 'pointer', width: '100%', height: '100%' }}
                  onClick={() => pickLibrary(item.url)}
                  aria-label={'Use ' + (item.label || 'image')}
                >
                  <img src={item.url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                </button>
                <button
                  onClick={(e) => { e.stopPropagation(); removeFromLibrary(item); }}
                  title="Remove from team library"
                  style={{
                    position: 'absolute', top: 4, right: 4,
                    width: 18, height: 18, borderRadius: 9, border: 0,
                    background: 'rgba(11,31,51,0.75)', color: '#fff',
                    fontSize: 11, lineHeight: '18px', textAlign: 'center',
                    cursor: 'pointer', padding: 0
                  }}
                >×</button>
              </div>
            ))}
          </div>
        </>
      )}
      <div className="editable-img__menu-sep mono">
        Stock library
        {teamLibLoading && <span style={{ float: 'right', opacity: 0.6, textTransform: 'none', letterSpacing: 0 }}>loading…</span>}
      </div>
      <div className="editable-img__library">
        {library.map((item, i) => (
          <button
            key={i}
            className={"editable-img__tile" + (effective === item.src ? ' is-active' : '')}
            onClick={() => pickLibrary(item.src)}
            title={item.label + (item.placeholder ? ' (placeholder slot)' : '')}
          >
            <img
              src={item.src}
              alt=""
              onError={(e) => {
                if (item.fallback && e.target.src !== item.fallback) e.target.src = item.fallback;
              }}
            />
            {item.placeholder && <span className="editable-img__tile-badge mono">SLOT</span>}
          </button>
        ))}
      </div>
      {onChangeAdjust && (
        <>
          <div className="editable-img__menu-sep mono">Position & crop</div>
          <div className="editable-img__adjust">
            <div className="adjust-row">
              <span className="adjust-label">Fit</span>
              <div className="adjust-toggle">
                <button className={fit === 'cover' ? 'is-active' : ''} onClick={() => setAdj({ fit: 'cover' })}>Fill</button>
                <button className={fit === 'contain' ? 'is-active' : ''} onClick={() => setAdj({ fit: 'contain' })}>Fit</button>
              </div>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Zoom</span>
              <input
                type="range" min="1" max="4" step="0.05"
                value={zoom}
                onChange={(e) => setAdj({ zoom: parseFloat(e.target.value) })}
                className="adjust-slider"
              />
              <span className="adjust-value mono">{zoom.toFixed(2)}x</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Horiz</span>
              <input
                type="range" min="0" max="100" step="1"
                value={posX}
                onChange={(e) => setAdj({ x: parseFloat(e.target.value), y: posY })}
                className="adjust-slider"
              />
              <span className="adjust-value mono">{Math.round(posX)}%</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Vert</span>
              <input
                type="range" min="0" max="100" step="1"
                value={posY}
                onChange={(e) => setAdj({ x: posX, y: parseFloat(e.target.value) })}
                className="adjust-slider"
              />
              <span className="adjust-value mono">{Math.round(posY)}%</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Anchor</span>
              <div className="adjust-grid">
                {posGrid.map((row, y) => row.map((pp, x) => (
                  <button
                    key={`${x}-${y}`}
                    className={"adjust-anchor" + (position === pp ? ' is-active' : '')}
                    onClick={() => {
                      const m = pp.match(/(-?[\d.]+)%\s+(-?[\d.]+)%/);
                      setAdj({ x: parseFloat(m[1]), y: parseFloat(m[2]) });
                    }}
                    title={pp}
                  />
                )))}
              </div>
            </div>
            {(fit !== defaultFit || posX !== 50 || posY !== 50 || zoom !== 1) && (
              <button
                className="adjust-reset mono"
                onClick={() => setAdj({ fit: defaultFit, x: 50, y: 50, zoom: 1 })}
              >Reset position</button>
            )}
            <div className="editable-img__menu-sep mono">Photo filters</div>
            <div className="adjust-row">
              <span className="adjust-label">Bright</span>
              <input type="range" min="40" max="160" step="1"
                value={brightness}
                onChange={(e) => setAdj({ brightness: parseFloat(e.target.value) })}
                className="adjust-slider" />
              <span className="adjust-value mono">{Math.round(brightness)}</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Contrast</span>
              <input type="range" min="40" max="160" step="1"
                value={contrast}
                onChange={(e) => setAdj({ contrast: parseFloat(e.target.value) })}
                className="adjust-slider" />
              <span className="adjust-value mono">{Math.round(contrast)}</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Saturate</span>
              <input type="range" min="0" max="200" step="1"
                value={saturation}
                onChange={(e) => setAdj({ saturation: parseFloat(e.target.value) })}
                className="adjust-slider" />
              <span className="adjust-value mono">{Math.round(saturation)}</span>
            </div>
            <div className="adjust-row">
              <span className="adjust-label">Tint</span>
              <div className="adjust-toggle">
                <button className={tintMode === 'none' ? 'is-active' : ''} onClick={() => setAdj({ tint: 'none' })}>None</button>
                <button className={tintMode === 'navy' ? 'is-active' : ''} onClick={() => setAdj({ tint: 'navy' })}>Navy</button>
                <button className={tintMode === 'teal' ? 'is-active' : ''} onClick={() => setAdj({ tint: 'teal' })}>Teal</button>
              </div>
            </div>
            {(brightness !== 100 || contrast !== 100 || saturation !== 100 || tintMode !== 'none') && (
              <button
                className="adjust-reset mono"
                onClick={() => setAdj({ brightness: 100, contrast: 100, saturation: 100, tint: 'none' })}
              >Reset filters</button>
            )}
          </div>
        </>
      )}
      <input
        ref={inputRef}
        type="file"
        accept="image/*"
        style={{ display: 'none' }}
        onChange={handleFile}
      />
      <input
        ref={libraryInputRef}
        type="file"
        accept="image/*"
        style={{ display: 'none' }}
        onChange={handleLibraryFile}
      />
      </div>
    </div>
    </>
  ) : null;

  return (
    <div
      className={"editable-img " + className}
      style={{ position: 'absolute', inset: 0, ...containerStyle }}
    >
      <img
        src={effective}
        alt={alt}
        onError={(e) => {
          // Image URL failed to load. ONLY swap if we have a brand SVG
          // fallback registered for this src (placeholder slots in
          // imagery.js). For everything else — team-uploaded library
          // photos, /assets/*.jpg, transient CDN failures — leave the
          // DOM alone. Hiding broken images was masking real photos
          // that were merely slow / blocked momentarily.
          const fb = window.VENTUM_IMAGERY?.fallbackFor?.(effective);
          if (fb && e.target.src !== fb) {
            e.target.src = fb;
          }
        }}
        style={{
          position: 'absolute', inset: 0,
          width: '100%', height: '100%',
          objectFit: fit,
          objectPosition: position,
          transform: zoom > 1 ? `scale(${zoom})` : 'none',
          transformOrigin: position,
          filter: filterStr,
          transition: 'transform 0.15s ease, object-position 0.15s ease, filter 0.15s ease',
          ...imgStyle
        }}
      />
      {tintMode !== 'none' && (
        <div style={{
          position: 'absolute', inset: 0,
          background: tintMode === 'navy' ? 'rgba(11,31,51,0.35)' : 'rgba(34,184,167,0.30)',
          mixBlendMode: 'multiply',
          pointerEvents: 'none'
        }} />
      )}
      <button
        ref={btnRef}
        type="button"
        onClick={openMenu}
        className="editable-img__btn mono"
        title="Replace this image"
      >
        <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" style={{ display: 'inline-block', verticalAlign: 'middle', marginRight: 5 }}>
          <rect x="1.5" y="3" width="13" height="10" rx="1" />
          <circle cx="5.5" cy="6.5" r="1.2" />
          <path d="M2 11l3.5-3 2.5 2.5 3-3 3.5 3.5" />
        </svg>
        {label}
      </button>
      {menuNode && ReactDOM.createPortal(menuNode, document.body)}
    </div>
  );
}

// ---------- Helper: update artifact path ----------
function setPath(obj, path, value) {
  const out = JSON.parse(JSON.stringify(obj));
  let cur = out;
  for (let i = 0; i < path.length - 1; i++) {
    if (cur[path[i]] === undefined) cur[path[i]] = (typeof path[i+1] === 'number') ? [] : {};
    cur = cur[path[i]];
  }
  cur[path[path.length - 1]] = value;
  return out;
}

// Convenience: returns an onChange handler that writes (slot, dataUrl) into a.image_overrides[slot].
function imgPatcher(a, onPatch) {
  return (slot, dataUrl) => {
    const next = JSON.parse(JSON.stringify(a));
    next.image_overrides = { ...(next.image_overrides || {}), [slot]: dataUrl };
    onPatch(next);
  };
}

// Convenience: returns an onChange handler that writes adjustments (fit/position/zoom) per slot.
function adjPatcher(a, onPatch) {
  return (slot, adj) => {
    const next = JSON.parse(JSON.stringify(a));
    next.image_adjustments = { ...(next.image_adjustments || {}), [slot]: adj };
    onPatch(next);
  };
}

// ---------- Brand-clean SVG icon set (no emoji) ----------
// Used by the announcement "What changes" badges and anywhere else
// we need a small operational icon. All icons share a 24-viewBox,
// 1.8-stroke geometric style — matches Ventum's brand minimalism.
function ChangeIcon({ name = 'arrow', size = 16, color = '#fff' }) {
  const stroke = { stroke: color, strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', fill: 'none' };
  const paths = {
    arrow: <path d="M5 12h14M13 6l6 6-6 6" {...stroke} />,
    check: <path d="M5 12l4 4 10-10" {...stroke} />,
    dot:   <circle cx="12" cy="12" r="4" fill={color} />,
    gear:  <g {...stroke}><circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 11-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 110-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 114 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 110 4h-.09a1.65 1.65 0 00-1.51 1z" /></g>,
    doc:   <g {...stroke}><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" /><path d="M14 2v6h6M8 13h8M8 17h6" /></g>,
    folder:<path d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" {...stroke} />,
    cal:   <g {...stroke}><rect x="3" y="4" width="18" height="18" rx="2" /><path d="M16 2v4M8 2v4M3 10h18" /></g>,
    chat:  <path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z" {...stroke} />,
    user:  <g {...stroke}><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 4-7 8-7s8 3 8 7" /></g>,
    cart:  <g {...stroke}><path d="M3 3h2l3 12h10l3-8H6" /><circle cx="9" cy="20" r="1.5" fill={color} /><circle cx="17" cy="20" r="1.5" fill={color} /></g>,
    bell:  <path d="M18 8a6 6 0 10-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.7 21a2 2 0 01-3.4 0" {...stroke} />,
    flag:  <g {...stroke}><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" /><line x1="4" y1="22" x2="4" y2="15" /></g>,
    shield:<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" {...stroke} />,
    star:  <polygon points="12,2 15,9 22,9 17,14 19,21 12,17 5,21 7,14 2,9 9,9" {...stroke} />,
    plus:  <path d="M12 5v14M5 12h14" {...stroke} />
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={{ display: 'block' }}>
      {paths[name] || paths.arrow}
    </svg>
  );
}
window.ChangeIcon = ChangeIcon;

// ---------- Editable section label ----------
// Reusable for the hardcoded section titles inside artifacts ("Specifications",
// "Why we chose Ventum", "About the partner", "Prepared for", etc.). Stores
// edits under a._labels[key] with the default falling through when no
// override has been saved. Schema-free — the LLM doesn't generate these,
// they're presentation defaults the reviewer can rename inline.
function SectionLabel({ a, onPatch, labelKey, defaultText, style = {}, className = 'mono', tag = 'div' }) {
  const labels = (a && a._labels) || {};
  const value = labels[labelKey] != null ? labels[labelKey] : defaultText;
  return (
    <Editable
      value={value}
      onChange={(v) => onPatch(setPath(a, ['_labels', labelKey], v))}
      tag={tag}
      className={className}
      style={style}
    />
  );
}

// ============================================================
// EditableCTA — a CTA button whose text stays inline-editable, with an
// optional link. A small editor-only field sets the URL; when a URL is present
// the button is wrapped in a real <a>, so it exports as a clickable link in the
// (headless-Chrome) PDF and the PPTX walker turns it into a slide hyperlink.
// The link is not followed on click inside the editor (you're editing the text).
// ============================================================
function EditableCTA({ value, onChange, url, onUrlChange, style }) {
  if (value == null) return null;
  const raw = (url || '').trim();
  const href = raw ? (/^https?:\/\//i.test(raw) ? raw : 'https://' + raw) : undefined;
  const editLink = () => {
    const next = window.prompt('Link for this button — paste a URL (leave blank to remove).', url || '');
    if (next === null) return; // cancelled
    onUrlChange(next.trim());
  };
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
      <button
        type="button"
        data-editor-only="true"
        className={'cta-link-btn' + (href ? ' is-set' : '')}
        title={href ? ('Linked to ' + href + ' · click to edit') : 'Add a link to this button'}
        onClick={editLink}
      >
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
          <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
        </svg>
      </button>
      <a
        href={href}
        target="_blank"
        rel="noopener noreferrer"
        data-cta-link={href || undefined}
        onClick={(e) => { if (href) e.preventDefault(); }}
        style={{ textDecoration: 'none', display: 'inline-block', color: 'inherit' }}
      >
        <Editable value={value} onChange={onChange} style={style} />
      </a>
    </span>
  );
}

// ============================================================
// One-pager — print-style 8.5x11
// Multiple layouts: 'classic' | 'splitVertical' | 'statLed'
// ============================================================
function OnePagerRender({ a, onPatch, intake = {} }) {
  const layout = a._layout || 'classic';
  if (layout === 'splitVertical') return <OnePagerSplit a={a} onPatch={onPatch} intake={intake} />;
  if (layout === 'statLed')       return <OnePagerStatLed a={a} onPatch={onPatch} intake={intake} />;
  return <OnePagerClassic a={a} onPatch={onPatch} intake={intake} />;
}

function OnePagerClassic({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  const overrides = a.image_overrides || {};
  const onImg = imgPatcher(a, onPatch);
  return (
    <div style={{
      width: 720, aspectRatio: '8.5/11', background: '#fff',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)',
      display: 'grid', gridTemplateRows: '164px 1fr', position: 'relative', overflow: 'hidden'
    }}>
      {/* HERO PHOTO BAND */}
      <div style={{ position: 'relative', overflow: 'hidden', background: '#0B1F33' }}>
        <EditableImage src={hero} slot="hero" overrides={overrides} adjustments={a.image_adjustments || {}} onChange={onImg} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.55) 0%, rgba(11,31,51,0.18) 50%, rgba(11,31,51,0.7) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, padding: '24px 40px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: 'white' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <VentumLogo background="navy" alt="Ventum" style={{ height: 64 }} />
            {accountLogo && (
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <SectionLabel a={a} onPatch={onPatch} labelKey="prepared_for_light" defaultText="Prepared for" style={{ display: 'inline-block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
                <div style={{ width: 160, height: 72, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <AccountLogoImg intake={intake} filter="brightness(0) invert(1)" />
                </div>
              </div>
            )}
          </div>
          <div>
            <Editable
              value={a.eyebrow}
              onChange={set(['eyebrow'])}
              className="mono"
              style={{ fontSize: 10, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.16em', textTransform: 'uppercase' }}
            />
          </div>
        </div>
      </div>

      {/* BODY — auto-fits to the page so heavier briefs scale down, not clip. */}
      <div style={{ padding: '32px 40px 28px', overflow: 'hidden', position: 'relative' }}>
        <FitToHeight maxH={708}>
        <div style={{ minHeight: 708, display: 'grid', gridTemplateRows: '1fr auto' }}>
        <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', height: '100%' }}>
        <div>
          <Editable
            value={a.headline}
            onChange={set(['headline'])}
            tag="h1"
            style={{ fontSize: 36, lineHeight: 1.02, letterSpacing: '-0.025em', fontWeight: 400, margin: 0 }}
          />
          <Editable
            value={a.subhead}
            onChange={set(['subhead'])}
            tag="p"
            style={{ fontSize: 15, color: 'var(--ink-80)', marginTop: 14, lineHeight: 1.5, maxWidth: 540 }}
          />
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginTop: 22 }}>
            {(a.benefits || []).slice(0, 3).map((b, i) => (
              <div key={i} style={{ borderLeft: '2px solid var(--teal)', padding: '6px 0 6px 10px' }}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em' }}>{String(i+1).padStart(2,'0')}</div>
                <Editable
                  value={b.title}
                  onChange={(v) => onPatch(setPath(a, ['benefits', i, 'title'], v))}
                  tag="h4"
                  style={{ fontSize: 13, margin: '3px 0', fontWeight: 500 }}
                />
                <Editable
                  value={b.body}
                  onChange={(v) => onPatch(setPath(a, ['benefits', i, 'body'], v))}
                  tag="p"
                  style={{ fontSize: 11, color: 'var(--ink-60)', lineHeight: 1.5 }}
                />
              </div>
            ))}
          </div>
          </div>
          {/* INFOGRAPHIC STRIP — LOG ladder + process ribbon */}
          <div style={{ marginTop: 20, display: 'grid', gridTemplateColumns: '1fr 1.35fr', gap: 22, alignItems: 'start' }}>
            <div style={{ background: 'var(--ink-05)', padding: '14px 16px', borderRadius: 2 }}>
              <LogLadder filled={6} label="Pathogen reduction" highlight="Up to 99.9995%" />
            </div>
            <ProcessRibbon
              steps={[
                { label: 'Apply', duration: 'Minutes', detail: 'One trained operator' },
                { label: 'Diffuse', duration: 'In-cycle', detail: 'Air + surfaces, one pass' },
                { label: 'Neutralize', duration: 'Post-cycle', detail: 'To water and oxygen' }
              ]}
            />
          </div>
          <div style={{ marginTop: 22, display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 18, alignItems: 'end' }}>
            <div style={{ borderLeft: '2px solid var(--teal)', paddingLeft: 14 }}>
              <Editable
                value={(a.proof_quote || {}).quote}
                onChange={(v) => onPatch(setPath(a, ['proof_quote','quote'], v))}
                tag="p"
                style={{ fontSize: 13.5, lineHeight: 1.4, letterSpacing: '-0.005em' }}
              />
              <Editable
                value={(a.proof_quote || {}).attribution}
                onChange={(v) => onPatch(setPath(a, ['proof_quote','attribution'], v))}
                className="mono"
                style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', marginTop: 6, letterSpacing: '0.1em' }}
              />
            </div>
            <div style={{ background: 'var(--navy)', color: 'white', padding: 14, borderRadius: 2 }}>
              <Editable
                value={(a.stat_block || {}).unit}
                onChange={(v) => onPatch(setPath(a, ['stat_block','unit'], v))}
                className="mono"
                style={{ fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }}
              />
              <Editable
                value={(a.stat_block || {}).value}
                onChange={(v) => onPatch(setPath(a, ['stat_block','value'], v))}
                style={{ display: 'block', fontSize: 32, lineHeight: 1, letterSpacing: '-0.03em', fontWeight: 400, marginTop: 4 }}
              />
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'end', paddingTop: 14, borderTop: '1px solid var(--ink-10)', marginTop: 18 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="footer_url" defaultText="ventum.bio" style={{ display: 'inline-block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          <EditableCTA
            value={a.cta}
            onChange={set(['cta'])}
            url={a.cta_url}
            onUrlChange={set(['cta_url'])}
            style={{ background: 'var(--navy)', color: 'white', padding: '10px 14px', fontSize: 12, fontWeight: 500, borderRadius: 2 }}
          />
        </div>
        </div>
        </FitToHeight>
      </div>
    </div>
  );
}

// One-pager — SPLIT VERTICAL: photo on left (full height), content on right
function OnePagerSplit({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  const overrides = a.image_overrides || {};
  const onImg = imgPatcher(a, onPatch);
  return (
    <div style={{
      width: 720, aspectRatio: '8.5/11', background: '#fff',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)',
      display: 'grid', gridTemplateColumns: '0.85fr 1.15fr', overflow: 'hidden'
    }}>
      {/* LEFT photo column */}
      <div style={{ position: 'relative', overflow: 'hidden', background: '#0B1F33' }}>
        <EditableImage src={hero} slot="hero" overrides={overrides} adjustments={a.image_adjustments || {}} onChange={onImg} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.45) 0%, rgba(11,31,51,0.15) 50%, rgba(11,31,51,0.75) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, padding: '24px 24px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: 'white' }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 56, alignSelf: 'flex-start' }} />
          <div style={{ maxWidth: '100%' }}>
            <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 9.5, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 24, lineHeight: 1.02, letterSpacing: '-0.025em', fontWeight: 400, color: 'white', marginTop: 10, textWrap: 'balance', maxWidth: 260 }} />
          </div>
        </div>
      </div>
      {/* RIGHT content column — auto-fits to the page height so heavier briefs
          scale down to fit instead of clipping at the bottom. */}
      <div style={{ padding: '32px 36px 40px', overflow: 'hidden' }}>
        <FitToHeight maxH={860}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minHeight: 860, justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', paddingBottom: 12, borderBottom: '1px solid var(--ink-10)' }}>
          <div className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase' }}>One-pager · v2</div>
          {accountLogo && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <SectionLabel a={a} onPatch={onPatch} labelKey="for_label" defaultText="For" style={{ display: 'inline-block', fontSize: 8, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
              <div style={{ width: 140, height: 60, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <AccountLogoImg intake={intake} />
              </div>
            </div>
          )}
        </div>
        <Editable value={a.subhead} onChange={set(['subhead'])} tag="p" style={{ fontSize: 14, color: 'var(--ink-80)', lineHeight: 1.5 }} />
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {(a.benefits || []).slice(0, 4).map((b, i) => (
            <div key={i} style={{ display: 'grid', gridTemplateColumns: '24px 1fr', gap: 10, paddingBottom: 12, borderBottom: '1px solid var(--ink-10)' }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.14em', paddingTop: 2 }}>{String(i+1).padStart(2,'0')}</div>
              <div>
                <Editable value={b.title} onChange={(v) => onPatch(setPath(a, ['benefits', i, 'title'], v))} tag="h4" style={{ fontSize: 13, margin: 0, fontWeight: 500 }} />
                <Editable value={b.body} onChange={(v) => onPatch(setPath(a, ['benefits', i, 'body'], v))} tag="p" style={{ fontSize: 11.5, color: 'var(--ink-60)', lineHeight: 1.5, marginTop: 2 }} />
              </div>
            </div>
          ))}
        </div>
        <div style={{ background: 'var(--ink-05)', padding: 14, borderRadius: 2 }}>
          <LogLadder filled={6} highlight="Up to 99.9995%" />
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 10, paddingTop: 12, borderTop: '1px solid var(--ink-10)' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="footer_url" defaultText="ventum.bio" style={{ display: 'inline-block', fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          <EditableCTA value={a.cta} onChange={set(['cta'])} url={a.cta_url} onUrlChange={set(['cta_url'])} style={{ background: 'var(--navy)', color: 'white', padding: '8px 12px', fontSize: 11, fontWeight: 500, borderRadius: 2, whiteSpace: 'nowrap' }} />
        </div>
        </div>
        </FitToHeight>
      </div>
    </div>
  );
}

// One-pager — STAT-LED: lead with giant proof number
function OnePagerStatLed({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  const overrides = a.image_overrides || {};
  const onImg = imgPatcher(a, onPatch);
  // Auto-shrink the stat-band headline so a long headline in the narrow navy
  // column doesn't blow out the band height (which pushed content off the page).
  const hlLen = (a.headline || '').length;
  const statHeadlineSize = hlLen > 58 ? 17 : hlLen > 44 ? 19 : hlLen > 30 ? 21 : 24;
  return (
    <div style={{
      width: 720, aspectRatio: '8.5/11', background: '#fff',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)',
      padding: 36, overflow: 'hidden', position: 'relative'
    }}>
      <FitToHeight maxH={860}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 20, minHeight: 860, justifyContent: 'space-between' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <VentumLogo background="white" alt="Ventum" style={{ height: 64 }} />
        {accountLogo && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="prepared_for_dark" defaultText="Prepared for" style={{ display: 'inline-block', fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
            <div style={{ width: 160, height: 72, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <AccountLogoImg intake={intake} />
            </div>
          </div>
        )}
      </div>
      <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
      {/* HERO STAT BAND */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 24, alignItems: 'center', padding: '20px 22px', background: 'var(--navy)', color: 'white', borderRadius: 2 }}>
        <div>
          <Editable value={(a.stat_block || {}).value} onChange={(v) => onPatch(setPath(a, ['stat_block','value'], v))} style={{ display: 'block', fontSize: 88, lineHeight: 0.92, letterSpacing: '-0.045em', fontWeight: 400, color: 'white' }} />
          <Editable value={(a.stat_block || {}).unit} onChange={(v) => onPatch(setPath(a, ['stat_block','unit'], v))} className="mono" style={{ display: 'block', fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase', marginTop: 8 }} />
        </div>
        <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: statHeadlineSize, lineHeight: 1.1, letterSpacing: '-0.02em', fontWeight: 400, color: 'white', margin: 0 }} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 22 }}>
        <div>
          <Editable value={a.subhead} onChange={set(['subhead'])} tag="p" style={{ fontSize: 14, color: 'var(--ink-80)', lineHeight: 1.55 }} />
          <div style={{ marginTop: 18, display: 'flex', flexDirection: 'column', gap: 12 }}>
            {(a.benefits || []).slice(0, 4).map((b, i) => (
              <div key={i}>
                <div className="mono" style={{ fontSize: 9, color: 'var(--teal)', letterSpacing: '0.14em' }}>{String(i+1).padStart(2,'0')}</div>
                <Editable value={b.title} onChange={(v) => onPatch(setPath(a, ['benefits', i, 'title'], v))} tag="h4" style={{ fontSize: 13, margin: '2px 0', fontWeight: 500 }} />
                <Editable value={b.body} onChange={(v) => onPatch(setPath(a, ['benefits', i, 'body'], v))} tag="p" style={{ fontSize: 11, color: 'var(--ink-60)', lineHeight: 1.5 }} />
              </div>
            ))}
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ position: 'relative', height: 220, overflow: 'hidden', borderRadius: 2, background: '#0B1F33' }}>
            <EditableImage src={hero} slot="hero" overrides={overrides} adjustments={a.image_adjustments || {}} onChange={onImg} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0) 50%, rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
          </div>
          <div style={{ background: 'var(--ink-05)', padding: '14px 16px', borderRadius: 2 }}>
            <BeforeAfterBars
              title="Operational lift"
              items={(a.chart_data?.before_after) || [
                { label: 'Before',     value: 100, suffix: 'idx' },
                { label: 'With Ventum', value: 32, suffix: 'idx' }
              ]}
              onEditValue={(idx, num) => {
                const next = JSON.parse(JSON.stringify(a));
                next.chart_data = next.chart_data || {};
                next.chart_data.before_after = next.chart_data.before_after || [
                  { label: 'Before',     value: 100, suffix: 'idx' },
                  { label: 'With Ventum', value: 32, suffix: 'idx' }
                ];
                next.chart_data.before_after[idx].value = num;
                onPatch(next);
              }}
            />
          </div>
          <div style={{ borderLeft: '2px solid var(--teal)', paddingLeft: 12 }}>
            <Editable value={(a.proof_quote || {}).quote} onChange={(v) => onPatch(setPath(a, ['proof_quote','quote'], v))} tag="p" style={{ fontSize: 13, lineHeight: 1.45 }} />
            <Editable value={(a.proof_quote || {}).attribution} onChange={(v) => onPatch(setPath(a, ['proof_quote','attribution'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', marginTop: 4, letterSpacing: '0.1em' }} />
          </div>
        </div>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'end', paddingTop: 14, borderTop: '1px solid var(--ink-10)' }}>
        <SectionLabel a={a} onPatch={onPatch} labelKey="footer_url" defaultText="ventum.bio" style={{ display: 'inline-block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
        <EditableCTA value={a.cta} onChange={set(['cta'])} url={a.cta_url} onUrlChange={set(['cta_url'])} style={{ background: 'var(--navy)', color: 'white', padding: '10px 14px', fontSize: 12, fontWeight: 500, borderRadius: 2 }} />
      </div>
      </div>
      </FitToHeight>
    </div>
  );
}
// ============================================================
// LinkedIn post — multiple layouts: 'standard' | 'photoFirst'
// ============================================================
function LinkedInPostRender({ a, onPatch, intake = {} }) {
  const layout = a._layout || 'standard';
  const inner = layout === 'photoFirst'
    ? <LinkedInPostPhotoFirst a={a} onPatch={onPatch} intake={intake} />
    : <LinkedInPostStandard a={a} onPatch={onPatch} intake={intake} />;
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      {inner}
      <div data-editor-only="true" style={{ width: 560, marginTop: 8 }}>
        <PerformancePanel
          value={a._performance || {}}
          onChange={(perf) => onPatch(setPath(a, ['_performance'], perf))}
        />
      </div>
    </div>
  );
}

function LinkedInPostStandard({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  return (
    <div style={{ width: 560, background: '#fff', borderRadius: 4, boxShadow: '0 30px 60px -20px rgba(11,31,51,0.15)', overflow: 'hidden' }}>
      <div style={{ padding: '20px 24px 0' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '44px 1fr', gap: 12, marginBottom: 14 }}>
          <div style={{ width: 56, height: 56, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
            <VentumLogo markOnly background="navy" alt="" style={{ height: 32 }} />
          </div>
          <div>
            <SectionLabel a={a} onPatch={onPatch} labelKey="li_author_name" defaultText="Ventum Biotech" className="" style={{ display: 'block', fontSize: 14, fontWeight: 500 }} />
            <SectionLabel a={a} onPatch={onPatch} labelKey="li_author_meta" defaultText="SCIENCE-LED BIODEFENSE · NOW" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.1em' }} />
          </div>
        </div>
        <Editable
          value={a.hook}
          onChange={set(['hook'])}
          tag="p"
          style={{ fontSize: 15, lineHeight: 1.55, fontWeight: 500, marginBottom: 12 }}
        />
        {(a.body || []).map((p, i) => (
          <Editable
            key={i}
            value={p}
            onChange={(v) => onPatch(setPath(a, ['body', i], v))}
            tag="p"
            style={{ fontSize: 14.5, lineHeight: 1.6, marginBottom: 10, color: 'var(--ink-100)' }}
          />
        ))}
        <Editable
          value={a.cta_line}
          onChange={set(['cta_line'])}
          tag="p"
          style={{ fontSize: 14.5, lineHeight: 1.6, marginTop: 12, fontWeight: 500 }}
        />
      {a.hashtags && (
        <Editable
          value={(a.hashtags || []).join(' ')}
          onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
          className="mono"
          style={{ display: 'block', fontSize: 11.5, color: 'var(--signal)', letterSpacing: '0.04em', marginTop: 14, marginBottom: 18 }}
        />
      )}
      </div>
      {/* HERO IMAGE — LinkedIn-style 1:1 card below the text */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '1.91/1', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.0), rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', bottom: 14, left: 18, right: 18, display: 'flex', alignItems: 'end', justifyContent: 'space-between', color: 'white' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="li_hero_overlay" defaultText="VENTUM BIOTECH" style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.85)' }} />
          <VentumLogo background="navy" alt="" style={{ height: 42, opacity: 0.95 }} />
        </div>
      </div>
      {a.image_direction && (
        <div className="mono" style={{ padding: '10px 24px 18px', fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }}>
          IMG · {a.image_direction}
        </div>
      )}
    </div>
  );
}

// LinkedIn post — PHOTO FIRST: large hero image up top, copy below
function LinkedInPostPhotoFirst({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  return (
    <div style={{ width: 560, background: '#fff', borderRadius: 4, boxShadow: '0 30px 60px -20px rgba(11,31,51,0.15)', overflow: 'hidden' }}>
      {/* Author */}
      <div style={{ padding: '20px 24px 14px', display: 'grid', gridTemplateColumns: '44px 1fr', gap: 12, alignItems: 'center' }}>
        <div style={{ width: 56, height: 56, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
          <VentumLogo markOnly background="navy" alt="" style={{ height: 32 }} />
        </div>
        <div>
          <SectionLabel a={a} onPatch={onPatch} labelKey="li_author_name" defaultText="Ventum Biotech" className="" style={{ display: 'block', fontSize: 14, fontWeight: 500 }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="li_author_meta" defaultText="SCIENCE-LED BIODEFENSE · NOW" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.1em' }} />
        </div>
      </div>
      {/* Photo first */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '1.91/1', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.45) 0%, rgba(11,31,51,0.0) 40%, rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', top: 16, left: 18, right: 18, display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
          <Editable value={a.hook} onChange={set(['hook'])} tag="h3" style={{ fontSize: 24, lineHeight: 1.05, letterSpacing: '-0.02em', fontWeight: 400, color: 'white', maxWidth: 380, margin: 0 }} />
          <VentumLogo background="navy" alt="" style={{ height: 42, opacity: 0.85 }} />
        </div>
      </div>
      {/* Body */}
      <div style={{ padding: '18px 24px 22px' }}>
        {(a.body || []).map((p, i) => (
          <Editable
            key={i}
            value={p}
            onChange={(v) => onPatch(setPath(a, ['body', i], v))}
            tag="p"
            style={{ fontSize: 14, lineHeight: 1.6, marginBottom: 10, color: 'var(--ink-100)' }}
          />
        ))}
        <Editable
          value={a.cta_line}
          onChange={set(['cta_line'])}
          tag="p"
          style={{ fontSize: 14, lineHeight: 1.6, marginTop: 8, fontWeight: 500 }}
        />
        {a.hashtags && (
          <Editable
            value={(a.hashtags || []).join(' ')}
            onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
            className="mono"
            style={{ display: 'block', fontSize: 11.5, color: 'var(--signal)', letterSpacing: '0.04em', marginTop: 12 }}
          />
        )}
      </div>
    </div>
  );
}

// ============================================================
// Email
// ============================================================
function EmailRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  return (
    <div style={{ width: 600, background: '#fff', borderRadius: 4, overflow: 'hidden', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.15)' }}>
      <div style={{ background: '#f3f4f6', padding: '16px 24px', borderBottom: '1px solid var(--ink-10)' }}>
        <SectionLabel a={a} onPatch={onPatch} labelKey="email_from" defaultText="FROM · sales@ventum.bio" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.12em' }} />
        <Editable value={a.subject} onChange={set(['subject'])} style={{ fontSize: 14, fontWeight: 500, marginTop: 4, display: 'block' }} />
        <Editable value={a.preheader} onChange={set(['preheader'])} style={{ fontSize: 12, color: 'var(--ink-60)', marginTop: 2, display: 'block' }} />
      </div>
      {/* HERO BAND */}
      <div style={{ position: 'relative', width: '100%', height: 200, background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.55) 0%, rgba(11,31,51,0.25) 60%, rgba(11,31,51,0.75) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', top: 18, left: 24, right: 24, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 56 }} />
          {accountLogo && (
            <div style={{ width: 150, height: 64, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <AccountLogoImg intake={intake} filter="brightness(0) invert(1)" />
            </div>
          )}
        </div>
      </div>
      <div style={{ padding: '24px 32px 32px' }}>
        <Editable value={a.salutation} onChange={set(['salutation'])} tag="p" style={{ fontSize: 14.5, lineHeight: 1.6 }} />
        {(a.body || []).map((p, i) => (
          <Editable key={i} value={p} onChange={(v) => onPatch(setPath(a, ['body', i], v))} tag="p" style={{ fontSize: 14.5, lineHeight: 1.6, marginTop: 12 }} />
        ))}
        <div style={{ margin: '24px 0 8px' }}>
          <EditableCTA value={a.cta_button} onChange={set(['cta_button'])} url={a.cta_button_url} onUrlChange={set(['cta_button_url'])} style={{ display: 'inline-block', background: 'var(--navy)', color: 'white', padding: '11px 18px', fontSize: 13, fontWeight: 500, borderRadius: 2 }} />
        </div>
        <Editable value={a.signoff} onChange={set(['signoff'])} tag="p" style={{ fontSize: 14.5, lineHeight: 1.6, marginTop: 20, color: 'var(--ink-80)' }} />
      </div>
    </div>
  );
}

// ============================================================
// Deck slide
// ============================================================
function DeckSlideRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  return (
    <div style={{ width: 880, aspectRatio: '16/9', background: '#fff', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)', display: 'grid', gridTemplateColumns: '1.2fr 1fr', overflow: 'hidden' }}>
      {/* LEFT — content */}
      <div style={{ padding: 44, display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          {accountLogo && (
            <div style={{ width: 164, height: 72, display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
              <AccountLogoImg intake={intake} />
            </div>
          )}
        </div>
        <div>
          <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, margin: 0 }} />
          <Editable value={a.body} onChange={set(['body'])} tag="p" style={{ fontSize: 15, color: 'var(--ink-80)', marginTop: 14, maxWidth: 460, lineHeight: 1.5 }} />
        </div>
        <div style={{ display: 'flex', alignItems: 'end', justifyContent: 'space-between', gap: 14 }}>
          {a.stat && (
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
              <Editable value={a.stat.value} onChange={(v) => onPatch(setPath(a, ['stat','value'], v))} style={{ fontSize: 44, fontWeight: 400, letterSpacing: '-0.035em', color: 'var(--navy)' }} />
              <Editable value={a.stat.unit} onChange={(v) => onPatch(setPath(a, ['stat','unit'], v))} className="mono" style={{ fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
            </div>
          )}
          {/* ghost watermark: color lockup at 50% opacity on a light bg — intentional, not an inverted light/dark mapping */}
          <VentumLogo background="white" alt="" style={{ height: 40, opacity: 0.5 }} />
        </div>
      </div>
      {/* RIGHT — hero photo */}
      <div style={{ position: 'relative', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(135deg, rgba(11,31,51,0.0) 60%, rgba(11,31,51,0.4) 100%)', pointerEvents: 'none' }} />
      </div>
    </div>
  );
}

// ============================================================
// Slide deck — multi-slide narrative
// ============================================================

// Kinds offered in the "add slide" menu, with a plain-language label. Every
// kind here has a matching branch in DeckSlide and a template below. Ordered
// as a rep would build a narrative (open, context, solution, proof, numbers,
// close).
const DECK_ADD_KINDS = [
  { kind: 'context',  label: 'Context' },
  { kind: 'solution', label: 'Solution' },
  { kind: 'proof',    label: 'Proof point' },
  { kind: 'market',   label: 'Stats' },
  { kind: 'cta',      label: 'Closing' },
];

// A minimal, VALID slide for each kind. Seeds light starter copy (not empty)
// so the new slide is visible and clickable in the editor. Deliberately avoids
// seeding invented figures — numeric slots get an editable "Add a figure"
// prompt rather than a fabricated number, so nothing untraceable ever lands in
// the deck (keeps the grounding / fact-audit guarantees intact).
function blankDeckSlide(kind) {
  switch (kind) {
    case 'title':
      return { kind, eyebrow: 'Section', headline: 'New title', subhead: '' };
    case 'solution':
      return { kind, eyebrow: '', headline: 'New headline', body: '', bullets: ['First point', 'Second point'] };
    case 'proof':
      return { kind, eyebrow: '', headline: 'New headline', body: '', stat: { value: 'Add a figure', unit: 'reduction in tested conditions' } };
    case 'market':
      return { kind, eyebrow: '', headline: 'New headline', stats: [{ label: 'Label', value: 'Add a figure', unit: '' }] };
    case 'cta':
      return { kind, eyebrow: '', headline: 'Next step', body: '', cta: 'Book a walkthrough' };
    case 'context':
    default:
      return { kind: 'context', eyebrow: '', headline: 'New headline', body: 'Add your supporting point here.' };
  }
}

function DeckRender({ a, onPatch, intake = {} }) {
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const support = window.VENTUM_IMAGERY.support(intake, 0);
  const product = window.VENTUM_IMAGERY.product(intake);
  const accountLogo = window.VENTUM_IMAGERY.customerLogo(intake);
  const slides = a.slides || [];
  const slideRefs = useRef([]);
  const [activeSlide, setActiveSlide] = useState(0);

  // Per-slide patchers. Immutable SHALLOW update — only the edited slide gets a
  // new object identity (was JSON.parse(JSON.stringify(a)), which deep-cloned
  // the whole deck on every edit and forced every slide to re-render — the
  // "reloads the entire presentation" report). Combined with the memoized
  // DeckSlide below, only the edited slide re-renders. The ref lets each
  // patcher read the latest artifact without changing its own identity, so
  // unedited slides stay memo-stable across edits.
  const aRef = useRef(a); aRef.current = a;
  const patchers = useMemo(
    () => (a.slides || []).map((_, i) => (patch) => {
      const cur = aRef.current;
      const nextSlides = cur.slides.slice();
      nextSlides[i] = { ...nextSlides[i], ...patch };
      onPatch({ ...cur, slides: nextSlides });
    }),
    [slides.length, onPatch]
  );

  // Observe each slide so the badge bar can highlight the one in view
  useEffect(() => {
    if (!slideRefs.current.length || !('IntersectionObserver' in window)) return;
    const io = new IntersectionObserver((entries) => {
      const visible = entries
        .filter((e) => e.isIntersecting)
        .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
      if (visible) {
        const idx = Number(visible.target.dataset.slideIdx);
        if (!isNaN(idx)) setActiveSlide(idx);
      }
    }, { threshold: [0.25, 0.6, 0.9] });
    slideRefs.current.forEach((el) => el && io.observe(el));
    return () => io.disconnect();
  }, [slides.length]);

  const jumpTo = (i) => {
    const el = slideRefs.current[i];
    if (el && el.scrollIntoView) {
      // anchor the slide inside the stage; avoid jumping the whole page
      el.scrollIntoView({ block: 'center', behavior: 'smooth' });
      setActiveSlide(i);
    }
  };

  // ── Slide management (add / delete / duplicate / reorder) ──────────────
  // Editor-only chrome; hidden from every export path (see .deck-slide-tools
  // CSS: opacity:0 unless hovered + data-editor-only stripped by the PDF/print
  // CSS). All ops route through the same whole-artifact onPatch used by the
  // per-slide patchers, so autosave and undo history stay consistent.
  const [confirmDel, setConfirmDel] = useState(null); // index pending delete-confirm
  const [addMenu, setAddMenu] = useState(null);       // index whose "add" menu is open

  // Apply a pure transform to a COPY of the slides array, then patch + refocus.
  const applySlides = (mut, focusIdx) => {
    const cur = aRef.current;
    const next = mut((cur.slides || []).slice());
    onPatch({ ...cur, slides: next });
    if (typeof focusIdx === 'number' && next.length) {
      setActiveSlide(Math.max(0, Math.min(next.length - 1, focusIdx)));
    }
  };
  const moveSlide = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= slides.length) return;
    applySlides((arr) => { const t = arr[i]; arr[i] = arr[j]; arr[j] = t; return arr; }, j);
  };
  const duplicateSlide = (i) =>
    // deep clone so edits to the copy never mutate the original slide's nested
    // objects (stat / chart_data / image_overrides)
    applySlides((arr) => { arr.splice(i + 1, 0, JSON.parse(JSON.stringify(arr[i]))); return arr; }, i + 1);
  const deleteSlide = (i) => {
    if (slides.length <= 1) return; // never leave an empty deck
    applySlides((arr) => { arr.splice(i, 1); return arr; }, Math.min(i, slides.length - 2));
  };
  const addSlide = (afterIdx, kind) =>
    applySlides((arr) => { arr.splice(afterIdx + 1, 0, blankDeckSlide(kind)); return arr; }, afterIdx + 1);

  const toolBtn = {
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    minWidth: 26, height: 26, padding: '0 7px', border: '1px solid var(--ink-10)',
    background: 'rgba(255,255,255,0.96)', borderRadius: 6, cursor: 'pointer',
    fontSize: 12, color: 'var(--ink-60)', lineHeight: 1,
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, alignItems: 'center', width: '100%' }}>
      {/* Slide nav bar — sticky badges */}
      <div className="deck-nav">
        <div className="mono" style={{ fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase' }}>
          {a.title || 'Untitled deck'}
        </div>
        <div className="deck-nav__badges">
          {slides.map((s, i) => (
            <button
              key={i}
              className={"deck-nav__badge" + (i === activeSlide ? ' is-active' : '')}
              onClick={() => jumpTo(i)}
              title={s.headline || s.kind || `Slide ${i+1}`}
            >
              <span className="mono">{String(i+1).padStart(2, '0')}</span>
              <span className="deck-nav__kind">{s.kind || ''}</span>
            </button>
          ))}
        </div>
      </div>
      {slides.map((s, i) => (
        // Outer div: centering only. The [data-slide-idx] node is the inner
        // 880px box, and its FIRST child must stay the slide itself — both
        // export paths read `[data-slide-idx].firstElementChild` as the slide,
        // so the editor tools go AFTER the slide, never before it.
        <div key={i} style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
          <div
            ref={(el) => slideRefs.current[i] = el}
            data-slide-idx={i}
            className={"deck-slide-wrap" + ((addMenu === i || confirmDel === i) ? " is-tooling" : "")}
            style={{ position: 'relative', width: 880, scrollMarginTop: 60 }}
          >
            <DeckSlideMemo
              slide={s}
              idx={i}
              total={slides.length}
              hero={hero}
              support={support}
              product={product}
              accountLogo={accountLogo}
              intake={intake}
              onPatch={patchers[i]}
            />

            {/* Per-slide tools — editor-only, hidden unless the slide is hovered
                and stripped from every export path. */}
            <div className="deck-slide-tools" data-editor-only="true"
                 style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 5, zIndex: 6 }}>
              <button style={{ ...toolBtn, opacity: i === 0 ? 0.35 : 1 }} disabled={i === 0}
                      title="Move up" aria-label="Move slide up" onClick={() => moveSlide(i, -1)}>↑</button>
              <button style={{ ...toolBtn, opacity: i === slides.length - 1 ? 0.35 : 1 }} disabled={i === slides.length - 1}
                      title="Move down" aria-label="Move slide down" onClick={() => moveSlide(i, 1)}>↓</button>
              <button style={toolBtn} title="Duplicate slide" aria-label="Duplicate slide"
                      onClick={() => duplicateSlide(i)}>⧉</button>
              {confirmDel === i ? (
                <>
                  <button style={{ ...toolBtn, width: 'auto', color: '#fff', background: '#A33027', borderColor: '#A33027' }}
                          title="Confirm remove" onClick={() => { deleteSlide(i); setConfirmDel(null); }}>Remove</button>
                  <button style={{ ...toolBtn, width: 'auto' }} title="Keep slide"
                          onClick={() => setConfirmDel(null)}>Keep</button>
                </>
              ) : (
                <button style={{ ...toolBtn, opacity: slides.length <= 1 ? 0.35 : 1 }} disabled={slides.length <= 1}
                        title="Delete slide" aria-label="Delete slide" onClick={() => setConfirmDel(i)}>✕</button>
              )}
            </div>

            {/* Insert-below affordance — sits in the gap under the slide. */}
            <div className="deck-slide-insert" data-editor-only="true"
                 style={{ position: 'absolute', left: 0, right: 0, bottom: -14, display: 'flex', justifyContent: 'center', zIndex: 6 }}>
              {addMenu === i ? (
                <div className="deck-add-menu" style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '6px 8px', background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 8, boxShadow: '0 8px 22px -10px rgba(11,31,51,0.35)' }}>
                  <span className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginRight: 2 }}>Add</span>
                  {DECK_ADD_KINDS.map((k) => (
                    <button key={k.kind} style={{ ...toolBtn, width: 'auto', fontSize: 11.5 }}
                            onClick={() => { addSlide(i, k.kind); setAddMenu(null); }}>{k.label}</button>
                  ))}
                  <button style={{ ...toolBtn, width: 'auto', fontSize: 11.5, color: 'var(--ink-40)' }}
                          onClick={() => setAddMenu(null)}>Cancel</button>
                </div>
              ) : (
                <button className="deck-add-btn" style={{ ...toolBtn, width: 'auto', fontSize: 11.5, fontWeight: 500, boxShadow: '0 4px 12px -6px rgba(11,31,51,0.3)' }}
                        title="Add a slide below" onClick={() => setAddMenu(i)}>+ Add slide</button>
              )}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// Scales its single child down (never up) so the child's natural height fits
// within maxH. Keeps tall deck-slide content from colliding with the bottom
// footer band: normal-length slides render at full size (scale 1 — look
// unchanged), only overlong content shrinks to fit. Runs identically in the
// live preview and both export paths (same render tree), and re-measures on
// every render so inline edits re-fit. transform doesn't affect scrollHeight,
// so the measurement is stable and the scale converges in one extra render.
function FitToHeight({ maxH, children, style = {} }) {
  const ref = React.useRef(null);
  const [scale, setScale] = React.useState(1);
  React.useLayoutEffect(() => {
    const el = ref.current;
    if (!el) return;
    // transform:scale does NOT change scrollHeight, so this always reports the
    // natural (untransformed) content height and the scale converges.
    const measure = () => {
      const nat = el.scrollHeight;
      setScale(nat > maxH ? Math.max(0.5, maxH / nat) : 1);
    };
    measure();
    // Re-fit whenever the content box changes size — critically, after the
    // Geist webfont loads (text reflows to more lines and grows taller; the
    // first synchronous measure runs against the fallback font and undercounts).
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(measure);
    return () => ro.disconnect();
  }, [maxH]);
  return (
    <div style={{ width: '100%', height: scale < 1 ? maxH : 'auto', ...style }}>
      <div ref={ref} style={{ transform: scale < 1 ? `scale(${scale})` : undefined, transformOrigin: 'left top' }}>
        {children}
      </div>
    </div>
  );
}

// Editable chart slot for deck slides. Brings the deck up to the same
// per-slot control the LinkedIn carousel + brochures already have: pick the
// chart TYPE (bars / decay / donut / plain text), edit the NUMBERS inline, or
// switch it to Text entirely. The type picker is data-editor-only (stripped
// from every export), and the chosen chart renders inside a fixed-height box
// so swapping types never reflows the surrounding slide layout.
//
// Default preservation: `kind` falls back to `defaultKind` when the artifact
// has no explicit choice, so existing decks render byte-identically — only an
// explicit user pick changes the output. Decay label keys stay un-prefixed
// (decay_from/to/duration) to preserve data already saved on older decks.
const DECK_CHART_LABELS = { bars: 'Bars', coverage: 'Coverage', donut: 'Donut', decay: 'Log curve', text: 'Text' };
function DeckChartSlot({ cd, onPatchChart, slotKey, defaultKind, theme = 'light', height = 104, width = 300, allow = ['bars', 'coverage', 'donut', 'decay', 'text'],
  barsKey, barsTitle = 'Operational lift, like-for-like', decayFrom = '10⁶', decayTo = '< 1', decayDuration = 'single cycle' }) {
  const isNavy = theme === 'navy';
  const kind = cd[slotKey + '_kind'] || defaultKind;
  // barsKey lets a slot reuse a pre-existing data key (proof stores its bars
  // under `before_after`) so upgrading the slot never orphans saved numbers.
  const bKey = barsKey || (slotKey + '_bars');
  const barsFallback = [{ label: 'Before', value: 100, suffix: 'idx' }, { label: 'With Ventum', value: 32, suffix: 'idx' }];
  const bars = cd[bKey] || barsFallback;
  return (
    <div>
      <div data-editor-only="true" style={{ display: 'inline-flex', alignItems: 'center', border: '1px solid ' + (isNavy ? 'rgba(255,255,255,0.18)' : 'var(--ink-10)'), borderRadius: 3, overflow: 'hidden', marginBottom: 8 }}>
        {allow.map((id) => {
          const active = kind === id;
          return (
            <button key={id} onClick={() => onPatchChart({ [slotKey + '_kind']: id })}
              style={{ background: active ? (isNavy ? 'rgba(255,255,255,0.18)' : 'var(--navy)') : 'transparent',
                color: active ? 'white' : (isNavy ? 'rgba(255,255,255,0.55)' : 'var(--ink-40)'),
                border: 'none', padding: '4px 8px', fontFamily: 'var(--mono)', fontSize: 9,
                letterSpacing: '0.1em', textTransform: 'uppercase', cursor: 'pointer', lineHeight: 1 }}>
              {DECK_CHART_LABELS[id]}
            </button>
          );
        })}
      </div>
      <div style={{ minHeight: height }}>
        {kind === 'bars' && (
          <BeforeAfterBars theme={isNavy ? 'navy' : 'light'} title={cd[slotKey + '_bars_title'] || barsTitle} items={bars}
            onEditValue={(idx, num) => onPatchChart({ [bKey]: bars.map((b, i) => i === idx ? { ...b, value: num } : b) })} />
        )}
        {kind === 'decay' && (
          <DecayCurve theme={isNavy ? 'navy' : 'light'}
            fromLabel={cd.decay_from ?? decayFrom} toLabel={cd.decay_to ?? decayTo} durationLabel={cd.decay_duration ?? decayDuration}
            width={width} height={Math.min(height, 104)}
            onEditFromLabel={(v) => onPatchChart({ decay_from: v })}
            onEditToLabel={(v) => onPatchChart({ decay_to: v })}
            onEditDurationLabel={(v) => onPatchChart({ decay_duration: v })} />
        )}
        {kind === 'donut' && (
          <div style={{ display: 'flex', justifyContent: 'center' }}>
            <DonutStat theme={isNavy ? 'navy' : 'light'} value={cd[slotKey + '_donut'] ?? 96} suffix="%"
              label={cd[slotKey + '_donut_label'] ?? 'single-cycle efficacy'} size={Math.min(height, 108)}
              onEditValue={(n) => onPatchChart({ [slotKey + '_donut']: n })}
              onEditLabel={(v) => onPatchChart({ [slotKey + '_donut_label']: v })} />
          </div>
        )}
        {kind === 'coverage' && (
          <CoverageMatrix theme={isNavy ? 'navy' : 'light'}
            title={cd[slotKey + '_cov_title'] || 'Single-cycle coverage'}
            items={Array.isArray(cd[slotKey + '_coverage']) ? cd[slotKey + '_coverage'] : ['High-touch surfaces', 'Air and aerosols', 'Floors and drains', 'Restroom fixtures', 'Shared equipment', 'Soft furnishings']} />
        )}
        {kind === 'text' && (
          <Editable value={cd[slotKey + '_text'] || 'Add a supporting point…'} onChange={(v) => onPatchChart({ [slotKey + '_text']: v })} tag="p"
            style={{ fontSize: 13, lineHeight: 1.5, color: isNavy ? 'rgba(255,255,255,0.85)' : 'var(--ink-60)', margin: 0 }} />
        )}
      </div>
    </div>
  );
}

function DeckSlide({ slide, idx, total, hero, support, product, accountLogo, intake = {}, onPatch }) {
  const W = 880;
  // Usable content height above the footer band (slide is 880×495 at 16/9;
  // the footer sits at bottom:16 with a ~38px logo → reserve ~56px).
  const FIT_H = 495 - 40 - 56;
  const set = (k) => (v) => onPatch({ [k]: v });
  const setStat = (k) => (v) => onPatch({ stat: { ...(slide.stat || {}), [k]: v } });
  const slideOverrides = slide.image_overrides || {};
  const onSlideImg = (slot, dataUrl) => onPatch({ image_overrides: { ...slideOverrides, [slot]: dataUrl } });
  const kind = slide.kind || ['title','context','solution','proof','cta'][idx];
  const photo = kind === 'title' ? hero : kind === 'context' ? support : kind === 'solution' ? product : kind === 'proof' ? hero : support;

  const Chrome = () => (
    <div style={{ position: 'absolute', bottom: 16, left: 28, right: 28, display: 'flex', justifyContent: 'space-between', alignItems: 'center', pointerEvents: 'none' }}>
      <div className="mono" style={{ fontSize: 9, letterSpacing: '0.16em', color: 'rgba(255,255,255,0.75)' }}>{String(idx+1).padStart(2,'0')} / {String(total).padStart(2,'0')}</div>
      <VentumLogo background="navy" alt="" style={{ height: 38, opacity: 0.7 }} />
    </div>
  );
  const ChromeLight = () => (
    <div style={{ position: 'absolute', bottom: 16, left: 28, right: 28, display: 'flex', justifyContent: 'space-between', alignItems: 'center', pointerEvents: 'none' }}>
      <div className="mono" style={{ fontSize: 9, letterSpacing: '0.16em', color: 'var(--ink-40)' }}>{String(idx+1).padStart(2,'0')} / {String(total).padStart(2,'0')}</div>
      {/* ghost watermark: color lockup at 50% opacity on a light bg — intentional, not an inverted light/dark mapping */}
      <VentumLogo background="white" alt="" style={{ height: 38, opacity: 0.5 }} />
    </div>
  );

  if (kind === 'title') {
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <EditableImage src={photo} slot="photo" overrides={slideOverrides} adjustments={slide.image_adjustments || {}} onChange={onSlideImg} onChangeAdjust={(slot, adj) => onPatch({ image_adjustments: { ...(slide.image_adjustments || {}), [slot]: adj } })} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.4) 0%, rgba(11,31,51,0.15) 40%, rgba(11,31,51,0.85) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, padding: '36px 56px 60px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: 'white' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <VentumLogo background="navy" alt="" style={{ height: 56 }} />
            {accountLogo && (
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <Editable
                  value={slide.prepared_for_label || 'Prepared for'}
                  onChange={set('prepared_for_label')}
                  tag="span"
                  className="mono"
                  style={{ display: 'inline-block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase' }}
                />
                <div style={{ width: 160, height: 68, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <AccountLogoImg intake={intake} filter="brightness(0) invert(1)" />
                </div>
              </div>
            )}
          </div>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 58, lineHeight: 0.98, letterSpacing: '-0.04em', fontWeight: 400, color: 'white', marginTop: 14, maxWidth: 700 }} />
            <Editable value={slide.subhead} onChange={set('subhead')} tag="p" style={{ fontSize: 17, color: 'rgba(255,255,255,0.78)', marginTop: 16, maxWidth: 520, lineHeight: 1.45 }} />
          </div>
        </div>
        <Chrome />
      </div>
    );
  }

  if (kind === 'context') {
    // Editorial split: a full-height image panel anchors the right edge (always
    // large, independent of the FitToHeight text scaling on the left), with the
    // chart as a compact inset over its lower portion. Text stays left-aligned.
    const CTX_PANEL = 350; // ~40% of the 880px slide
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#fff', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        {/* Full-height image panel — edge to edge on the right */}
        <div style={{ position: 'absolute', top: 0, right: 0, bottom: 0, width: CTX_PANEL, background: '#0B1F33', overflow: 'hidden' }}>
          <EditableImage src={photo} slot="photo" overrides={slideOverrides} adjustments={slide.image_adjustments || {}} onChange={onSlideImg} onChangeAdjust={(slot, adj) => onPatch({ image_adjustments: { ...(slide.image_adjustments || {}), [slot]: adj } })} alt="" />
          <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.10) 0%, rgba(11,31,51,0) 32%, rgba(11,31,51,0.88) 100%)', pointerEvents: 'none' }} />
          <Editable value={slide.image_caption_label || 'Field conditions'} onChange={set('image_caption_label')} className="mono" style={{ position: 'absolute', top: 26, left: 26, fontSize: 9, color: 'rgba(255,255,255,0.82)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
          <div style={{ position: 'absolute', left: 24, right: 24, bottom: 56, background: 'rgba(255,255,255,0.97)', borderRadius: 3, padding: '12px 14px', boxShadow: '0 10px 24px -10px rgba(0,0,0,0.5)' }}>
            <DeckChartSlot
              cd={slide.chart_data || {}}
              onPatchChart={(p) => onPatch({ chart_data: { ...(slide.chart_data || {}), ...p } })}
              slotKey="ctx" defaultKind="bars" theme="light" height={92}
            />
          </div>
        </div>
        {/* Left text column */}
        <div style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: W - CTX_PANEL, padding: '44px 40px 56px 56px', display: 'flex', alignItems: 'center' }}>
          <FitToHeight maxH={FIT_H}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, marginTop: 10 }} />
            <Editable value={slide.body} onChange={set('body')} tag="p" style={{ fontSize: 15, color: 'var(--ink-80)', marginTop: 16, lineHeight: 1.5 }} />
            {slide.stat && (
              // Stack vertically — earlier attempts with display:flex +
              // alignItems baseline/flex-end both produced overlap in
              // the html2canvas capture (live console showed
              // foreignObject failing for every deck slide and falling
              // back to the standard text engine, which mis-positions
              // adjacent elements with very different font sizes).
              // Stacking sidesteps the issue completely.
              //
              // Also: drop the stat value's negative letter-spacing to
              // 0. Headlines render fine with -0.04em at 42px, but the
              // 52px stat with $-digits-commas is the sweet spot where
              // html2canvas's text engine drifts individual characters
              // and they end up looking double-printed in the PDF.
              // Zero letter-spacing gives a clean rasterization at the
              // cost of slightly looser tracking on the stat itself.
              // marginTop/Bottom on the SHOULDER elements (not on the flex
              // gap) because html2canvas in the standard path mis-measures
              // the rendered text-box height when lineHeight is tight —
              // it positions the next sibling based on a metrics-fallback
              // height that's shorter than the actual rasterized glyphs,
              // so the caption ends up drawn over the bottom of the digits.
              // Generous lineHeight + explicit marginBottom on the value
              // (rather than gap on the parent) gives a deterministic clear
              // band the engine can't undershoot. display:block forces each
              // Editable out of inline flow so wrapping is predictable.
              // Stat at fontSize 42 (was 52). Larger sizes amplify
              // html2canvas's subpixel positioning errors — that's
              // visible in the "$24,390+" rendering chasing through
              // multiple commits. 42 is in the same regime as the
              // headlines (which render cleanly) and reads as the
              // hero number it's meant to be at the slide's effective
              // viewing size.
              //
              // Vertical clearance: lineHeight 1.25 + marginBottom 14.
              // Tuned so the caption doesn't push down into the slide
              // footer (overflow visible in the latest screenshot)
              // while still keeping clear of the stat's descenders.
              //
              // No font-feature overrides (tabular-nums + fontKerning
              // + textRendering produced character crushing in an
              // earlier attempt). Natural kerning from the font's own
              // metrics gives the cleanest html2canvas result here.
              <div style={{ marginTop: 22 }}>
                <Editable value={slide.stat.value} onChange={setStat('value')} style={{ display: 'block', fontSize: 40, fontWeight: 400, color: 'var(--navy)', lineHeight: 1.2, marginBottom: 10 }} />
                <Editable value={slide.stat.unit} onChange={setStat('unit')} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', lineHeight: 1.5 }} />
              </div>
            )}
          </div>
          </FitToHeight>
        </div>
        {/* Custom footer: page number on the light side; white ghost logo over the image panel */}
        <div className="mono" style={{ position: 'absolute', bottom: 20, left: 56, fontSize: 9, letterSpacing: '0.16em', color: 'var(--ink-40)', pointerEvents: 'none' }}>{String(idx+1).padStart(2,'0')} / {String(total).padStart(2,'0')}</div>
        <div style={{ position: 'absolute', bottom: 15, right: 22, pointerEvents: 'none' }}>
          <VentumLogo background="navy" alt="" style={{ height: 30, opacity: 0.85 }} />
        </div>
      </div>
    );
  }

  if (kind === 'solution') {
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0,
          backgroundImage: 'radial-gradient(ellipse 60% 50% at 90% 0%, rgba(37,99,235,0.30), transparent 55%), radial-gradient(ellipse 70% 60% at 10% 100%, rgba(34,184,167,0.22), transparent 60%)'
        }} />
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 32, alignItems: 'center' }}>
          <div style={{ position: 'relative', height: '80%', borderRadius: 2, overflow: 'hidden', background: '#142A40' }}>
            <EditableImage src={photo} slot="photo" overrides={slideOverrides} adjustments={slide.image_adjustments || {}} onChange={onSlideImg} onChangeAdjust={(slot, adj) => onPatch({ image_adjustments: { ...(slide.image_adjustments || {}), [slot]: adj } })} alt="" />
          </div>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 38, lineHeight: 1.04, letterSpacing: '-0.03em', fontWeight: 400, marginTop: 10, color: 'white' }} />
            <Editable value={slide.body} onChange={set('body')} tag="p" style={{ fontSize: 14.5, color: 'rgba(255,255,255,0.78)', marginTop: 16, lineHeight: 1.5 }} />
            <div style={{ marginTop: 20, display: 'flex', flexDirection: 'column', gap: 10 }}>
              {(slide.bullets || []).map((b, bi) => (
                <div key={bi} style={{ display: 'grid', gridTemplateColumns: '18px 1fr', gap: 10, alignItems: 'baseline' }}>
                  <span className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.14em' }}>{String(bi+1).padStart(2,'0')}</span>
                  <Editable
                    value={b}
                    onChange={(v) => {
                      const next = [...(slide.bullets || [])];
                      next[bi] = v;
                      onPatch({ bullets: next });
                    }}
                    style={{ fontSize: 14, lineHeight: 1.4, color: 'rgba(255,255,255,0.92)' }}
                  />
                </div>
              ))}
            </div>
          </div>
        </div>
        <Chrome />
      </div>
    );
  }

  if (kind === 'proof') {
    const cd = slide.chart_data || {};
    const bars = cd.before_after || [{ label: 'Before', value: 100, suffix: 'idx' }, { label: 'With Ventum', value: 32, suffix: 'idx' }];
    const setChart = (key, value) => onPatch({ chart_data: { ...cd, [key]: value } });
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#fff', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 32, alignItems: 'stretch' }}>
          <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
            <div>
              <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
              <Editable value={slide.headline} onChange={set('headline')} tag="h2" style={{ fontSize: 30, fontWeight: 400, letterSpacing: '-0.025em', lineHeight: 1.1, marginTop: 8 }} />
              <div style={{ marginTop: 18, borderLeft: '3px solid var(--teal)', paddingLeft: 16 }}>
                <Editable value={slide.quote} onChange={set('quote')} tag="p" style={{ fontSize: 19, lineHeight: 1.35, letterSpacing: '-0.012em', color: 'var(--ink-100)' }} />
                <Editable value={slide.attribution} onChange={set('attribution')} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--ink-60)', marginTop: 10, letterSpacing: '0.1em' }} />
              </div>
            </div>
            {/* Inline chart — editable type + values (Bars / Decay / Text) */}
            <div style={{ marginTop: 18, padding: '14px 16px', background: 'var(--ink-05)', borderRadius: 2 }}>
              <DeckChartSlot
                cd={cd}
                onPatchChart={(p) => onPatch({ chart_data: { ...cd, ...p } })}
                slotKey="proof_bars" defaultKind="bars" barsKey="before_after"
                theme="light" height={72} allow={['bars', 'decay', 'text']}
              />
            </div>
          </div>
          <div style={{ background: 'var(--navy)', color: 'white', padding: 24, borderRadius: 2, display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
            <div>
              <Editable value={(slide.stat || {}).unit} onChange={setStat('unit')} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
              <Editable value={(slide.stat || {}).value} onChange={setStat('value')} style={{ display: 'block', fontSize: 60, lineHeight: 1, letterSpacing: '-0.04em', fontWeight: 400, marginTop: 6 }} />
            </div>
            <div style={{ marginTop: 16 }}>
              <DeckChartSlot
                cd={cd}
                onPatchChart={(p) => onPatch({ chart_data: { ...cd, ...p } })}
                slotKey="proof_stat" defaultKind="coverage"
                theme="navy" height={90} width={280}
                decayFrom="10⁶" decayTo="< 1" decayDuration="cycle"
                allow={['decay', 'donut', 'text']}
              />
            </div>
          </div>
        </div>
        <ChromeLight />
      </div>
    );
  }

  if (kind === 'cta') {
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0,
          backgroundImage: 'radial-gradient(ellipse 80% 60% at 20% 110%, rgba(34,184,167,0.30), transparent 60%), radial-gradient(ellipse 70% 50% at 90% 0%, rgba(37,99,235,0.30), transparent 55%)'
        }} />
        <div style={{ position: 'absolute', inset: 0, padding: '44px 60px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <VentumLogo background="navy" alt="" style={{ height: 56 }} />
            {accountLogo && (
              <div style={{ width: 164, height: 68, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <AccountLogoImg intake={intake} filter="brightness(0) invert(1)" />
              </div>
            )}
          </div>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 54, lineHeight: 1.0, letterSpacing: '-0.04em', fontWeight: 400, color: 'white', marginTop: 14, maxWidth: 720 }} />
            <Editable value={slide.body} onChange={set('body')} tag="p" style={{ fontSize: 16, color: 'rgba(255,255,255,0.78)', marginTop: 16, maxWidth: 540, lineHeight: 1.5 }} />
            {slide.cta && (
              <div style={{ marginTop: 24 }}>
                <EditableCTA value={slide.cta} onChange={set('cta')} url={slide.cta_url} onUrlChange={set('cta_url')} style={{ display: 'inline-flex', alignItems: 'center', background: 'white', color: 'var(--navy)', padding: '13px 20px', fontSize: 14.5, fontWeight: 500, borderRadius: 2, lineHeight: 1 }} />
              </div>
            )}
          </div>
        </div>
        <Chrome />
      </div>
    );
  }

  // ----------------------------------------------------------
  // PITCH-DECK SLIDE KINDS (added for pitch_10 template)
  // Each has its own visual treatment so a 10-slide pitch doesn't
  // look like 10 versions of the same template.
  // ----------------------------------------------------------

  // PROBLEM — empathy frame. Big headline, customer quote pull, stat anchor.
  if (kind === 'problem') {
    const q = slide.customer_quote || {};
    const setQuote = (k) => (v) => onPatch({ customer_quote: { ...q, [k]: v } });
    const stat = slide.stat || {};
    const setStatLabel = (v) => onPatch({ stat: { ...stat, label: v } });
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0,
          backgroundImage: 'radial-gradient(ellipse 60% 50% at 0% 0%, rgba(163,48,39,0.18), transparent 60%), radial-gradient(ellipse 70% 60% at 100% 100%, rgba(37,99,235,0.18), transparent 60%)'
        }} />
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'flex', alignItems: 'center' }}>
          <FitToHeight maxH={FIT_H}>
          <div style={{ display: 'grid', gridTemplateColumns: '1.15fr 1fr', gap: 36, alignItems: 'center', width: '100%' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 50, lineHeight: 1.02, letterSpacing: '-0.035em', fontWeight: 400, color: 'white', marginTop: 12, maxWidth: 520 }} />
            <Editable value={slide.body} onChange={set('body')} tag="p" style={{ fontSize: 16, color: 'rgba(255,255,255,0.72)', marginTop: 18, lineHeight: 1.5, maxWidth: 460 }} />
            {(stat.value || stat.unit || stat.label) && (
              <div style={{ marginTop: 28, paddingTop: 18, borderTop: '1px solid rgba(255,255,255,0.12)', display: 'flex', alignItems: 'baseline', gap: 12 }}>
                <Editable value={stat.value} onChange={setStat('value')} style={{ fontSize: 44, fontWeight: 400, letterSpacing: '-0.035em', color: 'var(--teal)' }} />
                <Editable value={stat.unit} onChange={setStat('unit')} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
                <Editable value={stat.label} onChange={setStatLabel} style={{ fontSize: 13, color: 'rgba(255,255,255,0.7)', marginLeft: 'auto' }} />
              </div>
            )}
          </div>
          {(q.text || q.attribution) && (
            <div style={{ position: 'relative', paddingLeft: 24, borderLeft: '3px solid rgba(255,255,255,0.2)' }}>
              <div style={{ fontFamily: 'Georgia, serif', fontSize: 70, lineHeight: 0.5, color: 'rgba(255,255,255,0.25)', position: 'absolute', top: -8, left: 4 }}>"</div>
              <Editable value={q.text} onChange={setQuote('text')} tag="blockquote" style={{ fontFamily: 'Georgia, serif', fontSize: 22, lineHeight: 1.35, fontStyle: 'italic', color: 'rgba(255,255,255,0.92)', margin: 0 }} />
              <Editable value={q.attribution} onChange={setQuote('attribution')} className="mono" style={{ display: 'block', marginTop: 16, fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
            </div>
          )}
          </div>
          </FitToHeight>
        </div>
        <Chrome />
      </div>
    );
  }

  // MARKET — TAM / SAM / SOM stat stack.
  if (kind === 'market') {
    const stats = Array.isArray(slide.stats) ? slide.stats : [];
    const setSlot = (i, k) => (v) => {
      const next = stats.slice();
      next[i] = { ...(next[i] || {}), [k]: v };
      onPatch({ stats: next });
    };
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#fff', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 44, lineHeight: 1.04, letterSpacing: '-0.035em', fontWeight: 400, marginTop: 10, maxWidth: 640 }} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 0 }}>
            {[0,1,2].map(i => {
              const s = stats[i] || {};
              // Stat values are a big-number slot ("$9.8B", "143", "LOG 6").
              // The AI sometimes fills them with a phrase ("Effective against
              // the biological spectrum") — at 56px that overflows and crams
              // (and the PPTX text-frame inherits the same size). Scale the
              // value down by length so long copy fits the slot instead.
              const vlen = String(s.value || '').length;
              const vFont = vlen <= 8 ? 56 : vlen <= 14 ? 42 : vlen <= 22 ? 30 : vlen <= 34 ? 23 : 19;
              return (
                <div key={i} style={{ padding: '24px 28px', borderLeft: i === 0 ? 'none' : '1px solid var(--ink-10)' }}>
                  <Editable value={s.label} onChange={setSlot(i, 'label')} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 12 }} />
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
                    <Editable value={s.value} onChange={setSlot(i, 'value')} style={{ fontSize: vFont, fontWeight: 400, letterSpacing: '-0.04em', color: 'var(--navy)', lineHeight: 0.95 }} />
                    <Editable value={s.unit} onChange={setSlot(i, 'unit')} className="mono" style={{ fontSize: 12, color: 'var(--ink-60)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
                  </div>
                </div>
              );
            })}
          </div>
          <Editable value={slide.source_note} onChange={set('source_note')} className="mono" style={{ display: 'block', fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
        </div>
        <ChromeLight />
      </div>
    );
  }

  // DEMO — image showcase with capability pills.
  if (kind === 'demo') {
    const caps = Array.isArray(slide.capabilities) ? slide.capabilities : [];
    const setCap = (i) => (v) => {
      const next = caps.slice();
      next[i] = v;
      onPatch({ capabilities: next });
    };
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#fff', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)', display: 'grid', gridTemplateColumns: '1.25fr 1fr' }}>
        <div style={{ position: 'relative', overflow: 'hidden', background: '#0B1F33' }}>
          <EditableImage src={photo} slot="photo" overrides={slideOverrides} adjustments={slide.image_adjustments || {}} onChange={onSlideImg} onChangeAdjust={(slot, adj) => onPatch({ image_adjustments: { ...(slide.image_adjustments || {}), [slot]: adj } })} alt="" />
          <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(110deg, rgba(11,31,51,0) 50%, rgba(11,31,51,0.45) 100%)', pointerEvents: 'none' }} />
        </div>
        <div style={{ padding: '40px 36px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 36, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, marginTop: 10 }} />
            <Editable value={slide.body} onChange={set('body')} tag="p" style={{ fontSize: 15, color: 'var(--ink-80)', marginTop: 14, lineHeight: 1.55 }} />
          </div>
          <div>
            <Editable
              value={slide.capabilities_label || 'Capabilities'}
              onChange={set('capabilities_label')}
              className="mono"
              style={{ display: 'block', fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10 }}
            />
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {[0,1,2,3].map(i => caps[i] ? (
                <div key={i} style={{ padding: '6px 12px', background: 'var(--ink-05)', border: '1px solid var(--ink-10)', borderRadius: 999, fontSize: 12 }}>
                  <Editable value={caps[i]} onChange={setCap(i)} />
                </div>
              ) : null)}
            </div>
          </div>
        </div>
        <div style={{ position: 'absolute', bottom: 16, left: 28, right: 28, display: 'flex', justifyContent: 'space-between', alignItems: 'center', pointerEvents: 'none' }}>
          <div className="mono" style={{ fontSize: 9, letterSpacing: '0.16em', color: 'rgba(255,255,255,0.75)' }}>{String(idx+1).padStart(2,'0')} / {String(total).padStart(2,'0')}</div>
        </div>
      </div>
    );
  }

  // TRACTION — growth grid with delta indicators.
  if (kind === 'traction') {
    const stats = Array.isArray(slide.stats) ? slide.stats : [];
    const setSlot = (i, k) => (v) => {
      const next = stats.slice();
      next[i] = { ...(next[i] || {}), [k]: v };
      onPatch({ stats: next });
    };
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#fff', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, marginTop: 10 }} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: stats.length >= 4 ? 'repeat(4, 1fr)' : 'repeat(3, 1fr)', gap: 14 }}>
            {stats.slice(0, 6).map((s, i) => {
              const delta = s.delta || '';
              const positive = !/^[-−]/.test(delta);
              return (
                <div key={i} style={{ padding: '18px 16px', border: '1px solid var(--ink-10)', borderRadius: 3, background: 'var(--ink-05)' }}>
                  <Editable value={s.label} onChange={setSlot(i, 'label')} className="mono" style={{ display: 'block', fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 8 }} />
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                    <Editable value={s.value} onChange={setSlot(i, 'value')} style={{ fontSize: 32, fontWeight: 400, letterSpacing: '-0.03em', color: 'var(--navy)', lineHeight: 1 }} />
                    <Editable value={s.unit} onChange={setSlot(i, 'unit')} className="mono" style={{ fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
                  </div>
                  {delta && (
                    <div style={{ marginTop: 6, fontSize: 11, color: positive ? '#1F5A48' : '#A33027', display: 'flex', alignItems: 'center', gap: 4 }}>
                      <span style={{ fontWeight: 600 }}>{positive ? '↑' : '↓'}</span>
                      <Editable value={delta} onChange={setSlot(i, 'delta')} />
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          <Editable value={slide.timeframe} onChange={set('timeframe')} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
        </div>
        <ChromeLight />
      </div>
    );
  }

  // TEAM — people grid with avatar initials, role, credential.
  if (kind === 'team') {
    const members = Array.isArray(slide.members) ? slide.members : [];
    const setMember = (i, k) => (v) => {
      const next = members.slice();
      next[i] = { ...(next[i] || {}), [k]: v };
      onPatch({ members: next });
    };
    const initials = (name) => (name || '').split(/\s+/).map(w => w[0] || '').slice(0, 2).join('').toUpperCase();
    const cols = members.length >= 4 ? 4 : Math.max(3, members.length || 3);
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0,
          backgroundImage: 'radial-gradient(ellipse 70% 60% at 80% 100%, rgba(34,184,167,0.22), transparent 60%)'
        }} />
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, color: 'white', marginTop: 10 }} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: 18 }}>
            {members.slice(0, 6).map((m, i) => (
              <div key={i} style={{ textAlign: 'center' }}>
                <div style={{ width: 72, height: 72, borderRadius: '50%', background: 'linear-gradient(135deg, var(--teal), #1A4D40)', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 12px', fontSize: 22, fontWeight: 500, letterSpacing: '0.05em', color: 'white' }}>
                  {initials(m.name)}
                </div>
                <Editable value={m.name} onChange={setMember(i, 'name')} style={{ display: 'block', fontSize: 15, fontWeight: 500, color: 'white' }} />
                <Editable value={m.role} onChange={setMember(i, 'role')} className="mono" style={{ display: 'block', fontSize: 9.5, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase', marginTop: 4 }} />
                <Editable value={m.credential} onChange={setMember(i, 'credential')} style={{ display: 'block', fontSize: 11.5, color: 'rgba(255,255,255,0.72)', marginTop: 6, lineHeight: 1.35 }} />
              </div>
            ))}
          </div>
          <Editable value={slide.advisors_note} onChange={set('advisors_note')} className="mono" style={{ display: 'block', fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
        </div>
        <Chrome />
      </div>
    );
  }

  // ASK — big number + use-of-funds horizontal bars + next step.
  if (kind === 'ask') {
    const funds = Array.isArray(slide.use_of_funds) ? slide.use_of_funds : [];
    const setFund = (i, k) => (v) => {
      const next = funds.slice();
      const cleaned = k === 'percent' ? Number(String(v).replace(/[^\d]/g, '')) || 0 : v;
      next[i] = { ...(next[i] || {}), [k]: cleaned };
      onPatch({ use_of_funds: next });
    };
    return (
      <div style={{ width: W, aspectRatio: '16/9', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden', boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
        <div style={{ position: 'absolute', inset: 0,
          backgroundImage: 'radial-gradient(ellipse 70% 60% at 0% 0%, rgba(34,184,167,0.25), transparent 55%), radial-gradient(ellipse 70% 60% at 100% 100%, rgba(37,99,235,0.22), transparent 60%)'
        }} />
        <div style={{ position: 'absolute', inset: 0, padding: '40px 56px 56px', display: 'grid', gridTemplateColumns: '1fr 1.2fr', gap: 40, alignItems: 'center' }}>
          <div>
            <Editable value={slide.eyebrow} onChange={set('eyebrow')} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={slide.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 36, lineHeight: 1.05, letterSpacing: '-0.03em', fontWeight: 400, color: 'white', marginTop: 8 }} />
            <Editable value={slide.ask_amount} onChange={set('ask_amount')} style={{ display: 'block', fontSize: 84, fontWeight: 400, letterSpacing: '-0.04em', color: 'var(--teal)', marginTop: 18, lineHeight: 0.95 }} />
            <div style={{ marginTop: 28, paddingTop: 18, borderTop: '1px solid rgba(255,255,255,0.18)' }}>
              <Editable
                value={slide.next_step_label || 'Next step'}
                onChange={set('next_step_label')}
                className="mono"
                style={{ display: 'block', fontSize: 10, letterSpacing: '0.16em', color: 'rgba(255,255,255,0.75)', textTransform: 'uppercase', marginBottom: 6 }}
              />
              <Editable value={slide.next_step} onChange={set('next_step')} style={{ fontSize: 15.5, color: 'rgba(255,255,255,0.92)', lineHeight: 1.45 }} />
            </div>
          </div>
          <div>
            <Editable
              value={slide.use_of_funds_label || 'Use of funds'}
              onChange={set('use_of_funds_label')}
              className="mono"
              style={{ display: 'block', fontSize: 10, letterSpacing: '0.16em', color: 'rgba(255,255,255,0.75)', textTransform: 'uppercase', marginBottom: 16 }}
            />
            {funds.slice(0, 5).map((f, i) => {
              const pct = Math.max(0, Math.min(100, Number(f.percent) || 0));
              return (
                <div key={i} style={{ marginBottom: 14 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                    <Editable value={f.category} onChange={setFund(i, 'category')} style={{ fontSize: 13, color: 'rgba(255,255,255,0.95)', fontWeight: 500 }} />
                    <span className="mono" style={{ fontSize: 12, color: 'var(--teal)', letterSpacing: '0.06em' }}>
                      <Editable value={String(pct)} onChange={setFund(i, 'percent')} />%
                    </span>
                  </div>
                  <div style={{ height: 8, background: 'rgba(255,255,255,0.08)', borderRadius: 4, overflow: 'hidden' }}>
                    <div style={{ width: pct + '%', height: '100%', background: 'linear-gradient(90deg, var(--teal), #1A4D40)' }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
        <Chrome />
      </div>
    );
  }

  return (
    <div style={{ width: W, aspectRatio: '16/9', background: '#fff', padding: 40, boxShadow: '0 20px 40px -15px rgba(11,31,51,0.18)' }}>
      <pre style={{ fontSize: 11 }}>{JSON.stringify(slide, null, 2)}</pre>
    </div>
  );
}

// Memoized deck slide — with the stable per-slide patchers in DeckRender, only
// the edited slide re-renders on an edit (no whole-deck reflash). Props are
// stable-by-value when unchanged (image URLs are strings; idx/total numbers;
// only the edited slide's `slide` object changes identity).
const DeckSlideMemo = React.memo(DeckSlide);

// ============================================================
// Web hero
// ============================================================
function WebHeroRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  return (
    <div style={{ width: 880, background: '#061320', color: 'white', padding: 48, display: 'grid', gridTemplateColumns: '1.1fr 1fr', gap: 32, alignItems: 'center', minHeight: 380, boxShadow: '0 30px 60px -20px rgba(11,31,51,0.25)' }}>
      <div>
        <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
        <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 46, lineHeight: 1.0, letterSpacing: '-0.035em', fontWeight: 400, color: 'white', marginTop: 12 }} />
        <Editable value={a.subhead} onChange={set(['subhead'])} tag="p" style={{ color: 'rgba(255,255,255,0.78)', marginTop: 16, maxWidth: 460, fontSize: 15.5, lineHeight: 1.5 }} />
        <div style={{ display: 'flex', gap: 12, marginTop: 22, alignItems: 'center' }}>
          <EditableCTA value={a.primary_cta} onChange={set(['primary_cta'])} url={a.primary_cta_url} onUrlChange={set(['primary_cta_url'])} style={{ background: 'white', color: 'var(--navy)', padding: '11px 18px', fontSize: 13.5, fontWeight: 500, borderRadius: 2 }} />
          <Editable value={a.secondary_cta_text} onChange={set(['secondary_cta_text'])} style={{ color: 'rgba(255,255,255,0.7)', fontSize: 12.5, borderBottom: '1px solid rgba(255,255,255,0.3)', paddingBottom: 1 }} />
        </div>
      </div>
      <div style={{ position: 'relative', height: 280, background: '#142A40', borderRadius: 2, overflow: 'hidden' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
        {a.stat_overlay && (
          <div style={{ position: 'absolute', bottom: 16, right: 16, background: 'rgba(11,31,51,0.85)', backdropFilter: 'blur(6px)', padding: '12px 14px', border: '1px solid rgba(255,255,255,0.18)' }}>
            <Editable value={a.stat_overlay.unit} onChange={(v) => onPatch(setPath(a, ['stat_overlay','unit'], v))} className="mono" style={{ fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
            <Editable value={a.stat_overlay.value} onChange={(v) => onPatch(setPath(a, ['stat_overlay','value'], v))} style={{ display: 'block', color: 'white', fontSize: 22, fontWeight: 400, letterSpacing: '-0.02em', marginTop: 2 }} />
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================
// Print ad
// ============================================================
function PrintAdRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake, { preferProduct: false });
  return (
    <div style={{ width: 480, aspectRatio: '3/4', background: '#0B1F33', position: 'relative', overflow: 'hidden', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.25)' }}>
      <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.7), rgba(11,31,51,0.15) 38%, transparent 55%, rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
      <div style={{ position: 'absolute', inset: 0, padding: 32, display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: 'white' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 60 }} />
          <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.14em', textTransform: 'uppercase', textAlign: 'right' }} />
        </div>
        <div>
          <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 44, lineHeight: 0.96, letterSpacing: '-0.035em', fontWeight: 400, maxWidth: 380, color: 'white' }} />
          {a.body && (
            <Editable value={a.body} onChange={set(['body'])} tag="p" style={{ fontSize: 13.5, lineHeight: 1.55, color: 'rgba(255,255,255,0.85)', maxWidth: 340, marginTop: 14 }} />
          )}
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'end', paddingTop: 12, borderTop: '1px solid rgba(255,255,255,0.18)' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="footer_url" defaultText="ventum.bio" className="" style={{ display: 'inline-block', fontSize: 12.5 }} />
          <Editable value={a.signoff} onChange={set(['signoff'])} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em' }} />
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Banner
// ============================================================
function BannerRender({ a, onPatch }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  return (
    <div style={{ width: 280, aspectRatio: '33/80', background: '#061320', color: 'white', display: 'flex', flexDirection: 'column', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.25)' }}>
      <div style={{ padding: '24px 22px 0' }}><VentumLogo background="navy" alt="Ventum" style={{ height: 64 }} /></div>
      <div style={{ flex: 1, padding: '24px 22px', display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 20, background: 'radial-gradient(ellipse 80% 50% at 0% 60%, rgba(34,184,167,0.25), transparent 60%)' }}>
        <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
        <Editable value={a.headline} onChange={set(['headline'])} tag="h2" style={{ fontSize: 30, lineHeight: 1.0, letterSpacing: '-0.03em', fontWeight: 400, color: 'white' }} />
        {a.stat && (
          <div>
            <Editable value={a.stat.value} onChange={(v) => onPatch(setPath(a, ['stat','value'], v))} style={{ fontSize: 56, lineHeight: 0.9, letterSpacing: '-0.04em', fontWeight: 400 }} />
            <Editable value={a.stat.unit} onChange={(v) => onPatch(setPath(a, ['stat','unit'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', marginTop: 6 }} />
          </div>
        )}
      </div>
      <div style={{ padding: '20px 22px', borderTop: '1px solid rgba(255,255,255,0.14)', textAlign: 'center' }}>
        <Editable value={a.cta} onChange={set(['cta'])} style={{ display: 'inline-block', background: 'white', color: 'var(--navy)', padding: '9px 12px', fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase' }} />
      </div>
    </div>
  );
}

// ============================================================
// LinkedIn carousel
// ============================================================
function CarouselRender({ a, onPatch }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16, alignItems: 'center' }}>
      <div style={{ display: 'flex', gap: 14, overflowX: 'auto', padding: '4px 4px 16px', maxWidth: 760 }}>
        {(a.frames || []).map((f, i) => {
          const isNavy = f.style === 'navy' || f.style === 'chart';
          const isChart = f.style === 'chart' || (f.style === 'navy' && /\b\d|%|x|min|hr|reduce|cut|drop|lift\b/i.test(f.body || ''));
          // pick a chart kind based on position (override via chart_data.f{i}_kind)
          const chartKind = a.chart_data?.[`f${i}_kind`] || ((i % 3 === 0) ? 'bars' : (i % 3 === 1) ? 'decay' : 'donut');
          return (
            <div key={i} data-carousel-frame="true" style={{
              width: 320, aspectRatio: '4/5', flex: '0 0 auto',
              background: isNavy ? '#0B1F33' : '#fff',
              color: isNavy ? 'white' : 'var(--ink-100)',
              padding: 24, display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
              boxShadow: '0 16px 30px -10px rgba(11,31,51,0.15)',
              borderRadius: 3
            }}>
              <div className="mono" style={{ fontSize: 10, color: isNavy ? 'rgba(255,255,255,0.75)' : 'var(--ink-40)', letterSpacing: '0.14em' }}>{String(f.frame_num).padStart(2,'0')} / {a.frames.length}</div>
              <div>
                <Editable
                  value={f.headline}
                  onChange={(v) => onPatch(setPath(a, ['frames', i, 'headline'], v))}
                  tag="h3"
                  style={{ fontSize: 22, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1.1, color: isNavy ? 'white' : 'var(--ink-100)' }}
                />
                {isChart ? (
                  <div style={{ marginTop: 14 }}>
                    {/* Chart + Smart-art type picker — editor only, stripped in export */}
                    <div data-editor-only="true" style={{ display: 'flex', flexDirection: 'column', gap: 4, marginBottom: 10 }}>
                      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 0, border: '1px solid rgba(255,255,255,0.18)', borderRadius: 3, overflow: 'hidden' }}>
                        {[
                          { id: 'bars',     label: 'Bars' },
                          { id: 'decay',    label: 'Decay' },
                          { id: 'donut',    label: 'Donut' },
                        ].map(opt => {
                          const active = chartKind === opt.id;
                          return (
                            <button
                              key={opt.id}
                              onClick={() => onPatch(setPath(a, ['chart_data', `f${i}_kind`], opt.id))}
                              style={{
                                background: active ? (isNavy ? 'rgba(255,255,255,0.18)' : 'var(--navy)') : 'transparent',
                                color: active ? (isNavy ? 'white' : 'white') : (isNavy ? 'rgba(255,255,255,0.55)' : 'var(--ink-40)'),
                                border: 'none',
                                padding: '4px 8px',
                                fontFamily: 'var(--mono)',
                                fontSize: 9,
                                letterSpacing: '0.1em',
                                textTransform: 'uppercase',
                                cursor: 'pointer',
                                lineHeight: 1
                              }}
                            >{opt.label}</button>
                          );
                        })}
                      </div>
                      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 0, border: '1px solid rgba(255,255,255,0.18)', borderRadius: 3, overflow: 'hidden' }}>
                        {[
                          { id: 'statgrid', label: 'Stat grid' },
                          { id: 'iconrow',  label: 'Steps' },
                          { id: 'table',    label: 'Compare' },
                          { id: 'split',    label: 'Split' },
                        ].map(opt => {
                          const active = chartKind === opt.id;
                          return (
                            <button
                              key={opt.id}
                              onClick={() => onPatch(setPath(a, ['chart_data', `f${i}_kind`], opt.id))}
                              style={{
                                background: active ? (isNavy ? 'rgba(34,184,167,0.30)' : 'var(--navy)') : 'transparent',
                                color: active ? (isNavy ? 'white' : 'white') : (isNavy ? 'rgba(255,255,255,0.55)' : 'var(--ink-40)'),
                                border: 'none',
                                padding: '4px 8px',
                                fontFamily: 'var(--mono)',
                                fontSize: 9,
                                letterSpacing: '0.1em',
                                textTransform: 'uppercase',
                                cursor: 'pointer',
                                lineHeight: 1
                              }}
                            >{opt.label}</button>
                          );
                        })}
                      </div>
                    </div>
                    {chartKind === 'bars' && (
                      <BeforeAfterBars
                        theme={isNavy ? 'navy' : 'light'}
                        title="Operational lift"
                        items={(a.chart_data?.[`f${i}_bars`]) || [
                          { label: 'Before', value: 100, suffix: 'idx' },
                          { label: 'Ventum', value: 34, suffix: 'idx' }
                        ]}
                        onEditValue={(idx, num) => {
                          const cd = a.chart_data || {};
                          const cur = cd[`f${i}_bars`] || [
                            { label: 'Before', value: 100, suffix: 'idx' },
                            { label: 'Ventum', value: 34, suffix: 'idx' }
                          ];
                          const next = cur.map((b, bi) => bi === idx ? { ...b, value: num } : b);
                          onPatch(setPath(a, ['chart_data', `f${i}_bars`], next));
                        }}
                      />
                    )}
                    {chartKind === 'decay' && (
                      <DecayCurve
                        theme={isNavy ? 'navy' : 'light'}
                        fromLabel={(a.chart_data?.[`f${i}_decay_from`]) ?? '10⁶'}
                        toLabel={(a.chart_data?.[`f${i}_decay_to`]) ?? '< 1'}
                        durationLabel={(a.chart_data?.[`f${i}_decay_duration`]) ?? 'cycle'}
                        width={260} height={92}
                        onEditFromLabel={(v) => onPatch(setPath(a, ['chart_data', `f${i}_decay_from`], v))}
                        onEditToLabel={(v) => onPatch(setPath(a, ['chart_data', `f${i}_decay_to`], v))}
                        onEditDurationLabel={(v) => onPatch(setPath(a, ['chart_data', `f${i}_decay_duration`], v))}
                      />
                    )}
                    {chartKind === 'donut' && (
                      <div style={{ display: 'flex', justifyContent: 'center', marginTop: 4 }}>
                        <DonutStat
                          theme={isNavy ? 'navy' : 'light'}
                          value={a.chart_data?.[`f${i}_donut`] ?? 96}
                          suffix="%"
                          label={(a.chart_data?.[`f${i}_donut_label`]) ?? 'single-cycle efficacy'}
                          size={120}
                          onEditValue={(num) => onPatch(setPath(a, ['chart_data', `f${i}_donut`], num))}
                          onEditLabel={(v) => onPatch(setPath(a, ['chart_data', `f${i}_donut_label`], v))}
                        />
                      </div>
                    )}
                    {chartKind === 'statgrid' && (
                      <StatCalloutGrid
                        theme={isNavy ? 'navy' : 'light'}
                        stats={(a.chart_data?.[`f${i}_statgrid`]) || [
                          { value: '99.9%', unit: '', label: 'Single-cycle efficacy' },
                          { value: '6-log', unit: '', label: 'Pathogen reduction' },
                          { value: '< 4 min', unit: '', label: 'Cycle time' },
                        ]}
                        onEditValue={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_statgrid`]) || [
                            { value: '99.9%', unit: '', label: 'Single-cycle efficacy' },
                            { value: '6-log', unit: '', label: 'Pathogen reduction' },
                            { value: '< 4 min', unit: '', label: 'Cycle time' },
                          ];
                          const next = cur.map((s, si) => si === idx ? { ...s, value: raw } : s);
                          onPatch(setPath(a, ['chart_data', `f${i}_statgrid`], next));
                        }}
                        onEditLabel={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_statgrid`]) || [
                            { value: '99.9%', unit: '', label: 'Single-cycle efficacy' },
                            { value: '6-log', unit: '', label: 'Pathogen reduction' },
                            { value: '< 4 min', unit: '', label: 'Cycle time' },
                          ];
                          const next = cur.map((s, si) => si === idx ? { ...s, label: raw } : s);
                          onPatch(setPath(a, ['chart_data', `f${i}_statgrid`], next));
                        }}
                      />
                    )}
                    {chartKind === 'iconrow' && (
                      <IconProcessRow
                        theme={isNavy ? 'navy' : 'light'}
                        steps={(a.chart_data?.[`f${i}_iconrow`]) || [
                          { number: '01', label: 'Deploy', detail: 'Install unit in space' },
                          { number: '02', label: 'Activate', detail: 'One-touch cycle start' },
                          { number: '03', label: 'Verify', detail: 'Automated log report' },
                        ]}
                        onEditLabel={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_iconrow`]) || [
                            { number: '01', label: 'Deploy', detail: 'Install unit in space' },
                            { number: '02', label: 'Activate', detail: 'One-touch cycle start' },
                            { number: '03', label: 'Verify', detail: 'Automated log report' },
                          ];
                          const next = cur.map((s, si) => si === idx ? { ...s, label: raw } : s);
                          onPatch(setPath(a, ['chart_data', `f${i}_iconrow`], next));
                        }}
                        onEditDetail={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_iconrow`]) || [
                            { number: '01', label: 'Deploy', detail: 'Install unit in space' },
                            { number: '02', label: 'Activate', detail: 'One-touch cycle start' },
                            { number: '03', label: 'Verify', detail: 'Automated log report' },
                          ];
                          const next = cur.map((s, si) => si === idx ? { ...s, detail: raw } : s);
                          onPatch(setPath(a, ['chart_data', `f${i}_iconrow`], next));
                        }}
                      />
                    )}
                    {chartKind === 'table' && (
                      <ComparisonTable
                        theme={isNavy ? 'navy' : 'light'}
                        leftHead={(a.chart_data?.[`f${i}_table_lhead`]) || 'Before'}
                        rightHead={(a.chart_data?.[`f${i}_table_rhead`]) || 'With Ventum'}
                        rows={(a.chart_data?.[`f${i}_table_rows`]) || [
                          { label: 'Cycle time',    before: '45 min',  after: '< 4 min' },
                          { label: 'Manual steps',  before: '12',      after: '1' },
                          { label: 'Log reduction', before: '2-log',   after: '6-log' },
                        ]}
                        onEditLabel={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_table_rows`]) || [
                            { label: 'Cycle time',    before: '45 min',  after: '< 4 min' },
                            { label: 'Manual steps',  before: '12',      after: '1' },
                            { label: 'Log reduction', before: '2-log',   after: '6-log' },
                          ];
                          const next = cur.map((r, ri) => ri === idx ? { ...r, label: raw } : r);
                          onPatch(setPath(a, ['chart_data', `f${i}_table_rows`], next));
                        }}
                        onEditBefore={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_table_rows`]) || [
                            { label: 'Cycle time',    before: '45 min',  after: '< 4 min' },
                            { label: 'Manual steps',  before: '12',      after: '1' },
                            { label: 'Log reduction', before: '2-log',   after: '6-log' },
                          ];
                          const next = cur.map((r, ri) => ri === idx ? { ...r, before: raw } : r);
                          onPatch(setPath(a, ['chart_data', `f${i}_table_rows`], next));
                        }}
                        onEditAfter={(idx, raw) => {
                          const cur = (a.chart_data?.[`f${i}_table_rows`]) || [
                            { label: 'Cycle time',    before: '45 min',  after: '< 4 min' },
                            { label: 'Manual steps',  before: '12',      after: '1' },
                            { label: 'Log reduction', before: '2-log',   after: '6-log' },
                          ];
                          const next = cur.map((r, ri) => ri === idx ? { ...r, after: raw } : r);
                          onPatch(setPath(a, ['chart_data', `f${i}_table_rows`], next));
                        }}
                      />
                    )}
                    {chartKind === 'split' && (
                      <BeforeAfterSplit
                        theme={isNavy ? 'navy' : 'light'}
                        left={(a.chart_data?.[`f${i}_split_left`]) || {
                          head: 'Before Ventum',
                          body: 'Manual 12-step protocol, 45 min per turnover, inconsistent documentation.',
                          badge: 'Status quo',
                        }}
                        right={(a.chart_data?.[`f${i}_split_right`]) || {
                          head: 'After Ventum',
                          body: 'One-touch activation, < 4 min per cycle, automated audit log.',
                          badge: '6-log reduction',
                        }}
                        onEditLeft={(field, raw) => {
                          const cur = (a.chart_data?.[`f${i}_split_left`]) || {
                            head: 'Before Ventum',
                            body: 'Manual 12-step protocol, 45 min per turnover, inconsistent documentation.',
                            badge: 'Status quo',
                          };
                          onPatch(setPath(a, ['chart_data', `f${i}_split_left`], { ...cur, [field]: raw }));
                        }}
                        onEditRight={(field, raw) => {
                          const cur = (a.chart_data?.[`f${i}_split_right`]) || {
                            head: 'After Ventum',
                            body: 'One-touch activation, < 4 min per cycle, automated audit log.',
                            badge: '6-log reduction',
                          };
                          onPatch(setPath(a, ['chart_data', `f${i}_split_right`], { ...cur, [field]: raw }));
                        }}
                      />
                    )}
                    <Editable
                      value={f.body}
                      onChange={(v) => onPatch(setPath(a, ['frames', i, 'body'], v))}
                      tag="p"
                      style={{ fontSize: 12.5, marginTop: 12, color: isNavy ? 'rgba(255,255,255,0.75)' : 'var(--ink-60)', lineHeight: 1.45 }}
                    />
                  </div>
                ) : (
                  <Editable
                    value={f.body}
                    onChange={(v) => onPatch(setPath(a, ['frames', i, 'body'], v))}
                    tag="p"
                    style={{ fontSize: 13.5, marginTop: 12, color: isNavy ? 'rgba(255,255,255,0.8)' : 'var(--ink-60)', lineHeight: 1.5 }}
                  />
                )}
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <VentumLogo background={isNavy ? 'navy' : 'white'} alt="Ventum" style={{ height: 50 }} />
              </div>
            </div>
          );
        })}
      </div>
      {a.caption && (
        <div style={{ maxWidth: 560, fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.55 }}>
          <Editable value={a.caption} onChange={(v) => onPatch(setPath(a, ['caption'], v))} tag="p" />
        </div>
      )}
    </div>
  );
}

// ============================================================
// Brochure
// ============================================================
function BrochureRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY?.hero?.(intake);
  return (
    <div style={{ width: 760, minHeight: 587, background: '#fff', display: 'grid', gridTemplateColumns: '1fr 1fr', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)', position: 'relative' }}>
      {/* Subtle fold line down the middle — visual cue for the bi-fold spread */}
      <div data-editor-only="false" style={{ position: 'absolute', top: 0, bottom: 0, left: '50%', width: 1, background: 'linear-gradient(180deg, transparent 0%, rgba(11,31,51,0.08) 8%, rgba(11,31,51,0.08) 92%, transparent 100%)', pointerEvents: 'none', zIndex: 5 }} />

      {/* LEFT PANEL — FRONT COVER (what people see folded) */}
      <div style={{ position: 'relative', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage
          src={hero}
          slot="hero"
          overrides={a.image_overrides || {}}
          adjustments={a.image_adjustments || {}}
          onChange={imgPatcher(a, onPatch)}
          onChangeAdjust={adjPatcher(a, onPatch)}
          alt=""
        />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.45) 0%, rgba(11,31,51,0.15) 35%, rgba(11,31,51,0.85) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, padding: '32px 32px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: 'white' }}>
          <div>
            <VentumLogo background="navy" alt="Ventum" style={{ height: 48 }} />
            <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ display: 'block', fontSize: 10, color: 'rgba(255,255,255,0.78)', letterSpacing: '0.16em', textTransform: 'uppercase', marginTop: 18 }} />
          </div>
          <div>
            <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 32, fontWeight: 400, letterSpacing: '-0.025em', lineHeight: 1.04, margin: 0, color: 'white' }} />
            <div data-editor-only="true" style={{ display: 'inline-block', marginTop: 16, padding: '3px 8px', background: 'rgba(255,255,255,0.12)', borderRadius: 2 }}>
              <span className="mono" style={{ fontSize: 9, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.7)' }}>FRONT COVER · EDITOR ONLY</span>
            </div>
          </div>
        </div>
      </div>

      {/* RIGHT PANEL — INSIDE CONTENT (what people see when they open it) */}
      <div style={{ padding: '32px 32px', display: 'flex', flexDirection: 'column', gap: 18, position: 'relative' }}>
        <div data-editor-only="true" style={{ position: 'absolute', top: 12, right: 16, padding: '3px 8px', background: 'var(--ink-05)', borderRadius: 2 }}>
          <span className="mono" style={{ fontSize: 9, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--ink-40)' }}>INSIDE · EDITOR ONLY</span>
        </div>

        <Editable value={a.overview} onChange={set(['overview'])} tag="p" style={{ fontSize: 14, color: 'var(--ink-80)', lineHeight: 1.55, margin: '8px 0 0' }} />

        <div style={{ background: 'var(--ink-05)', padding: 16, borderRadius: 3 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="specs_title" defaultText="Specifications" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 10 }} />
          {(a.specs || []).map((s, i) => (
            <div key={i} style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 12, padding: '5px 0', borderTop: i === 0 ? 'none' : '1px solid var(--ink-10)' }}>
              <Editable value={s.label} onChange={(v) => onPatch(setPath(a, ['specs', i, 'label'], v))} className="mono" style={{ fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
              <Editable value={s.value} onChange={(v) => onPatch(setPath(a, ['specs', i, 'value'], v))} style={{ fontSize: 12.5 }} />
            </div>
          ))}
        </div>

        {a.proof_block && (
          <div style={{ borderLeft: '2px solid var(--teal)', paddingLeft: 12 }}>
            <Editable value={a.proof_block.quote} onChange={(v) => onPatch(setPath(a, ['proof_block','quote'], v))} tag="p" style={{ fontSize: 13, lineHeight: 1.45, margin: 0, fontStyle: 'italic' }} />
            <Editable value={a.proof_block.attribution} onChange={(v) => onPatch(setPath(a, ['proof_block','attribution'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', marginTop: 6, letterSpacing: '0.1em' }} />
          </div>
        )}

        <div style={{ marginTop: 'auto', paddingTop: 14, borderTop: '1px solid var(--ink-10)', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 12 }}>
          <Editable value={a.cta} onChange={set(['cta'])} style={{ display: 'inline-block', background: 'var(--navy)', color: 'white', padding: '10px 14px', fontSize: 12.5, fontWeight: 500 }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="footer_url" defaultText="ventum.bio" style={{ display: 'inline-block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Case study summary
// ============================================================
function CaseStudyRender({ a, onPatch }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  return (
    <div style={{ width: 640, background: '#fff', padding: 32, boxShadow: '0 30px 60px -20px rgba(11,31,51,0.15)', borderRadius: 3 }}>
      <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
      <Editable value={a.headline} onChange={set(['headline'])} tag="h2" style={{ fontSize: 28, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1.1, marginTop: 8 }} />
      <Editable value={a.customer_descriptor} onChange={set(['customer_descriptor'])} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', marginTop: 8, letterSpacing: '0.1em' }} />
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, marginTop: 22 }}>
        <div>
          <SectionLabel a={a} onPatch={onPatch} labelKey="situation_title" defaultText="Situation" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }} />
          <Editable value={a.situation} onChange={set(['situation'])} tag="p" style={{ fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.5 }} />
        </div>
        <div>
          <SectionLabel a={a} onPatch={onPatch} labelKey="ventum_role_title" defaultText="Ventum's role" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }} />
          <Editable value={a.ventum_role} onChange={set(['ventum_role'])} tag="p" style={{ fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.5 }} />
        </div>
      </div>
      <div style={{ marginTop: 22, padding: 18, background: 'var(--navy)', color: 'white', display: 'grid', gridTemplateColumns: '1fr 1.1fr', gap: 18, alignItems: 'center' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 14 }}>
          <Editable value={a.outcome_stat?.value} onChange={(v) => onPatch(setPath(a, ['outcome_stat','value'], v))} style={{ fontSize: 42, fontWeight: 400, letterSpacing: '-0.035em' }} />
          <Editable value={a.outcome_stat?.unit} onChange={(v) => onPatch(setPath(a, ['outcome_stat','unit'], v))} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
        </div>
        <DecayCurve
          theme="navy"
          fromLabel={(a.chart_data?.decay_from) ?? 'Baseline'}
          toLabel={(a.chart_data?.decay_to) ?? 'Post-cycle'}
          durationLabel={(a.chart_data?.decay_duration) ?? 'protocol'}
          width={260} height={84}
          onEditFromLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_from'], v))}
          onEditToLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_to'], v))}
          onEditDurationLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_duration'], v))}
        />
      </div>
      <div style={{ marginTop: 16 }}>
        <CoverageMatrix
          items={['Air column', 'High-touch surfaces', 'Soft furnishings', 'Hidden recesses']}
          title="What the cycle covered"
        />
      </div>
      <div style={{ marginTop: 18, borderLeft: '2px solid var(--teal)', paddingLeft: 12 }}>
        <Editable value={a.quote?.text} onChange={(v) => onPatch(setPath(a, ['quote','text'], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.5 }} />
        <Editable value={a.quote?.attribution} onChange={(v) => onPatch(setPath(a, ['quote','attribution'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', marginTop: 6, letterSpacing: '0.1em' }} />
      </div>
      <div style={{ marginTop: 22, paddingTop: 16, borderTop: '1px solid var(--ink-10)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <Editable value={a.cta} onChange={set(['cta'])} style={{ display: 'inline-block', background: 'var(--navy)', color: 'white', padding: '10px 14px', fontSize: 12.5, fontWeight: 500 }} />
        <VentumLogo background="white" alt="Ventum" style={{ height: 64 }} />
      </div>
    </div>
  );
}

// ============================================================
// Account brief
// Identity-led leave-behind for warm accounts: customer logo +
// today → with-Ventum panel + pilot scope + proof + next step.
// ============================================================
function AccountBriefRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const customerName = intake.account_name || a.prepared_for || 'Customer Name';
  const logoUrl = intake.account_logo_url;
  const fallbackLogo = logoUrl ? null : (intake.account_domain ? window.VENTUM_LOGO?.favicon(intake.account_domain) : null);
  const today = a.today_lines || [];
  const withV = a.with_ventum_lines || [];
  const rows = Math.max(today.length, withV.length, 3);

  return (
    <div style={{
      width: 920, aspectRatio: '11/8.5', background: '#fff',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.2)',
      padding: 40, display: 'grid',
      gridTemplateRows: 'auto auto 1fr auto auto',
      gap: 22
    }}>
      {/* IDENTITY HEADER */}
      <div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 20, alignItems: 'center', paddingBottom: 18, borderBottom: '2px solid var(--navy)' }}>
        <div style={{
          width: 88, height: 88,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          overflow: 'hidden'
        }}>
          {(logoUrl || fallbackLogo) ? (
            <img
              src={logoUrl || fallbackLogo}
              alt={customerName + ' logo'}
              onError={(e) => { if (fallbackLogo && e.target.src !== fallbackLogo) e.target.src = fallbackLogo; else e.target.style.display = 'none'; }}
              style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
            />
          ) : (
            <div className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', textAlign: 'center', lineHeight: 1.3 }}>
              Customer<br />logo
            </div>
          )}
        </div>
        <div>
          <SectionLabel a={a} onPatch={onPatch} labelKey="prepared_for" defaultText="Prepared for" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          <div style={{ fontSize: 24, fontWeight: 500, letterSpacing: '-0.015em', marginTop: 4 }}>{customerName}</div>
          <Editable value={a.customer_descriptor} onChange={set(['customer_descriptor'])} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--ink-60)', marginTop: 4, letterSpacing: '0.06em' }} />
        </div>
        <div style={{ textAlign: 'right' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="prepared_by" defaultText="Prepared by" style={{ display: 'block', fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          <VentumLogo background="white" alt="Ventum Biotech" style={{ height: 56, marginTop: 6 }} />
        </div>
      </div>

      {/* INTRO */}
      <Editable
        value={a.intro_line}
        onChange={set(['intro_line'])}
        tag="p"
        style={{ fontSize: 19, lineHeight: 1.35, letterSpacing: '-0.01em', color: 'var(--ink-100)', maxWidth: 720 }}
      />

      {/* TODAY → WITH VENTUM PANEL */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 24px 1fr', gap: 20, alignItems: 'stretch' }}>
        {/* Today column */}
        <div style={{ background: 'var(--ink-05)', padding: '18px 20px', borderRadius: 2 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="today_title" defaultText="— Today" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 14 }} />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {Array.from({ length: rows }).map((_, i) => {
              const item = today[i] || { label: '', detail: '' };
              return (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: 10, alignItems: 'baseline' }}>
                  <span className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.14em' }}>{String(i+1).padStart(2,'0')}</span>
                  <div>
                    <Editable value={item.label} onChange={(v) => onPatch(setPath(a, ['today_lines', i, 'label'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-100)', letterSpacing: '0.12em', textTransform: 'uppercase', fontWeight: 500 }} />
                    <Editable value={item.detail} onChange={(v) => onPatch(setPath(a, ['today_lines', i, 'detail'], v))} tag="p" style={{ fontSize: 12.5, color: 'var(--ink-80)', marginTop: 2, lineHeight: 1.4 }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
        {/* Arrow */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--teal)' }}>
          <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" strokeWidth="1.4">
            <path d="M4 12h16M14 6l6 6-6 6" />
          </svg>
        </div>
        {/* With Ventum column */}
        <div style={{ background: 'var(--navy)', color: 'white', padding: '18px 20px', borderRadius: 2 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="with_ventum_title" defaultText="With Ventum" style={{ display: 'block', fontSize: 10, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 14 }} />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {Array.from({ length: rows }).map((_, i) => {
              const item = withV[i] || { label: '', detail: '' };
              return (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: 10, alignItems: 'baseline' }}>
                  <span className="mono" style={{ fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em' }}>{String(i+1).padStart(2,'0')}</span>
                  <div>
                    <Editable value={item.label} onChange={(v) => onPatch(setPath(a, ['with_ventum_lines', i, 'label'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'white', letterSpacing: '0.12em', textTransform: 'uppercase', fontWeight: 500 }} />
                    <Editable value={item.detail} onChange={(v) => onPatch(setPath(a, ['with_ventum_lines', i, 'detail'], v))} tag="p" style={{ fontSize: 12.5, color: 'rgba(255,255,255,0.85)', marginTop: 2, lineHeight: 1.4 }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      {/* PILOT SCOPE */}
      <div>
        <SectionLabel a={a} onPatch={onPatch} labelKey="pilot_scope_title" defaultText="Suggested pilot scope" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10 }} />
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, position: 'relative' }}>
          {(a.pilot_scope || []).slice(0,3).map((stage, i) => (
            <div key={i} style={{ border: '1px solid var(--ink-10)', padding: '14px 16px', position: 'relative' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                <span className="mono" style={{ fontSize: 9, color: 'var(--teal)', letterSpacing: '0.16em' }}>0{i+1}</span>
                <Editable value={stage.duration} onChange={(v) => onPatch(setPath(a, ['pilot_scope', i, 'duration'], v))} className="mono" style={{ fontSize: 9, color: 'var(--ink-40)', letterSpacing: '0.1em', textTransform: 'uppercase' }} />
              </div>
              <Editable value={stage.stage} onChange={(v) => onPatch(setPath(a, ['pilot_scope', i, 'stage'], v))} style={{ display: 'block', fontSize: 16, fontWeight: 500, letterSpacing: '-0.01em', marginTop: 4 }} />
              <Editable value={stage.scope} onChange={(v) => onPatch(setPath(a, ['pilot_scope', i, 'scope'], v))} tag="p" style={{ fontSize: 12, color: 'var(--ink-60)', marginTop: 6, lineHeight: 1.45 }} />
            </div>
          ))}
        </div>
      </div>

      {/* PROOF + NEXT STEP FOOTER */}
      <div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr 1fr', gap: 22, alignItems: 'center', paddingTop: 14, borderTop: '1px solid var(--ink-10)' }}>
        <DonutStat
          value={Number(String(a.proof_stat?.value || '').replace(/[^0-9.]/g, '')) || 96}
          suffix={a.proof_stat?.unit?.match(/%|min|hr/i)?.[0] || '%'}
          label={a.proof_stat?.unit || 'measured lift'}
          size={104}
          onEditValue={(num) => {
            const next = JSON.parse(JSON.stringify(a));
            next.proof_stat = next.proof_stat || {};
            next.proof_stat.value = String(num);
            onPatch(next);
          }}
        />
        <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
            <Editable value={a.proof_stat?.value} onChange={(v) => onPatch(setPath(a, ['proof_stat','value'], v))} style={{ fontSize: 30, fontWeight: 400, letterSpacing: '-0.035em', color: 'var(--navy)' }} />
            <Editable value={a.proof_stat?.unit} onChange={(v) => onPatch(setPath(a, ['proof_stat','unit'], v))} className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          </div>
          <Editable value={a.proof_stat?.supporting} onChange={(v) => onPatch(setPath(a, ['proof_stat','supporting'], v))} style={{ display: 'block', fontSize: 11.5, color: 'var(--ink-60)', lineHeight: 1.4 }} />
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', alignItems: 'flex-end', height: '100%' }}>
          <Editable value={a.next_step} onChange={set(['next_step'])} style={{ fontSize: 13, color: 'var(--ink-80)', textAlign: 'right', maxWidth: 280 }} />
          <Editable value={a.cta} onChange={set(['cta'])} style={{ display: 'inline-block', background: 'var(--navy)', color: 'white', padding: '10px 14px', fontSize: 12.5, fontWeight: 500, marginTop: 8 }} />
        </div>
      </div>
    </div>
  );
}

// ============================================================
// INFO PACK — multi-section response pack that flexes its length to
// whatever content the agent populated. Sections render in fixed
// order; null sections drop out entirely so empty subjects don't
// produce blank pages. PDF export slices vertically across pages.
// ============================================================
function InfoPackRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const customerName = (a.cover && a.cover.prepared_for) || intake.account_name || 'Customer Name';
  const logoUrl = intake.account_logo_url;
  const fallbackLogo = logoUrl ? null : (intake.account_domain ? window.VENTUM_LOGO?.favicon(intake.account_domain) : null);

  const W = 880; // matches PDF host width
  const sectionBase = { padding: '56px 64px', borderTop: '1px solid var(--ink-10)' };

  // Image slot wiring. Each EditableImage in the pack reads from
  // a.image_overrides[slot] (the operator-uploaded URL) and falls back
  // to a sensible default from VENTUM_IMAGERY based on the account's
  // vertical/product. image_adjustments[slot] carries position/zoom/
  // filter per slot.
  const slideOverrides = a.image_overrides || {};
  const slideAdjustments = a.image_adjustments || {};
  const onSlotImg = (slot, dataUrl) => onPatch({ ...a, image_overrides: { ...slideOverrides, [slot]: dataUrl } });
  const onSlotAdj = (slot, adj) => onPatch({ ...a, image_adjustments: { ...slideAdjustments, [slot]: adj } });
  const imagery = window.VENTUM_IMAGERY;
  const heroPhoto = imagery ? imagery.hero(intake) : '';
  const supportPhoto = imagery ? imagery.support(intake, 0) : '';
  const productPhoto = imagery ? imagery.product(intake) : '';

  // Section heading scaffold — eyebrow tag + h2 title.
  const SectionHead = ({ tag, title, accent = 'var(--teal)' }) => (
    <div style={{ marginBottom: 22 }}>
      <div className="mono" style={{ fontSize: 10, color: accent, letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 8 }}>{tag}</div>
      <h2 style={{ fontSize: 30, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1.15, margin: 0, color: 'var(--ink-100)' }}>{title}</h2>
    </div>
  );

  const cover = a.cover || {};
  const exec = a.exec_summary || {};
  const cta = a.cta || {};

  return (
    <div style={{ width: W, background: '#fff', color: 'var(--ink-100)', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)', overflow: 'hidden' }}>
      {/* COVER */}
      <div style={{ background: '#0B1F33', color: 'white', padding: '72px 64px 56px', position: 'relative', overflow: 'hidden', minHeight: 520 }}>
        {/* Cover hero photo — full bleed, vignette overlay */}
        <EditableImage
          src={heroPhoto}
          slot="cover_hero"
          overrides={slideOverrides}
          adjustments={slideAdjustments}
          onChange={onSlotImg}
          onChangeAdjust={onSlotAdj}
          alt=""
        />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.55) 0%, rgba(11,31,51,0.4) 40%, rgba(11,31,51,0.92) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(ellipse 70% 50% at 90% 0%, rgba(37,99,235,0.30), transparent 55%), radial-gradient(ellipse 70% 60% at 10% 100%, rgba(34,184,167,0.22), transparent 60%)', pointerEvents: 'none' }} />
        <div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 56 }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 44 }} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <Editable
              value={a.cover_prepared_label || 'Prepared for'}
              onChange={set(['cover_prepared_label'])}
              tag="span"
              className="mono"
              style={{ display: 'inline-block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }}
            />
            {(logoUrl || fallbackLogo) ? (
              <div style={{ width: 120, height: 56, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <img
                  src={logoUrl || fallbackLogo}
                  alt={customerName + ' logo'}
                  onError={(e) => { if (fallbackLogo && e.target.src !== fallbackLogo) e.target.src = fallbackLogo; else e.target.style.display = 'none'; }}
                  style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
                />
              </div>
            ) : (
              <span className="mono" style={{ fontSize: 16, color: 'white', fontWeight: 500 }}>{customerName}</span>
            )}
          </div>
        </div>
        <div style={{ position: 'relative' }}>
          <Editable value={cover.eyebrow} onChange={set(['cover','eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
          <Editable value={cover.headline} onChange={set(['cover','headline'])} tag="h1" style={{ fontSize: 56, lineHeight: 1.02, letterSpacing: '-0.02em', fontWeight: 400, color: 'white', marginTop: 16, maxWidth: 680 }} />
          <Editable value={cover.subhead} onChange={set(['cover','subhead'])} tag="p" style={{ fontSize: 18, color: 'rgba(255,255,255,0.78)', marginTop: 18, maxWidth: 580, lineHeight: 1.5 }} />
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 24, marginTop: 48, paddingTop: 24, borderTop: '1px solid rgba(255,255,255,0.15)' }}>
            <div>
              <SectionLabel a={a} onPatch={onPatch} labelKey="cover_account_label" defaultText="Account" style={{ display: 'block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
              <div style={{ fontSize: 16, color: 'white', marginTop: 6 }}>{customerName}</div>
            </div>
            <div>
              <SectionLabel a={a} onPatch={onPatch} labelKey="cover_date_label" defaultText="Date" style={{ display: 'block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
              <Editable value={cover.date_line} onChange={set(['cover','date_line'])} style={{ fontSize: 16, color: 'white', marginTop: 6 }} />
            </div>
          </div>
        </div>
      </div>

      {/* EXECUTIVE SUMMARY */}
      <div style={sectionBase}>
        <SectionHead tag="Executive Summary" title="At a glance" />
        <Editable value={exec.intro} onChange={set(['exec_summary','intro'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680, marginBottom: 28 }} />
        {Array.isArray(exec.points) && exec.points.length > 0 && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '18px 32px' }}>
            {exec.points.map((p, i) => (
              <div key={i} style={{ borderLeft: '2px solid var(--teal)', paddingLeft: 14 }}>
                <Editable value={p.label} onChange={(v) => { const next = exec.points.slice(); next[i] = { ...p, label: v }; onPatch(setPath(a, ['exec_summary','points'], next)); }} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }} />
                <Editable value={p.detail} onChange={(v) => { const next = exec.points.slice(); next[i] = { ...p, detail: v }; onPatch(setPath(a, ['exec_summary','points'], next)); }} style={{ fontSize: 14, lineHeight: 1.45, color: 'var(--ink-100)' }} />
              </div>
            ))}
          </div>
        )}
      </div>

      {/* PROBLEM */}
      {a.problem && (
        <div style={sectionBase}>
          <SectionHead tag="The Problem" title={a.problem.headline || 'The risk'} accent="var(--signal)" />
          <Editable value={a.problem.body} onChange={set(['problem','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680 }} />
          {a.problem.stat && (
            <div style={{ marginTop: 28, paddingTop: 22, borderTop: '1px solid var(--ink-10)', display: 'flex', alignItems: 'baseline', gap: 16 }}>
              <Editable value={a.problem.stat.value} onChange={set(['problem','stat','value'])} style={{ fontSize: 46, fontWeight: 400, letterSpacing: '-0.03em', color: 'var(--signal)' }} />
              <div>
                <Editable value={a.problem.stat.unit} onChange={set(['problem','stat','unit'])} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
                <Editable value={a.problem.stat.supporting} onChange={set(['problem','stat','supporting'])} style={{ fontSize: 13, color: 'var(--ink-80)', marginTop: 4 }} />
              </div>
            </div>
          )}
        </div>
      )}

      {/* SOLUTION */}
      {a.solution && (
        <div style={sectionBase}>
          <SectionHead tag="The Solution" title={a.solution.headline || 'How Ventum works'} />
          {/* Solution hero photo — full-width banner above body */}
          <div style={{ position: 'relative', width: '100%', height: 280, marginBottom: 24, overflow: 'hidden', borderRadius: 2, background: '#0B1F33' }}>
            <EditableImage
              src={productPhoto || heroPhoto}
              slot="solution_hero"
              overrides={slideOverrides}
              adjustments={slideAdjustments}
              onChange={onSlotImg}
              onChangeAdjust={onSlotAdj}
              alt=""
            />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0) 50%, rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
            <div style={{ position: 'absolute', bottom: 14, left: 18, right: 18 }}>
              <Editable
                value={a.solution_image_caption || 'Ventum in field conditions'}
                onChange={set(['solution_image_caption'])}
                className="mono"
                style={{ display: 'block', fontSize: 10, color: 'rgba(255,255,255,0.85)', letterSpacing: '0.16em', textTransform: 'uppercase' }}
              />
            </div>
          </div>
          <Editable value={a.solution.body} onChange={set(['solution','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680, marginBottom: 28 }} />
          {Array.isArray(a.solution.devices) && a.solution.devices.length > 0 && (
            <>
              <SectionLabel a={a} onPatch={onPatch} labelKey="solution_devices_label" defaultText="Devices" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 12 }} />
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 14, marginBottom: 24 }}>
                {a.solution.devices.map((d, i) => (
                  <div key={i} style={{ padding: '14px 16px', background: 'var(--ink-05)', borderRadius: 2, border: '1px solid var(--ink-10)' }}>
                    <Editable value={d.name} onChange={(v) => { const next = a.solution.devices.slice(); next[i] = { ...d, name: v }; onPatch(setPath(a, ['solution','devices'], next)); }} style={{ display: 'block', fontSize: 16, fontWeight: 500, color: 'var(--navy)' }} />
                    <Editable value={d.role} onChange={(v) => { const next = a.solution.devices.slice(); next[i] = { ...d, role: v }; onPatch(setPath(a, ['solution','devices'], next)); }} style={{ display: 'block', fontSize: 12, color: 'var(--ink-80)', marginTop: 4 }} />
                    <Editable value={d.spec} onChange={(v) => { const next = a.solution.devices.slice(); next[i] = { ...d, spec: v }; onPatch(setPath(a, ['solution','devices'], next)); }} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.06em', marginTop: 8 }} />
                  </div>
                ))}
              </div>
            </>
          )}
          {a.solution.formula && (
            <div style={{ padding: '16px 18px', background: '#0B1F33', color: 'white', borderRadius: 2, display: 'grid', gridTemplateColumns: 'auto 1fr 1fr', gap: 20, alignItems: 'center' }}>
              <SectionLabel a={a} onPatch={onPatch} labelKey="solution_formula_label" defaultText="Formula" style={{ display: 'block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
              <div>
                <Editable value={a.solution.formula.name} onChange={set(['solution','formula','name'])} style={{ fontSize: 18, fontWeight: 500, color: 'white' }} />
                <Editable value={a.solution.formula.registration} onChange={set(['solution','formula','registration'])} className="mono" style={{ display: 'block', fontSize: 10.5, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.06em', marginTop: 4 }} />
              </div>
              <Editable value={a.solution.formula.efficacy} onChange={set(['solution','formula','efficacy'])} style={{ fontSize: 13, color: 'rgba(255,255,255,0.85)' }} />
            </div>
          )}
        </div>
      )}

      {/* VALIDATION */}
      {a.validation && (
        <div style={sectionBase}>
          <SectionHead tag="Validation" title={a.validation.headline || 'Proof in field conditions'} />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 28, alignItems: 'start', marginBottom: 22 }}>
            <Editable value={a.validation.body} onChange={set(['validation','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)' }} />
            {/* Efficacy chart — exponential decay curve */}
            <div style={{ background: 'var(--ink-05)', padding: '18px 20px', borderRadius: 2 }}>
              <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10 }}>Efficacy · single cycle</div>
              <DecayCurve
                fromLabel={(a.chart_data?.decay_from) ?? '10⁶ CFU'}
                toLabel={(a.chart_data?.decay_to) ?? '< 1'}
                durationLabel={(a.chart_data?.decay_duration) ?? 'single cycle'}
                width={340} height={140}
                onEditFromLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_from'], v))}
                onEditToLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_to'], v))}
                onEditDurationLabel={(v) => onPatch(setPath(a, ['chart_data', 'decay_duration'], v))}
              />
            </div>
          </div>
          {Array.isArray(a.validation.references) && a.validation.references.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 14 }}>
              {a.validation.references.map((r, i) => (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 16, alignItems: 'baseline', paddingBottom: 12, borderBottom: '1px dashed var(--ink-10)' }}>
                  <Editable value={r.label} onChange={(v) => { const next = a.validation.references.slice(); next[i] = { ...r, label: v }; onPatch(setPath(a, ['validation','references'], next)); }} className="mono" style={{ fontSize: 11, color: 'var(--navy)', letterSpacing: '0.06em', fontWeight: 500 }} />
                  <Editable value={r.detail} onChange={(v) => { const next = a.validation.references.slice(); next[i] = { ...r, detail: v }; onPatch(setPath(a, ['validation','references'], next)); }} style={{ fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.5 }} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* OPS FIT */}
      {a.ops_fit && (
        <div style={sectionBase}>
          <SectionHead tag="Operational Fit" title={a.ops_fit.headline || 'How it integrates'} />
          <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 28, alignItems: 'start', marginBottom: 22 }}>
            <Editable value={a.ops_fit.body} onChange={set(['ops_fit','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)' }} />
            {/* Ops fit photo — operational scene */}
            <div style={{ position: 'relative', height: 200, overflow: 'hidden', borderRadius: 2, background: '#0B1F33' }}>
              <EditableImage
                src={supportPhoto}
                slot="ops_fit_hero"
                overrides={slideOverrides}
                adjustments={slideAdjustments}
                onChange={onSlotImg}
                onChangeAdjust={onSlotAdj}
                alt=""
              />
              <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0) 50%, rgba(11,31,51,0.5))', pointerEvents: 'none' }} />
              <div style={{ position: 'absolute', bottom: 12, left: 14, right: 14 }}>
                <Editable
                  value={a.ops_fit_image_caption || 'Integrates with existing turnover'}
                  onChange={set(['ops_fit_image_caption'])}
                  className="mono"
                  style={{ display: 'block', fontSize: 9, color: 'rgba(255,255,255,0.85)', letterSpacing: '0.16em', textTransform: 'uppercase' }}
                />
              </div>
            </div>
          </div>
          {Array.isArray(a.ops_fit.points) && a.ops_fit.points.length > 0 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              {a.ops_fit.points.map((p, i) => (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: '22px 100px 1fr', gap: 12, alignItems: 'baseline' }}>
                  <span className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.14em' }}>{String(i+1).padStart(2,'0')}</span>
                  <Editable value={p.label} onChange={(v) => { const next = a.ops_fit.points.slice(); next[i] = { ...p, label: v }; onPatch(setPath(a, ['ops_fit','points'], next)); }} className="mono" style={{ fontSize: 11, color: 'var(--navy)', letterSpacing: '0.06em', fontWeight: 500 }} />
                  <Editable value={p.detail} onChange={(v) => { const next = a.ops_fit.points.slice(); next[i] = { ...p, detail: v }; onPatch(setPath(a, ['ops_fit','points'], next)); }} style={{ fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.5 }} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* COMPLIANCE */}
      {a.compliance && (
        <div style={sectionBase}>
          <SectionHead tag="Compliance" title={a.compliance.headline || 'Regulatory posture'} accent="var(--navy)" />
          <Editable value={a.compliance.body} onChange={set(['compliance','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680, marginBottom: 22 }} />
          {Array.isArray(a.compliance.items) && a.compliance.items.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
              {a.compliance.items.map((it, i) => (
                <div key={i} style={{ padding: '14px 16px', background: 'var(--ink-05)', borderLeft: '2px solid var(--navy)' }}>
                  <Editable value={it.label} onChange={(v) => { const next = a.compliance.items.slice(); next[i] = { ...it, label: v }; onPatch(setPath(a, ['compliance','items'], next)); }} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }} />
                  <Editable value={it.detail} onChange={(v) => { const next = a.compliance.items.slice(); next[i] = { ...it, detail: v }; onPatch(setPath(a, ['compliance','items'], next)); }} style={{ fontSize: 13.5, color: 'var(--ink-100)', lineHeight: 1.45 }} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* PRICING */}
      {a.pricing && (
        <div style={sectionBase}>
          <SectionHead tag="Commercial" title={a.pricing.headline || 'Pilot through scale'} />
          <Editable value={a.pricing.body} onChange={set(['pricing','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680, marginBottom: 22 }} />
          {Array.isArray(a.pricing.tiers) && a.pricing.tiers.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(a.pricing.tiers.length, 4)}, 1fr)`, gap: 14 }}>
              {a.pricing.tiers.map((t, i) => (
                <div key={i} style={{ padding: '18px 18px 22px', border: '1px solid var(--ink-20)', borderRadius: 2 }}>
                  <Editable value={t.name} onChange={(v) => { const next = a.pricing.tiers.slice(); next[i] = { ...t, name: v }; onPatch(setPath(a, ['pricing','tiers'], next)); }} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--teal)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 10 }} />
                  <Editable value={t.scope} onChange={(v) => { const next = a.pricing.tiers.slice(); next[i] = { ...t, scope: v }; onPatch(setPath(a, ['pricing','tiers'], next)); }} style={{ display: 'block', fontSize: 15, fontWeight: 500, color: 'var(--ink-100)', marginBottom: 10 }} />
                  <Editable value={t.terms} onChange={(v) => { const next = a.pricing.tiers.slice(); next[i] = { ...t, terms: v }; onPatch(setPath(a, ['pricing','tiers'], next)); }} style={{ display: 'block', fontSize: 12.5, color: 'var(--ink-80)', lineHeight: 1.45 }} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* TEAM */}
      {a.team && (
        <div style={sectionBase}>
          <SectionHead tag="Team" title={a.team.headline || 'Who you work with'} />
          <Editable value={a.team.body} onChange={set(['team','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.6, color: 'var(--ink-80)', maxWidth: 680, marginBottom: 22 }} />
          {Array.isArray(a.team.members) && a.team.members.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(170px, 1fr))', gap: 18 }}>
              {a.team.members.map((m, i) => {
                const initials = (m.name || '').split(/\s+/).map(w => w[0] || '').slice(0, 2).join('').toUpperCase();
                return (
                  <div key={i} style={{ textAlign: 'center' }}>
                    <div style={{ width: 56, height: 56, borderRadius: '50%', background: 'linear-gradient(135deg, var(--teal), #1A4D40)', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 10px', fontSize: 16, fontWeight: 500, letterSpacing: '0.05em', color: 'white' }}>
                      {initials || '·'}
                    </div>
                    <Editable value={m.name} onChange={(v) => { const next = a.team.members.slice(); next[i] = { ...m, name: v }; onPatch(setPath(a, ['team','members'], next)); }} style={{ display: 'block', fontSize: 14, fontWeight: 500, color: 'var(--ink-100)' }} />
                    <Editable value={m.role} onChange={(v) => { const next = a.team.members.slice(); next[i] = { ...m, role: v }; onPatch(setPath(a, ['team','members'], next)); }} className="mono" style={{ display: 'block', fontSize: 9.5, color: 'var(--ink-60)', letterSpacing: '0.14em', textTransform: 'uppercase', marginTop: 4 }} />
                    <Editable value={m.credential} onChange={(v) => { const next = a.team.members.slice(); next[i] = { ...m, credential: v }; onPatch(setPath(a, ['team','members'], next)); }} style={{ display: 'block', fontSize: 11, color: 'var(--ink-80)', marginTop: 6, lineHeight: 1.4 }} />
                  </div>
                );
              })}
            </div>
          )}
        </div>
      )}

      {/* FAQ */}
      {a.faq && Array.isArray(a.faq.items) && a.faq.items.length > 0 && (
        <div style={sectionBase}>
          <SectionHead tag="FAQ" title={a.faq.headline || 'Questions we hear'} />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
            {a.faq.items.map((q, i) => (
              <div key={i} style={{ paddingBottom: 16, borderBottom: i === a.faq.items.length - 1 ? 'none' : '1px solid var(--ink-10)' }}>
                <Editable value={q.question} onChange={(v) => { const next = a.faq.items.slice(); next[i] = { ...q, question: v }; onPatch(setPath(a, ['faq','items'], next)); }} style={{ display: 'block', fontSize: 15, fontWeight: 500, color: 'var(--ink-100)', marginBottom: 8 }} />
                <Editable value={q.answer} onChange={(v) => { const next = a.faq.items.slice(); next[i] = { ...q, answer: v }; onPatch(setPath(a, ['faq','items'], next)); }} style={{ display: 'block', fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.55 }} />
              </div>
            ))}
          </div>
        </div>
      )}

      {/* APPENDIX */}
      {a.appendix && Array.isArray(a.appendix.items) && a.appendix.items.length > 0 && (
        <div style={sectionBase}>
          <SectionHead tag="Appendix" title={a.appendix.headline || 'References & methodology'} accent="var(--ink-60)" />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 10 }}>
            {a.appendix.items.map((it, i) => (
              <div key={i} style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: 16, alignItems: 'baseline' }}>
                <Editable value={it.label} onChange={(v) => { const next = a.appendix.items.slice(); next[i] = { ...it, label: v }; onPatch(setPath(a, ['appendix','items'], next)); }} className="mono" style={{ fontSize: 10.5, color: 'var(--ink-60)', letterSpacing: '0.08em' }} />
                <Editable value={it.detail} onChange={(v) => { const next = a.appendix.items.slice(); next[i] = { ...it, detail: v }; onPatch(setPath(a, ['appendix','items'], next)); }} style={{ fontSize: 12.5, color: 'var(--ink-80)', lineHeight: 1.5 }} />
              </div>
            ))}
          </div>
        </div>
      )}

      {/* CTA */}
      <div style={{ padding: '56px 64px', background: '#0B1F33', color: 'white', position: 'relative', overflow: 'hidden' }}>
        <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(ellipse 70% 50% at 10% 100%, rgba(34,184,167,0.22), transparent 60%)', pointerEvents: 'none' }} />
        <div style={{ position: 'relative' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="cta_eyebrow" defaultText="Next step" tag="div" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 10 }} />
          <Editable value={cta.headline} onChange={set(['cta','headline'])} tag="h2" style={{ fontSize: 36, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1.1, color: 'white', maxWidth: 600 }} />
          <Editable value={cta.body} onChange={set(['cta','body'])} tag="p" style={{ fontSize: 15, color: 'rgba(255,255,255,0.78)', marginTop: 14, maxWidth: 520, lineHeight: 1.55 }} />
          <div style={{ marginTop: 24, display: 'flex', alignItems: 'center', gap: 24 }}>
            <Editable value={cta.primary} onChange={set(['cta','primary'])} style={{ display: 'inline-block', background: 'white', color: 'var(--navy)', padding: '12px 18px', fontSize: 13.5, fontWeight: 500, borderRadius: 2 }} />
            <Editable value={cta.contact} onChange={set(['cta','contact'])} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.7)', letterSpacing: '0.06em' }} />
          </div>
          <div style={{ marginTop: 36, paddingTop: 18, borderTop: '1px solid rgba(255,255,255,0.15)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <VentumLogo background="navy" alt="Ventum" style={{ height: 32, opacity: 0.85 }} />
            <span className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.45)', letterSpacing: '0.18em' }}>VENTUM.BIO</span>
          </div>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Layouts registry — declares alternate layouts per format so
// the stage UI can render a layout switcher.
// ============================================================
window.VENTUM_LAYOUTS = {
  one_pager: [
    { key: 'classic',        name: 'Hero photo' },
    { key: 'splitVertical',  name: 'Split column' },
    { key: 'statLed',        name: 'Stat-led' }
  ],
  linkedin_post: [
    { key: 'standard',   name: 'Text first' },
    { key: 'photoFirst', name: 'Photo first' }
  ]
};

// ============================================================
// LinkedIn campaign — stacked post cards. Each card is editable in
// place; the card row has reorder / copy / delete controls so the
// reviewer can sequence and prune posts without leaving the preview.
// ============================================================
const ROLE_LABEL = {
  lead:     'LEAD · HOOK',
  tension:  'TENSION · PROBLEM',
  solution: 'SOLUTION',
  proof:    'PROOF',
  cta:      'CTA'
};
function postToText(p) {
  const lines = [];
  if (p.hook) lines.push(p.hook);
  if (p.body && p.body.length) { lines.push(''); lines.push(...p.body); }
  if (p.cta_line) { lines.push(''); lines.push(p.cta_line); }
  if (p.hashtags && p.hashtags.length) { lines.push(''); lines.push(p.hashtags.join(' ')); }
  return lines.join('\n');
}
function LinkedInCampaignRender({ a, onPatch, intake = {}, strategy = {}, onRegeneratePost }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const posts = a.posts || [];
  // Pick a different visual from the vertical's supports list for each post so
  // the campaign reads as a mini visual identity, not five copies of the same image.
  const supports = (window.VENTUM_IMAGERY?.supports?.(intake.vertical) || []);
  const heroFallback = window.VENTUM_IMAGERY?.hero?.(intake);
  const postImage = (i) => supports[i % Math.max(1, supports.length)] || heroFallback;
  const [regenStatus, setRegenStatus] = useState({}); // { [postIdx]: 'pending' }
  const movePost = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= posts.length) return;
    const next = posts.slice();
    [next[i], next[j]] = [next[j], next[i]];
    onPatch(setPath(a, ['posts'], next.map((p, k) => ({ ...p, post_num: k + 1 }))));
  };
  const deletePost = (i) => {
    const next = posts.filter((_, k) => k !== i).map((p, k) => ({ ...p, post_num: k + 1 }));
    onPatch(setPath(a, ['posts'], next));
  };
  const copyPost = (p) => {
    navigator.clipboard.writeText(postToText(p));
    window.__toast && window.__toast(`Post ${p.post_num} copied`);
  };
  const copyAll = () => {
    const text = posts.map(p => `=== Post ${p.post_num} · ${ROLE_LABEL[p.role] || p.role || ''} ${p.suggested_post_time ? '· ' + p.suggested_post_time : ''} ===\n\n${postToText(p)}`).join('\n\n');
    navigator.clipboard.writeText(text);
    window.__toast && window.__toast('Campaign copied');
  };

  return (
    <div style={{ width: 620, display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* Campaign header */}
      <div style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, padding: '20px 24px' }}>
        <div className="mono" data-editor-only="true" style={{ fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 8 }}>LINKEDIN CAMPAIGN · {posts.length || 5} POSTS · EDITOR ONLY</div>
        <Editable
          value={a.campaign_title}
          onChange={set(['campaign_title'])}
          tag="h2"
          style={{ fontSize: 22, lineHeight: 1.2, letterSpacing: '-0.01em', margin: '0 0 8px', fontWeight: 500 }}
        />
        <Editable
          value={a.campaign_arc}
          onChange={set(['campaign_arc'])}
          tag="p"
          multiline
          style={{ fontSize: 13.5, color: 'var(--ink-80)', lineHeight: 1.5, margin: '0 0 14px' }}
        />
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
          {(a.recurring_hashtags || []).length > 0 && (
            <Editable
              value={(a.recurring_hashtags || []).join(' ')}
              onChange={(v) => onPatch(setPath(a, ['recurring_hashtags'], v.split(/\s+/).filter(Boolean)))}
              className="mono"
              style={{ fontSize: 11, color: 'var(--signal)', letterSpacing: '0.04em' }}
            />
          )}
          <button
            onClick={copyAll}
            className="mono"
            data-editor-only="true"
            style={{ marginLeft: 'auto', padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}
          >Copy all posts</button>
        </div>
      </div>

      {/* Post cards — styled to look like actual LinkedIn posts */}
      {posts.map((p, i) => {
        const engagement = window.VentumAgents?.runEngagementScore?.(p, 'linkedin_campaign');
        const regenerating = regenStatus[i] === 'pending';
        const handleRegen = async () => {
          if (!onRegeneratePost) {
            window.__toast && window.__toast('Regenerate not available — try refreshing the page');
            return;
          }
          setRegenStatus({ ...regenStatus, [i]: 'pending' });
          try {
            const newPost = await onRegeneratePost('linkedin_campaign', i);
            const nextPosts = posts.slice();
            // preserve performance data + image overrides during regen
            nextPosts[i] = { ...newPost, _performance: p._performance, image_overrides: p.image_overrides, image_adjustments: p.image_adjustments };
            onPatch(setPath(a, ['posts'], nextPosts));
            window.__toast && window.__toast(`Post ${i + 1} regenerated`);
          } catch (e) {
            console.error(e);
            window.__toast && window.__toast('Regenerate failed — try again');
          } finally {
            setRegenStatus(prev => { const next = { ...prev }; delete next[i]; return next; });
          }
        };
        return (
        <div key={i} style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 8, overflow: 'hidden', boxShadow: '0 1px 0 rgba(11,31,51,0.04)', position: 'relative', opacity: regenerating ? 0.55 : 1, transition: 'opacity 0.2s' }}>
          {/* Editor-only meta bar: post number, role label, time, score, actions */}
          <div data-editor-only="true" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 16px', background: '#F4F7FA', borderBottom: '1px solid var(--ink-05)', flexWrap: 'wrap' }}>
            <div style={{ width: 22, height: 22, borderRadius: '50%', background: '#0B1F33', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 500 }}>{p.post_num || (i + 1)}</div>
            <div className="mono" style={{ fontSize: 9.5, letterSpacing: '0.16em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>{ROLE_LABEL[p.role] || (p.role || '').toUpperCase()}</div>
            {p.suggested_post_time && (
              <Editable
                value={p.suggested_post_time}
                onChange={(v) => onPatch(setPath(a, ['posts', i, 'suggested_post_time'], v))}
                className="mono"
                style={{ fontSize: 9.5, letterSpacing: '0.14em', color: 'var(--ink-60)', textTransform: 'uppercase', marginLeft: 8 }}
              />
            )}
            {engagement && <EngagementBadge score={engagement.score} signals={engagement.signals} />}
            <div style={{ marginLeft: 'auto', display: 'flex', gap: 4 }}>
              <button onClick={() => openInComposer('linkedin', postToText(p))} title="Open LinkedIn composer pre-filled" style={{ ...cardBtnStyle(false), width: 'auto', padding: '0 8px', fontSize: 10, letterSpacing: '0.08em', textTransform: 'uppercase', fontFamily: 'var(--mono)' }}>↗ POST</button>
              <button onClick={handleRegen} disabled={regenerating} title="Regenerate this post only" style={cardBtnStyle(regenerating)}>{regenerating ? '…' : '🔄'}</button>
              <button onClick={() => movePost(i, -1)} disabled={i === 0} title="Move up" style={cardBtnStyle(i === 0)}>↑</button>
              <button onClick={() => movePost(i, 1)} disabled={i === posts.length - 1} title="Move down" style={cardBtnStyle(i === posts.length - 1)}>↓</button>
              <button onClick={() => copyPost(p)} title="Copy this post" style={cardBtnStyle(false)}>⧉</button>
              <button onClick={() => deletePost(i)} title="Delete post" style={cardBtnStyle(false)}>×</button>
            </div>
          </div>
          {/* LinkedIn-style author header */}
          <div style={{ padding: '14px 18px 8px', display: 'grid', gridTemplateColumns: '48px 1fr', gap: 10, alignItems: 'center' }}>
            <div style={{ width: 48, height: 48, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
              <VentumLogo markOnly background="navy" alt="" style={{ height: 26 }} />
            </div>
            <div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                <SectionLabel a={a} onPatch={onPatch} labelKey="li_campaign_author_name" defaultText="Ventum Biotech" className="" style={{ display: 'inline-block', fontWeight: 600, fontSize: 14, color: 'var(--ink-100)' }} />
                <span style={{ color: 'var(--ink-40)', fontSize: 12 }}>• Following</span>
              </div>
              <SectionLabel a={a} onPatch={onPatch} labelKey="li_campaign_author_tagline" defaultText="Science-led environmental hygiene · Following" className="" style={{ display: 'block', fontSize: 12, color: 'var(--ink-60)', lineHeight: 1.4 }} />
              <div style={{ fontSize: 11, color: 'var(--ink-40)', display: 'flex', alignItems: 'center', gap: 4 }}>
                <SectionLabel a={a} onPatch={onPatch} labelKey="li_campaign_timestamp" defaultText="1d" className="" style={{ display: 'inline-block', fontSize: 11, color: 'var(--ink-40)' }} /><span>·</span><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/><path d="M12 7v5l4 2"/></svg>
              </div>
            </div>
          </div>
          {/* Post body */}
          <div style={{ padding: '4px 18px 14px' }}>
            <Editable
              value={p.hook}
              onChange={(v) => onPatch(setPath(a, ['posts', i, 'hook'], v))}
              tag="p"
              style={{ fontSize: 14, lineHeight: 1.5, fontWeight: 600, margin: '0 0 10px', color: 'var(--ink-100)' }}
            />
            {(p.body || []).map((para, j) => (
              <Editable
                key={j}
                value={para}
                onChange={(v) => onPatch(setPath(a, ['posts', i, 'body', j], v))}
                tag="p"
                style={{ fontSize: 14, lineHeight: 1.5, margin: '0 0 8px', color: 'var(--ink-100)' }}
              />
            ))}
            <Editable
              value={p.cta_line}
              onChange={(v) => onPatch(setPath(a, ['posts', i, 'cta_line'], v))}
              tag="p"
              style={{ fontSize: 14, lineHeight: 1.5, margin: '8px 0 10px', fontWeight: 500, color: 'var(--ink-100)' }}
            />
            {p.hashtags && (
              <Editable
                value={(p.hashtags || []).join(' ')}
                onChange={(v) => onPatch(setPath(a, ['posts', i, 'hashtags'], v.split(/\s+/).filter(Boolean)))}
                className="mono"
                style={{ display: 'block', fontSize: 13, color: '#0a66c2', letterSpacing: '0', marginTop: 4 }}
              />
            )}
          </div>
          {/* LinkedIn-style native hero image — 1.91:1, no overlay or stylized chrome */}
          <div style={{ position: 'relative', width: '100%', aspectRatio: '1.91/1', background: '#0B1F33', overflow: 'hidden' }}>
            <EditableImage
              src={postImage(i)}
              slot="hero"
              overrides={p.image_overrides || {}}
              adjustments={p.image_adjustments || {}}
              onChange={imgPatcher(p, (nextP) => onPatch(setPath(a, ['posts', i], nextP)))}
              onChangeAdjust={adjPatcher(p, (nextP) => onPatch(setPath(a, ['posts', i], nextP)))}
              alt=""
            />
          </div>
          {/* LinkedIn-style reaction strip (faded — preview-only) */}
          <div data-editor-only="true" style={{ padding: '8px 18px', borderTop: '1px solid var(--ink-05)', display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--ink-40)' }}>
            <div style={{ display: 'flex' }}>
              <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#0a66c2', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, fontWeight: 700, border: '1.5px solid #fff', marginRight: -3 }}>👍</div>
              <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#df704d', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, border: '1.5px solid #fff', marginRight: -3 }}>❤</div>
              <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#6dae4f', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, border: '1.5px solid #fff' }}>💡</div>
            </div>
            <span>Preview · audience varies</span>
          </div>
          {/* Editor-only image direction note */}
          {p.image_direction && (
            <div data-editor-only="true" style={{ padding: '10px 18px', background: '#F8FAFC', borderTop: '1px solid var(--ink-05)' }}>
              <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>VISUAL DIRECTION · EDITOR ONLY</div>
              <Editable
                value={p.image_direction}
                onChange={(v) => onPatch(setPath(a, ['posts', i, 'image_direction'], v))}
                multiline
                style={{ fontSize: 12, color: 'var(--ink-60)', lineHeight: 1.4 }}
              />
            </div>
          )}
          {/* Per-post performance tracking */}
          <div data-editor-only="true">
            <PerformancePanel
              value={p._performance || {}}
              onChange={(perf) => onPatch(setPath(a, ['posts', i, '_performance'], perf))}
            />
          </div>
        </div>
        );
      })}
    </div>
  );
}
function cardBtnStyle(disabled) {
  return {
    width: 24, height: 24,
    background: 'transparent',
    border: '1px solid var(--ink-10)',
    borderRadius: 2,
    fontSize: 12,
    lineHeight: 1,
    color: disabled ? 'var(--ink-20)' : 'var(--ink-60)',
    cursor: disabled ? 'not-allowed' : 'pointer',
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    padding: 0
  };
}

// ============================================================
// Shared helpers for campaign renderers — composer deep-links,
// engagement-score badge, per-post performance panel.
// ============================================================

// Composer deep-links — opens each platform's native composer pre-filled
// so the user can review-then-post in <30 seconds without needing OAuth.
function composerURL(platform, text) {
  const t = (text || '').slice(0, 2900); // LinkedIn share dialog cuts at ~3000c
  if (platform === 'linkedin') {
    return 'https://www.linkedin.com/feed/?shareActive=true&text=' + encodeURIComponent(t);
  }
  if (platform === 'twitter' || platform === 'x') {
    return 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(t.slice(0, 280));
  }
  // Instagram has no web composer URL — fallback is copy-to-clipboard.
  return null;
}
function openInComposer(platform, text) {
  const url = composerURL(platform, text);
  if (url) {
    // Always copy to clipboard too so user can repaste if the redirect mangles formatting
    try { navigator.clipboard.writeText(text); } catch (_) {}
    window.open(url, '_blank', 'noopener');
    window.__toast && window.__toast(`Opening ${platform === 'linkedin' ? 'LinkedIn' : 'X'} composer · text also copied`);
  } else {
    // Instagram path
    navigator.clipboard.writeText(text);
    window.__toast && window.__toast('Caption copied · paste into Instagram on your phone');
  }
}

// Engagement score pill — colored by score band.
function EngagementBadge({ score, signals }) {
  if (typeof score !== 'number') return null;
  const band = score >= 80 ? 'high' : score >= 60 ? 'mid' : 'low';
  const bg = band === 'high' ? '#067647' : band === 'mid' ? '#b54708' : '#b42318';
  const tooltip = (signals || []).map(s => `${s.hit ? '✓' : '✗'} ${s.name} (${s.weight}) — ${s.detail}`).join('\n');
  return (
    <div
      title={tooltip}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 4,
        padding: '2px 8px',
        background: bg, color: '#fff',
        borderRadius: 99,
        fontSize: 10, fontWeight: 600,
        letterSpacing: '0.06em',
        fontFamily: 'var(--mono)'
      }}
    >
      <span>{score}</span>
      <span style={{ opacity: 0.8 }}>/ 100</span>
    </div>
  );
}

// Per-post performance tracking — collapsible form for actual results
// after the team has posted. Saves with the artifact, persists via library.
function PerformancePanel({ value = {}, onChange }) {
  const [open, setOpen] = useState(!!(value.reach || value.likes || value.posted_at));
  const set = (k, v) => onChange({ ...value, [k]: v });
  const numField = (k, label) => (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
      <span className="mono" style={{ fontSize: 9, letterSpacing: '0.12em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>{label}</span>
      <input
        type="number"
        value={value[k] || ''}
        onChange={(e) => set(k, e.target.value ? Number(e.target.value) : '')}
        style={{ width: '100%', padding: '4px 6px', border: '1px solid var(--ink-10)', borderRadius: 2, fontSize: 12, fontFamily: 'var(--mono)' }}
      />
    </label>
  );
  return (
    <div style={{ padding: '10px 18px', background: '#F4F7FA', borderTop: '1px solid var(--ink-05)' }}>
      <button
        onClick={() => setOpen(!open)}
        className="mono"
        style={{ background: 'transparent', border: 'none', cursor: 'pointer', fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-60)', textTransform: 'uppercase', padding: 0, display: 'flex', alignItems: 'center', gap: 6 }}
      >
        <span>{open ? '▾' : '▸'}</span>
        <span>Actual performance {value.reach || value.likes ? '· filled' : '· optional'}</span>
      </button>
      {open && (
        <div style={{ marginTop: 8, display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 8 }}>
          {numField('reach', 'Reach')}
          {numField('likes', 'Likes')}
          {numField('comments', 'Comments')}
          {numField('shares', 'Shares')}
          {numField('clicks', 'Clicks')}
          <label style={{ gridColumn: 'span 5', display: 'flex', flexDirection: 'column', gap: 2 }}>
            <span className="mono" style={{ fontSize: 9, letterSpacing: '0.12em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>Posted at</span>
            <input
              type="text"
              placeholder="e.g. 2026-05-21 09:00 ET"
              value={value.posted_at || ''}
              onChange={(e) => set('posted_at', e.target.value)}
              style={{ width: '100%', padding: '4px 6px', border: '1px solid var(--ink-10)', borderRadius: 2, fontSize: 12, fontFamily: 'var(--mono)' }}
            />
          </label>
          <label style={{ gridColumn: 'span 5', display: 'flex', flexDirection: 'column', gap: 2 }}>
            <span className="mono" style={{ fontSize: 9, letterSpacing: '0.12em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>Notes</span>
            <textarea
              rows={2}
              value={value.notes || ''}
              onChange={(e) => set('notes', e.target.value)}
              style={{ width: '100%', padding: '4px 6px', border: '1px solid var(--ink-10)', borderRadius: 2, fontSize: 12 }}
            />
          </label>
        </div>
      )}
    </div>
  );
}

// ============================================================
// X / Twitter thread renderer — tweet-card stack
// ============================================================
function TwitterThreadRender({ a, onPatch, intake = {} }) {
  const tweets = a.thread_tweets || [];
  const copyTweet = (text) => {
    navigator.clipboard.writeText(text);
    window.__toast && window.__toast('Tweet copied');
  };
  const copyAll = () => {
    const all = [a.hook_tweet || '', ...tweets.map(t => t.body || ''), a.cta_tweet || ''].filter(Boolean).join('\n\n---\n\n');
    navigator.clipboard.writeText(all);
    window.__toast && window.__toast('Thread copied');
  };
  const TweetCard = ({ value, onChange, label, char_limit = 280, num, last }) => {
    const len = (value || '').length;
    const over = len > char_limit;
    return (
      <div style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 16, padding: '14px 16px', display: 'grid', gridTemplateColumns: '44px 1fr', gap: 12 }}>
        <div style={{ width: 44, height: 44, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <VentumLogo markOnly background="navy" alt="" style={{ height: 24 }} />
        </div>
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginBottom: 4 }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="x_author_name" defaultText="Ventum Biotech" className="" style={{ display: 'inline-block', fontWeight: 700, fontSize: 14 }} />
            <SectionLabel a={a} onPatch={onPatch} labelKey="x_author_handle" defaultText="@ventumbiotech · now" className="" style={{ display: 'inline-block', color: 'var(--ink-40)', fontSize: 13 }} />
            <span className="mono" style={{ marginLeft: 'auto', fontSize: 10, letterSpacing: '0.12em', color: 'var(--ink-40)', textTransform: 'uppercase' }} data-editor-only="true">{label}</span>
          </div>
          <Editable
            value={value}
            onChange={onChange}
            tag="p"
            style={{ fontSize: 14.5, lineHeight: 1.45, margin: '0 0 8px', color: 'var(--ink-100)', whiteSpace: 'pre-wrap' }}
          />
          <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 6 }}>
            <span className="mono" style={{ fontSize: 10, color: over ? '#C0392B' : 'var(--ink-40)', letterSpacing: '0.06em' }}>{len} / {char_limit}</span>
            <button onClick={() => copyTweet(value || '')} title="Copy tweet" style={{ marginLeft: 'auto', width: 24, height: 24, border: '1px solid var(--ink-10)', borderRadius: 2, background: 'transparent', cursor: 'pointer', fontSize: 11 }}>⧉</button>
          </div>
        </div>
      </div>
    );
  };
  return (
    <div style={{ width: 600, display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <div className="mono" data-editor-only="true" style={{ fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>X / TWITTER THREAD · {tweets.length + 2} TWEETS · EDITOR ONLY</div>
        <Editable value={a.thread_title} onChange={(v) => onPatch(setPath(a, ['thread_title'], v))} style={{ fontSize: 14, fontWeight: 500 }} />
        <button onClick={copyAll} className="mono" style={{ marginLeft: 'auto', padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}>Copy thread</button>
      </div>
      <TweetCard value={a.hook_tweet} onChange={(v) => onPatch(setPath(a, ['hook_tweet'], v))} label="HOOK" num={1} />
      {tweets.map((t, i) => (
        <TweetCard
          key={i}
          value={t.body}
          onChange={(v) => onPatch(setPath(a, ['thread_tweets', i, 'body'], v))}
          label={`TWEET ${t.tweet_num || i + 2}`}
          num={t.tweet_num || i + 2}
        />
      ))}
      <TweetCard value={a.cta_tweet} onChange={(v) => onPatch(setPath(a, ['cta_tweet'], v))} label="CTA" last />
      {(a.hashtags || []).length > 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, padding: '10px 16px' }}>
          <Editable
            value={(a.hashtags || []).join(' ')}
            onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
            className="mono"
            style={{ fontSize: 12, color: 'var(--signal)', letterSpacing: '0.04em' }}
          />
        </div>
      )}
    </div>
  );
}

// ============================================================
// Instagram caption-set renderer — phone-frame-style cards
// ============================================================
function InstagramCaptionSetRender({ a, onPatch, intake = {} }) {
  const posts = a.posts || [];
  const supports = (window.VENTUM_IMAGERY?.supports?.(intake.vertical) || []);
  const heroFallback = window.VENTUM_IMAGERY?.hero?.(intake);
  const postImage = (i) => supports[i % Math.max(1, supports.length)] || heroFallback;
  const copyPost = (p) => {
    const out = [p.caption_hook, '', ...(p.caption_body || []), '', p.cta_line, '', (p.hashtags || []).join(' ')].filter(Boolean).join('\n');
    navigator.clipboard.writeText(out);
    window.__toast && window.__toast(`Post ${p.post_num || ''} caption copied`);
  };
  const copyAll = () => {
    const all = posts.map((p, i) => `=== Post ${p.post_num || i + 1} · ${p.visual_concept || ''} ===\n\nALT: ${p.alt_text || ''}\n\n${p.caption_hook || ''}\n\n${(p.caption_body || []).join('\n\n')}\n\n${p.cta_line || ''}\n\n${(p.hashtags || []).join(' ')}`).join('\n\n\n');
    navigator.clipboard.writeText(all);
    window.__toast && window.__toast('Caption set copied');
  };
  return (
    <div style={{ width: 720, display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, padding: '18px 22px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <div className="mono" data-editor-only="true" style={{ fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }}>INSTAGRAM CAPTION SET · {posts.length} POSTS · EDITOR ONLY</div>
        <Editable value={a.campaign_title} onChange={(v) => onPatch(setPath(a, ['campaign_title'], v))} style={{ fontSize: 14, fontWeight: 500 }} />
        <button onClick={copyAll} className="mono" style={{ marginLeft: 'auto', padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}>Copy all</button>
      </div>
      {posts.map((p, i) => (
        <div key={i} style={{ background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 6, overflow: 'hidden', display: 'grid', gridTemplateColumns: '280px 1fr' }}>
          {/* IG-style square image */}
          <div style={{ position: 'relative', aspectRatio: '1 / 1', background: '#0B1F33' }}>
            <EditableImage
              src={postImage(i)}
              slot="hero"
              overrides={p.image_overrides || {}}
              adjustments={p.image_adjustments || {}}
              onChange={imgPatcher(p, (nextP) => onPatch(setPath(a, ['posts', i], nextP)))}
              onChangeAdjust={adjPatcher(p, (nextP) => onPatch(setPath(a, ['posts', i], nextP)))}
              alt=""
            />
            <div style={{ position: 'absolute', top: 10, left: 10, padding: '4px 8px', background: 'rgba(0,0,0,0.55)', color: '#fff', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', borderRadius: 2 }}>{p.post_num || i + 1} of {posts.length}</div>
          </div>
          {/* Caption area */}
          <div style={{ padding: '14px 18px', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <div style={{ width: 24, height: 24, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <VentumLogo markOnly background="navy" alt="" style={{ height: 14 }} />
              </div>
              <SectionLabel a={a} onPatch={onPatch} labelKey="ig_handle" defaultText="ventumbiotech" className="" style={{ display: 'inline-block', fontWeight: 600, fontSize: 13 }} />
              <button onClick={() => copyPost(p)} title="Copy caption + hashtags" style={{ marginLeft: 'auto', width: 24, height: 24, border: '1px solid var(--ink-10)', borderRadius: 2, background: 'transparent', cursor: 'pointer', fontSize: 11 }} data-editor-only="true">⧉</button>
            </div>
            <Editable
              value={p.caption_hook}
              onChange={(v) => onPatch(setPath(a, ['posts', i, 'caption_hook'], v))}
              tag="p"
              style={{ fontSize: 14, lineHeight: 1.45, margin: 0, fontWeight: 500 }}
            />
            {(p.caption_body || []).map((para, j) => (
              <Editable
                key={j}
                value={para}
                onChange={(v) => onPatch(setPath(a, ['posts', i, 'caption_body', j], v))}
                tag="p"
                style={{ fontSize: 13.5, lineHeight: 1.55, margin: 0, color: 'var(--ink-100)' }}
              />
            ))}
            <Editable
              value={p.cta_line}
              onChange={(v) => onPatch(setPath(a, ['posts', i, 'cta_line'], v))}
              tag="p"
              style={{ fontSize: 13.5, lineHeight: 1.55, margin: '4px 0 0', fontWeight: 500 }}
            />
            <Editable
              value={(p.hashtags || []).join(' ')}
              onChange={(v) => onPatch(setPath(a, ['posts', i, 'hashtags'], v.split(/\s+/).filter(Boolean)))}
              className="mono"
              style={{ display: 'block', fontSize: 11, color: 'var(--signal)', letterSpacing: '0.04em', marginTop: 4, wordBreak: 'break-word' }}
            />
            {p.visual_concept && (
              <div className="mono" style={{ marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--ink-05)', fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }}>
                VISUAL · {p.visual_concept}
              </div>
            )}
            <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.06em' }}>
              ALT · <Editable value={p.alt_text} onChange={(v) => onPatch(setPath(a, ['posts', i, 'alt_text'], v))} style={{ display: 'inline', fontSize: 9.5, color: 'var(--ink-60)' }} />
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ============================================================
// Twitter / X single-post renderer
// ============================================================
function TwitterPostRender({ a, onPatch, intake = {} }) {
  const setVal = (k) => (v) => onPatch(setPath(a, [k], v));
  const len = (a.body || '').length;
  const over = len > 280;
  const engagement = window.VentumAgents?.runEngagementScore?.(a, 'twitter_post');
  return (
    <div style={{ width: 560, background: '#fff', borderRadius: 16, border: '1px solid var(--ink-10)', padding: '14px 16px', display: 'grid', gridTemplateColumns: '44px 1fr', gap: 12 }}>
      <div style={{ width: 44, height: 44, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <VentumLogo markOnly background="navy" alt="" style={{ height: 24 }} />
      </div>
      <div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginBottom: 4 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="x_author_name" defaultText="Ventum Biotech" className="" style={{ display: 'inline-block', fontWeight: 700, fontSize: 14 }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="x_author_handle" defaultText="@ventumbiotech · now" className="" style={{ display: 'inline-block', color: 'var(--ink-40)', fontSize: 13 }} />
          {engagement && <span style={{ marginLeft: 'auto' }} data-editor-only="true"><EngagementBadge score={engagement.score} signals={engagement.signals} /></span>}
        </div>
        <Editable
          value={a.body}
          onChange={setVal('body')}
          tag="p"
          style={{ fontSize: 15, lineHeight: 1.5, margin: '0 0 8px', color: 'var(--ink-100)', whiteSpace: 'pre-wrap' }}
        />
        {a.hashtags && (
          <Editable
            value={(a.hashtags || []).join(' ')}
            onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
            className="mono"
            style={{ display: 'block', fontSize: 13, color: '#1d9bf0', marginTop: 2 }}
          />
        )}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginTop: 10, paddingTop: 10, borderTop: '1px solid var(--ink-05)' }}>
          <span className="mono" style={{ fontSize: 10, color: over ? '#C0392B' : 'var(--ink-40)' }}>{len} / 280</span>
          <button onClick={() => openInComposer('twitter', (a.body || '') + (a.hashtags?.length ? '\n' + a.hashtags.join(' ') : ''))} className="mono" style={{ marginLeft: 'auto', padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}>↗ Post on X</button>
        </div>
        {a.image_direction && (
          <div className="mono" style={{ marginTop: 10, paddingTop: 8, borderTop: '1px solid var(--ink-05)', fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }}>
            IMG · <Editable value={a.image_direction} onChange={setVal('image_direction')} style={{ display: 'inline', fontSize: 9.5 }} />
          </div>
        )}
        <div data-editor-only="true" style={{ marginTop: 10, marginLeft: -16, marginRight: -16, marginBottom: -14 }}>
          <PerformancePanel
            value={a._performance || {}}
            onChange={(perf) => onPatch(setPath(a, ['_performance'], perf))}
          />
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Instagram single-post renderer
// ============================================================
function InstagramPostRender({ a, onPatch, intake = {} }) {
  const setVal = (k) => (v) => onPatch(setPath(a, [k], v));
  const hero = window.VENTUM_IMAGERY?.hero?.(intake);
  const engagement = window.VentumAgents?.runEngagementScore?.(a, 'instagram_post');
  return (
    <div style={{ width: 480, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 6, overflow: 'hidden' }}>
      <div style={{ padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ width: 28, height: 28, borderRadius: '50%', background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <VentumLogo markOnly background="navy" alt="" style={{ height: 16 }} />
        </div>
        <SectionLabel a={a} onPatch={onPatch} labelKey="ig_handle" defaultText="ventumbiotech" className="" style={{ display: 'inline-block', fontWeight: 600, fontSize: 13 }} />
        {engagement && <span style={{ marginLeft: 'auto' }} data-editor-only="true"><EngagementBadge score={engagement.score} signals={engagement.signals} /></span>}
      </div>
      <div style={{ position: 'relative', width: '100%', aspectRatio: '1/1', background: '#0B1F33' }}>
        <EditableImage src={hero} slot="hero" overrides={a.image_overrides || {}} adjustments={a.image_adjustments || {}} onChange={imgPatcher(a, onPatch)} onChangeAdjust={adjPatcher(a, onPatch)} alt="" />
      </div>
      <div style={{ padding: '12px 16px' }}>
        <Editable value={a.caption_hook} onChange={setVal('caption_hook')} tag="p" style={{ fontSize: 14, lineHeight: 1.45, margin: '0 0 8px', fontWeight: 500 }} />
        {(a.caption_body || []).map((para, j) => (
          <Editable key={j} value={para} onChange={(v) => onPatch(setPath(a, ['caption_body', j], v))} tag="p" style={{ fontSize: 13.5, lineHeight: 1.55, margin: '0 0 8px', color: 'var(--ink-100)' }} />
        ))}
        <Editable value={a.cta_line} onChange={setVal('cta_line')} tag="p" style={{ fontSize: 13.5, lineHeight: 1.55, margin: '6px 0 8px', fontWeight: 500 }} />
        <Editable
          value={(a.hashtags || []).join(' ')}
          onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
          className="mono"
          style={{ display: 'block', fontSize: 11, color: 'var(--signal)', letterSpacing: '0.04em', marginTop: 4, wordBreak: 'break-word' }}
        />
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12, paddingTop: 8, borderTop: '1px solid var(--ink-05)' }}>
          <button
            onClick={() => {
              const out = [a.caption_hook, '', ...(a.caption_body || []), '', a.cta_line, '', (a.hashtags || []).join(' ')].filter(Boolean).join('\n');
              openInComposer('instagram', out);
            }}
            className="mono"
            style={{ marginLeft: 'auto', padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}
          >⧉ Copy caption</button>
        </div>
        {a.visual_concept && (
          <div className="mono" style={{ marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--ink-05)', fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }}>
            VISUAL · <Editable value={a.visual_concept} onChange={setVal('visual_concept')} style={{ display: 'inline', fontSize: 9.5 }} />
          </div>
        )}
        <div className="mono" style={{ marginTop: 4, fontSize: 9.5, color: 'var(--ink-40)' }}>
          ALT · <Editable value={a.alt_text} onChange={setVal('alt_text')} style={{ display: 'inline', fontSize: 9.5, color: 'var(--ink-60)' }} />
        </div>
      </div>
      <div data-editor-only="true">
        <PerformancePanel
          value={a._performance || {}}
          onChange={(perf) => onPatch(setPath(a, ['_performance'], perf))}
        />
      </div>
    </div>
  );
}

// ============================================================
// Partner announcement renderers
// ============================================================

// EMAIL — looks like a mail-client message from partner leadership to staff
function PartnerAnnouncementEmailRender({ a, onPatch, intake = {} }) {
  const set = (k) => (v) => onPatch(setPath(a, [k], v));
  // Pick a hero from the partner-industry imagery library (falls back to intake vertical).
  const heroVertical = intake.partner_industry || intake.vertical;
  const heroSrc = (window.VENTUM_IMAGERY?.supports?.(heroVertical) || [])[0] || window.VENTUM_IMAGERY?.hero?.({ ...intake, vertical: heroVertical });
  return (
    <div style={{ width: 640, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, overflow: 'hidden', boxShadow: '0 1px 0 rgba(11,31,51,0.04)' }}>
      <div style={{ padding: '10px 18px', background: '#F4F7FA', borderBottom: '1px solid var(--ink-05)', display: 'flex', alignItems: 'center', gap: 14, fontSize: 11, color: 'var(--ink-60)' }}>
        <div className="mono" style={{ letterSpacing: '0.14em', textTransform: 'uppercase', fontSize: 9.5 }}>From</div>
        <Editable value={a.from_name} onChange={set('from_name')} style={{ fontSize: 12, color: 'var(--ink-100)' }} />
      </div>
      {/* Hero banner — 3:1 keeps it as a header strip, not a dominating block */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '3 / 1', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage
          src={heroSrc}
          slot="email_hero"
          overrides={a.image_overrides || {}}
          adjustments={a.image_adjustments || {}}
          onChange={imgPatcher(a, onPatch)}
          onChangeAdjust={adjPatcher(a, onPatch)}
          alt=""
        />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0) 50%, rgba(11,31,51,0.6))', pointerEvents: 'none' }} />
        {(intake.partner_name || a.from_name) && (
          <div style={{ position: 'absolute', bottom: 10, left: 18, right: 18, color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="email_banner_partner" defaultText={intake.partner_name || 'Partner Organization'} style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.85)' }} />
            <VentumLogo background="navy" alt="" style={{ height: 22, opacity: 0.85 }} />
          </div>
        )}
      </div>
      <div style={{ padding: '14px 22px 4px' }}>
        <div className="mono" style={{ fontSize: 9, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 4 }}>Subject</div>
        <Editable value={a.subject} onChange={set('subject')} tag="h3" style={{ fontSize: 17, fontWeight: 500, margin: '0 0 6px', color: 'var(--ink-100)' }} />
        <Editable value={a.preheader} onChange={set('preheader')} style={{ display: 'block', fontSize: 12, color: 'var(--ink-60)', marginBottom: 14 }} />
      </div>
      <div style={{ padding: '4px 22px 22px' }}>
        <Editable value={a.salutation} onChange={set('salutation')} tag="p" style={{ fontSize: 14, color: 'var(--ink-100)', margin: '0 0 14px' }} />
        {(a.body || []).map((para, i) => (
          <Editable key={i} value={para} onChange={(v) => onPatch(setPath(a, ['body', i], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.6, margin: '0 0 12px', color: 'var(--ink-100)' }} />
        ))}
        <Editable value={a.signoff} onChange={set('signoff')} tag="p" style={{ fontSize: 14, margin: '14px 0 4px', color: 'var(--ink-100)' }} />
        <Editable value={a.signature} onChange={set('signature')} multiline style={{ display: 'block', fontSize: 13, lineHeight: 1.5, color: 'var(--ink-80)', whiteSpace: 'pre-line' }} />
      </div>
      {a.hero_image_direction && (
        <div data-editor-only="true" style={{ padding: '10px 22px', background: '#F8FAFC', borderTop: '1px solid var(--ink-05)' }}>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>Banner direction · Editor only</div>
          <Editable value={a.hero_image_direction} onChange={set('hero_image_direction')} multiline style={{ fontSize: 12, color: 'var(--ink-60)', lineHeight: 1.4 }} />
        </div>
      )}
    </div>
  );
}

// SLACK — looks like a Slack channel post (with attachment image)
function PartnerAnnouncementSlackRender({ a, onPatch, intake = {} }) {
  const set = (k) => (v) => onPatch(setPath(a, [k], v));
  const heroVertical = intake.partner_industry || intake.vertical;
  const attachmentSrc = (window.VENTUM_IMAGERY?.supports?.(heroVertical) || [])[0] || window.VENTUM_IMAGERY?.hero?.({ ...intake, vertical: heroVertical });
  const copyForSlack = () => {
    const body = (a.emoji_lead ? a.emoji_lead + ' ' : '') + (a.body || '');
    const all = a.cta ? body + '\n\n' + a.cta : body;
    navigator.clipboard.writeText(all);
    window.__toast && window.__toast('Slack post copied');
  };
  return (
    <div style={{ width: 560, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 6, padding: '16px 18px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
        <Editable value={a.channel_hint} onChange={set('channel_hint')} className="mono" style={{ fontSize: 12, color: '#1264a3', fontWeight: 600 }} />
        <span className="mono" style={{ fontSize: 10, color: 'var(--ink-40)' }}>· now</span>
        <button onClick={copyForSlack} className="mono" style={{ marginLeft: 'auto', padding: '4px 10px', background: 'transparent', color: 'var(--navy)', border: '1px solid var(--ink-20)', borderRadius: 2, fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase', cursor: 'pointer' }}>⧉ Copy</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '36px 1fr', gap: 10 }}>
        <div style={{ width: 36, height: 36, borderRadius: 4, background: '#0B1F33', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <VentumLogo markOnly background="navy" alt="" style={{ height: 20 }} />
        </div>
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginBottom: 4 }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="slack_bot_name" defaultText="Operations" className="" style={{ display: 'inline-block', fontWeight: 700, fontSize: 14, color: 'var(--ink-100)' }} />
            <SectionLabel a={a} onPatch={onPatch} labelKey="slack_bot_meta" defaultText="BOT · 9:00 AM" style={{ display: 'inline-block', fontSize: 10, color: 'var(--ink-40)' }} />
          </div>
          <div style={{ display: 'flex', gap: 6, alignItems: 'baseline', marginBottom: 10 }}>
            <Editable value={a.emoji_lead} onChange={set('emoji_lead')} style={{ fontSize: 18 }} />
            <Editable value={a.body} onChange={set('body')} multiline style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--ink-100)', whiteSpace: 'pre-wrap', flex: 1 }} />
          </div>
          {/* Slack-style image attachment */}
          <div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 10, borderLeft: '3px solid var(--ink-10)', paddingLeft: 10, marginBottom: 8 }}>
            <div style={{ position: 'relative', width: 180, aspectRatio: '1 / 1', background: '#0B1F33', borderRadius: 4, overflow: 'hidden' }}>
              <EditableImage
                src={attachmentSrc}
                slot="slack_attachment"
                overrides={a.image_overrides || {}}
                adjustments={a.image_adjustments || {}}
                onChange={imgPatcher(a, onPatch)}
                onChangeAdjust={adjPatcher(a, onPatch)}
                alt=""
              />
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 4 }}>
              <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase' }}>Attachment</div>
              {a.attachment_image_direction ? (
                <Editable value={a.attachment_image_direction} onChange={set('attachment_image_direction')} multiline style={{ fontSize: 12, color: 'var(--ink-80)', lineHeight: 1.4 }} />
              ) : (
                <span style={{ fontSize: 12, color: 'var(--ink-60)' }}>Partner-industry environment</span>
              )}
            </div>
          </div>
          {a.cta && (
            <Editable value={a.cta} onChange={set('cta')} style={{ display: 'block', fontSize: 13.5, color: '#1264a3', marginTop: 4 }} />
          )}
          {a.thread_starter && (
            <div style={{ marginTop: 10, paddingLeft: 12, borderLeft: '2px solid var(--ink-10)' }}>
              <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>Thread reply 1</div>
              <Editable value={a.thread_starter} onChange={set('thread_starter')} multiline style={{ fontSize: 13, color: 'var(--ink-80)', lineHeight: 1.5, whiteSpace: 'pre-wrap' }} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// PRESS RELEASE — formal press-release layout
function PartnerAnnouncementPressRender({ a, onPatch, intake = {} }) {
  const set = (k) => (v) => onPatch(setPath(a, [k], v));
  const heroVertical = intake.partner_industry || intake.vertical;
  const leadSrc = (window.VENTUM_IMAGERY?.supports?.(heroVertical) || [])[0] || window.VENTUM_IMAGERY?.hero?.({ ...intake, vertical: heroVertical });
  return (
    <div style={{ width: 700, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, padding: '28px 36px', fontFamily: 'Georgia, "Times New Roman", serif' }}>
      <SectionLabel a={a} onPatch={onPatch} labelKey="for_immediate_release" defaultText="For immediate release" style={{ display: 'block', fontSize: 10, letterSpacing: '0.16em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 14, fontFamily: 'var(--mono)' }} />
      <Editable value={a.headline} onChange={set('headline')} tag="h1" style={{ fontSize: 24, lineHeight: 1.2, letterSpacing: '-0.01em', margin: '0 0 16px', fontWeight: 600, color: 'var(--ink-100)' }} />
      {/* Lead photo — 3:1 banner shape so it doesn't dwarf the press body */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '3 / 1', background: '#0B1F33', overflow: 'hidden', marginBottom: 14, borderRadius: 2 }}>
        <EditableImage
          src={leadSrc}
          slot="press_lead"
          overrides={a.image_overrides || {}}
          adjustments={a.image_adjustments || {}}
          onChange={imgPatcher(a, onPatch)}
          onChangeAdjust={adjPatcher(a, onPatch)}
          alt=""
        />
      </div>
      {a.lead_image_direction && (
        <div className="mono" style={{ fontSize: 10, color: 'var(--ink-40)', letterSpacing: '0.06em', textAlign: 'center', marginBottom: 14, fontFamily: 'var(--mono)' }}>
          <Editable value={a.lead_image_direction} onChange={set('lead_image_direction')} style={{ display: 'inline', fontSize: 10, fontStyle: 'italic', color: 'var(--ink-60)' }} />
        </div>
      )}
      <Editable value={a.dateline} onChange={set('dateline')} style={{ display: 'block', fontSize: 13, fontWeight: 500, color: 'var(--ink-80)', marginBottom: 14 }} />
      <Editable value={a.lead} onChange={set('lead')} tag="p" style={{ fontSize: 15.5, lineHeight: 1.55, margin: '0 0 14px', color: 'var(--ink-100)', fontWeight: 500 }} />
      {(a.body || []).map((para, i) => (
        <Editable key={i} value={para} onChange={(v) => onPatch(setPath(a, ['body', i], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.65, margin: '0 0 12px', color: 'var(--ink-100)' }} />
      ))}
      {a.partner_quote?.text && (
        <div style={{ borderLeft: '3px solid var(--ink-20)', paddingLeft: 14, margin: '18px 0', fontStyle: 'italic' }}>
          <Editable value={a.partner_quote.text} onChange={(v) => onPatch(setPath(a, ['partner_quote', 'text'], v))} tag="p" style={{ fontSize: 14.5, lineHeight: 1.55, margin: '0 0 6px', color: 'var(--ink-100)' }} />
          <Editable value={a.partner_quote.attribution} onChange={(v) => onPatch(setPath(a, ['partner_quote', 'attribution'], v))} style={{ display: 'block', fontSize: 12, color: 'var(--ink-60)', fontStyle: 'normal' }} />
        </div>
      )}
      {a.ventum_quote?.text && (
        <div style={{ borderLeft: '3px solid var(--ink-20)', paddingLeft: 14, margin: '18px 0', fontStyle: 'italic' }}>
          <Editable value={a.ventum_quote.text} onChange={(v) => onPatch(setPath(a, ['ventum_quote', 'text'], v))} tag="p" style={{ fontSize: 14.5, lineHeight: 1.55, margin: '0 0 6px', color: 'var(--ink-100)' }} />
          <Editable value={a.ventum_quote.attribution} onChange={(v) => onPatch(setPath(a, ['ventum_quote', 'attribution'], v))} style={{ display: 'block', fontSize: 12, color: 'var(--ink-60)', fontStyle: 'normal' }} />
        </div>
      )}
      <hr style={{ border: 'none', borderTop: '1px solid var(--ink-10)', margin: '22px 0 14px' }} />
      {a.partner_boilerplate && (
        <div style={{ marginBottom: 12 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="about_partner" defaultText="About the partner" style={{ display: 'block', fontSize: 9, letterSpacing: '0.16em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 4, fontFamily: 'var(--mono)' }} />
          <Editable value={a.partner_boilerplate} onChange={set('partner_boilerplate')} multiline style={{ display: 'block', fontSize: 12.5, lineHeight: 1.55, color: 'var(--ink-80)' }} />
        </div>
      )}
      {a.ventum_boilerplate && (
        <div style={{ marginBottom: 12 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="about_ventum" defaultText="About Ventum Biotech" style={{ display: 'block', fontSize: 9, letterSpacing: '0.16em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 4, fontFamily: 'var(--mono)' }} />
          <Editable value={a.ventum_boilerplate} onChange={set('ventum_boilerplate')} multiline style={{ display: 'block', fontSize: 12.5, lineHeight: 1.55, color: 'var(--ink-80)' }} />
        </div>
      )}
      {a.media_contacts && (
        <div style={{ marginTop: 8 }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="media_contacts" defaultText="Media contacts" style={{ display: 'block', fontSize: 9, letterSpacing: '0.16em', color: 'var(--ink-40)', textTransform: 'uppercase', marginBottom: 4, fontFamily: 'var(--mono)' }} />
          <Editable value={a.media_contacts.partner} onChange={(v) => onPatch(setPath(a, ['media_contacts', 'partner'], v))} multiline style={{ display: 'block', fontSize: 12, lineHeight: 1.5, color: 'var(--ink-80)' }} />
          <Editable value={a.media_contacts.ventum} onChange={(v) => onPatch(setPath(a, ['media_contacts', 'ventum'], v))} multiline style={{ display: 'block', fontSize: 12, lineHeight: 1.5, color: 'var(--ink-80)' }} />
        </div>
      )}
    </div>
  );
}

// LINKEDIN (partner POV) — reuses LinkedIn-true styling but the speaker is the partner
function PartnerAnnouncementLinkedInRender({ a, onPatch, intake = {} }) {
  const set = (k) => (v) => onPatch(setPath(a, [k], v));
  const partnerName = intake.partner_name || 'Partner Organization';
  const heroVertical = intake.partner_industry || intake.vertical;
  const heroSrc = (window.VENTUM_IMAGERY?.supports?.(heroVertical) || [])[0] || window.VENTUM_IMAGERY?.hero?.({ ...intake, vertical: heroVertical });
  const copyAll = () => {
    const out = [a.hook, '', ...(a.body || []), '', a.cta_line, '', (a.hashtags || []).join(' ')].filter(Boolean).join('\n');
    navigator.clipboard.writeText(out);
    window.__toast && window.__toast('Post copied');
  };
  return (
    <div style={{ width: 600, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 8, overflow: 'hidden' }}>
      <div style={{ padding: '14px 18px 8px', display: 'grid', gridTemplateColumns: '48px 1fr auto', gap: 10, alignItems: 'center' }}>
        <div style={{ width: 48, height: 48, borderRadius: '50%', background: 'var(--ink-10)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--mono)', fontSize: 14, color: 'var(--ink-60)' }}>
          {partnerName.slice(0, 2).toUpperCase()}
        </div>
        <div>
          <div style={{ fontWeight: 600, fontSize: 14 }}>{partnerName}</div>
          <div style={{ fontSize: 12, color: 'var(--ink-60)' }}>{intake.partner_industry || 'Partner organization'} · Following</div>
          <div style={{ fontSize: 11, color: 'var(--ink-40)' }}>1d · 🌐</div>
        </div>
        <button onClick={copyAll} className="mono" style={{ padding: '6px 12px', background: '#0B1F33', color: '#fff', border: 'none', borderRadius: 2, fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer' }}>⧉ Copy</button>
      </div>
      <div style={{ padding: '4px 18px 14px' }}>
        <Editable value={a.hook} onChange={set('hook')} tag="p" style={{ fontSize: 14, lineHeight: 1.5, fontWeight: 600, margin: '0 0 10px', color: 'var(--ink-100)' }} />
        {(a.body || []).map((para, i) => (
          <Editable key={i} value={para} onChange={(v) => onPatch(setPath(a, ['body', i], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.5, margin: '0 0 8px', color: 'var(--ink-100)' }} />
        ))}
        <Editable value={a.cta_line} onChange={set('cta_line')} tag="p" style={{ fontSize: 14, lineHeight: 1.5, margin: '8px 0 10px', fontWeight: 500 }} />
        {a.mention_handle && (
          <div className="mono" style={{ fontSize: 10.5, color: 'var(--ink-40)', letterSpacing: '0.06em', marginBottom: 8 }}>
            Tag: <Editable value={a.mention_handle} onChange={set('mention_handle')} style={{ display: 'inline', color: '#0a66c2', fontFamily: 'inherit' }} />
          </div>
        )}
        <Editable
          value={(a.hashtags || []).join(' ')}
          onChange={(v) => onPatch(setPath(a, ['hashtags'], v.split(/\s+/).filter(Boolean)))}
          className="mono"
          style={{ display: 'block', fontSize: 13, color: '#0a66c2', marginTop: 4 }}
        />
      </div>
      {/* LinkedIn-native 1.91:1 hero image below the text */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '1.91 / 1', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage
          src={heroSrc}
          slot="linkedin_hero"
          overrides={a.image_overrides || {}}
          adjustments={a.image_adjustments || {}}
          onChange={imgPatcher(a, onPatch)}
          onChangeAdjust={adjPatcher(a, onPatch)}
          alt=""
        />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0) 60%, rgba(11,31,51,0.55))', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', bottom: 14, left: 18, right: 18, display: 'flex', alignItems: 'end', justifyContent: 'space-between', color: 'white' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="li_lockup_text" defaultText={`${partnerName} × Ventum`} style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.85)' }} />
          <VentumLogo background="navy" alt="" style={{ height: 32, opacity: 0.9 }} />
        </div>
      </div>
      {/* Faded LinkedIn reactions strip below the image */}
      <div data-editor-only="true" style={{ padding: '8px 18px', borderTop: '1px solid var(--ink-05)', display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--ink-40)' }}>
        <div style={{ display: 'flex' }}>
          <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#0a66c2', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, fontWeight: 700, border: '1.5px solid #fff', marginRight: -3 }}>👍</div>
          <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#df704d', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, border: '1.5px solid #fff', marginRight: -3 }}>❤</div>
          <div style={{ width: 16, height: 16, borderRadius: '50%', background: '#6dae4f', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 9, border: '1.5px solid #fff' }}>💡</div>
        </div>
        <span>Preview · audience varies</span>
      </div>
      {a.image_direction && (
        <div data-editor-only="true" style={{ padding: '10px 18px', background: '#F8FAFC', borderTop: '1px solid var(--ink-05)' }}>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>Visual direction · Editor only</div>
          <Editable value={a.image_direction} onChange={set('image_direction')} multiline style={{ fontSize: 12, color: 'var(--ink-60)', lineHeight: 1.4 }} />
        </div>
      )}
    </div>
  );
}

// ALL-HANDS — structured talking-points doc with hero banner
function PartnerAnnouncementAllHandsRender({ a, onPatch, intake = {} }) {
  const set = (k) => (v) => onPatch(setPath(a, [k], v));
  const heroVertical = intake.partner_industry || intake.vertical;
  const heroSrc = (window.VENTUM_IMAGERY?.supports?.(heroVertical) || [])[0] || window.VENTUM_IMAGERY?.hero?.({ ...intake, vertical: heroVertical });
  return (
    <div style={{ width: 720, background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 4, overflow: 'hidden' }}>
      {/* Compact hero banner — 5:1 keeps the header from dominating the doc */}
      <div style={{ position: 'relative', width: '100%', aspectRatio: '5 / 1', background: '#0B1F33', overflow: 'hidden' }}>
        <EditableImage
          src={heroSrc}
          slot="allhands_hero"
          overrides={a.image_overrides || {}}
          adjustments={a.image_adjustments || {}}
          onChange={imgPatcher(a, onPatch)}
          onChangeAdjust={adjPatcher(a, onPatch)}
          alt=""
        />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(135deg, rgba(11,31,51,0.55) 0%, rgba(11,31,51,0.2) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', inset: 0, padding: '16px 28px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: '#fff' }}>
          <SectionLabel a={a} onPatch={onPatch} labelKey="allhands_banner_text" defaultText={`All-hands talking points · ${intake.partner_name || 'Partner'}`} style={{ display: 'inline-block', fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.9)', fontWeight: 500 }} />
          <VentumLogo background="navy" alt="" style={{ height: 24, opacity: 0.9 }} />
        </div>
      </div>
      <div style={{ padding: '28px 36px' }}>
      <Editable value={a.title} onChange={set('title')} tag="h2" style={{ fontSize: 24, lineHeight: 1.2, letterSpacing: '-0.01em', margin: '0 0 12px', fontWeight: 500 }} />
      <Editable value={a.intro_line} onChange={set('intro_line')} tag="p" style={{ fontSize: 15, lineHeight: 1.55, margin: '0 0 24px', color: 'var(--ink-80)', fontWeight: 500 }} />

      {/* WHY WE CHOSE VENTUM — numbered card grid for visual rhythm */}
      <div style={{ marginBottom: 26 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
          <div style={{ width: 3, height: 14, background: 'var(--teal)' }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="why_ventum_title" defaultText="Why we chose Ventum" style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }} />
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 10 }}>
          {(a.why_ventum || []).map((item, i) => (
            <div key={i} style={{ display: 'grid', gridTemplateColumns: '22px 1fr', gap: 10, padding: '10px 12px', background: 'var(--ink-05)', borderRadius: 3, alignItems: 'start' }}>
              <div style={{ width: 22, height: 22, borderRadius: '50%', background: 'var(--teal)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 600, lineHeight: 1, flexShrink: 0 }}>{i + 1}</div>
              <Editable value={item} onChange={(v) => onPatch(setPath(a, ['why_ventum', i], v))} style={{ display: 'block', fontSize: 13, lineHeight: 1.5, color: 'var(--ink-100)' }} />
            </div>
          ))}
        </div>
      </div>

      {/* WHAT CHANGES — colored letter badge per area + detail card */}
      <div style={{ marginBottom: 26 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
          <div style={{ width: 3, height: 14, background: 'var(--navy)' }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="what_changes_title" defaultText="What changes" style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }} />
        </div>
        <div style={{ display: 'grid', gap: 8 }}>
          {(a.what_changes || []).map((c, i) => {
            // Lightweight keyword-based default if the LLM didn't pick an icon
            const guessIcon = (area) => {
              const t = (area || '').toLowerCase();
              if (/order|procure|cart|purchas/.test(t)) return 'cart';
              if (/train|onboard|cert/.test(t)) return 'check';
              if (/audit|compli|inspect|log/.test(t)) return 'doc';
              if (/vendor|roster|approv|list/.test(t)) return 'folder';
              if (/schedul|timeline|calendar|date/.test(t)) return 'cal';
              if (/contact|chat|notif|message/.test(t)) return 'chat';
              if (/ops|protocol|workflow|process|daily/.test(t)) return 'gear';
              if (/team|staff|people|hire/.test(t)) return 'user';
              if (/alert|reminder|notif/.test(t)) return 'bell';
              if (/launch|milestone|goal|target/.test(t)) return 'flag';
              if (/safe|comply|protect/.test(t)) return 'shield';
              return 'arrow';
            };
            const iconName = c.icon || guessIcon(c.area);
            return (
              <div key={i} style={{ display: 'grid', gridTemplateColumns: '36px 140px 1fr', gap: 14, padding: '10px 14px', background: '#fff', border: '1px solid var(--ink-10)', borderRadius: 3, alignItems: 'center' }}>
                <div style={{ width: 32, height: 32, borderRadius: 4, background: 'var(--navy)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  <ChangeIcon name={iconName} size={16} color="#fff" />
                </div>
                <Editable value={c.area} onChange={(v) => onPatch(setPath(a, ['what_changes', i, 'area'], v))} className="mono" style={{ fontSize: 10.5, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--ink-100)', fontWeight: 600 }} />
                <Editable value={c.detail} onChange={(v) => onPatch(setPath(a, ['what_changes', i, 'detail'], v))} style={{ fontSize: 13.5, lineHeight: 1.5, color: 'var(--ink-80)' }} />
              </div>
            );
          })}
        </div>
      </div>

      <div style={{ marginBottom: 26 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14 }}>
          <div style={{ width: 3, height: 14, background: 'var(--signal)' }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="rollout_title" defaultText="Rollout timeline" style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }} />
          <div data-editor-only="true" style={{ marginLeft: 'auto', display: 'flex', gap: 4 }}>
            <button
              onClick={() => {
                const next = [...(a.rollout_timeline || []), { phase: 'Phase ' + ((a.rollout_timeline || []).length + 1), when: '', scope: '', icon: '•', accent: 'teal' }];
                onPatch(setPath(a, ['rollout_timeline'], next));
              }}
              disabled={(a.rollout_timeline || []).length >= 6}
              className="mono"
              style={{ padding: '3px 8px', fontSize: 9, letterSpacing: '0.12em', textTransform: 'uppercase', background: 'transparent', border: '1px solid var(--ink-20)', borderRadius: 2, cursor: 'pointer', color: 'var(--ink-60)' }}
              title="Add a rollout phase (max 6)"
            >+ Phase</button>
            <button
              onClick={() => {
                const cur = a.rollout_timeline || [];
                if (cur.length <= 1) return;
                onPatch(setPath(a, ['rollout_timeline'], cur.slice(0, -1)));
              }}
              disabled={(a.rollout_timeline || []).length <= 1}
              className="mono"
              style={{ padding: '3px 8px', fontSize: 9, letterSpacing: '0.12em', textTransform: 'uppercase', background: 'transparent', border: '1px solid var(--ink-20)', borderRadius: 2, cursor: 'pointer', color: 'var(--ink-60)' }}
              title="Remove the last phase"
            >− Phase</button>
          </div>
        </div>
        {/* Connector line behind the phase cards */}
        <div style={{ position: 'relative', display: 'grid', gridTemplateColumns: `repeat(${Math.max(1, (a.rollout_timeline || []).length)}, 1fr)`, gap: 14 }}>
          {/* Connector line — behind cards, only when 2+ phases */}
          {(a.rollout_timeline || []).length > 1 && (
            <div style={{ position: 'absolute', top: 28, left: '8%', right: '8%', height: 2, background: 'linear-gradient(90deg, var(--teal) 0%, var(--navy) 100%)', opacity: 0.3, zIndex: 0 }} />
          )}
          {(a.rollout_timeline || []).map((p, i) => {
            const accentColor = {
              teal: 'var(--teal)',
              navy: 'var(--navy)',
              signal: 'var(--signal)',
              efficacy: 'var(--efficacy)'
            }[p.accent || 'teal'] || 'var(--teal)';
            return (
              <div key={i} style={{ padding: '14px 16px', background: '#fff', border: `1px solid var(--ink-10)`, borderTop: `3px solid ${accentColor}`, borderRadius: 4, position: 'relative', zIndex: 1, boxShadow: '0 1px 0 rgba(11,31,51,0.02)' }}>
                {/* Phase number + icon header */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                  <div style={{ flex: '0 0 28px', width: 28, height: 28, borderRadius: '50%', background: accentColor, color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 600, lineHeight: 1 }}>
                    <Editable
                      value={p.icon || (i + 1).toString()}
                      onChange={(v) => onPatch(setPath(a, ['rollout_timeline', i, 'icon'], v))}
                      style={{ color: '#fff', minWidth: 8, textAlign: 'center', lineHeight: 1 }}
                    />
                  </div>
                  <Editable
                    value={p.phase}
                    onChange={(v) => onPatch(setPath(a, ['rollout_timeline', i, 'phase'], v))}
                    className="mono"
                    style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: accentColor, fontWeight: 600 }}
                  />
                </div>
                <Editable
                  value={p.when}
                  onChange={(v) => onPatch(setPath(a, ['rollout_timeline', i, 'when'], v))}
                  style={{ display: 'block', fontSize: 14, fontWeight: 600, color: 'var(--ink-100)', marginBottom: 6, letterSpacing: '-0.005em' }}
                />
                <Editable
                  value={p.scope}
                  onChange={(v) => onPatch(setPath(a, ['rollout_timeline', i, 'scope'], v))}
                  style={{ display: 'block', fontSize: 12.5, color: 'var(--ink-80)', lineHeight: 1.45 }}
                />
                {/* Accent picker — editor-only */}
                <div data-editor-only="true" style={{ marginTop: 10, paddingTop: 8, borderTop: '1px dashed var(--ink-05)', display: 'flex', gap: 4 }}>
                  {['teal', 'navy', 'signal', 'efficacy'].map(c => (
                    <button
                      key={c}
                      onClick={() => onPatch(setPath(a, ['rollout_timeline', i, 'accent'], c))}
                      title={`Accent: ${c}`}
                      style={{
                        width: 14, height: 14, borderRadius: '50%', cursor: 'pointer',
                        border: (p.accent || 'teal') === c ? '2px solid var(--ink-60)' : '1px solid var(--ink-20)',
                        background: ({ teal: '#22B8A7', navy: '#0B1F33', signal: '#5b6cff', efficacy: '#067647' })[c]
                      }}
                    />
                  ))}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* FAQ — card-style Q&A with colored "Q" badge for visual rhythm */}
      <div style={{ marginBottom: 26 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
          <div style={{ width: 3, height: 14, background: 'var(--efficacy)' }} />
          <SectionLabel a={a} onPatch={onPatch} labelKey="faq_title" defaultText="FAQ" style={{ display: 'inline-block', fontSize: 10, letterSpacing: '0.14em', color: 'var(--ink-40)', textTransform: 'uppercase' }} />
        </div>
        <div style={{ display: 'grid', gap: 8 }}>
          {(a.faq || []).map((q, i) => (
            <div key={i} style={{ display: 'grid', gridTemplateColumns: '24px 1fr', gap: 12, padding: '12px 14px', background: '#F8FAFC', border: '1px solid var(--ink-05)', borderLeft: '3px solid var(--efficacy)', borderRadius: 3, alignItems: 'start' }}>
              <div className="mono" style={{ width: 22, height: 22, borderRadius: '50%', background: 'var(--efficacy)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 600, lineHeight: 1, letterSpacing: 0 }}>Q</div>
              <div>
                <Editable value={q.question} onChange={(v) => onPatch(setPath(a, ['faq', i, 'question'], v))} tag="p" style={{ fontSize: 13.5, fontWeight: 600, margin: '0 0 6px', color: 'var(--ink-100)', lineHeight: 1.4 }} />
                <Editable value={q.answer} onChange={(v) => onPatch(setPath(a, ['faq', i, 'answer'], v))} tag="p" style={{ fontSize: 13, margin: 0, color: 'var(--ink-80)', lineHeight: 1.55 }} />
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* CONTACT — styled card instead of plain inline text */}
      <div style={{ padding: '14px 18px', background: 'var(--navy)', color: '#fff', borderRadius: 4, display: 'grid', gridTemplateColumns: 'auto 1fr', gap: 14, alignItems: 'center' }}>
        <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'rgba(255,255,255,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
            <circle cx="12" cy="8" r="4" />
            <path d="M4 21c0-4 4-7 8-7s8 3 8 7" />
          </svg>
        </div>
        <div>
          <div className="mono" style={{ fontSize: 9.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.75)', marginBottom: 2 }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="contact_title" defaultText="Questions" style={{ display: 'inline-block', fontSize: 9.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.75)' }} />
          </div>
          <Editable value={a.contact} onChange={set('contact')} style={{ display: 'block', fontSize: 13.5, color: '#fff', lineHeight: 1.4 }} />
        </div>
      </div>
      {a.hero_image_direction && (
        <div style={{ marginTop: 18, paddingTop: 12, borderTop: '1px solid var(--ink-05)' }}>
          <div className="mono" style={{ fontSize: 9.5, color: 'var(--ink-40)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>Banner direction</div>
          <Editable value={a.hero_image_direction} onChange={set('hero_image_direction')} multiline style={{ fontSize: 12, color: 'var(--ink-60)', lineHeight: 1.4 }} />
        </div>
      )}
      </div>
    </div>
  );
}

// ============================================================
// Renderer error boundary — catches render exceptions in any
// per-format component so a single broken artifact doesn't
// white-screen the whole studio.
// ============================================================
class ArtifactErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }
  static getDerivedStateFromError(error) {
    return { error };
  }
  componentDidCatch(error, info) {
    console.error('[ArtifactRender] crashed:', error, info);
  }
  render() {
    if (this.state.error) {
      return (
        <div style={{ padding: 24, background: '#FFF6F2', border: '1px solid #F0C5B0', color: '#7B3A1B', borderRadius: 4, maxWidth: 880, margin: '24px auto', fontFamily: 'var(--sans)' }}>
          <div className="mono" style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 8, color: '#A04A1F' }}>Render error · {this.props.format}</div>
          <div style={{ fontSize: 14, fontWeight: 500, marginBottom: 10 }}>This artifact didn't render. The studio is otherwise fine.</div>
          <pre style={{ fontSize: 11, fontFamily: 'var(--mono)', whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: '#fff', padding: 10, borderRadius: 2, color: 'var(--ink-80)', maxHeight: 160, overflow: 'auto' }}>
            {String(this.state.error?.message || this.state.error)}
          </pre>
          <div style={{ fontSize: 12, marginTop: 12, color: 'var(--ink-60)' }}>Most often this means the agent returned a shape the renderer didn't expect. Try Regenerate; if it persists, screenshot this card.</div>
        </div>
      );
    }
    return this.props.children;
  }
}

// ============================================================
// Blog post — editorial long-form. Hero, sections (H2 + paragraphs +
// optional callout + optional inline image), pull quote, key takeaways,
// FAQ, CTA. Designed for AEO + thought leadership. Renders at 720w with
// natural vertical overflow; PDF pageConfig: multiPage.
// ============================================================
function BlogPostRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const hero = window.VENTUM_IMAGERY.hero(intake);
  const overrides = a.image_overrides || {};
  const adjustments = a.image_adjustments || {};
  const onImg = imgPatcher(a, onPatch);
  const onAdj = adjPatcher(a, onPatch);
  const sections = Array.isArray(a.sections) ? a.sections : [];
  const takeaways = Array.isArray(a.key_takeaways) ? a.key_takeaways : [];
  const faq = Array.isArray(a.faq) ? a.faq : [];
  const author = a.author || {};
  const pull = a.pull_quote || {};
  const cta = a.cta || {};

  return (
    <div style={{
      width: 720, background: '#fff', color: 'var(--ink-100)',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)', overflow: 'hidden'
    }}>
      {/* HERO BANNER */}
      <div style={{ position: 'relative', width: '100%', height: 360, overflow: 'hidden', background: '#0B1F33' }}>
        <EditableImage src={hero} slot="hero" overrides={overrides} adjustments={adjustments} onChange={onImg} onChangeAdjust={onAdj} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.25) 0%, rgba(11,31,51,0.55) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, padding: '28px 48px 24px', color: 'white' }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 28, marginBottom: 18, opacity: 0.9 }} />
          <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
        </div>
      </div>

      {/* HEADLINE + DECK + META */}
      <div style={{ padding: '40px 56px 0' }}>
        <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 40, lineHeight: 1.08, letterSpacing: '-0.025em', fontWeight: 400, margin: 0, color: 'var(--ink-100)' }} />
        <Editable value={a.deck} onChange={set(['deck'])} tag="p" style={{ fontSize: 18, lineHeight: 1.5, color: 'var(--ink-80)', marginTop: 18, maxWidth: 600 }} />
        <div style={{ display: 'flex', alignItems: 'center', gap: 18, marginTop: 26, paddingTop: 18, borderTop: '1px solid var(--ink-10)', flexWrap: 'wrap' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <div style={{ width: 32, height: 32, borderRadius: '50%', background: 'var(--teal)', color: 'white', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 500 }}>
              {(author.name || 'V').charAt(0).toUpperCase()}
            </div>
            <div>
              <Editable value={author.name} onChange={(v) => onPatch(setPath(a, ['author','name'], v))} style={{ display: 'block', fontSize: 13, fontWeight: 500, lineHeight: 1.2 }} />
              <Editable value={author.role} onChange={(v) => onPatch(setPath(a, ['author','role'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.1em', textTransform: 'uppercase', marginTop: 2 }} />
            </div>
          </div>
          <div style={{ flex: 1 }} />
          <Editable value={a.publish_date_line} onChange={set(['publish_date_line'])} className="mono" style={{ fontSize: 11, color: 'var(--ink-60)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
          <span style={{ width: 1, height: 12, background: 'var(--ink-20)' }} />
          <Editable value={a.reading_time} onChange={set(['reading_time'])} className="mono" style={{ fontSize: 11, color: 'var(--ink-60)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
        </div>
      </div>

      {/* BODY SECTIONS */}
      <div style={{ padding: '36px 56px 0' }}>
        {sections.map((s, i) => (
          <div key={i} style={{ marginBottom: 38, breakInside: 'avoid' }}>
            <Editable value={s.heading} onChange={(v) => onPatch(setPath(a, ['sections', i, 'heading'], v))} tag="h2" style={{ fontSize: 26, lineHeight: 1.15, letterSpacing: '-0.02em', fontWeight: 400, margin: '0 0 16px', color: 'var(--ink-100)' }} />
            {(Array.isArray(s.paragraphs) ? s.paragraphs : []).map((p, j) => (
              <Editable key={j} value={p} onChange={(v) => onPatch(setPath(a, ['sections', i, 'paragraphs', j], v))} tag="p" style={{ fontSize: 15.5, lineHeight: 1.65, color: 'var(--ink-80)', margin: '0 0 14px' }} />
            ))}
            {s.callout && (
              <div style={{
                margin: '20px 0 6px',
                padding: '18px 22px',
                background: s.callout.kind === 'quote' ? 'var(--ink-05)' : (s.callout.kind === 'stat' ? 'var(--navy)' : '#fff'),
                color: s.callout.kind === 'stat' ? 'white' : 'var(--ink-100)',
                borderLeft: s.callout.kind === 'note' ? '3px solid var(--teal)' : 'none',
                borderRadius: 2
              }}>
                <Editable value={s.callout.label} onChange={(v) => onPatch(setPath(a, ['sections', i, 'callout', 'label'], v))} className="mono" style={{ fontSize: 9, color: s.callout.kind === 'stat' ? 'rgba(255,255,255,0.75)' : 'var(--ink-60)', letterSpacing: '0.16em', textTransform: 'uppercase', display: 'block', marginBottom: 6 }} />
                <Editable value={s.callout.value} onChange={(v) => onPatch(setPath(a, ['sections', i, 'callout', 'value'], v))} style={{ fontSize: s.callout.kind === 'stat' ? 28 : 16, fontWeight: s.callout.kind === 'stat' ? 400 : 500, lineHeight: 1.3, letterSpacing: s.callout.kind === 'stat' ? '-0.02em' : 'normal', display: 'block' }} />
                {s.callout.supporting && (
                  <Editable value={s.callout.supporting} onChange={(v) => onPatch(setPath(a, ['sections', i, 'callout', 'supporting'], v))} style={{ fontSize: 12, color: s.callout.kind === 'stat' ? 'rgba(255,255,255,0.7)' : 'var(--ink-60)', marginTop: 6, display: 'block', lineHeight: 1.5 }} />
                )}
              </div>
            )}
            {s.inline_image_direction && (
              <div style={{ marginTop: 18, position: 'relative', width: '100%', height: 280, overflow: 'hidden', background: '#0B1F33', borderRadius: 2 }}>
                <EditableImage
                  src={window.VENTUM_IMAGERY.support(intake, i)}
                  slot={`inline_${i}`}
                  overrides={overrides}
                  adjustments={adjustments}
                  onChange={onImg}
                  onChangeAdjust={onAdj}
                  alt=""
                />
              </div>
            )}
          </div>
        ))}
      </div>

      {/* PULL QUOTE */}
      {pull.text && (
        <div style={{ padding: '20px 56px 36px', breakInside: 'avoid' }}>
          <div style={{ borderLeft: '3px solid var(--teal)', padding: '12px 0 12px 22px' }}>
            <Editable value={pull.text} onChange={set(['pull_quote','text'])} tag="p" style={{ fontSize: 24, lineHeight: 1.3, fontWeight: 400, letterSpacing: '-0.015em', color: 'var(--ink-100)', margin: 0 }} />
            <Editable value={pull.attribution} onChange={set(['pull_quote','attribution'])} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--ink-60)', marginTop: 12, letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          </div>
        </div>
      )}

      {/* KEY TAKEAWAYS */}
      {takeaways.length > 0 && (
        <div style={{ margin: '0 56px 36px', padding: '24px 28px', background: 'var(--ink-05)', borderRadius: 2, breakInside: 'avoid' }}>
          <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 14 }}>Key takeaways</div>
          <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
            {takeaways.map((t, i) => (
              <li key={i} style={{ display: 'grid', gridTemplateColumns: '22px 1fr', gap: 10, padding: '8px 0', borderBottom: i < takeaways.length - 1 ? '1px solid var(--ink-10)' : 'none' }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.1em', paddingTop: 4 }}>{String(i + 1).padStart(2, '0')}</div>
                <Editable value={t} onChange={(v) => onPatch(setPath(a, ['key_takeaways', i], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--ink-80)', margin: 0 }} />
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* FAQ */}
      {faq.length > 0 && (
        <div style={{ padding: '20px 56px 36px', breakInside: 'avoid' }}>
          <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 18 }}>FAQ</div>
          {faq.map((item, i) => (
            <div key={i} style={{ paddingBottom: 16, marginBottom: 16, borderBottom: i < faq.length - 1 ? '1px solid var(--ink-10)' : 'none', breakInside: 'avoid' }}>
              <Editable value={item.question} onChange={(v) => onPatch(setPath(a, ['faq', i, 'question'], v))} tag="h3" style={{ fontSize: 16, fontWeight: 500, margin: '0 0 8px', color: 'var(--ink-100)', lineHeight: 1.3 }} />
              <Editable value={item.answer} onChange={(v) => onPatch(setPath(a, ['faq', i, 'answer'], v))} tag="p" style={{ fontSize: 14, lineHeight: 1.55, color: 'var(--ink-80)', margin: 0 }} />
            </div>
          ))}
        </div>
      )}

      {/* CTA BANNER */}
      <div style={{ background: 'var(--navy)', color: 'white', padding: '32px 56px 36px', marginTop: 8, breakInside: 'avoid' }}>
        <Editable value={cta.headline} onChange={set(['cta','headline'])} tag="h3" style={{ fontSize: 22, fontWeight: 400, margin: 0, lineHeight: 1.2, letterSpacing: '-0.015em' }} />
        <Editable value={cta.body} onChange={set(['cta','body'])} tag="p" style={{ fontSize: 14, color: 'rgba(255,255,255,0.78)', marginTop: 10, marginBottom: 18, lineHeight: 1.5, maxWidth: 540 }} />
        <Editable value={cta.primary} onChange={set(['cta','primary'])} style={{ display: 'inline-block', background: 'var(--teal)', color: 'var(--navy)', padding: '10px 16px', fontSize: 13, fontWeight: 500, borderRadius: 2 }} />
      </div>
    </div>
  );
}

// ============================================================
// White paper — formal authority document. Cover · exec summary ·
// problem · methodology (w/ image) · evidence (case cards) ·
// recommendations · compliance · references · CTA. Renders at 880w
// (info_pack PDF host width); PDF pageConfig: multiPage.
// ============================================================
function WhitePaperRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const customerName = (a.cover && a.cover.prepared_for) || intake.account_name || '';
  const overrides = a.image_overrides || {};
  const adjustments = a.image_adjustments || {};
  const onImg = imgPatcher(a, onPatch);
  const onAdj = adjPatcher(a, onPatch);
  const imagery = window.VENTUM_IMAGERY;
  const heroPhoto = imagery ? imagery.hero(intake) : '';
  const methodologyPhoto = imagery ? imagery.product(intake) : '';

  const W = 880;
  const sectionBase = { padding: '56px 64px', borderTop: '1px solid var(--ink-10)' };

  const SectionHead = ({ tag, title }) => (
    <div style={{ marginBottom: 22 }}>
      <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 8 }}>{tag}</div>
      <h2 style={{ fontSize: 30, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1.15, margin: 0, color: 'var(--ink-100)' }}>{title}</h2>
    </div>
  );

  const cover = a.cover || {};
  const exec = a.exec_summary || {};
  const problem = a.problem || {};
  const methodology = a.methodology || {};
  const evidence = a.evidence || {};
  const recs = a.recommendations || {};
  const compliance = a.compliance;
  const refs = a.references || {};
  const cta = a.cta || {};

  return (
    <div style={{ width: W, background: '#fff', color: 'var(--ink-100)', boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)', overflow: 'hidden' }}>
      {/* COVER */}
      <div style={{ background: '#0B1F33', color: 'white', padding: '72px 64px 56px', position: 'relative', overflow: 'hidden', minHeight: 560 }}>
        <EditableImage src={heroPhoto} slot="cover_hero" overrides={overrides} adjustments={adjustments} onChange={onImg} onChangeAdjust={onAdj} alt="" />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(11,31,51,0.7) 0%, rgba(11,31,51,0.45) 50%, rgba(11,31,51,0.96) 100%)', pointerEvents: 'none' }} />
        <div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 80 }}>
          <VentumLogo background="navy" alt="Ventum" style={{ height: 44 }} />
          <Editable value={cover.date_line} onChange={set(['cover','date_line'])} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
        </div>
        <div style={{ position: 'relative' }}>
          <Editable value={cover.eyebrow} onChange={set(['cover','eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.2em', textTransform: 'uppercase' }} />
          <Editable value={cover.headline} onChange={set(['cover','headline'])} tag="h1" style={{ fontSize: 56, lineHeight: 1.02, letterSpacing: '-0.02em', fontWeight: 400, color: 'white', marginTop: 18, maxWidth: 720 }} />
          <Editable value={cover.subhead} onChange={set(['cover','subhead'])} tag="p" style={{ fontSize: 19, color: 'rgba(255,255,255,0.78)', marginTop: 20, maxWidth: 620, lineHeight: 1.5 }} />
          <div style={{ marginTop: 56, paddingTop: 24, borderTop: '1px solid rgba(255,255,255,0.18)' }}>
            <SectionLabel a={a} onPatch={onPatch} labelKey="wp_prepared_for_label" defaultText="Prepared for" style={{ display: 'block', fontSize: 9, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.18em', textTransform: 'uppercase' }} />
            <Editable value={cover.prepared_for} onChange={set(['cover','prepared_for'])} style={{ display: 'block', fontSize: 17, color: 'white', marginTop: 8 }} />
          </div>
        </div>
      </div>

      {/* EXECUTIVE SUMMARY */}
      <div style={sectionBase}>
        <SectionHead tag="Executive Summary" title="Key findings" />
        <Editable value={exec.intro} onChange={set(['exec_summary','intro'])} tag="p" style={{ fontSize: 16, lineHeight: 1.65, color: 'var(--ink-80)', maxWidth: 720, marginBottom: 28 }} />
        {Array.isArray(exec.key_findings) && exec.key_findings.length > 0 && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px 32px' }}>
            {exec.key_findings.map((f, i) => (
              <div key={i} style={{ borderLeft: '2px solid var(--teal)', paddingLeft: 16 }}>
                <Editable value={f.label} onChange={(v) => onPatch(setPath(a, ['exec_summary','key_findings', i, 'label'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 6 }} />
                <Editable value={f.detail} onChange={(v) => onPatch(setPath(a, ['exec_summary','key_findings', i, 'detail'], v))} tag="p" style={{ fontSize: 14, color: 'var(--ink-80)', lineHeight: 1.55, margin: 0 }} />
              </div>
            ))}
          </div>
        )}
      </div>

      {/* PROBLEM */}
      {problem && (problem.headline || problem.body) && (
        <div style={sectionBase}>
          <SectionHead tag="The Problem" title={problem.headline || ''} />
          <Editable value={problem.body} onChange={set(['problem','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.7, color: 'var(--ink-80)', maxWidth: 720 }} />
          {problem.stat && (
            <div style={{ marginTop: 28, padding: '20px 24px', background: 'var(--ink-05)', display: 'inline-flex', alignItems: 'baseline', gap: 16 }}>
              <Editable value={problem.stat.value} onChange={set(['problem','stat','value'])} style={{ fontSize: 40, fontWeight: 400, letterSpacing: '-0.02em', lineHeight: 1, color: 'var(--ink-100)' }} />
              <div>
                <Editable value={problem.stat.unit} onChange={set(['problem','stat','unit'])} className="mono" style={{ display: 'block', fontSize: 11, color: 'var(--ink-60)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
                <Editable value={problem.stat.supporting} onChange={set(['problem','stat','supporting'])} style={{ display: 'block', fontSize: 12, color: 'var(--ink-60)', marginTop: 4, lineHeight: 1.4 }} />
              </div>
            </div>
          )}
        </div>
      )}

      {/* METHODOLOGY */}
      {methodology && (methodology.headline || methodology.body) && (
        <div style={sectionBase}>
          <SectionHead tag="Methodology" title={methodology.headline || ''} />
          <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 32 }}>
            <div>
              <Editable value={methodology.body} onChange={set(['methodology','body'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.65, color: 'var(--ink-80)', marginBottom: 24 }} />
              {Array.isArray(methodology.specs) && methodology.specs.length > 0 && (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
                  {methodology.specs.map((s, i) => (
                    <div key={i} style={{ display: 'grid', gridTemplateColumns: '140px 1fr', gap: 12, padding: '10px 0', borderBottom: '1px solid var(--ink-10)' }}>
                      <Editable value={s.label} onChange={(v) => onPatch(setPath(a, ['methodology','specs', i, 'label'], v))} className="mono" style={{ fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
                      <Editable value={s.value} onChange={(v) => onPatch(setPath(a, ['methodology','specs', i, 'value'], v))} style={{ fontSize: 13.5, color: 'var(--ink-80)' }} />
                    </div>
                  ))}
                </div>
              )}
            </div>
            <div>
              <div style={{ position: 'relative', width: '100%', height: 260, overflow: 'hidden', background: '#0B1F33' }}>
                <EditableImage src={methodologyPhoto} slot="methodology_image" overrides={overrides} adjustments={adjustments} onChange={onImg} onChangeAdjust={onAdj} alt="" />
                {a.methodology_image_caption && (
                  <div style={{ position: 'absolute', left: 12, bottom: 10 }}>
                    <Editable value={a.methodology_image_caption} onChange={set(['methodology_image_caption'])} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.85)', letterSpacing: '0.14em', textTransform: 'uppercase', background: 'rgba(11,31,51,0.6)', padding: '4px 8px' }} />
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>
      )}

      {/* EVIDENCE */}
      {evidence && (evidence.headline || (Array.isArray(evidence.cases) && evidence.cases.length > 0)) && (
        <div style={sectionBase}>
          <SectionHead tag="Evidence" title={evidence.headline || ''} />
          <Editable value={evidence.intro} onChange={set(['evidence','intro'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.65, color: 'var(--ink-80)', maxWidth: 720, marginBottom: 28 }} />
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 18 }}>
            {(evidence.cases || []).map((c, i) => (
              <div key={i} style={{ padding: '22px 24px', background: 'var(--ink-05)', borderRadius: 2, breakInside: 'avoid' }}>
                <Editable value={c.title} onChange={(v) => onPatch(setPath(a, ['evidence','cases', i, 'title'], v))} className="mono" style={{ display: 'block', fontSize: 10, color: 'var(--teal)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 6 }} />
                <Editable value={c.setting} onChange={(v) => onPatch(setPath(a, ['evidence','cases', i, 'setting'], v))} style={{ display: 'block', fontSize: 15, fontWeight: 500, lineHeight: 1.3, marginBottom: 10, color: 'var(--ink-100)' }} />
                <Editable value={c.finding} onChange={(v) => onPatch(setPath(a, ['evidence','cases', i, 'finding'], v))} tag="p" style={{ fontSize: 13.5, lineHeight: 1.55, color: 'var(--ink-80)', marginBottom: 14 }} />
                {c.metric && (
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, paddingTop: 12, borderTop: '1px solid var(--ink-20)' }}>
                    <Editable value={c.metric.value} onChange={(v) => onPatch(setPath(a, ['evidence','cases', i, 'metric','value'], v))} style={{ fontSize: 24, fontWeight: 400, letterSpacing: '-0.02em', color: 'var(--ink-100)' }} />
                    <Editable value={c.metric.unit} onChange={(v) => onPatch(setPath(a, ['evidence','cases', i, 'metric','unit'], v))} className="mono" style={{ fontSize: 10, color: 'var(--ink-60)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
                  </div>
                )}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* RECOMMENDATIONS */}
      {recs && (recs.headline || (Array.isArray(recs.items) && recs.items.length > 0)) && (
        <div style={sectionBase}>
          <SectionHead tag="Recommendations" title={recs.headline || ''} />
          <Editable value={recs.intro} onChange={set(['recommendations','intro'])} tag="p" style={{ fontSize: 15.5, lineHeight: 1.65, color: 'var(--ink-80)', maxWidth: 720, marginBottom: 28 }} />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            {(recs.items || []).map((it, i) => (
              <div key={i} style={{ display: 'grid', gridTemplateColumns: '64px 1fr', gap: 18, paddingBottom: 16, borderBottom: '1px solid var(--ink-10)', breakInside: 'avoid' }}>
                <div className="mono" style={{ fontSize: 32, fontWeight: 300, color: 'var(--teal)', letterSpacing: '-0.02em', lineHeight: 1 }}>
                  {String(it.number || (i + 1)).padStart(2, '0')}
                </div>
                <div>
                  <Editable value={it.title} onChange={(v) => onPatch(setPath(a, ['recommendations','items', i, 'title'], v))} tag="h3" style={{ fontSize: 17, fontWeight: 500, margin: '0 0 6px', color: 'var(--ink-100)', lineHeight: 1.3 }} />
                  <Editable value={it.detail} onChange={(v) => onPatch(setPath(a, ['recommendations','items', i, 'detail'], v))} tag="p" style={{ fontSize: 14, color: 'var(--ink-80)', lineHeight: 1.55, margin: 0 }} />
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* COMPLIANCE */}
      {compliance && (compliance.headline || compliance.body) && (
        <div style={sectionBase}>
          <SectionHead tag="Compliance" title={compliance.headline || ''} />
          <Editable value={compliance.body} onChange={set(['compliance','body'])} tag="p" style={{ fontSize: 15, lineHeight: 1.65, color: 'var(--ink-80)', maxWidth: 720, marginBottom: 24 }} />
          {Array.isArray(compliance.items) && compliance.items.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px 28px' }}>
              {compliance.items.map((it, i) => (
                <div key={i} style={{ padding: '14px 18px', background: 'var(--ink-05)', borderLeft: '2px solid var(--navy)' }}>
                  <Editable value={it.label} onChange={(v) => onPatch(setPath(a, ['compliance','items', i, 'label'], v))} className="mono" style={{ display: 'block', fontSize: 9, color: 'var(--ink-60)', letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 6 }} />
                  <Editable value={it.detail} onChange={(v) => onPatch(setPath(a, ['compliance','items', i, 'detail'], v))} style={{ display: 'block', fontSize: 13, color: 'var(--ink-80)', lineHeight: 1.5 }} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* REFERENCES */}
      {refs && Array.isArray(refs.items) && refs.items.length > 0 && (
        <div style={sectionBase}>
          <SectionHead tag="References" title="Sources" />
          <ol style={{ margin: 0, padding: 0, listStyle: 'none' }}>
            {refs.items.map((r, i) => (
              <li key={i} style={{ display: 'grid', gridTemplateColumns: '36px 1fr', gap: 12, padding: '10px 0', borderBottom: i < refs.items.length - 1 ? '1px solid var(--ink-10)' : 'none' }}>
                <div className="mono" style={{ fontSize: 11, color: 'var(--ink-60)', letterSpacing: '0.1em', paddingTop: 2 }}>{String(i + 1).padStart(2, '0')}</div>
                <Editable value={r} onChange={(v) => onPatch(setPath(a, ['references','items', i], v))} style={{ fontSize: 13, color: 'var(--ink-80)', lineHeight: 1.5 }} />
              </li>
            ))}
          </ol>
        </div>
      )}

      {/* CTA */}
      <div style={{ background: 'var(--navy)', color: 'white', padding: '48px 64px', borderTop: '1px solid var(--ink-10)' }}>
        <div style={{ maxWidth: 720 }}>
          <Editable value={cta.headline} onChange={set(['cta','headline'])} tag="h2" style={{ fontSize: 28, fontWeight: 400, margin: 0, lineHeight: 1.2, letterSpacing: '-0.02em' }} />
          <Editable value={cta.body} onChange={set(['cta','body'])} tag="p" style={{ fontSize: 15, color: 'rgba(255,255,255,0.78)', marginTop: 12, marginBottom: 24, lineHeight: 1.55 }} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 24, flexWrap: 'wrap' }}>
            <Editable value={cta.primary} onChange={set(['cta','primary'])} style={{ display: 'inline-block', background: 'var(--teal)', color: 'var(--navy)', padding: '12px 18px', fontSize: 13, fontWeight: 500, borderRadius: 2 }} />
            <Editable value={cta.contact} onChange={set(['cta','contact'])} className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase' }} />
          </div>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Infographic — single-page social-shareable. ONE claim + stat block +
// supporting stats + (sequence | comparison) + proof line + signoff.
// Renders at 720×1080 portrait (4:6, prints as letter). PDF: default
// single-page route.
// ============================================================
function InfographicRender({ a, onPatch, intake = {} }) {
  const set = (path) => (v) => onPatch(setPath(a, path, v));
  const overrides = a.image_overrides || {};
  const adjustments = a.image_adjustments || {};
  const onImg = imgPatcher(a, onPatch);
  const onAdj = adjPatcher(a, onPatch);
  const supportingStats = Array.isArray(a.supporting_stats) ? a.supporting_stats : [];
  const sequence = a.sequence;
  const comparison = a.comparison;
  const stat = a.stat_block || {};
  const signoff = a.signoff || {};
  const heroPhoto = window.VENTUM_IMAGERY ? window.VENTUM_IMAGERY.product(intake) : '';

  return (
    <div style={{
      width: 720, height: 1080, background: '#0B1F33', color: 'white',
      boxShadow: '0 30px 60px -20px rgba(11,31,51,0.18)',
      display: 'grid', gridTemplateRows: 'auto auto 1fr auto auto', position: 'relative', overflow: 'hidden'
    }}>
      {/* Decorative gradient field */}
      <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(ellipse 70% 40% at 100% 0%, rgba(37,99,235,0.35), transparent 55%), radial-gradient(ellipse 70% 50% at 0% 100%, rgba(34,184,167,0.25), transparent 60%)', pointerEvents: 'none' }} />

      {/* HEADER BAND */}
      <div style={{ position: 'relative', padding: '40px 56px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <VentumLogo background="navy" alt="Ventum" style={{ height: 32 }} />
        <Editable value={a.eyebrow} onChange={set(['eyebrow'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.2em', textTransform: 'uppercase' }} />
      </div>

      {/* HEADLINE + SUBHEAD */}
      <div style={{ position: 'relative', padding: '28px 56px 0' }}>
        <Editable value={a.headline} onChange={set(['headline'])} tag="h1" style={{ fontSize: 52, lineHeight: 1.02, letterSpacing: '-0.025em', fontWeight: 400, margin: 0, color: 'white', maxWidth: 580 }} />
        <Editable value={a.subhead} onChange={set(['subhead'])} tag="p" style={{ fontSize: 17, color: 'rgba(255,255,255,0.75)', marginTop: 16, lineHeight: 1.5, maxWidth: 540 }} />
      </div>

      {/* HERO STAT + SUPPORTING STATS + (SEQUENCE or COMPARISON) */}
      <div style={{ position: 'relative', padding: '36px 56px 0', display: 'grid', gridTemplateRows: 'auto auto 1fr', gap: 28 }}>
        {/* Hero stat */}
        <div style={{ padding: '24px 28px', background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.12)', display: 'flex', alignItems: 'baseline', gap: 20 }}>
          <Editable value={stat.value} onChange={set(['stat_block','value'])} style={{ fontSize: 84, fontWeight: 300, letterSpacing: '-0.04em', lineHeight: 1, color: 'var(--teal)' }} />
          <div style={{ flex: 1 }}>
            <Editable value={stat.unit} onChange={set(['stat_block','unit'])} className="mono" style={{ display: 'block', fontSize: 12, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.16em', textTransform: 'uppercase' }} />
            <Editable value={stat.supporting} onChange={set(['stat_block','supporting'])} style={{ display: 'block', fontSize: 14, color: 'rgba(255,255,255,0.85)', marginTop: 8, lineHeight: 1.45 }} />
          </div>
        </div>

        {/* Supporting stats row */}
        {supportingStats.length > 0 && (
          <div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(supportingStats.length, 4)}, 1fr)`, gap: 14 }}>
            {supportingStats.slice(0, 4).map((s, i) => (
              <div key={i} style={{ padding: '14px 14px', borderLeft: '2px solid var(--teal)' }}>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
                  <Editable value={s.value} onChange={(v) => onPatch(setPath(a, ['supporting_stats', i, 'value'], v))} style={{ fontSize: 24, fontWeight: 400, letterSpacing: '-0.02em', color: 'white' }} />
                  <Editable value={s.unit} onChange={(v) => onPatch(setPath(a, ['supporting_stats', i, 'unit'], v))} className="mono" style={{ fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.12em', textTransform: 'uppercase' }} />
                </div>
                <Editable value={s.label} onChange={(v) => onPatch(setPath(a, ['supporting_stats', i, 'label'], v))} style={{ display: 'block', fontSize: 11, color: 'rgba(255,255,255,0.75)', marginTop: 6, lineHeight: 1.4 }} />
              </div>
            ))}
          </div>
        )}

        {/* Sequence OR Comparison panel */}
        {sequence && Array.isArray(sequence.steps) && sequence.steps.length > 0 ? (
          <div style={{ alignSelf: 'start' }}>
            <Editable value={sequence.title} onChange={set(['sequence','title'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', display: 'block', marginBottom: 14 }} />
            <div style={{ display: 'grid', gridTemplateColumns: `repeat(${sequence.steps.length}, 1fr)`, gap: 10 }}>
              {sequence.steps.map((step, i) => (
                <div key={i} style={{ position: 'relative', padding: '16px 14px', background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.1)' }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--teal)', letterSpacing: '0.18em', marginBottom: 8 }}>{String(step.number || (i + 1)).padStart(2, '0')}</div>
                  <Editable value={step.label} onChange={(v) => onPatch(setPath(a, ['sequence','steps', i, 'label'], v))} style={{ display: 'block', fontSize: 16, fontWeight: 500, color: 'white', marginBottom: 6 }} />
                  <Editable value={step.detail} onChange={(v) => onPatch(setPath(a, ['sequence','steps', i, 'detail'], v))} style={{ display: 'block', fontSize: 11, color: 'rgba(255,255,255,0.7)', lineHeight: 1.4 }} />
                  {i < sequence.steps.length - 1 && (
                    <div style={{ position: 'absolute', right: -10, top: '50%', transform: 'translateY(-50%)', color: 'var(--teal)', fontSize: 14 }}>→</div>
                  )}
                </div>
              ))}
            </div>
          </div>
        ) : comparison && Array.isArray(comparison.columns) && comparison.columns.length === 2 ? (
          <div style={{ alignSelf: 'start' }}>
            <Editable value={comparison.title} onChange={set(['comparison','title'])} className="mono" style={{ fontSize: 11, color: 'var(--teal)', letterSpacing: '0.18em', textTransform: 'uppercase', display: 'block', marginBottom: 14 }} />
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
              {comparison.columns.map((col, i) => (
                <div key={i} style={{ padding: '18px 18px', background: i === 0 ? 'rgba(255,255,255,0.04)' : 'rgba(34,184,167,0.1)', border: '1px solid ' + (i === 0 ? 'rgba(255,255,255,0.1)' : 'rgba(34,184,167,0.3)') }}>
                  <Editable value={col.label} onChange={(v) => onPatch(setPath(a, ['comparison','columns', i, 'label'], v))} style={{ display: 'block', fontSize: 16, fontWeight: 500, color: i === 0 ? 'rgba(255,255,255,0.9)' : 'var(--teal)', marginBottom: 14, paddingBottom: 10, borderBottom: '1px solid rgba(255,255,255,0.15)' }} />
                  <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
                    {(col.points || []).map((p, j) => (
                      <li key={j} style={{ display: 'grid', gridTemplateColumns: '14px 1fr', gap: 8, marginBottom: 8 }}>
                        <div style={{ color: i === 0 ? 'rgba(255,255,255,0.4)' : 'var(--teal)', fontSize: 12 }}>{i === 0 ? '·' : '→'}</div>
                        <Editable value={p} onChange={(v) => onPatch(setPath(a, ['comparison','columns', i, 'points', j], v))} style={{ fontSize: 12.5, color: 'rgba(255,255,255,0.85)', lineHeight: 1.45 }} />
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>
          </div>
        ) : null}
      </div>

      {/* PROOF LINE */}
      <div style={{ position: 'relative', padding: '20px 56px 0' }}>
        <Editable value={a.proof_line} onChange={set(['proof_line'])} className="mono" style={{ display: 'block', fontSize: 10, color: 'rgba(255,255,255,0.75)', letterSpacing: '0.14em', textTransform: 'uppercase', borderTop: '1px solid rgba(255,255,255,0.15)', paddingTop: 14 }} />
      </div>

      {/* SIGNOFF */}
      <div style={{ position: 'relative', padding: '20px 56px 36px', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <Editable value={signoff.tagline} onChange={set(['signoff','tagline'])} style={{ fontSize: 16, fontWeight: 400, color: 'white', letterSpacing: '-0.01em' }} />
        <Editable value={signoff.cta} onChange={set(['signoff','cta'])} style={{ display: 'inline-block', background: 'var(--teal)', color: 'var(--navy)', padding: '10px 16px', fontSize: 12, fontWeight: 500, borderRadius: 2 }} />
      </div>

      {/* Hidden hero slot for any operator image upload (overlaid behind gradient if used) */}
      <div style={{ display: 'none' }}>
        <EditableImage src={heroPhoto} slot="hero" overrides={overrides} adjustments={adjustments} onChange={onImg} onChangeAdjust={onAdj} alt="" />
      </div>
    </div>
  );
}

// ============================================================
// Renderer dispatch
// ============================================================
function ArtifactRenderInner({ format, artifact, onPatch, intake, strategy, onRegeneratePost }) {
  if (!artifact) return null;
  const a = artifact;
  switch (format) {
    case 'one_pager':         return <OnePagerRender a={a} onPatch={onPatch} intake={intake} />;
    case 'linkedin_post':     return <LinkedInPostRender a={a} onPatch={onPatch} intake={intake} />;
    case 'linkedin_campaign': return <LinkedInCampaignRender a={a} onPatch={onPatch} intake={intake} strategy={strategy} onRegeneratePost={onRegeneratePost} />;
    case 'twitter_post':      return <TwitterPostRender a={a} onPatch={onPatch} intake={intake} />;
    case 'twitter_thread':    return <TwitterThreadRender a={a} onPatch={onPatch} intake={intake} />;
    case 'instagram_post':    return <InstagramPostRender a={a} onPatch={onPatch} intake={intake} />;
    case 'instagram_caption_set': return <InstagramCaptionSetRender a={a} onPatch={onPatch} intake={intake} />;
    case 'partner_announcement_email':    return <PartnerAnnouncementEmailRender a={a} onPatch={onPatch} intake={intake} />;
    case 'partner_announcement_slack':    return <PartnerAnnouncementSlackRender a={a} onPatch={onPatch} intake={intake} />;
    case 'partner_announcement_press':    return <PartnerAnnouncementPressRender a={a} onPatch={onPatch} intake={intake} />;
    case 'partner_announcement_linkedin': return <PartnerAnnouncementLinkedInRender a={a} onPatch={onPatch} intake={intake} />;
    case 'partner_announcement_allhands': return <PartnerAnnouncementAllHandsRender a={a} onPatch={onPatch} intake={intake} />;
    case 'email':             return <EmailRender a={a} onPatch={onPatch} intake={intake} />;
    case 'deck_slide':        return <DeckSlideRender a={a} onPatch={onPatch} intake={intake} />;
    case 'deck':              return <DeckRender a={a} onPatch={onPatch} intake={intake} />;
    case 'web_hero':          return <WebHeroRender a={a} onPatch={onPatch} intake={intake} />;
    case 'print_ad':          return <PrintAdRender a={a} onPatch={onPatch} intake={intake} />;
    case 'trade_show_banner': return <BannerRender a={a} onPatch={onPatch} intake={intake} />;
    case 'linkedin_carousel': return <CarouselRender a={a} onPatch={onPatch} intake={intake} />;
    case 'brochure':          return <BrochureRender a={a} onPatch={onPatch} intake={intake} />;
    case 'case_study_summary':return <CaseStudyRender a={a} onPatch={onPatch} intake={intake} />;
    case 'account_brief':     return <AccountBriefRender a={a} onPatch={onPatch} intake={intake} />;
    case 'info_pack':         return <InfoPackRender a={a} onPatch={onPatch} intake={intake} />;
    case 'blog_post':         return <BlogPostRender a={a} onPatch={onPatch} intake={intake} />;
    case 'white_paper':       return <WhitePaperRender a={a} onPatch={onPatch} intake={intake} />;
    case 'infographic':       return <InfographicRender a={a} onPatch={onPatch} intake={intake} />;
    default:
      return (
        <div style={{ padding: 24, background: '#fff', border: '1px solid var(--ink-10)' }}>
          <pre style={{ fontSize: 12, color: 'var(--ink-80)' }}>{JSON.stringify(a, null, 2)}</pre>
        </div>
      );
  }
}

// Wrapper that catches per-format render exceptions. ArtifactRender
// is the public-facing component; ArtifactRenderInner is the actual
// switch. Window export goes through the wrapper so every consumer
// (Room 5, Room 6, print stage, PDF / PPTX off-screen mounts) gets
// the error boundary for free.
// Editor-only popover that lets you click any logo in the preview to change
// its variant. Mounted only when ArtifactRender gets `editableLogo` (the live
// preview + deep edit) — never in export/share renders. The popover itself is
// data-editor-only and position:fixed, so it has zero layout impact and is
// stripped from every export path even if it were somehow open during capture.
const LOGO_VARIANT_OPTIONS = [
  { id: 'auto', label: 'Auto (light / dark by background)' },
  { id: 'color', label: 'Color lockup' },
  { id: 'white', label: 'White lockup' },
  { id: 'black', label: 'Black mark' },
  { id: 'grayscale', label: 'Grayscale mark' },
  { id: 'pride', label: 'Pride mark' }
];

function LogoPickerProvider({ artifact, onPatch, children }) {
  const [menu, setMenu] = React.useState(null); // { x, y } screen coords or null
  const current = (artifact && artifact._logo_variant) || 'auto';
  const open = React.useCallback((anchorEl) => {
    if (!anchorEl) return;
    const r = anchorEl.getBoundingClientRect();
    // Anchor below the logo, clamped into the viewport.
    const x = Math.min(Math.max(8, r.left), window.innerWidth - 236);
    const y = Math.min(r.bottom + 6, window.innerHeight - 260);
    setMenu({ x, y });
  }, []);
  const ctxVal = React.useMemo(() => ({ open }), [open]);
  const pick = (id) => {
    onPatch({ ...artifact, _logo_variant: id });
    setMenu(null);
  };
  return (
    <VentumLogoPickerCtx.Provider value={ctxVal}>
      {children}
      {menu && (
        <div data-editor-only="true" onClick={() => setMenu(null)}
          style={{ position: 'fixed', inset: 0, zIndex: 9998 }}>
          <div onClick={(e) => e.stopPropagation()}
            style={{ position: 'fixed', left: menu.x, top: menu.y, width: 228, zIndex: 9999,
              background: '#fff', border: '1px solid var(--ink-10, #e3e7eb)', borderRadius: 8,
              boxShadow: '0 12px 32px -8px rgba(11,31,51,0.28)', padding: 6, fontFamily: 'inherit' }}>
            <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase',
              color: 'var(--ink-40, #8a97a3)', padding: '6px 8px 4px' }}>Logo variant</div>
            {LOGO_VARIANT_OPTIONS.map((opt) => (
              <button key={opt.id} onClick={() => pick(opt.id)}
                style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', textAlign: 'left',
                  border: 'none', background: opt.id === current ? 'var(--ink-05, #f2f5f7)' : 'transparent',
                  borderRadius: 5, padding: '7px 8px', fontSize: 12.5, cursor: 'pointer',
                  color: 'var(--ink, #0B1F33)', fontWeight: opt.id === current ? 600 : 400 }}>
                <span style={{ width: 14, display: 'inline-block', color: 'var(--teal, #22B8A7)' }}>{opt.id === current ? '✓' : ''}</span>
                {opt.label}
              </button>
            ))}
          </div>
        </div>
      )}
    </VentumLogoPickerCtx.Provider>
  );
}

function ArtifactRender(props) {
  // Per-artifact logo variant (set by the Room 6 picker). Wrapping the whole
  // render in the context lets every <VentumLogo> inside pick it up without
  // threading a prop through each renderer. Default 'auto' = light/dark by bg.
  const logoVariant = (props.artifact && props.artifact._logo_variant) || 'auto';
  const inner = (
    <VentumLogoVariantCtx.Provider value={logoVariant}>
      <ArtifactRenderInner {...props} />
    </VentumLogoVariantCtx.Provider>
  );
  return (
    <ArtifactErrorBoundary format={props.format}>
      {props.editableLogo && props.onPatch
        ? <LogoPickerProvider artifact={props.artifact} onPatch={props.onPatch}>{inner}</LogoPickerProvider>
        : inner}
    </ArtifactErrorBoundary>
  );
}

// expose
window.ArtifactRender = ArtifactRender;

// ============================================================
// Device frames — optional chrome around the rendered artifact
// to preview how it lands in context (phone, email client, browser).
// Used by the stage in Room 5; toggled via a pill in the layout switcher.
// ============================================================
function DeviceFrame({ kind, children }) {
  if (!kind || kind === 'none') return children;
  if (kind === 'iphone') {
    return (
      <div className="device-frame device-frame--iphone">
        <div className="device-frame__bezel">
          <div className="device-frame__notch" />
          <div className="device-frame__screen">
            {children}
          </div>
        </div>
        <div className="device-frame__label mono">iPhone preview</div>
      </div>
    );
  }
  if (kind === 'email') {
    return (
      <div className="device-frame device-frame--email">
        <div className="device-frame__app">
          <div className="device-frame__app-sidebar">
            <div className="device-frame__app-folder">Inbox</div>
            <div className="device-frame__app-folder">Starred</div>
            <div className="device-frame__app-folder">Sent</div>
            <div className="device-frame__app-folder">Drafts</div>
          </div>
          <div className="device-frame__app-main">
            <div className="device-frame__app-toolbar">
              <span className="mono">Inbox</span>
              <span className="mono device-frame__app-count">1 of 384</span>
            </div>
            <div className="device-frame__app-body">{children}</div>
          </div>
        </div>
        <div className="device-frame__label mono">Email client preview</div>
      </div>
    );
  }
  if (kind === 'browser') {
    return (
      <div className="device-frame device-frame--browser">
        <div className="device-frame__chrome">
          <div className="device-frame__buttons">
            <span /><span /><span />
          </div>
          <div className="device-frame__url mono">ventumbiotech.com</div>
        </div>
        <div className="device-frame__viewport">{children}</div>
        <div className="device-frame__label mono">Browser preview</div>
      </div>
    );
  }
  return children;
}
window.DeviceFrame = DeviceFrame;

// Mapping: which device-frame modes apply per format
window.VENTUM_DEVICE_FRAMES = {
  linkedin_post:     ['none', 'iphone'],
  linkedin_carousel: ['none', 'iphone'],
  email:             ['none', 'email'],
  web_hero:          ['none', 'browser']
};
