// ABLY — Main App: sections composing the landing page
const { useState, useEffect, useRef } = React;

// Shared mobile-breakpoint hook (exposed on window for the other section files).
const useIsMobile = (bp = 768) => {
  const query = `(max-width: ${bp}px)`;
  const [isMobile, setIsMobile] = React.useState(
    () => typeof window !== 'undefined' && window.matchMedia(query).matches
  );
  React.useEffect(() => {
    const mq = window.matchMedia(query);
    const onChange = () => setIsMobile(mq.matches);
    onChange();
    if (mq.addEventListener) mq.addEventListener('change', onChange);
    else mq.addListener(onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', onChange);
      else mq.removeListener(onChange);
    };
  }, [query]);
  return isMobile;
};
window.useIsMobile = useIsMobile;

const openWhatsApp = (message) => {
  // NOTE: replace the phone number below with the real ABLY WhatsApp line.
  const base = 'https://wa.me/15555555555';
  const url = message ? `${base}?text=${encodeURIComponent(message)}` : base;
  if (typeof gtag === 'function') gtag('event', 'whatsapp_click');
  window.open(url, '_blank');
};

// Context-specific WhatsApp messages
const WA_MESSAGES = {
  celebration: "Hi ABLY, I'm interested in the Celebration Yacht experience. Can you help me check availability and options?",
  vip: "Hi ABLY, I'm interested in the Ultra Luxury VIP experience. Can you help me check availability and options?",
  'private-escape': "Hi ABLY, I'm interested in the Private Escape experience. Can you help me check availability and options?",
  general: "Hi ABLY, I'm planning a private yacht experience in Cabo and would like help finding the best option.",
  quiz: "Hi ABLY, I completed the quiz and would like to check availability for my recommended yacht experience.",
  advisor: "Hi ABLY, I'd like some help choosing the right private yacht experience in Cabo. Can you guide me?",
};
window.WA_MESSAGES = WA_MESSAGES;

// ============ HEADER ============
// `heroCtaVisible` is driven by an IntersectionObserver on the hero's own
// primary CTA (see App). On MOBILE the header CTA + tagline stay hidden while
// the hero CTA is still on screen and only fade in once it scrolls away — the
// CSS that does this is scoped to the mobile breakpoint, so the desktop
// "transparent on-dark → solid" header behaviour is unchanged.
const Header = ({ scrolled, onOpenQuiz, isHeroVisible, heroCtaVisible = false }) => {
  const onLight = scrolled || !isHeroVisible;
  const navRef = useRef(null);
  const nameRef = useRef(null);
  const [logoShift, setLogoShift] = useState(0);
  const isMobile = window.useIsMobile ? window.useIsMobile() : false;

  // Above the fold the ABLY wordmark is centered + enlarged via transform; on
  // scroll it slides left and shrinks. We measure the exact translateX needed
  // to centre the (unscaled) wordmark inside the nav so it's pixel-accurate at
  // any phone width, and drive the transform as an inline STRING (not a CSS
  // var) — a changing inline transform reliably triggers the CSS transition,
  // whereas a transitioned transform whose var() updates post-mount can stall.
  // Using transform (never layout) means the enlargement can't reflow the page
  // or push the headline below the fold.
  const LOGO_SCALE = 1.36;
  const [logoReady, setLogoReady] = useState(false);
  React.useLayoutEffect(() => {
    if (!isMobile) { setLogoShift(0); setLogoReady(false); return undefined; }
    const measure = () => {
      const nm = nameRef.current, nv = navRef.current;
      if (!nm || !nv) return;
      const w = nm.offsetWidth;          // layout width — unaffected by transform
      const navW = nv.clientWidth;
      setLogoShift(Math.max(0, navW / 2 - (LOGO_SCALE * w) / 2));
    };
    measure();
    // Enable the transition only AFTER the first measurement so the wordmark is
    // already centered on first paint (it snaps into place rather than sliding
    // in from the left on load); state changes after this animate smoothly.
    setLogoReady(true);
    // Re-measure once the brand font settles and on resize/orientation change.
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(measure);
    window.addEventListener('resize', measure, { passive: true });
    return () => window.removeEventListener('resize', measure);
  }, [isMobile]);

  const nameTransform = isMobile
    ? (heroCtaVisible ? `translateX(${logoShift}px) scale(${LOGO_SCALE})` : 'translateX(0px) scale(1)')
    : undefined;

  return (
    <header
      className={`site-header on-dark ${onLight ? 'solid' : 'transparent'}${heroCtaVisible ? ' hero-cta-onscreen' : ''}${logoReady ? ' logo-ready' : ''}`}
    >
      <div className="container">
        <div className="nav-inner" ref={navRef} style={{ color: 'var(--white)' }}>
          <div className="logo-mark">
            <span className="name" ref={nameRef} style={{ transform: nameTransform }}>ABLY</span>
            <span className="desc">Private Yacht Experiences &amp;<br />Private Luxury Transportation</span>
          </div>
          <nav className="nav-links">
            <a href="#experiences">Experiences</a>
            <a href="#advisor">Your Advisor</a>
            <a href="#gallery">Gallery</a>
            <a href="#faq">FAQ</a>
            <a href="#footer">Contact</a>
          </nav>
          <button className="btn btn-gold btn-sm header-cta-btn" onClick={onOpenQuiz}>
            Plan My Day
          </button>
        </div>
      </div>
    </header>
  );
};

