/* Reusable components: Header, Footer, Buttons, Cards, Modal */ const NAV_ITEMS = [ { key: "pacientes", label: "Pacientes" }, { key: "medicos", label: "Médicos" }, { key: "clinicas", label: "Clínicas" }, { key: "empresas", label: "Empresas" }, { key: "catalogo", label: "Estudios" }, { key: "sucursales", label: "Sucursales" }, { key: "vacunacion", label: "Vacunación" }, { key: "resultados", label: "Resultados" }, { key: "contacto", label: "Contacto" }, ]; function Header({ page, navigate, onOpenLead }) { const [drawer, setDrawer] = React.useState(false); const [openAcc, setOpenAcc] = React.useState(null); const APP = "https://app.infectolab.mx/"; const ORDEN = "https://app.infectolab.mx/solicitud"; const FACT = "https://facturacion.infectolab.mx/"; const go = (k) => { navigate(k); setDrawer(false); }; // Mega-menu data. Items use either nav (internal page) or href (external). const CATS = [ { key: "pacientes", label: "Pacientes", nav: "pacientes", width: 480, align: "left", cols: [ { label: "Servicios", items: [ { icon: "microscope", name: "Estudios y diagnóstico", desc: "Más de 200 pruebas disponibles", nav: "catalogo" }, { icon: "drop", name: "Vacunación", desc: "Vacunas para adultos con orientación profesional", nav: "vacunacion" }, { icon: "home", name: "Toma domiciliaria", desc: "Muestras en la comodidad de tu hogar", nav: "pacientes" }, ]}, { label: "Acceso", items: [ { icon: "docCheck", name: "Mis resultados", desc: "Portal seguro 24/7", nav: "resultados" }, { icon: "route", name: "Cómo funciona", desc: "Proceso de 3 pasos para tu prueba", nav: "pacientes" }, ]}, ], foot: { variant: "light", lead: "¿Primera vez?", linkText: "Conoce InfectoLab →", nav: "pacientes" } }, { key: "medicos", label: "Médicos", nav: "medicos", width: 480, align: "left", cols: [ { label: "Plataforma", items: [ { icon: "monitor", name: "InfectoApp", desc: "Gestión de órdenes y resultados en línea", href: APP }, { icon: "clipboard", name: "Orden de laboratorio", desc: "Genera y envía órdenes en segundos", href: ORDEN }, ]}, { label: "Catálogo", items: [ { icon: "dna", name: "Catálogo de estudios", desc: "Búsqueda por nombre, clave o patología", nav: "catalogo" }, { icon: "star", name: "Programa Médico Lealtad", desc: "Descuentos y línea directa con el especialista", nav: "lealtad" }, ]}, ], foot: { variant: "light", lead: "¿Eres médico con convenio?", linkText: "Ingresar a InfectoApp →", href: APP } }, { key: "clinicas", label: "Clínicas", nav: "clinicas", width: 480, align: "left", cols: [ { label: "Operaciones", items: [ { icon: "hospital", name: "Convenios institucionales", desc: "Condiciones especiales para tu clínica", nav: "clinicas" }, { icon: "home", name: "Toma domiciliaria", desc: "Servicio para pacientes hospitalizados", nav: "clinicas" }, ]}, { label: "Digital", items: [ { icon: "monitor", name: "InfectoApp para clínicas", desc: "Panel de gestión multi-usuario", href: APP }, { icon: "trending", name: "Reportes y seguimiento", desc: "Dashboard de resultados en tiempo real", nav: "clinicas" }, ]}, ], foot: { variant: "light", linkText: "Agendar cita con área de ventas →", nav: "contacto" } }, { key: "empresas", label: "Empresas", nav: "empresas", width: 420, align: "right", cols: [ { items: [ { icon: "building", name: "Convenios corporativos", desc: "Pruebas para tu equipo con factura", nav: "empresas" }, { icon: "stethoscope", name: "Pruebas ocupacionales", desc: "Salud laboral y medicina del trabajo", nav: "empresas" }, { icon: "briefcase", name: "Cotización corporativa", desc: "Precios por volumen personalizados", action: onOpenLead }, { icon: "receipt", name: "Facturación", desc: "Portal de facturación electrónica", href: FACT }, ]}, ], foot: { variant: "naranja", linkText: "¿Más de 10 colaboradores? Escríbenos →", nav: "contacto" } }, { key: "infectolab", label: "InfectoLab", nav: null, width: 520, align: "right", cols: [ { label: "Encuéntranos", items: [ { icon: "pin", name: "Sucursales", desc: "6 ubicaciones en Tijuana · una 24/7", nav: "sucursales" }, { icon: "phone", name: "Contacto", desc: "WhatsApp · teléfono · email", nav: "contacto" }, { icon: "receipt", name: "Facturación", desc: "Genera tu CFDI en línea", href: FACT }, ]}, { label: "Nosotros", items: [ { icon: "award", name: "Acerca de InfectoLab", desc: "15+ años de diagnóstico clínico", nav: "home" }, { icon: "user", name: "Dr. Samuel Navarro", desc: "Director Médico e Infectólogo", nav: "home" }, { icon: "shield", name: "Certificaciones", desc: "ISO 9001:2015 · PACAL", nav: "home" }, ]}, ], foot: { variant: "dark" } }, ]; const itemHandler = (it) => { if (it.href) return null; // anchor handles it return (e) => { e.preventDefault(); if (it.action) { it.action(); setDrawer(false); } else { go(it.nav); } }; }; const PanelLink = ({ it }) => { const inner = ( <> {it.name}{it.desc} ); if (it.href) return {inner}; return {inner}; }; const PanelFoot = ({ foot }) => { if (foot.variant === "dark") { return (
InfectoLab © 2026 InfectoLab · Tijuana, B.C.
); } return (
{foot.lead ? foot.lead + " " : ""} {foot.href ? {foot.linkText} : { e.preventDefault(); go(foot.nav); }}>{foot.linkText}}
); }; const isActive = (cat) => cat.nav === page || (cat.key === "infectolab" && page === "sucursales"); return ( <> {/* Mobile drawer */}
setDrawer(false)}>
); } const HEADER_CSS = ` .il-nav { position: sticky; top: 0; z-index: 100; background: #fff; border-bottom: 1px solid var(--ink-200); } .il-nav-inner { display: flex; align-items: center; gap: 20px; height: 72px; } .il-logo { flex: 0 0 auto; display: inline-flex; align-items: center; } .il-logo img { height: 34px; width: auto; } .il-menu { display: flex; align-items: center; gap: 2px; list-style: none; margin: 0; padding: 0; flex: 1; justify-content: center; } .il-item { position: relative; } .il-trigger { display: inline-flex; align-items: center; gap: 6px; background: none; border: none; font: inherit; font-size: 15px; font-weight: 600; color: var(--ink-700); padding: 10px 14px; border-radius: 8px; position: relative; cursor: pointer; } .il-trigger .chev { transition: transform .2s; } .il-trigger::after { content: ""; position: absolute; left: 50%; bottom: 4px; height: 2px; width: 0; background: var(--brand-yellow); border-radius: 2px; transform: translateX(-50%); transition: width .22s ease; } .il-item:hover > .il-trigger, .il-item:focus-within > .il-trigger, .il-item.is-active > .il-trigger { color: var(--brand-primary); } .il-item:hover > .il-trigger::after, .il-item:focus-within > .il-trigger::after, .il-item.is-active > .il-trigger::after { width: calc(100% - 28px); } .il-item:hover > .il-trigger .chev, .il-item:focus-within > .il-trigger .chev { transform: rotate(180deg); } .il-result { display: inline-flex; align-items: center; gap: 7px; border: 1.5px solid var(--brand-primary); color: var(--brand-primary); font-size: 14px; font-weight: 700; border-radius: 8px; padding: 8px 16px; margin-left: 6px; transition: background .15s, color .15s; } .il-result svg { transition: stroke .15s; } .il-result:hover, .il-result.is-on { background: var(--brand-primary); color: #fff; } .il-result:hover svg, .il-result.is-on svg { stroke: #fff; } .il-panel { position: absolute; top: 100%; left: 0; padding-top: 12px; opacity: 0; visibility: hidden; transform: translateY(8px); transition: opacity .18s ease, transform .18s ease, visibility .18s; z-index: 60; } .il-panel.right { left: auto; right: 0; } .il-item:hover > .il-panel, .il-item:focus-within > .il-panel { opacity: 1; visibility: visible; transform: translateY(0); } .il-panel-card { background: #fff; border: 1px solid var(--ink-200); border-radius: 16px; box-shadow: 0 8px 40px rgba(57,83,164,.12); overflow: hidden; } .il-panel-body { display: grid; gap: 4px; padding: 16px; } .il-col { display: flex; flex-direction: column; } .il-col-label { font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-500); padding: 6px 12px 8px; } .il-link { display: flex; gap: 12px; align-items: flex-start; padding: 10px 12px; border-radius: 10px; transition: background .14s; text-decoration: none; } .il-link:hover { background: var(--ink-50); } .il-link-ic { width: 36px; height: 36px; border-radius: 9px; background: rgba(57,83,164,.08); color: var(--brand-primary); display: flex; align-items: center; justify-content: center; flex: 0 0 36px; } .il-link-tx b { display: block; font-size: 14px; font-weight: 700; color: var(--ink-900); line-height: 1.25; } .il-link:hover .il-link-tx b { color: var(--brand-primary); } .il-link-tx small { display: block; font-size: 12px; color: var(--ink-500); margin-top: 3px; line-height: 1.4; } .il-panel-foot { padding: 12px 20px; border-top: 1px solid var(--ink-200); background: var(--ink-50); font-size: 13px; color: var(--ink-500); } .il-panel-foot a { color: var(--brand-primary); font-weight: 700; } .il-panel-foot a:hover { text-decoration: underline; } .il-panel-foot.naranja a { color: #F07B35; } .il-panel-foot.dark { background: linear-gradient(120deg, #1A2A5E, #30477F); color: rgba(255,255,255,.78); border-top: none; display: flex; align-items: center; justify-content: space-between; gap: 12px; } .il-panel-foot.dark img { height: 20px; } .il-actions { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; } .il-ghost { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; border: 1px solid var(--ink-200); background: #fff; color: var(--ink-900); font: inherit; font-size: 14px; font-weight: 600; border-radius: 8px; padding: 9px 16px; transition: .15s; } .il-ghost:hover { border-color: var(--brand-primary); color: var(--brand-primary); } .il-primary { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; border: none; background: var(--brand-yellow); color: var(--brand-deep); font: inherit; font-size: 14px; font-weight: 700; border-radius: 8px; padding: 10px 18px; box-shadow: 0 6px 16px -8px rgba(253,195,69,.9); transition: .15s; } .il-primary:hover { background: var(--brand-yellow-600); transform: translateY(-1px); } .il-burger { display: none; width: 42px; height: 42px; border-radius: 10px; border: 1px solid var(--ink-200); background: #fff; align-items: center; justify-content: center; color: var(--ink-900); } .il-overlay { position: fixed; inset: 0; background: rgba(26,42,94,.45); backdrop-filter: blur(2px); opacity: 0; visibility: hidden; transition: opacity .25s, visibility .25s; z-index: 200; } .il-overlay.open { opacity: 1; visibility: visible; } .il-drawer { position: fixed; top: 0; right: 0; height: 100%; width: 85%; max-width: 380px; background: #fff; transform: translateX(100%); transition: transform .28s cubic-bezier(.4,0,.2,1); z-index: 201; display: flex; flex-direction: column; } .il-drawer.open { transform: translateX(0); } .il-drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 0 20px; height: 72px; border-bottom: 1px solid var(--ink-200); flex: 0 0 auto; } .il-drawer-head img { height: 30px; } .il-x { width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--ink-200); background: #fff; display: flex; align-items: center; justify-content: center; color: var(--ink-900); cursor: pointer; } .il-drawer-body { flex: 1; overflow-y: auto; } .il-acc-trigger { width: 100%; display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border: none; border-bottom: 1px solid var(--ink-200); background: none; font: inherit; font-size: 15.5px; font-weight: 700; color: var(--ink-900); text-align: left; cursor: pointer; } .il-acc-trigger .chev { transition: transform .2s; color: var(--ink-500); } .il-acc-trigger.open .chev { transform: rotate(180deg); } .il-acc-content { display: none; background: var(--ink-50); } .il-acc-content.open { display: block; } .il-acc-link { display: flex; gap: 12px; align-items: flex-start; padding: 14px 20px; border-bottom: 1px solid var(--ink-200); text-decoration: none; } .il-acc-link:last-child { border-bottom: none; } .il-acc-link .il-link-ic { width: 32px; height: 32px; flex: 0 0 32px; } .il-acc-link b { font-size: 14px; font-weight: 700; color: var(--ink-900); display: block; } .il-acc-link small { font-size: 12px; color: var(--ink-500); display: block; margin-top: 2px; } .il-drawer-foot { flex: 0 0 auto; padding: 16px 20px; border-top: 1px solid var(--ink-200); display: flex; flex-direction: column; gap: 10px; } .il-drawer-foot .il-ghost, .il-drawer-foot .il-primary { width: 100%; justify-content: center; } @media (max-width: 960px) { .il-menu, .il-actions .il-ghost, .il-actions .il-primary { display: none; } .il-burger { display: inline-flex; } .il-nav-inner { justify-content: space-between; gap: 0; } } `; function Footer({ navigate }) { return ( ); } /* ─────────── Section heading helper ─────────── */ function SectionHead({ eyebrow, title, sub, aside, light = false }) { return (
{eyebrow &&
{eyebrow}
}

{title}

{sub &&

{sub}

} {aside}
); } /* ─────────── Segment card ─────────── */ function SegmentCard({ icon, title, desc, cta, featured, onClick, sub }) { return (

{title}

{desc}

{sub &&
{sub}
}
{cta}
); } /* ─────────── Service card (grid) ─────────── */ function ServiceCard({ icon, title, count, tag }) { return (

{title}

{count} estudios {tag && {tag}}
); } /* ─────────── FAQ accordion ─────────── */ function FaqItem({ q, a, defaultOpen = false }) { const [open, setOpen] = React.useState(defaultOpen); return (
{a}
); } /* ─────────── Lead modal ─────────── */ function LeadModal({ onClose, defaultSegment = "" }) { const [step, setStep] = React.useState(0); const [data, setData] = React.useState({ tipo: defaultSegment, nombre: "", email: "", tel: "", mensaje: "" }); const update = (k, v) => setData({ ...data, [k]: v }); return (
e.stopPropagation()}> {step === 0 && (
Agendar prueba

Cuéntanos quién eres

Te conectamos con el equipo de atención correcto para tu necesidad.

{[ ["paciente", "Paciente", "user"], ["medico", "Médico", "stethoscope"], ["clinica", "Clínica", "hospital"], ["empresa", "Empresa", "building"], ].map(([key, label, ic]) => ( ))}
)} {step === 1 && (
Paso 2 de 2

Tus datos

Un asesor te contactará en menos de 24 horas.

update("nombre", e.target.value)} placeholder="Ej. Ana Ramírez" />
update("email", e.target.value)} placeholder="correo@ejemplo.com" />
update("tel", e.target.value)} placeholder="55 0000 0000" />