// events-widget.jsx — Halcyon Pilates events widget.
// Two screens:
//   List   — stacked rows: thumbnail + date tile, title, meta, short
//             description, Register button. Visually condensed.
//   Detail — hero image, title, date/time/location, sidebar with price
//             and Register, About this event, location with map.

const { useState: useEvtState, useEffect: useEvtEffect } = React;

const EVT_BREAKPOINT = 760;
const EVT_MAX_TICKETS = 10;
// Mix a hex color toward white by a given ratio (0 = white, 1 = original).
// Used to derive a soft border tint from the primary text color so the
// outline always relates back to the brand instead of looking like a
// hard-coded grey.
function evtTintWhite(hex, ratio) {
  if (!hex || hex[0] !== '#') return hex;
  const c = hex.slice(1).padStart(6, '0');
  const r = parseInt(c.substring(0, 2), 16);
  const g = parseInt(c.substring(2, 4), 16);
  const b = parseInt(c.substring(4, 6), 16);
  const m = (ch) => Math.round(ch * ratio + 255 * (1 - ratio));
  return `rgb(${m(r)}, ${m(g)}, ${m(b)})`;
}

function useEvtMobile() {
  const [m, setM] = useEvtState(
    typeof window !== 'undefined' ? window.innerWidth < EVT_BREAKPOINT : false
  );
  useEvtEffect(() => {
    const onResize = () => setM(window.innerWidth < EVT_BREAKPOINT);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return m;
}

// ────────────────────────────────────────────────────────────────
// Data
// ────────────────────────────────────────────────────────────────
const EVENTS = [
  {
    id: 'community-pilates',
    title: 'Community Pilates for Women',
    type: 'Community class',
    instructor: 'Marisol Pena',
    month: 'May', day: 1, weekday: 'Friday', year: 2026,
    start: '11:00 AM', end: '1:00 PM',
    timezone: 'America/Chicago',
    location: 'Halcyon Studio',
    address: '218 Atlantic Ave, Brooklyn, NY 11201',
    price: 25,
    image: 'https://images.unsplash.com/photo-1518611012118-696072aa579a?auto=format&fit=crop&w=1200&q=70',
    summary: 'A welcoming community class for women of all levels — mindful movement and core-strengthening exercises with guided modifications throughout. Bring a friend, leave feeling stronger, more aligned, and connected.',
    description: 'Join us for an uplifting community Pilates class designed for women of all fitness levels, blending mindful movement with core-strengthening exercises. Expect a welcoming, supportive vibe with guided modifications so you can move confidently at your own pace. Come connect, sweat, and leave feeling stronger, more aligned, and refreshed.',
  },
  {
    id: 'spring-workshop',
    title: 'Spring Reformer Workshop',
    type: 'Workshop',
    instructor: 'Lena Ortiz',
    month: 'May', day: 30, weekday: 'Saturday', year: 2026,
    start: '1:00 PM', end: '4:00 PM',
    timezone: 'America/New_York',
    location: 'Reformer Room',
    address: '218 Atlantic Ave, Brooklyn, NY 11201',
    price: 65,
    image: 'https://images.unsplash.com/photo-1599901860904-17e6ed7083a0?auto=format&fit=crop&w=1200&q=70',
    summary: 'A three-hour deep dive built for intermediate practitioners. Hour one is form and breath, hour two is sequencing and progressions, hour three is a long guided flow. Bring water and a small towel.',
    description: 'A three-hour intensive built for practitioners with at least six months on the reformer. We will spend the first hour on form and breathwork, the second on sequencing and progressions, and the third on a long, guided flow. Bring water and a small towel.',
  },
  {
    id: 'breathwork-evening',
    title: 'Breathwork & Restorative Evening',
    type: 'Workshop',
    instructor: 'Anika Rao',
    month: 'Jun', day: 8, weekday: 'Monday', year: 2026,
    start: '6:30 PM', end: '8:00 PM',
    timezone: 'America/New_York',
    location: 'Studio A',
    address: '218 Atlantic Ave, Brooklyn, NY 11201',
    price: 35,
    image: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?auto=format&fit=crop&w=1200&q=70',
    summary: 'A slow, intentional evening to reset the nervous system — guided breath practices, long-held restorative shapes supported by props, and a closing meditation. Tea is served. Bring a journal if you like.',
    description: 'A slow, intentional evening designed to reset the nervous system. We will move through a sequence of guided breath practices, then settle into long-held restorative shapes supported by props. Closing with a brief meditation and tea. Bring a journal if you would like.',
  },
  {
    id: 'open-house',
    title: 'Summer Open House',
    type: 'Open house',
    instructor: 'Studio Team',
    month: 'Jun', day: 22, weekday: 'Monday', year: 2026,
    start: '5:00 PM', end: '8:00 PM',
    timezone: 'America/New_York',
    location: 'Halcyon Studio',
    address: '218 Atlantic Ave, Brooklyn, NY 11201',
    price: 0,
    image: 'https://images.unsplash.com/photo-1532384748853-8f54a8f476e2?auto=format&fit=crop&w=1200&q=70',
    summary: 'Free and open to the public. Drop by anytime — tour the studio, meet our instructors, sample 15-minute mini-classes on the reformer, and grab a discounted intro pack only available on the night. Light refreshments served.',
    description: 'Free, open to the public. Drop by anytime between 5 and 8. Tour the studio, meet our instructors, sample 15-minute mini-classes on the reformer, and grab a discounted intro pack only available on the night. Light refreshments served.',
  },
];

// ────────────────────────────────────────────────────────────────
// Root
// ────────────────────────────────────────────────────────────────
function EventsApp({ brandId = 'halcyon' }) {
  const baseBrand = window.BRANDS[brandId];
  const mobile = useEvtMobile();

  const tweaksEnabled = typeof window !== 'undefined' && window.EVT_TWEAKS_ENABLED;
  const defaults = (typeof window !== 'undefined' && window.EVT_TWEAK_DEFAULTS) || {};
  const [t, setTweak] = (tweaksEnabled ? window.useTweaks(defaults) : [defaults, () => {}]);

  const ink = (tweaksEnabled ? (t.headline ?? baseBrand.ink) : baseBrand.ink);
  const derivedBorder = evtTintWhite(ink, 0.14);

  const brand = tweaksEnabled ? {
    ...baseBrand,
    accent:        t.accent     ?? baseBrand.accent,
    accentDeep:    t.accent     ?? baseBrand.accentDeep,
    accentSoft:    baseBrand.accentSoft,
    surface:       t.panel      ?? baseBrand.surface,
    ink,
    inkSoft:       t.details    ?? baseBrand.inkSoft,
    panelInk:      t.panelInk     ?? t.headline ?? baseBrand.ink,
    panelInkSoft:  t.panelInkSoft ?? t.details  ?? baseBrand.inkSoft,
    border:        t.lineColor  ?? derivedBorder,
    displayFont:   t.font       ?? baseBrand.displayFont,
    bodyFont:      t.font       ?? baseBrand.bodyFont,
    displayWeight: t.weight     ?? baseBrand.displayWeight,
    _radius:       t.panelRadius ?? t.radius,
    _panelRadius:  t.panelRadius ?? t.radius,
    _buttonRadius: t.buttonRadius ?? t.radius,
    _buttonTextColor: t.buttonTextColor,
  } : {
    ...baseBrand,
    panelInk:     baseBrand.ink,
    panelInkSoft: baseBrand.inkSoft,
    border:       derivedBorder,
  };
  const appBg = tweaksEnabled ? (t.background ?? '#FFFFFF') : '#FFFFFF';

  const [activeId, setActiveId] = useEvtState(null);
  const activeEvent = EVENTS.find(e => e.id === activeId);

  return (
    <div style={{
      background: appBg, color: brand.ink,
      minHeight: '100vh', fontFamily: brand.bodyFont,
    }}>
      <BrandBar brand={brand} mobile={mobile} />

      <div style={{
        maxWidth: 1080, margin: '0 auto',
        padding: mobile ? '20px 16px 64px' : '32px 32px 80px',
      }}>
        {!activeEvent && (
          <EventsList brand={brand} mobile={mobile}
            onOpen={setActiveId}
            thumbnailRatio={t.thumbnailRatio || 'natural'}
            hideFilters={!!t.hideFilters}
            hidePrice={!!t.hidePrice}
            hideLocation={!!t.hideLocation}
            hideDescription={!!t.hideDescription}
            hideThumbnail={!!t.hideThumbnail}
            hideDateTag={!!t.hideDateTag}
            hideRegister={!!t.hideRegister} />
        )}
        {activeEvent && (
          <EventDetail brand={brand} mobile={mobile}
            event={activeEvent}
            onBack={() => setActiveId(null)} />
        )}
        <PoweredByZipper />
      </div>

      {tweaksEnabled && <EventsTweaks t={t} setTweak={setTweak} />}
    </div>
  );
}

function BrandBar({ brand, mobile }) {
  return (
    <div style={{
      borderBottom: `1px solid ${brand.border}`,
      background: '#fff',
      padding: mobile ? '14px 16px' : '18px 32px',
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      gap: 12,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{
          width: mobile ? 30 : 34, height: mobile ? 30 : 34,
          borderRadius: 8,
          background: brand.accent, color: '#fff',
          display: 'grid', placeItems: 'center',
          fontFamily: brand.displayFont, fontWeight: 800,
          fontSize: mobile ? 13 : 15, letterSpacing: '0.02em',
        }}>H</div>
        <div style={{
          fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
          fontSize: mobile ? 16 : 18, color: brand.ink, letterSpacing: '-0.01em',
        }}>Halcyon Pilates</div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Screen 1 — List
// ────────────────────────────────────────────────────────────────
function EventsList({ brand, mobile, onOpen, thumbnailRatio, hideFilters,
                     hidePrice, hideLocation, hideDescription, hideThumbnail, hideDateTag, hideRegister }) {
  const [typeFilter,        setTypeFilter]        = useEvtState('All events');
  const [locationFilter,    setLocationFilter]    = useEvtState('All locations');
  const [instructorFilter,  setInstructorFilter]  = useEvtState('All instructors');

  const allTypes        = ['All events',      ...Array.from(new Set(EVENTS.map(e => e.type)))];
  const allLocations    = ['All locations',   ...Array.from(new Set(EVENTS.map(e => e.location)))];
  const allInstructors  = ['All instructors', ...Array.from(new Set(EVENTS.map(e => e.instructor)))];

  const visible = EVENTS.filter(e =>
    (typeFilter       === 'All events'      || e.type       === typeFilter) &&
    (locationFilter   === 'All locations'   || e.location   === locationFilter) &&
    (instructorFilter === 'All instructors' || e.instructor === instructorFilter)
  );

  const clearAll = () => {
    setTypeFilter('All events');
    setLocationFilter('All locations');
    setInstructorFilter('All instructors');
  };

  return (
    <div>
      {!hideFilters && (
        <div style={{
          display: 'flex', gap: 8, flexWrap: 'wrap',
          justifyContent: 'center',
          marginBottom: mobile ? 14 : 22,
        }}>
          <FilterPill brand={brand} value={typeFilter}       options={allTypes}       onChange={setTypeFilter} />
          <FilterPill brand={brand} value={locationFilter}   options={allLocations}   onChange={setLocationFilter} />
          <FilterPill brand={brand} value={instructorFilter} options={allInstructors} onChange={setInstructorFilter} />
        </div>
      )}

      <div style={{ display: 'flex', flexDirection: 'column', gap: mobile ? 16 : 22 }}>
        {visible.length === 0 ? (
          <div style={{
            padding: '32px 20px',
            border: `1px dashed ${brand.border}`,
            borderRadius: brand._panelRadius != null ? brand._panelRadius : 10,
            textAlign: 'center', color: brand.inkSoft, fontSize: 14, lineHeight: 1.55,
          }}>
            No events match these filters.
            <button type="button" onClick={clearAll} style={{
              display: 'block', margin: '8px auto 0',
              background: 'transparent', border: 0, padding: 0,
              color: brand.accent, fontSize: 13, fontWeight: 700, cursor: 'pointer',
            }}>Clear filters</button>
          </div>
        ) : (() => {
          const out = [];
          let lastGroup = null;
          visible.forEach(ev => {
            const group = `${ev.month} ${ev.year}`;
            if (group !== lastGroup) {
              out.push(
                <MonthDivider key={`m-${group}`} brand={brand} mobile={mobile}
                  label={`${MONTH_LONG[ev.month] || ev.month} ${ev.year}`} />
              );
              lastGroup = group;
            }
            out.push(
              <EventRow key={ev.id} brand={brand} mobile={mobile}
                event={ev} onOpen={() => onOpen(ev.id)}
                thumbnailRatio={thumbnailRatio}
                hidePrice={hidePrice}
                hideLocation={hideLocation}
                hideDescription={hideDescription}
                hideThumbnail={hideThumbnail}
                hideDateTag={hideDateTag}
                hideRegister={hideRegister} />
            );
          });
          return out;
        })()}
      </div>
    </div>
  );
}

function FilterPill({ brand, value, options, onChange }) {
  const isAll = value.startsWith('All');
  return (
    <div style={{ position: 'relative' }}>
      <select
        value={value}
        onChange={e => onChange(e.target.value)}
        style={{
          appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none',
          background: isAll ? brand.surface : brand.accentSoft,
          color: isAll ? brand.panelInk : brand.accentDeep,
          border: `1px solid ${isAll ? brand.border : brand.accent}`,
          borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 999,
          padding: '8px 32px 8px 14px',
          fontSize: 13, fontWeight: 600,
          fontFamily: brand.bodyFont,
          cursor: 'pointer', outline: 'none',
        }}>
        {options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none"
           stroke={isAll ? brand.panelInkSoft : brand.accentDeep}
           strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"
           style={{
             position: 'absolute', right: 12, top: '50%',
             transform: 'translateY(-50%)', pointerEvents: 'none',
           }}>
        <polyline points="6 9 12 15 18 9" />
      </svg>
    </div>
  );
}

const MONTH_LONG = {
  Jan: 'January', Feb: 'February', Mar: 'March',     Apr: 'April',
  May: 'May',     Jun: 'June',     Jul: 'July',      Aug: 'August',
  Sep: 'September', Oct: 'October', Nov: 'November', Dec: 'December',
};

function MonthDivider({ brand, mobile, label }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 12,
      paddingTop: mobile ? 4 : 6,
    }}>
      <span style={{
        fontFamily: brand.bodyFont, fontSize: 11, fontWeight: 700,
        letterSpacing: '0.14em', textTransform: 'uppercase',
        color: brand.inkSoft,
      }}>{label}</span>
      <span style={{ flex: 1, height: 1, background: brand.border }} />
    </div>
  );
}

const RATIO_MAP = {
  natural: null,
  '1:1':   '1 / 1',
  '4:3':   '4 / 3',
  '3:2':   '3 / 2',
  '16:9':  '16 / 9',
};

function EventRow({ brand, mobile, event, onOpen, thumbnailRatio,
                   hidePrice, hideLocation, hideDescription, hideThumbnail, hideDateTag, hideRegister }) {
  const [hover, setHover] = useEvtState(false);
  const radius = brand._radius != null ? brand._radius : 10;
  const ratio = RATIO_MAP[thumbnailRatio];
  const sidePadding = hideRegister && hidePrice;

  return (
    <div
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        border: `1px solid ${hover ? brand.accent : brand.border}`,
        borderRadius: radius,
        background: brand.surface,
        overflow: 'hidden',
        display: 'flex',
        flexDirection: mobile ? 'column' : 'row',
        alignItems: 'stretch',
        transform: hover ? 'translateY(-2px)' : 'translateY(0)',
        boxShadow: hover
          ? `0 6px 20px -8px ${evtTintWhite(brand.ink, 0.35)}`
          : 'none',
        transition: 'transform .18s ease, border-color .18s ease, box-shadow .18s ease',
      }}>
      {!hideThumbnail && (
        <div style={{
          position: 'relative',
          flex: '0 0 auto',
          width: mobile ? '100%' : 280,
          aspectRatio: ratio || undefined,
          height: mobile ? (ratio ? 'auto' : 200) : (ratio ? 'auto' : '100%'),
          background: brand.accentSoft,
        }}>
          <img src={event.image} alt=""
            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
          {!hideDateTag && (
            <div style={{
              position: 'absolute', top: 12, left: 12,
              background: brand.surface, borderRadius: 8,
              padding: '4px 8px 5px',
              minWidth: 46, textAlign: 'center',
              boxShadow: '0 1px 3px rgba(0,0,0,0.08)',
            }}>
              <div style={{
                fontSize: 9.5, fontWeight: 700, letterSpacing: '0.1em',
                textTransform: 'uppercase', color: brand.panelInkSoft,
              }}>{event.month}</div>
              <div style={{
                fontFamily: brand.displayFont, fontWeight: 800, fontSize: 17,
                color: brand.panelInk, lineHeight: 1, marginTop: 1,
              }}>{event.day}</div>
            </div>
          )}
        </div>
      )}

      <div style={{
        flex: 1,
        padding: mobile ? '22px 18px 24px' : '30px 28px',
        display: 'flex', flexDirection: 'column', gap: 8,
        minWidth: 0,
      }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
          fontSize: 11.5, fontWeight: 700, letterSpacing: '0.08em',
          textTransform: 'uppercase', color: brand.accent,
        }}>
          <span>{event.weekday}, {event.month} {event.day}, {event.year}</span>
          <span style={{ opacity: 0.6 }}>·</span>
          <span>{event.start} – {event.end}</span>
        </div>

        <div style={{
          fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
          fontSize: mobile ? 18 : 20, letterSpacing: '-0.01em',
          color: brand.panelInk, lineHeight: 1.2,
        }}>{event.title}</div>

        {!hideDescription && (
          <div style={{
            fontFamily: brand.bodyFont, fontSize: 13.5, lineHeight: 1.55,
            color: brand.panelInkSoft,
          }}>{event.summary}</div>
        )}

        {!hideLocation && (
          <div style={{
            marginTop: 4,
            fontFamily: brand.bodyFont, fontSize: 13,
            color: brand.panelInkSoft, display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                 strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
              <circle cx="12" cy="10" r="3" />
            </svg>
            {event.location}
          </div>
        )}
      </div>

      {!sidePadding && (
        <div style={{
          flex: '0 0 auto',
          padding: mobile ? '0 18px 24px' : '30px 28px',
          borderLeft: mobile ? 0 : `1px solid ${brand.border}`,
          display: 'flex', flexDirection: 'column',
          alignItems: mobile ? 'stretch' : 'flex-end',
          gap: 10,
          minWidth: mobile ? 0 : 150,
        }}>
          {!hidePrice && (
            <div style={{
              flex: 1,
              display: 'flex', alignItems: 'center',
              justifyContent: mobile ? 'flex-start' : 'flex-end',
              fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
              fontSize: 22, letterSpacing: '-0.01em',
              color: brand.panelInk, lineHeight: 1,
            }}>{event.price === 0 ? 'Free' : `$${event.price}`}</div>
          )}
          {!hideRegister && <RegisterButton brand={brand} onClick={onOpen} />}
        </div>
      )}
    </div>
  );
}

function RegisterButton({ brand, onClick, small, label, disabled, block }) {
  const textColor = brand._buttonTextColor || '#fff';
  return (
    <button type="button" onClick={onClick} disabled={disabled}
      style={{
        background: disabled ? brand.border : brand.accent,
        color: disabled ? '#fff' : textColor,
        border: 0,
        borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 10,
        padding: small ? '8px 14px' : '12px 18px',
        fontFamily: brand.displayFont, fontWeight: 700,
        fontSize: small ? 12.5 : 14,
        letterSpacing: '0.04em', textTransform: 'uppercase',
        cursor: disabled ? 'not-allowed' : 'pointer', whiteSpace: 'nowrap',
        width: block ? '100%' : undefined,
        display: block ? 'flex' : 'inline-flex',
        alignItems: 'center', justifyContent: 'center', gap: 6,
      }}>
      {label || 'Register'}
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
           strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
        <line x1="5" y1="12" x2="19" y2="12" />
        <polyline points="12 5 19 12 12 19" />
      </svg>
    </button>
  );
}

// ────────────────────────────────────────────────────────────────
// Small self-contained inputs for the detail registration card
// (the events widget doesn't load the shared components.jsx).
// ────────────────────────────────────────────────────────────────
function EvtField({ brand, label, type = 'text', value, onChange, required, optional }) {
  const [focused, setFocused] = useEvtState(false);
  return (
    <label style={{ display: 'block' }}>
      <div style={{
        fontSize: 10.5, fontWeight: 700, letterSpacing: '0.05em',
        textTransform: 'uppercase', color: brand.panelInkSoft, marginBottom: 5,
      }}>{label}{optional ? ' · optional' : ''}</div>
      <input
        type={type}
        value={value || ''}
        onChange={e => onChange(e.target.value)}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        style={{
          width: '100%',
          background: '#fff',
          border: `1.5px solid ${focused ? brand.accent : brand.border}`,
          borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 8,
          padding: '10px 12px', fontSize: 14, color: brand.ink,
          outline: 'none', fontFamily: brand.bodyFont,
          boxShadow: focused ? `0 0 0 3px ${brand.accentSoft}` : 'none',
          transition: 'border-color .15s ease, box-shadow .15s ease',
        }}
      />
    </label>
  );
}

function EvtStepper({ brand, value, min = 1, max = 10, onChange }) {
  const btn = (kind, disabled) => (
    <button
      type="button"
      disabled={disabled}
      aria-label={kind === 'inc' ? 'Increase' : 'Decrease'}
      onClick={() => onChange(value + (kind === 'inc' ? 1 : -1))}
      style={{
        width: 32, height: 32, borderRadius: 8,
        border: `1.5px solid ${disabled ? brand.border : brand.accent}`,
        background: '#fff', color: disabled ? brand.border : brand.accent,
        display: 'grid', placeItems: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer', flex: '0 0 32px',
      }}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
           stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round">
        {kind === 'inc' && <line x1="12" y1="5" x2="12" y2="19" />}
        <line x1="5" y1="12" x2="19" y2="12" />
      </svg>
    </button>
  );
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, flex: '0 0 auto' }}>
      {btn('dec', value <= min)}
      <div style={{
        minWidth: 20, textAlign: 'center',
        fontFamily: brand.displayFont, fontWeight: 700, fontSize: 16, color: brand.panelInk,
      }}>{value}</div>
      {btn('inc', value >= max)}
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Screen 2 — Detail
// ────────────────────────────────────────────────────────────────
function EventDetail({ brand, mobile, event, onBack }) {
  const radius = brand._radius != null ? brand._radius : 10;

  return (
    <div>
      <button type="button" onClick={onBack}
        style={{
          background: 'transparent', border: 0, padding: '4px 0',
          fontFamily: brand.bodyFont, fontSize: 12, fontWeight: 700,
          letterSpacing: '0.08em', textTransform: 'uppercase', color: brand.accent,
          display: 'inline-flex', alignItems: 'center', gap: 6,
          cursor: 'pointer',
          marginBottom: mobile ? 14 : 18,
        }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor"
             strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
          <line x1="19" y1="12" x2="5" y2="12" />
          <polyline points="12 19 5 12 12 5" />
        </svg>
        Back to events
      </button>

      <div style={{
        borderRadius: radius,
        overflow: 'hidden',
        marginBottom: mobile ? 18 : 24,
        background: brand.accentSoft,
        aspectRatio: '16 / 7',
        maxHeight: 380,
      }}>
        <img src={event.image} alt=""
          style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      </div>

      {/* Event details (left) + Location (right) */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: mobile ? '1fr' : '1.4fr 1fr',
        gap: mobile ? 18 : 32,
        alignItems: 'start',
      }}>
        <div>
          <h1 style={{
            margin: 0,
            fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
            fontSize: mobile ? 28 : 36, letterSpacing: '-0.02em',
            color: brand.ink, lineHeight: 1.1,
          }}>{event.title}</h1>

          <div style={{
            marginTop: 14,
            display: 'flex', flexDirection: 'column', gap: 8,
          }}>
            <MetaRow brand={brand} icon="calendar">
              <div>{event.weekday}, {event.month} {event.day}, {event.year}</div>
              <div style={{ fontSize: 13, color: brand.inkSoft, marginTop: 1 }}>
                {event.start} – {event.end} ({event.timezone})
              </div>
            </MetaRow>
            <MetaRow brand={brand} icon="pin">
              <div>{event.location}</div>
              <div style={{ fontSize: 13, color: brand.inkSoft, marginTop: 1 }}>{event.address}</div>
            </MetaRow>
          </div>

          {/* Jump to the checkout form below */}
          <a href="#evt-register"
             onClick={(e) => {
               e.preventDefault();
               const el = document.getElementById('evt-register');
               if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
             }}
             style={{
               marginTop: 16,
               display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
               textDecoration: 'none',
               background: brand.accent, color: brand._buttonTextColor || '#fff',
               borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 10,
               padding: '13px 24px',
               fontFamily: brand.displayFont, fontWeight: 700, fontSize: 14,
               letterSpacing: '0.03em',
             }}>
            Register Now
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                 strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
              <line x1="12" y1="5" x2="12" y2="19" />
              <polyline points="19 12 12 19 5 12" />
            </svg>
          </a>

          <div style={{ height: 1, background: brand.border, margin: '20px 0' }} />

          <h2 style={{
            margin: 0,
            fontFamily: brand.displayFont, fontWeight: 700,
            fontSize: mobile ? 17 : 19, letterSpacing: '-0.01em',
            color: brand.ink,
          }}>About this event</h2>
          <p style={{
            margin: '10px 0 0',
            fontFamily: brand.bodyFont, fontSize: 14.5, lineHeight: 1.6,
            color: brand.inkSoft,
          }}>{event.description}</p>
        </div>

        {/* Location — now to the right of the event details */}
        <aside style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div>
            <h2 style={{
              margin: '0 0 10px',
              fontFamily: brand.displayFont, fontWeight: 700,
              fontSize: mobile ? 17 : 19, letterSpacing: '-0.01em',
              color: brand.ink,
            }}>Location</h2>
            <MapPlaceholder brand={brand} />
            <a href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(event.address)}`}
               target="_blank" rel="noopener noreferrer"
               style={{
                 marginTop: 10, display: 'inline-flex', alignItems: 'center', gap: 6,
                 fontFamily: brand.bodyFont, fontSize: 13, fontWeight: 600,
                 color: brand.accent, textDecoration: 'none',
               }}>
              View on Google Maps
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                   strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
                <polyline points="15 3 21 3 21 9" />
                <line x1="10" y1="14" x2="21" y2="3" />
              </svg>
            </a>
          </div>

          <div style={{ display: 'flex', gap: 8 }}>
            <ShareButton brand={brand} label="Share" />
            <ShareButton brand={brand} label="Add to calendar" />
          </div>
        </aside>
      </div>

      {/* Complete checkout, stepper-style, below */}
      <EventCheckout brand={brand} mobile={mobile} event={event} />
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Checkout — stepper-style registration below the event details.
// Single ticket price, so no per-attendee pricing: just buyer details,
// ticket quantity (+ a name/email per additional guest), then payment.
// ────────────────────────────────────────────────────────────────
function EventCheckout({ brand, mobile, event }) {
  const [activeStep, setActiveStep] = useEvtState(1);
  const [completed, setCompleted] = useEvtState({});
  const [reg, setReg] = useEvtState({ firstName: '', lastName: '', email: '', phone: '' });
  const [qty, setQtyState] = useEvtState(1);
  const [guests, setGuests] = useEvtState([]);
  // Liability waiver — signed by the person booking only (not the guests).
  const [waiverOpen, setWaiverOpen] = useEvtState(false);
  const [waiverChecked, setWaiverChecked] = useEvtState(false);

  const setQty = (n) => {
    const next = Math.max(1, Math.min(EVT_MAX_TICKETS, n));
    setQtyState(next);
    setGuests(prev => {
      const rows = prev.slice(0, next - 1);
      while (rows.length < next - 1) rows.push({ firstName: '', lastName: '', email: '', phone: '' });
      return rows;
    });
  };
  const updateGuest = (i, k) => (v) =>
    setGuests(prev => prev.map((g, idx) => (idx === i ? { ...g, [k]: v } : g)));
  const setRegK = (k) => (v) => setReg(r => ({ ...r, [k]: v }));

  const isFree = event.price === 0;
  const total = event.price * qty;
  const ticketWord = qty === 1 ? 'ticket' : 'tickets';

  const goNext = (s) => { setCompleted(c => ({ ...c, [s]: true })); setActiveStep(s + 1); };
  const editStep = (s) => {
    setActiveStep(s);
    setCompleted(c => { const n = { ...c }; delete n[s]; return n; });
  };

  const regValid = reg.firstName.trim() && reg.lastName.trim() && /\S+@\S+\.\S+/.test(reg.email);
  const guestsOk = guests.every(g => (g.firstName || '').trim() && (g.lastName || '').trim());
  const step1Ok = regValid && guestsOk && waiverChecked;
  // Card entry is a Stripe-style mock (matches the class checkout), so the
  // submit only gates on the registrant + guest details.
  const canSubmit = step1Ok;
  const detailsSummary = completed[1]
    ? `${`${reg.firstName} ${reg.lastName}`.trim() || 'You'} · ${qty} ${ticketWord}`
    : null;

  const accentBtn = (label, onClick, disabled, block) => (
    <button type="button" onClick={onClick} disabled={disabled}
      style={{
        background: disabled ? brand.border : brand.accent,
        color: disabled ? '#fff' : (brand._buttonTextColor || '#fff'),
        border: 0, borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 10,
        padding: '13px 22px', fontFamily: brand.displayFont, fontWeight: 700,
        fontSize: 14, letterSpacing: '0.03em',
        cursor: disabled ? 'not-allowed' : 'pointer',
        width: block ? '100%' : undefined,
      }}>
      {label}
    </button>
  );

  return (
    <div id="evt-register" style={{ marginTop: mobile ? 28 : 40, scrollMarginTop: 16 }}>
      <div style={{ height: 1, background: brand.border, marginBottom: mobile ? 22 : 28 }} />
      <h2 style={{
        margin: '0 0 16px',
        fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
        fontSize: mobile ? 22 : 26, letterSpacing: '-0.02em', color: brand.ink,
      }}>Register</h2>

      <div style={{
        display: 'grid',
        gridTemplateColumns: mobile ? '1fr' : 'minmax(0,1fr) 320px',
        gap: mobile ? 16 : 28,
        alignItems: 'start',
      }}>
        {mobile && (
          <EvtOrderSummary brand={brand} event={event} qty={qty}
            total={total} isFree={isFree} ticketWord={ticketWord} />
        )}

        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {/* Step 1 — your details + tickets + guests */}
          <EvtStepCard brand={brand} mobile={mobile} step={1} title="Your details"
            isOpen={activeStep === 1} isCompleted={!!completed[1]}
            summary={detailsSummary} onEdit={() => editStep(1)}>
            <div style={{ display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 1fr', gap: 10 }}>
              <EvtField brand={brand} label="First name" required
                        value={reg.firstName} onChange={setRegK('firstName')} />
              <EvtField brand={brand} label="Last name" required
                        value={reg.lastName} onChange={setRegK('lastName')} />
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 1fr', gap: 10, marginTop: 10 }}>
              <EvtField brand={brand} label="Email" type="email" required
                        value={reg.email} onChange={setRegK('email')} />
              <EvtField brand={brand} label="Phone" type="tel" optional
                        value={reg.phone} onChange={setRegK('phone')} />
            </div>

            {/* Tickets */}
            <div style={{
              marginTop: 16, padding: '12px 14px',
              border: `1px solid ${brand.border}`,
              borderRadius: brand._panelRadius != null ? brand._panelRadius : 10,
              display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
            }}>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 13.5, fontWeight: 700, color: brand.ink }}>Tickets</div>
                <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 1 }}>
                  Buying for more than one?
                </div>
              </div>
              <EvtStepper brand={brand} value={qty} min={1} max={EVT_MAX_TICKETS} onChange={setQty} />
            </div>

            {/* Additional guests */}
            {qty > 1 && (
              <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
                <div style={{
                  fontSize: 11, fontWeight: 700, letterSpacing: '0.1em',
                  textTransform: 'uppercase', color: brand.inkSoft,
                }}>Additional guests</div>
                {guests.map((g, i) => (
                  <div key={i} style={{
                    padding: 14,
                    border: `1px solid ${brand.border}`,
                    borderRadius: brand._panelRadius != null ? brand._panelRadius : 10,
                    background: brand.surface,
                    display: 'flex', flexDirection: 'column', gap: 8,
                  }}>
                    <div style={{ fontSize: 12, fontWeight: 700, color: brand.panelInk }}>
                      Guest {i + 1}
                    </div>
                    <div style={{ display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 1fr', gap: 8 }}>
                      <EvtField brand={brand} label="First name" required
                                value={g.firstName} onChange={updateGuest(i, 'firstName')} />
                      <EvtField brand={brand} label="Last name" required
                                value={g.lastName} onChange={updateGuest(i, 'lastName')} />
                    </div>
                    <EvtField brand={brand} label="Email" type="email" optional
                              value={g.email} onChange={updateGuest(i, 'email')} />
                    <EvtField brand={brand} label="Phone" type="tel" optional
                              value={g.phone} onChange={updateGuest(i, 'phone')} />
                  </div>
                ))}
                <div style={{ fontSize: 12, color: brand.inkSoft, lineHeight: 1.5 }}>
                  If provided, we'll email each guest their own ticket.
                </div>
              </div>
            )}

            {/* Liability waiver — the person booking signs; guests do not. */}
            <EvtWaiverInline brand={brand} brandName="Halcyon Pilates"
              open={waiverOpen} setOpen={setWaiverOpen}
              checked={waiverChecked} onChange={setWaiverChecked} />

            <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>
              {accentBtn('Continue', () => goNext(1), !step1Ok)}
            </div>
          </EvtStepCard>

          {/* Step 2 — payment / confirm */}
          <EvtStepCard brand={brand} mobile={mobile} step={2}
            title={isFree ? 'Confirm registration' : 'Payment'}
            isOpen={activeStep === 2} isCompleted={false} onEdit={() => editStep(2)}>
            {isFree ? (
              <div style={{
                padding: '14px 16px',
                borderRadius: brand._panelRadius != null ? brand._panelRadius : 10,
                background: brand.accentSoft, color: brand.ink,
                fontSize: 13.5, lineHeight: 1.5,
              }}>
                This event is free — no payment needed. Confirm to reserve your {qty} {ticketWord}.
              </div>
            ) : (
              <EvtPaymentSection brand={brand} methods={{ apple: true, google: true, link: true }} />
            )}

            <div style={{ marginTop: 18 }}>
              {accentBtn(
                isFree
                  ? `Complete registration · ${qty} ${ticketWord}`
                  : `Pay $${total}`,
                () => alert(`Registered ${qty} ${ticketWord} for ${event.title}${isFree ? '' : ` · $${total}`}`),
                !canSubmit, true,
              )}
            </div>
          </EvtStepCard>
        </div>

        {!mobile && (
          <EvtOrderSummary brand={brand} event={event} qty={qty}
            total={total} isFree={isFree} ticketWord={ticketWord} />
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Liability waiver — expandable card with a sign-off checkbox. Mirrors the
// class booking checkout's waiver. Only the person booking signs it.
// ────────────────────────────────────────────────────────────────
function EvtWaiverInline({ brand, brandName, open, setOpen, checked, onChange }) {
  const radius = brand._panelRadius != null ? brand._panelRadius : 12;
  return (
    <div style={{
      marginTop: 16,
      border: `1px solid ${brand.border}`,
      borderRadius: radius, overflow: 'hidden', background: brand.surface,
    }}>
      <button type="button" onClick={() => setOpen(!open)} aria-expanded={open}
        style={{
          width: '100%', display: 'flex', alignItems: 'center', gap: 10,
          padding: '12px 14px', background: 'transparent', border: 0,
          textAlign: 'left', cursor: 'pointer', fontFamily: brand.bodyFont,
        }}>
        <div style={{
          width: 28, height: 28, borderRadius: 8,
          background: brand.accentSoft, color: brand.accentDeep,
          display: 'grid', placeItems: 'center', flex: '0 0 auto',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
               strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
            <polyline points="14 2 14 8 20 8" /><line x1="9" y1="15" x2="15" y2="15" />
          </svg>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 700, color: brand.ink }}>Liability waiver</div>
          <div style={{ fontSize: 11.5, color: brand.inkSoft, marginTop: 1 }}>
            {open ? 'Tap to collapse' : 'Tap to read full waiver'}
          </div>
        </div>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={brand.inkSoft}
             strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"
             style={{ transform: open ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform .2s ease' }}>
          <polyline points="6 9 12 15 18 9" />
        </svg>
      </button>
      {open && (
        <div style={{
          maxHeight: 200, overflow: 'auto', padding: '0 14px 14px',
          fontSize: 12, lineHeight: 1.55, color: brand.inkSoft,
          borderTop: `1px solid ${brand.border}`,
        }}>
          <p style={{ marginTop: 12 }}>I, the undersigned, acknowledge that participation in the activities offered by {brandName} carries inherent risks of physical injury. I confirm that I am physically able to participate and have disclosed any conditions that may affect my safe practice.</p>
          <p>I voluntarily assume all risk of injury, loss, or damage to person or property arising from participation, including (but not limited to) strains, sprains, falls, and contact with equipment. I agree to follow all instructor and studio guidance.</p>
          <p>I release {brandName}, its instructors, employees, and contractors from any and all claims, demands, and causes of action arising out of my participation, except where caused by gross negligence.</p>
          <p>This waiver is binding upon me, my heirs, and my legal representatives. I have read this waiver in full and understand its terms.</p>
        </div>
      )}
      <div style={{ padding: '12px 14px', borderTop: `1px solid ${brand.border}`, background: '#fff' }}>
        <label style={{ display: 'flex', alignItems: 'flex-start', gap: 8, cursor: 'pointer' }}>
          <span
            onClick={(e) => { e.preventDefault(); onChange(!checked); }}
            style={{
              flex: '0 0 16px', width: 16, height: 16, marginTop: 1, borderRadius: 4,
              border: `1.5px solid ${checked ? brand.accent : brand.border}`,
              background: checked ? brand.accent : '#fff',
              display: 'grid', placeItems: 'center', transition: 'all .15s ease',
            }}>
            {checked && (
              <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#fff"
                   strokeWidth="4" strokeLinecap="round" strokeLinejoin="round">
                <polyline points="20 6 9 17 4 12" />
              </svg>
            )}
          </span>
          <span style={{ fontSize: 12.5, color: brand.ink, lineHeight: 1.45 }}>
            I've read and agree to the liability waiver. I'm participating at my own risk and have no conditions that prevent safe practice.
          </span>
          <input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)}
                 style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
        </label>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Payment section — Stripe-style, mirrors the class booking checkout:
// express-pay wallets, "or pay with card" divider, a boxed card field
// with brand logos, and an ACH link. Card entry is a visual mock.
// ────────────────────────────────────────────────────────────────
function EvtPaymentSection({ brand, methods = {} }) {
  const wallets = [];
  if (methods.apple)  wallets.push(<EvtWalletButton key="a" kind="apple"  brand={brand} />);
  if (methods.google) wallets.push(<EvtWalletButton key="g" kind="google" brand={brand} />);
  if (methods.link)   wallets.push(<EvtWalletButton key="l" kind="link"   brand={brand} />);
  return (
    <div>
      {wallets.length > 0 && (
        <>
          <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>{wallets}</div>
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10, margin: '14px 0',
            color: brand.inkSoft, fontSize: 11, letterSpacing: '0.08em',
            textTransform: 'uppercase', fontWeight: 600,
          }}>
            <div style={{ flex: 1, height: 1, background: brand.border }} />
            or pay with card
            <div style={{ flex: 1, height: 1, background: brand.border }} />
          </div>
        </>
      )}
      <EvtCardField brand={brand} />
      <button type="button" style={{
        marginTop: 8, background: 'transparent', border: 0,
        color: brand.inkSoft, fontSize: 12.5, padding: '4px 0', fontWeight: 500,
        cursor: 'pointer', fontFamily: brand.bodyFont,
      }}>or pay by bank transfer (ACH) →</button>
    </div>
  );
}

function EvtWalletButton({ kind, brand }) {
  const styles = {
    apple: { bg: '#000', fg: '#fff', label: (
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
        <svg width="16" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.08zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/></svg>
        Pay
      </span>) },
    google: { bg: '#fff', fg: '#1F2A22', label: (
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        <svg width="20" height="20" viewBox="0 0 24 24"><path fill="#4285F4" d="M21.6 12.23c0-.7-.06-1.4-.2-2.06H12v3.92h5.4a4.6 4.6 0 0 1-2 3v2.5h3.23c1.9-1.74 2.97-4.32 2.97-7.36z"/><path fill="#34A853" d="M12 22c2.7 0 4.97-.9 6.63-2.42l-3.23-2.5c-.9.6-2.04.95-3.4.95-2.6 0-4.83-1.76-5.62-4.13H3.04v2.58A10 10 0 0 0 12 22z"/><path fill="#FBBC05" d="M6.38 13.9a6 6 0 0 1 0-3.8V7.52H3.04a10 10 0 0 0 0 8.96l3.34-2.58z"/><path fill="#EA4335" d="M12 5.95c1.47 0 2.78.5 3.82 1.5l2.86-2.86A10 10 0 0 0 12 2 10 10 0 0 0 3.04 7.52l3.34 2.58A6 6 0 0 1 12 5.95z"/></svg>
        <span style={{ fontWeight: 500 }}>Pay</span>
      </span>) },
    link: { bg: '#00D66F', fg: '#0E1B14', label: (
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontWeight: 700, letterSpacing: '-0.01em' }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="6"/></svg>
        Link
      </span>) },
  }[kind];
  return (
    <button type="button" style={{
      flex: 1, background: styles.bg, color: styles.fg,
      border: kind === 'google' ? `1px solid ${brand.border}` : 0,
      borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 10,
      padding: '12px 0', fontSize: 14.5, fontWeight: 600, fontFamily: brand.bodyFont,
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
      cursor: 'pointer', minHeight: 46,
    }}>{styles.label}</button>
  );
}

// Mock card field — looks like Stripe Elements.
function EvtCardField({ brand }) {
  const [num, setNum] = useEvtState('');
  const [exp, setExp] = useEvtState('');
  const [cvc, setCvc] = useEvtState('');
  const [zip, setZip] = useEvtState('');
  const placeholderColor = brand.inkSoft || '#8C9690';
  const inputStyle = {
    flex: 1, background: 'transparent', border: 0, fontSize: 14,
    color: brand.ink, outline: 'none', fontFamily: brand.bodyFont,
    padding: '14px 12px', minWidth: 0,
  };
  return (
    <div style={{
      background: brand.surface,
      border: `1.5px solid ${brand.border}`,
      borderRadius: brand._panelRadius != null ? brand._panelRadius : 12,
      overflow: 'hidden',
    }}>
      <style>{`.evt-cf::placeholder { color: ${placeholderColor}; opacity: 1; }`}</style>
      <div style={{ display: 'flex', alignItems: 'center', borderBottom: `1px solid ${brand.border}` }}>
        <input className="evt-cf" value={num} onChange={e => setNum(e.target.value)}
          placeholder="1234 1234 1234 1234" inputMode="numeric" autoComplete="cc-number"
          aria-label="Card number" style={{ ...inputStyle, paddingLeft: 14 }} />
        <div style={{ display: 'flex', gap: 4, paddingRight: 12 }}>
          <EvtCardLogo kind="visa" /><EvtCardLogo kind="mc" /><EvtCardLogo kind="amex" />
        </div>
      </div>
      <div style={{ display: 'flex' }}>
        <input className="evt-cf" value={exp} onChange={e => setExp(e.target.value)}
          placeholder="MM / YY" inputMode="numeric" autoComplete="cc-exp"
          aria-label="Card expiration date"
          style={{ ...inputStyle, borderRight: `1px solid ${brand.border}`, paddingLeft: 14 }} />
        <input className="evt-cf" value={cvc} onChange={e => setCvc(e.target.value)}
          placeholder="CVC" inputMode="numeric" autoComplete="cc-csc"
          aria-label="Card security code"
          style={{ ...inputStyle, borderRight: `1px solid ${brand.border}` }} />
        <input className="evt-cf" value={zip} onChange={e => setZip(e.target.value)}
          placeholder="ZIP" inputMode="numeric" autoComplete="postal-code"
          aria-label="Billing ZIP code" style={inputStyle} />
      </div>
    </div>
  );
}

function EvtCardLogo({ kind }) {
  const fills = { visa: '#1A1F71', mc: '#EB001B', amex: '#006FCF' };
  const labels = { visa: 'VISA', mc: 'mc', amex: 'AMEX' };
  return (
    <div style={{
      width: 30, height: 20, borderRadius: 4, background: '#fff',
      border: '1px solid #E8E8E4', display: 'grid', placeItems: 'center',
      fontSize: 8, fontWeight: 800, color: fills[kind],
      fontFamily: 'system-ui, sans-serif', letterSpacing: '-0.02em',
    }}>{labels[kind]}</div>
  );
}

// Collapsible numbered step card for the events checkout.
function EvtStepCard({ brand, mobile, step, title, isOpen, isCompleted, summary, onEdit, children }) {
  const radius = brand._panelRadius != null ? brand._panelRadius : 10;
  return (
    <div style={{
      background: '#fff',
      border: `1px solid ${isOpen ? brand.accent : brand.border}`,
      boxShadow: isOpen ? `0 0 0 3px ${brand.accentSoft}` : 'none',
      borderRadius: radius, overflow: 'hidden', transition: 'all .2s ease',
    }}>
      <div
        onClick={() => { if (!isOpen && isCompleted) onEdit(); }}
        style={{
          display: 'flex', alignItems: 'center', gap: 12,
          padding: mobile ? '14px 16px' : '16px 18px',
          cursor: !isOpen && isCompleted ? 'pointer' : 'default',
        }}>
        <div style={{
          width: 26, height: 26, borderRadius: 999,
          background: isCompleted || isOpen ? brand.accent : 'transparent',
          border: `1.5px solid ${isCompleted || isOpen ? brand.accent : brand.border}`,
          color: isCompleted || isOpen ? '#fff' : brand.inkSoft,
          fontSize: 13, fontWeight: 700, fontFamily: brand.bodyFont,
          display: 'grid', placeItems: 'center', flex: '0 0 auto',
        }}>
          {isCompleted ? (
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                 strokeWidth="3.2" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="20 6 9 17 4 12" />
            </svg>
          ) : step}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontFamily: brand.displayFont, fontWeight: 700,
            fontSize: mobile ? 15 : 16,
            color: isCompleted && !isOpen ? brand.inkSoft : brand.ink,
          }}>{title}</div>
          {summary && !isOpen && (
            <div style={{ fontSize: mobile ? 12 : 13, color: brand.inkSoft, marginTop: 2 }}>{summary}</div>
          )}
        </div>
        {isCompleted && !isOpen && (
          <button type="button" onClick={(e) => { e.stopPropagation(); onEdit(); }}
            style={{
              background: 'transparent', border: 0, color: brand.accent,
              fontSize: 12, fontWeight: 700, letterSpacing: '0.06em',
              textTransform: 'uppercase', cursor: 'pointer', fontFamily: brand.bodyFont,
            }}>Edit</button>
        )}
      </div>
      {isOpen && (
        <div style={{ padding: mobile ? '0 16px 16px' : '0 18px 18px' }}>{children}</div>
      )}
    </div>
  );
}

// Order summary rail for the events checkout.
function EvtOrderSummary({ brand, event, qty, total, isFree, ticketWord }) {
  const radius = brand._panelRadius != null ? brand._panelRadius : 10;
  return (
    <aside style={{
      position: 'sticky', top: 24,
      border: `1px solid ${brand.border}`,
      borderRadius: radius, background: brand.surface,
      padding: 20,
    }}>
      <div style={{
        fontSize: 11, fontWeight: 700, letterSpacing: '0.1em',
        textTransform: 'uppercase', color: brand.panelInkSoft, marginBottom: 14,
      }}>Order summary</div>

      <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
        <div style={{
          width: 52, height: 52, borderRadius: 8, flex: '0 0 auto',
          background: `url(${event.image}) center/cover`,
        }} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600, color: brand.panelInk, lineHeight: 1.35 }}>
            {event.title}
          </div>
          <div style={{ fontSize: 12, color: brand.panelInkSoft, marginTop: 2 }}>
            {event.weekday}, {event.month} {event.day} · {event.start}
          </div>
        </div>
      </div>

      <div style={{
        marginTop: 14, paddingTop: 14, borderTop: `1px dashed ${brand.border}`,
        display: 'flex', justifyContent: 'space-between', fontSize: 13.5, color: brand.panelInk,
      }}>
        <span>{isFree ? 'Free admission' : `$${event.price} × ${qty} ${ticketWord}`}</span>
        <span style={{ fontWeight: 600 }}>{isFree ? 'Free' : `$${total}`}</span>
      </div>

      <div style={{
        marginTop: 12, paddingTop: 12, borderTop: `1px solid ${brand.border}`,
        display: 'flex', justifyContent: 'space-between',
        fontFamily: brand.displayFont, fontWeight: 700, fontSize: 16, color: brand.panelInk,
      }}>
        <span>Total</span>
        <span>{isFree ? 'Free' : `$${total}`}</span>
      </div>

      <div style={{
        marginTop: 16, paddingTop: 14, borderTop: `1px solid ${brand.border}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        fontSize: 10.5, fontWeight: 700, letterSpacing: '0.1em',
        textTransform: 'uppercase', color: brand.panelInkSoft,
      }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor"
             strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
          <polyline points="9 12 11 14 15 10" />
        </svg>
        Secure checkout
      </div>
    </aside>
  );
}

