// ABLY — Offer Configurator Modal
// Per-offer 4-step configurator with live price summary.

const OFFERS = {
  'private-escape': {
    name: 'Private Escape',
    badge: 'Best for Small Groups',
    baseFrom: 750,
    accent: '#0E7490',
    accentSoft: 'rgba(14,116,144,0.08)',
    accentTint: 'rgba(14,116,144,0.18)',
    accentBorder: 'rgba(14,116,144,0.35)',
    badgeStyle: 'soft',
    upsell: { label: 'Looking for a larger boat?', target: 'celebration', targetName: 'Celebration Cruise' },
    yachts: [
      {
        id: 'fsail42', name: 'French Sail Boat 42 ft', type: 'Sail boat / 42 ft',
        price: 750, baseGuests: 6, maxGuests: 12, extraGuest: 80, hours: 3, extraHr: 213,
        gradient: 'linear-gradient(135deg,#c9d4dd 0%,#6c8aa6 100%)',
        images: [
          'assets/boats/b000.avif',
          'assets/boats/b001.avif',
          'assets/boats/b002.avif',
          'assets/boats/b003.avif',
          'assets/boats/b004.avif',
          'assets/boats/b005.avif',
        ],
        bullets: ['Sail boat / 42 ft', '3 cabins', 'Kitchen', 'Living room', 'Shaded back seating', 'Large front seating', 'Optional sailing experience'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'bayliner35', name: 'Bayliner 35 ft', type: 'Yacht / 35 ft',
        price: 950, baseGuests: 6, maxGuests: 8, extraGuest: 80, hours: 3, extraHr: 269,
        gradient: 'linear-gradient(135deg,#bfc8d2 0%,#5a708a 100%)',
        images: [
          'assets/boats/b006.avif',
          'assets/boats/b007.avif',
          'assets/boats/b008.avif',
          'assets/boats/b009.avif',
        ],
        bullets: ['Yacht / 35 ft', 'Compact yacht for small groups', 'Front bed seating', 'Dining area', 'Kitchen', 'Bedroom', 'Bathroom'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'cruiser37', name: 'Cruiser 37 ft', type: 'Yacht / 37 ft',
        price: 1050, baseGuests: 6, maxGuests: 8, extraGuest: 80, hours: 3, extraHr: 298,
        gradient: 'linear-gradient(135deg,#aebac8 0%,#465f7c 100%)',
        images: [
          'assets/boats/b010.avif',
          'assets/boats/b011.avif',
          'assets/boats/b012.avif',
          'assets/boats/b013.avif',
          'assets/boats/b014.avif',
          'assets/boats/b015.avif',
          'assets/boats/b016.avif',
          'assets/boats/b017.avif',
          'assets/boats/b018.avif',
        ],
        bullets: ['Yacht / 37 ft', 'Slightly more spacious option', 'Spacious front bed seating', 'Dining area', 'Kitchen', 'Bedroom', 'Bathroom'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'searay45', name: 'Sea Ray 45 ft', type: 'Yacht / 45 ft',
        price: 1500, baseGuests: 8, maxGuests: 14, extraGuest: 80, hours: 3, extraHr: 425,
        gradient: 'linear-gradient(135deg,#a3b0c0 0%,#374a66 100%)',
        images: [
          'assets/boats/b019.avif',
          'assets/boats/b020.avif',
          'assets/boats/b021.avif',
          'assets/boats/b022.avif',
          'assets/boats/b023.avif',
        ],
        bullets: ['Yacht / 45 ft', 'Strongest upgrade in Private Escape', 'Large sunbathing area', 'Shaded stern seating', 'Dining area', 'Kitchen', 'Private cabin', 'Bathroom'],
        included: ['paddle', 'snorkel', 'mat'],
      },
    ],
  },
  'celebration': {
    name: 'Celebration Cruise',
    badge: 'Most Popular',
    baseFrom: 1850,
    accent: '#BFA46A',
    accentSoft: 'rgba(191,164,106,0.10)',
    accentTint: 'rgba(191,164,106,0.18)',
    accentBorder: 'rgba(191,164,106,0.45)',
    badgeStyle: 'gold',
    upsell: { label: 'Looking for the most exclusive experience?', target: 'vip', targetName: 'Ultra Luxury VIP' },
    yachts: [
      {
        id: 'azimut46', name: 'Azimut 46 ft', type: 'Yacht / 46 ft',
        price: 1850, baseGuests: 10, maxGuests: 16, extraGuest: 90, hours: 3, extraHr: 524,
        gradient: 'linear-gradient(135deg,#1f3957 0%,#0c2440 100%)',
        images: [
          'assets/boats/b024.avif',
          'assets/boats/b025.avif',
          'assets/boats/b026.avif',
          'assets/boats/b027.avif',
          'assets/boats/b028.avif',
          'assets/boats/b029.avif',
          'assets/boats/b030.avif',
          'assets/boats/b031.avif',
          'assets/boats/b032.avif',
        ],
        bullets: ['Yacht / 46 ft', 'Sunbathing area', 'Shaded back seating', 'Living room', 'Dining table', '2 bedrooms · 2 bathrooms', 'Air-conditioned', 'Flybridge'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'papillon47', name: 'Catamaran Papillon 47 ft', type: 'Catamaran / 47 ft',
        price: 1900, baseGuests: 14, maxGuests: 40, extraGuest: 80, hours: 3, extraHr: 538,
        gradient: 'linear-gradient(135deg,#27486e 0%,#0e7490 100%)',
        images: [
          'assets/boats/b033.avif',
          'assets/boats/b034.avif',
          'assets/boats/b035.avif',
          'assets/boats/b036.avif',
          'assets/boats/b037.avif',
          'assets/boats/b038.avif',
        ],
        bullets: ['Catamaran / 47 ft', 'Great for larger groups and parties', '2 bathrooms', 'Shaded area', 'Large front seating', 'High-quality music system', 'Bluetooth'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'leopard52', name: 'Catamaran Leopard 52 ft', type: 'Catamaran / 52 ft',
        price: 2200, baseGuests: 14, maxGuests: 35, extraGuest: 90, hours: 3, extraHr: 623,
        gradient: 'linear-gradient(135deg,#2b3f5c 0%,#0a2440 100%)',
        images: [
          'assets/boats/b039.avif',
          'assets/boats/b040.avif',
          'assets/boats/b041.avif',
          'assets/boats/b042.avif',
        ],
        bullets: ['Catamaran / 52 ft', 'Kitchen with chef area', 'Interior and exterior dining', 'Lounge beds · shaded seating', 'Front net', '2 cabins · 2 bathrooms', 'Air-conditioned'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'sunseeker60', name: 'Sunseeker 60 ft', type: 'Yacht / 60 ft',
        price: 2350, baseGuests: 10, maxGuests: 22, extraGuest: 90, hours: 3, extraHr: 783,
        gradient: 'linear-gradient(135deg,#15283e 0%,#061b2b 100%)',
        images: [
          'assets/boats/b043.avif',
          'assets/boats/b044.avif',
          'assets/boats/b045.avif',
          'assets/boats/b046.avif',
          'assets/boats/b047.avif',
          'assets/boats/b048.avif',
          'assets/boats/b049.avif',
          'assets/boats/b050.avif',
          'assets/boats/b051.avif',
          'assets/boats/b052.avif',
        ],
        bullets: ['Yacht / 60 ft', 'Italian-style luxury interiors', '2 VIP cabins · 3 bathrooms', 'Spacious living room', 'Dining table', 'Air-conditioned', 'Flybridge'],
        included: ['paddle', 'snorkel', 'mat'],
      },
      {
        id: 'azimut68', name: 'Azimut 68 ft', type: 'Yacht / 68 ft',
        price: 3350, baseGuests: 10, maxGuests: 20, extraGuest: 90, hours: 3, extraHr: 1117,
        gradient: 'linear-gradient(135deg,#1a1a1a 0%,#3a2f1f 60%,#BFA46A 200%)',
        images: [
          'assets/boats/b053.avif',
          'assets/boats/b054.avif',
          'assets/boats/b055.avif',
          'assets/boats/b056.avif',
          'assets/boats/b057.avif',
          'assets/boats/b058.avif',
          'assets/boats/b059.avif',
        ],
        bullets: ['Yacht / 68 ft', 'Premium celebration upgrade', '2 VIP cabins', 'Open-air areas', 'Living room · dining table', '3 bathrooms · sunbathing area', 'Air-conditioned', 'Flybridge'],
        included: ['snorkel', 'mat'],
      },
    ],
  },
  'vip': {
    name: 'Ultra Luxury VIP',
    badge: 'Premium Upgrade',
    baseFrom: 5400,
    accent: '#BFA46A',
    accentSoft: 'rgba(191,164,106,0.10)',
    accentTint: 'rgba(191,164,106,0.18)',
    accentBorder: 'rgba(191,164,106,0.55)',
    badgeStyle: 'outline',
    flagship: true,
    upsell: null,
    yachts: [
      {
        id: 'sunseeker80', name: 'Sunseeker 80 ft', type: 'Yacht / 80 ft',
        price: 5400, baseGuests: 10, maxGuests: 30, extraGuest: 175, hours: 3, extraHr: 1800,
        gradient: 'linear-gradient(135deg,#1a1a1a 0%,#2a2a2a 50%,#BFA46A 220%)',
        images: [
          'assets/boats/b060.avif',
          'assets/boats/b061.avif',
          'assets/boats/b062.avif',
          'assets/boats/b063.avif',
          'assets/boats/b064.avif',
          'assets/boats/b065.avif',
          'assets/boats/b066.avif',
          'assets/boats/b067.avif',
        ],
        bullets: ['Yacht / 80 ft', 'Flagship luxury option', '4 bedrooms · 4 bathrooms', '5 TVs · JBL Bluetooth', 'Stabilization system', 'Hydraulic swim platform', 'Maximum comfort, status and exclusivity'],
        included: ['paddle', 'snorkel', 'mat'],
      },
    ],
  },
};

const INCLUDED_SERVICES = [
  { id: 'private', label: 'Private yacht experience', always: true },
  { id: 'crew', label: 'Professional captain and crew', always: true },
  { id: 'cooler', label: 'Cooler with ice', always: true },
  { id: 'water', label: 'Bottled water', always: true },
  { id: 'drinks', label: 'Domestic drinks', always: true },
  { id: 'food', label: 'Food and snacks', always: true },
  { id: 'sound', label: 'Bluetooth sound system', always: true },
  { id: 'safety', label: 'Safety equipment', always: true },
  { id: 'fuel', label: 'Fuel for the standard route', always: true },
  { id: 'paddle', label: 'Paddle board' },
  { id: 'snorkel', label: 'Snorkel gear' },
  { id: 'mat', label: 'Floating mat' },
];

// Only operator-verified prices are shown; everything else is quoted by the
// concierge ("Price to be confirmed"). Transportation is priced per zone
// (operator pitchbook, roundtrip) — the three zone cards are mutually
// exclusive via `group: 'transport'`.
const EXTRA_SERVICES = [
  { id: 'chef', label: 'Private chef', price: null },
  { id: 'catering', label: 'Premium catering', price: null },
  { id: 'champagne', label: 'Champagne package', price: null },
  { id: 'openbar', label: 'Premium open bar', price: null },
  { id: 'bday', label: 'Birthday decoration', price: null },
  { id: 'romantic', label: 'Romantic decoration', price: null },
  { id: 'photo', label: 'Photographer', price: null },
  { id: 'drone', label: 'Drone footage', price: null },
  { id: 'dj', label: 'DJ / entertainment', price: null },
  { id: 'jetski', label: 'Jet ski', price: null },
  { id: 'transport-csl', label: 'Private transportation — Cabo San Lucas (midtown)', sub: 'Round-trip hotel ↔ marina', price: 60, group: 'transport' },
  { id: 'transport-corridor', label: 'Private transportation — Tourist Corridor', sub: 'Round-trip hotel ↔ marina', price: 85, group: 'transport' },
  { id: 'transport-sjd', label: 'Private transportation — San José del Cabo · Puerto Los Cabos · Diamante', sub: 'Round-trip hotel ↔ marina', price: 100, group: 'transport' },
  { id: 'route', label: 'Custom route request', price: null }, // TBC
];

const COUNTRY_CODES = [
  { code: '+1',  label: 'United States (+1)' },
  { code: '+52', label: 'Mexico (+52)' },
  { code: '+1c', label: 'Canada (+1)' },
  { code: '+44', label: 'United Kingdom (+44)' },
  { code: 'other', label: 'Other' },
];

function fmt(n) { return '$' + Math.round(n).toLocaleString(); }

// Format ISO date (yyyy-mm-dd) -> 'July 12, 2026'
function fmtDate(iso) {
  if (!iso) return '';
  const [y, m, d] = iso.split('-').map(Number);
  if (!y || !m || !d) return iso;
  const months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
  return `${months[m - 1]} ${d}, ${y}`;
}

const DATE_TYPE_LABEL = {
  exact: 'Exact date',
  approx: 'Approximate date / I’m not sure yet',
};

function buildWhatsAppMessage({ offer, yacht, date, dateType, guests, extras, total, hasTBC }) {
  const addonNames = extras.length
    ? extras.map(e => (e.price == null ? `${e.label} (price on request)` : e.label)).join(', ')
    : 'None';
  const dateLine = date ? fmtDate(date) : 'To be confirmed';
  const dtype = dateType ? DATE_TYPE_LABEL[dateType] : '—';
  const lines = [
    'Hi ABLY, I’m interested in a private yacht experience.',
    '',
    `Experience: ${offer.name}`,
    `Yacht: ${yacht.name}`,
    `Date: ${dateLine}`,
    `Date type: ${dtype}`,
    `Guests: ${guests}`,
    `Add-ons: ${addonNames}`,
    `Estimated price: ${fmt(total)}${hasTBC ? ' +' : ''}`,
    '',
    'Could you please confirm availability?',
  ];
  return lines.join('\n');
}

const OfferModal = ({ offerKey, onClose, onSwitchOffer }) => {
  const offer = OFFERS[offerKey];
  if (!offer) return null;

  const [step, setStep] = React.useState(0);
  const [yachtIdx, setYachtIdx] = React.useState(0);
  const [photoIdx, setPhotoIdx] = React.useState(0);
  const [date, setDate] = React.useState('');
  const [dateType, setDateType] = React.useState(''); // 'exact' | 'approx'
  const [guests, setGuests] = React.useState(2);
  const [extraHrs, setExtraHrs] = React.useState(0);
  const [services, setServices] = React.useState(() => {
    // default-select all "always" + yacht-specific included
    const init = {};
    INCLUDED_SERVICES.forEach(s => { if (s.always) init[s.id] = true; });
    return init;
  });
  const [extras, setExtras] = React.useState({});
  const [contact, setContact] = React.useState({ name: '', country: '+1', phone: '', email: '', notes: '' });
  // Privacy consent — legally required to start unchecked; gates the final step
  const [consent, setConsent] = React.useState(false);
  const [submitted, setSubmitted] = React.useState(false);
  const [showSummary, setShowSummary] = React.useState(false);

  const yacht = offer.yachts[yachtIdx];

  // Sync default included services to current yacht's available add-ons
  React.useEffect(() => {
    setServices(prev => {
      const next = { ...prev };
      INCLUDED_SERVICES.forEach(s => {
        if (s.always) next[s.id] = next[s.id] !== false;
        else if (yacht.included.includes(s.id)) next[s.id] = next[s.id] !== false;
        else delete next[s.id];
      });
      return next;
    });
    // clamp guests within new yacht's max
    setGuests(g => Math.min(Math.max(1, g), yacht.maxGuests));
    setPhotoIdx(0);
  }, [yacht.id]);

  // Lock body scroll while open
  React.useEffect(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = prev; };
  }, []);

  // Price calc
  const extraGuestCount = Math.max(0, guests - yacht.baseGuests);
  const extraGuestCost = extraGuestCount * yacht.extraGuest;
  const extraHrCost = extraHrs * yacht.extraHr;
  const selectedExtras = EXTRA_SERVICES.filter(e => extras[e.id]);
  const extrasCost = selectedExtras.reduce((s, e) => s + (e.price || 0), 0);
  const total = yacht.price + extraGuestCost + extraHrCost + extrasCost;
  const hasTBC = selectedExtras.some(e => e.price == null);

  const handleNext = () => {
    if (step < 3) setStep(step + 1);
    else if (step === 3) setSubmitted(true);
  };
  const handleBack = () => { if (step > 0) setStep(step - 1); };

  const canNext = (
    step === 0 ? !!yacht :
    step === 1 ? !!date && !!dateType && guests >= 1 :
    step === 2 ? true :
    step === 3 ? contact.name.trim() && contact.phone.trim() && contact.country && consent : false
  );

  const stepLabels = ['Select yacht', 'Date & guests', 'Services & extras', 'Contact'];

  // Apply per-offer accent as CSS vars on the modal root
  const cssVars = {
    '--om-accent': offer.accent,
    '--om-accent-soft': offer.accentSoft,
    '--om-accent-tint': offer.accentTint,
    '--om-accent-border': offer.accentBorder,
  };

  const handleWhatsApp = () => {
    const message = buildWhatsAppMessage({
      offer,
      yacht,
      date,
      dateType,
      guests,
      extras: selectedExtras,
      total,
      hasTBC,
    });
    window.openWhatsApp(message);
  };

  if (submitted) {
    return (
      <div className="om-backdrop" onClick={onClose}>
        <div className="om-modal om-success" style={cssVars} onClick={e => e.stopPropagation()}>
          <button className="om-close" onClick={onClose} aria-label="Close"><Icon name="close" size={18} /></button>
          <div className="om-success-inner">
            <div className="om-success-icon"><Icon name="check" size={36} stroke={2.2} /></div>
            <div className="om-gold-line" />
            <h2>Your yacht request has been sent.</h2>
            <p>Our team reviews your request and confirms availability in the next 24 hours.</p>
            <div className="om-success-card">
              <div className="om-success-row"><span>Experience</span><strong>{offer.name}</strong></div>
              <div className="om-success-row"><span>Yacht</span><strong>{yacht.name}</strong></div>
              <div className="om-success-row"><span>Date</span><strong>{date ? fmtDate(date) : '—'}</strong></div>
              <div className="om-success-row"><span>Date type</span><strong>{dateType ? DATE_TYPE_LABEL[dateType] : '—'}</strong></div>
              <div className="om-success-row"><span>Guests</span><strong>{guests}</strong></div>
              {selectedExtras.length > 0 && (
                <div className="om-success-row"><span>Add-ons</span><strong>{selectedExtras.map(e => e.label).join(', ')}</strong></div>
              )}
              <div className="om-success-row"><span>Estimated total</span><strong>{fmt(total)}{hasTBC ? ' +' : ''}</strong></div>
            </div>
            <div className="om-success-ctas">
              <button className="btn btn-wa" onClick={handleWhatsApp}>
                <Icon name="wa" size={16} /> Continue on WhatsApp
              </button>
              <button className="btn btn-secondary" onClick={onClose}>Close</button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="om-backdrop" onClick={onClose}>
      <div className="om-modal" style={cssVars} onClick={e => e.stopPropagation()}>
        {/* Header */}
        <header className="om-header">
          <div>
            <span className={`badge ${offer.badgeStyle === 'gold' ? 'badge-gold' : offer.badgeStyle === 'outline' ? 'badge-outline' : 'badge-soft'}`} style={offer.badgeStyle === 'soft' ? {background: offer.accentSoft, color: offer.accent} : null}>
              {offer.badge}
            </span>
            <h2>{offer.name} <span className="om-from">From {fmt(offer.baseFrom)}</span></h2>
          </div>
          <div className="om-stepper">
            {stepLabels.map((l, i) => (
              <div key={l} className={`om-stepper-item ${i === step ? 'active' : i < step ? 'done' : ''}`}>
                <span className="om-stepper-dot">{i < step ? <Icon name="check" size={10} stroke={3} /> : i + 1}</span>
                <span className="om-stepper-label">{l}</span>
              </div>
            ))}
          </div>
          <button className="om-close" onClick={onClose} aria-label="Close"><Icon name="close" size={18} /></button>
        </header>

        {/* Body */}
        <div className="om-body">
          {/* Left: yacht info */}
          <aside className="om-left">
            <div className="om-photo">
              {yacht.images && yacht.images.length > 0 ? (
                <div
                  className="om-photo-img"
                  style={{
                    backgroundImage: `url("${window.__resUrl ? window.__resUrl(yacht.images[photoIdx % yacht.images.length]) : encodeURI(yacht.images[photoIdx % yacht.images.length])}")`,
                    backgroundSize: 'cover',
                    backgroundPosition: 'center',
                  }}
                />
              ) : (
                <div className="om-photo-img" style={{ background: yacht.gradient }} />
              )}
              <div className="om-photo-grad" />
              <div className="om-photo-label">{yacht.name} · photo {photoIdx + 1} of {(yacht.images && yacht.images.length) || 4}</div>
              <button className="om-photo-arrow left" onClick={() => {
                const n = (yacht.images && yacht.images.length) || 4;
                setPhotoIdx((photoIdx + n - 1) % n);
              }} aria-label="Previous photo">
                <Icon name="arrowLeft" size={16} />
              </button>
              <button className="om-photo-arrow right" onClick={() => {
                const n = (yacht.images && yacht.images.length) || 4;
                setPhotoIdx((photoIdx + 1) % n);
              }} aria-label="Next photo">
                <Icon name="arrowRight" size={16} />
              </button>
              <div className="om-photo-dots">
                {Array.from({ length: (yacht.images && yacht.images.length) || 4 }).map((_, i) => (
                  <span key={i} className={i === photoIdx ? 'active' : ''} />
                ))}
              </div>
              {offer.flagship && <span className="om-flagship-tag"><Icon name="crown" size={11} /> Flagship</span>}
            </div>
            <div className="om-left-content">
              <h3>{yacht.name}</h3>
              <div className="om-type">{yacht.type}</div>
              <ul className="om-bullets">
                {yacht.bullets.map(b => (
                  <li key={b}><Icon name="check" size={12} stroke={2} /> {b}</li>
                ))}
              </ul>
              <div className="om-yacht-meta">
                <div><span>Capacity</span><strong>Up to {yacht.maxGuests}</strong></div>
                <div><span>Duration</span><strong>{yacht.hours} hours</strong></div>
              </div>
            </div>
          </aside>

          {/* Center: step content */}
          <main className="om-center">
            {step === 0 && (
              <div>
                <h3 className="om-step-title">{offer.flagship ? 'Your flagship yacht' : 'Select your yacht'}</h3>
                <p className="om-step-desc">
                  {offer.flagship
                    ? `The ${offer.name} package features one curated flagship yacht — the pinnacle of comfort and exclusivity in Cabo.`
                    : `These yachts are curated for the ${offer.name} experience. Choose the one that fits your group and atmosphere.`
                  }
                </p>
                <div className={`om-yacht-list ${offer.flagship ? 'flagship' : ''}`}>
                  {offer.yachts.map((y, i) => (
                    <button
                      key={y.id}
                      className={`om-yacht-card ${i === yachtIdx ? 'selected' : ''}`}
                      onClick={() => setYachtIdx(i)}
                    >
                      <div
                        className="om-yacht-thumb"
                        style={y.images && y.images.length > 0 ? {
                          backgroundImage: `url("${window.__resUrl ? window.__resUrl(y.images[0]) : encodeURI(y.images[0])}")`,
                          backgroundSize: 'cover',
                          backgroundPosition: 'center',
                        } : { background: y.gradient }}
                      />
                      <div className="om-yacht-info">
                        <div className="om-yacht-name">{y.name}</div>
                        <div className="om-yacht-sub">{y.type} · up to {y.maxGuests} guests</div>
                        <div className="om-yacht-price">From {fmt(y.price)}</div>
                      </div>
                      <div className="om-yacht-check">
                        {i === yachtIdx ? <Icon name="check" size={14} stroke={2.5} /> : null}
                      </div>
                    </button>
                  ))}
                </div>
                {offer.upsell && (
                  <button className="om-upsell" onClick={() => onSwitchOffer(offer.upsell.target)}>
                    <div>
                      <div className="om-upsell-label">{offer.upsell.label}</div>
                      <div className="om-upsell-target">Switch to {offer.upsell.targetName}</div>
                    </div>
                    <Icon name="arrowRight" size={16} />
                  </button>
                )}
              </div>
            )}

            {step === 1 && (
              <div>
                <h3 className="om-step-title">When are you setting sail?</h3>
                <p className="om-step-desc">Pick your preferred date and group size — we'll confirm final availability with you.</p>

                <div className="om-field">
                  <label>Preferred date <span className="req">*</span></label>
                  <input type="date" className="om-input" value={date} onChange={e => setDate(e.target.value)} />
                  <small>Final availability will be confirmed by our concierge.</small>
                </div>

                <div className="om-field" style={{ marginTop: 22 }}>
                  <label>Is this your exact date or an approximate date? <span className="req">*</span></label>
                  <div className="om-datetype">
                    <button
                      type="button"
                      className={`om-datetype-card ${dateType === 'exact' ? 'selected' : ''}`}
                      onClick={() => setDateType('exact')}
                      aria-pressed={dateType === 'exact'}
                    >
                      <span className="om-datetype-icon"><Icon name="calendar" size={18} stroke={1.7} /></span>
                      <span className="om-datetype-body">
                        <span className="om-datetype-title">Exact date</span>
                        <span className="om-datetype-sub">I’m booking for this specific day.</span>
                      </span>
                      <span className="om-datetype-radio" aria-hidden="true">
                        {dateType === 'exact' && <Icon name="check" size={11} stroke={3} />}
                      </span>
                    </button>
                    <button
                      type="button"
                      className={`om-datetype-card ${dateType === 'approx' ? 'selected' : ''}`}
                      onClick={() => setDateType('approx')}
                      aria-pressed={dateType === 'approx'}
                    >
                      <span className="om-datetype-icon"><Icon name="calendarApprox" size={18} stroke={1.7} /></span>
                      <span className="om-datetype-body">
                        <span className="om-datetype-title">Approximate date</span>
                        <span className="om-datetype-sub">I’m not sure yet — still planning.</span>
                      </span>
                      <span className="om-datetype-radio" aria-hidden="true">
                        {dateType === 'approx' && <Icon name="check" size={11} stroke={3} />}
                      </span>
                    </button>
                  </div>
                  {!dateType && date && (
                    <small>Pick one so our team knows whether to lock the day or keep options open.</small>
                  )}
                </div>

                <div className="om-field" style={{ marginTop: 28 }}>
                  <label>Number of guests</label>
                  <div className="om-counter">
                    <button onClick={() => setGuests(Math.max(1, guests - 1))} disabled={guests <= 1} aria-label="Decrease">
                      <Icon name="arrowLeft" size={16} />
                    </button>
                    <div className="om-counter-val">
                      <strong>{guests}</strong>
                      <span>{guests === 1 ? 'guest' : 'guests'}</span>
                    </div>
                    <button onClick={() => setGuests(Math.min(yacht.maxGuests, guests + 1))} disabled={guests >= yacht.maxGuests} aria-label="Increase">
                      <Icon name="arrowRight" size={16} />
                    </button>
                  </div>
                  <small>
                    Up to {yacht.baseGuests} guests are included in the base price.
                    {' '}Additional guests are <strong>{fmt(yacht.extraGuest)} each</strong>, up to {yacht.maxGuests}.
                  </small>
                  {extraGuestCount > 0 && (
                    <div className="om-callout">
                      <Icon name="sparkle" size={14} stroke={2} />
                      <span>{extraGuestCount} extra {extraGuestCount === 1 ? 'guest' : 'guests'} · +{fmt(extraGuestCost)}</span>
                    </div>
                  )}
                </div>
              </div>
            )}

            {step === 2 && (
              <div>
                <h3 className="om-step-title">Services & Extras</h3>
                <p className="om-step-desc">Customize what's onboard. Included services are already in your price — extras enhance your day.</p>

                <div className="om-section-label">Included</div>
                <div className="om-svc-grid">
                  {INCLUDED_SERVICES
                    .filter(s => s.always || yacht.included.includes(s.id))
                    .map(s => (
                      <label key={s.id} className={`om-svc ${services[s.id] ? 'checked' : ''}`}>
                        <input
                          type="checkbox"
                          checked={!!services[s.id]}
                          onChange={e => setServices({ ...services, [s.id]: e.target.checked })}
                        />
                        <span className="om-check">
                          {services[s.id] && <Icon name="check" size={11} stroke={3} />}
                        </span>
                        <span className="om-svc-label">{s.label}</span>
                      </label>
                    ))}
                </div>

                <div className="om-section-label" style={{ marginTop: 32 }}>Extras</div>

                {/* Extra hours */}
                <div className="om-extra-hours">
                  <div>
                    <div className="om-extra-title">Extra hours</div>
                    <div className="om-extra-sub">{fmt(yacht.extraHr)} per hour</div>
                  </div>
                  <div className="om-counter compact">
                    <button onClick={() => setExtraHrs(Math.max(0, extraHrs - 1))} disabled={extraHrs <= 0}>
                      <Icon name="arrowLeft" size={14} />
                    </button>
                    <div className="om-counter-val">
                      <strong>{extraHrs}</strong>
                      <span>{extraHrs === 1 ? 'hour' : 'hours'}</span>
                    </div>
                    <button onClick={() => setExtraHrs(Math.min(10, extraHrs + 1))} disabled={extraHrs >= 10}>
                      <Icon name="arrowRight" size={14} />
                    </button>
                  </div>
                </div>
                {extraHrs > 0 && (
                  <div className="om-callout" style={{ marginTop: 10 }}>
                    <Icon name="clock" size={14} />
                    <span>{extraHrs} × {fmt(yacht.extraHr)} = +{fmt(extraHrCost)}</span>
                  </div>
                )}

                <div className="om-extras-grid">
                  {EXTRA_SERVICES.map(e => (
                    <label key={e.id} className={`om-extra-card ${extras[e.id] ? 'checked' : ''}`}>
                      <input
                        type="checkbox"
                        checked={!!extras[e.id]}
                        onChange={ev => {
                          const next = { ...extras, [e.id]: ev.target.checked };
                          // Grouped extras (e.g. transport zones) are mutually exclusive
                          if (ev.target.checked && e.group) {
                            EXTRA_SERVICES.forEach(o => {
                              if (o.group === e.group && o.id !== e.id) delete next[o.id];
                            });
                          }
                          setExtras(next);
                        }}
                      />
                      <div className="om-extra-card-body">
                        <div className="om-extra-card-name">{e.label}</div>
                        {e.sub && <div className="om-extra-card-sub">{e.sub}</div>}
                        <div className="om-extra-card-price">{e.price ? fmt(e.price) : 'Price to be confirmed'}</div>
                      </div>
                      <span className="om-check">
                        {extras[e.id] && <Icon name="check" size={11} stroke={3} />}
                      </span>
                    </label>
                  ))}
                </div>
              </div>
            )}

            {step === 3 && (
              <div>
                <h3 className="om-step-title">Your contact details</h3>
                <p className="om-step-desc">Our concierge will reach out personally — typically within a few hours.</p>
                <div className="om-form">
                  <div className="om-field">
                    <label>Full name <span className="req">*</span></label>
                    <input className="om-input" placeholder="Your full name" value={contact.name} onChange={e => setContact({...contact, name: e.target.value})} />
                  </div>
                  <div className="om-field-row">
                    <div className="om-field">
                      <label>Country code <span className="req">*</span></label>
                      <select className="om-input" value={contact.country} onChange={e => setContact({...contact, country: e.target.value})}>
                        {COUNTRY_CODES.map(c => <option key={c.code} value={c.code}>{c.label}</option>)}
                      </select>
                    </div>
                    <div className="om-field" style={{ flex: 2 }}>
                      <label>Phone number <span className="req">*</span></label>
                      <input className="om-input" placeholder="e.g. 555 123 4567" value={contact.phone} onChange={e => setContact({...contact, phone: e.target.value})} />
                    </div>
                  </div>
                  <div className="om-field">
                    <label>Email <span className="opt">(optional)</span></label>
                    <input className="om-input" type="email" placeholder="you@email.com" value={contact.email} onChange={e => setContact({...contact, email: e.target.value})} />
                  </div>
                  <div className="om-field">
                    <label>Additional notes or special requests <span className="opt">(optional)</span></label>
                    <textarea className="om-input" rows={3} placeholder="Anything special about your day?" value={contact.notes} onChange={e => setContact({...contact, notes: e.target.value})} />
                  </div>
                </div>
                <label className="om-consent">
                  <input type="checkbox" checked={consent} onChange={e => setConsent(e.target.checked)} />
                  <span>I have read and accept the <a href="privacy.html" target="_blank" rel="noopener">Privacy Notice</a> for handling my reservation details.</span>
                </label>
                <p className="om-reassure">
                  Our concierge will review your selected yacht, date, guests, and extras before contacting you with availability and final pricing.
                </p>
              </div>
            )}
          </main>

          {/* Right: live summary */}
          <aside className={`om-right ${showSummary ? 'mobile-open' : ''}`}>
            <div className="om-summary-head">
              <div>
                <div className="om-summary-label">Estimated total</div>
                <div className="om-summary-total">{fmt(total)}{hasTBC ? ' +' : ''}</div>
                <div className="om-summary-sub">Final pricing confirmed by concierge.</div>
              </div>
              <button className="om-summary-toggle" onClick={() => setShowSummary(false)} aria-label="Close summary">
                <Icon name="close" size={16} />
              </button>
            </div>
            <div className="om-gold-line" />
            <div className="om-summary-list">
              <div className="om-sum-row">
                <span>{yacht.name}</span>
                <strong>{fmt(yacht.price)}</strong>
              </div>
              <div className="om-sum-row sub">
                <span>Date</span>
                <span>{date ? fmtDate(date) : '—'}</span>
              </div>
              <div className="om-sum-row sub">
                <span>Date type</span>
                <span>{dateType ? (dateType === 'exact' ? 'Exact' : 'Approximate') : '—'}</span>
              </div>
              <div className="om-sum-row sub">
                <span>Guests · included</span>
                <span>{guests} · {Math.min(guests, yacht.baseGuests)}</span>
              </div>
              {extraGuestCount > 0 && (
                <div className="om-sum-row">
                  <span>Extra guests · {extraGuestCount} × {fmt(yacht.extraGuest)}</span>
                  <strong>+{fmt(extraGuestCost)}</strong>
                </div>
              )}
              <div className="om-sum-row sub">
                <span>Base duration</span>
                <span>{yacht.hours} hours</span>
              </div>
              {extraHrs > 0 && (
                <div className="om-sum-row">
                  <span>Extra hours · {extraHrs} × {fmt(yacht.extraHr)}</span>
                  <strong>+{fmt(extraHrCost)}</strong>
                </div>
              )}

              <div className="om-sum-divider" />
              <div className="om-sum-section">Included</div>
              {INCLUDED_SERVICES
                .filter(s => services[s.id])
                .map(s => (
                  <div key={s.id} className="om-sum-row sub">
                    <span>· {s.label}</span>
                    <span className="om-incl">Included</span>
                  </div>
                ))}

              {selectedExtras.length > 0 && (
                <>
                  <div className="om-sum-divider" />
                  <div className="om-sum-section">Extras</div>
                  {selectedExtras.map(e => (
                    <div key={e.id} className="om-sum-row">
                      <span>· {e.label}</span>
                      <strong>{e.price ? '+' + fmt(e.price) : 'TBC'}</strong>
                    </div>
                  ))}
                </>
              )}
            </div>
            <div className="om-summary-foot">
              <div className="om-sum-row total">
                <span>Estimated total</span>
                <strong>{fmt(total)}{hasTBC ? ' +' : ''}</strong>
              </div>
            </div>
          </aside>
        </div>

        {/* Footer */}
        <footer className="om-footer">
          <button className="om-back" onClick={handleBack} disabled={step === 0} style={{ opacity: step === 0 ? 0.4 : 1 }}>
            <Icon name="arrowLeft" size={14} /> Back
          </button>

          <button className="om-mobile-summary" onClick={() => setShowSummary(true)}>
            <span className="lab">View breakdown</span>
            <strong>{fmt(total)}{hasTBC ? ' +' : ''}</strong>
          </button>

          <button className="om-next" onClick={handleNext} disabled={!canNext} style={{ opacity: canNext ? 1 : 0.5 }}>
            {step === 3 ? 'Request Availability & Final Quote' : step === 2 ? 'Continue to contact' : step === 1 ? 'Continue' : 'Continue'}
            <Icon name="arrowRight" size={14} />
          </button>
        </footer>
      </div>
    </div>
  );
};

window.OfferModal = OfferModal;
