/* screen_marketing_activacao.jsx
   Marketing · Activação — Aprovação, agendamento e publicação de peças.
   Views: Dashboard · Fila · Calendário · Histórico · Config
   Expõe window.MktActivacaoScreen.
*/

// ── Approver scope ─────────────────────────────────────────────────────────────
const _APPROVER_SCOPE = {
  'fabio.costa@digidelta.pt':  'all',
  'rui.leitao@digidelta.pt':   'all',
  'bruno@netscreen.pt':        'netscreen_only',
  'bruno.rosa@digidelta.pt':   'netscreen_only',
  'armando@digidelta.pt':      'all_except_netscreen',
  'armando.mota@digidelta.pt': 'all_except_netscreen',
};

function getApproverScope(email) {
  if (!email) return 'all';
  return _APPROVER_SCOPE[email.toLowerCase()] || 'all';
}

function canApprovePeca(email, peca) {
  const scope = getApproverScope(email);
  if (scope === 'all') return true;
  if (scope === 'netscreen_only') return peca.marca_slug === 'netscreen';
  if (scope === 'all_except_netscreen') return peca.marca_slug !== 'netscreen';
  return true;
}

// ── Current user ───────────────────────────────────────────────────────────────
function getCurrentUser() {
  const params = new URLSearchParams(window.location.search);
  if (params.get('dev') === 'costa') {
    return { email: 'fabio.costa@digidelta.pt', nome_apresentar: 'Fábio Costa' };
  }
  return window.currentUser || { email: 'fabio.costa@digidelta.pt', nome_apresentar: 'Fábio Costa' };
}

// ── Status config ──────────────────────────────────────────────────────────────
const ACT_STATUS = {
  pending:         { label: 'Pendente',    color: '#F59E0B', bg: 'rgba(245,158,11,0.12)' },
  ready_review:    { label: 'Para rever',  color: '#3859D0', bg: 'rgba(56,89,208,0.12)' },
  approved:        { label: 'Aprovada',    color: '#10B981', bg: 'rgba(16,185,129,0.12)' },
  scheduled:       { label: 'Agendada',    color: '#3859D0', bg: 'rgba(56,89,208,0.12)' },
  publishing:      { label: 'A publicar',  color: '#F59E0B', bg: 'rgba(245,158,11,0.12)', pulse: true },
  published:       { label: 'Publicada',   color: '#10B981', bg: 'rgba(16,185,129,0.12)' },
  failed_publish:  { label: 'Falhou',      color: '#EF4444', bg: 'rgba(239,68,68,0.12)' },
  cancelled:       { label: 'Cancelada',   color: '#9CA3AF', bg: 'rgba(156,163,175,0.12)' },
  paused:          { label: 'Pausada',     color: '#9CA3AF', bg: 'rgba(156,163,175,0.12)' },
};

function ActStatusBadge({ status }) {
  const cfg = ACT_STATUS[status] || ACT_STATUS.pending;
  return (
    <span style={{
      display: 'inline-block', fontSize: 10.5, fontWeight: 600,
      padding: '2px 8px', borderRadius: 99,
      color: cfg.color, background: cfg.bg,
      fontFamily: 'var(--font-mono, monospace)',
      animation: cfg.pulse ? 'pulse 1.5s ease-in-out infinite' : 'none',
      whiteSpace: 'nowrap',
    }}>
      {cfg.label}
    </span>
  );
}

// ── Cores de marca ─────────────────────────────────────────────────────────────
const _AC = {
  mimaki: '#e60012', biond: '#00a86b', decal: '#f59e0b',
  alldecor: '#ec4899', sensek: '#8B2DE8', netscreen: '#F97316', digidelta: '#3859D0',
};
const _actBrandColor = (s) => _AC[s] || '#3859D0';

// ── Canais canónicos — alinhados com Briefings (fonte de verdade) ──────────────
// Grupos para uso na view Canais (MA1):
//   PAID:     meta_ads, linkedin_ads, google_ads_search, google_ads_display
//   ORGÂNICO: instagram, facebook, linkedin
//   DIRECTO:  email, whatsapp
//   WEB:      website
//   FÍSICO:   muppi_led (Muppi + NovaStar unificados por panel_type)
//   INTERNO:  email_interno, whatsapp_interno, portal_notificacao (só Config)
const CANAL_LABELS = {
  // Paid
  meta_ads:           'Meta Ads',
  linkedin_ads:       'LinkedIn Ads',
  google_ads_search:  'Google Search Ads',
  google_ads_display: 'Google Display',
  // Orgânico (Campanhas e Activação — não em Briefings)
  instagram:          'Instagram',
  facebook:           'Facebook',
  linkedin:           'LinkedIn',
  // Directo
  email:              'Email',
  whatsapp:           'WhatsApp',
  // Web
  website:            'Website',
  // Físico (Muppi + NovaStar unificados)
  muppi_led:          'Painéis LED',
  // Interno (não aparecem na grelha principal — só Config → Notificações)
  email_interno:      'Email Interno',
  whatsapp_interno:   'WhatsApp Interno',
  portal_notificacao: 'Portal · Notificação',
  // Legado (backward compat para dados antigos)
  novastar:           'Painéis LED',
};
const CANAL_GROUPS = {
  paid:     ['meta_ads', 'linkedin_ads', 'google_ads_search', 'google_ads_display'],
  organico: ['instagram', 'facebook', 'linkedin'],
  directo:  ['email', 'whatsapp'],
  web:      ['website'],
  fisico:   ['muppi_led'],
};
const CANAL_GROUP_LABELS = {
  paid: 'Publicidade', organico: 'Orgânico', directo: 'Directo', web: 'Web', fisico: 'Físico',
};
const canalLabel = (c) => CANAL_LABELS[c] || c;

// ── API helpers ────────────────────────────────────────────────────────────────
async function actFetch(url, opts = {}) {
  try {
    const res = await fetch(url, { headers: { 'Content-Type': 'application/json' }, ...opts });
    if (!res.ok) { let b = {}; try { b = await res.json(); } catch {} throw new Error(b.error || `HTTP ${res.status}`); }
    return res.json();
  } catch (e) {
    throw e;
  }
}

const ActAPI = {
  dashboard: (email) => actFetch(`/api/marketing/activacao/dashboard?approver_email=${encodeURIComponent(email)}`),
  fila: (params) => actFetch(`/api/marketing/activacao/fila?${new URLSearchParams(params)}`),
  aprovar: (id, actor_email, actor_name) => actFetch(`/api/marketing/activacao/peca/${id}/aprovar`, { method: 'POST', body: JSON.stringify({ actor_email, actor_name }) }),
  rejeitar: (id, actor_email, actor_name, reason, rejection_category) => actFetch(`/api/marketing/activacao/peca/${id}/rejeitar`, { method: 'POST', body: JSON.stringify({ actor_email, actor_name, reason, rejection_category }) }),
  agendar: (id, scheduled_for, actor_email) => actFetch(`/api/marketing/activacao/peca/${id}/agendar`, { method: 'POST', body: JSON.stringify({ scheduled_for, actor_email }) }),
  reagendar: (id, scheduled_for, actor_email) => actFetch(`/api/marketing/activacao/peca/${id}/reagendar`, { method: 'POST', body: JSON.stringify({ scheduled_for, actor_email }) }),
  cancelar: (id, actor_email, reason) => actFetch(`/api/marketing/activacao/peca/${id}/cancelar`, { method: 'POST', body: JSON.stringify({ actor_email, reason }) }),
  aprovarBulk: (peca_ids, actor_email, actor_name) => actFetch('/api/marketing/activacao/aprovar-bulk', { method: 'POST', body: JSON.stringify({ peca_ids, actor_email, actor_name }) }),
  calendario: (params) => actFetch(`/api/marketing/activacao/calendario?${new URLSearchParams(params)}`),
  historico: (params) => actFetch(`/api/marketing/activacao/historico?${new URLSearchParams(params)}`),
  logs: (peca_id) => actFetch(`/api/marketing/activacao/logs/${peca_id}`),
  retry: (id, actor_email) => actFetch(`/api/marketing/activacao/peca/${id}/retry`, { method: 'POST', body: JSON.stringify({ actor_email }) }),
  campanhas: (brand, email) => actFetch(`/api/marketing/activacao/campanhas?approver_email=${encodeURIComponent(email)}${brand && brand !== 'todas' ? `&brand=${brand}` : ''}`),
  campanhaDetalhe: (id, email) => actFetch(`/api/marketing/activacao/campanha/${id}?approver_email=${encodeURIComponent(email)}`),
  canalDetalhe: (campId, canal, email) => actFetch(`/api/marketing/activacao/campanha/${campId}/canal/${canal}?approver_email=${encodeURIComponent(email)}`),
  campanhaPausar:  (id, actor_email, actor_name, reason) => actFetch(`/api/marketing/activacao/campanha/${id}/pausar`,  { method: 'POST', body: JSON.stringify({ actor_email, actor_name, reason }) }),
  campanhaRetomar: (id, actor_email, actor_name)         => actFetch(`/api/marketing/activacao/campanha/${id}/retomar`, { method: 'POST', body: JSON.stringify({ actor_email, actor_name }) }),
  canalAprovarBulk: (campId, canal, actor_email, actor_name) => actFetch(`/api/marketing/activacao/canal/${campId}/${canal}/aprovar-bulk`, { method: 'POST', body: JSON.stringify({ actor_email, actor_name }) }),
  // WA specific
  waTemplateStatus:   (campId)                      => actFetch(`/api/marketing/activacao/wa/template-status/${campId}`),
  waSubmitTemplate:   (campId, actor_email, actor_name) => actFetch(`/api/marketing/activacao/wa/submit-template`,  { method: 'POST', body: JSON.stringify({ campanha_id: campId, actor_email, actor_name }) }),
  waSaveSegmentacao:  (campId, tipo, contactos)     => actFetch(`/api/marketing/activacao/wa/save-segmentacao`,    { method: 'POST', body: JSON.stringify({ campanha_id: campId, tipo, contactos }) }),
  waSend:             (campId, actor_email, actor_name) => actFetch(`/api/marketing/activacao/wa/send`,             { method: 'POST', body: JSON.stringify({ campanha_id: campId, actor_email, actor_name }) }),
  waSendStatus:       (campId)                          => actFetch(`/api/marketing/activacao/wa/send-status/${campId}`),
};

// ── Formatters ─────────────────────────────────────────────────────────────────
function fmtDate(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d)) return '—';
  return d.toLocaleDateString('pt-PT', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' });
}
function fmtDateShort(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d)) return '—';
  return d.toLocaleDateString('pt-PT', { day: '2-digit', month: 'short' });
}
function fmtRelative(iso) {
  if (!iso) return '';
  const diff = Date.now() - new Date(iso).getTime();
  const mins = Math.floor(diff / 60000);
  if (mins < 2) return 'agora';
  if (mins < 60) return `há ${mins}m`;
  const h = Math.floor(mins / 60);
  if (h < 24) return `há ${h}h`;
  const d = Math.floor(h / 24);
  return `há ${d}d`;
}

// ── Dropdown (namespace único) ─────────────────────────────────────────────────
const ActivacaoDropdown = ({ label, value, options, onChange, disabled, minWidth = 160 }) => {
  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 current = options.find(o => o.value === value) || options[0];
  return (
    <div ref={ref} style={{ position: 'relative', display: 'inline-block' }}>
      <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', whiteSpace: 'nowrap',
      }}>
        <span style={{ color: 'var(--text-dim)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em', fontFamily: 'var(--font-mono)' }}>{label}</span>
        <span style={{ fontWeight: 500 }}>{current?.label || '—'}</span>
        <span style={{ color: 'var(--text-muted)', fontSize: 9 }}>▾</span>
      </button>
      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 4px)', left: 0, zIndex: 120,
          background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 6,
          boxShadow: '0 8px 24px rgba(17,41,84,0.12)', minWidth, padding: 4, maxHeight: 260, 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', whiteSpace: 'nowrap',
            }}>{o.label}</button>
          ))}
        </div>
      )}
    </div>
  );
};