// ============ SOCIAL PROOF BAR ============
// Compact, credible proof row: overlapping guest avatars + gold star rating +
// score and matched-guest count. Shared by the mobile and desktop hero.
//
// ⚠️ PLACEHOLDER DATA — the avatars, the "4.9" rating and the "200+ guests"
// count below are ALL placeholders. They MUST be replaced with ABLY's real
// review score, real matched-guest count and real guest photos before launch.
// Do not present these invented numbers as final.
const PROOF_AVATARS = [
  // TODO: swap for real, consented guest photos before launch.
  { src: 'assets/reviews/jen.png', alt: 'ABLY guest' },
  { src: 'assets/reviews/cristopher.png', alt: 'ABLY guest' },
  { src: 'assets/reviews/liane.png', alt: 'ABLY guest' },
  { src: 'assets/reviews/gina.png', alt: 'ABLY guest' },
];
const ProofBar = ({ className = '' }) => {
  const res = (s) => (window.__resUrl ? window.__resUrl(s) : s);
  return (
    <div className={`proof-bar ${className}`}>
      <div className="proof-avatars">
        {PROOF_AVATARS.map((a, i) => (
          <img
            key={i}
            className="proof-avatar"
            src={res(a.src)}
            alt={a.alt}
            loading="lazy"
            decoding="async"
            draggable="false"
          />
        ))}
      </div>
      <div className="proof-rating">
        {/* TODO: replace 4.9 with ABLY's real aggregate rating */}
        <span className="proof-stars" role="img" aria-label="Rated 4.9 out of 5">
          {[0, 1, 2, 3, 4].map((i) => (
            <Icon key={i} name="star" size={15} fill="var(--gold)" stroke="var(--gold)" />
          ))}
        </span>
        <span className="proof-score">
          <strong>4.9</strong>
          {/* TODO: replace 200+ with ABLY's real matched-guest count */}
          <span className="proof-count"> · 200+ guests matched in Cabo</span>
        </span>
      </div>
    </div>
  );
};
window.ProofBar = ProofBar;

// ============ HERO FLOATING CARD CAROUSEL ============
// A premium stacked image-card carousel for the hero. Image-only cards,
// auto-advances every 3s with a physical card-switch motion, pauses on
// hover (desktop) and dims/blurs the area behind the active card.
const HERO_MOMENTS = [
  { src: 'assets/hero-carousel/moment-1.avif', portrait: false },
  { src: 'assets/hero-carousel/moment-2.avif', portrait: false },
  { src: 'assets/hero-carousel/moment-3-portrait.avif', portrait: true },
  { src: 'assets/hero-carousel/moment-4.avif', portrait: false },
  { src: 'assets/hero-carousel/moment-5.avif', portrait: false },
];

