/* screen_marketing_estrategia.jsx
   Submenu Estratégia — lista, geração SSE, detalhe 3 tabs.
   Gate duplo: Rui Leitão (RL) → Fábio Costa (FC).
   Proposals criadas automaticamente quando briefing é aprovado.
*/

// ─── API Layer ─────────────────────────────────────────────────────────────────

(function () {
  const BASE = '/api/marketing';
  const go = async (path, opts = {}) => {
    try {
      const r = await fetch(BASE + path, { headers: { 'Content-Type': 'application/json' }, ...opts });
      if (!r.ok) throw new Error(`HTTP ${r.status}`);
      return r.json();
    } catch (e) { console.warn('[MktEstrategia]', e.message); return null; }
  };
  const strict = async (path, opts = {}) => {
    const r = await fetch(BASE + path, { headers: { 'Content-Type': 'application/json' }, ...opts });
    if (!r.ok) { let m = `HTTP ${r.status}`; try { const j = await r.json(); m = j.error || m; } catch {} throw new Error(m); }
    return r.json();
  };
  window.MktEstrategiaAPI = {
    getBrands:      ()            => go('/brands'),
    list:           (brand_id)    => go(`/strategy${brand_id && brand_id !== 'todas' ? `?brand_id=${brand_id}` : ''}`),
    get:            (id)          => go(`/strategy/${id}`),
    getBriefing:    (id)          => go(`/briefings/${id}`),
    approveRL:      (id, data)    => strict(`/strategy/${id}/approve-rl`, { method: 'POST', body: JSON.stringify(data) }),
    approveFC:      (id, data)    => strict(`/strategy/${id}/approve-fc`, { method: 'POST', body: JSON.stringify(data) }),
    addCommPlan:    (id, data)    => strict(`/strategy/${id}/comm-plan`,  { method: 'POST', body: JSON.stringify(data) }),
    deleteCommPlan: (itemId)      => go(`/comm-plan/${itemId}`, { method: 'DELETE' }),
    deleteProposal: (id)          => go(`/strategy/${id}`,      { method: 'DELETE' }),
  };
})();

// ─── Constantes ────────────────────────────────────────────────────────────────

const ESTRAT_STATUS = {
  pending_rl:  { label: 'Aguarda RL',  color: 'var(--warning)', bg: 'color-mix(in oklch, var(--warning) 12%, transparent)' },
  approved_rl: { label: 'Aprovado RL', color: 'var(--ai-500)',  bg: 'color-mix(in oklch, var(--ai-500) 12%, transparent)' },
  rejected_rl: { label: 'Rejeitado',   color: 'var(--danger)',  bg: 'color-mix(in oklch, var(--danger) 12%, transparent)' },
  published:   { label: 'Publicado',   color: 'var(--success)', bg: 'color-mix(in oklch, var(--success) 12%, transparent)' },
};

const ESTRAT_GENERATE_STEPS = [
  { id: 1, label: 'A verificar proposta' },
  { id: 2, label: 'A ler briefing completo' },
  { id: 3, label: 'A carregar skill criativa' },
  { id: 4, label: 'A gerar com Claude AI' },
  { id: 5, label: 'A estruturar campos' },
];

const ESTRAT_CHANNELS = {
  social: 'Social', facebook: 'Facebook', instagram: 'Instagram',
  linkedin: 'LinkedIn', youtube: 'YouTube', google_ads: 'Google Ads',
  email: 'Email', whatsapp: 'WhatsApp', website: 'Website', muppi_led: 'Muppi LED',
  blog: 'Blog', pr: 'PR', ads: 'Anúncios', site: 'Website / Blog', led: 'Muppi LED',
  newsletter: 'Newsletter', eventos: 'Eventos', store: 'Loja Online', academy: 'Academy',
  showroom: 'Showroom', catalogo: 'Catálogo', video: 'Vídeo', outros: 'Outros',
};

// Converte texto livre do briefing (block4.channels[]) em slugs normalizados
const normalizeBriefingChannels = (rawList) => {
  if (!rawList || !rawList.length) return null;
  const MAP = [
    [/instagram/i,    'instagram'],
    [/facebook/i,     'facebook'],
    [/linkedin/i,     'linkedin'],
    [/youtube/i,      'youtube'],
    [/redes sociais|social/i, 'social'],
    [/google ads|google/i, 'google_ads'],
    [/email|newsletter|e-mail/i, 'email'],
    [/whatsapp/i,     'whatsapp'],
    [/website|web|e-commerce|loja/i, 'website'],
    [/muppi|led|outdoor/i, 'muppi_led'],
    [/blog|recursos/i, 'blog'],
    [/catálogo|catalogo|materiais/i, 'catalogo'],
    [/showroom|demo/i, 'showroom'],
    [/event|feira/i,  'eventos'],
    [/academy|forma/i, 'academy'],
    [/video|vídeo/i,  'video'],
    [/pr\b|relações/i, 'pr'],
  ];
  const seen = new Set();
  const result = [];
  for (const raw of rawList) {
    for (const [re, slug] of MAP) {
      if (re.test(raw) && !seen.has(slug)) { seen.add(slug); result.push(slug); break; }
    }
  }
  return result.length ? result : null;
};

const COMM_STATUS_CFG = {
  planned:     { label: 'Planeado',  color: 'var(--text-muted)' },
  in_progress: { label: 'Em curso',  color: 'var(--warning)' },
  published:   { label: 'Publicado', color: 'var(--success)' },
  cancelled:   { label: 'Cancelado', color: 'var(--danger)' },
};

const BRAND_ORDER_E = ['digidelta', 'biond', 'decal', 'mimaki', 'sensek', 'alldecor', 'netscreen'];
const BRAND_NAMES_E = { digidelta: 'Digidelta', biond: 'Biond', decal: 'Decal', mimaki: 'Mimaki', sensek: 'Sensek', alldecor: 'Alldecor', netscreen: 'NetScreen' };

// ─── Helpers UI ────────────────────────────────────────────────────────────────

const EstratBadge = ({ status }) => {
  const s = ESTRAT_STATUS[status] || { label: status, color: 'var(--text-muted)', bg: 'var(--bg-sunken)' };
  return (
    <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', letterSpacing: '0.06em', padding: '2px 8px', borderRadius: 4, color: s.color, background: s.bg }}>
      {s.label.toUpperCase()}
    </span>
  );
};

const Dropdown = ({ label, value, options, onChange, disabled }) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [open]);
  const cur = options.find(o => o.value === value) || options[0];
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button onClick={() => !disabled && setOpen(v => !v)} disabled={disabled} style={{
        background: 'var(--bg-elev)', color: disabled ? 'var(--text-dim)' : 'var(--text)',
        border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', fontSize: 11.5,
        display: 'inline-flex', alignItems: 'center', gap: 8,
        cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.55 : 1,
        fontFamily: 'inherit', transition: 'border-color .15s',
      }}>
        <span style={{ color: 'var(--text-dim)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em', fontFamily: 'var(--font-mono)' }}>{label}</span>
        <span style={{ fontWeight: 500 }}>{cur?.label || '—'}</span>
        <span style={{ color: 'var(--text-muted)', fontSize: 9 }}>▾</span>
      </button>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 4px)', left: 0, zIndex: 50, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 6, boxShadow: '0 8px 24px rgba(0,0,0,0.12)', minWidth: 180, padding: 4, maxHeight: 280, overflowY: 'auto' }}>
          {options.map(o => (
            <button key={o.value} onClick={() => { onChange(o.value); setOpen(false); }} style={{
              display: 'block', width: '100%', textAlign: 'left',
              background: o.value === value ? 'color-mix(in oklch, var(--ai-500) 12%, transparent)' : 'transparent',
              color: o.value === value ? 'var(--ai-500)' : 'var(--text)',
              border: 'none', padding: '7px 10px', borderRadius: 4,
              fontSize: 12, fontWeight: o.value === value ? 600 : 500, cursor: 'pointer', fontFamily: 'inherit',
            }}>{o.label}</button>
          ))}
        </div>
      )}
    </div>
  );
};

// Cabeçalho de coluna ordenável — idêntico ao briefings
const estratThSt = {
  textAlign: 'left', padding: '8px 12px',
  fontSize: 10, fontFamily: 'var(--font-display)', fontWeight: 600,
  letterSpacing: '0.10em', textTransform: 'uppercase',
  color: 'var(--text-muted)', whiteSpace: 'nowrap',
};
const SortHeader = ({ label, sortKey, sortBy, onSort, width }) => {
  const active = sortBy.key === sortKey;
  return (
    <th style={{ ...estratThSt, width, cursor: sortKey ? 'pointer' : 'default', userSelect: 'none' }}
      onClick={() => sortKey && onSort(sortKey)}>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
        {label}
        {active && sortKey && window.Icon &&
          <window.Icon name={sortBy.dir === 'asc' ? 'arrowUp' : 'arrowDown'} size={9} style={{ color: 'var(--ai-500)' }} />}
      </span>
    </th>
  );
};

const ETInput = ({ value, onChange, placeholder, multiline, rows = 3 }) => {
  const [focused, setFocused] = React.useState(false);
  const base = {
    width: '100%', padding: '8px 12px', boxSizing: 'border-box',
    background: 'var(--bg-sunken)', border: `1px solid ${focused ? 'var(--ai-500)' : 'var(--border)'}`,
    borderRadius: 6, color: 'var(--text)', fontSize: 13, fontFamily: 'var(--font-body)', outline: 'none',
    boxShadow: focused ? '0 0 0 3px color-mix(in oklch, var(--ai-500) 12%, transparent)' : 'none',
    transition: 'border-color 0.15s, box-shadow 0.15s',
  };
  const evs = { onFocus: () => setFocused(true), onBlur: () => setFocused(false) };
  return multiline
    ? <textarea value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} rows={rows} {...evs} style={{ ...base, resize: 'vertical' }} />
    : <input type="text" value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} {...evs} style={base} />;
};