// ── Empty state ────────────────────────────────────────────────────────────────
const ActEmptyState = ({ icon, title, sub }) => (
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '56px 24px', gap: 12, color: 'var(--text-muted)' }}>
    <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.35 }}>
      {icon === 'inbox' && <><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2"/><line x1="12" y1="12" x2="12" y2="16"/><line x1="10" y1="14" x2="14" y2="14"/></>}
      {icon === 'calendar' && <><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></>}
      {icon === 'history' && <><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.5"/></>}
      {icon === 'settings' && <><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></>}
      {!icon && <><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={{ fontWeight: 600, fontSize: 14, color: 'var(--text)' }}>{title || 'Sem dados'}</div>
    {sub && <div style={{ fontSize: 12, color: 'var(--text-muted)', textAlign: 'center', maxWidth: 320, lineHeight: 1.6 }}>{sub}</div>}
  </div>
);

// ── Spinner ────────────────────────────────────────────────────────────────────
const ActSpinner = () => (
  <div style={{ display: 'flex', justifyContent: 'center', padding: '48px 0' }}>
    <div style={{ width: 28, height: 28, border: '2.5px solid var(--border)', borderTopColor: 'var(--brand-primary, #3859D0)', borderRadius: '50%', animation: 'spin 0.75s linear infinite' }}/>
  </div>
);

// ═══════════════════════════════════════════════════════════════════════════════
// MOCK DATA (fallback when API returns 404 or error)
// ═══════════════════════════════════════════════════════════════════════════════
// URL ROUTING HELPERS — 3 níveis via hash
// ═══════════════════════════════════════════════════════════════════════════════
function parseActivacaoHash() {
  const h = window.location.hash.replace(/^#/, '');
  const params = new URLSearchParams(h);
  return {
    screen: params.get('screen'),
    sub:    params.get('sub'),
    camp:   params.get('camp'),
    canal:  params.get('canal'),
    view:   params.get('view') || 'kanban',
    tab:    params.get('tab')  || null,
  };
}

function setActivacaoHash(patch) {
  const cur = parseActivacaoHash();
  const merged = { ...cur, ...patch };
  const params = new URLSearchParams();
  params.set('screen', 'marketing');
  params.set('sub', 'activacao');
  if (merged.camp)  params.set('camp',  merged.camp);
  if (merged.canal) params.set('canal', merged.canal);
  if (merged.view && merged.view !== 'kanban') params.set('view', merged.view);
  if (merged.tab)  params.set('tab',  merged.tab);
  window.location.hash = params.toString();
}

// ═══════════════════════════════════════════════════════════════════════════════
// HEADER — multi-nível (level 1/2/3)
// ═══════════════════════════════════════════════════════════════════════════════
// ── Tab button helper — padrão Briefings/Campanhas ─────────────────────────────
const _tabBtn = (label, active, onClick, extra = {}) => (
  <button onClick={onClick} style={{
    background: 'none', border: 'none', outline: 'none',
    borderBottom: `2px solid ${active ? 'var(--ai-500, #3859D0)' : 'transparent'}`,
    color: active ? 'var(--text)' : 'var(--text-muted)',
    fontSize: 13, fontWeight: active ? 600 : 500,
    fontFamily: 'var(--font-display, Montserrat, sans-serif)', letterSpacing: '.01em',
    padding: '10px 18px 12px', cursor: 'pointer', whiteSpace: 'nowrap',
    transition: 'color .15s, border-color .15s',
    ...extra,
  }}>{label}</button>
);

const ActivacaoHeaderNew = ({ level, breadcrumb, title, subInfo, subNav, subNavActive, onSubNav, extraMenu }) => {
  const { brand, setBrand } = window.useMktBrand
    ? window.useMktBrand()
    : { brand: 'todas', setBrand: () => {} };

  const allBrands = [
    { slug:'todas',    name:'Todas' },    { slug:'mimaki',   name:'Mimaki' },
    { slug:'biond',    name:'BIOND' },    { slug:'decal',    name:'Decal' },
    { slug:'alldecor', name:'AllDecor' }, { slug:'sensek',   name:'Sensek' },
    { slug:'netscreen',name:'NetScreen' },{ slug:'digidelta', name:'Digidelta' },
  ];

  return (
    <div style={{ background: 'var(--bg-elev)', borderBottom: '1px solid var(--border)', padding: '20px 40px 0', flexShrink: 0 }}>
      {/* Breadcrumb — UPPERCASE · mono · peso 600 */}
      <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', color: 'var(--text-muted)', textTransform: 'uppercase', marginBottom: 6, fontFamily: 'var(--font-mono, monospace)' }}>
        {breadcrumb.map((b, i) => (
          <span key={i}>
            {i > 0 && <span style={{ margin: '0 6px' }}>·</span>}
            {b.onClick
              ? <a href="#" onClick={e => { e.preventDefault(); b.onClick(); }} style={{ color: 'var(--text-muted)', textDecoration: 'none' }}>{b.label}</a>
              : b.label}
          </span>
        ))}
      </div>
      {/* Title + actions — H1 à esquerda, extraMenu à direita */}
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16 }}>
        <div>
          <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', letterSpacing: '-0.01em', lineHeight: 1.2 }}>
            {title}
          </h1>
          {subInfo && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 11, color: 'var(--text-muted)', fontFamily: 'var(--font-body, Inter, sans-serif)' }}>
                {subInfo}
              </span>
            </div>
          )}
        </div>
        {extraMenu && <div style={{ flexShrink: 0, marginTop: 2 }}>{extraMenu}</div>}
      </div>
      {/* Separador */}
      <div style={{ height: 1, background: 'var(--border)', margin: '16px -40px 0' }} />
      {/* Brand tabs — só Nível 1 */}
      {level === 1 && (
        <div style={{ display: 'flex', gap: 0, overflowX: 'auto' }}>
          {allBrands.map(b => _tabBtn(b.name, brand === b.slug, () => setBrand(b.slug)))}
        </div>
      )}
      {/* Sub-nav — Nível 2/3 */}
      {subNav && subNav.length > 0 && (
        <div style={{ display: 'flex' }}>
          {subNav.map(t => _tabBtn(t.label, subNavActive === t.id, () => onSubNav && onSubNav(t.id)))}
        </div>
      )}
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// BANNER DIGI AI — contextual ao estado de publicação (Activação)
// ═══════════════════════════════════════════════════════════════════════════════
const ActBanner = ({ kpis, campanhas = [], userName }) => {
  const [seed] = React.useState(Math.random);
  const firstName = (userName || '').split(' ')[0] || 'Olá';
  const pl = (n, s, p) => n === 1 ? s : p;

  const { heading, body } = React.useMemo(() => {
    if (!kpis) return { heading: '', body: '' };
    const { total = 0, a_publicar = 0, em_publicacao = 0, com_falhas = 0, concluidas = 0 } = kpis;
    const aguarda = campanhas.filter(c => c.n_canais_review > 0).length;

    // Prioridade: falhas > aguarda aprovação > em publicação > a publicar > vazio
    let hPool, bodyParts = [];

    if (com_falhas > 0) {
      hPool = [
        `${firstName}, ${com_falhas} ${pl(com_falhas,'canal tem','canais têm')} erros. Resolve antes que a publicação pare.`,
        `${firstName}, atenção — ${com_falhas} ${pl(com_falhas,'canal falhado','canais falhados')} no pipeline. Vai a Activação e faz retry.`,
        `${firstName}, ${com_falhas} ${pl(com_falhas,'publicação falhou','publicações falharam')}. Verifica os erros antes de avançar.`,
      ];
    } else if (aguarda > 0) {
      hPool = [
        `${firstName}, ${aguarda} ${pl(aguarda,'campanha está pronta','campanhas estão prontas')} para aprovares. Não percas a janela de publicação.`,
        `${firstName}, a Digi AI produziu — falta o teu go em ${aguarda} ${pl(aguarda,'campanha','campanhas')}.`,
        `${firstName}, tens ${aguarda} ${pl(aguarda,'campanha','campanhas')} à espera de aprovação. Aprova agora para publicar a tempo.`,
      ];
    } else if (em_publicacao > 0) {
      hPool = [
        `${firstName}, ${em_publicacao} ${pl(em_publicacao,'campanha está','campanhas estão')} a publicar agora. Tudo em curso.`,
        `${firstName}, pipeline activo — ${em_publicacao} ${pl(em_publicacao,'campanha em publicação','campanhas em publicação')}.`,
      ];
    } else if (a_publicar > 0) {
      hPool = [
        `${firstName}, tens ${a_publicar} ${pl(a_publicar,'campanha agendada','campanhas agendadas')} para publicar em breve.`,
        `${firstName}, ${a_publicar} ${pl(a_publicar,'campanha pronta','campanhas prontas')} para agendar e publicar.`,
      ];
    } else if (total === 0) {
      hPool = [
        `${firstName}, pipeline limpo. Aprova uma campanha em Campanhas para a publicação começar.`,
        `${firstName}, ainda não há campanhas em Activação. Vai a Campanhas e aprova uma para começar.`,
      ];
    } else {
      hPool = [
        `${firstName}, pipeline em dia. Nada urgente para fazer aqui.`,
        `${firstName}, sem acções pendentes. ${concluidas} ${pl(concluidas,'campanha publicada','campanhas publicadas')}.`,
      ];
    }

    const heading = hPool[Math.floor(seed * hPool.length)];

    // Body dinâmico com lista de campanhas por estado
    const falhas  = campanhas.filter(c => c.n_canais_failed > 0);
    const aguardam = campanhas.filter(c => c.n_canais_review > 0 && !c.n_canais_failed);
    const emCurso  = campanhas.filter(c => c.kanban_col === 'em_publicacao' && !c.n_canais_review && !c.n_canais_failed);
    const agendadas = campanhas.filter(c => c.kanban_col === 'a_publicar' && !c.n_canais_review && !c.n_canais_failed);

    const fmtCamp = (arr) => arr.slice(0, 3).map(c => c.titulo || c.id.slice(0,8)).join(', ') + (arr.length > 3 ? ` e mais ${arr.length - 3}` : '');

    if (falhas.length)    bodyParts.push(`${fmtCamp(falhas)} ${pl(falhas.length,'tem','têm')} canais com erros — revê antes de prosseguir.`);
    if (aguardam.length)  bodyParts.push(`${fmtCamp(aguardam)} ${pl(aguardam.length,'aguarda','aguardam')} a tua aprovação.`);
    if (emCurso.length)   bodyParts.push(`${fmtCamp(emCurso)} ${pl(emCurso.length,'está','estão')} em publicação activa.`);
    if (agendadas.length) bodyParts.push(`${fmtCamp(agendadas)} ${pl(agendadas.length,'está agendada','estão agendadas')} para publicar em breve.`);
    if (total === 0)      bodyParts.push('Aprova uma campanha no módulo Campanhas para iniciar a publicação de assets.');

    return { heading, body: bodyParts.join(' ') };
  }, [kpis, campanhas, firstName, seed]);

  if (!heading) return null;

  return (
    <div style={{ flexShrink: 0, padding: '10px 0 18px' }}>
      <div style={{ fontSize: 22, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', marginBottom: 6, letterSpacing: '-0.02em' }}>
        {heading}
      </div>
      {body && (
        <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.75 }}>
          {body}
        </div>
      )}
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// FILTER BAR — padrão BriefingDropdown adaptado a Activação
// ═══════════════════════════════════════════════════════════════════════════════
const ActDropdown = ({ label, value, options, onChange }) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onClick = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onClick);
    return () => document.removeEventListener('mousedown', onClick);
  }, [open]);
  const current = options.find(o => o.value === value) || options[0];
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button onClick={() => setOpen(v => !v)} style={{
        background: 'var(--bg-elev, #ffffff)', color: 'var(--text, #112954)',
        border: '1px solid var(--border, #dde3ef)', borderRadius: 6,
        padding: '6px 10px', fontSize: 11.5,
        display: 'inline-flex', alignItems: 'center', gap: 8,
        cursor: 'pointer', fontFamily: 'inherit', transition: 'border-color .15s',
      }}>
        <span style={{ color: 'var(--text-dim, #475569)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em', fontFamily: 'var(--font-mono, monospace)' }}>{label}</span>
        <span style={{ fontWeight: 500 }}>{current?.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, #ffffff)', border: '1px solid var(--border, #dde3ef)', borderRadius: 6,
          boxShadow: '0 8px 24px rgba(17,41,84,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 ? 'rgba(56,89,208,0.08)' : 'transparent',
              color: o.value === value ? 'var(--ai-500, #3859D0)' : 'var(--text, #112954)',
              border: 'none', padding: '7px 10px', borderRadius: 4,
              fontSize: 12, fontWeight: o.value === value ? 600 : 500,
              cursor: 'pointer', fontFamily: 'inherit',
            }}>{o.label}</button>
          ))}
        </div>
      )}
    </div>
  );
};

const PERIODO_OPTIONS = [
  { value: 'all',    label: 'Todo o período' },
  { value: 'hoje',   label: 'Hoje' },
  { value: 'semana', label: 'Esta semana' },
  { value: 'mes',    label: 'Este mês' },
];

const ESTADO_ACT_OPTIONS = [
  { value: 'all',           label: 'Todos' },
  { value: 'a_publicar',    label: 'A publicar' },
  { value: 'em_publicacao', label: 'Em publicação' },
  { value: 'concluidas',    label: 'Concluídas' },
  { value: 'com_falhas',    label: 'Com falhas' },
  { value: 'pausadas',      label: 'Pausadas' },
];

const CANAL_ACT_OPTIONS = [
  { value: 'all',                 label: 'Todos' },
  { value: 'meta_ads',            label: 'Meta Ads' },
  { value: 'instagram',           label: 'Instagram' },
  { value: 'facebook',            label: 'Facebook' },
  { value: 'linkedin',            label: 'LinkedIn' },
  { value: 'linkedin_ads',        label: 'LinkedIn Ads' },
  { value: 'google_ads_search',   label: 'Google Search' },
  { value: 'google_ads_display',  label: 'Google Display' },
  { value: 'email',               label: 'Email' },
  { value: 'whatsapp',            label: 'WhatsApp' },
  { value: 'website',             label: 'Website' },
  { value: 'muppi_led',           label: 'Painéis LED' },
];

// ── View toggle — segmented control (Kanban / Calendário / Lista) ───────────────
const ACT_VIEWS = [
  {
    id: 'kanban', label: 'Kanban',
    icon: (active) => (
      <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
        <rect x="1" y="1" width="6" height="6" rx="1.5" fill={active ? '#fff' : 'var(--text-muted)'}/>
        <rect x="9" y="1" width="6" height="6" rx="1.5" fill={active ? '#fff' : 'var(--text-muted)'}/>
        <rect x="1" y="9" width="6" height="6" rx="1.5" fill={active ? '#fff' : 'var(--text-muted)'}/>
        <rect x="9" y="9" width="6" height="6" rx="1.5" fill={active ? '#fff' : 'var(--text-muted)'}/>
      </svg>
    ),
  },
  {
    id: 'calendario', label: 'Calendário',
    icon: (active) => (
      <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
        <rect x="1" y="3" width="14" height="12" rx="2" stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5"/>
        <line x1="5" y1="1" x2="5" y2="5" stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5" strokeLinecap="round"/>
        <line x1="11" y1="1" x2="11" y2="5" stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5" strokeLinecap="round"/>
        <line x1="1" y1="7" x2="15" y2="7" stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5"/>
      </svg>
    ),
  },
  {
    id: 'lista', label: 'Lista',
    icon: (active) => (
      <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
        <line x1="1" y1="4"  x2="15" y2="4"  stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5" strokeLinecap="round"/>
        <line x1="1" y1="8"  x2="15" y2="8"  stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5" strokeLinecap="round"/>
        <line x1="1" y1="12" x2="15" y2="12" stroke={active ? '#fff' : 'var(--text-muted)'} strokeWidth="1.5" strokeLinecap="round"/>
      </svg>
    ),
  },
];

const ActViewToggle = ({ view, onChange }) => (
  <div style={{ display: 'inline-flex', border: '1px solid var(--border, #dde3ef)', borderRadius: 7, overflow: 'hidden' }}>
    {ACT_VIEWS.map((v, i) => {
      const active = view === v.id;
      return (
        <button key={v.id} onClick={() => onChange(v.id)} title={v.label} style={{
          display: 'inline-flex', alignItems: 'center', gap: 5,
          padding: '5px 10px', background: active ? 'var(--ai-500, #3859D0)' : 'transparent',
          border: 'none', borderRight: i < ACT_VIEWS.length - 1 ? '1px solid var(--border, #dde3ef)' : 'none',
          cursor: 'pointer', transition: 'background 120ms',
          fontSize: 11, fontWeight: active ? 600 : 500,
          color: active ? '#fff' : 'var(--text-muted)',
          fontFamily: 'var(--font-body)',
        }}>
          {v.icon(active)}
          {v.label}
        </button>
      );
    })}
  </div>
);

