/* global React */
const { useState, useMemo, useEffect } = React;

/* =============================================================================
   GALAHOME — Calculadoras financieras
   Spec v1.0 (Abril 2026): /compra → /calculadoras
   Contiene: Calculadora de Crédito Hipotecario + Calculadora ROI inversionista
   ============================================================================= */

/* ----------------------------- DATOS VERIFICADOS --------------------------- */

const BANCOS = [
  { key: 'bbva',        label: 'BBVA',        tafMin: 10.75, tafMax: 12.50, cat: 13.2, engMin: 10 },
  { key: 'santander',   label: 'Santander',   tafMin:  9.79, tafMax: 13.50, cat: 12.1, engMin: 10 },
  { key: 'hsbc',        label: 'HSBC',        tafMin:  9.65, tafMax: 12.25, cat: 12.4, engMin:  3 },
  { key: 'banorte',     label: 'Banorte',     tafMin:  9.38, tafMax: 11.25, cat: 11.9, engMin: 10 },
  { key: 'scotiabank',  label: 'Scotiabank',  tafMin: 10.20, tafMax: 13.64, cat: 12.8, engMin:  5 },
  { key: 'citibanamex', label: 'Citibanamex', tafMin:  9.25, tafMax: 11.11, cat: 12.4, engMin: 10 },
];

const INFONAVIT_RANGOS = [
  { key: 'min',   label: 'Salario mínimo (~$8,364)', tasa: 3.50 },
  { key: 'medio', label: 'Ingresos medios',           tasa: 7.00 },
  { key: 'alto',  label: 'Ingresos altos',            tasa: 10.45 },
];

const FOVISSSTE_TIPOS = [
  { key: 'tradicional', label: 'Tradicional (Pesos)',  tasa: 9.5,  max: 1405090 },
  { key: 'paratodos',   label: 'Fovissste para Todos', tasa: 9.88, max: 4800000 },
];

const ORGANISMOS = [
  { key: 'banca',      label: 'Banca comercial' },
  { key: 'infonavit',  label: 'Infonavit' },
  { key: 'cofinavit',  label: 'Cofinavit (Infonavit + banco)' },
  { key: 'fovissste',  label: 'Fovissste' },
];

const CATALOGO_MOCK = [
  { id: 1, title: 'Depto Del Valle Norte', zone: 'Del Valle · CDMX', price: 6800000,  beds: 2, baths: 2, m2: 95,  img: 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=900&q=70' },
  { id: 2, title: 'Penthouse Narvarte',     zone: 'Narvarte · CDMX',  price: 7500000,  beds: 3, baths: 2, m2: 128, img: 'https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?auto=format&fit=crop&w=900&q=70' },
  { id: 3, title: 'Loft Xoco',              zone: 'Xoco · CDMX',      price: 5900000,  beds: 1, baths: 1, m2: 72,  img: 'https://images.unsplash.com/photo-1613977257363-707ba9348227?auto=format&fit=crop&w=900&q=70' },
  { id: 4, title: 'Residencia Coyoacán',    zone: 'Coyoacán · CDMX',  price: 12400000, beds: 4, baths: 3, m2: 240, img: 'https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=900&q=70' },
  { id: 5, title: 'Depto Mixcoac',          zone: 'Mixcoac · CDMX',   price: 4200000,  beds: 2, baths: 1, m2: 68,  img: 'https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?auto=format&fit=crop&w=900&q=70' },
];

/* -------------------------------- HELPERS --------------------------------- */

const fmtMXN = (n) => {
  if (!isFinite(n) || n == null) return '—';
  return '$' + Math.round(n).toLocaleString('es-MX') + ' MXN';
};
const fmtMXNcompact = (n) => {
  if (!isFinite(n) || n == null) return '—';
  if (n >= 1e6) return '$' + (n/1e6).toFixed(2) + 'M MXN';
  if (n >= 1e3) return '$' + (n/1e3).toFixed(0) + 'K MXN';
  return '$' + Math.round(n).toLocaleString('es-MX');
};
const fmtPct = (n, d=2) => (isFinite(n) ? n.toFixed(d) + '%' : '—');

// Fórmula de amortización francesa
function mensualidad(P, tasaAnual, anios) {
  if (!P || P <= 0 || !anios) return 0;
  const r = (tasaAnual / 100) / 12;
  const n = anios * 12;
  if (r === 0) return P / n;
  return P * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
}

/* -------------------- HOOK para la paleta de acento (tweak) --------------- */

function useAccent() {
  const [accent, setAccent] = useState('violeta');
  const palettes = {
    violeta:  { bg: '#8A46CE', fg: '#fff',  soft: 'rgba(138,70,206,0.12)', softFg: '#5B2E8E', ring: 'rgba(138,70,206,0.22)' },
    azul:     { bg: '#0D2B5E', fg: '#fff',  soft: 'rgba(13,43,94,0.10)',   softFg: '#0D2B5E', ring: 'rgba(13,43,94,0.22)' },
    lavanda:  { bg: '#C4A8E8', fg: '#1C1C1E', soft: 'rgba(196,168,232,0.25)', softFg: '#5B2E8E', ring: 'rgba(196,168,232,0.35)' },
  };
  return { accent, setAccent, c: palettes[accent] };
}

/* ============================================================================
   COMPONENTES DE UI REUTILIZABLES
   ============================================================================ */

function FieldLabel({ children, hint }) {
  return (
    <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:8}}>
      <label style={{fontSize:12,fontWeight:600,color:'var(--gh-azul-profundo)',letterSpacing:'.04em',textTransform:'uppercase'}}>{children}</label>
      {hint && <span style={{fontSize:11,color:'rgba(28,28,30,0.5)'}}>{hint}</span>}
    </div>
  );
}