const EField = ({ label, children, hint }) => (
  <div style={{ marginBottom: 16 }}>
    <label style={{ display: 'block', fontSize: 11, fontWeight: 600, color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6 }}>{label}</label>
    {children}
    {hint && <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>{hint}</div>}
  </div>
);

// ─── Linha da tabela de proposals ──────────────────────────────────────────────

const EstratRow = ({ p, isAll, onSelect, onGenerate, onEdit, onDelete, attentionColor, userRole }) => {
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [confirming, setConfirming] = React.useState(false);
  const menuRef = React.useRef(null);
  const content = p.content || {};
  const hasContent = !!(content._narrative);
  const defaultBg = attentionColor ? `color-mix(in oklch, ${attentionColor} 6%, transparent)` : 'transparent';
  const canGenerate = (userRole === 'strategist' || userRole === 'admin') && (p.status === 'rejected_rl' || (p.status === 'pending_rl' && !hasContent));

  React.useEffect(() => {
    if (!menuOpen) return;
    const handler = (e) => {
      if (menuRef.current && !menuRef.current.contains(e.target)) {
        setMenuOpen(false); setConfirming(false);
      }
    };
    document.addEventListener('mousedown', handler);
    document.addEventListener('touchstart', handler);
    return () => { document.removeEventListener('mousedown', handler); document.removeEventListener('touchstart', handler); };
  }, [menuOpen]);

  return (
    <tr onClick={() => onSelect(p)}
      onMouseEnter={e => { e.currentTarget.style.background = attentionColor ? `color-mix(in oklch, ${attentionColor} 10%, var(--bg-hover))` : 'var(--bg-hover)'; }}
      onMouseLeave={e => { e.currentTarget.style.background = defaultBg; }}
      style={{ background: defaultBg, boxShadow: attentionColor ? `inset 3px 0 0 ${attentionColor}` : 'none', cursor: 'pointer', borderBottom: '1px solid var(--border)', transition: 'background 80ms' }}>

      <td style={{ padding: '10px 12px', overflow: 'hidden' }}>
        <div style={{ fontWeight: 500, color: 'var(--text)', fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
          {p.product_name || <span style={{ color: 'var(--text-dim)', fontStyle: 'italic', fontWeight: 400 }}>Sem produto</span>}
        </div>
        <div style={{ marginTop: 2 }}>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)' }}>#{p.briefing_id}</span>
        </div>
      </td>

      {isAll && (
        <td style={{ padding: '10px 12px' }}>
          <span style={{ display: 'inline-block', fontSize: 10, fontFamily: 'var(--font-display)', fontWeight: 700, letterSpacing: '0.08em', padding: '3px 9px', borderRadius: 4, color: p.brand_color || 'var(--text-muted)', background: `${p.brand_color || '#888888'}1A` }}>
            {(p.brand_name || '').toUpperCase()}
          </span>
        </td>
      )}

      <td style={{ padding: '10px 12px' }}><EstratBadge status={p.status} /></td>
      <td style={{ padding: '10px 12px', textAlign: 'center' }}>
        {hasContent
          ? <span style={{ fontSize: 13, color: 'var(--success)' }}>✓</span>
          : <span style={{ fontSize: 12, color: 'var(--text-dim)' }}>—</span>}
      </td>
      <td style={{ padding: '10px 12px' }}>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)' }}>
          {p.approved_at ? new Date(p.approved_at).toLocaleDateString('pt-PT') : '—'}
        </span>
      </td>
      <td style={{ padding: '10px 12px' }}>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)' }}>
          {p.created_at ? new Date(p.created_at).toLocaleDateString('pt-PT') : '—'}
        </span>
      </td>

      <td style={{ padding: '6px 8px', textAlign: 'right' }} onClick={e => e.stopPropagation()}>
        {canGenerate && (
          <button onClick={() => onGenerate(p)} className="btn btn-sm btn-ai" style={{ height: 26, padding: '0 10px', fontSize: 11, gap: 5, display: 'inline-flex', alignItems: 'center' }}>
            {window.Icon ? <window.Icon name="sparkle" size={11} /> : '✦'} Gerar
          </button>
        )}
      </td>

      {/* Kebab menu */}
      <td style={{ padding: '4px 6px', textAlign: 'right' }} onClick={e => e.stopPropagation()}>
        <div ref={menuRef} style={{ position: 'relative', display: 'inline-block' }}>
          <button
            onClick={() => { setMenuOpen(o => !o); if (menuOpen) setConfirming(false); }}
            style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, borderRadius: 5, cursor: 'pointer', background: menuOpen ? 'var(--bg-elev)' : 'none', border: `1px solid ${menuOpen ? 'var(--border)' : 'transparent'}`, color: 'var(--text-muted)', transition: 'all 100ms' }}
            onMouseEnter={e => { if (!menuOpen) { e.currentTarget.style.background = 'var(--bg-elev)'; e.currentTarget.style.borderColor = 'var(--border)'; } }}
            onMouseLeave={e => { if (!menuOpen) { e.currentTarget.style.background = 'none'; e.currentTarget.style.borderColor = 'transparent'; } }}
          >
            {window.Icon ? <window.Icon name="more" size={14} /> : '⋮'}
          </button>
          {menuOpen && (
            <div style={{ position: 'absolute', top: 'calc(100% + 4px)', right: 0, zIndex: 60, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 8, minWidth: 148, boxShadow: '0 8px 24px rgba(0,0,0,0.14)', overflow: 'hidden' }}>
              {confirming ? (
                <div style={{ padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text)' }}>Eliminar proposta?</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', lineHeight: 1.4 }}>Esta acção não pode ser revertida.</div>
                  <div style={{ display: 'flex', gap: 5 }}>
                    <button onClick={() => setConfirming(false)} className="btn btn-xs" style={{ flex: 1, fontSize: 11 }}>Cancelar</button>
                    <button onClick={() => { setMenuOpen(false); setConfirming(false); onDelete(p); }} className="btn btn-xs" style={{ flex: 1, fontSize: 11, background: 'var(--danger)', color: '#fff', borderColor: 'var(--danger)' }}>Eliminar</button>
                  </div>
                </div>
              ) : (
                <>
                  <button onClick={() => { setMenuOpen(false); onEdit(p); }} style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13, color: 'var(--text)', textAlign: 'left', fontFamily: 'inherit' }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'none'}>
                    <svg width={13} height={13} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, color: 'var(--text-muted)' }} aria-hidden="true"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.1 2.1 0 013 3L12 15l-4 1 1-4 9.5-9.5z" /></svg>
                    Editar
                  </button>
                  <div style={{ borderTop: '1px solid var(--border)' }} />
                  <button onClick={() => setConfirming(true)} style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13, color: 'var(--danger)', textAlign: 'left', fontFamily: 'inherit' }}
                    onMouseEnter={e => e.currentTarget.style.background = 'color-mix(in oklch, var(--danger) 8%, transparent)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'none'}>
                    <svg width={13} height={13} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }} aria-hidden="true"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6" /></svg>
                    Apagar
                  </button>
                </>
              )}
            </div>
          )}
        </div>
      </td>

      <td style={{ padding: '10px 6px', textAlign: 'right' }}>
        {window.Icon ? <window.Icon name="chevronRight" size={13} style={{ color: 'var(--text-dim)' }} /> : <span style={{ color: 'var(--text-dim)', fontSize: 13 }}>›</span>}
      </td>
    </tr>
  );
};

// ─── Vista de geração SSE ──────────────────────────────────────────────────────