// ============ HERO ROTATING MEDIA ============
// Full-bleed media slideshow shared by the desktop + mobile hero. The yacht
// animation video plays FIRST (~2.5s), then crossfades through the Cabo
// "moment" photos — 2.5s per slide, looping back to the video. Each layer is
// absolutely stacked and fades via opacity, so transitions are elegant.
// The video uses webm (primary) with an mp4 fallback and a lightweight poster
// so a first frame shows instantly on slow connections.
const HERO_ROT_IMAGES = HERO_MOMENTS.map((m) => m.src);
const HERO_SLIDE_MS = 2500;

const HeroRotatingMedia = () => {
  const n = HERO_ROT_IMAGES.length + 1; // +1 for the video slide (index 0)
  const [active, setActive] = React.useState(0);
  const videoRef = React.useRef(null);
  const res = (s) => (window.__resUrl ? window.__resUrl(s) : s);

  const reduceMotion = React.useMemo(
    () => typeof window !== 'undefined' && window.matchMedia &&
      window.matchMedia('(prefers-reduced-motion: reduce)').matches,
    []
  );

  const webm = (window.__resources && window.__resources.heroVideoWebm) || 'videos/yacht-anim.webm';
  const mp4 = (window.__resources && window.__resources.heroVideo) || 'videos/yacht-anim.mp4';
  const poster = (window.__resources && window.__resources.heroPoster) || 'videos/yacht-poster.jpg';

  // Advance the slideshow every 2.5s (skip when the user prefers reduced motion).
  React.useEffect(() => {
    if (reduceMotion) return undefined;
    const id = setInterval(() => setActive((a) => (a + 1) % n), HERO_SLIDE_MS);
    return () => clearInterval(id);
  }, [n, reduceMotion]);

  // Kick autoplay on mount; some mobile browsers ignore the markup attribute.
  React.useEffect(() => {
    const v = videoRef.current;
    if (!v) return undefined;
    v.muted = true;
    const tryPlay = () => { const p = v.play(); if (p && p.catch) p.catch(() => {}); };
    tryPlay();
    v.addEventListener('canplay', tryPlay, { once: true });
    return () => v.removeEventListener('canplay', tryPlay);
  }, []);

  // Restart the clip from the top whenever the video slide comes back around.
  React.useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    if (active === 0) {
      try { v.currentTime = 0; } catch (e) { /* ignore */ }
      v.muted = true;
      const p = v.play(); if (p && p.catch) p.catch(() => {});
    }
  }, [active]);

  return (
    <React.Fragment>
      <video
        ref={videoRef}
        className={`hero-rot-layer hero-rot-video${active === 0 ? ' is-active' : ''}`}
        muted
        playsInline
        preload="auto"
        autoPlay
        poster={res(poster)}
        aria-hidden="true"
      >
        <source src={res(webm)} type="video/webm" />
        <source src={res(mp4)} type="video/mp4" />
      </video>
      {HERO_ROT_IMAGES.map((s, i) => (
        <img
          key={s}
          className={`hero-rot-layer hero-rot-img${active === i + 1 ? ' is-active' : ''}`}
          src={res(s)}
          alt=""
          aria-hidden="true"
          draggable="false"
          loading={i === 0 ? 'eager' : 'lazy'}
          decoding="async"
        />
      ))}
    </React.Fragment>
  );
};

