// components.jsx — shared atoms used across all checkout flows
// Loaded as a global script; exports to window at the end.

const { useState, useEffect, useRef, useMemo } = React;

// ────────────────────────────────────────────────────────────────
//  Studio brand chrome — header that wears the studio's identity
// ────────────────────────────────────────────────────────────────
function StudioHeader({ brand, returning, onSignIn, compact }) {
  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: compact ? '14px 20px 10px' : '18px 22px 14px',
      background: 'transparent',
      gap: 12,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
        <div style={{
          width: 36, height: 36,
          background: brand.accent,
          borderRadius: 10,
          display: 'grid', placeItems: 'center',
          color: '#fff',
          fontFamily: brand.displayFont,
          fontWeight: 800,
          fontSize: 18,
          letterSpacing: '-0.02em',
          flex: '0 0 auto',
        }}>{brand.initials}</div>
        <div style={{ minWidth: 0 }}>
          <div style={{
            fontFamily: brand.displayFont,
            fontWeight: brand.displayWeight,
            fontSize: 15,
            color: brand.ink,
            letterSpacing: '-0.01em',
            lineHeight: 1.1,
          }}>{brand.name}</div>
          <div style={{
            fontSize: 11,
            color: brand.inkSoft,
            letterSpacing: '0.02em',
            marginTop: 2,
          }}>{brand.tagline}</div>
        </div>
      </div>
      {!returning && (
        <button onClick={onSignIn} style={{
          background: 'transparent',
          border: 0,
          color: brand.inkSoft,
          fontSize: 12.5,
          fontWeight: 600,
          padding: '6px 2px',
        }}>Sign in</button>
      )}
      {returning && (
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '5px 10px',
          background: brand.accentSoft,
          borderRadius: 999,
          fontSize: 11.5,
          fontWeight: 600,
          color: brand.accentDeep,
          letterSpacing: '0.01em',
        }}>
          <span style={{ width: 6, height: 6, borderRadius: 999, background: brand.accent }}></span>
          Welcome back
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
//  Section heading inside the checkout form
// ────────────────────────────────────────────────────────────────
function SectionTitle({ children, brand, step }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 10,
      margin: '20px 0 10px',
    }}>
      {step != null && (
        <div style={{
          width: 22, height: 22,
          borderRadius: 999,
          border: `1.5px solid ${brand.border}`,
          color: brand.inkSoft,
          fontSize: 11,
          fontWeight: 700,
          display: 'grid', placeItems: 'center',
          fontFamily: brand.bodyFont,
        }}>{step}</div>
      )}
      <div style={{
        fontFamily: brand.displayFont,
        fontWeight: 700,
        fontSize: 14,
        letterSpacing: '0.02em',
        textTransform: 'uppercase',
        color: brand.inkSoft,
      }}>{children}</div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