const ActFilterBar = ({ filterCanal, setFilterCanal, filterEstado, setFilterEstado, filterPeriodo, setFilterPeriodo, view, onViewChange, total, onClear, hasActive }) => (
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8, marginBottom: 4 }}>
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
      <ActDropdown label="Canal"  value={filterCanal}   options={CANAL_ACT_OPTIONS}  onChange={setFilterCanal} />
      <ActDropdown label="Estado" value={filterEstado}  options={ESTADO_ACT_OPTIONS} onChange={setFilterEstado} />
      <span style={{ fontSize: 12, color: 'var(--text-muted)', fontFamily: 'var(--font-body)', paddingLeft: 4 }}>
        {total} resultado{total !== 1 ? 's' : ''}
      </span>
      {hasActive && (
        <button onClick={onClear} style={{ background: 'none', border: 'none', color: 'var(--text-muted)', fontSize: 11, cursor: 'pointer', padding: '2px 4px', fontFamily: 'inherit' }}>
          Limpar filtros ×
        </button>
      )}
    </div>
    <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
      <ActViewToggle view={view} onChange={onViewChange} />
      <ActDropdown label="Período" value={filterPeriodo} options={PERIODO_OPTIONS} onChange={setFilterPeriodo} />
    </div>
  </div>
);

// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 1 — Kanban Board
// ═══════════════════════════════════════════════════════════════════════════════
const KANBAN_COLS_DEF = [
  { id: 'a_publicar',    label: 'A publicar em breve', accent: '#F59E0B', bg: 'rgba(245,158,11,0.04)' },
  { id: 'em_publicacao', label: 'Em publicação',       accent: '#3859D0', bg: 'rgba(56,89,208,0.06)', highlight: true },
  { id: 'concluidas',    label: 'Concluídas · 30d',    accent: '#10B981', bg: 'rgba(16,185,129,0.04)' },
];