// ============ HERO (mobile) ============
// Mobile composition that leads with a large immersive media block at the very
// top of the viewport (bleeding up behind the fixed header), then drops onto
// SOLID navy for all the copy so text is legible regardless of which carousel
// frame is showing. Top → bottom:
//   media (with the header's centered ABLY wordmark overlaid on its dark top)
//   → gold-outline badge pill → headline → sub → social-proof bar → primary CTA
//   → risk-reversal micro-row → benefit checklist.
//
// HeroRotatingMedia is reused verbatim — only its container treatment differs
// from desktop. The CTA wrapper keeps the shared `.hero-ctas` hook so the
// App's scroll observer (header CTA reveal + logo shrink/slide) works unchanged.
const HeroMobileImageTop = ({ onOpenQuiz }) => {
  return (
    <section className="hero-mb" id="hero">
      {/* 1 — Large immersive media block. Bleeds up behind the fixed header; its
          dark top keeps the overlaid ABLY wordmark legible, and its lower edge
          dissolves into the solid navy background below. */}
      <div className="hero-mb-stage">
        <HeroRotatingMedia />
        {/* Darkens the top of the media so the header's white ABLY wordmark
            stays legible over any carousel frame. */}
        <div className="hero-mb-topdark" aria-hidden="true" />
        {/* Sky-style fade that dissolves the media into the navy body below
            (same treatment family as the desktop .hero-video-fade). */}
        <div className="hero-mb-fade" aria-hidden="true" />
      </div>

      {/* 2 — Copy block on SOLID navy */}
      <div className="container hero-mb-body">
        {/* a — Centered gold-outline concierge badge */}
        <div className="hero-mb-pill">
          <span className="hero-mb-pill-dot" aria-hidden="true" />
          Cabo San Lucas · Concierge Service
        </div>

        {/* b — Left-aligned headline */}
        <h1 className="hero-mb-title">
          Your perfect day on the water starts right here.
        </h1>

        {/* c — Left-aligned sub-headline */}
        <p className="hero-sub hero-mb-sub">
          Tell us your group, your occasion, and your budget, and we'll match you to the right yacht and handle the details, so you're not comparing dozens of operators on your own.
        </p>

        {/* d — Left-aligned social-proof bar (avatars + stars + 4.9 + count).
            Rating / count / avatars are PLACEHOLDERS — see TODOs in ProofBar. */}
        <ProofBar className="hero-mb-proof" />

        {/* e — Full-width primary teal CTA. Keeps `.hero-ctas` so the App scroll
            observer that reveals the header CTA still targets it. */}
        <div className="hero-ctas hero-mb-ctas">
          <button className="btn btn-gold" onClick={onOpenQuiz}>
            Find My Perfect Experience
            <Icon name="arrowRight" size={14} />
          </button>
        </div>

        {/* f — Bottom risk-reversal micro-row (no benefit checklist in Variant B) */}
        <p className="hero-mb-microproof">Free · No obligation · We reply in minutes on WhatsApp</p>

        {/* g — Benefit checklist (parity with Variant A) */}
        <div className="hero-mb-benefits">
          <span><Icon name="check" size={13} stroke={2.5} /> Personalized for your group</span>
          <span><Icon name="check" size={13} stroke={2.5} /> Local Cabo yacht experts</span>
          <span><Icon name="check" size={13} stroke={2.5} /> Takes less than 2 minutes</span>
        </div>
      </div>
    </section>
  );
};

// ============ HERO ============
// Mobile renders the image-top composition (HeroMobileImageTop); desktop
// renders the original split hero below.
const Hero = ({ onOpenQuiz, scrollTo }) => {
  const isMobile = useIsMobile();

  if (isMobile) {
    return <HeroMobileImageTop onOpenQuiz={onOpenQuiz} />;
  }
  return (
    <section className="hero hero-split" id="hero">
      <div className="hero-bg" />
      <div className="hero-video-wrap" aria-hidden="true">
        <HeroRotatingMedia />
        <div className="hero-video-tint" />
        <div className="hero-video-fade" />
      </div>
      <div className="hero-grain" />
      <div className="container hero-inner">
        <div className="hero-copy-anim hero-copy">
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10, padding: '6px 14px', background: 'rgba(255,255,255,0.08)', border: '1px solid rgba(191,164,106,0.3)', borderRadius: 999, fontSize: 12, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.85)' }}>
            <span style={{ width: 6, height: 6, background: 'var(--gold)', borderRadius: '50%' }} />
            Cabo San Lucas · Concierge Service
          </div>
          <div className="hero-trusted">
            <Icon name="layers" size={15} stroke={1.5} />
            <span>
              <strong>Trusted by Cabo's Leading Yacht Operator</strong>
              Hand-selected experiences delivered by top-rated local fleets.
            </span>
          </div>
          {/* CHANGE 6 — desktop parity: same social-proof bar as mobile */}
          <ProofBar className="hero-proof" />
          <h1 style={{ marginTop: 28 }}>
            Your perfect day on the water starts right here.
          </h1>
          <p className="hero-sub">
            Tell us your group, your occasion, and your budget, and we'll match you to the right yacht and handle the details, so you're not comparing dozens of operators on your own.
          </p>
          <div className="hero-ctas">
            <button className="btn btn-gold" onClick={onOpenQuiz}>
              Find My Perfect Experience
              <Icon name="arrowRight" size={14} />
            </button>
          </div>
          {/* CHANGE 6 — desktop parity: risk-reversal microcopy under the CTA */}
          <p className="hero-microproof">Free · No obligation · We reply in minutes on WhatsApp</p>
          <div className="hero-micro-benefits">
            <span><Icon name="check" size={13} stroke={2.5} /> Personalized for your group</span>
            <span><Icon name="check" size={13} stroke={2.5} /> Local Cabo yacht experts</span>
            <span><Icon name="check" size={13} stroke={2.5} /> Takes less than 2 minutes</span>
          </div>
        </div>
      </div>
    </section>
  );
};

