/* ── CARTEIRA DETAIL VIEW ─────────────────────────────────────────────────
   Shows full per-carteira detail: KPIs, history chart, asset table
   ─────────────────────────────────────────────────────────────────────── */

function CarteiraView({ month, nome, allMonths, onBack }) {
  const [tab, setTab] = React.useState('resumo');
  const [obsText, setObsText] = React.useState('');
  const [obsSaved, setObsSaved] = React.useState(null);
  const [obsEditing, setObsEditing] = React.useState(false);
  const [quotesTick, setQuotesTick] = React.useState(0);

  React.useEffect(() => {
    if (!month || !nome) return;
    const o = Store.getObservacao(month.key, nome);
    setObsText(o?.texto || '');
    setObsSaved(o);
    setObsEditing(false);
  }, [month?.key, nome]);

  // Buscar cotacoes via Brapi quando a aba Composicao for aberta
  React.useEffect(() => {
    if (tab !== 'ativos' || !month || !nome) return;
    const c = month.carteiras?.[nome];
    if (!c) return;
    const TICKER_RE = /\b([A-Z]{4}\d{1,2})\b/;
    const tickers = Array.from(new Set(
      (c.ativos || [])
        .filter(a => a.type === 'ativo')
        .map(a => (a.nome || '').match(TICKER_RE)?.[1])
        .filter(Boolean)
    ));
    if (!tickers.length || typeof window.fetchQuotes !== 'function') return;
    window.fetchQuotes(tickers).then(() => setQuotesTick(t => t + 1));
  }, [tab, month?.key, nome]);

  function saveObs() {
    Store.setObservacao(month.key, nome, obsText);
    setObsSaved(obsText ? { texto: obsText, atualizadoEm: new Date().toISOString() } : null);
    setObsEditing(false);
  }
  function cancelObs() {
    setObsText(obsSaved?.texto || '');
    setObsEditing(false);
  }

  if (!month || !nome) return null;
  const c = month.carteiras[nome];
  if (!c) return <div className="empty-state"><p>Carteira não encontrada: {nome}</p></div>;

  // Build historical series across all months (sorted oldest→newest)
  const history = allMonths
    .slice()
    .sort((a, b) => a.key.localeCompare(b.key))
    .map(m => {
      const mc = m.carteiras[nome];
      return mc ? { key: m.key, label: m.label.replace(' 20', " '"), value: mc.plAtual, rent: mc.rentMes, status: mc.status } : null;
    })
    .filter(Boolean);

  const chartData = history.map(h => ({ key: h.key, label: h.label, value: h.value, rent: h.rent || 0 }));

  const erros   = c.erros   !== '-' ? c.erros.split(' | ')   : [];
  const alertas = c.alertas !== '-' ? c.alertas.split(' | ') : [];
  const lims    = c.limitacoes !== '-' ? c.limitacoes.split(' | ') : [];
  const isClean = erros.length === 0 && alertas.length === 0 && lims.length === 0;

  const classes = (c.ativos || []).filter(a => a.type === 'classe');
  const ativos  = (c.ativos || []).filter(a => a.type === 'ativo');
  const saidas  = (c.ativos || []).filter(a => a.type === 'saida');

  return (
    <div>
      {/* Header */}
      <div style={{ background: 'var(--white)', border: '1px solid var(--rule)', marginBottom: 1, padding: '20px 24px 0' }}>
        <div className="detail-back" onClick={onBack}><Icon.back /> Voltar ao painel</div>
        <div className="detail-header-row" style={{ display: 'flex', alignItems: 'flex-end', gap: 16, paddingBottom: 16 }}>
          <div>
            <h2 style={{ fontFamily: 'Cormorant Garamond, serif', fontSize: '1.8rem', marginBottom: 4 }}>{c.nome}</h2>
            <div style={{ display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' }}>
              <span className={`badge ${statusBadge(c.status)}`}>{c.status}</span>
              <span style={{ fontSize: '0.68rem', color: 'var(--muted)' }}>{month.label} · Extrato {month.dataExtrato}</span>
            </div>
          </div>
          <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
            <button className="btn btn-secondary btn-sm" onClick={() => exportCarteiraHTML(c, month, allMonths)}>
              <Icon.export /> Exportar PDF
            </button>
          </div>
        </div>

        {/* Tabs */}
        <div className="detail-tabs" style={{ display: 'flex', gap: 0, borderTop: '1px solid var(--rule)', marginTop: 4 }}>
          {[['resumo','Resumo'],['historico','Histórico'],['ativos','Composição'],['achados','Achados']].map(([id, label]) => (
            <button key={id} onClick={() => setTab(id)} style={{
              padding: '10px 18px', fontSize: '0.72rem', fontWeight: 500, letterSpacing: '0.04em',
              borderBottom: tab === id ? '2px solid var(--navy)' : '2px solid transparent',
              color: tab === id ? 'var(--navy)' : 'var(--muted)',
              background: 'transparent',
              transition: 'all 0.12s',
            }}>{label}</button>
          ))}
        </div>
      </div>

      {/* ── TAB: RESUMO ── */}
      {tab === 'resumo' && (
        <div>
          {/* KPI grid */}
          <div className="detail-kpis">
            {[
              { label: 'PL Anterior', value: fmtBRL(c.plAnterior, true), sub: month.baselineLabel },
              { label: 'PL Atual',    value: fmtBRL(c.plAtual, true),    sub: month.label },
              { label: 'Variação R$', value: fmtBRL(c.varRS, true), sub: '', cls: colorClass(c.varRS) },
              { label: 'Variação %',  value: fmtPct(c.varPct),            sub: '', cls: colorClass(c.varPct) },
              { label: 'Rent. Mês',   value: fmtPct(c.rentMes),           sub: month.label, cls: colorClass(c.rentMes) },
              { label: 'Continuidade', value: fmtPct(c.continuidade), sub: 'tolerância 0,30%', cls: (c.continuidade||0)>0.003 ? 'tbl-neg' : '' },
              (() => {
                const roaCliente = (window.ROA_DATA?.clientes || []).find(rc => rc.cliente === c.nome);
                return {
                  label: 'Receita YTD (XLSX ROA)',
                  value: roaCliente ? fmtBRL(roaCliente.receitaYTD, true) : '—',
                  sub: roaCliente ? `Fee + rebates Ex-Mirabaud · ${roaCliente.gerente}` : 'sem match em ROA',
                  cls: roaCliente ? '' : 'tbl-nt',
                };
              })(),
              { label: 'Ativos Mar',  value: c.nAtivosMar || '—', sub: '' },
              { label: 'Ativos Abr',  value: c.nAtivosAbr || '—', sub: '' },
            ].map((k, i) => (
              <div className="detail-kpi" key={i}>
                <div className="detail-kpi-label">{k.label}</div>
                <div className={`detail-kpi-value ${k.cls||''}`}>{k.value}</div>
                {k.sub && <div style={{ fontSize: '0.62rem', color: 'var(--muted)', marginTop: 2 }}>{k.sub}</div>}
              </div>
            ))}
          </div>

          {/* Composição AUM + Receita por origem (Mirabaud vs Ex-Mirabaud) */}
          {(() => {
            const rc = (window.ROA_DATA?.clientes || []).find(x => x.cliente === c.nome);
            if (!rc) return null;
            // Taxas anuais oficiais dos fundos proprios da Mirabaud:
            // Tradition 0,50% · Conviction 0,60% · Debentures Incentivadas 0,80% · Previdencia 0,80%
            const TAXA = { tradition: 0.005, conviction: 0.006, debInc: 0.008, prev: 0.008 };
            const recTrad = (rc.tradition || 0) * TAXA.tradition;
            const recConv = (rc.conviction || 0) * TAXA.conviction;
            const recDeb  = (rc.debInc || 0)    * TAXA.debInc;
            const recPrev = (rc.prev || 0)      * TAXA.prev;
            const recProprios = recTrad + recConv + recDeb + recPrev;
            const proprios = (rc.tradition || 0) + (rc.conviction || 0) + (rc.debInc || 0) + (rc.prev || 0);
            const exMir = Math.max(0, rc.aum - proprios);
            const total = proprios + exMir;
            if (total <= 0) return null;
            const pctProp = (proprios / total) * 100;
            const pctEx = (exMir / total) * 100;
            // Fee declarado sobre Ex-Mirabaud (anual)
            const recExMirFee = exMir * (rc.fee || 0);
            // Receita YTD da planilha = Fee Ex-Mirabaud + rebates e outros
            // Rebates = ROA total cobrado − Fee Ex-Mirabaud declarado
            const recYTDtotal = rc.receitaYTD || 0;
            const recRebates = Math.max(0, recYTDtotal - recExMirFee);
            const recExMirTotal = recExMirFee + recRebates;
            const recTotalCarteira = recProprios + recExMirTotal;
            return (
              <div className="card" style={{ marginTop: 16 }}>
                <div className="card-header">
                  <h3>Receita 2025 por origem · Mirabaud vs Ex-Mirabaud</h3>
                  <span style={{ fontSize: '0.7rem', color: 'var(--muted)' }}>fee não cobrado em duplicidade</span>
                </div>
                <div style={{ padding: '18px 20px' }}>
                  {/* Barra de AUM */}
                  <div style={{ fontSize: '0.62rem', fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 6 }}>
                    Composição do AUM
                  </div>
                  <div style={{ display: 'flex', height: 22, borderRadius: 'var(--r-sm)', overflow: 'hidden', border: '1px solid var(--rule)', marginBottom: 18 }}>
                    {proprios > 0 && (
                      <div style={{ width: `${pctProp}%`, background: 'var(--gold)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--white)', fontSize: '0.7rem', fontWeight: 600 }}>
                        {pctProp >= 8 && `${pctProp.toFixed(1)}%`}
                      </div>
                    )}
                    {exMir > 0 && (
                      <div style={{ width: `${pctEx}%`, background: 'var(--navy)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--white)', fontSize: '0.7rem', fontWeight: 600 }}>
                        {pctEx >= 8 && `${pctEx.toFixed(1)}%`}
                      </div>
                    )}
                  </div>

                  {/* Detalhamento de receita */}
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
                    {/* Coluna Mirabaud */}
                    <div style={{ borderLeft: '3px solid var(--gold)', paddingLeft: 14 }}>
                      <div style={{ fontSize: '0.62rem', fontWeight: 600, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 4 }}>Produtos Mirabaud</div>
                      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 4 }}>
                        <span style={{ fontFamily: 'Cormorant Garamond, serif', fontSize: '1.3rem', fontWeight: 500, color: 'var(--heading)' }}>{fmtBRL(proprios, true)}</span>
                        <span style={{ fontSize: '0.66rem', color: 'var(--muted)' }}>AUM</span>
                      </div>
                      <div style={{ fontSize: '0.85rem', color: 'var(--gold)', fontWeight: 600, fontFamily: 'JetBrains Mono, monospace', marginBottom: 10 }}>
                        Receita {fmtBRL(recProprios, true)}
                      </div>
                      {proprios > 0 ? (
                        <table style={{ width: '100%', fontSize: '0.7rem', fontFamily: 'JetBrains Mono, monospace' }}>
                          <tbody>
                            {rc.tradition > 0 && <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Tradition</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>{fmtBRL(rc.tradition)}</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--gold)' }}>+{fmtBRL(recTrad)}</td>
                            </tr>}
                            {rc.conviction > 0 && <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Conviction</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>{fmtBRL(rc.conviction)}</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--gold)' }}>+{fmtBRL(recConv)}</td>
                            </tr>}
                            {rc.debInc > 0 && <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Deb. Incentivadas</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>{fmtBRL(rc.debInc)}</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--gold)' }}>+{fmtBRL(recDeb)}</td>
                            </tr>}
                            {rc.prev > 0 && <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Previdência</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>{fmtBRL(rc.prev)}</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--gold)' }}>+{fmtBRL(recPrev)}</td>
                            </tr>}
                          </tbody>
                        </table>
                      ) : (
                        <div style={{ fontSize: '0.72rem', color: 'var(--muted)', fontStyle: 'italic' }}>nenhum produto próprio nesta carteira</div>
                      )}
                      <div style={{ fontSize: '0.6rem', color: 'var(--muted)', marginTop: 8, fontStyle: 'italic' }}>
                        Tradition 0,50% · Conviction 0,60% · Deb Inc 0,80% · Prev 0,80%
                      </div>
                    </div>

                    {/* Coluna Ex-Mirabaud */}
                    <div style={{ borderLeft: '3px solid var(--navy)', paddingLeft: 14 }}>
                      <div style={{ fontSize: '0.62rem', fontWeight: 600, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--muted)', marginBottom: 4 }}>Produtos Ex-Mirabaud</div>
                      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 4 }}>
                        <span style={{ fontFamily: 'Cormorant Garamond, serif', fontSize: '1.3rem', fontWeight: 500, color: 'var(--heading)' }}>{fmtBRL(exMir, true)}</span>
                        <span style={{ fontSize: '0.66rem', color: 'var(--muted)' }}>AUM</span>
                      </div>
                      <div style={{ fontSize: '0.85rem', color: 'var(--navy)', fontWeight: 600, fontFamily: 'JetBrains Mono, monospace', marginBottom: 10 }}>
                        Receita {fmtBRL(recExMirTotal, true)}
                      </div>
                      {exMir > 0 ? (
                        <table style={{ width: '100%', fontSize: '0.7rem', fontFamily: 'JetBrains Mono, monospace' }}>
                          <tbody>
                            <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Fee {(rc.fee*100).toFixed(2)}% a.a.</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>{fmtBRL(exMir)}</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--navy)' }}>+{fmtBRL(recExMirFee)}</td>
                            </tr>
                            {recRebates > 0.01 && <tr>
                              <td style={{ padding: '2px 0', color: 'var(--body)' }}>Rebates e outros</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--muted)' }}>—</td>
                              <td style={{ textAlign: 'right', padding: '2px 0', color: 'var(--navy)' }}>+{fmtBRL(recRebates)}</td>
                            </tr>}
                          </tbody>
                        </table>
                      ) : (
                        <div style={{ fontSize: '0.72rem', color: 'var(--muted)', fontStyle: 'italic' }}>carteira sem alocação ex-Mirabaud</div>
                      )}
                      <div style={{ fontSize: '0.6rem', color: 'var(--muted)', marginTop: 8, fontStyle: 'italic' }}>
                        Fee declarado + ajuste para fechar com ROA real da planilha
                      </div>
                    </div>
                  </div>

                  {/* Total combinado */}
                  <div style={{ marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--rule)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <span style={{ fontSize: '0.7rem', fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--heading)' }}>
                      Receita Total Estimada 2025
                    </span>
                    <span style={{ fontFamily: 'Cormorant Garamond, serif', fontSize: '1.5rem', fontWeight: 600, color: 'var(--heading)' }}>
                      {fmtBRL(recTotalCarteira, true)}
                    </span>
                  </div>
                </div>
              </div>
            );
          })()}

          {/* Asset allocation */}
          {c.assetAllocation && c.assetAllocation.length > 0 && (
            <div className="card" style={{ marginTop: 16 }}>
              <div className="card-header"><h3>Asset Allocation</h3></div>
              <div style={{ padding: '0 20px' }}>
                {c.assetAllocation.map((a, i) => {
                  const pct = a.pct || (a.plAtual / c.plAtual * 100);
                  return (
                    <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0', borderBottom: i < c.assetAllocation.length - 1 ? '1px solid var(--rule)' : 'none' }}>
                      <div style={{ width: 120, fontSize: '0.78rem', fontWeight: 500, color: 'var(--heading)' }}>{a.classe}</div>
                      <div style={{ flex: 1, height: 4, background: 'var(--rule)', borderRadius: 2, overflow: 'hidden' }}>
                        <div style={{ width: `${Math.min(100, pct||0)}%`, height: '100%', background: 'var(--navy)', borderRadius: 2 }} />
                      </div>
                      <div style={{ width: 50, fontFamily: 'JetBrains Mono', fontSize: '0.72rem', textAlign: 'right', color: 'var(--body)' }}>{(pct||0).toFixed(1)}%</div>
                      <div style={{ width: 130, fontFamily: 'JetBrains Mono', fontSize: '0.72rem', textAlign: 'right', color: 'var(--muted)' }}>{fmtBRL(a.valor || a.plAtual)}</div>
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {/* Observação editável */}
          <div className="card" style={{ marginTop: 16 }}>
            <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--rule)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <span style={{ fontSize: '0.68rem', fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--muted)' }}>
                Observação · {month.label}
              </span>
              {!obsEditing && (
                <button className="btn btn-secondary btn-sm" onClick={() => setObsEditing(true)}>
                  {obsSaved ? 'Editar' : 'Adicionar observação'}
                </button>
              )}
            </div>
            <div style={{ padding: '14px 20px' }}>
              {obsEditing ? (
                <div>
                  <textarea
                    value={obsText}
                    onChange={e => setObsText(e.target.value)}
                    placeholder="Registre comentários sobre esta conciliação… (eventos relevantes, justificativas, decisões)"
                    style={{ width: '100%', minHeight: 100, padding: 12, border: '1px solid var(--rule)', fontSize: '0.85rem', fontFamily: 'Inter, sans-serif', resize: 'vertical', outline: 'none', color: 'var(--body)', lineHeight: 1.5 }}
                    autoFocus
                  />
                  <div style={{ display: 'flex', gap: 8, marginTop: 10, justifyContent: 'flex-end' }}>
                    <button className="btn btn-secondary btn-sm" onClick={cancelObs}>Cancelar</button>
                    <button className="btn btn-primary btn-sm" onClick={saveObs}><Icon.check /> Salvar</button>
                  </div>
                </div>
              ) : obsSaved ? (
                <div>
                  <div style={{ fontSize: '0.85rem', color: 'var(--body)', lineHeight: 1.55, whiteSpace: 'pre-wrap' }}>{obsSaved.texto}</div>
                  <div style={{ fontSize: '0.66rem', color: 'var(--muted)', marginTop: 8 }}>
                    Atualizado em {new Date(obsSaved.atualizadoEm).toLocaleString('pt-BR', { dateStyle: 'short', timeStyle: 'short' })}
                  </div>
                </div>
              ) : (
                <div style={{ fontSize: '0.82rem', color: 'var(--muted)', fontStyle: 'italic' }}>
                  {c.observacao || 'Nenhuma observação registrada.'}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ── TAB: HISTÓRICO ── */}
      {tab === 'historico' && (
        <div>
          <div className="card" style={{ marginTop: 16, overflow: 'hidden' }}>
            <div className="card-header" style={{ background: '#0D1520', border: 'none' }}>
              <h3 style={{ color: 'rgba(255,255,255,0.7)', fontFamily: 'Inter, sans-serif', fontSize: '0.78rem', fontWeight: 500, letterSpacing: '0.04em' }}>
                Retorno Acumulado
              </h3>
              <span style={{ fontSize: '0.68rem', color: 'rgba(255,255,255,0.35)' }}>{history.length} meses · Jan → {allMonths[0]?.label}</span>
            </div>
            <TVChart data={chartData} height={280} nome={c.nome} />
          </div>

          <div className="card" style={{ marginTop: 16 }}>
            <div className="card-header"><h3>Conciliações Mensais</h3></div>
            <div className="timeline">
              {history.slice().reverse().map((h, i) => (
                <div className="timeline-card" key={i}>
                  <div className="timeline-card-month">
                    <span>{h.label}</span>
                    <span className={`badge ${statusBadge(h.status)}`} style={{ fontSize: '0.55rem' }}>{h.status}</span>
                  </div>
                  <div className="timeline-card-pl" style={{ fontFamily: 'JetBrains Mono', fontSize: '0.82rem' }}>{fmtBRL(h.value)}</div>
                  <div className="timeline-card-meta" style={{ display: 'flex', gap: 10, marginTop: 4 }}>
                    <span>Rent. <span style={{ color: h.rent > 0 ? 'var(--green)' : h.rent < 0 ? 'var(--red)' : 'var(--muted)', fontFamily: 'JetBrains Mono', fontSize: '0.72rem' }}>{fmtPct(h.rent)}</span></span>
                    {window.BENCHMARKS?.monthly_cdi?.[h.key] && (
                      <span style={{ color: 'var(--muted)', fontSize: '0.68rem' }}>
                        CDI {fmtPct(window.BENCHMARKS.monthly_cdi[h.key])}
                      </span>
                    )}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}

      {/* ── TAB: COMPOSIÇÃO ── */}
      {tab === 'ativos' && (() => {
        const hasIndividualAtivos = (c.ativos || []).some(a => a.type === 'ativo' || a.type === 'saida');
        return (
          <div className="card" style={{ marginTop: 16 }}>
            {!hasIndividualAtivos && (
              <div style={{ padding: '14px 20px', background: 'var(--amber-bg)', borderBottom: '1px solid var(--rule)', display: 'flex', alignItems: 'center', gap: 10, fontSize: '0.78rem', color: 'var(--amber)' }}>
                <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="6" stroke="currentColor" strokeWidth="1.2"/><path d="M7 4v3.5M7 9.5v.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
                Composição importada via PDF apenas com classes/estratégias — ativos individuais não disponíveis neste mês. O detalhe completo pode ser consultado no extrato original do SmartBrain.
              </div>
            )}
            {/* Asset allocation bars if only classes */}
            {!hasIndividualAtivos && c.assetAllocation && c.assetAllocation.length > 0 ? (
              <div style={{ padding: '20px' }}>
                <div className="label" style={{ marginBottom: 14 }}>Asset Allocation · {month.label}</div>
                {c.assetAllocation.map((a, i) => {
                  const pct = a.pct || (c.plAtual ? a.valor / c.plAtual * 100 : 0);
                  return (
                    <div key={i} style={{ marginBottom: 14 }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 5 }}>
                        <span style={{ fontFamily: 'Cormorant Garamond, serif', fontStyle: 'italic', fontSize: '0.95rem', color: 'var(--heading)' }}>{a.classe}</span>
                        <div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
                          <span style={{ fontFamily: 'JetBrains Mono', fontSize: '0.75rem', color: 'var(--muted)' }}>{fmtBRL(a.valor)}</span>
                          <span style={{ fontFamily: 'JetBrains Mono', fontSize: '0.78rem', fontWeight: 600, color: 'var(--body)', minWidth: 40, textAlign: 'right' }}>{pct.toFixed(1)}%</span>
                        </div>
                      </div>
                      <div style={{ height: 6, background: 'var(--rule)', borderRadius: 3, overflow: 'hidden' }}>
                        <div style={{ height: '100%', width: `${Math.min(100, pct)}%`, background: 'var(--navy)', borderRadius: 3, transition: 'width 0.4s' }} />
                      </div>
                    </div>
                  );
                })}
              </div>
            ) : (
              <div style={{ overflowX: 'auto', WebkitOverflowScrolling: 'touch' }}>
                <table className="tbl tbl-composicao">
                  <thead>
                    <tr>
                      <th>Classe / Ativo</th>
                      <th>Instituição</th>
                      <th className="r">Saldo Anterior</th>
                      <th className="r">Saldo Atual</th>
                      <th className="r">Variação</th>
                      <th className="r">Compras</th>
                      <th className="r">Resgates</th>
                      <th className="r">Eventos</th>
                      <th className="r">Impostos</th>
                      <th className="r">Part. %</th>
                      <th className="r">Cotação</th>
                    </tr>
                  </thead>
                  <tbody>
                    {(c.ativos || []).map((a, i) => {
                      if (a.type === 'classe') {
                        return (
                          <tr key={i} style={{ background: 'var(--paper)' }}>
                            <td style={{ fontFamily: 'Cormorant Garamond, serif', fontWeight: 500, fontStyle: 'italic', fontSize: '0.9rem', color: 'var(--heading)' }} colSpan={2}>{a.classe}</td>
                            <td className="num">{fmtBRL(a.plMarco || a.plAnterior)}</td>
                            <td className="num">{fmtBRL(a.plAbril || a.plAtual)}</td>
                            <td className={`num ${colorClass(a.diff)}`}>{a.diff != null ? fmtBRL(a.diff) : '—'}</td>
                            <td className="num">—</td><td className="num">—</td>
                            <td className="num">—</td><td className="num">—</td>
                            <td className="num">{a.part != null ? (a.part*100).toFixed(1)+'%' : '—'}</td>
                            <td className="num">—</td>
                          </tr>
                        );
                      }
                      const isSaida = a.type === 'saida';
                      const ticker = (a.nome || '').match(/\b([A-Z]{4}\d{1,2})\b/)?.[1];
                      const q = ticker ? (window.MARKET_DATA?.quotes?.[ticker]) : null;
                      return (
                        <tr key={i} style={isSaida ? { opacity: 0.5, textDecoration: 'line-through' } : {}}>
                          <td style={{ paddingLeft: 28, fontSize: '0.78rem', fontFamily: 'JetBrains Mono', color: 'var(--body)' }}>{a.nome}{isSaida ? ' (saiu)' : ''}</td>
                          <td style={{ fontSize: '0.72rem', color: 'var(--muted)' }}>{a.instituicao || '—'}</td>
                          <td className="num">{fmtBRL(a.plMarco || a.plAnterior)}</td>
                          <td className="num">{fmtBRL(isSaida ? 0 : (a.plAbril || a.plAtual))}</td>
                          <td className={`num ${colorClass(a.diff)}`}>{fmtBRL(a.diff)}</td>
                          <td className="num">{fmtBRL(a.compras || 0)}</td>
                          <td className="num">{fmtBRL(a.vendas || 0)}</td>
                          <td className="num">{fmtBRL(a.eventos || 0)}</td>
                          <td className="num">{fmtBRL(a.impostos || 0)}</td>
                          <td className="num">{a.part != null ? (a.part*100).toFixed(1)+'%' : '—'}</td>
                          <td className="num" style={{ fontSize: '0.72rem' }} data-tick={quotesTick}>
                            {q ? (
                              <span>
                                <span style={{ fontFamily: 'JetBrains Mono', color: 'var(--body)' }}>{fmtBRL(q.price)}</span>
                                {q.change != null && (
                                  <span className={colorClass(q.change)} style={{ marginLeft: 6, fontFamily: 'JetBrains Mono' }}>
                                    {(q.change >= 0 ? '+' : '') + q.change.toFixed(2)}%
                                  </span>
                                )}
                              </span>
                            ) : ticker ? (
                              <span style={{ color: 'var(--muted)', fontStyle: 'italic' }}>—</span>
                            ) : ''}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        );
      })()}

      {/* ── TAB: ACHADOS ── */}
      {tab === 'achados' && (
        <div className="card" style={{ marginTop: 16 }}>
          {isClean ? (
            <div style={{ padding: '28px 20px', display: 'flex', alignItems: 'center', gap: 10, color: 'var(--green)' }}>
              <Icon.check />
              <span style={{ fontSize: '0.85rem' }}>Sem ressalvas — conciliação dentro da tolerância.</span>
            </div>
          ) : (
            <div>
              {erros.map((e, i) => (
                <div key={`erro-${i}`} className="finding-item">
                  <div className="finding-header">
                    <span className="badge badge-corrigir">Erro</span>
                    <span className="finding-nome">{c.nome}</span>
                  </div>
                  <div className="finding-text error">{e}</div>
                  <ComentarioAchado monthKey={month.key} carteiraNome={c.nome} tipo="erro" idx={i} texto={e} />
                </div>
              ))}
              {alertas.map((a, i) => (
                <div key={`alerta-${i}`} className="finding-item">
                  <div className="finding-header">
                    <span className="badge badge-alerta">Alerta</span>
                    <span className="finding-nome">{c.nome}</span>
                  </div>
                  <div className="finding-text warn">{a}</div>
                  <ComentarioAchado monthKey={month.key} carteiraNome={c.nome} tipo="alerta" idx={i} texto={a} />
                </div>
              ))}
              {lims.map((l, i) => (
                <div key={`lim-${i}`} className="finding-item">
                  <div className="finding-header">
                    <span className="badge" style={{ background: 'var(--paper-mid)', color: 'var(--body)' }}>Limitação</span>
                  </div>
                  <div className="finding-text">{l}</div>
                  <ComentarioAchado monthKey={month.key} carteiraNome={c.nome} tipo="limitacao" idx={i} texto={l} />
                </div>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

/* ── COMENTARIO POR ACHADO ─────────────────────────────────────────────
   Textarea persistido em localStorage via Store.setComentarioAchado.
   Chave estavel: tipo + idx + hash do texto do achado. */
function ComentarioAchado({ monthKey, carteiraNome, tipo, idx, texto }) {
  const achadoId = React.useMemo(
    () => Store.achadoId(tipo, idx, texto),
    [tipo, idx, texto]
  );
  const [saved, setSaved] = React.useState(null);
  const [draft, setDraft] = React.useState('');
  const [editing, setEditing] = React.useState(false);

  React.useEffect(() => {
    const c = Store.getComentarioAchado(monthKey, carteiraNome, achadoId);
    setSaved(c);
    setDraft(c?.texto || '');
    setEditing(false);
  }, [monthKey, carteiraNome, achadoId]);

  function save() {
    Store.setComentarioAchado(monthKey, carteiraNome, achadoId, draft);
    setSaved(draft ? { texto: draft, atualizadoEm: new Date().toISOString() } : null);
    setEditing(false);
  }
  function cancel() {
    setDraft(saved?.texto || '');
    setEditing(false);
  }

  return (
    <div style={{ marginTop: 10, paddingTop: 10, borderTop: '1px dashed var(--rule)' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
        <span style={{ fontSize: '0.65rem', textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--muted)' }}>
          Comentário
        </span>
        {!editing && (
          <button className="btn btn-secondary btn-sm" onClick={() => setEditing(true)} style={{ fontSize: '0.7rem', padding: '3px 10px' }}>
            {saved ? 'Editar' : 'Adicionar'}
          </button>
        )}
      </div>
      {editing ? (
        <div>
          <textarea
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            rows={3}
            placeholder="Justifique, contextualize ou registre acao tomada"
            style={{ width: '100%', fontSize: '0.8rem', padding: 8, border: '1px solid var(--rule)', borderRadius: 2, fontFamily: 'inherit' }}
          />
          <div style={{ display: 'flex', gap: 8, marginTop: 6, justifyContent: 'flex-end' }}>
            <button className="btn btn-secondary btn-sm" onClick={cancel} style={{ fontSize: '0.7rem' }}>Cancelar</button>
            <button className="btn btn-primary btn-sm" onClick={save} style={{ fontSize: '0.7rem' }}><Icon.check /> Salvar</button>
          </div>
        </div>
      ) : saved ? (
        <div>
          <div style={{ fontSize: '0.8rem', color: 'var(--body)', lineHeight: 1.5, whiteSpace: 'pre-wrap' }}>{saved.texto}</div>
          <div style={{ fontSize: '0.65rem', color: 'var(--muted)', marginTop: 4 }}>
            Atualizado em {new Date(saved.atualizadoEm).toLocaleString('pt-BR', { dateStyle: 'short', timeStyle: 'short' })}
          </div>
        </div>
      ) : (
        <div style={{ fontSize: '0.7rem', color: 'var(--muted)', fontStyle: 'italic' }}>Sem comentário registrado</div>
      )}
    </div>
  );
}

/* ── Export carteira as beautiful printable HTML (private banking style) ── */
function exportCarteiraHTML(c, month, allMonths) {
  const history = (allMonths || [])
    .slice().sort((a,b) => a.key.localeCompare(b.key))
    .map(m => { const mc = m.carteiras?.[c.nome]; return mc ? { key: m.key, label: m.label.replace(' 2026'," '26"), value: mc.plAtual, rent: mc.rentMes, status: mc.status } : null; })
    .filter(Boolean);
  const base = history[0]?.value || 1;
  const retPts = history.map(h => ({ ...h, ret: (h.value / base) - 1 }));

  function buildMiniChart() {
    if (retPts.length < 2) return '';
    const W=560, H=160, pad={t:12,r:8,b:24,l:52};
    const iW=W-pad.l-pad.r, iH=H-pad.t-pad.b, n=retPts.length;
    const allV=retPts.map(d=>d.ret), minY=Math.min(0,...allV)-0.001, maxY=Math.max(0,...allV)+0.001, rangeY=maxY-minY;
    const xi=i=>pad.l+(i/(n-1))*iW, yi=v=>pad.t+iH-((v-minY)/rangeY)*iH;
    const pts=retPts.map((d,i)=>`${xi(i)},${yi(d.ret)}`).join(' ');
    const area=`${xi(0)},${yi(0)} ${pts} ${xi(n-1)},${yi(0)}`;
    const positive=retPts[n-1].ret>=0, c1=positive?'#1A5C36':'#7A1E1E';
    const clines=Array.from({length:5},(_,i)=>{const v=minY+rangeY*i/4,yv=yi(v),pct=(v>=0?'+':'')+(v*100).toFixed(2)+'%';return `<line x1="${pad.l}" x2="${W-pad.r}" y1="${yv}" y2="${yv}" stroke="#e3ddd5" stroke-width="0.5"/><text x="${pad.l-4}" y="${yv+3.5}" text-anchor="end" font-size="8" fill="#9a9188" font-family="monospace">${pct}</text>`;}).join('');
    const labels=retPts.map((d,i)=>`<text x="${xi(i)}" y="${H-4}" text-anchor="${i===0?'start':i===n-1?'end':'middle'}" font-size="8.5" fill="#9a9188" font-family="Inter,sans-serif">${d.label}</text>`).join('');
    return `<svg viewBox="0 0 ${W} ${H}" style="width:100%;height:${H}px;display:block" preserveAspectRatio="none"><defs><linearGradient id="pg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="${c1}" stop-opacity="0.18"/><stop offset="100%" stop-color="${c1}" stop-opacity="0"/></linearGradient></defs><rect x="${pad.l}" y="${pad.t}" width="${iW}" height="${iH}" fill="#f9f7f4"/>${clines}<polygon points="${area}" fill="url(#pg)"/><polyline points="${pts}" fill="none" stroke="${c1}" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/>${retPts.map((d,i)=>`<circle cx="${xi(i)}" cy="${yi(d.ret)}" r="3" fill="white" stroke="${c1}" stroke-width="1.5"/>`).join('')}${labels}</svg>`;
  }

  function buildAllocBars() {
    const alloc = (c.assetAllocation||[]).filter(a=>a.valor>0||a.pct>0);
    if (!alloc.length) return '<p style="color:#9a9188;font-size:0.78rem">Asset allocation não disponível.</p>';
    const total=alloc.reduce((s,a)=>s+(a.valor||0),0)||1;
    return alloc.map(a=>{const pct=a.pct||(a.valor/total*100);return `<div style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;margin-bottom:4px;font-size:0.78rem"><span style="font-family:Georgia,serif;font-style:italic;color:#1a1814">${a.classe}</span><div style="display:flex;gap:14px"><span style="font-family:monospace;color:#565d65">${a.valor?a.valor.toLocaleString('pt-BR',{style:'currency',currency:'BRL'}):'—'}</span><span style="font-family:monospace;font-weight:700;min-width:36px;text-align:right;color:#0d1520">${pct.toFixed(1)}%</span></div></div><div style="height:5px;background:#e3ddd5;border-radius:2px;overflow:hidden"><div style="height:100%;width:${Math.min(100,pct)}%;background:#0d1520;border-radius:2px"></div></div></div>`;}).join('');
  }

  const statusColor=c.status==='LIBERAR'?'#1a5c36':c.status==='LIBERAR COM ALERTA'?'#7a5318':'#7a1e1e';
  const statusBg=c.status==='LIBERAR'?'#eaf4ee':c.status==='LIBERAR COM ALERTA'?'#fbf0dc':'#fae8e8';
  const hasAtivos=(c.ativos||[]).some(a=>a.type==='ativo');
  const varSign=(c.varRS||0)>=0?'+':'';
  const rentSign=(c.rentMes||0)>=0?'+':'';
  const cdiVal=window.BENCHMARKS?.monthly_cdi?.[month.key]||0;

  const html=`<!DOCTYPE html><html lang="pt-BR"><head><meta charset="utf-8">
<title>${c.nome} · ${month.label} · Mirabaud</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@300;400;500;600&display=swap');
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Inter',sans-serif;background:white;color:#1a1814;font-size:13px;-webkit-font-smoothing:antialiased}
.page{width:794px;margin:0 auto}
.header{background:#0D1520;color:white;padding:32px 40px 28px}
.brand{font-family:'Cormorant Garamond',serif;font-size:0.75rem;font-weight:600;letter-spacing:0.22em;text-transform:uppercase;color:#C4A228;margin-bottom:18px}
.name{font-family:'Cormorant Garamond',serif;font-size:2.4rem;font-weight:400;color:white;line-height:1;margin-bottom:10px}
.meta{display:flex;align-items:center;gap:14px}
.badge{display:inline-block;font-size:0.58rem;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;padding:3px 9px;border-radius:2px}
.period{font-size:0.72rem;color:rgba(255,255,255,0.5)}
.kpis{display:grid;grid-template-columns:repeat(5,1fr);border-bottom:1px solid #e3ddd5}
.kpi{padding:16px 18px;border-right:1px solid #e3ddd5}
.kpi:last-child{border-right:none}
.kpi-l{font-size:0.58rem;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:#9a9188;margin-bottom:6px}
.kpi-v{font-family:'Cormorant Garamond',serif;font-size:1.25rem;font-weight:500;color:#0d1520;line-height:1}
.kpi-sub{font-size:0.62rem;color:#9a9188;margin-top:3px}
.section{padding:20px 40px;border-bottom:1px solid #e3ddd5}
.section-title{font-size:0.58rem;font-weight:700;letter-spacing:0.12em;text-transform:uppercase;color:#9a9188;margin-bottom:12px}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:28px}
.obs{background:#f9f7f4;border:1px solid #e3ddd5;padding:12px 16px;font-size:0.78rem;color:#565d65;line-height:1.5}
.alert-box{padding:12px 16px;font-size:0.75rem;line-height:1.5;margin-top:10px}
table{width:100%;border-collapse:collapse}
th{font-size:0.58rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:#9a9188;padding:7px 8px;border-bottom:1px solid #c8c0b5;text-align:left}
td{padding:7px 8px;border-bottom:1px solid #f2eee8;font-size:0.78rem}
tr:last-child td{border-bottom:none}
.r{text-align:right}
.pos{color:#1a5c36}.neg{color:#7a1e1e}
.footer{background:#f9f7f4;padding:14px 40px;display:flex;justify-content:space-between;font-size:0.62rem;color:#9a9188;border-top:1px solid #e3ddd5}
@media print{body{-webkit-print-color-adjust:exact;print-color-adjust:exact}}
@page{size:A4;margin:0}
</style></head><body>
<div class="page">
<div class="header">
  <div class="brand">Mirabaud · Family Office</div>
  <div class="name">${c.nome}</div>
  <div class="meta">
    <span class="badge" style="background:${statusBg};color:${statusColor}">${c.status}</span>
    <span class="period">${month.label} &nbsp;·&nbsp; Extrato ${month.dataExtrato}</span>
    <span class="period" style="margin-left:auto">Analista: ${c.analista} &nbsp;·&nbsp; Aprovador: ${c.aprovador}</span>
  </div>
</div>
<div class="kpis">
  <div class="kpi"><div class="kpi-l">PL Anterior</div><div class="kpi-v">${fmtBRL(c.plAnterior,true)}</div><div class="kpi-sub">${month.baselineLabel||'Mês ant.'}</div></div>
  <div class="kpi"><div class="kpi-l">PL Atual</div><div class="kpi-v">${fmtBRL(c.plAtual,true)}</div><div class="kpi-sub">${month.label}</div></div>
  <div class="kpi"><div class="kpi-l">Variação R$</div><div class="kpi-v ${(c.varRS||0)>=0?'pos':'neg'}">${varSign}${fmtBRL(c.varRS,true)}</div></div>
  <div class="kpi"><div class="kpi-l">Variação %</div><div class="kpi-v ${(c.varPct||0)>=0?'pos':'neg'}">${varSign}${((c.varPct||0)*100).toFixed(2)}%</div></div>
  <div class="kpi"><div class="kpi-l">Rent. Mês</div><div class="kpi-v ${(c.rentMes||0)>=0?'pos':'neg'}">${rentSign}${((c.rentMes||0)*100).toFixed(2)}%</div><div class="kpi-sub">CDI: ${(cdiVal*100).toFixed(2)}%</div></div>
</div>
${retPts.length>=2?`<div style="padding:0 40px"><div class="section-title" style="padding-top:18px;margin-bottom:10px">Retorno Acumulado</div>${buildMiniChart()}</div>`:''}
<div class="section">
  <div class="two-col">
    <div><div class="section-title">Asset Allocation</div>${buildAllocBars()}</div>
    <div>
      <div class="section-title">Observação</div>
      <div class="obs">${c.observacao||'Sem observações registradas.'}</div>
      ${c.alertas!=='-'?`<div class="alert-box" style="background:#fbf0dc;border:1px solid rgba(122,83,24,0.2);color:#7a5318"><strong>Alerta:</strong> ${c.alertas}</div>`:''}
      ${c.erros!=='-'?`<div class="alert-box" style="background:#fae8e8;border:1px solid rgba(122,30,30,0.2);color:#7a1e1e"><strong>Erro:</strong> ${c.erros}</div>`:''}
    </div>
  </div>
</div>
${hasAtivos?`<div class="section">
  <div class="section-title">Composição de Ativos</div>
  <table style="margin-top:10px">
    <thead><tr><th style="padding-left:20px">Ativo</th><th>Instituição</th><th class="r">Saldo Ant.</th><th class="r">Saldo Atual</th><th class="r">Variação</th><th class="r">Part.%</th></tr></thead>
    <tbody>${(c.ativos||[]).filter(a=>a.type==='ativo'||a.type==='saida').map(a=>{const neg=a.type==='saida';return`<tr style="${neg?'text-decoration:line-through;opacity:0.5':''}"><td style="padding-left:20px;font-family:monospace;font-size:0.72rem">${a.nome||''}</td><td style="color:#9a9188">${a.instituicao||'—'}</td><td class="r" style="font-family:monospace">${(a.plMarco||a.plAnterior||0).toLocaleString('pt-BR',{style:'currency',currency:'BRL'})}</td><td class="r" style="font-family:monospace">${((neg?0:(a.plAbril||a.plAtual||0))).toLocaleString('pt-BR',{style:'currency',currency:'BRL'})}</td><td class="r ${(a.diff||0)>=0?'pos':'neg'}" style="font-family:monospace">${a.diff!=null?((a.diff>=0?'+':'')+a.diff.toLocaleString('pt-BR',{style:'currency',currency:'BRL'})):'—'}</td><td class="r" style="font-family:monospace">${a.part!=null?(a.part*100).toFixed(1)+'%':'—'}</td></tr>`;}).join('')}</tbody>
  </table>
</div>`:''}
${history.length>1?`<div class="section">
  <div class="section-title">Histórico de Conciliações</div>
  <table style="margin-top:10px">
    <thead><tr><th>Período</th><th>Status</th><th class="r">PL</th><th class="r">Rent. Mês</th><th class="r">Retorno Acumulado</th></tr></thead>
    <tbody>${history.slice().reverse().map(h=>{const sc=h.status==='LIBERAR'?'#1a5c36':h.status==='LIBERAR COM ALERTA'?'#7a5318':'#7a1e1e';const sb=h.status==='LIBERAR'?'#eaf4ee':h.status==='LIBERAR COM ALERTA'?'#fbf0dc':'#fae8e8';const acum=((h.value/base)-1)*100;return`<tr><td style="font-weight:500">${h.label}</td><td><span style="font-size:0.58rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;padding:2px 7px;border-radius:2px;background:${sb};color:${sc}">${h.status}</span></td><td class="r" style="font-family:monospace">${h.value.toLocaleString('pt-BR',{style:'currency',currency:'BRL'})}</td><td class="r ${h.rent>=0?'pos':'neg'}" style="font-family:monospace">${(h.rent>=0?'+':'')}${(h.rent*100).toFixed(2)}%</td><td class="r ${acum>=0?'pos':'neg'}" style="font-family:monospace">${(acum>=0?'+':'')}${acum.toFixed(2)}%</td></tr>`;}).join('')}</tbody>
  </table>
</div>`:''}
<div class="footer">
  <span>Mirabaud Family Office · Plataforma interna de verificação</span>
  <span>${c.nome} · ${month.label} · Gerado em ${new Date().toLocaleDateString('pt-BR',{day:'2-digit',month:'long',year:'numeric'})}</span>
</div>
</div>
<script>window.onload=()=>setTimeout(()=>window.print(),400);</script>
</body></html>`;

  const w=window.open('','_blank');
  w.document.write(html);
  w.document.close();
}

Object.assign(window, { CarteiraView });