//  Form field — text/email/tel/textarea, floating label
// ────────────────────────────────────────────────────────────────
function Field({ label, type='text', value, onChange, brand, hint, error, autoComplete, required, optional, rows }) {
  const [focused, setFocused] = useState(false);
  const filled = value && value.length > 0;
  // Date inputs render the native "mm/dd/yyyy" placeholder INSIDE the input, which
  // visually collides with the floating label. For date fields we drop the floating
  // pattern and put a static label above the input instead.
  const isDate = type === 'date';
  const lifted = focused || filled;
  const Tag = rows ? 'textarea' : 'input';

  const borderColor = error ? '#C0392B' : (focused ? brand.accent : brand.border);

  if (isDate) {
    return (
      <label style={{ display: 'block', marginBottom: 10 }}>
        <div style={{
          fontSize: 10.5, fontWeight: 600, letterSpacing: '0.04em',
          textTransform: 'uppercase', color: brand.inkSoft,
          marginBottom: 6, marginLeft: 2,
        }}>
          {label}{optional ? ' · optional' : ''}
        </div>
        <input
          type="date"
          value={value || ''}
          autoComplete={autoComplete}
          onFocus={() => setFocused(true)}
          onBlur={() => setFocused(false)}
          onChange={e => onChange(e.target.value)}
          style={{
            width: '100%',
            background: brand.surface,
            border: `1.5px solid ${borderColor}`,
            borderRadius: 12,
            padding: '14px 14px',
            fontSize: 15,
            color: filled ? brand.ink : brand.inkSoft,
            outline: 'none',
            transition: 'border-color .15s ease, box-shadow .15s ease',
            boxShadow: focused ? `0 0 0 3px ${brand.accentSoft}` : 'none',
            fontFamily: brand.bodyFont,
          }}
        />
      </label>
    );
  }
  return (
    <label style={{
      display: 'block',
      position: 'relative',
      marginBottom: 10,
    }}>
      <div style={{
        position: 'absolute',
        left: 14,
        top: lifted ? 8 : 17,
        fontSize: lifted ? 10.5 : 14,
        fontWeight: lifted ? 600 : 400,
        color: lifted ? (error ? '#C0392B' : brand.inkSoft) : brand.inkSoft,
        letterSpacing: lifted ? '0.04em' : 0,
        textTransform: lifted ? 'uppercase' : 'none',
        transition: 'all .15s ease',
        pointerEvents: 'none',
        background: 'transparent',
      }}>
        {label}{optional && lifted ? ' · optional' : ''}
      </div>
      <Tag
        type={type}
        value={value || ''}
        autoComplete={autoComplete}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        onChange={e => onChange(e.target.value)}
        rows={rows}
        style={{
          width: '100%',
          background: brand.surface,
          border: `1.5px solid ${borderColor}`,
          borderRadius: 12,
          padding: rows ? '24px 14px 12px' : '22px 14px 8px',
          fontSize: 15,
          color: brand.ink,
          outline: 'none',
          transition: 'border-color .15s ease, box-shadow .15s ease',
          boxShadow: focused ? `0 0 0 3px ${brand.accentSoft}` : 'none',
          fontFamily: brand.bodyFont,
          resize: rows ? 'vertical' : undefined,
          minHeight: rows ? 80 : undefined,
        }}
      />
      {error && (
        <div style={{ fontSize: 11.5, color: '#C0392B', marginTop: 4, paddingLeft: 4 }}>{error}</div>
      )}
      {hint && !error && (
        <div style={{ fontSize: 11.5, color: brand.inkSoft, marginTop: 4, paddingLeft: 4 }}>{hint}</div>
      )}
    </label>
  );
}

// ────────────────────────────────────────────────────────────────
//  Primary CTA button — wears the studio's accent color
// ────────────────────────────────────────────────────────────────
function PrimaryButton({ children, onClick, brand, loading, disabled, full=true, sub }) {
  return (
    <button onClick={onClick} disabled={disabled || loading} style={{
      width: full ? '100%' : 'auto',
      background: disabled ? brand.border : brand.accent,
      color: '#fff',
      border: 0,
      borderRadius: 14,
      padding: sub ? '14px 18px' : '16px 18px',
      fontSize: 15.5,
      fontWeight: 700,
      fontFamily: brand.bodyFont,
      letterSpacing: '-0.005em',
      boxShadow: disabled ? 'none' : `0 6px 20px ${brand.accent}40`,
      transition: 'transform .1s ease, background .15s ease, box-shadow .15s ease',
      transform: 'translateZ(0)',
      cursor: disabled || loading ? 'not-allowed' : 'pointer',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
      lineHeight: 1.1,
    }}
      onMouseDown={e => !disabled && !loading && (e.currentTarget.style.transform = 'scale(.98)')}
      onMouseUp={e => (e.currentTarget.style.transform = 'scale(1)')}
      onMouseLeave={e => (e.currentTarget.style.transform = 'scale(1)')}
    >
      {loading
        ? <Spinner />
        : <span style={{ display: 'flex', flexDirection: sub ? 'column' : 'row', alignItems: 'center', gap: sub ? 1 : 8 }}>
            <span>{children}</span>
            {sub && <span style={{ fontSize: 11.5, fontWeight: 500, opacity: .85, letterSpacing: '0.01em' }}>{sub}</span>}
          </span>
      }
    </button>
  );
}

function Spinner({ size = 18, color = '#fff' }) {
  return (
    <span style={{
      width: size, height: size,
      border: `2px solid ${color}40`,
      borderTopColor: color,
      borderRadius: 999,
      display: 'inline-block',
      animation: 'spinFlip 0.7s linear infinite',
    }}>
      <style>{`@keyframes spinFlip { to { transform: rotate(360deg); } }`}</style>
    </span>
  );
}

