/* eslint-disable react/no-unescaped-entities */
/* ============================================================
   Consumer Journey — Declared-data flow for CGO/CMO view
   9 screens × 3 variants. Real form entry + 3 declared-insight
   questions. Right panel shows marketing-grade signal at every step:
   ZIP enrichment, identity graph, declared psychographics,
   predicted LTV, CAC savings, retention forecast.
   ============================================================ */

const CJ_VARIANTS = {
  one: {
    id: "one",
    label: "UBER ONE",
    tint: "#d4b370",
    tintSoft: "rgba(212,179,112,0.18)",
    headline: "Free month of Uber One.",
    sub: "30 days. No charge. Member perks across rides and Eats.",
    rewardLabel: "30-DAY FREE TRIAL",
    rewardWord: "Uber One",
    rewardCurrency: "",
    rewardAmount: "",
    ctaClaim: "Start Free Trial",
    confirmedH: "You're in.",
    confirmedSub: "Uber One Free Trial activated. 30 days on us — cancel anytime.",
    perks: ["Free delivery on Eats", "$0 cancellation on rides", "10% back on select rides"],
    funnel: "Uber One trial-start",
    funnelTag: "UBER_ONE_TRIAL",
    primaryKpi: "Trial-to-paid conversion",
    lift: "+18% vs paid-digital control",
    ltv: 187,
    cacSave: 14.2,
    retention: { d30: 62, d60: 48, d90: 38 },
    crossFunnel: 0.41,
  },
  cash: {
    id: "cash",
    label: "UBER CASH",
    tint: "#5fb3ff",
    tintSoft: "rgba(95,179,255,0.16)",
    headline: "$15 in Uber Cash.",
    sub: "Use it on rides, Eats, or anything Uber. Yours instantly.",
    rewardLabel: "ADDED TO YOUR ACCOUNT",
    rewardWord: "",
    rewardCurrency: "$",
    rewardAmount: "15",
    ctaClaim: "Add to Wallet",
    confirmedH: "$15 added.",
    confirmedSub: "It's in your Uber Cash wallet — use it on your next ride or order.",
    perks: ["Works on rides", "Works on Eats", "No expiration"],
    funnel: "Cross-funnel acquisition",
    funnelTag: "CROSS_FUNNEL",
    primaryKpi: "First-trip + Eats attach",
    lift: "+24% vs paid-digital control",
    ltv: 142,
    cacSave: 11.6,
    retention: { d30: 71, d60: 54, d90: 42 },
    crossFunnel: 0.58,
  },
  eats: {
    id: "eats",
    label: "UBER EATS",
    tint: "#06c167",
    tintSoft: "rgba(6,193,103,0.16)",
    headline: "$15 off your next Eats order.",
    sub: "On the way home, get the food you didn't eat at the venue.",
    rewardLabel: "PROMO APPLIED",
    rewardWord: "",
    rewardCurrency: "$",
    rewardAmount: "15",
    ctaClaim: "Order Food",
    confirmedH: "Promo applied.",
    confirmedSub: "Auto-applied to your next Eats order over $25. Valid for 14 days.",
    perks: ["No min. order code", "Valid 14 days", "Stacks with member offers"],
    funnel: "Eats first-order acquisition",
    funnelTag: "EATS_FIRST_ORDER",
    primaryKpi: "Eats first-order conversion",
    lift: "+32% vs paid-digital control",
    ltv: 164,
    cacSave: 16.8,
    retention: { d30: 58, d60: 41, d90: 33 },
    crossFunnel: 0.36,
  },
};

const CJ_STEP_LABELS = [
  "WELCOME",
  "CONSENT",
  "IDENTITY",
  "VERIFY",
  "DECLARED",
  "ACCOUNT",
  "REWARD",
  "SWEEPSTAKES",
  "ATTRIBUTED",
];

// declared-data choices (rich psychographics — CMO gold)
const Q_REASON = [
  { id: "headliner", label: "The headliner",      tax: "music · headliner-driven" },
  { id: "vibes",     label: "The vibes",          tax: "social · scene-driven" },
  { id: "friend",    label: "Came with a friend", tax: "social · referred audience" },
  { id: "trying",    label: "Trying something new", tax: "discovery · explorer cohort" },
];
const Q_GROUP = [
  { id: "solo",   label: "Just me",       size: 1, tax: "solo rider" },
  { id: "pair",   label: "One other",     size: 2, tax: "couple / pair" },
  { id: "small",  label: "Group of 3–4",  size: 4, tax: "small group · UberX/UberXL" },
  { id: "large",  label: "5 or more",     size: 6, tax: "large group · UberXL/SUV" },
];
const Q_FREQ = [
  { id: "rare",     label: "1–2 times a year", cohort: "low-frequency", retention: 28 },
  { id: "regular",  label: "A few times a year", cohort: "regular-attender", retention: 44 },
  { id: "monthly",  label: "Monthly or more",  cohort: "high-frequency", retention: 62 },
  { id: "weekly",   label: "Weekly+",          cohort: "super-fan", retention: 78 },
];

// ZIP-based geo-enrichment lookup (illustrative — top markets)
function enrichZip(zip) {
  const z = (zip || "").trim();
  if (z.length < 5) return null;
  const prefix = z.slice(0, 3);
  const map = {
    "100": { metro: "NYC · Manhattan",    tier: "TIER 1", hhi: 122 },
    "101": { metro: "NYC · Manhattan",    tier: "TIER 1", hhi: 134 },
    "112": { metro: "NYC · Brooklyn",     tier: "TIER 1", hhi:  98 },
    "900": { metro: "LA · West",          tier: "TIER 1", hhi: 118 },
    "902": { metro: "LA · Beverly Hills", tier: "TIER 1", hhi: 148 },
    "941": { metro: "SF · San Francisco", tier: "TIER 1", hhi: 156 },
    "945": { metro: "SF · Oakland",       tier: "TIER 1", hhi:  92 },
    "946": { metro: "SF · Berkeley",      tier: "TIER 1", hhi: 104 },
    "021": { metro: "Boston · Cambridge", tier: "TIER 1", hhi: 116 },
    "606": { metro: "Chicago · North",    tier: "TIER 1", hhi: 102 },
    "200": { metro: "DC · NW",            tier: "TIER 1", hhi: 124 },
    "303": { metro: "Atlanta · ITP",      tier: "TIER 1", hhi:  96 },
    "750": { metro: "Dallas · Uptown",    tier: "TIER 1", hhi:  88 },
    "770": { metro: "Houston · Inner Loop", tier: "TIER 1", hhi:  84 },
    "850": { metro: "Phoenix · Central",  tier: "TIER 2", hhi:  78 },
    "981": { metro: "Seattle · Capitol Hill", tier: "TIER 1", hhi: 112 },
    "972": { metro: "Portland · NE",      tier: "TIER 1", hhi:  92 },
    "331": { metro: "Miami · Beach",      tier: "TIER 1", hhi: 102 },
  };
  if (map[prefix]) return map[prefix];
  // Fallback: synth from first digit
  const first = parseInt(z[0], 10);
  if (Number.isNaN(first)) return null;
  const fallbacks = [
    { metro: "Northeast metro", tier: "TIER 2", hhi: 78 },
    { metro: "Northeast metro", tier: "TIER 2", hhi: 82 },
    { metro: "Mid-Atlantic",    tier: "TIER 2", hhi: 76 },
    { metro: "Southeast metro", tier: "TIER 2", hhi: 72 },
    { metro: "Midwest metro",   tier: "TIER 2", hhi: 70 },
    { metro: "Midwest metro",   tier: "TIER 3", hhi: 64 },
    { metro: "South-central",   tier: "TIER 2", hhi: 68 },
    { metro: "Mountain West",   tier: "TIER 2", hhi: 74 },
    { metro: "West coast metro",tier: "TIER 1", hhi: 88 },
    { metro: "Pacific Northwest", tier: "TIER 1", hhi: 86 },
  ];
  return fallbacks[first] || { metro: "US metro", tier: "TIER 2", hhi: 72 };
}