function CurrencyInput({ value, onChange, placeholder, prefix='$' }) {
  const display = value ? Number(value).toLocaleString('es-MX') : '';
  return (
    <div style={{position:'relative'}}>
      <span style={{position:'absolute',left:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)',fontSize:14,pointerEvents:'none'}}>{prefix}</span>
      <input
        inputMode="numeric"
        value={display}
        placeholder={placeholder}
        onChange={(e)=>{
          const raw = e.target.value.replace(/[^\d]/g, '');
          onChange(raw ? Number(raw) : 0);
        }}
        style={{width:'100%',padding:'14px 14px 14px 28px',fontSize:16,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',color:'var(--gh-gris-carbon)',fontWeight:500}}
      />
    </div>
  );
}

function Slider({ value, min, max, step=1, onChange, formatter=v=>v }) {
  return (
    <div>
      <div style={{display:'flex',justifyContent:'space-between',fontSize:13,color:'rgba(28,28,30,0.6)',marginBottom:6}}>
        <span>{formatter(min)}</span>
        <span style={{color:'var(--gh-azul-profundo)',fontWeight:700,fontSize:15}}>{formatter(value)}</span>
        <span>{formatter(max)}</span>
      </div>
      <input type="range" min={min} max={max} step={step} value={value}
        onChange={e=>onChange(Number(e.target.value))}
        style={{width:'100%', accentColor:'var(--gh-violeta)'}}/>
    </div>
  );
}

function Warning({ kind='info', children }) {
  const bg = kind === 'error' ? 'rgba(229,65,81,0.08)' : kind === 'warn' ? 'rgba(229,165,30,0.08)' : 'rgba(138,70,206,0.06)';
  const bd = kind === 'error' ? '#E54151' : kind === 'warn' ? '#E5A51E' : 'var(--gh-violeta)';
  return (
    <div style={{display:'flex',gap:10,padding:'10px 12px',background:bg,borderLeft:`3px solid ${bd}`,borderRadius:6,fontSize:13,lineHeight:1.45,color:'var(--gh-gris-carbon)'}}>
      <div style={{flexShrink:0,color:bd,fontWeight:700}}>!</div>
      <div>{children}</div>
    </div>
  );
}

/* ============================================================================
   BARRA DE AMORTIZACIÓN (visual: capital vs intereses)
   ============================================================================ */

function AmortizationBar({ capital, intereses, accent }) {
  const total = capital + intereses;
  const pctCap = total ? (capital / total) * 100 : 0;
  return (
    <div>
      <div style={{display:'flex',justifyContent:'space-between',fontSize:12,marginBottom:8,color:'rgba(28,28,30,0.6)'}}>
        <span>Capital: <strong style={{color:'var(--gh-azul-profundo)'}}>{fmtPct(pctCap,0)}</strong></span>
        <span>Intereses: <strong style={{color:accent.bg}}>{fmtPct(100-pctCap,0)}</strong></span>
      </div>
      <div style={{height:12,borderRadius:999,background:'#EEF0F3',display:'flex',overflow:'hidden'}}>
        <div style={{width:pctCap+'%',background:'var(--gh-azul-profundo)',transition:'width 400ms cubic-bezier(.2,.9,.3,1)'}}/>
        <div style={{width:(100-pctCap)+'%',background:accent.bg,transition:'width 400ms cubic-bezier(.2,.9,.3,1)'}}/>
      </div>
    </div>
  );
}

/* ============================================================================
   CALCULADORA — CRÉDITO HIPOTECARIO
   ============================================================================ */

function CalculadoraCredito({ accent }) {
  // Inputs
  const [precio, setPrecio]         = useState(6500000);
  const [organismo, setOrganismo]   = useState('banca');
  const [bancoKey, setBancoKey]     = useState('banorte');
  const [engPct, setEngPct]         = useState(20);
  const [plazo, setPlazo]           = useState(20);
  const [infonavitRango, setInfonavitRango] = useState('medio');
  const [fovisssteTipo, setFovisssteTipo]   = useState('tradicional');
  const [subcuenta, setSubcuenta]   = useState(200000);
  const [tasa, setTasa]             = useState(9.38);

  // Gate + form
  const [unlocked, setUnlocked]   = useState(false);
  const [showForm, setShowForm]   = useState(false);
  const [formData, setFormData]   = useState({ email:'', whatsapp:'' });
  const [sent, setSent]           = useState(false);

  const banco = BANCOS.find(b => b.key === bancoKey);
  const infonavitR = INFONAVIT_RANGOS.find(r => r.key === infonavitRango);
  const fovTipo = FOVISSSTE_TIPOS.find(t => t.key === fovisssteTipo);

  // Sync default tasa cuando cambia banco/organismo
  useEffect(() => {
    if (organismo === 'banca' || organismo === 'cofinavit') setTasa(banco.tafMin);
    else if (organismo === 'infonavit') setTasa(infonavitR.tasa);
    else if (organismo === 'fovissste') setTasa(fovTipo.tasa);
  }, [organismo, bancoKey, infonavitRango, fovisssteTipo]);

  // Montos derivados
  const { monto, enganche, M, totalPagar, intereses, ingresoMin, warnings } = useMemo(() => {
    const warns = [];
    let eng;
    if (organismo === 'banca' || organismo === 'cofinavit') {
      eng = precio * (engPct/100);
      if (engPct < 10) warns.push({kind:'error', text:'Enganche mínimo aceptado por la mayoría de los bancos es 10%.'});
      else if (engPct < 20) warns.push({kind:'warn', text:'Con enganche menor al 20% la tasa real puede ser mayor a la mostrada.'});
    } else {
      // Infonavit / Fovissste: enganche = subcuenta
      eng = Math.min(subcuenta, precio);
    }
    const monto = Math.max(0, precio - eng);
    const M = mensualidad(monto, tasa, plazo);
    const total = M * plazo * 12;
    const intereses = total - monto;

    // Ingreso mínimo por organismo
    let ingMin;
    if (organismo === 'banca' || organismo === 'cofinavit') ingMin = M / 0.30;
    else if (organismo === 'infonavit') ingMin = M / 0.25;
    else ingMin = M / 0.25;

    // Advertencias adicionales
    if ((organismo === 'banca' || organismo === 'cofinavit') && tasa < 8) warns.push({kind:'warn', text:'Las tasas actuales del mercado están por encima de este valor.'});
    if (precio < 500000) warns.push({kind:'error', text:'Precio mínimo $500,000 MXN.'});
    if (plazo < 5 || plazo > 30) warns.push({kind:'error', text:'Plazo fuera de rango (5–30 años).'});

    return { monto, enganche: eng, M, totalPagar: total, intereses, ingresoMin: ingMin, warnings: warns };
  }, [precio, organismo, engPct, subcuenta, plazo, tasa]);

  // Catálogo filtrado por precio ±20%
  const catalogoMatch = useMemo(() => {
    const lo = precio * 0.8, hi = precio * 1.2;
    return CATALOGO_MOCK.filter(p => p.price >= lo && p.price <= hi).slice(0,3);
  }, [precio]);

  const submitForm = (e) => {
    e.preventDefault();
    // Mock — en producción enviaría a Notion
    setSent(true);
    setUnlocked(true);
    setTimeout(() => setShowForm(false), 1200);
  };

  return (
    <div style={{display:'grid',gridTemplateColumns:'minmax(0,440px) 1fr',gap:40,alignItems:'start'}}>

      {/* -------- COLUMNA IZQUIERDA — INPUTS -------- */}
      <div style={{background:'#fff',borderRadius:16,padding:32,boxShadow:'var(--gh-shadow-md)',border:'1px solid #EEF0F3',position:'sticky',top:140}}>
        <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 1 · Datos</div>
        <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:26,color:'var(--gh-azul-profundo)',margin:'0 0 24px'}}>Simula tu crédito</h3>

        {/* Precio */}
        <FieldLabel hint="Min $500,000">Precio de la propiedad</FieldLabel>
        <CurrencyInput value={precio} onChange={setPrecio} placeholder="6,500,000"/>

        {/* Organismo */}
        <div style={{marginTop:22}}>
          <FieldLabel>Organismo / tipo de crédito</FieldLabel>
          <select value={organismo} onChange={e=>setOrganismo(e.target.value)}
            style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',background:'#fff'}}>
            {ORGANISMOS.map(o=><option key={o.key} value={o.key}>{o.label}</option>)}
          </select>
        </div>

        {/* Condicional: banco */}
        {(organismo === 'banca' || organismo === 'cofinavit') && (
          <div style={{marginTop:22}}>
            <FieldLabel>Institución bancaria</FieldLabel>
            <select value={bancoKey} onChange={e=>setBancoKey(e.target.value)}
              style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',background:'#fff'}}>
              {BANCOS.map(b=><option key={b.key} value={b.key}>{b.label} · TAF desde {b.tafMin}%</option>)}
            </select>
          </div>
        )}

        {/* Condicional: rango salarial Infonavit */}
        {organismo === 'infonavit' && (
          <div style={{marginTop:22}}>
            <FieldLabel>Rango de ingreso mensual</FieldLabel>
            <select value={infonavitRango} onChange={e=>setInfonavitRango(e.target.value)}
              style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',background:'#fff'}}>
              {INFONAVIT_RANGOS.map(r=><option key={r.key} value={r.key}>{r.label} · {r.tasa}%</option>)}
            </select>
          </div>
        )}

        {/* Condicional: tipo Fovissste */}
        {organismo === 'fovissste' && (
          <div style={{marginTop:22}}>
            <FieldLabel>Tipo de crédito Fovissste</FieldLabel>
            <select value={fovisssteTipo} onChange={e=>setFovisssteTipo(e.target.value)}
              style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',background:'#fff'}}>
              {FOVISSSTE_TIPOS.map(t=><option key={t.key} value={t.key}>{t.label} · {t.tasa}%</option>)}
            </select>
          </div>
        )}

        {/* Enganche */}
        <div style={{marginTop:22}}>
          {(organismo === 'banca' || organismo === 'cofinavit') ? (
            <>
              <FieldLabel hint={`Equivale a ${fmtMXNcompact(enganche)}`}>Enganche (%)</FieldLabel>
              <Slider value={engPct} min={5} max={50} onChange={setEngPct} formatter={v=>v+'%'}/>
            </>
          ) : (
            <>
              <FieldLabel hint="Saldo acumulado estimado">Saldo de subcuenta de vivienda</FieldLabel>
              <CurrencyInput value={subcuenta} onChange={setSubcuenta}/>
            </>
          )}
        </div>

        {/* Plazo */}
        <div style={{marginTop:22}}>
          <FieldLabel>Plazo</FieldLabel>
          <Slider value={plazo} min={5} max={30} onChange={setPlazo} formatter={v=>v+' años'}/>
        </div>

        {/* Tasa */}
        <div style={{marginTop:22}}>
          <FieldLabel hint="Editable · precargada según organismo">Tasa anual fija</FieldLabel>
          <div style={{position:'relative'}}>
            <input type="number" step="0.01" value={tasa} onChange={e=>setTasa(Number(e.target.value))}
              style={{width:'100%',padding:'14px 32px 14px 14px',fontSize:16,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',fontWeight:500}}/>
            <span style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)'}}>%</span>
          </div>
        </div>

        {/* Warnings */}
        {warnings.length > 0 && (
          <div style={{marginTop:20,display:'flex',flexDirection:'column',gap:8}}>
            {warnings.map((w,i)=><Warning key={i} kind={w.kind}>{w.text}</Warning>)}
          </div>
        )}
      </div>

      {/* -------- COLUMNA DERECHA — RESULTADOS -------- */}
      <div style={{display:'flex',flexDirection:'column',gap:24}}>

        {/* HERO — mensualidad (siempre visible = gate suave) */}
        <div style={{background:'var(--gh-azul-profundo)',borderRadius:16,padding:'40px 40px 32px',color:'#fff',position:'relative',overflow:'hidden'}}>
          <div style={{position:'absolute',top:-80,right:-60,width:260,height:260,borderRadius:'50%',background:`radial-gradient(circle, ${accent.bg}55 0%, transparent 70%)`}}/>
          <div style={{position:'relative'}}>
            <div style={{fontSize:11,letterSpacing:'.16em',textTransform:'uppercase',fontWeight:700,color:accent.bg==='#C4A8E8'?'#C4A8E8':'rgba(255,255,255,0.6)',marginBottom:12}}>Tu mensualidad estimada</div>
            <div style={{fontFamily:'var(--gh-font-serif)',fontSize:64,lineHeight:1,letterSpacing:'-0.02em'}}>
              ${Math.round(M).toLocaleString('es-MX')}
              <span style={{fontSize:20,fontFamily:'var(--gh-font-sans)',fontWeight:400,opacity:0.7,marginLeft:8}}>MXN / mes</span>
            </div>
            <div style={{marginTop:20,display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:0,borderTop:'1px solid rgba(255,255,255,0.15)',paddingTop:20}}>
              <div>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Monto financiado</div>
                <div style={{fontSize:18,fontWeight:600}}>{fmtMXNcompact(monto)}</div>
              </div>
              <div style={{borderLeft:'1px solid rgba(255,255,255,0.12)',paddingLeft:20}}>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Ingreso mínimo</div>
                <div style={{fontSize:18,fontWeight:600}}>${Math.round(ingresoMin).toLocaleString('es-MX')}</div>
              </div>
              <div style={{borderLeft:'1px solid rgba(255,255,255,0.12)',paddingLeft:20}}>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Tasa aplicada</div>
                <div style={{fontSize:18,fontWeight:600}}>{fmtPct(tasa)}</div>
              </div>
            </div>
          </div>
        </div>

        {/* BLOQUE GATED — desglose completo */}
        <div style={{position:'relative',background:'#fff',borderRadius:16,padding:36,boxShadow:'var(--gh-shadow-md)',border:'1px solid #EEF0F3'}}>

          <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
            <div>
              <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 2 · Desglose completo</div>
              <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:0}}>Qué pagas en total</h3>
            </div>
            {!unlocked && (
              <button onClick={()=>setShowForm(true)}
                style={{padding:'10px 18px',border:'none',borderRadius:999,background:accent.bg,color:accent.fg,fontWeight:600,fontSize:13,cursor:'pointer',display:'flex',alignItems:'center',gap:8}}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
                Desbloquear resultados
              </button>
            )}
          </div>

          <div style={{filter: unlocked ? 'none' : 'blur(6px)', transition:'filter 300ms', pointerEvents: unlocked ? 'auto' : 'none'}}>

            {/* Grid 2x2 de números */}
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:16,marginBottom:28}}>
              {[
                { label: 'Enganche', value: fmtMXN(enganche) },
                { label: 'Monto financiado', value: fmtMXN(monto) },
                { label: 'Total a pagar', value: fmtMXN(totalPagar) },
                { label: 'Intereses acumulados', value: fmtMXN(intereses), highlight: true },
              ].map((x,i)=>(
                <div key={i} style={{padding:'16px 18px',background: x.highlight ? accent.soft : 'var(--gh-blanco-frio)',borderRadius:10,borderLeft: x.highlight ? `3px solid ${accent.bg}` : '3px solid transparent'}}>
                  <div style={{fontSize:11,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:6}}>{x.label}</div>
                  <div style={{fontSize:20,fontWeight:600,color: x.highlight ? accent.softFg : 'var(--gh-azul-profundo)'}}>{x.value}</div>
                </div>
              ))}
            </div>

            {/* Barra capital vs intereses */}
            <div style={{marginBottom:28}}>
              <div style={{fontSize:12,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:10}}>Desglose del pago total</div>
              <AmortizationBar capital={monto} intereses={intereses} accent={accent}/>
            </div>

            {/* Tabla condiciones */}
            <div style={{fontSize:12,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:10}}>Condiciones aplicadas</div>
            <table style={{width:'100%',borderCollapse:'collapse',fontSize:14}}>
              <tbody>
                {[
                  ['Organismo', ORGANISMOS.find(o=>o.key===organismo).label],
                  (organismo==='banca'||organismo==='cofinavit') && ['Banco', banco.label + ' · CAT ' + banco.cat + '%'],
                  (organismo==='infonavit') && ['Rango salarial', infonavitR.label],
                  (organismo==='fovissste') && ['Tipo', fovTipo.label],
                  ['Plazo', plazo + ' años (' + (plazo*12) + ' pagos)'],
                  ['Tasa anual fija', fmtPct(tasa)],
                ].filter(Boolean).map(([k,v])=>(
                  <tr key={k} style={{borderBottom:'1px solid #F1F3F6'}}>
                    <td style={{padding:'12px 0',color:'rgba(28,28,30,0.65)'}}>{k}</td>
                    <td style={{padding:'12px 0',textAlign:'right',fontWeight:600,color:'var(--gh-azul-profundo)'}}>{v}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        {/* CATÁLOGO MATCH */}
        {catalogoMatch.length > 0 && (
          <div style={{marginTop:8}}>
            <div style={{marginBottom:20}}>
              <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 3 · Propiedades que se ajustan</div>
              <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:0}}>Estas propiedades se ajustan a tu perfil</h3>
              <p style={{fontSize:14,color:'rgba(28,28,30,0.6)',marginTop:8,margin:0}}>Catálogo filtrado por rango ±20% de tu precio objetivo.</p>
            </div>
            <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:16}}>
              {catalogoMatch.map(p=>(
                <div key={p.id} style={{background:'#fff',borderRadius:12,overflow:'hidden',boxShadow:'var(--gh-shadow-sm)',border:'1px solid #EEF0F3',cursor:'pointer',transition:'transform 200ms, box-shadow 200ms'}}
                  onMouseEnter={e=>{e.currentTarget.style.transform='translateY(-2px)';e.currentTarget.style.boxShadow='var(--gh-shadow-md)';}}
                  onMouseLeave={e=>{e.currentTarget.style.transform='none';e.currentTarget.style.boxShadow='var(--gh-shadow-sm)';}}>
                  <div style={{height:140,backgroundImage:`url(${p.img})`,backgroundSize:'cover',backgroundPosition:'center'}}/>
                  <div style={{padding:16}}>
                    <div style={{fontSize:11,color:'rgba(28,28,30,0.55)',marginBottom:4}}>{p.zone}</div>
                    <div style={{fontFamily:'var(--gh-font-serif)',fontSize:18,color:'var(--gh-azul-profundo)',marginBottom:8}}>{p.title}</div>
                    <div style={{fontSize:18,fontWeight:700,color:accent.bg,marginBottom:10}}>{fmtMXNcompact(p.price)}</div>
                    <div style={{display:'flex',gap:12,fontSize:12,color:'rgba(28,28,30,0.65)'}}>
                      <span>{p.beds} rec</span>
                      <span>·</span>
                      <span>{p.baths} baños</span>
                      <span>·</span>
                      <span>{p.m2}m²</span>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* DISCLAIMER legal */}
        <div style={{marginTop:8,padding:'20px 24px',background:'var(--gh-blanco-frio)',borderRadius:12,fontSize:12,lineHeight:1.6,color:'rgba(28,28,30,0.65)'}}>
          <strong style={{color:'var(--gh-azul-profundo)',fontSize:11,letterSpacing:'.12em',textTransform:'uppercase'}}>Aviso legal</strong>
          <p style={{margin:'8px 0 0'}}>Los resultados son estimaciones con fines informativos. No constituyen una oferta de crédito ni asesoría financiera. Las tasas y condiciones reales dependen de tu perfil crediticio y la institución. GALAHOME no es una institución financiera ni intermediario de crédito; facilitamos el proceso de búsqueda y acompañamos la operación con asesoría legal.</p>
        </div>
      </div>

      {/* -------------------- MODAL — FORM DE CAPTURA -------------------- */}
      {showForm && (
        <div onClick={()=>setShowForm(false)}
          style={{position:'fixed',inset:0,zIndex:200,background:'rgba(13,43,94,0.55)',backdropFilter:'blur(4px)',display:'flex',alignItems:'center',justifyContent:'center',padding:24,animation:'pm-fade 180ms'}}>
          <div onClick={e=>e.stopPropagation()}
            style={{background:'#fff',borderRadius:16,padding:40,maxWidth:440,width:'100%',boxShadow:'0 30px 60px -12px rgba(13,43,94,0.45)',position:'relative',animation:'pm-lift 220ms cubic-bezier(.2,.9,.3,1.2)'}}>
            <button onClick={()=>setShowForm(false)}
              style={{position:'absolute',top:14,right:14,width:32,height:32,borderRadius:999,background:'#F4F7FA',border:0,cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center',color:'var(--gh-azul-profundo)'}}>×</button>

            {sent ? (
              <div style={{textAlign:'center',padding:'20px 0'}}>
                <div style={{width:48,height:48,borderRadius:999,background:accent.soft,display:'flex',alignItems:'center',justifyContent:'center',color:accent.bg,margin:'0 auto 16px'}}>
                  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                </div>
                <div style={{fontFamily:'var(--gh-font-serif)',fontSize:22,color:'var(--gh-azul-profundo)'}}>Resultados desbloqueados</div>
                <p style={{marginTop:8,color:'rgba(28,28,30,0.65)',fontSize:14}}>Un asesor te contactará en menos de 24 horas.</p>
              </div>
            ) : (
              <form onSubmit={submitForm}>
                <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Último paso</div>
                <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:'0 0 8px'}}>Desbloquea el desglose completo</h3>
                <p style={{fontSize:14,color:'rgba(28,28,30,0.65)',lineHeight:1.5,margin:'0 0 24px'}}>Te enviamos el resumen por WhatsApp y un asesor revisa tu caso en privado.</p>

                <FieldLabel>Correo electrónico</FieldLabel>
                <input type="email" required value={formData.email} onChange={e=>setFormData({...formData, email:e.target.value})}
                  placeholder="tu@correo.mx"
                  style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',marginBottom:16}}/>

                <FieldLabel>WhatsApp</FieldLabel>
                <input type="tel" required value={formData.whatsapp} onChange={e=>setFormData({...formData, whatsapp:e.target.value})}
                  placeholder="+52 55 1234 5678"
                  style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',marginBottom:20}}/>

                <button type="submit"
                  style={{width:'100%',padding:'16px',border:'none',borderRadius:10,background:accent.bg,color:accent.fg,fontWeight:700,fontSize:15,cursor:'pointer'}}>
                  Ver desglose completo
                </button>
                <p style={{fontSize:11,color:'rgba(28,28,30,0.5)',lineHeight:1.5,marginTop:14,textAlign:'center'}}>
                  Al continuar aceptas el aviso de privacidad GALAHOME.
                </p>
              </form>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

/* ============================================================================
   CALCULADORA — ROI INVERSIONISTA (Spec v1.0 §3)
   ============================================================================ */

/* —— Tabla predial CDMX 2025 (Art. 130 Código Fiscal CDMX) —— */
const PREDIAL_RANGOS = [
  { rango:'A', limInf:0.01,        limSup:230227,      cuota:61.31,        pct:0.02340 },
  { rango:'B', limInf:230227,      limSup:460453,      cuota:115.17,       pct:0.02555 },
  { rango:'C', limInf:460453,      limSup:920907,      cuota:173.96,       pct:0.03816 },
  { rango:'D', limInf:920907,      limSup:1841813,     cuota:349.85,       pct:0.05436 },
  { rango:'E', limInf:1841813,     limSup:3683626,     cuota:850.36,       pct:0.07684 },
  { rango:'F', limInf:3683626,     limSup:7367253,     cuota:2264.44,      pct:0.10651 },
  { rango:'G', limInf:7367253,     limSup:14734505,    cuota:6187.41,      pct:0.14449 },
  { rango:'H', limInf:14734505,    limSup:31883631,    cuota:16843.43,     pct:0.19163 },
  { rango:'I', limInf:31883631,    limSup:63767262,    cuota:49705.80,     pct:0.25204 },
  { rango:'J', limInf:63767262,    limSup:127534524,   cuota:130061.64,    pct:0.32921 },
  { rango:'K', limInf:127534524,   limSup:255069048,   cuota:339970.61,    pct:0.42106 },
  { rango:'L', limInf:255069048,   limSup:510138096,   cuota:877105.77,    pct:0.52834 },
  { rango:'M', limInf:510138096,   limSup:Infinity,    cuota:2224785.49,   pct:0.64805 },
];

const PLUSVALIA_ESCENARIOS = [
  { key:'conservador', label:'Conservador',  pct:4.5, hint:'Del Valle (mercado maduro)' },
  { key:'base',        label:'Base',         pct:5.5, hint:'Narvarte, Portales (renovación)' },
  { key:'optimista',   label:'Optimista',    pct:8.0, hint:'Xoco, Mitikah (impacto urbano)' },
];

/* Predial anual CDMX a partir del precio comercial */
function predialAnualCDMX(precioComercial) {
  if (!precioComercial || precioComercial <= 0) return 0;
  const valorCatastral = precioComercial * 0.30;
  const r = PREDIAL_RANGOS.find(x => valorCatastral >= x.limInf && valorCatastral < x.limSup) || PREDIAL_RANGOS[0];
  const bimestral = r.cuota + (valorCatastral - r.limInf) * (r.pct / 100);
  return bimestral * 6;
}

function CalculadoraROI({ accent }) {
  // Inputs
  const [precio, setPrecio]               = useState(6500000);
  const [renta, setRenta]                 = useState(28000);
  const [usaCredito, setUsaCredito]       = useState(true);
  const [engPct, setEngPct]               = useState(20);
  const [plazo, setPlazo]                 = useState(20);
  const [tasa, setTasa]                   = useState(9.38);
  const [escrituracionPct, setEscPct]     = useState(7);
  const [isrPct, setIsrPct]               = useState(7);
  const [mantoMensual, setMantoMensual]   = useState(2000);
  const [adminMensual, setAdminMensual]   = useState(1500);
  const [plusvKey, setPlusvKey]           = useState('base');
  const [plusvPct, setPlusvPct]           = useState(5.5);
  const [horizonte, setHorizonte]         = useState(5);

  const [unlocked, setUnlocked]   = useState(false);
  const [showForm, setShowForm]   = useState(false);
  const [formData, setFormData]   = useState({ email:'', whatsapp:'' });
  const [sent, setSent]           = useState(false);

  // Sincroniza el % de plusvalía con el escenario elegido (sólo si el usuario no lo ha tocado)
  useEffect(() => {
    const esc = PLUSVALIA_ESCENARIOS.find(e => e.key === plusvKey);
    if (esc) setPlusvPct(esc.pct);
  }, [plusvKey]);

  const calc = useMemo(() => {
    const warns = [];

    // Costos de entrada
    const enganche = usaCredito ? precio * (engPct/100) : precio;
    const escrituracion = precio * (escrituracionPct/100);
    const capitalInvertido = enganche + escrituracion;

    // Hipoteca (si aplica)
    const monto = usaCredito ? Math.max(0, precio - enganche) : 0;
    const M = usaCredito ? mensualidad(monto, tasa, plazo) : 0;
    const hipotecaAnual = M * 12;

    // Gastos
    const predialAnual = predialAnualCDMX(precio);
    const isrAnual = renta * 12 * (isrPct/100);
    const gastosOperativosAnual = (mantoMensual + adminMensual) * 12;
    const gastosAnualTotal = predialAnual + isrAnual + gastosOperativosAnual;

    // Renta neta y rendimientos
    const rentaBrutaAnual = renta * 12;
    const rentaNetaAnual = rentaBrutaAnual - gastosAnualTotal;
    const flujoEfectivoAnual = rentaNetaAnual - hipotecaAnual;

    const capRate = precio > 0 ? (rentaNetaAnual / precio) * 100 : 0;
    const cocReturn = capitalInvertido > 0 ? (flujoEfectivoAnual / capitalInvertido) * 100 : 0;
    const roiAnual = capRate + plusvPct;
    const payback = flujoEfectivoAnual > 0 ? capitalInvertido / flujoEfectivoAnual : Infinity;

    // Proyección por horizonte (lineal)
    const plusvAcumulada = precio * (plusvPct/100) * horizonte;
    const rentaAcumulada = flujoEfectivoAnual * horizonte;
    const gananciaTotal = plusvAcumulada + rentaAcumulada;
    const roiTotalPct = capitalInvertido > 0 ? (gananciaTotal / capitalInvertido) * 100 : 0;

    // Edge cases
    if (renta <= 0) warns.push({kind:'error', text:'La renta mensual no puede ser cero.'});
    if (capRate < 3 && renta > 0) warns.push({kind:'warn', text:'Cap rate por debajo del 3% — rentabilidad baja para CDMX.'});
    if (capRate > 10) warns.push({kind:'warn', text:'Cap rate por encima del 10% — verifica los datos ingresados.'});
    if (plusvPct > 15) warns.push({kind:'warn', text:'Plusvalía por encima del promedio histórico (CDMX 2024: 5.1%).'});
    if (flujoEfectivoAnual < 0) warns.push({kind:'warn', text:'Flujo de caja negativo — la renta no cubre gastos + hipoteca.'});

    return {
      enganche, escrituracion, capitalInvertido,
      monto, M, hipotecaAnual,
      predialAnual, isrAnual, gastosOperativosAnual, gastosAnualTotal,
      rentaBrutaAnual, rentaNetaAnual, flujoEfectivoAnual,
      capRate, cocReturn, roiAnual, payback,
      plusvAcumulada, rentaAcumulada, gananciaTotal, roiTotalPct,
      warnings: warns,
    };
  }, [precio, renta, usaCredito, engPct, plazo, tasa, escrituracionPct, isrPct, mantoMensual, adminMensual, plusvPct, horizonte]);

  // Catálogo match ±20%
  const catalogoMatch = useMemo(() => {
    const lo = precio * 0.8, hi = precio * 1.2;
    return CATALOGO_MOCK.filter(p => p.price >= lo && p.price <= hi).slice(0,3);
  }, [precio]);

  const submitForm = (e) => {
    e.preventDefault();
    setSent(true);
    setUnlocked(true);
    setTimeout(() => setShowForm(false), 1200);
  };

  return (
    <div style={{display:'grid',gridTemplateColumns:'minmax(0,440px) 1fr',gap:40,alignItems:'start'}}>

      {/* -------- COLUMNA IZQUIERDA — INPUTS -------- */}
      <div style={{background:'#fff',borderRadius:16,padding:32,boxShadow:'var(--gh-shadow-md)',border:'1px solid #EEF0F3',position:'sticky',top:140,maxHeight:'calc(100vh - 160px)',overflowY:'auto'}}>
        <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 1 · Datos</div>
        <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:26,color:'var(--gh-azul-profundo)',margin:'0 0 24px'}}>Simula tu inversión</h3>

        {/* Precio */}
        <FieldLabel hint="Min $500,000">Precio de compra</FieldLabel>
        <CurrencyInput value={precio} onChange={setPrecio} placeholder="6,500,000"/>

        {/* Renta */}
        <div style={{marginTop:22}}>
          <FieldLabel hint="Renta esperada / actual">Renta mensual</FieldLabel>
          <CurrencyInput value={renta} onChange={setRenta} placeholder="28,000"/>
        </div>

        {/* Modalidad de compra */}
        <div style={{marginTop:22}}>
          <FieldLabel>Modalidad de compra</FieldLabel>
          <div style={{display:'flex',gap:6,padding:4,background:'var(--gh-blanco-frio)',borderRadius:10}}>
            {[
              {key:true,  label:'Con crédito'},
              {key:false, label:'De contado'},
            ].map(opt => (
              <button key={String(opt.key)} onClick={()=>setUsaCredito(opt.key)} type="button"
                style={{flex:1,padding:'10px 12px',border:0,borderRadius:8,background: usaCredito===opt.key ? '#fff' : 'transparent',color: usaCredito===opt.key ? 'var(--gh-azul-profundo)' : 'rgba(28,28,30,0.6)',fontWeight:600,fontSize:13,cursor:'pointer',boxShadow: usaCredito===opt.key ? 'var(--gh-shadow-sm)' : 'none',fontFamily:'inherit',transition:'all 180ms'}}>
                {opt.label}
              </button>
            ))}
          </div>
        </div>

        {/* Bloque hipoteca */}
        {usaCredito && (
          <>
            <div style={{marginTop:22}}>
              <FieldLabel hint={`Equivale a ${fmtMXNcompact(calc.enganche)}`}>Enganche (%)</FieldLabel>
              <Slider value={engPct} min={10} max={50} onChange={setEngPct} formatter={v=>v+'%'}/>
            </div>
            <div style={{marginTop:22}}>
              <FieldLabel>Plazo del crédito</FieldLabel>
              <Slider value={plazo} min={5} max={30} onChange={setPlazo} formatter={v=>v+' años'}/>
            </div>
            <div style={{marginTop:22}}>
              <FieldLabel hint="Tasa fija anual">Tasa hipotecaria</FieldLabel>
              <div style={{position:'relative'}}>
                <input type="number" step="0.01" value={tasa} onChange={e=>setTasa(Number(e.target.value))}
                  style={{width:'100%',padding:'14px 32px 14px 14px',fontSize:16,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',fontWeight:500}}/>
                <span style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)'}}>%</span>
              </div>
            </div>
          </>
        )}

        {/* Gastos */}
        <div style={{marginTop:24,paddingTop:22,borderTop:'1px solid #EEF0F3'}}>
          <div style={{fontSize:11,letterSpacing:'.10em',textTransform:'uppercase',fontWeight:700,color:'rgba(28,28,30,0.55)',marginBottom:14}}>Gastos mensuales</div>

          <FieldLabel hint="Editable">Mantenimiento</FieldLabel>
          <CurrencyInput value={mantoMensual} onChange={setMantoMensual}/>

          <div style={{marginTop:16}}>
            <FieldLabel hint="Cuota condominal">Administración</FieldLabel>
            <CurrencyInput value={adminMensual} onChange={setAdminMensual}/>
          </div>

          <div style={{marginTop:16}}>
            <FieldLabel hint="Predial CDMX automático">Predial anual estimado</FieldLabel>
            <div style={{padding:'14px',fontSize:15,border:'1px solid #EEF0F3',borderRadius:10,background:'var(--gh-blanco-frio)',color:'var(--gh-azul-profundo)',fontWeight:600}}>
              {fmtMXN(calc.predialAnual)}
              <span style={{display:'block',fontSize:11,fontWeight:400,color:'rgba(28,28,30,0.55)',marginTop:4}}>Calculado sobre valor catastral (30% del precio comercial).</span>
            </div>
          </div>
        </div>

        {/* Porcentajes */}
        <div style={{marginTop:24,paddingTop:22,borderTop:'1px solid #EEF0F3'}}>
          <div style={{fontSize:11,letterSpacing:'.10em',textTransform:'uppercase',fontWeight:700,color:'rgba(28,28,30,0.55)',marginBottom:14}}>Costos y supuestos</div>

          <FieldLabel hint="Tasa estimada bajo deducción ciega">ISR arrendamiento (%)</FieldLabel>
          <div style={{position:'relative'}}>
            <input type="number" step="0.5" value={isrPct} onChange={e=>setIsrPct(Number(e.target.value))}
              style={{width:'100%',padding:'14px 32px 14px 14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',fontWeight:500}}/>
            <span style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)'}}>%</span>
          </div>

          <div style={{marginTop:16}}>
            <FieldLabel hint="ISAI + notario + registro">Escrituración (%)</FieldLabel>
            <div style={{position:'relative'}}>
              <input type="number" step="0.5" value={escrituracionPct} onChange={e=>setEscPct(Number(e.target.value))}
                style={{width:'100%',padding:'14px 32px 14px 14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',fontWeight:500}}/>
              <span style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)'}}>%</span>
            </div>
          </div>
        </div>

        {/* Plusvalía */}
        <div style={{marginTop:24,paddingTop:22,borderTop:'1px solid #EEF0F3'}}>
          <div style={{fontSize:11,letterSpacing:'.10em',textTransform:'uppercase',fontWeight:700,color:'rgba(28,28,30,0.55)',marginBottom:14}}>Plusvalía y horizonte</div>

          <FieldLabel>Escenario de plusvalía</FieldLabel>
          <div style={{display:'flex',gap:6,padding:4,background:'var(--gh-blanco-frio)',borderRadius:10,marginBottom:10}}>
            {PLUSVALIA_ESCENARIOS.map(esc => (
              <button key={esc.key} onClick={()=>setPlusvKey(esc.key)} type="button"
                style={{flex:1,padding:'8px 6px',border:0,borderRadius:8,background: plusvKey===esc.key ? '#fff' : 'transparent',color: plusvKey===esc.key ? 'var(--gh-azul-profundo)' : 'rgba(28,28,30,0.6)',fontWeight:600,fontSize:12,cursor:'pointer',boxShadow: plusvKey===esc.key ? 'var(--gh-shadow-sm)' : 'none',fontFamily:'inherit'}}>
                {esc.label}
              </button>
            ))}
          </div>
          <div style={{position:'relative'}}>
            <input type="number" step="0.1" value={plusvPct} onChange={e=>setPlusvPct(Number(e.target.value))}
              style={{width:'100%',padding:'14px 32px 14px 14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',fontWeight:500}}/>
            <span style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',color:'rgba(28,28,30,0.5)'}}>% anual</span>
          </div>
          <div style={{fontSize:11,color:'rgba(28,28,30,0.55)',marginTop:6}}>{(PLUSVALIA_ESCENARIOS.find(e=>e.key===plusvKey)||{}).hint}</div>

          <div style={{marginTop:16}}>
            <FieldLabel>Años de tenencia</FieldLabel>
            <div style={{display:'flex',gap:6,padding:4,background:'var(--gh-blanco-frio)',borderRadius:10}}>
              {[3,5,7].map(yr => (
                <button key={yr} onClick={()=>setHorizonte(yr)} type="button"
                  style={{flex:1,padding:'10px 12px',border:0,borderRadius:8,background: horizonte===yr ? '#fff' : 'transparent',color: horizonte===yr ? 'var(--gh-azul-profundo)' : 'rgba(28,28,30,0.6)',fontWeight:600,fontSize:13,cursor:'pointer',boxShadow: horizonte===yr ? 'var(--gh-shadow-sm)' : 'none',fontFamily:'inherit'}}>
                  {yr} años
                </button>
              ))}
            </div>
          </div>
        </div>

        {/* Warnings */}
        {calc.warnings.length > 0 && (
          <div style={{marginTop:20,display:'flex',flexDirection:'column',gap:8}}>
            {calc.warnings.map((w,i)=><Warning key={i} kind={w.kind}>{w.text}</Warning>)}
          </div>
        )}
      </div>

      {/* -------- COLUMNA DERECHA — RESULTADOS -------- */}
      <div style={{display:'flex',flexDirection:'column',gap:24}}>

        {/* HERO — métricas clave */}
        <div style={{background:'var(--gh-azul-profundo)',borderRadius:16,padding:'40px',color:'#fff',position:'relative',overflow:'hidden'}}>
          <div style={{position:'absolute',top:-80,right:-60,width:280,height:280,borderRadius:'50%',background:`radial-gradient(circle, ${accent.bg}55 0%, transparent 70%)`,pointerEvents:'none'}}/>
          <div style={{position:'relative'}}>
            <div style={{fontSize:11,letterSpacing:'.16em',textTransform:'uppercase',fontWeight:700,color:'rgba(255,255,255,0.6)',marginBottom:14}}>Rendimiento estimado</div>
            <div style={{display:'grid',gridTemplateColumns:'repeat(2,1fr)',gap:32}}>
              <div>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Cap Rate</div>
                <div style={{fontFamily:'var(--gh-font-serif)',fontSize:52,lineHeight:1,letterSpacing:'-0.02em'}}>
                  {fmtPct(calc.capRate, 2)}
                </div>
                <div style={{fontSize:12,opacity:0.65,marginTop:6}}>Renta neta / precio</div>
              </div>
              <div style={{borderLeft:'1px solid rgba(255,255,255,0.15)',paddingLeft:32}}>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>ROI anual total</div>
                <div style={{fontFamily:'var(--gh-font-serif)',fontSize:52,lineHeight:1,letterSpacing:'-0.02em'}}>
                  {fmtPct(calc.roiAnual, 2)}
                </div>
                <div style={{fontSize:12,opacity:0.65,marginTop:6}}>Cap rate + plusvalía</div>
              </div>
            </div>

            <div style={{marginTop:28,paddingTop:24,borderTop:'1px solid rgba(255,255,255,0.15)',display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:0}}>
              <div>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Cash-on-cash</div>
                <div style={{fontSize:18,fontWeight:600}}>{fmtPct(calc.cocReturn, 2)}</div>
              </div>
              <div style={{borderLeft:'1px solid rgba(255,255,255,0.12)',paddingLeft:24}}>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Payback</div>
                <div style={{fontSize:18,fontWeight:600}}>
                  {isFinite(calc.payback) ? calc.payback.toFixed(1) + ' años' : '—'}
                </div>
              </div>
              <div style={{borderLeft:'1px solid rgba(255,255,255,0.12)',paddingLeft:24}}>
                <div style={{fontSize:11,opacity:0.6,textTransform:'uppercase',letterSpacing:'.08em',marginBottom:4}}>Flujo neto / mes</div>
                <div style={{fontSize:18,fontWeight:600,color: calc.flujoEfectivoAnual < 0 ? '#FFB4B8' : '#fff'}}>
                  {fmtMXNcompact(calc.flujoEfectivoAnual / 12)}
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* BLOQUE GATED — desglose y proyección */}
        <div style={{position:'relative',background:'#fff',borderRadius:16,padding:36,boxShadow:'var(--gh-shadow-md)',border:'1px solid #EEF0F3'}}>
          <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
            <div>
              <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 2 · Desglose y proyección</div>
              <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:0}}>Tu inversión a {horizonte} años</h3>
            </div>
            {!unlocked && (
              <button onClick={()=>setShowForm(true)}
                style={{padding:'10px 18px',border:'none',borderRadius:999,background:accent.bg,color:accent.fg,fontWeight:600,fontSize:13,cursor:'pointer',display:'flex',alignItems:'center',gap:8}}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
                Desbloquear resultados
              </button>
            )}
          </div>

          <div style={{filter: unlocked ? 'none' : 'blur(6px)', transition:'filter 300ms', pointerEvents: unlocked ? 'auto' : 'none'}}>

            {/* Capital invertido */}
            <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:12,marginBottom:24}}>
              {[
                { label:'Enganche',         value:fmtMXN(calc.enganche) },
                { label:'Escrituración',    value:fmtMXN(calc.escrituracion) },
                { label:'Capital invertido',value:fmtMXN(calc.capitalInvertido), highlight:true },
              ].map((x,i)=>(
                <div key={i} style={{padding:'14px 16px',background: x.highlight ? accent.soft : 'var(--gh-blanco-frio)',borderRadius:10,borderLeft: x.highlight ? `3px solid ${accent.bg}` : '3px solid transparent'}}>
                  <div style={{fontSize:11,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:4}}>{x.label}</div>
                  <div style={{fontSize:16,fontWeight:600,color: x.highlight ? accent.softFg : 'var(--gh-azul-profundo)'}}>{x.value}</div>
                </div>
              ))}
            </div>

            {/* Tabla flujo anual */}
            <div style={{fontSize:12,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:10}}>Flujo anual</div>
            <table style={{width:'100%',borderCollapse:'collapse',fontSize:14,marginBottom:28}}>
              <tbody>
                {[
                  ['Renta bruta anual', fmtMXN(calc.rentaBrutaAnual), false],
                  ['Predial CDMX',           '− ' + fmtMXN(calc.predialAnual), false],
                  ['ISR arrendamiento',      '− ' + fmtMXN(calc.isrAnual), false],
                  ['Mantenimiento + admin',  '− ' + fmtMXN(calc.gastosOperativosAnual), false],
                  ['Renta neta anual', fmtMXN(calc.rentaNetaAnual), true],
                  usaCredito && ['Hipoteca anual', '− ' + fmtMXN(calc.hipotecaAnual), false],
                  ['Flujo de efectivo anual', fmtMXN(calc.flujoEfectivoAnual), true],
                ].filter(Boolean).map(([k,v,bold])=>(
                  <tr key={k} style={{borderBottom:'1px solid #F1F3F6'}}>
                    <td style={{padding:'10px 0',color: bold ? 'var(--gh-azul-profundo)' : 'rgba(28,28,30,0.65)',fontWeight: bold ? 600 : 400}}>{k}</td>
                    <td style={{padding:'10px 0',textAlign:'right',fontWeight: bold ? 700 : 500,color:'var(--gh-azul-profundo)'}}>{v}</td>
                  </tr>
                ))}
              </tbody>
            </table>

            {/* Proyección por horizonte */}
            <div style={{fontSize:12,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:10}}>Proyección a {horizonte} años (lineal)</div>
            <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:12,marginBottom:18}}>
              {[
                { label:'Plusvalía acumulada', value:fmtMXN(calc.plusvAcumulada),  sub:`${plusvPct}% × ${horizonte} años` },
                { label:'Renta neta acumulada', value:fmtMXN(calc.rentaAcumulada), sub:`Flujo × ${horizonte}` },
                { label:'Ganancia total',      value:fmtMXN(calc.gananciaTotal),  sub:`ROI ${fmtPct(calc.roiTotalPct,1)}`, highlight:true },
              ].map((x,i)=>(
                <div key={i} style={{padding:'14px 16px',background: x.highlight ? accent.soft : 'var(--gh-blanco-frio)',borderRadius:10,borderLeft: x.highlight ? `3px solid ${accent.bg}` : '3px solid transparent'}}>
                  <div style={{fontSize:11,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.55)',marginBottom:4}}>{x.label}</div>
                  <div style={{fontSize:16,fontWeight:600,color: x.highlight ? accent.softFg : 'var(--gh-azul-profundo)'}}>{x.value}</div>
                  <div style={{fontSize:11,color:'rgba(28,28,30,0.5)',marginTop:2}}>{x.sub}</div>
                </div>
              ))}
            </div>

            {/* Composición de la ganancia */}
            <div>
              <div style={{display:'flex',justifyContent:'space-between',fontSize:12,marginBottom:8,color:'rgba(28,28,30,0.6)'}}>
                <span>Plusvalía: <strong style={{color:'var(--gh-azul-profundo)'}}>{calc.gananciaTotal>0 ? fmtPct(calc.plusvAcumulada/calc.gananciaTotal*100,0) : '—'}</strong></span>
                <span>Rentas: <strong style={{color:accent.bg}}>{calc.gananciaTotal>0 ? fmtPct(calc.rentaAcumulada/calc.gananciaTotal*100,0) : '—'}</strong></span>
              </div>
              <div style={{height:12,borderRadius:999,background:'#EEF0F3',display:'flex',overflow:'hidden'}}>
                <div style={{width: (calc.gananciaTotal>0 ? Math.max(0,calc.plusvAcumulada/calc.gananciaTotal*100) : 0)+'%',background:'var(--gh-azul-profundo)',transition:'width 400ms cubic-bezier(.2,.9,.3,1)'}}/>
                <div style={{width: (calc.gananciaTotal>0 ? Math.max(0,calc.rentaAcumulada/calc.gananciaTotal*100) : 0)+'%',background:accent.bg,transition:'width 400ms cubic-bezier(.2,.9,.3,1)'}}/>
              </div>
            </div>
          </div>
        </div>

        {/* CATÁLOGO MATCH */}
        {catalogoMatch.length > 0 && (
          <div style={{marginTop:8}}>
            <div style={{marginBottom:20}}>
              <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Paso 3 · Propiedades que se ajustan</div>
              <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:0}}>Estas propiedades coinciden con tu inversión</h3>
              <p style={{fontSize:14,color:'rgba(28,28,30,0.6)',marginTop:8,margin:0}}>Catálogo filtrado por rango ±20% de tu precio objetivo.</p>
            </div>
            <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:16}}>
              {catalogoMatch.map(p=>(
                <div key={p.id} style={{background:'#fff',borderRadius:12,overflow:'hidden',boxShadow:'var(--gh-shadow-sm)',border:'1px solid #EEF0F3',cursor:'pointer',transition:'transform 200ms, box-shadow 200ms'}}
                  onMouseEnter={e=>{e.currentTarget.style.transform='translateY(-2px)';e.currentTarget.style.boxShadow='var(--gh-shadow-md)';}}
                  onMouseLeave={e=>{e.currentTarget.style.transform='none';e.currentTarget.style.boxShadow='var(--gh-shadow-sm)';}}>
                  <div style={{height:140,backgroundImage:`url(${p.img})`,backgroundSize:'cover',backgroundPosition:'center'}}/>
                  <div style={{padding:16}}>
                    <div style={{fontSize:11,color:'rgba(28,28,30,0.55)',marginBottom:4}}>{p.zone}</div>
                    <div style={{fontFamily:'var(--gh-font-serif)',fontSize:18,color:'var(--gh-azul-profundo)',marginBottom:8}}>{p.title}</div>
                    <div style={{fontSize:18,fontWeight:700,color:accent.bg,marginBottom:10}}>{fmtMXNcompact(p.price)}</div>
                    <div style={{display:'flex',gap:12,fontSize:12,color:'rgba(28,28,30,0.65)'}}>
                      <span>{p.beds} rec</span>
                      <span>·</span>
                      <span>{p.baths} baños</span>
                      <span>·</span>
                      <span>{p.m2}m²</span>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* DISCLAIMER */}
        <div style={{marginTop:8,padding:'20px 24px',background:'var(--gh-blanco-frio)',borderRadius:12,fontSize:12,lineHeight:1.6,color:'rgba(28,28,30,0.65)'}}>
          <strong style={{color:'var(--gh-azul-profundo)',fontSize:11,letterSpacing:'.12em',textTransform:'uppercase'}}>Aviso legal</strong>
          <p style={{margin:'8px 0 0'}}>Los cálculos de ROI se basan en supuestos de mercado y no garantizan rendimientos futuros. La plusvalía histórica no garantiza plusvalía futura. Predial CDMX calculado sobre el Art. 130 del Código Fiscal CDMX 2025 con valor catastral estimado al 30% del valor comercial. ISR por arrendamiento bajo deducción ciega del 35% (Art. 115 LISR). Consulta a un asesor fiscal y a tu contador para una proyección personalizada.</p>
        </div>
      </div>

      {/* MODAL FORM */}
      {showForm && (
        <div onClick={()=>setShowForm(false)}
          style={{position:'fixed',inset:0,zIndex:200,background:'rgba(13,43,94,0.55)',backdropFilter:'blur(4px)',display:'flex',alignItems:'center',justifyContent:'center',padding:24,animation:'pm-fade 180ms'}}>
          <div onClick={e=>e.stopPropagation()}
            style={{background:'#fff',borderRadius:16,padding:40,maxWidth:440,width:'100%',boxShadow:'0 30px 60px -12px rgba(13,43,94,0.45)',position:'relative',animation:'pm-lift 220ms cubic-bezier(.2,.9,.3,1.2)'}}>
            <button onClick={()=>setShowForm(false)}
              style={{position:'absolute',top:14,right:14,width:32,height:32,borderRadius:999,background:'#F4F7FA',border:0,cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center',color:'var(--gh-azul-profundo)'}}>×</button>

            {sent ? (
              <div style={{textAlign:'center',padding:'20px 0'}}>
                <div style={{width:48,height:48,borderRadius:999,background:accent.soft,display:'flex',alignItems:'center',justifyContent:'center',color:accent.bg,margin:'0 auto 16px'}}>
                  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                </div>
                <div style={{fontFamily:'var(--gh-font-serif)',fontSize:22,color:'var(--gh-azul-profundo)'}}>Resultados desbloqueados</div>
                <p style={{marginTop:8,color:'rgba(28,28,30,0.65)',fontSize:14}}>Un asesor te contactará en menos de 24 horas.</p>
              </div>
            ) : (
              <form onSubmit={submitForm}>
                <div style={{fontSize:11,letterSpacing:'.14em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:6}}>Último paso</div>
                <h3 style={{fontFamily:'var(--gh-font-serif)',fontSize:24,color:'var(--gh-azul-profundo)',margin:'0 0 8px'}}>Desbloquea la proyección completa</h3>
                <p style={{fontSize:14,color:'rgba(28,28,30,0.65)',lineHeight:1.5,margin:'0 0 24px'}}>Te enviamos el análisis por WhatsApp y un asesor revisa tu caso en privado.</p>

                <FieldLabel>Correo electrónico</FieldLabel>
                <input type="email" required value={formData.email} onChange={e=>setFormData({...formData, email:e.target.value})}
                  placeholder="tu@correo.mx"
                  style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',marginBottom:16}}/>

                <FieldLabel>WhatsApp</FieldLabel>
                <input type="tel" required value={formData.whatsapp} onChange={e=>setFormData({...formData, whatsapp:e.target.value})}
                  placeholder="+52 55 1234 5678"
                  style={{width:'100%',padding:'14px',fontSize:15,fontFamily:'inherit',border:'1px solid #E5E7EB',borderRadius:10,boxSizing:'border-box',marginBottom:20}}/>

                <button type="submit"
                  style={{width:'100%',padding:'16px',border:'none',borderRadius:10,background:accent.bg,color:accent.fg,fontWeight:700,fontSize:15,cursor:'pointer'}}>
                  Ver proyección completa
                </button>
                <p style={{fontSize:11,color:'rgba(28,28,30,0.5)',lineHeight:1.5,marginTop:14,textAlign:'center'}}>
                  Al continuar aceptas el aviso de privacidad GALAHOME.
                </p>
              </form>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

/* ============================================================================
   PÁGINA PRINCIPAL — /calculadoras
   ============================================================================ */

function Calculadoras({ tweakAccent }) {
  const [tab, setTab] = useState('credito');
  const accent = tweakAccent;

  return (
    <div style={{background:'var(--gh-blanco-frio)',minHeight:'100vh'}}>
      {/* HERO compacto */}
      <div style={{background:'#fff',borderBottom:'1px solid #EEF0F3'}}>
        <div style={{maxWidth:1200,margin:'0 auto',padding:'56px 24px 32px'}}>
          <div style={{fontSize:11,letterSpacing:'.18em',textTransform:'uppercase',fontWeight:700,color:accent.bg,marginBottom:12}}>Herramientas</div>
          <h1 style={{fontFamily:'var(--gh-font-serif)',fontSize:52,color:'var(--gh-azul-profundo)',margin:0,letterSpacing:'-0.01em',lineHeight:1.05,maxWidth:720}}>
            Calcula antes de decidir.
          </h1>
          <p style={{fontSize:17,color:'rgba(28,28,30,0.7)',marginTop:16,maxWidth:640,lineHeight:1.6}}>
            Datos bancarios verificados (enero 2025), predial CDMX, Infonavit y Fovissste reales.
            Sin promesas de marketing — sólo números que puedes llevar a tu asesor.
          </p>

          {/* Tabs */}
          <div style={{marginTop:40,display:'inline-flex',background:'var(--gh-blanco-frio)',padding:4,borderRadius:999,gap:2}}>
            {[
              { key:'credito', label:'Crédito hipotecario' },
              { key:'roi',     label:'ROI inversión' },
            ].map(t=>(
              <button key={t.key} onClick={()=>setTab(t.key)}
                style={{padding:'10px 22px',border:'none',borderRadius:999,background: tab===t.key ? '#fff' : 'transparent',color: tab===t.key ? 'var(--gh-azul-profundo)' : 'rgba(28,28,30,0.6)',fontWeight:600,fontSize:14,cursor:'pointer',boxShadow: tab===t.key ? 'var(--gh-shadow-sm)' : 'none',transition:'all 180ms'}}>
                {t.label}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* CONTENIDO */}
      <div style={{maxWidth:1200,margin:'0 auto',padding:'40px 24px 80px'}}>
        {tab === 'credito' && <CalculadoraCredito accent={accent}/>}
        {tab === 'roi' && <CalculadoraROI accent={accent}/>}
      </div>
    </div>
  );
}

/* ============================================================================
   TWEAKS PANEL — paleta de acento
   ============================================================================ */

function CalcTweaks({ accentKey, onChange, onClose }) {
  const opts = [
    { key:'violeta', label:'Violeta institucional', swatch:'#8A46CE' },
    { key:'azul',    label:'Azul profundo',         swatch:'#0D2B5E' },
    { key:'lavanda', label:'Lavanda suave',         swatch:'#C4A8E8' },
  ];
  return (
    <div style={{position:'fixed',right:24,bottom:24,zIndex:300,width:280,background:'#fff',borderRadius:14,boxShadow:'0 20px 40px -8px rgba(13,43,94,0.3)',border:'1px solid #EEF0F3',overflow:'hidden'}}>
      <div style={{padding:'14px 18px',borderBottom:'1px solid #EEF0F3',display:'flex',justifyContent:'space-between',alignItems:'center',background:'var(--gh-blanco-frio)'}}>
        <span style={{fontSize:12,fontWeight:700,letterSpacing:'.14em',textTransform:'uppercase',color:'var(--gh-azul-profundo)'}}>Tweaks</span>
        <button onClick={onClose} style={{border:0,background:'transparent',cursor:'pointer',color:'rgba(28,28,30,0.5)',fontSize:18}}>×</button>
      </div>
      <div style={{padding:18}}>
        <div style={{fontSize:11,letterSpacing:'.08em',textTransform:'uppercase',fontWeight:600,color:'rgba(28,28,30,0.6)',marginBottom:10}}>Paleta de acento</div>
        <div style={{display:'flex',flexDirection:'column',gap:8}}>
          {opts.map(o=>(
            <button key={o.key} onClick={()=>onChange(o.key)}
              style={{display:'flex',alignItems:'center',gap:12,padding:'10px 12px',border: accentKey===o.key ? '1px solid var(--gh-azul-profundo)':'1px solid #EEF0F3',borderRadius:10,background: accentKey===o.key ? 'var(--gh-blanco-frio)':'#fff',cursor:'pointer',textAlign:'left',width:'100%'}}>
              <span style={{width:22,height:22,borderRadius:'50%',background:o.swatch,border:'1px solid rgba(0,0,0,0.1)',flexShrink:0}}/>
              <span style={{fontSize:13,fontWeight: accentKey===o.key ? 600 : 500,color:'var(--gh-gris-carbon)'}}>{o.label}</span>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

/* Exportar al scope global para uso desde index.html */
Object.assign(window, { Calculadoras, CalcTweaks, useAccent });