// ============ TRUST BAR ============
// Conversion-focused trust bar — sits directly under the hero on the dark
// midnight background to feel like a natural continuation of the hero.
const Trust = () => {
  const items = [
    { icon: 'clock',      title: 'Free cancellation',   sub: 'Up to 72 hours before' },
    { icon: 'concierge',  title: 'Professional crew',   sub: 'Captain & hosts onboard' },
    { icon: 'shield',     title: 'No hidden fees',       sub: 'Final price confirmed upfront' },
    { icon: 'chat',       title: 'No pressure to book',  sub: 'Get guidance before you decide' },
  ];
  return (
    <section className="trustbar" aria-label="ABLY trust benefits">
      <div className="container reveal">
        <ul className="trustbar-grid">
          {items.map((it) => (
            <li className="trustbar-item" key={it.title}>
              <span className="trustbar-icon"><Icon name={it.icon} size={20} stroke={1.6} /></span>
              <div className="trustbar-copy">
                <div className="trustbar-title">{it.title}</div>
                <div className="trustbar-sub">{it.sub}</div>
              </div>
            </li>
          ))}
        </ul>
        <div className="trustbar-social-proof">
          <Icon name="layers" size={14} stroke={1.5} />
          <span>
            <strong>Trusted by Cabo's Leading Yacht Operator</strong>
            &nbsp;— Hand-selected experiences delivered by top-rated local fleets.
          </span>
        </div>
      </div>
    </section>
  );
};

// ============ OFFERS ============
const BOAT_BASE = 'assets/boats/';
const boatSrc = (id) => {
  const path = BOAT_BASE + id + '.avif';
  return window.__resUrl ? window.__resUrl(path) : encodeURI(path);
};

// Auto-rotating, crossfading image stack for an offer card's image area.
// - 2.5s per image, ~700ms crossfade
// - staggered start per card so the three cards never switch in unison
// - pauses on hover, respects prefers-reduced-motion
// - preloads the first 3 images, lazy-mounts the rest as the rotation reaches them
const RotatingOfferImage = ({ gallery, label, startDelay = 0, paused = false }) => {
  const reduceMotion = React.useMemo(
    () => typeof window !== 'undefined' &&
      window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches,
    []
  );
  const [current, setCurrent] = React.useState(0);
  // How many layers are mounted (lazy reveal). Start with up to 3 preloaded.
  const [mountCount, setMountCount] = React.useState(() => Math.min(3, gallery.length));
  const pausedRef = React.useRef(paused);
  pausedRef.current = paused;

  React.useEffect(() => {
    if (reduceMotion || gallery.length <= 1) return undefined;
    let intervalId;
    const tick = () => {
      if (pausedRef.current) return;
      setCurrent((prev) => {
        const next = (prev + 1) % gallery.length;
        // Ensure the upcoming image (and one beyond) is mounted before it shows.
        setMountCount((m) => Math.min(gallery.length, Math.max(m, next + 2)));
        return next;
      });
    };
    const startId = setTimeout(() => {
      tick();
      intervalId = setInterval(tick, 2500);
    }, startDelay);
    return () => { clearTimeout(startId); if (intervalId) clearInterval(intervalId); };
  }, [gallery.length, startDelay, reduceMotion]);

  const shown = reduceMotion ? 1 : mountCount;

  return (
    <React.Fragment>
      {gallery.slice(0, shown).map((id, i) => (
        <img
          key={id}
          className="offer-img-layer"
          src={boatSrc(id)}
          alt={i === 0 ? label : ''}
          aria-hidden={i === 0 ? undefined : true}
          loading={i < 3 ? 'eager' : 'lazy'}
          decoding="async"
          fetchpriority={i === 0 ? 'high' : 'low'}
          draggable={false}
          style={{ opacity: i === current ? 1 : 0 }}
        />
      ))}
    </React.Fragment>
  );
};