const EstratGenerateView = ({ proposal, onDone, onCancel }) => {
  const [phase, setPhase]           = React.useState('idle');
  const [currentStep, setCurrentStep] = React.useState(0);
  const [streamText, setStreamText] = React.useState('');
  const [errorMsg, setErrorMsg]     = React.useState('');
  const abortRef   = React.useRef(null);
  const streamRef  = React.useRef(null);

  React.useEffect(() => () => abortRef.current?.abort(), []);

  const runGenerate = async () => {
    setPhase('running'); setCurrentStep(1); setStreamText(''); setErrorMsg('');
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    try {
      const res = await fetch(`/api/marketing/strategy/${proposal.id}/generate`, { method: 'POST', signal: ctrl.signal });
      const reader = res.body.getReader();
      const dec = new TextDecoder();
      let buf = '';
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buf += dec.decode(value, { stream: true });
        const lines = buf.split('\n');
        buf = lines.pop() || '';
        for (const line of lines) {
          if (!line.startsWith('data: ')) continue;
          try {
            const evt = JSON.parse(line.slice(6));
            if (evt.type === 'status') {
              const m = (evt.message || '').toLowerCase();
              if (m.includes('verificar'))       setCurrentStep(1);
              else if (m.includes('ler'))        setCurrentStep(2);
              else if (m.includes('skill'))      setCurrentStep(3);
              else if (m.includes('extrair') || m.includes('estruturar')) setCurrentStep(5);
            } else if (evt.type === 'token') {
              setCurrentStep(s => s < 4 ? 4 : s);
              setStreamText(t => { const next = t + evt.text; if (streamRef.current) streamRef.current.scrollTop = streamRef.current.scrollHeight; return next; });
            } else if (evt.type === 'done') {
              setCurrentStep(6); setPhase('done');
            } else if (evt.type === 'error') {
              setErrorMsg(evt.message || 'Erro desconhecido'); setPhase('error');
            }
          } catch {}
        }
      }
      setPhase(p => p === 'running' ? 'done' : p);
    } catch (e) {
      if (e.name !== 'AbortError') { setErrorMsg(e.message); setPhase('error'); }
    }
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
      <div style={{ padding: '28px 32px 18px', flexShrink: 0 }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' }}>
              MARKETING · AI STRATEGIST · CONTEÚDOS · GERAR
            </div>
            <h1 className="font-display" style={{ margin: '6px 0 4px', fontSize: 26, fontWeight: 600, letterSpacing: '-0.015em' }}>
              AI Strategist · {proposal.product_name || 'Estratégia'}
            </h1>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 8 }}>
              <EstratBadge status={proposal.status} />
              {proposal.brand_name && <span>· {proposal.brand_name}</span>}
            </div>
          </div>
          <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <button className="btn btn-ghost" style={{ height: 30, minWidth: 80, padding: '0 12px', fontSize: 12, whiteSpace: 'nowrap' }} onClick={onCancel}>← Voltar</button>
          </div>
        </div>
      </div>
      <div style={{ borderBottom: '1px solid var(--border)', flexShrink: 0 }} />

      <div className="scrollbar" style={{ flex: 1, overflowY: 'auto', padding: 28 }}>
        <div style={{ maxWidth: 720, margin: '0 auto' }}>

          {phase === 'idle' && (
            <div style={{ padding: 24, borderRadius: 12, border: '1px solid var(--border)', background: 'var(--bg-elev)', display: 'flex', flexDirection: 'column', gap: 16 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <div style={{ width: 40, height: 40, borderRadius: 10, background: 'color-mix(in oklch, var(--ai-500) 14%, transparent)', border: '1px solid color-mix(in oklch, var(--ai-500) 28%, transparent)', display: 'grid', placeItems: 'center', color: 'var(--ai-500)', fontSize: 18, flexShrink: 0 }}>✦</div>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>Claude AI · AI Strategist</div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Lê o briefing completo e gera proposta criativa estruturada</div>
                </div>
              </div>
              <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.7, paddingLeft: 52 }}>
                Usa a skill criativa Digidelta + todos os blocos do briefing. Duração: ~30–60 segundos.
                Resultado: conceito, mensagens-chave, copies por canal e plano de comunicação.
              </div>
              <div style={{ paddingLeft: 52 }}>
                <button onClick={runGenerate} className="btn btn-ai" style={{ height: 36, padding: '0 20px', fontSize: 13, gap: 8, display: 'inline-flex', alignItems: 'center' }}>
                  {window.Icon ? <window.Icon name="sparkle" size={14} /> : '✦'} Gerar Estratégia
                </button>
              </div>
            </div>
          )}

          {phase === 'running' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
              <style>{`@keyframes e-spin{to{transform:rotate(360deg)}} @keyframes e-pulse{0%,100%{opacity:1}50%{opacity:.35}}`}</style>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                {ESTRAT_GENERATE_STEPS.map(step => {
                  const done    = currentStep > step.id;
                  const active  = currentStep === step.id;
                  const pending = currentStep < step.id;
                  return (
                    <div key={step.id} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                      <div style={{ width: 28, height: 28, borderRadius: '50%', flexShrink: 0, display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 600, background: done ? 'color-mix(in oklch, var(--success) 20%, transparent)' : active ? 'color-mix(in oklch, var(--ai-500) 20%, transparent)' : 'var(--bg-sunken)', border: `2px solid ${done ? 'var(--success)' : active ? 'var(--ai-500)' : 'var(--border)'}`, color: done ? 'var(--success)' : active ? 'var(--ai-500)' : 'var(--text-dim)', transition: 'all 0.3s' }}>
                        {done ? '✓' : step.id}
                      </div>
                      <div style={{ flex: 1, fontSize: 13, fontWeight: active ? 600 : 400, color: pending ? 'var(--text-dim)' : 'var(--text)', transition: 'all 0.3s' }}>{step.label}</div>
                      {active && <div style={{ width: 16, height: 16, borderRadius: '50%', flexShrink: 0, border: '2.5px solid var(--ai-500)', borderTopColor: 'transparent', animation: 'e-spin 0.8s linear infinite' }} />}
                    </div>
                  );
                })}
              </div>
              {streamText.length > 0 && (
                <div style={{ borderRadius: 8, overflow: 'hidden', border: '1px solid var(--border)' }}>
                  <div style={{ padding: '6px 12px', background: 'var(--bg-elev)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 8 }}>
                    <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em' }}>SAÍDA CLAUDE · AO VIVO</span>
                    <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: 'var(--ai-500)', animation: 'e-pulse 1s ease-in-out infinite', marginLeft: 4 }} />
                  </div>
                  <pre ref={streamRef} style={{ margin: 0, padding: '14px 16px', fontSize: 12, lineHeight: 1.7, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: 'var(--bg-sunken)', maxHeight: 320, overflowY: 'auto' }}>{streamText}</pre>
                </div>
              )}
            </div>
          )}

          {phase === 'done' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
              <div style={{ padding: '14px 16px', borderRadius: 8, fontSize: 14, background: 'color-mix(in oklch, var(--success) 10%, transparent)', border: '1px solid color-mix(in oklch, var(--success) 30%, transparent)', color: 'var(--success)', fontWeight: 500, display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ fontSize: 18 }}>✓</span> Estratégia gerada — proposta pronta para revisão RL
              </div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={onCancel} className="btn" style={{ height: 34, padding: '0 16px', fontSize: 12 }}>← Ver lista</button>
                <button onClick={onDone}   className="btn btn-ai" style={{ height: 34, padding: '0 16px', fontSize: 12 }}>Ver proposta</button>
              </div>
            </div>
          )}

          {phase === 'error' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div style={{ padding: '12px 16px', borderRadius: 8, fontSize: 13, background: 'color-mix(in oklch, var(--danger) 10%, transparent)', border: '1px solid color-mix(in oklch, var(--danger) 30%, transparent)', color: 'var(--danger)' }}>{errorMsg}</div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={onCancel}     className="btn" style={{ height: 32, padding: '0 14px', fontSize: 12 }}>Cancelar</button>
                <button onClick={runGenerate}  className="btn btn-ai" style={{ height: 32, padding: '0 14px', fontSize: 12 }}>Tentar novamente</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

// ─── Tab: Plano de Comunicação ─────────────────────────────────────────────────

const EstratCommPlan = ({ proposalId, items, userRole, onRefresh, briefingChannels }) => {
  const [viewMode, setViewMode] = React.useState('table');
  const [adding, setAdding]     = React.useState(false);
  const [newItem, setNewItem]   = React.useState({ channel: '', content_type: '', title: '', planned_date: '' });
  const [saving, setSaving]     = React.useState(false);

  // Canais do briefing primeiro, depois todos os restantes
  const chanOpts = React.useMemo(() => {
    const bChs = (briefingChannels || []).map(slug => ({ value: slug, label: ESTRAT_CHANNELS[slug] || slug }));
    const rest  = Object.entries(ESTRAT_CHANNELS)
      .filter(([k]) => !(briefingChannels || []).includes(k))
      .map(([k, v]) => ({ value: k, label: v }));
    return briefingChannels && briefingChannels.length
      ? [...bChs, { value: '__sep__', label: '──────', disabled: true }, ...rest]
      : rest;
  }, [briefingChannels]);

  React.useEffect(() => {
    if (!newItem.channel && chanOpts.length) {
      const first = chanOpts.find(o => !o.disabled);
      if (first) setNewItem(i => ({ ...i, channel: first.value }));
    }
  }, [chanOpts]);

  const handleAdd = async () => {
    setSaving(true);
    try {
      await window.MktEstrategiaAPI.addCommPlan(proposalId, newItem);
      setNewItem({ channel: 'social', content_type: '', title: '', planned_date: '' });
      setAdding(false);
      onRefresh && onRefresh();
    } catch (e) { alert('Erro: ' + e.message); }
    finally { setSaving(false); }
  };

  const handleDelete = async (id) => {
    await window.MktEstrategiaAPI.deleteCommPlan(id);
    onRefresh && onRefresh();
  };

  // ── Calendar subcomponent ──
  const CommCalendar = ({ items }) => {
    const today = new Date();
    const [year, setYear]   = React.useState(today.getFullYear());
    const [month, setMonth] = React.useState(today.getMonth());
    const daysInMonth = new Date(year, month + 1, 0).getDate();
    const firstDay = new Date(year, month, 1).getDay();
    const monthName = new Date(year, month, 1).toLocaleDateString('pt-PT', { month: 'long', year: 'numeric' });
    const byDate = React.useMemo(() => {
      const m = {};
      items.forEach(item => {
        if (!item.planned_date) return;
        const d = new Date(item.planned_date);
        if (d.getFullYear() !== year || d.getMonth() !== month) return;
        const day = d.getDate();
        if (!m[day]) m[day] = [];
        m[day].push(item);
      });
      return m;
    }, [items, year, month]);
    const cells = [];
    for (let i = 0; i < (firstDay === 0 ? 6 : firstDay - 1); i++) cells.push(null);
    for (let d = 1; d <= daysInMonth; d++) cells.push(d);
    const WEEK = ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb', 'Dom'];
    const prevM = () => { if (month === 0) { setYear(y => y - 1); setMonth(11); } else setMonth(m => m - 1); };
    const nextM = () => { if (month === 11) { setYear(y => y + 1); setMonth(0); } else setMonth(m => m + 1); };
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <button onClick={prevM} style={{ background: 'none', border: '1px solid var(--border)', borderRadius: 5, padding: '4px 8px', cursor: 'pointer', color: 'var(--text-muted)', fontSize: 13 }}>‹</button>
          <span style={{ flex: 1, textAlign: 'center', fontWeight: 600, fontSize: 14, textTransform: 'capitalize', color: 'var(--text)' }}>{monthName}</span>
          <button onClick={nextM} style={{ background: 'none', border: '1px solid var(--border)', borderRadius: 5, padding: '4px 8px', cursor: 'pointer', color: 'var(--text-muted)', fontSize: 13 }}>›</button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 1, borderRadius: 8, overflow: 'hidden', border: '1px solid var(--border)' }}>
          {WEEK.map(w => <div key={w} style={{ padding: '6px 0', textAlign: 'center', fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', background: 'var(--bg-elev)', fontWeight: 600 }}>{w}</div>)}
          {cells.map((day, idx) => (
            <div key={idx} style={{ minHeight: 64, padding: 5, background: day ? 'var(--bg)' : 'var(--bg-sunken)', borderTop: '1px solid var(--border)', display: 'flex', flexDirection: 'column', gap: 2 }}>
              {day && (
                <>
                  <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: (day === today.getDate() && month === today.getMonth() && year === today.getFullYear()) ? 'var(--ai-500)' : 'var(--text-dim)', fontWeight: (day === today.getDate() && month === today.getMonth() && year === today.getFullYear()) ? 700 : 400 }}>{day}</span>
                  {(byDate[day] || []).map((item, i) => (
                    <div key={i} style={{ padding: '1px 4px', borderRadius: 3, fontSize: 9.5, lineHeight: 1.4, background: 'color-mix(in oklch, var(--ai-500) 12%, transparent)', color: 'var(--ai-500)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={item.title}>
                      {ESTRAT_CHANNELS[item.channel] || item.channel}
                    </div>
                  ))}
                </>
              )}
            </div>
          ))}
        </div>
      </div>
    );
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
        <div style={{ display: 'flex', borderRadius: 6, overflow: 'hidden', border: '1px solid var(--border)' }}>
          {[{ id: 'table', label: 'Tabela' }, { id: 'calendar', label: 'Calendário' }].map(m => (
            <button key={m.id} onClick={() => setViewMode(m.id)} style={{ padding: '5px 12px', fontSize: 12, border: 'none', cursor: 'pointer', fontFamily: 'inherit', background: viewMode === m.id ? 'var(--ai-500)' : 'var(--bg-elev)', color: viewMode === m.id ? '#fff' : 'var(--text-muted)', transition: 'all .15s' }}>{m.label}</button>
          ))}
        </div>
        {userRole === 'strategist' && !adding && (
          <button onClick={() => setAdding(true)} className="btn btn-sm" style={{ height: 28, padding: '0 10px', fontSize: 11 }}>+ Adicionar</button>
        )}
      </div>

      {adding && (
        <div style={{ padding: 16, borderRadius: 8, border: '1px solid var(--border)', background: 'var(--bg-elev)', display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <EField label="Canal">
              <select value={newItem.channel} onChange={e => { if (e.target.value !== '__sep__') setNewItem(i => ({ ...i, channel: e.target.value })); }} style={{ width: '100%', padding: '7px 10px', background: 'var(--bg-sunken)', border: '1px solid var(--border)', borderRadius: 6, color: 'var(--text)', fontSize: 13 }}>
                {chanOpts.map(o => <option key={o.value} value={o.value} disabled={o.disabled}>{o.label}</option>)}
              </select>
            </EField>
            <EField label="Tipo de conteúdo">
              <ETInput value={newItem.content_type} onChange={v => setNewItem(i => ({ ...i, content_type: v }))} placeholder="post, story, anúncio..." />
            </EField>
          </div>
          <EField label="Título">
            <ETInput value={newItem.title} onChange={v => setNewItem(i => ({ ...i, title: v }))} placeholder="Título da peça" />
          </EField>
          <EField label="Data prevista (opcional)">
            <input type="date" value={newItem.planned_date} onChange={e => setNewItem(i => ({ ...i, planned_date: e.target.value }))} style={{ padding: '7px 10px', background: 'var(--bg-sunken)', border: '1px solid var(--border)', borderRadius: 6, color: 'var(--text)', fontSize: 13 }} />
          </EField>
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={() => setAdding(false)} className="btn btn-sm">Cancelar</button>
            <button onClick={handleAdd} disabled={saving || !newItem.title.trim()} className="btn btn-sm btn-ai" style={{ marginLeft: 'auto' }}>{saving ? 'A guardar...' : 'Adicionar'}</button>
          </div>
        </div>
      )}

      {viewMode === 'table' && (
        items.length === 0
          ? <div style={{ padding: '28px 0', textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>Ainda não há items. A geração AI preenche automaticamente.</div>
          : <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <thead>
                  <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--bg-elev)' }}>
                    {['Canal', 'Tipo', 'Título / Hook', 'Data', 'Estado', ''].map((h, i) => (
                      <th key={i} style={{ padding: '8px 12px', fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--text-dim)', textAlign: 'left' }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {items.map(item => {
                    const scfg = COMM_STATUS_CFG[item.status] || COMM_STATUS_CFG.planned;
                    return (
                      <tr key={item.id} style={{ borderBottom: '1px solid var(--border)' }}
                        onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
                        onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                        <td style={{ padding: '9px 12px' }}><span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--ai-500)' }}>{ESTRAT_CHANNELS[item.channel] || item.channel}</span></td>
                        <td style={{ padding: '9px 12px' }}><span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{item.content_type || '—'}</span></td>
                        <td style={{ padding: '9px 12px', maxWidth: 260 }}>
                          <div style={{ fontSize: 13, color: 'var(--text)', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{item.title || '—'}</div>
                          {item.hook && <div style={{ fontSize: 11, color: 'var(--text-muted)', fontStyle: 'italic', marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{item.hook}</div>}
                        </td>
                        <td style={{ padding: '9px 12px' }}><span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)' }}>{item.planned_date ? new Date(item.planned_date + 'T12:00:00').toLocaleDateString('pt-PT') : '—'}</span></td>
                        <td style={{ padding: '9px 12px' }}><span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: scfg.color, letterSpacing: '0.05em' }}>{scfg.label.toUpperCase()}</span></td>
                        {userRole === 'strategist' && (
                          <td style={{ padding: '9px 8px', textAlign: 'right' }}>
                            <button onClick={() => handleDelete(item.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px 6px', fontSize: 13, color: 'var(--text-dim)' }}
                              onMouseEnter={e => e.currentTarget.style.color = 'var(--danger)'}
                              onMouseLeave={e => e.currentTarget.style.color = 'var(--text-dim)'}>×</button>
                          </td>
                        )}
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
      )}
      {viewMode === 'calendar' && <CommCalendar items={items} />}
    </div>
  );
};

// ─── Tab: Estratégia (narrative + campos AI) ───────────────────────────────────

const EstratContentTab = ({ content, onGenerate, userRole, status }) => {
  const [showRaw, setShowRaw] = React.useState(false);
  const hasContent = content && content._narrative;

  if (!hasContent) {
    return (
      <div style={{ padding: '40px 0', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14, color: 'var(--text-muted)' }}>
        <div style={{ fontSize: 32 }}>✦</div>
        <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--text)' }}>Proposta ainda não gerada</div>
        <div style={{ fontSize: 13 }}>Gera com Claude AI para obter conceito, copy e plano de comunicação.</div>
        {(userRole === 'strategist' || userRole === 'admin') && (status === 'pending_rl' || status === 'rejected_rl') && (
          <button onClick={onGenerate} className="btn btn-ai" style={{ height: 36, padding: '0 20px', fontSize: 13, gap: 8, display: 'inline-flex', alignItems: 'center', marginTop: 8 }}>
            {window.Icon ? <window.Icon name="sparkle" size={14} /> : '✦'} Gerar Estratégia
          </button>
        )}
      </div>
    );
  }

  const renderSection = (label, value) => {
    if (!value) return null;
    return (
      <div style={{ marginBottom: 20 }}>
        <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 8 }}>{label}</div>
        <div style={{ fontSize: 13, color: 'var(--text)', lineHeight: 1.7, whiteSpace: 'pre-wrap' }}>{value}</div>
      </div>
    );
  };

  const renderList = (label, arr) => {
    if (!arr || !arr.length) return null;
    return (
      <div style={{ marginBottom: 20 }}>
        <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 8 }}>{label}</div>
        <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
          {arr.map((item, i) => (
            <li key={i} style={{ fontSize: 13, color: 'var(--text)', lineHeight: 1.7, display: 'flex', gap: 8 }}>
              <span style={{ color: 'var(--ai-500)', fontWeight: 700, flexShrink: 0 }}>·</span>
              <span>{item}</span>
            </li>
          ))}
        </ul>
      </div>
    );
  };

  const adCopyObj  = content.ad_copy  || content.ad_copies || null;
  const adCopies   = adCopyObj ? Object.entries(adCopyObj) : [];
  const hooks      = content.hooks_by_channel || null;
  const hooksArr   = hooks ? Object.entries(hooks).filter(([, v]) => Array.isArray(v) && v.length) : [];
  const imgPrompts = Array.isArray(content.image_prompts) ? content.image_prompts : [];
  const sf         = content.strategic_foundation || null;
  const personas   = sf?.personas || [];

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 16 }}>
        <button onClick={() => setShowRaw(v => !v)} style={{ background: 'none', border: '1px solid var(--border)', borderRadius: 5, padding: '4px 10px', fontSize: 11, cursor: 'pointer', color: 'var(--text-muted)', fontFamily: 'inherit' }}>
          {showRaw ? 'Ver estruturado' : 'Ver narrativa completa'}
        </button>
      </div>
      {showRaw
        ? <pre style={{ fontSize: 12, lineHeight: 1.8, fontFamily: 'var(--font-mono)', color: 'var(--text)', whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: 'var(--bg-sunken)', padding: 16, borderRadius: 8 }}>{content._narrative}</pre>
        : (
          <>
            {renderSection('Conceito de Campanha', content.summary || content.campaign_concept)}
            {renderSection('Posicionamento', content.positioning)}
            {renderList('Mensagens-chave', content.key_messages)}
            {renderSection('Tom de Voz', content.tone || content.tone_of_voice)}
            {content.timeline_notes && renderSection('Timing e Prioridade', content.timeline_notes)}

            {/* Fundação estratégica */}
            {sf && (sf.core_pain_or_desire || personas.length > 0) && (
              <div style={{ marginBottom: 20 }}>
                <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 10 }}>Fundação Estratégica</div>
                {sf.core_pain_or_desire && (
                  <div style={{ fontSize: 13, color: 'var(--text)', lineHeight: 1.7, marginBottom: 8, padding: '10px 14px', background: 'var(--bg-elev)', borderRadius: 8, border: '1px solid var(--border)', borderLeft: '3px solid var(--ai-500)' }}>
                    <span style={{ fontSize: 11, color: 'var(--ai-500)', fontWeight: 600, display: 'block', marginBottom: 4 }}>{sf.primary_anchor === 'pain' ? '🎯 DOR CENTRAL' : '✦ DESEJO CENTRAL'}</span>
                    {sf.core_pain_or_desire}
                  </div>
                )}
                {personas.length > 0 && (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 8 }}>
                    {personas.map((persona, i) => (
                      <div key={i} style={{ padding: '10px 14px', borderRadius: 8, background: 'var(--bg-elev)', border: '1px solid var(--border)' }}>
                        <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text)', marginBottom: 4 }}>{persona.name}</div>
                        <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5, marginBottom: 4 }}>{persona.profile}</div>
                        {persona.how_they_experience_it && <div style={{ fontSize: 11.5, color: 'var(--text-dim)', fontStyle: 'italic' }}>"{persona.how_they_experience_it}"</div>}
                      </div>
                    ))}
                  </div>
                )}
              </div>
            )}

            {/* Hooks por canal */}
            {hooksArr.length > 0 && (
              <div style={{ marginBottom: 20 }}>
                <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 10 }}>Hooks por Canal</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 10 }}>
                  {hooksArr.map(([chan, hookList]) => {
                    const chanLabel = chan === 'email_subject' ? 'Email (Assunto)' : chan.charAt(0).toUpperCase() + chan.slice(1);
                    return (
                      <div key={chan} style={{ padding: '10px 14px', borderRadius: 8, background: 'var(--bg-elev)', border: '1px solid var(--border)' }}>
                        <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--ai-500)', letterSpacing: '0.07em', marginBottom: 8, textTransform: 'uppercase' }}>{chanLabel}</div>
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                          {hookList.map((h, i) => (
                            <div key={i} style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.5, display: 'flex', gap: 6 }}>
                              <span style={{ color: 'var(--text-dim)', flexShrink: 0 }}>{i + 1}.</span>
                              <span>{h}</span>
                            </div>
                          ))}
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}

            {/* Ad copy por plataforma */}
            {adCopies.length > 0 && (
              <div style={{ marginBottom: 20 }}>
                <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 10 }}>Copy por Plataforma</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                  {adCopies.map(([chan, copy]) => (
                    <div key={chan} style={{ padding: 14, borderRadius: 8, background: 'var(--bg-elev)', border: '1px solid var(--border)' }}>
                      <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--ai-500)', letterSpacing: '0.06em', marginBottom: 10, textTransform: 'uppercase' }}>{chan === 'meta' ? 'Meta (Facebook/Instagram)' : chan === 'linkedin' ? 'LinkedIn' : chan === 'google' ? 'Google Ads' : chan}</div>
                      {copy.primary_text   && <div style={{ marginBottom: 6 }}><span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Texto principal · </span><span style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.6 }}>{copy.primary_text}</span></div>}
                      {copy.intro_text     && <div style={{ marginBottom: 6 }}><span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Intro · </span><span style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.6 }}>{copy.intro_text}</span></div>}
                      {copy.headline       && <div style={{ marginBottom: 4 }}><span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Título · </span><span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{copy.headline}</span></div>}
                      {copy.description    && <div style={{ marginBottom: 4 }}><span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Descrição · </span><span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{copy.description}</span></div>}
                      {Array.isArray(copy.headlines) && copy.headlines.length > 0 && (
                        <div style={{ marginBottom: 4 }}>
                          <span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Títulos · </span>
                          {copy.headlines.map((h, i) => <div key={i} style={{ fontSize: 12, color: 'var(--text)', marginTop: 2, paddingLeft: 8 }}>· {h}</div>)}
                        </div>
                      )}
                      {Array.isArray(copy.descriptions) && copy.descriptions.length > 0 && (
                        <div>
                          <span style={{ fontSize: 10, color: 'var(--text-dim)', textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>Descrições · </span>
                          {copy.descriptions.map((d, i) => <div key={i} style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2, paddingLeft: 8 }}>· {d}</div>)}
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              </div>
            )}

            {/* Prompts de imagem */}
            {imgPrompts.length > 0 && (
              <div style={{ marginBottom: 20 }}>
                <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-dim)', marginBottom: 10 }}>Prompts de Imagem · IA</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {imgPrompts.map((img, i) => (
                    <div key={i} style={{ padding: '10px 14px', borderRadius: 8, background: 'var(--bg-elev)', border: '1px solid var(--border)' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
                        {img.for        && <span style={{ fontSize: 10, fontWeight: 600, color: 'var(--text)', background: 'var(--bg-sunken)', border: '1px solid var(--border)', borderRadius: 3, padding: '2px 6px', fontFamily: 'var(--font-mono)' }}>{img.for}</span>}
                        {img.dimensions && <span style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>{img.dimensions}</span>}
                        {img.model      && <span style={{ fontSize: 10, fontWeight: 600, color: 'var(--ai-500)', fontFamily: 'var(--font-mono)', marginLeft: 'auto' }}>{img.model.toUpperCase()}</span>}
                      </div>
                      {img.prompt && <div style={{ fontSize: 11.5, color: 'var(--text)', lineHeight: 1.6, marginBottom: img.negative_prompt ? 4 : 0 }}>{img.prompt}</div>}
                      {img.negative_prompt && <div style={{ fontSize: 11, color: 'var(--danger)', lineHeight: 1.5, fontStyle: 'italic' }}>Negative: {img.negative_prompt}</div>}
                    </div>
                  ))}
                </div>
              </div>
            )}
          </>
        )
      }
    </div>
  );
};

