// Home page sections.
// v2 design system: headline emphasis is a terracotta `.hl` word (drawn underline),
// stats count up on entry. All copy is unchanged from v1.

const { useEffect: hUseEffect, useState: hUseState, useRef: hUseRef } = React;

const HOME_COPY = {
  es: {
    eyebrow: 'Para hoteles en la era de la IA',
    trustedBy: 'Con la confianza de',
    heroTitle: <>Tu aliado para el <em>comercio</em> <em className="hl">agéntico.</em></>,
    heroLead: 'Cada vez más clientes buscan y reservan a través de plataformas de IA. En Listo, nos aseguramos de que te encuentren y puedan reservarte a través de estos canales.',
    heroCtaPrimary: 'Solicita una demo',
    heroCtaSecondary: 'Cómo funciona',
    heroSearchText: 'hoteles boutique lisboa',
    heroChatText: 'Quiero un hotel boutique tranquilo en Lisboa para el próximo jueves',
    shiftEyebrow: '§ 01 · El cambio',
    shiftTitle: <>La forma en que la gente busca y reserva está <em className="hl">cambiando</em>.</>,
    shiftBody1: 'Los clientes ya no buscan: preguntan. En lugar de comparar entre decenas de webs, le piden a un asistente de IA que les encuentre la mejor opción y la reserve.',
    shiftBody2: <>Los negocios <em className="hl">visibles</em> en la IA capturarán esta demanda. Los que no, se quedarán fuera.</>,
    stat1Label: 'de los consumidores inician su búsqueda y reservas de viaje en plataformas de IA',
    stat2Label: 'de los hoteles están ausentes de las búsquedas en canales de IA',
    stat3Number: '+1.700%',
    stat3Label: 'de crecimiento del tráfico desde IA hacia webs de viaje (jul 2024 a feb 2025)',
    dashboardCaption: 'Panel de visibilidad en IA · demo',
    shiftClosing: <>Los negocios <em className="hl">visibles</em> en la IA capturarán esta demanda. Los que no, se quedarán fuera.</>,
    whyEyebrow: '§ 02 · Por qué un partner para el comercio agéntico',
    whyTitle: <>Para competir en los canales de IA, se necesitan <em className="hl">dos claves</em>.</>,
    pillar1Title: 'Visibilidad',
    pillar1Tagline: 'Que los agentes de IA te encuentren.',
    pillar1Body: [
      "Si la IA no te encuentra, no te recomienda. Visibilidad es aparecer cuando alguien pide 'un hotel boutique en Lisboa' en ChatGPT, Claude, Gemini o Perplexity.",
      'Va más allá del SEO: depende de cómo la IA interpreta tu negocio y de qué fuentes te cita.',
    ],
    pillar2Title: 'Accionabilidad',
    pillar2Tagline: 'Que los agentes de IA puedan reservar contigo.',
    pillar2Body: [
      'La visibilidad hace que te recomienden; la accionabilidad permite reservar contigo. Permite a los agentes consultar tu disponibilidad, mostrar tus precios y completar la reserva.',
      'Es una conexión directa a tus sistemas para que la IA reserve en nombre del cliente, sin salir de la conversación.',
    ],
    pillarLink: 'Más información',
    auditCta: 'Auditoría gratis',
    visCheckText: 'Comprueba cómo la IA ve tu negocio',
    platformEyebrow: '§ 03 · La plataforma',
    platformTitle: <>Listo te prepara completamente para este <em className="hl">nuevo canal de ventas</em>.</>,
    platformLead: 'Listo se encarga de todo lo necesario para que tu negocio sea visible y reservable en la IA.',
    visBlockTag: 'Plataforma de visibilidad',
    visBlockTitle: <>Para que la <em className="hl">IA te encuentre</em>.</>,
    visBlockLead: 'Entiende, mide y mejora cómo te ven los modelos y las plataformas de IA.',
    visFeature1Num: 'Mide',
    visFeature1Body: 'Monitoriza tu visibilidad y tráfico en ChatGPT, Claude, Gemini y Perplexity: cómo apareces por plataforma y región, quién te cita y cómo apareces frente a la competencia.',
    visFeature2Num: 'Mejora',
    visFeature2Body: 'Auditamos tu web y tu presencia digital, encontramos lo que falla y optimizamos tu estructura y contenido para que la IA te encuentre, te entienda y te recomiende.',
    visBlockLink: 'Hablemos sobre Visibilidad →',
    actBlockTag: 'Plataforma de accionabilidad',
    actBlockTitle: <>Para que la <em className="hl">IA pueda reservar contigo</em>.</>,
    actBlockLead: 'Conecta tus sistemas y distribúyete en canales de IA. Exponte y entiende cómo los clientes y los agentes interactúan con tu negocio.',
    actFeature1Num: 'Construye',
    actFeature1Body: <>Listo se conecta a tus sistemas actuales como tu PMS y construye <a href="https://es.mirai.com/es/blog/mcp-el-puente-que-permitira-a-los-hoteles-competir-en-la-era-de-los-asistentes-ia-y-llms/" target="_blank" rel="noopener noreferrer">tu capa MCP</a>. Tú no cambias nada: construimos lo necesario para que tu negocio funcione dentro de todos los canales de IA.</>,
    actFeature2Num: 'Distribuye',
    actFeature2Body: 'Una sola integración para todos los canales: ChatGPT, Claude, Gemini, Perplexity y los que vengan. Infraestructura y analíticas centralizadas en un solo sitio.',
    actBlockLink: 'Hablemos sobre Accionabilidad →',
    actMcpCta: 'Prueba uno de nuestros MCPs',
    pricingEyebrow: 'Precios',
    pricingTitle: <>Planes que <em className="hl">crecen contigo</em>.</>,
    pricingLead: 'Empieza por ser visible en la IA y amplía hasta ser totalmente reservable. Sin permanencia, cancela cuando quieras.',
    pricingMonthly: 'Mensual',
    pricingAnnual: 'Anual',
    pricingSave: 'Ahorra 17%',
    pricingPopular: 'Más popular',
    pricingPerMo: '/mes',
    pricingCustom: 'A medida',
    pricingBilledMonthly: 'Precio por propiedad',
    pricingSavePrefix: 'Ahorra',
    pricingTalk: 'Hablemos',
    pricingPropertiesLabel: 'Número de propiedades',
    propertyOpts: ['1 propiedad', '2 propiedades', '3 propiedades', '4 propiedades', '5+ propiedades'],
    tiers: [
      { name: 'Visibility', tagline: 'Empieza a aparecer cuando los viajeros planifican su viaje con IA.', priceMonthly: '€59', priceAnnualMo: '€49', billAnnual: 'Facturado anualmente · €800/año', saveAnnual: '€120', featured: false, cta: 'Empezar',
        groups: [
          { label: 'Visibility Intelligence', icon: 'radar', benefit: 'Saber exactamente dónde y cómo apareces cuando los viajeros preguntan a la IA.', items: ['Seguimiento semanal', '2 perfiles de viajero', '4 plataformas (ChatGPT, Gemini, Claude, Perplexity)', '2 idiomas o regiones', 'Informe semanal'] },
          { label: 'Agent-ready', icon: 'code', benefit: 'Aseguramos que tu web sea legible para las plataformas de IA, inyectando datos estructurados y código para que los asistentes de IA la puedan leer y entender.', items: ['Schema / JSON-LD inyectado en tu código', 'robots.txt + agent.txt optimizados para crawlers de IA', 'FAQs estructuradas', 'Marcado semántico de tus páginas clave', 'Instalación en un clic con el plugin de WordPress', 'Actualizaciones automáticas continuas'] },
        ] },
      { name: 'Grow', tagline: 'Todo lo de Visibility, más la mejora activa de cómo te presenta la IA.', priceMonthly: '€179', priceAnnualMo: '€149', billAnnual: 'Facturado anualmente · €1.000/año', saveAnnual: '€360', featured: true, cta: 'Empezar',
        groups: [
          { label: 'Todo lo de Visibility', items: [] },
          { label: 'AI Marketing Engine', icon: 'bulb', benefit: 'Convierte tus datos de visibilidad en recomendaciones y acciones para optimizar tu presencia en los canales de IA.', items: ['Lectura completa de tu presencia digital (Booking, Expedia, TripAdvisor, tu web, …)', 'Comprobaciones de sindicación y consistencia de tu presencia digital', 'Sugerencias de edición de contenido de marketing', 'Borradores de respuesta a reseñas en OTAs', 'Recomendaciones de posicionamiento'] },
        ] },
      { name: 'Expand', tagline: 'Reservable en la IA, con tu propio MCP.', custom: true, billCustom: 'Precio a medida según tu operación', featured: false, cta: 'Hablemos',
        groups: [
          { label: 'Todo lo de Grow', items: [] },
          { label: 'MCP dedicado', icon: 'robot', benefit: 'Deja que los agentes de IA te reserven directamente sobre una infraestructura hecha a la medida de tu stack.', items: ['Construcción, optimización y despliegue de un MCP a medida', 'Los agentes reservan e interactúan con tu inventario en vivo', 'Analíticas dedicadas del canal de agentes'] },
        ] },
    ],
    pricingSeeIncluded: 'Ver qué incluye',
    pricingMatrixTitle: 'Compara todos los planes',
    pricingMatrixSub: 'Módulos y cobertura, lado a lado.',
    pricingIncluded: 'Incluido',
    pricingNotIncluded: 'No incluido',
    pricingMatrix: [
      { label: 'Módulos', rows: [
        { label: 'Seguimiento de visibilidad', vals: ['check', 'check', 'check'] },
        { label: 'SEO/GEO técnico', vals: ['check', 'check', 'check'] },
        { label: 'Sugerencias con IA', vals: ['dash', 'check', 'check'] },
        { label: 'MCP dedicado', vals: ['dash', 'dash', 'check'] },
      ] },
      { label: 'Cobertura', rows: [
        { label: 'Plataformas de IA monitorizadas', vals: ['4', '4', 'A medida'] },
        { label: 'Frecuencia de seguimiento', vals: ['Semanal', 'Semanal', 'A medida'] },
        { label: 'Idiomas / regiones', vals: ['2', '3', 'A medida'] },
        { label: 'Perfiles de viajero', vals: ['2', '3', 'A medida'] },
        { label: 'Palabras clave', vals: ['3', '5', 'A medida'] },
        { label: 'Informes', vals: ['Semanal', 'Semanal', 'A medida'] },
        { label: 'Lectura de presencia digital (Booking, Expedia, TripAdvisor, web)', vals: ['dash', 'check', 'check'] },
        { label: 'Comprobaciones de sindicación y consistencia de tu presencia digital', vals: ['dash', 'check', 'check'] },
        { label: 'Sugerencias de edición de contenido de marketing', vals: ['dash', 'check', 'check'] },
        { label: 'Borradores de respuesta a reseñas OTA', vals: ['dash', 'check', 'check'] },
        { label: 'Recomendaciones de posicionamiento', vals: ['dash', 'check', 'check'] },
        { label: 'MCP reservable (los agentes reservan tu inventario)', vals: ['dash', 'dash', 'check'] },
      ] },
    ],
    faqEyebrow: 'Preguntas frecuentes',
    faqTitle: 'Lo que nos preguntan nuestros clientes.',
    faqs: [
      { q: `¿Cómo aparece mi negocio cuando un viajero pregunta en ChatGPT o Gemini?`,
        a: `Es función de tres capas que operan a la vez. La primera es lo que el modelo conoce de sus datos de entrenamiento. La segunda es lo que el asistente encuentra al hacer una búsqueda en internet en tiempo real (tu web, OTAs, guías turísticas). La tercera es lo que el asistente puede consultar directamente en tus sistemas, si existe esa conexión: disponibilidad, precios, condiciones. Las tres capas operan a la vez, y Listo trabaja y optimiza las tres.` },
      { q: `¿Es lo mismo SEO que GEO? ¿Debería hacer GEO?`,
        a: `No es lo mismo, pero son compatibles. El SEO clásico es una pieza importante para que los asistentes encuentren y puedan leer tu web. El GEO (Generative Engine Optimization) intenta influir en lo que el modelo interpreta y dice sobre tu marca. Listo trabaja ambas: el SEO/GEO técnico para exponer tu web a los agentes, y la optimización de tu contenido digital para que tengas mayor control sobre cómo la IA te interpreta y habla de ti.` },
      { q: `Mi web ya está bien posicionada en Google. ¿No es suficiente?`,
        a: `Hasta cierto punto. El SEO sigue siendo una base importante y te ayuda a aparecer cuando el asistente busca en la web. Pero cuando el viajero quiere decidir o reservar (recomendaciones, fechas, condiciones, precio real) el SEO se queda corto. Hace falta saber y controlar cómo el asistente hablará de tu hotel, y si tiene acceso a datos en vivo. Sin esto, el asistente se apoya en los datos de Booking o Expedia, y lo que sucedió en Google con las OTAs se vuelve a repetir dentro de los canales de IA.` },
      { q: `¿Qué es MCP y por qué importa para mi negocio?`,
        a: `MCP (Model Context Protocol) es el estándar que permite a los asistentes consultar fuentes oficiales y conectadas en tiempo real, en lugar de leer páginas web. Es la capa que da certezas: si hay habitación libre el 12 de agosto, si admite niños, si el desayuno está incluido. Para tu negocio significa que la IA puede citar información verificada directamente desde tus sistemas, y que los consumidores y los agentes pueden comparar y reservar directamente contigo, sin depender de una OTA.` },
      { q: `Si la IA puede reservar dentro del asistente, ¿qué pasa con mi canal directo?`,
        a: `La conversación se convierte en parte del canal directo, no en su sustituto. Tu web sigue siendo central, pero parte de la decisión y, con el tiempo, parte de la reserva ocurren dentro del asistente. Ese espacio no se quedará vacío: si tu negocio no lo ocupa con datos oficiales y conectados, lo ocupan Booking o Expedia. Prepararse hoy (datos estructurados, inventario expuesto a los agentes, tarifas y condiciones en una única fuente, un MCP) es lo que separa al negocio que mantiene su canal directo del que lo cede.` },
    ],
  },
  en: {
    eyebrow: 'For hotels in the AI era',
    trustedBy: 'Trusted by',
    heroTitle: <>Your <em>agentic</em> <em className="hl">commerce</em> partner.</>,
    heroLead: 'More and more travelers are searching through AI platforms. Listo makes sure they can find you and can book you through those channels.',
    heroCtaPrimary: 'Request a demo',
    heroCtaSecondary: 'How it works',
    heroSearchText: 'boutique hotels lisbon',
    heroChatText: 'find me a quiet boutique hotel in Lisbon for next week',
    shiftEyebrow: '§ 01 · The shift',
    shiftTitle: <>The way people search and book is <em className="hl">changing</em>.</>,
    shiftBody1: "Travelers don't just search anymore. They ask AI. Instead of comparing dozens of sites, they ask an AI assistant to find the best option and book it.",
    shiftBody2: <>Businesses <em className="hl">visible</em> in AI search will capture this demand. Those that are not will be left out.</>,
    stat1Label: 'of consumers start their travel research and bookings on AI platforms',
    stat2Label: 'of hotels are absent from AI-channel searches',
    stat3Number: '+1,700%',
    stat3Label: 'growth in AI-driven traffic to travel websites (Jul 2024 to Feb 2025)',
    dashboardCaption: 'Live AI-visibility dashboard · demo',
    shiftClosing: <>Businesses <em className="hl">visible</em> in AI search will capture this demand. Those that are not will be left out.</>,
    whyEyebrow: '§ 02 · Why a partner for agentic commerce',
    whyTitle: <>There are <em className="hl">two keys</em> to competing AI channels.</>,
    pillar1Title: 'Visibility',
    pillar1Tagline: 'So AI agents find you.',
    pillar1Body: [
      "If AI can't find you, it can't recommend you. Visibility means showing up when someone asks for 'a boutique hotel in Lisbon' on ChatGPT, Claude, Gemini, or Perplexity.",
      "It goes beyond SEO: it's about how AI interprets your business and which sources cite you.",
    ],
    pillar2Title: 'Actionability',
    pillar2Tagline: 'So AI agents can book you.',
    pillar2Body: [
      'Visibility gets you recommended; actionability gets you booked. It lets agents check your availability, show your prices, and complete the booking.',
      "It's a direct connection to your systems so AI can book on the customer's behalf, without leaving the conversation.",
    ],
    pillarLink: 'Learn more',
    auditCta: 'Free audit',
    visCheckText: 'See how AI sees your business',
    platformEyebrow: '§ 03 · The platform',
    platformTitle: <>Listo gets you fully ready for this <em className="hl">new sales channel</em>.</>,
    platformLead: 'Listo handles everything you need to be visible and bookable inside AI.',
    visBlockTag: 'Visibility platform',
    visBlockTitle: <>So <em className="hl">AI can find you</em>.</>,
    visBlockLead: 'Understand, measure, and improve how AI models find and recommend you.',
    visFeature1Num: 'Measure',
    visFeature1Body: 'Track your visibility and traffic across ChatGPT, Claude, Gemini, and Perplexity: how you show up by platform, region, who cites you, and how you show up against the competition.',
    visFeature2Num: 'Improve',
    visFeature2Body: 'We audit your website and digital presence, find what is broken, and optimise your structure and content so AI can find, understand, and recommend you.',
    visBlockLink: "Let's talk about Visibility →",
    actBlockTag: 'Actionability platform',
    actBlockTitle: <>So <em className="hl">AI can book you</em>.</>,
    actBlockLead: 'Connect your systems and distribute through AI channels. Get discovered, and understand how customers and agents interact with your business.',
    actFeature1Num: 'Build',
    actFeature1Body: <>Listo connects to your existing systems, like your PMS, and builds <a href="https://www.mirai.com/blog/mcp-the-bridge-that-will-allow-hotels-to-compete-in-the-era-of-ai-assistants-and-llms/" target="_blank" rel="noopener noreferrer">your MCP server</a>. You change nothing: we build everything needed for your business to be operable inside every AI channel.</>,
    actFeature2Num: 'Distribute',
    actFeature2Body: 'One integration for every channel: ChatGPT, Claude, Gemini, Perplexity, and whatever comes next. We handle the infrastructure and analytics, centralised in one place.',
    actBlockLink: "Let's talk about Actionability →",
    actMcpCta: 'Try one of our MCPs',
    pricingEyebrow: 'Pricing',
    pricingTitle: <>Plans that <em className="hl">grow with you</em>.</>,
    pricingLead: 'Start by being visible in AI and scale all the way to fully bookable. No lock-in, cancel anytime.',
    pricingMonthly: 'Monthly',
    pricingAnnual: 'Annual',
    pricingSave: 'Save 17%',
    pricingPopular: 'Most popular',
    pricingPerMo: '/mo',
    pricingCustom: 'Custom',
    pricingBilledMonthly: 'Price per property',
    pricingSavePrefix: 'Save',
    pricingTalk: 'Talk to us',
    pricingPropertiesLabel: 'Number of properties',
    propertyOpts: ['1 property', '2 properties', '3 properties', '4 properties', '5+ properties'],
    tiers: [
      { name: 'Visibility', tagline: 'Start showing up when travellers plan their trips with AI.', priceMonthly: '€59', priceAnnualMo: '€49', billAnnual: 'Billed annually · €800/yr', saveAnnual: '€120', featured: false, cta: 'Get started',
        groups: [
          { label: 'Visibility Intelligence', icon: 'radar', benefit: 'Know exactly where and how you show up when travellers ask AI.', items: ['Weekly tracking', '2 traveller profiles', '4 platforms (ChatGPT, Gemini, Claude, Perplexity)', '2 languages or regions', 'Weekly report'] },
          { label: 'Agent-ready', icon: 'code', benefit: 'We make sure your site is legible to AI platforms, injecting structured data and code so AI assistants can read and understand it.', items: ['Schema / JSON-LD injected into your code', 'robots.txt + agent.txt tuned for AI crawlers', 'Structured FAQs', 'Semantic markup of your key pages', 'One-click install via WordPress plugin', 'Continuous automatic updates'] },
        ] },
      { name: 'Grow', tagline: 'Everything in Visibility, plus active improvement of how AI presents you.', priceMonthly: '€179', priceAnnualMo: '€149', billAnnual: 'Billed annually · €1,000/yr', saveAnnual: '€360', featured: true, cta: 'Get started',
        groups: [
          { label: 'Everything in Visibility', items: [] },
          { label: 'AI Marketing Engine', icon: 'bulb', benefit: 'Turn your visibility data into recommendations and actions to optimise your presence across AI channels.', items: ['Full read of your digital presence (Booking, Expedia, TripAdvisor, your site, …)', 'Syndication & consistency checks of your digital presence', 'Marketing-content edit suggestions', 'OTA review-response drafts', 'Positioning recommendations'] },
        ] },
      { name: 'Expand', tagline: 'Bookable in AI, with your own MCP.', custom: true, billCustom: 'Custom pricing for your operation', featured: false, cta: 'Talk to us',
        groups: [
          { label: 'Everything in Grow', items: [] },
          { label: 'Dedicated MCP', icon: 'robot', benefit: 'Let AI agents book you directly, on infrastructure built around your stack.', items: ['Custom MCP build, optimisation and deployment', 'Agents book and interact with your live inventory', 'Dedicated agent-channel analytics'] },
        ] },
    ],
    pricingSeeIncluded: "See what's included",
    pricingMatrixTitle: 'Compare every plan',
    pricingMatrixSub: 'Modules and coverage, side by side.',
    pricingIncluded: 'Included',
    pricingNotIncluded: 'Not included',
    pricingMatrix: [
      { label: 'Modules', rows: [
        { label: 'Visibility tracking', vals: ['check', 'check', 'check'] },
        { label: 'Technical SEO/GEO', vals: ['check', 'check', 'check'] },
        { label: 'AI suggestions', vals: ['dash', 'check', 'check'] },
        { label: 'Dedicated MCP', vals: ['dash', 'dash', 'check'] },
      ] },
      { label: 'Coverage', rows: [
        { label: 'AI platforms tracked', vals: ['4', '4', 'Custom'] },
        { label: 'Tracking frequency', vals: ['Weekly', 'Weekly', 'Custom'] },
        { label: 'Languages / regions', vals: ['2', '3', 'Custom'] },
        { label: 'Traveller profiles', vals: ['2', '3', 'Custom'] },
        { label: 'Keywords', vals: ['3', '5', 'Custom'] },
        { label: 'Reporting', vals: ['Weekly', 'Weekly', 'Custom'] },
        { label: 'Digital-presence read (Booking, Expedia, TripAdvisor, site)', vals: ['dash', 'check', 'check'] },
        { label: 'Syndication & consistency checks of your digital presence', vals: ['dash', 'check', 'check'] },
        { label: 'Marketing-content edit suggestions', vals: ['dash', 'check', 'check'] },
        { label: 'OTA review-reply drafts', vals: ['dash', 'check', 'check'] },
        { label: 'Positioning recommendations', vals: ['dash', 'check', 'check'] },
        { label: 'Bookable MCP (agents book your inventory)', vals: ['dash', 'dash', 'check'] },
      ] },
    ],
    faqEyebrow: 'FAQ',
    faqTitle: 'What our clients ask us.',
    faqs: [
      { q: `How does my business show up when a traveller asks ChatGPT or Gemini?`,
        a: `It comes down to three layers, all of which work at the same time. The first is what the model knows from its training data. The second is what the assistant finds when it executes a web search real time (your site, OTAs, travel guides). The third is what the assistant can pull directly from your systems, when that connection exists: availability, prices, conditions. All three layers run at once, and Listo works on and optimises all three.` },
      { q: `Is SEO the same as GEO? Should I be doing GEO?`,
        a: `They are not the same, but they are compatible. Classic SEO is an important primitive so assistants can find and read your site. GEO (Generative Engine Optimisation) tries to shape what the model interprets and says about your brand. Listo works on both: technical SEO/GEO to expose your site to agents, and optimising your digital content so you have more control over how AI interprets and talks about you.` },
      { q: `My site already ranks well on Google. Isn't that enough?`,
        a: `To an extent. SEO is still an important foundation and helps you appear when the assistant searches the web. But when the traveller wants to decide or book (recommendations, dates, conditions, live prices) SEO falls short. You need to know and control how the assistant will talk about your hotel, and whether it has access to live data. Without this, the assistant leans on Booking's or Expedia's data, and what happened with Google and OTAs repeats itself inside the AI channels.` },
      { q: `What is MCP and why does it matter for my business?`,
        a: `MCP (Model Context Protocol) is the standard that lets assistants query official, connected sources in real time instead of reading web pages. It is the layer that delivers certainty: whether a room is free on 12 August, what the price is, whether any of your policies have changed. For your business it means AI can cite verified information straight from your systems, and that consumers and agents can compare and book directly with you, without depending on an OTA.` },
      { q: `If AI can book inside the assistant, what happens to my direct channel?`,
        a: `The AI channel becomes part of your direct channel, not a replacement of it. Your website stays central, but part of the decision and, over time, part of the booking will happen inside the AI assistant. That space will not stay empty: if your business does not fill it with official, connected data, Booking or Expedia will. Preparing now (structured data, inventory exposed to agents, rates and conditions in a single source, an MCP) is what separates the business that protects its direct channel on AI from the one that hands it over to OTAs.` },
    ],
  },
};