function MetaRow({ brand, icon, children }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'flex-start', gap: 10,
      fontFamily: brand.bodyFont, fontSize: 14, fontWeight: 600,
      color: brand.ink,
    }}>
      <div style={{
        flex: '0 0 auto', width: 32, height: 32, borderRadius: 8,
        background: brand.accentSoft, color: brand.accentDeep,
        display: 'grid', placeItems: 'center',
      }}>
        {icon === 'calendar' && (
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor"
               strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <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" />
          </svg>
        )}
        {icon === 'pin' && (
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor"
               strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
            <circle cx="12" cy="10" r="3" />
          </svg>
        )}
      </div>
      <div style={{ paddingTop: 1 }}>{children}</div>
    </div>
  );
}

function MapPlaceholder({ brand }) {
  return (
    <div style={{
      borderRadius: 10,
      border: `1px solid ${brand.border}`,
      height: 220,
      background: `linear-gradient(135deg, ${brand.accentSoft} 0%, #FFFFFF 100%)`,
      position: 'relative',
      overflow: 'hidden',
    }}>
      <svg width="100%" height="100%" viewBox="0 0 600 220" preserveAspectRatio="none"
           style={{ position: 'absolute', inset: 0, opacity: 0.5 }}>
        <path d="M0 60 L120 90 L210 50 L330 110 L420 80 L520 150 L600 130" stroke={brand.accentDeep}
              strokeWidth="2" fill="none" />
        <path d="M0 140 L80 170 L180 130 L260 180 L380 150 L470 200 L600 180" stroke={brand.accent}
              strokeWidth="2" fill="none" opacity="0.7" />
        <circle cx="300" cy="110" r="6" fill={brand.accent} />
        <circle cx="300" cy="110" r="14" fill={brand.accent} opacity="0.25" />
      </svg>
    </div>
  );
}

