// Pre-order page — configurator + checkout with Stripe Payment Element
// Supports card, Afterpay/Clearpay, and Zip via Stripe's unified Payment Element
// $25 deposit model — card saved for future balance charge

const { useState: useStateP, useEffect: useEffectP, useRef: useRefP } = React;

const STRIPE_PUBLIC_KEY = window.__STRIPE_KEY__;

// ── PromoInput component ──
function PromoInput({ totalAmount, applied, onApply, onClear }) {
  const [open, setOpen] = React.useState(!!window.__promoOpen);
  const [code, setCode] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  const toggleOpen = (val) => {
    window.__promoOpen = val;
    setOpen(val);
  };

  const handleApply = async () => {
    if (!code.trim()) return;
    setLoading(true);
    setError(null);
    try {
      const res = await fetch('/api/validate-promo', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ code: code.trim(), totalAmount }),
      });
      const data = await res.json();
      if (data.valid) {
        onApply(data);
      } else {
        setError(data.error || 'Invalid code.');
      }
    } catch (e) {
      setError('Could not validate code right now.');
    } finally {
      setLoading(false);
    }
  };

  if (applied) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 14px', background: '#EBF3EC', borderRadius: 10, border: '1.5px solid #2D6633' }}>
        <span style={{ fontSize: 13, fontWeight: 700, color: '#2D6633' }}>✓ {applied.label || applied.code} — ${applied.discountAmount || ''} off applied</span>
        <button onClick={onClear} style={{ background: 'none', border: 'none', fontSize: 12, color: 'var(--muted)', cursor: 'pointer', textDecoration: 'underline' }}>Remove</button>
      </div>
    );
  }

  return (
    <div>
      {!open ? (
        <button
          onClick={() => toggleOpen(true)}
          style={{ background: 'none', border: 'none', padding: 0, fontFamily: 'var(--body)', fontSize: 14, fontWeight: 600, color: 'var(--cta)', cursor: 'pointer' }}
        >
          + Got a discount code?
        </button>
      ) : (
        <div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <input
              value={code}
              onChange={e => { setCode(e.target.value.toUpperCase()); setError(null); }}
              onKeyDown={e => e.key === 'Enter' && handleApply()}
              placeholder="ENTER CODE"
              autoFocus
              style={{ flex: 1, minWidth: 0, padding: '12px 16px', border: '2px solid var(--cta)', borderRadius: 24, fontFamily: 'var(--body)', fontSize: 14, fontWeight: 600, letterSpacing: '0.05em', background: '#FFFCF4', color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' }}
            />
            <button
              onClick={handleApply}
              disabled={loading || !code.trim()}
              style={{ flexShrink: 0, padding: '12px 20px', background: loading || !code.trim() ? '#bbb' : 'var(--dark)', color: '#fff', border: 'none', borderRadius: 24, fontFamily: 'var(--body)', fontWeight: 700, fontSize: 14, cursor: loading ? 'wait' : 'pointer', whiteSpace: 'nowrap' }}
            >
              {loading ? '…' : 'Apply'}
            </button>
          </div>
          {error && <p style={{ color: 'var(--coral)', fontSize: 12, marginTop: 6 }}>{error}</p>}
        </div>
      )}
    </div>
  );
}

// ── Send Klaviyo confirmation after payment ──
async function sendConfirmation({ name, email, address, city, state, postcode, quantity, phones, totalAmount, balanceOwed, paymentMethodType, discountAmount, promotionCode }) {
  try {
    await fetch('/api/send-confirmation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, email, address, city, state, postcode, quantity, phones, totalAmount, balanceOwed, paymentMethodType, discountAmount, promotionCode }),
    });
  } catch (e) {
    console.error('Confirmation send failed:', e);
  }
}