function homeT() {
  const lang = (typeof window !== 'undefined' && window.detectLang) ? window.detectLang() : 'es';
  return HOME_COPY[lang];
}

/* ----------------- Count-up numeral ----------------- */
function useInView(ref, threshold) {
  const [inView, setInView] = hUseState(false);
  hUseEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (!('IntersectionObserver' in window)) { setInView(true); return; }
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => { if (e.isIntersecting) { setInView(true); io.disconnect(); } }),
      { threshold: threshold || 0.4 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return inView;
}

function parseStat(str) {
  const m = String(str).match(/^(\D*?)([\d.,]+)(\D*)$/);
  if (!m) return null;
  const [, pre, num, suf] = m;
  const sepMatch = num.match(/[.,]/);
  return {
    pre,
    suf,
    sep: sepMatch ? sepMatch[0] : '',
    value: parseInt(num.replace(/[.,]/g, ''), 10),
  };
}

function groupNum(n, sep) {
  if (!sep) return String(n);
  return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, sep);
}

// Numerals animate 0 → target over 1400ms (easeOutCubic), 380ms after entry.
function CountUpNumber({ value }) {
  const ref = hUseRef(null);
  const inView = useInView(ref, 0.4);
  const parsed = parseStat(value);
  const [display, setDisplay] = hUseState(parsed ? '0' : value);

  hUseEffect(() => {
    if (!parsed || !inView) return;
    let raf;
    let start;
    const dur = 1400;
    const ease = (t) => 1 - Math.pow(1 - t, 3);
    const tick = (ts) => {
      if (!start) start = ts;
      const t = Math.min(1, (ts - start) / dur);
      setDisplay(groupNum(Math.round(ease(t) * parsed.value), parsed.sep));
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    const to = setTimeout(() => { raf = requestAnimationFrame(tick); }, 380);
    return () => { clearTimeout(to); if (raf) cancelAnimationFrame(raf); };
  }, [inView]);

  if (!parsed) return <span ref={ref}>{value}</span>;
  return (
    <span ref={ref}>
      {parsed.pre ? <span className="pre">{parsed.pre}</span> : null}
      {display}{parsed.suf}
    </span>
  );
}

/* ----------------- Hero ----------------- */
function Hero() {
  const t = homeT();

  return (
    <section className="hero">
      <div className="container">
        <div className="hero-grid">
          <div className="hero-left">
            <h1 className="display reveal" style={{ marginTop: 0 }}>{t.heroTitle}</h1>
            <p className="lead reveal delay-1" style={{ marginTop: 28, maxWidth: 540 }}>{t.heroLead}</p>
            <div className="reveal delay-2" style={{ marginTop: 36, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
              <a href="#platform" className="btn btn-ghost">{t.heroCtaSecondary}</a>
              <a href={window.STRINGS[window.detectLang()].benchmark} className="btn btn-primary">
                {t.auditCta} <span aria-hidden="true">→</span>
              </a>
            </div>
          </div>
          <div className="hero-right reveal delay-3">
            <iframe
              className="hero-widget-frame"
              src="/widgets/seaclub-widget.html"
              title="SeaClub Resort · ChatGPT"
              loading="lazy"
              scrolling="no"
            ></iframe>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ----------------- Section 2: The Shift ----------------- */
function Shift() {
  const t = homeT();
  return (
    <section className="section" id="shift">
      <div className="container">
        <div className="reveal split">
          <div>
            <h2 className="h1">{t.shiftTitle}</h2>
          </div>
          <div className="body split-body">
            <p>{t.shiftBody1}</p>
            <p style={{ color: 'var(--ink)', fontWeight: 600, fontSize: 18, lineHeight: 1.4, marginTop: 24 }}>
              {t.shiftBody2}
            </p>
          </div>
        </div>

        <div className="stat-grid reveal delay-2">
          <Stat number="56%" label={t.stat1Label} source="Phocuswright Research" />
          <Stat number="84%" label={t.stat2Label} source="Hotel World AI" />
          <Stat number={t.stat3Number} label={t.stat3Label} source="Adobe Analytics" />
        </div>
      </div>
    </section>
  );
}

function Stat({ number, label, source }) {
  return (
    <div className="stat reveal">
      <div className="stat-number"><CountUpNumber value={number} /></div>
      <div className="stat-label">{label}</div>
      <div className="stat-source">{source}</div>
    </div>
  );
}

/* ----------------- Section 3: Why ----------------- */
function Why() {
  const t = homeT();
  return (
    <section className="section" id="why" style={{ borderTop: '1px solid var(--hairline)', paddingBottom: 'clamp(48px, 6vw, 80px)' }}>
      <div className="container">
        <div className="reveal" style={{ maxWidth: 980 }}>
          <h2 className="h1">{t.whyTitle}</h2>
        </div>

        <div className="pillars">
          <Pillar
            n="01"
            title={t.pillar1Title}
            tagline={t.pillar1Tagline}
            body={t.pillar1Body}
            icon="search"
            foot={
              <div className="pillar-foot">
                <span className="pillar-foot-text">{t.visCheckText}</span>
                <a href={window.STRINGS[window.detectLang()].benchmark} className="btn btn-primary auditoria-btn">
                  {t.auditCta} <span aria-hidden="true">→</span>
                </a>
              </div>
            }
          />
          <Pillar
            n="02"
            title={t.pillar2Title}
            tagline={t.pillar2Tagline}
            body={t.pillar2Body}
            icon="bolt"
          />
        </div>
      </div>
    </section>
  );
}

function Pillar({ n, title, tagline, body, icon, foot }) {
  return (
    <div className="pillar reveal">
      <div className="pillar-head">
        <div className="pillar-icon" aria-hidden="true">
          {icon === 'search' ? (
            <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.6">
              <circle cx="11" cy="11" r="7" />
              <path d="M21 21l-4.3-4.3" />
            </svg>
          ) : (
            <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" strokeLinecap="round">
              <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z" />
            </svg>
          )}
        </div>
      </div>
      <h3 className="pillar-title">{title}</h3>
      <p className="pillar-tag"><em>{tagline}</em></p>
      <div className="body" style={{ marginTop: 16 }}>
        {body.map((p, i) => <p key={i}>{p}</p>)}
      </div>
      {foot}
    </div>
  );
}

/* ----------------- Section 4: Platform ----------------- */
function Platform() {
  const t = homeT();
  const lang = (typeof window !== 'undefined' && window.detectLang) ? window.detectLang() : 'es';
  const dashSrc = lang === 'en' ? '/widgets/geo-dashboard-en.html' : '/widgets/geo-dashboard-es.html';

  // Size the embedded dashboard. On phones (≤600px) render it at a fixed internal
  // width and scale it to fit, so its cards never clip off-screen; on desktop keep
  // the CSS scale. Parent height always tracks the iframe's actual (scaled) box.
  const sizeDash = (ifr) => {
    if (!ifr || !ifr.contentWindow) return;
    try {
      const parent = ifr.parentElement;
      const MOBILE_INTERNAL = 620;
      if (window.innerWidth <= 600) {
        ifr.style.width = MOBILE_INTERNAL + 'px';
        ifr.style.transform = 'scale(' + (parent.clientWidth / MOBILE_INTERNAL) + ')';
      } else {
        ifr.style.width = '';
        ifr.style.transform = '';
      }
      const body = ifr.contentWindow.document.body;
      const h = Math.max(body.scrollHeight, body.offsetHeight);
      if (h > 0) {
        ifr.style.height = h + 'px';
        parent.style.height = Math.ceil(ifr.getBoundingClientRect().height) + 'px';
      }
    } catch (e) {}
  };

  hUseEffect(() => {
    let raf;
    const fit = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => sizeDash(document.querySelector('.platform-dash-frame iframe')));
    };
    window.addEventListener('resize', fit);
    return () => { window.removeEventListener('resize', fit); cancelAnimationFrame(raf); };
  }, []);

  return (
    <section className="section" id="platform" style={{ background: 'var(--surface)', borderTop: '1px solid var(--hairline)' }}>
      <div className="container">
        <div className="reveal" style={{ maxWidth: 980 }}>
          <h2 className="h1">{t.platformTitle}</h2>
          <p className="lead" style={{ marginTop: 28, maxWidth: 760 }}>{t.platformLead}</p>
        </div>

        <div className="platform-stack" style={{ marginTop: 56 }}>
          {/* Blue card — full width, contents laid out horizontally */}
          <div className="platform-block platform-row reveal" style={{ '--pa': 'var(--blue)' }}>
            <div className="platform-row-head">
              <h3 className="h2" style={{ marginTop: 0 }}>{t.visBlockTitle}</h3>
              <p className="body" style={{ marginTop: 14 }}>{t.visBlockLead}</p>
            </div>
            <div className="feature">
              <div className="feature-num">{t.visFeature1Num}</div>
              <p>{t.visFeature1Body}</p>
            </div>
            <div className="feature">
              <div className="feature-num">{t.visFeature2Num}</div>
              <p>{t.visFeature2Body}</p>
            </div>
          </div>

          {/* Live dashboard — full width, transparent so its cards float on the section */}
          <div className="platform-dash-frame reveal delay-1">
            <iframe
              src={dashSrc}
              title={t.dashboardCaption}
              loading="lazy"
              scrolling="no"
              onLoad={(e) => sizeDash(e.currentTarget)}
            ></iframe>
          </div>

          {/* Orange card — full width, contents laid out horizontally */}
          <div className="platform-block platform-row reveal delay-1" style={{ '--pa': 'var(--terracotta)' }}>
            <div className="platform-row-head">
              <h3 className="h2" style={{ marginTop: 0 }}>{t.actBlockTitle}</h3>
              <p className="body" style={{ marginTop: 14 }}>{t.actBlockLead}</p>
            </div>
            <div className="feature">
              <div className="feature-num">{t.actFeature1Num}</div>
              <p>{t.actFeature1Body}</p>
            </div>
            <div className="feature">
              <div className="feature-num">{t.actFeature2Num}</div>
              <p>{t.actFeature2Body}</p>
            </div>
            <div className="platform-cta">
              <a
                href="https://chatgpt.com/apps/seaclub-alcudia/asdk_app_697b9790a2c481918af9c72439f29974"
                target="_blank"
                rel="noopener noreferrer"
                className="platform-mcp-btn"
              >
                {t.actMcpCta} <span aria-hidden="true">→</span>
              </a>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* Pricing module icons (ported from the standalone pricing prototype) */
const PRICE_ICONS = {
  radar: (<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19.07 4.93A10 10 0 0 0 6.99 3.34" /><path d="M4 6h.01" /><path d="M2.29 9.62A10 10 0 1 0 21.31 8.35" /><path d="M16.24 7.76A6 6 0 1 0 8.23 16.67" /><path d="M12 18h.01" /><path d="M17.99 11.66A6 6 0 0 1 15.77 16.67" /><circle cx="12" cy="12" r="2" /><path d="m13.41 10.59 5.66-5.66" /></svg>),
  code: (<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="16 18 22 12 16 6" /><polyline points="8 6 2 12 8 18" /></svg>),
  bulb: (<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" /><path d="M9 18h6" /><path d="M10 22h4" /></svg>),
  robot: (<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="10" rx="2" /><circle cx="12" cy="5" r="2" /><path d="M12 7v4" /><line x1="8" y1="16" x2="8" y2="16" /><line x1="16" y1="16" x2="16" y2="16" /></svg>),
};
const PRICE_SPARK = (<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M18.4 5.6l-2.1 2.1M7.7 16.3l-2.1 2.1" /></svg>);

/* ----------------- Pricing ----------------- */
function Pricing() {
  const t = homeT();
  const [annual, setAnnual] = hUseState(false);
  const [openAcc, setOpenAcc] = hUseState({});
  const [compareOpen, setCompareOpen] = hUseState(false);
  const [properties, setProperties] = hUseState('1');
  const toggleAcc = (k) => setOpenAcc((s) => ({ ...s, [k]: !s[k] }));
  const contactHref = (typeof window !== 'undefined' && window.STRINGS && window.detectLang)
    ? window.STRINGS[window.detectLang()].contact : 'contact.html';
  return (
    <section className="section pricing" id="pricing" style={{ borderTop: '1px solid var(--hairline)' }}>
      <div className="container">
        <div className="reveal" style={{ maxWidth: 820 }}>
          <h2 className="h1">{t.pricingTitle}</h2>
          <p className="lead" style={{ marginTop: 24, maxWidth: 680 }}>{t.pricingLead}</p>
        </div>

        <div className="pricing-toggle reveal delay-1">
          <button type="button" className={'pt-opt' + (!annual ? ' on' : '')} onClick={() => setAnnual(false)}>
            {t.pricingMonthly}
          </button>
          <button type="button" className={'pt-opt' + (annual ? ' on' : '')} onClick={() => setAnnual(true)}>
            {t.pricingAnnual} <span className="pt-save">{t.pricingSave}</span>
          </button>
        </div>

        <div className="pricing-grid reveal delay-1">
          {t.tiers.map((tier, i) => (
            <div className={'price-card' + (tier.featured ? ' featured' : '')} key={i}>
              {tier.featured && <div className="price-badge">{t.pricingPopular}</div>}
              <h3 className="price-name">{tier.name}</h3>
              <p className="price-tag">{tier.tagline}</p>
              <div className="price-amount">
                {tier.custom ? (
                  <span className="price-num price-custom">{t.pricingCustom}</span>
                ) : (
                  <>
                    <span className="price-num">{annual ? tier.priceAnnualMo : tier.priceMonthly}</span>
                    <span className="price-per">{t.pricingPerMo}</span>
                    {annual && tier.saveAnnual && (
                      <span className="price-save">{t.pricingSavePrefix} {tier.saveAnnual}</span>
                    )}
                  </>
                )}
              </div>
              <div className="price-bill">
                {tier.custom ? tier.billCustom : t.pricingBilledMonthly}
              </div>
              <select
                className={'price-props' + (tier.custom ? ' price-props-hidden' : '')}
                value={tier.custom ? '1' : properties}
                onChange={(e) => setProperties(e.target.value)}
                disabled={tier.custom}
                aria-hidden={tier.custom || undefined}
                tabIndex={tier.custom ? -1 : undefined}
                aria-label={t.pricingPropertiesLabel}
              >
                {['1', '2', '3', '4', '5+'].map((v, idx) => (
                  <option key={v} value={v}>{t.propertyOpts[idx]}</option>
                ))}
              </select>
              <a href={contactHref} className={'btn price-cta ' + (tier.featured ? 'btn-primary' : 'btn-ghost')}>
                {(!tier.custom && properties !== '1') ? t.pricingTalk : tier.cta}
              </a>
              <div className="price-features">
                {tier.groups.map((g, gi) => {
                  if (g.items.length === 0) {
                    return (
                      <div className="price-inherit" key={gi}>
                        <span className="price-inherit-ic" aria-hidden="true">{PRICE_SPARK}</span>
                        <span>{g.label}</span>
                      </div>
                    );
                  }
                  const accKey = i + '-' + gi;
                  const isOpen = !!openAcc[accKey];
                  return (
                    <div className="price-fgroup" key={gi}>
                      <div className="price-mhead">
                        <span className="price-micon" aria-hidden="true">{PRICE_ICONS[g.icon]}</span>
                        <div>
                          <div className="price-fhead">{g.label}</div>
                          {g.benefit && <p className="price-mbenefit">{g.benefit}</p>}
                        </div>
                      </div>
                      <div className="price-mbody">
                        <button type="button" className="price-acc-toggle" aria-expanded={isOpen}
                                onClick={() => toggleAcc(accKey)}>
                          <span>{t.pricingSeeIncluded}</span>
                          <span className="price-chev" aria-hidden="true">
                            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9" /></svg>
                          </span>
                        </button>
                        <div className={'price-acc-panel' + (isOpen ? ' open' : '')}>
                          <ul>{g.items.map((it, ii) => <li key={ii}>{it}</li>)}</ul>
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </div>

        <div className="pricing-compare reveal delay-1">
          <button type="button" className={'pc-toggle' + (compareOpen ? ' open' : '')} aria-expanded={compareOpen} onClick={() => setCompareOpen((v) => !v)}>
            <span className="pc-toggle-label">{t.pricingMatrixTitle}</span>
            <span className="pc-toggle-chev" aria-hidden="true">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9" /></svg>
            </span>
          </button>
          <div className={'pc-collapse' + (compareOpen ? ' open' : '')}>
            <div className="pc-scroll">
            <table className="pc-table">
              <thead>
                <tr>
                  <th></th>
                  {t.tiers.map((tier, i) => (
                    <th key={i} className={'pc-plan' + (tier.featured ? ' featured' : '')}>{tier.name}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {t.pricingMatrix.map((group, gi) => (
                  <React.Fragment key={gi}>
                    <tr className="pc-group"><th colSpan={1 + t.tiers.length}>{group.label}</th></tr>
                    {group.rows.map((row, ri) => (
                      <tr key={ri}>
                        <td className="pc-row-label">{row.label}</td>
                        {row.vals.map((v, ci) => (
                          <td key={ci} className={'pc-cell' + (t.tiers[ci] && t.tiers[ci].featured ? ' featured' : '')}>
                            {v === 'check' ? (
                              <span className="pc-check" role="img" aria-label={t.pricingIncluded}>✓</span>
                            ) : v === 'dash' ? (
                              <span className="pc-dash" role="img" aria-label={t.pricingNotIncluded}>–</span>
                            ) : (
                              <span className="pc-val">{v}</span>
                            )}
                          </td>
                        ))}
                      </tr>
                    ))}
                  </React.Fragment>
                ))}
              </tbody>
            </table>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ----------------- Destination Break (framed photo) ----------------- */
function DestinationBreak() {
  return (
    <section className="destination-break reveal">
      <img src="/assets/photos/Listo_hotel_website_image_4.png" alt="A Mediterranean coastal hotel at dusk" loading="lazy" />
    </section>
  );
}

/* ----------------- Logo carousel (between hero and Shift) ----------------- */
const CLIENT_LOGOS = [
  { src: '/assets/logos/travelsupermarket.png', h: 54, alt: 'TravelSupermarket', href: 'https://chatgpt.com/apps/travelsupermarket/asdk_app_6a0c2a748e1c8191b71697ee496fcce3', label: 'TravelSupermarket' },
  { src: '/assets/logos/rusticae.png', h: 40, alt: 'Rusticae' },
  { src: '/assets/logos/economybookings.png', alt: 'EconomyBookings', href: 'https://chatgpt.com/apps/economybookings/asdk_app_6a02fad225b08191a6b3728fae704bba', label: 'EconomyBookings' },
];
function LogoCarousel() {
  const t = homeT();
  // Repeat the set enough times that one half always exceeds the viewport width,
  // then duplicate into two identical halves so the -50% marquee loops with no gap.
  const half = Array.from({ length: 6 }, () => CLIENT_LOGOS).flat();
  const all = [...half, ...half];
  return (
    <section className="logo-carousel reveal">
      <div className="logo-carousel-label">{t.trustedBy}</div>
      <div className="logo-marquee">
        <div className="logo-track">
          {all.map((l, i) => (
            l.href ? (
              <a className="logo-link" key={i} href={l.href} target="_blank" rel="noopener noreferrer" aria-label={l.label}>
                <img className="logo-item" src={l.src} alt={l.alt}
                     style={l.h ? { height: l.h + 'px' } : undefined} />
              </a>
            ) : (
              <img className="logo-item" key={i} src={l.src} alt={l.alt}
                   style={l.h ? { height: l.h + 'px' } : undefined} />
            )
          ))}
        </div>
      </div>
    </section>
  );
}

/* ----------------- FAQ (homepage) ----------------- */
function FAQ() {
  const t = homeT();
  const [open, setOpen] = hUseState(0);
  return (
    <section className="section faq" id="faq" style={{ borderTop: '1px solid var(--hairline)' }}>
      <div className="container">
        <div className="reveal" style={{ maxWidth: 820 }}>
          <h2 className="h1">{t.faqTitle}</h2>
        </div>
        <div className="faq-list reveal delay-1">
          {t.faqs.map((f, i) => (
            <div className={'faq-item' + (open === i ? ' open' : '')} key={i}>
              <button type="button" className="faq-q" aria-expanded={open === i} onClick={() => setOpen(open === i ? -1 : i)}>
                <span>{f.q}</span>
                <span className="faq-chev" aria-hidden="true"></span>
              </button>
              <div className="faq-a"><p>{f.a}</p></div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Hero, Shift, Why, Platform, Pricing, DestinationBreak, LogoCarousel, FAQ });