const CampanhaCardNew = ({ c, onClick, cardIndex = 0 }) => {
  const [hover, setHover] = React.useState(false);
  const brandColor = _actBrandColor(c.marca_slug);

  // Badge de estado — prioridade: falhas > pausada > aguarda > em publicação > a publicar > concluída
  const badge = c.n_canais_failed > 0
    ? { label: 'Com falhas',       color: '#EF4444', bg: 'rgba(239,68,68,0.12)' }
    : c.pausada
    ? { label: 'Pausada',          color: '#9CA3AF', bg: 'rgba(156,163,175,0.12)' }
    : c.n_canais_review > 0
    ? { label: 'Aguarda aprovação',color: '#F59E0B', bg: 'rgba(245,158,11,0.12)' }
    : c.kanban_col === 'em_publicacao'
    ? { label: 'Em publicação',    color: '#3859D0', bg: 'rgba(56,89,208,0.12)' }
    : c.kanban_col === 'concluidas'
    ? { label: 'Concluída',        color: '#10B981', bg: 'rgba(16,185,129,0.12)' }
    : { label: 'A publicar',       color: '#F59E0B', bg: 'rgba(245,158,11,0.12)' };

  return (
    <div
      onClick={onClick}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        background: 'var(--bg-elev, #fff)',
        borderTop: '1px solid var(--border, #ECEFF5)',
        borderRight: '1px solid var(--border, #ECEFF5)',
        borderBottom: '1px solid var(--border, #ECEFF5)',
        borderLeft: `3px solid ${brandColor}`,
        borderRadius: 8, padding: '12px 14px', cursor: 'pointer',
        boxShadow: hover ? '0 4px 12px rgba(0,0,0,0.08)' : '0 1px 3px rgba(0,0,0,0.04)',
        transition: 'box-shadow 150ms ease, transform 150ms ease',
        transform: hover ? 'translateY(-1px)' : 'translateY(0)',
        animation: 'slide-up 0.2s ease-out both',
        animationDelay: `${Math.min(cardIndex, 9) * 25}ms`,
      }}>
      {/* Header: marca + badge */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
        <span style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: brandColor, fontFamily: 'var(--font-mono, monospace)' }}>
          {c.marca_slug}
        </span>
        <span style={{ fontSize: 9, fontWeight: 700, padding: '2px 6px', borderRadius: 99, color: badge.color, background: badge.bg, fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.05em', whiteSpace: 'nowrap' }}>
          {badge.label}
        </span>
      </div>
      {/* Título */}
      <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text, #1d2e38)', fontFamily: 'var(--font-display, Montserrat, sans-serif)', lineHeight: 1.35, marginBottom: 10, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical' }}>
        {c.titulo || c.id.slice(0, 8)}
      </div>
      {/* Canais — dot state + mono bold */}
      {(c.canais || []).length > 0 && (
        <div style={{ display: 'flex', gap: 3, marginBottom: 10, flexWrap: 'wrap' }}>
          {(c.canais || []).slice(0, 5).map(canal => {
            const est = c.canais_estado?.[canal] || {};
            const dot = est.n_failed > 0 ? '#EF4444' : est.n_publishing > 0 ? '#F59E0B' : est.n_published > 0 ? '#10B981' : (est.n_scheduled > 0 || est.n_approved > 0) ? '#3859D0' : est.n_review > 0 ? '#F59E0B' : '#9CA3AF';
            return (
              <span key={canal} style={{ fontSize: 9, fontWeight: 700, padding: '2px 5px', borderRadius: 4, background: 'rgba(56,89,208,.08)', color: '#3859D0', fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.05em', display: 'inline-flex', alignItems: 'center', gap: 3 }}>
                <span style={{ width: 5, height: 5, borderRadius: '50%', background: dot, flexShrink: 0 }} />
                {canalLabel(canal).replace(/ (Ads|Search|Display)$/, '')}
              </span>
            );
          })}
          {(c.canais || []).length > 5 && (
            <span style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono, monospace)' }}>+{c.canais.length - 5}</span>
          )}
        </div>
      )}
      {/* Footer — mono state text */}
      <div style={{ fontSize: 10, color: '#94a3b8', fontFamily: 'var(--font-mono, monospace)', letterSpacing: '0.03em' }}>
        {c.pausada
          ? '⏸ pausada'
          : c.kanban_col === 'concluidas'   ? `publicada ${fmtDateShort(c.last_scheduled)}`
          : c.kanban_col === 'em_publicacao' ? `em curso · ${c.total_published || 0}/${c.total_pecas} peças`
          : c.next_scheduled                 ? `próxima: ${fmtDate(c.next_scheduled)}`
          : `${c.n_canais_review || 0} aguardam aprovação`}
      </div>
    </div>
  );
};


const KanbanBoard = ({ campanhas, onOpen }) => {
  const [collapsedCols, setCollapsedCols] = React.useState(() => new Set());
  const toggleCol = id => setCollapsedCols(prev => {
    const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next;
  });

  const grouped = React.useMemo(() => {
    const g = { a_publicar: [], em_publicacao: [], concluidas: [] };
    for (const c of campanhas) g[c.kanban_col]?.push(c);
    g.a_publicar.sort((a,b) => (a.next_scheduled||'9999') > (b.next_scheduled||'9999') ? 1 : -1);
    g.em_publicacao.sort((a,b) => (a.next_scheduled||'9999') > (b.next_scheduled||'9999') ? 1 : -1);
    g.concluidas.sort((a,b) => (a.last_scheduled||'') < (b.last_scheduled||'') ? 1 : -1);
    return g;
  }, [campanhas]);

  const kpiPerCol = React.useMemo(() => ({
    a_publicar: {
      value: grouped.a_publicar.length,
      fill: grouped.a_publicar.length === 0 ? 0
        : grouped.a_publicar.filter(c => c.n_canais_review === 0).length / grouped.a_publicar.length,
      sub: grouped.a_publicar.filter(c => c.n_canais_review > 0).length > 0
        ? `${grouped.a_publicar.filter(c => c.n_canais_review > 0).length} aguardam aprovação`
        : 'prontas para agendar',
    },
    em_publicacao: {
      value: grouped.em_publicacao.length,
      fill: grouped.em_publicacao.length === 0 ? 0
        : grouped.em_publicacao.reduce((s,c) => s + (c.total_published||0), 0) /
          Math.max(grouped.em_publicacao.reduce((s,c) => s + (c.total_pecas||1), 0), 1),
      sub: `${grouped.em_publicacao.reduce((s,c) => s + (c.total_published||0), 0)} peças publicadas`,
    },
    concluidas: {
      value: grouped.concluidas.length,
      fill: 1,
      sub: 'últimos 30 dias',
    },
  }), [grouped]);

  return (
    <div style={{ paddingBottom: 8 }}>
      <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
        {KANBAN_COLS_DEF.map((col, i) => {
          const collapsed = collapsedCols.has(col.id);
          const k = kpiPerCol[col.id];
          return (
            <div key={col.id} style={{ flex: collapsed ? '0 0 52px' : '1 1 0', minWidth: 0, transition: 'flex 0.22s ease', animation: 'slide-up 0.25s ease-out both', animationDelay: `${i * 40}ms` }}>
              {/* KPI header card — clicável para colapsar */}
              {collapsed ? (
                <div onClick={() => toggleCol(col.id)} title={`Expandir ${col.label}`} style={{
                  width: '100%', borderRadius: 8, cursor: 'pointer', overflow: 'hidden',
                  background: col.accent + '10', border: `1px solid ${col.accent}30`,
                  display: 'flex', flexDirection: 'column', alignItems: 'center',
                  padding: '10px 0 8px', gap: 6, marginBottom: 10, transition: 'background 0.15s',
                }}>
                  <div style={{ width: 24, height: 24, borderRadius: '50%', background: k.value > 0 ? col.accent : 'transparent', border: `1.5px solid ${col.accent}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                    <span style={{ fontSize: 11, fontWeight: 700, color: k.value > 0 ? '#fff' : col.accent, fontFamily: 'monospace', lineHeight: 1 }}>{k.value}</span>
                  </div>
                  <div style={{ writingMode: 'vertical-rl', textOrientation: 'mixed', transform: 'rotate(180deg)', fontSize: 10, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase', color: col.accent, fontFamily: 'var(--font-mono, monospace)', userSelect: 'none' }}>{col.label}</div>
                  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke={col.accent} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
                </div>
              ) : (
                <div style={{
                  background: 'var(--bg-elev, #ffffff)', border: '1px solid var(--border, #e2e8f0)',
                  borderRadius: 8, marginBottom: 10, overflow: 'hidden', cursor: 'pointer',
                  transition: 'border-color 150ms',
                }} onClick={() => toggleCol(col.id)}>
                  <div style={{ padding: '10px 14px 0' }}>
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
                      <div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-muted)', fontFamily: 'var(--font-mono, monospace)', whiteSpace: 'nowrap' }}>{col.label}</div>
                      <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--text-dim,#475569)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
                    </div>
                    <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display, Montserrat, sans-serif)', color: col.accent, lineHeight: 1, paddingBottom: 4 }}>{k.value}</div>
                    <div style={{ fontSize: 10, color: 'var(--text-muted)', fontFamily: 'var(--font-mono, monospace)', marginBottom: 8 }}>{k.sub}</div>
                    <div style={{ height: 3, background: 'var(--bg-sunken, #f1f5f9)', overflow: 'hidden' }}>
                      <div style={{ height: '100%', width: `${(k.fill || 0) * 100}%`, background: col.accent, transition: 'width .4s' }} />
                    </div>
                  </div>
                </div>
              )}
              {/* Cards */}
              {!collapsed && (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {grouped[col.id].length === 0
                    ? <div style={{ height: 40, borderRadius: 8, border: '1px dashed var(--border, #e2e8f0)', opacity: 0.4 }} />
                    : grouped[col.id].map((c, idx) => (
                        <CampanhaCardNew key={c.id} c={c} onClick={() => onOpen(c.id)} cardIndex={idx} />
                      ))}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 1 — Calendário Board
// ═══════════════════════════════════════════════════════════════════════════════
function startOfWeek(d) { const dt = new Date(d); const day = (dt.getDay()+6)%7; dt.setDate(dt.getDate()-day); dt.setHours(0,0,0,0); return dt; }
function addDays(d,n) { const c = new Date(d); c.setDate(c.getDate()+n); return c; }
function ymd(d) { return d.toISOString().slice(0,10); }
function nomeDia(d) { return ['Seg','Ter','Qua','Qui','Sex','Sáb','Dom'][(d.getDay()+6)%7]; }

const CalendarioBoard = ({ campanhas, onOpen }) => {
  const [anchor, setAnchor] = React.useState(startOfWeek(new Date()));
  const [range, setRange] = React.useState('semana');
  const days = React.useMemo(() => Array.from({ length: range==='dia'?1:range==='semana'?7:30 }, (_,i) => addDays(anchor,i)), [anchor, range]);
  const cellsByDay = React.useMemo(() => {
    const m = {};
    for (const c of campanhas) {
      if (!c.next_scheduled) continue;
      const k = ymd(new Date(c.next_scheduled));
      if (!m[k]) m[k] = [];
      m[k].push(c);
    }
    return m;
  }, [campanhas]);
  const nav = n => setAnchor(addDays(anchor, range==='dia'?n:range==='semana'?n*7:n*30));
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <button onClick={() => nav(-1)} style={{ padding: '6px 12px', border: '1px solid var(--border)', background: 'transparent', borderRadius: 6, cursor: 'pointer' }}>←</button>
          <button onClick={() => setAnchor(startOfWeek(new Date()))} style={{ padding: '6px 12px', border: '1px solid var(--border)', background: 'transparent', borderRadius: 6, cursor: 'pointer' }}>Hoje</button>
          <button onClick={() => nav(1)} style={{ padding: '6px 12px', border: '1px solid var(--border)', background: 'transparent', borderRadius: 6, cursor: 'pointer' }}>→</button>
          <span style={{ marginLeft: 12, alignSelf: 'center', fontFamily: 'var(--font-display)', fontSize: 15, fontWeight: 600 }}>{anchor.toLocaleDateString('pt-PT', { month:'long', year:'numeric' })}</span>
        </div>
        <div style={{ display: 'flex', gap: 4 }}>
          {['dia','semana','mes'].map(r => (
            <button key={r} onClick={() => setRange(r)} style={{ padding: '6px 12px', fontSize: 12, fontWeight: range===r?600:400, background: range===r?'var(--ai-500)':'transparent', color: range===r?'#fff':'var(--text-muted)', border: range===r?'none':'1px solid var(--border)', borderRadius: 6, cursor: 'pointer' }}>{r}</button>
          ))}
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(days.length,7)},1fr)`, gap: 4 }}>
        {days.map((d,i) => {
          const k = ymd(d); const items = cellsByDay[k]||[]; const isToday = k===ymd(new Date());
          return (
            <div key={i} style={{ border: `1px solid ${isToday?'var(--ai-500)':'var(--border)'}`, borderRadius: 6, padding: 8, background: 'var(--bg-elev)', minHeight: 80, display: 'flex', flexDirection: 'column', gap: 4 }}>
              <div style={{ fontSize: 10, color: 'var(--text-muted)', fontFamily: 'var(--font-mono,monospace)', textTransform: 'uppercase' }}>{nomeDia(d)} {d.getDate()}</div>
              {items.map(c => (
                <div key={c.id} onClick={() => onOpen(c.id)} style={{ fontSize: 11, padding: '3px 6px', borderRadius: 4, background: `${_actBrandColor(c.marca_slug)}22`, borderLeft: `3px solid ${_actBrandColor(c.marca_slug)}`, cursor: 'pointer', color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.titulo||c.id.slice(0,8)}</div>
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 1 HOME
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 1 — Lista (tabela sortable)
// ═══════════════════════════════════════════════════════════════════════════════
const ListaView = ({ campanhas, onOpen }) => {
  const [sortBy, setSortBy]   = React.useState('next_scheduled');
  const [sortDir, setSortDir] = React.useState('asc');

  const toggleSort = (col) => {
    if (sortBy === col) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortBy(col); setSortDir('asc'); }
  };

  const sorted = React.useMemo(() => {
    return [...campanhas].sort((a, b) => {
      let va = a[sortBy] ?? '';
      let vb = b[sortBy] ?? '';
      if (va < vb) return sortDir === 'asc' ? -1 : 1;
      if (va > vb) return sortDir === 'asc' ?  1 : -1;
      return 0;
    });
  }, [campanhas, sortBy, sortDir]);

  const SortIcon = ({ col }) => {
    if (sortBy !== col) return <span style={{ color: 'var(--text-dim)', marginLeft: 4 }}>↕</span>;
    return <span style={{ color: 'var(--ai-500)', marginLeft: 4 }}>{sortDir === 'asc' ? '↑' : '↓'}</span>;
  };

  const thStyle = { padding: '9px 14px', textAlign: 'left', fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.07em', color: 'var(--text-dim)', fontFamily: 'var(--font-mono, monospace)', borderBottom: '1px solid var(--border)', cursor: 'pointer', userSelect: 'none', whiteSpace: 'nowrap' };
  const tdStyle = { padding: '10px 14px', borderBottom: '1px solid var(--border)', verticalAlign: 'middle' };

  if (campanhas.length === 0) return (
    <div style={{ padding: '48px 0', textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>
      Sem campanhas para os filtros actuais.
    </div>
  );

  return (
    <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden', background: 'var(--bg-elev)' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead style={{ background: 'var(--bg)' }}>
          <tr>
            <th style={thStyle} onClick={() => toggleSort('titulo')}>Campanha <SortIcon col="titulo"/></th>
            <th style={thStyle} onClick={() => toggleSort('marca_slug')}>Marca <SortIcon col="marca_slug"/></th>
            <th style={{ ...thStyle, cursor: 'default' }}>Canais</th>
            <th style={thStyle} onClick={() => toggleSort('kanban_col')}>Estado <SortIcon col="kanban_col"/></th>
            <th style={thStyle} onClick={() => toggleSort('next_scheduled')}>Próxima publicação <SortIcon col="next_scheduled"/></th>
          </tr>
        </thead>
        <tbody>
          {sorted.map((c, idx) => {
            const brandColor = _actBrandColor(c.marca_slug);
            const badge = c.n_canais_failed > 0
              ? { label: 'Com falhas',  color: '#EF4444', bg: 'rgba(239,68,68,0.10)' }
              : c.pausada
              ? { label: 'Pausada',     color: '#9CA3AF', bg: 'rgba(156,163,175,0.10)' }
              : c.n_canais_review > 0
              ? { label: 'Aguarda',     color: '#F59E0B', bg: 'rgba(245,158,11,0.10)' }
              : c.kanban_col === 'em_publicacao'
              ? { label: 'Em publicação', color: '#3859D0', bg: 'rgba(56,89,208,0.10)' }
              : c.kanban_col === 'concluidas'
              ? { label: 'Concluída',   color: '#10B981', bg: 'rgba(16,185,129,0.10)' }
              : { label: 'A publicar',  color: '#F59E0B', bg: 'rgba(245,158,11,0.10)' };
            return (
              <tr key={c.id} onClick={() => onOpen(c.id)} style={{
                cursor: 'pointer', transition: 'background 100ms',
                animation: 'slide-up 0.15s ease-out both',
                animationDelay: `${Math.min(idx, 15) * 20}ms`,
              }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover, rgba(56,89,208,0.03))'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                <td style={tdStyle}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                    <div style={{ width: 3, height: 28, borderRadius: 2, background: brandColor, flexShrink: 0 }} />
                    <div>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', fontFamily: 'var(--font-display)' }}>{c.titulo || c.id.slice(0,8)}</div>
                    </div>
                  </div>
                </td>
                <td style={tdStyle}>
                  <span style={{ fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', color: brandColor, fontFamily: 'var(--font-mono)' }}>
                    {c.marca_slug}
                  </span>
                </td>
                <td style={tdStyle}>
                  <div style={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
                    {(c.canais || []).slice(0, 4).map(canal => {
                      const est = c.canais_estado?.[canal] || {};
                      const dot = est.n_failed > 0 ? '#EF4444' : est.n_published > 0 ? '#10B981' : est.n_scheduled > 0 || est.n_approved > 0 ? '#3859D0' : '#9CA3AF';
                      return (
                        <span key={canal} style={{ fontSize: 9, fontWeight: 700, padding: '2px 5px', borderRadius: 4, background: 'rgba(56,89,208,.08)', color: '#3859D0', fontFamily: 'var(--font-mono)', letterSpacing: '0.05em', display: 'inline-flex', alignItems: 'center', gap: 3 }}>
                          <span style={{ width: 5, height: 5, borderRadius: '50%', background: dot }} />
                          {canalLabel(canal).replace(/ (Ads|Search|Display)$/, '')}
                        </span>
                      );
                    })}
                    {(c.canais || []).length > 4 && <span style={{ fontSize: 9, color: '#94a3b8', fontFamily: 'var(--font-mono)' }}>+{c.canais.length - 4}</span>}
                  </div>
                </td>
                <td style={tdStyle}>
                  <span style={{ fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 99, color: badge.color, background: badge.bg, fontFamily: 'var(--font-mono)', letterSpacing: '0.05em', whiteSpace: 'nowrap' }}>
                    {badge.label}
                  </span>
                </td>
                <td style={{ ...tdStyle, fontSize: 12, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' }}>
                  {c.pausada ? '⏸ Pausada'
                    : c.kanban_col === 'concluidas' ? fmtDateShort(c.last_scheduled)
                    : c.next_scheduled ? fmtDate(c.next_scheduled)
                    : '—'}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

const Nivel1Home = ({ view, user, onChangeView, onOpenCampanha }) => {
  const { brand, isAll } = window.useMktBrand ? window.useMktBrand() : { brand: 'todas', isAll: true };
  const [data, setData]             = React.useState(null);
  const [loading, setLoading]       = React.useState(true);
  const [error, setError]           = React.useState(null);
  const [filterCanal, setFilterCanal]   = React.useState('all');
  const [filterEstado, setFilterEstado] = React.useState('all');
  const [filterPeriodo, setFilterPeriodo] = React.useState('all');

  const reload = React.useCallback(async () => {
    try { setError(null); const d = await ActAPI.campanhas(brand, user.email); setData(d); }
    catch (e) { setError(e.message); }
    finally { setLoading(false); }
  }, [brand, user.email]);
  React.useEffect(() => { setLoading(true); reload(); }, [reload]);
  React.useEffect(() => { const t = setInterval(reload, 30000); return () => clearInterval(t); }, [reload]);

  const filtered = React.useMemo(() => {
    if (!data) return [];
    let arr = data.campanhas;
    if (filterCanal !== 'all')  arr = arr.filter(c => (c.canais||[]).includes(filterCanal));
    if (filterEstado !== 'all') {
      if (filterEstado === 'com_falhas') arr = arr.filter(c => c.n_canais_failed > 0);
      else if (filterEstado === 'pausadas') arr = arr.filter(c => c.pausada);
      else arr = arr.filter(c => c.kanban_col === filterEstado);
    }
    if (filterPeriodo !== 'all') {
      const now = new Date(); const today = now.toISOString().slice(0,10);
      const weekStart = new Date(now); weekStart.setDate(now.getDate() - now.getDay());
      const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
      arr = arr.filter(c => {
        const d = c.next_scheduled || c.last_scheduled;
        if (!d) return false;
        const dt = new Date(d);
        if (filterPeriodo === 'hoje')   return d.slice(0,10) === today;
        if (filterPeriodo === 'semana') return dt >= weekStart;
        if (filterPeriodo === 'mes')    return dt >= monthStart;
        return true;
      });
    }
    return arr;
  }, [data, filterCanal, filterEstado, filterPeriodo]);

  const hasActive = filterCanal !== 'all' || filterEstado !== 'all' || filterPeriodo !== 'all';
  const clearFilters = () => { setFilterCanal('all'); setFilterEstado('all'); setFilterPeriodo('all'); };

  const kpis = data?.kpis;
  const subInfo = kpis
    ? `${kpis.total} campanha${kpis.total !== 1 ? 's' : ''}${!isAll ? '' : ' · todas as marcas'}`
    : null;

  return (
    <div style={{ display:'flex', flexDirection:'column', height:'100%', minHeight:0 }}>
      <ActivacaoHeaderNew
        level={1}
        breadcrumb={[{label:'Marketing'},{label:'Activação'}]}
        title="Activação"
        subInfo={subInfo}
      />
      <div className="scrollbar" style={{ flex:1, minHeight:0, overflowY:'auto', overflowX:'hidden', padding:'28px 40px 0', background:'var(--bg, #f8fafc)', display:'flex', flexDirection:'column', gap:18 }}>
        {!loading && !error && data && (
          <ActBanner kpis={data.kpis} campanhas={data.campanhas} userName={user.nome_apresentar} />
        )}
        <ActFilterBar
          filterCanal={filterCanal}   setFilterCanal={setFilterCanal}
          filterEstado={filterEstado} setFilterEstado={setFilterEstado}
          filterPeriodo={filterPeriodo} setFilterPeriodo={setFilterPeriodo}
          view={view} onViewChange={onChangeView}
          total={filtered.length} hasActive={hasActive} onClear={clearFilters}
        />
        {loading && <ActSpinner />}
        {error && <ActEmptyState icon="⚠" title="Erro a carregar" sub={error} />}
        {!loading && !error && data && view === 'kanban'     && <KanbanBoard    campanhas={filtered} onOpen={onOpenCampanha} />}
        {!loading && !error && data && view === 'calendario' && <CalendarioBoard campanhas={filtered} onOpen={onOpenCampanha} />}
        {!loading && !error && data && view === 'lista'      && <ListaView       campanhas={filtered} onOpen={onOpenCampanha} />}
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 2 — Detalhe da campanha
// ═══════════════════════════════════════════════════════════════════════════════
const CAMPANHA_SUBNAV = [
  { id:'publicar',   label:'Publicar' },
  { id:'enviar',     label:'Enviar' },
  { id:'timeline',   label:'Timeline' },
  { id:'metricas',   label:'Métricas' },
];

const CANAL_ESTADO_UI = {
  em_producao:       { label:'Em produção',       color:'#9CA3AF', bg:'rgba(156,163,175,0.12)' },
  aguarda_aprovacao: { label:'Aguarda aprovação',  color:'#F59E0B', bg:'rgba(245,158,11,0.12)' },
  aprovado_parcial:  { label:'Aprovação parcial',  color:'#F59E0B', bg:'rgba(245,158,11,0.12)' },
  aprovado:          { label:'Aprovado',           color:'#10B981', bg:'rgba(16,185,129,0.12)' },
  agendado:          { label:'Agendado',           color:'#3859D0', bg:'rgba(56,89,208,0.12)' },
  em_publicacao:     { label:'Em publicação',      color:'#F59E0B', bg:'rgba(245,158,11,0.12)', pulse:true },
  publicado:         { label:'Publicado',          color:'#10B981', bg:'rgba(16,185,129,0.12)' },
  com_falhas:        { label:'Com falhas',         color:'#EF4444', bg:'rgba(239,68,68,0.12)' },
};

const ApprovalConfirmDialog = ({ n, modo, onCancel, onConfirm, loading }) => (
  <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.5)', zIndex:100, display:'flex', alignItems:'center', justifyContent:'center' }} onClick={onCancel}>
    <div style={{ background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:8, padding:24, minWidth:400, maxWidth:500 }} onClick={e => e.stopPropagation()}>
      <h3 style={{ fontFamily:'var(--font-display)', fontSize:17, fontWeight:600, marginTop:0 }}>Confirmar aprovação</h3>
      <p style={{ color:'var(--text-muted)', fontSize:13, lineHeight:1.6 }}>
        {modo === 'enviar' ? `Vais aprovar ${n} variações que serão enviadas conforme o agendamento. Confirmar?` : `Vais aprovar ${n} variações que serão publicadas conforme o agendamento. Confirmar?`}
      </p>
      <div style={{ display:'flex', gap:8, justifyContent:'flex-end', marginTop:20 }}>
        <button onClick={onCancel} className="btn btn-sm" disabled={loading}>Cancelar</button>
        <button onClick={onConfirm} className="btn btn-sm btn-ai" disabled={loading}>{loading ? 'A aprovar…' : 'Confirmar'}</button>
      </div>
    </div>
  </div>
);

const CanalAprovarButton = ({ c, user, onChange, campId }) => {
  const [confirming, setConfirming] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const doAprovar = async () => {
    setLoading(true);
    try { await ActAPI.canalAprovarBulk(campId, c.canal_pai, user.email, user.name); onChange(); }
    catch (e) { alert(`Erro: ${e.message}`); }
    finally { setLoading(false); setConfirming(false); }
  };
  if (confirming) return <ApprovalConfirmDialog n={c.n_variacoes} modo={c.modo} onCancel={() => setConfirming(false)} onConfirm={doAprovar} loading={loading} />;
  return <button onClick={() => setConfirming(true)} className="btn btn-xs btn-ai" style={{ padding:'6px 12px' }}>Aprovar e agendar →</button>;
};

// ── WA Canal Card — fluxo específico: template → segmentação → envio ──────────
const WACanal = ({ c, user, campId, onChange }) => {
  const [tmpl, setTmpl]             = React.useState(null);
  const [seg, setSeg]               = React.useState(null);
  const [sendStats, setSendStats]   = React.useState(null);
  const [envios, setEnvios]         = React.useState([]);
  const [loading, setLoading]       = React.useState(true);
  const [submitting, setSubmitting] = React.useState(false);
  const [sending, setSending]       = React.useState(false);
  const [showSeg, setShowSeg]       = React.useState(false);
  const [phones, setPhones]         = React.useState('');
  const [savingSeg, setSavingSeg]   = React.useState(false);

  const load = React.useCallback(async () => {
    try {
      const r = await ActAPI.waTemplateStatus(campId);
      setTmpl(r.template || null);
    } catch { setTmpl(null); }
    try {
      const r = await fetch(`/api/marketing/activacao/wa/segmentacao/${campId}`);
      if (r.ok) setSeg(await r.json());
    } catch { setSeg(null); }
    try {
      const r = await ActAPI.waSendStatus(campId);
      setSendStats(parseInt(r.total) > 0 ? r : null);
    } catch { setSendStats(null); }
    try {
      const r = await fetch(`/api/marketing/activacao/wa/envios/${campId}`);
      if (r.ok) setEnvios(await r.json());
    } catch { setEnvios([]); }
    setLoading(false);
  }, [campId]);

  // Auto-poll a cada 30s quando há envios activos
  React.useEffect(() => {
    const hasPending = envios.some(e => ['sent','delivered'].includes(e.status));
    if (!hasPending) return;
    const t = setInterval(load, 30000);
    return () => clearInterval(t);
  }, [envios.length, load]);
  React.useEffect(() => { load(); }, [load]);

  const doSubmit = async () => {
    setSubmitting(true);
    try { await ActAPI.waSubmitTemplate(campId, user.email, user.name); await load(); onChange(); }
    catch (e) { alert(`Erro: ${e.message}`); }
    finally { setSubmitting(false); }
  };

  const doSaveSeg = async () => {
    setSavingSeg(true);
    try {
      const list = phones.split('\n').map(l => l.trim()).filter(Boolean).map(p => ({ phone: p }));
      if (!list.length) { alert('Adiciona pelo menos um número'); return; }
      await ActAPI.waSaveSegmentacao(campId, 'manual', list);
      await load(); setShowSeg(false);
    } catch (e) { alert(`Erro: ${e.message}`); }
    finally { setSavingSeg(false); }
  };

  const metaStatus = tmpl?.meta_status;
  const segCount   = seg?.total || 0;

  // Badge de estado do template
  const tmplBadge = !tmpl
    ? { label: 'Template não submetido', color: '#9CA3AF', bg: 'rgba(156,163,175,0.12)' }
    : metaStatus === 'approved'
    ? { label: 'Template aprovado ✓',   color: '#10B981', bg: 'rgba(16,185,129,0.12)' }
    : metaStatus === 'rejected'
    ? { label: 'Template rejeitado ✗',  color: '#EF4444', bg: 'rgba(239,68,68,0.12)' }
    : { label: 'Aguarda aprovação Meta', color: '#F59E0B', bg: 'rgba(245,158,11,0.12)' };

  return (
    <div style={{ border:'1px solid var(--border)', borderRadius:8, background:'var(--bg-elev)', padding:16, display:'flex', flexDirection:'column', gap:12 }}>
      {/* Header */}
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
        <div style={{ display:'flex', alignItems:'center', gap:10 }}>
          <span style={{ fontFamily:'var(--font-display)', fontSize:15, fontWeight:600, color:'var(--text)' }}>WhatsApp</span>
          <span style={{ fontSize:10, padding:'2px 8px', borderRadius:99, background:'var(--bg)', color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)', textTransform:'uppercase' }}>enviar</span>
        </div>
        <span style={{ fontSize:11, fontWeight:600, padding:'3px 10px', borderRadius:99, color:tmplBadge.color, background:tmplBadge.bg, fontFamily:'var(--font-mono,monospace)' }}>
          {loading ? 'A verificar…' : tmplBadge.label}
        </span>
      </div>

      {/* Template info */}
      {tmpl && (
        <div style={{ fontSize:12, color:'var(--text-muted)', lineHeight:1.6 }}>
          <div><b style={{ color:'var(--text)' }}>Template:</b> {tmpl.template_name}</div>
          <div><b style={{ color:'var(--text)' }}>Categoria:</b> {tmpl.categoria}</div>
          {tmpl.body && <div style={{ marginTop:4, padding:'8px 10px', background:'var(--bg)', borderRadius:6, fontSize:12, color:'var(--text)', lineHeight:1.5 }}>{tmpl.body}</div>}
          {metaStatus === 'rejected' && tmpl.rejection_reason && (
            <div style={{ marginTop:4, color:'#EF4444', fontSize:11 }}>Motivo: {tmpl.rejection_reason}</div>
          )}
        </div>
      )}

      {/* Segmentação — só mostra se template aprovado */}
      {metaStatus === 'approved' && (
        <div style={{ borderTop:'1px solid var(--border)', paddingTop:10 }}>
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:6 }}>
            <span style={{ fontSize:12, fontWeight:600, color:'var(--text)' }}>Segmentação</span>
            {segCount > 0 && <span style={{ fontSize:11, color:'#10B981', fontFamily:'var(--font-mono,monospace)' }}>{segCount} destinatários</span>}
          </div>
          {segCount === 0 && !showSeg && (
            <p style={{ fontSize:12, color:'var(--text-muted)', margin:'0 0 8px' }}>Nenhuma segmentação configurada. Define quem vai receber esta mensagem.</p>
          )}
          {showSeg ? (
            <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
              <label style={{ fontSize:11, color:'var(--text-muted)' }}>Números de telefone (um por linha, formato: 351xxxxxxxxx)</label>
              <textarea
                value={phones}
                onChange={e => setPhones(e.target.value)}
                rows={5}
                placeholder={'351918590905\n351917856423\n...'}
                style={{ width:'100%', padding:'8px 10px', borderRadius:6, border:'1px solid var(--border)', background:'var(--bg)', color:'var(--text)', fontSize:12, fontFamily:'var(--font-mono,monospace)', resize:'vertical', boxSizing:'border-box' }}
              />
              <div style={{ display:'flex', gap:8 }}>
                <button onClick={() => setShowSeg(false)} className="btn btn-xs">Cancelar</button>
                <button onClick={doSaveSeg} disabled={savingSeg} className="btn btn-xs btn-ai">{savingSeg ? 'A guardar…' : 'Guardar segmentação'}</button>
              </div>
            </div>
          ) : (
            <button onClick={() => setShowSeg(true)} className="btn btn-xs">{segCount > 0 ? 'Editar segmentação' : '+ Adicionar destinatários'}</button>
          )}
        </div>
      )}

      {/* Acções */}
      <div style={{ display:'flex', gap:8, borderTop:'1px solid var(--border)', paddingTop:10 }}>
        {!tmpl && (
          <button onClick={doSubmit} disabled={submitting} className="btn btn-xs btn-ai" style={{ padding:'6px 14px' }}>
            {submitting ? 'A submeter…' : 'Submeter template à Meta →'}
          </button>
        )}
        {tmpl && ['submitted','pending'].includes(metaStatus) && (
          <button onClick={load} className="btn btn-xs" style={{ padding:'6px 12px' }}>
            Verificar aprovação
          </button>
        )}
        {metaStatus === 'rejected' && (
          <button onClick={doSubmit} disabled={submitting} className="btn btn-xs" style={{ padding:'6px 12px', color:'#F59E0B' }}>
            {submitting ? 'A resubmeter…' : 'Resubmeter template'}
          </button>
        )}
        {metaStatus === 'approved' && segCount > 0 && !sendStats && (
          <button
            onClick={async () => {
              if (!confirm(`Vais enviar para ${segCount} destinatários. Confirmar?`)) return;
              setSending(true);
              try {
                const r = await ActAPI.waSend(campId, user.email, user.name);
                setSendStats(r);
                onChange();
              } catch (e) { alert(`Erro: ${e.message}`); }
              finally { setSending(false); }
            }}
            disabled={sending}
            className="btn btn-xs btn-ai" style={{ padding:'6px 14px' }}>
            {sending ? 'A enviar…' : `Enviar para ${segCount} destinatários →`}
          </button>
        )}
        {sendStats && (
          <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
            {[
              { label:'Enviados',   val: sendStats.enviados,  color:'#64748b' },
              { label:'Entregues',  val: sendStats.entregues, color:'#3859D0' },
              { label:'Lidos',      val: sendStats.lidos,     color:'#10B981' },
              { label:'Falhados',   val: sendStats.falhados,  color:'#EF4444' },
              { label:'Opt-out',    val: sendStats.optouts,   color:'#F59E0B' },
            ].map(s => parseInt(s.val) > 0 && (
              <div key={s.label} style={{ padding:'6px 12px', borderRadius:6, background:`${s.color}10`, border:`1px solid ${s.color}30`, textAlign:'center' }}>
                <div style={{ fontSize:16, fontWeight:700, color:s.color, fontFamily:'var(--font-mono,monospace)' }}>{s.val}</div>
                <div style={{ fontSize:9, color:s.color, textTransform:'uppercase', letterSpacing:'0.06em', fontFamily:'var(--font-mono,monospace)' }}>{s.label}</div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Tabela de envios individuais */}
      {envios.length > 0 && (
        <div style={{ borderTop:'1px solid var(--border)', paddingTop:10 }}>
          <div style={{ fontSize:11, fontWeight:600, color:'var(--text-muted)', textTransform:'uppercase', letterSpacing:'0.06em', fontFamily:'var(--font-mono,monospace)', marginBottom:8 }}>
            Detalhe de envios
          </div>
          <div style={{ overflowX:'auto' }}>
            <table style={{ width:'100%', borderCollapse:'collapse', fontSize:12 }}>
              <thead>
                <tr style={{ borderBottom:'1px solid var(--border)', background:'var(--bg)' }}>
                  {['Destinatário','Estado','Enviado','Entregue','Lido'].map(h => (
                    <th key={h} style={{ padding:'6px 10px', textAlign:'left', fontSize:9, fontWeight:600, color:'var(--text-dim)', textTransform:'uppercase', letterSpacing:'0.06em', fontFamily:'var(--font-mono,monospace)', whiteSpace:'nowrap' }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {envios.map((e, i) => {
                  const SC = { sent:'#64748b', delivered:'#3859D0', read:'#10B981', failed:'#EF4444', optout:'#F59E0B' };
                  const SL = { sent:'Enviado', delivered:'Entregue', read:'Lido', failed:'Falhado', optout:'Opt-out' };
                  const col = SC[e.status] || '#64748b';
                  const ft = ts => ts ? new Date(ts).toLocaleTimeString('pt-PT', { hour:'2-digit', minute:'2-digit' }) : '—';
                  return (
                    <tr key={i} style={{ borderBottom:'1px solid var(--border)', background: i%2===0 ? 'transparent' : 'var(--bg)' }}>
                      <td style={{ padding:'7px 10px', fontFamily:'var(--font-mono,monospace)', color:'var(--text)' }}>+{e.destinatario_phone}</td>
                      <td style={{ padding:'7px 10px' }}>
                        <span style={{ fontSize:10, fontWeight:600, padding:'2px 7px', borderRadius:99, color:col, background:`${col}14`, fontFamily:'var(--font-mono,monospace)' }}>
                          {SL[e.status] || e.status}
                        </span>
                      </td>
                      <td style={{ padding:'7px 10px', color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)' }}>{ft(e.enviado_at)}</td>
                      <td style={{ padding:'7px 10px', color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)' }}>{ft(e.entregue_at)}</td>
                      <td style={{ padding:'7px 10px', color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)' }}>{ft(e.lido_at)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
};

const CanalCard = ({ c, user, onOpen, onChange, campId }) => {
  // WA usa componente específico
  if (c.canal_pai === 'whatsapp') {
    return <WACanal c={c} user={user} campId={campId} onChange={onChange} />;
  }

  const estado = CANAL_ESTADO_UI[c.estado] || CANAL_ESTADO_UI.em_producao;
  const isPublicar = c.modo === 'publicar';
  const primeira = c.variacoes[0] || {};
  const thumb = primeira.composed_urls ? Object.values(primeira.composed_urls)[0] : null;
  const thumbUrl = thumb && typeof thumb === 'object' ? Object.values(thumb)[0] : thumb;
  return (
    <div style={{ border:'1px solid var(--border)', borderRadius:8, background:'var(--bg-elev)', padding:16, display:'flex', gap:20 }}>
      <div style={{ width:160, height:160, background:'var(--bg)', borderRadius:6, flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', overflow:'hidden', border:'1px solid var(--border)' }}>
        {thumbUrl ? <img src={thumbUrl} alt="preview" style={{ maxWidth:'100%', maxHeight:'100%', objectFit:'contain' }} /> : <div style={{ color:'var(--text-dim)', fontSize:11 }}>sem preview</div>}
      </div>
      <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:8 }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:12 }}>
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <span style={{ fontFamily:'var(--font-display)', fontSize:15, fontWeight:600, color:'var(--text)' }}>{canalLabel(c.canal_pai)}</span>
            <span style={{ fontSize:10, padding:'2px 8px', borderRadius:99, background:'var(--bg)', color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)', textTransform:'uppercase' }}>{c.modo}</span>
          </div>
          <span style={{ display:'inline-block', fontSize:11, fontWeight:600, padding:'3px 10px', borderRadius:99, color:estado.color, background:estado.bg, fontFamily:'var(--font-mono,monospace)', animation:estado.pulse?'pulse 1.5s ease-in-out infinite':'none' }}>{estado.label}</span>
        </div>
        <div style={{ fontSize:12, color:'var(--text-muted)', lineHeight:1.6 }}>
          {isPublicar ? <>
            {primeira.headline && <div><b style={{ color:'var(--text)' }}>Headline:</b> {primeira.headline}</div>}
            {primeira.setup_payload?.audience && <div><b style={{ color:'var(--text)' }}>Audiência:</b> {primeira.setup_payload.audience}</div>}
            {primeira.setup_payload?.budget && <div><b style={{ color:'var(--text)' }}>Budget:</b> {primeira.setup_payload.budget}€</div>}
            <div><b style={{ color:'var(--text)' }}>{c.n_variacoes} variações</b> · {c.next_scheduled ? `agendado ${fmtDate(c.next_scheduled)}` : 'sem agendamento'}</div>
          </> : <>
            {primeira.headline && <div><b style={{ color:'var(--text)' }}>Template:</b> {primeira.headline}</div>}
            {primeira.segmentacao_payload?.contagem && <div><b style={{ color:'var(--text)' }}>Destinatários:</b> {primeira.segmentacao_payload.contagem}</div>}
            <div><b style={{ color:'var(--text)' }}>{c.n_variacoes} variações</b> · {c.next_scheduled ? `agendado ${fmtDate(c.next_scheduled)}` : 'sem agendamento'}</div>
          </>}
        </div>
        <div style={{ display:'flex', gap:8, marginTop:4 }}>
          <button onClick={onOpen} className="btn btn-xs" style={{ padding:'6px 12px' }}>Ver detalhe →</button>
          {c.estado === 'aguarda_aprovacao' && <CanalAprovarButton c={c} user={user} onChange={onChange} campId={campId} />}
          {c.estado === 'com_falhas' && <button className="btn btn-xs" style={{ padding:'6px 12px', color:'#EF4444' }}>Ver erros</button>}
        </div>
      </div>
    </div>
  );
};

// ── Canal Mockups — frames autênticos por plataforma ──────────────────────────
const MetaAdMockup = ({ imgUrl, headline, body, cta, pageName = 'Digidelta' }) => (
  <div style={{ border:'1px solid #dde0e4', borderRadius:8, overflow:'hidden', background:'#fff', maxWidth:340, fontFamily:'Helvetica, Arial, sans-serif', fontSize:14 }}>
    {/* Header */}
    <div style={{ padding:'10px 12px', display:'flex', alignItems:'center', gap:8 }}>
      <div style={{ width:36, height:36, borderRadius:'50%', background:'#3859D0', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
        <span style={{ color:'#fff', fontSize:13, fontWeight:700 }}>D</span>
      </div>
      <div>
        <div style={{ fontSize:13, fontWeight:700, color:'#050505' }}>{pageName}</div>
        <div style={{ fontSize:11, color:'#65676b' }}>Patrocinado · <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#65676b" strokeWidth="2"><circle cx="12" cy="12" r="10"/><polyline points="12 8 12 12 14 14"/></svg></div>
      </div>
    </div>
    {/* Body text */}
    {body && <div style={{ padding:'0 12px 10px', fontSize:13, color:'#050505', lineHeight:1.5 }}>{body.length>120?body.slice(0,120)+'…':body}</div>}
    {/* Image */}
    <div style={{ background:'#f0f2f5', aspectRatio:'1.91/1', overflow:'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}>
      {imgUrl ? <img src={imgUrl} alt="" style={{ width:'100%', objectFit:'cover' }} /> : <span style={{ color:'#65676b', fontSize:12 }}>Imagem do anúncio</span>}
    </div>
    {/* Ad footer */}
    <div style={{ padding:'10px 12px', background:'#f0f2f5', display:'flex', alignItems:'center', justifyContent:'space-between' }}>
      <div>
        <div style={{ fontSize:11, color:'#65676b', textTransform:'uppercase' }}>mimaki.digidelta.pt</div>
        <div style={{ fontSize:14, fontWeight:700, color:'#050505' }}>{headline || 'Headline do anúncio'}</div>
      </div>
      {cta && <div style={{ padding:'7px 14px', background:'#e4e6eb', borderRadius:4, fontSize:13, fontWeight:600, color:'#050505', flexShrink:0 }}>{cta}</div>}
    </div>
    {/* Reactions */}
    <div style={{ padding:'8px 12px', borderTop:'1px solid #dde0e4', display:'flex', gap:16 }}>
      {['👍 Gosto','💬 Comentar','↗ Partilhar'].map(a => (
        <span key={a} style={{ fontSize:12, color:'#65676b', cursor:'pointer' }}>{a}</span>
      ))}
    </div>
  </div>
);

const InstagramMockup = ({ imgUrl, headline, body, pageName = 'digidelta' }) => (
  <div style={{ border:'1px solid #dbdbdb', borderRadius:8, overflow:'hidden', background:'#fff', maxWidth:340, fontFamily:'-apple-system, BlinkMacSystemFont, sans-serif' }}>
    {/* Header */}
    <div style={{ padding:'10px 12px', display:'flex', alignItems:'center', justifyContent:'space-between' }}>
      <div style={{ display:'flex', alignItems:'center', gap:8 }}>
        <div style={{ width:32, height:32, borderRadius:'50%', background:'linear-gradient(45deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888)', padding:2 }}>
          <div style={{ width:'100%', height:'100%', borderRadius:'50%', background:'#3859D0', display:'flex', alignItems:'center', justifyContent:'center' }}>
            <span style={{ color:'#fff', fontSize:11, fontWeight:700 }}>D</span>
          </div>
        </div>
        <div>
          <div style={{ fontSize:13, fontWeight:700, color:'#262626' }}>{pageName}</div>
          <div style={{ fontSize:11, color:'#8e8e8e' }}>Patrocinado</div>
        </div>
      </div>
      <span style={{ fontSize:18, color:'#262626' }}>⋯</span>
    </div>
    {/* Image */}
    <div style={{ background:'#f5f5f5', aspectRatio:'1/1', overflow:'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}>
      {imgUrl ? <img src={imgUrl} alt="" style={{ width:'100%', objectFit:'cover' }} /> : <span style={{ color:'#8e8e8e', fontSize:12 }}>Imagem do post</span>}
    </div>
    {/* Actions */}
    <div style={{ padding:'8px 12px 4px', display:'flex', gap:12 }}>
      {['♡','💬','↗'].map(i => <span key={i} style={{ fontSize:22, cursor:'pointer' }}>{i}</span>)}
    </div>
    {/* Caption */}
    <div style={{ padding:'0 12px 12px', fontSize:13, color:'#262626', lineHeight:1.5 }}>
      <span style={{ fontWeight:700 }}>{pageName}</span>{' '}
      {body ? (body.length>80?body.slice(0,80)+'…':body) : headline || ''}
    </div>
  </div>
);

const LinkedInMockup = ({ imgUrl, headline, body, pageName = 'Digidelta' }) => (
  <div style={{ border:'1px solid #e0e0e0', borderRadius:8, overflow:'hidden', background:'#fff', maxWidth:340, fontFamily:'-apple-system, BlinkMacSystemFont, sans-serif' }}>
    <div style={{ padding:'12px 16px', display:'flex', alignItems:'center', gap:8 }}>
      <div style={{ width:40, height:40, borderRadius:4, background:'#3859D0', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
        <span style={{ color:'#fff', fontSize:14, fontWeight:700 }}>D</span>
      </div>
      <div>
        <div style={{ fontSize:13, fontWeight:700, color:'rgba(0,0,0,.9)' }}>{pageName}</div>
        <div style={{ fontSize:11, color:'rgba(0,0,0,.6)' }}>Promovido</div>
      </div>
    </div>
    {body && <div style={{ padding:'0 16px 12px', fontSize:13, color:'rgba(0,0,0,.9)', lineHeight:1.5 }}>{body.length>100?body.slice(0,100)+'…':body}</div>}
    <div style={{ background:'#f3f2ef', aspectRatio:'1.91/1', overflow:'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}>
      {imgUrl ? <img src={imgUrl} alt="" style={{ width:'100%', objectFit:'cover' }} /> : <span style={{ color:'rgba(0,0,0,.4)', fontSize:12 }}>Imagem</span>}
    </div>
    {headline && <div style={{ padding:'10px 16px', fontSize:14, fontWeight:700, color:'rgba(0,0,0,.9)', borderTop:'1px solid #e0e0e0' }}>{headline}</div>}
  </div>
);

const EmailMockup = ({ headline, body, cta, pageName = 'Digidelta' }) => (
  <div style={{ border:'1px solid #e2e8f0', borderRadius:8, overflow:'hidden', background:'#fff', maxWidth:400, fontFamily:'Arial, sans-serif' }}>
    {/* Inbox row */}
    <div style={{ padding:'10px 14px', background:'#f8fafc', borderBottom:'1px solid #e2e8f0', display:'flex', gap:10, alignItems:'center' }}>
      <div style={{ width:32, height:32, borderRadius:'50%', background:'#3859D0', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
        <span style={{ color:'#fff', fontSize:12, fontWeight:700 }}>D</span>
      </div>
      <div style={{ flex:1, minWidth:0 }}>
        <div style={{ display:'flex', justifyContent:'space-between' }}>
          <span style={{ fontSize:13, fontWeight:700, color:'#1a1a1a' }}>{pageName}</span>
          <span style={{ fontSize:11, color:'#64748b' }}>agora</span>
        </div>
        <div style={{ fontSize:12, color:'#475569', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{headline || 'Assunto do email'}</div>
      </div>
    </div>
    {/* Email body */}
    <div style={{ padding:'16px', background:'#ffffff' }}>
      {headline && <div style={{ fontSize:18, fontWeight:700, color:'#1a1a1a', marginBottom:10, lineHeight:1.3 }}>{headline}</div>}
      {body && <div style={{ fontSize:13, color:'#374151', lineHeight:1.65, marginBottom:16 }}>{body.length>160?body.slice(0,160)+'…':body}</div>}
      {cta && <div style={{ display:'inline-block', padding:'10px 20px', background:'#3859D0', color:'#fff', borderRadius:6, fontSize:13, fontWeight:600 }}>{cta}</div>}
    </div>
  </div>
);

const GenericMockup = ({ imgUrl, headline, canal }) => (
  <div style={{ border:'1px solid #e2e8f0', borderRadius:8, overflow:'hidden', background:'#fff', maxWidth:340 }}>
    <div style={{ background:'#f8fafc', aspectRatio:'16/9', overflow:'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}>
      {imgUrl ? <img src={imgUrl} alt="" style={{ width:'100%', objectFit:'cover' }} /> : <span style={{ color:'#94a3b8', fontSize:12 }}>Preview {canal}</span>}
    </div>
    {headline && <div style={{ padding:'10px 14px', fontSize:13, fontWeight:600, color:'#1d2e38' }}>{headline}</div>}
  </div>
);

const CanalMockup = ({ canal, imgUrl, headline, body, cta, pageName }) => {
  if (['meta_ads','facebook'].includes(canal)) return <MetaAdMockup imgUrl={imgUrl} headline={headline} body={body} cta={cta} pageName={pageName} />;
  if (canal === 'instagram') return <InstagramMockup imgUrl={imgUrl} headline={headline} body={body} pageName={pageName?.toLowerCase()} />;
  if (['linkedin','linkedin_ads'].includes(canal)) return <LinkedInMockup imgUrl={imgUrl} headline={headline} body={body} pageName={pageName} />;
  if (canal === 'email') return <EmailMockup headline={headline} body={body} cta={cta} pageName={pageName} />;
  return <GenericMockup imgUrl={imgUrl} headline={headline} canal={canal} />;
};

// ── PublicarWorkspace — master-detail 30/70 ────────────────────────────────────
const CANAL_ACCENT = {
  meta_ads:'#0866FF', facebook:'#1877F2', instagram:'#E4405F', linkedin_ads:'#0A66C2',
  linkedin:'#0A66C2', google_ads:'#4285F4', google_ads_search:'#4285F4',
  google_ads_display:'#4285F4', youtube:'#FF0000', tiktok:'#000000',
  website:'#3859D0', muppi_led:'#F59E0B',
};

// ═══════════════════════════════════════════════════════════════════════════
// AudienceCardLive — mostra audiência associada à campanha com dados live do CRM
// ═══════════════════════════════════════════════════════════════════════════
const AudienceCardLive = ({ audienceLabel, campanhaId, canal }) => {
  const [seg, setSeg] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    if (!campanhaId) { setLoading(false); return; }
    // Vai buscar a segmentação guardada (contém audience_id + snapshot)
    fetch(`/api/marketing/activacao/wa/segmentacao/${campanhaId}`)
      .then(r => r.ok ? r.json() : null)
      .then(d => { setSeg(d); setLoading(false); })
      .catch(() => setLoading(false));
  }, [campanhaId]);

  const audId = seg?.definicao?.audience_id;
  const total = seg?.total;

  const openCRMWithContext = () => {
    const c = canal === 'whatsapp' ? 'wa' : canal === 'email' ? 'email' : '';
    window.location.hash = `#screen=marketing&sub=crm?campanha=${campanhaId}&intent=segmentar${c ? `&canal=${c}` : ''}`;
  };

  // Não há audiência configurada ainda
  if (!loading && !seg && !audienceLabel) {
    return (
      <div style={{ padding:'12px 14px', background:'color-mix(in oklch, var(--ai-500) 5%, var(--bg))', borderRadius:8, border:'1px dashed var(--ai-500)', fontSize:12, display:'flex', alignItems:'center', gap:10 }}>
        <div>
          <div style={{ fontSize:10, color:'var(--ai-500)', fontFamily:'var(--font-mono,monospace)', marginBottom:2, fontWeight:700, letterSpacing:'0.06em', textTransform:'uppercase' }}>AUDIÊNCIA</div>
          <div style={{ color:'var(--text-muted)', fontSize:11 }}>Ainda não definida</div>
        </div>
        <button onClick={openCRMWithContext}
          style={{ marginLeft:8, padding:'5px 12px', borderRadius:6, border:'none', background:'var(--ai-500)', color:'#fff', fontSize:11, fontWeight:600, cursor:'pointer' }}>
          Segmentar no CRM →
        </button>
      </div>
    );
  }

  return (
    <div style={{ padding:'10px 14px', background:'var(--bg)', borderRadius:8, border:'1px solid var(--border)', fontSize:12, display:'flex', alignItems:'center', gap:12 }}>
      <div>
        <div style={{ fontSize:10, color:'var(--text-dim)', fontFamily:'var(--font-mono,monospace)', marginBottom:2, letterSpacing:'0.06em' }}>AUDIÊNCIA</div>
        <div style={{ color:'var(--text)', fontWeight:600 }}>
          {audienceLabel || (audId ? 'Audiência CRM' : 'Configurada manualmente')}
        </div>
        {total != null && (
          <div style={{ fontSize:10, color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)', marginTop:2 }}>
            {total.toLocaleString('pt-PT')} contactos
          </div>
        )}
      </div>
      <button onClick={openCRMWithContext}
        style={{ marginLeft:'auto', background:'none', border:'1px solid var(--border)', borderRadius:6, padding:'4px 10px', fontSize:10, color:'var(--ai-500)', cursor:'pointer', fontWeight:600 }}
        title="Editar audiência no CRM">
        Editar no CRM ↗
      </button>
    </div>
  );
};

const PublicarWorkspace = ({ canais, user, onOpen, onChange, campId }) => {
  const [sel, setSel] = React.useState(canais[0]?.canal_pai || null);
  const selCanal = canais.find(c => c.canal_pai === sel) || canais[0];
  if (!selCanal) return <ActEmptyState icon="○" title="Sem canais de publicação" sub="Esta campanha não tem canais broadcast activos." />;

  const primeira = selCanal.variacoes?.[0] || {};
  const thumb = primeira.composed_urls ? (Object.values(Object.values(primeira.composed_urls)[0] || {})[0] || null) : null;
  const estado = CANAL_ESTADO_UI[selCanal.estado] || CANAL_ESTADO_UI.em_producao;

  return (
    <div style={{ display:'flex', gap:0, height:'100%', minHeight:0, borderRadius:8, border:'1px solid var(--border)', overflow:'hidden', background:'var(--bg-elev)' }}>

      {/* ── Lista (30%) ── */}
      <div style={{ width:'30%', minWidth:220, borderRight:'1px solid var(--border)', display:'flex', flexDirection:'column', overflowY:'auto' }}>
        {canais.map(c => {
          const isSel = c.canal_pai === sel;
          const est   = CANAL_ESTADO_UI[c.estado] || CANAL_ESTADO_UI.em_producao;
          const accent = CANAL_ACCENT[c.canal_pai] || '#64748b';
          return (
            <div key={c.canal_pai} onClick={() => setSel(c.canal_pai)} style={{
              padding:'14px 18px', cursor:'pointer', borderLeft:`3px solid ${isSel ? accent : 'transparent'}`,
              background: isSel ? `${accent}08` : 'transparent',
              borderBottom:'1px solid var(--border)', transition:'background 120ms',
            }}>
              <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:4 }}>
                <span style={{ fontSize:13, fontWeight:isSel?700:500, color:'var(--text)', fontFamily:'var(--font-body)' }}>
                  {canalLabel(c.canal_pai)}
                </span>
                <span style={{ fontSize:10, fontWeight:600, padding:'2px 7px', borderRadius:99, color:est.color, background:est.bg, fontFamily:'var(--font-mono,monospace)' }}>
                  {est.label}
                </span>
              </div>
              <div style={{ fontSize:11, color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)' }}>
                {c.n_variacoes} variação{c.n_variacoes !== 1 ? 'ões' : ''}
                {c.next_scheduled && ` · ${fmtDate(c.next_scheduled)}`}
              </div>
            </div>
          );
        })}
      </div>

      {/* ── Preview + config (70%) ── */}
      <div style={{ flex:1, display:'flex', flexDirection:'column', minWidth:0, padding:'24px 28px', overflowY:'auto', gap:20 }}>

        {/* Canal header */}
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <div style={{ width:10, height:10, borderRadius:'50%', background: CANAL_ACCENT[selCanal.canal_pai] || '#64748b', flexShrink:0 }} />
            <span style={{ fontSize:18, fontWeight:700, color:'var(--text)', fontFamily:'var(--font-display)' }}>{canalLabel(selCanal.canal_pai)}</span>
          </div>
          <span style={{ fontSize:11, fontWeight:600, padding:'3px 10px', borderRadius:99, color:estado.color, background:estado.bg, fontFamily:'var(--font-mono,monospace)' }}>{estado.label}</span>
        </div>

        {/* Mockup autêntico */}
        <CanalMockup
          canal={selCanal.canal_pai}
          imgUrl={thumb}
          headline={primeira.headline}
          body={primeira.body || primeira.caption_organica}
          cta={primeira.cta}
          pageName="Digidelta"
        />

        {/* Setup info */}
        {(primeira.setup_payload || selCanal.next_scheduled) && (
          <div style={{ display:'flex', flexWrap:'wrap', gap:12 }}>
            {/* Audiência — card CRM linked (Workflow) */}
            <AudienceCardLive
              audienceLabel={primeira.setup_payload?.audience}
              campanhaId={campId}
              canal={selCanal.canal_pai}
            />
            {primeira.setup_payload?.budget && (
              <div style={{ padding:'10px 14px', background:'var(--bg)', borderRadius:8, border:'1px solid var(--border)', fontSize:12 }}>
                <div style={{ fontSize:10, color:'var(--text-dim)', fontFamily:'var(--font-mono,monospace)', marginBottom:2 }}>BUDGET</div>
                <div style={{ color:'var(--text)', fontWeight:500 }}>{primeira.setup_payload.budget}€</div>
              </div>
            )}
            {selCanal.next_scheduled && (
              <div style={{ padding:'10px 14px', background:'var(--bg)', borderRadius:8, border:'1px solid var(--border)', fontSize:12 }}>
                <div style={{ fontSize:10, color:'var(--text-dim)', fontFamily:'var(--font-mono,monospace)', marginBottom:2 }}>AGENDAMENTO</div>
                <div style={{ color:'var(--text)', fontWeight:500 }}>{fmtDate(selCanal.next_scheduled)}</div>
              </div>
            )}
            <div style={{ padding:'10px 14px', background:'var(--bg)', borderRadius:8, border:'1px solid var(--border)', fontSize:12 }}>
              <div style={{ fontSize:10, color:'var(--text-dim)', fontFamily:'var(--font-mono,monospace)', marginBottom:2 }}>VARIAÇÕES</div>
              <div style={{ color:'var(--text)', fontWeight:500 }}>{selCanal.n_variacoes}</div>
            </div>
          </div>
        )}

        {/* Acções */}
        <div style={{ display:'flex', gap:8, paddingTop:4 }}>
          <button onClick={() => onOpen(selCanal.canal_pai)} className="btn btn-xs" style={{ padding:'8px 16px' }}>Ver detalhe →</button>
          {selCanal.estado === 'aguarda_aprovacao' && <CanalAprovarButton c={selCanal} user={user} onChange={onChange} campId={campId} />}
        </div>
      </div>
    </div>
  );
};

// ── EnviarWorkspace — master-detail 30/70 para canais directos (WA, Email) ───
const _ENV_ACCENT = {
  whatsapp: '#25D366', email: '#3859D0', muppi_led: '#F59E0B', novastar: '#8B2DE8',
};

const EnviarWorkspace = ({ canais, user, onChange, campId }) => {
  const [sel, setSel] = React.useState(canais[0]?.canal_pai || null);
  const selCanal = canais.find(c => c.canal_pai === sel) || canais[0];
  if (!selCanal) return <ActEmptyState icon="○" title="Sem canais de envio" sub="Esta campanha não tem canais directos activos." />;

  return (
    <div style={{ display:'flex', gap:0, minHeight:500, borderRadius:8, border:'1px solid var(--border)', overflow:'hidden', background:'var(--bg-elev)' }}>

      {/* Lista 30% */}
      <div style={{ width:'30%', minWidth:200, borderRight:'1px solid var(--border)', display:'flex', flexDirection:'column', overflowY:'auto' }}>
        {canais.map(c => {
          const isSel  = c.canal_pai === sel;
          const est    = CANAL_ESTADO_UI[c.estado] || CANAL_ESTADO_UI.em_producao;
          const accent = _ENV_ACCENT[c.canal_pai] || '#64748b';
          return (
            <div key={c.canal_pai} onClick={() => setSel(c.canal_pai)} style={{
              padding:'14px 18px', cursor:'pointer',
              borderLeft:`3px solid ${isSel ? accent : 'transparent'}`,
              background: isSel ? `${accent}12` : 'transparent',
              borderBottom:'1px solid var(--border)', transition:'background 120ms',
            }}>
              <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:4 }}>
                <span style={{ fontSize:13, fontWeight:isSel?700:500, color:'var(--text)' }}>
                  {canalLabel(c.canal_pai)}
                </span>
                <span style={{ fontSize:10, fontWeight:600, padding:'2px 7px', borderRadius:99, color:est.color, background:est.bg, fontFamily:'var(--font-mono,monospace)' }}>
                  {est.label}
                </span>
              </div>
              <div style={{ fontSize:11, color:'var(--text-muted)', fontFamily:'var(--font-mono,monospace)' }}>
                {c.n_variacoes} variação{c.n_variacoes !== 1 ? 'ões' : ''}
              </div>
            </div>
          );
        })}
      </div>

      {/* Painel de envio 70% */}
      <div style={{ flex:1, display:'flex', flexDirection:'column', minWidth:0, padding:'24px 28px', overflowY:'auto', gap:16 }}>
        {selCanal.canal_pai === 'whatsapp'
          ? <WACanal c={selCanal} user={user} campId={campId} onChange={onChange} />
          : <div style={{ padding:40, color:'var(--text-muted)', fontSize:13 }}>
              {canalLabel(selCanal.canal_pai)} — em construção
            </div>
        }
      </div>
    </div>
  );
};

const CanalSection = ({ title, canais, user, onOpen, onChange, campId }) => {
  const [collapsed, setCollapsed] = React.useState(false);
  const nA = canais.filter(c => ['aprovado','agendado','em_publicacao','publicado'].includes(c.estado)).length;
  const nF = canais.filter(c => c.estado === 'com_falhas').length;
  const nR = canais.filter(c => c.estado === 'aguarda_aprovacao').length;
  return (
    <div style={{ borderRadius:8, border:'1px solid var(--border)', overflow:'hidden' }}>
      <div onClick={() => setCollapsed(!collapsed)} style={{ padding:'12px 20px', background:'var(--bg-elev)', cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'space-between' }}>
        <div style={{ display:'flex', alignItems:'center', gap:12 }}>
          <h3 style={{ fontFamily:'var(--font-display)', fontSize:15, fontWeight:600, color:'var(--text)', margin:0 }}>{title}</h3>
          <div style={{ display:'flex', gap:6, fontSize:11, fontFamily:'var(--font-mono,monospace)', color:'var(--text-muted)' }}>
            <span>{canais.length} canais</span>
            {nA > 0 && <span>· {nA} aprovados</span>}
            {nR > 0 && <span style={{ color:'#F59E0B' }}>· {nR} aguardam</span>}
            {nF > 0 && <span style={{ color:'#EF4444' }}>· {nF} falhas</span>}
          </div>
        </div>
        <button style={{ background:'transparent', border:'none', color:'var(--text-muted)', cursor:'pointer' }}>{collapsed?'▶':'▼'}</button>
      </div>
      {!collapsed && (
        <div style={{ display:'flex', flexDirection:'column', gap:12, padding:'16px 20px', background:'var(--bg)' }}>
          {canais.map(c => <CanalCard key={c.canal_pai} c={c} user={user} onOpen={() => onOpen(c.canal_pai)} onChange={onChange} campId={campId} />)}
        </div>
      )}
    </div>
  );
};

const CampanhaMenu = ({ campId, pausada, user, onChange }) => {
  const [open, setOpen] = React.useState(false);
  const toggle = async () => {
    if (pausada) await ActAPI.campanhaRetomar(campId, user.email, user.name);
    else         await ActAPI.campanhaPausar(campId, user.email, user.name, null);
    onChange(); setOpen(false);
  };
  return (
    <div style={{ position:'relative' }}>
      <button onClick={() => setOpen(!open)} style={{ padding:'6px 12px', background:'transparent', border:'1px solid var(--border)', borderRadius:6, cursor:'pointer' }}>⋯</button>
      {open && (
        <div style={{ position:'absolute', right:0, top:'100%', marginTop:4, background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:6, minWidth:180, zIndex:10, boxShadow:'0 4px 12px rgba(0,0,0,0.15)' }}>
          <button onClick={toggle} style={{ display:'block', width:'100%', textAlign:'left', padding:'10px 14px', background:'transparent', border:'none', cursor:'pointer', color:'var(--text)' }}>
            {pausada ? 'Retomar campanha' : 'Pausar campanha'}
          </button>
        </div>
      )}
    </div>
  );
};

const CampanhaDetalhe = ({ campId, tab, user, onBack, onOpenCanal }) => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [subTab, setSubTab] = React.useState(tab || 'publicar');
  React.useEffect(() => setSubTab(tab||'publicar'), [tab]);

  const reload = React.useCallback(async () => {
    try { setError(null); const d = await ActAPI.campanhaDetalhe(campId, user.email); setData(d); }
    catch (e) { setError(e.message); }
    finally { setLoading(false); }
  }, [campId, user.email]);
  React.useEffect(() => { setLoading(true); reload(); }, [reload]);
  React.useEffect(() => { const t = setInterval(reload, 30000); return () => clearInterval(t); }, [reload]);

  const subInfoL2 = data?.kpis
    ? [
        data.kpis.n_canais > 0 ? `${data.kpis.n_canais} canal${data.kpis.n_canais !== 1 ? 'ais' : ''}` : null,
        data.kpis.n_aprovados > 0 ? `${data.kpis.n_aprovados} aprovado${data.kpis.n_aprovados !== 1 ? 's' : ''}` : null,
        data.kpis.n_aguarda > 0   ? `${data.kpis.n_aguarda} aguarda` : null,
        data.kpis.n_falhas > 0    ? `${data.kpis.n_falhas} falha${data.kpis.n_falhas !== 1 ? 's' : ''}` : null,
      ].filter(Boolean).join(' · ')
    : null;

  return (
    <div style={{ display:'flex', flexDirection:'column', height:'100%', minHeight:0 }}>
      <ActivacaoHeaderNew
        level={2}
        breadcrumb={[{ label:'Marketing' }, { label:'Activação', onClick: onBack }, { label: data?.campanha?.titulo || campId.slice(0,8) }]}
        title={data?.campanha?.titulo || 'A carregar…'}
        subInfo={subInfoL2}
        subNav={CAMPANHA_SUBNAV}
        subNavActive={subTab}
        onSubNav={id => { setSubTab(id); setActivacaoHash({ tab: id }); }}
        extraMenu={data?.campanha && <CampanhaMenu campId={campId} pausada={!!data.pausa} user={user} onChange={reload} />}
      />
      <div className="scrollbar" style={{ flex:1, minHeight:0, overflowY:'auto', overflowX:'clip', padding:'28px 40px 0', background:'var(--bg, #f8fafc)' }}>
        {loading && <ActSpinner />}
        {error && <ActEmptyState icon="⚠" title="Erro a carregar" sub={error} />}
        {!loading && !error && data && subTab === 'publicar' && (
          <PublicarWorkspace canais={data.canais_publicar} user={user} onOpen={onOpenCanal} onChange={reload} campId={data.campanha.id} />
        )}
        {!loading && !error && data && subTab === 'enviar' && (
          data.canais_enviar.length > 0
            ? <EnviarWorkspace canais={data.canais_enviar} user={user} onChange={reload} campId={data.campanha.id} />
            : <ActEmptyState icon="○" title="Sem canais de envio" sub="Esta campanha não tem canais directos (WhatsApp, Email) activos." />
        )}
        {!loading && !error && data && subTab === 'timeline' && <div style={{ padding:40, color:'var(--text-muted)' }}>Timeline — sprint futuro</div>}
        {!loading && !error && data && subTab === 'metricas'  && <div style={{ padding:40, color:'var(--text-muted)' }}>Métricas — ver módulo Performance</div>}
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// NÍVEL 3 — Detalhe do canal
// ═══════════════════════════════════════════════════════════════════════════════
const CANAL_SUBNAV = [
  { id:'variacoes',   label:'Variações' },
  { id:'setup',       label:'Setup' },
  { id:'segmentacao', label:'Segmentação' },
  { id:'log',         label:'Log' },
];

const RejectReasonDialog = ({ pecaId, user, onCancel, onDone }) => {
  const [category, setCategory] = React.useState('');
  const [reason, setReason] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const CATS = [{ id:'off_brand',label:'Off-brand' },{ id:'texto_errado',label:'Texto errado' },{ id:'imagem_qualidade',label:'Imagem má qualidade' },{ id:'audiencia',label:'Problema audiência' },{ id:'outro',label:'Outro' }];
  const doSubmit = async () => {
    if (!category) { alert('Selecciona uma categoria'); return; }
    setLoading(true);
    try { await ActAPI.rejeitar(pecaId, user.email, user.name, reason, category); onDone(); }
    catch (e) { alert(`Erro: ${e.message}`); }
    finally { setLoading(false); }
  };
  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.5)', zIndex:100, display:'flex', alignItems:'center', justifyContent:'center' }} onClick={onCancel}>
      <div style={{ background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:8, padding:24, minWidth:400, maxWidth:500 }} onClick={e => e.stopPropagation()}>
        <h3 style={{ fontFamily:'var(--font-display)', fontSize:17, fontWeight:600, marginTop:0 }}>Rejeitar variação</h3>
        <label style={{ display:'block', fontSize:12, color:'var(--text-muted)', marginBottom:6 }}>Categoria</label>
        <select value={category} onChange={e => setCategory(e.target.value)} style={{ width:'100%', padding:'8px 12px', borderRadius:6, border:'1px solid var(--border)', background:'var(--bg)', color:'var(--text)', marginBottom:12 }}>
          <option value="">— Selecciona —</option>
          {CATS.map(c => <option key={c.id} value={c.id}>{c.label}</option>)}
        </select>
        <label style={{ display:'block', fontSize:12, color:'var(--text-muted)', marginBottom:6 }}>Nota (opcional)</label>
        <textarea value={reason} onChange={e => setReason(e.target.value)} rows={3} style={{ width:'100%', padding:'8px 12px', borderRadius:6, border:'1px solid var(--border)', background:'var(--bg)', color:'var(--text)', resize:'vertical', boxSizing:'border-box' }} />
        <div style={{ display:'flex', gap:8, justifyContent:'flex-end', marginTop:16 }}>
          <button onClick={onCancel} className="btn btn-sm" disabled={loading}>Cancelar</button>
          <button onClick={doSubmit} className="btn btn-sm" style={{ color:'#EF4444' }} disabled={loading}>{loading ? 'A rejeitar…' : 'Rejeitar'}</button>
        </div>
      </div>
    </div>
  );
};

const VariacaoCard = ({ v, user, onChange }) => {
  const est = ACT_STATUS[v.status] || ACT_STATUS.pending;
  const thumb = v.composed_urls ? Object.values(v.composed_urls)[0] : null;
  const thumbUrl = thumb && typeof thumb === 'object' ? Object.values(thumb)[0] : thumb;
  const [rejecting, setRejecting] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const [showFailure, setShowFailure] = React.useState(false);
  const doAprovar = async () => {
    setLoading(true);
    try { await ActAPI.aprovar(v.id, user.email, user.name); onChange(); }
    catch (e) { alert(`Erro: ${e.message}`); }
    finally { setLoading(false); }
  };
  return (
    <div style={{ border:'1px solid var(--border)', borderRadius:8, background:'var(--bg-elev)', padding:16, display:'flex', gap:20 }}>
      <div style={{ width:200, height:200, background:'var(--bg)', borderRadius:6, flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', overflow:'hidden' }}>
        {thumbUrl ? <img src={thumbUrl} alt="preview" style={{ maxWidth:'100%', maxHeight:'100%', objectFit:'contain' }} /> : <div style={{ color:'var(--text-dim)', fontSize:11 }}>sem preview</div>}
      </div>
      <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:6 }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
          <div style={{ fontFamily:'var(--font-display)', fontSize:14, fontWeight:600 }}>{v.content_type} {v.ratio ? `· ${v.ratio}` : ''} {v.canal_filho ? `· ${v.canal_filho}` : ''}</div>
          <ActStatusBadge status={v.status} />
        </div>
        <div style={{ fontSize:12, color:'var(--text-muted)', lineHeight:1.7 }}>
          {v.headline && <div><b style={{ color:'var(--text)' }}>Headline:</b> {v.headline}</div>}
          {v.cta      && <div><b style={{ color:'var(--text)' }}>CTA:</b> {v.cta}</div>}
          {v.url_destino && <div><b style={{ color:'var(--text)' }}>URL:</b> {v.url_destino}</div>}
          {v.modelo   && <div><b style={{ color:'var(--text)' }}>Modelo:</b> {v.modelo}</div>}
          {v.approved_by_email && <div style={{ color:'#10B981', fontSize:11, marginTop:6 }}>✓ Aprovada por {v.approved_by_email} · {fmtDate(v.approved_at)}</div>}
          {v.rejected_by_email && <div style={{ color:'#EF4444', fontSize:11, marginTop:6 }}>✗ Rejeitada por {v.rejected_by_email} — {v.rejection_category}</div>}
        </div>
        <div style={{ display:'flex', gap:8, marginTop:8 }}>
          {v.status === 'ready_review' && (
            <>
              <button onClick={() => setRejecting(true)} className="btn btn-xs" style={{ padding:'6px 12px', color:'#EF4444' }}>Rejeitar</button>
              <button onClick={doAprovar} disabled={loading} className="btn btn-xs btn-ai" style={{ padding:'6px 12px' }}>{loading?'A aprovar…':'Aprovar →'}</button>
            </>
          )}
          {v.status === 'failed_publish' && <button onClick={() => setShowFailure(true)} className="btn btn-xs" style={{ padding:'6px 12px', color:'#EF4444' }}>Ver erro</button>}
        </div>
      </div>
      {rejecting && <RejectReasonDialog pecaId={v.id} user={user} onCancel={() => setRejecting(false)} onDone={() => { setRejecting(false); onChange(); }} />}
      {showFailure && (
        <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.5)', zIndex:100, display:'flex', alignItems:'center', justifyContent:'center' }} onClick={() => setShowFailure(false)}>
          <div style={{ background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:8, padding:24, minWidth:500, maxWidth:700 }} onClick={e => e.stopPropagation()}>
            <h3 style={{ color:'#EF4444', marginTop:0 }}>⚠ Detalhe da falha</h3>
            <div style={{ background:'var(--bg)', padding:12, borderRadius:6, fontFamily:'var(--font-mono,monospace)', fontSize:11, color:'#EF4444', maxHeight:300, overflow:'auto' }}>{v.last_publish_error || 'Sem detalhes.'}</div>
            <div style={{ display:'flex', gap:8, justifyContent:'flex-end', marginTop:16 }}>
              <button onClick={() => setShowFailure(false)} className="btn btn-sm">Fechar</button>
              <button onClick={async () => { try { await ActAPI.retry(v.id, user.email); onChange(); } catch(e) { alert(e.message); } setShowFailure(false); }} className="btn btn-sm btn-ai">Retry</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

const AprovarCanalBar = ({ canalPai, campId, n, user, onChange }) => {
  const [confirming, setConfirming] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const doAprovar = async () => {
    setLoading(true);
    try { await ActAPI.canalAprovarBulk(campId, canalPai, user.email, user.name); onChange(); }
    catch (e) { alert(`Erro: ${e.message}`); }
    finally { setLoading(false); setConfirming(false); }
  };
  return (
    <div style={{ display:'flex', gap:8, justifyContent:'flex-end', padding:'16px 0', borderTop:'1px solid var(--border)' }}>
      <button className="btn btn-sm" style={{ color:'#EF4444' }}>Rejeitar canal inteiro</button>
      <button onClick={() => setConfirming(true)} className="btn btn-sm btn-ai">Aprovar todas as variações e agendar →</button>
      {confirming && <ApprovalConfirmDialog n={n} modo="publicar" onCancel={() => setConfirming(false)} onConfirm={doAprovar} loading={loading} />}
    </div>
  );
};

const CanalDetalhe = ({ campId, canalPai, tab, user, onBack }) => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [subTab, setSubTab] = React.useState(tab || 'variacoes');
  React.useEffect(() => setSubTab(tab||'variacoes'), [tab]);

  const reload = React.useCallback(async () => {
    try { setError(null); const d = await ActAPI.canalDetalhe(campId, canalPai, user.email); setData(d); }
    catch (e) { setError(e.message); }
    finally { setLoading(false); }
  }, [campId, canalPai, user.email]);
  React.useEffect(() => { setLoading(true); reload(); }, [reload]);

  const CANAIS_ENVIAR = ['email','whatsapp','muppi_led','novastar'];
  const subInfoL3 = data
    ? `${data.variacoes.length} variação${data.variacoes.length !== 1 ? 'ões' : ''} · modo ${CANAIS_ENVIAR.includes(canalPai) ? 'enviar' : 'publicar'}`
    : null;

  return (
    <div style={{ display:'flex', flexDirection:'column', height:'100%', minHeight:0 }}>
      <ActivacaoHeaderNew
        level={3}
        breadcrumb={[
          { label:'Marketing' },
          { label:'Activação', onClick: () => { window.location.hash = '#screen=marketing&sub=activacao'; } },
          { label: data?.campanha?.titulo || campId.slice(0,8), onClick: onBack },
          { label: canalLabel(canalPai) },
        ]}
        title={`${canalLabel(canalPai)} · ${data?.campanha?.titulo || ''}`}
        subInfo={subInfoL3}
        subNav={CANAL_SUBNAV}
        subNavActive={subTab}
        onSubNav={id => { setSubTab(id); setActivacaoHash({ tab: id }); }}
      />
      <div className="scrollbar" style={{ flex:1, minHeight:0, overflowY:'auto', overflowX:'clip', padding:'28px 40px 0', background:'var(--bg, #f8fafc)' }}>
        {loading && <ActSpinner />}
        {error && <ActEmptyState icon="⚠" title="Erro a carregar" sub={error} />}
        {!loading && !error && data && subTab === 'variacoes' && (
          <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
            {data.variacoes.map(v => <VariacaoCard key={v.id} v={v} user={user} onChange={reload} />)}
            {data.variacoes.filter(v => v.status==='ready_review').length > 0 && (
              <AprovarCanalBar canalPai={canalPai} campId={campId} n={data.variacoes.filter(v => v.status==='ready_review').length} user={user} onChange={reload} />
            )}
          </div>
        )}
        {!loading && !error && data && subTab === 'setup' && (
          <div style={{ maxWidth:600, background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:8, padding:24 }}>
            <h3 style={{ fontFamily:'var(--font-display)', fontSize:16, fontWeight:600, margin:'0 0 16px' }}>Setup do canal (leitura)</h3>
            <div style={{ display:'grid', gridTemplateColumns:'160px 1fr', gap:'8px 16px', fontSize:13 }}>
              {[
                ['Audiência', data.variacoes[0]?.setup_payload?.audience || '—'],
                ['Budget', data.variacoes[0]?.setup_payload?.budget ? `${data.variacoes[0].setup_payload.budget}€` : '—'],
                ['Placement', data.variacoes[0]?.setup_payload?.placement || '—'],
                ['Modelo', data.variacoes[0]?.modelo || '—'],
                ['Ratio', data.variacoes[0]?.ratio || '—'],
              ].map(([k,v],i) => (
                <React.Fragment key={i}>
                  <div style={{ color:'var(--text-muted)' }}>{k}</div>
                  <div style={{ color:'var(--text)' }}>{v}</div>
                </React.Fragment>
              ))}
            </div>
          </div>
        )}
        {!loading && !error && data && subTab === 'segmentacao' && (
          <div style={{ maxWidth:700, background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:8, padding:24 }}>
            <h3 style={{ fontFamily:'var(--font-display)', fontSize:16, fontWeight:600, margin:'0 0 16px' }}>Segmentação</h3>
            <div style={{ fontSize:13, marginBottom:8 }}><b>Descrição:</b> {data.variacoes[0]?.segmentacao_payload?.descricao || '—'}</div>
            <div style={{ fontSize:13, marginBottom:8 }}><b>Contagem:</b> {data.variacoes[0]?.segmentacao_payload?.contagem || '—'}</div>
          </div>
        )}
        {!loading && !error && data && subTab === 'log' && (
          <div style={{ maxWidth:800 }}>
            <h3 style={{ fontFamily:'var(--font-display)', fontSize:16, fontWeight:600, marginTop:0 }}>Timeline ({data.logs.length} eventos)</h3>
            {data.logs.length === 0
              ? <ActEmptyState icon="○" title="Sem eventos" sub="Ainda não há registos de acções neste canal." />
              : data.logs.map(l => (
                  <div key={l.id} style={{ padding:'10px 14px', background:'var(--bg-elev)', border:'1px solid var(--border)', borderRadius:6, marginBottom:8 }}>
                    <div style={{ display:'flex', justifyContent:'space-between', fontSize:11, color:'var(--text-muted)' }}>
                      <span style={{ fontFamily:'var(--font-mono,monospace)' }}>{l.event_type}</span>
                      <span>{fmtDate(l.created_at)}</span>
                    </div>
                    <div style={{ fontSize:12, color:'var(--text)', marginTop:4 }}>{l.actor_name || l.actor_email}</div>
                  </div>
                ))}
          </div>
        )}
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════════════
// ROOT SHELL — 3 níveis via URL hash
// ═══════════════════════════════════════════════════════════════════════════════
const MktActivacaoScreen = () => {
  const [hashState, setHashState] = React.useState(parseActivacaoHash());
  React.useEffect(() => {
    const onHash = () => setHashState(parseActivacaoHash());
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  const { camp, canal, view, tab } = hashState;
  const user = React.useMemo(() => getCurrentUser(), []);

  return (
    <div className="scrollbar" style={{ height:'100%', display:'flex', flexDirection:'column' }}>
      <style>{`
        @keyframes spin     { to { transform: rotate(360deg); } }
        @keyframes pulse    { 0%,100% { opacity: 1; } 50% { opacity: 0.55; } }
        @keyframes slide-up { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
      `}</style>
      {camp && canal
        ? <CanalDetalhe campId={camp} canalPai={canal} tab={tab||'variacoes'} user={user} onBack={() => setActivacaoHash({ canal:null, tab:null })} />
        : camp
        ? <CampanhaDetalhe campId={camp} tab={tab||'publicar'} user={user} onBack={() => setActivacaoHash({ camp:null, tab:null })} onOpenCanal={c => setActivacaoHash({ canal:c, tab:null })} />
        : <Nivel1Home view={view||'kanban'} user={user} onChangeView={v => setActivacaoHash({ view:v })} onOpenCampanha={id => setActivacaoHash({ camp:id, tab:null })} />
      }
    </div>
  );
};

window.MktActivacaoScreen = MktActivacaoScreen;