function PreorderPage({ navigate, tweaks, initialQty = 1, initialStep = 'configure' }) {
  // ── Hydrate from sessionStorage if /phone passed config along ──
  const stashed = (() => {
    try {
      const raw = sessionStorage.getItem('cb_config');
      if (!raw) return null;
      const parsed = JSON.parse(raw);
      if (parsed && Array.isArray(parsed.phones) && parsed.phones.length) return parsed;
    } catch (e) {}
    return null;
  })();

  const startQty = stashed ? stashed.quantity : initialQty;

  // ── Read Stripe redirect from sessionStorage (set by index.html before React boots) ──
  const stripeRedirect = (() => {
    try {
      const r = JSON.parse(sessionStorage.getItem('stripe_redirect') || 'null');
      if (r) sessionStorage.removeItem('stripe_redirect');
      return r;
    } catch(e) { return null; }
  })();
  const isRedirectConfirmed = stripeRedirect?.status === 'succeeded';
  const isRedirectFailed = stripeRedirect?.status === 'failed' || stripeRedirect?.status === 'canceled';
  const isRedirectPending = stripeRedirect?.status === 'pending';

  // Restore form from sessionStorage after redirect
  const savedForm = (() => {
    try { return JSON.parse(sessionStorage.getItem('cb_form') || '{}'); } catch(e) { return {}; }
  })();
  const savedConfig = (() => {
    try { return JSON.parse(sessionStorage.getItem('cb_config') || '{}'); } catch(e) { return {}; }
  })();

  const [step, setStep] = useStateP(
    isRedirectConfirmed ? 'confirmed' :
    isRedirectFailed ? 'payment' :
    isRedirectPending ? 'verifying' :
    initialStep
  );
  const [redirectError, setRedirectError] = useStateP(
    isRedirectFailed ? 'Your payment was unsuccessful. Please try a different payment method or card.' : null
  );
  const [quantity, setQuantity] = useStateP(startQty);
  const [phones, setPhones] = useStateP(() => {
    if (stashed) return stashed.phones;
    return Array.from({ length: startQty }, () => ({ top: 'buttercream', bot: 'buttercream', name: '' }));
  });
  const [form, setForm] = useStateP({
    name: savedForm.name || '', 
    email: savedForm.email || '', 
    address: savedForm.address || '', 
    city: savedForm.city || '', 
    postcode: savedForm.postcode || '', 
    state: savedForm.state || 'NSW',
  });

  // Stripe state
  const urlPromo = (() => {
    try {
      const hash = window.location.hash || '';
      const qIndex = hash.indexOf('?');
      if (qIndex !== -1) {
        const params = new URLSearchParams(hash.slice(qIndex + 1));
        const p = params.get('promo');
        if (p) { sessionStorage.setItem('cb_promo', p); return p; }
      }
      return sessionStorage.getItem('cb_promo') || null;
    } catch(e) { return null; }
  })();
  const KINDY_PROMO = urlPromo === 'KINDY5' ? { code: 'KINDY5', label: 'The Kindy Garden', discountAmount: 5 } : null;

  const [stripeInstance, setStripeInstance] = useStateP(null);
  const [elementsInstance, setElementsInstance] = useStateP(null);
  const [paymentElement, setPaymentElement] = useStateP(null);
  const [elementMounted, setElementMounted] = useStateP(false);
  const [clientSecret, setClientSecret] = useStateP(null);
  const [verifyClientSecret, setVerifyClientSecret] = useStateP(stripeRedirect?.clientSecret || null);
  const [paymentMethodType, setPaymentMethodType] = useStateP(() => {
    try { return sessionStorage.getItem('payment_method_type') || 'card'; } catch(e) { return 'card'; }
  });
  const [depositAmount, setDepositAmount] = useStateP(25);
  const [totalAmount, setTotalAmount] = useStateP(null);
  const [balanceOwed, setBalanceOwed] = useStateP(null);
  const [paymentError, setPaymentError] = useStateP(null);
  const [paymentProcessing, setPaymentProcessing] = useStateP(false);
  const [cardSaveConsent, setCardSaveConsent] = useStateP(false);
  const [promotionApplied, setPromotionApplied] = useStateP(KINDY_PROMO);
  const [discountAmount, setDiscountAmount] = useStateP(KINDY_PROMO ? 5 : 0);
  const paymentElementRef = useRefP(null);

  // ── Sync phones array length with quantity ──
  useEffectP(() => {
    setPhones(prev => {
      if (prev.length === quantity) return prev;
      if (prev.length < quantity) {
        return [...prev, ...Array.from({ length: quantity - prev.length }, () => ({ top: 'buttercream', bot: 'buttercream', name: '' }))];
      }
      return prev.slice(0, quantity);
    });
  }, [quantity]);

  // Persist config to sessionStorage
  useEffectP(() => {
    try {
      sessionStorage.setItem('cb_config', JSON.stringify({ quantity, phones }));
    } catch (e) {}
  }, [quantity, phones]);

  // Pricing
  const pricing = PRICING.bundles[quantity] || { price: PRICING.preorder * quantity, save: (PRICING.rrp - PRICING.preorder) * quantity };
  const rrpTotal = quantity * PRICING.rrp;

  // ── Verify payment status for Afterpay redirects ──
  // Fire Klaviyo confirmation for BNPL redirect (status=succeeded skips verifying step)
  useEffectP(() => {
    if (!isRedirectConfirmed) return;
    sendConfirmation({
      name: savedForm.name || '',
      email: savedForm.email || '',
      address: savedForm.address || '',
      city: savedForm.city || '',
      state: savedForm.state || '',
      postcode: savedForm.postcode || '',
      quantity: savedConfig.quantity || 1,
      phones: savedConfig.phones || [],
      totalAmount: (PRICING.bundles[savedConfig.quantity || 1] || { price: PRICING.preorder }).price,
      balanceOwed: ((PRICING.bundles[savedConfig.quantity || 1] || { price: PRICING.preorder }).price) - 25,
      paymentMethodType: 'bnpl',
      discountAmount: 0,
      promotionCode: '',
    });
  }, []);

  useEffectP(() => {
    if (step !== 'verifying') return;
    if (!verifyClientSecret) {
      setRedirectError('Your payment was unsuccessful. Please try a different payment method or card.');
      setStep('payment');
      return;
    }
    const verify = async (stripe) => {
      try {
        let paymentIntent;
        for (let i = 0; i < 3; i++) {
          const result = await stripe.retrievePaymentIntent(verifyClientSecret);
          paymentIntent = result.paymentIntent;
          if (paymentIntent?.status === 'succeeded') break;
          if (i < 2) await new Promise(r => setTimeout(r, 1000));
        }
        if (paymentIntent?.status === 'succeeded') {
          // Read form data BEFORE clearing sessionStorage
          const formData = (() => { try { return JSON.parse(sessionStorage.getItem('cb_form') || '{}'); } catch(e) { return {}; } })();
          const configData = (() => { try { return JSON.parse(sessionStorage.getItem('cb_config') || '{}'); } catch(e) { return {}; } })();
          console.log('BNPL verify - formData:', formData, 'configData:', configData, 'email:', formData.email);
          // Send Klaviyo confirmation BEFORE clearing session
          sendConfirmation({
            name: formData.name || '',
            email: formData.email || '',
            address: formData.address || '',
            city: formData.city || '',
            state: formData.state || '',
            postcode: formData.postcode || '',
            quantity: configData.quantity || quantity,
            phones: configData.phones || phones,
            totalAmount: pricing.price,
            balanceOwed: pricing.price - 25 - discountAmount,
            paymentMethodType: 'bnpl',
            discountAmount,
            promotionCode: promotionApplied?.code || '',
          });
          try { sessionStorage.clear(); localStorage.removeItem('stripe_pending'); } catch(e) {}
          try { sessionStorage.setItem('payment_method_type', 'bnpl'); } catch(e) {}
          setPaymentMethodType('bnpl');
          setStep('confirmed');
        } else {
          setRedirectError('Your payment was unsuccessful. Please try a different payment method or card.');
          setStep('payment');
        }
      } catch(e) {
        setRedirectError('Could not verify payment. Please try again.');
        setStep('payment');
      }
    };

    if (stripeInstance) {
      verify(stripeInstance);
    } else {
      const interval = setInterval(() => {
        if (window.Stripe) {
          clearInterval(interval);
          verify(window.Stripe(STRIPE_PUBLIC_KEY));
        }
      }, 100);
      return () => clearInterval(interval);
    }
  }, [step, stripeInstance, verifyClientSecret]);

  // ── Load Stripe.js once ──
  useEffectP(() => {
    if (window.Stripe) { setStripeInstance(window.Stripe(STRIPE_PUBLIC_KEY)); return; }
    const script = document.createElement('script');
    script.src = 'https://js.stripe.com/v3/';
    script.async = true;
    script.onload = () => setStripeInstance(window.Stripe(STRIPE_PUBLIC_KEY));
    document.body.appendChild(script);
  }, []);

  // ── Reset payment intent when promo code changes ──
  useEffectP(() => {
    if (step !== 'payment') return;
    if (!clientSecret) return;
    if (paymentElement) {
      try { paymentElement.unmount(); } catch (e) {}
    }
    setClientSecret(null);
    setPaymentElement(null);
    setElementsInstance(null);
    setElementMounted(false);
    setPaymentError(null);
  }, [promotionApplied?.code]);

  // ── Create Payment Intent when entering payment step ──
  useEffectP(() => {
    if (step !== 'payment' || !stripeInstance || clientSecret) return;
    const createIntent = async () => {
      try {
        const res = await fetch('/api/create-payment-intent', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            quantity,
            phones,
            customer: {
              name: form.name,
              email: form.email,
              address: form.address,
              city: form.city,
              postcode: form.postcode,
              state: form.state,
            },
            promotionCode: promotionApplied?.code || null,
          }),
        });
        const data = await res.json();
        if (data.error) { setPaymentError(data.error); return; }
        setClientSecret(data.clientSecret);
        setDepositAmount(data.depositAmount || 25);
        setTotalAmount(data.totalAmount);
        setBalanceOwed(data.balanceOwed);
      } catch (e) {
        setPaymentError('Could not start checkout. Please try again.');
      }
    };
    createIntent();
  }, [step, stripeInstance]);

  // ── Mount Payment Element once we have clientSecret ──
  useEffectP(() => {
    if (!stripeInstance || !clientSecret || paymentElement) return;
    const elements = stripeInstance.elements({
      clientSecret,
      appearance: {
        theme: 'stripe',
        variables: {
          colorPrimary: '#2D6633',
          colorText: '#2C2416',
          fontFamily: '"Nunito", "DM Sans", system-ui, sans-serif',
          borderRadius: '10px',
        },
      },
    });
    const pe = elements.create('payment', { layout: 'tabs' });
    requestAnimationFrame(() => {
      if (paymentElementRef.current) {
        pe.mount(paymentElementRef.current);
        pe.on('ready', () => setElementMounted(true));
        pe.on('change', (e) => {
          const type = e.value?.type || 'card';
          const isBNPL = type === 'afterpay_clearpay' || type === 'zip';
          try { sessionStorage.setItem('payment_method_type', isBNPL ? 'bnpl' : 'card'); } catch(err) {}
          setPaymentMethodType(isBNPL ? 'bnpl' : 'card');
        });
        setElementsInstance(elements);
        setPaymentElement(pe);
      }
    });
  }, [stripeInstance, clientSecret]);

  // ── Handle payment submission ──
  const handlePayment = async (e) => {
    e.preventDefault();
    if (!stripeInstance || !elementsInstance) return;
    setPaymentProcessing(true);
    setPaymentError(null);

    setVerifyClientSecret(clientSecret);
    try { localStorage.setItem('stripe_pending', '1'); } catch(e) {}

    const { error } = await stripeInstance.confirmPayment({
      elements: elementsInstance,
      confirmParams: {
        return_url: `${window.location.origin}/#/preorder`,
        receipt_email: form.email,
      },
      redirect: 'if_required',
    });

    try { localStorage.removeItem('stripe_pending'); } catch(e) {}
    try { sessionStorage.setItem('payment_method_type', 'card'); } catch(e) {}
    setPaymentMethodType('card');

    if (error) {
      setPaymentError(error.message);
      setPaymentProcessing(false);
    } else {
      // Card payment succeeded — send Klaviyo confirmation
      sendConfirmation({
        ...form,
        quantity, phones,
        totalAmount: totalAmount || pricing.price,
        balanceOwed: balanceOwed || (pricing.price - 25 - discountAmount),
        paymentMethodType: 'card',
        discountAmount,
        promotionCode: promotionApplied?.code || '',
      });
      try { sessionStorage.clear(); localStorage.removeItem('stripe_pending'); } catch(e) {}
      window.scrollTo({ top: 0, behavior: 'smooth' });
      setStep('confirmed');
      setPaymentProcessing(false);
    }
  };

  // ── Verifying payment (Afterpay redirect) ──
  if (step === 'verifying') {
    return (
      <main style={{ paddingTop: 100, paddingBottom: 100, textAlign: 'center' }}>
        <div className="container">
          <Pill>Checking payment</Pill>
          <h2 style={{ marginTop: 24 }}>Just a moment…</h2>
          <p style={{ marginTop: 12, color: 'var(--muted)' }}>We're confirming your payment with Afterpay.</p>
        </div>
      </main>
    );
  }

  // ── Confirmed ──
  if (step === 'confirmed') {
    const isBNPL = paymentMethodType === 'bnpl';
    const balance = balanceOwed || (pricing.price - 25 - discountAmount);
    return (
      <main style={{ paddingTop: 100, paddingBottom: 100 }}>
        <div className="container">
          <div className="confirm-block" style={{ position: 'relative' }}>
            <img src="assets/doodle-popsicle.png" alt="" aria-hidden="true"
              className="section-doodle"
              style={{ right: 30, top: -20, width: 90, height: 90, transform: 'rotate(12deg)', position: 'absolute' }} />
            <Pill>Reservation received</Pill>
            <h2 style={{ marginTop: 24 }}>Thanks, {form.name.split(' ')[0] || 'friend'} — your Ciao Bella is on the way.</h2>
            {isBNPL ? (
              <p>We&apos;ve held a spot for you with a $25 deposit. A confirmation is heading to <strong>{form.email}</strong>. When your phone is ready to ship, we&apos;ll send you a separate payment link for the balance of <strong>${balance}</strong> — you won&apos;t be charged automatically.</p>
            ) : (
              <p>We&apos;ve held a spot for you with a $25 deposit. A confirmation is heading to <strong>{form.email}</strong>, and we&apos;ll be in touch the moment your phone is dispatched — that&apos;s when the balance of <strong>${balance}</strong> is charged automatically to your card.</p>
            )}
            <div style={{ marginTop: 32 }}>
              <CTA onClick={() => navigate('/')}>Back to home</CTA>
            </div>
          </div>
        </div>
      </main>
    );
  }

  // ── Order summary (shared) ──
  const OrderSummary = ({ showCta, ctaLabel, onCta, ctaDisabled, allowPromo }) => {
    const discountedTotal = pricing.price - discountAmount;
    const discountedBalance = Math.max(0, discountedTotal - 25);
    return (
    <div className="config-summary">
      <h3>Your order</h3>
      <div className="config-summary-list">
        {phones.map((p, i) => (
          <div key={i} className="config-summary-line">
            <span>Ciao Bella #{i + 1} · {(typeof getCombo === 'function' ? getCombo(p.top, p.bot) : getShell(p.top)).name}</span>
            <span className="price">${PRICING.preorder}</span>
          </div>
        ))}
        <div className="config-summary-line" style={{ color: 'var(--muted)' }}>
          <span>RRP total</span>
          <span style={{ textDecoration: 'line-through' }}>${rrpTotal}</span>
        </div>
        <div className="config-summary-line" style={{ color: 'var(--coral)', fontWeight: 600 }}>
          <span>Pre-order saving</span>
          <span>−${pricing.save}</span>
        </div>
        {discountAmount > 0 && (
          <div className="config-summary-line" style={{ color: 'var(--cta)', fontWeight: 600 }}>
            <span>Code {promotionApplied?.code}</span>
            <span>−${discountAmount}</span>
          </div>
        )}
        <div className="config-summary-line" style={{ color: 'var(--muted)' }}>
          <span>Shipping</span>
          <span>Free</span>
        </div>
      </div>
      {allowPromo && (
        <div style={{ margin: '12px 0 4px' }}>
          <PromoInput
            totalAmount={pricing.price}
            applied={promotionApplied}
            onApply={(data) => {
              setPromotionApplied({ code: data.code, promotionCodeId: data.promotionCodeId, discountAmount: data.discountAmount });
              setDiscountAmount(data.discountAmount);
            }}
            onClear={() => {
              setPromotionApplied(null);
              setDiscountAmount(0);
            }}
          />
        </div>
      )}
      <div className="config-summary-total">
        <span className="label">Reserve today</span>
        <span className="amt">$25</span>
      </div>
      <div className="config-summary-saved">Balance ${discountedBalance} charged when your phone ships.</div>
      <div className="config-summary-gst" style={{ fontSize: 11.5, color: 'var(--muted)', textAlign: 'center', marginTop: 4, letterSpacing: '0.02em' }}>All prices in AUD, incl. GST.</div>
      {showCta && (
        <CTA className="config-summary-cta" onClick={onCta} disabled={ctaDisabled}>
          {ctaDisabled ? 'Processing…' : ctaLabel}
        </CTA>
      )}
      <div className="config-reassurance">
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> $25 today · cancel anytime before shipping</div>
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> 30-day money-back · 12-month warranty</div>
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> Australian-owned · ships from June 2026</div>
      </div>
    </div>
    );
  };

  // ── Payment step ──
  if (step === 'payment') {
    return (
      <main style={{ paddingTop: 60, paddingBottom: 100 }}>
        <div className="container">
          <a href="#" onClick={(e) => { 
            e.preventDefault(); 
            setClientSecret(null);
            setPaymentElement(null);
            setElementsInstance(null);
            setElementMounted(false);
            setPaymentError(null);
            setRedirectError(null);
            setStep('checkout'); 
          }} className="cta-ghost" style={{ marginBottom: 32, display: 'inline-flex' }}>← Back to your details</a>
          <div style={{ textAlign: 'center', marginBottom: 56 }}>
            <Pill>Almost there</Pill>
            <h1 className="h-section" style={{ marginTop: 20 }}>Secure payment</h1>
            <p style={{ fontFamily: 'var(--hand)', fontWeight: 500, color: 'var(--sub-2)', marginTop: 12 }}>
              Your $25 deposit is secured by Stripe. Pay by card, Afterpay, or Zip.
            </p>
          </div>
          <div className="checkout-grid">
            <div>
              <div className="checkout-step">
                <h3><span className="checkout-step-num">3</span>Payment</h3>
                {!clientSecret && !paymentError && (
                  <div style={{ marginTop: 16 }}>
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, marginBottom: 12, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, marginBottom: 12, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <style>{`@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }`}</style>
                  </div>
                )}
                {clientSecret && !elementMounted && (
                  <div style={{ marginTop: 16 }}>
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, marginBottom: 12, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, marginBottom: 12, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, marginBottom: 12, animation: 'pulse 1.5s ease-in-out infinite' }} />
                    <div style={{ height: 44, background: '#f0f0f0', borderRadius: 10, animation: 'pulse 1.5s ease-in-out infinite' }} />
                  </div>
                )}
                <div style={{ display: clientSecret ? 'block' : 'none', visibility: elementMounted ? 'visible' : 'hidden', height: elementMounted ? 'auto' : 0, overflow: 'hidden' }}>
                  <form onSubmit={handlePayment}>
                    {(paymentError || redirectError) && (
                      <div style={{ background: '#FFF0ED', border: '1.5px solid var(--coral)', borderRadius: 10, padding: '12px 16px', marginBottom: 16, marginTop: 16 }}>
                        <p style={{ color: 'var(--coral)', fontSize: 14, fontWeight: 600 }}>⚠️ {paymentError || redirectError}</p>
                      </div>
                    )}
                    <div ref={paymentElementRef} style={{ marginTop: 16, marginBottom: 20 }} />

                    {paymentMethodType === 'card' && (
                      <label className="card-save-consent" style={{
                        display: 'flex', alignItems: 'flex-start', gap: 12,
                        background: '#FFFCF4', border: '1.5px solid rgba(46, 44, 41, 0.18)',
                        borderRadius: 12, padding: '14px 16px', marginBottom: 18, cursor: 'pointer',
                        fontFamily: 'var(--body)', transition: 'border-color 0.15s, background 0.15s',
                        ...(cardSaveConsent ? { borderColor: 'var(--cta)', background: 'var(--cta-circle)' } : {}),
                      }}>
                        <input type="checkbox" checked={cardSaveConsent} onChange={(e) => setCardSaveConsent(e.target.checked)}
                          style={{ width: 18, height: 18, marginTop: 2, accentColor: 'var(--cta)', cursor: 'pointer', flexShrink: 0 }} required />
                        <span style={{ fontSize: 13.5, lineHeight: 1.45, color: 'var(--ink)' }}>
                          I understand my card will be securely saved by Stripe so Ciao Bella can charge the remaining balance (${balanceOwed ?? '—'}) when my phone ships. I can request removal at any time before then.
                        </span>
                      </label>
                    )}

                    {paymentMethodType !== 'card' && (
                      <div style={{
                        background: '#FFFCF4', border: '1.5px solid rgba(46, 44, 41, 0.18)',
                        borderRadius: 12, padding: '14px 16px', marginBottom: 18,
                        fontFamily: 'var(--body)', fontSize: 13.5, lineHeight: 1.45, color: 'var(--ink)',
                      }}>
                        Your $25 deposit is processed by Stripe via Afterpay or Zip. We don&apos;t store any card details. When your phone ships, we&apos;ll email you a separate payment link for the balance of <strong>${balanceOwed ?? '—'}</strong>.
                      </div>
                    )}

                    <CTA type="submit" disabled={paymentProcessing || (paymentMethodType === 'card' && !cardSaveConsent)}>
                      {paymentProcessing ? 'Processing…' : 'Confirm reservation — $25'}
                    </CTA>
                    <p style={{ fontSize: 12, color: 'var(--muted)', marginTop: 12, display: 'flex', alignItems: 'center', gap: 6 }}>
                      <svg width="12" height="14" viewBox="0 0 12 14" fill="none"><rect x="1" y="5" width="10" height="8" rx="2" stroke="#aaa" strokeWidth="1.5"/><path d="M3.5 5V3.5a2.5 2.5 0 015 0V5" stroke="#aaa" strokeWidth="1.5" strokeLinecap="round"/></svg>
                      Secured by Stripe. We never store your card details.
                    </p>
                  </form>
                </div>
              </div>
            </div>
            <OrderSummary showCta={false} allowPromo={true} />
          </div>
        </div>
      </main>
    );
  }

  // ── Checkout step (details form) ──
  if (step === 'checkout') {
    const handleDetailsSubmit = (e) => {
      e.preventDefault();
      try { sessionStorage.setItem('cb_form', JSON.stringify(form)); } catch(e) {}
      setStep('payment');
      window.scrollTo({ top: 0, behavior: 'smooth' });
    };
    return (
      <main style={{ paddingTop: 60, paddingBottom: 100 }}>
        <div className="container">
          <a href="#" onClick={(e) => { e.preventDefault(); setStep('configure'); }} className="cta-ghost" style={{ marginBottom: 32, display: 'inline-flex' }}>← Back to your build</a>
          <div style={{ textAlign: 'center', marginBottom: 56 }}>
            <Pill>Almost there</Pill>
            <h1 className="h-section" style={{ marginTop: 20 }}>Your details</h1>
            <p style={{ fontFamily: 'var(--hand)', fontWeight: 500, color: 'var(--sub-2)', marginTop: 12 }}>
              Just a few details so we know where to send your Ciao Bella.
            </p>
          </div>
          <div className="checkout-grid">
            <form onSubmit={handleDetailsSubmit}>
              <div className="checkout-step" style={{ marginBottom: 40 }}>
                <h3><span className="checkout-step-num">1</span>Contact</h3>
                <div className="field-row">
                  <div className="field"><label>Full name</label>
                    <input value={form.name} onChange={e => setForm({...form, name: e.target.value})} placeholder="Alex Doe" required /></div>
                  <div className="field"><label>Email</label>
                    <input type="email" value={form.email} onChange={e => setForm({...form, email: e.target.value})} placeholder="alex@example.com" required /></div>
                </div>
              </div>
              <div className="checkout-step" style={{ marginBottom: 40 }}>
                <h3><span className="checkout-step-num">2</span>Shipping address</h3>
                <div className="field-row single">
                  <div className="field"><label>Street address</label>
                    <input value={form.address} onChange={e => setForm({...form, address: e.target.value})} placeholder="14 Brunswick St" required /></div>
                </div>
                <div className="field-row">
                  <div className="field"><label>Suburb / city</label>
                    <input value={form.city} onChange={e => setForm({...form, city: e.target.value})} placeholder="Fitzroy" required /></div>
                  <div className="field"><label>State</label>
                    <select value={form.state} onChange={e => setForm({...form, state: e.target.value})}>
                      {['NSW','VIC','QLD','WA','SA','TAS','ACT','NT'].map(s => <option key={s}>{s}</option>)}
                    </select>
                  </div>
                  <div className="field"><label>Postcode</label>
                    <input value={form.postcode} onChange={e => setForm({...form, postcode: e.target.value})} placeholder="3065" required /></div>
                </div>
              </div>
              <OrderSummary showCta={true} ctaLabel="Continue to payment" onCta={handleDetailsSubmit} ctaDisabled={false} allowPromo={true} />
            </form>
            <div>
              <OrderSummary showCta={false} allowPromo={true} />
            </div>
          </div>
        </div>
      </main>
    );
  }

  // ── Configure (default step) ──
  const summary = (
    <div className="config-summary">
      <h3>Your build</h3>
      <div className="config-summary-list">
        {phones.map((p, i) => (
          <div key={i} className="config-summary-line">
            <span>Phone {i + 1} · {(typeof getCombo === 'function' ? getCombo(p.top, p.bot) : getShell(p.top)).name}</span>
            <span className="price">${PRICING.preorder}</span>
          </div>
        ))}
        <div className="config-summary-line" style={{ color: 'var(--muted)' }}>
          <span>RRP total</span>
          <span style={{ textDecoration: 'line-through' }}>${rrpTotal}</span>
        </div>
        <div className="config-summary-line" style={{ color: 'var(--coral)', fontWeight: 600 }}>
          <span>Pre-order saving</span>
          <span>−${pricing.save}</span>
        </div>
        <div className="config-summary-line" style={{ color: 'var(--muted)' }}>
          <span>Total when it ships</span>
          <span>${pricing.price}</span>
        </div>
      </div>
      <div className="config-summary-total">
        <span className="label">Reserve today</span>
        <span className="amt">$25</span>
      </div>
      <div className="config-summary-saved">You save ${pricing.save} vs. RRP · Cancel anytime before shipping</div>
      <div className="config-summary-gst" style={{ fontSize: 11.5, color: 'var(--muted)', textAlign: 'center', marginTop: 4, letterSpacing: '0.02em' }}>All prices in AUD, incl. GST.</div>
      <CTA className="config-summary-cta" onClick={() => { setStep('checkout'); window.scrollTo({ top: 0, behavior: 'smooth' }); }}>Reserve for $25</CTA>
      <div className="config-reassurance">
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> $25 today, balance charged at ship</div>
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> 30-day money-back guarantee</div>
        <div><span className="check"><svg viewBox="0 0 12 12" width="8" height="8"><path d="M2 6 L 5 9 L 10 3" stroke="#343433" strokeWidth="2" fill="none" strokeLinecap="round"/></svg></span> 12-month warranty · Australian-owned</div>
      </div>
    </div>
  );

  return (
    <main style={{ paddingTop: 60, paddingBottom: 100 }}>
      <Bundles navigate={navigate} />
      <div className="container" style={{ marginTop: 60 }}>
        <div style={{ textAlign: 'center', marginBottom: 56, position: 'relative' }}>
          <img src="assets/star-doodle.svg" alt="" aria-hidden="true"
            className="section-doodle"
            style={{ left: 'max(20px, calc(50% - 380px))', top: -20, width: 80, height: 80, transform: 'rotate(-12deg)', position: 'absolute' }} />
          <Pill>Build your own</Pill>
          <h1 className="h-hero" style={{ marginTop: 20, fontSize: 'clamp(36px, 5vw, 60px)' }}>
            Build your <em>Ciao Bella</em>
          </h1>
          <p style={{ fontFamily: 'var(--heading-font)', fontWeight: 500, fontSize: 18, color: 'var(--sub)', marginTop: 16, maxWidth: 580, marginLeft: 'auto', marginRight: 'auto' }}>
            Or skip the bundles and pick exact colours below.
          </p>
        </div>
        <Configurator
          quantity={quantity}
          setQuantity={setQuantity}
          phones={phones}
          setPhones={setPhones}
          summary={summary}
        />
      </div>
    </main>
  );
}

Object.assign(window, { PreorderPage });
