// claude-onboarding.jsx — Settld onboarding, redesigned.
// Thesis: value BEFORE the gate (PCD §6.3). The user touches a live split and
// sees "X owes you ₹Y" before being asked for phone/OTP. Fewer steps, each
// justified. Settling lands on a PENDING state with a butter pulse dot, not
// instant confetti — honouring the real two-party confirm model from flows/07.

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "entry": "new",
  "step": "1"
}/*EDITMODE-END*/;

// ── helpers ───────────────────────────────────────────────────
const inr = (n) => new Intl.NumberFormat('en-IN').format(Math.round(n));

function initials(name) {
  if (!name) return '?';
  const parts = name.trim().split(/\s+/).filter(Boolean);
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}

function formatPhone(v) {
  v = v.replace(/\D/g, '').slice(0, 10);
  if (v.length > 5) v = v.slice(0, 5) + ' ' + v.slice(5);
  return v;
}

// ── default demo data (seeded so any step survives a cold jump) ──
const DEMO_SPLIT = {
  title: 'Farzi Cafe · dinner',
  total: 4200,
  payer: 'Aarav',
  people: [
    { id: 'a', name: 'Aarav',  color: 'teal',   avClass: '' },
    { id: 'p', name: 'Priya',  color: 'coral',  avClass: 'c2' },
    { id: 'r', name: 'Rohan',  color: 'teal',   avClass: '' },
    { id: 'k', name: 'Kabir',  color: 'butter', avClass: 'c3' },
  ],
};

const DEFAULT_CREW = [
  { name: 'Priya', phone: '98201 22134', avClass: '' },
  { name: 'Rohan', phone: '99876 44210', avClass: 'c2' },
  { name: 'Kabir', phone: '93215 87090', avClass: 'c3' },
  { name: 'Tara',  phone: '74091 66001', avClass: 'c2' },
];

const FAKE_OTP = '248361';
const TOTAL_STEPS = 5;

// ── CTA row ───────────────────────────────────────────────────
function CtaRow({ onNext, nextLabel = 'continue →', nextDisabled = false, onBack, children }) {
  return (
    <div className="ob-cta">
      {onBack && (
        <button className="c-btn ghost-only" onClick={onBack}>← back</button>
      )}
      {children ? children : (
        <button
          className="c-btn primary"
          onClick={onNext}
          disabled={nextDisabled}
          style={{ opacity: nextDisabled ? 0.42 : 1, cursor: nextDisabled ? 'not-allowed' : 'pointer' }}
        >
          {nextLabel}
        </button>
      )}
    </div>
  );
}