// Build the marketing-insights overlay rows + an insight callout per step
function buildOverlay(state, v) {
  const geo = enrichZip(state.zip);
  const declared = (state.qReason && state.qGroup && state.qFreq);
  const reason = Q_REASON.find(q => q.id === state.qReason);
  const group  = Q_GROUP.find(q => q.id === state.qGroup);
  const freq   = Q_FREQ.find(q => q.id === state.qFreq);

  // LTV uplift from declared data (illustrative)
  const ltvBoost =
    (freq ? (freq.cohort === "super-fan" ? 1.42 : freq.cohort === "high-frequency" ? 1.22 : freq.cohort === "regular-attender" ? 1.06 : 0.88) : 1) *
    (group && group.size >= 4 ? 1.12 : 1) *
    (geo && geo.tier === "TIER 1" ? 1.18 : 1);
  const projectedLtv = Math.round(v.ltv * ltvBoost);
  const cacSave = (v.cacSave * (geo && geo.tier === "TIER 1" ? 1.15 : 1)).toFixed(2);
  const newRider = state.userKind === "new";

  // ROWS PER STEP and INSIGHT CALLOUT
  const rows = [
    // 0 — WELCOME
    {
      rows: [
        ["venue.tier",     "Anchor circuit · NCA-AMP-001"],
        ["scan.event",     "qr.scan · t=21:48 PT"],
        ["variant.arm",    v.id.toUpperCase() + " · " + v.funnelTag],
        ["audience.size",  "~8,400 above usable concourse"],
      ],
      insight: {
        k: "MARKETING CONTEXT",
        v: "Inaugural rideshare moment. Variant " + v.label + " serves to a captive, high-intent crowd in the post-event mobility window.",
      },
    },
    // 1 — CONSENT
    {
      rows: [
        ["consent.21plus",  state.age21 ? "✓ confirmed" : "pending"],
        ["consent.ccpa",    state.ccpa ? "✓ explicit · granular" : "pending"],
        ["marketable",      state.age21 && state.ccpa ? "✓ true · permissioned" : "false"],
        ["audience.bucket", state.age21 && state.ccpa ? "CCPA-consented · marketable" : "—"],
      ],
      insight: {
        k: "MARKETING INSIGHT",
        v: state.age21 && state.ccpa
          ? "Marketable audience record created. Every signal from here forward is fully consented and re-usable across Uber's CRM."
          : "Consent gate is the cleanliness guarantee — no PII collected without explicit opt-in.",
      },
    },
    // 2 — IDENTITY (name + email + zip)
    {
      rows: [
        ["identity.name",   state.firstName ? state.firstName + " " + (state.lastName || "") : "—"],
        ["identity.email",  state.email || "—"],
        ["email.domain",    state.email && state.email.includes("@") ? state.email.split("@")[1] : "—"],
        ["geo.zip",         state.zip || "—"],
        ["geo.market",      geo ? geo.metro + " · " + geo.tier : "—"],
        ["geo.est_hhi",     geo ? "$" + geo.hhi + "K (median)" : "—"],
      ],
      insight: {
        k: "FIRST-PARTY ENRICHMENT",
        v: geo
          ? "ZIP → " + geo.metro + " · " + geo.tier + ". Census-tract median HHI $" + geo.hhi + "K. Hashed email queued for Uber CRM match."
          : "Email + ZIP unlocks geo-enrichment + CRM identity match. Required for cohort modeling.",
      },
    },
    // 3 — VERIFY
    {
      rows: [
        ["identity.phone",  state.phone ? "•••• " + state.phone.replace(/\D/g,"").slice(-4) : "—"],
        ["otp.verified",    state.otpCode.length === 4 ? "✓ verified" : "pending"],
        ["sms.optin",       "✓ marketing opt-in"],
        ["identity.graph",  state.phone && state.email ? "phone + email · HIGH match" : "partial"],
        ["dedupe.key",      state.email || "—"],
      ],
      insight: {
        k: "IDENTITY GRAPH",
        v: "Phone + email cross-match = HIGH-confidence identity. Cross-device & cross-funnel attribution unlocked. SMS opt-in extends retargeting surface.",
      },
    },
    // 4 — DECLARED
    {
      rows: [
        ["declared.reason", reason ? reason.tax : "—"],
        ["declared.party",  group ? "size=" + group.size + " · " + group.tax : "—"],
        ["declared.freq",   freq ? freq.cohort + " · base ret=" + freq.retention + "%" : "—"],
        ["audience.profile", declared
            ? "Declared · " + (reason && reason.id === "headliner" ? "music-driven" : reason && reason.id === "vibes" ? "scene-driven" : reason && reason.id === "friend" ? "social-referral" : "explorer") + " · " + (freq ? freq.cohort : "—")
            : "—"],
        ["lookalike.seed", declared ? "✓ eligible · post-claim" : "pending"],
      ],
      insight: {
        k: "DECLARED PSYCHOGRAPHICS",
        v: declared
          ? "Real, opted-in psychographic signal — not inferred. Feeds audience taxonomy + lookalike seed. Group size " + group.size + " maps directly to UberX/XL/SUV product mix."
          : "Three taps. Three signals Uber's growth team can't buy anywhere else: why they came, who's with them, how often they go.",
      },
    },
    // 5 — ACCOUNT
    {
      rows: [
        ["user.state",        state.userKind === "new" ? "non_rider · device_first_seen" : state.userKind === "existing" ? "existing_rider · re-engaged" : "—"],
        ["acquisition.path",  "ape_uber_pilot/v=" + v.id],
        ["projected.ltv_90d", "$" + projectedLtv + " (declared-adjusted)"],
        ["cac.savings",       "$" + cacSave + " vs paid-digital benchmark"],
        ["funnel.target",     v.primaryKpi],
      ],
      insight: {
        k: "ECONOMIC ATTRIBUTION",
        v: (newRider
          ? "Net-new acquisition. "
          : "Re-engagement. ") +
          "Projected 90-day LTV $" + projectedLtv + " — uplifted by declared frequency + Tier-" + (geo && geo.tier === "TIER 1" ? "1" : "2") + " geo. CAC saving $" + cacSave + " per acquired user vs paid-digital baseline.",
      },
    },
    // 6 — REWARD
    {
      rows: [
        ["incentive.served", "v=" + v.id + " · " + (v.id === "one" ? "30d trial" : v.id === "cash" ? "$15 cash" : "$15 Eats credit")],
        ["funnel.entered",   v.funnel],
        ["model.lift",       v.lift],
        ["cohort.tag",       "ape_uber_pilot · " + v.id + " · " + (freq ? freq.cohort : "—")],
        ["conversion.event", "claim_started"],
      ],
      insight: {
        k: "FUNNEL ENTRY",
        v: v.label + " is the headline " + (v.id === "one" ? "subscription" : v.id === "cash" ? "wallet" : "Eats") + " incentive. Modeled lift " + v.lift + ". Cohort-tagged for variant A/B/C readout against control.",
      },
    },
    // 7 — SWEEPSTAKES
    {
      rows: [
        ["sweeps.entry",    state.entryId || "—"],
        ["sweeps.prize",    "$5,000 Uber credit"],
        ["sweeps.drawing",  "post-season · 90d window"],
        ["email.window",    "✓ 90-day marketing window opened"],
        ["secondary.event", "newsletter_optin · soft_optin"],
      ],
      insight: {
        k: "EMAIL CAPTURE",
        v: "Sweepstakes opt-in extends the marketing window 90 days. Email enters Uber's lifecycle pipeline. One entry per dedupe key.",
      },
    },
    // 8 — ATTRIBUTED (final)
    {
      rows: [
        ["conversion.event", "claim_completed"],
        ["funnel.cohort",    "ape_uber_pilot · " + v.id + " · " + (state.userKind === "new" ? "new" : "existing")],
        ["projected.ltv_90d", "$" + projectedLtv],
        ["retention.30d",    v.retention.d30 + "%"],
        ["retention.60d",    v.retention.d60 + "%"],
        ["retention.90d",    v.retention.d90 + "%"],
        ["crossfunnel.score", v.crossFunnel.toFixed(2) + " · " + v.funnelTag],
      ],
      insight: {
        k: "ATTRIBUTED ACQUISITION",
        v: (newRider ? "Net-new " : "Re-engaged ") + v.label + " acquisition. Predicted 30/60/90-day retention " + v.retention.d30 + "/" + v.retention.d60 + "/" + v.retention.d90 + "%. Cross-funnel propensity " + v.crossFunnel.toFixed(2) + ". Every signal first-party · Uber-owned.",
      },
    },
  ];
  return rows;
}