// ────────────────────────────────────────────────────────────────
//  Capacity counter — three states
// ────────────────────────────────────────────────────────────────
function CapacityCounter({ state='plenty', brand, total=12 }) {
  const cfg = ({
    plenty:  { taken: 4,  bg: '#E8EDE4', text: '#3D5C2E', dot: '#6ABC5A', label: `${total - 4} of ${total} spots left` },
    almost:  { taken: 11, bg: '#F5EFE0', text: '#8A6620', dot: '#C4993A', label: `Only 1 spot left` },
    waitlist:{ taken: 12, bg: '#F2E6E8', text: '#6C2030', dot: '#A04A5A', label: `Class is full · join waitlist` },
  })[state];

  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 8,
      background: cfg.bg,
      color: cfg.text,
      padding: '5px 11px 5px 9px',
      borderRadius: 999,
      fontSize: 11.5,
      fontWeight: 600,
    }}>
      <span style={{
        width: 7, height: 7, borderRadius: 999, background: cfg.dot,
        boxShadow: state === 'almost' ? `0 0 0 3px ${cfg.dot}30` : 'none',
        animation: state === 'almost' ? 'pulseDot 1.6s ease-in-out infinite' : 'none',
      }}></span>
      {cfg.label}
      <style>{`@keyframes pulseDot { 0%,100% { box-shadow: 0 0 0 0 ${cfg.dot}40; } 50% { box-shadow: 0 0 0 5px ${cfg.dot}10; } }`}</style>
    </div>
  );
}

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

  return (
    <button style={{
      flex: 1,
      background: styles.bg,
      color: styles.fg,
      border: kind === 'google' ? `1px solid ${brand.border}` : 0,
      borderRadius: 12,
      padding: '12px 0',
      fontSize: 14.5,
      fontWeight: 600,
      fontFamily: brand.bodyFont,
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
      cursor: 'pointer',
      minHeight: 46,
    }}>
      {styles.label}
    </button>
  );
}

// Mock card field — looks like Stripe Elements
function CardField({ brand }) {
  // Start fields empty so browser autofill / wallet-fill is the only thing
  // that ever populates them. When autofill isn't available, the user just
  // sees the placeholder hint (1234 1234 1234 1234, MM / YY, CVC, ZIP).
  const [num, setNum] = useState('');
  const [exp, setExp] = useState('');
  const [cvc, setCvc] = useState('');
  const [zip, setZip] = useState('');
  const placeholderColor = brand.inkSoft || '#8C9690';
  const inputStyle = {
    flex: 1,
    background: 'transparent',
    border: 0,
    fontSize: 14,
    color: brand.ink,
    outline: 'none',
    fontFamily: brand.bodyFont,
    padding: '14px 12px',
    minWidth: 0,
  };
  return (
    <div style={{
      background: brand.surface,
      border: `1.5px solid ${brand.border}`,
      borderRadius: 12,
      overflow: 'hidden',
    }}>
      <style>{`
        .cf-input::placeholder { color: ${placeholderColor}; opacity: 1; }
      `}</style>
      <div style={{ display: 'flex', alignItems: 'center', borderBottom: `1px solid ${brand.border}` }}>
        <input
          className="cf-input"
          value={num} onChange={e => setNum(e.target.value)}
          placeholder="1234 1234 1234 1234"
          inputMode="numeric" autoComplete="cc-number"
          name="cardnumber" aria-label="Card number"
          style={{ ...inputStyle, paddingLeft: 14 }} />
        <div style={{ display: 'flex', gap: 4, paddingRight: 12 }}>
          <CardLogo brand="visa" />
          <CardLogo brand="mc" />
          <CardLogo brand="amex" />
        </div>
      </div>
      <div style={{ display: 'flex' }}>
        <input
          className="cf-input"
          value={exp} onChange={e => setExp(e.target.value)}
          placeholder="MM / YY"
          inputMode="numeric" autoComplete="cc-exp"
          name="cc-exp" aria-label="Card expiration date"
          style={{ ...inputStyle, borderRight: `1px solid ${brand.border}`, paddingLeft: 14 }} />
        <input
          className="cf-input"
          value={cvc} onChange={e => setCvc(e.target.value)}
          placeholder="CVC"
          inputMode="numeric" autoComplete="cc-csc"
          name="cvc" aria-label="Card security code"
          style={{ ...inputStyle, borderRight: `1px solid ${brand.border}` }} />
        <input
          className="cf-input"
          value={zip} onChange={e => setZip(e.target.value)}
          placeholder="ZIP"
          inputMode="numeric" autoComplete="postal-code"
          name="postal" aria-label="Billing ZIP code"
          style={inputStyle} />
      </div>
    </div>
  );
}
function CardLogo({ brand }) {
  const fills = { visa:'#1A1F71', mc:'#EB001B', amex:'#006FCF' };
  const labels = { visa:'VISA', mc:'mc', amex:'AMEX' };
  return (
    <div style={{
      width: 30, height: 20,
      borderRadius: 4,
      background: '#fff',
      border: '1px solid #E8E8E4',
      display: 'grid', placeItems: 'center',
      fontSize: 8, fontWeight: 800,
      color: fills[brand],
      fontFamily: 'system-ui, sans-serif',
      letterSpacing: '-0.02em',
    }}>{labels[brand]}</div>
  );
}

