// Mobile Responden Flow — landing → survey → reward
const { useState: useState_mr, useEffect: useEffect_mr } = React;

const DEMO_QUESTIONS = [
  { id: 'q1', type: 'open',   text: 'Sebutkan 3 nama brand kopi yang pertama kali muncul di pikiranmu.', placeholder: 'cth. Kopi Kenanga, Janji Manis, Tomoro' },
  { id: 'q2', type: 'choice', text: 'Brand kopi mana yang paling sering kamu beli dalam 30 hari terakhir?', options: ['Kopi Kenanga', 'Kopi Janji Manis', 'Tomoro Coffee', 'Fore Coffee', 'Lainnya'] },
  { id: 'q3', type: 'scale',  text: 'Seberapa kamu rekomendasikan Kopi Kenanga ke teman?' },
  { id: 'q4', type: 'choice', text: 'Apa alasan utama kamu memilih brand kopi favorit?', options: ['Rasa', 'Harga', 'Lokasi outlet', 'Promo', 'Kemasan'] },
  { id: 'q5', type: 'location', text: 'Di mana lokasimu sekarang?' },
];

function MobileFlow({ slug }) {
  const [stage, setStage] = useState_mr('landing'); // landing | profile | survey | reward
  const [step, setStep] = useState_mr(0);
  const [answers, setAnswers] = useState_mr({});
  const [location, setLocation] = useState_mr(null);
  const [detecting, setDetecting] = useState_mr(false);
  // Respondent profile collected before the questions, when the campaign
  // configures any respondentFields. Empty object when no profile is asked.
  const [profile, setProfile] = useState_mr({});

  // Live data when slug provided; otherwise fall back to demo questions
  // so the design canvas / preview still works end-to-end.
  const [survey, setSurvey] = useState_mr(null); // { campaign, questions, landing }
  const [loadError, setLoadError] = useState_mr(null);
  const [submitting, setSubmitting] = useState_mr(false);
  const [reward, setReward] = useState_mr(null); // { code, valueOrLink }

  // Active profile fields config (from campaign); region is intentionally
  // excluded — it's still collected via the location question / GPS.
  const respondentFields = (survey?.campaign?.respondentFields || []).filter(
    (f) => f && f.key !== 'region',
  );

  useEffect_mr(() => {
    if (!slug) return;
    window.api
      .getPublicSurvey(slug)
      .then(setSurvey)
      .catch((err) => setLoadError(err.message || 'Survei tidak tersedia'));
  }, [slug]);

  // When slug is set we're in real-survey mode → never fall back to demo
  // questions, otherwise the responder thinks they're filling out a different
  // brand's survey. Only the design-canvas (no slug) uses the demo set.
  const questions = slug
    ? (survey?.questions || []).map((q) => ({
        id: q.id,
        type: q.type,
        text: q.text,
        options: q.options || undefined,
        placeholder: 'Tulis jawabanmu di sini',
      }))
    : DEMO_QUESTIONS;

  const answer = (id, val) => setAnswers((a) => ({ ...a, [id]: val }));

  const submitToBackend = async () => {
    if (!slug || submitting) {
      setStage('reward');
      return;
    }
    // Preview mode (campaign not yet active): skip the POST and just show
    // the reward screen with a stub code so the owner can see the full flow
    // without polluting analytics.
    if (survey?.preview) {
      setReward({ type: 'preview', code: 'PRATINJAU-DEMO', valueOrLink: 'Pratinjau — jawaban tidak disimpan' });
      setStage('reward');
      return;
    }
    setSubmitting(true);
    try {
      const payload = {
        respondentName: profile.respondentName ?? null,
        region: location?.region ?? null,
        latitude: location?.lat ?? null,
        longitude: location?.lng ?? null,
        // Demographic fields the campaign asked for (sent only when filled).
        phone: profile.phone || null,
        ageRange: profile.ageRange || null,
        gender: profile.gender || null,
        education: profile.education || null,
        occupation: profile.occupation || null,
        incomeRange: profile.incomeRange || null,
        maritalStatus: profile.maritalStatus || null,
        domicileCity: profile.domicileCity || null,
        originCity: profile.originCity || null,
        answers: Object.entries(answers).map(([questionId, value]) => ({
          questionId,
          answerText: typeof value === 'string' ? value : JSON.stringify(value),
        })),
      };
      const res = await window.api.submitResponse(slug, payload);
      setReward(res.reward);
      setStage('reward');
    } catch (err) {
      setLoadError(err.message || 'Gagal mengirim jawaban');
    } finally {
      setSubmitting(false);
    }
  };

  const next = () => {
    if (step < questions.length - 1) setStep(step + 1);
    else if (slug) submitToBackend();
    else setStage('reward');
  };
  const back = () => step > 0 && setStep(step - 1);

  const detectGPS = () => {
    setDetecting(true);
    if (slug && navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (pos) => {
          setLocation({
            region: 'Lokasi GPS terdeteksi',
            lat: pos.coords.latitude,
            lng: pos.coords.longitude,
          });
          setDetecting(false);
        },
        () => {
          setLocation({ region: 'Gubeng, Surabaya', lat: -7.2756, lng: 112.7521 });
          setDetecting(false);
        },
        { enableHighAccuracy: false, timeout: 6000 },
      );
    } else {
      setTimeout(() => {
        setLocation({ region: 'Gubeng, Surabaya', lat: -7.2756, lng: 112.7521 });
        setDetecting(false);
      }, 1400);
    }
  };

  if (slug && loadError) {
    return (
      <div className="phone">
        <div className="phone-notch"></div>
        <div className="phone-screen" style={{ display: 'grid', placeItems: 'center', padding: 24, textAlign: 'center' }}>
          <div>
            <div style={{ fontSize: 32, marginBottom: 8 }}>🚧</div>
            <div style={{ fontWeight: 600, fontSize: 15 }}>Survei tidak tersedia</div>
            <div style={{ fontSize: 12.5, color: 'var(--ink-3)', marginTop: 6 }}>{loadError}</div>
          </div>
        </div>
      </div>
    );
  }

  if (slug && !survey) {
    return (
      <div className="phone">
        <div className="phone-notch"></div>
        <div className="phone-screen" style={{ display: 'grid', placeItems: 'center', color: 'var(--ink-3)' }}>
          Memuat survei…
        </div>
      </div>
    );
  }

  // Survey loaded but has no questions configured yet
  if (slug && survey && questions.length === 0) {
    return (
      <div className="phone">
        <div className="phone-notch"></div>
        <div className="phone-screen" style={{ display: 'grid', placeItems: 'center', padding: 24, textAlign: 'center' }}>
          <div>
            <div style={{ fontSize: 32, marginBottom: 8 }}>📝</div>
            <div style={{ fontWeight: 600, fontSize: 15 }}>Belum ada pertanyaan</div>
            <div style={{ fontSize: 12.5, color: 'var(--ink-3)', marginTop: 6 }}>
              Owner campaign perlu menambahkan pertanyaan dulu di Campaign Builder.
            </div>
          </div>
        </div>
      </div>
    );
  }

  const cur = questions[step];
  const answered = answers[cur?.id] || (cur?.type === 'location' && location);

  return (
    <div className="phone">
      <div className="phone-notch"></div>
      <div className="phone-screen" style={{ position: 'relative' }}>
        {survey?.preview && (
          <div style={{
            position: 'absolute', top: 50, left: '50%', transform: 'translateX(-50%)',
            zIndex: 60,
            padding: '4px 10px', fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em',
            background: 'oklch(0.96 0.06 75)', color: 'oklch(0.42 0.12 155)',
            border: '1px solid oklch(0.84 0.08 155)',
            borderRadius: 999,
            textTransform: 'uppercase',
          }}>
            🔒 PRATINJAU · {survey.campaign.status}
          </div>
        )}
        {/* status bar — only meaningful inside the design-canvas phone frame.
             Hidden on real-mobile viewports via .phone-host .phone-status-fake. */}
        <div className="phone-status-fake" style={{ height: 38, padding: '14px 26px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12, fontWeight: 600 }}>
          <span>9:41</span>
          <span style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <span style={{ fontSize: 10 }}>•••</span>
            <svg width="14" height="10" viewBox="0 0 14 10" fill="currentColor"><path d="M0 8h2v2H0zM4 6h2v4H4zM8 3h2v7H8zM12 0h2v10h-2z"/></svg>
            <svg width="22" height="10" viewBox="0 0 22 10" fill="none" stroke="currentColor" strokeWidth="1"><rect x="0.5" y="0.5" width="18" height="9" rx="2"/><rect x="2" y="2" width="13" height="6" rx="1" fill="currentColor"/><rect x="20" y="3.5" width="1.5" height="3" fill="currentColor"/></svg>
          </span>
        </div>

        {stage === 'landing' && (
          <ResLanding
            onStart={() => setStage(respondentFields.length > 0 ? 'profile' : 'survey')}
            campaignTitle={survey?.campaign?.title}
            landing={survey?.landing}
            reward={survey?.reward}
            questionCount={questions.length}
            profileFieldCount={respondentFields.length}
          />
        )}
        {stage === 'profile' && (
          <ResProfile
            fields={respondentFields}
            profile={profile}
            setProfile={setProfile}
            onBack={() => setStage('landing')}
            onContinue={() => setStage('survey')}
          />
        )}
        {stage === 'survey' && (
          <ResSurvey
            cur={cur} step={step} total={questions.length}
            answers={answers} answer={answer}
            location={location} setLocation={setLocation}
            detecting={detecting} detectGPS={detectGPS}
            next={next} back={back} answered={answered}
            submitting={submitting}
          />
        )}
        {stage === 'reward' && <ResReward
          reward={reward}
          onRestart={() => { setStage('landing'); setStep(0); setAnswers({}); setLocation(null); setReward(null); setProfile({}); }}
        />}
      </div>
    </div>
  );
}

// ─── Landing ─────────────────────────────────────────────────────────
// Responder-facing landing for the public /survey/:slug route. Pulls config
// from per-campaign LANDING_CONFIG (templateId, themeColor, logoUrl, hero
// text, custom styles), and now also surfaces:
//   • Reward preview (real type + value, from /api/public/surveys/:slug)
//   • Estimated duration (computed from question + profile field counts)
//   • A 3-step "what to expect" mini-stepper
//   • Trust signals (anonymous, no spam, instant reward)

// Map reward type → emoji + friendly label for the preview card.
const RES_REWARD_META = {
  voucher:        { emoji: '🎟️', label: 'Voucher Digital' },
  e_wallet:       { emoji: '💸', label: 'Cashback E-Wallet' },
  promo_code:     { emoji: '🏷️', label: 'Kode Promo' },
  digital_access: { emoji: '⭐', label: 'Akses Eksklusif' },
};

function ResLanding({ onStart, campaignTitle, landing, reward, questionCount = 5, profileFieldCount = 0 }) {
  const brand = campaignTitle
    ? campaignTitle.replace(/^(Brand Awareness|Market Gap|Concept Test|Brand Name Test|Brand Perception)\s+/i, '')
    : 'Kopi Kenanga';
  const cs = landing?.customStyles || {};
  const initials = (cs.logo || brand).slice(0, 2).toUpperCase();
  const themeColor = landing?.themeColor || 'var(--primary)';
  const heroText = landing?.heroText || 'Bantu kami jadi pilihan favoritmu ☕';
  const subhead = cs.subhead || 'Isi survei singkat dan dapatkan reward langsung. Jawabanmu sangat berharga buat kami.';
  const ctaText = cs.cta || 'Mulai Survei';
  const template = landing?.templateId || 'hero';
  const bgMode = cs.bg || (landing?.backgroundImage ? 'image' : 'gradient');

  // Estimate duration: ~12s per question, ~8s per profile field, +15s buffer.
  // Round to nearest 30s, display as "X menit" or "X½ menit".
  const estSeconds = Math.max(60, questionCount * 12 + profileFieldCount * 8 + 15);
  const estMinutes = Math.round(estSeconds / 30) / 2; // 0.5 increments
  const durationLabel = estMinutes < 1
    ? '< 1 menit'
    : Number.isInteger(estMinutes)
      ? `${estMinutes} menit`
      : `${Math.floor(estMinutes)}½ menit`;

  const rewardMeta = reward?.type ? RES_REWARD_META[reward.type] : null;

  // Theme — derive a darker companion color for the gradient using color-mix
  // (good browser support, vs the relative-oklch() syntax which is much newer).
  const darker = `color-mix(in oklch, ${themeColor}, black 25%)`;
  const overlay = `color-mix(in oklch, ${themeColor}, black 12%)`;
  const headerBg = (() => {
    if (bgMode === 'image' && landing?.backgroundImage) {
      return `linear-gradient(160deg, ${overlay} 0%, ${darker} 100%), url("${landing.backgroundImage}") center/cover no-repeat`;
    }
    if (bgMode === 'solid') return themeColor;
    return `linear-gradient(160deg, ${themeColor} 0%, ${darker} 100%)`;
  })();

  const isMinimal = template === 'minimal';

  return (
    <div className="fade-in scroll" style={{ display: 'flex', flexDirection: 'column', minHeight: 0, overflowY: 'auto' }}>
      {/* ─── Hero header with brand + headline ─────────────────────── */}
      <div style={{
        position: 'relative',
        background: headerBg,
        color: 'white',
        // Generous bottom padding agar headline + subhead pasti terlihat
        // sebelum reward card overlap. Kita kasih ~92px bottom (dengan
        // overlap -28 → visible margin sebelum chip = 64px).
        padding: isMinimal ? '32px 24px 92px' : '24px 24px 92px',
        borderRadius: '0 0 28px 28px',
        textAlign: isMinimal ? 'center' : 'left',
        overflow: 'hidden',
      }}>
        {/* Decorative orbs — pointerEvents none; ditaruh di pojok jauh
             supaya tidak menutupi text. */}
        <div style={{
          position: 'absolute', top: -50, right: -50,
          width: 140, height: 140, borderRadius: '50%',
          background: 'rgba(255,255,255,0.10)',
          pointerEvents: 'none',
        }} />
        <div style={{
          position: 'absolute', bottom: -80, left: -40,
          width: 180, height: 180, borderRadius: '50%',
          background: 'rgba(255,255,255,0.06)',
          pointerEvents: 'none',
        }} />

        {/* Brand identity — logo tampil natural sesuai aspect ratio.
             Logo wide (mis. 300×136) tidak dipaksa kotak — height tetap
             ~36px, width auto sampai 60% lebar hero. Kalau gak ada logo,
             fallback ke avatar inisial. */}
        <div style={{
          position: 'relative',
          marginBottom: isMinimal ? 16 : 18,
          textAlign: isMinimal ? 'center' : 'left',
        }}>
          {landing?.logoUrl ? (
            <>
              <img
                src={landing.logoUrl}
                alt={brand}
                style={{
                  height: 36, width: 'auto', maxWidth: '70%',
                  objectFit: 'contain',
                  display: isMinimal ? 'inline-block' : 'block',
                }}
              />
              <div style={{
                marginTop: 8, fontSize: 10.5, opacity: 0.85, fontWeight: 600,
                textTransform: 'uppercase', letterSpacing: '0.08em',
              }}>
                Survei resmi · {brand}
              </div>
            </>
          ) : (
            <div style={{
              display: 'flex', alignItems: 'center', gap: 10,
              justifyContent: isMinimal ? 'center' : 'flex-start',
            }}>
              <div style={{
                width: 40, height: 40, borderRadius: 11,
                background: 'rgba(255,255,255,0.18)', backdropFilter: 'blur(10px)',
                border: '1px solid rgba(255,255,255,0.3)',
                display: 'grid', placeItems: 'center',
                color: 'white', fontWeight: 700, fontSize: 14, flexShrink: 0,
              }}>{initials}</div>
              <div>
                <div style={{ fontWeight: 600, fontSize: 14 }}>{brand}</div>
                <div style={{ fontSize: 10.5, opacity: 0.8, fontWeight: 500, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Survei resmi</div>
              </div>
            </div>
          )}
        </div>

        <h1 style={{
          position: 'relative',
          fontSize: isMinimal ? 21 : 23,
          fontWeight: 700, lineHeight: 1.25, letterSpacing: '-0.01em',
          margin: 0,
          // Beri text-shadow halus supaya tetap kebaca walau orb terdekat
          textShadow: '0 1px 2px rgba(0,0,0,0.08)',
        }}>
          {heroText}
        </h1>
        <p style={{
          position: 'relative', fontSize: 13, opacity: 0.92, lineHeight: 1.5,
          marginTop: 10, marginBottom: 0,
        }}>
          {subhead}
        </p>
      </div>

      {/* ─── Reward preview card (overlapping the hero) ───────────── */}
      {rewardMeta && reward.valueOrLink && (
        <div style={{
          margin: '-28px 20px 0', position: 'relative',
          background: 'var(--surface)',
          border: '1px solid var(--line)',
          borderRadius: 14, padding: '12px 14px',
          boxShadow: 'var(--shadow-md)',
          display: 'flex', alignItems: 'center', gap: 12,
        }}>
          <div style={{
            width: 40, height: 40, borderRadius: 11,
            background: `${themeColor}15`,
            display: 'grid', placeItems: 'center',
            fontSize: 20, lineHeight: 1, flexShrink: 0,
          }}>{rewardMeta.emoji}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 10.5, color: 'var(--ink-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              Hadiah untukmu
            </div>
            <div style={{ fontSize: 13.5, fontWeight: 700, marginTop: 2, lineHeight: 1.3, color: 'var(--ink)' }}>
              {reward.valueOrLink}
            </div>
          </div>
          <span style={{
            fontSize: 9, padding: '3px 7px', borderRadius: 999, fontWeight: 700,
            background: 'oklch(0.95 0.05 155)', color: 'oklch(0.42 0.14 155)',
            textTransform: 'uppercase', letterSpacing: '0.05em', flexShrink: 0,
          }}>Otomatis</span>
        </div>
      )}

      {/* ─── Body: stats + steps + trust ──────────────────────────── */}
      <div style={{
        padding: rewardMeta ? '18px 24px 20px' : '24px 24px 20px',
        flex: 1, display: 'flex', flexDirection: 'column',
      }}>
        {/* Stats row */}
        <div style={{ display: 'flex', gap: 8, marginBottom: 20 }}>
          {[
            { ic: '⏱️', t: durationLabel, s: 'estimasi' },
            { ic: '📝', t: `${questionCount} soal`, s: 'singkat' },
            { ic: '🔒', t: 'Anonim', s: 'aman' },
          ].map((x, i) => (
            <div key={i} style={{
              flex: 1, padding: '12px 6px', textAlign: 'center',
              background: 'var(--bg-2)', borderRadius: 12,
            }}>
              <div style={{ fontSize: 18, marginBottom: 4 }}>{x.ic}</div>
              <div style={{ fontSize: 12.5, fontWeight: 600 }}>{x.t}</div>
              <div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{x.s}</div>
            </div>
          ))}
        </div>

        {/* "Cara kerja" mini-stepper */}
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontSize: 10.5, fontWeight: 700, color: 'var(--ink-3)',
            textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 10,
          }}>
            Cara kerja
          </div>
          {[
            profileFieldCount > 0
              ? { n: 1, t: 'Sedikit tentang kamu', d: `${profileFieldCount} info ringan untuk konteks` }
              : null,
            { n: profileFieldCount > 0 ? 2 : 1, t: 'Jawab pertanyaan', d: `${questionCount} soal pilihan & pendek` },
            { n: profileFieldCount > 0 ? 3 : 2, t: 'Klaim hadiah', d: rewardMeta ? 'Otomatis muncul setelah submit' : 'Selesai!' },
          ].filter(Boolean).map((s, i, arr) => (
            <div key={s.n} style={{ display: 'flex', alignItems: 'flex-start', gap: 12, position: 'relative' }}>
              <div style={{
                width: 28, height: 28, borderRadius: '50%',
                background: themeColor, color: 'white',
                display: 'grid', placeItems: 'center',
                fontSize: 12, fontWeight: 700, flexShrink: 0,
                position: 'relative', zIndex: 1,
              }}>{s.n}</div>
              <div style={{ paddingTop: 3, paddingBottom: i === arr.length - 1 ? 0 : 14, flex: 1 }}>
                <div style={{ fontSize: 13.5, fontWeight: 600 }}>{s.t}</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>{s.d}</div>
              </div>
              {i < arr.length - 1 && (
                <div style={{
                  position: 'absolute', left: 13.5, top: 28, bottom: -14,
                  width: 1, background: 'var(--line-2)',
                }} />
              )}
            </div>
          ))}
        </div>

        {/* Trust signals */}
        <div style={{
          display: 'flex', flexDirection: 'column', gap: 6,
          padding: '10px 12px', borderRadius: 10,
          background: 'var(--bg-2)', marginBottom: 16,
        }}>
          {[
            'Jawabanmu anonim — kami tidak menyimpan identitas pribadi.',
            'Tanpa spam, tanpa pendaftaran. Cuma 1 kali isi.',
            rewardMeta ? 'Hadiah otomatis muncul setelah submit, no follow-up.' : null,
          ].filter(Boolean).map((t, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 7, fontSize: 11.5, color: 'var(--ink-2)', lineHeight: 1.5 }}>
              <I.Check size={12} style={{ color: 'oklch(0.55 0.15 155)', marginTop: 2, flexShrink: 0 }} />
              <span>{t}</span>
            </div>
          ))}
        </div>

        {/* CTA */}
        <div style={{ marginTop: 'auto' }}>
          <button onClick={onStart} style={{
            width: '100%', padding: '15px',
            background: themeColor, color: 'white',
            border: 'none', borderRadius: 14, fontSize: 15, fontWeight: 600,
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
            boxShadow: `0 10px 24px -10px ${themeColor}`,
            cursor: 'pointer',
          }}>
            {ctaText} <I.ArrowRight size={16} />
          </button>
          <div style={{ textAlign: 'center', fontSize: 11, color: 'var(--ink-3)', marginTop: 12 }}>
            Powered by <b style={{ color: 'var(--ink-2)' }}>Survey TOM</b>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Profile ─────────────────────────────────────────────────────────
// Renders demographic fields the campaign asked for, in one screen, before
// the survey questions. Required fields gate the Continue button.
const PROFILE_LABELS_MR = {
  respondentName: { label: 'Nama lengkap', placeholder: 'cth. Putri Anjani', input: 'text' },
  phone:          { label: 'Nomor HP / WhatsApp', placeholder: '08xxxxxxxxxx', input: 'tel' },
  ageRange:       { label: 'Rentang umur',  options: ['18-24', '25-34', '35-44', '45+'] },
  gender:         { label: 'Gender',        options: ['perempuan', 'laki-laki', 'lainnya'] },
  education:      { label: 'Pendidikan terakhir', options: ['SD', 'SMP', 'SMA', 'D3', 'S1', 'S2', 'S3', 'Lainnya'] },
  occupation:     { label: 'Pekerjaan',     placeholder: 'cth. Mahasiswa, Guru, Wiraswasta', input: 'text' },
  incomeRange:    { label: 'Income bulanan', options: ['<2jt', '2-5jt', '5-10jt', '10-20jt', '>20jt'] },
  maritalStatus:  { label: 'Status pernikahan', options: ['single', 'menikah', 'bercerai', 'janda/duda'] },
  domicileCity:   { label: 'Kota domisili', placeholder: 'cth. Surabaya', input: 'text' },
  originCity:     { label: 'Kota asal',     placeholder: 'cth. Malang',   input: 'text' },
};

function ResProfile({ fields, profile, setProfile, onBack, onContinue }) {
  const set = (k, v) => setProfile((p) => ({ ...p, [k]: v }));
  const missingRequired = fields.some(
    (f) => f.required && !String(profile[f.key] ?? '').trim(),
  );

  return (
    <div className="fade-in" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
      <div style={{ padding: '16px 22px 0', display: 'flex', alignItems: 'center', gap: 12 }}>
        <button onClick={onBack} style={{
          background: 'none', border: 'none', padding: 4, color: 'var(--ink-2)', cursor: 'pointer', display: 'flex',
        }}><I.ChevronLeft size={20} /></button>
        <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>Kenalan dulu</div>
      </div>

      <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: '12px 22px 22px' }}>
        <h2 style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-0.01em', margin: '8px 0 4px' }}>
          Sedikit tentang kamu
        </h2>
        <p style={{ fontSize: 13, color: 'var(--ink-3)', margin: '0 0 18px', lineHeight: 1.5 }}>
          Info ini cuma dipakai untuk analisis agregat — kami tidak akan share data pribadimu.
        </p>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {fields.map((f) => {
            const meta = PROFILE_LABELS_MR[f.key];
            if (!meta) return null;
            const val = profile[f.key] ?? '';
            return (
              <div key={f.key}>
                <label className="label" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                  <span>{meta.label}</span>
                  {!f.required && <span style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 400 }}>opsional</span>}
                </label>
                {meta.options ? (
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {meta.options.map((opt) => (
                      <button
                        key={opt}
                        type="button"
                        onClick={() => set(f.key, val === opt ? '' : opt)}
                        style={{
                          padding: '8px 12px', borderRadius: 8,
                          border: '1px solid ' + (val === opt ? 'var(--primary)' : 'var(--line-2)'),
                          background: val === opt ? 'var(--primary-50)' : 'var(--surface)',
                          color: val === opt ? 'var(--primary)' : 'var(--ink-2)',
                          fontSize: 13, fontWeight: val === opt ? 600 : 500,
                          cursor: 'pointer', textTransform: 'capitalize',
                        }}
                      >
                        {opt}
                      </button>
                    ))}
                  </div>
                ) : (
                  <input
                    className="input"
                    type={meta.input ?? 'text'}
                    value={val}
                    onChange={(e) => set(f.key, e.target.value)}
                    placeholder={meta.placeholder}
                  />
                )}
              </div>
            );
          })}
        </div>
      </div>

      <div style={{ padding: '14px 22px 22px', borderTop: '1px solid var(--line)', background: 'var(--surface)' }}>
        <button
          onClick={onContinue}
          disabled={missingRequired}
          className="btn btn-primary"
          style={{ width: '100%', padding: 14, fontSize: 14.5, justifyContent: 'center', opacity: missingRequired ? 0.5 : 1 }}
        >
          Lanjut ke Survei <I.ArrowRight size={15} />
        </button>
        {missingRequired && (
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 8, textAlign: 'center' }}>
            Isi field wajib (tanpa label "opsional") untuk lanjut.
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Survey ───────────────────────────────────────────────────────────
function ResSurvey({ cur, step, total, answers, answer, location, setLocation, detecting, detectGPS, next, back, answered, submitting }) {
  const progress = ((step + 1) / total) * 100;

  return (
    <div className="fade-in" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
      {/* Header */}
      <div style={{ padding: '14px 20px 12px', borderBottom: '1px solid var(--line)' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
          <button onClick={back} disabled={step === 0} style={{
            background: 'none', border: 'none', padding: 4, color: step === 0 ? 'var(--ink-4)' : 'var(--ink-2)',
            cursor: step === 0 ? 'default' : 'pointer', display: 'flex',
          }}><I.ChevronLeft size={20} /></button>
          <div className="mono" style={{ fontSize: 12, color: 'var(--ink-3)', fontWeight: 600 }}>
            {step + 1} <span style={{ color: 'var(--ink-4)' }}>/ {total}</span>
          </div>
          <div style={{ width: 28 }}></div>
        </div>
        <div className="progress"><span style={{ width: progress + '%' }}></span></div>
      </div>

      <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: '24px 20px' }}>
        <div key={step} className="fade-in">
          <h2 style={{ fontSize: 19, fontWeight: 600, lineHeight: 1.35, letterSpacing: '-0.005em', margin: '0 0 18px' }}>
            {cur.text}
          </h2>

          {cur.type === 'open' && (
            <textarea className="textarea" rows="4" placeholder={cur.placeholder}
              value={answers[cur.id] || ''}
              onChange={(e) => answer(cur.id, e.target.value)}
              style={{ fontSize: 14.5 }}
            />
          )}

          {cur.type === 'choice' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {cur.options.map((o) => {
                const sel = answers[cur.id] === o;
                return (
                  <button key={o} onClick={() => answer(cur.id, o)} style={{
                    padding: '14px 14px', textAlign: 'left',
                    background: sel ? 'var(--primary-50)' : 'var(--surface)',
                    border: sel ? '1.5px solid var(--primary)' : '1px solid var(--line-2)',
                    borderRadius: 12, fontSize: 14.5, color: 'var(--ink)',
                    display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer',
                    fontWeight: sel ? 600 : 500,
                  }}>
                    <div style={{
                      width: 20, height: 20, borderRadius: '50%',
                      border: sel ? 'none' : '1.5px solid var(--line-2)',
                      background: sel ? 'var(--primary)' : 'transparent',
                      display: 'grid', placeItems: 'center', flexShrink: 0,
                    }}>
                      {sel && <I.Check size={12} style={{ color: 'white' }} strokeWidth={3} />}
                    </div>
                    <span style={{ flex: 1 }}>{o}</span>
                  </button>
                );
              })}
            </div>
          )}

          {cur.type === 'scale' && (
            <div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(11, 1fr)', gap: 4 }}>
                {Array.from({ length: 11 }).map((_, i) => {
                  const sel = answers[cur.id] === i;
                  return (
                    <button key={i} onClick={() => answer(cur.id, i)} style={{
                      aspectRatio: '1', padding: 0,
                      background: sel ? 'var(--primary)' : 'var(--surface)',
                      border: sel ? 'none' : '1px solid var(--line-2)',
                      color: sel ? 'white' : 'var(--ink-2)',
                      borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: 'pointer',
                      fontFamily: 'var(--font-mono)',
                    }}>{i}</button>
                  );
                })}
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11.5, color: 'var(--ink-3)', marginTop: 8 }}>
                <span>Tidak mungkin</span><span>Sangat mungkin</span>
              </div>
            </div>
          )}

          {cur.type === 'location' && (
            <div>
              <button onClick={detectGPS} disabled={detecting || !!location} style={{
                width: '100%', padding: '16px',
                background: location ? 'var(--success-soft)' : 'var(--primary-50)',
                border: `1.5px solid ${location ? 'oklch(0.78 0.12 155)' : 'var(--primary)'}`,
                borderRadius: 12, cursor: detecting ? 'wait' : 'pointer',
                display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14,
              }}>
                <div style={{
                  width: 38, height: 38, borderRadius: 10,
                  background: location ? 'oklch(0.62 0.16 155)' : 'var(--primary)', color: 'white',
                  display: 'grid', placeItems: 'center', flexShrink: 0,
                  animation: detecting ? 'pulse 1s ease-in-out infinite' : 'none',
                }}>
                  {location ? <I.Check size={18} /> : <I.Crosshair size={18} />}
                </div>
                <div style={{ textAlign: 'left', flex: 1 }}>
                  <div style={{ fontSize: 14, fontWeight: 600, color: location ? 'oklch(0.42 0.12 155)' : 'var(--primary)' }}>
                    {detecting ? 'Mendeteksi…' : location ? 'Lokasi terdeteksi' : 'Deteksi Lokasi Saya'}
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--ink-2)', marginTop: 2 }}>
                    {location ? location.region : 'Lebih cepat & akurat lewat GPS'}
                  </div>
                </div>
              </button>

              <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '14px 0', color: 'var(--ink-3)', fontSize: 12 }}>
                <div style={{ flex: 1, height: 1, background: 'var(--line)' }}></div>
                <span>atau pilih manual</span>
                <div style={{ flex: 1, height: 1, background: 'var(--line)' }}></div>
              </div>

              <select className="select" value={location?.region || ''}
                onChange={(e) => setLocation({ region: e.target.value })}
                style={{ fontSize: 14 }}>
                <option value="">Pilih kecamatan…</option>
                {['Gubeng, Surabaya', 'Sukolilo, Surabaya', 'Tegalsari, Surabaya', 'Wonokromo, Surabaya', 'Rungkut, Surabaya', 'Mulyorejo, Surabaya', 'Sawahan, Surabaya', 'Tandes, Surabaya'].map((r) => (
                  <option key={r}>{r}</option>
                ))}
              </select>
            </div>
          )}
        </div>
      </div>

      {/* Footer */}
      <div style={{ padding: '14px 20px 24px', borderTop: '1px solid var(--line)', background: 'var(--surface)' }}>
        <button onClick={next} disabled={!answered || submitting} style={{
          width: '100%', padding: 14,
          background: answered && !submitting ? 'var(--primary)' : 'var(--bg-2)',
          color: answered && !submitting ? 'white' : 'var(--ink-4)',
          border: 'none', borderRadius: 14,
          fontSize: 15, fontWeight: 600,
          cursor: answered && !submitting ? 'pointer' : 'not-allowed',
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        }}>
          {submitting ? 'Mengirim…' : (step === total - 1 ? 'Submit & Klaim Hadiah' : 'Lanjut')}
          {!submitting && <I.ArrowRight size={16} />}
        </button>
      </div>
    </div>
  );
}