// ── STEP 1: Feel it first ─────────────────────────────────────
function Step1Feel({ onNext }) {
  const [included, setIncluded] = React.useState(
    () => new Set(DEMO_SPLIT.people.map((p) => p.id))
  );

  const toggle = (id) => {
    setIncluded((prev) => {
      const next = new Set(prev);
      if (next.has(id) && next.size === 1) return prev; // never all excluded
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const count = included.size;
  const share = count > 0 ? DEMO_SPLIT.total / count : DEMO_SPLIT.total;

  return (
    <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">this is a split</span>
      <h1 className="ob-h c-reveal ob-r2">
        ₹{inr(DEMO_SPLIT.total)} at <em>Farzi Cafe</em>.
        <br />Feel how it splits.
      </h1>
      <p className="ob-sub c-reveal ob-r3">
        Tap a person to include or exclude them. Watch the amounts re-balance live.
        No account needed yet.
      </p>

      <div className="ob-demo-card c-reveal ob-r4">
        <div className="ob-demo-head">
          <div className="ob-demo-title">{DEMO_SPLIT.title}</div>
          <div className="ob-demo-total">
            <span className="cur">₹</span>{inr(DEMO_SPLIT.total)}
          </div>
        </div>

        <div className="ob-demo-hint">tap to include / exclude ↓</div>

        {DEMO_SPLIT.people.map((p, i) => {
          const isIn = included.has(p.id);
          const avColors = {
            teal:   { bg: '#D6EAE2', fg: '#0A5F4F' },
            coral:  { bg: '#FADED4', fg: '#8B3722' },
            butter: { bg: '#F5E4A8', fg: '#6B5208' },
          };
          const col = avColors[p.color];
          return (
            <div
              key={p.id}
              className={`ob-share-row c-reveal ob-r${Math.min(i + 1, 5)}${isIn ? ' included' : ' excluded'}`}
              onClick={() => toggle(p.id)}
              role="checkbox"
              aria-checked={isIn}
              tabIndex={0}
              onKeyDown={(e) => { if (e.key === ' ' || e.key === 'Enter') toggle(p.id); }}
            >
              <div
                className="ob-share-av"
                style={{ background: col.bg, color: col.fg }}
              >
                {initials(p.name)}
              </div>
              <div className="ob-share-name">{p.name}</div>
              <div className="ob-share-amt">
                {isIn ? `₹${inr(share)}` : '—'}
              </div>
              <div className="ob-share-check">
                {isIn && (
                  <svg viewBox="0 0 10 10" fill="none" width="10" height="10">
                    <path d="M2 5l2.5 2.5L8 2.5" stroke="#FBF8F0" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                )}
              </div>
            </div>
          );
        })}

        <div className="ob-demo-rebalance-note">
          {count} {count === 1 ? 'person' : 'people'} · ₹{inr(share)} each
        </div>
      </div>

      <CtaRow onNext={onNext} nextLabel="make my own →" />
    </div>
  );
}

// ── STEP 2: You ───────────────────────────────────────────────
function Step2You({ name, setName, phone, setPhone, onNext, onBack }) {
  const isValid = name.trim().length >= 2 && phone.replace(/\s+/g, '').length === 10;

  return (
    <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">who are you</span>
      <h2 className="ob-h c-reveal ob-r2">First, the <em>basics</em>.</h2>
      <p className="ob-sub c-reveal ob-r3">
        No email, no password. Just enough so a chai split looks like a chai split with Rohan.
      </p>

      <div className="ob-field-block c-reveal ob-r4">
        <div className="ob-field">
          <label className="ob-field-label" htmlFor="ob-name">Your name</label>
          <input
            id="ob-name"
            className="ob-input"
            type="text"
            placeholder="Aarav Mehta"
            autoComplete="given-name"
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
        </div>
        <div className="ob-field">
          <label className="ob-field-label" htmlFor="ob-phone">Phone · OTP next, never spam</label>
          <div className="ob-phone-row">
            <span className="ob-phone-prefix">+91</span>
            <input
              id="ob-phone"
              className="ob-input mono"
              type="tel"
              placeholder="98765 43210"
              maxLength={11}
              value={phone}
              onChange={(e) => setPhone(formatPhone(e.target.value))}
            />
          </div>
        </div>
      </div>

      <CtaRow
        onNext={onNext}
        onBack={onBack}
        nextLabel="send OTP →"
        nextDisabled={!isValid}
      />
    </div>
  );
}

// ── STEP 3: Verify ────────────────────────────────────────────
function Step3Verify({ phone, entry, onVerified, onBack }) {
  const [digits, setDigits] = React.useState('');
  const [smsBannerVisible, setSmsBannerVisible] = React.useState(false);
  const inputRef = React.useRef(null);
  const timerRef = React.useRef(null);
  const smsTimerRef = React.useRef(null);

  // focus on step entry and schedule fake SMS
  React.useEffect(() => {
    setDigits('');
    setTimeout(() => {
      try { inputRef.current && inputRef.current.focus({ preventScroll: true }); } catch(e) {}
    }, 400);
    smsTimerRef.current = setTimeout(() => setSmsBannerVisible(true), 1100);
    return () => {
      clearTimeout(timerRef.current);
      clearTimeout(smsTimerRef.current);
    };
  }, []);

  // auto-advance when 6 digits filled
  React.useEffect(() => {
    if (digits.length === 6) {
      timerRef.current = setTimeout(() => onVerified(), 380);
    }
    return () => clearTimeout(timerRef.current);
  }, [digits]);

  const handleInput = (e) => {
    const clean = e.target.value.replace(/\D/g, '').slice(0, 6);
    setDigits(clean);
  };

  const autofill = () => {
    setSmsBannerVisible(false);
    let i = 0;
    const tick = () => {
      if (i >= 6) return;
      setDigits(FAKE_OTP.slice(0, ++i));
      setTimeout(tick, 75);
    };
    tick();
  };

  const displayPhone = phone.length > 0 ? `+91 ${phone}` : '+91 98765 43210';

  return (
    <>
      {/* SMS banner — direct child of ob-step so it anchors to the absolute container */}
      <div
        className={`ob-sms-banner${smsBannerVisible ? ' in' : ''}`}
        onClick={autofill}
      >
        <div className="ob-sms-icon">S</div>
        <div className="ob-sms-body">
          <div className="ob-sms-top">
            <span>Settld</span>
            <span className="dot" />
            <span>now</span>
          </div>
          <div className="ob-sms-text"><b>{FAKE_OTP.slice(0,3)}&nbsp;{FAKE_OTP.slice(3)}</b>&nbsp;is your Settld code.</div>
        </div>
        <span className="ob-sms-hint">Fill</span>
      </div>

      <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">verify · step 2/5</span>
      <h2 className="ob-h c-reveal ob-r2">Six digits, <em>freshly stamped</em>.</h2>
      <p className="ob-otp-meta c-reveal ob-r3">{displayPhone}</p>
      <p className="ob-otp-sent c-reveal ob-r3">code sent · tap the banner or enter manually</p>

      <div className="ob-otp-wrap c-reveal ob-r4">
        <input
          ref={inputRef}
          className="ob-otp-native"
          type="tel"
          inputMode="numeric"
          autoComplete="one-time-code"
          maxLength={6}
          value={digits}
          onChange={handleInput}
          aria-label="6-digit verification code"
        />
        <div className="ob-otp-cells">
          {Array.from({ length: 6 }).map((_, i) => {
            const char = digits[i] || '';
            const firstEmpty = digits.length;
            const isFilled = !!char;
            const isCursor = !isFilled && i === firstEmpty;
            return (
              <div
                key={i}
                className={`ob-otp-cell${isFilled ? ' filled' : ''}${isCursor ? ' cursor' : ''}`}
              >
                {char}
              </div>
            );
          })}
        </div>
      </div>

      <p className="ob-otp-resend c-reveal ob-r5">
        Didn't get it?{' '}
        <span className="ob-otp-link" onClick={() => {}}>resend</span>
        {' · '}
        <span className="ob-otp-link" onClick={autofill}>demo autofill</span>
      </p>

      <CtaRow onBack={onBack}>
        <button className="c-btn secondary" onClick={onBack} style={{ flex: '0 0 auto' }}>
          edit number
        </button>
      </CtaRow>
      </div>
    </>
  );
}

// ── STEP 4: Your crew ─────────────────────────────────────────
function Step4Crew({ crew, setCrew, onNext, onBack }) {
  const [permDone, setPermDone] = React.useState(false);
  const [contactPref, setContactPref] = React.useState(null); // null | 'yes' | 'no'
  const [added, setAdded] = React.useState(new Set()); // set of names
  const [manualVal, setManualVal] = React.useState('');

  const handlePermAction = (action) => {
    setContactPref(action);
    setPermDone(true);
  };

  const toggleContact = (name) => {
    setAdded((prev) => {
      const next = new Set(prev);
      if (next.has(name)) next.delete(name);
      else next.add(name);
      // Sync up to parent crew state
      const newCrew = DEFAULT_CREW.filter((c) => next.has(c.name));
      setCrew(newCrew);
      return next;
    });
  };

  const addManual = () => {
    const name = manualVal.trim();
    if (!name || added.has(name)) return;
    const newPerson = { name, phone: '', avClass: '' };
    setCrew((prev) => [...prev, newPerson]);
    setAdded((prev) => new Set(prev).add(name));
    setManualVal('');
  };

  const removeChip = (name) => {
    setAdded((prev) => {
      const next = new Set(prev);
      next.delete(name);
      return next;
    });
    setCrew((prev) => prev.filter((c) => c.name !== name));
  };

  const canProceed = added.size >= 1;
  const showContacts = permDone && contactPref === 'yes';
  const showManual = permDone && contactPref === 'no';

  return (
    <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">your crew</span>
      <h2 className="ob-h c-reveal ob-r2">Who's in <em>on this</em>?</h2>

      {/* permission pre-prompt */}
      <div className={`ob-perm-block c-reveal ob-r3${permDone ? ' consumed' : ''}`}>
        <p className="ob-perm-h">Find friends faster?</p>
        <p className="ob-perm-p">
          We'll suggest people from your contacts when you split. Your address book never
          leaves this device — nothing is uploaded, nobody gets texted without your tap.
        </p>
        <div className="ob-perm-cta">
          <button className="c-btn secondary" onClick={() => handlePermAction('no')}>
            skip — I'll type
          </button>
          <button className="c-btn primary" onClick={() => handlePermAction('yes')}>
            allow contacts
          </button>
        </div>
      </div>

      {/* chip stage */}
      {permDone && (
        <>
          <p className="ob-crew-label">To →</p>
          <div className={`ob-chip-stage${added.size > 0 ? ' has-items' : ''}`}>
            {added.size === 0 && (
              <span className="ob-chip-empty">nobody yet — tap a name below</span>
            )}
            {Array.from(added).map((name) => {
              const contact = DEFAULT_CREW.find((c) => c.name === name) || { avClass: '' };
              return (
                <span key={name} className="ob-chip">
                  <span className={`ob-chip-av ${contact.avClass}`}>{initials(name)}</span>
                  {name}
                  <span className="ob-chip-rm" onClick={() => removeChip(name)}>×</span>
                </span>
              );
            })}
          </div>

          {showContacts && (
            <>
              <p className="ob-contacts-label">From your contacts</p>
              <div className="ob-contact-list">
                {DEFAULT_CREW.map((c) => (
                  <div
                    key={c.name}
                    className={`ob-contact-row${added.has(c.name) ? ' added' : ''}`}
                    onClick={() => toggleContact(c.name)}
                  >
                    <div className={`ob-contact-av ${c.avClass}`}>{initials(c.name)}</div>
                    <div className="ob-contact-info">
                      <div className="ob-contact-name">{c.name}</div>
                      <div className="ob-contact-sub">+91 {c.phone}</div>
                    </div>
                    <div className="ob-contact-add">
                      {added.has(c.name) ? (
                        <svg viewBox="0 0 10 10" fill="none" width="10" height="10">
                          <path d="M2 5l2.5 2.5L8 2.5" stroke="#FBF8F0" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
                        </svg>
                      ) : '+'}
                    </div>
                  </div>
                ))}
              </div>
            </>
          )}

          {showManual && (
            <>
              <p className="ob-contacts-label">Add manually</p>
              <div className="ob-manual-row">
                <input
                  className="ob-manual-input"
                  type="text"
                  placeholder="Type a name…"
                  maxLength={24}
                  value={manualVal}
                  onChange={(e) => setManualVal(e.target.value)}
                  onKeyDown={(e) => { if (e.key === 'Enter' && manualVal.trim()) addManual(); }}
                />
                <button
                  className="ob-manual-btn"
                  onClick={addManual}
                  disabled={!manualVal.trim()}
                >
                  Add
                </button>
              </div>
            </>
          )}
        </>
      )}

      <CtaRow
        onNext={onNext}
        onBack={onBack}
        nextLabel="lock them in →"
        nextDisabled={!canProceed}
      />
    </div>
  );
}

// ── STEP 5: First split → honest settle ───────────────────────
function Step5Split({ name, crew, onReset }) {
  const [pending, setPending] = React.useState(false);

  // Build split from crew + self
  const payer = name.trim().split(/\s+/)[0] || 'You';
  const crewNames = crew.length > 0
    ? crew.slice(0, 3).map((c) => c.name)
    : ['Priya', 'Rohan', 'Kabir'];
  const allPeople = [payer, ...crewNames];
  const total = 4200;
  const share = total / allPeople.length;

  const avClasses = ['', 'c2', 'c3', ''];

  const handleSettle = () => {
    setPending(true);
  };

  const handleLettsSettld = () => {
    // Resets to step 1 for prototype looping
    setPending(false);
    onReset();
  };

  return (
    <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">first split · live</span>
      <h2 className="ob-h c-reveal ob-r2">
        {pending ? <>Waiting on <em>{crewNames[0] || 'Priya'}</em>.</> : <>Watch it <em>settle</em>.</>}
      </h2>
      {!pending && (
        <p className="ob-sub c-reveal ob-r3">
          This is your first real split. Tap "settle up" — see what actually happens.
        </p>
      )}

      {/* Split card */}
      <div className={`ob-split-card c-reveal ob-r4${pending ? '' : ''}`}>
        <div className="ob-split-head">
          <div className="ob-split-title">Farzi Cafe · dinner</div>
          <div className="ob-split-label">split</div>
        </div>
        <div className="ob-split-amt">
          <span className="cur">₹</span>{inr(total)}
        </div>
        <div className="ob-split-payer">
          Paid by <b>{payer}</b> · split {allPeople.length} ways
        </div>
        <div>
          {allPeople.map((person, i) => (
            <div key={person} className="ob-owe-row" style={{ opacity: pending && i === 0 ? 0.42 : 1 }}>
              <div className={`ob-owe-av ${avClasses[i] || ''}`}>{initials(person)}</div>
              <div className="ob-owe-name">
                {i === 0 ? `${person} (you)` : person}
              </div>
              <div className="ob-owe-amt" style={{ color: i === 0 ? 'var(--teal)' : undefined }}>
                {i === 0 ? `gets back ₹${inr(share * (allPeople.length - 1))}` : `owes ₹${inr(share)}`}
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Pending settle state */}
      {pending && (
        <div className="ob-settle-state show c-reveal ob-r4">
          <div className="ob-settle-h">
            <span className="c-pending-dot" />
            Opening UPI app…
          </div>
          <p className="ob-settle-lede">
            Waiting for {crewNames[0] || 'Priya'} to confirm they got it.
          </p>
          <div className="ob-settle-note">
            <b>Settld never moves money</b> — it just opens your UPI app, and marks the split
            settled once they confirm receipt. Until then, it shows as pending.
          </div>
        </div>
      )}

      {/* CTA */}
      <div className="ob-cta">
        {!pending ? (
          <>
            <button className="c-btn secondary" onClick={onReset} style={{ flex: '0 0 auto' }}>← back</button>
            <button className="c-btn primary" onClick={handleSettle}>
              settle up →
            </button>
          </>
        ) : (
          <button className="c-btn primary" style={{ background: 'var(--teal)' }} onClick={handleLettsSettld}>
            let's settld →
          </button>
        )}
      </div>
    </div>
  );
}

// ── RETURNING: welcome back screen (after OTP in returning mode) ──
function ReturningWelcome({ phone, onContinue }) {
  return (
    <div className="ob-step-inner">
      <span className="ob-eyebrow c-reveal ob-r1">welcome back</span>
      <h2 className="ob-h c-reveal ob-r2">Back in <em>two taps</em>.</h2>
      <p className="ob-sub c-reveal ob-r3">Your splits are right where you left them.</p>

      <div className="ob-welcome-back c-reveal ob-r4">
        <span className="ob-eyebrow" style={{ marginBottom: 0 }}>signed in</span>
        <div className="ob-back-id">
          <div className="ob-back-av">A</div>
          <div>
            <div className="ob-back-name">Aarav Mehta</div>
            <div className="ob-back-phone">+91 {phone || '98765 43210'}</div>
          </div>
        </div>
        <div className="ob-back-ft">
          <span>Welcome back — your splits are waiting.</span>
          <span>Just now</span>
        </div>
      </div>

      <div className="ob-cta">
        <button className="c-btn primary" style={{ background: 'var(--teal)' }} onClick={onContinue}>
          let's settld →
        </button>
      </div>
    </div>
  );
}

// ── Tweaks panel ──────────────────────────────────────────────
function OnboardingTweaks({ t, setTweak }) {
  return (
    <window.TweaksPanel title="Onboarding tweaks">
      <window.TweakSection label="flow">
        <window.TweakRadio
          label="entry"
          value={t.entry}
          options={[
            { label: 'new',       value: 'new' },
            { label: 'returning', value: 'returning' },
          ]}
          onChange={(v) => setTweak('entry', v)}
        />
      </window.TweakSection>
      <window.TweakSection label="jump to step">
        <window.TweakSelect
          label="step"
          value={t.step}
          options={[
            { label: '1 · Feel it',   value: '1' },
            { label: '2 · You',       value: '2' },
            { label: '3 · Verify',    value: '3' },
            { label: '4 · Crew',      value: '4' },
            { label: '5 · Settle',    value: '5' },
          ]}
          onChange={(v) => setTweak('step', v)}
        />
      </window.TweakSection>
    </window.TweaksPanel>
  );
}

// ── Root ───────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  // user identity
  const [name, setName] = React.useState('');
  const [phone, setPhone] = React.useState('');

  // crew
  const [crew, setCrew] = React.useState([]);

  // step state — single source of truth
  const [step, setStep] = React.useState(1);

  // when tweaks change, jump to that step and reset derived state
  React.useEffect(() => {
    const n = parseInt(t.step, 10);
    if (!isNaN(n) && n >= 1 && n <= 5) {
      setStep(n);
    }
  }, [t.step, t.entry]);

  // returning mode short-circuits to phone→OTP→welcome
  const isReturning = t.entry === 'returning';

  // for returning, we remap visual steps: 1→phone, 2→otp, 3→welcome
  // but we keep internal state as 1/2/3 for returning and 1-5 for new
  // simplification: just use a single step integer; returning users have steps 1,2,3 mapped to 2,3,returning
  const goTo = (n) => {
    setStep(n);
    setTweak('step', String(n));
  };

  const goNext = () => goTo(step + 1);
  const goBack = () => goTo(Math.max(1, step - 1));

  function renderStep() {
    if (isReturning) {
      // Returning: show phone → otp → welcome (3-step sequence)
      const rs = Math.max(1, Math.min(3, step));
      if (rs === 1) {
        return (
          <Step2You
            name={name} setName={setName}
            phone={phone} setPhone={setPhone}
            onNext={goNext}
            onBack={null}
          />
        );
      }
      if (rs === 2) {
        return (
          <Step3Verify
            phone={phone}
            entry="returning"
            onVerified={goNext}
            onBack={goBack}
          />
        );
      }
      // rs === 3
      return (
        <ReturningWelcome
          phone={phone}
          onContinue={() => goTo(1)}
        />
      );
    }

    // New user: steps 1-5
    switch (step) {
      case 1:
        return <Step1Feel onNext={goNext} />;
      case 2:
        return (
          <Step2You
            name={name} setName={setName}
            phone={phone} setPhone={setPhone}
            onNext={goNext}
            onBack={goBack}
          />
        );
      case 3:
        return (
          <Step3Verify
            phone={phone}
            entry="new"
            onVerified={goNext}
            onBack={goBack}
          />
        );
      case 4:
        return (
          <Step4Crew
            crew={crew} setCrew={setCrew}
            onNext={goNext}
            onBack={goBack}
          />
        );
      case 5:
        return (
          <Step5Split
            name={name}
            crew={crew}
            onReset={() => goTo(1)}
          />
        );
      default:
        return <Step1Feel onNext={goNext} />;
    }
  }

  const displayStep = isReturning ? Math.max(1, Math.min(3, step)) : Math.max(1, Math.min(TOTAL_STEPS, step));
  const totalSteps = isReturning ? 3 : TOTAL_STEPS;

  return (
    <>
      <window.IOSDevice width={390} height={844}>
        <div className="screen">
          {/* Step rail */}
          <div className="ob-rail" style={{ position: 'absolute', top: 66, left: 0, right: 0, padding: '0 20px', zIndex: 60 }}>
            {Array.from({ length: totalSteps }).map((_, i) => (
              <div key={i} className={
                `ob-pip${i + 1 < displayStep ? ' done' : i + 1 === displayStep ? ' active' : ''}`
              } />
            ))}
            <span className="ob-stamp">
              {String(displayStep).padStart(2, '0')} / {String(totalSteps).padStart(2, '0')}
            </span>
          </div>

          {/* Step slides */}
          <div style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
            {[1, 2, 3, 4, 5].map((s) => {
              const isActive = step === s;
              return (
                <div
                  key={s}
                  className={`ob-step${isActive ? ' active' : ''}`}
                >
                  {isActive && renderStep()}
                </div>
              );
            })}
          </div>
        </div>
      </window.IOSDevice>
      <OnboardingTweaks t={t} setTweak={setTweak} />
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