function genEntryId() {
  const ch = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
  let s = "";
  for (let i = 0; i < 6; i++) s += ch[Math.floor(Math.random() * ch.length)];
  return "UB-" + s;
}

function ConsumerJourney({ variantKey, onVariantChange }) {
  const [step, setStep] = useState(0);
  const [direction, setDirection] = useState(1);
  // form state
  const [age21, setAge21] = useState(false);
  const [ccpa, setCcpa] = useState(false);
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");
  const [zip, setZip] = useState("");
  const [phone, setPhone] = useState("");
  const [otpSent, setOtpSent] = useState(false);
  const [otpCode, setOtpCode] = useState("");
  const [qReason, setQReason] = useState(null);
  const [qGroup, setQGroup] = useState(null);
  const [qFreq, setQFreq] = useState(null);
  const [userKind, setUserKind] = useState(null);
  const [entryId, setEntryId] = useState("");

  const v = CJ_VARIANTS[variantKey];
  const total = 9;

  function go(n) {
    setDirection(n > step ? 1 : -1);
    setStep(n);
    if (n === 7 && !entryId) setEntryId(genEntryId());
  }
  function next() { if (step < total - 1) go(step + 1); }
  function back() { if (step > 0) go(step - 1); }
  function restart() {
    setDirection(-1); setStep(0);
    setAge21(false); setCcpa(false);
    setFirstName(""); setLastName(""); setEmail(""); setZip("");
    setPhone(""); setOtpSent(false); setOtpCode("");
    setQReason(null); setQGroup(null); setQFreq(null);
    setUserKind(null); setEntryId("");
  }
  function switchVariant(k) {
    onVariantChange(k);
    restart();
  }
  useEffect(() => { restart(); /* eslint-disable-next-line */ }, [variantKey]);

  // ---- validators ----
  const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  const nameOk = firstName.trim().length >= 1 && lastName.trim().length >= 1;
  const zipOk = /^\d{5}$/.test(zip);
  const phoneDigits = phone.replace(/\D/g, "");
  const phoneOk = phoneDigits.length === 10;
  const otpOk = otpCode.length === 4;
  const declaredOk = qReason && qGroup && qFreq;

  function canAdvance() {
    if (step === 1) return age21 && ccpa;
    if (step === 2) return nameOk && emailOk && zipOk;
    if (step === 3) return phoneOk && otpSent && otpOk;
    if (step === 4) return declaredOk;
    if (step === 5) return !!userKind;
    return true;
  }

  function fmtPhoneInput(raw) {
    const d = raw.replace(/\D/g, "").slice(0, 10);
    if (d.length === 0) return "";
    if (d.length < 4) return "(" + d;
    if (d.length < 7) return "(" + d.slice(0, 3) + ") " + d.slice(3);
    return "(" + d.slice(0, 3) + ") " + d.slice(3, 6) + "-" + d.slice(6);
  }

  function sendOtp() {
    setOtpSent(true);
    setTimeout(() => setOtpCode("4825"), 800);
  }

  const overlay = buildOverlay(
    { age21, ccpa, firstName, lastName, email, zip, phone, otpCode, qReason, qGroup, qFreq, userKind, entryId },
    v
  );
  const stepData = overlay[step];

  const times = ["21:48", "21:48", "21:49", "21:49", "21:50", "21:50", "21:51", "21:51", "21:52"];
  const geo = enrichZip(zip);

  return (
    <div className="cj-stage">
      <style>{`
        .cj-stage {
          display: grid;
          grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.05fr);
          gap: clamp(20px, 3vw, 48px);
          align-items: start;
        }
        @media (max-width: 1200px) {
          .cj-stage { grid-template-columns: 1fr; gap: 36px; }
          .cj-stage > * { justify-self: center; }
        }

        /* --- LEFT --- */
        .cj-left { display: flex; flex-direction: column; gap: 22px; min-width: 0; max-width: 360px; }
        .cj-pills { display: flex; gap: 8px; flex-wrap: wrap; }
        .cj-pill {
          padding: 9px 16px;
          border-radius: 999px;
          border: 1px solid var(--line);
          background: transparent;
          color: var(--t-3);
          font-family: var(--f-mono);
          font-size: 11px;
          letter-spacing: 0.14em;
          cursor: pointer;
          transition: all 160ms ease;
          white-space: nowrap;
          display: inline-flex; align-items: center; gap: 7px;
        }
        .cj-pill::before {
          content: "";
          width: 6px; height: 6px; border-radius: 50%;
          background: var(--pill-tint, transparent);
          opacity: 0.9;
        }
        .cj-pill.active { background: var(--paper); color: var(--ink); border-color: var(--paper); }
        .cj-pill.active::before { background: var(--pill-tint); opacity: 1; }
        .cj-pill:hover:not(.active) { color: var(--t-1); border-color: var(--line-strong); }

        .cj-can-block {
          position: relative;
          width: clamp(170px, 18vw, 220px);
          aspect-ratio: 1024/1536;
          margin: 8px 0 0;
          filter: drop-shadow(0 50px 60px rgba(0,0,0,0.6));
        }
        .cj-can-block img { width: 100%; height: 100%; object-fit: contain; }
        .cj-can-block::after {
          content: "";
          position: absolute;
          inset: -10% -25%;
          background: radial-gradient(ellipse at center, var(--tint, transparent), transparent 55%);
          opacity: 0.18;
          filter: blur(40px);
          z-index: -1;
          transition: background 360ms ease;
        }
        .cj-explain {
          color: var(--t-3);
          font-size: 13px;
          line-height: 1.55;
        }
        .cj-explain b { color: var(--t-1); font-weight: 600; }

        .cj-stepnav { margin-top: 6px; display: grid; gap: 2px; }
        .cj-stepnav-item {
          display: grid;
          grid-template-columns: 22px 1fr;
          align-items: center;
          gap: 10px;
          padding: 6px 8px;
          border-radius: 6px;
          cursor: pointer;
          transition: background 140ms ease;
        }
        .cj-stepnav-item:hover { background: rgba(255,255,255,0.04); }
        .cj-stepnav-num { font-family: var(--f-mono); font-size: 10px; color: var(--t-4); letter-spacing: 0.06em; }
        .cj-stepnav-label { font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.14em; color: var(--t-4); }
        .cj-stepnav-item.done .cj-stepnav-num,
        .cj-stepnav-item.done .cj-stepnav-label { color: var(--t-2); }
        .cj-stepnav-item.active .cj-stepnav-num,
        .cj-stepnav-item.active .cj-stepnav-label { color: var(--t-1); font-weight: 600; }
        .cj-stepnav-item.active { background: rgba(255,255,255,0.04); }
        .cj-stepnav-item.active .cj-stepnav-num::before { content: "▸ "; color: var(--tint); }

        /* --- PHONE --- */
        .cj-phone-wrap { display: flex; flex-direction: column; align-items: center; gap: 18px; }
        .cj-phone {
          width: 320px;
          height: 640px;
          border-radius: 46px;
          background: #0a0a0a;
          border: 9px solid #1a1a1a;
          position: relative;
          overflow: hidden;
          box-shadow: 0 30px 80px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06) inset;
        }
        .cj-phone::before {
          content: "";
          position: absolute; inset: 0;
          background: radial-gradient(circle at 50% -10%, var(--tint-soft, transparent), transparent 55%);
          opacity: 0.55;
          pointer-events: none;
          z-index: 0;
          transition: background 360ms ease;
        }
        .cj-phone-notch {
          position: absolute;
          top: 12px; left: 50%;
          transform: translateX(-50%);
          width: 110px; height: 26px;
          background: #000;
          border-radius: 999px;
          z-index: 5;
        }
        .cj-status-bar {
          position: absolute;
          top: 14px; left: 0; right: 0;
          height: 28px;
          display: flex; justify-content: space-between;
          padding: 6px 28px 0;
          font-family: var(--f-display);
          font-weight: 600;
          font-size: 13px;
          color: #fff;
          z-index: 4;
          letter-spacing: -0.01em;
        }
        .cj-status-right { display: inline-flex; gap: 5px; align-items: center; }

        .cj-screen-wrap {
          position: absolute;
          inset: 50px 0 0;
          overflow: hidden;
          z-index: 2;
        }
        .cj-screen {
          position: absolute;
          inset: 0;
          padding: 16px 22px 22px;
          display: flex;
          flex-direction: column;
          color: #fff;
          transition: opacity 380ms ease, transform 380ms cubic-bezier(.2,.7,.2,1);
          background: linear-gradient(180deg, rgba(255,255,255,0.02) 0%, transparent 80%);
          overflow-y: auto;
          overflow-x: hidden;
          -webkit-overflow-scrolling: touch;
        }
        .cj-screen::-webkit-scrollbar { width: 0; }
        .cj-screen.active { transform: translateX(0); opacity: 1; }
        .cj-screen.exit-right { transform: translateX(100%); opacity: 0; }
        .cj-screen.exit-left { transform: translateX(-100%); opacity: 0; }

        .cj-progress { display: flex; gap: 3px; margin-bottom: 14px; }
        .cj-progress span {
          height: 3px; flex: 1; border-radius: 999px;
          background: rgba(255,255,255,0.14);
          transition: background 200ms ease;
        }
        .cj-progress span.done { background: rgba(255,255,255,0.5); }
        .cj-progress span.active { background: var(--tint); }

        .cj-uber { font-family: var(--f-display); font-weight: 700; font-size: 22px; letter-spacing: -0.045em; color: #fff; line-height: 1; }
        .cj-screen-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
        .cj-screen-head-r { font-family: var(--f-mono); font-size: 9px; letter-spacing: 0.16em; color: rgba(255,255,255,0.45); }

        .cj-vchip {
          display: inline-flex; align-items: center; gap: 6px;
          padding: 5px 10px;
          border-radius: 999px;
          background: var(--tint);
          color: #000;
          font-family: var(--f-mono);
          font-size: 10px;
          letter-spacing: 0.14em;
          font-weight: 600;
          align-self: flex-start;
          margin-bottom: 12px;
        }
        .cj-vchip::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: #000; }

        .cj-h {
          font-family: var(--f-display);
          font-weight: 700;
          font-size: 24px;
          letter-spacing: -0.022em;
          line-height: 1.05;
          margin: 0 0 10px;
          text-wrap: balance;
        }
        .cj-sub { font-size: 13px; color: rgba(255,255,255,0.74); line-height: 1.5; margin-bottom: 16px; }
        .cj-body { font-size: 13px; color: rgba(255,255,255,0.7); line-height: 1.5; }

        .cj-btn {
          width: 100%;
          height: 50px;
          background: #fff;
          color: #000;
          border-radius: 12px;
          border: none;
          font-family: var(--f-display);
          font-weight: 600;
          font-size: 15px;
          letter-spacing: -0.005em;
          display: flex; align-items: center; justify-content: center;
          gap: 10px;
          transition: transform 120ms ease, opacity 120ms ease, background 120ms ease;
        }
        .cj-btn:active { transform: scale(0.985); }
        .cj-btn:disabled { opacity: 0.36; background: rgba(255,255,255,0.5); cursor: not-allowed; }
        .cj-btn.tinted { background: var(--tint); color: #000; }
        .cj-btn.tinted:disabled { background: rgba(255,255,255,0.18); color: rgba(255,255,255,0.4); }
        .cj-btn.ghost { background: transparent; color: #fff; border: 1px solid rgba(255,255,255,0.22); }
        .cj-btn.ghost:hover { background: rgba(255,255,255,0.04); }
        .cj-cta-stack { margin-top: auto; display: grid; gap: 10px; padding-top: 12px; }

        .cj-toggle {
          display: flex; align-items: center; justify-content: space-between;
          padding: 12px 14px;
          border: 1px solid rgba(255,255,255,0.12);
          border-radius: 12px;
          margin-bottom: 8px;
          cursor: pointer;
          user-select: none;
          transition: border-color 160ms ease, background 160ms ease;
        }
        .cj-toggle:hover { background: rgba(255,255,255,0.03); }
        .cj-toggle.on { border-color: rgba(255,255,255,0.25); background: rgba(255,255,255,0.02); }
        .cj-toggle-l { font-size: 12.5px; color: rgba(255,255,255,0.9); line-height: 1.3; padding-right: 12px; }
        .cj-toggle-l b { display: block; color: #fff; font-weight: 600; font-size: 13.5px; margin-bottom: 2px; }
        .cj-switch {
          flex-shrink: 0;
          width: 42px; height: 24px;
          border-radius: 999px;
          background: rgba(255,255,255,0.15);
          position: relative;
          transition: background 200ms ease;
        }
        .cj-switch::after {
          content: "";
          position: absolute;
          top: 3px; left: 3px;
          width: 18px; height: 18px;
          background: #fff;
          border-radius: 50%;
          transition: transform 200ms ease;
        }
        .cj-toggle.on .cj-switch { background: var(--tint); }
        .cj-toggle.on .cj-switch::after { transform: translateX(18px); }

        .cj-field { margin-bottom: 10px; }
        .cj-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px; }
        .cj-label {
          display: block;
          font-family: var(--f-mono);
          font-size: 9px;
          letter-spacing: 0.16em;
          color: rgba(255,255,255,0.55);
          margin-bottom: 4px;
        }
        .cj-input {
          width: 100%;
          padding: 11px 12px;
          background: rgba(255,255,255,0.05);
          border: 1px solid rgba(255,255,255,0.12);
          color: #fff;
          border-radius: 10px;
          font-family: var(--f-body);
          font-size: 14px;
          transition: border-color 160ms ease, background 160ms ease;
        }
        .cj-input:focus { outline: none; border-color: var(--tint); background: rgba(255,255,255,0.07); }
        .cj-input.invalid { border-color: rgba(255,90,90,0.55); }
        .cj-input::placeholder { color: rgba(255,255,255,0.32); }
        .cj-field-hint {
          font-family: var(--f-mono);
          font-size: 9px;
          letter-spacing: 0.06em;
          color: rgba(255,255,255,0.4);
          margin-top: 3px;
        }
        .cj-field-hint.ok { color: var(--tint); }
        .cj-field-hint.err { color: rgb(255,120,120); }

        /* Geo readout chip — shows when zip enriches */
        .cj-geo-readout {
          padding: 8px 10px;
          background: rgba(255,255,255,0.03);
          border: 1px solid var(--tint);
          border-radius: 8px;
          margin-bottom: 10px;
          animation: cjFade 280ms ease;
        }
        .cj-geo-k { font-family: var(--f-mono); font-size: 8.5px; letter-spacing: 0.16em; color: rgba(255,255,255,0.55); margin-bottom: 3px; }
        .cj-geo-v { font-family: var(--f-mono); font-size: 11px; color: var(--tint); font-weight: 600; }

        .cj-otp-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 8px; }
        .cj-otp-cell {
          height: 50px;
          background: rgba(255,255,255,0.05);
          border: 1px solid rgba(255,255,255,0.12);
          border-radius: 10px;
          color: #fff;
          font-family: var(--f-display);
          font-size: 22px;
          font-weight: 600;
          text-align: center;
        }
        .cj-otp-cell.filled { border-color: var(--tint); background: rgba(255,255,255,0.07); }
        .cj-resend {
          background: transparent;
          border: none;
          color: var(--tint);
          font-family: var(--f-mono);
          font-size: 11px;
          letter-spacing: 0.08em;
          cursor: pointer;
          padding: 4px 0;
          text-decoration: underline;
          text-underline-offset: 3px;
        }
        .cj-otp-status {
          font-family: var(--f-mono);
          font-size: 10px;
          letter-spacing: 0.08em;
          color: rgba(255,255,255,0.5);
          padding: 4px 0;
        }
        .cj-otp-status.ok { color: var(--tint); }

        /* Declared question — compact tap-grid */
        .cj-q-block { margin-bottom: 10px; }
        .cj-q-label {
          display: block;
          font-family: var(--f-mono);
          font-size: 9px;
          letter-spacing: 0.16em;
          color: rgba(255,255,255,0.55);
          margin-bottom: 6px;
        }
        .cj-q-grid {
          display: grid;
          grid-template-columns: 1fr 1fr;
          gap: 6px;
        }
        .cj-q-opt {
          padding: 9px 10px;
          background: rgba(255,255,255,0.04);
          border: 1px solid rgba(255,255,255,0.12);
          border-radius: 9px;
          color: rgba(255,255,255,0.85);
          font-family: var(--f-body);
          font-size: 12px;
          line-height: 1.25;
          text-align: left;
          cursor: pointer;
          transition: all 140ms ease;
        }
        .cj-q-opt:hover { background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.22); }
        .cj-q-opt.on {
          border-color: var(--tint);
          background: rgba(255,255,255,0.06);
          color: #fff;
        }

        /* Choice cards (account) */
        .cj-choice { display: grid; gap: 10px; margin-bottom: 12px; }
        .cj-choice button {
          text-align: left;
          padding: 14px 14px;
          background: rgba(255,255,255,0.03);
          border: 1px solid rgba(255,255,255,0.12);
          color: #fff;
          border-radius: 12px;
          cursor: pointer;
          font-family: var(--f-body);
          font-size: 13.5px;
          line-height: 1.35;
          transition: all 160ms ease;
        }
        .cj-choice button:hover { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.25); }
        .cj-choice button.active { border-color: var(--tint); background: rgba(255,255,255,0.05); }
        .cj-choice button b { display: block; font-weight: 600; font-size: 14.5px; margin-bottom: 2px; }
        .cj-choice .muted { color: rgba(255,255,255,0.5); font-size: 12px; }

        /* Claim card */
        .cj-claim-card {
          padding: 22px 18px;
          background: var(--tint-soft);
          border: 1px solid var(--tint);
          border-radius: 14px;
          margin: 2px 0 14px;
        }
        .cj-claim-k { font-family: var(--f-mono); font-size: 9px; letter-spacing: 0.18em; color: rgba(255,255,255,0.7); margin-bottom: 10px; }
        .cj-claim-v { font-family: var(--f-display); font-weight: 700; letter-spacing: -0.04em; line-height: 0.95; color: #fff; display: flex; align-items: flex-start; gap: 4px; }
        .cj-claim-v .currency { font-size: 24px; margin-top: 6px; opacity: 0.85; }
        .cj-claim-v .amount   { font-size: 50px; }
        .cj-claim-v .word     { font-size: 36px; }
        .cj-claim-perks { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
        .cj-claim-perks li { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: rgba(255,255,255,0.85); }
        .cj-claim-perks li::before { content: "✓"; color: var(--tint); font-weight: 700; font-size: 12px; }

        .cj-sweeps-hero {
          padding: 18px 16px;
          background: rgba(255,255,255,0.04);
          border: 1px solid rgba(255,255,255,0.12);
          border-radius: 14px;
          margin-bottom: 12px;
          text-align: center;
        }
        .cj-sweeps-hero-k { font-family: var(--f-mono); font-size: 9px; letter-spacing: 0.18em; color: rgba(255,255,255,0.55); margin-bottom: 6px; }
        .cj-sweeps-hero-v { font-family: var(--f-display); font-weight: 700; font-size: 36px; letter-spacing: -0.035em; color: #fff; line-height: 1; margin-bottom: 4px; }
        .cj-sweeps-hero-v small { font-size: 18px; opacity: 0.7; font-weight: 600; }
        .cj-sweeps-hero-sub { font-family: var(--f-mono); font-size: 10px; letter-spacing: 0.1em; color: rgba(255,255,255,0.55); }
        .cj-entry-box {
          padding: 12px 14px;
          background: var(--tint-soft);
          border: 1px dashed var(--tint);
          border-radius: 12px;
          margin-bottom: 12px;
          display: grid;
          grid-template-columns: 1fr auto;
          gap: 10px;
          align-items: center;
        }
        .cj-entry-k { font-family: var(--f-mono); font-size: 9px; letter-spacing: 0.16em; color: rgba(255,255,255,0.65); margin-bottom: 3px; }
        .cj-entry-v { font-family: var(--f-mono); font-size: 17px; letter-spacing: 0.1em; color: #fff; font-weight: 600; }
        .cj-entry-badge { padding: 5px 10px; background: var(--tint); color: #000; border-radius: 999px; font-family: var(--f-mono); font-size: 9px; letter-spacing: 0.14em; font-weight: 700; }
        .cj-tc {
          font-family: var(--f-mono);
          font-size: 9.5px;
          letter-spacing: 0.04em;
          color: rgba(255,255,255,0.45);
          line-height: 1.55;
          padding: 12px 12px;
          background: rgba(255,255,255,0.02);
          border: 1px solid rgba(255,255,255,0.08);
          border-radius: 10px;
          margin-bottom: 12px;
        }
        .cj-tc b { color: rgba(255,255,255,0.7); display: block; margin-bottom: 4px; font-weight: 600; }

        .cj-check-wrap {
          width: 60px; height: 60px;
          border-radius: 50%;
          background: var(--tint);
          color: #000;
          display: flex; align-items: center; justify-content: center;
          margin: 4px 0 14px;
          animation: cjPop 380ms cubic-bezier(.2,1.5,.4,1);
        }
        @keyframes cjPop { 0% { transform: scale(0); } 70% { transform: scale(1.12); } 100% { transform: scale(1); } }

        .cj-recap {
          padding: 12px 14px;
          background: rgba(255,255,255,0.04);
          border: 1px solid rgba(255,255,255,0.10);
          border-radius: 12px;
          margin-bottom: 12px;
        }
        .cj-recap-row {
          display: flex; justify-content: space-between; align-items: center;
          padding: 6px 0;
          border-bottom: 1px dashed rgba(255,255,255,0.10);
          font-size: 12px;
        }
        .cj-recap-row:last-child { border-bottom: none; }
        .cj-recap-row .k { color: rgba(255,255,255,0.55); font-family: var(--f-mono); font-size: 10px; letter-spacing: 0.1em; }
        .cj-recap-row .v { color: #fff; font-weight: 500; }

        .cj-fine {
          font-family: var(--f-mono);
          font-size: 9px;
          letter-spacing: 0.06em;
          color: rgba(255,255,255,0.4);
          line-height: 1.5;
          margin-top: 12px;
        }

        /* Controls under phone */
        .cj-controls { display: flex; align-items: center; gap: 10px; font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.1em; color: var(--t-3); }
        .cj-control-btn {
          width: 34px; height: 34px;
          border: 1px solid var(--line-strong);
          border-radius: 999px;
          background: transparent;
          color: var(--t-2);
          display: inline-flex; align-items: center; justify-content: center;
          transition: all 160ms ease;
        }
        .cj-control-btn:hover:not(:disabled) { background: rgba(255,255,255,0.06); color: var(--t-1); }
        .cj-control-btn:disabled { opacity: 0.3; cursor: not-allowed; }
        .cj-control-btn.flip svg { transform: rotate(180deg); }
        .cj-restart { padding: 0 14px; height: 34px; border: 1px solid var(--line-strong); background: transparent; color: var(--t-2); border-radius: 999px; font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.12em; cursor: pointer; transition: all 160ms ease; }
        .cj-restart:hover { background: rgba(255,255,255,0.06); color: var(--t-1); }
        .cj-counter { font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.08em; color: var(--t-3); }

        /* --- RIGHT OVERLAY (marketing-insights panel) --- */
        .cj-overlay {
          width: 100%;
          max-width: 440px;
          padding: 22px 22px 18px;
          border: 1px solid var(--line);
          border-radius: 16px;
          background: #0a0a0c;
          position: relative;
          overflow: hidden;
          align-self: stretch;
        }
        .cj-overlay::before {
          content: "";
          position: absolute; inset: 0;
          background: radial-gradient(ellipse 70% 30% at 90% 0%, rgba(95,179,255,0.06), transparent 60%);
          pointer-events: none;
        }
        .cj-overlay > * { position: relative; }
        .cj-overlay-head {
          display: flex; justify-content: space-between; align-items: center;
          padding-bottom: 12px;
          border-bottom: 1px solid var(--line);
          margin-bottom: 14px;
        }
        .cj-overlay-k { font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.16em; color: var(--t-2); }
        .cj-overlay-step { font-family: var(--f-mono); font-size: 10px; letter-spacing: 0.12em; color: var(--t-4); }
        .cj-overlay-rows { display: grid; gap: 0; }
        .cj-overlay-row {
          display: grid;
          grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
          gap: 14px;
          padding: 9px 0;
          border-bottom: 1px dashed var(--line);
          font-family: var(--f-mono);
          font-size: 12px;
          animation: cjFade 320ms ease;
        }
        .cj-overlay-row:last-child { border-bottom: none; }
        .cj-overlay-row .k { color: var(--t-3); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; align-self: center; }
        .cj-overlay-row .v { color: var(--t-1); word-break: break-word; font-size: 11.5px; }
        @keyframes cjFade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

        /* The MARKETING INSIGHT callout — the CMO/CGO money shot */
        .cj-overlay-insight {
          margin-top: 16px;
          padding: 14px 14px 14px 16px;
          background: linear-gradient(180deg, rgba(95,179,255,0.08), rgba(95,179,255,0.02));
          border: 1px solid rgba(95,179,255,0.30);
          border-left: 3px solid var(--uber-cash-blue);
          border-radius: 0 12px 12px 0;
          animation: cjFade 320ms ease;
        }
        .cj-overlay-insight-k {
          font-family: var(--f-mono);
          font-size: 10px;
          letter-spacing: 0.18em;
          color: var(--uber-cash-blue);
          margin-bottom: 8px;
          display: flex; align-items: center; gap: 8px;
        }
        .cj-overlay-insight-k::before { content: "◆"; font-size: 9px; }
        .cj-overlay-insight-v {
          font-family: var(--f-body);
          font-size: 13px;
          line-height: 1.5;
          color: var(--t-1);
        }

        .cj-overlay-foot {
          margin-top: 14px;
          padding-top: 12px;
          border-top: 1px solid var(--line);
          font-family: var(--f-mono);
          font-size: 10px;
          letter-spacing: 0.1em;
          color: var(--t-4);
          line-height: 1.5;
        }
      `}</style>

      {/* LEFT */}
      <div className="cj-left">
        <div className="cj-pills">
          {Object.values(CJ_VARIANTS).map((vv) => (
            <button
              key={vv.id}
              className={"cj-pill" + (vv.id === variantKey ? " active" : "")}
              style={{ "--pill-tint": vv.tint }}
              onClick={() => switchVariant(vv.id)}
            >
              {vv.label}
            </button>
          ))}
        </div>
        <div className="cj-can-block" style={{ "--tint": v.tint }}>
          <img src="assets/uber_can_front.png" alt="Uber co-branded water can"/>
        </div>
        <div className="cj-explain">
          <b>Declared-data consumer flow.</b> 9 screens. Every tap, declaration, and confirmation surfaces a marketing-grade signal on the right — predicted LTV, CAC savings, declared psychographics, cohort fit, retention forecast.
        </div>
        <div className="cj-stepnav">
          {CJ_STEP_LABELS.map((lbl, i) => (
            <div
              key={i}
              className={"cj-stepnav-item " + (i === step ? "active" : i < step ? "done" : "")}
              style={{ "--tint": v.tint }}
              onClick={() => { if (i <= step) go(i); }}
            >
              <div className="cj-stepnav-num">{String(i + 1).padStart(2, "0")}</div>
              <div className="cj-stepnav-label">{lbl}</div>
            </div>
          ))}
        </div>
      </div>

      {/* PHONE */}
      <div className="cj-phone-wrap">
        <div className="cj-phone" style={{ "--tint": v.tint, "--tint-soft": v.tintSoft }}>
          <div className="cj-phone-notch" />
          <div className="cj-status-bar">
            <span>{times[step]}</span>
            <span className="cj-status-right">
              <svg width="14" height="10" viewBox="0 0 14 10" fill="currentColor"><path d="M0 8h2v2H0zM4 6h2v4H4zM8 3h2v7H8zM12 0h2v10h-2z"/></svg>
              <svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" strokeWidth="1.2"><path d="M1 3a8 8 0 0 1 12 0M3 5.5a5 5 0 0 1 8 0M5 8a2 2 0 0 1 4 0"/></svg>
              <svg width="22" height="10" viewBox="0 0 22 10" fill="none" stroke="currentColor" strokeWidth="1"><rect x="1" y="1" width="18" height="8" rx="2"/><rect x="2.5" y="2.5" width="13" height="5" rx="0.5" fill="currentColor"/><rect x="20" y="3.5" width="1.5" height="3" fill="currentColor"/></svg>
            </span>
          </div>

          <div className="cj-screen-wrap">
            {/* 0 — WELCOME */}
            <Screen active={step === 0} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">01 · SCAN · {v.id.toUpperCase()}</div>
              </div>
              <div className="cj-vchip" style={{ background: v.tint }}>{v.label}</div>
              <h1 className="cj-h">{v.headline}</h1>
              <p className="cj-sub">{v.sub}</p>
              <p className="cj-body" style={{ marginBottom: 14 }}>
                You scanned an Ape × Uber can. Two minutes — and you're entered into our <b style={{ color: "#fff" }}>$5,000 Uber-credit sweepstakes</b>.
              </p>
              <div className="cj-sweeps-hero">
                <div className="cj-sweeps-hero-k">SWEEPSTAKES PRIZE</div>
                <div className="cj-sweeps-hero-v"><small>$</small>5,000</div>
                <div className="cj-sweeps-hero-sub">UBER CREDIT · DRAWING POST-SEASON</div>
              </div>
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <div className="cj-fine">~2 MIN · CCPA · 21+</div>
              </div>
            </Screen>

            {/* 1 — CONSENT */}
            <Screen active={step === 1} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">02 · CONSENT</div>
              </div>
              <h1 className="cj-h">A couple of confirmations.</h1>
              <p className="cj-sub">We don't collect a single signal without them.</p>
              <div className={"cj-toggle" + (age21 ? " on" : "")} onClick={() => setAge21(!age21)} role="button" tabIndex={0}>
                <div className="cj-toggle-l">
                  <b>I'm 21 or older.</b>
                  Required for venue activations.
                </div>
                <div className="cj-switch"/>
              </div>
              <div className={"cj-toggle" + (ccpa ? " on" : "")} onClick={() => setCcpa(!ccpa)} role="button" tabIndex={0}>
                <div className="cj-toggle-l">
                  <b>I agree to Uber's privacy terms.</b>
                  CCPA-compliant. Granular opt-in. You can withdraw any time.
                </div>
                <div className="cj-switch"/>
              </div>
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" disabled={!canAdvance()} onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 2 — IDENTITY (name + email + zip) */}
            <Screen active={step === 2} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">03 · YOUR INFO</div>
              </div>
              <h1 className="cj-h">Name, email, ZIP.</h1>
              <p className="cj-sub">For sweepstakes entry, account match, and tonight's nearest pickup.</p>
              <div className="cj-field-row">
                <div>
                  <label className="cj-label">FIRST NAME</label>
                  <input className="cj-input" placeholder="Alex" value={firstName} onChange={(e) => setFirstName(e.target.value)}/>
                </div>
                <div>
                  <label className="cj-label">LAST NAME</label>
                  <input className="cj-input" placeholder="Morgan" value={lastName} onChange={(e) => setLastName(e.target.value)}/>
                </div>
              </div>
              <div className="cj-field">
                <label className="cj-label">EMAIL ADDRESS</label>
                <input
                  className={"cj-input" + (email && !emailOk ? " invalid" : "")}
                  type="email"
                  placeholder="alex@example.com"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  autoComplete="email"
                />
                {email && !emailOk && <div className="cj-field-hint err">CHECK YOUR EMAIL FORMAT</div>}
              </div>
              <div className="cj-field">
                <label className="cj-label">ZIP CODE</label>
                <input
                  className={"cj-input" + (zip && !zipOk ? " invalid" : "")}
                  inputMode="numeric"
                  maxLength={5}
                  placeholder="94612"
                  value={zip}
                  onChange={(e) => setZip(e.target.value.replace(/\D/g, "").slice(0, 5))}
                />
                {zip && !zipOk && <div className="cj-field-hint err">5 DIGITS</div>}
              </div>
              {zipOk && geo && (
                <div className="cj-geo-readout" style={{ "--tint": v.tint }}>
                  <div className="cj-geo-k">DETECTED MARKET</div>
                  <div className="cj-geo-v">{geo.metro} · {geo.tier} · est. HHI ${geo.hhi}K</div>
                </div>
              )}
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" disabled={!canAdvance()} onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 3 — VERIFY */}
            <Screen active={step === 3} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">04 · VERIFY</div>
              </div>
              <h1 className="cj-h">Verify your phone.</h1>
              <p className="cj-sub">We text a 4-digit code. Used once, then discarded.</p>
              <div className="cj-field">
                <label className="cj-label">MOBILE NUMBER</label>
                <input
                  className={"cj-input" + (phone && !phoneOk ? " invalid" : "")}
                  type="tel"
                  inputMode="tel"
                  placeholder="(555) 555-1234"
                  value={phone}
                  onChange={(e) => { setPhone(fmtPhoneInput(e.target.value)); setOtpSent(false); setOtpCode(""); }}
                  autoComplete="tel"
                />
                {phone && !phoneOk && <div className="cj-field-hint err">10 DIGITS, US FORMAT</div>}
              </div>
              {!otpSent && (
                <button className="cj-btn ghost" disabled={!phoneOk} onClick={sendOtp} style={{ marginBottom: 10 }}>
                  Text me the code
                </button>
              )}
              {otpSent && (
                <div className="cj-field">
                  <label className="cj-label">ENTER 4-DIGIT CODE</label>
                  <div className="cj-otp-row">
                    {[0,1,2,3].map((i) => (
                      <input
                        key={i}
                        className={"cj-otp-cell" + (otpCode[i] ? " filled" : "")}
                        maxLength={1}
                        inputMode="numeric"
                        value={otpCode[i] || ""}
                        onChange={(e) => {
                          const d = e.target.value.replace(/\D/g, "").slice(0, 1);
                          const arr = otpCode.split("");
                          arr[i] = d;
                          setOtpCode(arr.join("").slice(0, 4));
                          if (d && e.target.nextSibling) e.target.nextSibling.focus();
                        }}
                      />
                    ))}
                  </div>
                  <div className={"cj-otp-status" + (otpOk ? " ok" : "")}>
                    {otpOk ? "✓ CODE VERIFIED" : "WAITING FOR CODE…"}
                  </div>
                  <button className="cj-resend" onClick={sendOtp}>Resend code</button>
                </div>
              )}
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" disabled={!canAdvance()} onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 4 — DECLARED INSIGHTS */}
            <Screen active={step === 4} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">05 · TONIGHT</div>
              </div>
              <h1 className="cj-h">Quick three.</h1>
              <p className="cj-sub">Helps us send the right rides home.</p>

              <div className="cj-q-block">
                <div className="cj-q-label">WHAT BROUGHT YOU OUT?</div>
                <div className="cj-q-grid">
                  {Q_REASON.map(q => (
                    <button key={q.id}
                      className={"cj-q-opt" + (qReason === q.id ? " on" : "")}
                      style={{ "--tint": v.tint }}
                      onClick={() => setQReason(q.id)}>
                      {q.label}
                    </button>
                  ))}
                </div>
              </div>

              <div className="cj-q-block">
                <div className="cj-q-label">WHO'S WITH YOU?</div>
                <div className="cj-q-grid">
                  {Q_GROUP.map(q => (
                    <button key={q.id}
                      className={"cj-q-opt" + (qGroup === q.id ? " on" : "")}
                      style={{ "--tint": v.tint }}
                      onClick={() => setQGroup(q.id)}>
                      {q.label}
                    </button>
                  ))}
                </div>
              </div>

              <div className="cj-q-block">
                <div className="cj-q-label">HOW OFTEN DO YOU GO OUT LIKE THIS?</div>
                <div className="cj-q-grid">
                  {Q_FREQ.map(q => (
                    <button key={q.id}
                      className={"cj-q-opt" + (qFreq === q.id ? " on" : "")}
                      style={{ "--tint": v.tint }}
                      onClick={() => setQFreq(q.id)}>
                      {q.label}
                    </button>
                  ))}
                </div>
              </div>

              <div className="cj-cta-stack">
                <button className="cj-btn tinted" disabled={!canAdvance()} onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 5 — ACCOUNT */}
            <Screen active={step === 5} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">06 · ACCOUNT</div>
              </div>
              <h1 className="cj-h">Existing Uber rider?</h1>
              <p className="cj-sub">We'll match your reward — or create your account.</p>
              <div className="cj-choice">
                <button
                  className={userKind === "existing" ? "active" : ""}
                  style={{ "--tint": v.tint, borderColor: userKind === "existing" ? v.tint : undefined }}
                  onClick={() => setUserKind("existing")}
                >
                  <b>Yes, I'm a rider</b>
                  <span className="muted">We'll match you by phone & email.</span>
                </button>
                <button
                  className={userKind === "new" ? "active" : ""}
                  style={{ "--tint": v.tint, borderColor: userKind === "new" ? v.tint : undefined }}
                  onClick={() => setUserKind("new")}
                >
                  <b>I'm new to Uber</b>
                  <span className="muted">One tap — first ride credit included.</span>
                </button>
              </div>
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" disabled={!canAdvance()} onClick={next}>Continue <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 6 — CLAIM */}
            <Screen active={step === 6} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">07 · CLAIM</div>
              </div>
              <div className="cj-vchip" style={{ background: v.tint }}>{v.label}</div>
              <h1 className="cj-h">Here's your reward, {firstName || "friend"}.</h1>
              <div className="cj-claim-card">
                <div className="cj-claim-k">{v.rewardLabel}</div>
                <div className="cj-claim-v">
                  {v.rewardCurrency && <span className="currency">{v.rewardCurrency}</span>}
                  {v.rewardAmount && <span className="amount">{v.rewardAmount}</span>}
                  {v.rewardWord && <span className="word">{v.rewardWord}</span>}
                </div>
                <ul className="cj-claim-perks">
                  {v.perks.map((p) => <li key={p}>{p}</li>)}
                </ul>
              </div>
              <p className="cj-body" style={{ marginBottom: 12 }}>
                One tap — applies instantly to your Uber account.
              </p>
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" onClick={next}>{v.ctaClaim} <Icon name="arrow" size={14}/></button>
                <button className="cj-btn ghost" onClick={back}>Back</button>
              </div>
            </Screen>

            {/* 7 — SWEEPSTAKES */}
            <Screen active={step === 7} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">08 · SWEEPSTAKES</div>
              </div>
              <h1 className="cj-h">You're entered.</h1>
              <p className="cj-sub">One entry per email. Drawing held post-season.</p>
              <div className="cj-sweeps-hero">
                <div className="cj-sweeps-hero-k">GRAND PRIZE</div>
                <div className="cj-sweeps-hero-v"><small>$</small>5,000</div>
                <div className="cj-sweeps-hero-sub">UBER CREDIT · ANY UBER PRODUCT</div>
              </div>
              <div className="cj-entry-box">
                <div>
                  <div className="cj-entry-k">YOUR ENTRY ID</div>
                  <div className="cj-entry-v">{entryId || "—"}</div>
                </div>
                <div className="cj-entry-badge">CONFIRMED</div>
              </div>
              <div className="cj-tc">
                <b>The fine print, short version</b>
                No purchase necessary. Open to US residents 21+. One entry per email. Drawing within 14 days of season close. Prize delivered as Uber credit. Full terms at uber.com/apewater-terms.
              </div>
              <div className="cj-cta-stack">
                <button className="cj-btn tinted" onClick={next}>See my summary <Icon name="arrow" size={14}/></button>
              </div>
            </Screen>

            {/* 8 — ATTRIBUTED (final) */}
            <Screen active={step === 8} dir={direction}>
              <Progress step={step} total={total} tint={v.tint}/>
              <div className="cj-screen-head">
                <div className="cj-uber">Uber</div>
                <div className="cj-screen-head-r">09 · ALL SET</div>
              </div>
              <div style={{ display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
                <div className="cj-check-wrap" style={{ background: v.tint }}>
                  <Icon name="check" size={28} stroke={2.4}/>
                </div>
                <h1 className="cj-h">{v.confirmedH}</h1>
                <p className="cj-sub">{v.confirmedSub}</p>
              </div>
              <div className="cj-recap">
                <div className="cj-recap-row">
                  <span className="k">REWARD</span>
                  <span className="v">{v.rewardCurrency}{v.rewardAmount}{v.rewardWord} {v.id === "one" ? "free trial" : v.id === "cash" ? "in Uber Cash" : "off Eats"}</span>
                </div>
                <div className="cj-recap-row">
                  <span className="k">SWEEPS ENTRY</span>
                  <span className="v">{entryId}</span>
                </div>
                <div className="cj-recap-row">
                  <span className="k">CONFIRMATION</span>
                  <span className="v">{email ? (email.length > 18 ? email.slice(0, 16) + "…" : email) : "—"}</span>
                </div>
                <div className="cj-recap-row">
                  <span className="k">ACCOUNT</span>
                  <span className="v">{userKind === "new" ? "New · created" : "Existing · matched"}</span>
                </div>
              </div>
              <div className="cj-cta-stack">
                <button className="cj-btn" onClick={() => alert("Demo: this would deep-link into the Uber app.")}>
                  Open the Uber app <Icon name="arrow" size={14}/>
                </button>
                <button className="cj-btn ghost" onClick={restart}>Start over</button>
              </div>
              <div className="cj-fine">
                DEMO · NOT AFFILIATED WITH UBER TECHNOLOGIES, INC.
              </div>
            </Screen>
          </div>
        </div>

        <div className="cj-controls">
          <button className="cj-control-btn flip" onClick={back} disabled={step === 0} aria-label="Back">
            <Icon name="arrow" size={13}/>
          </button>
          <span className="cj-counter">{String(step + 1).padStart(2, "0")} / 09</span>
          <button className="cj-control-btn" onClick={next} disabled={step === total - 1 || !canAdvance()} aria-label="Next">
            <Icon name="arrow" size={13}/>
          </button>
          <button className="cj-restart" onClick={restart}>RESTART</button>
        </div>
      </div>

      {/* RIGHT: marketing-insights overlay */}
      <div className="cj-overlay">
        <div className="cj-overlay-head">
          <div className="cj-overlay-k"><span className="live-dot"/>DECLARED-DATA · CGO VIEW</div>
          <div className="cj-overlay-step">{CJ_STEP_LABELS[step]} · {String(step + 1).padStart(2, "0")} / 09</div>
        </div>
        <div className="cj-overlay-rows">
          {stepData.rows.map(([k, val], i) => (
            <div className="cj-overlay-row" key={step + "-" + i}>
              <div className="k">{k}</div>
              <div className="v">{val}</div>
            </div>
          ))}
        </div>
        {stepData.insight && (
          <div className="cj-overlay-insight">
            <div className="cj-overlay-insight-k">{stepData.insight.k}</div>
            <div className="cj-overlay-insight-v">{stepData.insight.v}</div>
          </div>
        )}
        <div className="cj-overlay-foot">
          FIRST-PARTY · UBER WAREHOUSE · NO MIDDLEWARE<br/>
          DEDUPED ON EMAIL · CONSENT REVOCABLE
        </div>
      </div>
    </div>
  );
}

function Screen({ active, dir, children }) {
  const cls = active
    ? "cj-screen active"
    : "cj-screen " + (dir > 0 ? "exit-left" : "exit-right");
  return <div className={cls}>{children}</div>;
}

function Progress({ step, total, tint }) {
  return (
    <div className="cj-progress">
      {Array.from({ length: total }).map((_, i) => (
        <span
          key={i}
          className={i === step ? "active" : i < step ? "done" : ""}
          style={i === step ? { background: tint } : {}}
        />
      ))}
    </div>
  );
}

function ExperienceIt() {
  const [variantKey, setVariantKey] = useState("one");
  return (
    <section className="section" id="experience">
      <style>{`
        .exp2-top { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 6vw, 80px); align-items: end; margin-bottom: 56px; }
        .exp2-h { font-family: var(--f-display); font-weight: 700; font-size: clamp(38px, 5vw, 72px); letter-spacing: -0.028em; line-height: 1.0; margin: 0; text-wrap: balance; }
        .exp2-h em { font-style: normal; color: var(--t-3); font-weight: 500; }
        .exp2-sub { color: var(--t-2); font-size: clamp(15px, 1.2vw, 18px); line-height: 1.55; max-width: 540px; }
        @media (max-width: 880px) { .exp2-top { grid-template-columns: 1fr; } }
      `}</style>
      <div className="container">
        <Reveal>
          <div className="eyebrow" style={{ marginBottom: 32 }}>EXPERIENCE IT · DECLARED-DATA FLOW</div>
        </Reveal>
        <div className="exp2-top">
          <Reveal>
            <h2 className="exp2-h">The consumer journey.<br/><em>What a CGO sees on the right.</em></h2>
          </Reveal>
          <Reveal delay={120}>
            <p className="exp2-sub">
              Every tap on the phone surfaces a marketing-grade insight on the right: ZIP enrichment, identity-graph confidence, declared psychographics, predicted 90-day LTV, CAC savings, retention forecast. This is what Uber's growth team can't buy anywhere else — declared, first-party, attributable.
            </p>
          </Reveal>
        </div>
        <Reveal>
          <ConsumerJourney variantKey={variantKey} onVariantChange={setVariantKey} />
        </Reveal>
      </div>
    </section>
  );
}

Object.assign(window, { ExperienceIt, ConsumerJourney });
