// 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;
// 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 }) {
  const textColor = brand._buttonTextColor || '#fff';
  return (
    <button type="button" onClick={onClick}
      style={{
        background: brand.accent, color: 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: 'pointer', whiteSpace: 'nowrap',
        display: 'inline-flex', alignItems: 'center', gap: 6,
      }}>
      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>
  );
}

// ────────────────────────────────────────────────────────────────
// 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>

      <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>

          <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>

          <h2 style={{
            margin: '26px 0 10px',
            fontFamily: brand.displayFont, fontWeight: 700,
            fontSize: mobile ? 17 : 19, letterSpacing: '-0.01em',
            color: brand.ink,
          }}>Location</h2>
          <div style={{
            fontFamily: brand.bodyFont, fontSize: 14, color: brand.inkSoft,
            marginBottom: 10,
          }}>{event.address}</div>
          <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>

        <aside style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{
            border: `1px solid ${brand.border}`,
            borderRadius: radius,
            background: brand.surface,
            padding: mobile ? '18px 18px' : '22px 22px',
          }}>
            <div style={{
              fontSize: 11, fontWeight: 700, letterSpacing: '0.1em',
              textTransform: 'uppercase', color: brand.panelInkSoft,
            }}>Price</div>
            <div style={{
              marginTop: 4,
              fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
              fontSize: 36, letterSpacing: '-0.02em',
              color: brand.panelInk, lineHeight: 1,
            }}>{event.price === 0 ? 'Free' : `$${event.price}`}</div>
            <div style={{
              marginTop: 6, fontFamily: brand.bodyFont, fontSize: 13,
              color: brand.panelInkSoft,
            }}>per attendee · cancellation up to 24 hours before</div>

            <div style={{ marginTop: 18 }}>
              <RegisterButton brand={brand}
                onClick={() => alert(`Registered for ${event.title}`)} />
            </div>
          </div>

          <div style={{
            border: `1px solid ${brand.border}`,
            borderRadius: radius,
            background: brand.surface,
            padding: mobile ? '16px 18px' : '18px 22px',
          }}>
            <div style={{
              fontSize: 11, fontWeight: 700, letterSpacing: '0.1em',
              textTransform: 'uppercase', color: brand.panelInkSoft,
            }}>Hosted by</div>
            <div style={{
              marginTop: 8,
              display: 'flex', alignItems: 'center', gap: 10,
            }}>
              <div style={{
                width: 38, height: 38, borderRadius: 10,
                background: brand.accent, color: '#fff',
                display: 'grid', placeItems: 'center',
                fontFamily: brand.displayFont, fontWeight: 800, fontSize: 15,
                flex: '0 0 auto',
              }}>H</div>
              <div style={{ minWidth: 0 }}>
                <div style={{
                  fontFamily: brand.displayFont, fontWeight: 700, fontSize: 14.5,
                  color: brand.panelInk,
                }}>Halcyon Pilates</div>
                <a href="#" style={{
                  fontSize: 12.5, color: brand.accent, textDecoration: 'none', fontWeight: 600,
                  display: 'inline-flex', alignItems: 'center', gap: 4, marginTop: 2,
                }}>
                  <svg width="11" height="11" 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>
                  Brooklyn, New York
                </a>
              </div>
            </div>
          </div>

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

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" />);
