/* global React */
const { useState: useStateFE, useMemo: useMemoFE, useEffect: useEffectFE } = React;

// =====================================================================
// FazerEscalaView V2 — sandbox de simulação de escala mensal
//
// Novidades V2:
//  - Onboarding inline quando sem regras ativas
//  - Validação de turnos vazios
//  - Mobile responsive (cards 1col em <720px, modal full-screen)
//  - Persistência de preferências (prefereLivre/cadeia/descanso/qualidade)
//  - Score breakdown (mínimos / qualidade / preferências)
//  - Re-simular com seed (mesmas regras → outras 3 propostas)
//  - Editor da proposta antes de adotar (modo "Ajustar")
//  - Histórico de adotadas
//  - Share API mobile com fallback clipboard
// =====================================================================

const _styles = `
@media (max-width: 720px) {
  .fe-cards { grid-template-columns: 1fr !important; }
  .fe-form-grid { grid-template-columns: 1fr !important; }
  .fe-form-3 { grid-template-columns: 1fr !important; }
  .fe-modal-shell { padding: 0 !important; align-items: stretch !important; }
  .fe-modal-card {
    max-height: 100vh !important; height: 100vh !important;
    border-radius: 0 !important; max-width: 100% !important;
  }
  .fe-actions { flex-direction: column !important; }
  .fe-actions > button { width: 100% !important; }
}
.fe-bar-fill { transition: width var(--dur-2, 0.3s) var(--ease, ease); }
`;

