// Medidor de Rendimiento Sell-U — App principal (Hero · Analizando · Resultados · Captura lead)
// Llama al backend Laravel para datos reales de PageSpeed + HTML scraping.

const { useState, useEffect, useRef } = React;

const ANALYZE_STEPS = window.ConvierteEngine.CATEGORIES.map((c) => c.label);

function scrollToId(id) {
  const el = document.getElementById(id);
  if (!el) return;
  const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const y = el.getBoundingClientRect().top + window.scrollY - 24;
  window.scrollTo({ top: y, behavior: reduce ? "auto" : "smooth" });
}

function normalizeUrl(raw) {
  let u = (raw || "").trim();
  if (!u) return "";
  if (!/^https?:\/\//i.test(u)) u = "https://" + u;
  return u;
}
function isValidUrl(raw) {
  const u = normalizeUrl(raw);
  return /^https?:\/\/([\w-]+\.)+[a-z]{2,}(\/\S*)?$/i.test(u);
}
function prettyHost(url) {
  try { return new URL(normalizeUrl(url)).host.replace(/^www\./, ""); }
  catch { return url; }
}

/* Nav y Footer del convertidor se eliminaron — ahora la vista Blade
   envuelve el #root con <x-nav /> y <x-footer /> de Sell-U para que
   el convertidor se integre visualmente con el resto del sitio. */

/* ===================== HERO ===================== */
function Hero({ url, setUrl, device, setDevice, onAnalyze, error }) {
  const inputRef = useRef(null);
  return (
    <section className="hero" aria-labelledby="hero-h1">
      <div className="hero-glow" aria-hidden="true" />
      <div className="container hero-inner">
        <span className="eyebrow hero-eyebrow">Medidor gratis · datos reales de Google</span>
        <h1 id="hero-h1" className="hero-h1">
          ¿Tu página web está perdiendo<br className="hide-mobile" /> clientes? <span className="hl">Descúbrelo en 30 segundos</span>
        </h1>
        <p className="hero-sub">
          Escribe la dirección de tu sitio y te decimos en lenguaje claro
          qué está bien, qué está mal y cómo arreglarlo — sin tecnicismos.
          Usamos la misma tecnología de Google para medir tu página.
        </p>

        <div className="hero-form" role="group" aria-label="Analizar una URL">
          <div className="url-row">
            <div className={"url-field" + (error ? " url-field--err" : "")}>
              <span className="url-proto" aria-hidden="true">https://</span>
              <input
                ref={inputRef}
                type="url"
                inputMode="url"
                className="url-input"
                placeholder="tu-sitio.com"
                aria-label="URL de tu página web"
                aria-invalid={!!error}
                aria-describedby={error ? "url-err" : "url-hint"}
                value={url}
                onChange={(e) => setUrl(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") onAnalyze(); }}
              />
            </div>
            <button className="btn btn-primary btn-lg url-btn" onClick={onAnalyze}>
              Analizar gratis <Icon name="arrow" size={18} stroke={2} />
            </button>
          </div>

          <div className="hero-controls">
            <div className="device-toggle" role="radiogroup" aria-label="Dispositivo a analizar">
              <button role="radio" aria-checked={device === "desktop"}
                className={"seg" + (device === "desktop" ? " seg--on" : "")}
                onClick={() => setDevice("desktop")}>
                <Icon name="desktop" size={16} /> Escritorio
              </button>
              <button role="radio" aria-checked={device === "mobile"}
                className={"seg" + (device === "mobile" ? " seg--on" : "")}
                onClick={() => setDevice("mobile")}>
                <Icon name="mobile" size={16} /> Móvil
              </button>
            </div>
            {error
              ? <span id="url-err" className="url-msg url-msg--err" role="alert"><Icon name="alert" size={15} stroke={2} /> {error}</span>
              : <span id="url-hint" className="url-msg">Sin registro. Resultados en segundos.</span>}
          </div>
        </div>

        <ul className="hero-chips" aria-label="Garantías">
          <li><Icon name="check" size={15} stroke={2} /> 100% gratis</li>
          <li><Icon name="check" size={15} stroke={2} /> Sin registro</li>
          <li><Icon name="check" size={15} stroke={2} /> Sin tecnicismos</li>
          <li><Icon name="check" size={15} stroke={2} /> Datos reales de Google</li>
        </ul>
      </div>
    </section>
  );
}

/* ===================== ANALIZANDO ===================== */
function Analyzing({ url, device, done, error, onRetry }) {
  const reduce = useRef(window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches).current;
  const total = ANALYZE_STEPS.length;
  // 'done' viene del padre cuando termina el fetch — pero animamos visualmente
  // un progreso suave mientras esperamos la respuesta del backend.
  const [step, setStep] = useState(0);

  useEffect(() => {
    if (done) { setStep(total); return; }
    const perStep = reduce ? 280 : 1100; // analisis backend tarda ~10–20s
    const id = setInterval(() => {
      setStep((s) => Math.min(total - 1, s + 1));
    }, perStep);
    return () => clearInterval(id);
  }, [done]);

  const pct = Math.round((step / total) * 100);

  if (error) {
    return (
      <section className="analyzing" aria-live="polite">
        <div className="container an-inner">
          <div className="an-pulse" style={{background:"var(--danger-100)", color:"var(--danger-500)"}} aria-hidden="true">
            <Icon name="alert" size={30} stroke={2} />
          </div>
          <h2 className="an-title">No pudimos completar el análisis</h2>
          <p className="an-sub" style={{color:"var(--danger-700)"}}>{error}</p>
          <div style={{marginTop:24}}>
            <button className="btn btn-primary btn-lg" onClick={onRetry}>← Intentar con otra URL</button>
          </div>
        </div>
      </section>
    );
  }

  return (
    <section className="analyzing" aria-live="polite" aria-busy="true">
      <div className="container an-inner">
        <div className="an-pulse" aria-hidden="true">
          <Icon name="search" size={30} stroke={1.75} />
        </div>
        <h2 className="an-title">Revisando {prettyHost(url)}…</h2>
        <p className="an-sub">
          Estamos midiendo tu página en {device === "mobile" ? "celular" : "computador"} usando la
          misma tecnología que Google. Esto toma 10 a 20 segundos.
        </p>

        <div className="an-progress">
          <div className="an-progress-track" role="progressbar" aria-valuenow={pct} aria-valuemin={0} aria-valuemax={100} aria-label="Progreso del análisis">
            <div className="an-progress-fill" style={{ width: pct + "%", transition: reduce ? "none" : "width .35s var(--ease-out)" }} />
          </div>
          <span className="an-progress-pct">{pct}%</span>
        </div>

        <ul className="an-checklist">
          {ANALYZE_STEPS.map((label, i) => {
            const state = i < step ? "done" : i === step ? "active" : "wait";
            return (
              <li key={label} className={"an-item an-item--" + state}>
                <span className="an-check" aria-hidden="true">
                  {state === "done" ? <Icon name="check" size={14} stroke={2.5} />
                    : state === "active" ? <span className="an-spin" /> : null}
                </span>
                <span className="an-label">{label}</span>
                <span className="an-status">{state === "done" ? "Listo" : state === "active" ? "Revisando" : ""}</span>
              </li>
            );
          })}
        </ul>
      </div>
    </section>
  );
}

/* ===================== RESULTADOS ===================== */
function PotentialCard({ pct }) {
  return (
    <div className="potential-card">
      <div className="potential-icon" aria-hidden="true"><Icon name="trending" size={22} stroke={2} /></div>
      <div>
        <div className="potential-label">Mejora potencial de conversión estimada</div>
        <div className="potential-num">+{pct}<span>%</span></div>
      </div>
      <p className="potential-note">Resolviendo los problemas detectados, basado en tu puntaje actual.</p>
    </div>
  );
}

/* ===================== VELOCIDAD REAL (Core Web Vitals con nombres humanos) ===================== */
function CWVCard({ label, sublabel, explain, value, unit, threshold, lowerBetter = true }) {
  if (value === null || value === undefined) {
    return (
      <div className="kpi-card">
        <div className="kpi-value" style={{opacity:.4}}>—</div>
        <div className="kpi-label">{label}</div>
        <p className="kpi-hint">No pudimos medirlo en este momento.</p>
      </div>
    );
  }
  // Determinar tono según threshold ([bueno, necesita-mejora])
  let tone = "success";
  if (lowerBetter) {
    if (value > threshold[1]) tone = "danger";
    else if (value > threshold[0]) tone = "warning";
  } else {
    if (value < threshold[0]) tone = "danger";
    else if (value < threshold[1]) tone = "warning";
  }
  const display = unit === "ms" && value > 1000
    ? (value / 1000).toFixed(1) + "s"
    : unit === "ms" ? Math.round(value) + "ms"
    : unit === "cls" ? value.toFixed(2)
    : value;

  const statusText = tone === "success" ? "✓ Muy bien" : tone === "warning" ? "Mejorable" : "✗ Problema";
  const statusFull = tone === "success"
    ? "Tu sitio cumple bien con esta medida."
    : tone === "warning"
    ? "Está aceptable, pero podría mejorar."
    : "Está afectando la experiencia de tus visitantes.";

  return (
    <div className="kpi-card">
      <span className="kpi-icon" style={{color:TONE[tone].color, background:TONE[tone].bg}}>
        <Icon name="gauge" size={18} />
      </span>
      <div className="kpi-value">{display}</div>
      <div className="kpi-label">{label}</div>
      {sublabel && <div style={{fontSize:11, color:"var(--fg-tertiary)", marginTop:2, fontStyle:"italic"}}>{sublabel}</div>}
      <p className="kpi-hint" style={{fontWeight:600, color:TONE[tone].fg, marginTop:6}}>
        {statusText}
      </p>
      <p className="kpi-hint" style={{marginTop:2}}>{statusFull}</p>
      {explain && <p className="kpi-hint" style={{marginTop:6, fontStyle:"italic", opacity:.8}}>{explain}</p>}
    </div>
  );
}

function CoreWebVitalsSection({ cwv }) {
  if (!cwv) return null;
  return (
    <section className="res-section container" aria-labelledby="cwv-h">
      <div className="section-head">
        <span className="eyebrow" style={{display:"inline-flex",alignItems:"center",gap:8}}>
          <span style={{background:"#16794a",color:"#fff",padding:"2px 7px",borderRadius:6,fontWeight:700}}>DATOS REALES</span>
          Medido en vivo por Google
        </span>
        <h2 id="cwv-h" className="section-h2">¿Qué tan rápida y estable es tu página?</h2>
        <p className="section-lead">
          Estas 4 mediciones son las que Google usa para decidir cuánto destaca tu sitio
          en los resultados de búsqueda y cuán cómoda es tu página para tus visitantes.
        </p>
      </div>
      <div className="traffic-kpis">
        <CWVCard
          label="Velocidad de carga principal"
          sublabel="LCP"
          explain="Tiempo que tarda en aparecer el contenido más importante (foto, título, etc.)"
          value={cwv.lcp_ms} unit="ms" threshold={[2500, 4000]} />
        <CWVCard
          label="Estabilidad al cargar"
          sublabel="CLS"
          explain="Si el contenido salta o se mueve mientras carga (lo cual molesta al usuario)"
          value={cwv.cls} unit="cls" threshold={[0.1, 0.25]} />
        <CWVCard
          label="Tiempo en mostrar algo"
          sublabel="FCP"
          explain="Cuándo aparece la primera imagen o texto en pantalla"
          value={cwv.fcp_ms} unit="ms" threshold={[1800, 3000]} />
        <CWVCard
          label="Tiempo en responder al click"
          sublabel="TBT"
          explain="Cuánto tarda tu página en reaccionar cuando el usuario hace algo"
          value={cwv.tbt_ms} unit="ms" threshold={[200, 600]} />
      </div>
    </section>
  );
}

/* ===================== AUDITORÍA TÉCNICA (datos REALES) ===================== */
function AuditoriaTecnicaSection({ a }) {
  if (!a || !a.ok) return null;
  const { fmtNum, fmtCompact } = window.ConvierteEngine;

  const w = a.whois || {};
  const c = a.crawl || {};
  const s = a.seo || {};
  const idx = a.indexed || {};
  const t = a.tech || {};
  const ssl = a.ssl || {};
  const sec = a.security || {};
  const ct = a.content || {};

  // KPIs reales con lenguaje natural
  const kpis = [];

  // 1. Páginas indexadas
  if (idx.indexed_pages !== null && idx.indexed_pages !== undefined) {
    kpis.push({ icon:"globe", label:"Páginas que aparecen en Google", value:fmtCompact(idx.indexed_pages),
      hint: idx.indexed_pages > 10 ? "Suficientes páginas en los resultados de búsqueda." : "Pocas páginas. Google podría no estar viendo todo tu sitio.",
      tone: idx.indexed_pages > 10 ? "success" : "warning" });
  }
  // 2. Edad del dominio
  if (w.domain_age_years) {
    kpis.push({ icon:"network", label:"Tu sitio existe hace", value:w.domain_age_years, suffix:" años",
      hint: w.domain_age_years >= 3 ? "Google confía más en dominios viejos." : (w.domain_age_years >= 1 ? "Aún relativamente nuevo." : "Muy nuevo. Google tarda en confiar."),
      tone: w.domain_age_years >= 3 ? "success" : (w.domain_age_years >= 1 ? "info" : "warning") });
  }
  // 3. Páginas crawleadas con OK
  kpis.push({ icon:"check", label:"Páginas revisadas", value:c.pages_crawled || 0,
    hint: (c.broken_count || 0) === 0 ? "Todas funcionando bien." : `${c.broken_count} con problemas (links rotos).`,
    tone: (c.broken_count || 0) === 0 ? "success" : "warning" });
  // 4. Links rotos
  if ((c.broken_count || 0) > 0) {
    kpis.push({ icon:"alert", label:"Enlaces rotos en tu sitio", value:c.broken_count,
      hint:"Cuando alguien hace click y la página no existe. Frustra al visitante y a Google.",
      tone: c.broken_count > 5 ? "danger" : "warning" });
  }
  // 5. SSL grade (candado de seguridad)
  if (ssl.grade) {
    kpis.push({ icon:"shield", label:"Seguridad del candado (HTTPS)", value:ssl.grade, suffix:"/A+",
      hint: ssl.grade.startsWith('A') ? "Excelente. Tu sitio es seguro para el visitante." : (ssl.grade === 'B' ? "Aceptable, podría mejorar." : "Tu certificado de seguridad tiene problemas."),
      tone: ssl.grade.startsWith('A') ? "success" : (ssl.grade === 'B' ? "info" : "warning") });
  } else if (ssl.has_https === false) {
    kpis.push({ icon:"alert", label:"Candado de seguridad", value:"NO TIENE", hint:"Tu sitio no usa HTTPS — Chrome lo marca como 'No seguro' y la gente se va.", tone:"danger" });
  }
  // 6. Security headers (configuración de seguridad)
  kpis.push({ icon:"shield", label:"Configuración de seguridad", value:sec.grade || "F",
    hint: (sec.missing_count || 0) > 0 ? `Le faltan ${sec.missing_count} protecciones de seguridad estándar.` : "Bien configurado.",
    tone: (sec.grade || "F") === "A" ? "success" : ((sec.grade || "F") === "B" ? "info" : "warning") });
  // 7. CMS detectado (qué plataforma usa)
  if (t.cms) {
    kpis.push({ icon:"layers", label:"Hecho con", value:t.cms, hint:"Plataforma con la que está construido tu sitio.", tone:"info" });
  } else if (t.frameworks?.length) {
    kpis.push({ icon:"layers", label:"Hecho con", value:t.frameworks[0], hint:"Tecnología detectada en tu sitio.", tone:"info" });
  }
  // 8. E-commerce
  if (t.ecommerce) {
    kpis.push({ icon:"cursor", label:"Tienda online", value:t.ecommerce, hint:"Detectamos que vendes online con esta plataforma.", tone:"info" });
  }
  // 9. Schema.org (Datos para Google)
  if ((s.meta?.schema_count || 0) > 0) {
    kpis.push({ icon:"check", label:"Datos extra para Google", value:"Sí",
      hint:"Le das información estructurada a Google (precios, reseñas, etc.) para que destaque mejor tu sitio.",
      tone:"success" });
  } else {
    kpis.push({ icon:"alert", label:"Datos extra para Google", value:"No",
      hint:"Pierdes la oportunidad de que Google muestre tu producto con estrellas, precios, etc.",
      tone:"warning" });
  }
  // 10. Open Graph (cómo se ve al compartir)
  const ogOk = s.meta?.has_og_image && s.meta?.has_og_title && s.meta?.has_og_desc;
  kpis.push({ icon:"globe", label:"Vista previa al compartir", value: ogOk ? "Bien" : "Incompleta",
    hint: ogOk ? "Cuando comparten tu link en WhatsApp/Facebook, se ve con foto y descripción." : "Al compartir tu link en redes, no aparece foto/título correctamente.",
    tone: ogOk ? "success" : "warning" });
  // 11. Sitemap (mapa de tu sitio)
  kpis.push({ icon:"layers", label:"Mapa del sitio (sitemap)", value: s.sitemap?.exists ? `${s.sitemap.urls_count} páginas` : "No tiene",
    hint: s.sitemap?.exists ? "Le facilitas a Google encontrar todas tus páginas." : "Sin sitemap, Google puede olvidar algunas páginas.",
    tone: s.sitemap?.exists ? "success" : "warning" });
  // 12. Contenido
  kpis.push({ icon:"message", label:"Palabras en tu página principal", value: fmtCompact(ct.word_count || 0),
    hint: ct.has_thin_content ? "Muy poco texto (menos de 250 palabras). Google prefiere páginas con más contenido." : "Cantidad de texto adecuada para Google.",
    tone: ct.has_thin_content ? "warning" : "success" });

  return (
    <section className="res-section container" aria-labelledby="audit-h">
      <div className="section-head">
        <span className="eyebrow" style={{display:"inline-flex",alignItems:"center",gap:8}}>
          <span style={{background:"#16794a",color:"#fff",padding:"2px 7px",borderRadius:6,fontWeight:700}}>DATOS REALES</span>
          Revisamos {c.pages_crawled || 0} páginas de tu sitio en vivo
        </span>
        <h2 id="audit-h" className="section-h2">¿Cómo está la salud técnica de tu sitio?</h2>
        <p className="section-lead">
          Estos son aspectos técnicos importantes que afectan cuán bien se ve tu página
          en Google, qué tan rápida es y qué tan segura. <strong>Todo medido en vivo</strong>,
          nada de estimaciones.
        </p>
      </div>

      <div className="traffic-kpis">
        {kpis.map((m, i) => (
          <div className="kpi-card" key={i}>
            <span className="kpi-icon" style={m.tone ? { color: TONE[m.tone].color, background: TONE[m.tone].bg } : null}>
              <Icon name={m.icon} size={18} />
            </span>
            <div className="kpi-value">{m.value}{m.suffix ? <span className="kpi-suffix">{m.suffix}</span> : null}</div>
            <div className="kpi-label">{m.label}</div>
            <p className="kpi-hint">{m.hint}</p>
          </div>
        ))}
      </div>

      {/* Tecnologías y analytics si hay */}
      {(t.analytics?.length > 0 || t.frameworks?.length > 0) && (
        <div style={{marginTop:24, padding:"20px 24px", background:"var(--white)", border:"1px solid var(--border-default)", borderRadius:"var(--radius-lg)"}}>
          <div style={{display:"grid", gridTemplateColumns:"repeat(auto-fit, minmax(220px, 1fr))", gap:24}}>
            {t.frameworks?.length > 0 && (
              <div>
                <div className="eyebrow" style={{marginBottom:8}}>Tecnologías que detectamos</div>
                <div style={{display:"flex", flexWrap:"wrap", gap:6}}>
                  {t.frameworks.map((f) => (
                    <span key={f} style={{padding:"4px 10px", borderRadius:8, background:"var(--info-100)", color:"var(--info-700)", fontSize:12, fontWeight:600}}>{f}</span>
                  ))}
                </div>
              </div>
            )}
            {t.analytics?.length > 0 && (
              <div>
                <div className="eyebrow" style={{marginBottom:8}}>Herramientas de seguimiento</div>
                <div style={{display:"flex", flexWrap:"wrap", gap:6}}>
                  {t.analytics.map((a) => (
                    <span key={a} style={{padding:"4px 10px", borderRadius:8, background:"var(--accent-100)", color:"var(--accent-700)", fontSize:12, fontWeight:600}}>{a}</span>
                  ))}
                </div>
              </div>
            )}
            {t.hosting && (
              <div>
                <div className="eyebrow" style={{marginBottom:8}}>Dónde está alojado</div>
                <span style={{padding:"4px 10px", borderRadius:8, background:"var(--navy-100)", color:"var(--navy-700)", fontSize:12, fontWeight:600}}>{t.hosting}</span>
              </div>
            )}
          </div>
        </div>
      )}

      <p className="traffic-foot">
        <Icon name="check" size={14} stroke={2} />
        <strong>Todo lo de arriba es real</strong> — lo medimos directamente entrando a tu sitio,
        revisando hasta {c.pages_crawled || 0} páginas, el certificado de seguridad, las tecnologías
        que usas y cuánto contenido tienes.
      </p>
    </section>
  );
}

function CategoryGrid({ categories }) {
  return (
    <div className="cat-grid">
      {categories.map((c, i) => (
        <div className="cat-card" key={c.key}>
          <div className="cat-head">
            <span className="cat-icon" style={{ color: TONE[c.band.tone].color, background: TONE[c.band.tone].bg }}>
              <Icon name={c.icon} size={20} />
            </span>
            <span className="cat-score" style={{ color: "var(--navy-900)" }}>{c.score}</span>
          </div>
          <div className="cat-name">{c.label}</div>
          <CatBar score={c.score} tone={c.band.tone} delay={i * 70} />
        </div>
      ))}
    </div>
  );
}

/* ════════════════════════════════════════════════════════════════════════════
   REDISEÑO 2026 — Paleta del handoff. Helpers compartidos para Google notes,
   métricas técnicas, áreas y problemas. Tres tonos según score:
     >=90  → success (verde)   50-89 → warn (ámbar)   <50 → danger (rojo)
   Los colores y border-radius vienen tal cual del mock HTML/CSS del handoff.
   ════════════════════════════════════════════════════════════════════════════ */
const NEW_META = (s) => {
  if (s == null || isNaN(s)) return { ring:'#8a90a3', track:'#eef0f4', bg:'#eef0f6', text:'#5b607d', statusLabel:'Sin dato' };
  if (s >= 90) return { ring:'#22c55e', track:'#d4f1de', bg:'#e7f8ee', text:'#15803d', statusLabel:'Bien' };
  if (s >= 50) return { ring:'#eab308', track:'#f3e9c6', bg:'#fdf6e0', text:'#a16207', statusLabel:'Mejorable' };
  return { ring:'#ef4444', track:'#f6d8d8', bg:'#fdecec', text:'#c0271d', statusLabel:'Crítico' };
};
const donutDash = (score, r) => {
  const c = 2 * Math.PI * r;
  const filled = c * (score == null ? 0 : score) / 100;
  return filled.toFixed(1) + ' ' + (c - filled).toFixed(1);
};

/* ─── Tooltip wrapper ─── click/tap en móvil, hover en desktop, esc para cerrar.
   Antes solo CSS :hover, no funcionaba en touch. Ahora usa state + outside-click. */
function HelpTip({ children, position = 'bottom' }) {
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);
  const isTop = position === 'top';

  // Click fuera → cerrar. Esc → cerrar.
  useEffect(() => {
    if (!open) return;
    const onDocClick = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('click', onDocClick);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('click', onDocClick); document.removeEventListener('keydown', onKey); };
  }, [open]);

  return (
    <span ref={wrapRef} style={{position:'relative', display:'inline-flex'}} className="diag-tipwrap">
      <button
        type="button"
        aria-label="Más información"
        aria-expanded={open}
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
        onMouseEnter={() => setOpen(true)}
        onMouseLeave={(e) => {
          // Solo cerramos por mouseleave si NO fue abierto por click (touch).
          // Si el usuario hizo tap, se queda hasta que toque fuera o el ?.
          if (e.nativeEvent && e.nativeEvent.relatedTarget !== null) setOpen(false);
        }}
        style={{
          width:17, height:17, borderRadius:'50%',
          background: open ? '#1a2340' : '#e6e8ee',
          color: open ? '#fff' : '#5b607d',
          fontSize:11, fontWeight:700,
          display:'flex', alignItems:'center', justifyContent:'center',
          cursor:'pointer', border:'none', padding:0, fontFamily:'inherit',
          transition:'background .15s, color .15s',
        }}>?</button>
      {open && (
        <span style={{
          position:'absolute', [isTop?'bottom':'top']:24, left:'50%', transform:'translateX(-50%)',
          width:230, background:'#1a2340', color:'#fff', borderRadius:12, padding:'13px 14px',
          boxShadow:'0 16px 30px -10px rgba(26,35,64,.5)', zIndex:60, textAlign:'left',
          fontSize:12.5, lineHeight:1.45,
        }} onClick={(e) => e.stopPropagation()}>{children}</span>
      )}
    </span>
  );
}

/* ─── 1. Google verification band (verde, con check) ─── */
function GoogleVerificationBand({ dx, onReanalizar }) {
  const [busy, setBusy] = useState(false);
  const fetched = dx.meta?.fetched_at ? new Date(dx.meta.fetched_at) : null;
  const ageMin = fetched ? Math.round((Date.now() - fetched.getTime()) / 60000) : null;
  const psWebUrl = `https://pagespeed.web.dev/analysis?url=${encodeURIComponent(dx.url)}&form_factor=${dx.device}`;
  const handleRe = async () => { setBusy(true); await onReanalizar(); setBusy(false); };

  return (
    <section className="diag-band" style={{background:'#ffffff', border:'1px solid #e6e8ee', borderLeft:'4px solid #22c55e', borderRadius:14, padding:'18px 24px', marginTop:18, display:'flex', alignItems:'center', gap:22, flexWrap:'wrap', boxShadow:'0 1px 2px rgba(26,35,64,.04)'}}>
      <div style={{display:'flex', alignItems:'center', gap:13, flex:'1 1 420px', minWidth:280}}>
        <span style={{flex:'0 0 auto', width:38, height:38, borderRadius:10, background:'#e7f8ee', color:'#15803d', display:'flex', alignItems:'center', justifyContent:'center', fontSize:20, fontWeight:800}}>✓</span>
        <div>
          <div style={{fontSize:13, fontWeight:700, color:'#15803d', letterSpacing:'.04em'}}>DATOS DIRECTOS DE GOOGLE</div>
          <div style={{fontSize:14, color:'#4a5169', lineHeight:1.45, marginTop:2}}>
            Estos no son inventados. Son los mismos números de la herramienta oficial de Google
            {fetched && <> · <span style={{color:'#8a90a3'}}>análisis hecho {ageMin < 1 ? 'hace un momento' : `hace ${ageMin} min`}</span></>}
          </div>
        </div>
      </div>
      <div className="diag-band-cta" style={{display:'flex', alignItems:'center', gap:10, flexWrap:'wrap'}}>
        <a href={psWebUrl} target="_blank" rel="noopener noreferrer" style={{display:'inline-flex', alignItems:'center', gap:7, background:'#ffffff', border:'1px solid #cdd2dd', color:'#1a2340', fontSize:14, fontWeight:600, padding:'10px 16px', borderRadius:10, textDecoration:'none'}}>
          Comprobar con Google →
        </a>
        <button onClick={handleRe} disabled={busy} style={{display:'inline-flex', alignItems:'center', gap:7, background:'#f5a623', border:'none', color:'#1a2340', fontSize:14, fontWeight:700, padding:'10px 16px', borderRadius:10, cursor: busy?'not-allowed':'pointer', opacity: busy?0.7:1}}>
          {busy ? 'Midiendo…' : '↻ Volver a medir'}
        </button>
      </div>
    </section>
  );
}

/* ─── 2. Google 4 notes (donuts con tooltip) ─── */
const GOOGLE_TOOLTIPS = [
  { what:'Mide cuánto tarda tu página en cargar y volverse usable en un celular.', ideal:'90 o más', why:'Una página lenta pierde ventas: muchos se van antes de ver tu producto.' },
  { what:'Revisa si cualquier persona puede leer, tocar y navegar tu página sin problemas.', ideal:'90 o más', why:'Si cuesta usarla, cuesta comprar.' },
  { what:'Comprueba que el sitio esté bien construido: HTTPS, código sano y sin errores.', ideal:'90 o más', why:'Un sitio sólido da confianza y evita fallas durante la compra.' },
  { what:'Mide qué tan bien Google entiende y muestra tu página en los resultados.', ideal:'90 o más', why:'Más visibilidad significa más visitas y más ventas.' },
];
function GoogleNotesSection({ psiScores, psiScoresSource }) {
  const labels = ['Velocidad', 'Fácil de usar', 'Calidad técnica', 'Visible en Google'];
  const subs   = ['Qué tan rápido carga tu página.', 'Qué tan fácil es navegarla.', 'Si está bien hecha por dentro.', 'Qué tan bien la encuentra Google.'];
  const keys   = ['performance', 'accessibility', 'best_practices', 'seo'];
  const src = psiScoresSource || ['unavailable','unavailable','unavailable','unavailable'];
  const algunaFalta = src.some(o => o !== 'google');

  return (
    <section style={{marginTop:38}}>
      <div style={{textAlign:'center', maxWidth:600, margin:'0 auto 28px'}}>
        <span style={{fontSize:12, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'#8a90a3'}}>Las 4 notas de Google</span>
        <h2 style={{fontSize:28, fontWeight:700, letterSpacing:'-.02em', color:'#1a2340', margin:'8px 0 8px'}}>Notas que Google le da a tu página</h2>
        <p style={{fontSize:15, color:'#5b607d', lineHeight:1.5, margin:0}}>
          Las mismas 4 notas que verías en la herramienta oficial de Google. Van de 0 a 100 — mientras más alto, mejor.
        </p>
      </div>
      <div className="diag-grid-4" style={{display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:18}}>
        {keys.map((k, i) => {
          const score = psiScores?.[k];
          const unavailable = src[i] === 'unavailable' || score == null;
          const m = NEW_META(score);
          const tip = GOOGLE_TOOLTIPS[i];
          return (
            <div key={k} style={{background:'#ffffff', border:'1px solid #e6e8ee', borderTop:`4px solid ${m.ring}`, borderRadius:16, padding:'22px 18px 20px', textAlign:'center', boxShadow:'0 1px 2px rgba(26,35,64,.04)'}}>
              <div style={{display:'flex', alignItems:'center', justifyContent:'center', gap:6, marginBottom:14}}>
                <span style={{fontSize:14, fontWeight:700, color:'#1a2340'}}>{labels[i]}</span>
                <HelpTip>
                  <span style={{display:'block', fontSize:13, fontWeight:600, lineHeight:1.4, marginBottom:6}}>{tip.what}</span>
                  <span style={{display:'block', fontSize:12, color:'#7be0a5', fontWeight:600, marginBottom:6}}>Ideal: {tip.ideal}</span>
                  <span style={{display:'block', fontSize:12, color:'rgba(255,255,255,.72)', lineHeight:1.45}}>{tip.why}</span>
                </HelpTip>
              </div>
              <div style={{position:'relative', width:118, height:118, margin:'0 auto'}}>
                <svg width="118" height="118" viewBox="0 0 118 118" style={{transform:'rotate(-90deg)'}}>
                  <circle cx="59" cy="59" r="50" fill="none" stroke={m.track} strokeWidth="10" />
                  <circle cx="59" cy="59" r="50" fill="none" stroke={m.ring} strokeWidth="10" strokeLinecap="round" strokeDasharray={donutDash(score || 0, 50)} />
                </svg>
                <div style={{position:'absolute', inset:0, display:'flex', alignItems:'center', justifyContent:'center', fontSize:36, fontWeight:800, letterSpacing:'-.02em', color:m.ring}}>
                  {unavailable ? '—' : score}
                </div>
              </div>
              <div style={{marginTop:14, display:'inline-flex', alignItems:'center', gap:6, background:m.bg, color:m.text, fontSize:12, fontWeight:700, padding:'5px 11px', borderRadius:999}}>
                {unavailable ? 'Sin dato' : m.statusLabel}
              </div>
              <p style={{fontSize:12.5, color:'#8a90a3', lineHeight:1.4, margin:'10px 0 0'}}>{subs[i]}</p>
            </div>
          );
        })}
      </div>
      {algunaFalta && (
        <div style={{marginTop:14, padding:'10px 14px', background:'#fdf6e0', border:'1px solid #f3e9c6', borderRadius:8, fontSize:13, color:'#a16207', textAlign:'center'}}>
          Google no respondió todas las notas esta vez. Toca <strong>"↻ Volver a medir"</strong> arriba.
        </div>
      )}
    </section>
  );
}

/* ─── 3. Métricas técnicas (LCP / CLS / FCP / TBT) ─── */
function TechnicalMetricsSection({ cwv }) {
  if (!cwv) return null;
  const formatMs = (v) => v == null ? '—' : v >= 1000 ? (v/1000).toFixed(1) + ' s' : Math.round(v) + ' ms';
  const scoreFromCwv = {
    LCP: cwv.lcp_ms == null ? null : (cwv.lcp_ms <= 2500 ? 95 : cwv.lcp_ms <= 4000 ? 60 : 20),
    CLS: cwv.cls == null ? null : (cwv.cls <= 0.1 ? 95 : cwv.cls <= 0.25 ? 60 : 20),
    FCP: cwv.fcp_ms == null ? null : (cwv.fcp_ms <= 1800 ? 95 : cwv.fcp_ms <= 3000 ? 60 : 20),
    TBT: cwv.tbt_ms == null ? null : (cwv.tbt_ms <= 200 ? 95 : cwv.tbt_ms <= 600 ? 60 : 20),
  };
  const items = [
    { code:'LCP', name:'Tiempo de carga visual', value: formatMs(cwv.lcp_ms), score: scoreFromCwv.LCP,
      what:'Cuánto tarda en aparecer lo más grande de la pantalla (foto o banner principal).', ideal:'Menos de 2.5 s', why:'Si tarda, la gente se va antes de ver tu producto.' },
    { code:'CLS', name:'Estabilidad visual',     value: cwv.cls == null ? '—' : Number(cwv.cls).toFixed(2), score: scoreFromCwv.CLS,
      what:'Si los elementos saltan o se mueven solos mientras la página carga.', ideal:'Menos de 0.1', why:'Los saltos hacen que toquen el botón equivocado y se frustren.' },
    { code:'FCP', name:'Primer contenido',       value: formatMs(cwv.fcp_ms), score: scoreFromCwv.FCP,
      what:'Cuándo aparece el primer texto o imagen de tu página.', ideal:'Menos de 1.8 s', why:'Es la primera señal de que "esto sí funciona".' },
    { code:'TBT', name:'Tiempo sin responder',   value: formatMs(cwv.tbt_ms), score: scoreFromCwv.TBT,
      what:'Cuánto tiempo la página no reacciona a los toques mientras carga.', ideal:'Menos de 200 ms', why:'Si no responde, parece rota y pierdes la venta.' },
  ];
  return (
    <section style={{marginTop:46}}>
      <div style={{display:'flex', alignItems:'flex-end', justifyContent:'space-between', gap:16, marginBottom:20, flexWrap:'wrap'}}>
        <div>
          <span style={{fontSize:12, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'#8a90a3'}}>Métricas técnicas de Google</span>
          <h2 style={{fontSize:24, fontWeight:700, letterSpacing:'-.02em', color:'#1a2340', margin:'6px 0 0'}}>Cómo se siente tu página al cargar</h2>
        </div>
        <span style={{fontSize:13, color:'#8a90a3'}}>Pasa el cursor sobre el ? para entender cada una</span>
      </div>
      <div className="diag-grid-4" style={{display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:18}}>
        {items.map((t) => {
          const m = NEW_META(t.score);
          return (
            <div key={t.code} style={{background:'#ffffff', border:'1px solid #e6e8ee', borderRadius:16, padding:20, boxShadow:'0 1px 2px rgba(26,35,64,.04)'}}>
              <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:14}}>
                <span style={{display:'inline-flex', alignItems:'center', gap:6, background:'#f1f2f6', color:'#4a5169', fontFamily:"'JetBrains Mono',monospace", fontSize:12, fontWeight:600, padding:'4px 9px', borderRadius:7}}>{t.code}</span>
                <HelpTip>
                  <span style={{display:'block', fontSize:13, fontWeight:600, lineHeight:1.4, marginBottom:6}}>{t.what}</span>
                  <span style={{display:'block', fontSize:12, color:'#7be0a5', fontWeight:600, marginBottom:6}}>Ideal: {t.ideal}</span>
                  <span style={{display:'block', fontSize:12, color:'rgba(255,255,255,.72)', lineHeight:1.45}}>{t.why}</span>
                </HelpTip>
              </div>
              <div style={{fontSize:32, fontWeight:800, letterSpacing:'-.02em', color:m.text, whiteSpace:'nowrap', lineHeight:1.1}}>{t.value}</div>
              <div style={{fontSize:13.5, fontWeight:600, color:'#1a2340', marginTop:6}}>{t.name}</div>
              <div style={{marginTop:12, display:'inline-flex', alignItems:'center', gap:6, background:m.bg, color:m.text, fontSize:12, fontWeight:700, padding:'5px 10px', borderRadius:999}}>
                <span style={{width:7, height:7, borderRadius:'50%', background:m.ring, display:'inline-block'}}></span>{m.statusLabel}
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
}

/* ─── 4. Acordeón con 8 áreas Sell-U (barras de progreso) ─── */
function AreasAccordion({ categories }) {
  const [open, setOpen] = useState(true);
  return (
    <section style={{marginTop:46, background:'#ffffff', border:'1px solid #e6e8ee', borderRadius:18, boxShadow:'0 1px 2px rgba(26,35,64,.04)', overflow:'hidden'}}>
      <button type="button" onClick={() => setOpen(!open)} className="diag-areas-head" style={{width:'100%', display:'flex', alignItems:'center', justifyContent:'space-between', gap:16, padding:'22px 26px', background: open?'#fbfaf7':'#ffffff', border:'none', borderBottom: open?'1px solid #eef0f4':'none', cursor:'pointer', textAlign:'left', fontFamily:'inherit'}}>
        <span style={{display:'flex', alignItems:'center', gap:13}}>
          <span style={{width:40, height:40, borderRadius:11, background:'#eef0f6', color:'#1a2340', display:'flex', alignItems:'center', justifyContent:'center', fontSize:19, fontWeight:800}}>8</span>
          <span>
            <span style={{display:'block', fontSize:18, fontWeight:700, color:'#1a2340', letterSpacing:'-.01em'}}>Ver análisis detallado por área</span>
            <span style={{display:'block', fontSize:13.5, color:'#8a90a3', marginTop:2}}>Las 8 áreas que revisamos, con su puntaje</span>
          </span>
        </span>
        <span style={{display:'inline-flex', alignItems:'center', gap:9, fontSize:14, fontWeight:600, color:'#5b607d'}}>
          {open ? 'Ocultar' : 'Mostrar'}
          <span style={{fontSize:13, transform: open?'rotate(180deg)':'rotate(0deg)', transition:'transform .2s'}}>▼</span>
        </span>
      </button>
      {open && (
        <div className="diag-grid-2 diag-areas-body" style={{padding:'24px 26px 28px', display:'grid', gridTemplateColumns:'1fr 1fr', gap:'26px 48px'}}>
          {categories.map((c) => {
            const m = NEW_META(c.score);
            const firstSignal = c.signals?.[0] || 'Cómo Sell-U lo mide.';
            return (
              <div key={c.key}>
                <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', gap:10, marginBottom:9}}>
                  <span style={{display:'flex', alignItems:'center', gap:7}}>
                    <span style={{fontSize:14.5, fontWeight:600, color:'#1a2340'}}>{c.label}</span>
                    <HelpTip position="top">
                      <span style={{display:'block', fontSize:11, fontWeight:700, letterSpacing:'.08em', textTransform:'uppercase', color:'#f5a623', marginBottom:5}}>Cómo se mide</span>
                      <span style={{display:'block', fontSize:12.5, color:'rgba(255,255,255,.85)', lineHeight:1.45}}>{firstSignal}</span>
                    </HelpTip>
                  </span>
                  <span style={{display:'flex', alignItems:'baseline', gap:3}}>
                    <span style={{fontSize:18, fontWeight:800, color:m.ring}}>{c.score}</span>
                    <span style={{fontSize:12, fontWeight:600, color:'#b0b4c0'}}>/100</span>
                  </span>
                </div>
                <div style={{height:10, background:'#eef0f4', borderRadius:999, overflow:'hidden'}}>
                  <div style={{height:'100%', width: c.score + '%', background:m.ring, borderRadius:999, transition:'width .8s ease-out'}}></div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </section>
  );
}

/* ─── 5. Lista de problemas con prioridad + solución bloqueada ─── */
const PRIORITY_META = {
  alta:  { bg:'#fdecec', text:'#c0271d', dot:'#ef4444', label:'ALTA' },
  media: { bg:'#fdf6e0', text:'#a16207', dot:'#eab308', label:'MEDIA' },
  baja:  { bg:'#eef0f6', text:'#4a5169', dot:'#8a90a3', label:'BAJA' },
};
function NewProblemCard({ p, locked, onUnlock }) {
  const m = PRIORITY_META[p.severity] || PRIORITY_META.media;
  return (
    <div className="diag-problem-card" style={{background:'#ffffff', border:'1px solid #e6e8ee', borderLeft:`5px solid ${m.dot}`, borderRadius:16, padding:'24px 26px', boxShadow:'0 1px 2px rgba(26,35,64,.04)'}}>
      <div style={{display:'flex', alignItems:'center', gap:10, marginBottom:12, flexWrap:'wrap'}}>
        <span style={{display:'inline-flex', alignItems:'center', gap:6, background:m.bg, color:m.text, fontSize:12, fontWeight:800, letterSpacing:'.04em', padding:'5px 12px', borderRadius:999, textTransform:'uppercase'}}>
          <span style={{width:7, height:7, borderRadius:'50%', background:m.dot, display:'inline-block'}}></span>{m.label}
        </span>
        <span style={{fontSize:12, fontWeight:600, color:'#8a90a3', background:'#f1f2f6', padding:'5px 11px', borderRadius:999}}>{p.catLabel}</span>
      </div>
      <h3 style={{fontSize:19, fontWeight:700, color:'#1a2340', letterSpacing:'-.01em', margin:'0 0 14px'}}>{p.problema}</h3>
      <div className="diag-grid-2" style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:18}}>
        <div style={{background:'#fbf6f3', borderRadius:12, padding:'14px 16px'}}>
          <div style={{fontSize:11, fontWeight:700, letterSpacing:'.1em', textTransform:'uppercase', color:'#c0271d', marginBottom:6}}>Impacto en tus ventas</div>
          <div style={{fontSize:14, lineHeight:1.5, color:'#4a5169'}}>{p.impacto}</div>
        </div>
        <div style={{position:'relative', background:'#f1f8f4', borderRadius:12, padding:'14px 16px', overflow:'hidden'}}>
          <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', gap:8, marginBottom:6}}>
            <span style={{fontSize:11, fontWeight:700, letterSpacing:'.1em', textTransform:'uppercase', color:'#15803d'}}>Cómo se soluciona</span>
            {locked && (
              <span style={{display:'inline-flex', alignItems:'center', gap:5, fontSize:10.5, fontWeight:700, color:'#a16207', background:'#fdf6e0', padding:'3px 8px', borderRadius:999}}>
                <Icon name="lock" size={11} stroke={2.4} /> BLOQUEADO
              </span>
            )}
          </div>
          <div style={{fontSize:14, lineHeight:1.5, color:'#4a5169', filter: locked?'blur(5px)':'none', userSelect: locked?'none':'auto', pointerEvents: locked?'none':'auto'}} aria-hidden={locked || undefined}>
            {p.solucion}
          </div>
          {locked && (
            <div style={{position:'absolute', inset:'34px 16px 14px', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:6, textAlign:'center'}}>
              <span style={{width:30, height:30, borderRadius:'50%', background:'#fff', border:'1px solid #d8e4dc', display:'flex', alignItems:'center', justifyContent:'center', boxShadow:'0 2px 6px rgba(26,35,64,.1)'}}>
                <Icon name="lock" size={14} stroke={2.2} />
              </span>
              <button type="button" onClick={onUnlock} style={{background:'transparent', border:'none', fontSize:12.5, fontWeight:600, color:'#15803d', textDecoration:'none', borderBottom:'1px solid #9cc9af', cursor:'pointer', padding:0}}>
                Desbloquear en tu reporte →
              </button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* Banner de verificación: muestra cuándo se hizo el análisis y permite
   comparar con pagespeed.web.dev en una pestaña nueva. */
function VerificacionBanner({ dx, onReanalizar }) {
  const [reanalizando, setReanalizando] = useState(false);
  const fetched = dx.meta?.fetched_at ? new Date(dx.meta.fetched_at) : null;
  const ageMin = fetched ? Math.round((Date.now() - fetched.getTime()) / 60000) : null;
  const psWebUrl = `https://pagespeed.web.dev/analysis?url=${encodeURIComponent(dx.url)}&form_factor=${dx.device}`;

  const handleRe = async () => {
    setReanalizando(true);
    await onReanalizar();
    setReanalizando(false);
  };

  return (
    <div className="container" style={{paddingTop: 16, paddingBottom: 0}}>
      <div style={{
        background: "linear-gradient(135deg, var(--success-100) 0%, #d8f0e1 100%)",
        border: "1px solid var(--success-500)",
        borderRadius: 12, padding: "16px 20px",
        display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "space-between",
        gap: 12,
      }}>
        <div style={{display: "flex", alignItems: "flex-start", gap: 12, flexWrap: "wrap", flex: "1 1 280px", minWidth: 0}}>
          <div style={{
            background: "var(--success-500)", color: "#fff",
            borderRadius: 8, padding: "4px 10px",
            fontSize: 11, fontWeight: 800, letterSpacing: ".06em",
            display: "inline-flex", alignItems: "center", gap: 4, flexShrink: 0,
          }}>
            <Icon name="check" size={14} stroke={3} /> DATOS DE GOOGLE
          </div>
          <div style={{fontSize: 13.5, color: "var(--success-700)", lineHeight: 1.55, minWidth: 0}}>
            <strong>Estos no son inventados.</strong> Los obtenemos directo de Google — los mismos números que verías en su herramienta oficial.
            {fetched && <span style={{display:"block", fontSize:12, opacity:0.85, marginTop:3}}>Análisis hecho {ageMin < 1 ? "hace un momento" : `hace ${ageMin} min`}</span>}
            <span style={{display:"block", fontSize: 12, opacity: 0.85, marginTop: 5, fontWeight: 600}}>
              ¿Quieres comprobarlo? Toca el botón verde →
            </span>
          </div>
        </div>
        <div style={{display: "flex", gap: 8, flexWrap: "wrap"}}>
          <a href={psWebUrl} target="_blank" rel="noopener noreferrer"
             className="btn btn-secondary btn-sm" title="Abrir la herramienta oficial de Google con la misma URL para comparar los números">
            Comprobar con Google <Icon name="arrow" size={14} stroke={2} />
          </a>
          <button className="btn btn-primary btn-sm" onClick={handleRe} disabled={reanalizando}>
            {reanalizando ? "Midiendo…" : "Volver a medir"}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ─── 6. Hero de resultados (gradient navy + donut global + verdict + URL chip) ─── */
function ResultsHero({ dx }) {
  const score = dx.overall;
  const m = NEW_META(score);
  const verdict = score >= 90
    ? { label:'Buen estado', title:'Tu página va muy bien. Afinemos los últimos detalles.', badgeBg:'rgba(34,197,94,.16)', badgeText:'#7be0a5' }
    : score >= 50
    ? { label:'Necesita atención', title:'Tu página tiene buena base, pero está perdiendo ventas por velocidad.', badgeBg:'rgba(245,166,35,.16)', badgeText:'#f5a623' }
    : { label:'Estado crítico', title:'Tu página necesita arreglos urgentes para dejar de perder ventas.', badgeBg:'rgba(239,68,68,.16)', badgeText:'#fca5a5' };
  const ringColor = '#f5a623'; // tono cálido de marca en el hero, independiente del score
  return (
    <section className="diag-hero-section" style={{background:'linear-gradient(180deg,#1a2340 0%,#222c4f 100%)', borderRadius:22, padding:'44px 48px', color:'#ffffff', boxShadow:'0 24px 48px -18px rgba(26,35,64,.45)', position:'relative', overflow:'hidden', marginTop:8}}>
      <div style={{position:'absolute', top:-60, right:-40, width:320, height:320, borderRadius:'50%', background:'radial-gradient(circle,rgba(245,166,35,.14),transparent 70%)'}}></div>
      <div className="diag-hero-row" style={{display:'flex', alignItems:'center', gap:44, flexWrap:'wrap', position:'relative'}}>
        <div style={{flex:'0 0 auto', display:'flex', flexDirection:'column', alignItems:'center'}}>
          <div className="diag-hero-donut" style={{position:'relative', width:200, height:200}}>
            <svg width="200" height="200" viewBox="0 0 200 200" style={{transform:'rotate(-90deg)'}}>
              <circle cx="100" cy="100" r="84" fill="none" stroke="rgba(255,255,255,.12)" strokeWidth="16" />
              <circle cx="100" cy="100" r="84" fill="none" stroke={ringColor} strokeWidth="16" strokeLinecap="round" strokeDasharray={donutDash(score, 84)} />
            </svg>
            <div style={{position:'absolute', inset:0, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center'}}>
              <span className="diag-hero-score" style={{fontSize:68, fontWeight:800, lineHeight:1, letterSpacing:'-.03em', color:'#ffffff'}}>{score}</span>
              <span style={{fontSize:15, fontWeight:600, color:'rgba(255,255,255,.6)', marginTop:2}}>de 100</span>
            </div>
          </div>
          <span style={{marginTop:14, fontSize:12, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'#f5a623'}}>Puntaje Sell-U</span>
        </div>
        <div style={{flex:'1 1 360px', minWidth:280}}>
          <div style={{display:'inline-flex', alignItems:'center', gap:8, background:verdict.badgeBg, color:verdict.badgeText, fontSize:13, fontWeight:700, padding:'6px 13px', borderRadius:999, marginBottom:16}}>
            <span style={{width:8, height:8, borderRadius:'50%', background:ringColor, display:'inline-block'}}></span>
            {verdict.label}
          </div>
          <h1 style={{fontSize:34, lineHeight:1.15, fontWeight:700, letterSpacing:'-.02em', color:'#ffffff', margin:'0 0 12px', maxWidth:560}}>{verdict.title}</h1>
          <p style={{fontSize:16, lineHeight:1.55, color:'rgba(255,255,255,.78)', margin:'0 0 26px', maxWidth:540}}>
            Combinamos las notas oficiales de Google con nuestra propia revisión de 8 áreas. Abajo te mostramos exactamente qué arreglar y en qué orden.
          </p>
          <div style={{display:'flex', alignItems:'center', gap:14, flexWrap:'wrap'}}>
            <a href="#arreglar" onClick={(e) => { e.preventDefault(); scrollToId('arreglar'); }} style={{display:'inline-flex', alignItems:'center', gap:9, background:'#f5a623', color:'#1a2340', fontSize:16, fontWeight:700, padding:'15px 26px', borderRadius:12, textDecoration:'none', boxShadow:'0 10px 22px -8px rgba(245,166,35,.6)'}}>
              Quiero que lo arreglen →
            </a>
            <div style={{display:'flex', alignItems:'center', gap:10, background:'rgba(255,255,255,.08)', border:'1px solid rgba(255,255,255,.16)', padding:'9px 16px', borderRadius:12}}>
              <span style={{fontFamily:"'JetBrains Mono',monospace", fontSize:14, fontWeight:500, color:'#ffffff'}}>{prettyHost(dx.url)}</span>
              <span style={{fontSize:11, fontWeight:700, letterSpacing:'.08em', background:'#f5a623', color:'#1a2340', padding:'3px 9px', borderRadius:999}}>
                {dx.device === 'mobile' ? 'MÓVIL' : 'ESCRITORIO'}
              </span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ─── 7. CTA "no quieres lidiar con todo esto" ─── */
function MidPageCTA() {
  return (
    <div className="diag-mid-cta" style={{marginTop:28, background:'linear-gradient(135deg,#1a2340,#252f54)', borderRadius:18, padding:'34px 40px', display:'flex', alignItems:'center', justifyContent:'space-between', gap:24, flexWrap:'wrap', boxShadow:'0 18px 36px -16px rgba(26,35,64,.4)'}}>
      <div style={{maxWidth:520}}>
        <h3 style={{fontSize:22, fontWeight:700, color:'#ffffff', letterSpacing:'-.01em', margin:'0 0 8px'}}>¿No quieres lidiar con todo esto?</h3>
        <p style={{fontSize:15, lineHeight:1.5, color:'rgba(255,255,255,.78)', margin:0}}>
          Nuestro equipo arregla cada uno de estos puntos por ti y te entrega tu página vendiendo más, en menos de lo que crees.
        </p>
      </div>
      <a href="#arreglar" onClick={(e) => { e.preventDefault(); scrollToId('arreglar'); }} style={{display:'inline-flex', alignItems:'center', gap:9, background:'#f5a623', color:'#1a2340', fontSize:16, fontWeight:700, padding:'15px 28px', borderRadius:12, textDecoration:'none', boxShadow:'0 10px 22px -8px rgba(245,166,35,.55)', whiteSpace:'nowrap'}}>
        Quiero que lo arreglen →
      </a>
    </div>
  );
}

/* ─── 8. Sticky "Volver a medir" abajo a la derecha ─── */
function StickyVolver({ onClick }) {
  return (
    <button type="button" onClick={onClick} className="diag-sticky" style={{position:'fixed', bottom:24, right:24, zIndex:60, display:'inline-flex', alignItems:'center', gap:9, background:'#ffffff', border:'1px solid #cdd2dd', color:'#1a2340', fontSize:14, fontWeight:600, padding:'12px 18px', borderRadius:999, cursor:'pointer', fontFamily:'inherit', boxShadow:'0 12px 28px -10px rgba(26,35,64,.35)'}}>
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#1a2340" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M3 12a9 9 0 1 0 3-6.7L3 8"></path>
        <path d="M3 3v5h5"></path>
      </svg>
      Volver a medir
    </button>
  );
}

/* ─── Cambiar dispositivo (móvil / escritorio) desde los resultados ─── */
function DeviceSwitch({ device, onDevice }) {
  const [busy, setBusy] = useState(false);
  const pick = async (d) => {
    if (d === device || busy) return;
    setBusy(true);
    try { await onDevice(d); } finally { setBusy(false); }
  };
  const seg = (on) => ({
    display:'inline-flex', alignItems:'center', gap:6, border:'none', cursor: busy?'wait':'pointer',
    background: on ? '#1a2340' : 'transparent', color: on ? '#fff' : '#5b607d',
    fontSize:13, fontWeight:700, padding:'8px 14px', borderRadius:999, fontFamily:'inherit',
  });
  return (
    <div role="radiogroup" aria-label="Dispositivo a ver" style={{display:'inline-flex', alignItems:'center', background:'#fff', border:'1px solid #d6dae3', borderRadius:999, padding:4, gap:4}}>
      <button type="button" role="radio" aria-checked={device==='desktop'} disabled={busy} onClick={() => pick('desktop')} style={seg(device==='desktop')}>
        <Icon name="desktop" size={15} /> Escritorio
      </button>
      <button type="button" role="radio" aria-checked={device==='mobile'} disabled={busy} onClick={() => pick('mobile')} style={seg(device==='mobile')}>
        <Icon name="mobile" size={15} /> Móvil
      </button>
      {busy && <span style={{fontSize:12, color:'#8a90a3', padding:'0 8px'}}>Midiendo…</span>}
    </div>
  );
}

/* ─── Modal de desbloqueo: captura datos del lead (se guardan en el panel admin) y libera el reporte ─── */
function UnlockModal({ url, dx, onClose, onUnlocked }) {
  const [data, setData] = useState({ nombre:'', correo:'', sitio: url || '' });
  const [touched, setTouched] = useState({});
  const [submitting, setSubmitting] = useState(false);
  const [err, setErr] = useState('');
  const errors = {
    nombre: !data.nombre.trim() ? 'Ingresa tu nombre.' : '',
    correo: !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.correo) ? 'Ingresa un correo válido.' : '',
  };
  const valid = !errors.nombre && !errors.correo;
  const set = (k) => (e) => setData((d) => ({ ...d, [k]: e.target.value }));
  const blur = (k) => () => setTouched((t) => ({ ...t, [k]: true }));

  const submit = async () => {
    setTouched({ nombre:true, correo:true });
    if (!valid) return;
    setSubmitting(true); setErr('');
    try {
      const payload = {
        nombre: data.nombre.trim(),
        correo: data.correo.trim().toLowerCase(),
        sitio: data.sitio.trim() || null,
        mensaje: 'Desbloqueó el reporte completo desde el medidor.',
      };
      if (dx) {
        payload.url_analizada = dx.url;
        payload.dispositivo = dx.device;
        payload.score_general = dx.overall;
        payload.scores_categorias = Object.fromEntries(dx.categories.map(c => [c.key, c.score]));
        payload.core_web_vitals = dx.core_web_vitals || dx.meta?.core_web_vitals || null;
        payload.problemas_count = dx.problems.length;
        payload.snapshot_diagnostico = {
          overall: dx.overall, potentialPct: dx.potentialPct, problems: dx.problems,
          categories: dx.categories.map(c => ({ key:c.key, label:c.label, score:c.score })),
        };
      }
      await window.ConvierteEngine.submitLead(payload);
      onUnlocked();
    } catch (e) {
      setErr((e && e.message) || 'No pudimos guardar tus datos. Intenta de nuevo.');
    } finally {
      setSubmitting(false);
    }
  };

  const inp = (hasErr) => ({ width:'100%', border: hasErr?'1px solid #c0271d':'1px solid #d6dae3', borderRadius:10, padding:'11px 13px', fontSize:14, fontFamily:'inherit', color:'#1a2340', outline:'none', background:'#fff', marginTop:6 });

  return (
    <div onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
      style={{position:'fixed', inset:0, zIndex:200, background:'rgba(13,27,62,.55)', display:'flex', alignItems:'center', justifyContent:'center', padding:18}}>
      <div role="dialog" aria-modal="true" aria-label="Desbloquear reporte completo"
        style={{width:'100%', maxWidth:440, background:'#fff', borderRadius:18, padding:'28px 26px', boxShadow:'0 30px 60px -20px rgba(13,27,62,.5)', position:'relative', maxHeight:'92vh', overflowY:'auto'}}>
        <button type="button" onClick={onClose} aria-label="Cerrar"
          style={{position:'absolute', top:12, right:14, background:'transparent', border:'none', fontSize:24, lineHeight:1, color:'#8a90a3', cursor:'pointer'}}>×</button>
        <span style={{display:'inline-flex', width:44, height:44, borderRadius:12, background:'#fef5dd', color:'#c89320', alignItems:'center', justifyContent:'center', marginBottom:14}}>
          <Icon name="lock" size={20} stroke={2} />
        </span>
        <h3 style={{fontSize:21, fontWeight:800, color:'#1a2340', margin:'0 0 8px', letterSpacing:'-.01em'}}>Desbloquea tu reporte completo</h3>
        <p style={{fontSize:14, lineHeight:1.55, color:'#4a5169', margin:'0 0 18px'}}>
          ¿Quieres ver el resto de tu reporte? Pásanos tus datos y desbloqueamos todas las soluciones al instante. Guardamos tus datos para enviarte el informe y contactarte.
        </p>
        <label style={{display:'block', fontSize:13, fontWeight:600, color:'#1a2340'}}>Nombre
          <input value={data.nombre} onChange={set('nombre')} onBlur={blur('nombre')} placeholder="María González" autoComplete="name" style={inp(touched.nombre && errors.nombre)} />
        </label>
        {touched.nombre && errors.nombre && <span style={{display:'block', fontSize:12, color:'#c0271d', marginTop:4}}>{errors.nombre}</span>}
        <label style={{display:'block', fontSize:13, fontWeight:600, color:'#1a2340', marginTop:14}}>Correo
          <input type="email" value={data.correo} onChange={set('correo')} onBlur={blur('correo')} placeholder="maria@empresa.com" autoComplete="email" style={inp(touched.correo && errors.correo)} />
        </label>
        {touched.correo && errors.correo && <span style={{display:'block', fontSize:12, color:'#c0271d', marginTop:4}}>{errors.correo}</span>}
        <label style={{display:'block', fontSize:13, fontWeight:600, color:'#1a2340', marginTop:14}}>URL de tu sitio
          <input value={data.sitio} onChange={set('sitio')} placeholder="https://tu-sitio.com" style={{...inp(false), fontFamily:"'JetBrains Mono',monospace", fontSize:13}} />
        </label>
        {err && <div role="alert" style={{marginTop:12, fontSize:13, color:'#c0271d', background:'#fdecec', border:'1px solid #f6d8d8', borderRadius:8, padding:'9px 12px'}}>{err}</div>}
        <button type="button" onClick={submit} disabled={submitting}
          style={{width:'100%', marginTop:18, background:'#f5a623', color:'#1a2340', fontSize:15.5, fontWeight:700, padding:14, border:'none', borderRadius:12, cursor: submitting?'not-allowed':'pointer', fontFamily:'inherit', opacity: submitting?0.7:1}}>
          {submitting ? 'Desbloqueando…' : 'Ver mi reporte completo →'}
        </button>
        <p style={{fontSize:11.5, color:'#8a90a3', textAlign:'center', margin:'10px 0 0'}}>Sin compromiso. Usamos tus datos solo para enviarte el reporte y la propuesta.</p>
      </div>
    </div>
  );
}

function Results({ dx, onReset, onReanalizar, device, onDevice, unlocked, onUnlock }) {
  const free = dx.problems.slice(0, dx.freeCount);
  const locked = dx.problems.slice(dx.freeCount);
  const lockedCount = locked.length;

  return (
    <main id="resultados" className="results-2026" style={{background:'#f4f5f8', minHeight:'100vh'}}>
      <div className="diag-wrap" style={{maxWidth:1180, margin:'0 auto', padding:'0 28px'}}>

        {/* Breadcrumb + cambio de dispositivo (ver resultados en móvil o escritorio) */}
        <div style={{padding:'18px 0 8px', display:'flex', alignItems:'center', justifyContent:'space-between', gap:12, flexWrap:'wrap'}}>
          <button type="button" onClick={onReset} style={{background:'transparent', border:'none', padding:0, fontSize:14, fontWeight:600, color:'#5b607d', cursor:'pointer', fontFamily:'inherit'}}>
            ← Analizar otra página
          </button>
          <div style={{display:'flex', alignItems:'center', gap:10, flexWrap:'wrap'}}>
            <span style={{fontSize:13, color:'#5b607d', fontWeight:600}}>Ver resultados en:</span>
            <DeviceSwitch device={device} onDevice={onDevice} />
          </div>
        </div>

        {/* 1 · Hero navy con donut grande, verdict y URL chip */}
        <ResultsHero dx={dx} />

        {/* 2 · Banda verde "DATOS DIRECTOS DE GOOGLE" + comprobar/re-medir */}
        <GoogleVerificationBand dx={dx} onReanalizar={onReanalizar} />

        {/* 3 · Las 4 notas oficiales de Google (donuts con tooltip) */}
        <GoogleNotesSection
          psiScores={dx.psi_scores}
          psiScoresSource={dx.psi_scores_source}
        />

        {/* 4 · Métricas técnicas (LCP, CLS, FCP, TBT) */}
        {dx.meta?.psi_ok && (
          <TechnicalMetricsSection cwv={dx.core_web_vitals || dx.meta?.core_web_vitals} />
        )}

        {/* 5 · Acordeón con las 8 áreas Sell-U */}
        <AreasAccordion categories={dx.categories} />

        {/* 6 · Lista de problemas con prioridad y solución bloqueada */}
        <section style={{marginTop:46}}>
          <div style={{marginBottom:22}}>
            <span style={{fontSize:12, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'#8a90a3'}}>Lo que hay que arreglar</span>
            <h2 style={{fontSize:28, fontWeight:700, letterSpacing:'-.02em', color:'#1a2340', margin:'8px 0 8px'}}>
              Problemas detectados, ordenados por impacto
            </h2>
            <p style={{fontSize:15, color:'#5b607d', lineHeight:1.5, margin:0, maxWidth:640}}>
              Empieza por los de prioridad alta — son los que más te están costando ventas hoy.
              {lockedCount > 0 && <> Te mostramos {dx.freeCount} gratis; los {lockedCount} restantes los recibes en el reporte completo.</>}
            </p>
          </div>
          <div style={{display:'flex', flexDirection:'column', gap:16}}>
            {free.map((p) => (
              <NewProblemCard key={p.id} p={p} locked={false} />
            ))}
            {locked.map((p) => (
              <NewProblemCard key={p.id} p={p} locked={!unlocked} onUnlock={onUnlock} />
            ))}
          </div>

          {/* CTA mid page */}
          <MidPageCTA />
        </section>

        {/* 7 · Análisis técnico detallado (colapsable, mantiene Auditoría + Methodology
            del análisis previo para no perder profundidad técnica). */}
        <details style={{marginTop:46, background:'#ffffff', border:'1px solid #e6e8ee', borderRadius:18, boxShadow:'0 1px 2px rgba(26,35,64,.04)', overflow:'hidden'}}>
          <summary style={{listStyle:'none', cursor:'pointer', padding:'22px 26px', display:'flex', alignItems:'center', justifyContent:'space-between', gap:16, fontSize:18, fontWeight:700, color:'#1a2340'}}>
            <span style={{display:'flex', alignItems:'center', gap:13}}>
              <span style={{width:40, height:40, borderRadius:11, background:'#eef0f6', color:'#1a2340', display:'flex', alignItems:'center', justifyContent:'center', fontSize:18}}>
                <Icon name="search" size={18} />
              </span>
              <span>
                <span style={{display:'block', fontSize:18, fontWeight:700, letterSpacing:'-.01em'}}>Análisis técnico avanzado</span>
                <span style={{display:'block', fontSize:13.5, color:'#8a90a3', marginTop:2, fontWeight:500}}>
                  Auditoría completa: indexación, SEO, SSL, seguridad, tecnología detectada y metodología
                </span>
              </span>
            </span>
            <span style={{fontSize:14, color:'#5b607d', fontWeight:600}}>Ver detalle ▼</span>
          </summary>
          <div style={{padding:'4px 26px 28px'}}>
            {dx.auditoria?.ok && <AuditoriaTecnicaSection a={dx.auditoria} />}
            <Methodology categories={dx.categories} />
          </div>
        </details>

      </div>

      {/* 8 · Sticky "Volver a medir" abajo a la derecha */}
      <StickyVolver onClick={onReset} />
    </main>
  );
}

function Methodology({ categories }) {
  return (
    <section className="res-section container methodology" aria-labelledby="method-h">
      <div className="section-head">
        <span className="eyebrow">¿De dónde salen estos números?</span>
        <h2 id="method-h" className="section-h2">Cómo medimos tu página</h2>
        <p className="section-lead">
          Usamos <strong>la misma tecnología de Google</strong> para medir la velocidad y el SEO técnico,
          además revisamos cada parte de tu página (titulares, botones, formularios, orden visual).
          Cada área pesa distinto: lo que más afecta tus ventas, pesa más.
        </p>
      </div>

      <div className="method-grid">
        {categories.map((c) => (
          <div className="method-card" key={c.key}>
            <div className="method-head">
              <span className="method-icon" aria-hidden="true"><Icon name={c.icon} size={18} /></span>
              <h3 className="method-name">{c.label}</h3>
              <span className="method-weight">
                <Icon name="trending" size={13} stroke={2} /> Impacto {c.weight >= 1.3 ? "alto" : c.weight >= 1.1 ? "medio" : "base"}
              </span>
            </div>
            <ul className="method-signals">
              {c.signals.map((s, i) => (
                <li key={i}><Icon name="check" size={14} stroke={2.25} /> {s}</li>
              ))}
            </ul>
          </div>
        ))}
      </div>

      <div className="method-note">
        <span className="method-note-icon" aria-hidden="true"><Icon name="search" size={18} stroke={1.75} /></span>
        <p>
          <strong>Sobre los datos:</strong> la velocidad, accesibilidad y SEO técnico son
          <strong> datos reales medidos por Google</strong>. Las visitas estimadas y enlaces externos
          son cálculos aproximados basados en lo que vemos en tu sitio.
        </p>
      </div>
    </section>
  );
}

/* ===================== CAPTURA ===================== */
function Capture({ url, dx }) {
  const [data, setData] = useState({ nombre: "", correo: "", sitio: url || "", objetivo: "", mensaje: "" });
  const [touched, setTouched] = useState({});
  const [sent, setSent] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [serverErr, setServerErr] = useState("");

  useEffect(() => { setData((d) => ({ ...d, sitio: d.sitio || url || "" })); }, [url]);

  const errors = {
    nombre: !data.nombre.trim() ? "Ingresa tu nombre." : "",
    correo: !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.correo) ? "Ingresa un correo válido." : "",
    objetivo: !data.objetivo ? "Elige una opción." : "",
  };
  const valid = !errors.nombre && !errors.correo && !errors.objetivo;

  const set = (k) => (e) => setData((d) => ({ ...d, [k]: e.target.value }));
  const blur = (k) => () => setTouched((t) => ({ ...t, [k]: true }));

  const submit = async () => {
    setTouched({ nombre: true, correo: true, objetivo: true });
    if (!valid) return;
    setSubmitting(true);
    setServerErr("");
    try {
      // Snapshot del diagnóstico actual para guardarlo con el lead
      const payload = {
        nombre: data.nombre.trim(),
        correo: data.correo.trim().toLowerCase(),
        sitio: data.sitio.trim() || null,
        objetivo: data.objetivo,
        mensaje: data.mensaje.trim() || null,
      };
      if (dx) {
        payload.url_analizada = dx.url;
        payload.dispositivo = dx.device;
        payload.score_general = dx.overall;
        payload.scores_categorias = Object.fromEntries(dx.categories.map(c => [c.key, c.score]));
        payload.core_web_vitals = dx.core_web_vitals || dx.meta?.core_web_vitals || null;
        payload.problemas_count = dx.problems.length;
        payload.snapshot_diagnostico = {
          overall: dx.overall,
          potentialPct: dx.potentialPct,
          problems: dx.problems,
          categories: dx.categories.map(c => ({ key: c.key, label: c.label, score: c.score })),
        };
      }
      await window.ConvierteEngine.submitLead(payload);
      setSent(true);
    } catch (e) {
      setServerErr(e.message || "No pudimos enviar tu solicitud. Intenta de nuevo.");
    } finally {
      setSubmitting(false);
    }
  };

  // ── Helper para inputs estilo handoff (border #d6dae3, radius 10, etc.) ──
  const inpStyle = (hasErr) => ({
    width:'100%', border: hasErr ? '1px solid #c0271d' : '1px solid #d6dae3',
    borderRadius:10, padding:'11px 13px', fontSize:14, fontFamily:'inherit',
    color:'#1a2340', outline:'none', background:'#fff',
  });
  const monoInpStyle = (hasErr) => ({ ...inpStyle(hasErr), fontFamily:"'JetBrains Mono',monospace", fontSize:13 });
  const labelStyle = { display:'block', fontSize:13, fontWeight:600, color:'#1a2340', marginBottom:6 };
  const errStyle = { display:'block', fontSize:12, color:'#c0271d', marginTop:4 };

  return (
    <section id="arreglar" className="diag-form-section" style={{background:'#f4f5f8'}}>
      <div style={{maxWidth:1180, margin:'0 auto', padding:'0 28px 64px'}}>
        <div className="diag-form-section-wrap" style={{marginTop:46, background:'#1a2340', borderRadius:22, padding:'44px', color:'#fff', boxShadow:'0 24px 48px -18px rgba(26,35,64,.45)'}}>
          <div className="diag-form-grid" style={{display:'grid', gridTemplateColumns:'0.9fr 1.1fr', gap:48, alignItems:'start'}}>

            {/* Columna izquierda — copy */}
            <div>
              <span style={{fontSize:12, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'#f5a623'}}>Hacemos los arreglos por ti</span>
              <h2 id="cap-h" style={{fontSize:32, lineHeight:1.1, fontWeight:700, letterSpacing:'-.02em', color:'#fff', margin:'12px 0 16px'}}>
                ¿Prefieres que nosotros lo arreglemos?
              </h2>
              <p style={{fontSize:15, lineHeight:1.55, color:'rgba(255,255,255,.78)', margin:'0 0 22px'}}>
                En Sell-U LATAM tenemos un equipo que arregla las cosas que detectó este medidor para que tu página venda más. Déjanos tus datos y te enviamos el <strong style={{color:'#fff'}}>reporte completo</strong> + una propuesta a tu medida.
              </p>
              <div style={{display:'flex', flexDirection:'column', gap:12}}>
                {[
                  'Reporte completo con todo lo que hay que arreglar',
                  'Plan ordenado por lo que más impacta tus ventas',
                  'Te contactamos en menos de 24h, sin compromiso',
                ].map((perk) => (
                  <div key={perk} style={{display:'flex', alignItems:'center', gap:10, fontSize:14.5, color:'rgba(255,255,255,.88)'}}>
                    <span style={{flex:'0 0 auto', width:22, height:22, borderRadius:'50%', background:'rgba(34,197,94,.18)', color:'#4ade80', display:'flex', alignItems:'center', justifyContent:'center', fontSize:13, fontWeight:800}}>✓</span>
                    {perk}
                  </div>
                ))}
              </div>
            </div>

            {/* Columna derecha — form (o success state) */}
            <div className="diag-form-box" style={{background:'#ffffff', borderRadius:18, padding:28}}>
              {sent ? (
                <div role="status" aria-live="polite" style={{textAlign:'center', padding:'12px 4px'}}>
                  <span style={{display:'inline-flex', width:54, height:54, borderRadius:'50%', background:'#e7f8ee', color:'#15803d', alignItems:'center', justifyContent:'center', fontSize:28, fontWeight:800, marginBottom:14}}>✓</span>
                  <h3 style={{fontSize:20, fontWeight:700, color:'#1a2340', margin:'0 0 8px'}}>¡Listo! Te contactaremos en menos de 24h</h3>
                  <p style={{fontSize:14, color:'#4a5169', lineHeight:1.55, margin:'0 0 16px'}}>
                    Recibimos tu solicitud para <strong>{prettyHost(data.sitio)}</strong>. Nuestro equipo te enviará el reporte completo y propuesta a <strong>{data.correo}</strong>.
                  </p>
                  <button type="button" onClick={() => { setSent(false); setData({nombre:'', correo:'', sitio: url||'', objetivo:'', mensaje:''}); }} style={{background:'transparent', border:'1px solid #d6dae3', borderRadius:10, padding:'9px 16px', fontSize:13, fontWeight:600, color:'#1a2340', cursor:'pointer'}}>
                    Enviar otra solicitud
                  </button>
                </div>
              ) : (
                <>
                  {/* Honeypot anti-bot */}
                  <input type="text" name="website" tabIndex={-1} autoComplete="off"
                    style={{position:'absolute', left:'-9999px', opacity:0, height:0, width:0}}
                    onChange={() => {}} />

                  <div className="diag-form-row" style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:16}}>
                    <label style={{display:'block'}}>
                      <span style={labelStyle}>Nombre</span>
                      <input value={data.nombre} onChange={set('nombre')} onBlur={blur('nombre')}
                        placeholder="María González" autoComplete="name"
                        style={inpStyle(touched.nombre && errors.nombre)} />
                      {touched.nombre && errors.nombre && <span style={errStyle}>{errors.nombre}</span>}
                    </label>
                    <label style={{display:'block'}}>
                      <span style={labelStyle}>Correo</span>
                      <input type="email" value={data.correo} onChange={set('correo')} onBlur={blur('correo')}
                        placeholder="maria@empresa.com" autoComplete="email"
                        style={inpStyle(touched.correo && errors.correo)} />
                      {touched.correo && errors.correo && <span style={errStyle}>{errors.correo}</span>}
                    </label>
                    <label style={{display:'block'}}>
                      <span style={labelStyle}>URL del sitio</span>
                      <input value={data.sitio} onChange={set('sitio')}
                        placeholder="https://tu-sitio.com" style={monoInpStyle(false)} />
                    </label>
                    <label style={{display:'block'}}>
                      <span style={labelStyle}>¿Qué buscas?</span>
                      <select value={data.objetivo} onChange={set('objetivo')} onBlur={blur('objetivo')}
                        style={inpStyle(touched.objetivo && errors.objetivo)}>
                        <option value="">Selecciona una opción…</option>
                        <option value="ventas">Que mi página cargue más rápido / vender más</option>
                        <option value="registros">Más registros / captar leads</option>
                        <option value="reservas">Aparecer mejor en Google</option>
                        <option value="otro">Rediseño completo</option>
                      </select>
                      {touched.objetivo && errors.objetivo && <span style={errStyle}>{errors.objetivo}</span>}
                    </label>
                  </div>

                  <label style={{display:'block', marginTop:16}}>
                    <span style={labelStyle}>Mensaje (opcional)</span>
                    <textarea value={data.mensaje} onChange={set('mensaje')} rows={2}
                      placeholder="Cuéntanos más sobre tu negocio…"
                      style={{...inpStyle(false), resize:'vertical'}} />
                  </label>

                  {serverErr && (
                    <div role="alert" style={{marginTop:12, fontSize:13, color:'#c0271d', background:'#fdecec', border:'1px solid #f6d8d8', borderRadius:8, padding:'9px 12px'}}>
                      {serverErr}
                    </div>
                  )}

                  <button type="button" onClick={submit} disabled={submitting}
                    style={{width:'100%', marginTop:18, background:'#f5a623', color:'#1a2340', fontSize:16, fontWeight:700, padding:15, border:'none', borderRadius:12, cursor: submitting?'not-allowed':'pointer', fontFamily:'inherit', boxShadow:'0 8px 18px -6px rgba(245,166,35,.5)', opacity: submitting?0.7:1}}>
                    {submitting ? 'Enviando…' : 'Enviar y recibir mi reporte →'}
                  </button>
                  <p style={{fontSize:12, color:'#8a90a3', textAlign:'center', margin:'12px 0 0', lineHeight:1.4}}>
                    Sin compromiso. Usamos tus datos solo para enviarte el reporte y la propuesta.
                  </p>
                </>
              )}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function Field({ label, id, error, children }) {
  return (
    <div className="field">
      <label htmlFor={id}>{label}</label>
      {children}
      {error ? <span className="field-err" role="alert">{error}</span> : null}
    </div>
  );
}

/* ===================== APP ===================== */
function App() {
  const [phase, setPhase] = useState("hero"); // hero | analyzing | results
  const [url, setUrl] = useState("");
  // Default MOBILE para alinear con pagespeed.web.dev (que también muestra mobile primero).
  // Si el cliente compara contra Google lado-a-lado, los números deben coincidir.
  const [device, setDevice] = useState("mobile");
  const [error, setError] = useState("");
  const [dx, setDx] = useState(null);
  const [analyzeError, setAnalyzeError] = useState("");
  const [analyzeDone, setAnalyzeDone] = useState(false);
  // Desbloqueo del reporte (lead): unlocked = reporte liberado · unlockOpen = modal visible
  const [unlocked, setUnlocked] = useState(false);
  const [unlockOpen, setUnlockOpen] = useState(false);

  const analyze = async (noCacheArg) => {
    // Defensa: si esta función se conecta directamente a un onClick, React
    // pasa el SyntheticEvent como primer argumento. Solo aceptamos `true`
    // literal (desde reanalizar()) — cualquier otra cosa es falsy.
    const noCache = noCacheArg === true;

    if (!isValidUrl(url)) {
      setError("Ingresa una URL válida, por ejemplo: tu-sitio.com");
      return;
    }
    setError("");
    setAnalyzeError("");
    setAnalyzeDone(false);
    if (!noCache) {
      setUnlocked(false); // nueva URL → el reporte vuelve a estar bloqueado
      setPhase("analyzing");
      window.scrollTo({ top: 0, behavior: "auto" });
    }

    try {
      const diag = await window.ConvierteEngine.fetchDiagnosis(normalizeUrl(url), device, noCache);
      // Mover core_web_vitals al meta también para que el componente CWV los encuentre
      if (diag.meta) diag.meta.core_web_vitals = diag.core_web_vitals;
      setDx(diag);
      setAnalyzeDone(true);
      if (!noCache) {
        // pequeña pausa visual para que termine la animación del progreso
        setTimeout(() => {
          setPhase("results");
          window.scrollTo({ top: 0, behavior: "auto" });
        }, 350);
      }
    } catch (e) {
      const msg = (e && typeof e.message === "string") ? e.message : "Error inesperado.";
      if (noCache) {
        // Si falló el re-análisis, no romper la UI — mostrar alerta y seguir
        alert("No pudimos re-analizar: " + msg);
      } else {
        setAnalyzeError(msg);
      }
    }
  };

  /** Re-analizar invalidando el cache del backend. Se queda en la vista de resultados. */
  const reanalizar = async () => analyze(true);

  /** Cambia entre móvil/escritorio desde los resultados y re-mide para ese dispositivo. */
  const cambiarDispositivo = async (nuevo) => {
    if (nuevo === device || !url) return;
    const prev = device;
    setDevice(nuevo);
    try {
      const diag = await window.ConvierteEngine.fetchDiagnosis(normalizeUrl(url), nuevo, false);
      if (diag.meta) diag.meta.core_web_vitals = diag.core_web_vitals;
      setDx(diag);
    } catch (e) {
      setDevice(prev);
      alert("No pudimos cambiar de dispositivo: " + ((e && e.message) || ""));
    }
  };

  const reset = () => {
    setPhase("hero");
    setDx(null);
    setAnalyzeError("");
    setAnalyzeDone(false);
    setUnlocked(false);
    setUnlockOpen(false);
    window.scrollTo({ top: 0, behavior: "auto" });
  };

  return (
    <div id="top" data-screen-label={"Medidor de Rendimiento · " + phase}>
      {/* ═══════════════════════════════════════════════════════════════════
          REDISEÑO 2026 — Reglas mobile-first del medidor de rendimiento.
          Los grids y paddings declarados inline en cada componente son los
          del desktop (handoff). Estas media queries los apilan en móvil para
          que el cliente lo vea bien desde el celular (≥80% del tráfico).
          ═══════════════════════════════════════════════════════════════════ */}
      <style>{`
        /* Tooltips ? — fade en hover/focus */
        .diag-tipwrap .diag-tip { transition: opacity .18s, visibility .18s; }
        .diag-tipwrap:hover .diag-tip,
        .diag-tipwrap:focus .diag-tip,
        .diag-tipwrap:focus-within .diag-tip { opacity:1 !important; visibility:visible !important; pointer-events:auto !important; }

        /* Tablet 720-900px: 4 col → 2 col */
        @media (max-width: 900px) {
          .diag-grid-4 { grid-template-columns: 1fr 1fr !important; }
          .diag-hero-section { padding: 36px 32px !important; }
        }

        /* Mobile ≤ 720px: todo a 1 columna, paddings/fuentes reducidas */
        @media (max-width: 720px) {
          .diag-wrap { padding: 0 16px !important; }
          .diag-grid-4 { grid-template-columns: 1fr 1fr !important; gap: 12px !important; }
          .diag-grid-2 { grid-template-columns: 1fr !important; gap: 18px 0 !important; }
          .diag-form-grid { grid-template-columns: 1fr !important; gap: 28px !important; }
          .diag-form-row { grid-template-columns: 1fr !important; }
          .diag-hero-section { padding: 28px 22px !important; border-radius: 16px !important; gap: 22px !important; }
          .diag-hero-row { flex-direction: column !important; align-items: center !important; gap: 22px !important; text-align: center; }
          .diag-hero-section h1 { font-size: 26px !important; line-height: 1.2 !important; }
          .diag-hero-section p { font-size: 14.5px !important; }
          .diag-hero-donut, .diag-hero-donut svg { width: 170px !important; height: 170px !important; }
          .diag-hero-score { font-size: 56px !important; }
          .diag-form-section-wrap { padding: 32px 22px !important; border-radius: 18px !important; }
          .diag-form-box { padding: 22px !important; border-radius: 14px !important; }
          .diag-sticky { padding: 10px 14px !important; font-size: 12.5px !important; bottom: 14px !important; right: 14px !important; }
          .diag-section-h2 { font-size: 22px !important; }
          .diag-problem-card { padding: 18px 20px !important; }
          .diag-problem-card h3 { font-size: 17px !important; }
          .diag-band { padding: 14px 16px !important; gap: 14px !important; }
          .diag-band-cta { width: 100%; }
          .diag-band-cta a, .diag-band-cta button { flex: 1; justify-content: center; }
          .diag-mid-cta { padding: 24px 22px !important; flex-direction: column; align-items: stretch !important; text-align: center; }
          .diag-mid-cta a { justify-content: center; }
          .diag-areas-head { padding: 18px 20px !important; }
          .diag-areas-body { padding: 18px 20px 22px !important; }
        }

        /* Ultra-small ≤ 400px */
        @media (max-width: 400px) {
          .diag-grid-4 { grid-template-columns: 1fr !important; }
          .diag-hero-section h1 { font-size: 23px !important; }
          .diag-hero-score { font-size: 48px !important; }
          .diag-hero-donut, .diag-hero-donut svg { width: 150px !important; height: 150px !important; }
        }
      `}</style>

      {/* Botón flotante "Analizar otra página" — solo en phase=analyzing
          (en phase=results el rediseño ya trae su propio breadcrumb + sticky). */}
      {phase === "analyzing" && (
        <div style={{
          position:"sticky", top:0, zIndex:40, background:"rgba(251,250,247,.92)",
          backdropFilter:"blur(8px)", borderBottom:"1px solid var(--border-default)",
          padding:"10px 0", width:"100%", maxWidth:"100%"
        }}>
          <div className="container" style={{display:"flex", justifyContent:"space-between", alignItems:"center", gap:12, flexWrap:"wrap"}}>
            <button className="btn btn-ghost btn-sm" onClick={reset}>← Analizar otra página</button>
          </div>
        </div>
      )}

      {phase === "hero" && (
        <main>
          <Hero url={url} setUrl={(v) => { setUrl(v); if (error) setError(""); }}
            device={device} setDevice={setDevice} onAnalyze={analyze} error={error} />
        </main>
      )}

      {phase === "analyzing" && (
        <main><Analyzing url={url} device={device} done={analyzeDone} error={analyzeError} onRetry={reset} /></main>
      )}

      {phase === "results" && dx && (
        <>
          <Results dx={dx} onReset={reset} onReanalizar={reanalizar}
            device={device} onDevice={cambiarDispositivo}
            unlocked={unlocked} onUnlock={() => setUnlockOpen(true)} />
          <Capture url={normalizeUrl(url)} dx={dx} />
          {unlockOpen && (
            <UnlockModal url={normalizeUrl(url)} dx={dx}
              onClose={() => setUnlockOpen(false)}
              onUnlocked={() => { setUnlocked(true); setUnlockOpen(false); }} />
          )}
        </>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