// ─── Tab: Aprovação ────────────────────────────────────────────────────────────

const EstratApprovalTab = ({ proposal, userName, userRole, onRefresh }) => {
  const [rlNotes, setRlNotes] = React.useState('');
  const [fcNotes, setFcNotes] = React.useState('');
  const [rlErr,   setRlErr]   = React.useState('');
  const [fcErr,   setFcErr]   = React.useState('');
  const [acting,  setActing]  = React.useState(false);

  const canRL = (userRole === 'admin' || (userRole === 'board' && userName === 'Rui Leitão')) && proposal.status === 'pending_rl' && !!(proposal.content || {})._narrative;
  const canFC = (userRole === 'admin' || (userRole === 'board' && userName === 'Fábio Costa')) && proposal.status === 'approved_rl';

  const handleRL = async (approved) => {
    if (!approved && !rlNotes.trim()) { setRlErr('Indica o motivo da rejeição.'); return; }
    setRlErr(''); setActing(true);
    try {
      await window.MktEstrategiaAPI.approveRL(proposal.id, { approved, notes: rlNotes, approver_name: userName });
      onRefresh && onRefresh();
    } catch (e) { setRlErr(e.message); }
    finally { setActing(false); }
  };

  const handleFC = async (approved) => {
    if (!approved && !fcNotes.trim()) { setFcErr('Indica o motivo da rejeição.'); return; }
    setFcErr(''); setActing(true);
    try {
      await window.MktEstrategiaAPI.approveFC(proposal.id, { approved, notes: fcNotes, approver_name: userName });
      onRefresh && onRefresh();
    } catch (e) { setFcErr(e.message); }
    finally { setActing(false); }
  };

  const STEPS = [
    { id: 'pending_rl',  label: 'Geração AI',     sub: 'Proposta gerada pelo Claude AI Strategist' },
    { id: 'approved_rl', label: 'Gate RL',          sub: 'Rui Leitão revê e aprova a estratégia' },
    { id: 'published',   label: 'Publicação FC',    sub: 'Fábio Costa autoriza a publicação' },
  ];
  const orderedStatus = ['pending_rl', 'approved_rl', 'published'];
  const curIdx = orderedStatus.indexOf(proposal.status === 'rejected_rl' ? 'pending_rl' : proposal.status);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 620 }}>
      {/* Timeline */}
      <div style={{ padding: '16px 20px', borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-elev)' }}>
        {STEPS.map((step, i) => {
          const done     = i < curIdx || proposal.status === 'published';
          const active   = i === curIdx && proposal.status !== 'rejected_rl';
          const rejected = proposal.status === 'rejected_rl' && i === curIdx;
          const last     = i === STEPS.length - 1;
          return (
            <div key={step.id} style={{ display: 'flex', gap: 14, paddingBottom: last ? 0 : 20, position: 'relative' }}>
              {!last && <div style={{ position: 'absolute', left: 15, top: 30, width: 2, bottom: 0, background: done ? 'var(--success)' : 'var(--border)' }} />}
              <div style={{ width: 30, height: 30, borderRadius: '50%', flexShrink: 0, display: 'grid', placeItems: 'center', fontSize: 13, fontWeight: 700, zIndex: 1, background: done ? 'color-mix(in oklch, var(--success) 20%, transparent)' : rejected ? 'color-mix(in oklch, var(--danger) 20%, transparent)' : active ? 'color-mix(in oklch, var(--ai-500) 20%, transparent)' : 'var(--bg-sunken)', border: `2px solid ${done ? 'var(--success)' : rejected ? 'var(--danger)' : active ? 'var(--ai-500)' : 'var(--border)'}`, color: done ? 'var(--success)' : rejected ? 'var(--danger)' : active ? 'var(--ai-500)' : 'var(--text-dim)' }}>
                {done ? '✓' : rejected ? '✗' : i + 1}
              </div>
              <div style={{ paddingTop: 4 }}>
                <div style={{ fontSize: 13, fontWeight: (active || done) ? 600 : 400, color: 'var(--text)' }}>{step.label}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{step.sub}</div>
              </div>
            </div>
          );
        })}
      </div>

      {/* Rejected notice */}
      {proposal.status === 'rejected_rl' && (
        <div style={{ padding: '12px 16px', borderRadius: 8, background: 'color-mix(in oklch, var(--danger) 8%, transparent)', border: '1px solid color-mix(in oklch, var(--danger) 28%, transparent)' }}>
          <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--danger)' }}>Rejeitado — deve ser regenerado com ajustes</div>
          {proposal.rl_notes && <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4, fontStyle: 'italic' }}>Nota RL: "{proposal.rl_notes}"</div>}
        </div>
      )}

      {/* RL approved banner */}
      {(proposal.status === 'approved_rl' || proposal.status === 'published') && proposal.approved_by_rl && (
        <div style={{ padding: '10px 14px', borderRadius: 8, background: 'color-mix(in oklch, var(--success) 8%, transparent)', border: '1px solid color-mix(in oklch, var(--success) 28%, transparent)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ color: 'var(--success)', fontWeight: 700 }}>✓</span>
            <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>Aprovado por {proposal.approved_by_rl}</span>
          </div>
          {proposal.rl_notes && <div style={{ marginTop: 4, fontSize: 12, color: 'var(--text-muted)', paddingLeft: 20, fontStyle: 'italic' }}>"{proposal.rl_notes}"</div>}
        </div>
      )}

      {/* Published banner */}
      {proposal.status === 'published' && proposal.approved_by_fc && (
        <div style={{ padding: '10px 14px', borderRadius: 8, background: 'color-mix(in oklch, var(--success) 8%, transparent)', border: '1px solid color-mix(in oklch, var(--success) 28%, transparent)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ color: 'var(--success)', fontWeight: 700 }}>✓</span>
            <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>Publicação aprovada por {proposal.approved_by_fc}</span>
          </div>
          {proposal.fc_notes && <div style={{ marginTop: 4, fontSize: 12, color: 'var(--text-muted)', paddingLeft: 20, fontStyle: 'italic' }}>"{proposal.fc_notes}"</div>}
        </div>
      )}

      {/* Gate RL */}
      {canRL && (
        <div style={{ padding: 20, borderRadius: 10, border: '1px solid color-mix(in oklch, var(--warning) 35%, transparent)', background: 'color-mix(in oklch, var(--warning) 6%, transparent)' }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', marginBottom: 14 }}>Gate Rui Leitão — Revisão de Estratégia</div>
          <EField label="Notas (obrigatório se rejeitar)">
            <ETInput value={rlNotes} onChange={v => { setRlNotes(v); if (v.trim()) setRlErr(''); }} placeholder="Feedback, ajustes, canal em falta..." multiline rows={3} />
          </EField>
          {rlErr && <div style={{ marginBottom: 10, fontSize: 12, color: 'var(--danger)', fontWeight: 500 }}>{rlErr}</div>}
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={() => handleRL(false)} disabled={acting} className="btn" style={{ height: 34, padding: '0 16px', fontSize: 12, color: 'var(--danger)', borderColor: 'var(--danger)' }}>Rejeitar</button>
            <button onClick={() => handleRL(true)}  disabled={acting} className="btn btn-ai" style={{ height: 34, padding: '0 16px', fontSize: 12, marginLeft: 'auto' }}>{acting ? 'A processar...' : '✓ Aprovar Estratégia'}</button>
          </div>
        </div>
      )}

      {/* Gate FC */}
      {canFC && (
        <div style={{ padding: 20, borderRadius: 10, border: '1px solid color-mix(in oklch, var(--ai-500) 35%, transparent)', background: 'color-mix(in oklch, var(--ai-500) 6%, transparent)' }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', marginBottom: 14 }}>Gate Fábio Costa — Autorização de Publicação</div>
          <EField label="Notas (obrigatório se rejeitar)">
            <ETInput value={fcNotes} onChange={v => { setFcNotes(v); if (v.trim()) setFcErr(''); }} placeholder="Motivo de rejeição ou notas finais..." multiline rows={3} />
          </EField>
          {fcErr && <div style={{ marginBottom: 10, fontSize: 12, color: 'var(--danger)', fontWeight: 500 }}>{fcErr}</div>}
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={() => handleFC(false)} disabled={acting} className="btn" style={{ height: 34, padding: '0 16px', fontSize: 12, color: 'var(--danger)', borderColor: 'var(--danger)' }}>Rejeitar</button>
            <button onClick={() => handleFC(true)}  disabled={acting} className="btn btn-ai" style={{ height: 34, padding: '0 16px', fontSize: 12, marginLeft: 'auto' }}>{acting ? 'A processar...' : '✓ Autorizar Publicação'}</button>
          </div>
        </div>
      )}

      {!canRL && !canFC && proposal.status !== 'rejected_rl' && proposal.status !== 'published' && (
        <div style={{ fontSize: 12, color: 'var(--text-muted)', padding: '8px 0' }}>
          {proposal.status === 'pending_rl' && (!(proposal.content || {})._narrative ? 'Gera a proposta primeiro para que Rui Leitão possa rever.' : 'Aguarda revisão por Rui Leitão.')}
          {proposal.status === 'approved_rl' && 'Aprovada por RL · Aguarda autorização de Fábio Costa.'}
        </div>
      )}
    </div>
  );
};

// ─── Vista de detalhe (3 tabs) ─────────────────────────────────────────────────

const EstratDetail = ({ proposal: initial, onBack, onGenerate, userRole, userName }) => {
  const [tab, setTab]         = React.useState('estrategia');
  const [proposal, setProposal] = React.useState(initial);
  const [briefing, setBriefing] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [confirmRegen, setConfirmRegen] = React.useState(false);

  const reload = React.useCallback(() => {
    window.MktEstrategiaAPI.get(initial.id).then(d => {
      if (d) setProposal(d);
      setLoading(false);
    });
  }, [initial.id]);

  React.useEffect(() => {
    reload();
    if (initial.briefing_id) {
      window.MktEstrategiaAPI.getBriefing(initial.briefing_id).then(b => { if (b) setBriefing(b); });
    }
  }, [reload, initial.briefing_id]);

  const commItems = proposal.comm_plan || [];
  const content   = proposal.content || {};
  const hasContent = !!(content._narrative);
  const canRegenerate = (userRole === 'strategist' || userRole === 'admin') && (proposal.status === 'pending_rl' || proposal.status === 'rejected_rl');

  // Canais do briefing normalizados (para o comm_plan dropdown)
  const briefingChannelSlugs = React.useMemo(() => {
    const raw = briefing?.block4?.channels;
    return normalizeBriefingChannels(raw) || Object.keys(ESTRAT_CHANNELS).slice(0, 8);
  }, [briefing]);

  const TABS = [
    { id: 'estrategia', label: 'Estratégia' },
    { id: 'plano',      label: `Plano de Comunicação${commItems.length ? ` (${commItems.length})` : ''}` },
    { id: 'aprovacao',  label: 'Aprovação' },
  ];

  const handleGenerate = () => {
    if (hasContent) { setConfirmRegen(true); }
    else { onGenerate(proposal); }
  };

  if (loading) return <div style={{ padding: 48, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar...</div>;

  // ── Painel de contexto do briefing ──
  const BriefingContext = () => {
    if (!briefing) return null;
    const b4 = briefing.block4 || {};
    const b1 = briefing.block1 || {};
    const channels = briefing.block4?.channels || [];
    const OBJ_MAP = { lead_gen: 'Geração de leads', brand_awareness: 'Notoriedade', retention: 'Retenção', conversion: 'Conversão', engagement: 'Engagement' };
    return (
      <div style={{ marginBottom: 24, padding: '14px 18px', borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-elev)', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.08em', color: 'var(--text-dim)' }}>BRIEFING DE ORIGEM — #{briefing.id}</div>
        <div style={{ display: 'flex', gap: 20, flexWrap: 'wrap' }}>
          {b4.objective && (
            <div>
              <div style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 2 }}>Objectivo</div>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text)' }}>{OBJ_MAP[b4.objective] || b4.objective}</div>
            </div>
          )}
          {b4.tone && (
            <div>
              <div style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 2 }}>Tom</div>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text)', textTransform: 'capitalize' }}>{b4.tone}</div>
            </div>
          )}
          {(b4.timeline_start || b4.timeline_end) && (
            <div>
              <div style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 2 }}>Campanha</div>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text)' }}>
                {b4.timeline_start ? new Date(b4.timeline_start).toLocaleDateString('pt-PT') : '?'}
                {' → '}
                {b4.timeline_end ? new Date(b4.timeline_end).toLocaleDateString('pt-PT') : '?'}
              </div>
            </div>
          )}
          {b4.key_message && (
            <div style={{ flex: 1, minWidth: 200 }}>
              <div style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 2 }}>Mensagem-chave</div>
              <div style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.5 }}>{b4.key_message}</div>
            </div>
          )}
        </div>
        {channels.length > 0 && (
          <div>
            <div style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 6 }}>Canais do briefing</div>
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
              {channels.map((c, i) => (
                <span key={i} style={{ fontSize: 10, fontFamily: 'var(--font-mono)', padding: '2px 8px', borderRadius: 4, background: 'color-mix(in oklch, var(--ai-500) 10%, transparent)', color: 'var(--ai-500)', letterSpacing: '0.04em' }}>
                  {c}
                </span>
              ))}
            </div>
          </div>
        )}
      </div>
    );
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>

      {/* Confirm regenerate modal */}
      {confirmRegen && (
        <div style={{ position: 'fixed', inset: 0, zIndex: 200, background: 'rgba(0,0,0,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ background: 'var(--bg-elev)', borderRadius: 12, padding: '28px 32px', maxWidth: 400, width: '90%', border: '1px solid var(--border)', boxShadow: '0 20px 60px rgba(0,0,0,0.3)' }}>
            <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--text)', marginBottom: 10 }}>Apagar e regenerar?</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.6, marginBottom: 24 }}>
              O conceito actual e o plano de comunicação serão eliminados. O Claude vai gerar uma nova proposta com base no briefing. Esta acção não pode ser revertida.
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
              <button onClick={() => setConfirmRegen(false)} className="btn" style={{ height: 34, padding: '0 16px', fontSize: 12 }}>Cancelar</button>
              <button onClick={() => { setConfirmRegen(false); onGenerate(proposal); }} className="btn btn-ai" style={{ height: 34, padding: '0 16px', fontSize: 12 }}>
                {window.Icon ? <window.Icon name="sparkle" size={11} /> : '✦'} Apagar e Regenerar
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Header — idêntico ao BriefingDetail */}
      <div style={{ padding: '28px 32px 18px', flexShrink: 0 }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' }}>
              MARKETING · AI STRATEGIST · CONTEÚDOS · DETALHE
            </div>
            <h1 className="font-display" style={{ margin: '6px 0 4px', fontSize: 26, fontWeight: 600, letterSpacing: '-0.015em' }}>
              AI Strategist · {proposal.product_name || 'Estratégia'}
            </h1>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 8 }}>
              <EstratBadge status={proposal.status} />
              {proposal.brand_name && <span>· {proposal.brand_name}</span>}
              {proposal.generated_at && <span>· gerado {new Date(proposal.generated_at).toLocaleDateString('pt-PT')}</span>}
            </div>
          </div>
          <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap' }}>
            <button className="btn btn-ghost" style={{ height: 30, minWidth: 80, padding: '0 12px', fontSize: 12, whiteSpace: 'nowrap' }} onClick={onBack}>← Voltar</button>
            {canRegenerate && (
              <button onClick={handleGenerate} className="btn btn-ai" style={{ height: 30, padding: '0 14px', fontSize: 12, gap: 6, display: 'inline-flex', alignItems: 'center' }}>
                {window.Icon ? <window.Icon name="sparkle" size={11} /> : '✦'} {hasContent ? 'Regenerar' : 'Gerar Estratégia'}
              </button>
            )}
          </div>
        </div>
      </div>

      {/* Tabs — separadas do header, com padding lateral */}
      <div style={{ display: 'flex', borderBottom: '1px solid var(--border)', overflowX: 'auto', flexShrink: 0, padding: '0 32px' }}>
        {TABS.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)} style={{
            padding: '8px 18px', fontSize: 13,
            fontWeight: tab === t.id ? 700 : 400,
            color: tab === t.id ? 'var(--ai-500)' : 'var(--text-muted)',
            borderBottom: tab === t.id ? '2px solid var(--ai-500)' : '2px solid transparent',
            background: 'none', border: 'none', borderRadius: 0,
            cursor: 'pointer', whiteSpace: 'nowrap', fontFamily: 'var(--font-display)',
          }}>{t.label}</button>
        ))}
      </div>

      <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: 28 }}>
        <div style={{ maxWidth: 960, margin: '0 auto' }}>
          <BriefingContext />
          {tab === 'estrategia' && (
            <EstratContentTab content={content} onGenerate={handleGenerate} userRole={userRole} status={proposal.status} />
          )}
          {tab === 'plano' && (
            <EstratCommPlan proposalId={proposal.id} items={commItems} userRole={userRole} onRefresh={reload} briefingChannels={briefingChannelSlugs} />
          )}
          {tab === 'aprovacao' && (
            <EstratApprovalTab proposal={proposal} userName={userName} userRole={userRole} onRefresh={reload} />
          )}
        </div>
      </div>
    </div>
  );
};