function FazerEscalaView({
  hospitais, blocosAgendaReal,
  preferenciasIniciais, onSalvarPreferencias,
  onIrParaHospitais, onAdotarProposta,
}) {
  const ativos = (hospitais || []).filter(h => h.regrasEscala?.ativo);
  const semRegras = ativos.length === 0;

  // ---- Form state -----------------------------------------------------
  const proximoMes = useMemoFE(() => {
    const d = new Date();
    d.setMonth(d.getMonth() + 1, 1);
    return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`;
  }, []);

  const [mesAlvo, setMesAlvo] = useStateFE(proximoMes);
  // Bloqueios persistem por mês (cada mês tem sua lista). Hidrata do prop.
  const [bloqueiosPorMes, setBloqueiosPorMes] = useStateFE(preferenciasIniciais?.bloqueiosPorMes || {});
  const bloqueios = bloqueiosPorMes[mesAlvo] || [];
  const setBloqueios = (novoArr) => setBloqueiosPorMes({ ...bloqueiosPorMes, [mesAlvo]: novoArr });
  const [novoBloqueio, setNovoBloqueio] = useStateFE('');
  // Hidrata preferências persistidas (aplica defaults se ausentes)
  const [prefereLivre, setPrefereLivre] = useStateFE(preferenciasIniciais?.prefereLivre || []);
  const [cadeiaMaxH, setCadeiaMaxH] = useStateFE(preferenciasIniciais?.cadeiaMaxH ?? 24);
  const [descansoMinH, setDescansoMinH] = useStateFE(preferenciasIniciais?.descansoMinH ?? 12);
  const [qualidadeRequerida, setQualidadeRequerida] = useStateFE(preferenciasIniciais?.qualidadeRequerida ?? 4);
  const [metaFinanceira, setMetaFinanceira] = useStateFE(preferenciasIniciais?.metaFinanceira || { ativo: false, valorMin: 0, valorMax: 0 });
  const [seed, setSeed] = useStateFE(0);

  // Salva prefs no parent quando muda (debounced via React's batching natural)
  useEffectFE(() => {
    if (!onSalvarPreferencias) return;
    onSalvarPreferencias({ prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida, bloqueiosPorMes, metaFinanceira });
  }, [prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida, bloqueiosPorMes, metaFinanceira]);

  const [resultado, setResultado] = useStateFE(null);
  const [propostaExpandida, setPropostaExpandida] = useStateFE(null);
  const [propostasSalvas, setPropostasSalvas] = useStateFE([]);
  const [salvandoId, setSalvandoId] = useStateFE(null);
  const [carregandoSalvas, setCarregandoSalvas] = useStateFE(true);
  const [aba, setAba] = useStateFE('simular'); // 'simular' | 'historico'
  const [gerando, setGerando] = useStateFE(false);
  const [visao, setVisao] = useStateFE('calendario'); // 'cards' | 'calendario' — toggle das 3 propostas

  // Carrega propostas do mês atual (rascunho/enviadas) e adotadas (todos os meses)
  useEffectFE(() => {
    let cancelado = false;
    setCarregandoSalvas(true);
    Promise.all([
      window.listarPropostas({ mesAlvo }),
      window.listarPropostas({ status: 'adotada' }),
    ]).then(([rMes, rAdot]) => {
      if (cancelado) return;
      const mesPropostas = rMes.ok ? rMes.propostas.filter(p => p.status !== 'adotada') : [];
      const adotadas = rAdot.ok ? rAdot.propostas : [];
      setPropostasSalvas([...mesPropostas, ...adotadas]);
      setCarregandoSalvas(false);
    });
    return () => { cancelado = true; };
  }, [mesAlvo]);

  // ---- Validações de input -------------------------------------------
  const erros = useMemoFE(() => {
    const e = [];
    if (cadeiaMaxH < 1) e.push('Cadeia máxima deve ser ≥ 1h.');
    if (descansoMinH < 0) e.push('Descanso mínimo não pode ser negativo.');
    if (qualidadeRequerida < 0) e.push('Janelas de descanso não pode ser negativo.');
    // Hospitais com regras inválidas (min > max)
    for (const h of ativos) {
      const r = h.regrasEscala;
      if (r.plantoesMin > r.plantoesMax) e.push(`${h.abrev}: plantões mín (${r.plantoesMin}) > máx (${r.plantoesMax})`);
      if (r.fdsMin > r.fdsMax) e.push(`${h.abrev}: FDS mín > máx`);
      if (r.horasMin > r.horasMax) e.push(`${h.abrev}: horas mín > máx`);
      if (!r.turnosPermitidos || r.turnosPermitidos.length === 0) {
        e.push(`${h.abrev}: nenhum turno permitido`);
      }
    }
    return e;
  }, [cadeiaMaxH, descansoMinH, qualidadeRequerida, ativos]);

  const adicionarBloqueio = () => {
    if (!novoBloqueio || bloqueios.includes(novoBloqueio)) return;
    setBloqueios([...bloqueios, novoBloqueio].sort());
    setNovoBloqueio('');
  };
  const removerBloqueio = (iso) => setBloqueios(bloqueios.filter(x => x !== iso));
  const togglePrefereLivre = (dow) => {
    setPrefereLivre(prefereLivre.includes(dow)
      ? prefereLivre.filter(x => x !== dow)
      : [...prefereLivre, dow].sort((a,b)=>a-b));
  };

  const gerar = (novaSeed) => {
    setResultado(null); setPropostaExpandida(null); setGerando(true);
    const usaSeed = novaSeed ?? Math.floor(Math.random() * 100000);
    setSeed(usaSeed);
    // setTimeout pra dar tempo de UI renderizar "gerando"
    setTimeout(() => {
      const prefs = { bloqueios, prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida, metaFinanceira };
      const r = window.gerarPropostasEscala(hospitais, prefs, mesAlvo, blocosAgendaReal, usaSeed);
      setResultado(r);
      setGerando(false);
    }, 30);
  };

  const salvarProposta = async (proposta) => {
    setSalvandoId(proposta.variante);
    const r = await window.criarProposta({
      mesAlvo, variante: proposta.variante,
      titulo: window.LABEL_VARIANTE[proposta.variante] || proposta.variante,
      blocosPropostos: proposta.blocosPropostos,
      regrasUsadas: resultado.regrasUsadas,
      preferencias: { bloqueios, prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida, metaFinanceira },
      score: proposta.score, status: 'rascunho',
    });
    setSalvandoId(null);
    if (r.ok) setPropostasSalvas([r.proposta, ...propostasSalvas]);
  };

  const apagarSalva = async (id) => {
    const r = await window.apagarProposta(id);
    if (r.ok) setPropostasSalvas(propostasSalvas.filter(p => p.id !== id));
  };

  // Aceita subset de blocos (modo selecionar parcial). Se subset=null, adota todos.
  const adotarProposta = (proposta, subset = null) => {
    const blocosParaAdotar = subset || proposta.blocosPropostos;
    const total = proposta.blocosPropostos.length;
    const N = blocosParaAdotar.length;
    const msg = N === total
      ? `Adotar ${total} plantões? Vão pra sua agenda real e podem ser editados depois.`
      : `Adotar ${N} de ${total} plantões selecionados? Os outros ${total - N} ficam só na proposta.`;
    if (!confirm(msg)) return;
    onAdotarProposta(blocosParaAdotar);
    // Marca status da proposta como adotada (mesmo se parcial)
    if (proposta.id) window.atualizarProposta(proposta.id, { status: 'adotada' });
  };

  // Gera PDF/impressão da proposta numa janela nova com layout formal.
  // Usa window.print() — Mariana escolhe "Salvar como PDF" no diálogo do navegador.
  const exportarPDF = (proposta) => {
    const w = window.open('', '_blank', 'width=900,height=1100');
    if (!w) { alert('Pop-up bloqueado. Libere pop-ups pra exportar PDF.'); return; }
    const [y, m] = (proposta.mesAlvo || mesAlvo).split('-').map(Number);
    const mesNome = window.MESES[m - 1];

    // Agrupa por hospital e ordena
    const porHosp = {};
    for (const b of proposta.blocosPropostos) {
      const h = hospitais.find(x => x.id === b.hospitalId);
      const abrev = h?.abrev || `Hospital ${b.hospitalId}`;
      if (!porHosp[abrev]) porHosp[abrev] = { hospital: h, blocos: [] };
      porHosp[abrev].blocos.push(b);
    }
    Object.values(porHosp).forEach(g => g.blocos.sort((a, b) => a.data.localeCompare(b.data) || a.horaInicio - b.horaInicio));

    const totalDias = new Date(y, m, 0).getDate();
    const dias = Array.from({length: totalDias}, (_, i) => window.toISO(new Date(y, m-1, i+1)));
    const primeiroDow = window.diaSemanaBR(dias[0]);
    const blocosPorData = {};
    for (const b of proposta.blocosPropostos) {
      if (!blocosPorData[b.data]) blocosPorData[b.data] = [];
      blocosPorData[b.data].push(b);
    }

    const html = `<!doctype html><html lang="pt-BR"><head>
<meta charset="utf-8"><title>Escala — ${mesNome} ${y}</title>
<style>
  @page { size: A4; margin: 18mm; }
  * { box-sizing: border-box; }
  body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    color: #3A2E2A; margin: 0; padding: 24px;
    line-height: 1.4;
  }
  h1 { font-size: 22pt; margin: 0 0 4pt; font-weight: 600; letter-spacing: -0.02em; }
  .lede { color: #7A6A60; margin: 0 0 18pt; font-size: 11pt; }
  h2 { font-size: 13pt; margin: 18pt 0 8pt; font-weight: 600; border-bottom: 1px solid #DDD; padding-bottom: 4pt; }
  table { border-collapse: collapse; width: 100%; font-size: 10pt; margin-bottom: 8pt; }
  th, td { padding: 4pt 8pt; text-align: left; border-bottom: 1px solid #EEE; }
  th { font-size: 9pt; text-transform: uppercase; letter-spacing: 0.04em; color: #7A6A60; }
  .cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2pt; margin: 8pt 0 18pt; }
  .cal-h { font-size: 9pt; font-weight: 600; text-align: center; color: #7A6A60; padding: 4pt 0; }
  .cal-d {
    border: 1px solid #DDD; border-radius: 3pt;
    padding: 3pt; min-height: 36pt;
    font-size: 9pt; position: relative;
  }
  .cal-d.fds { background: #FAF7F2; }
  .cal-num { font-weight: 600; }
  .cal-bloco {
    margin-top: 2pt; padding: 1pt 3pt; font-size: 7pt;
    border-left: 2pt solid; border-radius: 2pt;
  }
  .resumo { display: flex; gap: 16pt; flex-wrap: wrap; margin: 12pt 0; }
  .resumo-card {
    border: 1px solid #DDD; border-radius: 4pt;
    padding: 8pt 12pt; min-width: 140pt;
  }
  .resumo-num { font-size: 18pt; font-weight: 600; }
  .footer { margin-top: 24pt; padding-top: 8pt; border-top: 1px solid #DDD; font-size: 9pt; color: #7A6A60; }
  @media print {
    body { padding: 0; }
    .no-print { display: none !important; }
  }
</style>
</head><body>

<h1>Proposta de escala — ${mesNome} ${y}</h1>
<p class="lede">${window.LABEL_VARIANTE[proposta.variante] || proposta.variante}${proposta.titulo ? ` · ${proposta.titulo}` : ''} · ${proposta.blocosPropostos.length} plantões · score ${proposta.score?.total ?? '?'}/100</p>

<div class="resumo">
  ${Object.values(proposta.score?.porHospital || {}).map(x => `
    <div class="resumo-card">
      <div style="font-size:9pt;text-transform:uppercase;letter-spacing:0.04em;color:#7A6A60">${x.hospitalNome}</div>
      <div class="resumo-num">${x.plantoes} <span style="font-size:11pt;font-weight:400;color:#7A6A60">plantões</span></div>
      <div style="font-size:10pt;color:#7A6A60">${x.fds} FDS · ${x.horas}h</div>
    </div>
  `).join('')}
</div>

<h2>Calendário do mês</h2>
<div class="cal">
  ${['Seg','Ter','Qua','Qui','Sex','Sáb','Dom'].map(d => `<div class="cal-h">${d}</div>`).join('')}
  ${Array.from({length: primeiroDow}).map(() => '<div></div>').join('')}
  ${dias.map(iso => {
    const dow = window.diaSemanaBR(iso);
    const ehFDS = dow === 5 || dow === 6;
    const dia = parseInt(iso.split('-')[2]);
    const blocosDia = (blocosPorData[iso] || []);
    return `<div class="cal-d ${ehFDS ? 'fds' : ''}">
      <div class="cal-num">${dia}</div>
      ${blocosDia.map(b => {
        const h = hospitais.find(x => x.id === b.hospitalId);
        return `<div class="cal-bloco" style="background:${h?.corWash||'#F5F5F5'};border-color:${h?.cor||'#999'};color:${h?.corDeep||'#333'}">
          <strong>${h?.abrev||'?'}</strong> ${window.fmtHora(b.horaInicio)}
        </div>`;
      }).join('')}
    </div>`;
  }).join('')}
</div>

<h2>Lista por hospital</h2>
${Object.entries(porHosp).sort().map(([abrev, g]) => `
  <h3 style="font-size:11pt;margin:12pt 0 4pt;color:${g.hospital?.corDeep||'#333'}">
    <span style="display:inline-block;width:10pt;height:10pt;background:${g.hospital?.cor||'#999'};border-radius:2pt;margin-right:4pt;vertical-align:middle"></span>
    ${abrev} — ${g.blocos.length} plantões
  </h3>
  <table>
    <thead><tr><th>Data</th><th>Dia</th><th>Turno</th><th>Hora</th><th>Duração</th></tr></thead>
    <tbody>
    ${g.blocos.map(b => {
      const dt = window.fromISO(b.data);
      const dow = window.DIAS_COMPLETO[window.diaSemanaBR(b.data)];
      return `<tr>
        <td>${dt.getDate()}/${String(m).padStart(2,'0')}</td>
        <td>${dow}</td>
        <td style="text-transform:capitalize">${b.turno || '—'}</td>
        <td>${window.fmtHora(b.horaInicio)}</td>
        <td>${b.duracao}h</td>
      </tr>`;
    }).join('')}
    </tbody>
  </table>
`).join('')}

<div class="footer">
  Gerado pelo Colo Ritmo · ${new Date().toLocaleDateString('pt-BR')} · ${proposta.blocosPropostos.length} plantões
</div>

<div class="no-print" style="margin-top: 24pt; text-align: center">
  <button onclick="window.print()" style="padding:10pt 24pt;font-size:11pt;background:#3A2E2A;color:#FFF;border:none;border-radius:4pt;cursor:pointer">
    Imprimir / Salvar como PDF
  </button>
</div>

<script>setTimeout(() => window.print(), 500);</script>
</body></html>`;
    w.document.write(html);
    w.document.close();
  };

  // Compartilhar via Web Share API se suportado, fallback clipboard.
  const compartilhar = async (proposta) => {
    const texto = formatarTextoCompartilhamento(proposta, hospitais, mesAlvo);
    const titulo = `Escala — ${window.MESES[parseInt(mesAlvo.split('-')[1]) - 1]} ${mesAlvo.split('-')[0]}`;
    if (navigator.share && /Mobi|Android|iPhone/i.test(navigator.userAgent)) {
      try {
        await navigator.share({ title: titulo, text: texto });
        if (proposta.id) window.atualizarProposta(proposta.id, { status: 'enviada' });
        return;
      } catch (e) { /* user cancelled or unsupported — fallback */ }
    }
    try {
      await navigator.clipboard.writeText(texto);
      alert('Texto copiado pro clipboard. Cole no WhatsApp/email pra mandar pra coordenação.');
      if (proposta.id) window.atualizarProposta(proposta.id, { status: 'enviada' });
    } catch (e) {
      alert('Não consegui copiar. Texto:\n\n' + texto);
    }
  };

  // Persiste blocos editados de uma proposta (modo Ajustar dentro do modal)
  const salvarAjustes = async (proposta, novosBlocos) => {
    const novoScore = window.recalcularScoreProposta(novosBlocos, hospitais, {
      bloqueios, prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida,
    });
    if (proposta.id) {
      const r = await window.atualizarProposta(proposta.id, {
        blocosPropostos: novosBlocos,
        score: { total: novoScore.total, breakdown: novoScore.breakdown,
                 porHospital: novoScore.porHospital, janelasLongas: novoScore.janelasLongas },
      });
      if (r.ok) setPropostasSalvas(propostasSalvas.map(p => p.id === proposta.id ? r.proposta : p));
    }
  };

  // ---- Render ---------------------------------------------------------
  const propostasMesAtual = propostasSalvas.filter(p => p.mesAlvo === mesAlvo && p.status !== 'adotada');
  const propostasAdotadas = propostasSalvas.filter(p => p.status === 'adotada');

  return (
    <div style={{display:'grid', gap:'var(--s-5)'}}>
      <style>{_styles}</style>

      <div>
        <h2 className="h2" style={{margin: 0}}>Fazer escala</h2>
        <p className="lede" style={{margin: '4px 0 0', maxWidth: 600}}>
          Sandbox pra você simular o mês e mandar a proposta pra coordenação dos hospitais.
        </p>
      </div>

      {/* Tabs internos */}
      <div style={{display:'flex', gap: 8, borderBottom: '1px solid var(--line)'}}>
        {[
          { id: 'simular', label: 'Simular' },
          { id: 'historico', label: `Histórico${propostasAdotadas.length ? ` (${propostasAdotadas.length})` : ''}` },
        ].map(t => (
          <button key={t.id} type="button"
            onClick={() => setAba(t.id)}
            style={{
              padding: '8px 16px', fontSize: 13, fontWeight: 600,
              border: 'none', background: 'none', cursor: 'pointer',
              color: aba === t.id ? 'var(--ink)' : 'var(--ink-3)',
              borderBottom: aba === t.id ? '2px solid var(--ink)' : '2px solid transparent',
              marginBottom: -1,
            }}>
            {t.label}
          </button>
        ))}
      </div>

      {aba === 'historico' && (
        <HistoricoAdotadas
          propostas={propostasAdotadas}
          hospitais={hospitais}
          carregando={carregandoSalvas}
          onVer={(p) => setPropostaExpandida({ ...p, _readonly: true })}
        />
      )}

      {aba === 'simular' && (
        <>
          {semRegras && (
            <div className="card" style={{
              padding: 'var(--s-4) var(--s-5)',
              background: 'var(--warn-bg, #FBF1E1)',
              border: '1px solid #B98A3F33',
              borderRadius: 'var(--r-md)',
              display:'grid', gap: 'var(--s-3)',
            }}>
              <div>
                <strong>Comece configurando pelo menos 1 hospital.</strong>
                <div className="small" style={{marginTop: 4}}>
                  Cada hospital tem regras próprias (qtos plantões/mês, FDS, horas).
                  Sem isso o solver não tem como propor escala.
                </div>
              </div>
              <div style={{display:'flex', gap: 8, flexWrap:'wrap'}}>
                {(hospitais || []).map(h => (
                  <button key={h.id} type="button"
                    onClick={() => onIrParaHospitais && onIrParaHospitais(h.id)}
                    style={{
                      padding: '8px 14px', fontSize: 12, fontWeight: 600,
                      background: h.corWash || 'var(--bg)',
                      color: h.corDeep || 'var(--ink)',
                      border: `1px solid ${h.corDeep || 'var(--line)'}`,
                      borderRadius: 'var(--r-pill)', cursor: 'pointer',
                    }}>
                    Configurar {h.abrev} →
                  </button>
                ))}
              </div>
            </div>
          )}

          {erros.length > 0 && !semRegras && (
            <div className="card" style={{
              padding: 'var(--s-3) var(--s-4)',
              background: 'var(--err-bg, #FBE9E5)', color:'var(--err, #B25A4D)',
              borderRadius: 'var(--r-md)', fontSize: 12,
            }}>
              <strong>Corrige antes de gerar:</strong>
              <ul style={{margin: '4px 0 0', paddingLeft: 18}}>
                {erros.map((e, i) => <li key={i}>{e}</li>)}
              </ul>
            </div>
          )}

          {/* Form */}
          <div className="card" style={{padding: 'var(--s-5)', display:'grid', gap:'var(--s-4)'}}>
            <div className="fe-form-grid" style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:'var(--s-4)'}}>
              <FormField label="Mês alvo">
                <input type="month" className="input" value={mesAlvo} onChange={e => setMesAlvo(e.target.value)}/>
              </FormField>
              <FormField label="Hospitais ativos">
                <div style={{display:'flex', flexWrap:'wrap', gap: 6, alignItems:'center', minHeight: 40}}>
                  {ativos.length === 0 && <span className="small" style={{color:'var(--ink-3)'}}>—</span>}
                  {ativos.map(h => (
                    <span key={h.id} style={{
                      padding: '4px 10px', borderRadius: 'var(--r-pill)',
                      background: h.corWash, color: h.corDeep,
                      border: `1px solid ${h.corDeep}33`,
                      fontSize: 12, fontWeight: 700,
                    }}>{h.abrev}</span>
                  ))}
                </div>
              </FormField>
            </div>

            <FormField label="Bloqueios pessoais"
              sub="Datas que você NÃO quer pegar plantão.">
              <div style={{display:'flex', gap: 8, alignItems:'center', flexWrap:'wrap'}}>
                <input type="date" className="input"
                  value={novoBloqueio}
                  onChange={e => setNovoBloqueio(e.target.value)}
                  style={{width: 180}}
                  min={`${mesAlvo}-01`} max={`${mesAlvo}-31`}/>
                <button type="button" className="btn btn--ghost"
                  onClick={adicionarBloqueio} disabled={!novoBloqueio}>
                  Adicionar
                </button>
                <div style={{display:'flex', gap: 4, flexWrap:'wrap', flex: 1}}>
                  {bloqueios.map(b => (
                    <span key={b} style={{
                      padding: '4px 8px 4px 10px',
                      background: 'var(--err-bg, #FBE9E5)', color: 'var(--err, #B25A4D)',
                      borderRadius: 'var(--r-pill)',
                      fontSize: 12, fontWeight: 600,
                      display:'inline-flex', alignItems:'center', gap: 6,
                    }}>
                      {window.fmtDataCurto(b)}
                      <button type="button" onClick={() => removerBloqueio(b)}
                        style={{border:'none', background:'none', cursor:'pointer',
                          color:'inherit', padding: 0, fontSize: 14, lineHeight: 1}}>×</button>
                    </span>
                  ))}
                </div>
              </div>
            </FormField>

            <FormField label="Dias da semana que você prefere livre"
              sub="Solver tenta evitar (não é obrigatório). Persistido entre sessões.">
              <div style={{display:'flex', gap: 4, flexWrap:'wrap'}}>
                {['Seg','Ter','Qua','Qui','Sex','Sáb','Dom'].map((d, i) => {
                  const sel = prefereLivre.includes(i);
                  return (
                    <button key={i} type="button" onClick={() => togglePrefereLivre(i)}
                      style={{
                        width: 50, padding: '6px 0', fontSize: 12, fontWeight: 600,
                        border: `1px solid ${sel ? 'var(--colo-sage, #5A6E50)' : 'var(--line)'}`,
                        background: sel ? 'var(--colo-sage-wash, #ECF6E7)' : 'var(--bg)',
                        color: sel ? 'var(--colo-sage, #5A6E50)' : 'var(--ink-2)',
                        borderRadius: 'var(--r-sm)', cursor: 'pointer',
                      }}>{d}</button>
                  );
                })}
              </div>
            </FormField>

            <div className="fe-form-3" style={{display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:'var(--s-4)'}}>
              <FormField label="Cadeia máxima (h)" sub="seguidas sem dormir">
                <input type="number" className="input" min={6} max={48}
                  value={cadeiaMaxH}
                  onChange={e => setCadeiaMaxH(parseInt(e.target.value) || 24)}/>
              </FormField>
              <FormField label="Descanso mín. (h)" sub="entre 2 plantões">
                <input type="number" className="input" min={0} max={48}
                  value={descansoMinH}
                  onChange={e => setDescansoMinH(parseInt(e.target.value) || 12)}/>
              </FormField>
              <FormField label="Janelas longas" sub="≥16h livres no mês">
                <input type="number" className="input" min={0} max={20}
                  value={qualidadeRequerida}
                  onChange={e => setQualidadeRequerida(parseInt(e.target.value) || 4)}/>
              </FormField>
            </div>

            {/* Meta financeira — opt-in, gating por hospital com remuneração ativa */}
            {(() => {
              const temRemuneracao = (hospitais || []).some(h => h.regrasEscala?.ativo && h.remuneracao?.ativo && h.remuneracao?.valorHoraBase);
              if (!temRemuneracao) {
                return (
                  <div style={{
                    padding: '8px 12px', fontSize: 11,
                    background: 'var(--bg-alt)', color:'var(--ink-3)',
                    borderRadius: 'var(--r-md)',
                  }}>
                    Pra usar <strong>Meta financeira</strong>, ligue a "Calculadora de plantão" em pelo menos 1 hospital ativo (Hospitais → editar).
                  </div>
                );
              }
              return (
                <div style={{
                  padding: 'var(--s-3) var(--s-4)',
                  background: metaFinanceira.ativo ? 'var(--ok-bg, #ECF6E7)' : 'var(--bg-alt)',
                  border: `1px solid ${metaFinanceira.ativo ? 'var(--ok, #5A6E50)' : 'var(--line)'}`,
                  borderRadius: 'var(--r-md)',
                }}>
                  <label style={{display:'flex', alignItems:'center', gap: 8, cursor:'pointer', marginBottom: metaFinanceira.ativo ? 8 : 0}}>
                    <input type="checkbox" checked={!!metaFinanceira.ativo}
                      onChange={() => setMetaFinanceira({...metaFinanceira, ativo: !metaFinanceira.ativo})}
                      style={{accentColor: 'var(--ok, #5A6E50)'}}/>
                    <strong style={{fontSize: 13}}>💰 Meta financeira do mês</strong>
                    <span className="small" style={{fontSize: 11, color:'var(--ink-3)'}}>
                      solver tenta atingir esse alvo bruto
                    </span>
                  </label>
                  {metaFinanceira.ativo && (
                    <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap: 12, marginTop: 8}} className="form-2col">
                      <FormField label="Mínimo (R$)" sub="solver garante atingir">
                        <input type="number" className="input" min={0} step={100}
                          value={metaFinanceira.valorMin || ''}
                          onChange={e => setMetaFinanceira({...metaFinanceira, valorMin: parseFloat(e.target.value) || 0})}
                          placeholder="ex: 8000"/>
                      </FormField>
                      <FormField label="Máximo (R$, opcional)" sub="solver para de adicionar acima disso">
                        <input type="number" className="input" min={0} step={100}
                          value={metaFinanceira.valorMax || ''}
                          onChange={e => setMetaFinanceira({...metaFinanceira, valorMax: parseFloat(e.target.value) || 0})}
                          placeholder="ex: 12000"/>
                      </FormField>
                    </div>
                  )}
                </div>
              );
            })()}

            <div style={{display:'flex', gap: 8, flexWrap:'wrap'}}>
              <button type="button" className="btn"
                onClick={() => gerar()}
                disabled={semRegras || erros.length > 0 || gerando}
                style={{
                  background: 'var(--ink)', color: 'var(--bg)',
                  justifyContent:'center', padding: '10px 20px', fontSize: 14, fontWeight: 700,
                  opacity: (semRegras || erros.length > 0 || gerando) ? 0.4 : 1,
                  flex: 1, minWidth: 180,
                }}>
                {gerando ? 'Gerando…' : 'Gerar 3 propostas'}
              </button>
              {resultado?.ok && (
                <button type="button" className="btn btn--ghost"
                  onClick={() => gerar()} disabled={gerando}
                  style={{padding: '10px 20px'}}>
                  ↻ Outra rodada
                </button>
              )}
            </div>
          </div>

          {/* Salvas do mês (não-adotadas) */}
          {!carregandoSalvas && propostasMesAtual.length > 0 && (
            <div>
              <div className="eyebrow" style={{marginBottom: 'var(--s-3)'}}>
                Salvas pra {window.MESES[parseInt(mesAlvo.split('-')[1]) - 1]} {mesAlvo.split('-')[0]}
              </div>
              <div style={{display:'grid', gap: 8}}>
                {propostasMesAtual.map(p => (
                  <PropostaSalvaRow key={p.id} proposta={p}
                    onVer={() => setPropostaExpandida(p)}
                    onApagar={() => { if (confirm('Apagar essa proposta?')) apagarSalva(p.id); }}/>
                ))}
              </div>
            </div>
          )}

          {/* 3 propostas geradas */}
          {resultado?.erro && (
            <div className="card" style={{padding:'var(--s-4)', color:'var(--err, #B25A4D)'}}>
              {resultado.erro}
            </div>
          )}

          {resultado?.ok && (
            <div style={{display:'grid', gap:'var(--s-4)'}}>
              <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', flexWrap:'wrap', gap: 8}}>
                <div className="eyebrow">
                  3 propostas pra {window.MESES[parseInt(mesAlvo.split('-')[1]) - 1]} {mesAlvo.split('-')[0]}
                  {' · ranqueadas por score · seed '}<code style={{fontSize:10}}>{resultado.seed}</code>
                </div>
                <div style={{
                  display:'inline-flex', gap: 4, padding: 4,
                  background: 'var(--bg-alt)', borderRadius: 'var(--r-pill)',
                  border: '1px solid var(--line)',
                }}>
                  {[
                    { id: 'cards', label: 'Cards' },
                    { id: 'calendario', label: 'Calendário' },
                  ].map(o => (
                    <button key={o.id} type="button"
                      onClick={() => setVisao(o.id)}
                      style={{
                        padding: '4px 12px', fontSize: 12, fontWeight: 600,
                        border:'none', cursor:'pointer',
                        background: visao === o.id ? 'var(--ink)' : 'transparent',
                        color: visao === o.id ? 'var(--bg)' : 'var(--ink-2)',
                        borderRadius: 'var(--r-pill)',
                      }}>{o.label}</button>
                  ))}
                </div>
              </div>

              {visao === 'cards' && (
                <div className="fe-cards" style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:'var(--s-4)'}}>
                  {resultado.propostas.map((p, idx) => (
                    <PropostaCard key={p.variante + idx}
                      proposta={p} rank={idx + 1}
                      hospitais={hospitais}
                      onExpand={() => setPropostaExpandida(p)}
                      onSalvar={() => salvarProposta(p)}
                      salvando={salvandoId === p.variante}/>
                  ))}
                </div>
              )}

              {visao === 'calendario' && (
                <div className="fe-cards" style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:'var(--s-4)'}}>
                  {resultado.propostas.map((p, idx) => (
                    <PropostaMiniMes key={p.variante + idx}
                      proposta={p} rank={idx + 1}
                      mesAlvo={mesAlvo}
                      hospitais={hospitais}
                      onExpand={() => setPropostaExpandida(p)}
                      onSalvar={() => salvarProposta(p)}
                      salvando={salvandoId === p.variante}/>
                  ))}
                </div>
              )}
            </div>
          )}
        </>
      )}

      {propostaExpandida && (
        <PropostaDetalhe
          proposta={propostaExpandida}
          mesAlvo={propostaExpandida.mesAlvo || mesAlvo}
          hospitais={hospitais}
          blocosAgendaReal={blocosAgendaReal}
          preferencias={{ bloqueios, prefereLivre, cadeiaMaxH, descansoMinH, qualidadeRequerida }}
          readonly={!!propostaExpandida._readonly}
          onClose={() => setPropostaExpandida(null)}
          onAdotar={(subset) => { adotarProposta(propostaExpandida, subset); setPropostaExpandida(null); }}
          onCompartilhar={() => compartilhar(propostaExpandida)}
          onExportarPDF={() => exportarPDF(propostaExpandida)}
          onSalvarAjustes={(novosBlocos) => salvarAjustes(propostaExpandida, novosBlocos)}/>
      )}
    </div>
  );
}

// =====================================================================
// Componentes auxiliares
// =====================================================================

function FormField({ label, sub, children }) {
  return (
    <label style={{display:'block'}}>
      <div className="eyebrow" style={{fontSize: 11, marginBottom: 4}}>{label}</div>
      {sub && <div className="small" style={{fontSize: 11, marginBottom: 4, color:'var(--ink-3)'}}>{sub}</div>}
      {children}
    </label>
  );
}

function PropostaSalvaRow({ proposta: p, onVer, onApagar }) {
  return (
    <div style={{
      display:'flex', alignItems:'center', gap:'var(--s-3)', flexWrap:'wrap',
      padding: 'var(--s-3) var(--s-4)',
      background: 'var(--bg)',
      border: '1px solid var(--line)',
      borderRadius: 'var(--r-md)',
    }}>
      <strong style={{fontSize: 13}}>{p.titulo || p.variante}</strong>
      <span className="small" style={{fontSize: 11}}>
        {p.blocosPropostos.length} plantões · {p.score?.total ?? '?'}/100
      </span>
      <span style={{
        padding: '2px 8px', fontSize: 10, fontWeight: 700,
        background: p.status === 'adotada' ? 'var(--ok-bg, #ECF6E7)'
          : p.status === 'enviada' ? 'var(--colo-blue-50, #EAF2F9)'
          : 'var(--bg-alt)',
        color: p.status === 'adotada' ? 'var(--ok, #5A6E50)'
          : p.status === 'enviada' ? 'var(--colo-blue-tag, #3F6E9C)'
          : 'var(--ink-3)',
        borderRadius: 'var(--r-pill)',
        textTransform:'uppercase', letterSpacing: '0.04em',
      }}>{p.status}</span>
      <span className="small" style={{fontSize: 10, marginLeft:'auto', color:'var(--ink-3)'}}>
        {new Date(p.criadaEm).toLocaleDateString('pt-BR')}
      </span>
      <button type="button" className="btn btn--ghost"
        style={{padding: '4px 10px', fontSize: 11}} onClick={onVer}>Ver</button>
      <button type="button" className="btn btn--ghost"
        style={{padding: '4px 10px', fontSize: 11, color:'var(--err, #B25A4D)'}}
        onClick={onApagar}>×</button>
    </div>
  );
}

function PropostaCard({ proposta, rank, hospitais, onExpand, onSalvar, salvando }) {
  const cor = proposta.score.total >= 85 ? 'var(--ok, #5A6E50)'
    : proposta.score.total >= 60 ? 'var(--warn, #B98A3F)'
    : 'var(--err, #B25A4D)';
  const breakdown = proposta.score.breakdown || {};

  return (
    <div className="card" style={{
      padding: 'var(--s-4)',
      display:'grid', gap:'var(--s-3)',
      border: rank === 1 ? '2px solid var(--colo-sage, #5A6E50)' : '1px solid var(--line)',
      position: 'relative',
    }}>
      {rank === 1 && (
        <span style={{
          position:'absolute', top: -10, left: 12,
          background: 'var(--colo-sage, #5A6E50)', color: 'var(--bg)',
          padding: '2px 8px', borderRadius: 'var(--r-pill)',
          fontSize: 10, fontWeight: 700, textTransform:'uppercase', letterSpacing: '0.04em',
        }}>Recomendada</span>
      )}

      <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline'}}>
        <h3 className="h3" style={{margin: 0, fontSize: 18}}>
          {window.LABEL_VARIANTE[proposta.variante] || proposta.variante}
        </h3>
        <div style={{display:'flex', alignItems:'baseline', gap: 4}}>
          <span style={{fontFamily:'var(--font-display)', fontSize: 28, fontWeight: 500, color: cor, lineHeight: 1}}>
            {proposta.score.total}
          </span>
          <span className="small" style={{fontSize: 10}}>/100</span>
        </div>
      </div>

      <p className="small" style={{margin: 0, fontSize: 12}}>
        {window.DESCRICAO_VARIANTE[proposta.variante] || ''}
      </p>

      {/* Score breakdown como mini-bars */}
      <div style={{display:'grid', gap: 4}}>
        <ScoreBar label="Mínimos" pct={breakdown.minimosScore ?? 0}/>
        <ScoreBar label="Qualidade" pct={breakdown.qualidadeScore ?? 0}/>
        <ScoreBar label="Preferências" pct={breakdown.prefsScore ?? 0}/>
        {breakdown.valorScore != null && <ScoreBar label="Financeiro" pct={breakdown.valorScore}/>}
      </div>

      <div style={{display:'grid', gap: 4}}>
        {Object.values(proposta.score.porHospital || {}).map((x, i) => (
          <div key={i} style={{
            display:'flex', justifyContent:'space-between', fontSize: 12,
            padding: '4px 0',
            borderTop: i > 0 ? '1px solid var(--line)' : 'none',
          }}>
            <strong>{x.hospitalNome}</strong>
            <span style={{color:'var(--ink-2)'}}>
              {x.plantoes} plantões · {x.fds} FDS · {x.horas}h
            </span>
          </div>
        ))}
      </div>

      <div style={{padding:'6px 10px', fontSize:11, background:'var(--bg-alt)', borderRadius:'var(--r-sm)'}}>
        <strong>{proposta.score.janelasLongas}</strong> janelas de ≥16h livres
      </div>

      {proposta.score.financeiro?.bruto > 0 && (
        <div style={{
          padding:'6px 10px', fontSize:11,
          background:'var(--ok-bg, #ECF6E7)', color:'var(--ok, #5A6E50)',
          borderRadius:'var(--r-sm)',
          display:'flex', justifyContent:'space-between', alignItems:'baseline',
        }}>
          <span>💰 Bruto estimado</span>
          <strong style={{fontFamily:'ui-monospace, SFMono-Regular, monospace', fontSize: 13}}>
            {window.fmtBRL(proposta.score.financeiro.bruto)}
          </strong>
        </div>
      )}

      {proposta.violacoes.length > 0 && (
        <details style={{
          padding: '6px 10px', fontSize: 11,
          background: 'var(--err-bg, #FBE9E5)', color:'var(--err, #B25A4D)',
          borderRadius: 'var(--r-sm)',
        }}>
          <summary style={{cursor:'pointer', fontWeight: 600}}>
            {proposta.violacoes.length} violação(ões)
          </summary>
          <ul style={{margin: '4px 0 0', paddingLeft: 18}}>
            {proposta.violacoes.map((v, i) => <li key={i}>{v}</li>)}
          </ul>
        </details>
      )}

      <div style={{display:'flex', gap: 6, marginTop: 'auto'}}>
        <button type="button" className="btn btn--ghost"
          onClick={onSalvar} disabled={salvando}
          style={{flex: 1, justifyContent:'center', fontSize: 12, padding: '6px 8px'}}>
          {salvando ? 'Salvando…' : 'Salvar'}
        </button>
        <button type="button" className="btn"
          onClick={onExpand}
          style={{flex: 1, justifyContent:'center', fontSize: 12, padding: '6px 8px',
            background: 'var(--ink)', color: 'var(--bg)'}}>
          Ver mês
        </button>
      </div>
    </div>
  );
}

// Mini-mês visual: a proposta inteira como mini-calendário do mês.
// Pra Mariana ver de relance qual proposta "respira" mais.
function PropostaMiniMes({ proposta, rank, mesAlvo, hospitais, onExpand, onSalvar, salvando }) {
  const cor = proposta.score.total >= 85 ? 'var(--ok, #5A6E50)'
    : proposta.score.total >= 60 ? 'var(--warn, #B98A3F)'
    : 'var(--err, #B25A4D)';
  const breakdown = proposta.score.breakdown || {};
  const [y, m] = mesAlvo.split('-').map(Number);
  const totalDias = new Date(y, m, 0).getDate();
  const dias = Array.from({length: totalDias}, (_, i) => window.toISO(new Date(y, m-1, i+1)));
  const primeiroDow = window.diaSemanaBR(dias[0]);

  // Index de blocos por data (pode ter múltiplos no mesmo dia)
  const blocosPorData = {};
  for (const b of proposta.blocosPropostos || []) {
    if (!blocosPorData[b.data]) blocosPorData[b.data] = [];
    blocosPorData[b.data].push(b);
  }

  return (
    <div className="card" style={{
      padding: 'var(--s-3)',
      display:'grid', gap:'var(--s-3)',
      border: rank === 1 ? '2px solid var(--colo-sage, #5A6E50)' : '1px solid var(--line)',
      position: 'relative',
    }}>
      {rank === 1 && (
        <span style={{
          position:'absolute', top: -10, left: 12,
          background: 'var(--colo-sage, #5A6E50)', color: 'var(--bg)',
          padding: '2px 8px', borderRadius: 'var(--r-pill)',
          fontSize: 10, fontWeight: 700, textTransform:'uppercase', letterSpacing: '0.04em',
        }}>Recomendada</span>
      )}

      {/* Cabeçalho compacto */}
      <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', gap: 8}}>
        <div style={{minWidth: 0}}>
          <h3 style={{margin: 0, fontSize: 15, fontWeight: 600, fontFamily:'var(--font-display)', lineHeight: 1.1}}>
            {window.LABEL_VARIANTE[proposta.variante] || proposta.variante}
          </h3>
          <div className="small" style={{fontSize: 11, color:'var(--ink-3)', marginTop: 2}}>
            {proposta.blocosPropostos.length} plantões · {proposta.score.janelasLongas} janelas livres
          </div>
        </div>
        <div style={{display:'flex', alignItems:'baseline', gap: 2}}>
          <span style={{fontFamily:'var(--font-display)', fontSize: 22, fontWeight: 500, color: cor, lineHeight: 1}}>
            {proposta.score.total}
          </span>
          <span className="small" style={{fontSize: 9}}>/100</span>
        </div>
      </div>

      {/* Mini calendário compacto — cada dia é um quadrado pequeno */}
      <div style={{display:'grid', gridTemplateColumns:'repeat(7, 1fr)', gap: 2}}>
        {['S','T','Q','Q','S','S','D'].map((d, i) => (
          <div key={i} style={{
            fontSize: 9, fontWeight: 700,
            textAlign:'center', color:'var(--ink-3)',
            padding: '2px 0',
          }}>{d}</div>
        ))}
        {Array.from({length: primeiroDow}).map((_, i) => <div key={`pad${i}`}/>)}
        {dias.map(iso => {
          const blocosNoDia = blocosPorData[iso] || [];
          const dow = window.diaSemanaBR(iso);
          const ehFDS = dow === 5 || dow === 6;
          const dia = parseInt(iso.split('-')[2]);
          // Cores empilhadas por hospital
          return (
            <div key={iso} style={{
              aspectRatio: '1 / 1',
              background: ehFDS ? 'var(--bg-alt)' : 'var(--bg)',
              border: '1px solid var(--line)',
              borderRadius: 3,
              fontSize: 9,
              padding: 2,
              display: 'flex', flexDirection: 'column',
              position: 'relative',
              overflow: 'hidden',
            }}>
              <span style={{
                fontSize: 9, fontWeight: 600,
                color: ehFDS ? 'var(--ink-3)' : 'var(--ink-2)',
                lineHeight: 1,
              }}>{dia}</span>
              {/* Marcadores de plantão como faixas coloridas */}
              <div style={{
                position:'absolute', left: 0, right: 0, bottom: 0,
                display: 'flex', flexDirection: 'column', gap: 1,
              }}>
                {blocosNoDia.map((b, i) => {
                  const h = hospitais.find(x => x.id === b.hospitalId);
                  return (
                    <div key={i} style={{
                      height: 4,
                      background: h?.cor || 'var(--ink)',
                    }} title={`${h?.abrev || '?'} ${window.fmtHora(b.horaInicio)}`}/>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>

      {/* Score breakdown compacto */}
      <div style={{display:'grid', gap: 2}}>
        <ScoreBar label="Mín" pct={breakdown.minimosScore ?? 0}/>
        <ScoreBar label="Qual" pct={breakdown.qualidadeScore ?? 0}/>
        <ScoreBar label="Pref" pct={breakdown.prefsScore ?? 0}/>
        {breakdown.valorScore != null && <ScoreBar label="$" pct={breakdown.valorScore}/>}
      </div>

      {proposta.score.financeiro?.bruto > 0 && (
        <div style={{
          padding:'4px 8px', fontSize:11,
          background:'var(--ok-bg, #ECF6E7)', color:'var(--ok, #5A6E50)',
          borderRadius:'var(--r-sm)',
          display:'flex', justifyContent:'space-between',
        }}>
          <span>💰 bruto</span>
          <strong style={{fontFamily:'ui-monospace, monospace'}}>
            {window.fmtBRL(proposta.score.financeiro.bruto)}
          </strong>
        </div>
      )}

      {/* Resumo por hospital — uma linha cada */}
      <div style={{display:'grid', gap: 2, fontSize: 11}}>
        {Object.values(proposta.score.porHospital || {}).map((x, i) => {
          const h = hospitais.find(hh => (hh.abrev || hh.nome) === x.hospitalNome);
          return (
            <div key={i} style={{display:'flex', alignItems:'center', gap: 4}}>
              <span style={{
                display:'inline-block', width: 8, height: 8, borderRadius: 2,
                background: h?.cor || 'var(--ink)',
              }}/>
              <strong style={{fontSize: 11}}>{x.hospitalNome}</strong>
              <span style={{color:'var(--ink-3)', fontSize: 11, marginLeft:'auto'}}>
                {x.plantoes}p · {x.fds}fds · {x.horas}h
              </span>
            </div>
          );
        })}
      </div>

      {proposta.violacoes.length > 0 && (
        <details style={{
          padding: '4px 8px', fontSize: 10,
          background: 'var(--err-bg, #FBE9E5)', color:'var(--err, #B25A4D)',
          borderRadius: 'var(--r-sm)',
        }}>
          <summary style={{cursor:'pointer', fontWeight: 600}}>
            {proposta.violacoes.length} violação(ões)
          </summary>
          <ul style={{margin: '2px 0 0', paddingLeft: 14}}>
            {proposta.violacoes.map((v, i) => <li key={i}>{v}</li>)}
          </ul>
        </details>
      )}

      <div style={{display:'flex', gap: 4, marginTop: 'auto'}}>
        <button type="button" className="btn btn--ghost"
          onClick={onSalvar} disabled={salvando}
          style={{flex: 1, justifyContent:'center', fontSize: 11, padding: '4px 6px'}}>
          {salvando ? '…' : 'Salvar'}
        </button>
        <button type="button" className="btn"
          onClick={onExpand}
          style={{flex: 1, justifyContent:'center', fontSize: 11, padding: '4px 6px',
            background: 'var(--ink)', color: 'var(--bg)'}}>
          Ver mês
        </button>
      </div>
    </div>
  );
}

function ScoreBar({ label, pct }) {
  const cor = pct >= 85 ? 'var(--ok, #5A6E50)'
    : pct >= 60 ? 'var(--warn, #B98A3F)' : 'var(--err, #B25A4D)';
  return (
    <div style={{display:'grid', gridTemplateColumns:'80px 1fr 32px', gap: 8, alignItems:'center', fontSize: 11}}>
      <span style={{color:'var(--ink-2)'}}>{label}</span>
      <div style={{height: 6, background:'var(--bg-alt)', borderRadius: 3, overflow:'hidden'}}>
        <div className="fe-bar-fill" style={{
          height:'100%', width: `${Math.max(0, Math.min(100, pct))}%`, background: cor,
        }}/>
      </div>
      <span style={{textAlign:'right', fontWeight: 600, color: cor}}>{pct}</span>
    </div>
  );
}

// =====================================================================
// PropostaDetalhe — modal full screen no mobile, modo Ajustar editável
// =====================================================================
function PropostaDetalhe({
  proposta, mesAlvo, hospitais, blocosAgendaReal, preferencias,
  readonly, onClose, onAdotar, onCompartilhar, onExportarPDF, onSalvarAjustes,
}) {
  const [y, m] = mesAlvo.split('-').map(Number);
  const totalDias = new Date(y, m, 0).getDate();
  const dias = Array.from({length: totalDias}, (_, i) => window.toISO(new Date(y, m-1, i+1)));
  const primeiroDow = window.diaSemanaBR(dias[0]);

  const [modoAjustar, setModoAjustar] = useStateFE(false);
  const [blocosEdit, setBlocosEdit] = useStateFE(proposta.blocosPropostos || []);
  const [editandoBloco, setEditandoBloco] = useStateFE(null);

  // Modo "Adotar parcial": checkboxes por bloco antes de mover pra agenda
  const [modoSelecionar, setModoSelecionar] = useStateFE(false);
  const [blocosSelecionados, setBlocosSelecionados] = useStateFE(() => new Set());

  // Re-sync se a proposta mudou
  useEffectFE(() => { setBlocosEdit(proposta.blocosPropostos || []); }, [proposta]);
  // Quando entra em modoSelecionar, marca todos por padrão
  useEffectFE(() => {
    if (modoSelecionar) {
      setBlocosSelecionados(new Set((proposta.blocosPropostos || []).map((_, i) => i)));
    }
  }, [modoSelecionar, proposta]);

  const idsAgenda = new Set((blocosAgendaReal || [])
    .filter(b => b.tipo === 'plantao')
    .map(b => b.data));

  // Score recalculado em tempo real durante edição
  const scoreLive = useMemoFE(() => {
    if (!modoAjustar) return null;
    return window.recalcularScoreProposta(blocosEdit, hospitais, preferencias);
  }, [modoAjustar, blocosEdit, hospitais, preferencias]);

  const blocosVisualizados = modoAjustar ? blocosEdit : (proposta.blocosPropostos || []);
  const scoreVisualizado = modoAjustar
    ? { total: scoreLive?.total, breakdown: scoreLive?.breakdown, porHospital: scoreLive?.porHospital, janelasLongas: scoreLive?.janelasLongas }
    : proposta.score;

  const removerBloco = (idx) => {
    setBlocosEdit(blocosEdit.filter((_, i) => i !== idx));
    setEditandoBloco(null);
  };
  const moverBloco = (idx, deltaDays) => {
    const b = blocosEdit[idx];
    const novaData = window.addDias(b.data, deltaDays);
    if (novaData < `${mesAlvo}-01` || novaData > `${mesAlvo}-${String(totalDias).padStart(2,'0')}`) return;
    const novos = [...blocosEdit];
    novos[idx] = { ...b, data: novaData };
    setBlocosEdit(novos);
  };
  const trocarTurno = (idx, novoTurno) => {
    const b = blocosEdit[idx];
    const h = hospitais.find(x => x.id === b.hospitalId);
    const t = h?.turnos?.[novoTurno];
    if (!t) return;
    const novos = [...blocosEdit];
    novos[idx] = { ...b, turno: novoTurno, horaInicio: t.inicio, duracao: t.duracao };
    setBlocosEdit(novos);
  };

  const dirty = JSON.stringify(blocosEdit) !== JSON.stringify(proposta.blocosPropostos || []);
  const salvar = async () => {
    if (!dirty) return;
    await onSalvarAjustes(blocosEdit);
    setModoAjustar(false);
  };

  return (
    <div onClick={onClose} className="fe-modal-shell" style={{
      position:'fixed', inset: 0, zIndex: 100,
      background: 'rgba(58,46,42,0.55)',
      display:'flex', alignItems:'center', justifyContent:'center',
      padding:'var(--s-4)',
    }}>
      <div onClick={e => e.stopPropagation()} className="fe-modal-card" style={{
        background:'var(--bg)', borderRadius:'var(--r-lg)',
        maxWidth: 900, width:'100%', maxHeight:'90vh', overflow:'auto',
        padding:'var(--s-5)',
      }}>
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', flexWrap:'wrap', gap:8, marginBottom:'var(--s-3)'}}>
          <div>
            <div className="eyebrow">Proposta {proposta.status ? `· ${proposta.status}` : ''}</div>
            <h2 className="h2" style={{margin: 0}}>
              {window.LABEL_VARIANTE[proposta.variante] || proposta.titulo || proposta.variante}
              <span style={{marginLeft: 12, fontSize: 16, color:'var(--ink-3)', fontWeight: 400}}>
                {window.MESES[m-1]} {y}
              </span>
            </h2>
          </div>
          <div style={{display:'flex', gap: 8, alignItems:'center', flexWrap:'wrap'}}>
            {!readonly && proposta.id && (
              <button type="button" className="btn"
                onClick={() => { setModoAjustar(!modoAjustar); setModoSelecionar(false); }}
                style={{
                  padding: '6px 14px', fontSize: 12,
                  background: modoAjustar ? 'var(--colo-lavender, #A299CB)' : 'var(--bg)',
                  color: modoAjustar ? 'var(--bg)' : 'var(--ink)',
                  border: modoAjustar ? 'none' : '1px solid var(--line)',
                }}>
                {modoAjustar ? 'Saindo do ajuste' : '✎ Ajustar'}
              </button>
            )}
            {!readonly && (
              <button type="button" className="btn"
                onClick={() => { setModoSelecionar(!modoSelecionar); setModoAjustar(false); }}
                style={{
                  padding: '6px 14px', fontSize: 12,
                  background: modoSelecionar ? 'var(--colo-blue-tag, #3F6E9C)' : 'var(--bg)',
                  color: modoSelecionar ? 'var(--bg)' : 'var(--ink)',
                  border: modoSelecionar ? 'none' : '1px solid var(--line)',
                }}>
                {modoSelecionar ? 'Saindo' : '☑ Selecionar'}
              </button>
            )}
            <button type="button" className="btn btn--ghost" onClick={onClose}
              style={{padding: '6px 14px'}}>Fechar</button>
          </div>
        </div>

        {modoAjustar && (
          <div className="card" style={{
            padding: '8px 12px', fontSize: 11,
            background: 'var(--colo-lavender-50, #ECEAF4)',
            border: '1px solid #A299CB55',
            borderRadius: 'var(--r-md)', marginBottom: 'var(--s-3)',
          }}>
            <strong>Modo Ajustar:</strong> clica num plantão pra mover, trocar turno, ou remover. Score recalcula na hora.
          </div>
        )}

        {modoSelecionar && (
          <div className="card" style={{
            padding: '8px 12px', fontSize: 11,
            background: 'var(--colo-blue-50, #EAF2F9)',
            border: '1px solid #3F6E9C55',
            borderRadius: 'var(--r-md)', marginBottom: 'var(--s-3)',
            display:'flex', alignItems:'center', gap: 8, flexWrap:'wrap',
          }}>
            <strong>Modo Selecionar:</strong>
            <span>{blocosSelecionados.size} de {(proposta.blocosPropostos||[]).length} marcados</span>
            <button type="button"
              onClick={() => setBlocosSelecionados(new Set((proposta.blocosPropostos||[]).map((_,i)=>i)))}
              style={{padding:'2px 8px', fontSize:11, border:'1px solid var(--line)', background:'var(--bg)', borderRadius:'var(--r-pill)', cursor:'pointer'}}>
              Marcar todos
            </button>
            <button type="button"
              onClick={() => setBlocosSelecionados(new Set())}
              style={{padding:'2px 8px', fontSize:11, border:'1px solid var(--line)', background:'var(--bg)', borderRadius:'var(--r-pill)', cursor:'pointer'}}>
              Desmarcar todos
            </button>
            <span style={{marginLeft:'auto', fontSize: 11, color:'var(--ink-3)'}}>Clica nos plantões pra alternar</span>
          </div>
        )}

        {/* Mini calendário */}
        <div style={{
          display:'grid', gridTemplateColumns:'repeat(7, 1fr)', gap: 4,
          marginBottom:'var(--s-4)',
        }}>
          {['Seg','Ter','Qua','Qui','Sex','Sáb','Dom'].map(d => (
            <div key={d} className="eyebrow" style={{fontSize: 10, textAlign:'center', padding:'4px 0'}}>{d}</div>
          ))}
          {Array.from({length: primeiroDow}).map((_, i) => <div key={`pad${i}`}/>)}
          {dias.map(iso => {
            const blocosNoDia = blocosVisualizados
              .map((b, originalIdx) => ({ b, originalIdx }))
              .filter(x => x.b.data === iso);
            const conflito = idsAgenda.has(iso) && blocosNoDia.length > 0;
            const dow = window.diaSemanaBR(iso);
            const ehFDS = dow === 5 || dow === 6;
            return (
              <div key={iso} style={{
                minHeight: 70, padding: 4,
                background: ehFDS ? 'var(--bg-alt)' : 'var(--bg)',
                border: conflito ? '2px solid var(--err, #B25A4D)' : '1px solid var(--line)',
                borderRadius: 'var(--r-sm)', fontSize: 11,
              }}>
                <div style={{fontWeight: 700, fontSize: 11, color: ehFDS ? 'var(--ink-3)' : 'var(--ink)'}}>
                  {parseInt(iso.split('-')[2])}
                </div>
                {blocosNoDia.map(({b, originalIdx}) => {
                  const h = hospitais.find(x => x.id === b.hospitalId);
                  const selecionado = blocosSelecionados.has(originalIdx);
                  const interativo = modoAjustar || modoSelecionar;
                  return (
                    <div key={originalIdx}
                      onClick={interativo ? () => {
                        if (modoSelecionar) {
                          const next = new Set(blocosSelecionados);
                          if (next.has(originalIdx)) next.delete(originalIdx);
                          else next.add(originalIdx);
                          setBlocosSelecionados(next);
                        } else if (modoAjustar) {
                          setEditandoBloco({ idx: originalIdx, bloco: b });
                        }
                      } : undefined}
                      style={{
                        marginTop: 2, padding: '2px 4px',
                        background: h?.corWash || 'var(--bg-alt)',
                        borderLeft: `3px solid ${h?.cor || 'var(--ink)'}`,
                        borderRadius: 2,
                        fontSize: 10, fontWeight: 600,
                        color: h?.corDeep || 'var(--ink)',
                        cursor: interativo ? 'pointer' : 'default',
                        outline: modoAjustar ? `1px dashed ${h?.corDeep || 'var(--ink-3)'}` : 'none',
                        opacity: modoSelecionar && !selecionado ? 0.35 : 1,
                        position: 'relative',
                      }}>
                      {modoSelecionar && (
                        <span style={{
                          position:'absolute', top: -2, right: -2,
                          width: 12, height: 12, borderRadius: 2,
                          background: selecionado ? (h?.corDeep || 'var(--ink)') : 'var(--bg)',
                          border: `1px solid ${h?.corDeep || 'var(--ink)'}`,
                          color: 'var(--bg)', fontSize: 9, fontWeight: 900,
                          display:'grid', placeItems:'center', lineHeight: 1,
                        }}>{selecionado ? '✓' : ''}</span>
                      )}
                      {h?.abrev || '?'} {window.fmtHora(b.horaInicio)}
                    </div>
                  );
                })}
                {conflito && (
                  <div style={{fontSize: 9, color:'var(--err, #B25A4D)', marginTop: 2}}>⚠ conflito</div>
                )}
              </div>
            );
          })}
        </div>

        {/* Score breakdown (mesma componentização dos cards) */}
        {scoreVisualizado?.breakdown && (
          <div style={{display:'grid', gap: 4, marginBottom:'var(--s-4)', maxWidth: 480}}>
            <ScoreBar label="Mínimos" pct={scoreVisualizado.breakdown.minimosScore ?? 0}/>
            <ScoreBar label="Qualidade" pct={scoreVisualizado.breakdown.qualidadeScore ?? 0}/>
            <ScoreBar label="Preferências" pct={scoreVisualizado.breakdown.prefsScore ?? 0}/>
            {scoreVisualizado.breakdown.valorScore != null && (
              <ScoreBar label="Financeiro" pct={scoreVisualizado.breakdown.valorScore}/>
            )}
          </div>
        )}

        {/* Card financeiro destacado */}
        {scoreVisualizado?.financeiro?.bruto > 0 && (
          <div className="card" style={{
            padding:'var(--s-4)', marginBottom:'var(--s-4)',
            background:'var(--ok-bg, #ECF6E7)',
            border:'1px solid var(--ok, #5A6E50)33',
            display:'grid', gap: 8,
          }}>
            <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', flexWrap:'wrap', gap: 8}}>
              <div>
                <div className="eyebrow" style={{fontSize: 10, color:'var(--ok, #5A6E50)'}}>💰 Estimativa financeira</div>
                <div style={{fontFamily:'var(--font-display)', fontSize: 32, fontWeight: 500, color:'var(--ok, #5A6E50)', lineHeight: 1, marginTop: 4}}>
                  {window.fmtBRL(scoreVisualizado.financeiro.bruto)}
                </div>
                <div className="small" style={{fontSize: 11, marginTop: 2}}>
                  bruto · líquido aprox {window.fmtBRL(scoreVisualizado.financeiro.liquido)}
                </div>
              </div>
              {scoreVisualizado.financeiro.meta && (
                <div style={{textAlign:'right', fontSize: 12}}>
                  <div className="small" style={{fontSize: 11}}>Meta:</div>
                  <div style={{fontWeight: 600}}>
                    {window.fmtBRL(scoreVisualizado.financeiro.meta.min)}
                    {scoreVisualizado.financeiro.meta.max > 0 && ` – ${window.fmtBRL(scoreVisualizado.financeiro.meta.max)}`}
                  </div>
                </div>
              )}
            </div>
            <div style={{display:'flex', gap: 6, flexWrap:'wrap'}}>
              {Object.entries(scoreVisualizado.financeiro.porHospital || {}).sort((a,b) => b[1]-a[1]).map(([abrev, val]) => (
                <span key={abrev} style={{
                  padding:'2px 8px', fontSize: 11,
                  background:'var(--bg)', border:'1px solid var(--line)',
                  borderRadius:'var(--r-pill)',
                  fontFamily:'ui-monospace, monospace',
                }}>
                  <strong>{abrev}</strong> {window.fmtBRL(val)}
                </span>
              ))}
            </div>
          </div>
        )}

        {/* Resumo por hospital */}
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(180px, 1fr))', gap:'var(--s-3)', marginBottom:'var(--s-4)'}}>
          {Object.values(scoreVisualizado?.porHospital || {}).map((x, i) => (
            <div key={i} className="card" style={{padding:'var(--s-3)'}}>
              <div className="eyebrow" style={{fontSize: 10}}>{x.hospitalNome}</div>
              <div style={{fontSize: 13, fontWeight: 600, marginTop: 4}}>{x.plantoes} plantões</div>
              <div className="small" style={{fontSize: 11}}>{x.fds} FDS · {x.horas}h</div>
            </div>
          ))}
        </div>

        {/* Botões de ação */}
        {!readonly && (
          <div className="fe-actions" style={{display:'flex', gap: 8, justifyContent:'flex-end', flexWrap:'wrap'}}>
            {modoAjustar && (
              <button type="button" className="btn"
                onClick={salvar} disabled={!dirty}
                style={{
                  padding: '8px 16px',
                  background: dirty ? 'var(--colo-lavender, #A299CB)' : 'var(--bg-alt)',
                  color: dirty ? 'var(--bg)' : 'var(--ink-3)',
                }}>
                Salvar ajustes
              </button>
            )}
            {!modoAjustar && (
              <>
                {onExportarPDF && (
                  <button type="button" className="btn btn--ghost" onClick={onExportarPDF}
                    style={{padding: '8px 16px'}}>
                    Imprimir / PDF
                  </button>
                )}
                <button type="button" className="btn btn--ghost" onClick={onCompartilhar}
                  style={{padding: '8px 16px'}}>
                  Compartilhar texto
                </button>
                {!readonly && (() => {
                  const selecionarParcial = modoSelecionar;
                  const totalDisponivel = (proposta.blocosPropostos || []).length;
                  const qtd = selecionarParcial ? blocosSelecionados.size : totalDisponivel;
                  const handleAdotar = () => {
                    if (selecionarParcial) {
                      const subset = (proposta.blocosPropostos || [])
                        .filter((_, i) => blocosSelecionados.has(i));
                      onAdotar(subset);
                    } else {
                      onAdotar(null); // null = todos
                    }
                  };
                  return (
                    <button type="button" className="btn"
                      onClick={handleAdotar} disabled={qtd === 0}
                      style={{
                        padding: '8px 16px',
                        background: qtd > 0 ? 'var(--colo-sage, #5A6E50)' : 'var(--bg-alt)',
                        color: qtd > 0 ? 'var(--bg)' : 'var(--ink-3)',
                      }}>
                      Adotar {selecionarParcial ? `${qtd} de ${totalDisponivel}` : 'tudo'}
                    </button>
                  );
                })()}
              </>
            )}
          </div>
        )}

        {/* Popup de edição de bloco no modo Ajustar */}
        {editandoBloco && (
          <EditarBlocoPopup
            bloco={editandoBloco.bloco}
            hospital={hospitais.find(h => h.id === editandoBloco.bloco.hospitalId)}
            onMover={(delta) => moverBloco(editandoBloco.idx, delta)}
            onTrocarTurno={(t) => trocarTurno(editandoBloco.idx, t)}
            onRemover={() => removerBloco(editandoBloco.idx)}
            onClose={() => setEditandoBloco(null)}/>
        )}
      </div>
    </div>
  );
}

function EditarBlocoPopup({ bloco, hospital, onMover, onTrocarTurno, onRemover, onClose }) {
  const turnosDisponiveis = hospital?.regrasEscala?.turnosPermitidos || Object.keys(hospital?.turnos || {});
  return (
    <div onClick={onClose} style={{
      position:'fixed', inset: 0, zIndex: 200, background: 'rgba(58,46,42,0.7)',
      display:'grid', placeItems:'center', padding: 'var(--s-4)',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        background:'var(--bg)', borderRadius:'var(--r-lg)',
        padding:'var(--s-4)', maxWidth: 360, width:'100%',
        display:'grid', gap:'var(--s-3)',
      }}>
        <div>
          <div className="eyebrow">Editando plantão</div>
          <div style={{fontSize: 14, fontWeight: 600}}>
            {hospital?.abrev} · {window.fmtDataCurto(bloco.data)} · {window.fmtHora(bloco.horaInicio)} ({bloco.duracao}h)
          </div>
        </div>

        <div>
          <div className="eyebrow" style={{fontSize: 10, marginBottom: 4}}>Mover dia</div>
          <div style={{display:'flex', gap: 4}}>
            {[-7, -1, +1, +7].map(d => (
              <button key={d} type="button" className="btn btn--ghost"
                onClick={() => onMover(d)}
                style={{flex: 1, padding: '6px 0', fontSize: 12, justifyContent:'center'}}>
                {d > 0 ? `+${d}` : d}
              </button>
            ))}
          </div>
        </div>

        {turnosDisponiveis.length > 0 && (
          <div>
            <div className="eyebrow" style={{fontSize: 10, marginBottom: 4}}>Trocar turno</div>
            <div style={{display:'flex', gap: 4, flexWrap:'wrap'}}>
              {turnosDisponiveis.map(t => (
                <button key={t} type="button"
                  onClick={() => onTrocarTurno(t)}
                  style={{
                    padding: '4px 10px', fontSize: 12,
                    background: bloco.turno === t ? 'var(--ink)' : 'var(--bg)',
                    color: bloco.turno === t ? 'var(--bg)' : 'var(--ink-2)',
                    border: '1px solid var(--line)', borderRadius: 'var(--r-pill)',
                    cursor:'pointer', textTransform:'capitalize',
                  }}>{t}</button>
              ))}
            </div>
          </div>
        )}

        <div style={{display:'flex', gap: 8, marginTop:'var(--s-2)'}}>
          <button type="button" className="btn btn--ghost"
            onClick={() => { if (confirm('Remover esse plantão da proposta?')) onRemover(); }}
            style={{flex: 1, justifyContent:'center', color:'var(--err, #B25A4D)'}}>
            Remover
          </button>
          <button type="button" className="btn"
            onClick={onClose}
            style={{flex: 1, justifyContent:'center', background:'var(--ink)', color:'var(--bg)'}}>
            OK
          </button>
        </div>
      </div>
    </div>
  );
}

function HistoricoAdotadas({ propostas, hospitais, carregando, onVer }) {
  if (carregando) return <p className="small">Carregando…</p>;
  if (propostas.length === 0) {
    return (
      <div className="card" style={{padding:'var(--s-5)', textAlign:'center', color:'var(--ink-3)'}}>
        Nenhuma proposta adotada ainda. Quando você adotar uma, aparece aqui.
      </div>
    );
  }
  return (
    <div style={{display:'grid', gap: 8}}>
      {propostas.map(p => (
        <div key={p.id} style={{
          display:'flex', alignItems:'center', gap:'var(--s-3)', flexWrap:'wrap',
          padding: 'var(--s-3) var(--s-4)',
          background: 'var(--bg)', border: '1px solid var(--line)',
          borderRadius: 'var(--r-md)',
        }}>
          <strong style={{fontSize: 13}}>{p.titulo || p.variante}</strong>
          <span className="small" style={{fontSize: 11}}>
            {window.MESES[parseInt(p.mesAlvo.split('-')[1]) - 1]} {p.mesAlvo.split('-')[0]} · {p.blocosPropostos.length} plantões
          </span>
          <span style={{
            padding: '2px 8px', fontSize: 10, fontWeight: 700,
            background: 'var(--ok-bg, #ECF6E7)', color: 'var(--ok, #5A6E50)',
            borderRadius: 'var(--r-pill)',
            textTransform:'uppercase', letterSpacing: '0.04em',
          }}>adotada</span>
          <span className="small" style={{fontSize: 10, marginLeft:'auto', color:'var(--ink-3)'}}>
            {new Date(p.atualizadaEm || p.criadaEm).toLocaleDateString('pt-BR')}
          </span>
          <button type="button" className="btn btn--ghost"
            style={{padding: '4px 10px', fontSize: 11}} onClick={() => onVer(p)}>Ver</button>
        </div>
      ))}
    </div>
  );
}

// =====================================================================
// Texto de compartilhamento — agrupado por hospital, formatado pra WhatsApp
// =====================================================================
function formatarTextoCompartilhamento(proposta, hospitais, mesAlvo) {
  const [y, m] = mesAlvo.split('-').map(Number);
  const linhas = [];
  linhas.push(`Proposta de escala — ${window.MESES[m-1]} ${y}`);
  linhas.push('');
  const porHosp = {};
  for (const b of proposta.blocosPropostos) {
    const h = hospitais.find(x => x.id === b.hospitalId);
    const abrev = h?.abrev || `Hospital ${b.hospitalId}`;
    if (!porHosp[abrev]) porHosp[abrev] = [];
    porHosp[abrev].push(b);
  }
  for (const abrev of Object.keys(porHosp).sort()) {
    linhas.push(`*${abrev}* — ${porHosp[abrev].length} plantões:`);
    porHosp[abrev]
      .sort((a, b) => a.data.localeCompare(b.data))
      .forEach(b => {
        const dt = window.fromISO(b.data);
        const dow = window.DIAS_SEMANA[window.diaSemanaBR(b.data)];
        linhas.push(`  • ${dow} ${dt.getDate()}/${m.toString().padStart(2,'0')} · ${b.turno || `${b.horaInicio}h`} (${b.duracao}h)`);
      });
    linhas.push('');
  }
  linhas.push(`Total: ${proposta.blocosPropostos.length} plantões`);
  return linhas.join('\n');
}

Object.assign(window, { FazerEscalaView });