// ─── Reward ───────────────────────────────────────────────────────────
function ResReward({ onRestart, reward }) {
  const [revealed, setRevealed] = useState_mr(false);
  const code = reward?.code || 'KK-9X4M-PR2N';
  const label = reward?.valueOrLink || 'Voucher Rp 10.000';
  const numericValue = label.match(/Rp\s*([\d.,]+)/i)?.[1] || '10.000';
  React.useEffect(() => {
    const t = setTimeout(() => setRevealed(true), 600);
    return () => clearTimeout(t);
  }, []);
  return (
    <div className="fade-in" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
      <div style={{
        background: 'linear-gradient(160deg, var(--primary) 0%, oklch(0.42 0.20 290) 100%)',
        color: 'white', padding: '36px 24px 56px', textAlign: 'center', position: 'relative', overflow: 'hidden',
      }}>
        {/* confetti dots */}
        {Array.from({ length: 12 }).map((_, i) => (
          <span key={i} style={{
            position: 'absolute',
            left: `${(i * 37) % 100}%`,
            top: `${(i * 53) % 80}%`,
            width: 6, height: 6, borderRadius: '50%',
            background: ['#fff', 'oklch(0.85 0.15 75)', 'oklch(0.78 0.18 25)'][i % 3],
            opacity: 0.7,
          }}></span>
        ))}
        <div style={{
          width: 72, height: 72, borderRadius: 22,
          background: 'rgba(255,255,255,0.2)', backdropFilter: 'blur(10px)',
          border: '1px solid rgba(255,255,255,0.4)',
          display: 'grid', placeItems: 'center',
          margin: '0 auto 16px', fontSize: 36,
        }}>🎉</div>
        <div style={{ fontSize: 12, opacity: 0.85, textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>
          Terima kasih!
        </div>
        <h2 style={{ fontSize: 22, fontWeight: 700, lineHeight: 1.25, margin: '6px 0 0' }}>
          Hadiahmu sudah siap diklaim
        </h2>
      </div>

      <div style={{ padding: '24px 20px', flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{
          background: 'var(--surface)', border: '1.5px dashed var(--primary)',
          borderRadius: 16, padding: 20, position: 'relative', marginTop: -32,
          boxShadow: 'var(--shadow-md)',
        }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>
            Voucher digital
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 6 }}>
            <span style={{ fontSize: 14, fontWeight: 600 }}>Rp</span>
            <span className="mono" style={{ fontSize: 36, fontWeight: 700, letterSpacing: '-0.02em', color: 'var(--primary)' }}>{numericValue}</span>
          </div>
          <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>
            {label} · berlaku 30 hari setelah klaim
          </div>

          <div style={{
            marginTop: 14, padding: 12, background: 'var(--bg-2)',
            borderRadius: 10, display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>Kode voucher</div>
              <div className="mono" style={{
                fontSize: 16, fontWeight: 700, letterSpacing: '0.08em',
                color: revealed ? 'var(--ink)' : 'transparent',
                background: revealed ? 'transparent' : 'oklch(0.88 0.01 265)',
                borderRadius: 4, transition: 'all 280ms', display: 'inline-block', minWidth: 130,
              }}>
                {revealed ? code : '••••-••••-••••'}
              </div>
            </div>
            <button className="btn btn-soft" style={{ padding: '6px 10px', fontSize: 12 }}>
              <I.Copy size={12} />Salin
            </button>
          </div>
        </div>

        <div style={{ marginTop: 18, padding: 14, background: 'var(--success-soft)', border: '1px solid oklch(0.84 0.08 155)', borderRadius: 12, fontSize: 13, color: 'oklch(0.32 0.10 155)', display: 'flex', gap: 10 }}>
          <I.Check size={16} style={{ flexShrink: 0, marginTop: 1 }} />
          <span>Voucher juga dikirim ke WhatsApp <b className="mono">+62 812-•••-••88</b> dalam 5 menit.</span>
        </div>

        <div style={{ marginTop: 'auto', paddingTop: 20, display: 'flex', flexDirection: 'column', gap: 8 }}>
          <button style={{
            width: '100%', padding: 14, background: 'var(--primary)', color: 'white',
            border: 'none', borderRadius: 14, fontSize: 14.5, fontWeight: 600, cursor: 'pointer',
          }}>Klaim ke WhatsApp</button>
          <button onClick={onRestart} style={{
            width: '100%', padding: 12, background: 'transparent', color: 'var(--ink-3)',
            border: 'none', fontSize: 13, fontWeight: 500, cursor: 'pointer',
          }}>Coba ulang demo</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { MobileFlow });