function ShareButton({ brand, label }) {
  return (
    <button type="button" style={{
      flex: 1,
      background: brand.surface, color: brand.panelInk,
      border: `1px solid ${brand.border}`,
      borderRadius: brand._buttonRadius != null ? brand._buttonRadius : 10,
      padding: '10px 12px',
      fontFamily: brand.bodyFont, fontSize: 12.5, fontWeight: 600,
      letterSpacing: '0.04em', cursor: 'pointer',
    }}>{label}</button>
  );
}

// ────────────────────────────────────────────────────────────────
// Tweaks panel
// ────────────────────────────────────────────────────────────────
function EventsTweaks({ t, setTweak }) {
  const {
    TweaksPanel: Panel, TweakSection: Section, TweakColor: Color,
    TweakSlider: Slider, TweakSelect: Select, TweakToggle: Toggle,
    TweakButton: Button,
  } = window;
  const resetAll = () => {
    const defaults = (typeof window !== 'undefined' && window.EVT_TWEAK_DEFAULTS) || {};
    Object.keys(defaults).forEach(k => setTweak(k, defaults[k]));
  };
  useEvtEffect(() => {
    if (!Panel) return;
    const id = window.setTimeout(() => window.postMessage({ type: '__activate_edit_mode' }, '*'), 0);
    return () => window.clearTimeout(id);
  }, [Panel]);
  if (!Panel) return null;
  const FONTS = [
    "'Poppins', system-ui, sans-serif",
    "'Inter', system-ui, sans-serif",
    "'Sora', system-ui, sans-serif",
    "'Open Sans', system-ui, sans-serif",
    "'DM Sans', system-ui, sans-serif",
    "'Manrope', system-ui, sans-serif",
    "'Bebas Neue', sans-serif",
    "'Playfair Display', serif",
  ];
  const fontLabel = (f) => f.replace(/['"]/g, '').split(',')[0];
  return (
    <Panel title="Studio settings" noDeckControls={true}>
      <Section label="Surfaces" />
      <Color label="Accent"      value={t.accent}     onChange={(v) => setTweak('accent', v)} />
      <Color label="Background"  value={t.background} onChange={(v) => setTweak('background', v)} />
      <Color label="Panel"       value={t.panel}      onChange={(v) => setTweak('panel', v)} />
      <Color label="Line color"  value={t.lineColor || '#ECECEC'}
                                 onChange={(v) => setTweak('lineColor', v)} />

      <Section label="Text on background" />
      <Color label="Primary"     value={t.headline}   onChange={(v) => setTweak('headline', v)} />
      <Color label="Secondary"   value={t.details}    onChange={(v) => setTweak('details', v)} />

      <Section label="Text on panel" />
      <Color label="Primary"     value={t.panelInk}     onChange={(v) => setTweak('panelInk', v)} />
      <Color label="Secondary"   value={t.panelInkSoft} onChange={(v) => setTweak('panelInkSoft', v)} />

      <Section label="Text on accent" />
      <Color label="Button text" value={t.buttonTextColor || '#FFFFFF'}
                                 onChange={(v) => setTweak('buttonTextColor', v)} />

      <Section label="Typography" />
      <Select label="Font family" value={t.font}
              options={FONTS.map(f => ({ value: f, label: fontLabel(f) }))}
              onChange={(v) => setTweak('font', v)} />
      <Slider label="Headline weight" value={t.weight} min={300} max={800} step={100}
              onChange={(v) => setTweak('weight', v)} />

      <Section label="Shape" />
      <Slider label="Panels"  value={t.panelRadius ?? t.radius}  min={0} max={28} step={1} unit="px"
              onChange={(v) => setTweak('panelRadius', v)} />
      <Slider label="Buttons" value={t.buttonRadius ?? t.radius} min={0} max={28} step={1} unit="px"
              onChange={(v) => setTweak('buttonRadius', v)} />

      <Section label="Thumbnails" />
      <Select label="Aspect ratio" value={t.thumbnailRatio || 'natural'}
              options={[
                { value: 'natural', label: 'Natural (fill card)' },
                { value: '1:1',     label: '1:1 — square' },
                { value: '4:3',     label: '4:3 — classic' },
                { value: '3:2',     label: '3:2 — photo' },
                { value: '16:9',    label: '16:9 — wide' },
              ]}
              onChange={(v) => setTweak('thumbnailRatio', v)} />

      <Section label="Hide" />
      <Toggle label="Filters"          value={!!t.hideFilters}     onChange={(v) => setTweak('hideFilters', v)} />
      <Toggle label="Thumbnail image"  value={!!t.hideThumbnail}   onChange={(v) => setTweak('hideThumbnail', v)} />
      <Toggle label="Date tag"         value={!!t.hideDateTag}     onChange={(v) => setTweak('hideDateTag', v)} />
      <Toggle label="Description"      value={!!t.hideDescription} onChange={(v) => setTweak('hideDescription', v)} />
      <Toggle label="Location"         value={!!t.hideLocation}    onChange={(v) => setTweak('hideLocation', v)} />
      <Toggle label="Price"            value={!!t.hidePrice}       onChange={(v) => setTweak('hidePrice', v)} />
      <Toggle label="Register button"  value={!!t.hideRegister}    onChange={(v) => setTweak('hideRegister', v)} />

      <Section label="" />
      <Button label="Restore default settings" secondary onClick={resetAll} />
    </Panel>
  );
}

function PoweredByZipper() {
  return (
    <div style={{
      padding: '36px 0 8px',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      gap: 10,
      fontSize: 10.5, fontWeight: 600, letterSpacing: '0.1em',
      textTransform: 'uppercase', color: '#9CA3AF',
    }}>
      <span>Powered by</span>
      <img src="zipper-logo-grey.svg" alt="Zipper" height="18"
           style={{ display: 'block', height: 18, width: 'auto' }} />
    </div>
  );
}

// Mount
const evtRoot = ReactDOM.createRoot(document.getElementById('root'));
evtRoot.render(<EventsApp brandId="halcyon" />);