const OfferCard = ({ o, index, onCustomize }) => {
  const [hovered, setHovered] = React.useState(false);
  return (
    <article
      className={`offer ${o.featured ? 'featured' : ''}`}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      <div className={`offer-img ${o.img}`}>
        <RotatingOfferImage
          gallery={o.gallery}
          label={`${o.title} — featured yacht`}
          startDelay={index * 800}
          paused={hovered}
        />
        <div className="offer-badge">
          <span className={`badge ${o.badge.cls}`}>{o.badge.text}</span>
        </div>
      </div>
      <div className="offer-body">
        <h3 className="offer-title">{o.title}</h3>
        <p className="offer-headline">{o.headline}</p>
        <p className="offer-desc">{o.desc}</p>
        <div className="offer-price">
          <span className="from">Experiences from</span>
          <span className="amt">${o.price.toLocaleString()}</span>
          <span className="offer-meta">{o.meta}</span>
        </div>
        <div className="offer-cta">
          <button className={`btn ${o.featured ? 'btn-primary' : 'btn-secondary'} btn-block`} onClick={() => onCustomize(o.key)}>
            {o.cta}
            <Icon name="arrowRight" size={14} />
          </button>
        </div>
      </div>
    </article>
  );
};

const Offers = ({ onCustomize, onOpenQuiz }) => {
  const offers = [
    {
      key: 'private-escape',
      img: 'offer-img-3',
      cover: 'assets/boats/b000.avif',
      badge: { text: 'Best for Small Groups', cls: 'badge-soft' },
      // Premium-ordered rotation. Covers every boat in this tier (Sea Ray 45,
      // French Sail 42, Bayliner 35, Cruiser 37); best shot leads, strongest boats weighted.
      gallery: ['b021', 'b002', 'b009', 'b014', 'b022', 'b010'],
      title: 'Private Escape',
      headline: "The kind of day you'll wish lasted longer.",
      desc: 'For couples, families, and small groups looking to relax away from the crowds.',
      price: 750,
      meta: 'Best for 2–8 guests',
      cta: 'Customize Experience',
    },
    {
      key: 'celebration',
      img: 'offer-img-1',
      cover: 'assets/boats/b033.avif',
      badge: { text: 'Most Popular', cls: 'badge-gold' },
      // Covers every boat in this tier (Sunseeker 60, Azimut 46, Leopard 52,
      // Papillon 47, Azimut 68); best shot leads.
      gallery: ['b043', 'b024', 'b040', 'b035', 'b057', 'b052'],
      title: 'Celebration Cruise',
      headline: 'Because some celebrations deserve more than a dinner reservation.',
      desc: 'Perfect for birthdays, bachelor parties, and unforgettable moments with friends.',
      price: 1850,
      meta: 'Best for 8–22 guests',
      cta: 'Customize Experience',
      featured: true,
    },
    {
      key: 'vip',
      img: 'offer-img-2',
      cover: 'assets/boats/b061.avif',
      badge: { text: 'Premium Upgrade', cls: 'badge-outline' },
      // Flagship Sunseeker 80 — the most exclusive yacht. Six strongest shots, best leads.
      gallery: ['b060', 'b061', 'b066', 'b062', 'b067', 'b063'],
      title: 'Ultra Luxury VIP',
      headline: "When ordinary luxury isn't enough.",
      desc: 'The highest level of privacy, service, and exclusivity available in Cabo.',
      price: 5400,
      meta: 'For high-end groups',
      cta: 'Customize Experience',
    },
  ];
  return (
    <section className="section-pad" id="experiences">
      <div className="container">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', flexWrap: 'wrap', gap: 24 }}>
          <div className="reveal" style={{ maxWidth: 640 }}>
            <div className="eyebrow">Three private experiences</div>
            <h2 className="section-title" style={{ marginTop: 16 }}>Find the day you came to Cabo for</h2>
            <p className="section-sub">Whether you're celebrating, escaping, or going all out, we'll help you find the right experience for your group.</p>
          </div>
          <div className="offers-micro-cta reveal dl1">
            <p>Not sure which one is right for you?<br/>Get a personalized recommendation in under 2 minutes.</p>
            <button className="btn btn-secondary" onClick={onOpenQuiz}>
              Find My Perfect Experience
              <Icon name="arrowRight" size={14} />
            </button>
          </div>
        </div>
        <div className="offers-grid reveal dl2">
          {offers.map((o, i) => (
            <OfferCard key={o.key} o={o} index={i} onCustomize={onCustomize} />
          ))}
        </div>
      </div>
    </section>
  );
};