// ─── Lista de proposals ────────────────────────────────────────────────────────

const EstratList = ({ brandId, onSelect, onGenerate, userRole, userName }) => {
  const [proposals, setProposals] = React.useState(null);
  const [allBrands, setAllBrands] = React.useState([]);
  const [filterEstado, setFilterEstado] = React.useState('all');
  const [filterMarca,  setFilterMarca]  = React.useState('all');
  const [filterAttn,   setFilterAttn]   = React.useState(false);
  const [sortBy,       setSortBy]       = React.useState({ key: 'created_at', dir: 'desc' });
  const isAll = !brandId || brandId === 'todas';
  const { setBrand: setActiveBrand, userMarcas } = window.useMktBrand ? window.useMktBrand() : { setBrand: () => {}, userMarcas: null };

  const load = React.useCallback(() => {
    setProposals(null);
    window.MktEstrategiaAPI.list(isAll ? null : brandId).then(d => setProposals(d || []));
  }, [brandId]);

  React.useEffect(load, [load]);

  React.useEffect(() => {
    window.MktEstrategiaAPI.getBrands().then(d => {
      let list = (d || []).filter(b => b.slug !== 'todas').map(b => ({ ...b, name: BRAND_NAMES_E[b.slug] || b.name }));
      if (userMarcas?.length) list = list.filter(b => userMarcas.includes(b.slug));
      list.sort((a, b) => { const ia = BRAND_ORDER_E.indexOf(a.slug), ib = BRAND_ORDER_E.indexOf(b.slug); return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib); });
      setAllBrands(list);
    });
  }, [userMarcas]);

  const kpi = React.useMemo(() => {
    if (!proposals) return { total: 0, pending_rl: 0, approved_rl: 0, published: 0, rejected_rl: 0 };
    const s = st => proposals.filter(p => p.status === st).length;
    return { total: proposals.length, pending_rl: s('pending_rl'), approved_rl: s('approved_rl'), published: s('published'), rejected_rl: s('rejected_rl') };
  }, [proposals]);

  // Atenção: estes memos TÊM DE VIR ANTES de `filtered`
  const stratNeedGen = React.useMemo(() => {
    if (userRole !== 'strategist' || !proposals) return [];
    return proposals.filter(p => p.status === 'pending_rl' && !(p.content || {})._narrative);
  }, [proposals, userRole]);

  const rlNeedReview = React.useMemo(() => {
    if (userRole !== 'board' || userName !== 'Rui Leitão' || !proposals) return [];
    return proposals.filter(p => p.status === 'pending_rl' && !!(p.content || {})._narrative);
  }, [proposals, userRole, userName]);

  const fcNeedApproval = React.useMemo(() => {
    if (userRole !== 'board' || userName !== 'Fábio Costa' || !proposals) return [];
    return proposals.filter(p => p.status === 'approved_rl');
  }, [proposals, userRole, userName]);

  const attentionIds = React.useMemo(() => {
    const items = userRole === 'strategist' ? stratNeedGen : userName === 'Rui Leitão' ? rlNeedReview : fcNeedApproval;
    return new Set(items.map(p => p.id));
  }, [stratNeedGen, rlNeedReview, fcNeedApproval, userRole, userName]);

  const filtered = React.useMemo(() => {
    if (!proposals) return [];
    const list = proposals.filter(p =>
      (filterEstado === 'all' || p.status === filterEstado) &&
      (filterMarca  === 'all' || p.brand_slug === filterMarca) &&
      (!filterAttn || attentionIds.has(p.id))
    );
    return list.sort((a, b) => {
      const av = a[sortBy.key] || '', bv = b[sortBy.key] || '';
      if (av < bv) return sortBy.dir === 'asc' ? -1 : 1;
      if (av > bv) return sortBy.dir === 'asc' ? 1 : -1;
      return 0;
    });
  }, [proposals, filterEstado, filterMarca, filterAttn, sortBy, attentionIds]);

  const hasActiveFilter = filterEstado !== 'all' || filterMarca !== 'all' || filterAttn;
  const clearFilters = () => { setFilterEstado('all'); setFilterMarca('all'); setFilterAttn(false); };

  const handleDelete = async (p) => {
    await window.MktEstrategiaAPI.deleteProposal(p.id);
    load();
  };

  const attnCount = attentionIds.size;
  const attnColor = userRole === 'strategist' ? 'var(--ai-500)' : 'var(--warning)';
  const attnLabel = userRole === 'strategist'
    ? `${attnCount} proposta${attnCount !== 1 ? 's' : ''} por gerar`
    : userName === 'Rui Leitão'
      ? `${attnCount} proposta${attnCount !== 1 ? 's' : ''} aguardam revisão RL`
      : `${attnCount} proposta${attnCount !== 1 ? 's' : ''} aguardam autorização de publicação`;

  const kpiCards = [
    { label: 'Total',       value: kpi.total,       accent: 'var(--ai-500)',  fill: 1 },
    { label: 'Aguarda RL',  value: kpi.pending_rl,  accent: 'var(--warning)', fill: kpi.total ? kpi.pending_rl / kpi.total : 0 },
    { label: 'Aprovado RL', value: kpi.approved_rl, accent: 'var(--ai-500)',  fill: kpi.total ? kpi.approved_rl / kpi.total : 0 },
    { label: 'Publicado',   value: kpi.published,   accent: 'var(--success)', fill: kpi.total ? kpi.published / kpi.total : 0 },
    { label: 'Rejeitado',   value: kpi.rejected_rl, accent: 'var(--danger)',  fill: kpi.total ? kpi.rejected_rl / kpi.total : 0 },
  ];

  if (proposals === null) return <div style={{ padding: 48, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar...</div>;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>

      <div style={{ padding: '28px 32px 0', flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 18 }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' }}>MARKETING · AI STRATEGIST · CONTEÚDOS</div>
            <h1 className="font-display" style={{ margin: '6px 0 4px', fontSize: 26, fontWeight: 600, letterSpacing: '-0.015em' }}>AI Strategist · Estratégia</h1>
            <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>
              {kpi.total} proposta{kpi.total !== 1 ? 's' : ''}{isAll ? ' · todas as marcas' : proposals[0] ? ` · ${proposals[0].brand_name}` : ''}
            </div>
          </div>
        </div>

        {/* Brand tabs */}
        <div style={{ display: 'flex', gap: 4, borderBottom: '1px solid var(--border)' }}>
          {[{ slug: 'todas', name: 'Todas' }, ...allBrands].map(b => {
            const active = b.slug === 'todas' ? isAll : brandId === b.slug;
            return (
              <button key={b.slug} onClick={() => setActiveBrand(b.slug === 'todas' ? null : b.slug)}
                style={{
                  background: 'none', border: 'none', outline: 'none',
                  borderBottom: `2px solid ${active ? 'var(--ai-500)' : 'transparent'}`,
                  marginBottom: '-1px',
                  color: active ? 'var(--text)' : 'var(--text-muted)',
                  fontSize: 13, fontWeight: active ? 600 : 500,
                  fontFamily: 'var(--font-display)', letterSpacing: '.01em',
                  padding: '6px 14px 10px',
                  cursor: 'pointer', whiteSpace: 'nowrap',
                  transition: 'all .15s',
                }}>
                {b.name}
              </button>
            );
          })}
        </div>

        {/* Filter row */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
            {isAll && (
              <Dropdown label="Marca" value={filterMarca} onChange={setFilterMarca}
                options={[{ value: 'all', label: 'Todas' }, ...allBrands.map(b => ({ value: b.slug, label: b.name }))]}
              />
            )}
            <Dropdown label="Estado" value={filterEstado} onChange={setFilterEstado}
              options={[
                { value: 'all',         label: 'Todos' },
                { value: 'pending_rl',  label: 'Aguarda RL' },
                { value: 'approved_rl', label: 'Aprovado RL' },
                { value: 'rejected_rl', label: 'Rejeitado' },
                { value: 'published',   label: 'Publicado' },
              ]}
            />
            {hasActiveFilter && (
              <button onClick={clearFilters} style={{ background: 'none', border: 'none', color: 'var(--text-muted)', fontSize: 11, cursor: 'pointer', padding: '4px 6px', fontFamily: 'var(--font-mono)' }}>✕ limpar</button>
            )}
            <span style={{ fontSize: 12, color: 'var(--text-muted)', paddingLeft: 4 }}>
              {filtered.length} resultado{filtered.length !== 1 ? 's' : ''}
            </span>
          </div>
        </div>

        {/* KPI strip */}
        <div style={{ display: 'flex', gap: 1, borderRadius: 8, overflow: 'hidden', border: '1px solid var(--border)' }}>
          {kpiCards.map((k, i) => (
            <div key={i} style={{ background: 'var(--bg-elev)', flex: 1, minWidth: 64, display: 'flex', flexDirection: 'column', padding: '10px 14px 0', gap: 4, overflow: 'hidden' }}>
              <div className="font-display" style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{k.label}</div>
              <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display)', color: k.accent, lineHeight: 1, paddingBottom: 8 }}>{k.value}</div>
              <div style={{ height: 3, background: 'var(--bg-sunken)', overflow: 'hidden' }}>
                <div style={{ height: '100%', width: `${(k.fill || 0) * 100}%`, background: k.accent, transition: 'width .4s' }} />
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Atenção */}
      {attnCount > 0 && (
        <div style={{ padding: '10px 32px 0', flexShrink: 0, display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 7, height: 7, borderRadius: '50%', background: attnColor, flexShrink: 0 }} />
          <span style={{ fontSize: 12, color: 'var(--text-muted)', flex: 1 }}>{attnLabel}</span>
          <button onClick={() => setFilterAttn(f => !f)} style={{ fontSize: 11, padding: '3px 10px', borderRadius: 5, cursor: 'pointer', background: filterAttn ? attnColor : 'none', color: filterAttn ? '#fff' : attnColor, border: `1px solid ${attnColor}`, fontWeight: 600, flexShrink: 0 }}>
            {filterAttn ? 'Ver todos' : 'Filtrar'}
          </button>
        </div>
      )}

      {/* Table */}
      {proposals.length === 0 ? (
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12, color: 'var(--text-muted)', marginTop: 18, padding: '0 32px', textAlign: 'center' }}>
          <div style={{ fontSize: 14 }}>{isAll ? 'Ainda não há propostas de estratégia.' : 'Ainda não há propostas para esta marca.'}</div>
          <div style={{ fontSize: 12 }}>As propostas são criadas automaticamente quando um briefing é aprovado.</div>
        </div>
      ) : filtered.length === 0 ? (
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 8, color: 'var(--text-muted)', marginTop: 18, padding: '0 32px' }}>
          <div style={{ fontSize: 14 }}>Sem resultados para os filtros actuais.</div>
          <button className="btn" style={{ height: 30, width: 96, padding: '0', fontSize: 12, whiteSpace: 'nowrap', justifyContent: 'center' }} onClick={clearFilters}>Limpar filtros</button>
        </div>
      ) : (
        <div className="scrollbar" style={{ flex: 1, overflow: 'auto', marginTop: 18, padding: '0 32px 32px' }}>
          <table style={{ width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontSize: 12.5, fontFamily: 'var(--font-sans)' }}>
            <colgroup>
              <col style={{ width: isAll ? '22%' : '28%' }} />
              {isAll && <col />}
              <col style={{ width: 130 }} />
              <col style={{ width: 72 }} />
              <col style={{ width: 110 }} />
              <col style={{ width: 100 }} />
              <col style={{ width: 100 }} />
              <col style={{ width: 44 }} />
              <col style={{ width: 28 }} />
            </colgroup>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--bg-elev)', position: 'sticky', top: 0, zIndex: 2 }}>
                <SortHeader label="Briefing"    sortKey="product_name" sortBy={sortBy} onSort={k => setSortBy(s => ({ key: k, dir: s.key === k && s.dir === 'asc' ? 'desc' : 'asc' }))} />
                {isAll && <SortHeader label="Marca" sortKey="brand_name" sortBy={sortBy} onSort={k => setSortBy(s => ({ key: k, dir: s.key === k && s.dir === 'asc' ? 'desc' : 'asc' }))} />}
                <SortHeader label="Estado"      sortKey="status"       sortBy={sortBy} onSort={k => setSortBy(s => ({ key: k, dir: s.key === k && s.dir === 'asc' ? 'desc' : 'asc' }))} />
                <SortHeader label="Gerado"      sortKey={null}         sortBy={sortBy} onSort={() => {}} />
                <SortHeader label="Data aprov." sortKey="approved_at"  sortBy={sortBy} onSort={k => setSortBy(s => ({ key: k, dir: s.key === k && s.dir === 'asc' ? 'desc' : 'asc' }))} />
                <SortHeader label="Criado"      sortKey="created_at"   sortBy={sortBy} onSort={k => setSortBy(s => ({ key: k, dir: s.key === k && s.dir === 'asc' ? 'desc' : 'asc' }))} />
                <th style={estratThSt} />
                <th style={estratThSt} />
                <th style={estratThSt} />
              </tr>
            </thead>
            <tbody>
              {filtered.map(p => {
                const rowAttn = attentionIds.has(p.id) ? (userRole === 'strategist' ? 'var(--ai-500)' : 'var(--warning)') : null;
                return (
                  <EstratRow key={p.id} p={p} isAll={isAll}
                    onSelect={() => onSelect(p)}
                    onGenerate={() => onGenerate(p)}
                    onEdit={() => onSelect(p)}
                    onDelete={() => handleDelete(p)}
                    attentionColor={rowAttn}
                    userRole={userRole}
                  />
                );
              })}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
};

// ─── Dev user helper ──────────────────────────────────────────────────────────

const getEstratUser = () => {
  const p = new URLSearchParams(window.location.search);
  const dev = p.get('dev'), mkt = p.get('mkt_role');
  if (mkt === 'strategist') return { nome: 'Carlos Alves', role: 'strategist' };
  if (dev === 'rui')        return { nome: 'Rui Leitão',   role: 'board' };
  if (dev === 'costa')      return { nome: 'Fábio Costa',  role: 'admin' };
  const nome = window.currentUser?.nome_apresentar || window.currentUser?.nome || 'Utilizador';
  const tipo = window.currentUser?.tipo || '';
  return { nome, role: tipo === 'admin' ? 'admin' : 'board' };
};

// ─── Orquestrador principal ────────────────────────────────────────────────────

const MktEstrategiaScreen = () => {
  const { brand: brandId } = window.useMktBrand ? window.useMktBrand() : { brand: 'todas' };
  const [view, setView]         = React.useState('list');
  const [selected, setSelected] = React.useState(null);
  const [stratUser]             = React.useState(getEstratUser);

  const userRole = stratUser.role;
  const userName = stratUser.nome;

  const goList     = () => { setSelected(null); setView('list'); };
  const goGenerate = (p) => { setSelected(p); setView('generate'); };
  const goDetail   = (p) => { setSelected(p); setView('detail'); };

  // Ao montar, verificar se vem de "Gerar Conteúdo" nos Briefings
  React.useEffect(() => {
    let pendingId;
    try { pendingId = localStorage.getItem('mkt-pending-proposal'); } catch {}
    if (!pendingId) return;
    try { localStorage.removeItem('mkt-pending-proposal'); } catch {}
    window.MktEstrategiaAPI.get(Number(pendingId)).then(proposal => {
      if (!proposal) return;
      const hasContent = !!(proposal.content?._narrative);
      if (hasContent) {
        goDetail(proposal);
      } else {
        goGenerate(proposal);
      }
    });
  }, []);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
      {view === 'list' && (
        <EstratList brandId={brandId} onSelect={goDetail} onGenerate={goGenerate} userRole={userRole} userName={userName} />
      )}
      {view === 'generate' && (
        <EstratGenerateView proposal={selected} onDone={() => goDetail(selected)} onCancel={goList} />
      )}
      {view === 'detail' && (
        <EstratDetail proposal={selected} onBack={goList} onGenerate={goGenerate} userRole={userRole} userName={userName} />
      )}
    </div>
  );
};

window.MktEstrategiaScreen = MktEstrategiaScreen;