// Payment section combining wallets + card + ACH
function PaymentSection({ brand, methods }) {
  const wallets = [];
  if (methods.apple)  wallets.push(<WalletButton key="a" kind="apple"  brand={brand} />);
  if (methods.google) wallets.push(<WalletButton key="g" kind="google" brand={brand} />);
  if (methods.link)   wallets.push(<WalletButton key="l" kind="link"   brand={brand} />);

  return (
    <div>
      {wallets.length > 0 && (
        <>
          <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>{wallets}</div>
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10,
            margin: '14px 0 14px',
            color: brand.inkSoft,
            fontSize: 11,
            letterSpacing: '0.08em',
            textTransform: 'uppercase',
            fontWeight: 600,
          }}>
            <div style={{ flex: 1, height: 1, background: brand.border }}></div>
            or pay with card
            <div style={{ flex: 1, height: 1, background: brand.border }}></div>
          </div>
        </>
      )}
      <CardField brand={brand} />
      <button style={{
        marginTop: 8,
        background: 'transparent',
        border: 0,
        color: brand.inkSoft,
        fontSize: 12.5,
        padding: '4px 0',
        fontWeight: 500,
      }}>or pay by bank transfer (ACH) →</button>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
//  Generic summary "what you're buying" card
// ────────────────────────────────────────────────────────────────
function SummaryCard({ brand, children }) {
  return (
    <div style={{
      background: brand.surface,
      border: `1px solid ${brand.border}`,
      borderRadius: 16,
      padding: 16,
      marginBottom: 18,
    }}>{children}</div>
  );
}

// Pill (small inline badge) — for tags like "First class free", "Member price"
function Pill({ brand, children, accent }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center',
      padding: '3px 9px',
      borderRadius: 999,
      fontSize: 10.5,
      fontWeight: 700,
      letterSpacing: '0.04em',
      textTransform: 'uppercase',
      background: accent ? brand.accentSoft : brand.border + '60',
      color: accent ? brand.accentDeep : brand.inkSoft,
    }}>{children}</span>
  );
}

// Inline checkbox for waiver / terms
function Checkbox({ checked, onChange, children, brand }) {
  return (
    <label style={{
      display: 'flex', alignItems: 'flex-start', gap: 10,
      cursor: 'pointer',
      padding: '10px 12px',
      border: `1px solid ${brand.border}`,
      borderRadius: 12,
      background: brand.surface,
    }}>
      <span onClick={e => { e.preventDefault(); onChange(!checked); }} style={{
        flex: '0 0 18px',
        width: 18, height: 18,
        marginTop: 1,
        borderRadius: 5,
        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="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>
      <span style={{ fontSize: 13, color: brand.ink, lineHeight: 1.4 }}>{children}</span>
      <input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)} style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
    </label>
  );
}

Object.assign(window, {
  StudioHeader, SectionTitle, Field,
  PrimaryButton, Spinner,
  CapacityCounter, WalletButton, CardField, PaymentSection,
  SummaryCard, Pill, Checkbox,
});