// ============ CUSTOMIZER ============
const ADDONS = [
  { name: 'Private Chef', icon: 'chef', premium: true },
  { name: 'Extra Hour', icon: 'clock' },
  { name: 'Premium Decorations', icon: 'sparkles' },
  { name: 'Champagne Package', icon: 'glass', premium: true },
  { name: 'DJ or Custom Playlist', icon: 'music' },
  { name: 'Drone Photos', icon: 'camera' },
  { name: 'Transportation', icon: 'car' },
  { name: 'Sunset Upgrade', icon: 'sun' },
  { name: 'Water Toys', icon: 'wave' },
  { name: 'Birthday Setup', icon: 'cake' },
  { name: 'Bachelor/Bachelorette Setup', icon: 'crown' },
];

const Customizer = React.forwardRef(({ initialExperience, onSendQuote }, ref) => {
  const [step, setStep] = useState(0);
  const [experience, setExperience] = useState(initialExperience || 'celebration');
  const [yacht, setYacht] = useState('premium');
  const [addons, setAddons] = useState(['Water Toys', 'Champagne Package']);

  useEffect(() => {
    if (initialExperience) setExperience(initialExperience);
  }, [initialExperience]);

  const experiences = [
    { id: 'private-escape', title: 'Private Escape', sub: '2–8 guests · from $750', icon: 'wave' },
    { id: 'celebration', title: 'Celebration Yacht', sub: '8–22 guests · from $1,850', icon: 'cake' },
    { id: 'vip', title: 'Ultra Luxury VIP', sub: 'High-end groups · from $5,400', icon: 'crown' },
  ];
  const yachts = [
    { id: 'standard', title: 'Standard Yacht', sub: 'Up to 8 guests · 35–37 ft' },
    { id: 'premium', title: 'Premium Yacht', sub: 'Up to 14 guests · 45–46 ft' },
    { id: 'cat', title: 'Luxury Catamaran', sub: 'Up to 40 guests · 47–52 ft' },
    { id: 'ultra', title: 'Ultra Luxury', sub: 'Up to 30 guests · 60–80 ft' },
  ];

  const expPrices = { 'private-escape': 750, 'celebration': 1850, 'vip': 5400 };
  const yachtMult = { standard: 1, premium: 1.15, cat: 1.25, ultra: 1.65 };
  const baseExp = expPrices[experience] || 1850;
  const yachtAdj = baseExp * (yachtMult[yacht] - 1);
  const addonAdj = addons.length * 220;
  const total = Math.round(baseExp + yachtAdj + addonAdj);

  const toggleAddon = (name) => {
    setAddons(addons.includes(name) ? addons.filter(a => a !== name) : [...addons, name]);
  };

  const goStep = (n) => setStep(n);

  return (
    <section className="section-pad" style={{ background: 'var(--offwhite)' }} id="customize" ref={ref}>
      <div className="container">
        <div style={{ maxWidth: 720 }}>
          <div className="eyebrow">Configure</div>
          <h2 className="section-title" style={{ marginTop: 16 }}>Customize your yacht experience</h2>
          <p className="section-sub">Start with one of ABLY's curated experiences, then upgrade your yacht, add premium services, and request a personalized quote.</p>
        </div>

        <div className="config-shell">
          <div className="config-steps">
            {['Choose experience', 'Upgrade yacht', 'Add extras'].map((label, i) => (
              <button key={label} className={`config-step-tab ${i === step ? 'active' : ''}`} onClick={() => goStep(i)}>
                <span className="num">{i + 1}</span>
                {label}
              </button>
            ))}
          </div>

          {step === 0 && (
            <div>
              <h3 className="config-title">Choose your experience</h3>
              <p className="config-desc">Start with the type of experience that matches your group and occasion.</p>
              <div className="config-options">
                {experiences.map(e => (
                  <button key={e.id} className={`config-option ${experience === e.id ? 'selected' : ''}`} onClick={() => setExperience(e.id)}>
                    <span className="opt-icon"><Icon name={e.icon} size={14} /></span>
                    <span className="opt-title">{e.title}</span>
                    <span className="opt-sub">{e.sub}</span>
                  </button>
                ))}
              </div>
            </div>
          )}

          {step === 1 && (
            <div>
              <h3 className="config-title">Upgrade your yacht level</h3>
              <p className="config-desc">Choose the size, comfort level and atmosphere that fits your group.</p>
              <div className="config-options yacht-grid">
                {yachts.map(y => (
                  <button key={y.id} className={`config-option ${yacht === y.id ? 'selected' : ''}`} onClick={() => setYacht(y.id)}>
                    <span className="opt-icon"><Icon name="yacht" size={14} /></span>
                    <span className="opt-title">{y.title}</span>
                    <span className="opt-sub">{y.sub}</span>
                  </button>
                ))}
              </div>
            </div>
          )}

          {step === 2 && (
            <div>
              <h3 className="config-title">Add premium extras</h3>
              <p className="config-desc">Enhance your experience with optional upgrades designed around your celebration.</p>
              <div className="addon-grid">
                {ADDONS.map(a => {
                  const sel = addons.includes(a.name);
                  return (
                    <button key={a.name} className={`chip ${sel ? 'selected' : ''} ${a.premium ? 'premium' : ''}`} onClick={() => toggleAddon(a.name)}>
                      <Icon name={a.icon} size={14} />
                      {a.name}
                      {sel ? <Icon name="check" size={13} stroke={2.5} /> : <Icon name="plus" size={13} stroke={2} />}
                    </button>
                  );
                })}
              </div>
            </div>
          )}

          <div className="config-summary">
            <div>
              <div className="sum-label">Estimated starting from</div>
              <div className="sum-value">${total.toLocaleString()}</div>
              <div className="sum-detail">
                {experiences.find(e => e.id === experience)?.title} · {yachts.find(y => y.id === yacht)?.title} · {addons.length} {addons.length === 1 ? 'add-on' : 'add-ons'}
              </div>
            </div>
            <div style={{ display: 'flex', gap: 10 }}>
              {step > 0 && <button className="btn btn-secondary" onClick={() => goStep(step - 1)}><Icon name="arrowLeft" size={14}/> Back</button>}
              {step < 2 ? (
                <button className="btn btn-primary" onClick={() => goStep(step + 1)}>Continue <Icon name="arrowRight" size={14}/></button>
              ) : (
                <button className="btn btn-primary" onClick={onSendQuote}>Build My Custom Quote <Icon name="arrowRight" size={14}/></button>
              )}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
});

window.Header = Header;
window.Hero = Hero;
window.Trust = Trust;
window.Offers = Offers;
window.Customizer = Customizer;
window.openWhatsApp = openWhatsApp;
