const TabAnunciosFull = ({ campanha, copy, prompts }) => {
  const proposta    = campanha?.proposta_json || {};
  const commPlan    = proposta.comm_plan || [];
  const canaisSetup = campanha?.canais_setup ? (typeof campanha.canais_setup === 'string' ? JSON.parse(campanha.canais_setup) : campanha.canais_setup) : null;
  const CHAN_NORM   = { linkedin:'linkedin_ads', google_ads:'google_ads_search', instagram:'meta_ads', facebook:'meta_ads', site:'website', led:'muppi_led' };

  const paidItems = commPlan.filter(item => {
    const norm = CHAN_NORM[item.canal] || item.canal;
    return PAID_CHANNELS.has(norm) || PAID_CHANNELS.has(item.canal);
  });

  if (paidItems.length === 0) return (
    <div style={{ padding: '48px 0', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
      <div style={{ fontSize: 13, color: 'var(--text-muted,#64748b)', textAlign: 'center' }}>
        Sem canais de anúncios pagos no plano de comunicação.<br/>Selecciona Meta Ads, LinkedIn Ads ou Google Ads no briefing.
      </div>
    </div>
  );

  // Agrupar items por canal normalizado
  const byChannel = {};
  paidItems.forEach(item => {
    const ch = CHAN_NORM[item.canal] || item.canal;
    if (!byChannel[ch]) byChannel[ch] = [];
    byChannel[ch].push(item);
  });

  const lSt = { fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--text-dim,#94a3b8)', fontFamily: 'var(--font-mono,monospace)', marginBottom: 4 };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      {Object.entries(byChannel).map(([ch, items]) => {
        const col   = CANAL_COLORS[ch] || '#3859D0';
        const setup = canaisSetup?.canais?.[ch];
        const audiencias = setup?.audiencias || [];

        return (
          <div key={ch} style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderLeft: `4px solid ${col}`, borderRadius: 10, overflow: 'hidden' }}>
            {/* Channel header */}
            <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--border,#e2e8f0)', display: 'flex', alignItems: 'center', gap: 12 }}>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 700, color, fontFamily: 'Montserrat,sans-serif' }}>{PAID_LABELS[ch] || ch}</div>
                {setup?.objectivo_campanha && <div style={{ fontSize: 11, color: 'var(--text-muted,#64748b)', marginTop: 2 }}>{setup.objectivo_campanha}</div>}
              </div>
              {setup?.budget_sugerido?.percentagem_total && (
                <div style={{ fontSize: 11, fontWeight: 700, padding: '3px 10px', borderRadius: 99, background: col+'14', color: col, fontFamily: 'monospace' }}>
                  {setup.budget_sugerido.percentagem_total}% budget
                </div>
              )}
            </div>

            {/* Ad Sets (audiences) */}
            {audiencias.length > 0 && (
              <div style={{ padding: '12px 20px', borderBottom: '1px solid var(--border,#e2e8f0)', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                <div style={{ ...lSt, width: '100%', marginBottom: 8 }}>Ad Sets</div>
                {audiencias.map((aud, i) => (
                  <div key={i} style={{ padding: '6px 12px', borderRadius: 8, background: 'var(--bg-sunken,#f8fafc)', border: '1px solid var(--border,#e2e8f0)', fontSize: 11 }}>
                    <span style={{ fontWeight: 600, color: col }}>{aud.nome}</span>
                    <span style={{ fontSize: 9, fontWeight: 600, marginLeft: 6, padding: '1px 5px', borderRadius: 3, background: col+'18', color: col, fontFamily: 'monospace' }}>{aud.tipo}</span>
                    {aud.descricao && <div style={{ fontSize: 10, color: 'var(--text-muted,#64748b)', marginTop: 2 }}>{aud.descricao}</div>}
                  </div>
                ))}
              </div>
            )}

            {/* Ads (comm_plan items com copy e prompt) */}
            <div style={{ padding: '12px 20px' }}>
              <div style={{ ...lSt, marginBottom: 10 }}>Anúncios ({items.length})</div>
              {items.map((item, i) => {
                const itemCopy    = (copy || []).find(c => c.comm_plan_item_index === commPlan.indexOf(item));
                const itemPrompts = (prompts || []).filter(p => p.comm_plan_item_index === commPlan.indexOf(item));
                const bgPrompt    = itemPrompts.find(p => p.tipo === 'background' || p.tipo === 'video_produto');
                const compPrompt  = itemPrompts.find(p => p.tipo === 'composicao' || p.tipo === 'composicao_video');

                return (
                  <div key={i} style={{ border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, padding: '12px 14px', marginBottom: 8, background: i % 2 === 0 ? 'var(--bg-sunken,#f8fafc)' : 'var(--bg-elev,#fff)' }}>
                    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginBottom: 8 }}>
                      <div style={{ width: 20, height: 20, borderRadius: 4, background: col+'18', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 9, fontWeight: 700, color: col, fontFamily: 'monospace', flexShrink: 0 }}>{i+1}</div>
                      <div style={{ flex: 1 }}>
                        <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{item.titulo || `Ad ${i+1}`}</div>
                        <div style={{ fontSize: 10, color: 'var(--text-dim,#94a3b8)', marginTop: 1 }}>{item.content_type} · Stage {item.awareness_stage} · {item.angulo_persona}</div>
                      </div>
                      <div style={{ display: 'flex', gap: 4 }}>
                        {itemCopy && <span style={{ fontSize: 9, padding: '2px 6px', borderRadius: 3, background: 'rgba(34,197,94,.12)', color: '#15803d', fontFamily: 'monospace' }}>Copy ✓</span>}
                        {bgPrompt && <span style={{ fontSize: 9, padding: '2px 6px', borderRadius: 3, background: `${col}14`, color: col, fontFamily: 'monospace' }}>{bgPrompt.plataforma || 'Visual'} ✓</span>}
                      </div>
                    </div>

                    {/* Hook */}
                    {item.hook && <div style={{ fontSize: 11, color: 'var(--text,#1d2e38)', fontStyle: 'italic', marginBottom: 8, paddingLeft: 30 }}>"{item.hook}"</div>}

                    {/* Copy aprovado */}
                    {itemCopy && (
                      <div style={{ paddingLeft: 30, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 8 }}>
                        {itemCopy.headline && <div><div style={lSt}>Headline</div><div style={{ fontSize: 12, color: 'var(--text,#1d2e38)', fontWeight: 600 }}>{itemCopy.headline}</div></div>}
                        {itemCopy.primary_text && <div><div style={lSt}>Primary Text</div><div style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.4 }}>{itemCopy.primary_text?.slice(0, 80)}{itemCopy.primary_text?.length > 80 ? '…' : ''}</div></div>}
                      </div>
                    )}

                    {/* Prompt visual */}
                    {bgPrompt && (
                      <div style={{ paddingLeft: 30 }}>
                        <div style={lSt}>{bgPrompt.plataforma} — {bgPrompt.tipo}</div>
                        <div style={{ fontSize: 10, color: 'var(--text-muted,#64748b)', lineHeight: 1.5 }}>{bgPrompt.prompt_texto?.slice(0,120)}…</div>
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
};

// Awareness stages (Eugene Schwartz) — usado pelo conceito para mapear personas ↔ mensagens
const AWARENESS_COLOR = {
  1: '#94a3b8',  // Unaware
  2: '#ea580c',  // Problem-Aware
  3: '#d97706',  // Solution-Aware
  4: '#3859D0',  // Product-Aware
  5: '#059669',  // Most Aware
};
const AWARENESS_LABEL = {
  1: 'Unaware', 2: 'Problem', 3: 'Solution', 4: 'Product', 5: 'Most Aware',
};
const toAwarenessNum = (v) => {
  if (v == null) return null;
  if (typeof v === 'number') return v;
  const s = String(v).toLowerCase().trim();
  if (!s) return null;
  if (s.includes('unaware'))  return 1;
  if (s.includes('problem'))  return 2;
  if (s.includes('solution')) return 3;
  if (s.includes('product'))  return 4;
  if (s.includes('most'))     return 5;
  const n = parseInt(s, 10);
  return isNaN(n) ? null : n;
};
const StageBadge = ({ stage, n }) => {
  const s = n || stage;
  if (!s) return null;
  const num   = typeof s === 'number' ? s : toAwarenessNum(s);
  const label = AWARENESS_LABEL[num] || String(s);
  const color = AWARENESS_COLOR[num] || '#94a3b8';
  return (
    <span style={{
      fontSize: 9, fontWeight: 700, padding: '2px 7px', borderRadius: 99,
      background: color + '15', color, border: `1px solid ${color}30`,
      fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.04em', whiteSpace: 'nowrap', flexShrink: 0,
    }}>{label}</span>
  );
};

// Fundação Criativa — 4 campos base do conceito (colunas em conteudo_campanhas)
const BASE_FIELDS_CFG = [
  { key: 'big_idea',       label: 'Big Idea',        desc: 'Ideia central em uma frase',            color: '#3859D0' },
  { key: 'posicionamento', label: 'Posicionamento',  desc: 'Como a marca/produto é percebido',       color: '#7C3AED' },
  { key: 'narrativa',      label: 'Narrativa',       desc: 'História que sustenta a campanha',       color: '#0EA5E9' },
  { key: 'tom_campanha',   label: 'Tom da Campanha', desc: 'Registo comunicacional',                 color: '#059669' },
];

// CONCEITO_STEPS definido no topo do ficheiro (junto ao PhaseLoadingState) —
// steps alinhados com o novo fluxo (fase 2) e filosofia B2B (integração 3-fases).

// Steps do generate-copy (SSE) — alinhados com endpoint marketing-dev-server.js:6642+
const COPY_STEPS = [
  { step: 1, label: 'Ler conceito',          duration: 3000 },
  { step: 2, label: 'Analisar plano',        duration: 3000 },
  { step: 3, label: 'Escrever orgânico',     duration: 15000 },
  { step: 4, label: 'Escrever performance',  duration: 10000 },
  { step: 5, label: 'Guardar copy',          duration: 3000 },
];

// Labels de canais (fallback quando CHAN_ABBR não cobre)
const CANAL_LABELS = {
  meta_ads: 'Meta Ads', linkedin_ads: 'LinkedIn Ads', google_ads_search: 'Google Search',
  google_ads_display: 'Google Display', email: 'Email', whatsapp: 'WhatsApp',
  website: 'Website', muppi_led: 'LED/Muppi',
  instagram: 'Instagram', facebook: 'Facebook', linkedin: 'LinkedIn', google_ads: 'Google Ads',
  site: 'Blog', led: 'LED', tiktok: 'TikTok', youtube: 'YouTube', social: 'Social',
  ads: 'Ads',
  email_interno: 'Email Interno', whatsapp_interno: 'WhatsApp Interno',
  portal_notificacao: 'Portal · Notificação',
};
const CANAL_COLORS = {
  meta_ads: '#0866FF', facebook: '#1877F2', instagram: '#E4405F', linkedin: '#0A66C2',
  linkedin_ads: '#0A66C2', google_ads: '#4285F4', google_ads_search: '#4285F4',
  google_ads_display: '#4285F4', youtube: '#FF0000', tiktok: '#000000',
  email: '#059669', whatsapp: '#25D366', website: '#3859D0', site: '#3859D0',
  muppi_led: '#F59E0B', led: '#F59E0B', social: '#8B5CF6', ads: '#0EA5E9',
  email_interno: '#059669', whatsapp_interno: '#25D366', portal_notificacao: '#3859D0',
};

// Bloco expansível — usado ao longo de várias tabs
const CollapsBlock = ({ title, subtitle, count, defaultOpen = false, accentColor = '#3859D0', children }) => {
  const [open, setOpen] = React.useState(!!defaultOpen);
  return (
    <div style={{ background: '#fff', border: '1px solid var(--border, #e2e8f0)', borderLeft: `3px solid ${accentColor}`, borderRadius: '0 10px 10px 0', overflow: 'hidden' }}>
      <button onClick={() => setOpen(o => !o)} style={{
        width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        background: 'transparent', border: 'none', padding: '12px 18px', cursor: 'pointer',
        fontFamily: 'inherit', color: 'inherit', textAlign: 'left',
      }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, flex: 1, minWidth: 0 }}>
          <span style={{ fontSize: 12, fontWeight: 700, color: accentColor, textTransform: 'uppercase', letterSpacing: '0.06em', fontFamily: 'var(--font-mono, monospace)' }}>{title}</span>
          {count    && <span style={{ fontSize: 10, fontWeight: 600, padding: '1px 8px', borderRadius: 99, background: `${accentColor}15`, color: accentColor, fontFamily: 'var(--font-mono, monospace)' }}>{count}</span>}
          {subtitle && <span style={{ fontSize: 11, color: 'var(--text-muted, #64748b)', fontStyle: 'italic' }}>{subtitle}</span>}
        </div>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={accentColor} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ transform: open ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 150ms', flexShrink: 0 }}>
          <polyline points="9 18 15 12 9 6"/>
        </svg>
      </button>
      {open && <div>{children}</div>}
    </div>
  );
};

// Timeline vertical simples — usada por CollapsBlock "Plano de Comunicação"
const CommPlanTimeline = ({ items = [], timelineStart = null }) => {
  if (!items.length) return null;
  const fmtDate = (d) => { try { return new Date(d).toLocaleDateString('pt-PT', { day: '2-digit', month: 'short' }); } catch { return d; } };
  return (
    <div style={{ padding: '10px 18px 18px' }}>
      {timelineStart && (
        <div style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'var(--font-mono, monospace)', marginBottom: 8 }}>
          Arranque: {fmtDate(timelineStart)}
        </div>
      )}
      <div style={{ borderLeft: '2px solid #e2e8f0', paddingLeft: 14, display: 'flex', flexDirection: 'column', gap: 12 }}>
        {items.map((it, i) => {
          const canal = it.canal || it.channel || '—';
          const label = CANAL_LABELS[canal] || canal;
          const col   = CANAL_COLORS[canal] || '#3859D0';
          const when  = it.planned_date || it.planned_week || it.data || null;
          return (
            <div key={i} style={{ position: 'relative' }}>
              <div style={{ position: 'absolute', left: -21, top: 4, width: 10, height: 10, borderRadius: '50%', background: col, border: '2px solid #fff' }} />
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 3 }}>
                <span style={{ fontSize: 11, fontWeight: 700, color: col, fontFamily: 'var(--font-mono, monospace)' }}>{label}</span>
                {when && <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'var(--font-mono, monospace)' }}>{fmtDate(when)}</span>}
                {it.content_type && <span style={{ fontSize: 10, color: '#94a3b8' }}>· {it.content_type}</span>}
              </div>
              {(it.titulo || it.title || it.hook) && (
                <div style={{ fontSize: 12, color: '#1d2e38', lineHeight: 1.4 }}>{it.titulo || it.title || it.hook}</div>
              )}
              {it.copy_resumo && (
                <div style={{ fontSize: 11, color: '#64748b', marginTop: 3, lineHeight: 1.4, fontStyle: 'italic' }}>{it.copy_resumo}</div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
};

const TabConceitoFull = ({ campanha, onAction, generating, conceitoStep = 0, conceitoMsg = '', scheduleStep = 0, scheduleMsg = '', scheduleResult = null }) => {
  const hasConceito    = !!(campanha?.big_idea);
  // Conceito considerado aprovado quando a campanha já passou desta fase (fluxo novo + legado)
  const isApproved     = [
    // Fluxo novo (pós-conceito)
    'orcamento_pendente','orcamento_gerado','orcamento_aprovado',
    'segmentacao_pendente','segmentacao_gerada','segmentacao_aprovada',
    'planeamento_pendente','planeamento_aprovado',
    'funil_pendente','funil_revisto',
    'pending_executive','em_aprovacao',
    // Legado (compat)
    'canais_pendente','canais_gerado','canais_aprovado',
    'copy_pendente','copy_gerado','copy_aprovado',
    'prompts_pendente','prompts_gerado','prompts_aprovado',
    'em_producao','publicado','concluida'
  ].includes(campanha?.status);
  const proposta       = campanha?.proposta_json || {};

  // ── Variantes por mercado (multi-country execution) ──
  const variants       = Array.isArray(proposta.variants_by_market) ? proposta.variants_by_market : [];
  const primaryVariant = variants.find(v => v.is_primary) || variants[0] || null;
  const [activeMarket, setActiveMarket] = React.useState(primaryVariant?.country || null);
  React.useEffect(() => {
    if (primaryVariant?.country && !variants.find(v => v.country === activeMarket)) {
      setActiveMarket(primaryVariant.country);
    }
  }, [primaryVariant?.country, variants.length]);
  const activeVariant  = variants.find(v => v.country === activeMarket) || primaryVariant;
  const useLocal       = variants.length > 1 && activeVariant && !activeVariant.is_primary;

  const allPersonas    = proposta.personas || (proposta.persona_principal ? [proposta.persona_principal] : []);
  const personasPool   = allPersonas.filter(p => p.nome || p.perfil);
  // Match tolerante: normaliza (lower + sem acentos) + compara as primeiras 2 palavras.
  // Resolve "Director de Produção" (PT) ↔ "Director de Producción" (ES) ↔ "Directeur de Production" (FR)
  const _norm2 = s => (s||'').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').split(/[^a-z0-9]+/).filter(Boolean).slice(0,2).join(' ');
  const priorityNames  = Array.isArray(activeVariant?.personas_priorizadas_local) ? activeVariant.personas_priorizadas_local : null;
  const personas = priorityNames && priorityNames.length
    ? priorityNames.map(name => {
        const target = _norm2(name);
        return personasPool.find(p => _norm2(p.nome) === target) || null;
      }).filter(Boolean).concat(
        personasPool.filter(p => !priorityNames.some(n => _norm2(n) === _norm2(p.nome)))
      )
    : personasPool;
  const msgAngles      = useLocal && activeVariant.messaging_angles_local ? activeVariant.messaging_angles_local : (proposta.messaging_angles || []);
  const hooks          = useLocal && activeVariant.hooks_local              ? activeVariant.hooks_local           : (proposta.hooks || null);
  const visualFormats  = proposta.visual_formats_recomendados || null;
  const commPlan       = useLocal && activeVariant.comm_plan_local          ? activeVariant.comm_plan_local       : (proposta.comm_plan || []);
  const adCopy         = useLocal && activeVariant.ad_copy_local            ? activeVariant.ad_copy_local         : (proposta.ad_copy || null);
  const imagePrompts   = proposta.image_prompts || [];
  const videoPrompts   = proposta.video_prompts || [];
  const narrativaProp  = useLocal && activeVariant.narrativa_estrategica_local ? activeVariant.narrativa_estrategica_local : (proposta.narrativa_proposta || null);
  const keyMessage     = useLocal && activeVariant.key_message_local        ? activeVariant.key_message_local     : (proposta.key_message || null);
  const tomLocal       = activeVariant ? (activeVariant.tom_local || proposta.tom_campanha) : proposta.tom_campanha;
  const anchorType     = proposta.anchor_type || null;
  const campanhaAnuncios = proposta.campanha_anuncios || null; // legado — mantido para compat mas não renderizado
  const abordagemCanal   = proposta.abordagem_por_canal || null;
  const needsUpgrade   = hasConceito && msgAngles.length === 0;

  // ── Timer de progresso por step ──
  const stepStartRef    = React.useRef(null);
  const [stepPct, setStepPct] = React.useState(0);
  // Elapsed timer — obrigatório antes de qualquer early return (Rules of Hooks)
  const [conceitoElapsed, setConceitoElapsed] = React.useState(0);
  const conceitoElapsedRef = React.useRef(null);

  React.useEffect(() => {
    if (!generating.conceito || conceitoStep <= 0) { setStepPct(0); return; }
    stepStartRef.current = Date.now();
    setStepPct(0);
  }, [conceitoStep]);

  React.useEffect(() => {
    if (generating.conceito) {
      setConceitoElapsed(0);
      conceitoElapsedRef.current = setInterval(() => setConceitoElapsed(s => s + 1), 1000);
    } else {
      clearInterval(conceitoElapsedRef.current);
      setConceitoElapsed(0);
    }
    return () => clearInterval(conceitoElapsedRef.current);
  }, [generating.conceito]);

  React.useEffect(() => {
    if (!generating.conceito || conceitoStep <= 0) return;
    const def = CONCEITO_STEPS.find(s => s.step === conceitoStep);
    if (!def?.duration) return;
    const iv = setInterval(() => {
      const elapsed = Date.now() - (stepStartRef.current || Date.now());
      setStepPct(Math.min((elapsed / def.duration) * 90, 90));
    }, 80);
    return () => clearInterval(iv);
  }, [conceitoStep, generating.conceito]);

  const totalSteps   = CONCEITO_STEPS.length;
  const doneSteps    = CONCEITO_STEPS.filter(s => s.step < conceitoStep).length;
  const overallPct   = Math.round(((doneSteps + stepPct / 100) / totalSteps) * 100);

  // ── Loading state — ANTES do empty state check ──
  if (generating.conceito) {
    const fmtEl = (s) => s < 60 ? `${s}s` : `${Math.floor(s/60)}m${String(s%60).padStart(2,'0')}s`;
    const bChannels = campanha?.briefing?.channels || [];
    const PERF_SET  = new Set(['meta_ads','linkedin_ads','google_ads_search','google_ads_display','muppi_led']);
    const hasMeta_  = bChannels.includes('meta_ads');
    const hasWA_    = bChannels.includes('whatsapp');
    const hasEmail_ = bChannels.includes('email');
    const nUsps_    = (campanha?.briefing?.usps || []).length;
    const nDores_   = (campanha?.briefing?.pain_points || []).length;
    const nObj_     = (campanha?.briefing?.objections || []).length;
    const ISO = { portugal:'PT', espanha:'ES', españa:'ES', france:'FR', germany:'DE', 'united kingdom':'UK', netherlands:'NL' };
    const mkts_ = (campanha?.briefing?.geo_markets || []).map(m => ISO[String(m).toLowerCase().trim()] || String(m).slice(0,2).toUpperCase()).filter(Boolean);
    const mktsStr = mkts_.length ? mkts_.join('+') : 'PT';
    const chStr_  = bChannels.filter(ch => !PERF_SET.has(ch)).map(ch => CANAL_LABELS[ch] || ch).join(' · ') || 'canais';

    const SECTIONS = [
      { label: 'Estratégia Criativa',     detail: 'Big Idea · Posicionamento · Narrativa · Tom',                                              doneAfter: 3 },
      { label: 'Ângulos por USP',         detail: `${nUsps_ || '—'} ângulos · 1 por USP · cada um integra as 3 fases do funil`,               doneAfter: 4 },
      { label: 'Abordagem por Canal',     detail: bChannels.length ? bChannels.map(ch => CANAL_LABELS[ch]||ch).join(' · ') : 'por canal do briefing', doneAfter: 5 },
      hasEmail_ ? { label: 'Email',       detail: `Sequência: Kick Off + Reminders + Last Call · objectivo por email`,                        doneAfter: 5 } : null,
      hasMeta_  ? { label: 'Meta Ads',    detail: `Objectivo · abordagem criativa · formatos · nº anúncios previstos`,                        doneAfter: 5 } : null,
      hasWA_    ? { label: 'WhatsApp',    detail: `Tipo (outbound/inbound) · Digi AI · tom conversacional`,                                    doneAfter: 5 } : null,
      { label: 'Cronograma Orgânico',     detail: `comm_plan por semana — passa depois para Planeamento`,                                     doneAfter: 6 },
      { label: 'Variantes por Mercado',   detail: `${mktsStr} · reinterpretação idiomática (não tradução) · tom cultural local`,             doneAfter: 8 },
    ].filter(Boolean);

    const ConceitoDot = ({ done, active }) => {
      if (done) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', background: 'rgba(21,128,61,.12)', border: '1.5px solid rgba(21,128,61,.3)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="8" height="8" viewBox="0 0 10 10" fill="none"><polyline points="1.5,5 4,7.5 8.5,2.5" stroke="#15803d" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
      );
      if (active) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid #5B43C5', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', animation: 'espin 1.4s linear infinite' }}>
          <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#5B43C5' }} />
        </div>
      );
      return <div style={{ width: 16, height: 16, borderRadius: '50%', border: '1.5px solid #e2e8f0', flexShrink: 0 }} />;
    };

    return (
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderRadius: 10, padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <style>{`
          @keyframes cpulse { 0%,100%{opacity:1} 50%{opacity:.25} }
          @keyframes espin  { 0%{box-shadow:0 -5px 0 #5B43C5} 25%{box-shadow:5px 0 0 #5B43C5} 50%{box-shadow:0 5px 0 #5B43C5} 75%{box-shadow:-5px 0 0 #5B43C5} 100%{box-shadow:0 -5px 0 #5B43C5} }
        `}</style>
        {/* Aviso */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: '#fffbeb', border: '1px solid #fde68a', borderRadius: 6 }}>
          <span style={{ fontSize: 13 }}>⚠</span>
          <span style={{ fontSize: 12, color: '#92400e', fontWeight: 500 }}>Não feches esta janela nem saias deste ecrã — a geração está em curso.</span>
        </div>
        {/* Barra de progresso + timer */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ flex: 1, height: 5, borderRadius: 99, background: 'var(--bg-app,#f5f6f8)', overflow: 'hidden' }}>
            <div style={{ height: '100%', borderRadius: 99, background: 'linear-gradient(90deg,#5B43C5,#7c6de0)', width: `${overallPct}%`, transition: 'width 0.15s linear' }} />
          </div>
          <span style={{ fontSize: 11, fontWeight: 700, color: '#5B43C5', fontFamily: 'monospace', flexShrink: 0, minWidth: 32 }}>{overallPct}%</span>
          <span style={{ fontSize: 11, fontWeight: 600, color: '#94a3b8', fontFamily: 'monospace', flexShrink: 0, minWidth: 36 }}>{fmtEl(conceitoElapsed)}</span>
        </div>
        {/* Tabela de secções */}
        <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
          <colgroup><col style={{ width: 28 }} /><col style={{ width: 220 }} /><col /></colgroup>
          <thead>
            <tr>
              <th style={{ padding: '4px 8px 4px 0', fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', textAlign: 'left' }} />
              <th style={{ padding: '4px 8px', fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', textAlign: 'left' }}>SECÇÃO</th>
              <th style={{ padding: '4px 8px', fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', textAlign: 'left' }}>DETALHE</th>
            </tr>
          </thead>
          <tbody>
            {SECTIONS.map((sec, idx) => {
              const done   = conceitoStep > sec.doneAfter;
              const active = !done && conceitoStep >= (idx === 0 ? 3 : SECTIONS[idx-1]?.doneAfter || 3);
              return (
                <tr key={idx} style={{ borderBottom: '1px solid #f1f5f9', background: active ? 'rgba(91,67,197,.02)' : 'transparent' }}>
                  <td style={{ padding: '8px 8px 8px 0', verticalAlign: 'middle' }}><ConceitoDot done={done} active={active} /></td>
                  <td style={{ padding: '8px', verticalAlign: 'middle' }}>
                    <span style={{ fontSize: 13, fontWeight: active ? 700 : done ? 500 : 400, color: done ? '#374151' : active ? 'var(--text,#1d2e38)' : '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>{sec.label}</span>
                  </td>
                  <td style={{ padding: '8px', verticalAlign: 'middle' }}>
                    <span style={{ fontSize: 12, color: active ? '#64748b' : done ? '#64748b' : '#cbd5e1', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>{sec.detail}</span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }

  if (!hasConceito) return (
    <PhaseEmptyState
      label="Conceito · fase 2"
      title="Ainda sem conceito criativo"
      description="Direcção criativa gerada a partir do briefing aprovado (USPs, dores, motivadores, tom, key_message, restrições) e da estratégia. Produz big idea unificada e ângulos criativos por USP — cada ângulo cobre as 3 fases do funil (awareness · consideration · decision) na mesma peça, seguindo a filosofia B2B Digidelta. Serve depois de base para a Produção de Conteúdos (várias peças por USP × canais aprovados)."
      ctaLabel="Gerar Conceito →"
      onCta={() => onAction('generateConceito')}
      loading={!!generating.conceito}
    />
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>

      {/* Header status + actions — padrão consistente com Estratégia */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', background: 'var(--bg-surface,#fff)', borderRadius: 'var(--radius-md,8px)', boxShadow: 'var(--shadow-card)' }}>
        <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', padding: '3px 8px', borderRadius: 'var(--radius-xs,4px)', background: isApproved ? 'var(--green-100,#E1F7E6)' : 'var(--dd-blue-100,#EBEFF9)', color: isApproved ? 'var(--green-700,#1F8A52)' : 'var(--dd-primary-600,#3859D0)' }}>
          {isApproved ? 'Aprovado' : 'Gerado — aguarda aprovação'}
        </span>
        <span style={{ fontSize: 11, color: 'var(--fg-3, var(--text-muted))' }}>
          {msgAngles.length} ângulo{msgAngles.length !== 1 ? 's' : ''} · {personas.length} persona{personas.length !== 1 ? 's' : ''}
          {variants.length > 1 && ` · ${variants.length} mercados`}
          {campanha?.conceito_generated_at && ` · gerado ${new Date(campanha.conceito_generated_at).toLocaleString('pt-PT')}`}
          {campanha?.conceito_manually_edited_at && ` · editado ${new Date(campanha.conceito_manually_edited_at).toLocaleDateString('pt-PT')}`}
        </span>
        {isApproved && campanha?.conceito_approved_at && (
          <span style={{ fontSize: 11, color: 'var(--green-700, #1F8A52)' }}>
            · aprovada {new Date(campanha.conceito_approved_at).toLocaleString('pt-PT')}{campanha.conceito_approved_by ? ` por ${String(campanha.conceito_approved_by).split('@')[0]}` : ''}
          </span>
        )}
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 6, alignItems: 'center' }}>
          <button
            onClick={() => onAction && onAction('generateConceito')}
            disabled={!!generating.conceito}
            className="btn"
            style={{ height: 28, padding: '0 12px', fontSize: 12 }}
            title="Regenerar conceito — invalida a aprovação"
          >Regenerar</button>
          {!isApproved && (
            <button onClick={() => onAction && onAction('aprovarConceito')} disabled={!!generating.approve} className="btn btn-ai" style={{ height: 28, padding: '0 14px', fontSize: 12 }}>
              Aprovar Conceito
            </button>
          )}
        </div>
      </div>

      {/* ── Chip picker por mercado (só quando há > 1 variante) ── */}
      {variants.length > 1 && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', background: '#fff', border: '1px solid #ECEFF5', borderRadius: 10, boxShadow: 'var(--shadow-card, 0 1px 2px rgba(15,23,42,0.04))' }}>
          <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--fg-3,#64748b)', fontFamily: 'var(--font-mono, monospace)' }}>Mercado</span>
          <div style={{ display: 'flex', gap: 6 }}>
            {variants.map(v => {
              const active = v.country === activeMarket;
              return (
                <button
                  key={v.country}
                  onClick={() => setActiveMarket(v.country)}
                  style={{
                    padding: '5px 12px', borderRadius: 999,
                    border: `1px solid ${active ? 'var(--dd-primary-600,#3859D0)' : '#ECEFF5'}`,
                    background: active ? 'var(--dd-primary-600,#3859D0)' : '#fff',
                    color: active ? '#fff' : 'var(--text,#1d2e38)',
                    fontSize: 12, fontWeight: 600, cursor: 'pointer',
                    fontFamily: 'var(--font-body, Inter, sans-serif)',
                    display: 'flex', alignItems: 'center', gap: 6,
                  }}
                >
                  {v.country}
                  {v.is_primary && (
                    <span style={{ fontSize: 9, fontWeight: 700, padding: '1px 5px', borderRadius: 3, background: active ? 'rgba(255,255,255,.2)' : 'rgba(56,89,208,.1)', color: active ? '#fff' : 'var(--dd-primary-600,#3859D0)', letterSpacing: '0.05em' }}>PRIMÁRIO</span>
                  )}
                </button>
              );
            })}
          </div>
          <span style={{ marginLeft: 'auto', fontSize: 11, color: 'var(--fg-3,#64748b)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
            Big idea, posicionamento e narrativa são cross-market. Tom, key message, ângulos, hooks, copy e plano adaptam-se ao mercado seleccionado.
          </span>
        </div>
      )}

      {/* ── Banner de aprovação ── */}
      {isApproved && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 18px', background: 'rgba(21,128,61,.06)', border: '1px solid rgba(21,128,61,.25)', borderRadius: 10 }}>
          <div style={{ width: 32, height: 32, borderRadius: '50%', background: 'rgba(21,128,61,.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#15803d" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: '#15803d', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Conceito aprovado</div>
            <div style={{ fontSize: 11, color: '#166534', fontFamily: 'var(--font-body, Inter, sans-serif)', marginTop: 1 }}>A estratégia criativa está confirmada. Avança para o setup de canais.</div>
          </div>
        </div>
      )}

      {/* ── Upgrade banner ── */}
      {needsUpgrade && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '12px 16px', background: '#fffbeb', border: '1px solid #fde68a', borderRadius: 10 }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#d97706" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: '#92400e', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Conceito incompleto — regeneração necessária</div>
            <div style={{ fontSize: 11, color: '#b45309', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Faltam: personas, ângulos de mensagem, hooks, estrutura de anúncios pagos e plano de comunicação orgânico.</div>
          </div>
          <button onClick={() => onAction('generateConceito')} disabled={generating.conceito} className="btn" style={{ fontSize: 11, color: '#92400e', borderColor: '#fde68a', background: '#fef3c7', whiteSpace: 'nowrap', flexShrink: 0 }}>
            {generating.conceito ? 'A gerar...' : 'Actualizar estratégia'}
          </button>
        </div>
      )}

      {/* ── 0. Mensagem-chave — hero FormCard ── */}
      {keyMessage && (
        <div style={{ background: '#fff', border: '1px solid rgba(56,89,208,.25)', borderLeft: '4px solid var(--ai-500, #3859D0)', borderRadius: '0 10px 10px 0', padding: '20px 24px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
            <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--ai-500, #3859D0)', fontFamily: 'var(--font-mono, monospace)' }}>Mensagem-chave</span>
            {useLocal && (
              <span style={{ fontSize: 9, fontWeight: 700, padding: '2px 8px', borderRadius: 99, background: 'rgba(56,89,208,.1)', color: 'var(--dd-primary-600,#3859D0)', fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.05em' }}>
                {activeMarket} · LOCAL
              </span>
            )}
            {anchorType && (
              <span style={{ fontSize: 9, fontWeight: 700, padding: '2px 8px', borderRadius: 99, background: anchorType === 'pain' ? 'rgba(220,38,38,.1)' : 'rgba(16,185,129,.1)', color: anchorType === 'pain' ? '#dc2626' : '#059669', fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.05em' }}>
                {anchorType === 'pain' ? 'PAIN ANCHOR' : 'DESIRE ANCHOR'}
              </span>
            )}
          </div>
          <p style={{ margin: 0, fontSize: 16, fontWeight: 600, color: 'var(--text, #1d2e38)', lineHeight: 1.55, fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>{keyMessage}</p>
        </div>
      )}

      {/* ── 1. Ângulos de Mensagem — FormCard wrapper ── */}
      {msgAngles.length > 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--border, #e2e8f0)', borderRadius: 10, padding: '20px 24px' }}>
          {/* Título secção */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, paddingBottom: 14, borderBottom: '1px solid var(--border, #e2e8f0)', marginBottom: 18 }}>
            <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-mono, monospace)' }}>Ângulos de Mensagem</span>
            <span style={{ fontSize: 9, fontWeight: 700, background: 'rgba(0,0,0,.05)', borderRadius: 99, padding: '1px 7px', color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-mono, monospace)' }}>{msgAngles.length}</span>
          </div>
          {/* Cards — sem stripe no topo, border completo */}
          <div style={{ display: 'grid', gridTemplateColumns: msgAngles.length === 1 ? '1fr' : 'repeat(auto-fit, minmax(320px, 1fr))', gap: 14 }}>
            {msgAngles.map((a, i) => {
              const stg = toAwarenessNum(a.awareness_stage) || a.awareness_stage;
              const stgColor = AWARENESS_COLOR[stg] || '#94a3b8';
              return (
                <div key={i} style={{ background: 'var(--bg-app, #F5F6F8)', border: '1px solid var(--border, #e2e8f0)', borderRadius: 10, padding: '16px 18px', display: 'flex', flexDirection: 'column', gap: 10 }}>
                  {/* Persona + Stage badge no mesmo row */}
                  <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 8 }}>
                    <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--text, #1d2e38)', fontFamily: 'var(--font-body, Inter, sans-serif)', lineHeight: 1.4 }}>{a.persona}</span>
                    <StageBadge stage={stg} />
                  </div>
                  {/* Quote */}
                  <p style={{ margin: 0, fontSize: 13, fontWeight: 600, color: 'var(--text, #1d2e38)', lineHeight: 1.55, fontStyle: 'italic', fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>"{a.angulo}"</p>
                  {/* Rationale */}
                  {a.rationale && <p style={{ margin: 0, fontSize: 11, color: 'var(--text-muted, #64748b)', lineHeight: 1.6, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{a.rationale}</p>}
                  {/* Objecções — destaque âmbar */}
                  {a.objections && a.objections.length > 0 && (
                    <div style={{ background: 'rgba(245,158,11,.06)', border: '1px solid rgba(245,158,11,.2)', borderRadius: 7, padding: '10px 12px', marginTop: 2 }}>
                      <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.06em', color: '#d97706', fontFamily: 'var(--font-mono, monospace)', marginBottom: 6 }}>⚠ Objecções a antecipar</div>
                      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                        {a.objections.map((obj, oi) => (
                          <div key={oi} style={{ fontSize: 11, color: 'var(--text-muted, #64748b)', lineHeight: 1.5, display: 'flex', gap: 6, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
                            <span style={{ color: '#d97706', flexShrink: 0 }}>—</span>{obj}
                          </div>
                        ))}
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* ── 2. Personas — FormCard wrapper ── */}
      {personas.length > 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--border, #e2e8f0)', borderRadius: 10, padding: '20px 24px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, paddingBottom: 14, borderBottom: '1px solid var(--border, #e2e8f0)', marginBottom: 18 }}>
            <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-mono, monospace)' }}>Personas</span>
            <span style={{ fontSize: 9, fontWeight: 700, background: 'rgba(0,0,0,.05)', borderRadius: 99, padding: '1px 7px', color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-mono, monospace)' }}>{personas.length}</span>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 14 }}>
            {personas.map((p, i) => {
              const initials = ((p.nome || p.perfil || '?').split(' ').slice(0,2).map(w => w[0]).join('').toUpperCase()) || '?';
              return (
                <div key={i} style={{ background: 'var(--bg-app, #F5F6F8)', border: '1px solid var(--border, #e2e8f0)', borderRadius: 10, padding: '16px 18px', display: 'flex', flexDirection: 'column', gap: 10 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                    <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--ai-500, #3859D0)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                      <span style={{ fontSize: 12, fontWeight: 700, color: '#fff', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{initials}</span>
                    </div>
                    <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text, #1d2e38)', lineHeight: 1.3, fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>{p.nome || 'Persona ' + (i+1)}</span>
                  </div>
                  {p.perfil && <p style={{ margin: 0, fontSize: 11, color: 'var(--text-muted, #64748b)', lineHeight: 1.6, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{p.perfil}</p>}
                  {p.como_vive_a_dor && <div style={{ fontSize: 11, color: '#c2410c', lineHeight: 1.5, borderTop: '1px solid var(--border, #e2e8f0)', paddingTop: 8, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{p.como_vive_a_dor}</div>}
                  {p.deepest_desire && <div style={{ fontSize: 11, color: '#059669', lineHeight: 1.5, borderTop: '1px solid var(--border, #e2e8f0)', paddingTop: 8, fontFamily: 'var(--font-body, Inter, sans-serif)' }}><span style={{ fontWeight: 700 }}>Desejo: </span>{p.deepest_desire}</div>}
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* ── 3. Fundação Criativa — FormCard wrapper ── */}
      {BASE_FIELDS_CFG.some(f => campanha[f.key]) && (
        <div style={{ background: '#fff', border: '1px solid var(--border, #e2e8f0)', borderRadius: 10, padding: '20px 24px' }}>
          <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-mono, monospace)', paddingBottom: 14, borderBottom: '1px solid var(--border, #e2e8f0)', marginBottom: 18 }}>Fundação Criativa</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            {BASE_FIELDS_CFG.map(f => {
              const isTom = f.key === 'tom_campanha';
              const value = isTom ? tomLocal : campanha[f.key];
              if (!value) return null;
              const localBadge = isTom && useLocal;
              return (
                <div key={f.key} style={{ background: 'var(--bg-app, #F5F6F8)', borderLeft: `3px solid ${f.color}`, border: '1px solid var(--border, #e2e8f0)', borderRadius: '0 10px 10px 0', padding: '14px 16px' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
                    <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: f.color, fontFamily: 'var(--font-mono, monospace)' }}>{f.label}</div>
                    {localBadge && (
                      <span style={{ fontSize: 8, fontWeight: 700, padding: '1px 5px', borderRadius: 3, background: 'rgba(56,89,208,.1)', color: 'var(--dd-primary-600,#3859D0)', fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.05em' }}>{activeMarket}</span>
                    )}
                  </div>
                  <div style={{ fontSize: 9, color: 'var(--text-dim, #94a3b8)', fontFamily: 'var(--font-body, Inter, sans-serif)', marginBottom: 8 }}>{f.desc}</div>
                  <p style={{ margin: 0, fontSize: 12.5, color: 'var(--text, #1d2e38)', lineHeight: 1.65, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{value}</p>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* ── 4. Abordagem por Canal — direcção criativa por canal do briefing ── */}
      {(() => {
        const abordagem = proposta.abordagem_por_canal || null;
        // Backward compat: se ainda for do formato antigo (campanha_anuncios), tenta mostrar
        const canaisCfg = abordagem && Object.keys(abordagem).length > 0 ? abordagem : null;
        if (!canaisCfg) return null;
        return (
          <CollapsBlock title="Abordagem por Canal" count={Object.keys(canaisCfg).length + ' canais'} defaultOpen={true} accentColor="var(--ai-500, #3859D0)">
            <div style={{ padding: '0 18px 16px', display: 'flex', flexDirection: 'column', gap: 18 }}>
              {Object.entries(canaisCfg).map(([ch, cfg]) => {
                const col = CANAL_COLORS[ch] || 'var(--ai-500, #3859D0)';
                const label = CANAL_LABELS[ch] || CANAL_LABEL[ch] || ch;
                const isEmail = ch === 'email';
                const isWebsite = ch === 'website';
                const isWA = ch === 'whatsapp';
                return (
                  <div key={ch} style={{ paddingTop: 14, borderTop: '1px solid var(--border-light, #f0f2f7)' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                      <div style={{ width: 10, height: 10, borderRadius: '50%', background: col, flexShrink: 0 }} />
                      <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text, #1d2e38)', fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>{label}</span>
                      {cfg.objectivo && (
                        <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 99, background: col + '14', color: col, fontFamily: 'var(--font-mono)', fontWeight: 600 }}>
                          {cfg.objectivo}
                        </span>
                      )}
                      {cfg.n_ads_previstos && (
                        <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 99, background: 'var(--bg-sunken)', color: 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>
                          {cfg.n_ads_previstos} anúncios
                        </span>
                      )}
                      {isWebsite && cfg.n_artigos && (
                        <span style={{ fontSize: 10, padding: '2px 7px', borderRadius: 99, background: 'var(--bg-sunken)', color: 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>
                          {cfg.n_artigos} artigos
                        </span>
                      )}
                    </div>

                    {/* Email — sequência */}
                    {isEmail && Array.isArray(cfg.sequencia) && cfg.sequencia.length > 0 && (
                      <div style={{ marginLeft: 18, marginBottom: 10 }}>
                        {cfg.sequencia.map((eml, i) => (
                          <div key={i} style={{ display: 'flex', gap: 10, alignItems: 'flex-start', padding: '8px 12px', marginBottom: 5, background: 'var(--bg-sunken)', borderRadius: 6, borderLeft: `3px solid ${col}` }}>
                            <span style={{ fontSize: 10, fontWeight: 700, padding: '2px 7px', borderRadius: 4, background: col + '18', color: col, fontFamily: 'var(--font-mono)', textTransform: 'uppercase', flexShrink: 0 }}>
                              {(eml.tipo || '').replace('_',' ')}{eml.n && eml.n > 1 ? ` ×${eml.n}` : ''}
                            </span>
                            <span style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.5 }}>{eml.objectivo}</span>
                          </div>
                        ))}
                      </div>
                    )}

                    {/* Website — página produto + tipo */}
                    {isWebsite && (
                      <div style={{ marginLeft: 18, marginBottom: 10, padding: '10px 14px', background: 'var(--bg-sunken)', borderRadius: 8, borderLeft: `3px solid ${col}` }}>
                        {cfg.tipo && <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text)', marginBottom: 4 }}>Tipo: {cfg.tipo}</div>}
                        {cfg.produto_pagina_ref && (
                          <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Página produto: <a href={cfg.produto_pagina_ref} target="_blank" rel="noreferrer" style={{ color: col }}>{cfg.produto_pagina_ref}</a></div>
                        )}
                      </div>
                    )}

                    {/* WhatsApp — tipo */}
                    {isWA && cfg.tipo && (
                      <div style={{ marginLeft: 18, marginBottom: 8, fontSize: 11, color: 'var(--text-muted)' }}>
                        Tipo: <strong style={{ color: 'var(--text)' }}>{cfg.tipo}</strong>
                      </div>
                    )}

                    {/* Formatos (canais Ads) */}
                    {Array.isArray(cfg.formatos) && cfg.formatos.length > 0 && (
                      <div style={{ marginLeft: 18, marginBottom: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                        {cfg.formatos.map((f, i) => (
                          <span key={i} style={{ fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99, background: col + '10', color: col, fontFamily: 'var(--font-mono)' }}>{f}</span>
                        ))}
                      </div>
                    )}

                    {/* Abordagem criativa */}
                    {cfg.abordagem_criativa && (
                      <div style={{ marginLeft: 18, marginBottom: 6, fontSize: 12, color: 'var(--text)', lineHeight: 1.55 }}>
                        {cfg.abordagem_criativa}
                      </div>
                    )}

                    {/* Notas */}
                    {cfg.notas && (
                      <div style={{ marginLeft: 18, fontSize: 11, color: 'var(--text-dim, #94a3b8)', fontStyle: 'italic', paddingLeft: 10, borderLeft: `2px solid ${col}30`, lineHeight: 1.5 }}>
                        {cfg.notas}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </CollapsBlock>
        );
      })()}

      {/* ── 5. Hooks por Canal ── */}
      {hooks && Object.keys(hooks).length > 0 && (
        <CollapsBlock title={'Hooks por Canal'} count={Object.keys(hooks).length + (Object.keys(hooks).length === 1 ? ' canal' : ' canais')} accentColor="#f59e0b">
          <div style={{ padding: '0 18px 16px', display: 'flex', flexDirection: 'column', gap: 16 }}>
            {Object.entries(hooks).map(([canal, hookList]) => {
              const vf = visualFormats && visualFormats[canal];
              return (
                <div key={canal} style={{ paddingTop: 14 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
                    <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--ai-500, #3859D0)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{CANAL_LABEL[canal] || canal}</div>
                    {vf && vf.length > 0 && (
                      <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
                        {vf.map((fmt, fi) => <span key={fi} style={{ fontSize: 9, padding: '1px 6px', borderRadius: 99, background: 'rgba(16,185,129,.1)', color: '#059669', fontWeight: 600, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{fmt}</span>)}
                      </div>
                    )}
                  </div>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
                    {(hookList || []).map((h, i) => {
                      const txt   = typeof h === 'object' ? h.texto : h;
                      const tipo  = typeof h === 'object' ? h.tipo  : null;
                      const stage = typeof h === 'object' ? (toAwarenessNum(h.target_stage) || h.target_stage) : null;
                      const stgColor = AWARENESS_COLOR[stage] || '#94a3b8';
                      return (
                        <div key={i} style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
                          <span style={{ fontSize: 9, fontWeight: 700, color: 'var(--text-dim, #94a3b8)', minWidth: 18, paddingTop: 2, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{i+1}.</span>
                          <div style={{ flex: 1 }}>
                            <div style={{ display: 'flex', gap: 6, marginBottom: 3, flexWrap: 'wrap' }}>
                              {tipo  && <span style={{ fontSize: 9, fontWeight: 700, color: 'var(--text-dim, #94a3b8)', textTransform: 'uppercase', letterSpacing: '0.06em', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{tipo}</span>}
                              {stage && <span style={{ fontSize: 9, fontWeight: 700, padding: '1px 6px', borderRadius: 99, background: stgColor + '18', color: stgColor, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>S{stage}</span>}
                            </div>
                            <span style={{ fontSize: 12, color: 'var(--text-muted, #64748b)', lineHeight: 1.55, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{txt}</span>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        </CollapsBlock>
      )}


      {/* ── 8. Narrativa Estratégica ── */}
      {narrativaProp && (
        <CollapsBlock title={useLocal ? `Narrativa Estratégica · ${activeMarket}` : 'Narrativa Estratégica'} subtitle="Para revisão RL / FC" accentColor="var(--ai-500, #3859D0)">
          <div style={{ padding: '18px 20px' }}>
            <div style={{ fontSize: 13, color: 'var(--text, #1d2e38)', lineHeight: 1.85, whiteSpace: 'pre-wrap', fontFamily: 'var(--font-body, Inter, sans-serif)', borderLeft: '3px solid var(--ai-500, #3859D0)', paddingLeft: 16 }}>{narrativaProp}</div>
          </div>
        </CollapsBlock>
      )}


    </div>
  );
};

// ── TabCopyFull (grid de canais) ───────────────────────────────────────────────
// ── TabIdiomas ─────────────────────────────────────────────────────────────────
const LANG_LABELS_UI = { pt: 'Português', es: 'Español', en: 'English', fr: 'Français', de: 'Deutsch', it: 'Italiano' };

const TabIdiomas = ({ campanha, idiomas, onAction, generating, idiomasStep = 0, idiomasMsg = '', idiomasTotal = 0, idiomasLangs = [] }) => {
  const [activeLang, setActiveLang] = React.useState(null);
  const [extraLang,  setExtraLang]  = React.useState('');
  const langs = [...new Set(idiomas.map(i => i.lingua))].filter(Boolean);

  React.useEffect(() => {
    if (langs.length > 0 && !activeLang) setActiveLang(langs[0]);
  }, [langs.length]);

  const hasIdiomas = idiomas.length > 0;
  const isGenerating = generating.idiomas;

  const overallPct = idiomasTotal > 0 ? Math.min(Math.round((idiomasStep / idiomasTotal) * 100), 99) : 0;

  // step 3+ = tradução por língua (índice = step - 3)
  const getLangStatus = (idx) => {
    const langStep = 3 + idx;
    if (idiomasStep > langStep) return 'done';
    if (idiomasStep === langStep) return 'active';
    return 'pending';
  };

  if (isGenerating) {
    const allCopy     = campanha?.copy || [];
    const orgCopy     = allCopy.filter(c => !c.copy_type || c.copy_type === 'organico');
    const perfCopy    = allCopy.filter(c => c.copy_type === 'performance');

    const getItemText = (cp) => {
      const t = cp.caption_organica || cp.headline || cp.item_title || '';
      return t.length > 80 ? t.slice(0, 80) + '…' : t;
    };

    const IDot = ({ done, active }) => {
      if (done) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', background: 'rgba(21,128,61,.12)', border: '1.5px solid rgba(21,128,61,.3)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="8" height="8" viewBox="0 0 10 10" fill="none"><polyline points="1.5,5 4,7.5 8.5,2.5" stroke="#15803d" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
      );
      if (active) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid #8b5cf6', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ width: 7, height: 7, borderRadius: '50%', background: '#8b5cf6', animation: 'cpulse 1s infinite' }} />
        </div>
      );
      return <div style={{ width: 16, height: 16, borderRadius: '50%', border: '1.5px solid #e2e8f0', flexShrink: 0 }} />;
    };

    const ItemsTable = ({ items, isOrg, langDone, langActive }) => {
      const TYPE_LABEL = { post:'Post', reel:'Reel', story:'Story', carrossel:'Carrossel', email:'Email', blog_post:'Blog', video:'Vídeo', rsa:'RSA', mensagem:'WA' };
      return (
        <div style={{ marginTop: 6 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
            <div style={{ width: 3, height: 12, borderRadius: 2, background: isOrg ? '#059669' : '#0ea5e9', flexShrink: 0 }} />
            <span style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.07em', color: isOrg ? '#059669' : '#0ea5e9', fontFamily: 'var(--font-mono,monospace)' }}>
              {isOrg ? 'Orgânico' : 'Performance'} · {items.length}
            </span>
          </div>
          <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
            <colgroup>
              <col style={{ width: 24 }} />
              <col style={{ width: 160 }} />
              <col style={{ width: 70 }} />
              <col />
            </colgroup>
            <thead>
              <tr style={{ background: 'var(--bg-app,#f5f6f8)', borderBottom: '1px solid var(--border,#e2e8f0)' }}>
                <th style={{ padding: '4px 4px' }} />
                <th style={{ padding: '4px 6px', textAlign: 'left', fontSize: 8, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Canal</th>
                <th style={{ padding: '4px 6px', textAlign: 'left', fontSize: 8, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Tipo</th>
                <th style={{ padding: '4px 6px', textAlign: 'left', fontSize: 8, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Conteúdo</th>
              </tr>
            </thead>
            <tbody>
              {items.map((cp, i) => {
                const text = getItemText(cp);
                const tc   = langDone ? '#374151' : langActive ? 'var(--text,#1d2e38)' : '#94a3b8';
                return (
                  <tr key={cp.id || i} style={{ borderBottom: '1px solid var(--border-light,#f8fafc)' }}>
                    <td style={{ padding: '5px 4px', verticalAlign: 'middle' }}><IDot done={langDone} active={langActive} /></td>
                    <td style={{ padding: '5px 6px', verticalAlign: 'middle' }}>
                      <span style={{ fontSize: 10, fontWeight: 700, padding: '1px 5px', borderRadius: 4, background: langDone ? 'rgba(21,128,61,.08)' : 'var(--bg-app,#f5f6f8)', color: langDone ? '#15803d' : '#64748b', fontFamily: 'monospace', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'block', maxWidth: 148 }}>
                        {CANAL_LABEL[cp.canal] || cp.canal}
                      </span>
                    </td>
                    <td style={{ padding: '5px 6px', verticalAlign: 'middle' }}>
                      <span style={{ fontSize: 9, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase' }}>
                        {TYPE_LABEL[cp.content_type] || cp.content_type || '—'}
                      </span>
                    </td>
                    <td style={{ padding: '5px 6px', verticalAlign: 'middle' }}>
                      <span style={{ fontSize: 11, color: tc, fontWeight: langActive ? 600 : 400, fontFamily: 'var(--font-body,Inter,sans-serif)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{text || '—'}</span>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      );
    };

    return (
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderRadius: 10, padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <style>{`@keyframes cpulse { 0%,100%{opacity:1} 50%{opacity:.25} }`}</style>

        {/* Barra de progresso compacta */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ flex: 1, height: 4, borderRadius: 99, background: 'var(--bg-app,#f5f6f8)', overflow: 'hidden' }}>
            <div style={{ height: '100%', borderRadius: 99, background: '#8b5cf6', width: `${overallPct}%`, transition: 'width 0.15s linear' }} />
          </div>
          <span style={{ fontSize: 11, fontWeight: 700, color: '#8b5cf6', fontFamily: 'monospace', flexShrink: 0 }}>{overallPct}%</span>
          <span style={{ fontSize: 11, color: '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)', flexShrink: 0 }}>{idiomasMsg || 'A traduzir…'}</span>
        </div>

        {/* Por idioma */}
        {idiomasLangs.map((lang, idx) => {
          const status    = getLangStatus(idx);
          const langDone  = status === 'done';
          const langActive = status === 'active';
          const color     = langDone ? '#15803d' : langActive ? '#8b5cf6' : '#94a3b8';
          const bgColor   = langDone ? 'rgba(21,128,61,.04)' : langActive ? 'rgba(139,92,246,.03)' : 'transparent';

          return (
            <div key={lang} style={{ border: `1px solid ${langDone ? 'rgba(21,128,61,.2)' : langActive ? 'rgba(139,92,246,.2)' : 'var(--border,#e2e8f0)'}`, borderRadius: 10, overflow: 'hidden', background: bgColor }}>
              {/* Header do idioma */}
              <div style={{ padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10 }}>
                <IDot done={langDone} active={langActive} />
                <span style={{ fontSize: 13, fontWeight: langActive ? 700 : 500, color, fontFamily: 'var(--font-display,Montserrat,sans-serif)', flex: 1 }}>
                  {LANG_LABELS_UI[lang] || lang.toUpperCase()}
                </span>
                {langDone && <span style={{ fontSize: 10, color: '#15803d', fontFamily: 'monospace' }}>{allCopy.length} traduzidos</span>}
                {langActive && <span style={{ fontSize: 10, color: '#8b5cf6', fontFamily: 'monospace' }}>a traduzir…</span>}
                {!langDone && !langActive && <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace' }}>{allCopy.length} pendentes</span>}
              </div>

              {/* Tabelas de items — só para idioma activo ou done */}
              {(langActive || langDone) && (
                <div style={{ padding: '0 14px 12px', borderTop: `1px solid ${langDone ? 'rgba(21,128,61,.15)' : 'rgba(139,92,246,.15)'}` }}>
                  {orgCopy.length > 0 && <ItemsTable items={orgCopy} isOrg={true} langDone={langDone} langActive={langActive} />}
                  {perfCopy.length > 0 && <ItemsTable items={perfCopy} isOrg={false} langDone={langDone} langActive={langActive} />}
                </div>
              )}
            </div>
          );
        })}
      </div>
    );
  }

  if (!hasIdiomas) {
    const GEO_LANG = {
      'espanha':'es','spain':'es','es':'es','españa':'es',
      'export':'en','global':'en','europa':'en','europe':'en','internacional':'en',
      'reino unido':'en','uk':'en','en':'en','inglês':'en',
      'france':'fr','fr':'fr','frança':'fr',
      'alemanha':'de','germany':'de','de':'de',
      'itália':'it','italy':'it','it':'it','italia':'it',
    };
    const geoMarkets = campanha?.briefing?.geo_markets || [];
    const geoExpanded = geoMarkets.flatMap(m => typeof m === 'string' ? m.split(/[\/,\-\+&]/).map(s => s.trim()) : [m]);
    const detectedLangs = [...new Set(
      geoExpanded.map(m => GEO_LANG[(m||'').toLowerCase().trim()]).filter(Boolean)
    )].filter(l => l !== 'pt');

    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '64px 0', gap: 20 }}>
        <div style={{ width: 56, height: 56, borderRadius: 14, background: 'rgba(139,92,246,.08)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#8b5cf6" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
          </svg>
        </div>
        <div style={{ textAlign: 'center', maxWidth: 440 }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text, #1d2e38)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', marginBottom: 8 }}>Traduções por gerar</div>
          {detectedLangs.length > 0 ? (
            <div style={{ fontSize: 13, color: 'var(--text-muted, #64748b)', lineHeight: 1.65, marginBottom: 8 }}>
              Com base no briefing, será gerado para:
              <div style={{ display: 'flex', gap: 6, justifyContent: 'center', marginTop: 10, flexWrap: 'wrap' }}>
                {detectedLangs.map(l => (
                  <span key={l} style={{ fontSize: 12, fontWeight: 600, padding: '4px 12px', borderRadius: 99, background: 'rgba(139,92,246,.1)', color: '#7c3aed', border: '1px solid rgba(139,92,246,.2)', fontFamily: 'Inter, sans-serif' }}>
                    {LANG_LABELS_UI[l] || l.toUpperCase()}
                  </span>
                ))}
              </div>
            </div>
          ) : (
            <div style={{ fontSize: 13, color: '#f59e0b', lineHeight: 1.65 }}>
              Sem idiomas alvo detectados no briefing (Bloco 1 — Mercados). Podes adicionar um idioma manualmente.
            </div>
          )}
        </div>
        <button onClick={() => onAction('generateIdiomas')} className="btn btn-ai" disabled={detectedLangs.length === 0} data-tutorial-step="idiomas">
          {detectedLangs.length > 0 ? 'Gerar Idiomas →' : '+ Adicionar idioma manualmente'}
        </button>
      </div>
    );
  }

  // ── Sprint 2: Tab layout with per-language content ────────────────────────────
  const [showAddLang, setShowAddLang] = React.useState(false);

  const allApproved = l => idiomas.filter(i => i.lingua === l).every(i => i.status === 'aprovado');
  const allLangs = ['pt', ...langs.filter(l => l !== 'pt')];
  React.useEffect(() => {
    if (!activeLang) setActiveLang('pt');
  }, []);

  const currentLangItems = activeLang === 'pt'
    ? (campanha?.copy || [])
    : idiomas.filter(i => i.lingua === activeLang);

  const langOrganic     = currentLangItems.filter(i => !i.copy_type || i.copy_type === 'organico');
  const langPerformance = currentLangItems.filter(i => i.copy_type === 'performance');

  const ctaForLang = (slug, l) => typeof window.ctaToText === 'function' ? window.ctaToText(slug, l) : (l === 'es' ? 'Más información' : 'Learn more');
  const offerIdi = campanha?.commercial_offer ? (typeof campanha.commercial_offer === 'string' ? (() => { try { return JSON.parse(campanha.commercial_offer); } catch { return null; } })() : campanha.commercial_offer) : null;
  const ctaSlugIdi = offerIdi?.primary_cta;

  const [expandedIdiomasRows, setExpandedIdiomasRows] = React.useState({});
  const [editingIdioma, setEditingIdioma]             = React.useState(null);
  const toggleIdiomasRow = (id) => setExpandedIdiomasRows(p => ({ ...p, [id]: !p[id] }));

  const thStIdi = { padding: '8px 12px', textAlign: 'left', fontSize: 10, fontWeight: 700, color: '#64748b', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.05em' };

  const IdiomaRow = ({ cp, lang }) => {
    const isExpanded = expandedIdiomasRows[cp.id];
    const bodyText   = cp.body || cp.caption_organica || '';
    const ctaVal     = cp.cta || ctaForLang(ctaSlugIdi, lang);
    return (
      <React.Fragment>
        <tr style={{ borderBottom: '1px solid var(--border,#e2e8f0)', cursor: 'pointer', background: isExpanded ? 'rgba(139,92,246,.02)' : 'transparent' }} onClick={() => toggleIdiomasRow(cp.id)}>
          <td style={{ padding: '10px 12px' }}>
            <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{CANAL_LABEL[cp.canal] || cp.canal}</span>
            {cp.content_type && <span style={{ fontSize: 9, color: '#94a3b8', marginLeft: 4, fontFamily: 'monospace', textTransform: 'uppercase' }}>{cp.content_type}</span>}
          </td>
          <td style={{ padding: '10px 12px', maxWidth: 200 }}>
            <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text,#1d2e38)', lineHeight: 1.3 }}>{cp.headline || '—'}</div>
          </td>
          <td style={{ padding: '10px 12px', maxWidth: 260 }}>
            <div style={{ fontSize: 12, color: 'var(--text-muted,#64748b)', lineHeight: 1.5 }}>
              {bodyText.slice(0, 100)}{bodyText.length > 100 ? '…' : ''}
            </div>
          </td>
          <td style={{ padding: '10px 12px' }}>
            <span style={{ fontSize: 11, fontWeight: 600, color: '#3859D0' }}>{ctaVal}</span>
          </td>
          <td style={{ padding: '10px 12px', minWidth: 90 }}>
            <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
              <button onClick={e => { e.stopPropagation(); onAction('regenerateIdioma', cp.id, lang); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Re-traduzir">⟳</button>
              <button onClick={e => { e.stopPropagation(); setEditingIdioma(cp); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Editar tradução">✏</button>
              <span style={{ fontSize: 11, color: '#94a3b8' }}>{isExpanded ? '▴' : '▾'}</span>
            </div>
          </td>
        </tr>
        {isExpanded && (
          <tr>
            <td colSpan={5} style={{ padding: '8px 12px 16px', background: 'rgba(139,92,246,.02)' }}>
              <div style={{ paddingTop: 10, borderTop: '1px solid var(--border-light,#f1f5f9)', display: 'flex', flexDirection: 'column', gap: 10 }}>
                {cp.copy_imagem && (
                  <div>
                    <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 4 }}>Texto Imagem</div>
                    <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text,#1d2e38)' }}>{cp.copy_imagem}</div>
                  </div>
                )}
                {bodyText && (
                  <div>
                    <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 4 }}>Tradução Completa</div>
                    <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', lineHeight: 1.7, whiteSpace: 'pre-wrap', background: 'var(--bg-app,#f5f6f8)', borderRadius: 8, padding: '10px 14px' }}>{bodyText}</div>
                  </div>
                )}
              </div>
            </td>
          </tr>
        )}
      </React.Fragment>
    );
  };

  const renderIdiomaSection = (items, isOrganic, lang) => {
    if (!items.length) return null;
    const accentColor = isOrganic ? '#059669' : '#0ea5e9';
    const label       = isOrganic ? 'Orgânico · Plano de Comunicação' : 'Performance · Anúncios Pagos';
    const countLabel  = isOrganic ? `${items.length} peças` : `${items.length} ads`;
    return (
      <CollapsBlock key={isOrganic ? 'org' : 'perf'} title={label} count={countLabel} defaultOpen={true} accentColor={accentColor}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr style={{ background: 'var(--bg-app,#f5f6f8)' }}>
              <th style={thStIdi}>Canal</th>
              <th style={thStIdi}>Headline</th>
              <th style={thStIdi}>Copy</th>
              <th style={thStIdi}>CTA</th>
              <th style={thStIdi}>Acções</th>
            </tr>
          </thead>
          <tbody>
            {items.map(cp => <IdiomaRow key={cp.id} cp={cp} lang={lang} />)}
          </tbody>
        </table>
      </CollapsBlock>
    );
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* Tabs por idioma */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 4, borderBottom: '2px solid var(--border,#e2e8f0)', marginBottom: 4, flexWrap: 'wrap', position: 'relative' }}>
        {allLangs.map(l => (
          <button key={l} onClick={() => setActiveLang(l)} style={{
            padding: '6px 16px', border: 'none',
            borderBottom: `2px solid ${activeLang === l ? '#8b5cf6' : 'transparent'}`,
            marginBottom: -2, background: 'none', cursor: 'pointer',
            fontSize: 12, fontWeight: activeLang === l ? 700 : 500,
            color: activeLang === l ? '#7c3aed' : 'var(--text-muted,#64748b)',
            fontFamily: 'var(--font-body,Inter,sans-serif)',
            display: 'flex', alignItems: 'center', gap: 4,
          }}>
            {LANG_LABELS_UI[l] || l.toUpperCase()}
            {l === 'pt' && <span style={{ fontSize: 9, color: '#94a3b8' }}>(original)</span>}
            {l !== 'pt' && allApproved(l) && <span style={{ fontSize: 10, color: '#15803d' }}>✓</span>}
          </button>
        ))}

        {/* Adicionar idioma */}
        <div style={{ marginLeft: 'auto', position: 'relative' }}>
          <button onClick={() => setShowAddLang(!showAddLang)} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 6, padding: '5px 10px', fontSize: 11, cursor: 'pointer', color: '#64748b', marginBottom: 4 }}>
            + Adicionar idioma
          </button>
          {showAddLang && (
            <div style={{ position: 'absolute', right: 0, top: '100%', marginTop: 4, background: '#fff', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, padding: 8, zIndex: 50, boxShadow: '0 4px 12px rgba(0,0,0,.1)', minWidth: 160 }}>
              {['en','fr','de','it','es'].filter(l => !allLangs.includes(l)).map(l => (
                <button key={l} onClick={() => { onAction('generateIdiomas', l); setShowAddLang(false); }} style={{ display: 'block', width: '100%', textAlign: 'left', padding: '6px 10px', background: 'none', border: 'none', borderRadius: 5, fontSize: 12, cursor: 'pointer', color: 'var(--text,#1d2e38)' }}>
                  {LANG_LABELS_UI[l] || l.toUpperCase()}
                </button>
              ))}
              {['en','fr','de','it','es'].filter(l => !allLangs.includes(l)).length === 0 && (
                <div style={{ fontSize: 11, color: '#94a3b8', padding: '6px 10px' }}>Todos os idiomas gerados</div>
              )}
            </div>
          )}
        </div>
      </div>

      {/* Conteúdo da tab activa */}
      {activeLang && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {renderIdiomaSection(langPerformance, false, activeLang)}
          {renderIdiomaSection(langOrganic, true, activeLang)}
          {currentLangItems.length === 0 && (
            <div style={{ textAlign: 'center', padding: '32px 0', color: 'var(--text-muted,#64748b)', fontSize: 13 }}>
              {activeLang === 'pt' ? 'Sem copy gerado ainda.' : `Sem tradução para ${LANG_LABELS_UI[activeLang] || activeLang.toUpperCase()} ainda.`}
            </div>
          )}
        </div>
      )}

      {/* Footer aprovação global */}
      {['idiomas_gerado','idiomas_pendente'].includes(campanha?.status) && (
        <div style={{ borderTop: '1px solid var(--border,#e2e8f0)', paddingTop: 16, marginTop: 4 }}>
          <button className="btn btn-ai" onClick={() => onAction('aprovarIdiomas')}>
            Aprovar Idiomas e Avançar para Prompts
          </button>
        </div>
      )}

      {/* Modal de edição de tradução */}
      {editingIdioma && (
        <EditCopyModal
          copy={editingIdioma}
          onClose={() => setEditingIdioma(null)}
          onSave={(id, data) => { onAction('saveCopy', id, data); setEditingIdioma(null); }}
        />
      )}
    </div>
  );
};

const TabCopyFull = ({ campanha, copy, onAction, generating, copyStep = 0, copyMsg = '', editMode = false }) => {
  const commPlan    = campanha?.proposta_json?.comm_plan || [];
  const hasCopy     = copy.length > 0;
  const conceptDone = campanha?.big_idea;

  // Todos os hooks ANTES de qualquer early return
  const stepStartRef      = React.useRef(null);
  const [stepPct, setStepPct]             = React.useState(0);
  const [expandedCopyRows, setExpandedCopyRows] = React.useState({});
  const [editingCopy, setEditingCopy]           = React.useState(null);
  const [collapsedCopy, setCollapsedCopy]       = React.useState({});

  React.useEffect(() => {
    if (!generating.copy || copyStep <= 0) { setStepPct(0); return; }
    stepStartRef.current = Date.now();
    setStepPct(0);
  }, [copyStep]);

  React.useEffect(() => {
    if (!generating.copy || copyStep <= 0) return;
    const def = COPY_STEPS.find(s => s.step === copyStep);
    if (!def?.duration) return;
    const iv = setInterval(() => {
      const elapsed = Date.now() - (stepStartRef.current || Date.now());
      setStepPct(Math.min((elapsed / def.duration) * 90, 90));
    }, 80);
    return () => clearInterval(iv);
  }, [copyStep, generating.copy]);

  const totalSteps = COPY_STEPS.length;
  const doneSteps  = COPY_STEPS.filter(s => s.step < copyStep).length;
  const overallPct = Math.round(((doneSteps + stepPct / 100) / totalSteps) * 100);

  // Chip picker por mercado (variants_by_market)
  const primaryCountry = React.useMemo(() => {
    const variants = campanha?.proposta_json?.variants_by_market || [];
    const p = Array.isArray(variants) ? variants.find(v => v.is_primary) : null;
    return p?.country || null;
  }, [campanha]);

  const markets = React.useMemo(() => {
    const set = new Set((copy || []).map(c => c.country).filter(Boolean));
    return [...set].sort((a, b) => (a === primaryCountry ? -1 : b === primaryCountry ? 1 : a.localeCompare(b)));
  }, [copy, primaryCountry]);

  const hasMarketVariants = markets.length > 0;
  const [activeMarket, setActiveMarket] = React.useState(markets[0] || null);
  React.useEffect(() => {
    if (markets.length > 0 && !markets.includes(activeMarket)) setActiveMarket(markets[0]);
  }, [markets]);

  const filteredCopy = hasMarketVariants
    ? (copy || []).filter(c => c.country === activeMarket)
    : (copy || []);

  if (generating.copy) {
    const proposta    = campanha?.proposta_json || {};
    const personas    = proposta.personas || [];
    const canaisSetup = campanha?.canais_setup ? (typeof campanha.canais_setup === 'string' ? JSON.parse(campanha.canais_setup) : campanha.canais_setup) : null;
    const PAID_CH     = ['meta_ads','linkedin_ads','google_ads_search','google_ads_display','muppi_led'];
    const adSetsPreview = [];
    PAID_CH.forEach(ch => {
      (canaisSetup?.canais?.[ch]?.audiencias || []).forEach(a => adSetsPreview.push({ ch, nome: a.nome }));
    });
    const orgDone  = copyStep > 3 ? commPlan.length : copyStep === 3 ? Math.floor((stepPct / 100) * commPlan.length) : 0;
    const perfDone = copyStep > 4 ? adSetsPreview.length : copyStep === 4 ? Math.floor((stepPct / 100) * adSetsPreview.length) : 0;

    const Dot = ({ done, active }) => {
      if (done) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', background: 'rgba(21,128,61,.12)', border: '1.5px solid rgba(21,128,61,.3)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="8" height="8" viewBox="0 0 10 10" fill="none"><polyline points="1.5,5 4,7.5 8.5,2.5" stroke="#15803d" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
      );
      if (active) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid #3859D0', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ width: 7, height: 7, borderRadius: '50%', background: '#3859D0', animation: 'cpulse 1s infinite' }} />
        </div>
      );
      return <div style={{ width: 16, height: 16, borderRadius: '50%', border: '1.5px solid #e2e8f0', flexShrink: 0 }} />;
    };

    return (
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderRadius: 10, padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <style>{`@keyframes cpulse { 0%,100%{opacity:1} 50%{opacity:.25} }`}</style>

        {/* Barra de progresso compacta no topo */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ flex: 1, height: 4, borderRadius: 99, background: 'var(--bg-app,#f5f6f8)', overflow: 'hidden' }}>
            <div style={{ height: '100%', borderRadius: 99, background: '#3859D0', width: `${overallPct}%`, transition: 'width 0.15s linear' }} />
          </div>
          <span style={{ fontSize: 11, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace', flexShrink: 0 }}>{overallPct}%</span>
          <span style={{ fontSize: 11, color: '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)', flexShrink: 0 }}>{copyMsg || 'A escrever copy…'}</span>
        </div>

        {/* Secção Orgânico */}
        {commPlan.length > 0 && (
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
              <div style={{ width: 3, height: 14, borderRadius: 2, background: '#059669', flexShrink: 0 }} />
              <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#059669', fontFamily: 'var(--font-mono,monospace)' }}>
                Orgânico · {orgDone}/{commPlan.length} peças
              </span>
            </div>
            <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
              <colgroup>
                <col style={{ width: 28 }} />
                <col style={{ width: 200 }} />
                <col style={{ width: 80 }} />
                <col />
                <col style={{ width: 160 }} />
              </colgroup>
              <thead>
                <tr style={{ background: 'var(--bg-app,#f5f6f8)', borderBottom: '1px solid var(--border,#e2e8f0)' }}>
                  <th style={{ padding: '5px 6px', width: 28 }} />
                  <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Canal</th>
                  <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Tipo</th>
                  <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Título</th>
                  <th style={{ padding: '5px 8px', textAlign: 'right', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Persona</th>
                </tr>
              </thead>
              <tbody>
                {commPlan.map((item, idx) => {
                  const isDone   = idx < orgDone;
                  const isActive = idx === orgDone && copyStep === 3;
                  const isPending = !isDone && !isActive;
                  const persona  = item.angulo_persona ? (personas.find(p => p.nome === item.angulo_persona)?.nome || item.angulo_persona).split(' ').slice(0,3).join(' ') : '';
                  const textColor = isDone ? '#374151' : isActive ? 'var(--text,#1d2e38)' : '#94a3b8';
                  return (
                    <tr key={idx} style={{ borderBottom: '1px solid var(--border-light,#f1f5f9)', opacity: isPending && idx > orgDone + 1 ? 0.4 : 1, transition: 'opacity 0.3s', background: isActive ? 'rgba(56,89,208,.02)' : 'transparent' }}>
                      <td style={{ padding: '6px 6px', verticalAlign: 'middle' }}><Dot done={isDone} active={isActive} /></td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                        <span style={{ fontSize: 10, fontWeight: 700, padding: '1px 6px', borderRadius: 4, background: isDone ? 'rgba(21,128,61,.08)' : 'var(--bg-app,#f5f6f8)', color: isDone ? '#15803d' : '#64748b', fontFamily: 'monospace', whiteSpace: 'nowrap', display: 'inline-block', maxWidth: 88, overflow: 'hidden', textOverflow: 'ellipsis' }}>
                          {CANAL_LABEL[item.canal] || item.canal}
                        </span>
                      </td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                        {item.content_type && <span style={{ fontSize: 9, fontWeight: 700, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase' }}>{item.content_type}</span>}
                      </td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                        <span style={{ fontSize: 12, color: textColor, fontWeight: isActive ? 600 : 400, fontFamily: 'var(--font-body,Inter,sans-serif)', lineHeight: 1.3, display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{item.titulo || ''}</span>
                      </td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle', textAlign: 'right' }}>
                        {persona && <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace' }}>{persona}</span>}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}

        {/* Secção Performance */}
        {adSetsPreview.length > 0 && (
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
              <div style={{ width: 3, height: 14, borderRadius: 2, background: '#0ea5e9', flexShrink: 0 }} />
              <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#0ea5e9', fontFamily: 'var(--font-mono,monospace)' }}>
                Performance · {perfDone}/{adSetsPreview.length} ad sets
              </span>
            </div>
            <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
              <colgroup>
                <col style={{ width: 28 }} />
                <col style={{ width: 200 }} />
                <col />
              </colgroup>
              <thead>
                <tr style={{ background: 'var(--bg-app,#f5f6f8)', borderBottom: '1px solid var(--border,#e2e8f0)' }}>
                  <th style={{ padding: '5px 6px', width: 28 }} />
                  <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Canal</th>
                  <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Ad Set</th>
                </tr>
              </thead>
              <tbody>
                {adSetsPreview.map((a, idx) => {
                  const isDone   = idx < perfDone;
                  const isActive = idx === perfDone && copyStep === 4;
                  const textColor = isDone ? '#374151' : isActive ? 'var(--text,#1d2e38)' : '#94a3b8';
                  return (
                    <tr key={idx} style={{ borderBottom: '1px solid var(--border-light,#f1f5f9)', opacity: copyStep < 4 && !isDone ? 0.4 : 1, transition: 'opacity 0.3s', background: isActive ? 'rgba(14,165,233,.02)' : 'transparent' }}>
                      <td style={{ padding: '6px 6px', verticalAlign: 'middle' }}><Dot done={isDone} active={isActive} /></td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                        <span style={{ fontSize: 10, fontWeight: 700, padding: '1px 6px', borderRadius: 4, background: isDone ? 'rgba(21,128,61,.08)' : 'var(--bg-app,#f5f6f8)', color: isDone ? '#15803d' : '#64748b', fontFamily: 'monospace', whiteSpace: 'nowrap', display: 'inline-block' }}>
                          {CANAL_LABEL[a.ch] || a.ch}
                        </span>
                      </td>
                      <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                        <span style={{ fontSize: 12, color: textColor, fontWeight: isActive ? 600 : 400, fontFamily: 'var(--font-body,Inter,sans-serif)' }}>{a.nome}</span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>
    );
  }

  if (!conceptDone) return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '64px 0', gap: 20 }}>
      <div style={{ width: 56, height: 56, borderRadius: 14, background: 'rgba(56,89,208,.08)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="var(--ai-500,#3859D0)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>
        </svg>
      </div>
      <div style={{ textAlign: 'center' }}>
        <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 6 }}>Conceito por aprovar</div>
        <div style={{ fontSize: 13, color: 'var(--text-muted,#64748b)', maxWidth: 320, lineHeight: 1.6, fontFamily: 'var(--font-body,Inter,sans-serif)' }}>Aprova o conceito da campanha antes de gerar o copy.</div>
      </div>
    </div>
  );

  // Separar copy por tipo (backward compat: NULL ou 'organico' → orgânico)
  const organicCopy     = filteredCopy.filter(c => !c.copy_type || c.copy_type === 'organico');
  const performanceCopy = filteredCopy.filter(c => c.copy_type === 'performance');

  const approved    = filteredCopy.filter(c => c.status === 'aprovado').length;
  const total       = filteredCopy.length;
  const pct         = total > 0 ? Math.round((approved / total) * 100) : 0;
  const allApproved = hasCopy && approved === total;

  // Normaliza planned_date para YYYY-MM-DD
  const normDate = (raw) => {
    if (!raw) return null;
    const s = typeof raw === 'string' ? raw : String(raw);
    return s.includes('T') ? s.split('T')[0] : s;
  };

  const formatDate = (d) => {
    if (!d) return null;
    try {
      const dt = new Date(d.includes('T') ? d : d + 'T12:00:00');
      if (isNaN(dt.getTime())) return d;
      return dt.toLocaleDateString('pt-PT', { day: 'numeric', month: 'short' });
    } catch { return d; }
  };

  // Agrupar por canal separado por tipo
  const groupByCanal = (arr) => {
    const map = {};
    arr.forEach(cp => { const k = cp.canal || 'outro'; if (!map[k]) map[k] = []; map[k].push(cp); });
    return Object.entries(map);
  };
  const organicGroups     = groupByCanal(organicCopy);
  const performanceGroups = groupByCanal(performanceCopy);

  if (!hasCopy) {
    const PERF_CH = new Set(['meta_ads','linkedin_ads','google_ads_search','google_ads_display','muppi_led']);
    const canaisSetupData = campanha?.canais_setup?.canais || {};
    // Orgânico: canais únicos no comm_plan + total peças
    const orgCanais = new Set(commPlan.map(i => i.canal)).size;
    const orgPecas  = commPlan.length;
    // Performance: canais pagos no canais_setup + total ad sets
    const perfEntries = Object.entries(canaisSetupData).filter(([k]) => PERF_CH.has(k));
    const perfCanais  = perfEntries.length;
    const perfPecas   = perfEntries.reduce((sum, [, cs]) => sum + (Array.isArray(cs.audiencias) ? cs.audiencias.length : 0), 0);

    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '64px 0', gap: 20 }}>
        <div style={{ width: 56, height: 56, borderRadius: 14, background: 'rgba(56,89,208,.08)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="var(--ai-500,#3859D0)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
          </svg>
        </div>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 10 }}>Copy por gerar</div>
          <div style={{ display: 'flex', gap: 12, justifyContent: 'center', flexWrap: 'wrap' }}>
            {orgPecas > 0 && (
              <div style={{ background: 'rgba(5,150,105,.06)', border: '1px solid rgba(5,150,105,.2)', borderRadius: 10, padding: '10px 18px', textAlign: 'left' }}>
                <div style={{ fontSize: 10, fontWeight: 700, color: '#059669', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 4 }}>Orgânico</div>
                <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontWeight: 600 }}>{orgCanais} {orgCanais === 1 ? 'canal' : 'canais'} · {orgPecas} {orgPecas === 1 ? 'peça' : 'peças'}</div>
              </div>
            )}
            {perfCanais > 0 && (
              <div style={{ background: 'rgba(14,165,233,.06)', border: '1px solid rgba(14,165,233,.2)', borderRadius: 10, padding: '10px 18px', textAlign: 'left' }}>
                <div style={{ fontSize: 10, fontWeight: 700, color: '#0ea5e9', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 4 }}>Performance</div>
                <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontWeight: 600 }}>{perfCanais} {perfCanais === 1 ? 'canal' : 'canais'} · {perfPecas > 0 ? `${perfPecas} peças` : 'anúncios pagos'}</div>
              </div>
            )}
            {orgPecas === 0 && perfCanais === 0 && (
              <div style={{ fontSize: 13, color: 'var(--text-muted,#64748b)', lineHeight: 1.6 }}>Conceito aprovado — pronto para gerar o copy da campanha.</div>
            )}
          </div>
        </div>
        <button onClick={() => onAction('generateCopy')} disabled={generating.copy} className="btn btn-ai" style={{ fontSize: 13, padding: '10px 24px' }} data-tutorial-step="copy">
          Gerar Copy com Digi AI
        </button>
      </div>
    );
  }

  const toggleCopyRow = (id) => setExpandedCopyRows(p => ({ ...p, [id]: !p[id] }));

  const offer = campanha?.commercial_offer
    ? (typeof campanha.commercial_offer === 'string' ? (() => { try { return JSON.parse(campanha.commercial_offer); } catch { return null; } })() : campanha.commercial_offer)
    : null;
  const ctaSlug = offer?.primary_cta;
  const ctaDefault = typeof window.ctaToText === 'function' ? window.ctaToText(ctaSlug, 'pt') : 'Saiba mais';

  // Banner campanhas antigas
  const isOldCampaign = copy.some(c =>
    (c.body || '').toLowerCase().includes('cold') ||
    (c.body || '').toLowerCase().includes('warm') ||
    (c.body || '').toLowerCase().includes('retargeting')
  );
  const oldCampaignBanner = isOldCampaign ? (
    <div style={{ background: 'rgba(245,158,11,.06)', border: '1px solid rgba(245,158,11,.3)', borderRadius: 10, padding: '12px 16px', marginBottom: 16, display: 'flex', gap: 10, alignItems: 'flex-start' }}>
      <span style={{ fontSize: 14 }}>⚠</span>
      <div>
        <div style={{ fontSize: 12, fontWeight: 600, color: '#92400e', marginBottom: 2 }}>Campanha gerada antes da actualização do fluxo (Junho 2026)</div>
        <div style={{ fontSize: 12, color: '#78350f' }}>O copy pode referenciar Cold/Warm/Retargeting em vez da narrativa integrada Awareness→Consideration→Decision. Para regenerar com o novo modelo, volta ao Conceito e clica "Regenerar".</div>
      </div>
    </div>
  ) : null;

  const thStCopy = { padding: '8px 12px', textAlign: 'left', fontSize: 10, fontWeight: 700, color: '#64748b', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.05em' };


  const CopyRow = ({ cp, isOrganic }) => {
    const isExpanded = expandedCopyRows[cp.id];
    const adSpecs = cp.ad_specs ? (typeof cp.ad_specs === 'string' ? (() => { try { return JSON.parse(cp.ad_specs); } catch { return null; } })() : cp.ad_specs) : null;
    const bodyText = cp.body || cp.caption_organica || '';
    return (
      <React.Fragment>
        <tr style={{ borderBottom: '1px solid var(--border,#e2e8f0)', cursor: 'pointer', background: expandedCopyRows[cp.id] ? 'rgba(56,89,208,.02)' : 'transparent' }} onClick={() => toggleCopyRow(cp.id)}>
          <td style={{ padding: '10px 12px', minWidth: 140 }}>
            <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>
              {CANAL_LABEL[cp.canal] || cp.canal}
            </span>
            {(() => {
              const badge = cp.canal === 'whatsapp' ? 'template'
                : ['meta_ads','linkedin_ads','google_ads_search','google_ads_display'].includes(cp.canal) ? 'ad'
                : cp.content_type || null;
              return badge ? <span style={{ fontSize: 9, color: '#94a3b8', marginLeft: 4, fontFamily: 'monospace', textTransform: 'uppercase' }}>{badge}</span> : null;
            })()}
          </td>
          <td style={{ padding: '10px 12px', maxWidth: 220 }}>
            <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text,#1d2e38)', lineHeight: 1.3 }}>
              {cp.canal === 'whatsapp'
                ? (adSpecs?.wa_template_name || cp.headline || '—')
                : (cp.headline || '—')}
            </div>
          </td>
          <td style={{ padding: '10px 12px', maxWidth: 300 }}>
            <div style={{ fontSize: 12, color: 'var(--text-muted,#64748b)', lineHeight: 1.5 }}>
              {(() => {
                const text = cp.canal === 'whatsapp'
                  ? (adSpecs?.wa_body || bodyText)
                  : bodyText;
                return text.slice(0, 120) + (text.length > 120 ? '…' : '');
              })()}
            </div>
          </td>
          <td style={{ padding: '10px 12px', minWidth: 120 }}>
            <span style={{ fontSize: 11, fontWeight: 600, color: '#3859D0' }}>{cp.cta || ctaDefault}</span>
          </td>
          <td style={{ padding: '10px 12px', minWidth: 80 }}>
            <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
              <button onClick={e => { e.stopPropagation(); onAction('regenerateCopy', cp.id); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Regenerar">⟳</button>
              <button onClick={e => { e.stopPropagation(); setEditingCopy(cp); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Editar">✏</button>
              <span style={{ fontSize: 11, color: '#94a3b8' }}>{isExpanded ? '▴' : '▾'}</span>
            </div>
          </td>
        </tr>
        {isExpanded && (
          <tr>
            <td colSpan={5} style={{ padding: '0 12px 16px', background: 'rgba(56,89,208,.02)' }}>
              <div style={{ borderTop: '1px solid var(--border-light,#f1f5f9)', paddingTop: 12, marginTop: 0 }}>
                <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#3859D0', fontFamily: 'monospace', marginBottom: 10 }}>Sugestão Criativa</div>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
                  <div>
                    <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 3 }}>Headline Imagem</div>
                    <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{cp.copy_imagem || cp.headline || '—'}</div>
                  </div>
                  <div>
                    <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 3 }}>CTA Imagem</div>
                    <div style={{ fontSize: 12, color: 'var(--text,#1d2e38)' }}>{cp.cta || ctaDefault}</div>
                  </div>
                  <div>
                    <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 3 }}>Descrição Visual</div>
                    <div style={{ fontSize: 12, color: 'var(--text-muted,#64748b)', lineHeight: 1.55 }}>{cp.prompt_visual || '—'}</div>
                  </div>
                </div>
                <button onClick={() => setEditingCopy({ ...cp, _mode: 'criativo' })} style={{ marginTop: 10, background: 'none', border: '1px solid rgba(56,89,208,.3)', borderRadius: 6, padding: '4px 10px', fontSize: 11, color: '#3859D0', cursor: 'pointer' }}>✏ Editar Sugestão Criativa</button>
              </div>
              {bodyText && (
                <div style={{ marginTop: 12, paddingTop: 12, borderTop: '1px solid var(--border-light,#f1f5f9)' }}>
                  <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 6 }}>Copy Completo</div>
                  <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', lineHeight: 1.7, whiteSpace: 'pre-wrap', background: 'var(--bg-app,#f5f6f8)', borderRadius: 8, padding: '10px 14px' }}>
                    {bodyText}
                  </div>
                </div>
              )}
            </td>
          </tr>
        )}
      </React.Fragment>
    );
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>

      {oldCampaignBanner}

      {/* Chip picker por mercado */}
      {hasMarketVariants && (
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <span style={{ fontSize: 11, fontWeight: 600, color: '#64748b', letterSpacing: '.05em', textTransform: 'uppercase' }}>Mercado</span>
          {markets.map(m => {
            const active = m === activeMarket;
            const isPrimary = m === primaryCountry;
            return (
              <button key={m} onClick={() => setActiveMarket(m)}
                style={{
                  padding: '6px 12px', fontSize: 12, fontWeight: 700, borderRadius: 6,
                  border: active ? '1px solid var(--dd-primary-600,#3859D0)' : '1px solid #e2e8f0',
                  background: active ? 'rgba(56,89,208,.08)' : '#fff',
                  color: active ? 'var(--dd-primary-600,#3859D0)' : '#475569',
                  cursor: 'pointer', fontFamily: 'var(--font-mono,monospace)', letterSpacing: '.05em',
                }}>
                {m}{isPrimary ? ' · PRIMÁRIO' : ''}
              </button>
            );
          })}
          {activeMarket !== primaryCountry && (
            <span style={{ fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 3,
              background: 'rgba(56,89,208,.12)', color: 'var(--dd-primary-600,#3859D0)',
              fontFamily: 'var(--font-mono,monospace)', letterSpacing: '.08em' }}>
              {activeMarket} · LOCAL
            </span>
          )}
        </div>
      )}

      {/* Secção Performance · Anúncios Pagos */}
      {performanceCopy.length > 0 && (
        <CollapsBlock title="Performance · Anúncios Pagos" count={performanceCopy.length + (performanceCopy.length === 1 ? ' canal' : ' canais')} defaultOpen={true} accentColor="#0ea5e9">
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ background: 'var(--bg-app,#f5f6f8)' }}>
                <th style={thStCopy}>Canal</th>
                <th style={thStCopy}>Headline</th>
                <th style={thStCopy}>Copy</th>
                <th style={thStCopy}>CTA</th>
                <th style={thStCopy}>Acções</th>
              </tr>
            </thead>
            <tbody>
              {performanceCopy.map(cp => <CopyRow key={cp.id} cp={cp} isOrganic={false} />)}
            </tbody>
          </table>
        </CollapsBlock>
      )}

      {/* Secção Orgânico · Plano de Comunicação */}
      {organicCopy.length > 0 && (
        <CollapsBlock title="Orgânico · Plano de Comunicação" count={organicCopy.length + ' peças'} defaultOpen={true} accentColor="#059669">
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ background: 'var(--bg-app,#f5f6f8)' }}>
                <th style={thStCopy}>Canal</th>
                <th style={thStCopy}>Headline</th>
                <th style={thStCopy}>Copy</th>
                <th style={thStCopy}>CTA</th>
                <th style={thStCopy}>Acções</th>
              </tr>
            </thead>
            <tbody>
              {organicCopy.map(cp => <CopyRow key={cp.id} cp={cp} isOrganic={true} />)}
            </tbody>
          </table>
        </CollapsBlock>
      )}

      {/* Footer aprovação global */}
      {hasCopy && ['copy_gerado','copy_pendente'].includes(campanha?.status) && (
        <div style={{ borderTop: '1px solid var(--border,#e2e8f0)', paddingTop: 16, marginTop: 4 }}>
          <button className="btn btn-ai" onClick={() => onAction('aprovarCopy')}>
            Aprovar Copy e Avançar para Prompts
          </button>
        </div>
      )}

      {/* Modal de edição de copy */}
      {editingCopy && (
        <EditCopyModal
          copy={editingCopy}
          onClose={() => setEditingCopy(null)}
          onSave={(id, data) => { onAction('saveCopy', id, data); setEditingCopy(null); }}
        />
      )}
    </div>
  );
};

const CANAL_COLOR_MAP = {
  meta_ads:'#1877F2', instagram:'#E1306C', facebook:'#1877F2',
  linkedin_ads:'#0A66C2', linkedin:'#0A66C2',
  email:'#6366f1', whatsapp:'#25D366',
  google_ads_search:'#4285F4', google_ads:'#4285F4', google_ads_display:'#34A853',
  website:'#0ea5e9', site:'#0ea5e9',
  muppi_led:'#8b5cf6', led:'#8b5cf6',
  youtube:'#FF0000', tiktok:'#1d1d1f',
  email_interno:'#6366f1', whatsapp_interno:'#25D366', portal_notificacao:'#0ea5e9',
  'email_interno+whatsapp_interno+portal_notificacao': '#6366f1',
};

const CanalSvgIcon = ({ canal, size = 15 }) => {
  const col = CANAL_COLOR_MAP[canal] || '#64748b';
  const sp = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: col, strokeWidth: '1.8', strokeLinecap: 'round', strokeLinejoin: 'round' };
  if (['meta_ads','instagram','facebook'].includes(canal)) return <svg {...sp}><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>;
  if (['linkedin_ads','linkedin'].includes(canal)) return <svg {...sp}><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg>;
  if (['email','email_interno'].includes(canal)) return <svg {...sp}><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>;
  if (['whatsapp','whatsapp_interno'].includes(canal)) return <svg {...sp}><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>;
  if (canal === 'portal_notificacao') return <svg {...sp}><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>;
  if (canal === 'email_interno+whatsapp_interno+portal_notificacao') return <svg {...sp}><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>;
  if (['google_ads_search','google_ads','google_ads_display'].includes(canal)) return <svg {...sp}><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>;
  if (['website','site'].includes(canal)) return <svg {...sp}><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>;
  if (['muppi_led','led'].includes(canal)) return <svg {...sp}><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>;
  if (canal === 'youtube') return <svg {...sp}><path d="M22.54 6.42a2.78 2.78 0 0 0-1.95-1.96C18.88 4 12 4 12 4s-6.88 0-8.59.46a2.78 2.78 0 0 0-1.95 1.96A29 29 0 0 0 1 12a29 29 0 0 0 .46 5.58A2.78 2.78 0 0 0 3.41 19.54C5.12 20 12 20 12 20s6.88 0 8.59-.46a2.78 2.78 0 0 0 1.95-1.96A29 29 0 0 0 23 12a29 29 0 0 0-.46-5.58z"/><polygon points="9.75 15.02 15.5 12 9.75 8.98 9.75 15.02"/></svg>;
  // default: file/doc
  return <svg {...sp}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>;
};

const CopyCardFull = ({ cp, onApprove, onFlag, onSave, editMode }) => {
  // Canais compostos (e.g. "email_interno+whatsapp_interno") — usar o primeiro segmento
  const primaryCanal = cp.canal ? cp.canal.split('+')[0].trim() : '';
  const canalLabel   = CANAL_LABEL[cp.canal] || CANAL_LABEL[primaryCanal] || (primaryCanal ? primaryCanal.replace(/_/g,' ') : '—');
  const canalCol     = CANAL_COLOR_MAP[cp.canal] || CANAL_COLOR_MAP[primaryCanal] || '#64748b';
  const isApproved = cp.status === 'aprovado';
  const isFlagged  = cp.status === 'correcao';
  const adSpecs    = cp.ad_specs ? (typeof cp.ad_specs === 'string' ? JSON.parse(cp.ad_specs) : cp.ad_specs) : null;

  const [editHeadline, setEditHeadline] = React.useState(cp.headline || '');
  const [editBody,     setEditBody]     = React.useState(cp.body || '');
  const [editCta,      setEditCta]      = React.useState(cp.cta || '');
  const [editHashtags, setEditHashtags] = React.useState(cp.hashtags || '');
  const [saving,       setSaving]       = React.useState(false);

  React.useEffect(() => {
    setEditHeadline(cp.headline || '');
    setEditBody(cp.body || '');
    setEditCta(cp.cta || '');
    setEditHashtags(cp.hashtags || '');
  }, [cp.id]);

  const handleSave = async () => {
    setSaving(true);
    await onSave({ headline: editHeadline, body: editBody, cta: editCta, hashtags: editHashtags });
    setSaving(false);
  };

  const editFieldStyle = { width: '100%', fontSize: 12.5, color: '#1d2e38', background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: 6, padding: '6px 10px', fontFamily: 'Inter, sans-serif', lineHeight: 1.5, resize: 'vertical', outline: 'none', boxSizing: 'border-box' };
  return (
    <div style={{
      background: '#fff',
      border: `1px solid ${isApproved ? 'rgba(34,197,94,.4)' : isFlagged ? 'rgba(251,146,60,.4)' : '#e2e8f0'}`,
      borderLeft: `3px solid ${isApproved ? '#22c55e' : isFlagged ? '#fb923c' : canalCol}`,
      borderRadius: '0 10px 10px 0',
      display: 'flex', flexDirection: 'column',
      boxShadow: '0 1px 3px rgba(0,0,0,.04)',
    }}>
      {/* Card header */}
      <div style={{
        padding: '12px 16px 10px', borderBottom: '1px solid #f1f5f9',
        background: isApproved ? 'rgba(34,197,94,.04)' : isFlagged ? 'rgba(251,146,60,.04)' : '#fafbfc',
        borderRadius: '0 10px 0 0', display: 'flex', flexDirection: 'column', gap: 6,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ width: 26, height: 26, borderRadius: 6, background: `${canalCol}14`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <CanalSvgIcon canal={primaryCanal || cp.canal} size={14} />
          </div>
          <span style={{ fontSize: 13, fontWeight: 700, color: '#1d2e38', flex: 1, fontFamily: 'Montserrat, sans-serif' }}>{canalLabel}</span>
          {cp.content_type && (
            <span style={{ fontSize: 10, color: '#64748b', background: '#f1f5f9', padding: '2px 7px', borderRadius: 5, fontFamily: 'monospace' }}>{cp.content_type}</span>
          )}
          {cp.formato && !cp.content_type && (
            <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace' }}>{cp.formato}</span>
          )}
          {/* Status inline */}
          <span style={{
            fontSize: 10, fontWeight: 600, padding: '2px 8px', borderRadius: 99, fontFamily: 'monospace',
            color: isApproved ? '#16a34a' : isFlagged ? '#ea580c' : '#64748b',
            background: isApproved ? 'rgba(34,197,94,.1)' : isFlagged ? 'rgba(251,146,60,.12)' : '#f1f5f9',
          }}>
            {isApproved ? '✓ Aprovado' : isFlagged ? '⚑ Correcção' : 'Pendente'}
          </span>
        </div>
        {/* Context row from comm_plan */}
        {(cp.planned_date || cp.item_title) && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            {cp.planned_date && (
              <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace', background: '#f1f5f9', padding: '1px 6px', borderRadius: 4 }}>{cp.planned_date}</span>
            )}
            {cp.item_title && (
              <span style={{ fontSize: 11, color: '#64748b', flex: 1, fontStyle: 'italic' }}>{cp.item_title}</span>
            )}
          </div>
        )}
      </div>

      {/* Card body */}
      <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 12, flex: 1 }}>
        {editMode ? (
          <>
            <div>
              <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', marginBottom: 4 }}>Headline</div>
              <input value={editHeadline} onChange={e => setEditHeadline(e.target.value)} style={editFieldStyle} />
            </div>
            {cp.body !== undefined && (
              <div>
                <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', marginBottom: 4 }}>Body</div>
                <textarea value={editBody} onChange={e => setEditBody(e.target.value)} rows={4} style={editFieldStyle} />
              </div>
            )}
            <div>
              <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', marginBottom: 4 }}>CTA</div>
              <input value={editCta} onChange={e => setEditCta(e.target.value)} style={editFieldStyle} />
            </div>
            {cp.hashtags !== undefined && (
              <div>
                <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', marginBottom: 4 }}>Hashtags</div>
                <input value={editHashtags} onChange={e => setEditHashtags(e.target.value)} style={editFieldStyle} />
              </div>
            )}
            <div style={{ display: 'flex', gap: 8, paddingTop: 8, borderTop: '1px solid #f1f5f9' }}>
              <button onClick={handleSave} disabled={saving} className="btn btn-ai" style={{ fontSize: 11 }}>
                {saving ? 'A guardar…' : '✓ Guardar'}
              </button>
            </div>
          </>
        ) : (
          <>
            {cp.canal === 'whatsapp' && adSpecs?.wa_template_name ? (
              /* ── WhatsApp: campos específicos Meta Template ── */
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: '#25D366', fontFamily: 'monospace', background: 'rgba(37,211,102,.08)', padding: '3px 8px', borderRadius: 4 }}>
                    WhatsApp · Template Meta
                  </span>
                  <span style={{ fontSize: 9, fontFamily: 'monospace', color: '#64748b', background: '#f1f5f9', padding: '3px 8px', borderRadius: 4 }}>
                    {adSpecs.wa_template_name}
                  </span>
                  <span style={{ fontSize: 9, fontFamily: 'monospace', color: '#64748b', background: '#f1f5f9', padding: '3px 8px', borderRadius: 4 }}>
                    {adSpecs.wa_categoria}
                  </span>
                </div>
                <CopyFieldLight label="Body (Template)" value={adSpecs.wa_body || cp.body} multiline />
                {adSpecs.wa_footer && <CopyFieldLight label="Footer" value={adSpecs.wa_footer} />}
                {Array.isArray(adSpecs.wa_buttons) && adSpecs.wa_buttons.length > 0 && (
                  <CopyFieldLight label="Botões" value={adSpecs.wa_buttons.map(b => `${b.type}: ${b.text}${b.url ? ` → ${b.url}` : ''}`).join(' | ')} mono />
                )}
                {adSpecs.wa_exemplo_vars && Object.keys(adSpecs.wa_exemplo_vars).length > 0 && (
                  <CopyFieldLight label="Variáveis" value={Object.entries(adSpecs.wa_exemplo_vars).map(([k,v]) => `{{${k}}}=${v}`).join(', ')} mono />
                )}
              </div>
            ) : (
              <>
                {/* ── Copy da Imagem ── */}
                {cp.copy_imagem && (
                  <div style={{ background: 'rgba(56,89,208,.05)', border: '1px solid rgba(56,89,208,.15)', borderRadius: 8, padding: '10px 12px', marginBottom: 4 }}>
                    <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: '#3859D0', fontFamily: 'monospace', marginBottom: 6 }}>Copy Imagem · texto sobre o visual</div>
                    <div style={{ fontSize: 14, fontWeight: 700, color: '#1d2e38', fontFamily: 'Montserrat, sans-serif', lineHeight: 1.3 }}>{cp.copy_imagem}</div>
                  </div>
                )}
                {/* ── Copy Publicação ── */}
                {(cp.headline || cp.body || cp.cta) && (
                  <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: '#94a3b8', fontFamily: 'monospace', marginTop: cp.copy_imagem ? 4 : 0 }}>Copy Publicação · post / email / anúncio</div>
                )}
                {cp.headline && <CopyFieldLight label="Headline" value={cp.headline} />}
                {cp.body     && <CopyFieldLight label="Body"     value={cp.body}     multiline />}
                {cp.cta      && <CopyFieldLight label="CTA"      value={cp.cta} />}
                {cp.hashtags && <CopyFieldLight label="Hashtags" value={cp.hashtags} mono />}
                {adSpecs     && <AdSpecsBlock   specs={adSpecs}  canal={cp.canal}    light />}
              </>
            )}
            {!isApproved && (
              <div style={{ display: 'flex', gap: 8, marginTop: 4, paddingTop: 10, borderTop: '1px solid #f1f5f9' }}>
                <button onClick={onApprove} className="btn btn-ai" style={{ fontSize: 11 }}>✓ Aprovar</button>
                <button onClick={onFlag}    className="btn" style={{ fontSize: 11, color: '#fb923c', borderColor: 'rgba(251,146,60,.3)' }}>⚑ Corrigir</button>
              </div>
            )}
            {isApproved && (
              <div style={{ fontSize: 11, color: '#16a34a', fontWeight: 600, paddingTop: 8, borderTop: '1px solid #f1f5f9' }}>✓ Copy aprovado</div>
            )}
          </>
        )}
      </div>
    </div>
  );
};

const TIPO_CONFIG = {
  background:    { label: 'Background',   plat: 'FLUX.2 [pro]',          color: '#3859D0', bg: 'rgba(56,89,208,.07)'  },
  video_produto: { label: 'Vídeo Produto', plat: 'Kling 3.0',             color: '#8b5cf6', bg: 'rgba(139,92,246,.07)' },
  video_operador:{ label: 'Vídeo Operador',plat: 'Higgsfield',            color: '#0ea5e9', bg: 'rgba(14,165,233,.07)' },
  composicao:    { label: 'Composição',    plat: 'Bannerbear / Puppeteer', color: '#059669', bg: 'rgba(5,150,105,.07)'  },
  imagem:        { label: 'Imagem',        plat: 'FLUX',                  color: '#3859D0', bg: 'rgba(56,89,208,.07)'  },
  video:         { label: 'Vídeo',         plat: 'Kling',                 color: '#8b5cf6', bg: 'rgba(139,92,246,.07)' },
};

const STEP_CONFIG = {
  background:       { step: '①', label: 'Fundo',             sub: 'Imagem sem texto',             color: '#3859D0', plat: 'FLUX.2 [pro]'    },
  imagem:           { step: '①', label: 'Fundo',             sub: 'Imagem sem texto',             color: '#3859D0', plat: 'FLUX'            },
  video_produto:    { step: '①', label: 'Vídeo de fundo',    sub: 'Equipamento em acção',         color: '#8b5cf6', plat: 'Kling 3.0'       },
  video_operador:   { step: '①', label: 'Vídeo de fundo',    sub: 'Operador a trabalhar',         color: '#0ea5e9', plat: 'Higgsfield'      },
  video:            { step: '①', label: 'Vídeo de fundo',    sub: 'Equipamento em acção',         color: '#8b5cf6', plat: 'Kling'           },
  composicao:       { step: '②', label: 'Texto na imagem',   sub: 'Copy + layout → imagem final', color: '#059669', plat: 'Bannerbear'      },
  composicao_video: { step: '②', label: 'Texto no vídeo',    sub: 'Copy + timing → vídeo final',  color: '#059669', plat: 'Puppeteer+ffmpeg' },
  composicao_email: { step: '①', label: 'Template Email',    sub: 'Estrutura + copy do email',    color: '#f59e0b', plat: 'HTML Template'   },
  composicao_rsa:   { step: '①', label: 'Criativo Google',   sub: 'Headlines + descriptions',     color: '#ef4444', plat: 'Google Ads'      },
};

const PromptMiniCard = ({ pr, onApprove, onFlag }) => {
  const [expanded, setExpanded] = React.useState(false);
  const [copied,   setCopied]   = React.useState(false);
  const scfg       = STEP_CONFIG[pr.tipo] || STEP_CONFIG.background;
  const isApproved = pr.status === 'aprovado';
  const isFlagged  = pr.status === 'correcao';

  let composicaoSpec = null;
  if (pr.tipo === 'composicao' && pr.prompt_texto) {
    try { composicaoSpec = JSON.parse(pr.prompt_texto); } catch {}
  }
  const promptShort = pr.prompt_texto && pr.prompt_texto.length > 130
    ? pr.prompt_texto.slice(0, 130) + '…'
    : pr.prompt_texto;

  const handleCopy = () => {
    navigator.clipboard?.writeText(pr.prompt_texto || '').then(() => {
      setCopied(true); setTimeout(() => setCopied(false), 1600);
    });
  };

  return (
    <div style={{
      background: '#fff', borderRadius: 10, overflow: 'hidden',
      border: `1px solid ${isApproved ? 'rgba(34,197,94,.35)' : isFlagged ? 'rgba(251,146,60,.35)' : '#e2e8f0'}`,
      display: 'flex', flexDirection: 'column',
    }}>
      {/* Thumbnail — só fundo/imagem (Nano Banana refs ou legacy single) */}
      {(() => {
        if (pr.tipo !== 'background' && pr.tipo !== 'imagem') return null;
        const brandRefs = (() => {
          if (!pr.brand_asset_refs) return null;
          if (typeof pr.brand_asset_refs === 'string') {
            try { return JSON.parse(pr.brand_asset_refs); } catch { return null; }
          }
          return pr.brand_asset_refs;
        })();
        const urls = brandRefs?.image_urls || [];
        if (urls.length > 0) {
          return (
            <div style={{ height: 80, background: '#f8fafc', position: 'relative', flexShrink: 0, display: 'grid', gridTemplateColumns: `repeat(${Math.min(urls.length, 3)}, 1fr)`, gap: 2, padding: 2 }}>
              {urls.slice(0, 3).map((url, idx) => (
                <img key={idx} src={url} alt={`ref ${idx + 1}`} style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 3 }} onError={e => { e.target.style.opacity = '0.3'; }} />
              ))}
              <span style={{ position: 'absolute', bottom: 5, right: 7, fontSize: 8, fontWeight: 700, color: '#fff', background: 'rgba(0,0,0,.55)', padding: '1px 5px', borderRadius: 3, fontFamily: 'monospace' }}>
                {urls.length} REFS
              </span>
            </div>
          );
        }
        if (pr.imagem_referencia) {
          return (
            <div style={{ height: 80, background: '#f8fafc', position: 'relative', flexShrink: 0 }}>
              <img src={pr.imagem_referencia} alt="ref" style={{ width: '100%', height: '100%', objectFit: 'contain', padding: 6 }} />
              <span style={{ position: 'absolute', bottom: 5, right: 7, fontSize: 8, fontWeight: 700, color: '#fff', background: 'rgba(0,0,0,.45)', padding: '1px 5px', borderRadius: 3, fontFamily: 'monospace' }}>REF</span>
            </div>
          );
        }
        return null;
      })()}

      {/* Header */}
      <div style={{ padding: '9px 12px 7px', borderBottom: '1px solid #f1f5f9', background: isApproved ? 'rgba(34,197,94,.04)' : scfg.color + '0d', display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ fontSize: 18, fontWeight: 700, color: scfg.color, lineHeight: 1 }}>{scfg.step}</span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12, fontWeight: 700, color: '#1d2e38', fontFamily: 'Montserrat, sans-serif' }}>{scfg.label}</div>
          <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace' }}>{pr.plataforma || scfg.plat}{pr.ratio ? ' · ' + pr.ratio : ''}</div>
        </div>
        {isApproved && <span style={{ fontSize: 10, color: '#16a34a', fontWeight: 700 }}>✓</span>}
        {isFlagged  && <span style={{ fontSize: 10, color: '#ea580c', fontWeight: 700 }}>⚑</span>}
      </div>

      {/* Conteúdo */}
      <div style={{ padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 8, flex: 1 }}>
        {composicaoSpec ? (
          <>
            {composicaoSpec.copy_overlay && (
              <div style={{ background: 'rgba(56,89,208,.06)', borderRadius: 7, padding: '8px 10px' }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: '#1d2e38', fontFamily: 'Montserrat, sans-serif', lineHeight: 1.3 }}>{composicaoSpec.copy_overlay}</div>
                {composicaoSpec.cta_overlay && <div style={{ fontSize: 11, color: '#3859D0', fontWeight: 600, marginTop: 3 }}>{composicaoSpec.cta_overlay} →</div>}
              </div>
            )}
            <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap' }}>
              {['overlay','headline_zone','logo_zone','accent_color'].map(k => composicaoSpec[k] && (
                <span key={k} style={{ fontSize: 9, color: '#64748b', background: '#f1f5f9', padding: '1px 6px', borderRadius: 4, fontFamily: 'monospace' }}>{k}: {String(composicaoSpec[k])}</span>
              ))}
            </div>
          </>
        ) : (
          <>
            <div style={{ fontSize: 11.5, color: '#475569', lineHeight: 1.65, fontFamily: 'Inter, sans-serif' }}>
              {expanded ? pr.prompt_texto : promptShort}
            </div>
            {pr.prompt_texto && pr.prompt_texto.length > 130 && (
              <button onClick={() => setExpanded(e => !e)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', fontSize: 10, color: '#3859D0', fontFamily: 'monospace', textAlign: 'left' }}>
                {expanded ? '▲ Colapsar' : '▼ Ver prompt completo'}
              </button>
            )}
          </>
        )}

        {/* Acções */}
        <div style={{ display: 'flex', gap: 6, paddingTop: 6, borderTop: '1px solid #f1f5f9', marginTop: 'auto' }}>
          {!isApproved ? (
            <>
              <button onClick={onApprove} className="btn btn-ai" style={{ fontSize: 10, height: 24, padding: '0 10px' }}>✓ Aprovar</button>
              <button onClick={onFlag}    className="btn" style={{ fontSize: 10, height: 24, padding: '0 8px', color: '#fb923c', borderColor: 'rgba(251,146,60,.3)' }}>⚑</button>
            </>
          ) : (
            <span style={{ fontSize: 10, color: '#16a34a', fontWeight: 600 }}>✓ Aprovado</span>
          )}
          {pr.tipo !== 'composicao' && (
            <button onClick={handleCopy} className="btn" style={{ fontSize: 10, height: 24, padding: '0 8px', color: copied ? '#16a34a' : '#64748b', marginLeft: 'auto' }}>
              {copied ? '✓' : '⎘'}
            </button>
          )}
        </div>
      </div>
    </div>
  );
};

// ── TabPromptsFull ────────────────────────────────────────────────────────────
const EditPromptModal = ({ prompt: p, onClose, onSave }) => {
  const GOOGLE_FONTS = ['Montserrat','Inter','Poppins','Raleway','Open Sans','Roboto','Lato','Nunito','Work Sans','Barlow','Exo 2','Bebas Neue','Oswald','Playfair Display','Source Sans Pro'];
  const ovRaw = p?.overlay_config ? (typeof p.overlay_config === 'string' ? (() => { try { return JSON.parse(p.overlay_config); } catch { return {}; } })() : p.overlay_config) : {};
  const [form, setForm] = React.useState({
    prompt_visual:   p?.prompt_visual || p?.prompt_texto || '',
    prompt_video:    p?.prompt_video || '',
    headline_imagem: p?.headline_imagem || '',
    cta_imagem:      p?.cta_imagem || '',
    font_family:     ovRaw.font_family || 'Montserrat',
    font_weight:     ovRaw.font_weight || '700',
    text_color:      ovRaw.text_color || '#FFFFFF',
    copy_overlay:    ovRaw.copy_overlay || '',
    cta_overlay:     ovRaw.cta_overlay || '',
    overlay:         ovRaw.overlay || 'dark_gradient',
    overlay_opacity: ovRaw.overlay_opacity ? String(ovRaw.overlay_opacity) : '0.55',
    accent_color:    ovRaw.accent_color || '',
    headline_zone:   ovRaw.headline_zone || ovRaw.text_position || 'bottom',
  });
  const [showAdvanced, setShowAdvanced] = React.useState(false);

  const lbl = (text) => (
    <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.05em', display: 'block', marginBottom: 5 }}>{text}</label>
  );
  const inp = (key, placeholder) => (
    <input value={form[key]} onChange={e => setForm(f => ({...f, [key]: e.target.value}))} placeholder={placeholder || ''} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', boxSizing: 'border-box' }} />
  );

  const handleSave = () => {
    const ovOut = { copy_overlay: form.copy_overlay, cta_overlay: form.cta_overlay, overlay: form.overlay, overlay_opacity: parseFloat(form.overlay_opacity)||0.55, accent_color: form.accent_color, headline_zone: form.headline_zone, cta_zone: ovRaw.cta_zone || 'bottom', logo_zone: ovRaw.logo_zone || 'top-left', font_family: form.font_family, font_weight: form.font_weight, text_color: form.text_color, background: 'transparent', ...( ovRaw.animation ? { animation: ovRaw.animation } : {} ), ...( ovRaw.text_timing_start ? { text_timing_start: ovRaw.text_timing_start, text_timing_end: ovRaw.text_timing_end } : {} ), ...( ovRaw.notes ? { notes: ovRaw.notes } : {} ) };
    onSave(p.id, { prompt_visual: form.prompt_visual, prompt_video: form.prompt_video, headline_imagem: form.headline_imagem, cta_imagem: form.cta_imagem, overlay_config: JSON.stringify(ovOut) });
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,.45)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
      <div style={{ background: '#fff', borderRadius: 14, width: '100%', maxWidth: 600, maxHeight: '90vh', overflow: 'auto', boxShadow: '0 20px 60px rgba(0,0,0,.2)' }}>
        <div style={{ padding: '20px 24px', borderBottom: '1px solid var(--border,#e2e8f0)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ fontSize: 14, fontWeight: 700, fontFamily: 'var(--font-display,Montserrat,sans-serif)' }}>Editar Prompts — {CANAL_LABEL[p?.canal] || p?.canal}</div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 18, color: '#94a3b8' }}>×</button>
        </div>
        <div style={{ padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>

          {/* Secção 1 — Texto/Headline + Tipografia */}
          <div style={{ background: 'rgba(124,58,237,.04)', border: '1px solid rgba(124,58,237,.15)', borderRadius: 8, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 10 }}>
            <div style={{ fontSize: 9, fontWeight: 700, color: '#7c3aed', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.07em' }}>1 · Texto / Headline</div>
            <div>{lbl('Headline da Imagem')}{inp('headline_imagem')}</div>
            <div>{lbl('CTA da Imagem')}{inp('cta_imagem')}</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 100px 80px', gap: 10 }}>
              <div>
                {lbl('Tipo de Letra (Google Fonts)')}
                <select value={form.font_family} onChange={e => setForm(f => ({...f, font_family: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', background: '#fff', fontFamily: form.font_family }}>
                  {GOOGLE_FONTS.map(fnt => <option key={fnt} value={fnt} style={{ fontFamily: fnt }}>{fnt}</option>)}
                </select>
              </div>
              <div>
                {lbl('Peso')}
                <select value={form.font_weight} onChange={e => setForm(f => ({...f, font_weight: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', background: '#fff' }}>
                  <option value="400">Regular</option>
                  <option value="600">Semi-Bold</option>
                  <option value="700">Bold</option>
                  <option value="800">Extra-Bold</option>
                  <option value="900">Black</option>
                </select>
              </div>
              <div>
                {lbl('Cor texto')}
                <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                  <input type="color" value={form.text_color} onChange={e => setForm(f => ({...f, text_color: e.target.value}))} style={{ width: 40, height: 36, padding: 2, border: '1px solid var(--border,#e2e8f0)', borderRadius: 6, cursor: 'pointer', background: '#fff' }} />
                  <input value={form.text_color} onChange={e => setForm(f => ({...f, text_color: e.target.value}))} style={{ flex: 1, padding: '8px 6px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 12, outline: 'none', fontFamily: 'monospace' }} />
                </div>
              </div>
            </div>
            {/* Preview da tipografia */}
            <div style={{ background: '#1d2e38', borderRadius: 8, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 9, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', flexShrink: 0 }}>Preview</span>
              <span style={{ fontSize: 18, fontWeight: parseInt(form.font_weight), color: form.text_color, fontFamily: `'${form.font_family}', sans-serif` }}>
                {form.headline_imagem || 'Headline da imagem'}
              </span>
            </div>
          </div>

          {/* Secção 2 — Fundo */}
          <div style={{ background: 'rgba(56,89,208,.04)', border: '1px solid rgba(56,89,208,.15)', borderRadius: 8, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 10 }}>
            <div style={{ fontSize: 9, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.07em' }}>2 · Prompt Fundo (Flux / Kling)</div>
            <div>
              {lbl('Prompt Fundo (Flux)')}
              <textarea value={form.prompt_visual} onChange={e => setForm(f => ({...f, prompt_visual: e.target.value}))} rows={3} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, fontFamily: 'var(--font-body,Inter,sans-serif)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
            </div>
            <div>
              {lbl('Prompt Vídeo (Kling)')}
              <textarea value={form.prompt_video} onChange={e => setForm(f => ({...f, prompt_video: e.target.value}))} rows={2} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, fontFamily: 'var(--font-body,Inter,sans-serif)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
            </div>
          </div>

          {/* Secção 3 — Composição */}
          <div style={{ background: 'rgba(5,150,105,.04)', border: '1px solid rgba(5,150,105,.15)', borderRadius: 8, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 10 }}>
            <div style={{ fontSize: 9, fontWeight: 700, color: '#059669', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.07em' }}>3 · Composição Final (Bannerbear / Puppeteer)</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <div>{lbl('Copy Overlay')}{inp('copy_overlay')}</div>
              <div>{lbl('CTA Overlay')}{inp('cta_overlay')}</div>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
              <div>
                {lbl('Overlay')}
                <select value={form.overlay} onChange={e => setForm(f => ({...f, overlay: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', background: '#fff' }}>
                  <option value="dark_gradient">Dark gradient</option>
                  <option value="light_gradient">Light gradient</option>
                  <option value="none">Sem overlay</option>
                </select>
              </div>
              <div>{lbl('Opacidade (0-1)')}{inp('overlay_opacity', '0.55')}</div>
              <div>{lbl('Accent color')}{inp('accent_color', '#hex')}</div>
            </div>
            <div>
              {lbl('Posição do texto')}
              <select value={form.headline_zone} onChange={e => setForm(f => ({...f, headline_zone: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', background: '#fff' }}>
                <option value="bottom">Bottom</option>
                <option value="center">Centro</option>
                <option value="top">Top</option>
                <option value="bottom_third">Bottom third</option>
              </select>
            </div>
          </div>

        </div>
        <div style={{ padding: '16px 24px', borderTop: '1px solid var(--border,#e2e8f0)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button onClick={onClose} className="btn">Cancelar</button>
          <button onClick={handleSave} className="btn btn-ai">Guardar Prompts</button>
        </div>
      </div>
    </div>
  );
};

const EditCopyModal = ({ copy: cp, onClose, onSave }) => {
  const isCriativo = cp?._mode === 'criativo';
  const [form, setForm] = React.useState(isCriativo
    ? { copy_imagem: cp?.copy_imagem || cp?.headline || '', cta_imagem: cp?.cta || '', prompt_visual: cp?.prompt_visual || '' }
    : { headline: cp?.headline || '', body: cp?.body || cp?.caption_organica || '', cta: cp?.cta || '', hashtags: cp?.hashtags || '', prompt_visual: cp?.prompt_visual || '' }
  );

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,.45)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
      <div style={{ background: '#fff', borderRadius: 14, width: '100%', maxWidth: 540, maxHeight: '90vh', overflow: 'auto', boxShadow: '0 20px 60px rgba(0,0,0,.2)' }}>
        <div style={{ padding: '20px 24px', borderBottom: '1px solid var(--border,#e2e8f0)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ fontSize: 14, fontWeight: 700, fontFamily: 'var(--font-display,Montserrat,sans-serif)' }}>
            {isCriativo ? 'Editar Sugestão Criativa' : 'Editar Copy'} — {CANAL_LABEL[cp?.canal] || cp?.canal}
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 18, color: '#94a3b8' }}>×</button>
        </div>
        <div style={{ padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {isCriativo ? (
            <>
              {[{ key: 'copy_imagem', label: 'Headline Imagem' }, { key: 'cta_imagem', label: 'CTA Imagem' }].map(f => (
                <div key={f.key}>
                  <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.05em', display: 'block', marginBottom: 5 }}>{f.label}</label>
                  <input value={form[f.key]} onChange={e => setForm(fv => ({...fv, [f.key]: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', boxSizing: 'border-box' }} />
                </div>
              ))}
              <div>
                <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.05em', display: 'block', marginBottom: 5 }}>Descrição Visual</label>
                <textarea value={form.prompt_visual} onChange={e => setForm(fv => ({...fv, prompt_visual: e.target.value}))} rows={3} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, fontFamily: 'var(--font-body,Inter,sans-serif)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
              </div>
            </>
          ) : (
            <>
              {[{ key: 'headline', label: 'Headline', type: 'input' }, { key: 'body', label: 'Copy / Caption', type: 'textarea' }, { key: 'cta', label: 'CTA', type: 'input' }, { key: 'hashtags', label: 'Hashtags', type: 'input' }, { key: 'prompt_visual', label: 'Descrição Visual', type: 'textarea' }].map(f => (
                <div key={f.key}>
                  <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.05em', display: 'block', marginBottom: 5 }}>{f.label}</label>
                  {f.type === 'textarea'
                    ? <textarea value={form[f.key]} onChange={e => setForm(fv => ({...fv, [f.key]: e.target.value}))} rows={f.key === 'prompt_visual' ? 3 : 4} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, fontFamily: 'var(--font-body,Inter,sans-serif)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }} />
                    : <input value={form[f.key]} onChange={e => setForm(fv => ({...fv, [f.key]: e.target.value}))} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', boxSizing: 'border-box' }} />
                  }
                </div>
              ))}
            </>
          )}
        </div>
        <div style={{ padding: '16px 24px', borderTop: '1px solid var(--border,#e2e8f0)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button onClick={onClose} className="btn">Cancelar</button>
          <button onClick={() => onSave(cp.id, form)} className="btn btn-ai">Guardar</button>
        </div>
      </div>
    </div>
  );
};

const TabPromptsFull = ({ campanha, prompts, onAction, generating }) => {
  const copyDone = (campanha?.copy || []).some(c => c.status === 'aprovado') || campanha?.big_idea;
  const [expandedPromptRows, setExpandedPromptRows] = React.useState({});
  const [editingPrompt, setEditingPrompt] = React.useState(null);
  const togglePromptRow = (id) => setExpandedPromptRows(p => ({ ...p, [id]: !p[id] }));

  // Canais dinâmicos — todos os copy sem filtro de canal
  const allCopy    = campanha?.copy || [];
  const orgVisual  = allCopy.filter(c => !c.copy_type || c.copy_type === 'organico');
  const perfVisual = allCopy.filter(c => c.copy_type === 'performance');
  const MODELO_LABEL = {
    flux2_pro: 'Flux2 Pro', flux: 'Flux2 Pro',
    kling3: 'Kling3', kling: 'Kling3',
    bannerbear: 'Bannerbear',
    'fal-ai/nano-banana-pro/edit': 'Nano Banana Pro 2',
    'nano-banana-pro': 'Nano Banana Pro 2',
  };

  // Timer de progresso — exactamente igual ao Copy/Canais/Conceito
  const promptStepRef = React.useRef(null);
  const [promptPct, setPromptPct] = React.useState(0);
  React.useEffect(() => {
    if (!generating.prompts) { setPromptPct(0); return; }
    promptStepRef.current = Date.now();
    setPromptPct(0);
  }, [generating.prompts]);
  React.useEffect(() => {
    if (!generating.prompts) return;
    const iv = setInterval(() => {
      const elapsed = Date.now() - (promptStepRef.current || Date.now());
      setPromptPct(Math.min((elapsed / 20000) * 90, 90));
    }, 80);
    return () => clearInterval(iv);
  }, [generating.prompts]);
  const overallPct = Math.round(promptPct);

  if (generating.prompts) {
    const TYPE_LABEL = { post:'Post', reel:'Reel', story:'Story', carrossel:'Carrossel', email:'Email', blog_post:'Blog', video:'Vídeo', rsa:'RSA', mensagem:'WA' };

    // Progressão por item — exactamente igual ao Copy (orgDone/perfDone baseado em overallPct)
    const perfDone = Math.floor((overallPct / 90) * perfVisual.length);
    const orgDone  = Math.max(0, Math.floor((overallPct / 90) * (perfVisual.length + orgVisual.length)) - perfVisual.length);

    // Dot — ✓/●/○ igual ao Copy
    const PDot = ({ done, active }) => {
      if (done) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', background: 'rgba(21,128,61,.12)', border: '1.5px solid rgba(21,128,61,.3)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="8" height="8" viewBox="0 0 10 10" fill="none"><polyline points="1.5,5 4,7.5 8.5,2.5" stroke="#15803d" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
      );
      if (active) return (
        <div style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid #3859D0', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ width: 7, height: 7, borderRadius: '50%', background: '#3859D0', animation: 'cpulse 1s infinite' }} />
        </div>
      );
      return <div style={{ width: 16, height: 16, borderRadius: '50%', border: '1.5px solid #e2e8f0', flexShrink: 0 }} />;
    };

    const PromptLoadTable = ({ items, isOrg, doneCount }) => (
      <div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
          <div style={{ width: 3, height: 14, borderRadius: 2, background: isOrg ? '#059669' : '#0ea5e9', flexShrink: 0 }} />
          <span style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: isOrg ? '#059669' : '#0ea5e9', fontFamily: 'var(--font-mono,monospace)' }}>
            {isOrg ? 'Orgânico' : 'Performance'} · {doneCount}/{items.length}
          </span>
        </div>
        <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
          <colgroup><col style={{ width: 24 }}/><col style={{ width: 200 }}/><col style={{ width: 70 }}/><col/></colgroup>
          <thead>
            <tr style={{ background: 'var(--bg-app,#f5f6f8)', borderBottom: '1px solid var(--border,#e2e8f0)' }}>
              <th style={{ padding: '5px 4px' }}/>
              <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Canal</th>
              <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Tipo</th>
              <th style={{ padding: '5px 8px', textAlign: 'left', fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase' }}>Conteúdo</th>
            </tr>
          </thead>
          <tbody>
            {items.map((cp, idx) => {
              const isDone   = idx < doneCount;
              const isActive = idx === doneCount;
              const text = (cp.copy_imagem || cp.headline || cp.item_title || '').slice(0, 80);
              const tc = isDone ? '#374151' : isActive ? 'var(--text,#1d2e38)' : '#94a3b8';
              return (
                <tr key={cp.id || idx} style={{ borderBottom: '1px solid var(--border-light,#f1f5f9)', opacity: !isDone && !isActive && idx > doneCount + 1 ? 0.45 : 1, transition: 'opacity 0.3s' }}>
                  <td style={{ padding: '6px 4px', verticalAlign: 'middle' }}><PDot done={isDone} active={isActive} /></td>
                  <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                    <span style={{ fontSize: 10, fontWeight: 700, padding: '1px 6px', borderRadius: 4, background: isDone ? 'rgba(21,128,61,.08)' : 'var(--bg-app,#f5f6f8)', color: isDone ? '#15803d' : '#64748b', fontFamily: 'monospace', whiteSpace: 'nowrap', display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 188 }}>
                      {CANAL_LABEL[cp.canal] || cp.canal}
                    </span>
                  </td>
                  <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                    <span style={{ fontSize: 9, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase' }}>{TYPE_LABEL[cp.content_type] || cp.content_type || '—'}</span>
                  </td>
                  <td style={{ padding: '6px 8px', verticalAlign: 'middle' }}>
                    <span style={{ fontSize: 12, color: tc, fontWeight: isActive ? 600 : 400, fontFamily: 'var(--font-body,Inter,sans-serif)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{text || '—'}</span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );

    return (
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderRadius: 10, padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <style>{`@keyframes cpulse { 0%,100%{opacity:1} 50%{opacity:.25} }`}</style>
        {/* Barra de progresso — exactamente igual ao Copy/Canais/Conceito */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ flex: 1, height: 4, borderRadius: 99, background: 'var(--bg-app,#f5f6f8)', overflow: 'hidden' }}>
            <div style={{ height: '100%', borderRadius: 99, background: '#3859D0', width: `${overallPct}%`, transition: 'width 0.1s linear' }} />
          </div>
          <span style={{ fontSize: 11, fontWeight: 700, color: '#3859D0', fontFamily: 'var(--font-mono,monospace)', flexShrink: 0 }}>{overallPct}%</span>
          <span style={{ fontSize: 11, color: '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)', flexShrink: 0 }}>Prompts visuais · ~20s</span>
        </div>
        {/* Performance primeiro, Orgânico depois — igual às outras fases */}
        {perfVisual.length > 0 && <PromptLoadTable items={perfVisual} isOrg={false} doneCount={perfDone} />}
        {orgVisual.length > 0  && <PromptLoadTable items={orgVisual}  isOrg={true}  doneCount={orgDone}  />}
      </div>
    );
  }

  if (!copyDone) return (
    <div style={{ padding: '32px 0', textAlign: 'center', color: 'var(--text-muted,#64748b)', fontSize: 13 }}>
      Aprova pelo menos um canal de copy antes de gerar prompts visuais.
    </div>
  );

  const total = prompts.length;
  const organicPrompts = prompts.filter(p => p.copy_type === 'organico' || !p.copy_type);
  const perfPrompts    = prompts.filter(p => p.copy_type === 'performance');

  const thStPr = { padding: '8px 12px', textAlign: 'left', fontSize: 10, fontWeight: 700, color: '#64748b', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.05em' };

  const PromptRow = ({ p }) => {
    const isExpanded = expandedPromptRows[p.id];
    const [showArtDir, setShowArtDir] = React.useState(false);
    const tipoConteudo = p.tipo_conteudo || (p.prompt_video ? 'video' : (p.tipo && ['video_produto','video_operador','video'].includes(p.tipo) ? 'video' : 'imagem'));
    const modelKey = p.model_used || p.modelo || (tipoConteudo === 'video' ? 'kling3' : 'flux2_pro');
    const modelo = MODELO_LABEL[modelKey] || (modelKey?.includes('nano-banana') ? 'Nano Banana Pro 2' : 'Flux2 Pro');
    const conceitoVisual = p.conceito_visual || p.estilo || (p.headline_imagem ? `${p.headline_imagem} · "${p.cta_imagem || ''}"` : (p.prompt_texto ? p.prompt_texto.slice(0, 80) + (p.prompt_texto.length > 80 ? '…' : '') : '—'));
    const promptVisualText = p.prompt_visual || p.prompt_texto || '';

    // Parse brand_asset_refs (JSONB) — contains image_urls from new Nano Banana pipeline
    const brandRefs = (() => {
      if (!p.brand_asset_refs) return null;
      if (typeof p.brand_asset_refs === 'string') {
        try { return JSON.parse(p.brand_asset_refs); } catch { return null; }
      }
      return p.brand_asset_refs;
    })();
    const refImageUrls = brandRefs?.image_urls || [];
    const refStrategy  = brandRefs?.strategy || null;
    const hasNewRefs   = refImageUrls.length > 0;
    const hasLegacyRef = !!p.imagem_referencia;

    return (
      <React.Fragment>
        <tr style={{ borderBottom: '1px solid var(--border,#e2e8f0)', cursor: 'pointer', background: isExpanded ? 'rgba(56,89,208,.02)' : 'transparent' }} onClick={() => togglePromptRow(p.id)}>
          <td style={{ padding: '10px 12px' }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{CANAL_LABEL[p.canal] || p.canal}</div>
          </td>
          <td style={{ padding: '10px 12px' }}>
            <div style={{ display: 'flex', gap: 4, alignItems: 'center', flexWrap: 'wrap' }}>
              <span style={{
                fontSize: 10, padding: '2px 8px', borderRadius: 99, fontWeight: 600,
                background: tipoConteudo === 'video' ? 'rgba(239,68,68,.08)' : 'rgba(56,89,208,.08)',
                color: tipoConteudo === 'video' ? '#dc2626' : '#3859D0',
                border: `1px solid ${tipoConteudo === 'video' ? 'rgba(239,68,68,.2)' : 'rgba(56,89,208,.2)'}`,
                fontFamily: 'monospace',
              }}>
                {tipoConteudo === 'video' ? 'Vídeo' : 'Imagem'}
              </span>
              <span style={{ fontSize: 10, color: '#64748b', fontFamily: 'monospace' }}>· {modelo}</span>
            </div>
          </td>
          <td style={{ padding: '10px 12px', maxWidth: 280 }}>
            <div style={{ fontSize: 12, color: 'var(--text,#1d2e38)', lineHeight: 1.4 }}>
              {conceitoVisual.slice(0, 100)}{conceitoVisual.length > 100 ? '…' : ''}
            </div>
          </td>
          <td style={{ padding: '10px 12px' }}>
            <div style={{ display: 'flex', gap: 4 }}>
              <button onClick={e => { e.stopPropagation(); onAction('regeneratePrompt', p.id); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Regenerar">⟳</button>
              <button onClick={e => { e.stopPropagation(); setEditingPrompt(p); }} style={{ background: 'none', border: '1px solid var(--border,#e2e8f0)', borderRadius: 5, padding: '3px 6px', cursor: 'pointer', fontSize: 11, color: '#64748b' }} title="Editar">✏</button>
              <span style={{ fontSize: 11, color: '#94a3b8', padding: '3px 4px' }}>{isExpanded ? '▴' : '▾'}</span>
            </div>
          </td>
        </tr>
        {isExpanded && (
          <tr>
            <td colSpan={4} style={{ padding: '0', background: 'rgba(56,89,208,.02)' }}>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>

                {/* ── SECÇÃO 1: Texto / Headline — 1fr | 1fr ── */}
                {(() => {
                  const ov = p.overlay_config ? (typeof p.overlay_config === 'string' ? (() => { try { return JSON.parse(p.overlay_config); } catch { return {}; } })() : p.overlay_config) : {};
                  const overlayTool = tipoConteudo === 'video' ? 'Puppeteer' : 'Bannerbear';
                  if (!p.headline_imagem && !p.cta_imagem) return null;
                  const secColor = '#7c3aed';
                  return (
                    <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--border-light,#f1f5f9)' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
                        <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: secColor, fontFamily: 'var(--font-mono,monospace)' }}>1 · Texto / Headline da Imagem</div>
                        <span style={{ fontSize: 9, padding: '2px 7px', borderRadius: 99, background: `rgba(124,58,237,.1)`, color: secColor, fontFamily: 'var(--font-mono,monospace)', fontWeight: 700 }}>{overlayTool}</span>
                      </div>
                      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
                        {/* Coluna esq — conteúdo */}
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                          <div>
                            <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 4 }}>Headline</div>
                            <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', lineHeight: 1.35, fontFamily: 'var(--font-display,Montserrat,sans-serif)' }}>{p.headline_imagem || '—'}</div>
                          </div>
                          <div>
                            <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 4 }}>CTA</div>
                            <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>{p.cta_imagem || '—'}</div>
                          </div>
                          <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginTop: 8, flexWrap: 'wrap' }}>
                            <div style={{ width: 18, height: 18, borderRadius: 4, background: ov.text_color || '#FFFFFF', border: '1px solid rgba(0,0,0,.15)' }} title={`Cor: ${ov.text_color || '#FFFFFF'}`} />
                            <span style={{ fontSize: 11, color: '#64748b', fontFamily: 'var(--font-mono,monospace)' }}>{ov.font_family || 'Montserrat'} {ov.font_weight || '700'}</span>
                            <span style={{ fontSize: 11, color: '#64748b', fontFamily: 'var(--font-mono,monospace)' }}>{ov.text_color || '#FFFFFF'}</span>
                            <span style={{ fontSize: 9, padding: '1px 6px', borderRadius: 3, background: 'rgba(5,150,105,.08)', color: '#059669', fontFamily: 'monospace' }}>{ov.background || 'transparent'}</span>
                          </div>
                        </div>
                        {/* Coluna dir — "prompt" Bannerbear como JSON */}
                        <div>
                          <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 4 }}>Prompt {overlayTool}</div>
                          <div style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.7, background: 'var(--bg-app,#f5f6f8)', padding: '10px 14px', borderRadius: 8, fontFamily: 'var(--font-mono,monospace)', whiteSpace: 'pre-wrap', overflowX: 'auto' }}>
                            {JSON.stringify(ov, null, 2)}
                          </div>
                          {ov.notes && <div style={{ marginTop: 6, fontSize: 11, color: '#64748b', fontStyle: 'italic', lineHeight: 1.5 }}>{ov.notes}</div>}
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* ── SECÇÃO 2: Fundo (Flux/Kling) — 1fr | 1fr ── */}
                {(promptVisualText || p.prompt_video) && (() => {
                  const secColor = tipoConteudo === 'video' ? '#dc2626' : '#3859D0';
                  const secBg    = tipoConteudo === 'video' ? 'rgba(220,38,38,.1)' : 'rgba(56,89,208,.1)';
                  return (
                    <div style={{ padding: '14px 16px' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
                        <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: secColor, fontFamily: 'var(--font-mono,monospace)' }}>
                          2 · {tipoConteudo === 'video' ? 'Prompt Vídeo' : 'Prompt Fundo'}
                        </div>
                        <span style={{ fontSize: 9, padding: '2px 7px', borderRadius: 99, background: secBg, color: secColor, fontFamily: 'var(--font-mono,monospace)', fontWeight: 700 }}>{modelo}</span>
                      </div>
                      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
                        {/* Coluna esq — imagens de referência (Nano Banana: benchmark + product refs) */}
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                          {hasNewRefs ? (
                            <>
                              <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                                <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase' }}>
                                  Refs ({refImageUrls.length}) · {modelo} input
                                </div>
                                {refStrategy && (
                                  <span style={{ fontSize: 8, padding: '1px 6px', borderRadius: 3, background: 'rgba(56,89,208,.08)', color: '#3859D0', fontFamily: 'monospace', fontWeight: 700, textTransform: 'uppercase' }}>
                                    {refStrategy}
                                  </span>
                                )}
                              </div>
                              <div style={{ display: 'grid', gridTemplateColumns: refImageUrls.length > 1 ? 'repeat(2, 1fr)' : '1fr', gap: 6 }}>
                                {refImageUrls.map((url, idx) => (
                                  <a key={idx} href={url} target="_blank" rel="noreferrer" onClick={e => e.stopPropagation()} style={{ display: 'block', position: 'relative' }}>
                                    <img src={url} alt={`ref ${idx + 1}`} style={{ width: '100%', borderRadius: 6, border: '1px solid var(--border,#e2e8f0)', objectFit: 'cover', background: '#fff', cursor: 'zoom-in', display: 'block', aspectRatio: '1', maxHeight: 140 }} onError={e => { e.target.style.opacity='0.3'; }} />
                                    <span style={{ position: 'absolute', top: 4, left: 4, fontSize: 8, fontWeight: 700, color: '#fff', background: 'rgba(0,0,0,.55)', padding: '1px 5px', borderRadius: 3, fontFamily: 'monospace' }}>@img{idx + 1}</span>
                                  </a>
                                ))}
                              </div>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>Clica para ver completa</div>
                            </>
                          ) : hasLegacyRef ? (
                            <>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase' }}>Imagem Referência ({modelo} input)</div>
                              <a href={p.imagem_referencia} target="_blank" rel="noreferrer" onClick={e => e.stopPropagation()} style={{ display: 'block' }}>
                                <img src={p.imagem_referencia} alt="referência" style={{ width: '100%', borderRadius: 8, border: '1px solid var(--border,#e2e8f0)', objectFit: 'contain', background: '#fff', cursor: 'zoom-in', display: 'block', maxHeight: 180 }} onError={e => { e.target.style.display='none'; }} />
                              </a>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>Clica para ver completa</div>
                            </>
                          ) : (
                            <div style={{ fontSize: 12, color: '#94a3b8', fontStyle: 'italic', padding: '20px 0' }}>Sem imagem de referência</div>
                          )}
                        </div>
                        {/* Coluna dir — prompt prose */}
                        <div>
                          <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 4 }}>Prompt {modelo}</div>
                          <div style={{ fontSize: 12, color: 'var(--text,#1d2e38)', lineHeight: 1.7, background: 'var(--bg-app,#f5f6f8)', padding: '10px 14px', borderRadius: 8, whiteSpace: 'pre-wrap', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>
                            {promptVisualText || p.prompt_video}
                          </div>
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* ── SECÇÃO 3: Composição Final (merge Fundo + Texto) — 1fr | 1fr ── */}
                {(() => {
                  const ov = p.overlay_config ? (typeof p.overlay_config === 'string' ? (() => { try { return JSON.parse(p.overlay_config); } catch { return {}; } })() : p.overlay_config) : {};
                  const overlayTool = tipoConteudo === 'video' ? 'Puppeteer' : 'Bannerbear';
                  const mergePlatform = tipoConteudo === 'video' ? 'FFmpeg / Puppeteer' : 'Bannerbear Compositor';
                  const mergeConfig = {
                    platform: mergePlatform,
                    background_layer: `flux_output.${tipoConteudo === 'video' ? 'mp4' : 'png'}`,
                    text_layer: `${overlayTool.toLowerCase()}_text.png`,
                    blend_mode: 'normal',
                    output_format: tipoConteudo === 'video' ? 'MP4' : 'PNG',
                    font_family: ov.font_family || 'Montserrat',
                    font_weight: ov.font_weight || '700',
                    text_color: ov.text_color || '#FFFFFF',
                    text_position: ov.headline_zone || ov.text_position || 'bottom',
                    logo_zone: ov.logo_zone || 'top-left',
                    overlay_type: ov.overlay || 'dark_gradient',
                    overlay_opacity: ov.overlay_opacity || 0.55,
                    accent_color: ov.accent_color,
                    ...(tipoConteudo === 'video' && ov.text_timing_start ? { text_in: ov.text_timing_start, text_out: ov.text_timing_end, animation: ov.animation } : {}),
                  };
                  return (
                    <div style={{ padding: '14px 16px', borderTop: '1px solid var(--border-light,#f1f5f9)' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
                        <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#059669', fontFamily: 'var(--font-mono,monospace)' }}>3 · Composição Final</div>
                        <span style={{ fontSize: 9, padding: '2px 7px', borderRadius: 99, background: 'rgba(5,150,105,.1)', color: '#059669', fontFamily: 'var(--font-mono,monospace)', fontWeight: 700 }}>{mergePlatform}</span>
                      </div>
                      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
                        {/* Coluna esq — inputs do merge */}
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                          <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 2 }}>Inputs</div>
                          {[
                            { label: 'Fundo', value: mergeConfig.background_layer, color: '#3859D0' },
                            { label: 'Texto (PNG)', value: mergeConfig.text_layer, color: '#7c3aed' },
                            { label: 'Output', value: mergeConfig.output_format },
                            { label: 'Blend', value: mergeConfig.blend_mode },
                          ].map(f => (
                            <div key={f.label} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                              <span style={{ fontSize: 9, fontWeight: 700, color: f.color || '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', minWidth: 50 }}>{f.label}</span>
                              <span style={{ fontSize: 11, color: 'var(--text,#1d2e38)', fontFamily: 'monospace' }}>{f.value}</span>
                            </div>
                          ))}
                        </div>
                        {/* Coluna dir — prompt de merge como JSON */}
                        <div>
                          <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', marginBottom: 4 }}>Prompt {mergePlatform}</div>
                          <div style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.7, background: 'var(--bg-app,#f5f6f8)', padding: '10px 14px', borderRadius: 8, fontFamily: 'var(--font-mono,monospace)', whiteSpace: 'pre-wrap', overflowX: 'auto' }}>
                            {JSON.stringify(mergeConfig, null, 2)}
                          </div>
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* ── SECÇÃO 4: Art Direction (creative_plan) — collapsível ── */}
                {(() => {
                  const cp = p.creative_plan
                    ? (typeof p.creative_plan === 'string' ? (() => { try { return JSON.parse(p.creative_plan); } catch { return null; } })() : p.creative_plan)
                    : null;
                  if (!cp) return null;

                  const MODEL_COLORS = {
                    'fal-ai/nano-banana/edit':     { bg: 'rgba(5,150,105,.1)',  color: '#059669', label: 'nano-banana · product preserve' },
                    'fal-ai/flux-pro/v1.1-ultra':  { bg: 'rgba(56,89,208,.1)', color: '#3859D0', label: 'Flux Pro Ultra · photoreal'      },
                    'fal-ai/flux-pro/v1.1':        { bg: 'rgba(56,89,208,.07)',color: '#3859D0', label: 'Flux Pro · background'           },
                    'fal-ai/ideogram-v2':           { bg: 'rgba(124,58,237,.1)',color: '#7c3aed', label: 'Ideogram v2 · text rendering'   },
                    'fal-ai/recraft-v3':            { bg: 'rgba(234,88,12,.1)', color: '#ea580c', label: 'Recraft v3 · graphic design'    },
                  };
                  const modelStyle = MODEL_COLORS[cp.model] || { bg: 'rgba(100,116,139,.1)', color: '#64748b', label: cp.model || 'modelo' };

                  return (
                    <div style={{ padding: '12px 16px', borderTop: '1px solid var(--border-light,#f1f5f9)' }}>
                      {/* Header clicável */}
                      <div
                        onClick={() => setShowArtDir(v => !v)}
                        style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer', userSelect: 'none' }}
                      >
                        <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#c026d3', fontFamily: 'var(--font-mono,monospace)' }}>
                          4 · Art Direction
                        </div>
                        <span style={{ fontSize: 9, padding: '2px 8px', borderRadius: 99, background: modelStyle.bg, color: modelStyle.color, fontFamily: 'var(--font-mono,monospace)', fontWeight: 700 }}>
                          {modelStyle.label}
                        </span>
                        {cp.copy_anchor?.tension_or_promise && (
                          <span style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', marginLeft: 4 }}>
                            · {cp.copy_anchor.tension_or_promise}
                          </span>
                        )}
                        <span style={{ marginLeft: 'auto', fontSize: 10, color: '#94a3b8' }}>{showArtDir ? '▲' : '▼'}</span>
                      </div>

                      {showArtDir && (
                        <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 12 }}>

                          {/* Copy anchor */}
                          {cp.copy_anchor && (
                            <div style={{ background: 'rgba(192,38,211,.05)', border: '1px solid rgba(192,38,211,.15)', borderRadius: 8, padding: '10px 14px' }}>
                              <div style={{ fontSize: 9, fontWeight: 700, color: '#c026d3', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 6 }}>Copy Anchor</div>
                              <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                                {[
                                  ['Headline echoes', cp.copy_anchor.headline_echoes],
                                  ['CTA supports',    cp.copy_anchor.cta_supports],
                                  ['Tension/Promise', cp.copy_anchor.tension_or_promise],
                                ].filter(([,v]) => v).map(([k, v]) => (
                                  <div key={k} style={{ display: 'flex', gap: 8 }}>
                                    <span style={{ fontSize: 9, fontWeight: 700, color: '#94a3b8', minWidth: 100, fontFamily: 'monospace', textTransform: 'uppercase' }}>{k}</span>
                                    <span style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.5 }}>{v}</span>
                                  </div>
                                ))}
                              </div>
                            </div>
                          )}

                          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                            {/* Coluna esq — Image refs */}
                            <div>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 6 }}>Referências R2 ({(cp.image_urls || []).length})</div>
                              {(cp.image_urls || []).length > 0 ? (
                                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                                  {cp.image_urls.map((url, i) => (
                                    <a key={i} href={url} target="_blank" rel="noreferrer" style={{ display: 'block', flexShrink: 0 }}>
                                      <img src={url} alt={`ref ${i+1}`} style={{ width: 72, height: 72, objectFit: 'cover', borderRadius: 6, border: '1px solid var(--border,#e2e8f0)', cursor: 'zoom-in' }} onError={e => { e.target.style.display='none'; }} />
                                    </a>
                                  ))}
                                </div>
                              ) : (
                                <div style={{ fontSize: 11, color: '#94a3b8', fontStyle: 'italic' }}>Sem refs R2 — geração text-to-image</div>
                              )}
                              {cp.image_urls_rationale && (
                                <div style={{ marginTop: 6, fontSize: 10, color: '#64748b', lineHeight: 1.5 }}>{cp.image_urls_rationale}</div>
                              )}

                              {/* Negative cues */}
                              {(cp.negative_cues || []).length > 0 && (
                                <div style={{ marginTop: 10 }}>
                                  <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 4 }}>Negative cues</div>
                                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                                    {cp.negative_cues.map((nc, i) => (
                                      <span key={i} style={{ fontSize: 9, padding: '2px 7px', borderRadius: 99, background: 'rgba(239,68,68,.08)', color: '#dc2626', fontFamily: 'monospace', border: '1px solid rgba(239,68,68,.2)' }}>{nc}</span>
                                    ))}
                                  </div>
                                </div>
                              )}
                            </div>

                            {/* Coluna dir — Art Direction details */}
                            <div>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 6 }}>Direcção Fotográfica</div>
                              {cp.art_direction ? (
                                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                                  {[
                                    ['Lens',        cp.art_direction.lens],
                                    ['Grain',       cp.art_direction.grain],
                                    ['Lighting',    cp.art_direction.lighting],
                                    ['Composition', cp.art_direction.composition],
                                  ].filter(([,v]) => v).map(([k, v]) => (
                                    <div key={k} style={{ display: 'flex', gap: 8 }}>
                                      <span style={{ fontSize: 9, fontWeight: 700, color: '#94a3b8', minWidth: 75, fontFamily: 'monospace', textTransform: 'uppercase' }}>{k}</span>
                                      <span style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.5 }}>{v}</span>
                                    </div>
                                  ))}
                                  {cp.art_direction.rationale && (
                                    <div style={{ marginTop: 4, padding: '6px 10px', background: 'var(--bg-app,#f5f6f8)', borderRadius: 6, fontSize: 10, color: '#64748b', lineHeight: 1.5, fontStyle: 'italic' }}>
                                      {cp.art_direction.rationale}
                                    </div>
                                  )}
                                </div>
                              ) : (
                                <div style={{ fontSize: 11, color: '#94a3b8', fontStyle: 'italic' }}>—</div>
                              )}

                              {/* Model rationale */}
                              {cp.model_rationale && (
                                <div style={{ marginTop: 10 }}>
                                  <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 4 }}>Modelo · Justificação</div>
                                  <div style={{ fontSize: 10, color: '#64748b', lineHeight: 1.5, padding: '6px 10px', background: modelStyle.bg, borderRadius: 6, border: `1px solid ${modelStyle.color}22` }}>
                                    {cp.model_rationale}
                                  </div>
                                </div>
                              )}
                            </div>
                          </div>

                          {/* Enriched prompt */}
                          {cp.enriched_prompt && (
                            <div>
                              <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 4 }}>Prompt Enriquecido (Art Director)</div>
                              <div style={{ fontSize: 11, color: 'var(--text,#1d2e38)', lineHeight: 1.7, background: 'var(--bg-app,#f5f6f8)', padding: '10px 14px', borderRadius: 8, fontFamily: 'var(--font-mono,monospace)', whiteSpace: 'pre-wrap', overflowX: 'auto' }}>
                                {cp.enriched_prompt}
                              </div>
                            </div>
                          )}
                        </div>
                      )}
                    </div>
                  );
                })()}

              </div>
            </td>
          </tr>
        )}
      </React.Fragment>
    );
  };

  const renderPromptsSection = (items, isOrganic) => {
    if (!items.length) return null;
    const accentColor = isOrganic ? '#059669' : '#0ea5e9';
    const label       = isOrganic ? 'Orgânico · Plano de Comunicação' : 'Performance · Anúncios Pagos';
    const countLabel  = isOrganic ? `${items.length} peças` : `${items.length} ads`;
    return (
      <CollapsBlock key={isOrganic ? 'org' : 'perf'} title={label} count={countLabel} defaultOpen={true} accentColor={accentColor}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr style={{ background: 'var(--bg-app,#f5f6f8)' }}>
              <th style={thStPr}>Canal</th>
              <th style={thStPr}>Tipo · Modelo</th>
              <th style={thStPr}>Conceito Visual</th>
              <th style={thStPr}>Acções</th>
            </tr>
          </thead>
          <tbody>
            {items.map(p => <PromptRow key={p.id} p={p} />)}
          </tbody>
        </table>
      </CollapsBlock>
    );
  };

  // Empty state — padrão centrado igual às outras fases
  if (total === 0) return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '64px 0', gap: 20 }}>
      <div style={{ width: 56, height: 56, borderRadius: 14, background: 'rgba(236,72,153,.08)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ec4899" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>
        </svg>
      </div>
      <div style={{ textAlign: 'center' }}>
        <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 10 }}>Prompts Visuais por gerar</div>
        <div style={{ display: 'flex', gap: 12, justifyContent: 'center', flexWrap: 'wrap' }}>
          {perfVisual.length > 0 && (
            <div style={{ background: 'rgba(14,165,233,.06)', border: '1px solid rgba(14,165,233,.2)', borderRadius: 10, padding: '10px 18px', textAlign: 'left' }}>
              <div style={{ fontSize: 10, fontWeight: 700, color: '#0ea5e9', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 4 }}>Performance</div>
              <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontWeight: 600 }}>{perfVisual.length} {perfVisual.length === 1 ? 'canal' : 'canais'}</div>
            </div>
          )}
          {orgVisual.length > 0 && (
            <div style={{ background: 'rgba(5,150,105,.06)', border: '1px solid rgba(5,150,105,.2)', borderRadius: 10, padding: '10px 18px', textAlign: 'left' }}>
              <div style={{ fontSize: 10, fontWeight: 700, color: '#059669', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 4 }}>Orgânico</div>
              <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontWeight: 600 }}>{orgVisual.length} {orgVisual.length === 1 ? 'peça' : 'peças'}</div>
            </div>
          )}
        </div>
      </div>
      <button onClick={() => onAction('generatePrompts')} disabled={generating.prompts} className="btn btn-ai" style={{ fontSize: 13, padding: '10px 24px' }} data-tutorial-step="prompts">
        Gerar Prompts com Digi AI
      </button>
    </div>
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* Secções — Performance primeiro, Orgânico depois */}
      {renderPromptsSection(perfPrompts, false)}
      {renderPromptsSection(organicPrompts, true)}


      {/* Modal de edição de prompt */}
      {editingPrompt && (
        <EditPromptModal
          prompt={editingPrompt}
          onClose={() => setEditingPrompt(null)}
          onSave={(id, data) => { onAction('saveCopy', id, data); setEditingPrompt(null); }}
        />
      )}
    </div>
  );
};

// ── TabAprovacao ───────────────────────────────────────────────────────────────
const MKT_APPROVERS = ['fabio.costa@digidelta.pt', 'rui.leitao@digidelta.pt', 'armando.mota@digidelta.pt', 'joao.paulino@digidelta.pt'];

// ── Modais de Aprovação ────────────────────────────────────────────────────────
const PedirAlteracoesAprovacaoModal = ({ onClose, onConfirm }) => {
  const [notes,    setNotes]    = React.useState('');
  const [revertTo, setRevertTo] = React.useState('conceito');
  // Apenas fases de Campanhas Marketing (Copy/Prompts/Idiomas ficam em Produção de Conteúdos)
  const FASES = [
    { value: 'briefing',     label: 'Briefing' },
    { value: 'estrategia',   label: 'Estratégia' },
    { value: 'conceito',     label: 'Conceito Criativo' },
    { value: 'orcamento',    label: 'Orçamento' },
    { value: 'segmentacao',  label: 'Target' },
    { value: 'planeamento',  label: 'Planeamento' },
    { value: 'funil',        label: 'Funil Multicanal' },
  ];
  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,.45)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
      <div style={{ background: '#fff', borderRadius: 14, maxWidth: 520, width: '100%', padding: '28px', boxShadow: '0 20px 60px rgba(0,0,0,.2)' }}>
        <div style={{ fontSize: 16, fontWeight: 700, color: '#d97706', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 16 }}>Pedir Alterações</div>
        <div style={{ marginBottom: 14 }}>
          <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', display: 'block', marginBottom: 6 }}>Voltar à fase</label>
          <select value={revertTo} onChange={e => setRevertTo(e.target.value)} style={{ width: '100%', padding: '8px 12px', border: '1px solid var(--border,#e2e8f0)', borderRadius: 8, fontSize: 13, outline: 'none', background: '#fff' }}>
            {FASES.map(f => <option key={f.value} value={f.value}>{f.label}</option>)}
          </select>
        </div>
        <div style={{ marginBottom: 20 }}>
          <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', display: 'block', marginBottom: 6 }}>O que precisa de ser corrigido (obrigatório)</label>
          <textarea value={notes} onChange={e => setNotes(e.target.value)} rows={4} placeholder="Descreve o que precisa de ser corrigido antes de aprovares…" style={{ width: '100%', padding: '8px 12px', border: `1px solid ${notes.length < 10 && notes.length > 0 ? '#dc2626' : 'var(--border,#e2e8f0)'}`, borderRadius: 8, fontSize: 13, outline: 'none', resize: 'vertical', boxSizing: 'border-box', fontFamily: 'var(--font-body,Inter,sans-serif)' }} />
        </div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn" onClick={() => onConfirm(notes, revertTo)} disabled={notes.trim().length < 10} style={{ color: '#d97706', borderColor: '#d97706', opacity: notes.trim().length < 10 ? 0.5 : 1 }}>Confirmar Pedido</button>
        </div>
      </div>
    </div>
  );
};

const RejeitarCampanhaModal = ({ onClose, onConfirm }) => {
  const [notes, setNotes] = React.useState('');
  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,.45)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
      <div style={{ background: '#fff', borderRadius: 14, maxWidth: 480, width: '100%', padding: '28px', boxShadow: '0 20px 60px rgba(0,0,0,.2)' }}>
        <div style={{ fontSize: 16, fontWeight: 700, color: '#dc2626', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 8 }}>Rejeitar Campanha</div>
        <div style={{ fontSize: 13, color: '#64748b', marginBottom: 16, lineHeight: 1.55 }}>A campanha voltará ao início (Conceito) para ser refeita. Esta acção não é reversível.</div>
        <div style={{ marginBottom: 20 }}>
          <label style={{ fontSize: 11, fontWeight: 600, color: '#64748b', fontFamily: 'monospace', textTransform: 'uppercase', display: 'block', marginBottom: 6 }}>Motivo (obrigatório)</label>
          <textarea value={notes} onChange={e => setNotes(e.target.value)} rows={4} placeholder="Descreve o motivo da rejeição…" style={{ width: '100%', padding: '8px 12px', border: '1px solid rgba(220,38,38,.3)', borderRadius: 8, fontSize: 13, outline: 'none', resize: 'vertical', boxSizing: 'border-box', fontFamily: 'var(--font-body,Inter,sans-serif)' }} />
        </div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn" onClick={() => onConfirm(notes)} disabled={notes.trim().length < 10} style={{ color: '#dc2626', borderColor: '#dc2626', opacity: notes.trim().length < 10 ? 0.5 : 1 }}>Confirmar Rejeição</button>
        </div>
      </div>
    </div>
  );
};

const TabAprovacao = ({ campanha, onAction, userEmail }) => {
  const isApprover   = MKT_APPROVERS.includes((userEmail || '').toLowerCase()) || canActOnCampaign(userEmail);
  const status       = campanha?.status || '';
  const isPending    = ['pending_executive','em_aprovacao'].includes(status);
  const isInProducao = ['em_producao','publicado'].includes(status);
  const bCol         = _brandColor(campanha?.brand_slug);

  const [showPedirAlt, setShowPedirAlt] = React.useState(false);
  const [showRejeitar, setShowRejeitar] = React.useState(false);
  const [submitting,   setSubmitting]   = React.useState(false);
  const [sending,      setSending]      = React.useState(false);
  const [boardData,    setBoardData]    = React.useState(null);

  // Derivar statuses directamente das colunas de timestamp — sem API calls extra
  const orcStatus  = campanha?.orcamento_approved_at  ? 'approved' : campanha?.orcamento_generated_at  ? 'done' : 'pending';
  const segStatus  = campanha?.segmentacao_approved_at ? 'approved' : campanha?.segmentacao_generated_at ? 'done' : 'pending';
  const planStatus = campanha?.planeamento_approved_at ? 'approved' : campanha?.planeamento_generated_at ? 'done' : 'pending';

  // Fetch dados para o Investment Case (orcamento + segmentacao)
  React.useEffect(() => {
    if (!campanha?.id) return;
    Promise.all([
      campApiCall(`/api/marketing/campanhas/${campanha.id}/orcamento`).catch(() => ({ rows: [] })),
      campApiCall(`/api/marketing/campanhas/${campanha.id}/segmentacao`).catch(() => ({ rows: [] })),
    ]).then(([orc, seg]) => {
      const totalBudget = (orc.rows || []).reduce((s, r) => s + (parseFloat(r.valor_eur) || 0), 0);
      const segRows = seg.rows || [];
      const emailContacts = segRows.filter(r => r.canal === 'email')
        .reduce((s, r) => s + ((typeof r.audiencia_json === 'object' ? r.audiencia_json?.n_contactos : null) || 0), 0);
      const waContacts = segRows.filter(r => r.canal === 'whatsapp')
        .reduce((s, r) => s + ((typeof r.audiencia_json === 'object' ? r.audiencia_json?.n_contactos : null) || 0), 0);
      const hasMetaAds = segRows.some(r => r.canal === 'meta_ads');
      const metaCountries = [...new Set(segRows.filter(r => r.canal === 'meta_ads').map(r => r.country))].length;
      setBoardData({ totalBudget, emailContacts, waContacts, hasMetaAds, metaCountries });
    });
  }, [campanha?.id]);

  const approvals = campanha?.camp_approvals || [];
  const brief     = campanha?.briefing || {};
  const markets   = campanha?.estrategia_json?.markets || [];
  const commPlan  = campanha?.proposta_json?.comm_plan || [];
  const allChs    = [...new Set(markets.flatMap(m => (m.channel_fit || []).map(c => c.canal)))];
  const chLabels  = { meta_ads:'Meta Ads', email:'Email', linkedin_ads:'LinkedIn Ads', whatsapp:'WhatsApp', website:'Blog/Website', muppi_led:'LED/Muppi', google_ads_search:'Google Search' };
  const usps      = Array.isArray(brief.usps) ? brief.usps : [];
  const pains     = Array.isArray(brief.pain_points) ? brief.pain_points : [];

  const CAMP_PHASES = [
    { id:'briefing',    label:'Briefing',          tab:'briefing',
      status: campanha?.briefing ? 'approved' : 'pending',
      detail: brief.commercial_name || campanha?.titulo || '—' },
    { id:'estrategia',  label:'Estratégia',         tab:'estrategia',
      status: campanha?.estrategia_approved_at ? 'approved' : campanha?.estrategia_json?.markets?.length ? 'done' : 'pending',
      detail: markets.length ? `${markets.map(m=>m.country).join(' + ')} · ${markets.length} mercado(s)` : 'Não gerada' },
    { id:'conceito',    label:'Conceito Criativo',  tab:'conceito',
      status: campanha?.conceito_approved_at ? 'approved' : campanha?.big_idea ? 'done' : 'pending',
      detail: campanha?.big_idea ? campanha.big_idea.slice(0,70)+'…' : 'Não gerado' },
    { id:'orcamento',   label:'Orçamento',           tab:'orcamento',
      status: orcStatus || 'pending',
      detail: orcStatus === 'approved' ? 'Aprovado' : orcStatus === 'done' ? 'Gerado — aguarda aprovação' : 'Não gerado' },
    { id:'segmentacao', label:'Target',              tab:'segmentacao',
      status: segStatus || 'pending',
      detail: segStatus === 'approved' ? 'Aprovada' : segStatus === 'done' ? 'Gerada — aguarda aprovação' : 'Não gerada' },
    { id:'planeamento', label:'Planeamento',         tab:'planeamento',
      status: planStatus || 'pending',
      detail: planStatus === 'approved' ? 'Aprovado' : planStatus === 'partial' ? 'Parcialmente aprovado' : planStatus === 'done' ? 'Gerado — aguarda aprovação' : 'Não gerado' },
    { id:'funil',       label:'Funil Multicanal',    tab:'funil',
      status: markets.length ? (isPending || isInProducao ? 'approved' : 'done') : 'pending',
      detail: markets.length ? `${allChs.map(c=>chLabels[c]||c).join(' · ')} · 5 layers` : 'Depende da Estratégia' },
  ];
  // ── Investment Case — dados do simulador + orcamento + segmentacao ─────────
  const PHT50_PRICE = 75; // €/pack — Tabela Mimaki Julho 2026 (PVP — custo real Digidelta será inferior)

  // EQUIP_DB: família de equipamentos com preços e cenários
  // family: modelos da mesma série ordenados do mais barato para o mais caro
  const EQUIP_DB = {
    'TxF150-75':   { pvp: 12800, total: 19103, promo: 8800,  promoPacks: 24, digirent: 395.11, family: ['TxF150-75','TxF300-75','TxF300-1600'] },
    'TxF300-75':   { pvp: 17300, total: null,  promo: 13400, promoPacks: 75, digirent: 316.45, family: ['TxF150-75','TxF300-75','TxF300-1600'] },
    'TxF300-1600': { pvp: 19900, total: null,  promo: null,  promoPacks:  0, digirent: 411.60, family: ['TxF150-75','TxF300-75','TxF300-1600'] },
    'TS200-1600':  { pvp: 32000, total: null,  promo: 25000, promoPacks:  0, digirent: null,   family: ['TS200-1600','TS500-1800'] },
    'TS500-1800':  { pvp: 49000, total: null,  promo: null,  promoPacks:  0, digirent: null,   family: ['TS200-1600','TS500-1800'] },
    'UCJV330-160': { pvp: 23800, total: null,  promo: 19800, promoPacks:  0, digirent: 492.26, family: ['UCJV300-75','UCJV330-160'] },
  };
  const SCENARIO_LABELS = ['Conservador', 'Base', 'Optimista'];

  const equip       = EQUIP_DB[brief.product_name] || null;
  const offerRaw2   = brief.commercial_offer;
  const offer2      = offerRaw2 ? (typeof offerRaw2 === 'string' ? (() => { try { return JSON.parse(offerRaw2); } catch { return { descricao: offerRaw2 }; } })() : offerRaw2) : {};
  const isPromo     = !!(offer2.condicao && /promo|summer|special/i.test(JSON.stringify(offer2)));

  // Cenários: família de modelos → conservador/base/optimista
  const familyModels  = equip?.family?.map(k => ({ key: k, ...EQUIP_DB[k] })).filter(Boolean) || (equip ? [{ key: brief.product_name, ...equip }] : []);
  const scenarioCount = familyModels.length;
  // Preço âncora = modelo do briefing (promo se existir, senão pvp)
  const pvp           = equip ? (isPromo && equip.promo ? equip.promo : (equip.total || equip.pvp)) : null;
  const pvpLabel      = equip ? (isPromo && equip.promo ? `€${equip.promo.toLocaleString('pt-PT')} promo` : equip.total ? `€${equip.total.toLocaleString('pt-PT')} configurado` : `€${equip.pvp?.toLocaleString('pt-PT')} base`) : null;

  const totalBudget   = boardData?.totalBudget   || 0;
  const emailContacts = boardData?.emailContacts || 0;
  const waContacts    = boardData?.waContacts    || 0;

  // Funil estimado B2B — benchmarks conservadores sector equipamento industrial
  const metaReach   = (boardData?.metaCountries || 1) * 100000;
  const metaLeads   = Math.round(metaReach * 0.015 * 0.04);
  const emailLeads  = Math.round(emailContacts * 0.28 * 0.03 * 0.20);
  const waLeads     = Math.round(waContacts * 0.40 * 0.15);
  const totalLeads  = metaLeads + emailLeads + waLeads;
  const hotLeads    = Math.round(totalLeads * 0.15);
  const demos       = Math.round(hotLeads * 0.65);
  const sales       = Math.max(1, Math.round(demos * 0.20));

  // Custo da oferta a PVP (nota: custo real Digidelta será inferior)
  const inkPacksPromo   = (isPromo && equip?.promoPacks) ? equip.promoPacks : 0;
  const offerCostUnit   = inkPacksPromo * PHT50_PRICE;   // PVP — conservador
  const totalOfferCost  = offerCostUnit * sales;
  const totalInvestment = totalBudget + totalOfferCost;

  // ROI por cenário (família de modelos)
  const scenarioROI = familyModels.map((m, i) => {
    const mPvp   = isPromo && m.promo ? m.promo : (m.total || m.pvp);
    const mOffer = (isPromo && m.promoPacks) ? m.promoPacks * PHT50_PRICE : 0;
    const mInvest = totalBudget + mOffer * sales;
    const mRev   = sales * mPvp;
    const mRoi   = mInvest > 0 ? Math.round((mRev - mInvest) / mInvest) : null;
    const mBE    = mInvest > 0 ? mInvest / mPvp : null;
    const label  = scenarioCount === 1 ? 'Único' : (SCENARIO_LABELS[i] || SCENARIO_LABELS[SCENARIO_LABELS.length-1]);
    return { key: m.key, label, pvp: mPvp, offer: mOffer, revenue: mRev, invest: mInvest, roi: mRoi, be: mBE };
  });

  // ROI âncora (modelo do briefing)
  const anchorIdx = familyModels.findIndex(m => m.key === brief.product_name);
  const anchorROI = scenarioROI[anchorIdx >= 0 ? anchorIdx : 0];
  // Timeline
  const tlStart = brief.timeline_start ? new Date(brief.timeline_start) : null;
  const tlEnd   = brief.timeline_end   ? new Date(brief.timeline_end)   : null;
  const tlDays  = tlStart && tlEnd ? Math.round((tlEnd - tlStart) / 864e5) : null;
  const fmtShort = d => d ? d.toLocaleDateString('pt-PT', { day:'numeric', month:'short' }) : '—';

  const InvestmentCase = () => (
    <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
      <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', letterSpacing:'.08em', textTransform:'uppercase', color:'var(--text-dim)', marginBottom:2 }}>
        Investment Case · visão executiva
      </div>

      {/* Row 1: Investimento + Equipamento + Timeline */}
      <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:10 }}>
        {[
          { lbl:'Investimento media',   val: totalBudget > 0 ? `€${Math.round(totalBudget).toLocaleString('pt-PT')}` : '—', sub: tlDays ? `${tlDays} dias de campanha` : null, col:'#3859D0' },
          { lbl:'Equipamento · ' + (isPromo ? 'Promo' : 'Total config.'), val: pvpLabel || '—', sub: brief.product_name || null, col:'#0F4C75' },
          { lbl:'Janela temporal',      val: tlStart ? `${fmtShort(tlStart)} → ${fmtShort(tlEnd)}` : '—', sub: tlDays ? `${tlDays} dias` : null, col:'#065F46' },
        ].map((c,i) => (
          <div key={i} style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderTop:`3px solid ${c.col}`, borderRadius:8, padding:'12px 14px' }}>
            <div style={{ fontSize:9, fontWeight:700, color:c.col, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:4 }}>{c.lbl}</div>
            <div style={{ fontSize:18, fontWeight:800, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', lineHeight:1 }}>{c.val}</div>
            {c.sub && <div style={{ fontSize:10, color:'var(--text-muted)', marginTop:4 }}>{c.sub}</div>}
          </div>
        ))}
      </div>

      {/* Row 2: Funil estimado */}
      {totalLeads > 0 && (
        <div style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderRadius:8, padding:'14px 16px' }}>
          <div style={{ fontSize:9, fontWeight:700, color:'var(--text-dim)', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:10 }}>Funil estimado · benchmarks B2B sector equipamento</div>
          <div style={{ display:'flex', alignItems:'center', gap:0 }}>
            {[
              { lbl:'Reach', val: `${(metaReach/1000).toFixed(0)}K+`, sub:'Meta Ads', col:'#0F4C75' },
              { lbl:'Leads', val: totalLeads, sub:`Meta ${metaLeads} · Email ${emailLeads} · WA ${waLeads}`, col:'#3859D0' },
              { lbl:'Qualificados', val: hotLeads, sub:'SDR Digi AI · 15%', col:'#065F46' },
              { lbl:'Demos', val: demos, sub:'Conversion 65%', col:'#92400E' },
              { lbl:'Fechos est.', val: sales, sub:'Close rate 20%', col:'#15803d' },
            ].map((s, i, arr) => (
              <React.Fragment key={i}>
                <div style={{ flex:1, textAlign:'center', padding:'6px 8px', background: i === arr.length-1 ? 'rgba(22,163,74,.07)' : 'transparent', borderRadius: i === arr.length-1 ? 6 : 0 }}>
                  <div style={{ fontSize:9, fontWeight:700, color:s.col, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em', marginBottom:3 }}>{s.lbl}</div>
                  <div style={{ fontSize:20, fontWeight:800, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', lineHeight:1 }}>{s.val}</div>
                  <div style={{ fontSize:9, color:'var(--text-muted)', marginTop:3, lineHeight:1.3 }}>{s.sub}</div>
                </div>
                {i < arr.length-1 && (
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#cbd5e1" strokeWidth="2" strokeLinecap="round"><polyline points="9 18 15 12 9 6"/></svg>
                )}
              </React.Fragment>
            ))}
          </div>
        </div>
      )}

      {/* Row 3: Investimento + Cenários ROI */}
      {scenarioROI.length > 0 && totalBudget > 0 && (
        <div style={{ display:'flex', flexDirection:'column', gap:10 }}>

          {/* Desdobramento do investimento (âncora) */}
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:8, padding:'10px 14px', background:'rgba(56,89,208,.04)', border:'1px solid rgba(56,89,208,.15)', borderRadius:8 }}>
            {[
              { lbl:'Investimento media', val:`€${Math.round(totalBudget).toLocaleString('pt-PT')}`, sub:'Ads + Email + WA' },
              { lbl:`Custo oferta* (${sales} vendas)`, val: offerCostUnit > 0 ? `€${Math.round(totalOfferCost).toLocaleString('pt-PT')}` : '—', sub: offerCostUnit > 0 ? `${sales}×${inkPacksPromo} packs×€${PHT50_PRICE} PVP` : 'sem oferta' },
              { lbl:'Investimento total', val:`€${Math.round(totalInvestment).toLocaleString('pt-PT')}`, sub:'media + custo oferta' },
            ].map((c,i) => (
              <div key={i}>
                <div style={{ fontSize:9, fontWeight:700, color:'#3859D0', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:3 }}>{c.lbl}</div>
                <div style={{ fontSize:15, fontWeight:800, color:'var(--navy,#112954)', fontFamily:'var(--font-display)' }}>{c.val}</div>
                <div style={{ fontSize:9, color:'var(--text-muted)', marginTop:2 }}>{c.sub}</div>
              </div>
            ))}
          </div>

          {/* Cenários ROI por modelo da família */}
          <div style={{ display:'grid', gridTemplateColumns:`repeat(${scenarioROI.length},1fr)`, gap:10 }}>
            {scenarioROI.map((sc, i) => {
              const isAnchor = sc.key === brief.product_name;
              const col = i === 0 ? '#64748b' : i === scenarioROI.length-1 ? '#15803d' : '#3859D0';
              const bg  = i === 0 ? 'rgba(100,116,139,.06)' : i === scenarioROI.length-1 ? 'rgba(22,163,74,.07)' : 'rgba(56,89,208,.06)';
              return (
                <div key={sc.key} style={{ background:bg, border:`1px solid var(--border)`, borderTop:`3px solid ${col}`, borderRadius:8, padding:'12px 14px', position:'relative' }}>
                  {isAnchor && <div style={{ position:'absolute', top:6, right:8, fontSize:8, fontWeight:700, color:col, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em', background:`${col}18`, padding:'1px 5px', borderRadius:3 }}>briefing</div>}
                  <div style={{ fontSize:9, fontWeight:700, color:col, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:6 }}>{sc.label} · {sc.key}</div>
                  <div style={{ display:'flex', flexDirection:'column', gap:4 }}>
                    <div>
                      <div style={{ fontSize:8, color:'var(--text-dim)', textTransform:'uppercase', letterSpacing:'.04em', fontFamily:'var(--font-mono)' }}>Preço equip.</div>
                      <div style={{ fontSize:14, fontWeight:800, color:'var(--navy,#112954)', fontFamily:'var(--font-display)' }}>€{sc.pvp.toLocaleString('pt-PT')}</div>
                    </div>
                    <div>
                      <div style={{ fontSize:8, color:'var(--text-dim)', textTransform:'uppercase', letterSpacing:'.04em', fontFamily:'var(--font-mono)' }}>Receita ({sales} vendas)</div>
                      <div style={{ fontSize:14, fontWeight:800, color:'var(--navy,#112954)', fontFamily:'var(--font-display)' }}>€{sc.revenue.toLocaleString('pt-PT')}</div>
                    </div>
                    <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:6, marginTop:4, paddingTop:6, borderTop:'1px solid var(--border-light,#f1f5f9)' }}>
                      <div>
                        <div style={{ fontSize:8, color:'var(--text-dim)', textTransform:'uppercase', letterSpacing:'.04em', fontFamily:'var(--font-mono)' }}>ROI</div>
                        <div style={{ fontSize:16, fontWeight:800, color: col, fontFamily:'var(--font-display)' }}>{sc.roi !== null ? `${sc.roi}×` : '—'}</div>
                      </div>
                      <div>
                        <div style={{ fontSize:8, color:'var(--text-dim)', textTransform:'uppercase', letterSpacing:'.04em', fontFamily:'var(--font-mono)' }}>Break-even</div>
                        <div style={{ fontSize:11, fontWeight:700, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', lineHeight:1.3 }}>
                          {sc.be !== null ? (sc.be < 1 ? `${(sc.be*100).toFixed(0)}% de 1 venda` : `${sc.be.toFixed(1)} vendas`) : '—'}
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>

          {offerCostUnit > 0 && (
            <div style={{ fontSize:9, color:'var(--text-dim)', fontStyle:'italic', lineHeight:1.5 }}>
              * Custo da oferta calculado a PVP (€{PHT50_PRICE}/pack) — custo real Digidelta será inferior. ROI subestimado.
            </div>
          )}
        </div>
      )}

      {/* Oferta comercial */}
      {(offer2.oferta || offer2.descricao) && (
        <div style={{ padding:'10px 14px', background:'rgba(146,64,14,.05)', border:'1px solid rgba(146,64,14,.2)', borderRadius:8, display:'flex', gap:10, alignItems:'flex-start' }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#92400E" strokeWidth="2" style={{ flexShrink:0, marginTop:1 }}><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
          <div>
            <div style={{ fontSize:10, fontWeight:700, color:'#92400E', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em', marginBottom:2 }}>Oferta comercial · campanha</div>
            <div style={{ fontSize:12, color:'var(--text)', lineHeight:1.5 }}>{offer2.oferta || offer2.descricao}{offer2.condicao ? ` — ${offer2.condicao}` : ''}{offer2.validade ? ` · Válida ${offer2.validade}` : ''}</div>
          </div>
        </div>
      )}

      <div style={{ fontSize:9, color:'var(--text-dim)', fontStyle:'italic', lineHeight:1.5, paddingTop:4 }}>
        * Funil estimado com base em benchmarks B2B sector equipamento industrial (Meta B2B CTR 1,5%, form conversion 4%, email open 28%, SDR qualify rate 15%). Valores reais dependem da qualidade das audiências e execução.
      </div>
    </div>
  );

  // Ordem: Briefing → Estratégia → Conceito → Orçamento → Target → Planeamento → Funil

  const SM = {
    approved: { label:'Aprovado', color:'#15803d', bg:'rgba(22,163,74,.1)',   dot:'#22c55e' },
    partial:  { label:'Parcial',  color:'#a16207', bg:'rgba(234,179,8,.1)',   dot:'#eab308' },
    done:     { label:'Pronto',   color:'#3859D0', bg:'rgba(56,89,208,.08)', dot:'#3859D0' },
    pending:  { label:'Pendente', color:'#94a3b8', bg:'var(--bg-sunken)',    dot:'#cbd5e1' },
  };

  const phasesDone     = CAMP_PHASES.filter(p => ['approved','done'].includes(p.status)).length;
  const phasesApproved = CAMP_PHASES.filter(p => p.status === 'approved').length;
  const pct            = Math.round((phasesDone / CAMP_PHASES.length) * 100);
  const canSubmit      = phasesDone >= 5; // briefing + estrategia + conceito + planeamento + funil minimamente

  const timeAgo = iso => { if (!iso) return null; const h = Math.floor((Date.now() - new Date(iso).getTime()) / 3600000); const d = Math.floor(h / 24); return h < 1 ? 'há menos de 1h' : h < 24 ? `há ${h}h` : `há ${d}d`; };
  const fmtDate = iso => iso ? new Date(iso).toLocaleDateString('pt-PT', { day:'numeric', month:'long', year:'numeric', hour:'2-digit', minute:'2-digit' }) : null;

  const approveRecord = approvals.find(a => a.phase === 'producao' && a.action === 'approved');
  const submitRecord  = approvals.find(a => a.action === 'approved' && a.phase !== 'producao') || approvals.find(a => a.phase === 'funil');

  // ─── STATE 3: Em Produção / Publicado ───────────────────────────────────────
  if (isInProducao) {
    const commPlanItems = campanha?.proposta_json?.comm_plan || [];
    const emailCount  = commPlanItems.filter(r => r.canal === 'email').length;
    const socialCount = commPlanItems.filter(r => ['instagram','facebook','linkedin'].includes(r.canal)).length;
    const adsCount    = commPlanItems.filter(r => ['meta_ads','linkedin_ads','google_ads_search'].includes(r.canal)).length;
    const approvedBy  = campanha?.funil_approved_by || approveRecord?.approver_name || approveRecord?.approver_email || null;
    const approvedAt  = campanha?.funil_approved_at || approveRecord?.created_at || null;
    return (
      <div style={{ display:'flex', flexDirection:'column', gap:20 }}>
        {/* Hero aprovada */}
        <div style={{ background:'rgba(22,163,74,.07)', border:'1px solid rgba(22,163,74,.25)', borderRadius:12, padding:'20px 24px' }}>
          <div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:4 }}>
            <div style={{ width:10, height:10, borderRadius:'50%', background:'#22c55e' }} />
            <div style={{ fontSize:15, fontWeight:700, color:'#15803d', fontFamily:'var(--font-display)' }}>
              {status === 'publicado' ? 'Campanha Publicada' : 'Aprovada — em Produção de Conteúdos'}
            </div>
          </div>
          {approvedBy && (
            <div style={{ fontSize:12, color:'#64748b', marginBottom:16 }}>
              Aprovado por <strong>{approvedBy}</strong>{approvedAt ? ` · ${fmtDate(approvedAt)}` : ''}
            </div>
          )}
          <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:10, marginBottom:16 }}>
            {[
              { lbl:'Emails planeados', val: emailCount  > 0 ? String(emailCount)  : '—' },
              { lbl:'Posts sociais',    val: socialCount > 0 ? String(socialCount) : '—' },
              { lbl:'Anúncios Ads',     val: adsCount    > 0 ? String(adsCount)    : '—' },
              { lbl:'Mercados',         val: markets.map(m=>m.country).join(' + ') || '—' },
            ].map((r,i) => (
              <div key={i} style={{ background:'rgba(22,163,74,.05)', borderRadius:8, padding:'10px 12px' }}>
                <div style={{ fontSize:9, fontWeight:700, color:'#94a3b8', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:3 }}>{r.lbl}</div>
                <div style={{ fontSize:18, fontWeight:800, color:'#112954', fontFamily:'var(--font-display)' }}>{r.val}</div>
              </div>
            ))}
          </div>
          <button onClick={() => { if (window.mktNavToSub) window.mktNavToSub('conteudos'); }}
            className="btn btn-ai" style={{ fontSize:13 }}>→ Acompanhar no Módulo Produção de Conteúdos</button>
        </div>
        <InvestmentCase />
        {/* Histórico */}
        <AprovacaoHistory approvals={approvals} timeAgo={timeAgo} campanha={campanha} />
      </div>
    );
  }

  // ─── STATE 2: Aguarda Aprovação Executiva ────────────────────────────────────
  if (isPending) {
    const sentBy = approvals.find(a => a.phase === 'funil' || !a.phase)?.approver_name || 'equipa marketing';
    return (
      <div style={{ display:'flex', flexDirection:'column', gap:20 }}>
        {/* Banner aguarda */}
        <div style={{ background:'#FEF3C7', border:'1px solid rgba(217,119,6,.3)', borderRadius:12, padding:'16px 20px', display:'flex', alignItems:'center', justifyContent:'space-between', gap:16 }}>
          <div>
            <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:4 }}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#92400E" strokeWidth="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
              <div style={{ fontSize:14, fontWeight:700, color:'#92400E', fontFamily:'var(--font-display)' }}>Aguarda Aprovação Executiva</div>
            </div>
            <div style={{ fontSize:12, color:'#92400E', opacity:.8 }}>Enviado por {sentBy} · Campanha "{campanha?.titulo}"</div>
          </div>
          {isApprover && (
            <div style={{ display:'flex', gap:8, flexShrink:0 }}>
              <button className="btn" style={{ color:'#d97706', borderColor:'rgba(217,119,6,.4)', fontSize:12 }}
                onClick={() => setShowPedirAlt(true)}>Pedir Alterações</button>
              <button className="btn" style={{ color:'#dc2626', borderColor:'rgba(220,38,38,.3)', fontSize:12 }}
                onClick={() => setShowRejeitar(true)}>Rejeitar</button>
              <button className="btn btn-ai" disabled={submitting} style={{ fontSize:12 }}
                onClick={async () => { setSubmitting(true); await onAction('enviarProducao').catch(()=>{}); setSubmitting(false); }}>
                {submitting ? 'A enviar...' : '→ Enviar para Produção de Conteúdos'}
              </button>
            </div>
          )}
        </div>

        {/* Resumo da campanha para revisão executiva */}
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
          {/* Info campanha */}
          <div style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderRadius:10, padding:'16px 18px' }}>
            <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.08em', color:'var(--text-dim)', marginBottom:12 }}>Campanha · Resumo para Aprovação</div>
            {[
              { lbl:'Marca',         val: campanha?.brand_name || '—' },
              { lbl:'Produto',       val: brief.commercial_name || campanha?.titulo || '—' },
              { lbl:'Mercados',      val: markets.map(m=>m.country).join(' + ') || '—' },
              { lbl:'Canais',        val: allChs.map(c=>chLabels[c]||c).join(' · ') || '—' },
              { lbl:'Objectivo',     val: brief.objective || '—' },
              { lbl:'Decisor',       val: brief.decision_maker || '—' },
            ].map((r,i) => (
              <div key={i} style={{ display:'flex', gap:8, padding:'6px 0', borderBottom:'1px solid var(--border-light,#f1f5f9)' }}>
                <div style={{ fontSize:10, fontWeight:700, color:'var(--text-dim)', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.04em', minWidth:90, flexShrink:0 }}>{r.lbl}</div>
                <div style={{ fontSize:12, color:'var(--text)', lineHeight:1.4 }}>{r.val}</div>
              </div>
            ))}
            {brief.key_message && (
              <div style={{ marginTop:10, padding:'8px 10px', background:'rgba(56,89,208,.05)', borderRadius:6, borderLeft:'3px solid #3859D0' }}>
                <div style={{ fontSize:9, fontWeight:700, color:'#3859D0', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:3 }}>Mensagem-chave</div>
                <div style={{ fontSize:12, color:'var(--text)', fontStyle:'italic', lineHeight:1.5 }}>"{brief.key_message}"</div>
              </div>
            )}
          </div>

          {/* USPs + Dores */}
          <div style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderRadius:10, padding:'16px 18px' }}>
            <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.08em', color:'var(--text-dim)', marginBottom:12 }}>Argumentos · Dores</div>
            {usps.length > 0 && (
              <div style={{ marginBottom:12 }}>
                <div style={{ fontSize:10, fontWeight:700, color:'#3859D0', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em', marginBottom:6 }}>Top USPs</div>
                {usps.slice(0,4).map((u,i) => (
                  <div key={i} style={{ display:'flex', gap:8, marginBottom:6 }}>
                    <div style={{ fontSize:12, fontWeight:800, color:'#3859D0', flexShrink:0, lineHeight:1.2 }}>{i+1}</div>
                    <div style={{ fontSize:11, color:'var(--text)', lineHeight:1.4 }}>{typeof u==='string'?u:u.usp||u.descricao||''}</div>
                  </div>
                ))}
              </div>
            )}
            {pains.length > 0 && (
              <div>
                <div style={{ fontSize:10, fontWeight:700, color:'#065F46', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em', marginBottom:6 }}>Dores dominantes</div>
                {pains.slice(0,3).map((p,i) => (
                  <div key={i} style={{ display:'flex', gap:8, marginBottom:5 }}>
                    <div style={{ width:5, height:5, borderRadius:'50%', background:'#065F46', flexShrink:0, marginTop:5 }} />
                    <div style={{ fontSize:11, color:'var(--text)', lineHeight:1.4 }}>{typeof p==='string'?p:p.descricao||''}</div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Fases — estado actual */}
        <div>
          <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', letterSpacing:'.08em', textTransform:'uppercase', color:'var(--text-dim)', marginBottom:10 }}>Estado das Fases ({phasesApproved}/{CAMP_PHASES.length} aprovadas)</div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:8 }}>
            {CAMP_PHASES.map(p => {
              const sm = SM[p.status] || SM.pending;
              return (
                <div key={p.id} style={{ background:'var(--bg-card,#fff)', border:`1px solid var(--border)`, borderTop:`3px solid ${sm.dot}`, borderRadius:8, padding:'10px 10px 8px' }}>
                  <div style={{ fontSize:9, fontWeight:700, color:sm.color, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.04em', marginBottom:4 }}>{sm.label}</div>
                  <div style={{ fontSize:11, fontWeight:700, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', lineHeight:1.2 }}>{p.label}</div>
                </div>
              );
            })}
          </div>
        </div>

        <InvestmentCase />
        <AprovacaoHistory approvals={approvals} timeAgo={timeAgo} campanha={campanha} />

        {showPedirAlt && <PedirAlteracoesAprovacaoModal onClose={() => setShowPedirAlt(false)} onConfirm={(notes, phase) => { onAction('pedirAlteracoes', [{ notes, phase }]); setShowPedirAlt(false); }} />}
        {showRejeitar && <RejeitarCampanhaModal onClose={() => setShowRejeitar(false)} onConfirm={(notes) => { onAction('rejeitarAprovacao', [notes]); setShowRejeitar(false); }} />}
      </div>
    );
  }

  // ─── STATE 1: Checklist — não submetido ─────────────────────────────────────
  return (
    <div style={{ display:'flex', flexDirection:'column', gap:20 }}>

      {/* Hero progresso */}
      <div style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderRadius:12, padding:'20px 24px' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:16, marginBottom:12 }}>
          <div>
            <div style={{ fontSize:15, fontWeight:700, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', marginBottom:3 }}>
              {phasesDone}/{CAMP_PHASES.length} fases concluídas
            </div>
            <div style={{ fontSize:12, color:'var(--text-muted)' }}>
              {canSubmit ? 'Pronto para submeter à aprovação executiva.' : `Completa as fases em falta antes de submeter.`}
            </div>
          </div>
          <div style={{ display:'flex', gap:8, flexShrink:0 }}>
            {canActOnCampaign(userEmail) && (<>
              <button className="btn" disabled={submitting || !canSubmit} style={{ opacity: canSubmit ? 1 : .5, fontSize: 12, height: 32, padding: '0 14px' }}
                onClick={async () => { setSubmitting(true); await onAction('enviarAprovacao').catch(()=>{}); setSubmitting(false); }}>
                Enviar para Aprovação Executiva
              </button>
              <button className="btn btn-ai" disabled={submitting || !canSubmit} style={{ opacity: canSubmit ? 1 : .5, fontSize: 12, height: 32, padding: '0 14px' }}
                onClick={async () => { setSubmitting(true); await onAction('enviarProducao').catch(()=>{}); setSubmitting(false); }}>
                {submitting ? 'A aprovar...' : 'Aprovar Internamente →'}
              </button>
            </>)}
          </div>
        </div>
        {/* Barra de progresso */}
        <div style={{ height:6, borderRadius:99, background:'var(--bg-sunken,#f1f5f9)', overflow:'hidden' }}>
          <div style={{ height:'100%', borderRadius:99, background: pct >= 80 ? '#22c55e' : pct >= 50 ? '#3859D0' : '#f59e0b', width:`${pct}%`, transition:'width .4s' }} />
        </div>
      </div>

      {/* Fases checklist */}
      <div>
        <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', letterSpacing:'.08em', textTransform:'uppercase', color:'var(--text-dim)', marginBottom:10 }}>Fases de Campanha Marketing</div>
        <div style={{ display:'flex', flexDirection:'column', gap:6 }}>
          {CAMP_PHASES.map(phase => {
            const sm = SM[phase.status] || SM.pending;
            return (
              <div key={phase.id} style={{ display:'flex', alignItems:'center', gap:12, padding:'12px 16px', background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderLeft:`3px solid ${sm.dot}`, borderRadius:8 }}>
                <div style={{ width:18, height:18, borderRadius:'50%', background:sm.bg, border:`1.5px solid ${sm.dot}`, display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
                  {phase.status === 'approved' && <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke={sm.color} strokeWidth="3"><polyline points="20 6 9 17 4 12"/></svg>}
                  {phase.status === 'done'     && <div style={{ width:6, height:6, borderRadius:'50%', background:sm.dot }} />}
                </div>
                <div style={{ flex:1, minWidth:0 }}>
                  <div style={{ fontSize:13, fontWeight:700, color:'var(--navy,#112954)', fontFamily:'var(--font-display)' }}>{phase.label}</div>
                  <div style={{ fontSize:11, color:'var(--text-muted)', marginTop:1 }}>{phase.detail}</div>
                </div>
                <span style={{ fontSize:10, fontWeight:700, padding:'2px 8px', borderRadius:20, background:sm.bg, color:sm.color, flexShrink:0 }}>{sm.label}</span>
              </div>
            );
          })}
        </div>
      </div>

      {!canSubmit && (
        <div style={{ background:'rgba(245,158,11,.06)', border:'1px solid rgba(245,158,11,.25)', borderRadius:8, padding:'12px 16px', fontSize:12, color:'#92400E', lineHeight:1.6 }}>
          Para submeter à aprovação executiva é necessário ter pelo menos Briefing, Estratégia, Conceito, Planeamento e Funil Multicanal concluídos.
        </div>
      )}

      <InvestmentCase />
      <AprovacaoHistory approvals={approvals} timeAgo={timeAgo} campanha={campanha} />
    </div>
  );
};

const AprovacaoHistory = ({ approvals, timeAgo, campanha }) => {
  const fmtExact = iso => iso ? new Date(iso).toLocaleString('pt-PT', { day:'2-digit', month:'short', year:'numeric', hour:'2-digit', minute:'2-digit' }) : '—';

  const ACTION_META = {
    generated:              { label:'Gerado',                        col:'#3859D0', bg:'rgba(56,89,208,.06)'  },
    approved:               { label:'Aprovado',                      col:'#15803d', bg:'rgba(22,163,74,.08)'  },
    rejected:               { label:'Rejeitado',                     col:'#dc2626', bg:'rgba(220,38,38,.07)'  },
    changes_requested:      { label:'Alterações pedidas',            col:'#d97706', bg:'rgba(217,119,6,.07)'  },
    request_changes:        { label:'Alterações pedidas',            col:'#d97706', bg:'rgba(217,119,6,.07)'  },
    submitted_for_approval: { label:'Enviado para aprovação exec.',  col:'#ea580c', bg:'rgba(234,88,12,.07)'  },
    reverted:               { label:'Revertido',                     col:'#64748b', bg:'rgba(100,116,139,.07)'},
  };

  const PHASE_LABEL = {
    estrategia:'Estratégia', conceito:'Conceito Criativo', orcamento:'Orçamento',
    segmentacao:'Target', planeamento:'Planeamento', funil:'Funil Multicanal',
    briefing:'Briefing', producao:'Produção', canais:'Canais', idiomas:'Idiomas',
  };

  // Construir eventos a partir das colunas de timestamp do campanha
  const tsEvents = [];
  const c = campanha || {};
  [
    ['estrategia',   c.estrategia_generated_at, null,                      c.estrategia_approved_at,   c.estrategia_approved_by  ],
    ['conceito',     c.conceito_generated_at,   null,                      c.conceito_approved_at,     c.conceito_approved_by    ],
    ['orcamento',    c.orcamento_generated_at,  null,                      c.orcamento_approved_at,    c.orcamento_approved_by   ],
    ['segmentacao',  c.segmentacao_generated_at,null,                      c.segmentacao_approved_at,  c.segmentacao_approved_by ],
    ['planeamento',  c.planeamento_generated_at,null,                      c.planeamento_approved_at,  c.planeamento_approved_by ],
  ].forEach(([phase, genAt, , appAt, appBy]) => {
    if (genAt) tsEvents.push({ action:'generated', phase, created_at: genAt, approver_name: null });
    if (appAt) tsEvents.push({ action:'approved',  phase, created_at: appAt, approver_name: appBy });
  });

  // Merge com camp_approvals — evitar duplicar aprovações já cobertas pelas colunas
  const coveredPhases = new Set(tsEvents.filter(e => e.action === 'approved').map(e => e.phase));
  const extraApprovals = (approvals || []).filter(a =>
    a.action !== 'approved' || !coveredPhases.has(a.phase)
  );

  const allEvents = [...tsEvents, ...extraApprovals]
    .filter(e => e.created_at)
    .sort((a, b) => new Date(a.created_at) - new Date(b.created_at));

  if (!allEvents.length) return null;

  return (
    <div>
      <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', letterSpacing:'.08em', textTransform:'uppercase', color:'var(--text-dim)', marginBottom:10 }}>
        Histórico de Decisões · {allEvents.length} eventos
      </div>
      <div style={{ display:'flex', flexDirection:'column', gap:6 }}>
        {allEvents.map((a, i) => {
          const meta  = ACTION_META[a.action] || { label: a.action, col:'#64748b', bg:'var(--bg-sunken)' };
          const name  = a.approver_name || a.approver_email?.split('@')[0] || null;
          const email = a.approver_email || null;
          const notes = a.notes || a.reject_notes || null;
          return (
            <div key={i} style={{ display:'grid', gridTemplateColumns:'auto 1fr auto', gap:12, alignItems:'flex-start', padding:'10px 14px', background:meta.bg, border:'1px solid var(--border)', borderRadius:8 }}>
              <div style={{ width:10, height:10, borderRadius:'50%', background:meta.col, marginTop:3, flexShrink:0 }} />
              <div>
                <div style={{ display:'flex', alignItems:'center', gap:6, flexWrap:'wrap', marginBottom: (name || email) ? 4 : 0 }}>
                  <span style={{ fontSize:12, fontWeight:700, color:meta.col }}>{meta.label}</span>
                  {a.phase && <span style={{ fontSize:10, fontFamily:'var(--font-mono)', color:'var(--text-dim)', background:'rgba(0,0,0,.06)', padding:'1px 7px', borderRadius:4 }}>{PHASE_LABEL[a.phase] || a.phase}</span>}
                </div>
                {(name || email) && (
                  <div style={{ display:'flex', alignItems:'center', gap:6 }}>
                    <div style={{ width:16, height:16, borderRadius:'50%', background:'var(--bg-sunken)', border:'1px solid var(--border)', display:'flex', alignItems:'center', justifyContent:'center', fontSize:8, fontWeight:700, color:'var(--text-dim)', fontFamily:'var(--font-mono)', flexShrink:0 }}>
                      {(name || email || '?')[0].toUpperCase()}
                    </div>
                    {name && <span style={{ fontSize:11, fontWeight:600, color:'var(--text)' }}>{name}</span>}
                    {email && <span style={{ fontSize:10, color:'var(--text-muted)', marginLeft: name ? 4 : 0 }}>{email}</span>}
                  </div>
                )}
                {notes && (
                  <div style={{ fontSize:11, color:'#92400E', marginTop:5, lineHeight:1.5, fontStyle:'italic', background:'rgba(146,64,14,.06)', padding:'5px 8px', borderRadius:5 }}>"{notes}"</div>
                )}
              </div>
              <div style={{ textAlign:'right', flexShrink:0 }}>
                <div style={{ fontSize:10, color:'var(--text-muted)', fontWeight:600 }}>{timeAgo(a.created_at)}</div>
                <div style={{ fontSize:9, color:'var(--text-dim)', marginTop:2, fontFamily:'var(--font-mono)' }}>{fmtExact(a.created_at)}</div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};


// ── TabProducao ────────────────────────────────────────────────────────────────
const TabProducao = ({ campanha, onAction, userEmail }) => {
  const [producaoStatus, setProducaoStatus] = React.useState(null);
  const [loadingStatus, setLoadingStatus]   = React.useState(true);
  const intervalRef = React.useRef(null);

  const status = campanha?.status;
  const isInProducao = ['em_producao', 'publicado'].includes(status);
  const approvals = campanha?.camp_approvals || [];
  const approveRecord   = approvals.find(a => a.phase === 'producao' && a.action === 'approved');
  const submitRecord    = approvals.find(a => a.phase === 'prompts'  && a.action === 'approved');

  const allCopy    = campanha?.copy || [];
  const allPrompts = campanha?.prompts || [];
  const payload    = campanha?.production_payload ? (typeof campanha.production_payload === 'string' ? (() => { try { return JSON.parse(campanha.production_payload); } catch { return null; } })() : campanha.production_payload) : null;

  const orgCount  = allCopy.filter(c => (!c.copy_type || c.copy_type === 'organico') && (!c.lingua || c.lingua === 'pt')).length;
  const perfCount = allCopy.filter(c => c.copy_type === 'performance' && (!c.lingua || c.lingua === 'pt')).length;

  const fetchStatus = React.useCallback(() => {
    if (!campanha?.id || !isInProducao) return;
    fetch(`/api/marketing/campanhas/${campanha.id}/producao-status`)
      .then(r => r.ok ? r.json() : null)
      .then(data => { if (data) setProducaoStatus(data); })
      .catch(() => {})
      .finally(() => setLoadingStatus(false));
  }, [campanha?.id, isInProducao]);

  React.useEffect(() => {
    fetchStatus();
    if (status === 'em_producao') {
      intervalRef.current = setInterval(fetchStatus, 30000);
    }
    return () => { if (intervalRef.current) clearInterval(intervalRef.current); };
  }, [fetchStatus, status]);

  const dateStr = (iso) => iso ? new Date(iso).toLocaleDateString('pt-PT', { day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit' }) : null;
  const timeAgo = (iso) => { if (!iso) return null; const h = Math.floor((Date.now() - new Date(iso).getTime()) / 3600000); const d = Math.floor(h / 24); return h < 1 ? 'há menos de 1 hora' : h < 24 ? `há ${h}h` : `há ${d} dia${d > 1 ? 's' : ''}`; };

  const ProgressBar = ({ done, total, color = '#3859D0' }) => {
    const pct = total > 0 ? Math.round((done / total) * 100) : 0;
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ flex: 1, height: 6, borderRadius: 99, background: 'var(--bg-app,#f5f6f8)', overflow: 'hidden' }}>
          <div style={{ height: '100%', borderRadius: 99, background: pct === 0 ? '#e2e8f0' : color, width: `${Math.max(pct, pct > 0 ? 3 : 0)}%`, transition: 'width 0.3s' }} />
        </div>
        <span style={{ fontSize: 11, fontWeight: 700, color: pct > 0 ? color : '#94a3b8', fontFamily: 'monospace', flexShrink: 0, minWidth: 50, textAlign: 'right' }}>{done}/{total}</span>
      </div>
    );
  };

  if (!isInProducao) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '64px 0', gap: 16 }}>
        <div style={{ width: 56, height: 56, borderRadius: 14, background: 'rgba(34,197,94,.08)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="1.5" strokeLinecap="round"><path d="M20 7H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="2"/></svg>
        </div>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-display,Montserrat,sans-serif)', marginBottom: 6 }}>Aguarda aprovação executiva</div>
          <div style={{ fontSize: 13, color: '#64748b', maxWidth: 380, lineHeight: 1.6 }}>A campanha precisa de ser aprovada no tab Aprovação por Fábio, Rui ou Armando antes de avançar para Produção.</div>
        </div>
      </div>
    );
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* ── CARD 1: ESTADO DE APROVAÇÃO + PACOTE ── */}
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid rgba(21,128,61,.25)', borderRadius: 12, padding: '20px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <div style={{ width: 10, height: 10, borderRadius: '50%', background: status === 'publicado' ? '#3859D0' : '#22c55e', animation: status === 'em_producao' ? 'cpulse 2s infinite' : 'none' }} />
          <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-display,Montserrat,sans-serif)' }}>
            {status === 'publicado' ? 'Campanha Publicada' : 'Em Produção'}
          </div>
          {approveRecord && <span style={{ fontSize: 12, color: '#64748b', marginLeft: 4 }}>{timeAgo(approveRecord.created_at)}</span>}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 16 }}>
          {approveRecord && (
            <div style={{ padding: '10px 14px', background: 'rgba(21,128,61,.04)', borderRadius: 8 }}>
              <div style={{ fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 3 }}>Aprovado por</div>
              <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{approveRecord.approver_name || approveRecord.approver_email}</div>
              <div style={{ fontSize: 11, color: '#64748b' }}>{dateStr(approveRecord.created_at)}</div>
            </div>
          )}
          {submitRecord && (
            <div style={{ padding: '10px 14px', background: 'var(--bg-app,#f5f6f8)', borderRadius: 8 }}>
              <div style={{ fontSize: 9, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 3 }}>Submetido por</div>
              <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text,#1d2e38)' }}>{submitRecord.approver_name || submitRecord.approver_email}</div>
              <div style={{ fontSize: 11, color: '#64748b' }}>{dateStr(submitRecord.created_at)}</div>
            </div>
          )}
        </div>

        <div style={{ borderTop: '1px solid var(--border-light,#f1f5f9)', paddingTop: 14, marginBottom: 16 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', marginBottom: 10 }}>Pacote enviado para Produção de Conteúdos</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {orgCount > 0  && <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>▸ <strong>{orgCount}</strong> peças orgânicas (PT {[...new Set(allCopy.filter(c => c.lingua && c.lingua !== 'pt').map(c => c.lingua.toUpperCase()))].join(' + ')})</div>}
            {perfCount > 0 && <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>▸ <strong>{perfCount}</strong> anúncios performance</div>}
            {allPrompts.length > 0 && <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>▸ <strong>{allPrompts.length}</strong> prompts visuais (Flux + Kling)</div>}
            {payload?.pecas && <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>▸ <strong>{payload.pecas.length}</strong> peças no pacote final</div>}
            {(payload?.periodo?.inicio || payload?.periodo?.fim) && <div style={{ fontSize: 13, color: 'var(--text,#1d2e38)', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>▸ Período: {payload?.periodo?.inicio} → {payload?.periodo?.fim}</div>}
          </div>
        </div>

        <button
          onClick={() => { if (window.mktNavToSub) window.mktNavToSub('conteudos'); }}
          style={{ background: '#3859D0', border: 'none', borderRadius: 8, padding: '10px 18px', fontSize: 13, color: '#fff', cursor: 'pointer', fontFamily: 'var(--font-body,Inter,sans-serif)', fontWeight: 600 }}>
          → Acompanhar no Módulo Produção de Conteúdos
        </button>
      </div>

      {/* ── CARD 2: ESTADO DE EXECUÇÃO ── */}
      <div style={{ background: 'var(--bg-elev,#fff)', border: '1px solid var(--border,#e2e8f0)', borderRadius: 12, padding: '20px 24px' }}>
        <div style={{ fontSize: 10, fontWeight: 700, color: '#94a3b8', fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.07em', marginBottom: 16 }}>Estado de Execução</div>

        {producaoStatus ? (
          <>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 16 }}>
              {[
                { label: 'Imagens geradas',  done: producaoStatus.imagens_geradas,    total: producaoStatus.imagens_total,      color: '#3859D0' },
                { label: 'Vídeos gerados',   done: producaoStatus.videos_gerados,     total: producaoStatus.videos_total,       color: '#ec4899' },
                { label: 'Composições',      done: producaoStatus.composicoes_prontas, total: producaoStatus.composicoes_total,  color: '#8b5cf6' },
                { label: 'Publicações',      done: producaoStatus.publicacoes_feitas,  total: producaoStatus.publicacoes_total,  color: '#059669' },
              ].map(({ label, done, total, color }) => (
                <div key={label} style={{ display: 'grid', gridTemplateColumns: '140px 1fr', gap: 10, alignItems: 'center' }}>
                  <div style={{ fontSize: 12, color: '#64748b', fontFamily: 'var(--font-body,Inter,sans-serif)' }}>{label}</div>
                  <ProgressBar done={done} total={total} color={color} />
                </div>
              ))}
            </div>
            {producaoStatus.publicacoes_feitas === 0 && (
              <div style={{ background: 'rgba(245,158,11,.06)', border: '1px solid rgba(245,158,11,.2)', borderRadius: 8, padding: '12px 14px', fontSize: 12, color: '#92400e', lineHeight: 1.55 }}>
                Produção agendada — a iniciar em breve. O Módulo Produção de Conteúdos vai gerar os assets visuais. Esta página actualiza automaticamente a cada 30 segundos.
              </div>
            )}
            {producaoStatus.ultima_publicacao && (
              <div style={{ fontSize: 12, color: '#64748b', marginTop: 10 }}>Última publicação: {dateStr(producaoStatus.ultima_publicacao)}</div>
            )}
          </>
        ) : loadingStatus ? (
          <div style={{ fontSize: 13, color: '#94a3b8', fontStyle: 'italic' }}>A carregar estado…</div>
        ) : (
          <div style={{ background: 'rgba(245,158,11,.06)', border: '1px solid rgba(245,158,11,.2)', borderRadius: 8, padding: '12px 14px', fontSize: 12, color: '#92400e' }}>
            Produção agendada — a iniciar em breve.
          </div>
        )}
      </div>

    </div>
  );
};

const NegativePromptBlock = ({ text }) => {
  const [open, setOpen] = React.useState(false);
  if (!text) return null;
  return (
    <div style={{ borderTop: '1px solid var(--border,#1e293b)', paddingTop: 8, marginTop: 2 }}>
      <button onClick={() => setOpen(o => !o)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 6, color: '#ef4444', fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', fontFamily: 'var(--font-mono,monospace)' }}>
        ⛔ Negative Prompt {open ? '▲' : '▼'}
      </button>
      {open && <div style={{ marginTop: 8, fontSize: 11, color: '#ef4444', lineHeight: 1.5, fontFamily: 'var(--font-mono,monospace)', background: 'rgba(239,68,68,.05)', borderRadius: 4, padding: '6px 8px' }}>{text}</div>}
    </div>
  );
};

const VariantPromptsBlock = ({ variants }) => {
  const [open, setOpen] = React.useState(false);
  if (!variants || !variants.length) return null;
  return (
    <div style={{ borderTop: '1px solid var(--border,#1e293b)', paddingTop: 8, marginTop: 2 }}>
      <button onClick={() => setOpen(o => !o)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 6, color: '#f59e0b', fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', fontFamily: 'var(--font-mono,monospace)' }}>
        🔀 Variantes ({variants.length}) {open ? '▲' : '▼'}
      </button>
      {open && (
        <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 8 }}>
          {variants.map((v, i) => (
            <div key={i} style={{ fontSize: 11, color: 'var(--text-muted,#64748b)', lineHeight: 1.55, borderLeft: '2px solid #f59e0b', paddingLeft: 10 }}>
              <span style={{ fontSize: 10, fontWeight: 700, color: '#f59e0b', fontFamily: 'var(--font-mono,monospace)', marginRight: 6 }}>V{i+1}</span>{v}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

const PromptCardFull = ({ pr, onApprove, onFlag }) => {
  const isApproved = pr.status === 'aprovado';
  const isFlagged  = pr.status === 'correcao';
  const cfg        = TIPO_CONFIG[pr.tipo] || TIPO_CONFIG.imagem;
  const [copied, setCopied] = React.useState(false);
  const variants = pr.variant_prompts ? (typeof pr.variant_prompts === 'string' ? JSON.parse(pr.variant_prompts) : pr.variant_prompts) : [];

  const handleCopy = () => {
    navigator.clipboard?.writeText(pr.prompt_texto || '').then(() => {
      setCopied(true); setTimeout(() => setCopied(false), 1800);
    });
  };

  // composicao: pretty-print JSON spec
  let composicaoSpec = null;
  if (pr.tipo === 'composicao' && pr.prompt_texto) {
    try { composicaoSpec = JSON.parse(pr.prompt_texto); } catch { composicaoSpec = null; }
  }

  return (
    <div style={{
      background: '#fff', display: 'flex', flexDirection: 'column',
      borderLeft: `3px solid ${isApproved ? '#22c55e' : isFlagged ? '#fb923c' : cfg.color}`,
    }}>
      {/* Imagem de referência (thumbnail) — só background e video */}
      {pr.imagem_referencia && pr.tipo !== 'composicao' && (
        <div style={{ position: 'relative', height: 100, overflow: 'hidden', background: '#f8fafc' }}>
          <img src={pr.imagem_referencia} alt="ref" style={{ width: '100%', height: '100%', objectFit: 'contain', padding: '8px' }} />
          <span style={{ position: 'absolute', bottom: 6, right: 8, fontSize: 9, fontWeight: 700, color: '#fff', background: 'rgba(0,0,0,.5)', padding: '2px 6px', borderRadius: 4, fontFamily: 'monospace' }}>REF</span>
        </div>
      )}

      {/* Card header */}
      <div style={{ padding: '11px 16px 9px', borderBottom: '1px solid #f1f5f9', background: isApproved ? 'rgba(34,197,94,.04)' : cfg.bg, display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ fontSize: 11, fontWeight: 700, color: cfg.color, fontFamily: 'monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{cfg.label}</span>
        <span style={{ fontSize: 10, color: '#94a3b8', background: '#f1f5f9', padding: '1px 7px', borderRadius: 99, fontFamily: 'monospace', flexShrink: 0 }}>{pr.plataforma || cfg.plat}</span>
        {pr.ratio && <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace' }}>{pr.ratio}</span>}
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 6 }}>
          {isApproved
            ? <span style={{ fontSize: 10, color: '#16a34a', fontWeight: 600, fontFamily: 'monospace' }}>✓ Aprovado</span>
            : isFlagged
            ? <span style={{ fontSize: 10, color: '#ea580c', fontWeight: 600, fontFamily: 'monospace' }}>⚑ Correcção</span>
            : <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace' }}>Pendente</span>}
        </div>
      </div>

      {/* Card body */}
      <div style={{ padding: '12px 16px', display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
        {composicaoSpec ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {composicaoSpec.copy_overlay && (
              <div style={{ background: 'rgba(56,89,208,.06)', border: '1px solid rgba(56,89,208,.2)', borderRadius: 8, padding: '10px 12px' }}>
                <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: '#3859D0', fontFamily: 'monospace', marginBottom: 6 }}>Texto sobre a imagem</div>
                <div style={{ fontSize: 15, fontWeight: 700, color: '#1d2e38', fontFamily: 'Montserrat, sans-serif', lineHeight: 1.3 }}>{composicaoSpec.copy_overlay}</div>
                {composicaoSpec.cta_overlay && <div style={{ fontSize: 12, color: '#3859D0', fontWeight: 600, marginTop: 4 }}>{composicaoSpec.cta_overlay} →</div>}
              </div>
            )}
            <div style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace' }}>Layout</div>
            {Object.entries(composicaoSpec).filter(([k]) => !['copy_overlay','cta_overlay'].includes(k)).map(([k, v]) => (
              <div key={k} style={{ display: 'flex', gap: 8 }}>
                <span style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace', minWidth: 120, flexShrink: 0 }}>{k}</span>
                <span style={{ fontSize: 11, color: '#1d2e38' }}>{String(v)}</span>
              </div>
            ))}
          </div>
        ) : (
          pr.prompt_texto && (
            <div>
              <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#94a3b8', fontFamily: 'monospace', marginBottom: 4 }}>Prompt</div>
              <div style={{ fontSize: 12, color: '#1d2e38', lineHeight: 1.65, fontFamily: 'Inter, sans-serif' }}>{pr.prompt_texto}</div>
            </div>
          )
        )}

        {pr.negative_prompt && (
          <details style={{ marginTop: 2 }}>
            <summary style={{ cursor: 'pointer', fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#ef4444', fontFamily: 'monospace', listStyle: 'none' }}>⛔ Negative prompt</summary>
            <div style={{ marginTop: 6, fontSize: 11, color: '#ef4444', lineHeight: 1.5, fontFamily: 'monospace', background: 'rgba(239,68,68,.04)', borderRadius: 4, padding: '6px 8px' }}>{pr.negative_prompt}</div>
          </details>
        )}

        {variants.length > 0 && (
          <details style={{ marginTop: 2 }}>
            <summary style={{ cursor: 'pointer', fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: '#f59e0b', fontFamily: 'monospace', listStyle: 'none' }}>🔀 {variants.length} variantes</summary>
            <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 8 }}>
              {variants.map((v, i) => (
                <div key={i} style={{ fontSize: 11, color: '#475569', lineHeight: 1.55, borderLeft: '2px solid #f59e0b', paddingLeft: 10 }}>
                  <span style={{ fontSize: 10, fontWeight: 700, color: '#f59e0b', fontFamily: 'monospace', marginRight: 6 }}>V{i+1}</span>{v}
                </div>
              ))}
            </div>
          </details>
        )}

        {pr.referencia && (
          <div style={{ fontSize: 10, color: '#94a3b8', fontStyle: 'italic', borderTop: '1px solid #f1f5f9', paddingTop: 8 }}>{pr.referencia}</div>
        )}

        {/* Actions */}
        <div style={{ display: 'flex', gap: 6, marginTop: 4, paddingTop: 10, borderTop: '1px solid #f1f5f9' }}>
          {!isApproved && (
            <>
              <button onClick={onApprove} className="btn btn-ai" style={{ fontSize: 11 }}>✓ Aprovar</button>
              <button onClick={onFlag}    className="btn" style={{ fontSize: 11, color: '#fb923c', borderColor: 'rgba(251,146,60,.3)' }}>⚑ Corrigir</button>
            </>
          )}
          {pr.tipo !== 'composicao' && (
            <button onClick={handleCopy} className="btn" style={{ fontSize: 11, marginLeft: 'auto', color: copied ? '#16a34a' : '#64748b' }}>
              {copied ? '✓ Copiado' : '⎘ Copiar'}
            </button>
          )}
        </div>
      </div>
    </div>
  );
};

// ── EditConceitoModal — helpers ───────────────────────────────────────────────
const _EcmSection = ({ title }) => (
  <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: '#3859D0', fontFamily: 'monospace', padding: '10px 0 6px', borderBottom: '1px solid #e2e8f0', marginTop: 4 }}>{title}</div>
);
const _EcmLabel = ({ label, hint }) => (
  <div style={{ marginBottom: hint ? 2 : 5 }}>
    <div style={{ fontSize: 11, fontWeight: 600, color: '#6b7fa3', fontFamily: 'monospace', letterSpacing: '0.05em', textTransform: 'uppercase' }}>{label}</div>
    {hint && <div style={{ fontSize: 10, color: '#94a3b8', marginTop: 1 }}>{hint}</div>}
  </div>
);
const _EcmTa = ({ value, onChange, rows = 2, placeholder = '' }) => (
  <textarea value={value || ''} onChange={e => onChange(e.target.value)} rows={rows} placeholder={placeholder}
    style={{ width: '100%', padding: '8px 10px', boxSizing: 'border-box', background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: 6, fontSize: 12.5, color: '#1d2e38', fontFamily: 'inherit', outline: 'none', resize: 'vertical', lineHeight: 1.55 }} />
);
const _EcmIn = ({ value, onChange, placeholder = '' }) => (
  <input value={value || ''} onChange={e => onChange(e.target.value)} placeholder={placeholder}
    style={{ width: '100%', padding: '7px 10px', boxSizing: 'border-box', background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: 6, fontSize: 12.5, color: '#1d2e38', fontFamily: 'inherit', outline: 'none' }} />
);
const _EcmAddBtn = ({ label, onClick }) => (
  <button onClick={onClick} style={{ fontSize: 11, padding: '4px 10px', borderRadius: 5, background: 'none', border: '1px solid #dde3ef', cursor: 'pointer', color: '#3859D0', fontFamily: 'inherit', marginTop: 6 }}>+ {label}</button>
);
const _EcmRemBtn = ({ onClick }) => (
  <button onClick={onClick} style={{ fontSize: 11, padding: '2px 8px', borderRadius: 4, background: 'none', border: '1px solid #fecaca', cursor: 'pointer', color: '#dc2626', fontFamily: 'inherit', flexShrink: 0 }}>✕</button>
);
const _EcmCard = ({ children, extra }) => (
  <div style={{ border: '1px solid #e2e8f0', borderRadius: 8, padding: '12px 14px', background: '#fafbfc', display: 'flex', flexDirection: 'column', gap: 10, position: 'relative' }}>
    {extra && <div style={{ position: 'absolute', top: 8, right: 8 }}>{extra}</div>}
    {children}
  </div>
);

// ── EditConceitoModal ──────────────────────────────────────────────────────────
const EditConceitoModal = ({ campanha, onSave, onClose }) => {
  const isFinal      = campanha?.status === 'publicado';
  const isProduction = campanha?.status === 'em_producao';

  React.useEffect(() => {
    if (isFinal) { alert('Não é possível editar o conceito de campanhas publicadas.'); onClose(); }
  }, [isFinal]);
  if (isFinal) return null;

  const pj = campanha.proposta_json || {};
  const [saving, setSaving] = React.useState(false);

  // ── Estratégia Central (colunas + campos simples) ──
  const [bigIdea,     setBigIdea]     = React.useState(campanha.big_idea       || '');
  const [posic,       setPosic]       = React.useState(campanha.posicionamento || '');
  const [narrativa,   setNarrativa]   = React.useState(campanha.narrativa      || '');
  const [tom,         setTom]         = React.useState(campanha.tom_campanha   || '');
  const [keyMsg,      setKeyMsg]      = React.useState(pj.key_message          || '');
  const [anchor,      setAnchor]      = React.useState(pj.anchor_type          || '');
  const [narProposta, setNarProposta] = React.useState(pj.narrativa_proposta   || '');

  // ── Personas ──
  const [personas, setPersonas] = React.useState(
    (pj.personas || []).map(p => ({ nome: p.nome||'', perfil: p.perfil||'', como_vive_a_dor: p.como_vive_a_dor||'', deepest_desire: p.deepest_desire||'' }))
  );
  const updPersona = (i, k, v) => setPersonas(ps => ps.map((p, j) => j === i ? { ...p, [k]: v } : p));

  // ── Messaging Angles ──
  const [angles, setAngles] = React.useState(
    (pj.messaging_angles || []).map(a => ({ persona: a.persona||'', dor_principal: a.dor_principal||'', usp_principal: a.usp_principal||'', angulo: a.angulo||'', rationale: a.rationale||'', awareness_stage: a.awareness_stage||'', awareness_nome: a.awareness_nome||'' }))
  );
  const updAngle = (i, k, v) => setAngles(as => as.map((a, j) => j === i ? { ...a, [k]: v } : a));

  // ── Hooks por Canal ──
  const [hooks, setHooks] = React.useState(() => {
    const h = pj.hooks || {};
    return Object.fromEntries(Object.entries(h).map(([ch, items]) => [ch, (items||[]).map(it => ({ texto: it.texto||'', tipo: it.tipo||'', target_stage: String(it.target_stage||'') }))]));
  });
  const updHook = (ch, i, k, v) => setHooks(h => ({ ...h, [ch]: h[ch].map((it, j) => j === i ? { ...it, [k]: v } : it) }));
  const addHook = (ch) => setHooks(h => ({ ...h, [ch]: [...(h[ch]||[]), { texto: '', tipo: '', target_stage: '' }] }));
  const remHook = (ch, i) => setHooks(h => ({ ...h, [ch]: h[ch].filter((_, j) => j !== i) }));

  // ── Ad Copy ──
  const [adCopy, setAdCopy] = React.useState(pj.ad_copy || {});
  const updAdCopy = (platform, k, v) => setAdCopy(c => ({ ...c, [platform]: { ...(c[platform]||{}), [k]: v } }));

  // ── Campanha Anúncios ──
  const [campAnuncios, setCampAnuncios] = React.useState(pj.campanha_anuncios || {});
  const updCA = (ch, path, v) => {
    setCampAnuncios(ca => {
      const updated = JSON.parse(JSON.stringify(ca));
      if (!updated[ch]) updated[ch] = {};
      const parts = path.split('.');
      let obj = updated[ch];
      for (let i = 0; i < parts.length - 1; i++) { if (!obj[parts[i]]) obj[parts[i]] = {}; obj = obj[parts[i]]; }
      obj[parts[parts.length - 1]] = v;
      return updated;
    });
  };
  const updCAAdSet = (ch, i, k, v) => setCampAnuncios(ca => ({ ...ca, [ch]: { ...ca[ch], ad_sets: (ca[ch]?.ad_sets||[]).map((s, j) => j === i ? { ...s, [k]: v } : s) } }));
  const updCACrHook = (ch, i, k, v) => setCampAnuncios(ca => ({ ...ca, [ch]: { ...ca[ch], criativo_principal: { ...(ca[ch]?.criativo_principal||{}), hooks: (ca[ch]?.criativo_principal?.hooks||[]).map((h, j) => j === i ? { ...h, [k]: v } : h) } } }));

  // ── Comm Plan ──
  const [commPlan, setCommPlan] = React.useState(
    (pj.comm_plan || []).map(c => ({ canal: c.canal||'', content_type: c.content_type||'', titulo: c.titulo||'', hook: c.hook||c.body||'', planned_week: c.planned_week||'', planned_date: c.planned_date||'' }))
  );
  const updCP = (i, k, v) => setCommPlan(ps => ps.map((p, j) => j === i ? { ...p, [k]: v } : p));

  // ── Image / Video Prompts ──
  const [imgPrompts, setImgPrompts] = React.useState(
    (pj.image_prompts || []).map(p => ({ for: p.for||'', prompt: p.prompt||'', model: p.model||'' }))
  );
  const [vidPrompts, setVidPrompts] = React.useState(
    (pj.video_prompts || []).map(p => ({ for: p.for||'', prompt: p.prompt||'', concept: p.concept||'', hook_visual: p.hook_visual||'' }))
  );

  const handleSave = async () => {
    setSaving(true);
    try {
      // rebuild hooks (preserve original extra fields)
      const hooksOut = {};
      Object.entries(hooks).forEach(([ch, items]) => {
        hooksOut[ch] = items.map((it, i) => {
          const orig = (pj.hooks?.[ch]?.[i]) || {};
          return { ...orig, texto: it.texto, tipo: it.tipo, target_stage: Number(it.target_stage)||orig.target_stage||2 };
        });
      });

      const payload = {
        action: 'editar',
        big_idea: bigIdea, posicionamento: posic, narrativa, tom_campanha: tom,
        key_message: keyMsg, anchor_type: anchor, narrativa_proposta: narProposta,
        personas: personas.map((p, i) => ({ ...(pj.personas?.[i]||{}), ...p })),
        messaging_angles: angles.map((a, i) => ({ ...(pj.messaging_angles?.[i]||{}), ...a, awareness_stage: Number(a.awareness_stage)||a.awareness_stage })),
        hooks: hooksOut,
        ad_copy: adCopy,
        campanha_anuncios: campAnuncios,
        comm_plan: commPlan.map((c, i) => ({ ...(pj.comm_plan?.[i]||{}), ...c })),
        image_prompts: imgPrompts.map((p, i) => ({ ...(pj.image_prompts?.[i]||{}), ...p })),
        video_prompts: vidPrompts.map((p, i) => ({ ...(pj.video_prompts?.[i]||{}), ...p })),
      };
      await CampAPI.patchConceito(campanha.id, payload);
      onSave(); onClose();
    } catch { setSaving(false); }
  };

  const hookChannels = Object.keys(hooks);
  const caChannels   = Object.keys(campAnuncios);
  const adChannels   = Object.keys(adCopy);

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 9999, background: 'rgba(0,0,0,.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }}
      onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{ background: '#fff', borderRadius: 12, width: '100%', maxWidth: 860, maxHeight: '92vh', display: 'flex', flexDirection: 'column', boxShadow: '0 24px 64px rgba(0,0,0,.25)' }}>

        {/* Header */}
        <div style={{ padding: '18px 24px 14px', borderBottom: '1px solid #e2e8f0', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
          <div>
            <div style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'monospace', letterSpacing: '0.08em', marginBottom: 3 }}>EDITAR CONCEITO</div>
            <div style={{ fontSize: 15, fontWeight: 700, color: '#1d2e38', fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>{campanha.titulo}</div>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', fontSize: 20, cursor: 'pointer', color: '#64748b', lineHeight: 1, padding: 4 }}>✕</button>
        </div>

        {/* Body */}
        <div className="scrollbar" style={{ flex: 1, overflowY: 'auto', padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 12 }}>
          {isProduction && (
            <div style={{ background: 'rgba(220,38,38,0.08)', border: '1px solid rgba(220,38,38,0.3)', borderRadius: 8, padding: '10px 14px', fontSize: 12, color: '#dc2626', lineHeight: 1.5 }}>
              <strong>Atenção:</strong> Campanha em produção. Editar pode dessincronizar copy e prompts já aprovados.
            </div>
          )}

          {/* ── Estratégia Central ── */}
          <_EcmSection title="Estratégia Central" />
          <_EcmLabel label="Big Idea" hint="Metáfora criativa central da campanha" />
          <_EcmTa value={bigIdea} onChange={setBigIdea} rows={3} />
          <_EcmLabel label="Posicionamento" hint="Diferenciação + awareness stage" />
          <_EcmTa value={posic} onChange={setPosic} rows={3} />
          <_EcmLabel label="Narrativa" hint="Arco Antes → Durante → Depois" />
          <_EcmTa value={narrativa} onChange={setNarrativa} rows={4} />
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div><_EcmLabel label="Tom da Campanha" /><_EcmTa value={tom} onChange={setTom} rows={2} /></div>
            <div><_EcmLabel label="Anchor Type" hint="pain · desire · contrarian" /><_EcmIn value={anchor} onChange={setAnchor} /></div>
          </div>
          <_EcmLabel label="Mensagem-Chave" hint="Mensagem transversal da campanha" />
          <_EcmTa value={keyMsg} onChange={setKeyMsg} rows={2} />

          {/* ── Personas ── */}
          <_EcmSection title="Personas" />
          {personas.map((p, i) => (
            <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => setPersonas(ps => ps.filter((_, j) => j !== i))} />}>
              <div style={{ fontSize: 11, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace' }}>Persona {i + 1}</div>
              <_EcmLabel label="Nome" /><_EcmIn value={p.nome} onChange={v => updPersona(i, 'nome', v)} />
              <_EcmLabel label="Perfil" /><_EcmTa value={p.perfil} onChange={v => updPersona(i, 'perfil', v)} rows={2} />
              <_EcmLabel label="Como vive a dor" /><_EcmTa value={p.como_vive_a_dor} onChange={v => updPersona(i, 'como_vive_a_dor', v)} rows={2} />
              <_EcmLabel label="Deepest Desire" /><_EcmTa value={p.deepest_desire} onChange={v => updPersona(i, 'deepest_desire', v)} rows={2} />
            </_EcmCard>
          ))}
          <_EcmAddBtn label="Adicionar Persona" onClick={() => setPersonas(ps => [...ps, { nome:'', perfil:'', como_vive_a_dor:'', deepest_desire:'' }])} />

          {/* ── Ângulos de Mensagem ── */}
          <_EcmSection title="Ângulos de Mensagem" />
          {angles.map((a, i) => (
            <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => setAngles(as => as.filter((_, j) => j !== i))} />}>
              <div style={{ fontSize: 11, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace' }}>Ângulo {i + 1}</div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                <div><_EcmLabel label="Persona" /><_EcmIn value={a.persona} onChange={v => updAngle(i,'persona',v)} /></div>
                <div><_EcmLabel label="Awareness Stage" hint="1-5" /><_EcmIn value={a.awareness_stage} onChange={v => updAngle(i,'awareness_stage',v)} placeholder="2" /></div>
              </div>
              <_EcmLabel label="Dor Principal" /><_EcmTa value={a.dor_principal} onChange={v => updAngle(i,'dor_principal',v)} rows={2} />
              <_EcmLabel label="USP Principal" /><_EcmTa value={a.usp_principal} onChange={v => updAngle(i,'usp_principal',v)} rows={2} />
              <_EcmLabel label="Ângulo" /><_EcmTa value={a.angulo} onChange={v => updAngle(i,'angulo',v)} rows={2} />
              <_EcmLabel label="Rationale" /><_EcmTa value={a.rationale} onChange={v => updAngle(i,'rationale',v)} rows={2} />
            </_EcmCard>
          ))}
          <_EcmAddBtn label="Adicionar Ângulo" onClick={() => setAngles(as => [...as, { persona:'', dor_principal:'', usp_principal:'', angulo:'', rationale:'', awareness_stage:'', awareness_nome:'' }])} />

          {/* ── Hooks por Canal ── */}
          <_EcmSection title="Hooks por Canal" />
          {hookChannels.map(ch => (
            <div key={ch}>
              <div style={{ fontSize: 11, fontWeight: 700, color: '#475569', fontFamily: 'monospace', marginBottom: 6, textTransform: 'uppercase' }}>{ch}</div>
              {(hooks[ch]||[]).map((h, i) => (
                <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => remHook(ch, i)} />}>
                  <_EcmLabel label="Texto do Hook" />
                  <_EcmTa value={h.texto} onChange={v => updHook(ch, i, 'texto', v)} rows={2} />
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                    <div><_EcmLabel label="Tipo" hint="Pain Agitation, Curiosity Gap…" /><_EcmIn value={h.tipo} onChange={v => updHook(ch, i, 'tipo', v)} /></div>
                    <div><_EcmLabel label="Target Stage" hint="1-5" /><_EcmIn value={h.target_stage} onChange={v => updHook(ch, i, 'target_stage', v)} placeholder="2" /></div>
                  </div>
                </_EcmCard>
              ))}
              <_EcmAddBtn label={`Adicionar hook ${ch}`} onClick={() => addHook(ch)} />
            </div>
          ))}

          {/* ── Ad Copy ── */}
          {adChannels.length > 0 && (<>
            <_EcmSection title="Ad Copy" />
            {adChannels.map(pl => {
              const c = adCopy[pl] || {};
              return (
                <div key={pl}>
                  <div style={{ fontSize: 11, fontWeight: 700, color: '#475569', fontFamily: 'monospace', marginBottom: 6, textTransform: 'uppercase' }}>{pl}</div>
                  <_EcmCard>
                    {pl === 'meta' && (<>
                      <_EcmLabel label="Headline" /><_EcmIn value={c.headline} onChange={v => updAdCopy(pl,'headline',v)} />
                      <_EcmLabel label="Primary Text" /><_EcmTa value={c.primary_text} onChange={v => updAdCopy(pl,'primary_text',v)} rows={3} />
                      <_EcmLabel label="Description" /><_EcmIn value={c.description} onChange={v => updAdCopy(pl,'description',v)} />
                    </>)}
                    {pl === 'linkedin' && (<>
                      <_EcmLabel label="Headline" /><_EcmIn value={c.headline} onChange={v => updAdCopy(pl,'headline',v)} />
                      <_EcmLabel label="Intro Text" /><_EcmTa value={c.intro_text} onChange={v => updAdCopy(pl,'intro_text',v)} rows={3} />
                    </>)}
                    {pl === 'google' && (<>
                      <_EcmLabel label="Headlines" hint="Uma por linha" />
                      <_EcmTa value={(c.headlines||[]).join('\n')} onChange={v => updAdCopy(pl,'headlines',v.split('\n'))} rows={4} />
                      <_EcmLabel label="Descriptions" hint="Uma por linha" />
                      <_EcmTa value={(c.descriptions||[]).join('\n')} onChange={v => updAdCopy(pl,'descriptions',v.split('\n'))} rows={3} />
                    </>)}
                    {!['meta','linkedin','google'].includes(pl) && (<>
                      <_EcmLabel label="Conteúdo" /><_EcmTa value={typeof c === 'string' ? c : JSON.stringify(c,null,2)} onChange={v => setAdCopy(ac => ({ ...ac, [pl]: v }))} rows={4} />
                    </>)}
                  </_EcmCard>
                </div>
              );
            })}
          </>)}

          {/* ── Campanha Anúncios ── */}
          {caChannels.length > 0 && (<>
            <_EcmSection title="Campanha Anúncios (Performance)" />
            {caChannels.map(ch => {
              const cfg = campAnuncios[ch] || {};
              const cp  = cfg.criativo_principal || {};
              const ads = cfg.ad_sets || [];
              return (
                <div key={ch}>
                  <div style={{ fontSize: 11, fontWeight: 700, color: '#475569', fontFamily: 'monospace', marginBottom: 6, textTransform: 'uppercase' }}>{ch}</div>
                  <_EcmCard>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                      <div><_EcmLabel label="Objectivo" /><_EcmIn value={cfg.campanha_objectivo} onChange={v => updCA(ch,'campanha_objectivo',v)} /></div>
                      <div><_EcmLabel label="Conversão" hint="formulario_nativo · landing_page" /><_EcmIn value={cfg.meta_ads_conversao} onChange={v => updCA(ch,'meta_ads_conversao',v)} /></div>
                    </div>
                    <_EcmLabel label="Mensagem Central" /><_EcmTa value={cfg.campanha_mensagem_central} onChange={v => updCA(ch,'campanha_mensagem_central',v)} rows={2} />

                    {/* Criativo Principal */}
                    <div style={{ fontSize: 10, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace', marginTop: 4 }}>CRIATIVO ÚNICO</div>
                    <_EcmLabel label="Headline" /><_EcmIn value={cp.headline} onChange={v => updCA(ch,'criativo_principal.headline',v)} />
                    <_EcmLabel label="Body" /><_EcmTa value={cp.body} onChange={v => updCA(ch,'criativo_principal.body',v)} rows={3} />
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                      <div><_EcmLabel label="CTA" /><_EcmIn value={cp.cta} onChange={v => updCA(ch,'criativo_principal.cta',v)} /></div>
                      <div><_EcmLabel label="Visual Direction" /><_EcmIn value={cp.visual_direction} onChange={v => updCA(ch,'criativo_principal.visual_direction',v)} /></div>
                    </div>

                    {/* Hooks do criativo */}
                    {(cp.hooks||[]).length > 0 && (<>
                      <div style={{ fontSize: 10, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace', marginTop: 4 }}>HOOKS DO CRIATIVO</div>
                      {(cp.hooks||[]).map((h, i) => (
                        <div key={i} style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 8, alignItems: 'start' }}>
                          <_EcmTa value={h.texto||h} onChange={v => updCACrHook(ch, i, 'texto', v)} rows={2} />
                          <_EcmIn value={h.tipo||''} onChange={v => updCACrHook(ch, i, 'tipo', v)} placeholder="tipo" />
                          <_EcmIn value={String(h.prioridade||i+1)} onChange={v => updCACrHook(ch, i, 'prioridade', Number(v))} placeholder="P" />
                        </div>
                      ))}
                    </>)}

                    {/* Ad Sets */}
                    {ads.length > 0 && (<>
                      <div style={{ fontSize: 10, fontWeight: 700, color: '#3859D0', fontFamily: 'monospace', marginTop: 4 }}>PÚBLICOS-ALVO ({ads.length})</div>
                      {ads.map((s, i) => (
                        <div key={i} style={{ padding: '8px 10px', background: '#f1f5f9', borderRadius: 6, display: 'flex', flexDirection: 'column', gap: 6 }}>
                          <div style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 8, alignItems: 'center' }}>
                            <_EcmIn value={s.nome} onChange={v => updCAAdSet(ch, i, 'nome', v)} placeholder="Nome do ad set" />
                            <_EcmIn value={s.tipo} onChange={v => updCAAdSet(ch, i, 'tipo', v)} placeholder="awareness" />
                            <_EcmIn value={String(s.awareness_stage||'')} onChange={v => updCAAdSet(ch, i, 'awareness_stage', Number(v))} placeholder="S" />
                          </div>
                          <_EcmTa value={s.targeting_resumo} onChange={v => updCAAdSet(ch, i, 'targeting_resumo', v)} rows={2} placeholder="Targeting resumo" />
                          <_EcmTa value={s.targeting_rationale} onChange={v => updCAAdSet(ch, i, 'targeting_rationale', v)} rows={1} placeholder="Targeting rationale" />
                        </div>
                      ))}
                    </>)}

                    <_EcmLabel label="Reutilização Orgânica" /><_EcmTa value={cfg.reutilizacao_organica} onChange={v => updCA(ch,'reutilizacao_organica',v)} rows={2} />
                  </_EcmCard>
                </div>
              );
            })}
          </>)}

          {/* ── Plano Editorial ── */}
          <_EcmSection title="Plano Editorial" />
          {commPlan.map((c, i) => (
            <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => setCommPlan(ps => ps.filter((_, j) => j !== i))} />}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 80px 60px', gap: 8 }}>
                <div><_EcmLabel label="Canal" /><_EcmIn value={c.canal} onChange={v => updCP(i,'canal',v)} /></div>
                <div><_EcmLabel label="Tipo" /><_EcmIn value={c.content_type} onChange={v => updCP(i,'content_type',v)} /></div>
                <div><_EcmLabel label="Semana" /><_EcmIn value={String(c.planned_week||'')} onChange={v => updCP(i,'planned_week',v)} placeholder="1" /></div>
                <div><_EcmLabel label="Data" /><_EcmIn value={c.planned_date||''} onChange={v => updCP(i,'planned_date',v)} placeholder="YYYY-MM-DD" /></div>
              </div>
              <_EcmLabel label="Título" /><_EcmIn value={c.titulo} onChange={v => updCP(i,'titulo',v)} />
              <_EcmLabel label="Hook / Body" /><_EcmTa value={c.hook} onChange={v => updCP(i,'hook',v)} rows={2} />
            </_EcmCard>
          ))}
          <_EcmAddBtn label="Adicionar item" onClick={() => setCommPlan(ps => [...ps, { canal:'', content_type:'', titulo:'', hook:'', planned_week:'', planned_date:'' }])} />

          {/* ── Image Prompts ── */}
          <_EcmSection title="Image Prompts (FLUX)" />
          {imgPrompts.map((p, i) => (
            <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => setImgPrompts(ps => ps.filter((_, j) => j !== i))} />}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                <div><_EcmLabel label="Para" /><_EcmIn value={p.for} onChange={v => setImgPrompts(ps => ps.map((x, j) => j === i ? { ...x, for: v } : x))} /></div>
                <div><_EcmLabel label="Modelo" /><_EcmIn value={p.model} onChange={v => setImgPrompts(ps => ps.map((x, j) => j === i ? { ...x, model: v } : x))} /></div>
              </div>
              <_EcmLabel label="Prompt" /><_EcmTa value={p.prompt} onChange={v => setImgPrompts(ps => ps.map((x, j) => j === i ? { ...x, prompt: v } : x))} rows={4} />
            </_EcmCard>
          ))}
          <_EcmAddBtn label="Adicionar prompt de imagem" onClick={() => setImgPrompts(ps => [...ps, { for:'', prompt:'', model:'flux-1.1-pro' }])} />

          {/* ── Video Prompts ── */}
          <_EcmSection title="Video Prompts (Kling)" />
          {vidPrompts.map((p, i) => (
            <_EcmCard key={i} extra={<_EcmRemBtn onClick={() => setVidPrompts(ps => ps.filter((_, j) => j !== i))} />}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                <div><_EcmLabel label="Para" /><_EcmIn value={p.for} onChange={v => setVidPrompts(ps => ps.map((x, j) => j === i ? { ...x, for: v } : x))} /></div>
                <div><_EcmLabel label="Modelo" /><_EcmIn value={p.model} onChange={v => setVidPrompts(ps => ps.map((x, j) => j === i ? { ...x, model: v } : x))} /></div>
              </div>
              <_EcmLabel label="Prompt" /><_EcmTa value={p.prompt} onChange={v => setVidPrompts(ps => ps.map((x, j) => j === i ? { ...x, prompt: v } : x))} rows={3} />
              <_EcmLabel label="Conceito Visual" /><_EcmTa value={p.concept} onChange={v => setVidPrompts(ps => ps.map((x, j) => j === i ? { ...x, concept: v } : x))} rows={2} />
              <_EcmLabel label="Hook Visual (3s)" /><_EcmTa value={p.hook_visual} onChange={v => setVidPrompts(ps => ps.map((x, j) => j === i ? { ...x, hook_visual: v } : x))} rows={2} />
            </_EcmCard>
          ))}
          <_EcmAddBtn label="Adicionar prompt de vídeo" onClick={() => setVidPrompts(ps => [...ps, { for:'', prompt:'', concept:'', hook_visual:'', model:'kling' }])} />

          {/* ── Narrativa Interna ── */}
          <_EcmSection title="Narrativa Interna" />
          <_EcmLabel label="Narrativa da Proposta" hint="Para revisão RL/FC — 4 parágrafos" />
          <_EcmTa value={narProposta} onChange={setNarProposta} rows={8} />
        </div>

        {/* Footer */}
        <div style={{ padding: '14px 24px', borderTop: '1px solid #e2e8f0', display: 'flex', gap: 8, justifyContent: 'flex-end', flexShrink: 0 }}>
          <button onClick={onClose} className="btn" style={{ height: 32, padding: '0 16px', fontSize: 12 }}>Cancelar</button>
          <button onClick={handleSave} disabled={saving} className="btn btn-ai" style={{ height: 32, padding: '0 18px', fontSize: 12 }}>
            {saving ? 'A guardar…' : '✓ Guardar alterações'}
          </button>
        </div>
      </div>
    </div>
  );
};

// ── EditTituloModal ────────────────────────────────────────────────────────────
const EditTituloModal = ({ campanha, onSave, onClose }) => {
  const [titulo, setTitulo] = React.useState(campanha.titulo);
  const [saving, setSaving] = React.useState(false);
  const inputRef = React.useRef(null);
  React.useEffect(() => { inputRef.current?.focus(); inputRef.current?.select(); }, []);
  const save = async () => {
    if (!titulo.trim() || titulo.trim() === campanha.titulo) { onClose(); return; }
    setSaving(true);
    await CampAPI.update(campanha.id, { titulo: titulo.trim() });
    onSave();
    onClose();
  };
  return (
    <>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,.5)', zIndex: 300 }} />
      <div style={{
        position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', zIndex: 301,
        background: '#ffffff', border: '1px solid var(--border, #e2e8f0)',
        borderRadius: 10, padding: '22px 24px', width: 400,
        boxShadow: '0 16px 48px rgba(0,0,0,.5)',
      }}>
        <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text, #1e293b)', marginBottom: 14, fontFamily: 'var(--font-display, Montserrat, sans-serif)' }}>
          Editar título
        </div>
        <input ref={inputRef} value={titulo} onChange={e => setTitulo(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter') save(); if (e.key === 'Escape') onClose(); }}
          style={{
            width: '100%', boxSizing: 'border-box', padding: '9px 12px', borderRadius: 6, fontSize: 13,
            background: 'var(--bg-sunken, #f1f5f9)', border: '1px solid var(--border, #e2e8f0)',
            color: 'var(--text, #1e293b)', outline: 'none', fontFamily: 'var(--font-body, Inter, sans-serif)',
            marginBottom: 14,
          }}
        />
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button onClick={onClose} className="btn" style={{ fontSize: 12 }}>Cancelar</button>
          <button onClick={save} disabled={saving || !titulo.trim()} className="btn btn-ai" style={{ fontSize: 12 }}>
            {saving ? 'A guardar…' : 'Guardar'}
          </button>
        </div>
      </div>
    </>
  );
};

// ── EmailBriefingModal ─────────────────────────────────────────────────────────
const EmailBriefingModal = ({ campanha, briefing, onClose }) => {
  const [search,        setSearch]        = React.useState('');
  const [selected,      setSelected]      = React.useState([]);
  const [externalInput, setExternalInput] = React.useState('');
  const [externalOpen,  setExternalOpen]  = React.useState(false);
  const [externalError, setExternalError] = React.useState('');
  const [showAll,       setShowAll]       = React.useState(false);
  const [allUsers,      setAllUsers]      = React.useState([]);
  const searchRef = React.useRef(null);

  // Carrega utilizadores do sistema (AdminUsersData pode estar pronto ou chegar via evento)
  React.useEffect(() => {
    const load = () => {
      const D = window.AdminUsersData;
      if (D && D.ALL_USERS && D.ALL_USERS.length) {
        setAllUsers(D.ALL_USERS.slice());
      }
    };
    load();
    window.addEventListener('digi-users-loaded', load);
    return () => window.removeEventListener('digi-users-loaded', load);
  }, []);

  React.useEffect(() => {
    setTimeout(() => searchRef.current && searchRef.current.focus(), 80);
  }, []);

  // Fechar com Escape
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose]);

  const baseUsers = showAll ? allUsers : allUsers.filter(u => u.portal_activo);

  const filteredUsers = baseUsers.filter(u => {
    if (!search.trim()) return true;
    const q = search.toLowerCase();
    return (u.nome_apresentar || '').toLowerCase().includes(q)
        || (u.email_profissional || '').toLowerCase().includes(q)
        || (u.perfil_cargo || '').toLowerCase().includes(q);
  });

  const toggle = (u) => {
    setSelected(prev =>
      prev.find(s => s.id === u.id)
        ? prev.filter(s => s.id !== u.id)
        : [...prev, { id: u.id, nome: u.nome_apresentar, email: u.email_profissional }]
    );
  };

  const removeSelected = (id) => setSelected(prev => prev.filter(s => s.id !== id));

  const addExternal = () => {
    const v = externalInput.trim();
    if (!v) return;
    const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRe.test(v)) { setExternalError('Email inválido.'); return; }
    if (selected.find(s => s.email === v)) { setExternalError('Já adicionado.'); return; }
    setSelected(prev => [...prev, { id: `ext_${v}`, nome: v, email: v, external: true }]);
    setExternalInput('');
    setExternalError('');
    setExternalOpen(false);
  };

  const buildEmailBody = () => {
    if (!briefing) return '';
    const b1 = briefing.block1 || {}, b2 = briefing.block2 || {},
          b3 = briefing.block3 || {}, b4 = briefing.block4 || {}, b5 = briefing.block5 || {};
    const arr = (v) => Array.isArray(v) && v.length ? v.join(', ') : '—';
    return [
      `BRIEFING — ${campanha.titulo}`,
      `Marca: ${campanha.brand_name || '—'}`,
      '',
      '── PRODUTO ──',
      `Nome comercial: ${b1.commercial_name || '—'}`,
      `Elevator pitch: ${b1.elevator_pitch || '—'}`,
      `USPs: ${arr(b1.usps)}`,
      `Aplicações: ${arr(b1.applications)}`,
      `Mercados: ${arr(b1.geo_markets)}`,
      '',
      '── CLIENTE-ALVO ──',
      `Decisor: ${b2.decision_maker || '—'}`,
      `Utilizador final: ${b2.end_user || '—'}`,
      `Dores: ${arr(b2.pain_points)}`,
      `Motivadores: ${arr(b2.motivators)}`,
      `Objecções: ${arr(b2.objections)}`,
      `Trigger de compra: ${b2.purchase_trigger || '—'}`,
      '',
      '── MERCADO ──',
      `Concorrentes: ${arr(b3.competitors)}`,
      `Diferenciação: ${arr(b3.differentiation_args)}`,
      `Tendências: ${arr(b3.market_trends)}`,
      `Posicionamento: ${b3.positioning_narrative || '—'}`,
      '',
      '── CAMPANHA ──',
      `Objectivo: ${b4.objective || '—'}`,
      `KPIs: ${formatKpis(b4.kpis)}`,
      `Canais: ${arr(b4.channels)}`,
      `Tom: ${b4.tone || '—'}`,
      `Mensagem-chave: ${b4.key_message || '—'}`,
      `Período: ${b4.timeline_start || '—'} → ${b4.timeline_end || '—'}`,
      '',
      '── RESTRIÇÕES ──',
      `Claims proibidos: ${arr(b5.prohibited_claims)}`,
      `Mensagens fora de posicionamento: ${arr(b5.off_brand_messages)}`,
      `Concorrentes a não nomear: ${arr(b5.competitors_not_name)}`,
    ].join('\n');
  };

  // TODO (Paulino): substituir esta função por POST /api/marketing/briefings/:id/send-email
  // com body { recipients: selected.map(s => s.email), subject, body }
  // e remover o window.open abaixo quando o SMTP estiver configurado.
  const handleSend = () => {
    if (!selected.length) return;
    const to = selected.map(s => s.email).join(',');
    const subject = encodeURIComponent(`Briefing — ${campanha.titulo}`);
    const body    = encodeURIComponent(buildEmailBody());
    window.open(`mailto:${to}?subject=${subject}&body=${body}`);
    onClose();
  };

  const TIPO_LABEL = {
    admin: 'Admin', c_suite: 'C-Suite', director: 'Director', manager: 'Manager',
    comercial: 'Comercial', tecnico: 'Técnico', marketing: 'Marketing',
    operacional: 'Operacional', administrativo: 'Administrativo',
  };

  const initials = (nome) => {
    const parts = (nome || '').split(' ').filter(Boolean);
    if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
    return (nome || '?')[0].toUpperCase();
  };

  return ReactDOM.createPortal(
    <div style={{
      position: 'fixed', inset: 0, zIndex: 10000,
      background: 'rgba(17,41,84,0.45)', backdropFilter: 'blur(2px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24,
    }} onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>

      <div style={{
        width: '100%', maxWidth: 520,
        background: '#ffffff', borderRadius: 14,
        boxShadow: '0 24px 64px rgba(17,41,84,0.18)',
        display: 'flex', flexDirection: 'column',
        maxHeight: 'calc(100vh - 48px)', overflow: 'hidden',
      }}>

        {/* Header */}
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--border, #ECEFF5)', flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
            <div>
              <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text, #283252)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', lineHeight: 1.3 }}>
                Enviar Briefing por Email
              </div>
              <div style={{ fontSize: 11.5, color: 'var(--text-muted, #94A4C4)', marginTop: 3, fontFamily: 'var(--font-body, Inter, sans-serif)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 380 }}>
                {campanha.titulo}
              </div>
            </div>
            <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted, #94A4C4)', padding: '2px 4px', fontSize: 18, lineHeight: 1, marginTop: -2, flexShrink: 0 }}>✕</button>
          </div>

          {/* Search */}
          <div style={{ marginTop: 14, position: 'relative' }}>
            <svg style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted, #94A4C4)', pointerEvents: 'none' }} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
            <input
              ref={searchRef}
              value={search}
              onChange={e => setSearch(e.target.value)}
              placeholder="Pesquisar por nome ou email…"
              style={{
                width: '100%', boxSizing: 'border-box',
                padding: '8px 12px 8px 32px',
                border: '1px solid var(--border, #ECEFF5)', borderRadius: 8,
                fontSize: 13, fontFamily: 'var(--font-body, Inter, sans-serif)',
                color: 'var(--text, #283252)', background: 'var(--bg-app, #F5F6F8)',
                outline: 'none',
              }}
            />
          </div>
        </div>

        {/* Selected chips */}
        {selected.length > 0 && (
          <div style={{ padding: '10px 24px', borderBottom: '1px solid var(--border, #ECEFF5)', display: 'flex', flexWrap: 'wrap', gap: 6, flexShrink: 0 }}>
            {selected.map(s => (
              <div key={s.id} style={{
                display: 'inline-flex', alignItems: 'center', gap: 5,
                background: 'rgba(56,89,208,0.08)', border: '1px solid rgba(56,89,208,0.18)',
                borderRadius: 99, padding: '3px 8px 3px 10px',
                fontSize: 12, color: 'var(--ai-500, #3859D0)', fontFamily: 'var(--font-body, Inter, sans-serif)', fontWeight: 500,
              }}>
                {s.nome}
                <button onClick={() => removeSelected(s.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ai-500, #3859D0)', padding: 0, fontSize: 13, lineHeight: 1, opacity: 0.7, display: 'flex', alignItems: 'center' }}>✕</button>
              </div>
            ))}
          </div>
        )}

        {/* User list */}
        <div className="scrollbar" style={{ flex: 1, overflowY: 'auto', minHeight: 0 }}>
          {allUsers.length === 0 ? (
            <div style={{ padding: '32px 24px', textAlign: 'center', fontSize: 13, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
              A carregar utilizadores…
            </div>
          ) : filteredUsers.length === 0 ? (
            <div style={{ padding: '32px 24px', textAlign: 'center', fontSize: 13, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
              Sem resultados para "{search}".
            </div>
          ) : (
            <div style={{ padding: '6px 0' }}>
              {filteredUsers.map(u => {
                const isSelected = !!selected.find(s => s.id === u.id);
                return (
                  <button key={u.id} onClick={() => toggle(u)} style={{
                    width: '100%', background: isSelected ? 'rgba(56,89,208,0.05)' : 'none',
                    border: 'none', padding: '9px 24px', cursor: 'pointer',
                    display: 'flex', alignItems: 'center', gap: 12, textAlign: 'left',
                    transition: 'background .1s',
                  }}
                  onMouseEnter={e => { if (!isSelected) e.currentTarget.style.background = 'var(--bg-app, #F5F6F8)'; }}
                  onMouseLeave={e => { e.currentTarget.style.background = isSelected ? 'rgba(56,89,208,0.05)' : 'none'; }}
                  >
                    {/* Avatar */}
                    <div style={{ width: 34, height: 34, borderRadius: '50%', flexShrink: 0, overflow: 'hidden', background: 'var(--border, #ECEFF5)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                      {u.foto_url
                        ? <img src={u.foto_url} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                        : <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{initials(u.nome_apresentar)}</span>
                      }
                    </div>
                    {/* Info */}
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text, #283252)', fontFamily: 'var(--font-body, Inter, sans-serif)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{u.nome_apresentar}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                        {u.perfil_cargo || TIPO_LABEL[u.tipo] || ''}
                        {u.email_profissional && <span style={{ marginLeft: 6, opacity: 0.75 }}>· {u.email_profissional}</span>}
                      </div>
                    </div>
                    {/* Checkbox */}
                    <div style={{
                      width: 18, height: 18, borderRadius: 5, flexShrink: 0,
                      border: `2px solid ${isSelected ? 'var(--ai-500, #3859D0)' : 'var(--border, #ECEFF5)'}`,
                      background: isSelected ? 'var(--ai-500, #3859D0)' : '#ffffff',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      transition: 'all .1s',
                    }}>
                      {isSelected && <svg width="10" height="10" viewBox="0 0 12 12" fill="none"><polyline points="2,6 5,9 10,3" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>}
                    </div>
                  </button>
                );
              })}
            </div>
          )}
        </div>

        {/* Footer */}
        <div style={{ borderTop: '1px solid var(--border, #ECEFF5)', padding: '12px 24px', flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 10 }}>

          {/* Email externo */}
          {externalOpen ? (
            <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
              <div style={{ flex: 1 }}>
                <input
                  value={externalInput}
                  onChange={e => { setExternalInput(e.target.value); setExternalError(''); }}
                  onKeyDown={e => e.key === 'Enter' && addExternal()}
                  placeholder="email@empresa.pt"
                  style={{
                    width: '100%', boxSizing: 'border-box',
                    padding: '7px 10px', border: `1px solid ${externalError ? '#CF2E2E' : 'var(--border, #ECEFF5)'}`,
                    borderRadius: 7, fontSize: 12.5, fontFamily: 'var(--font-body, Inter, sans-serif)',
                    color: 'var(--text, #283252)', background: 'var(--bg-app, #F5F6F8)', outline: 'none',
                  }}
                  autoFocus
                />
                {externalError && <div style={{ fontSize: 11, color: '#CF2E2E', marginTop: 3, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{externalError}</div>}
              </div>
              <button onClick={addExternal} className="btn btn-xs btn-ai">Adicionar</button>
              <button onClick={() => { setExternalOpen(false); setExternalError(''); setExternalInput(''); }} className="btn btn-xs">Cancelar</button>
            </div>
          ) : (
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
              <button
                onClick={() => setExternalOpen(true)}
                style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 12, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)', padding: 0, display: 'flex', alignItems: 'center', gap: 4 }}
              >
                <span style={{ fontSize: 14, lineHeight: 1 }}>+</span> Adicionar email externo
              </button>
              {!showAll && allUsers.some(u => !u.portal_activo) && (
                <button
                  onClick={() => setShowAll(true)}
                  style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 11.5, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)', padding: 0 }}
                >
                  Mostrar todos ({allUsers.length})
                </button>
              )}
            </div>
          )}

          {/* Actions */}
          <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
            <button onClick={onClose} className="btn" style={{ height: 34, padding: '0 16px', fontSize: 13 }}>Cancelar</button>
            <button
              onClick={handleSend}
              disabled={!selected.length}
              className="btn btn-ai"
              style={{ height: 34, padding: '0 18px', fontSize: 13, opacity: selected.length ? 1 : 0.45 }}
            >
              Abrir no Email →
            </button>
          </div>
        </div>

      </div>
    </div>,
    document.body
  );
};

// ── BriefingResumo ─────────────────────────────────────────────────────────────
const BriefingResumo = ({ campanha, onBack, onRefresh }) => {
  const [briefing,    setBriefing]    = React.useState(null);
  const [loading,     setLoading]     = React.useState(true);
  const [generating,  setGenerating]  = React.useState(false);
  const [emailModal,  setEmailModal]  = React.useState(false);
  const bCol = _brandColor(campanha.brand_slug);

  React.useEffect(() => {
    if (!campanha.briefing_id) { setLoading(false); return; }
    CampAPI.getBriefing(campanha.briefing_id)
      .then(d => setBriefing(d))
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [campanha.briefing_id]);

  const handleGerar = async () => {
    setGenerating(true);
    try { await CampAPI.generateConceito(campanha.id); } catch (e) {}
    setGenerating(false);
    onRefresh();
    onBack();
  };

  // Helpers para texto narrativo
  const str = (v) => v || null;
  const list = (v) => Array.isArray(v) && v.length ? v : null;
  const joinNarr = (items, prefix) => {
    if (!items || !items.length) return null;
    const clean = items.map(i => typeof i === 'object' ? (i.name || i.label || '') : i).filter(Boolean);
    if (!clean.length) return null;
    if (clean.length === 1) return `${prefix} ${clean[0]}.`;
    return `${prefix} ${clean.slice(0, -1).join(', ')} e ${clean[clean.length - 1]}.`;
  };

  const Section = ({ title, num, children }) => (
    <div style={{ background: '#ffffff', border: '1px solid var(--border, #ECEFF5)', borderRadius: 10, padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 22, height: 22, borderRadius: '50%', background: bCol, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <span style={{ fontSize: 10, fontWeight: 700, color: '#fff', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{num}</span>
        </div>
        <div style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: bCol, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{title}</div>
      </div>
      {children}
    </div>
  );

  const Row = ({ label, value }) => value ? (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <div style={{ fontSize: 10, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{label}</div>
      <div style={{ fontSize: 13.5, color: 'var(--text, #283252)', lineHeight: 1.65, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{value}</div>
    </div>
  ) : null;

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg-app, #F5F6F8)' }}>

      {/* ── Page Header ── */}
      <div style={{ background: '#ffffff', borderBottom: '1px solid var(--border, #ECEFF5)', padding: '20px 40px 20px', flexShrink: 0 }}>

        <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', color: 'var(--text-muted, #94A4C4)', textTransform: 'uppercase', marginBottom: 6, fontFamily: 'var(--font-mono, monospace)' }}>
          MARKETING · CAMPANHAS
        </div>

        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16 }}>
          <div>
            <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text, #283252)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', letterSpacing: '-0.01em', lineHeight: 1.2 }}>
              {campanha.titulo}
            </h1>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6, flexWrap: 'wrap' }}>
              <CampStatusBadge status={campanha.status || 'conceito_pendente'} />
              {campanha.brand_name && (
                <span style={{ fontSize: 11, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
                  {campanha.brand_name}
                </span>
              )}
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexShrink: 0, marginTop: 2 }}>
            <button onClick={onBack} className="btn" style={{ height: 30, padding: '0 12px', fontSize: 12 }}>← Voltar</button>
            <button onClick={() => setEmailModal(true)} disabled={!briefing} className="btn" style={{ height: 30, padding: '0 12px', fontSize: 12 }}>Enviar por Email</button>
            <button onClick={handleGerar} disabled={generating || !briefing} className="btn btn-ai" style={{ height: 30, padding: '0 14px', fontSize: 12 }}>
              {generating ? 'A gerar…' : 'Gerar Conceito'}
            </button>
          </div>
        </div>
      </div>

      {/* Conteúdo scrollável */}
      <div className="scrollbar" style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ display: 'flex', gap: 20, padding: '24px 40px 40px', alignItems: 'flex-start' }}>

          {loading ? (
            <div style={{ flex: 1, padding: 32, fontSize: 13, color: 'var(--text-muted, #94A4C4)' }}>A carregar briefing…</div>
          ) : !briefing ? (
            <div style={{ flex: 1, padding: 32, fontSize: 13, color: 'var(--text-muted, #94A4C4)' }}>Briefing não encontrado.</div>
          ) : (
            <>
              {/* Coluna principal */}
              <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 12 }}>

                {/* B1 — Produto */}
                {briefing.block1 && (
                  <Section title="Produto" num="1">
                    {str(briefing.block1.elevator_pitch) && (
                      <Row label="Em resumo" value={briefing.block1.elevator_pitch} />
                    )}
                    {list(briefing.block1.usps) && (
                      <Row label="Vantagens competitivas" value={joinNarr(briefing.block1.usps, 'O produto destaca-se por')} />
                    )}
                    {list(briefing.block1.applications) && (
                      <Row label="Aplicações" value={joinNarr(briefing.block1.applications, 'Indicado para')} />
                    )}
                    {list(briefing.block1.geo_markets) && (
                      <Row label="Mercados" value={joinNarr(briefing.block1.geo_markets, 'Actua em')} />
                    )}
                  </Section>
                )}

                {/* B2 — Cliente-alvo */}
                {briefing.block2 && (
                  <Section title="Cliente-alvo" num="2">
                    {(str(briefing.block2.decision_maker) || str(briefing.block2.end_user)) && (
                      <Row label="Quem decide e quem usa"
                        value={[briefing.block2.decision_maker && `O decisor de compra é o ${briefing.block2.decision_maker}`, briefing.block2.end_user && `quem utiliza o produto no dia-a-dia é o ${briefing.block2.end_user}`].filter(Boolean).join('. ') + '.'}
                      />
                    )}
                    {list(briefing.block2.pain_points) && (
                      <Row label="Principais desafios" value={joinNarr(briefing.block2.pain_points, 'Os principais problemas que enfrentam são')} />
                    )}
                    {list(briefing.block2.motivators) && (
                      <Row label="O que os motiva a comprar" value={joinNarr(briefing.block2.motivators, 'Os motivadores de decisão são')} />
                    )}
                    {list(briefing.block2.objections) && (
                      <Row label="Objecções a antecipar" value={joinNarr(briefing.block2.objections, 'As objecções mais comuns são')} />
                    )}
                    {str(briefing.block2.purchase_trigger) && (
                      <Row label="O que precipita a decisão" value={briefing.block2.purchase_trigger} />
                    )}
                  </Section>
                )}

                {/* B3 — Mercado */}
                {briefing.block3 && (
                  <Section title="Mercado" num="3">
                    {list(briefing.block3.competitors) && (
                      <Row label="Concorrentes directos" value={joinNarr(briefing.block3.competitors, 'Competimos directamente com')} />
                    )}
                    {list(briefing.block3.differentiation_args) && (
                      <Row label="Como nos diferenciamos" value={joinNarr(briefing.block3.differentiation_args, 'Os nossos argumentos de diferenciação são')} />
                    )}
                    {list(briefing.block3.market_trends) && (
                      <Row label="Tendências relevantes" value={joinNarr(briefing.block3.market_trends, 'O mercado está a ser influenciado por')} />
                    )}
                    {str(briefing.block3.positioning_narrative) && (
                      <Row label="Posicionamento desejado" value={briefing.block3.positioning_narrative} />
                    )}
                  </Section>
                )}

                {/* B4 — Campanha */}
                {briefing.block4 && (
                  <Section title="Campanha" num="4">
                    {str(briefing.block4.key_message) && (
                      <Row label="Mensagem central" value={briefing.block4.key_message} />
                    )}
                    {str(briefing.block4.objective) && (
                      <Row label="Objectivo" value={(() => { const m = { awareness: 'Awareness — aumentar reconhecimento de marca', lead_gen: 'Geração de leads qualificados', conversion: 'Conversão directa', retention: 'Retenção e upsell de clientes existentes' }; return m[briefing.block4.objective] || briefing.block4.objective; })()} />
                    )}
                    {list(briefing.block4.kpis) && (
                      <Row label="KPIs de sucesso" value={formatKpis(briefing.block4.kpis)} />
                    )}
                    {str(briefing.block4.tone) && (
                      <Row label="Tom e linguagem" value={briefing.block4.tone} />
                    )}
                    {list(briefing.block4.channels) && (
                      <Row label="Canais" value={joinNarr(briefing.block4.channels, 'A campanha vai estar presente em')} />
                    )}
                    {(str(briefing.block4.timeline_start) || str(briefing.block4.timeline_end)) && (
                      <Row label="Período" value={[briefing.block4.timeline_start, briefing.block4.timeline_end].filter(Boolean).join(' → ')} />
                    )}
                    {briefing.block4.commercial_offer && (() => {
                      const o = briefing.block4.commercial_offer;
                      const tl = { digirent:'Digirent', printplan:'PrintPlan', voucher:'Voucher on Demand', direct_discount:'Desconto Directo', trade_in:'Trade-In' };
                      const cl = { quote_request:'pedido de proposta', whatsapp:'WhatsApp', form:'formulário', call:'chamada directa', landing:'landing page' };
                      const tm = { standard:'Standard', premium:'Premium', tailor_made:'Tailor-Made', tailor_made_rappel:'Tailor-Made (entrada Rappel)', tailor_made_renda:'Tailor-Made (entrada + renda)' };
                      const parts = [`${tl[o.type] || o.type}${o.tier ? ' · ' + (tm[o.tier] || o.tier) : ''}`];
                      if (o.details) parts.push(o.details);
                      const ctaStr = o.primary_cta && o.primary_cta !== 'none' ? `CTA: ${cl[o.primary_cta] || o.primary_cta}` : null;
                      const val = [parts.join(' — '), ctaStr, o.negotiable ? 'Tier negociável.' : null].filter(Boolean).join('. ');
                      return <Row label="Oferta comercial" value={val} />;
                    })()}
                  </Section>
                )}

                {/* B5 — Restrições */}
                {briefing.block5 && (list(briefing.block5.prohibited_claims) || list(briefing.block5.off_brand_messages) || list(briefing.block5.competitors_not_name)) && (
                  <Section title="Restrições" num="5">
                    {list(briefing.block5.prohibited_claims) && (
                      <Row label="Claims que não podem ser usados" value={joinNarr(briefing.block5.prohibited_claims, 'É proibido afirmar')} />
                    )}
                    {list(briefing.block5.off_brand_messages) && (
                      <Row label="Mensagens fora de posicionamento" value={joinNarr(briefing.block5.off_brand_messages, 'Não deve transmitir')} />
                    )}
                    {list(briefing.block5.competitors_not_name) && (
                      <Row label="Concorrentes a não nomear" value={joinNarr(briefing.block5.competitors_not_name, 'Não devem ser referenciados')} />
                    )}
                  </Section>
                )}
              </div>

              {/* Painel direito — meta */}
              <div style={{ width: 260, flexShrink: 0, position: 'sticky', top: 20, display: 'flex', flexDirection: 'column', gap: 12 }}>
                <div style={{ background: '#ffffff', border: '1px solid var(--border, #ECEFF5)', borderRadius: 10, padding: '16px 18px', display: 'flex', flexDirection: 'column', gap: 12 }}>
                  <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Resumo</div>
                  {campanha.brand_name && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                      <span style={{ fontSize: 10, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Marca</span>
                      <span style={{ fontSize: 13, fontWeight: 600, color: bCol, fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{campanha.brand_name}</span>
                    </div>
                  )}
                  {(campanha.commercial_name || campanha.product_name) && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                      <span style={{ fontSize: 10, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Produto</span>
                      <span style={{ fontSize: 12, color: 'var(--text, #283252)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{campanha.commercial_name || campanha.product_name}</span>
                    </div>
                  )}
                  {list(briefing.block4?.channels) && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                      <span style={{ fontSize: 10, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Canais</span>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                        {briefing.block4.channels.map((ch, i) => (
                          <span key={i} style={{ fontSize: 11, padding: '2px 8px', borderRadius: 99, background: 'var(--bg-app, #F5F6F8)', border: '1px solid var(--border, #ECEFF5)', color: 'var(--text, #283252)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
                            {CANAL_LABEL[ch] || ch}
                          </span>
                        ))}
                      </div>
                    </div>
                  )}
                  {list(briefing.block1?.geo_markets) && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                      <span style={{ fontSize: 10, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Mercados</span>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                        {briefing.block1.geo_markets.map((m, i) => (
                          <span key={i} style={{ fontSize: 11, padding: '2px 8px', borderRadius: 99, background: 'var(--bg-app, #F5F6F8)', border: '1px solid var(--border, #ECEFF5)', color: 'var(--text, #283252)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{m}</span>
                        ))}
                      </div>
                    </div>
                  )}
                  {(briefing.block4?.timeline_start || briefing.block4?.timeline_end) && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                      <span style={{ fontSize: 10, color: 'var(--text-muted, #94A4C4)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>Período</span>
                      <span style={{ fontSize: 12, color: 'var(--text, #283252)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>{[briefing.block4.timeline_start, briefing.block4.timeline_end].filter(Boolean).join(' → ')}</span>
                    </div>
                  )}
                </div>
              </div>
            </>
          )}
        </div>
      </div>

      {emailModal && (
        <EmailBriefingModal
          campanha={campanha}
          briefing={briefing}
          onClose={() => setEmailModal(false)}
        />
      )}
    </div>
  );
};

// ── NovaCampanhaModal ──────────────────────────────────────────────────────────
const NovaCampanhaModal = ({ onClose, onCreated }) => {
  const [briefings,    setBriefings]    = React.useState(null);
  const [selected,     setSelected]     = React.useState(null);
  const [saving,       setSaving]       = React.useState(false);
  const [error,        setError]        = React.useState('');
  const [brandFilter,  setBrandFilter]  = React.useState('all');
  const isSubmittingRef = React.useRef(false);

  React.useEffect(() => {
    CampAPI.availableForCampaign()
      .then(d => setBriefings(Array.isArray(d) ? d : []))
      .catch(() => setBriefings([]));
  }, []);

  const handleCreate = async () => {
    if (!selected || isSubmittingRef.current) return;
    isSubmittingRef.current = true;
    setSaving(true); setError('');
    try {
      const titulo = selected.commercial_name || selected.product_name || `Campanha #${selected.id}`;
      const camp = await CampAPI.create({ briefing_id: selected.id, titulo });
      if (camp?.error) throw new Error(camp.error);
      onCreated(camp);
    } catch (e) {
      setError(e.message || 'Erro ao criar campanha.');
    } finally {
      isSubmittingRef.current = false;
      setSaving(false);
    }
  };

  const goToBriefings = () => {
    onClose();
    if (window.mktNavToSub) window.mktNavToSub('briefings');
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(0,0,0,0.55)', display: 'flex', alignItems: 'center', justifyContent: 'center',
    }} onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{
        background: '#ffffff', border: '1px solid var(--border, #e2e8f0)',
        borderRadius: 12, width: 520, height: 480, display: 'flex', flexDirection: 'column',
        boxShadow: '0 24px 64px rgba(0,0,0,0.4)',
      }}>
        {/* Header */}
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--border, #e2e8f0)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
          <div>
            <div style={{ fontSize: 10, fontFamily: 'var(--font-mono, monospace)', color: 'var(--text-dim, #475569)', letterSpacing: '0.08em', marginBottom: 4 }}>NOVA CAMPANHA</div>
            <div style={{ fontSize: 15, fontWeight: 600, fontFamily: 'var(--font-display, Montserrat, sans-serif)', color: 'var(--text, #1e293b)' }}>Selecciona um briefing aprovado</div>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', color: 'var(--text-muted, #64748b)', fontSize: 18, cursor: 'pointer', lineHeight: 1, padding: 4 }}>✕</button>
        </div>

        {/* Brand pills */}
        {briefings && briefings.length > 0 && (() => {
          const brands = [{ slug: 'all', name: 'Todas', color: '#3859D0' },
            ...Object.values(briefings.reduce((acc, b) => {
              if (b.brand_slug && !acc[b.brand_slug]) acc[b.brand_slug] = { slug: b.brand_slug, name: b.brand_name || b.brand_slug, color: b.brand_color || '#3859D0' };
              return acc;
            }, {}))
          ];
          if (brands.length <= 2) return null;
          return (
            <div style={{ display: 'flex', gap: 6, padding: '10px 24px', borderBottom: '1px solid var(--border, #ECEFF5)', flexWrap: 'wrap', flexShrink: 0 }}>
              {brands.map(b => {
                const active = b.slug === brandFilter;
                return (
                  <button key={b.slug} onClick={() => { setBrandFilter(b.slug); setSelected(null); }} style={{
                    padding: '4px 12px', borderRadius: 99, border: `1px solid ${active ? b.color : 'var(--border, #ECEFF5)'}`,
                    background: active ? b.color + '15' : 'transparent',
                    color: active ? b.color : 'var(--text-muted, #94A4C4)',
                    fontSize: 12, fontWeight: active ? 600 : 400,
                    fontFamily: 'var(--font-body, Inter, sans-serif)', cursor: 'pointer', transition: 'all .12s',
                  }}>
                    {b.name}
                  </button>
                );
              })}
            </div>
          );
        })()}

        {/* Body */}
        <div className="scrollbar" style={{ flex: 1, overflowY: 'auto', padding: '12px 24px' }}>
          {briefings === null ? (
            <div style={{ padding: '32px 0', textAlign: 'center', color: 'var(--text-muted, #64748b)', fontSize: 13 }}>A carregar…</div>
          ) : briefings.length === 0 ? (
            <div style={{ padding: '32px 0', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
              <div style={{ fontSize: 13, color: 'var(--text-muted, #64748b)' }}>Não há briefings aprovados disponíveis.</div>
              <button onClick={goToBriefings} className="btn btn-ai">
                Ir para Briefings
              </button>
            </div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {briefings.filter(b => brandFilter === 'all' || b.brand_slug === brandFilter).map(b => {
                const isActive = selected?.id === b.id;
                const bColor = b.brand_color || '#3859D0';
                return (
                  <div key={b.id} onClick={() => setSelected(b)} style={{
                    padding: '12px 14px', borderRadius: 8, cursor: 'pointer',
                    border: `1px solid ${isActive ? 'var(--ai-500, #3859D0)' : 'var(--border, #e2e8f0)'}`,
                    background: isActive ? 'color-mix(in oklch, var(--ai-500, #3859D0) 8%, transparent)' : 'var(--bg, #f8fafc)',
                    transition: 'border-color .15s, background .15s',
                    display: 'flex', alignItems: 'center', gap: 12,
                  }}>
                    <div style={{ width: 4, borderRadius: 2, alignSelf: 'stretch', background: bColor, flexShrink: 0 }} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                        <span style={{ fontSize: 11, fontWeight: 700, color: bColor, fontFamily: 'var(--font-display, Montserrat, sans-serif)', letterSpacing: '0.04em' }}>{b.brand_name}</span>
                        {(b.commercial_name || b.product_name) && (
                          <span style={{ fontSize: 12, color: 'var(--text, #1e293b)', fontWeight: 500 }}>{b.commercial_name || b.product_name}</span>
                        )}
                      </div>
                    </div>
                    {isActive && <div style={{ color: 'var(--ai-500, #3859D0)', fontSize: 16, flexShrink: 0 }}>✓</div>}
                  </div>
                );
              })}
            </div>
          )}
          {error && <div style={{ marginTop: 8, fontSize: 12, color: 'var(--danger, #ef4444)' }}>{error}</div>}
        </div>

        {/* Footer */}
        {briefings && briefings.length > 0 && (
          <div style={{ padding: '14px 24px', borderTop: '1px solid var(--border, #e2e8f0)', display: 'flex', justifyContent: 'flex-end', gap: 8, flexShrink: 0 }}>
            <button onClick={onClose} className="btn">Cancelar</button>
            <button onClick={handleCreate} disabled={!selected || saving} className="btn btn-ai"
              style={{ opacity: (!selected || saving) ? 0.5 : 1 }}>
              {saving ? 'A criar…' : 'Criar Campanha'}
            </button>
          </div>
        )}
      </div>
    </div>
  );
};

// ── MktCampanhasScreen (main) ──────────────────────────────────────────────────
// ── TabPerformanceFull ─────────────────────────────────────────────────────────
const TabPerformanceFull = ({ campanhaId }) => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState('');

  const load = React.useCallback(() => {
    if (!campanhaId) return;
    setLoading(true);
    campApiCall(`/api/marketing/campanhas/${campanhaId}/performance`)
      .then(d => { setData(d); setLoading(false); })
      .catch(e => { setError(e.message); setLoading(false); });
  }, [campanhaId]);

  React.useEffect(() => { load(); }, [load]);

  if (loading) return <div style={{ padding: 40, textAlign: 'center', fontSize: 13, color: 'var(--text-muted)' }}>A carregar métricas...</div>;
  if (error)   return <div style={{ padding: 24, fontSize: 13, color: '#dc2626' }}>{error}</div>;
  if (!data || !data.metrics?.length) return (
    <div style={{ padding: 40, textAlign: 'center', fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.7, maxWidth: 400, margin: '0 auto' }}>
      <div style={{ fontWeight: 600, color: 'var(--text)', marginBottom: 8 }}>Sem métricas disponíveis</div>
      <div>{data?.message || 'Quando a campanha for publicada e ligada a um external_id (ad_id), as métricas aparecerão aqui.'}</div>
    </div>
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em', marginBottom: 4, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span>PERFORMANCE · {data.metrics.length} {data.metrics.length === 1 ? 'publicação' : 'publicações'}</span>
        <button onClick={load} className="btn" style={{ height: 24, padding: '0 10px', fontSize: 11 }}>Actualizar</button>
      </div>
      {data.metrics.map((m, i) => (
        <div key={i} style={{ background: '#fff', borderRadius: 10, border: '1px solid var(--border)', padding: '16px 20px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
            <CanalSvgIcon canal={m.canal} size={16} />
            <span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)' }}>
              {CANAL_LABEL[m.canal] || m.canal}
            </span>
            {m.external_id && <span style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>#{m.external_id}</span>}
            {m.publicado_em && <span style={{ fontSize: 10, color: 'var(--text-dim)' }}>{new Date(m.publicado_em).toLocaleDateString('pt-PT', { day: '2-digit', month: 'short' })}</span>}
          </div>
          {m.error ? (
            <div style={{ fontSize: 12, color: '#d97706', padding: '8px 12px', background: 'rgba(217,119,6,.06)', borderRadius: 6, border: '1px solid rgba(217,119,6,.2)' }}>
              {m.error}
            </div>
          ) : (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(100px, 1fr))', gap: 10 }}>
              {[
                { label: 'Impressões', val: m.impressions || m.reach || '—' },
                { label: 'Cliques',    val: m.clicks || '—' },
                { label: 'CTR',        val: m.ctr ? `${(m.ctr * 100).toFixed(2)}%` : '—' },
                { label: 'Leads',      val: m.leads || m.conversions || '—' },
                { label: 'CPL',        val: m.cpl ? `€${Number(m.cpl).toFixed(2)}` : '—' },
                { label: 'Gasto',      val: m.spend ? `€${Number(m.spend).toFixed(2)}` : '—' },
              ].map(kv => (
                <div key={kv.label} style={{ textAlign: 'center', padding: '8px 4px', background: 'var(--bg-sunken)', borderRadius: 6 }}>
                  <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-mono)' }}>{kv.val}</div>
                  <div style={{ fontSize: 10, color: 'var(--text-dim)', marginTop: 2 }}>{kv.label}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      ))}
    </div>
  );
};

// ── TabSDRAI — Ficha SDR por campanha · o que vai ser injectado no SP_CLIENTES ─
const TabSDRAI = ({ campanha, userEmail }) => {
  const brief    = campanha?.briefing || {};
  const proposta = campanha?.proposta_json || {};
  const estrat   = campanha?.estrategia_json || {};
  const commPlan = (proposta.comm_plan || []);

  const MATERIAIS_BRANDS = new Set(['decal','biond','sensek','alldecor']);
  const isMateriais = MATERIAIS_BRANDS.has((campanha?.brand_slug || '').toLowerCase());
  const ctaLabel    = isMateriais ? '1 rolo / amostra de teste sem risco' : 'Demo no showroom + voucher €100';
  const bCol = _brandColor(campanha?.brand_slug);

  const _a = v => Array.isArray(v) ? v : (v ? [v] : []);
  const _str = v => typeof v === 'string' ? v : (v?.descricao || v?.usp || v?.angulo || JSON.stringify(v) || '');

  const usps        = _a(brief.usps).slice(0,5).map(_str);
  const pains       = _a(brief.pain_points).slice(0,5).map(_str);
  const diffArgs    = _a(brief.differentiation_args).slice(0,4).map(_str);
  const angles      = _a(proposta.messaging_angles).slice(0,4);
  const competitors = _a(brief.competitors).slice(0,3).map(_str);
  const markets     = estrat.markets || [];
  const personas    = markets.flatMap(m => _a(m.personas_priorizadas)).filter((p,i,a) => a.findIndex(x => (x.nome||x.perfil) === (p.nome||p.perfil)) === i).slice(0,3);
  const msgPT       = markets.find(m => m.country === 'PT')?.mensagem_unificada || markets[0]?.mensagem_unificada || {};

  const offerRaw  = brief.commercial_offer;
  const offer     = offerRaw ? (typeof offerRaw === 'string' ? (() => { try { return JSON.parse(offerRaw); } catch { return { descricao: offerRaw }; } })() : offerRaw) : {};

  // Objecções derivadas: brief.objections (se existir) + derivadas das dores/diff_args
  const rawObj = _a(brief.objections).map(_str).filter(Boolean);
  const derivedObj = rawObj.length > 0 ? rawObj : [
    ...pains.slice(0,2).map(p => `"Já temos fornecedor e funciona" — ${p.slice(0,80)}...`),
    ...diffArgs.slice(0,2).map(d => `Preocupação com mudança — ${d.slice(0,80)}...`),
  ];
  const objections = derivedObj.slice(0,4);

  // Respostas SDR às objecções (baseadas nas diff_args e mensagem estratégia)
  const objResponses = [
    diffArgs[1] || 'Reposicionamento e remoção sem resíduos — compare ao vivo com 1 rolo.',
    diffArgs[0] || 'Qualquer colaborador aplica, sem espátula — menos custo de instalação.',
    msgPT.consideration?.slice(0,120) || 'Os custos ocultos (limpeza, retrabalho, bolhas em obra) são onde está a diferença real.',
    'É precisamente por isso que criámos o teste de 1 rolo — sem compromisso, sem mudança de fornecedor. Só para comparar.',
  ];

  const waItems    = commPlan.filter(i => i.canal === 'whatsapp');
  const emailItems = commPlan.filter(i => i.canal === 'email');

  const CRM_FIELDS = isMateriais ? [
    'Produto / referência testada','Aplicação testada','Material actual utilizado',
    'Marca / fornecedor actual','Volume estimado (rolos/mês)','Dor principal identificada',
    'USP mais relevante','Rolo teste aceite (S/N)','Data envio amostra','Data prevista do teste',
    'Resultado do teste','Potencial mensal (€ / nº rolos)','Score','Próxima acção',
  ] : [
    'Sector / aplicação','Parque actual (marca + modelo)','Volume m²/mês',
    'Subcontratação (% / €/mês)','Budget','Timing','Decisor identificado',
    'Ten#1 Produto','Ten#2 Confiança','Ten#3 Marca','Score (0-120)','Demo agendada','Próxima acção',
  ];

  const SCORE = isMateriais ? [
    { criterio:'Usa actualmente a categoria de produto', pts:20 },
    { criterio:'Volume de consumo relevante (rolos/mês)', pts:20 },
    { criterio:'Usa produto concorrente identificado', pts:15 },
    { criterio:'Tem aplicação adequada ao produto', pts:15 },
    { criterio:'Identificou uma dor concreta (custo, tempo, qualidade)', pts:10 },
    { criterio:'Demonstrou interesse em testar', pts:10 },
    { criterio:'Aceitou receber amostra / rolo de teste', pts:10 },
  ] : [
    { criterio:'Ten#1 Produto ≥ 8 (confiança no produto)', pts:35 },
    { criterio:'Ten#2 Confiança ≥ 7 (confia na Digidelta)', pts:30 },
    { criterio:'Ten#3 Marca ≥ 7 (confia na marca)', pts:25 },
    { criterio:'Demo agendada', pts:10 },
  ];

  // Cenários de conversa — 100% dinâmicos a partir dos dados da campanha
  const productName = brief.commercial_name || campanha?.titulo || 'produto';
  const ofertaStr   = offer.oferta ? `${offer.oferta}${offer.condicao ? ` — ${offer.condicao}` : ''}` : (isMateriais ? `1 ${productName} de teste` : 'demo no showroom + voucher €100');
  const pitchCurto  = (brief.elevator_pitch || pains[0] || '').slice(0,100);
  const painA_raw   = pains[0] || '';
  const painB_raw   = pains[1] || '';
  const uspPrincipal= diffArgs[0] || usps[0] || '';
  const uspSecundario= diffArgs[1] || usps[1] || '';
  const uspTecnico  = diffArgs[2] || usps[2] || '';
  const objA        = objections[0] || '';
  const respA       = objResponses[0] || '';
  const decisao     = msgPT.decision?.slice(0,120) || (isMateriais ? `Posso avançar com ${ofertaStr}?` : 'Vale a pena vires 30 minutos — sais com os números reais para o teu caso.');
  const persona1    = personas[0] ? _str(personas[0].nome || personas[0].perfil).split('—')[0].trim().slice(0,50) : 'decisor de produção';

  // Para equipamentos: seguir SP_CLIENTES (demo-centric, Three Tens)
  const SCENARIOS_EQUIP = [
    {
      id:'A', label:'Lead com dor activa', badge:'🔥 Alta prioridade', badgeCol:'#dc2626',
      desc: `Lead: ${persona1} — chega com dor de ${pitchCurto.slice(0,60)}...`,
      msgs:[
        { from:'digi', text:`${pitchCurto ? pitchCurto.slice(0,80) + '.' : `${productName} — há alguma coisa específica que te trouxe até nós?`} Sou a Digi, agente de IA da Digidelta. Tens dois minutos?` },
        { from:'lead', text:`Sim. Estou a avaliar opções para upgrade de produção.` },
        { from:'digi', text:`${uspPrincipal.slice(0,100)} — é exactamente o que o ${productName} oferece. Vale a pena vires ao showroom ver ao vivo. São 30 minutos, sais com os números reais para o teu volume. E quando vieres tens um voucher de €100 em consumíveis. Que disponibilidade tens?` },
      ],
    },
    {
      id:'B', label:'"Estou só a recolher informação"', badge:'🟢 Potencial', badgeCol:'#16a34a',
      desc:'Lead não tem urgência mas tem interesse no produto.',
      msgs:[
        { from:'digi', text:`Sou a Digi, IA da Digidelta. O ${productName} — pelo vosso perfil, pode fazer sentido. Posso fazer-te duas perguntas rápidas?` },
        { from:'lead', text:`Claro, mas estamos só a ver opções por agora.` },
        { from:'digi', text:`Percebo. ${painA_raw.slice(0,80) || 'Que desafio de produção vos está a preocupar mais neste momento?'}` },
        { from:'lead', text:`[resposta sobre o contexto de produção]` },
        { from:'digi', text:`${uspPrincipal.slice(0,100)}. A demo é um test drive — vês ao vivo, sais com os números reais. Quando tens 30 minutos nas próximas semanas?` },
      ],
    },
    {
      id:'C', label:'Objecção de investimento', badge:'🟡 Qualificar', badgeCol:'#d97706',
      desc:'Lead interessado mas com objecção de preço / timing.',
      msgs:[
        { from:'digi', text:`O ${productName} ${pitchCurto.slice(0,60)}. Tens dois minutos?` },
        { from:'lead', text:`Sim, mas o timing é complicado — já temos um equipamento recente.` },
        { from:'digi', text:`Faz sentido. ${uspSecundario.slice(0,100) || uspPrincipal.slice(0,100)}. Há sempre uma forma de fazer sentido financeiramente — DigiRent (€0 entrada), PrintPlan (custo por m²). Qual a tua situação actual de volume?` },
        { from:'lead', text:`Fazemos cerca de [X m²/mês].` },
        { from:'digi', text:`Com esse volume o PayBack é rápido. Vamos ver os números reais — são 30 minutos. Quando tens disponibilidade?` },
      ],
    },
  ];

  // Para materiais: metodologia Rui (1 rolo teste, sem risco)
  const SCENARIOS_MAT = [
    {
      id:'A', label:'Lead com dor activa', badge:'🔥 Alta prioridade', badgeCol:'#dc2626',
      desc:`Lead: ${persona1} — chega com dor de ${painA_raw.slice(0,60)}...`,
      msgs:[
        { from:'digi', text:`${painA_raw.slice(0,80) || `Empresas com o vosso perfil têm frequentemente desafios com ${productName}`}. Sou a Digi, IA da Digidelta. Tens dois minutos?` },
        { from:'lead', text:`Sim, temos esse problema com regularidade.` },
        { from:'digi', text:`Que produto utilizam actualmente para essa aplicação?` },
        { from:'lead', text:`Usamos [produto concorrente]. Funciona mas temos [problema].` },
        { from:'digi', text:`Percebo — e esse [problema] já vai no orçamento ou sai da margem? O ${productName}: ${uspPrincipal.slice(0,100)}. Proponho algo simples: experimente 1 ${productName}. Compara com o que usa hoje — se não notar diferença, não perdeu nada.` },
        { from:'lead', text:`Isso seria interessante.` },
        { from:'digi', text:`${ofertaStr}. Qual seria a aplicação ideal para o teste?` },
      ],
    },
    {
      id:'B', label:'"Satisfeito com o fornecedor actual"', badge:'🟢 Potencial', badgeCol:'#16a34a',
      desc:'Lead diz que está satisfeito com o que usa actualmente.',
      msgs:[
        { from:'digi', text:`Sou a Digi, IA da Digidelta. Estamos a fazer uma campanha com o ${productName} — pelo vosso perfil, achei que poderia fazer sentido. Posso fazer-te duas perguntas?` },
        { from:'lead', text:`Pode ser, mas estamos satisfeitos com o fornecedor actual.` },
        { from:'digi', text:`Fico contente que funcione. Uma pergunta: ${painB_raw.slice(0,80) || `no vosso processo, há alguma etapa que gostaria de tornar mais eficiente ou económica?`}` },
        { from:'lead', text:`[resposta sobre o contexto]` },
        { from:'digi', text:`${uspSecundario.slice(0,100) || uspPrincipal.slice(0,100)}. Não vos estou a pedir para mudar de fornecedor — só para comparar com 1 ${productName} numa aplicação real. O que acha?` },
        { from:'lead', text:`Pode ser interessante.` },
        { from:'digi', text:`${decisao} Que aplicação faria sentido para o teste?` },
      ],
    },
    {
      id:'C', label:'Objecção técnica / compatibilidade', badge:'🟡 Qualificar', badgeCol:'#d97706',
      desc:`Lead questiona compatibilidade ou condições técnicas.`,
      msgs:[
        { from:'digi', text:`${pitchCurto.slice(0,80) || `Pelo vosso perfil, o ${productName} pode ser relevante`}. Tens dois minutos?` },
        { from:'lead', text:`Sim, mas já tivemos problemas com ${objA.slice(0,60) || 'compatibilidade com novos materiais'}.` },
        { from:'digi', text:`É uma preocupação legítima. ${uspTecnico.slice(0,120) || respA.slice(0,120)}` },
        { from:'lead', text:`Isso é importante para o nosso processo.` },
        { from:'digi', text:`É exactamente por isso que criámos o teste: experimente no vosso equipamento, na vossa aplicação real. ${ofertaStr}. Que equipamento utilizam?` },
        { from:'lead', text:`[resposta sobre equipamento]` },
        { from:'digi', text:`Quando têm o próximo trabalho em que faria sentido testar?` },
      ],
    },
  ];

  const SCENARIOS = isMateriais ? SCENARIOS_MAT : SCENARIOS_EQUIP;

  const secTitle = (t, col) => (
    <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.08em', color:col||bCol, marginBottom:10, paddingBottom:6, borderBottom:`1px solid ${(col||bCol)}30` }}>{t}</div>
  );
  const pill = (t, col) => (
    <span style={{ fontSize:9, fontWeight:700, padding:'2px 8px', borderRadius:99, background:`${col}18`, color:col, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.04em', display:'inline-block' }}>{t}</span>
  );
  const card = (children, extra={}) => (
    <div style={{ background:'var(--bg-card,#fff)', border:'1px solid var(--border)', borderRadius:8, padding:'14px 16px', ...extra }}>{children}</div>
  );

  return (
    <div style={{ display:'flex', flexDirection:'column', gap:20 }}>

      {/* Princípio comercial — só para Materiais */}
      {isMateriais && (
        <div style={{ background:'linear-gradient(135deg,rgba(22,163,74,.08),rgba(5,150,105,.05))', border:'1.5px solid rgba(22,163,74,.3)', borderRadius:10, padding:'14px 18px' }}>
          <div style={{ fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.08em', color:'#16a34a', marginBottom:6 }}>
            Princípio comercial desta campanha
          </div>
          <div style={{ fontSize:14, fontWeight:700, color:'var(--navy,#112954)', fontFamily:'var(--font-display)', lineHeight:1.4, marginBottom:10 }}>
            "Não estamos a pedir ao cliente para mudar de fornecedor. Estamos a pedir-lhe para fazer um teste sem risco e deixar o produto provar o seu valor."
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:10 }}>
            {[
              { num:'01', q:'O cliente utiliza este tipo de material?' },
              { num:'02', q:'Existe uma vantagem concreta vs o que usa hoje?' },
              { num:'03', q:'Conseguimos levá-lo a experimentar 1 rolo?' },
            ].map((q,i) => (
              <div key={i} style={{ background:'rgba(22,163,74,.08)', borderRadius:7, padding:'10px 12px' }}>
                <div style={{ fontSize:10, fontWeight:800, color:'#16a34a', fontFamily:'var(--font-mono)', marginBottom:4 }}>{q.num}</div>
                <div style={{ fontSize:11, color:'var(--text)', lineHeight:1.4, fontWeight:500 }}>{q.q}</div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Header */}
      <div style={{ display:'flex', alignItems:'center', gap:12, padding:'10px 14px', background:'var(--bg-surface,#fff)', borderRadius:8, boxShadow:'var(--shadow-card)' }}>
        {pill(isMateriais ? 'Materiais / Consumíveis' : 'Equipamentos', bCol)}
        <span style={{ fontSize:11, color:'var(--fg-3,var(--text-muted))' }}>
          {campanha?.brand_name} · {brief.commercial_name || campanha?.titulo}
        </span>
        <span style={{ marginLeft:'auto', fontSize:10, fontWeight:700, padding:'2px 10px', borderRadius:99, background:'rgba(100,116,139,.08)', color:'var(--text-dim)', fontFamily:'var(--font-mono)' }}>
          CTA → {ctaLabel}
        </span>
        <button className="btn" style={{ height:28, padding:'0 12px', fontSize:11, opacity:.4, cursor:'not-allowed' }} disabled>
          Activar no Digi AI
        </button>
      </div>

      {/* ══ CENÁRIOS DE CONVERSA ══ */}
      <div style={{ background:'linear-gradient(135deg,rgba(17,41,84,.04),rgba(56,89,208,.06))', border:'2px solid rgba(56,89,208,.2)', borderRadius:12, padding:'18px 20px' }}>
        <div style={{ fontSize:11, fontWeight:700, fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.08em', color:'#3859D0', marginBottom:4 }}>
          Cenários de Qualificação · Como a Digi AI vai conduzir a conversa
        </div>
        <div style={{ fontSize:11, color:'var(--text-muted)', marginBottom:16 }}>
          Exemplos reais baseados nos dados desta campanha — produto, dores, USPs e oferta comercial
        </div>
        <div style={{ display:'flex', flexDirection:'column', gap:16 }}>
          {SCENARIOS.map(sc => (
            <div key={sc.id} style={{ background:'var(--bg-card,#fff)', borderRadius:10, border:'1px solid var(--border)', overflow:'hidden' }}>
              {/* Scenario header */}
              <div style={{ padding:'10px 14px', background:'var(--bg-sunken)', borderBottom:'1px solid var(--border)', display:'flex', alignItems:'center', gap:10 }}>
                <div style={{ width:22, height:22, borderRadius:'50%', background:sc.badgeCol, display:'flex', alignItems:'center', justifyContent:'center', fontSize:11, fontWeight:700, color:'#fff', flexShrink:0 }}>{sc.id}</div>
                <div>
                  <div style={{ fontSize:12, fontWeight:700, color:'var(--navy,#112954)' }}>{sc.label}</div>
                  <div style={{ fontSize:10, color:'var(--text-muted)' }}>{sc.desc}</div>
                </div>
                <span style={{ marginLeft:'auto', fontSize:9, fontWeight:700, padding:'2px 8px', borderRadius:99, background:`${sc.badgeCol}15`, color:sc.badgeCol, fontFamily:'var(--font-mono)' }}>{sc.badge}</span>
              </div>
              {/* Chat bubbles */}
              <div style={{ padding:'12px 14px', display:'flex', flexDirection:'column', gap:8 }}>
                {sc.msgs.map((msg,i) => (
                  <div key={i} style={{ display:'flex', flexDirection:'column', alignItems: msg.from === 'digi' ? 'flex-start' : 'flex-end' }}>
                    <div style={{ fontSize:8, fontWeight:700, color: msg.from === 'digi' ? bCol : '#64748b', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:3, paddingLeft:4, paddingRight:4 }}>
                      {msg.from === 'digi' ? '🤖 Digi AI' : '👤 Lead'}
                    </div>
                    <div style={{
                      maxWidth:'85%', padding:'8px 12px', borderRadius: msg.from === 'digi' ? '4px 12px 12px 12px' : '12px 4px 12px 12px',
                      background: msg.from === 'digi' ? `${bCol}12` : '#f1f5f9',
                      border: msg.from === 'digi' ? `1px solid ${bCol}25` : '1px solid #e2e8f0',
                      fontSize:11, color:'var(--text)', lineHeight:1.5,
                    }}>
                      {msg.text}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Grid produto + personas */}
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
        {card(<>
          {secTitle('Produto & Oferta', '#0F4C75')}
          {[
            { l:'Produto',    v: brief.commercial_name || campanha?.titulo },
            { l:'Pitch',      v: brief.elevator_pitch?.slice(0,120) },
            { l:'Oferta',     v: ofertaStr || null },
            { l:'CTA',        v: ctaLabel },
            { l:'Não nomear', v: competitors.join(' · ') || null },
          ].filter(r => r.v).map((r,i) => (
            <div key={i} style={{ display:'flex', gap:8, paddingBottom:5, borderBottom:'1px solid var(--border-light,#f1f5f9)' }}>
              <div style={{ fontSize:9, fontWeight:700, color:'#0F4C75', fontFamily:'var(--font-mono)', textTransform:'uppercase', minWidth:90, flexShrink:0 }}>{r.l}</div>
              <div style={{ fontSize:11, color:'var(--text)', lineHeight:1.4 }}>{r.v}</div>
            </div>
          ))}
        </>)}
        {card(<>
          {secTitle('Personas & Mensagem', '#3859D0')}
          {personas.slice(0,2).map((p,i) => (
            <div key={i} style={{ fontSize:11, color:'var(--text)', marginBottom:6, paddingLeft:8, borderLeft:`2px solid ${bCol}40` }}>
              <div style={{ fontWeight:600 }}>{_str(p.nome || p.perfil).slice(0,70)}</div>
              {p.peso && <div style={{ fontSize:9, color:'var(--text-dim)' }}>{p.peso}% peso · {p.razao?.slice(0,60)}</div>}
            </div>
          ))}
          {msgPT.awareness && (
            <div style={{ marginTop:10, padding:'8px 10px', background:'rgba(56,89,208,.05)', borderRadius:6, borderLeft:'3px solid #3859D0' }}>
              <div style={{ fontSize:9, fontWeight:700, color:'#3859D0', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:3 }}>Mensagem âncora (PT)</div>
              <div style={{ fontSize:10, color:'var(--text)', lineHeight:1.4 }}>{msgPT.awareness?.slice(0,150)}…</div>
            </div>
          )}
        </>)}
      </div>

      {/* USP Matrix */}
      {card(<>
        {secTitle('USP Matrix — Dor → USP → Benefício para o SDR', '#065F46')}
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:6, marginBottom:8 }}>
          {['DOR DO CLIENTE','USP RELEVANTE','BENEFÍCIO CONCRETO (script)'].map((h,i) => (
            <div key={i} style={{ fontSize:9, fontWeight:700, color:'#065F46', fontFamily:'var(--font-mono)', textTransform:'uppercase', letterSpacing:'.05em' }}>{h}</div>
          ))}
        </div>
        {pains.slice(0,4).map((pain,i) => {
          const usp     = diffArgs[i] || diffArgs[0] || usps[i] || '—';
          const angle   = angles[i];
          const benefit = angle?.beneficio || angle?.angulo || (usp.split('—')[0]?.trim()) || usp;
          return (
            <div key={i} style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:6, padding:'7px 0', borderTop:'1px solid var(--border-light,#f1f5f9)' }}>
              <div style={{ fontSize:10, color:'#dc2626', lineHeight:1.4 }}>{pain.slice(0,100)}{pain.length>100?'…':''}</div>
              <div style={{ fontSize:10, color:'var(--text)', fontWeight:500, lineHeight:1.4 }}>{usp.slice(0,100)}{usp.length>100?'…':''}</div>
              <div style={{ fontSize:10, color:'#065F46', lineHeight:1.4 }}>{_str(benefit).slice(0,100)}{_str(benefit).length>100?'…':''}</div>
            </div>
          );
        })}
      </>)}

      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
        {/* Objecções */}
        {card(<>
          {secTitle('Objecções Esperadas & Respostas SDR', '#92400E')}
          {objections.map((obj,i) => (
            <div key={i} style={{ padding:'8px 0', borderBottom:'1px solid var(--border-light,#f1f5f9)' }}>
              <div style={{ fontSize:10, fontWeight:600, color:'#92400E', marginBottom:4, display:'flex', gap:6 }}>
                <span>❌</span><span>{obj.slice(0,100)}{obj.length>100?'…':''}</span>
              </div>
              <div style={{ fontSize:10, color:'#065F46', paddingLeft:18, display:'flex', gap:6 }}>
                <span>✅</span><span>{objResponses[i]?.slice(0,120)}{objResponses[i]?.length>120?'…':''}</span>
              </div>
            </div>
          ))}
          {objections.length === 0 && (
            <div style={{ fontSize:11, color:'var(--text-muted)' }}>Derivar das dores e diff_args do briefing.</div>
          )}
        </>)}

        {/* Planeamento contacto */}
        {card(<>
          {secTitle('Planeamento de Contacto', '#16a34a')}
          {waItems.length > 0 && (
            <div style={{ marginBottom:10 }}>
              <div style={{ fontSize:9, fontWeight:700, color:'#16a34a', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:6 }}>WA — Qualificação 1:1</div>
              {waItems.map((w,i) => (
                <div key={i} style={{ display:'flex', justifyContent:'space-between', fontSize:10, color:'var(--text)', marginBottom:4 }}>
                  <span style={{ fontWeight:500 }}>{w.objectivo_wa || `WA ${i+1}`} <span style={{ fontSize:9, color:'var(--text-dim)' }}>· {w.audiencia_count||'—'} contactos</span></span>
                  <span style={{ color:'var(--text-dim)', fontFamily:'var(--font-mono)', fontSize:9 }}>{w.planned_date}</span>
                </div>
              ))}
            </div>
          )}
          {emailItems.length > 0 && (
            <div>
              <div style={{ fontSize:9, fontWeight:700, color:'#7c3aed', fontFamily:'var(--font-mono)', textTransform:'uppercase', marginBottom:6 }}>Email marketing</div>
              {emailItems.map((e,i) => (
                <div key={i} style={{ display:'flex', justifyContent:'space-between', fontSize:10, color:'var(--text)', marginBottom:3 }}>
                  <span>{e.titulo?.split('—')[0]?.trim()?.slice(0,40)}</span>
                  <span style={{ color:'var(--text-dim)', fontFamily:'var(--font-mono)', fontSize:9 }}>{e.planned_date}</span>
                </div>
              ))}
            </div>
          )}
          {waItems.length === 0 && emailItems.length === 0 && (
            <div style={{ fontSize:11, color:'var(--text-muted)' }}>Gera o Planeamento para ver as datas de contacto.</div>
          )}
        </>)}
      </div>

      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
        {/* CRM Fields */}
        {card(<>
          {secTitle('CRM — Campos a Registar após Conversa', '#0891b2')}
          <div style={{ display:'flex', flexDirection:'column', gap:3 }}>
            {CRM_FIELDS.map((f,i) => (
              <div key={i} style={{ display:'flex', alignItems:'center', gap:8, padding:'3px 0', borderBottom:'1px solid var(--border-light,#f1f5f9)' }}>
                <div style={{ width:14, height:14, borderRadius:3, border:'1.5px solid #0891b230', background:'var(--bg-sunken)', flexShrink:0 }}/>
                <div style={{ fontSize:10, color:'var(--text)' }}>{f}</div>
              </div>
            ))}
          </div>
        </>)}

        {/* Score */}
        {card(<>
          {secTitle(`Score SDR · ${SCORE.reduce((s,i)=>s+i.pts,0)} pontos`, bCol)}
          <div style={{ display:'flex', flexDirection:'column', gap:5, marginBottom:12 }}>
            {SCORE.map((s,i) => (
              <div key={i} style={{ display:'flex', justifyContent:'space-between', alignItems:'center', padding:'5px 8px', background:'var(--bg-sunken)', borderRadius:5 }}>
                <div style={{ fontSize:10, color:'var(--text)' }}>{s.criterio}</div>
                <div style={{ fontSize:11, fontWeight:700, color:bCol, fontFamily:'var(--font-mono)', flexShrink:0, marginLeft:8 }}>{s.pts}</div>
              </div>
            ))}
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:6 }}>
            {(isMateriais ? [
              { l:'🔥 Alta prioridade', r:'80–100', col:'#dc2626', bg:'#fef2f2' },
              { l:'🟢 Potencial',       r:'60–79',  col:'#16a34a', bg:'#f0fdf4' },
              { l:'🟡 Nurturing',       r:'<60',    col:'#d97706', bg:'#fffbeb' },
            ] : [
              { l:'🔥 HOT',        r:'90–120', col:'#dc2626', bg:'#fef2f2' },
              { l:'🟢 Qualificado',r:'70–89',  col:'#16a34a', bg:'#f0fdf4' },
              { l:'🟡 Nurturing',  r:'<70',    col:'#d97706', bg:'#fffbeb' },
            ]).map((t,i) => (
              <div key={i} style={{ background:t.bg, borderRadius:6, padding:'8px', textAlign:'center' }}>
                <div style={{ fontSize:9, fontWeight:700, color:t.col, fontFamily:'var(--font-mono)' }}>{t.r}</div>
                <div style={{ fontSize:9, color:t.col, marginTop:2 }}>{t.l}</div>
              </div>
            ))}
          </div>
        </>)}
      </div>

      {/* Lead Prioritization — só para Materiais */}
      {isMateriais && (
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16 }}>
          {card(<>
            {secTitle('Priorização de Leads A/B/C', '#3859D0')}
            {[
              { badge:'🔥 A', label:'Forte potencial', col:'#dc2626', bg:'#fef2f2',
                criteria:['Já compra Decal/BIOND','Tem volume de consumo','Produto concorrente identificado'] },
              { badge:'🟢 B', label:'Potencial',       col:'#16a34a', bg:'#f0fdf4',
                criteria:['Utiliza a aplicação mas não compra actualmente','Impressoras compatíveis','Aplicações compatíveis com o produto'] },
              { badge:'🟡 C', label:'Exploração',      col:'#d97706', bg:'#fffbeb',
                criteria:['Pode ter aplicação — ainda não confirmado','Não há historial de compra','Primeira abordagem'] },
            ].map((l,i) => (
              <div key={i} style={{ background:l.bg, borderRadius:8, padding:'10px 12px', marginBottom:8 }}>
                <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:6 }}>
                  <span style={{ fontSize:12, fontWeight:700 }}>{l.badge}</span>
                  <span style={{ fontSize:11, fontWeight:600, color:'var(--text)' }}>{l.label}</span>
                </div>
                {l.criteria.map((c,j) => (
                  <div key={j} style={{ fontSize:10, color:'var(--text)', marginBottom:2, paddingLeft:4 }}>· {c}</div>
                ))}
              </div>
            ))}
          </>)}
          {card(<>
            {secTitle('Follow-up Cycle · Teste → Consumo → Recompra', '#7c3aed')}
            {[
              { day:'D+0',   action:'Enviar amostra / rolo de teste', note:'Confirmar morada + aplicação ideal', col:'#3859D0' },
              { day:'D+2/3', action:'Primeiro follow-up — não vender, ouvir', note:'"Já conseguiu experimentar?"', col:'#7c3aed' },
              { day:'D+7',   action:'Resultado do teste', note:'Gostou → volume regular · Dúvida → suporte técnico · Não testou → reagendar', col:'#16a34a' },
              { day:'D+14',  action:'Follow-up de conversão', note:'"Usam X rolos/mês — faz sentido começarmos regularmente?"', col:'#d97706' },
              { day:'Recur', action:'Recompra + cross-sell', note:'Teste → consumo → fidelização', col:'#dc2626' },
            ].map((f,i) => (
              <div key={i} style={{ display:'flex', gap:10, paddingBottom:8, borderBottom:'1px solid var(--border-light,#f1f5f9)', alignItems:'flex-start' }}>
                <div style={{ fontSize:9, fontWeight:700, color:f.col, fontFamily:'var(--font-mono)', minWidth:42, flexShrink:0, marginTop:2 }}>{f.day}</div>
                <div>
                  <div style={{ fontSize:10, fontWeight:600, color:'var(--text)' }}>{f.action}</div>
                  <div style={{ fontSize:9, color:'var(--text-dim)', fontStyle:'italic' }}>{f.note}</div>
                </div>
              </div>
            ))}
          </>)}
        </div>
      )}

      {/* Aviso activação */}
      <div style={{ padding:'12px 16px', background:'rgba(56,89,208,.04)', border:'1px dashed rgba(56,89,208,.25)', borderRadius:8, fontSize:11, color:'var(--text-muted)', display:'flex', alignItems:'center', gap:10 }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#3859D0" strokeWidth="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
        <span>Esta ficha será injectada no <strong>SP_CLIENTES</strong> como contexto de campanha activa (PASSO 0, item 4). Quando activada, a Digi AI recebe produto, USPs, CTA, objecções e plano de contacto desta campanha.</span>
      </div>

    </div>
  );
};

// ── CampanhaDetail ─────────────────────────────────────────────────────────────
// Vista de detalhe: fetch da campanha completa + tabs (Briefing/Conceito/Copy/…)
