// stepper-class.jsx — Stripe-style split-screen, collapsible-section variant
// of the Class booking flow. Supports both mobile + desktop, and a logged-in
// returning-client mode (family members + active membership).
//
// Mounts <StepperClassApp /> to #root (unless data-framed is set).
// Reuses brand data from brands.jsx and shared components from
// components.jsx / scenarios.jsx / flows.jsx.

const { useState: useStateSC, useEffect: useEffectSC } = React;

const MOBILE_BREAKPOINT = 900;
function useViewportIsMobile() {
  const [isMobile, setIsMobile] = useStateSC(
    typeof window !== 'undefined' ? window.innerWidth < MOBILE_BREAKPOINT : false,
  );
  useEffectSC(() => {
    const onResize = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return isMobile;
}

// ────────────────────────────────────────────────────────────────
// Returning-client account profile (used when loggedIn = true).
// One per brand. Match family/membership feel to the brand.
// ────────────────────────────────────────────────────────────────
const RETURNING_PROFILES = {
  halcyon: {
    customer: { name: 'Jordan Reyes', email: 'jordan.reyes@gmail.com', phone: '(347) 555-0181' },
    family: [
      { id: 'kid-1', name: 'Ellie Reyes',  relation: 'Daughter (12)' },
      { id: 'kid-2', name: 'Marcus Reyes', relation: 'Son (10)'      },
    ],
    membership: { name: 'Unlimited Reformer', renews: 'Sep 1', credits: 'Unlimited classes' },
    creditsLeft: 6,            // for non-unlimited memberships; here informational
    guestPasses: 2,
    initials: 'JR',
  },
  forge: {
    customer: { name: 'Sam Bennett', email: 'sam.bennett@hey.com', phone: '(512) 555-0144' },
    family: [
      { id: 'spouse', name: 'Alex Bennett', relation: 'Spouse' },
    ],
    membership: { name: 'Unlimited Strength', renews: 'Sep 14', credits: 'Unlimited classes' },
    creditsLeft: 8,
    guestPasses: 3,
    initials: 'SB',
  },
  sol: {
    customer: { name: 'Priya Shah', email: 'priya.shah@gmail.com', phone: '(303) 555-0127' },
    family: [
      { id: 'kid', name: 'Riya Shah', relation: 'Daughter (14)' },
      { id: 'parent', name: 'Asha Shah', relation: 'Mother' },
    ],
    membership: { name: 'Unlimited Yoga', renews: 'Sep 6', credits: 'Unlimited classes' },
    creditsLeft: 5,
    guestPasses: 1,
    initials: 'PS',
  },
};

function StepperClassApp({ mobile: mobileProp, loggedIn = false, initialBrand = 'halcyon' }) {
  const viewportIsMobile = useViewportIsMobile();
  const mobile = mobileProp !== undefined ? mobileProp : viewportIsMobile;
  const allBrands = window.BRANDS;
  const [brandId, setBrandId] = useStateSC(initialBrand);
  const baseBrand = allBrands[brandId];
  const profile = loggedIn ? RETURNING_PROFILES[brandId] : null;

  // ── Studio settings (tweaks) panel — opt-in via window.SC_TWEAKS_ENABLED ──
  const tweaksEnabled = typeof window !== 'undefined' && window.SC_TWEAKS_ENABLED;
  const tweakDefaults = (typeof window !== 'undefined' && window.SC_TWEAK_DEFAULTS) || {};
  const [t, setTweak] = (tweaksEnabled ? window.useTweaks(tweakDefaults) : [tweakDefaults, () => {}]);

  const brand = tweaksEnabled ? {
    ...baseBrand,
    accent:        t.accent     ?? baseBrand.accent,
    accentDeep:    t.accent     ?? baseBrand.accentDeep,
    accentSoft:    baseBrand.accentSoft,
    surface:       t.panel      ?? baseBrand.surface,
    border:        t.lineColor  ?? baseBrand.border,
    ink:           t.headline   ?? baseBrand.ink,
    inkSoft:       t.details    ?? baseBrand.inkSoft,
    displayFont:   t.font       ?? baseBrand.displayFont,
    bodyFont:      t.font       ?? baseBrand.bodyFont,
    displayWeight: t.weight     ?? baseBrand.displayWeight,
    _radius:       t.radius     ?? 12,
    _buttonTextColor: t.buttonTextColor,
  } : { ...baseBrand, _radius: 12 };
  const appBg = tweaksEnabled
    ? (t.background ?? '#FAFAF7')
    : ((typeof window !== 'undefined' && window.STEPPER_APP_BG) || '#FAFAF7');
  const hideTerms = !!t.hideTerms;
  const hideBillingAddress = !!t.hideBillingAddress;
  const hideLogo = !!t.hideLogo;

  const c = brand.class;

  // --- form state ---
  // Single-attendee booking (matches the Purchase screen pattern).
  const [activeStep, setActiveStep] = useStateSC(1);
  const [completed, setCompleted] = useStateSC({});
  const [tierId, setTierId] = useStateSC(loggedIn ? 'membership' : 'dropin');
  const tier = c.pricing.find(t => t.id === tierId) || c.pricing[0];
  // Buyer details — name split into first/last, address moved to step 3.
  const defaultCustomer = {
    firstName: '', lastName: '', email: '', phone: '',
    street: '', apt: '', city: '', state: '', zip: '',
  };
  const splitProfileCustomer = (p) => {
    const parts = (p?.name || '').trim().split(/\s+/);
    return {
      ...defaultCustomer,
      firstName: parts[0] || '',
      lastName: parts.slice(1).join(' '),
      email: p?.email || '',
      phone: p?.phone || '',
    };
  };
  const [customer, setCustomer] = useStateSC(loggedIn ? splitProfileCustomer(profile.customer) : defaultCustomer);
  // Waiver — single attendee. Logged-in clients are already on file.
  const [waiverOpen, setWaiverOpen] = useStateSC(false);
  const [waiverChecked, setWaiverChecked] = useStateSC(loggedIn);
  // SMS + terms + recipient
  const [smsTransactional, setSmsTransactional] = useStateSC(true);
  const [smsMarketing, setSmsMarketing] = useStateSC(true);
  const [agreeTerms, setAgreeTerms] = useStateSC(true);
  const [forSomeoneElse, setForSomeoneElse] = useStateSC(false);
  const [recipientType, setRecipientType] = useStateSC(''); // '' | 'family' | 'guest'
  const [recipient, setRecipient] = useStateSC({
    firstName: '', lastName: '', birthday: '',
    email: '', phone: '',
  });
  const [recipientWaiverChecked, setRecipientWaiverChecked] = useStateSC(false);
  const [referralSource, setReferralSource] = useStateSC('');
  // Payment
  const [savePay, setSavePay] = useStateSC(true);
  const [discount, setDiscount] = useStateSC(0);
  const [promoCode, setPromoCode] = useStateSC('');
  const [summaryOpen, setSummaryOpen] = useStateSC(false);   // mobile drawer state

  // Static — single attendee, no family/guest arrays remain.
  const whoFor = { self: true, family: [], guests: [], addedFamily: [], allWaiversSigned: waiverChecked };
  const householdTierId = tierId;
  const setHouseholdTierId = setTierId;
  const guestTierIds = [];
  const setGuestTierIds = () => {};

  // Charge model: drop-ins are per-person, packs and memberships are a
  // single household purchase regardless of how many bookings they cover
  // today (the remaining sessions stay on the account for next time).
  const tierTotalForCount = (t, count) => {
    if (!t || count <= 0) return 0;
    if (t.recurring) return t.price;
    if (t.sessions && t.sessions > 1) return t.price;
    return t.price * count;
  };

  const addedFamilyCount = (whoFor.addedFamily || []).length;
  const familyTotalCount = whoFor.family.length + addedFamilyCount;
  const householdCount = (whoFor.self ? 1 : 0) + familyTotalCount;
  const guestCount = whoFor.guests.length;
  const attendeeCount = Math.max(1, householdCount + guestCount);
  const dropInUnitPrice = c.pricing[0].price;

  const householdTier = c.pricing.find(t => t.id === householdTierId) || c.pricing[0];
  const guestTiers = whoFor.guests.map((_, i) =>
    c.pricing.find(t => t.id === (guestTierIds[i] || 'dropin')) || c.pricing[0]
  );

  // Logged-in mode: account holder uses membership credit or drop-in;
  // family members always pay drop-in (no per-family choice); each guest
  // can pay with their own tier or burn a guest pass off the account.
  // NLI mode: household shares one tier; each guest picks their own.
  const usingMembership = loggedIn && tierId === 'membership';
  let subtotal, membershipCredit, displayPrice, total, unitPrice;
  if (loggedIn) {
    const householdGrossDropIn = dropInUnitPrice * householdCount;
    const guestGross = whoFor.guests.reduce((sum, _, i) => {
      const id = guestTierIds[i] || 'dropin';
      if (id === 'guestpass') return sum;
      const t = c.pricing.find(t => t.id === id) || c.pricing[0];
      return sum + tierTotalForCount(t, 1);
    }, 0);
    subtotal = householdGrossDropIn + guestGross;
    membershipCredit = usingMembership && whoFor.self ? dropInUnitPrice : 0;
    displayPrice = subtotal - membershipCredit;
    total = Math.max(0, displayPrice - discount);
    unitPrice = dropInUnitPrice;
  } else {
    const householdSubtotal = tierTotalForCount(householdTier, householdCount);
    const guestSubtotal = guestTiers.reduce((sum, t) => sum + tierTotalForCount(t, 1), 0);
    subtotal = householdSubtotal + guestSubtotal;
    membershipCredit = 0;
    displayPrice = subtotal;
    total = Math.max(0, displayPrice - discount);
    unitPrice = householdTier.price;
  }

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

  const whoForSummary = () => {
    const ppl = [];
    if (whoFor.self) ppl.push(loggedIn ? profile.customer.name.split(' ')[0] : 'You');
    whoFor.family.forEach(id => {
      const member = profile?.family.find(f => f.id === id);
      if (member) ppl.push(member.name.split(' ')[0]);
    });
    (whoFor.addedFamily || []).forEach(f => {
      if (f.name) ppl.push(f.name.trim().split(' ')[0]);
    });
    whoFor.guests.forEach(g => ppl.push(g.name || 'Guest'));
    return ppl.length ? `${ppl.length} spot${ppl.length > 1 ? 's' : ''} reserved · ${ppl.join(' + ')}` : 'No attendees selected';
  };

  const paySummary = () => {
    if (loggedIn) {
      const selfPart = whoFor.self ? (usingMembership ? 'Membership' : 'Drop-in') : null;
      const familyPart = familyTotalCount > 0
        ? `${familyTotalCount} family`
        : null;
      const guestPart = guestCount > 0
        ? `${guestCount} guest${guestCount > 1 ? 's' : ''}`
        : null;
      const parts = [selfPart, familyPart, guestPart].filter(Boolean);
      return `${parts.join(' · ')} · $${total.toFixed(2)}`;
    }
    // NLI summary collapses to "Household: X · N guests" so the step header
    // stays compact even when several payment methods were chosen.
    const householdLabelShort = householdCount > 0 ? `${householdTier.label}` : null;
    const guestLabel = guestCount > 0
      ? `${guestCount} guest${guestCount > 1 ? 's' : ''}`
      : null;
    const parts = [householdLabelShort, guestLabel].filter(Boolean);
    return `${parts.join(' · ')} · $${total.toFixed(2)}`;
  };

  // Per-group payment breakdown used by the order summary. Each entry is one
  // line item the buyer sees on the right (or in the mobile drawer).
  const householdLabel = whoFor.self && familyTotalCount === 0
    ? 'Yourself'
    : !whoFor.self && familyTotalCount > 0
      ? `${familyTotalCount} family member${familyTotalCount > 1 ? 's' : ''}`
      : `Yourself + ${familyTotalCount} family member${familyTotalCount > 1 ? 's' : ''}`;
  const paymentBreakdown = loggedIn ? [
    // Self
    ...(whoFor.self ? [{
      label: profile.customer.name.split(' ')[0] || 'Yourself',
      sub: usingMembership ? `${profile.membership.name} · Free` : 'Drop-in',
      amount: usingMembership ? 0 : dropInUnitPrice,
    }] : []),
    // Family on file (selected) + inline-added family
    ...whoFor.family.map(id => {
      const member = profile.family.find(f => f.id === id);
      return {
        label: member ? member.name.split(' ')[0] : 'Family',
        sub: 'Drop-in',
        amount: dropInUnitPrice,
      };
    }),
    ...(whoFor.addedFamily || []).map(f => ({
      label: f.name ? f.name.trim().split(' ')[0] : 'Family',
      sub: 'Drop-in',
      amount: dropInUnitPrice,
    })),
    // Guests — guest pass renders as $0/Pass
    ...whoFor.guests.map((g, i) => {
      const id = guestTierIds[i] || 'dropin';
      if (id === 'guestpass') {
        return { label: g.name || `Guest ${i + 1}`, sub: 'Guest pass', amount: 0 };
      }
      const t = c.pricing.find(t => t.id === id) || c.pricing[0];
      return {
        label: g.name || `Guest ${i + 1}`,
        sub: t.label,
        amount: tierTotalForCount(t, 1),
      };
    }),
  ] : [
    ...(householdCount > 0 ? [{
      label: householdLabel,
      sub: householdTier.label + (householdCount > 1 && householdTier.sessions === 1 && !householdTier.recurring
        ? ` · ${householdCount} × $${householdTier.price}`
        : ''),
      amount: tierTotalForCount(householdTier, householdCount),
    }] : []),
    ...whoFor.guests.map((g, i) => ({
      label: g.name ? g.name : `Guest ${i + 1}`,
      sub: guestTiers[i] ? guestTiers[i].label : 'Drop-in',
      amount: tierTotalForCount(guestTiers[i], 1),
    })),
  ];

  // ─── Step bodies ───────────────────────────────────────────────
  // Step 1 — booker details (single attendee), liability waiver, optional
  // "for someone else" block, SMS consent. Matches the Purchase screen but
  // keeps the waiver since this is a class/appointment booking.
  const detailsSummary = customer.firstName && customer.email
    ? `${customer.firstName} ${customer.lastName} · ${customer.email}`.trim()
    : null;
  const stepWhoFor = (
    <StepCard
      brand={brand} mobile={mobile}
      step={1} title="Your details"
      isOpen={activeStep === 1} isCompleted={completed[1]}
      summary={completed[1] ? detailsSummary : null}
      onEdit={() => editStep(1)}
    >
      {loggedIn ? (
        <div style={{
          padding: '12px 14px', borderRadius: 12,
          background: brand.accentSoft, border: `1px solid ${brand.border}`,
          fontSize: 13.5, color: brand.ink, lineHeight: 1.5,
        }}>
          Booking as <strong>{profile.customer.name}</strong> · {profile.customer.email}.
          Waiver already on file.
        </div>
      ) : (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field brand={brand} label="First name"
                   value={customer.firstName}
                   onChange={v => setCustomer(c => ({ ...c, firstName: v }))}
                   autoComplete="given-name" />
            <Field brand={brand} label="Last name"
                   value={customer.lastName}
                   onChange={v => setCustomer(c => ({ ...c, lastName: v }))}
                   autoComplete="family-name" />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Field brand={brand} label="Email" type="email"
                   value={customer.email}
                   onChange={v => setCustomer(c => ({ ...c, email: v }))}
                   autoComplete="email" />
            <Field brand={brand} label="Phone" type="tel"
                   value={customer.phone}
                   onChange={v => setCustomer(c => ({ ...c, phone: v }))}
                   autoComplete="tel" />
          </div>
          <SmsConsent
            brand={brand}
            transactional={smsTransactional} setTransactional={setSmsTransactional}
            marketing={smsMarketing} setMarketing={setSmsMarketing}
          />
          <SCRecipientBlock
            brand={brand}
            enabled={forSomeoneElse} setEnabled={setForSomeoneElse}
            type={recipientType} setType={setRecipientType}
            recipient={recipient} setRecipient={setRecipient}
            waiverChecked={recipientWaiverChecked}
            setWaiverChecked={setRecipientWaiverChecked}
            brandName={brand.name}
          />
          {!forSomeoneElse && (
            <WaiverInline
              brand={brand} brandName={brand.name}
              open={waiverOpen} setOpen={setWaiverOpen}
              checked={waiverChecked} onChange={setWaiverChecked}
            />
          )}
          <SCReferralSourceSelect
            brand={brand}
            value={referralSource}
            onChange={setReferralSource}
          />
        </>
      )}
      <StepNext brand={brand} onClick={() => goNext(1)} />
    </StepCard>
  );

  const loggedInPayOptions = loggedIn ? [
    {
      id: 'membership',
      label: `Use ${profile.membership.name.toLowerCase()} credit`,
      sub: `${profile.membership.credits} · renews ${profile.membership.renews}`,
      cost: 'Free',
    },
    {
      id: 'dropin',
      label: 'Pay drop-in',
      sub: 'Save your credits for another time',
      cost: `$${c.pricing[0].price}`,
    },
  ] : null;

  const stepPay = (
    <StepCard
      brand={brand} mobile={mobile}
      step={2} title="Choose how to pay"
      isOpen={activeStep === 2} isCompleted={completed[2]}
      summary={completed[2] ? paySummary() : null}
      onEdit={() => editStep(2)}
    >
      <PaymentGroup
        brand={brand}
        title={loggedIn ? 'For you' : 'For this booking'}
        subtitle={loggedIn
          ? 'Use your membership credit or pay drop-in.'
          : 'Pick a drop-in, class pack, or membership.'}
      >
        {loggedIn ? (
          <PaymentSourceChoice
            brand={brand}
            options={loggedInPayOptions}
            value={tierId}
            onChange={setTierId}
          />
        ) : (
          <>
            <TierPicker brand={brand} options={c.pricing} value={tierId} onChange={setTierId} />
            {tier.sessions > 1 && !tier.recurring && (
              <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 10, lineHeight: 1.5 }}>
                1 credit applied today. {Math.max(0, tier.sessions - 1)} remaining for future bookings.
              </div>
            )}
            {tier.recurring && (
              <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 10, lineHeight: 1.5 }}>
                Membership starts today and includes this class. Pause or cancel any time, no fees.
              </div>
            )}
          </>
        )}
      </PaymentGroup>
      <StepNext brand={brand} onClick={() => goNext(2)} />
    </StepCard>
  );

  // For logged-in: payment details are simplified — confirmation + saved card.
  // When the booking is free (membership credit covers it, or a discount
  // brings total to $0), we skip every credit-card affordance.
  const isFree = total === 0;
  const stepPayment = (
    <StepCard
      brand={brand} mobile={mobile}
      step={3} title={isFree ? 'Confirm booking' : (loggedIn ? 'Confirm & book' : 'Payment')}
      isOpen={activeStep === 3} isCompleted={false}
      summary={null}
      onEdit={() => editStep(3)}
    >
      {isFree ? (
        <>
          <div style={{
            marginTop: loggedIn ? 0 : 14,
            padding: '14px 16px',
            borderRadius: 12,
            background: brand.accentSoft,
            border: `1px solid ${brand.border}`,
            fontSize: 13.5, color: brand.ink, lineHeight: 1.5,
          }}>
            {usingMembership
              ? `This booking is covered by your ${profile.membership.name.toLowerCase()} membership. No payment needed.`
              : 'No payment required — your discount covers the full booking.'}
          </div>
        </>
      ) : loggedIn ? (
        <SavedPaymentRow brand={brand} customer={profile.customer} />
      ) : (
        <>
          <PaymentSection brand={brand} methods={{ apple: true, google: true, link: true, ach: true }} />
          <SavePayment brand={brand} returning={false} value={savePay} onChange={setSavePay} />
          {!hideBillingAddress && (
            <SCAddressBlock brand={brand} customer={customer} setCustomer={setCustomer} />
          )}
        </>
      )}
      {!loggedIn && !hideTerms && (
        <SCPurchaseTermsAccordion
          brand={brand} agreed={agreeTerms} setAgreed={setAgreeTerms}
        />
      )}

      {(() => {
         const detailsOk = loggedIn
           || (customer.firstName && customer.lastName && /\S+@\S+\.\S+/.test(customer.email));
         // Waiver gating:
         //   - logged-in: already on file
         //   - booking for self: buyer signs the waiver
         //   - booking for family: family member's waiver checkbox (in their card)
         //   - booking for guest: signed at the studio at check-in, not required here
         const waiverOk = loggedIn
           || (forSomeoneElse
                 ? (recipientType === 'guest' || (recipientType === 'family' && recipientWaiverChecked))
                 : waiverChecked);
         const termsOk = hideTerms || agreeTerms;
         const ok = (loggedIn || (waiverOk && termsOk && detailsOk));
         return (
           <button
             disabled={!ok}
             onClick={() => alert(`Booked ${c.title} · ${isFree ? 'Free' : `$${total.toFixed(2)}`}`)}
             style={{
               width: '100%',
               marginTop: 18,
               background: ok ? brand.accent : '#D8D6CF',
               color: '#fff',
               border: 0, borderRadius: 12,
               padding: '16px 18px',
               fontSize: 15, fontWeight: 700,
               cursor: ok ? 'pointer' : 'not-allowed',
               fontFamily: brand.displayFont,
               letterSpacing: '-0.005em',
             }}>
             {isFree
               ? 'Confirm booking · Free'
               : (loggedIn
                   ? `Confirm booking · $${total.toFixed(2)}`
                   : (tier.recurring ? `Start membership · $${total}/mo` : `Book class · $${total}`))
             }
           </button>
         );
       })()}
    </StepCard>
  );

  // ─── Layout ────────────────────────────────────────────────────
  return (
    <div style={{
      minHeight: mobile ? 0 : '100vh',
      background: appBg,
      fontFamily: brand.bodyFont,
      color: brand.ink,
    }}>
      {/* Brand bar */}
      {!hideLogo && (
      <BrandBar
        brand={brand} mobile={mobile} loggedIn={loggedIn}
        profile={profile}
        allBrands={allBrands} brandId={brandId}
        setBrandId={(id) => {
          setBrandId(id);
          setActiveStep(1);
          setCompleted({});
          // Reset state that's brand-dependent
          if (loggedIn) {
            const newProfile = RETURNING_PROFILES[id];
            setCustomer(newProfile.customer);
            setTierId('membership');
          }
        }}
      />
      )}

      {/* Body — desktop = 2 col, mobile = single col with collapsible summary */}
      {mobile ? (
        <div style={{ padding: '14px 16px 120px', display: 'flex', flexDirection: 'column', gap: 12 }}>
          <ClassDetailsCard brand={brand} c={c} mobile />
          {loggedIn
            ? <WelcomeBackCallout brand={brand} profile={profile} />
            : <SignInCallout brand={brand} />}
          {stepWhoFor}
          {stepPay}
          {stepPayment}
        </div>
      ) : (
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'minmax(0, 1fr) 380px',
          gap: 0,
          maxWidth: 1280,
          margin: '0 auto',
          padding: '28px 28px 60px',
          alignItems: 'start',
        }}>
          <div style={{ paddingRight: 48, display: 'flex', flexDirection: 'column', gap: 14 }}>
            <ClassDetailsCard brand={brand} c={c} />
            {loggedIn
              ? <WelcomeBackCallout brand={brand} profile={profile} />
              : <SignInCallout brand={brand} />}
            {stepWhoFor}
            {stepPay}
            {stepPayment}
          </div>

          <OrderSummaryAside
            brand={brand} c={c} tier={tier}
            displayPrice={displayPrice} subtotal={subtotal} membershipCredit={membershipCredit}
            discount={discount} total={total}
            promoCode={promoCode} setPromoCode={setPromoCode}
            onApplyPromo={() => promoCode && setDiscount(5)}
            usingMembership={usingMembership}
            attendeeCount={attendeeCount} dropInUnitPrice={dropInUnitPrice}
            paymentBreakdown={paymentBreakdown}
          />
        </div>
      )}

      {/* Mobile sticky bottom bar with collapsible summary drawer */}
      {mobile && (
        <MobileBottomBar
          brand={brand} c={c} tier={tier}
          displayPrice={displayPrice} subtotal={subtotal} membershipCredit={membershipCredit}
          discount={discount} total={total}
          promoCode={promoCode} setPromoCode={setPromoCode}
          onApplyPromo={() => promoCode && setDiscount(5)}
          open={summaryOpen} setOpen={setSummaryOpen}
          usingMembership={usingMembership}
          attendeeCount={attendeeCount} dropInUnitPrice={dropInUnitPrice}
          paymentBreakdown={paymentBreakdown}
        />
      )}

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

