/* global React, Icon, Placeholder, Reveal, Counter */ const { useState: useStateS2, useEffect: useEffectS2, useRef: useRefS2 } = React; /* ============================================================ SERVICES (expandable list) ============================================================ */ function Services({ lang }) { const services = lang === "es" ? [ { id: "general", title: "Limpieza General", desc: "Mantenimiento y limpieza cotidiana de espacios, asegurando un ambiente pulcro y saludable." }, { id: "profunda", title: "Limpieza Profunda", desc: "Servicio intensivo enfocado en áreas que requieren atención especial, eliminando acumulaciones de suciedad y desinfectando a fondo." }, { id: "sanitizacion",title: "Sanitización", desc: "Aplicación de técnicas y productos especializados para eliminar virus y bacterias, garantizando un entorno seguro." }, { id: "pisos", title: "Pulido y Abrillantado de Pisos", desc: "Mejora de la estética de los pisos a través de procedimientos que restauran su brillo natural." }, { id: "insumos", title: "Suministro Insumos de Limpieza", desc: "Ofrecimiento de productos de limpieza de alta calidad para el mantenimiento diario." }, { id: "asesoria", title: "Asesoría", desc: "Orientación profesional sobre las mejores prácticas de limpieza y mantenimiento para espacios comerciales e industriales." }, { id: "alfombras", title: "Recuperación de Alfombras", desc: "Restauración de la apariencia y la textura de las alfombras, extendiendo su vida útil." }, ] : [ { id: "general", title: "General Cleaning", desc: "Daily maintenance and cleaning of spaces, ensuring a spotless and healthy environment." }, { id: "profunda", title: "Deep Cleaning", desc: "Intensive service focused on areas requiring special attention, eliminating dirt buildup and thoroughly disinfecting." }, { id: "sanitizacion",title: "Sanitization", desc: "Application of specialized techniques and products to eliminate viruses and bacteria, guaranteeing a safe environment." }, { id: "pisos", title: "Floor Polish & Brightening", desc: "Improving the aesthetics of floors through procedures that restore their natural shine." }, { id: "insumos", title: "Cleaning Supplies", desc: "Offering high-quality cleaning products for daily maintenance." }, { id: "asesoria", title: "Consulting", desc: "Professional guidance on best cleaning and maintenance practices for commercial and industrial spaces." }, { id: "alfombras", title: "Carpet Recovery", desc: "Restoration of the appearance and texture of carpets, extending their useful life." }, ]; const [open, setOpen] = useStateS2(0); return (
{lang==="es"?"SERVICIOS — 07 disciplinas":"SERVICES — 07 disciplines"}

{lang==="es" ? <>Soluciones a la medida
de cada espacio. : <>Solutions tailored
to every space.}

{lang==="es" ? "Combinamos servicios para construir un programa único por cliente. Da clic en cada uno para ver alcance e incluidos." : "We combine services into a custom program per client. Click any item for scope and what's included."}

{services.map((s, i) => { const isOpen = open === i; return (
setOpen(isOpen ? -1 : i)}> {String(i + 1).padStart(2, "0")}

{s.title}

{s.desc}

); })}
); } /* ============================================================ PRESENCE / STATS / MAP ============================================================ */ function Presence({ lang }) { const logos = [ { src: "assets/logos/cinemex.png", alt: "Cinemex", w: 168, h: 58, big: true }, { src: "assets/logos/SMARTFIT-82ec121e03b7fd6f6b9d177d56b327d7caf09390f8a0826b4015a305608c4f2f.png", alt: "Smart Fit", w: 723, h: 264 }, { src: "assets/logos/PayPal_Logo_Grey.svg.png", alt: "PayPal", w: 1280, h: 312 }, { src: "assets/logos/BASF-Logo_bw.svg.png", alt: "BASF", w: 960, h: 347 }, { src: "assets/logos/alboa.png", alt: "Alboa", w: 320, h: 121, big: true }, { src: "assets/logos/mazda.png", alt: "Mazda", w: 504, h: 495, big: true }, ]; // Real Mexico outline + lat/lon projection const VW = 340, VH = 200, PAD = 8; const LON_MIN = -118, LON_MAX = -86; const LAT_MIN = 14, LAT_MAX = 33; const proj = (lat, lon) => [ PAD + ((lon - LON_MIN) / (LON_MAX - LON_MIN)) * (VW - 2 * PAD), PAD + ((LAT_MAX - lat) / (LAT_MAX - LAT_MIN)) * (VH - 2 * PAD), ]; // Mainland — clockwise from head of Gulf of California → US border → Gulf coast → Yucatán → Pacific const mainland = [ [31.70, -114.72], [32.55, -114.72], [32.55, -113.30], [31.85, -113.10], [31.33, -111.07], [31.33, -109.55], [31.78, -108.21], [31.78, -106.53], // El Paso / Cd. Juárez [29.78, -104.40], [28.99, -103.00], // Big Bend dip [29.27, -101.00], [27.50, -99.50], // Del Rio / Laredo [26.00, -98.30], [25.95, -97.15], // Reynosa / Matamoros [23.50, -97.75], [22.27, -97.87], // Gulf coast / Tampico [21.13, -97.31], [19.20, -96.13], // Tuxpan / Veracruz [18.40, -94.50], [18.50, -93.20], // Coatza / Frontera [18.65, -91.80], [19.84, -90.53], // Cd. del Carmen / Campeche [20.86, -90.40], [21.36, -89.66], // Celestún / Progreso [21.62, -88.30], [21.60, -86.86], // NE Yucatán / Cabo Catoche [21.16, -86.81], [20.21, -87.46], // Cancún / Tulum [18.50, -88.30], [17.92, -89.14], // Chetumal / Belize border [16.83, -90.93], [16.10, -92.10], // Guatemala border [15.10, -92.20], [15.84, -94.00], // Tapachula → Pacific [16.16, -95.20], [15.84, -96.30], // Salina Cruz / Huatulco [16.78, -99.90], [17.65, -101.55], // Acapulco / Zihuatanejo [17.96, -102.20], [19.05, -104.32], // Lázaro Cárdenas / Manzanillo [20.62, -105.23], [21.54, -105.29], // Pto. Vallarta / San Blas [22.50, -105.85], [23.25, -106.40], // Mazatlán [24.80, -108.00], [25.60, -109.05], // Topolobampo [27.00, -110.20], [27.92, -110.90], // Guaymas [28.80, -111.90], [29.50, -112.40], [30.50, -113.20], [31.32, -113.55], // Pto. Peñasco [31.70, -114.72], ]; // Baja California peninsula const baja = [ [32.53, -117.12], // Tijuana [32.62, -115.45], [32.00, -115.00], // Mexicali [31.00, -114.85], [29.50, -114.00], // San Felipe / Bahía LA [28.00, -113.00], [27.00, -111.50], [25.50, -110.70], [24.15, -110.30], // La Paz [23.20, -109.45], [22.88, -109.92], // Cabo San Lucas [23.40, -110.70], [24.50, -111.70], [25.80, -112.30], [26.50, -113.50], [27.50, -114.50], [28.40, -114.20], [29.00, -115.50], [30.00, -116.00], // Ensenada [31.50, -116.50], [32.53, -117.12], ]; const toPath = (coords) => "M " + coords.map(([lat, lon]) => proj(lat, lon).map(n => n.toFixed(1)).join(" ")).join(" L ") + " Z"; const states = [ { name: "Baja California", lat: 32.62, lon: -115.45 }, { name: "Baja California Sur", lat: 24.15, lon: -110.30 }, { name: "Campeche", lat: 19.83, lon: -90.53 }, { name: "Chiapas", lat: 16.75, lon: -93.12 }, { name: "Chihuahua", lat: 28.63, lon: -106.08 }, { name: "Ciudad de México", lat: 19.43, lon: -99.13 }, { name: "Coahuila", lat: 27.06, lon: -101.70 }, { name: "Durango", lat: 24.02, lon: -104.65 }, { name: "Guanajuato", lat: 20.92, lon: -101.00 }, { name: "Guerrero", lat: 17.55, lon: -99.50 }, { name: "Hidalgo", lat: 20.10, lon: -98.75 }, { name: "Jalisco", lat: 20.67, lon: -103.35 }, { name: "México", lat: 19.28, lon: -99.65 }, { name: "Michoacán", lat: 19.57, lon: -101.71 }, { name: "Morelos", lat: 18.92, lon: -99.23 }, { name: "Nuevo León", lat: 25.67, lon: -100.32 }, { name: "Oaxaca", lat: 17.07, lon: -96.72 }, { name: "Puebla", lat: 19.04, lon: -98.20 }, { name: "Querétaro", lat: 20.59, lon: -100.39 }, { name: "Quintana Roo", lat: 21.16, lon: -86.85 }, { name: "San Luis Potosí", lat: 22.15, lon: -100.98 }, { name: "Sinaloa", lat: 24.80, lon: -107.39 }, { name: "Sonora", lat: 29.07, lon: -110.96 }, { name: "Tabasco", lat: 17.99, lon: -92.93 }, { name: "Tamaulipas", lat: 23.74, lon: -99.14 }, { name: "Veracruz", lat: 19.54, lon: -96.91 }, { name: "Yucatán", lat: 20.97, lon: -89.59 }, { name: "Zacatecas", lat: 22.77, lon: -102.58 }, ]; return (
{lang==="es" ? "PRESENCIA — 28 ESTADOS" : "COVERAGE — 28 STATES"}

{lang==="es" ? <>Operación nacional,
ejecución local. : <>National footprint,
local execution.}

{lang==="es" ? "Tenemos cuadrillas y supervisores en las principales metrópolis del país, listos para arrancar tu programa con personal de la zona." : "We have crews and supervisors in every major Mexican metro, ready to launch your program with local talent."}

+
{lang==="es"?"Sedes servidas":"Sites served"}
+
{lang==="es"?"Clientes activos":"Active Clients"}
+
{lang==="es"?"Colaboradores":"Employees"}
REPSE
{lang==="es"?"Certificación":"Certification"}
{lang==="es"?"Estamos presentes en":"We operate in"} 28 {lang==="es"?"estados":"states"}
{states.map((s, i) => { const [x, y] = proj(s.lat, s.lon); const begin = ((i % 6) * 0.42).toFixed(2) + "s"; return ( ); })}
{states.map((s) => (
{s.name}
))}
{lang==="es" ? "Y contando..." : "And counting..."}
{/* Logo carousel */}
{[...logos, ...logos, ...logos].map((l, i) => ( {i ))}
); } /* ============================================================ TESTIMONIAL ============================================================ */ function Quote({ lang }) { return (
{lang === "es" ? <>Cambiamos a Over Klin después de auditar a cuatro proveedores. La diferencia se nota en lo que no tenemos que pedir dos veces. : <>We switched to Over Klin after auditing four vendors. The difference shows up in what we don't have to ask for twice.}
{lang==="es" ? "Directora de Facilities · Corporativo en Polanco" : "Head of Facilities · Corporate HQ, Polanco"}
{[0,1,2,3,4].map(i => )}
); } /* ============================================================ FAQ ============================================================ */ function FAQ({ lang }) { const items = lang === "es" ? [ ["¿Cómo se cotiza el servicio?", "El costo se calcula en función del tipo de servicio, la frecuencia requerida, el número de colaboradores asignados y el equipo o insumos especiales necesarios. Cualquier ajuste posterior al contrato se gestiona mediante una orden de cambio firmada por ambas partes, sin cargos sorpresa."], ["¿Tienen personal propio o subcontratan?", "Plantilla 100% propia. No trabajamos con terceros: cada colaborador es contratado directamente por Grupo Over Klin, lo que nos permite garantizar estándares de servicio uniformes en todas las cuentas."], ["¿Manejan turnos nocturnos o fines de semana?", "Sí, operamos 24/7 los 365 días del año. Diseñamos rotaciones a la medida de tu operación respetando jornadas laborales conforme a la Ley Federal del Trabajo."], ["¿Cómo se capacita al personal?", "Todo el personal recibe capacitación inicial en técnicas de limpieza, manejo de químicos, uso de EPP y protocolos de seguridad. Además, cada colaborador cuenta con la Constancia de Competencias Laborales DC-3 emitida por la STPS, y se imparten capacitaciones específicas según las necesidades de cada cliente."], ["¿Cómo verifican los antecedentes del personal?", "Antes de asignar a cualquier colaborador realizamos verificación de antecedentes penales, referencias laborales y validación de identidad. En cuentas con requerimientos de seguridad elevados aplicamos filtros adicionales según las políticas del cliente."], ] : [ ["How is the service priced?", "Cost is calculated based on service type, required frequency, number of assigned staff and any special equipment or supplies needed. Any post-contract adjustment is handled through a change order signed by both parties — no surprise charges."], ["In-house staff or subcontractors?", "100% in-house. We never use third parties: every team member is directly employed by Grupo Over Klin, which lets us guarantee consistent service standards across all accounts."], ["Night shifts or weekends?", "Yes, we operate 24/7, 365 days a year. We design rotations tailored to your operation in full compliance with Mexican labor law."], ["How is staff trained?", "All personnel receive initial training in cleaning techniques, chemical handling, PPE use and safety protocols. Every operator holds the DC-3 Labor Competency Certificate issued by Mexico's STPS, and account-specific training is provided based on each client's needs."], ["How do you screen your staff?", "Before assigning any team member we run criminal background checks, employment reference verification and identity validation. For accounts with higher security requirements we apply additional screening according to the client's policies."], ]; const [open, setOpen] = useStateS2(0); return (
{lang==="es"?"PREGUNTAS FRECUENTES":"FREQUENTLY ASKED"}

{lang==="es" ? <>Las preguntas que siempre nos hacen. : <>The questions we always get.}

{lang==="es" ? "Si no encuentras la tuya, escríbenos: respondemos en menos de 2 horas hábiles." : "If yours isn't here, drop us a line — we answer within 2 business hours."}

{items.map(([q, a], i) => (
{a}
))}
); } /* ============================================================ CTA + Multi-step booking ============================================================ */ function CTA({ lang }) { const [step, setStep] = useStateS2(0); const bookCardRef = useRefS2(null); const isFirstRender = useRefS2(true); useEffectS2(() => { if (isFirstRender.current) { isFirstRender.current = false; return; } if (window.innerWidth >= 1000) return; const el = bookCardRef.current; if (!el) return; const top = el.getBoundingClientRect().top + window.scrollY - 80; window.scrollTo({ top, behavior: "smooth" }); }, [step]); const [sliderVal, setSliderVal] = useStateS2(1); const [formErrors, setFormErrors] = useStateS2({}); const [isSubmitting, setIsSubmitting] = useStateS2(false); const [submitError, setSubmitError] = useStateS2(null); const [folio, setFolio] = useStateS2(""); const [data, setData] = useStateS2({ services: [], personas: "", materialIncluido: "", equipoEspecial: [], name: "", company: "", email: "", phone: "+", zip: "", ubicaciones: "", dias: [], horaInicio: 8, horaFin: 17, frecuencia: "", frecuenciaCustom: "", }); const update = (k, v) => setData((d) => ({...d, [k]: v})); const toggleArr = (k, v) => setData((d) => { const arr = d[k]; return {...d, [k]: arr.includes(v) ? arr.filter(x => x !== v) : [...arr, v]}; }); const tiposLimpieza = lang==="es" ? ["Limpieza general","Limpieza profunda","Sanitización","Pulido y abrillantado de pisos","Suministro insumos de limpieza","Asesoría","Recuperación de alfombras"] : ["General cleaning","Deep cleaning","Sanitization","Floor polish & brightening","Cleaning supplies","Consulting","Carpet recovery"]; const sliderNum = sliderVal <= 25 ? sliderVal : null; const adviceOpt = lang==="es" ? "No estoy seguro – necesito asesoramiento" : "Not sure – I need advice"; const colaborador = lang==="es" ? "colaboradores" : "collaborators"; const materialOpts = lang==="es" ? ["Sí, incluir material","No, ya contamos con material","No estoy seguro"] : ["Yes, include supplies","No, we have our own","Not sure"]; const equipoOpts = lang==="es" ? ["Casco","Guantes especiales","Botas industriales","Arnés y cuerda","Mascarilla / respirador","Traje protector","Otro"] : ["Hard hat","Special gloves","Safety boots","Harness & rope","Mask / respirator","Protective suit","Other"]; const diasOpts = lang==="es" ? ["Lun","Mar","Mié","Jue","Vie","Sáb","Dom"] : ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]; const diasLaborales = lang==="es" ? ["Lun","Mar","Mié","Jue","Vie"] : ["Mon","Tue","Wed","Thu","Fri"]; const frecuenciaOpts = lang==="es" ? ["Una sola vez","Diario","Semanal","Quincenal","Mensual","Personalizado"] : ["One time","Daily","Weekly","Bi-weekly","Monthly","Custom"]; const customFrecOpt = lang==="es" ? "Personalizado" : "Custom"; const ubicacionesOpts = lang==="es" ? ["Sí","No"] : ["Yes","No"]; const fmtHora = (h) => `${String(h % 24).padStart(2,"0")}:00`; const turnoDisplay = data.horaInicio === data.horaFin ? (lang==="es" ? "Turno 24h" : "24h shift") : data.horaFin < data.horaInicio ? `${fmtHora(data.horaInicio)} – ${fmtHora(data.horaFin)} ${lang==="es"?"(+1 día)":"(+1 day)"}` : `${fmtHora(data.horaInicio)} – ${fmtHora(data.horaFin)}`; const handlePhone2 = (v) => { if (!v.startsWith("+")) v = "+" + v.replace(/^\+*/,""); return v; }; const sliderLabel = sliderNum !== null ? `${sliderNum}` : "25+"; const personasDisplay = data.personas === adviceOpt ? adviceOpt : `${sliderLabel} ${colaborador}`; const canNext = (() => { if (step === 0) return data.services.length > 0; if (step === 1) return true; if (step === 2) return data.materialIncluido !== ""; if (step === 3) return data.frecuencia !== "" && (data.frecuencia !== customFrecOpt || data.dias.length > 0); if (step === 4) return true; return true; })(); const generateFolio = () => { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let result = 'OVK-'; for (let i = 0; i < 6; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; }; const handleSubmit = async () => { setIsSubmitting(true); setSubmitError(null); const newFolio = generateFolio(); setFolio(newFolio); const summaryStr = [ `${lang === "es" ? "Servicios" : "Services"}: ${data.services.join(", ")}`, `${lang === "es" ? "Personal" : "Personnel"}: ${personasDisplay}`, `${lang === "es" ? "Material" : "Supplies"}: ${data.materialIncluido}`, data.equipoEspecial.length > 0 ? `${lang === "es" ? "Equipo" : "Equipment"}: ${data.equipoEspecial.join(", ")}` : null, `${lang === "es" ? "Frecuencia" : "Frequency"}: ${data.frecuencia === customFrecOpt && data.frecuenciaCustom ? data.frecuenciaCustom : data.frecuencia}`, data.dias.length > 0 ? `${lang === "es" ? "Días" : "Days"}: ${data.dias.join(", ")}` : null, `${lang === "es" ? "Turno" : "Shift"}: ${turnoDisplay}`, `${lang === "es" ? "Múltiples ubicaciones" : "Multiple locations"}: ${data.ubicaciones}` ].filter(Boolean).join(" | "); const payload = { folio: newFolio, name: data.name, company: data.company, email: data.email, phone: data.phone, postalCode: data.zip, services: data.services, personal: data.personas === adviceOpt ? 0 : Number(sliderVal), requiresAdvisory: data.personas === adviceOpt, materialIncluded: data.materialIncluido === materialOpts[0], requiredEquipment: data.equipoEspecial, frequency: data.frecuencia === customFrecOpt && data.frecuenciaCustom ? data.frecuenciaCustom : data.frecuencia, shiftStart: fmtHora(data.horaInicio), shiftEnd: fmtHora(data.horaFin), multipleLocations: data.ubicaciones === (lang === "es" ? "Sí" : "Yes"), language: lang, summary: summaryStr }; try { const response = await fetch("https://n8n-acto.matic0.com/webhook/service-assessment", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error("Failed to submit"); setStep(5); setTimeout(() => { const el = bookCardRef.current; if (!el) return; const top = el.getBoundingClientRect().top + window.scrollY - 80; window.scrollTo({ top, behavior: "smooth" }); }, 50); } catch (error) { console.error("Submission error:", error); setSubmitError(lang === "es" ? "Hubo un error al enviar. Por favor intente de nuevo." : "There was an error submitting. Please try again."); } finally { setIsSubmitting(false); } }; const handleNext = () => { if (step === 4) { const es = lang === "es"; const errs = {}; if (!data.name?.trim() || data.name.trim().length < 3) errs.name = es ? "Mínimo 3 caracteres" : "Min. 3 characters"; if (!data.company?.trim()) errs.company = es ? "Requerido" : "Required"; if (!/^[^@\s]+@[^@\s]+\.[^\s@]{2,}$/.test(data.email?.trim() || "")) errs.email = es ? "Correo inválido" : "Invalid email"; if (!/^\+[0-9 ().-]{9,}$/.test(data.phone?.trim() || "")) errs.phone = es ? "Mín. 10 dígitos con +" : "Min. 10 digits with +"; if (!/^\d{5}$/.test(data.zip?.trim() || "")) errs.zip = es ? "5 dígitos requeridos" : "5-digit code required"; if (!data.ubicaciones) errs.ubicaciones = es ? "Selecciona una opción" : "Select an option"; setFormErrors(errs); if (Object.keys(errs).length > 0) { setTimeout(() => { const firstErr = bookCardRef.current?.querySelector(".field.error, .err"); if (firstErr) { const top = firstErr.getBoundingClientRect().top + window.scrollY - 120; window.scrollTo({ top, behavior: "smooth" }); } }, 50); return; } handleSubmit(); } else { if (step === 1 && !data.personas) update("personas", `${sliderLabel} ${colaborador}`); setStep(step + 1); } }; return (
{lang==="es"?"COTIZADOR EXPRESS":"INSTANT QUOTE"}

{lang==="es" ? <>Cuéntanos qué espacio
quieres impecable. : <>Tell us which space
you need spotless.}

{lang==="es" ? "Tres minutos para describirnos tu operación. Te respondemos con una propuesta a la medida." : "Three minutes to describe your operation. We come back with a proposal tailored to your needs."}

Tel 55 3717 5828
Email contacto@grupooverklin.com
{lang==="es"?"Oficinas":"Office"} Av. Insurgentes 1605, CDMX
{lang==="es"?"Horario":"Hours"} {lang==="es"?"Lun–Dom · 24/7":"Mon–Sun · 24/7"}
{step < 5 ? ( <>
{[0,1,2,3,4].map(i => ( ))}
{lang==="es"?`PASO ${step+1} DE 5`:`STEP ${step+1} OF 5`}
{step === 0 && ( <>

{lang==="es"?"¿Qué tipo de limpieza necesitas?":"What type of cleaning do you need?"}

{lang==="es"?"Selección múltiple":"Multiple selection"}

{tiposLimpieza.map((s) => ( ))}
)} {step === 1 && ( <>

{lang==="es"?"¿Cuánto personal necesitas?":"How many staff do you need?"}

{data.personas === adviceOpt ? "?" : sliderLabel}
{colaborador}
{ const v = Number(e.target.value); setSliderVal(v); const lbl = v <= 25 ? `${v}` : "25+"; update("personas", `${lbl} ${colaborador}`); }} />
125+
)} {step === 2 && ( <>

{lang==="es"?"¿Quieres contratar personal con material de limpieza?":"Do you want to hire staff with cleaning supplies?"}

{materialOpts.map((m) => ( ))}
{equipoOpts.map((eq) => ( ))}
)} {step === 3 && ( <>

{lang==="es"?"Horario del servicio":"Service schedule"}

{/* Frecuencia */}
{frecuenciaOpts.map(f => ( ))}
{/* Días — solo en Personalizado */} {data.frecuencia === customFrecOpt && (
{diasOpts.map(d => ( ))}
)} {/* Turno — slider de horas */}
{turnoDisplay}
{lang==="es"?"INICIO":"START"} update("horaInicio", Number(e.target.value))} /> {fmtHora(data.horaInicio)}
{lang==="es"?"FIN":"END"} update("horaFin", Number(e.target.value))} /> {fmtHora(data.horaFin)}
)} {step === 4 && ( <>

{lang==="es"?"Tus datos":"Your details"}

{update("name", e.target.value); setFormErrors(p=>({...p,name:""}));}} placeholder={lang==="es"?"Ej. Juan García":"e.g. John Smith"} /> {formErrors.name && {formErrors.name}}
{update("company", e.target.value); setFormErrors(p=>({...p,company:""}));}} placeholder={lang==="es"?"Nombre de la empresa":"Company name"} /> {formErrors.company && {formErrors.company}}
{update("email", e.target.value); setFormErrors(p=>({...p,email:""}));}} placeholder="correo@empresa.com" /> {formErrors.email && {formErrors.email}}
{update("phone", handlePhone2(e.target.value)); setFormErrors(p=>({...p,phone:""}));}} placeholder="+52 55 0000 0000" /> {formErrors.phone && {formErrors.phone}}
{update("zip", e.target.value.replace(/\D/g,"")); setFormErrors(p=>({...p,zip:""}));}} placeholder="06600" maxLength={5} /> {formErrors.zip && {formErrors.zip}}
{ubicacionesOpts.map((r) => ( ))}
{formErrors.ubicaciones && {formErrors.ubicaciones}}
{lang==="es"?"Servicios":"Services"}
{data.services.length ? data.services.map(s => ( {s} )) : }
{lang==="es"?"Personas":"People"} {personasDisplay}
{lang==="es"?"Material":"Supplies"} {data.materialIncluido ? {data.materialIncluido} : }
{data.equipoEspecial.length > 0 && (
{lang==="es"?"Equipo":"Equipment"}
{data.equipoEspecial.map(eq => ( {eq} ))}
)} {data.dias.length > 0 && (
{lang==="es"?"Días":"Days"}
{data.dias.map(d => ( {d} ))}
)} {data.frecuencia && (
{lang==="es"?"Frecuencia":"Frequency"} {data.frecuencia === customFrecOpt && data.frecuenciaCustom ? data.frecuenciaCustom : data.frecuencia}
)} {data.horaFin > data.horaInicio && (
{lang==="es"?"Turno":"Shift"} {turnoDisplay}
)} {data.zip && (
{lang==="es"?"C.P.":"ZIP"} {data.zip}
)} {data.ubicaciones && (
{lang==="es"?"Mult. ubicaciones":"Multi-location"} {data.ubicaciones}
)}
)}
{step > 0 ? : }
{submitError &&
{submitError}
} ) : (

{lang==="es"?"¡Solicitud recibida!":"Request received!"}

{lang==="es" ? `Gracias, ${data.name || "—"}. Un asesor te contactará pronto al ${data.phone || "tu teléfono"}.` : `Thanks, ${data.name || "—"}. An advisor will reach out soon at ${data.phone || "your phone"}.`}

REF · {folio}
)}
); } /* ============================================================ FOOTER ============================================================ */ function Footer({ lang }) { return ( ); } Object.assign(window, { Services, Presence, Quote, FAQ, CTA, Footer });