// booking.jsx — full port of the production booking widget for the preview.
// Mirrors src/components/booking/{BookingWidget,BookingCalendar,BookingForm}.tsx
// but standalone: no framer-motion, lucide, react-hook-form, zod, tailwind.
// All UX preserved: state machine, slot cache, COT timezone, slot conflicts, errors.

(() => {
  const BASE_URL = 'https://egljtgwpkhqkudzitkka.supabase.co/functions/v1';
  const MONTH_NAMES = ['January','February','March','April','May','June','July','August','September','October','November','December'];
  const MONTH_SHORT = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  const DAY_NAMES = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
  const DAY_SHORT = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];

  const padZ = (n) => String(n).padStart(2, '0');
  const toDateStr = (y, m, d) => `${y}-${padZ(m + 1)}-${padZ(d)}`;
  const todayStr = () => { const d = new Date(); return toDateStr(d.getFullYear(), d.getMonth(), d.getDate()); };
  const getCOTHour = (utcISO) => (new Date(utcISO).getUTCHours() - 5 + 24) % 24;
  const toCOT = (utcISO) => {
    const d = new Date(utcISO);
    const h24 = getCOTHour(utcISO);
    const min = d.getUTCMinutes();
    const period = h24 >= 12 ? 'PM' : 'AM';
    const h = h24 % 12 || 12;
    return `${h}:${padZ(min)} ${period}`;
  };
  const getCalendarCells = (year, month) => {
    const firstDow = new Date(year, month, 1).getDay();
    const startOffset = (firstDow + 6) % 7;
    const daysInMonth = new Date(year, month + 1, 0).getDate();
    return [...Array(startOffset).fill(null), ...Array.from({ length: daysInMonth }, (_, i) => i + 1)];
  };
  const formatConfirmedTime = (iso) => {
    const d = new Date(iso);
    const h24 = (d.getUTCHours() - 5 + 24) % 24;
    const min = d.getUTCMinutes();
    const period = h24 >= 12 ? 'PM' : 'AM';
    const h = h24 % 12 || 12;
    const utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
    return `${DAY_SHORT[utcDate.getUTCDay()]}, ${MONTH_SHORT[utcDate.getUTCMonth()]} ${utcDate.getUTCDate()} · ${h}:${padZ(min)} ${period} COT`;
  };
  const groupSlotsByPeriod = (slots) => {
    const morning = [], afternoon = [];
    slots.forEach((s) => (getCOTHour(s.startTime) < 12 ? morning : afternoon).push(s));
    const out = [];
    if (morning.length) out.push({ label: 'Morning', slots: morning });
    if (afternoon.length) out.push({ label: 'Afternoon', slots: afternoon });
    return out;
  };

  // Module-level caches (mirror prod behavior)
  const monthCache = new Map();
  const slotCache = new Map();
  const MONTH_TTL = 10 * 60 * 1000;
  const SLOT_TTL = 3 * 60 * 1000;

  // Inline icons (replacing lucide-react)
  const I = {
    Clock: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" /></svg>),
    ChevronL: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...p}><polyline points="15 18 9 12 15 6" /></svg>),
    ChevronR: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...p}><polyline points="9 18 15 12 9 6" /></svg>),
    ArrowL: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...p}><line x1="19" y1="12" x2="5" y2="12" /><polyline points="12 19 5 12 12 5" /></svg>),
    Plus: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" {...p}><line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /></svg>),
    Spinner: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...p} style={{ ...(p.style || {}), animation: 'bk-spin 1s linear infinite' }}><path d="M21 12a9 9 0 11-6.219-8.56" /></svg>),
    CalCheck: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="4" width="18" height="18" rx="2" /><line x1="16" y1="2" x2="16" y2="6" /><line x1="8" y1="2" x2="8" y2="6" /><line x1="3" y1="10" x2="21" y2="10" /><polyline points="8 14 11 17 16 12" /></svg>),
    External: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" /><polyline points="15 3 21 3 21 9" /><line x1="10" y1="14" x2="21" y2="3" /></svg>),
  };

  // ── CSS injected once (preview aesthetic: light + violet) ────────────────
  const CSS = `
    .bk-root { min-height: 280px; display: flex; flex-direction: column; }
    .bk-fade-enter { animation: bk-fade-slide 280ms cubic-bezier(0.16,1,0.3,1) both; }
    .bk-slot-enter { animation: bk-slot-in 220ms cubic-bezier(0.16,1,0.3,1) both; }
    .bk-panel-enter { animation: bk-panel-in 280ms cubic-bezier(0.16,1,0.3,1) both; }
    @keyframes bk-fade-slide { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
    @keyframes bk-slot-in { from { opacity: 0; transform: translateY(6px) scale(0.97); } to { opacity: 1; transform: none; } }
    @keyframes bk-panel-in { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: none; } }
    @keyframes bk-spin { to { transform: rotate(360deg); } }
    @keyframes bk-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.85; } }
    @keyframes bk-ripple { 0% { opacity: 0.35; transform: scale(0.4); } 100% { opacity: 0; transform: scale(2.2); } }
    @keyframes bk-check { from { stroke-dashoffset: 32; } to { stroke-dashoffset: 0; } }
    .bk-btn-tap:active:not(:disabled) { transform: scale(0.95); transition: transform 80ms ease-out; }
    .bk-btn-day-tap:active:not(:disabled) { transform: scale(0.85); transition: transform 80ms cubic-bezier(0.3,0,0.2,1); }
    .bk-slot { width: 100%; border-radius: 8px; border: 1px solid var(--hairline); padding: 6px 4px; font-size: 12.5px; font-weight: 500; font-variant-numeric: tabular-nums; text-align: center; white-space: nowrap; background: color-mix(in srgb, var(--fg) 3%, transparent); color: var(--fg-muted); cursor: pointer; transition: all 180ms ease; font-family: inherit; }
    .bk-slot:hover:not(.bk-slot-sel) { border-color: var(--eyebrow-bd); background: var(--eyebrow-bg); color: var(--accent); transform: translateY(-1px); }
    .bk-slot.bk-slot-sel { border-color: var(--accent); background: var(--accent); color: var(--platinum); font-weight: 600; transform: scale(1.02); box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 30%, transparent); }
    .bk-day { height: 30px; width: 30px; border-radius: 8px; font-size: 12.5px; display: inline-flex; align-items: center; justify-content: center; transition: all 150ms ease; background: transparent; border: none; color: var(--fg); cursor: pointer; position: relative; overflow: hidden; padding: 0; font-family: inherit; }
    .bk-day:hover:not(:disabled):not(.bk-day-sel) { background: var(--eyebrow-bg); color: var(--accent); }
    .bk-day:disabled { color: var(--fg-faint); cursor: not-allowed; text-decoration: line-through; opacity: 0.6; }
    .bk-day.bk-day-today:not(.bk-day-sel) { color: var(--accent); font-weight: 600; }
    .bk-day.bk-day-sel { background: var(--accent); color: var(--platinum); font-weight: 600; box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 35%, transparent); }
    .bk-day-today-dot { position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); height: 3px; width: 3px; border-radius: 999px; background: var(--accent); }
    .bk-day-ripple { position: absolute; inset: 0; border-radius: 9px; pointer-events: none; animation: bk-ripple 280ms ease-out both; background: radial-gradient(circle, color-mix(in srgb, var(--accent) 45%, transparent) 0%, transparent 70%); }
    .bk-monthnav { height: 30px; width: 30px; border-radius: 8px; border: 1px solid var(--hairline); background: transparent; color: var(--fg-muted); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; transition: all 150ms ease; }
    .bk-monthnav:hover:not(:disabled) { border-color: var(--eyebrow-bd); background: var(--eyebrow-bg); color: var(--accent); }
    .bk-monthnav:disabled { opacity: 0.3; pointer-events: none; }
    .bk-input { width: 100%; border-radius: 10px; border: 1px solid var(--hairline); background: color-mix(in srgb, var(--fg) 3%, transparent); padding: 10px 14px; font-size: 14px; color: var(--fg); transition: all 150ms ease; outline: none; font-family: inherit; box-sizing: border-box; }
    .bk-input::placeholder { color: var(--fg-faint); }
    .bk-input:hover { border-color: var(--eyebrow-bd); }
    .bk-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); }
    .bk-input:disabled { opacity: 0.5; cursor: not-allowed; }
    .bk-back { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--fg-muted); background: transparent; border: none; padding: 0; cursor: pointer; transition: color 150ms ease; margin-bottom: 14px; font-family: inherit; }
    .bk-back:hover { color: var(--accent); }
    .bk-back:hover .bk-back-icon { transform: translateX(-3px); }
    .bk-back-icon { transition: transform 180ms ease; display: inline-flex; }
    .bk-submit { position: relative; flex: 2 1 0; border-radius: 12px; padding: 13px 16px; font-size: 14px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: 8px; overflow: hidden; cursor: pointer; border: none; background: var(--accent); color: var(--platinum); transition: all 200ms ease; font-family: inherit; }
    .bk-submit:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 14px 30px color-mix(in srgb, var(--accent) 32%, transparent); background: var(--violet-soft); }
    .bk-submit:active:not(:disabled) { transform: scale(0.98); }
    .bk-submit:disabled { opacity: 0.6; cursor: not-allowed; }
    .bk-secondary { flex: 1 1 0; border-radius: 12px; padding: 13px 16px; font-size: 14px; font-weight: 500; background: transparent; border: 1px solid var(--eyebrow-bd); color: var(--accent); cursor: pointer; transition: all 150ms ease; font-family: inherit; }
    .bk-secondary:hover:not(:disabled) { background: var(--eyebrow-bg); }
    .bk-skel { height: 36px; border-radius: 10px; background: var(--eyebrow-bg); animation: bk-pulse 1.4s ease-in-out infinite; }
    .bk-card { background: transparent; padding: 0; color: var(--fg); font-family: var(--font-body, inherit); }
    .bk-cal-layout { display: grid; grid-template-columns: minmax(0, 250px) minmax(0, 1fr); gap: 22px; }
    .bk-cal-left { display: flex; flex-direction: column; gap: 8px; }
    .bk-cal-right { border-left: 1px solid var(--hairline); padding-left: 22px; display: flex; flex-direction: column; min-width: 0; }
    @media (max-width: 720px) {
      .bk-cal-layout { grid-template-columns: 1fr; }
      .bk-cal-right { border-left: none; border-top: 1px solid var(--hairline); padding-left: 0; padding-top: 16px; margin-top: 4px; }
    }
  `;

  // ── Day cell with ripple ────────────────────────────────────────────────
  function DayCell({ day, dateStr, isDisabled, isToday, isSelected, onSelect }) {
    const [rippling, setRippling] = React.useState(false);
    const click = () => {
      if (isDisabled) return;
      setRippling(true);
      setTimeout(() => { setRippling(false); onSelect(); }, 120);
    };
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <button type="button" disabled={isDisabled} onClick={click}
          aria-label={`${dateStr}${isSelected ? ', selected' : ''}`} aria-pressed={isSelected}
          className={`bk-day bk-btn-day-tap${isToday ? ' bk-day-today' : ''}${isSelected ? ' bk-day-sel' : ''}`}>
          {day}
          {rippling && (
            <span className="bk-day-ripple" style={{ background: isSelected
              ? 'radial-gradient(circle, rgba(66,83,175,0.60) 0%, transparent 70%)'
              : 'radial-gradient(circle, rgba(235,152,89,0.55) 0%, transparent 70%)' }} />
          )}
          {isToday && !isSelected && <span className="bk-day-today-dot" />}
        </button>
      </div>
    );
  }

  // ── Calendar ────────────────────────────────────────────────────────────
  function BookingCalendar({ selectedDate, selectedSlot, onDateSelect, onSlotSelect }) {
    const today = todayStr();
    const now = new Date();
    const [viewYear, setViewYear] = React.useState(() => now.getFullYear());
    const [viewMonth, setViewMonth] = React.useState(() => now.getMonth());
    const [availableDates, setAvailableDates] = React.useState(new Set());
    const [loadingMonth, setLoadingMonth] = React.useState(false);
    const [monthFetchFailed, setMonthFetchFailed] = React.useState(false);
    const [slots, setSlots] = React.useState([]);
    const [loadingSlots, setLoadingSlots] = React.useState(false);
    const [slotsError, setSlotsError] = React.useState(false);
    const [slotsKey, setSlotsKey] = React.useState(0);
    const abortRef = React.useRef(null);

    const fetchMonth = React.useCallback(async (year, month) => {
      const key = `${year}-${padZ(month + 1)}`;
      const cached = monthCache.get(key);
      if (cached && Date.now() - cached.ts < MONTH_TTL) { setAvailableDates(cached.dates); return; }
      setLoadingMonth(true);
      setMonthFetchFailed(false);
      try {
        const res = await fetch(`${BASE_URL}/ms-bookings-slots?month=${key}`);
        if (!res.ok) { setMonthFetchFailed(true); return; }
        const data = await res.json();
        const dateSet = new Set(data.available_dates ?? []);
        monthCache.set(key, { dates: dateSet, ts: Date.now() });
        setAvailableDates(dateSet);
      } catch { setMonthFetchFailed(true); }
      finally { setLoadingMonth(false); }
    }, []);

    React.useEffect(() => { fetchMonth(viewYear, viewMonth); }, [viewYear, viewMonth, fetchMonth]);

    React.useEffect(() => {
      if (!selectedDate) { setSlots([]); return; }
      if (abortRef.current) abortRef.current.abort();
      const cached = slotCache.get(selectedDate);
      if (cached && Date.now() - cached.ts < SLOT_TTL) {
        setSlots(cached.slots.filter((s) => s.available));
        setSlotsKey((k) => k + 1);
        setLoadingSlots(false);
        setSlotsError(false);
        return;
      }
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      setLoadingSlots(true);
      setSlotsError(false);
      fetch(`${BASE_URL}/ms-bookings-slots?date=${selectedDate}`, { signal: ctrl.signal })
        .then((res) => { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json(); })
        .then((data) => {
          const all = data.slots ?? [];
          slotCache.set(selectedDate, { slots: all, ts: Date.now() });
          setSlots(all.filter((s) => s.available));
          setSlotsKey((k) => k + 1);
        })
        .catch((err) => { if (err.name !== 'AbortError') setSlotsError(true); })
        .finally(() => setLoadingSlots(false));
    }, [selectedDate]);

    const isPrevDisabled = viewYear === now.getFullYear() && viewMonth === now.getMonth();
    const prevMonth = () => {
      if (viewMonth === 0) { setViewMonth(11); setViewYear((y) => y - 1); }
      else setViewMonth((m) => m - 1);
    };
    const nextMonth = () => {
      if (viewMonth === 11) { setViewMonth(0); setViewYear((y) => y + 1); }
      else setViewMonth((m) => m + 1);
    };

    const cells = getCalendarCells(viewYear, viewMonth);
    const nextAvail = (() => {
      if (!selectedDate || availableDates.size === 0) return null;
      const sorted = [...availableDates].filter((d) => d > selectedDate).sort();
      return sorted[0] ?? null;
    })();
    const slotGroups = groupSlotsByPeriod(slots);

    return (
      <div className="bk-cal-layout">
        {/* Left: calendar */}
        <div className="bk-cal-left">
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--fg-faint)' }}>
            <I.Clock style={{ height: 13, width: 13 }} />
            <span>Colombia Time (COT, UTC-5)</span>
          </div>

          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <button type="button" className="bk-monthnav bk-btn-tap" onClick={prevMonth} disabled={isPrevDisabled} aria-label="Previous month">
              <I.ChevronL style={{ height: 14, width: 14 }} />
            </button>
            <span style={{ fontSize: 14, fontWeight: 600, color: 'var(--fg)' }}>{MONTH_NAMES[viewMonth]} {viewYear}</span>
            <button type="button" className="bk-monthnav bk-btn-tap" onClick={nextMonth} aria-label="Next month">
              <I.ChevronR style={{ height: 14, width: 14 }} />
            </button>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)' }}>
            {DAY_NAMES.map((d) => (
              <div key={d} style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--fg-faint)', textAlign: 'center', fontWeight: 600, padding: '4px 0' }}>{d}</div>
            ))}
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', rowGap: 2, justifyItems: 'center' }}>
            {cells.map((day, i) => {
              if (day === null) return <div key={'e' + i} />;
              const dateStr = toDateStr(viewYear, viewMonth, day);
              const isPast = dateStr < today;
              const isToday = dateStr === today;
              const isAvailable = !loadingMonth && (monthFetchFailed || availableDates.has(dateStr));
              const isSelected = dateStr === selectedDate;
              const isDisabled = isPast || (!loadingMonth && !monthFetchFailed && !isAvailable);
              return (
                <DayCell key={dateStr} day={day} dateStr={dateStr}
                  isDisabled={isDisabled} isToday={isToday} isSelected={isSelected}
                  onSelect={() => onDateSelect(dateStr)} />
              );
            })}
          </div>
        </div>

        {/* Right: slots */}
        <div className={`bk-cal-right${selectedDate ? ' bk-panel-enter' : ''}`}>
          {!selectedDate && (
            <p style={{ fontSize: 13, color: 'var(--fg-faint)', margin: 0, alignSelf: 'center', textAlign: 'center', paddingTop: 32 }}>Select a date to see available times.</p>
          )}

          {selectedDate && (<>
            <p style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--fg-faint)', fontWeight: 600, margin: '0 0 12px' }}>Available times</p>

            {loadingSlots && (
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
                {Array.from({ length: 9 }).map((_, i) => (
                  <div key={i} className="bk-skel" style={{ animationDelay: `${i * 60}ms` }} />
                ))}
              </div>
            )}

            {!loadingSlots && slotsError && (<p style={{ fontSize: 13, color: 'var(--fg-muted)', margin: 0 }}>Could not load times. Please try again.</p>)}

            {!loadingSlots && !slotsError && slots.length === 0 && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <p style={{ fontSize: 13, color: 'var(--fg-muted)', margin: 0 }}>No availability.</p>
                {nextAvail && (
                  <button type="button" onClick={() => onDateSelect(nextAvail)}
                    style={{ fontSize: 13, color: 'var(--accent)', background: 'transparent', border: 'none', padding: 0, cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit' }}>
                    Next: {nextAvail}
                  </button>
                )}
              </div>
            )}

            {!loadingSlots && slots.length > 0 && (
              <div key={slotsKey} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                {slotGroups.map((g) => (
                  <div key={g.label}>
                    {slotGroups.length > 1 && (
                      <p style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'var(--fg-faint)', fontWeight: 600, margin: '0 0 6px' }}>{g.label}</p>
                    )}
                    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
                      {g.slots.map((slot, idx) => (
                        <button key={slot.id} type="button" aria-pressed={selectedSlot?.id === slot.id}
                          onClick={() => onSlotSelect(slot)}
                          className={`bk-slot bk-slot-enter${selectedSlot?.id === slot.id ? ' bk-slot-sel' : ''}`}
                          style={{ animationDelay: `${idx * 30 + 40}ms` }}>
                          {toCOT(slot.startTime)}
                        </button>
                      ))}
                    </div>
                  </div>
                ))}
              </div>
            )}
          </>)}
        </div>
      </div>
    );
  }

  // ── Slot summary + countdown ────────────────────────────────────────────
  function SlotSummary({ slot }) {
    const d = new Date(slot.startTime);
    const h24 = (d.getUTCHours() - 5 + 24) % 24;
    const min = d.getUTCMinutes();
    const period = h24 >= 12 ? 'PM' : 'AM';
    const h = h24 % 12 || 12;
    const timeLabel = `${h}:${padZ(min)} ${period} COT`;
    const utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
    const dateLabel = `${DAY_SHORT[utcDate.getUTCDay()]}, ${MONTH_SHORT[utcDate.getUTCMonth()]} ${utcDate.getUTCDate()}`;
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, borderRadius: 10, border: '1px solid var(--eyebrow-bd)', background: 'var(--eyebrow-bg)', padding: '10px 14px' }}>
        <div style={{ height: 8, width: 8, borderRadius: 999, background: 'var(--accent)', flexShrink: 0 }} />
        <span style={{ fontSize: 14, color: 'var(--fg)', fontWeight: 600 }}>{dateLabel} · {timeLabel}</span>
      </div>
    );
  }

  function SlotTimer({ startedAt }) {
    const [remaining, setRemaining] = React.useState(10 * 60);
    React.useEffect(() => {
      const id = setInterval(() => {
        setRemaining(Math.max(0, 10 * 60 - Math.floor((Date.now() - startedAt) / 1000)));
      }, 1000);
      return () => clearInterval(id);
    }, [startedAt]);
    if (remaining === 0) return <p style={{ fontSize: 12, color: 'var(--accent)', margin: 0 }}>Slot may no longer be available; submit to confirm.</p>;
    const m = Math.floor(remaining / 60);
    const s = remaining % 60;
    return <p style={{ fontSize: 12, color: 'var(--fg-faint)', fontVariantNumeric: 'tabular-nums', margin: 0 }}>Slot held for {m}:{padZ(s)}</p>;
  }

  // ── Field ───────────────────────────────────────────────────────────────
  function Field({ label, error, optional, children }) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.1em', color: 'var(--fg-faint)', fontWeight: 600 }}>
          {label}
          {optional && <span style={{ textTransform: 'none', letterSpacing: 'normal', fontSize: 10, opacity: 0.7 }}>(optional)</span>}
        </label>
        {children}
        {error && <p role="alert" style={{ fontSize: 12, color: '#c0563f', margin: 0 }}>{error}</p>}
      </div>
    );
  }

  // ── Booking form ────────────────────────────────────────────────────────
  function BookingForm({ slot, onConfirmed, onSlotConflict, onError, onBack }) {
    const [firstName, setFirstName] = React.useState('');
    const [lastName, setLastName] = React.useState('');
    const [email, setEmail] = React.useState('');
    const [company, setCompany] = React.useState('');
    const [notes, setNotes] = React.useState('');
    const [showNotes, setShowNotes] = React.useState(false);
    const [errs, setErrs] = React.useState({});
    const [submitting, setSubmitting] = React.useState(false);
    const [timerStart] = React.useState(() => Date.now());

    const validate = () => {
      const e = {};
      if (!firstName.trim()) e.firstName = 'Required';
      else if (firstName.length > 60) e.firstName = 'Too long';
      if (!lastName.trim()) e.lastName = 'Required';
      else if (lastName.length > 60) e.lastName = 'Too long';
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) e.email = 'Invalid email';
      if (company.length > 100) e.company = 'Too long';
      if (notes.length > 500) e.notes = 'Too long';
      return e;
    };

    const submit = async (ev) => {
      ev.preventDefault();
      const e = validate();
      setErrs(e);
      if (Object.keys(e).length) return;
      setSubmitting(true);
      try {
        const d = new Date(slot.startTime);
        const h24 = (d.getUTCHours() - 5 + 24) % 24;
        const cotMin = d.getUTCMinutes();
        const res = await fetch(`${BASE_URL}/ms-bookings-book`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            date: `${d.getUTCFullYear()}-${padZ(d.getUTCMonth() + 1)}-${padZ(d.getUTCDate())}`,
            time: `${padZ(h24)}:${padZ(cotMin)}`,
            firstName: firstName.trim(),
            lastName: lastName.trim(),
            email: email.trim(),
            company: company.trim() || undefined,
            notes: notes.trim() || undefined,
          }),
        });
        if (res.status === 409) { onSlotConflict(); return; }
        if (!res.ok) {
          const body = await res.json().catch(() => ({}));
          onError(body.error || 'SERVER_ERROR'); return;
        }
        const result = await res.json();
        onConfirmed({ bookingId: result.bookingId, startTime: result.startTime, calendarUrl: result.calendarUrl }, email);
      } catch (err) {
        onError('NETWORK_ERROR');
      } finally {
        setSubmitting(false);
      }
    };

    return (
      <form onSubmit={submit} noValidate style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {/* slot summary + timer side by side */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
          <div style={{ flex: '1 1 320px' }}><SlotSummary slot={slot} /></div>
          <SlotTimer startedAt={timerStart} />
        </div>

        {/* 2-column grid for ALL fields to use horizontal space */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 10 }}>
          <Field label="First Name" error={errs.firstName}>
            <input className="bk-input" type="text" autoComplete="given-name" placeholder="Jane"
              value={firstName} onChange={(e) => setFirstName(e.target.value)} disabled={submitting} />
          </Field>
          <Field label="Last Name" error={errs.lastName}>
            <input className="bk-input" type="text" autoComplete="family-name" placeholder="Doe"
              value={lastName} onChange={(e) => setLastName(e.target.value)} disabled={submitting} />
          </Field>
          <Field label="Work Email" error={errs.email}>
            <input className="bk-input" type="email" autoComplete="email" placeholder="jane@company.com"
              value={email} onChange={(e) => setEmail(e.target.value)} disabled={submitting} />
          </Field>
          <Field label="Company" optional error={errs.company}>
            <input className="bk-input" type="text" autoComplete="organization" placeholder="Acme Corp"
              value={company} onChange={(e) => setCompany(e.target.value)} disabled={submitting} />
          </Field>
        </div>

        {!showNotes ? (
          <button type="button" onClick={() => setShowNotes(true)}
            style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 13, color: 'var(--accent)', background: 'transparent', border: 'none', padding: 0, cursor: 'pointer', alignSelf: 'flex-start', fontFamily: 'inherit', fontWeight: 500 }}>
            <I.Plus style={{ height: 13, width: 13 }} />
            Add notes
          </button>
        ) : (
          <Field label="Notes" optional error={errs.notes}>
            <textarea className="bk-input" rows={2} placeholder="Anything specific to discuss?"
              value={notes} onChange={(e) => setNotes(e.target.value)} disabled={submitting} style={{ resize: 'none' }} />
          </Field>
        )}

        <div style={{ display: 'flex', gap: 10, paddingTop: 2 }}>
          <button type="button" onClick={onBack} disabled={submitting} className="bk-secondary bk-btn-tap">Back</button>
          <button type="submit" disabled={submitting} className="bk-submit">
            {submitting ? (<><I.Spinner style={{ height: 14, width: 14 }} /> Confirming...</>) : 'Confirm Meeting'}
          </button>
        </div>
      </form>
    );
  }

  // ── Phase screens ───────────────────────────────────────────────────────
  function BackHeader({ label, onClick }) {
    return (
      <button type="button" onClick={onClick} className="bk-back">
        <span className="bk-back-icon"><I.ArrowL style={{ height: 12, width: 12 }} /></span>
        <span>{label}</span>
      </button>
    );
  }

  function IdleView({ onStart }) {
    return (
      <div className="bk-fade-enter" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', minHeight: 240, padding: '20px 0' }}>
        <svg width="44" height="44" viewBox="0 0 48 48" fill="none" aria-hidden="true">
          <rect x="6" y="10" width="36" height="32" rx="4" stroke="var(--accent)" strokeWidth="1.5" />
          <line x1="6" y1="20" x2="42" y2="20" stroke="var(--accent)" strokeWidth="1.5" />
          <line x1="16" y1="6" x2="16" y2="14" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" />
          <line x1="32" y1="6" x2="32" y2="14" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" />
          <rect x="14" y="26" width="4" height="4" rx="0.5" fill="var(--accent)" opacity="0.5" />
          <rect x="22" y="26" width="4" height="4" rx="0.5" fill="var(--accent)" opacity="0.5" />
          <rect x="30" y="26" width="4" height="4" rx="0.5" fill="var(--accent)" opacity="0.5" />
          <rect x="14" y="34" width="4" height="4" rx="0.5" fill="var(--accent)" opacity="0.3" />
          <rect x="22" y="34" width="4" height="4" rx="0.5" fill="var(--accent)" opacity="0.3" />
        </svg>
        <p style={{ color: 'var(--fg)', fontFamily: 'var(--font-display, inherit)', fontWeight: 600, fontSize: 'clamp(1.1rem, 1.6vw, 1.3rem)', margin: '14px 0 0' }}>Book a discovery call</p>
        <p style={{ color: 'var(--fg-muted)', fontSize: 14, lineHeight: 1.6, margin: '8px 0 0', textAlign: 'center', maxWidth: 320 }}>
          30 minutes with a founder. No commitment, no sales pitch — just an honest conversation about what you're building.
        </p>
        <button type="button" onClick={onStart} className="bk-submit"
          style={{ marginTop: 24, flex: 'none', minWidth: 240 }}>
          Pick a time →
        </button>
      </div>
    );
  }

  function AnimatedCheckmark() {
    return (
      <svg width="56" height="56" viewBox="0 0 64 64" fill="none" aria-hidden="true">
        <circle cx="32" cy="32" r="30" stroke="color-mix(in srgb, var(--accent) 25%, transparent)" strokeWidth="1.5" fill="color-mix(in srgb, var(--accent) 10%, transparent)" />
        <path d="M20 33L28 41L44 25" stroke="var(--accent)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
          strokeDasharray="32" strokeDashoffset="32" style={{ animation: 'bk-check 450ms cubic-bezier(0.16,1,0.3,1) 200ms forwards' }} />
      </svg>
    );
  }

  function ConfirmationScreen({ confirmation, email, onDone }) {
    return (
      <div className="bk-fade-enter" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', padding: '24px 0', gap: 14 }}>
        <AnimatedCheckmark />
        <div>
          <p style={{ fontSize: 'clamp(1.1rem, 1.6vw, 1.3rem)', fontWeight: 600, color: 'var(--fg)', margin: 0, fontFamily: 'var(--font-display, inherit)' }}>Meeting scheduled.</p>
          <p style={{ fontSize: 14, color: 'var(--fg-muted)', margin: '6px 0 0' }}>{formatConfirmedTime(confirmation.startTime)}</p>
        </div>
        <p style={{ fontSize: 13, color: 'var(--fg-faint)', maxWidth: 320, margin: 0 }}>
          Confirmation sent to <span style={{ color: 'var(--fg)', fontWeight: 600 }}>{email}</span>
        </p>
        {confirmation.calendarUrl && (
          <a href={confirmation.calendarUrl} target="_blank" rel="noopener noreferrer"
            style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 13, color: 'var(--accent)', textDecoration: 'none', fontWeight: 500 }}
            onMouseEnter={(e) => { e.currentTarget.style.textDecoration = 'underline'; }}
            onMouseLeave={(e) => { e.currentTarget.style.textDecoration = 'none'; }}>
            <I.CalCheck style={{ height: 15, width: 15 }} />
            Add to Google Calendar
            <I.External style={{ height: 12, width: 12, opacity: 0.6 }} />
          </a>
        )}
        <button type="button" onClick={onDone}
          style={{ marginTop: 4, fontSize: 13, color: 'var(--fg-faint)', background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: 'inherit' }}>
          Done
        </button>
      </div>
    );
  }

  function SlotConflictScreen({ onBack }) {
    return (
      <div className="bk-fade-enter" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', padding: '24px 0', gap: 14 }}>
        <div style={{ height: 56, width: 56, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--eyebrow-bg)', border: '1px solid var(--eyebrow-bd)' }}>
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
            <path d="M12 9v4M12 17h.01" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" />
            <circle cx="12" cy="12" r="10" stroke="var(--accent)" strokeWidth="1.5" />
          </svg>
        </div>
        <div>
          <p style={{ fontSize: 16, fontWeight: 600, color: 'var(--fg)', margin: 0, fontFamily: 'var(--font-display, inherit)' }}>Slot just taken</p>
          <p style={{ fontSize: 13, color: 'var(--fg-muted)', maxWidth: 280, margin: '6px 0 0' }}>That time was booked by someone else. Choose another time.</p>
        </div>
        <button type="button" onClick={onBack} className="bk-submit" style={{ width: '100%', flex: 'none', maxWidth: 320 }}>Pick another time</button>
      </div>
    );
  }

  function ErrorScreen({ code, onRetry }) {
    const isNet = code === 'NETWORK_ERROR';
    return (
      <div className="bk-fade-enter" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', padding: '24px 0', gap: 14 }}>
        <div style={{ height: 56, width: 56, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(192,86,63,0.08)', border: '1px solid rgba(192,86,63,0.20)' }}>
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
            <path d="M18 6L6 18M6 6l12 12" stroke="#c0563f" strokeWidth="2" strokeLinecap="round" />
          </svg>
        </div>
        <div>
          <p style={{ fontSize: 16, fontWeight: 600, color: 'var(--fg)', margin: 0, fontFamily: 'var(--font-display, inherit)' }}>
            {isNet ? 'Connection problem' : 'Something went wrong'}
          </p>
          <p style={{ fontSize: 13, color: 'var(--fg-muted)', maxWidth: 280, margin: '6px 0 0' }}>
            {isNet ? 'Check your connection and try again.' : 'An error occurred. You can retry or email us.'}
          </p>
        </div>
        <button type="button" onClick={onRetry} className="bk-submit" style={{ width: '100%', flex: 'none', maxWidth: 320 }}>Try again</button>
        <a href="mailto:hello@prometio.group" style={{ fontSize: 13, color: 'var(--fg-faint)', textDecoration: 'none' }}>or write to hello@prometio.group</a>
      </div>
    );
  }

  // ── State machine + main widget ─────────────────────────────────────────
  function reducer(state, action) {
    switch (action.type) {
      case 'START': return { name: 'selecting', selectedDate: null, selectedSlot: null };
      case 'BACK_TO_IDLE': return { name: 'idle' };
      case 'SELECT_DATE':
        if (state.name === 'selecting') return { ...state, selectedDate: action.date, selectedSlot: null };
        return state;
      case 'SELECT_SLOT': return { name: 'filling_form', slot: action.slot };
      case 'BACK_TO_CALENDAR': return { name: 'selecting', selectedDate: null, selectedSlot: null };
      case 'CONFIRMED': return { name: 'confirmed', confirmation: action.confirmation, email: action.email };
      case 'SLOT_CONFLICT': return { name: 'slot_conflict' };
      case 'ERROR': return { name: 'error', code: action.code };
      case 'RETRY': return { name: 'selecting', selectedDate: null, selectedSlot: null };
      default: return state;
    }
  }

  function BookingWidget({ initialPhase, onClose }) {
    const [state, dispatch] = React.useReducer(reducer, initialPhase === 'selecting'
      ? { name: 'selecting', selectedDate: null, selectedSlot: null }
      : { name: 'idle' });

    // If the parent launched us straight into selecting, "back" returns to the parent.
    // Otherwise back goes to the internal idle view.
    const backFromCalendar = onClose && initialPhase === 'selecting'
      ? onClose
      : () => dispatch({ type: 'BACK_TO_IDLE' });

    return (
      <div className="bk-card">
        <style dangerouslySetInnerHTML={{ __html: CSS }} />
        <div className="bk-root">
          {state.name === 'idle' && <IdleView onStart={() => dispatch({ type: 'START' })} />}

          {state.name === 'selecting' && (
            <div className="bk-fade-enter">
              <BackHeader label="Back" onClick={backFromCalendar} />
              <p style={{ fontSize: 'clamp(1.05rem, 1.5vw, 1.2rem)', fontWeight: 600, color: 'var(--fg)', margin: '0 0 18px', fontFamily: 'var(--font-display, inherit)' }}>Book a discovery call</p>
              <BookingCalendar
                selectedDate={state.selectedDate}
                selectedSlot={state.selectedSlot}
                onDateSelect={(date) => dispatch({ type: 'SELECT_DATE', date })}
                onSlotSelect={(slot) => dispatch({ type: 'SELECT_SLOT', slot })}
              />
            </div>
          )}

          {state.name === 'filling_form' && (
            <div className="bk-fade-enter">
              <BackHeader label="Change time" onClick={() => dispatch({ type: 'BACK_TO_CALENDAR' })} />
              <BookingForm
                slot={state.slot}
                onConfirmed={(confirmation, email) => dispatch({ type: 'CONFIRMED', confirmation, email })}
                onSlotConflict={() => dispatch({ type: 'SLOT_CONFLICT' })}
                onError={(code) => dispatch({ type: 'ERROR', code })}
                onBack={() => dispatch({ type: 'BACK_TO_CALENDAR' })}
              />
            </div>
          )}

          {state.name === 'confirmed' && (
            <ConfirmationScreen
              confirmation={state.confirmation}
              email={state.email}
              onDone={onClose || (() => dispatch({ type: 'BACK_TO_IDLE' }))}
            />
          )}

          {state.name === 'slot_conflict' && (
            <SlotConflictScreen onBack={() => dispatch({ type: 'BACK_TO_CALENDAR' })} />
          )}

          {state.name === 'error' && (
            <ErrorScreen code={state.code} onRetry={() => dispatch({ type: 'RETRY' })} />
          )}
        </div>
      </div>
    );
  }

  window.BookingWidget = BookingWidget;
})();