// ────────────────────────────────────────────────────────────────
// WelcomeBackCallout — replaces SignInCallout for returning members.
// Mirrors the visual shape of SignInCallout (white card with accent
// border + soft glow) but greets the user and surfaces their active
// membership and renewal date instead of a sign-in CTA.
// ────────────────────────────────────────────────────────────────
function WelcomeBackCallout({ brand, profile }) {
  const firstName = profile.customer.name.split(' ')[0];
  return (
    <div style={{ padding: '4px 2px', marginBottom: 10 }}>
      <div style={{
        fontFamily: brand.displayFont,
        fontWeight: brand.displayWeight,
        fontSize: 26,
        color: brand.ink,
        lineHeight: 1.2,
        letterSpacing: '-0.01em',
      }}>
        Welcome back, {firstName}
      </div>
      <div style={{ fontSize: 13, color: brand.inkSoft, marginTop: 4, lineHeight: 1.4 }}>
        {profile.membership.name} membership · renews {profile.membership.renews}
        {profile.guestPasses > 0 && (
          <> · {profile.guestPasses} guest pass{profile.guestPasses === 1 ? '' : 'es'} available</>
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Brand bar — shows logged-in user's avatar instead of brand-switcher
// when loggedIn=true. Brand switcher still visible (for prototype demo).
// ────────────────────────────────────────────────────────────────
function BrandBar({ brand, mobile, loggedIn, profile, allBrands, brandId, setBrandId }) {
  return (
    <div style={{
      padding: mobile ? '20px 16px 0' : '28px 28px 0',
      maxWidth: 1280, margin: '0 auto',
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      gap: 12,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
        <div style={{
          width: mobile ? 36 : 40, height: mobile ? 36 : 40,
          borderRadius: brand._radius ?? 10,
          background: brand.accent, color: '#fff',
          display: 'grid', placeItems: 'center',
          fontFamily: brand.displayFont, fontWeight: 800,
          fontSize: mobile ? 15 : 17, letterSpacing: '-0.01em',
          flex: '0 0 auto',
        }}>{brand.initials}</div>
        <div style={{
          fontFamily: brand.displayFont, fontWeight: brand.displayWeight,
          fontSize: mobile ? 16 : 19, color: brand.ink,
          letterSpacing: '-0.01em',
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{brand.name}</div>
      </div>

      {loggedIn && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{
            width: 32, height: 32, borderRadius: 999,
            background: brand.accentSoft, color: brand.accentDeep,
            display: 'grid', placeItems: 'center',
            fontWeight: 700, fontSize: 12,
            fontFamily: brand.displayFont,
            border: `1.5px solid ${brand.accent}`,
          }}>{profile.initials}</div>
          {!mobile && (
            <div style={{ fontSize: 13, color: brand.ink, fontWeight: 600 }}>
              {profile.customer.name.split(' ')[0]}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// SavedPaymentRow — single row showing card on file (logged-in only)
// ────────────────────────────────────────────────────────────────
function SavedPaymentRow({ brand, customer }) {
  return (
    <div style={{
      border: `1px solid ${brand.border}`,
      borderRadius: 12,
      padding: '14px 16px',
      display: 'flex', alignItems: 'center', gap: 12,
      background: '#FAFAF7',
    }}>
      <div style={{
        width: 38, height: 26, borderRadius: 5,
        background: 'linear-gradient(135deg, #1F1D1A, #44423E)',
        color: '#fff',
        fontSize: 8, fontWeight: 800,
        display: 'grid', placeItems: 'center',
        flex: '0 0 auto',
        letterSpacing: '0.05em',
      }}>VISA</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13.5, fontWeight: 600, color: brand.ink }}>Visa ending in 4242</div>
        <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 1 }}>Default · {customer.email}</div>
      </div>
      <button style={{
        background: 'transparent', border: 0,
        color: brand.accent, fontSize: 12, fontWeight: 700,
        letterSpacing: '0.06em', textTransform: 'uppercase',
        cursor: 'pointer',
      }}>Change</button>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// OrderSummaryAside — sticky right sidebar on desktop
// ────────────────────────────────────────────────────────────────
function OrderSummaryAside({ brand, c, tier, displayPrice, subtotal, membershipCredit, discount, total, promoCode, setPromoCode, onApplyPromo, usingMembership, attendeeCount, dropInUnitPrice, paymentBreakdown }) {
  return (
    <aside style={{
      position: 'sticky',
      top: 28,
      background: '#fff',
      border: `1px solid ${brand.border}`,
      borderRadius: 14,
      padding: 24,
      boxShadow: '0 1px 2px rgba(0,0,0,0.03)',
    }}>
      <div style={{ fontFamily: brand.displayFont, fontWeight: 700, fontSize: 18, color: brand.ink, marginBottom: 18, letterSpacing: '-0.01em' }}>Order Summary</div>

      <SummaryLineItem brand={brand} c={c} tier={tier} displayPrice={displayPrice} usingMembership={usingMembership} attendeeCount={attendeeCount} dropInUnitPrice={dropInUnitPrice} paymentBreakdown={paymentBreakdown} />

      <PromoInput brand={brand} value={promoCode} onChange={setPromoCode} onApply={onApplyPromo} />

      <SummaryTotals brand={brand} subtotal={subtotal} membershipCredit={membershipCredit} discount={discount} total={total} usingMembership={usingMembership} />

      <div style={{
        marginTop: 18, paddingTop: 16,
        borderTop: `1px solid ${brand.border}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        fontSize: 11, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase',
        color: brand.inkSoft,
      }}>
        <svg width="14" height="14" 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 SSL Checkout
      </div>
    </aside>
  );
}

// ────────────────────────────────────────────────────────────────
// MobileBottomBar — fixed bottom CTA + collapsible summary
// ────────────────────────────────────────────────────────────────
function MobileBottomBar({ brand, c, tier, displayPrice, subtotal, membershipCredit, discount, total, promoCode, setPromoCode, onApplyPromo, open, setOpen, usingMembership, attendeeCount, dropInUnitPrice, paymentBreakdown }) {
  return (
    <div style={{
      position: 'fixed',
      bottom: 0, left: 0, right: 0,
      background: '#fff',
      borderTop: `1px solid ${brand.border}`,
      boxShadow: '0 -4px 24px rgba(0,0,0,0.06)',
      zIndex: 30,
    }}>
      {open && (
        <div style={{
          padding: '16px 16px 12px',
          borderBottom: `1px solid ${brand.border}`,
          maxHeight: '50vh',
          overflow: 'auto',
        }}>
          <SummaryLineItem brand={brand} c={c} tier={tier} displayPrice={displayPrice} usingMembership={usingMembership} attendeeCount={attendeeCount} dropInUnitPrice={dropInUnitPrice} paymentBreakdown={paymentBreakdown} compact />
          <div style={{ height: 12 }}></div>
          <PromoInput brand={brand} value={promoCode} onChange={setPromoCode} onApply={onApplyPromo} />
          <div style={{ height: 12 }}></div>
          <SummaryTotals brand={brand} subtotal={subtotal} membershipCredit={membershipCredit} discount={discount} total={total} usingMembership={usingMembership} />
        </div>
      )}
      <button
        onClick={() => setOpen(!open)}
        style={{
          width: '100%',
          background: 'transparent',
          border: 0,
          padding: '12px 16px 10px',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          cursor: 'pointer',
        }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <svg width="14" height="14" 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="18 15 12 9 6 15"/>
          </svg>
          <span style={{ fontSize: 12, fontWeight: 700, color: brand.inkSoft, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
            {open ? 'Hide summary' : 'Order summary'}
          </span>
        </div>
        <div style={{ fontFamily: brand.displayFont, fontWeight: 700, fontSize: 15, color: brand.ink }}>
          {usingMembership ? 'Free' : `$${total.toFixed(2)}`}
        </div>
      </button>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Reusable summary chunks
// ────────────────────────────────────────────────────────────────
function SummaryLineItem({ brand, c, tier, displayPrice, usingMembership, attendeeCount = 1, dropInUnitPrice, compact, paymentBreakdown }) {
  const additional = Math.max(0, attendeeCount - 1);
  const showLegacyBreakdown = attendeeCount > 1 && !paymentBreakdown;
  return (
    <div style={{ marginBottom: compact ? 0 : 18 }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
        <div style={{
          width: 56, height: 56, borderRadius: 10,
          flex: '0 0 auto',
          background: c.image ? `url(${c.image}) center/cover` : `linear-gradient(135deg, ${brand.accent}, ${brand.accentDeep})`,
          position: 'relative',
        }}>
          <div style={{
            position: 'absolute', top: -6, right: -6,
            minWidth: 22, height: 22, borderRadius: 999,
            padding: '0 6px',
            background: brand.ink, color: '#fff',
            display: 'grid', placeItems: 'center',
            fontSize: 11, fontWeight: 700,
          }}>{attendeeCount}</div>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600, color: brand.ink, lineHeight: 1.35 }}>{c.title}</div>
          <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 2, lineHeight: 1.4 }}>
            {c.instructor} · {c.date}
            <br/>
            {c.time} · {c.duration}
          </div>
          {showLegacyBreakdown && (
            <div style={{ fontSize: 11.5, color: brand.inkSoft, marginTop: 4, lineHeight: 1.4 }}>
              {usingMembership ? (
                <>1 × Membership credit{additional > 0 && <> · {additional} × Drop-in (${dropInUnitPrice})</>}</>
              ) : (
                <>{attendeeCount} × ${tier.price}</>
              )}
            </div>
          )}
        </div>
        <div style={{ fontFamily: brand.displayFont, fontSize: 14, fontWeight: 700, color: brand.ink, textAlign: 'right' }}>
          {usingMembership && additional === 0 ? (
            <>
              <div style={{ fontSize: 11, color: brand.inkSoft, fontWeight: 500, textDecoration: 'line-through' }}>${tier.price}</div>
              <div style={{ color: '#3A7A4D' }}>Free</div>
            </>
          ) : `$${displayPrice}`}
        </div>
      </div>
      {paymentBreakdown && paymentBreakdown.length > 0 && (
        <div style={{
          marginTop: 12, paddingTop: 12,
          borderTop: `1px dashed ${brand.border}`,
          display: 'flex', flexDirection: 'column', gap: 6,
        }}>
          {paymentBreakdown.map((row, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12, fontWeight: 600, color: brand.ink, lineHeight: 1.3 }}>{row.label}</div>
                <div style={{ fontSize: 11, color: brand.inkSoft, marginTop: 1 }}>{row.sub}</div>
              </div>
              <div style={{ fontSize: 12.5, fontWeight: 700, color: brand.ink, fontFamily: brand.displayFont }}>
                ${Number(row.amount).toFixed(2)}
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function PromoInput({ brand, value, onChange, onApply }) {
  return (
    <div>
      <div style={{ fontSize: 11, fontWeight: 700, color: brand.inkSoft, letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 8 }}>Gift or discount code</div>
      <div style={{ display: 'flex', gap: 8 }}>
        <input
          value={value}
          onChange={e => onChange(e.target.value)}
          placeholder="Code"
          style={{
            flex: 1,
            padding: '11px 12px',
            borderRadius: 8,
            border: `1px solid ${brand.border}`,
            background: '#F4F2EC',
            fontSize: 13,
            color: brand.ink,
            outline: 'none',
          }}
        />
        <button
          onClick={onApply}
          style={{
            padding: '0 16px',
            borderRadius: 8,
            border: `1px solid ${brand.border}`,
            background: '#fff',
            fontSize: 12, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase',
            color: brand.ink,
            cursor: 'pointer',
          }}>Apply</button>
      </div>
    </div>
  );
}

function SummaryTotals({ brand, subtotal, membershipCredit = 0, discount, total, usingMembership }) {
  return (
    <div style={{ paddingTop: 14, fontSize: 13.5 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '4px 0' }}>
        <span>Subtotal</span><span>${subtotal.toFixed(2)}</span>
      </div>
      {usingMembership && membershipCredit > 0 && (
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '4px 0', color: '#3A7A4D' }}>
          <span>Membership credit</span><span>−${membershipCredit.toFixed(2)}</span>
        </div>
      )}
      {discount > 0 && (
        <div style={{ display: 'flex', justifyContent: 'space-between', padding: '4px 0', color: brand.accent }}>
          <span>Discount</span><span>−${discount.toFixed(2)}</span>
        </div>
      )}
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '4px 0' }}>
        <span>Tax</span><span>$0.00</span>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '12px 0 0', borderTop: `1px solid ${brand.border}`, marginTop: 8, fontWeight: 700, fontFamily: brand.displayFont, fontSize: 15 }}>
        <span>Total</span><span>${total.toFixed(2)}</span>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Class details card (always visible)
// ────────────────────────────────────────────────────────────────
function ClassDetailsCard({ brand, c, mobile }) {
  return (
    <div style={{
      background: '#fff',
      border: `1px solid ${brand.border}`,
      borderRadius: 14,
      padding: mobile ? 14 : 18,
      display: 'flex',
      gap: mobile ? 12 : 16,
      alignItems: 'center',
    }}>
      <div style={{
        width: mobile ? 72 : 96, height: mobile ? 72 : 96, borderRadius: 12,
        flex: '0 0 auto',
        background: c.image ? `url(${c.image}) center/cover` : `linear-gradient(135deg, ${brand.accent}, ${brand.accentDeep})`,
      }}></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: mobile ? 10 : 11, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: brand.inkSoft, marginBottom: mobile ? 4 : 6 }}>You're booking</div>
        <div style={{ fontFamily: brand.displayFont, fontWeight: brand.displayWeight, fontSize: mobile ? 18 : 22, color: brand.ink, lineHeight: 1.2, letterSpacing: '-0.01em' }}>{c.title}</div>
        <div style={{ fontSize: mobile ? 12 : 13, color: brand.inkSoft, marginTop: mobile ? 4 : 6, lineHeight: 1.5 }}>
          {c.instructor} · {c.date} {mobile ? <br/> : 'at '}
          {c.time} · {c.duration}
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Step wrapper (collapsible card)
// ────────────────────────────────────────────────────────────────
function StepCard({ brand, mobile, step, title, isOpen, isCompleted, summary, onEdit, children }) {
  const stateColor = isOpen ? brand.accent : (isCompleted ? '#3A7A4D' : brand.border);
  return (
    <div style={{
      background: '#fff',
      border: `1px solid ${isOpen ? brand.accent : brand.border}`,
      boxShadow: isOpen ? `0 0 0 3px ${brand.accentSoft}` : 'none',
      borderRadius: 14,
      transition: 'all .2s ease',
      overflow: 'hidden',
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: mobile ? '14px 16px' : '18px 20px',
        cursor: !isOpen && isCompleted ? 'pointer' : 'default',
      }} onClick={() => { if (!isOpen && isCompleted) onEdit(); }}>
        <div style={{
          width: 26, height: 26, borderRadius: 999,
          background: isCompleted ? '#3A7A4D' : (isOpen ? brand.accent : 'transparent'),
          border: `1.5px solid ${stateColor}`,
          color: isCompleted || isOpen ? '#fff' : brand.inkSoft,
          fontSize: 13, fontWeight: 700,
          display: 'grid', placeItems: 'center',
          flex: '0 0 auto',
          fontFamily: brand.bodyFont,
        }}>
          {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,
            letterSpacing: '-0.005em',
          }}>{title}</div>
          {summary && !isOpen && (
            <div style={{ fontSize: mobile ? 12 : 13, color: brand.inkSoft, marginTop: 2 }}>{summary}</div>
          )}
        </div>
        {isCompleted && !isOpen && (
          <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',
          }}>Edit</button>
        )}
      </div>
      {isOpen && (
        <div style={{ padding: mobile ? '0 16px 16px' : '0 20px 20px' }}>
          {children}
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// SmsConsent — two compact, preselected SMS consent checkboxes
// shown directly under the phone field.
// ────────────────────────────────────────────────────────────────
function SmsConsent({ brand, transactional, setTransactional, marketing, setMarketing }) {
  const row = (checked, onChange, label) => (
    <label style={{
      display: 'flex', alignItems: 'flex-start', gap: 8,
      cursor: 'pointer',
      padding: '4px 0',
    }}>
      <span
        onClick={e => { e.preventDefault(); onChange(!checked); }}
        style={{
          flex: '0 0 14px',
          width: 14, height: 14,
          marginTop: 2,
          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="9" height="9" 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: 11.5, color: brand.inkSoft, lineHeight: 1.45 }}>{label}</span>
      <input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)} style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
    </label>
  );
  return (
    <div style={{ marginTop: 8, paddingLeft: 2 }}>
      {row(transactional, setTransactional, 'I agree to receive transactional SMS messages (class/appt reminders + confirmations).')}
      {row(marketing, setMarketing, 'I agree to receive other SMS communication from this business (news, promotions) and can opt-out at any time.')}
    </div>
  );
}

// PaymentGroup — labelled wrapper around a TierPicker so Step 2 can list one
// section per payment group (household vs. each guest). Title is the human
// label (e.g. "Yourself + Ava"); subtitle explains how the group's payment
// covers the bookings inside it.
function PaymentGroup({ brand, title, subtitle, children }) {
  return (
    <div>
      <div style={{
        fontSize: 11, fontWeight: 700, letterSpacing: '0.08em',
        textTransform: 'uppercase', color: brand.inkSoft, marginBottom: 4,
      }}>{title}</div>
      {subtitle && (
        <div style={{ fontSize: 12, color: brand.inkSoft, marginBottom: 10, lineHeight: 1.45 }}>
          {subtitle}
        </div>
      )}
      {children}
    </div>
  );
}

function StepNext({ brand, onClick }) {
  return (
    <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>
      <button onClick={onClick} style={{
        background: brand.accent, color: '#fff',
        border: 0, borderRadius: 10,
        padding: '12px 28px',
        fontSize: 14, fontWeight: 700,
        cursor: 'pointer',
        fontFamily: brand.displayFont,
        letterSpacing: '-0.005em',
      }}>Next</button>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Inline expandable waiver inside Payment step
// ────────────────────────────────────────────────────────────────
function WaiverInline({ brand, brandName, open, setOpen, checked, onChange }) {
  return (
    <div style={{
      border: `1px solid ${brand.border}`,
      borderRadius: 12,
      overflow: 'hidden',
      marginTop: 14,
      background: '#FAFAF7',
    }}>
      <button
        type="button"
        onClick={() => setOpen(!open)}
        style={{
          width: '100%',
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '12px 14px',
          background: 'transparent',
          border: 0,
          textAlign: 'left',
          cursor: 'pointer',
        }}>
        <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' }}>
        <Checkbox brand={brand} checked={checked} onChange={onChange}>
          I've read and agree to the liability waiver. I'm participating at my own risk and have no conditions that prevent safe practice.
        </Checkbox>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// "For someone else" recipient block — same pattern as the Purchase
// screen. Heart-circle/arrow-to-person icon, dashed accent card, with
// mutually-exclusive Family / Guest / Gift type checkboxes.
// ────────────────────────────────────────────────────────────────
function SCRecipientBlock({
  brand, enabled, setEnabled, type, setType, recipient, setRecipient,
  waiverChecked, setWaiverChecked, brandName,
}) {
  const pickType = (next) => {
    setType(prev => prev === next ? '' : next);
    if (next !== type) {
      setRecipient({
        firstName: '', lastName: '', birthday: '',
        email: '', phone: '',
      });
      if (setWaiverChecked) setWaiverChecked(false);
    }
  };
  const update = (k) => (v) => setRecipient(r => ({ ...r, [k]: v }));

  return (
    <div style={{
      marginTop: 18,
      border: `1.5px dashed ${enabled ? brand.accent : brand.border}`,
      background: enabled ? brand.accentSoft : '#fff',
      borderRadius: 14, padding: 16,
      transition: 'border-color .15s ease, background .15s ease',
    }}>
      <button
        type="button"
        onClick={() => setEnabled(!enabled)}
        aria-expanded={enabled}
        style={{
          width: '100%', background: 'transparent', border: 0,
          padding: 0, cursor: 'pointer', textAlign: 'left',
          display: 'flex', alignItems: 'center', gap: 12,
          fontFamily: brand.bodyFont,
        }}>
        <span aria-hidden="true" style={{
          width: 36, height: 36, borderRadius: '50%',
          background: enabled ? brand.accent : brand.surface,
          color: enabled ? '#fff' : brand.accent,
          display: 'grid', placeItems: 'center', flex: '0 0 36px',
          transition: 'background .15s ease, color .15s ease',
          border: enabled ? 'none' : `1.5px solid ${brand.border}`,
        }}>
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none"
               stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <circle cx="17" cy="8" r="3.2"/>
            <path d="M11.5 20 v-1 a4.5 4.5 0 0 1 4.5-4.5h1 a4.5 4.5 0 0 1 4.5 4.5 v1"/>
            {/* Arrow — same geometry as the SignInCallout log-in arrow */}
            <line x1="2" y1="12" x2="11" y2="12"/>
            <polyline points="6 7 11 12 6 17"/>
          </svg>
        </span>
        <span style={{ flex: 1, minWidth: 0 }}>
          <span style={{
            display: 'block',
            fontFamily: brand.displayFont, fontWeight: 700,
            fontSize: 15, color: brand.ink, letterSpacing: '-0.005em',
          }}>
            I'm booking this for someone else
          </span>
          <span style={{
            display: 'block', fontSize: 12.5, color: brand.inkSoft, marginTop: 2,
          }}>
            {enabled ? 'Pick who this booking is for.' : 'Booking a class for a family member, friend, or as a gift? Tap to add their details.'}
          </span>
        </span>
        <span aria-hidden="true" style={{
          width: 38, height: 22, borderRadius: 999,
          background: enabled ? brand.accent : brand.border,
          position: 'relative', transition: 'background .15s ease', flex: '0 0 38px',
        }}>
          <span style={{
            position: 'absolute', top: 2,
            left: enabled ? 18 : 2,
            width: 18, height: 18, borderRadius: '50%',
            background: '#fff', boxShadow: '0 1px 2px rgba(0,0,0,0.12)',
            transition: 'left .15s ease',
          }} />
        </span>
        <input type="checkbox" checked={enabled} onChange={() => setEnabled(!enabled)}
               style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
      </button>

      {enabled && (
        <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 22, paddingLeft: 2 }}>
            <SCTypeBox brand={brand} checked={type === 'family'}
                       onChange={() => pickType('family')} label="Family member" />
            <SCTypeBox brand={brand} checked={type === 'guest'}
                       onChange={() => pickType('guest')} label="Guest" />
          </div>

          {type === 'family' && (
            <SCRecipientSection brand={brand} groupTitle="FAMILY MEMBER"
              helper="We'll save them to your account so you can book for them with one tap next time.">
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                <Field brand={brand} label="First name"
                       value={recipient.firstName} onChange={update('firstName')} autoComplete="given-name" />
                <Field brand={brand} label="Last name"
                       value={recipient.lastName} onChange={update('lastName')} autoComplete="family-name" />
              </div>
              <Field brand={brand} label="Date of birth" type="date"
                     value={recipient.birthday} onChange={update('birthday')} autoComplete="bday" />
              <Field brand={brand} label="Family member's email (optional)" type="email"
                     value={recipient.email} onChange={update('email')} autoComplete="email" />
              <Field brand={brand} label="Family member's phone (optional)" type="tel"
                     value={recipient.phone} onChange={update('phone')} autoComplete="tel" />
              <SCFamilyWaiver
                brand={brand} brandName={brandName}
                checked={!!waiverChecked} onChange={setWaiverChecked}
              />
            </SCRecipientSection>
          )}

          {type === 'guest' && (
            <SCRecipientSection brand={brand} groupTitle="GUEST"
              helper="Your guest will have their own account for future bookings, but will be linked to yours as a guest as well. They'll be asked to sign the studio's liability waiver in person at check-in.">
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                <Field brand={brand} label="First name"
                       value={recipient.firstName} onChange={update('firstName')} autoComplete="given-name" />
                <Field brand={brand} label="Last name"
                       value={recipient.lastName} onChange={update('lastName')} autoComplete="family-name" />
              </div>
              <Field brand={brand} label="Guest's email" type="email"
                     value={recipient.email} onChange={update('email')} autoComplete="email" />
              <Field brand={brand} label="Guest's phone (optional)" type="tel"
                     value={recipient.phone} onChange={update('phone')} autoComplete="tel" />
            </SCRecipientSection>
          )}
        </div>
      )}
    </div>
  );
}

function SCTypeBox({ brand, checked, onChange, label }) {
  return (
    <label style={{
      display: 'inline-flex', alignItems: 'center', gap: 8,
      cursor: 'pointer', padding: '4px 0',
    }}>
      <span
        onClick={(e) => { e.preventDefault(); onChange(); }}
        style={{
          width: 16, height: 16, borderRadius: 4,
          border: `1.5px solid ${checked ? brand.accent : brand.border}`,
          background: checked ? brand.accent : '#fff',
          display: 'grid', placeItems: 'center',
          transition: 'all .15s ease', flex: '0 0 16px',
        }}>
        {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: 13.5, color: brand.ink }}>{label}</span>
      <input type="checkbox" checked={checked} onChange={onChange}
             style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
    </label>
  );
}

// Per-family-member waiver — a slimmer variant of WaiverInline that
// lives inside the FAMILY MEMBER card. Same expand/read/agree pattern.
function SCFamilyWaiver({ brand, brandName, checked, onChange }) {
  const [open, setOpen] = useStateSC(false);
  return (
    <div style={{
      marginTop: 10,
      border: `1px solid ${brand.border}`,
      borderRadius: 12,
      overflow: 'hidden',
      background: '#fff',
    }}>
      <button
        type="button"
        onClick={() => setOpen(!open)}
        style={{
          width: '100%',
          display: 'flex', alignItems: 'center', gap: 10,
          padding: '12px 14px',
          background: 'transparent', border: 0,
          textAlign: 'left', cursor: 'pointer',
          fontFamily: brand.bodyFont,
        }}
        aria-expanded={open}>
        <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: 180, overflow: 'auto',
          padding: '0 14px 14px',
          fontSize: 12, lineHeight: 1.55, color: brand.inkSoft,
          borderTop: `1px solid ${brand.border}`,
        }}>
          <p style={{ marginTop: 12 }}>I, as the legal guardian or authorized booker for this family member, acknowledge that participation in the activities offered by {brandName} carries inherent risks of physical injury. I confirm that the participant is physically able to participate and have disclosed any conditions that may affect their safe practice.</p>
          <p>On their behalf, 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. The participant agrees 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 the participant's participation, except where caused by gross negligence.</p>
          <p>This waiver is binding upon me, the participant, our heirs, and our legal representatives.</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 on this family member's behalf.
          </span>
          <input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)}
                 style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
        </label>
      </div>
    </div>
  );
}

function SCRecipientSection({ brand, groupTitle, helper, children }) {
  return (
    <div style={{
      padding: 16,
      border: `1px solid ${brand.border}`,
      background: brand.surface,
      borderRadius: 12,
    }}>
      <div style={{
        fontFamily: brand.bodyFont, fontSize: 11, fontWeight: 700,
        letterSpacing: '0.1em', textTransform: 'uppercase',
        color: brand.ink, marginBottom: 12,
      }}>{groupTitle}</div>
      {children}
      <div style={{
        fontSize: 12, color: brand.inkSoft,
        marginTop: 6, lineHeight: 1.5,
      }}>{helper}</div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Billing address — collected in the payment step.
// ────────────────────────────────────────────────────────────────
// "How did you hear about us?" — single attribution question, ported
// from the Purchase screen for cross-flow consistency.
function SCReferralSourceSelect({ brand, value, onChange }) {
  const options = [
    'Instagram', 'TikTok', 'Google search',
    'Friend or family', 'Walked by the studio',
    'Email or newsletter', 'Other',
  ];
  return (
    <label style={{ display: 'block', position: 'relative', marginTop: 16, marginBottom: 4 }}>
      <div style={{
        position: 'absolute', left: 14, top: 8,
        fontSize: 10.5, fontWeight: 600,
        letterSpacing: '0.04em', textTransform: 'uppercase',
        color: brand.inkSoft, pointerEvents: 'none',
      }}>How did you hear about us?</div>
      <select
        value={value}
        onChange={e => onChange(e.target.value)}
        style={{
          width: '100%',
          appearance: 'none', WebkitAppearance: 'none',
          background: brand.surface,
          border: `1.5px solid ${brand.border}`,
          borderRadius: 12,
          padding: '22px 38px 8px 14px',
          fontSize: 15, color: value ? brand.ink : brand.inkSoft,
          fontFamily: brand.bodyFont,
          outline: 'none', cursor: 'pointer',
        }}>
        <option value="">Select an option</option>
        {options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
      <svg
        width="14" height="14" viewBox="0 0 24 24"
        fill="none" stroke={brand.inkSoft} strokeWidth="2.2"
        strokeLinecap="round" strokeLinejoin="round"
        style={{ position: 'absolute', right: 14, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none' }}>
        <polyline points="6 9 12 15 18 9" />
      </svg>
    </label>
  );
}

function SCAddressBlock({ brand, customer, setCustomer }) {
  const update = (k) => (v) => setCustomer(c => ({ ...c, [k]: v }));
  return (
    <div style={{ marginTop: 16 }}>
      <div style={{
        fontFamily: brand.bodyFont, fontSize: 10.5, fontWeight: 700,
        letterSpacing: '0.08em', textTransform: 'uppercase',
        color: brand.inkSoft, marginBottom: 8, paddingLeft: 2,
      }}>Billing address</div>
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 10 }}>
        <Field brand={brand} label="Street address"
               value={customer.street} onChange={update('street')} autoComplete="address-line1" />
        <Field brand={brand} label="Apt / unit" optional
               value={customer.apt} onChange={update('apt')} autoComplete="address-line2" />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: 10 }}>
        <Field brand={brand} label="City"
               value={customer.city} onChange={update('city')} autoComplete="address-level2" />
        <Field brand={brand} label="State"
               value={customer.state} onChange={update('state')} autoComplete="address-level1" />
        <Field brand={brand} label="ZIP"
               value={customer.zip} onChange={update('zip')} autoComplete="postal-code" />
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Purchase terms accordion — pre-checked, expand to read the studio
// purchase terms (refunds, booking, cancellations, memberships, gifts).
// Mirrors the Purchase screen accordion.
// ────────────────────────────────────────────────────────────────
function SCPurchaseTermsAccordion({ brand, agreed, setAgreed }) {
  const [open, setOpen] = useStateSC(false);
  return (
    <div style={{
      marginTop: 14,
      border: `1.5px solid ${agreed ? brand.accent : brand.border}`,
      background: agreed ? brand.accentSoft : '#fff',
      borderRadius: 12,
      transition: 'border-color .15s ease, background .15s ease',
      overflow: 'hidden',
    }}>
      <button
        type="button" onClick={() => setOpen(o => !o)}
        style={{
          width: '100%', background: 'transparent', border: 0,
          padding: '14px 16px',
          display: 'flex', alignItems: 'center', gap: 10,
          cursor: 'pointer', textAlign: 'left',
          fontFamily: brand.bodyFont, color: brand.ink,
        }}
        aria-expanded={open}>
        <span aria-hidden="true" style={{
          width: 18, height: 18, borderRadius: 999,
          border: `1.5px solid ${agreed ? brand.accent : brand.border}`,
          background: agreed ? brand.accent : 'transparent',
          display: 'grid', placeItems: 'center', flexShrink: 0,
        }}>
          {agreed && (
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff"
                 strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="20 6 9 17 4 12" />
            </svg>
          )}
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: brand.ink, letterSpacing: '-0.005em' }}>
            Purchase terms and conditions
          </div>
          <div style={{ fontSize: 12, color: brand.inkSoft, marginTop: 2 }}>
            {agreed ? 'Agreed — tap to review.' : 'Required — tap to review and agree.'}
          </div>
        </div>
        <svg width="14" height="14" viewBox="0 0 24 24"
             fill="none" stroke={brand.inkSoft} strokeWidth="2.4"
             strokeLinecap="round" strokeLinejoin="round"
             style={{ transform: open ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform .15s ease' }}>
          <polyline points="6 9 12 15 18 9" />
        </svg>
      </button>
      {open && (
        <div style={{
          padding: '0 16px 16px',
          fontFamily: brand.bodyFont, fontSize: 13, color: brand.inkSoft, lineHeight: 1.55,
        }}>
          <div style={{
            background: '#fff', border: `1px solid ${brand.border}`,
            borderRadius: 10, padding: '12px 14px',
            maxHeight: 200, overflowY: 'auto', color: brand.ink,
          }}>
            <p style={{ margin: '0 0 8px' }}>
              <strong>All sales are final.</strong> Drop-ins, class packs, memberships,
              gift cards and add-on purchases are non-refundable.
            </p>
            <p style={{ margin: '0 0 8px' }}>
              <strong>Booking.</strong> All classes and appointments must be booked
              online through the studio's scheduling tools — walk-ins are not
              guaranteed a spot.
            </p>
            <p style={{ margin: '0 0 8px' }}>
              <strong>Cancellations.</strong> Cancel or reschedule at least 12 hours
              before your booking to avoid losing the credit. Late cancellations
              and no-shows forfeit the credit.
            </p>
            <p style={{ margin: '0 0 8px' }}>
              <strong>Memberships.</strong> Recurring memberships renew automatically
              until cancelled. You can cancel at any time from your account;
              cancellation takes effect at the end of the current billing cycle.
            </p>
            <p style={{ margin: 0 }}>
              <strong>Gifts.</strong> When booking for someone else, the recipient
              receives access to the booked item; the buyer retains the billing
              record. Gift bookings are non-transferrable once redeemed.
            </p>
          </div>
          <label style={{
            marginTop: 12,
            display: 'flex', alignItems: 'flex-start', gap: 8,
            cursor: 'pointer',
          }}>
            <span
              onClick={(e) => { e.preventDefault(); setAgreed(!agreed); }}
              style={{
                flex: '0 0 14px',
                width: 14, height: 14, marginTop: 2,
                borderRadius: 4,
                border: `1.5px solid ${agreed ? brand.accent : brand.border}`,
                background: agreed ? brand.accent : '#fff',
                display: 'grid', placeItems: 'center',
                transition: 'all .15s ease',
              }}>
              {agreed && (
                <svg width="9" height="9" 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, color: brand.inkSoft, lineHeight: 1.45 }}>
              I agree to the purchase terms and conditions above.
            </span>
            <input type="checkbox" checked={agreed} onChange={e => setAgreed(e.target.checked)}
                   style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
          </label>
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// Studio settings panel — same pattern as Purchase / Appointment.
// Gated by window.SC_TWEAKS_ENABLED.
// ────────────────────────────────────────────────────────────────
function SCTweaks({ 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.SC_TWEAK_DEFAULTS) || {};
    Object.keys(defaults).forEach(k => setTweak(k, defaults[k]));
  };
  useEffectSC(() => {
    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 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="Corner radius" value={t.radius} min={0} max={28} step={1} unit="px"
              onChange={(v) => setTweak('radius', v)} />

      <Section label="Hide" />
      <Toggle label="Logo"                          value={!!t.hideLogo}
              onChange={(v) => setTweak('hideLogo', v)} />
      <Toggle label="Purchase terms and conditions" value={!!t.hideTerms}
              onChange={(v) => setTweak('hideTerms', v)} />
      <Toggle label="Billing address"               value={!!t.hideBillingAddress}
              onChange={(v) => setTweak('hideBillingAddress', v)} />

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

// ────────────────────────────────────────────────────────────────
// Brand switcher
// ────────────────────────────────────────────────────────────────
function BrandSwitcher({ allBrands, brandId, setBrandId, mobile }) {
  return (
    <div style={{ display: 'inline-flex', gap: 4, padding: 3, background: '#F4F2EC', borderRadius: 999 }}>
      {Object.values(allBrands).map(b => (
        <button key={b.id} onClick={() => setBrandId(b.id)} style={{
          background: brandId === b.id ? '#fff' : 'transparent',
          border: 0, borderRadius: 999,
          padding: mobile ? '5px 10px' : '6px 14px',
          fontSize: mobile ? 11 : 12, fontWeight: brandId === b.id ? 700 : 500,
          color: brandId === b.id ? b.ink : '#6E6E6A',
          boxShadow: brandId === b.id ? '0 1px 3px rgba(0,0,0,0.08)' : 'none',
          cursor: 'pointer',
        }}>{mobile ? b.name.split(' ')[0] : b.name}</button>
      ))}
    </div>
  );
}

// Expose for both standalone and framed renders
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>
  );
}

window.StepperClassApp = StepperClassApp;
const _stepperRoot = document.getElementById('root');
if (_stepperRoot && !_stepperRoot.dataset.framed) {
  ReactDOM.createRoot(_stepperRoot).render(<StepperClassApp />);
}
