const { useState, useMemo, useEffect, useRef } = React;
const API_BASE = ""; // same-origin: the funnel and /api live under librancy.com
const REF_TOKEN = (new URLSearchParams(window.location.search).get("ref") || "").replace(/[^a-z0-9]/g, "").slice(0, 24) || null;

/* ── Visitor identity: one stable id per browser, so a drop-off at ANY step is
      still a followable lead. Survives reloads and the landing-page handoff. ── */
const QS = new URLSearchParams(window.location.search);
const SESSION_ID = (() => {
  try {
    let s = localStorage.getItem("lbr_sid");
    if (!s) {
      s = "s" + Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
      localStorage.setItem("lbr_sid", s);
    }
    return s;
  } catch (e) { return "s" + Date.now().toString(36) + Math.random().toString(36).slice(2, 10); }
})();
const SOURCE = (QS.get("utm_source") || QS.get("src") || document.referrer.split("/")[2] || "direct").slice(0, 60);
const CAMPAIGN = (QS.get("utm_campaign") || QS.get("c") || "").slice(0, 120) || null;

/* Meta pixel bridge: fires standard events if the pixel is installed on the page.
   Safe no-op if fbq isn't present, so the funnel never breaks without it. */
function lbrTrack(event, params) {
  try { if (typeof window !== "undefined" && typeof window.fbq === "function") window.fbq("track", event, params || {}); } catch (e) {}
}

/* Fire-and-forget: never blocks or breaks the funnel. */
function trackLead(milestone, data) {
  try {
    fetch(API_BASE + "/api/lead.php", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        sessionId: SESSION_ID, milestone,
        childName: data.childName || null, ageBand: data.ageBand || null,
        interests: data.interests || null, experience: data.experience || null,
        aspirations: data.aspirations || null, commitment: data.commitment || null,
        parentName: data.parentName || null, phone: data.phone || null, email: data.email || null,
        consent: !!(data.waConsent || data.consent), source: SOURCE, campaign: CAMPAIGN,
      }),
      keepalive: true,
    }).catch(() => {});
  } catch (e) {}
}

/**
 * LIBRANCY — Conversion Funnel Engine (Phase 1, Sprint 1)
 * ------------------------------------------------------------------
 * A vertical-agnostic, config-driven quiz funnel. The AI-Kids vertical
 * is loaded as data; Entrepreneurship / Public Speaking slot in the same way.
 *
 * What's wired in this build:
 *  - Single source of truth for child name  -> name propagates to EVERY screen
 *    (fixes the Ubasinachi/Ogbonna bug from the Horizon prototype)
 *  - Soft price signal on the hero (FUN-01)
 *  - REAL personalization on the offer: age band + interests drive the
 *    recommended path and the reason copy (FUN-09) — not "all 4 to everyone"
 *  - Entry tier + split-payment option (the two pricing fixes)
 *  - NDPA consent checkbox before data capture (FUN-08)
 *  - Trust artifacts (sample lesson, guarantee, social proof, Paystack)
 *  - Mobile-first, single-column, large tap targets
 *  - Lead persistence against the real API contract (see saveLead)
 *
 * Production note: in the real app, funnel state mirrors to localStorage for
 * session recovery and POSTs to /api/leads on the parent-details step. The
 * artifact sandbox forbids localStorage, so state lives in React only here.
 */

/* ============================ DESIGN TOKENS ============================ */
const T = {
  navy: "#101450",
  navy2: "#1B2270",
  coral: "#FF6B6B",
  coralDark: "#E24B4A",
  blue: "#1C6BF6",
  teal: "#02B5AA",
  tealDeep: "#00715E",
  tealTint: "#E6F7F3",
  yellow: "#FEC323",
  yellowTint: "#FFF6DC",
  ink: "#1B2733",
  slate: "#5C6B7A",
  mist: "#8597A6",
  line: "#E4EAF0",
  paper: "#FFFFFF",
  cloud: "#F5F8FB",
  good: "#1B9E6B",
};
const FONT = `"Poppins","Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif`;
const NGN = (n) => "₦" + n.toLocaleString("en-NG");

/* ============================ VERTICAL CONFIG ============================ */
/* Everything specific to a vertical lives here. The engine never hard-codes "AI". */
const VERTICALS = {
  ai: {
    slug: "ai",
    brandSuffix: "AI",
    accent: T.teal,
    hero: {
      eyebrow: "Librancy AI Academy",
      headline: "What if your child could build the future before everyone else?",
      sub: "Discover how AI, creativity and technology can unlock your child’s potential — with courses made for African children, at home and in the diaspora.",
      priceFrom: 37500,
      timeMins: 3,
    },
    ageBands: [
      { id: "7-9", label: "7–9", tag: "Explorer", icon: "spark" },
      { id: "10-12", label: "10–12", tag: "Builder", icon: "rocket" },
      { id: "13-15", label: "13–15", tag: "Founder", icon: "bolt" },
    ],
    interests: [
      "Drawing & creativity", "Making videos", "Playing games", "Building things",
      "Solving problems", "Speaking", "Technology", "Storytelling", "Exploring ideas",
    ],
    aspirations: [
      "Confident leader", "Tech creator", "Entrepreneur", "Smart communicator",
      "Global problem-solver", "Innovative thinker", "World-class creator", "Financially independent",
    ],
    courses: [
      { id: "explorer", name: "AI Explorers", ages: "7–9", band: "7-9", price: 37500,
        blurb: "Their first joyful encounter with AI — create stories, art and characters, and learn to prompt with confidence." },
      { id: "builders", name: "AI Builders", ages: "10–13", band: "10-12", price: 37500,
        blurb: "Build real AI projects and their first AI tools using friendly no-code platforms." },
      { id: "prompt", name: "Prompt Mastery", ages: "12–15", band: "13-15", price: 37500,
        blurb: "Master the language of AI — structured prompting and powerful AI interactions." },
      { id: "founders", name: "AI Founder’s Program", ages: "10–15", band: "13-15", price: 37500,
        blurb: "Build a real AI business end-to-end: problem → idea → validate → build → launch → scale." },
    ],
    bundle: { name: "Complete Bundle", count: 4, price: 87500, anchor: 150000 },
  },
};

/* ============================ TINY ICONS ============================ */
const Ico = ({ d, size = 22, stroke = "currentColor", fill = "none", sw = 1.8 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke={stroke}
    strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    {d}
  </svg>
);
const I = {
  spark: <Ico d={<><path d="M12 3l1.8 4.6L18 9l-4.2 1.4L12 15l-1.8-4.6L6 9l4.2-1.4z" /><path d="M19 14l.7 1.8L21 16.5l-1.3.7L19 19l-.7-1.8L17 16.5l1.3-.7z" /></>} />,
  rocket: <Ico d={<><path d="M5 15c-1.5 1.5-2 5-2 5s3.5-.5 5-2" /><path d="M14.5 4.5C18 8 18 12 14 16l-3 1-3-3 1-3c4-4 8-4 5.5-6.5z" /><circle cx="13" cy="9" r="1.3" /></>} />,
  bolt: <Ico d={<path d="M13 2L4 14h7l-1 8 9-12h-7z" />} />,
  check: <Ico d={<path d="M5 13l4 4L19 7" sw={2.4} />} size={18} />,
  arrow: <Ico d={<path d="M5 12h14M13 6l6 6-6 6" />} size={18} />,
  back: <Ico d={<path d="M19 12H5M11 6l-6 6 6 6" />} size={18} />,
  shield: <Ico d={<><path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6z" /><path d="M9 12l2 2 4-4" /></>} size={18} />,
  play: <Ico d={<><circle cx="12" cy="12" r="9" /><path d="M10 9l5 3-5 3z" fill="currentColor" sw={0} /></>} size={18} />,
  lock: <Ico d={<><rect x="5" y="11" width="14" height="9" rx="2" /><path d="M8 11V8a4 4 0 018 0v3" /></>} size={16} />,
  gift: <Ico d={<><rect x="4" y="9" width="16" height="11" rx="1.5" /><path d="M4 13h16M12 9v11M12 9S10 3 7.5 4.5 9 9 12 9zM12 9s2-6 4.5-4.5S15 9 12 9z" /></>} size={20} />,
  star: <Ico d={<path d="M12 3l2.6 6 6.4.5-4.9 4.2 1.5 6.3L12 17l-5.6 3 1.5-6.3L3 9.5 9.4 9z" fill="currentColor" sw={0} />} size={15} />,
};

/* ============================ PRIMITIVES ============================ */
function Shell({ children, wide }) {
  return (
    <div style={{ minHeight: "100%", background: T.cloud, fontFamily: FONT, color: T.ink }}>
      <div className={"lbr-shell" + (wide ? " wide" : "")}>
        {children}
      </div>
    </div>
  );
}

function Progress({ step, total }) {
  const pct = Math.round((step / total) * 100);
  return (
    <div style={{ height: 5, background: T.line, position: "sticky", top: 0, zIndex: 5 }}>
      <div style={{ height: "100%", width: `${pct}%`, background: `linear-gradient(90deg, ${T.navy}, ${T.teal})`,
        borderRadius: "0 4px 4px 0", transition: "width .4s cubic-bezier(.4,0,.2,1)" }} />
    </div>
  );
}

function TopBar({ onBack, showBack }) {
  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between",
      padding: "14px 20px 4px" }}>
      {showBack ? (
        <button onClick={onBack} style={{ ...ghostBtn, color: T.slate }}>
          {I.back}<span style={{ marginLeft: 4 }}>Back</span>
        </button>
      ) : <span />}
      <img src="/assets/cert/logo.png" alt="Librancy AI" style={{ height: 26, display: "block" }} />
      <span style={{ width: 52 }} />
    </div>
  );
}

function Page({ children }) {
  return <div style={{ padding: "8px 22px 20px", flex: 1, animation: "fadein .35s ease" }}>{children}</div>;
}

function Eyebrow({ children, color = T.teal }) {
  return <div style={{ fontSize: 12.5, fontWeight: 600, letterSpacing: 1.2, textTransform: "uppercase",
    color, marginBottom: 10 }}>{children}</div>;
}
function H1({ children }) {
  return <h1 style={{ fontSize: 27, lineHeight: 1.18, fontWeight: 700, color: T.navy, margin: "0 0 10px" }}>{children}</h1>;
}
function Sub({ children }) {
  return <p style={{ fontSize: 15.5, lineHeight: 1.55, color: T.slate, margin: "0 0 22px" }}>{children}</p>;
}

function PrimaryBtn({ children, onClick, disabled }) {
  return (
    <button onClick={onClick} disabled={disabled}
      style={{
        width: "100%", padding: "17px 20px", border: "none", borderRadius: 16,
        background: disabled ? "#F0C4C4" : T.coral, color: "#fff", fontSize: 16.5, fontWeight: 600,
        fontFamily: FONT, cursor: disabled ? "not-allowed" : "pointer", display: "flex",
        alignItems: "center", justifyContent: "center", gap: 8,
        boxShadow: disabled ? "none" : "0 8px 20px rgba(255,107,107,.35)",
        transition: "transform .12s, box-shadow .2s",
      }}
      onMouseDown={(e) => !disabled && (e.currentTarget.style.transform = "scale(.985)")}
      onMouseUp={(e) => (e.currentTarget.style.transform = "scale(1)")}
      onMouseLeave={(e) => (e.currentTarget.style.transform = "scale(1)")}>
      {children}{!disabled && I.arrow}
    </button>
  );
}

const ghostBtn = { background: "none", border: "none", display: "inline-flex", alignItems: "center",
  fontSize: 14, fontWeight: 500, cursor: "pointer", fontFamily: FONT, padding: 4 };

function Footer({ children }) {
  return <div style={{ padding: "12px 22px 22px", borderTop: `1px solid ${T.line}`, background: T.paper }}>{children}</div>;
}

/* Selectable card (single or multi) */
function Choice({ active, onClick, children, compact }) {
  return (
    <button onClick={onClick} style={{
      width: "100%", textAlign: "left", padding: compact ? "14px 16px" : "16px 18px",
      borderRadius: 14, cursor: "pointer", fontFamily: FONT,
      border: `2px solid ${active ? T.teal : T.line}`,
      background: active ? T.tealTint : T.paper,
      display: "flex", alignItems: "center", gap: 12, transition: "all .15s",
    }}>
      {children}
      <span style={{ marginLeft: "auto", width: 22, height: 22, borderRadius: "50%", flexShrink: 0,
        border: `2px solid ${active ? T.teal : T.line}`, background: active ? T.teal : "transparent",
        color: "#fff", display: "grid", placeItems: "center" }}>
        {active && I.check}
      </span>
    </button>
  );
}

function TrustStrip() {
  const item = (icon, label) => (
    <div style={{ display: "flex", alignItems: "center", gap: 5, color: T.slate, fontSize: 11.5, fontWeight: 500 }}>
      <span style={{ color: T.teal }}>{icon}</span>{label}
    </div>
  );
  return (
    <div style={{ display: "flex", flexWrap: "wrap", gap: "10px 16px", justifyContent: "center",
      padding: "14px 12px", background: T.cloud, borderRadius: 14 }}>
      {item(I.shield, "Secure Paystack")}
      {item(I.check, "30-day guarantee")}
      {item(I.star, "125 studio-filmed lessons")}
    </div>
  );
}

/* ============================ SCREENS ============================ */

// 1 — HERO
function Hero({ v, next }) {
  return (
    <>
      <div style={{ padding: "18px 22px 6px", display: "flex", alignItems: "center", gap: 9 }}>
        <Logo />
      </div>
      <Page>
        <div className="hero-grid">
          <div>
            <Eyebrow>{v.hero.eyebrow}</Eyebrow>
            <H1>{v.hero.headline}</H1>
            <Sub>{v.hero.sub}</Sub>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between",
              margin: "0 2px 16px" }}>
              <span style={{ fontSize: 13.5, color: T.slate, display: "flex", alignItems: "center", gap: 6 }}>
                <span style={{ width: 7, height: 7, borderRadius: "50%", background: T.teal }} />
                Takes about {v.hero.timeMins} minutes
              </span>
              <span style={{ fontSize: 13.5, fontWeight: 600, color: T.navy }}>
                Plans from {NGN(v.hero.priceFrom)}
              </span>
            </div>
          </div>
          <div>
            {/* Signature visual: a child's learning dashboard, illustrated, not stock */}
            <DashboardArt accent={v.accent} />
          </div>
        </div>
      </Page>
      <Footer>
        <PrimaryBtn onClick={next}>Discover their potential</PrimaryBtn>
        <button style={{ ...ghostBtn, color: T.teal, width: "100%", justifyContent: "center", marginTop: 12, fontWeight: 600 }}>
          {I.play}<span style={{ marginLeft: 6 }}>Watch a free sample lesson</span>
        </button>
        <div style={{ marginTop: 14 }}><TrustStrip /></div>
      </Footer>
    </>
  );
}

// 2 — CHILD BASICS
function ChildBasics({ v, data, set, next }) {
  const ok = data.childName.trim().length >= 2 && data.ageBand;
  return (
    <>
      <Page>
        <H1>Let’s start with the basics</H1>
        <Sub>Tell us a little about your child so we can shape their journey.</Sub>

        <Label>Child’s first name</Label>
        <input value={data.childName} onChange={(e) => set({ childName: e.target.value })}
          placeholder="e.g. Ada" autoFocus
          style={inputStyle} />

        <Label style={{ marginTop: 22 }}>Age range</Label>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10 }}>
          {v.ageBands.map((b) => {
            const active = data.ageBand === b.id;
            return (
              <button key={b.id} onClick={() => set({ ageBand: b.id })} style={{
                padding: "18px 8px", borderRadius: 16, cursor: "pointer", fontFamily: FONT,
                border: `2px solid ${active ? T.teal : T.line}`, background: active ? T.tealTint : T.paper,
                display: "flex", flexDirection: "column", alignItems: "center", gap: 8, transition: "all .15s",
              }}>
                <span style={{ color: active ? T.tealDeep : T.mist }}>{I[b.icon]}</span>
                <span style={{ fontWeight: 700, color: T.navy, fontSize: 16 }}>{b.label}</span>
                <span style={{ fontSize: 11, color: active ? T.tealDeep : T.mist, fontWeight: 600 }}>{b.tag}</span>
              </button>
            );
          })}
        </div>
      </Page>
      <Footer><PrimaryBtn onClick={next} disabled={!ok}>Continue</PrimaryBtn></Footer>
    </>
  );
}

// 3 — INTERESTS
function Interests({ v, data, set, next }) {
  const toggle = (x) => {
    const has = data.interests.includes(x);
    set({ interests: has ? data.interests.filter((i) => i !== x) : [...data.interests, x] });
  };
  return (
    <>
      <Page>
        <H1>What does {nameOf(data)} naturally enjoy?</H1>
        <Sub>Pick all that fit — there are no wrong answers.</Sub>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {v.interests.map((x) => {
            const active = data.interests.includes(x);
            return (
              <button key={x} onClick={() => toggle(x)} style={{
                padding: "16px 14px", borderRadius: 14, cursor: "pointer", fontFamily: FONT, textAlign: "left",
                border: `2px solid ${active ? T.teal : T.line}`, background: active ? T.tealTint : T.paper,
                fontWeight: 600, fontSize: 14.5, color: active ? T.tealDeep : T.ink, transition: "all .15s",
                display: "flex", alignItems: "center", justifyContent: "space-between", gap: 6,
              }}>
                {x}{active && <span style={{ color: T.teal }}>{I.check}</span>}
              </button>
            );
          })}
        </div>
      </Page>
      <Footer>
        <PrimaryBtn onClick={next} disabled={data.interests.length === 0}>
          {data.interests.length ? `Continue · ${data.interests.length} chosen` : "Choose at least one"}
        </PrimaryBtn>
      </Footer>
    </>
  );
}

// 3.5 — SOFT CAPTURE: the plan is the promise, the number is the exchange
function WhatsAppCapture({ data, set, next }) {
  const name = nameOf(data);
  const digits = (data.phone || "").replace(/[^0-9]/g, "");
  const valid = digits.length >= 10 && data.waConsent;
  return (
    <>
      <Page>
        <H1>Where should we send {name}'s learning plan?</H1>
        <Sub>We're building it as you answer. We'll WhatsApp you a copy — free, whether or not you enrol.</Sub>

        <div style={{ background: T.tealTint, borderRadius: 14, padding: "13px 15px", margin: "4px 0 18px" }}>
          <div style={{ fontSize: 13, color: T.tealDeep, lineHeight: 1.55 }}>
            <b>What you'll get:</b> the courses we'd start {name} on, what they'd build in the
            first week, and a free sample lesson to watch together.
          </div>
        </div>

        <Label>WhatsApp number</Label>
        <input value={data.phone} onChange={(e) => set({ phone: e.target.value })}
          placeholder="0806 000 0000" type="tel" inputMode="tel" style={inputStyle} />

        <Label style={{ marginTop: 18 }}>Email <span style={{ color: T.mist, fontWeight: 400 }}>(optional)</span></Label>
        <input value={data.email} onChange={(e) => set({ email: e.target.value })}
          placeholder="you@email.com" type="email" style={inputStyle} />

        <label style={{ display: "flex", gap: 10, marginTop: 18, cursor: "pointer", alignItems: "flex-start" }}>
          <input type="checkbox" checked={data.waConsent} onChange={(e) => set({ waConsent: e.target.checked })}
            style={{ width: 20, height: 20, accentColor: T.teal, marginTop: 1, flexShrink: 0 }} />
          <span style={{ fontSize: 12.5, color: T.slate, lineHeight: 1.5 }}>
            Yes, send {name}'s plan on WhatsApp and occasional updates about their learning.
            I can stop them any time. <span style={{ color: T.teal, fontWeight: 600 }}>Privacy Policy</span> (NDPA consent)
          </span>
        </label>
      </Page>
      <Footer>
        <PrimaryBtn onClick={next} disabled={!valid}>
          {valid ? "Send my plan · continue" : "Add your WhatsApp number"}
        </PrimaryBtn>
        <div onClick={next} style={{
          textAlign: "center", marginTop: 10, fontSize: 12.5, color: T.mist,
          cursor: "pointer", textDecoration: "underline",
        }}>I'll add it later</div>
      </Footer>
    </>
  );
}

// 4 — EXPERIENCE
function Experience({ data, set, next }) {
  const opts = [
    { id: "frequent", t: "Yes, often", s: "Ready for intermediate content" },
    { id: "little", t: "A little", s: "Ready for beginner content" },
    { id: "none", t: "Not yet", s: "Perfect — 80% of our learners start here" },
  ];
  return (
    <>
      <Page>
        <H1>Has {nameOf(data)} used AI tools before?</H1>
        <Sub>This helps us set the right starting point.</Sub>
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {opts.map((o) => (
            <Choice key={o.id} active={data.experience === o.id} onClick={() => set({ experience: o.id })}>
              <div>
                <div style={{ fontWeight: 700, color: T.navy, fontSize: 15.5 }}>{o.t}</div>
                <div style={{ fontSize: 13, color: T.slate, marginTop: 2 }}>{o.s}</div>
              </div>
            </Choice>
          ))}
        </div>
        {data.experience === "none" && (
          <div style={{ marginTop: 16, padding: "14px 16px", borderRadius: 14, background: T.yellowTint,
            border: `1px solid ${T.yellow}`, fontSize: 14, color: T.navy, lineHeight: 1.5 }}>
            Excellent! Most of our learners start exactly where {nameOf(data)} is. We guide them step by step from the very beginning.
          </div>
        )}
      </Page>
      <Footer><PrimaryBtn onClick={next} disabled={!data.experience}>Continue</PrimaryBtn></Footer>
    </>
  );
}

// 5 — ASPIRATIONS
function Aspirations({ v, data, set, next }) {
  const toggle = (x) => {
    const has = data.aspirations.includes(x);
    set({ aspirations: has ? data.aspirations.filter((i) => i !== x) : [...data.aspirations, x] });
  };
  return (
    <>
      <Page>
        <H1>What future would you love for {nameOf(data)}?</H1>
        <Sub>Choose all that resonate with you.</Sub>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {v.aspirations.map((x) => {
            const active = data.aspirations.includes(x);
            return (
              <button key={x} onClick={() => toggle(x)} style={{
                padding: "15px 14px", borderRadius: 14, cursor: "pointer", fontFamily: FONT, textAlign: "left",
                border: `2px solid ${active ? T.teal : T.line}`, background: active ? T.tealTint : T.paper,
                fontWeight: 600, fontSize: 13.8, color: active ? T.tealDeep : T.ink, transition: "all .15s",
                lineHeight: 1.3,
              }}>{x}</button>
            );
          })}
        </div>
      </Page>
      <Footer>
        <PrimaryBtn onClick={next} disabled={data.aspirations.length === 0}>Continue</PrimaryBtn>
      </Footer>
    </>
  );
}

// 6 — VALUE REFRAME (the anchor)
function ValueReframe({ data, next }) {
  return (
    <>
      <Page>
        <Eyebrow color={T.coral}>A quick thought</Eyebrow>
        <H1>Some gifts last a season. Others last a lifetime.</H1>
        <Sub>Children outgrow shoes in months. Future skills shape the rest of their lives.</Sub>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, margin: "8px 0 20px" }}>
          <div style={{ borderRadius: 16, border: `1px solid ${T.line}`, padding: 16, background: T.paper, opacity: .75 }}>
            <div style={{ height: 88, borderRadius: 12, background: T.cloud, display: "grid", placeItems: "center", marginBottom: 12 }}>
              <ShoeArt />
            </div>
            <div style={{ fontWeight: 700, color: T.slate, fontSize: 14 }}>A new pair of shoes</div>
            <div style={{ fontSize: 12.5, color: T.mist, marginTop: 2 }}>Outgrown in months</div>
          </div>
          <div style={{ borderRadius: 16, border: `2px solid ${T.yellow}`, padding: 16, background: T.yellowTint }}>
            <div style={{ height: 88, borderRadius: 12, background: "#fff", display: "grid", placeItems: "center", marginBottom: 12 }}>
              <FutureArt accent={T.teal} />
            </div>
            <div style={{ fontWeight: 700, color: T.navy, fontSize: 14, display: "flex", alignItems: "center", gap: 5 }}>
              Future-ready skills <span style={{ color: T.yellow }}>{I.star}</span>
            </div>
            <div style={{ fontSize: 12.5, color: T.tealDeep, marginTop: 2 }}>Last a lifetime</div>
          </div>
        </div>
        <p style={{ textAlign: "center", fontSize: 15, fontWeight: 600, color: T.navy }}>
          Which investment could shape {nameOf(data)} longer?
        </p>
      </Page>
      <Footer><PrimaryBtn onClick={next}>I understand</PrimaryBtn></Footer>
    </>
  );
}

// 7 — COMMITMENT (single-select)
function Commitment({ data, set, next }) {
  const options = [
    { label: "Not important",       value: 10 },
    { label: "Moderately",          value: 40 },
    { label: "Very important",      value: 70 },
    { label: "Extremely important", value: 100 },
  ];
  const idx = options.findIndex((o) => o.value === data.commitment);
  return (
    <>
      <Page>
        <H1>How important is future-ready education for {nameOf(data)}?</H1>
        <Sub>Help us understand your commitment.</Sub>

        <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: 6 }}>
          {options.map((o, i) => {
            const active = i === idx;
            return (
              <button key={o.label} onClick={() => set({ commitment: o.value })} style={{
                width: "100%", textAlign: "left", padding: "16px", borderRadius: 14, cursor: "pointer",
                fontFamily: FONT, transition: "all .15s", display: "flex",
                justifyContent: "space-between", alignItems: "center",
                border: `2px solid ${active ? T.teal : T.line}`,
                background: active ? T.tealTint : T.paper,
              }}>
                <span style={{ fontWeight: 600, fontSize: 14.5, color: active ? T.tealDeep : T.ink }}>{o.label}</span>
                {active && <span style={{ color: T.teal, fontWeight: 800 }}>✓</span>}
              </button>
            );
          })}
        </div>
        {idx >= 2 && (
          <div style={{ marginTop: 14, padding: "12px 14px", borderRadius: 12, background: T.tealTint,
            color: T.tealDeep, fontWeight: 600, fontSize: 14, textAlign: "center" }}>
            Perfect — you’re committed to {nameOf(data)}’s future.
          </div>
        )}
      </Page>
      <Footer><PrimaryBtn onClick={next} disabled={idx < 0}>Continue</PrimaryBtn></Footer>
    </>
  );
}

// 8 — PARENT DETAILS (+ NDPA consent, writes Lead)
function ParentDetails({ data, set, next }) {
  const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email);
  const ok = data.parentName.trim().length >= 2 && emailOk && data.consent;
  return (
    <>
      <Page>
        <H1>Where should we send {nameOf(data)}’s learning plan?</H1>
        <Sub>We’ll use this to create the account and send {nameOf(data)}’s curriculum.</Sub>

        <Label>Your full name</Label>
        <input value={data.parentName} onChange={(e) => set({ parentName: e.target.value })}
          placeholder="Your name" style={inputStyle} />

        <Label style={{ marginTop: 18 }}>Email address</Label>
        <input value={data.email} onChange={(e) => set({ email: e.target.value })}
          placeholder="you@email.com" type="email" style={inputStyle} />
        <div style={{ fontSize: 12, color: T.mist, marginTop: 6 }}>We’ll send account login details here.</div>

        <Label style={{ marginTop: 18 }}>Phone number <span style={{ color: T.mist, fontWeight: 400 }}>(optional)</span></Label>
        <input value={data.phone} onChange={(e) => set({ phone: e.target.value })}
          placeholder="+234…" style={inputStyle} />

        <label style={{ display: "flex", gap: 10, marginTop: 20, cursor: "pointer", alignItems: "flex-start" }}>
          <input type="checkbox" checked={data.consent} onChange={(e) => set({ consent: e.target.checked })}
            style={{ width: 20, height: 20, accentColor: T.teal, marginTop: 1, flexShrink: 0 }} />
          <span style={{ fontSize: 12.5, color: T.slate, lineHeight: 1.5 }}>
            I agree to Librancy creating an account for my child and contacting me about their learning. I’ve read the{" "}
            <span style={{ color: T.teal, fontWeight: 600 }}>Privacy Policy</span>. (NDPA consent)
          </span>
        </label>
      </Page>
      <Footer><PrimaryBtn onClick={next} disabled={!ok}>Continue to courses</PrimaryBtn></Footer>
    </>
  );
}

// 9 — OFFER (real personalization + entry tier + split pay)
function Offer({ v, data, set, next }) {
  const rec = useMemo(() => recommend(v, data), [v, data]);
  const sel = data.selection;
  const setSel = (s) => set({ selection: s });

  const bundleSelected = sel?.type === "bundle";
  const total = sel?.type === "bundle" ? v.bundle.price : sel?.type === "course"
    ? v.courses.find((c) => c.id === sel.id)?.price ?? 0 : 0;

  return (
    <>
      <Page>
        <H1>Choose {nameOf(data)}’s learning path</H1>
        <Sub>{rec.reason}</Sub>

        {/* Recommended bundle (anchor + default) */}
        <div style={{ position: "relative", marginBottom: 18 }}>
          <div style={{ position: "absolute", top: -11, left: 16, background: T.navy, color: "#fff",
            fontSize: 11, fontWeight: 700, padding: "4px 12px", borderRadius: 20, letterSpacing: .4 }}>
            ★ Recommended for {nameOf(data)}
          </div>
          <button onClick={() => setSel({ type: "bundle" })} style={{
            width: "100%", textAlign: "left", padding: "22px 18px 18px", borderRadius: 18, cursor: "pointer",
            fontFamily: FONT, border: `2.5px solid ${bundleSelected ? T.navy : T.line}`,
            background: bundleSelected ? "#fff" : T.paper, transition: "all .15s",
            boxShadow: bundleSelected ? "0 10px 26px rgba(0,31,63,.12)" : "none",
          }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={{ color: T.teal }}>{I.gift}</span>
                <span style={{ fontWeight: 700, color: T.navy, fontSize: 17 }}>{v.bundle.name}</span>
              </div>
              <span style={{ background: T.yellow, color: T.navy, fontSize: 11, fontWeight: 700,
                padding: "4px 8px", borderRadius: 8 }}>SAVE {NGN(v.bundle.anchor - v.bundle.price)}</span>
            </div>
            <div style={{ display: "flex", alignItems: "baseline", gap: 10, margin: "12px 0 6px" }}>
              <span style={{ fontSize: 30, fontWeight: 800, color: T.navy }}>{NGN(v.bundle.price)}</span>
              <span style={{ fontSize: 15, color: T.mist, textDecoration: "line-through" }}>{NGN(v.bundle.anchor)}</span>
            </div>
            <div style={{ fontSize: 13.5, color: T.slate, lineHeight: 1.5 }}>
              All {v.bundle.count} courses — {nameOf(data)}’s complete path to becoming a confident AI creator.
            </div>
          </button>
        </div>

        <Divider label="Or choose individually" />
        <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: 14 }}>
          {rec.ordered.map((c) => {
            const active = sel?.type === "course" && sel.id === c.id;
            return (
              <button key={c.id} onClick={() => setSel({ type: "course", id: c.id })} style={{
                width: "100%", textAlign: "left", padding: "14px 16px", borderRadius: 14, cursor: "pointer",
                fontFamily: FONT, border: `2px solid ${active ? T.teal : T.line}`,
                background: active ? T.tealTint : T.paper, transition: "all .15s",
              }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                  <span style={{ fontWeight: 700, color: T.navy, fontSize: 14.5 }}>{c.name}</span>
                  <span style={{ fontWeight: 700, color: T.navy, fontSize: 14.5 }}>{NGN(c.price)}</span>
                </div>
                <div style={{ fontSize: 11.5, color: T.teal, fontWeight: 600, margin: "2px 0 4px" }}>Ages {c.ages}</div>
                <div style={{ fontSize: 12.5, color: T.slate, lineHeight: 1.45 }}>{c.blurb}</div>
              </button>
            );
          })}
        </div>

        {/* Split-pay option appears when a paid path is selected */}
        {total >= 37500 && (
          <label style={{ display: "flex", gap: 10, marginTop: 18, cursor: "pointer", alignItems: "center",
            padding: "13px 15px", borderRadius: 14, border: `1.5px dashed ${T.teal}`, background: T.tealTint }}>
            <input type="checkbox" checked={data.splitPay} onChange={(e) => set({ splitPay: e.target.checked })}
              style={{ width: 19, height: 19, accentColor: T.teal }} />
            <span style={{ fontSize: 13, color: T.navy, fontWeight: 500 }}>
              Spread the cost — pay <b>{NGN(Math.ceil(total / 3 / 100) * 100)} × 3</b> instead of all at once
            </span>
          </label>
        )}
      </Page>
      <Footer>
        <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 12, fontSize: 14 }}>
          <span style={{ color: T.slate }}>{selLabel(v, sel) || "Select a path"}</span>
          <span style={{ fontWeight: 800, color: T.navy, fontSize: 17 }}>{total ? NGN(total) : "—"}</span>
        </div>
        <PrimaryBtn onClick={next} disabled={!sel}>Proceed to checkout</PrimaryBtn>
      </Footer>
    </>
  );
}

// 10 — CHECKOUT
function Checkout({ v, data, onPay }) {
  const sel = data.selection;
  const total = sel?.type === "bundle" ? v.bundle.price : sel?.type === "course"
    ? v.courses.find((c) => c.id === sel.id)?.price ?? 0 : 0;
  const perInstallment = Math.ceil(total / 3 / 100) * 100;
  return (
    <>
      <Page>
        <H1>Ready to give {nameOf(data)} an unfair advantage?</H1>
        <Sub>Review the plan below to finish enrolment.</Sub>

        <div style={{ borderRadius: 18, overflow: "hidden", border: `1px solid ${T.line}` }}>
          <div style={{ background: T.navy, color: "#fff", padding: "14px 18px", fontWeight: 700, fontSize: 14,
            display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ color: T.teal }}>{I.shield}</span> Your selection
          </div>
          <div style={{ padding: 18 }}>
            <Row k="Student" val={`${nameOf(data)} (${data.ageBand} yrs)`} />
            <Row k="Parent email" val={data.email || "—"} />
            <Row k="Path" val={selLabel(v, sel)} />
            <div style={{ height: 1, background: T.line, margin: "14px 0" }} />
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <span style={{ fontWeight: 700, color: T.navy }}>Total {data.splitPay ? "(today)" : "investment"}</span>
              <span style={{ fontSize: 24, fontWeight: 800, color: T.navy }}>
                {NGN(data.splitPay ? perInstallment : total)}
              </span>
            </div>
            {data.splitPay && (
              <div style={{ fontSize: 12.5, color: T.tealDeep, marginTop: 4, textAlign: "right" }}>
                then {NGN(perInstallment)} × 2 — one course unlocks per payment
              </div>
            )}
            <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 7 }}>
              <Perk text="Lifetime access to all materials" />
              <Perk text="Secure payment via Paystack" />
            </div>
          </div>
        </div>

        <div style={{ marginTop: 16, padding: "14px 16px", borderRadius: 14, background: T.yellowTint,
          border: `1px solid ${T.yellow}`, textAlign: "center" }}>
          <div style={{ fontWeight: 700, color: T.navy, fontSize: 14, display: "flex", justifyContent: "center", gap: 6 }}>
            <span style={{ color: T.coral }}>{I.shield}</span> 30-day satisfaction guarantee
          </div>
          <div style={{ fontSize: 12.5, color: T.slate, marginTop: 4, lineHeight: 1.5 }}>
            If you’re not thrilled with {nameOf(data)}’s progress, we’ll refund you in full. No questions asked.
          </div>
        </div>
      </Page>
      <Footer>
        <PrimaryBtn onClick={onPay}>
          Complete payment · {NGN(data.splitPay ? perInstallment : total)}
        </PrimaryBtn>
      </Footer>
    </>
  );
}

// 11 — HANDOFF (Sprint 2 seam, shown honestly)
function Handoff({ data }) {
  return (
    <Page>
      <div style={{ textAlign: "center", padding: "40px 8px" }}>
        <div style={{ width: 72, height: 72, borderRadius: "50%", background: T.tealTint, color: T.tealDeep,
          display: "grid", placeItems: "center", margin: "0 auto 20px" }}>
          <Ico d={<path d="M5 13l4 4L19 7" sw={2.4} />} size={34} stroke={T.tealDeep} />
        </div>
        <H1>Lead captured — Paystack opens here</H1>
        <p style={{ fontSize: 14.5, color: T.slate, lineHeight: 1.6, maxWidth: 340, margin: "0 auto" }}>
          In production this hands off to Paystack to take payment, then creates {nameOf(data)}’s account and grants the
          course entitlement. That wiring is <b>Sprint 2</b> of Phase 1 — the funnel engine you just clicked through is Sprint 1.
        </p>
        <pre style={{ textAlign: "left", marginTop: 22, background: T.navy, color: "#CFE9E2", padding: 16,
          borderRadius: 12, fontSize: 11.5, overflowX: "auto", lineHeight: 1.6 }}>
{`POST /api/leads        → lead saved (done at step 8)
POST /api/checkout     → Paystack init  (Sprint 2)
POST /webhooks/paystack→ verify + grant (Sprint 2)
   → entitlement(child → course) created
   → account email sent`}
        </pre>
      </div>
    </Page>
  );
}

/* ============================ SUB-COMPONENTS ============================ */
function Logo() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
      <div style={{ width: 34, height: 34, borderRadius: 10, background: T.navy, position: "relative" }}>
        {["#FF6B6B", "#00D4AA", "#FFC93C", "#0066FF", "#FF6B9D"].map((c, i) => {
          const a = (i / 5) * Math.PI * 2;
          return <span key={i} style={{ position: "absolute", width: 8, height: 8, borderRadius: "50%", background: c,
            top: 13 + Math.sin(a) * 8, left: 13 + Math.cos(a) * 8 }} />;
        })}
      </div>
      <span style={{ fontWeight: 800, fontSize: 19, color: T.navy }}>Librancy <span style={{ color: T.teal }}>AI</span></span>
    </div>
  );
}
function DashboardArt({ accent }) {
  return (
    <div style={{ borderRadius: 18, overflow: "hidden", border: `1px solid ${T.line}`,
      background: `linear-gradient(135deg, ${T.navy} 0%, ${T.navy2} 100%)`, padding: 16 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
        <span style={{ color: "#fff", fontSize: 13, fontWeight: 600 }}>Welcome back, Champion 👋</span>
        <span style={{ width: 26, height: 26, borderRadius: "50%", background: accent }} />
      </div>
      <div style={{ background: "rgba(255,255,255,.12)", borderRadius: 10, padding: "9px 12px", marginBottom: 10,
        color: "#fff", fontSize: 12, fontWeight: 600, display: "flex", justifyContent: "space-between" }}>
        <span>Your AI journey</span><span>70%</span>
      </div>
      <div style={{ height: 6, borderRadius: 4, background: "rgba(255,255,255,.18)", marginBottom: 14 }}>
        <div style={{ height: "100%", width: "70%", background: accent, borderRadius: 4 }} />
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8 }}>
        {["Intro to AI", "Prompt basics", "Build a tool"].map((t, i) => (
          <div key={t} style={{ background: "rgba(255,255,255,.1)", borderRadius: 9, padding: "10px 8px" }}>
            <div style={{ width: 18, height: 18, borderRadius: 5, background: ["#FF6B6B", "#00D4AA", "#FFC93C"][i], marginBottom: 8 }} />
            <div style={{ color: "#fff", fontSize: 10.5, fontWeight: 600, lineHeight: 1.2 }}>{t}</div>
          </div>
        ))}
      </div>
    </div>
  );
}
const ShoeArt = () => (
  <svg width="56" height="40" viewBox="0 0 56 40" fill="none" stroke={T.mist} strokeWidth="2">
    <path d="M4 28h40c4 0 8-2 8-4s-6-3-12-6-8-8-12-8-6 6-10 9-12 3-12 7 4 5 10 6z" />
    <path d="M4 28v4h48v-4" />
  </svg>
);
const FutureArt = ({ accent }) => (
  <svg width="56" height="44" viewBox="0 0 56 44" fill="none" stroke={accent} strokeWidth="2" strokeLinecap="round">
    <rect x="10" y="8" width="36" height="24" rx="3" />
    <path d="M22 38h12M28 32v6" />
    <circle cx="28" cy="20" r="5" /><path d="M28 15v-3M28 28v-3M20 20h-3M39 20h-3" />
  </svg>
);
function Label({ children, style }) {
  return <div style={{ fontSize: 13.5, fontWeight: 700, color: T.navy, marginBottom: 8, ...style }}>{children}</div>;
}
const inputStyle = {
  width: "100%", padding: "15px 16px", borderRadius: 14, border: `2px solid ${T.line}`,
  fontSize: 16, fontFamily: FONT, color: T.ink, outline: "none", boxSizing: "border-box", background: T.paper,
};
function Divider({ label }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12, margin: "20px 0 0" }}>
      <span style={{ flex: 1, height: 1, background: T.line }} />
      <span style={{ fontSize: 12.5, fontWeight: 700, color: T.mist }}>{label}</span>
      <span style={{ flex: 1, height: 1, background: T.line }} />
    </div>
  );
}
function Row({ k, val }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", gap: 16, marginBottom: 10 }}>
      <span style={{ fontSize: 13, color: T.mist }}>{k}</span>
      <span style={{ fontSize: 13.5, fontWeight: 600, color: T.navy, textAlign: "right" }}>{val}</span>
    </div>
  );
}
function Perk({ text }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: T.ink }}>
      <span style={{ color: T.good }}>{I.check}</span>{text}
    </div>
  );
}

/* ============================ LOGIC ============================ */
function nameOf(d) {
  const n = (d.childName || "").trim();
  return n.length ? n : "your child";
}
// Real personalization: age band picks the lead course; interests reorder; reason uses actual inputs.
function recommend(v, data) {
  const band = data.ageBand;
  const lead = v.courses.find((c) => c.band === band) || v.courses[0];
  const ordered = [lead, ...v.courses.filter((c) => c.id !== lead.id)];
  const picks = data.interests.slice(0, 3).map((s) => s.toLowerCase());
  const interestBit = picks.length
    ? `${nameOf(data)}’s love of ${listify(data.interests.slice(0, 3))}`
    : `${nameOf(data)}’s profile`;
  const reason = `Based on ${interestBit} and age (${data.ageBand}), we’d start with ${lead.name} — and the bundle covers the full path as ${nameOf(data)} grows.`;
  return { lead, ordered, reason };
}
function listify(arr) {
  const a = arr.map((s) => s.toLowerCase());
  if (a.length === 1) return a[0];
  if (a.length === 2) return `${a[0]} and ${a[1]}`;
  return `${a.slice(0, -1).join(", ")} and ${a[a.length - 1]}`;
}
function selLabel(v, sel) {
  if (!sel) return "";
  if (sel.type === "bundle") return `${v.bundle.name} (${v.bundle.count} courses)`;
  if (sel.type === "course") return v.courses.find((c) => c.id === sel.id)?.name || "";
  return "";
}
// Maps the funnel's local course ids to the backend course slugs.
const SLUG_FOR = { explorer: "explorers", builders: "builders", prompt: "prompt-mastery", founders: "ai-founders" };

// Starts a real Paystack checkout: server prices the SKU, returns a redirect URL.
async function startCheckout(data) {
  const sku = data.selection.type === "bundle" ? "bundle"
    : "course:" + (SLUG_FOR[data.selection.id] || data.selection.id);
  const payload = {
    email: data.email, parentName: data.parentName, phone: data.phone,
    childName: data.childName, ageBand: data.ageBand, interests: data.interests,
    sku, plan: data.splitPay ? "split" : "full", refToken: REF_TOKEN,
  };
  try {
    const res = await fetch(API_BASE + "/api/checkout", {
      method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload),
    });
    const j = await res.json();
    if (j.authorization_url) { window.location.href = j.authorization_url; return; }
    alert(j.error || "Could not start checkout. Please try again.");
  } catch (e) {
    alert("Network error starting checkout. Please try again.");
  }
}

// Posts the lead to the live PHP API (api/index.php → /leads).
function saveLead(data) {
  const lead = {
    childName: data.childName, ageBand: data.ageBand, interests: data.interests,
    experience: data.experience, aspirations: data.aspirations, commitment: data.commitment,
    parentName: data.parentName, email: data.email, phone: data.phone, consentAt: new Date().toISOString(),
    vertical: "ai", utm: REF_TOKEN ? { ref: REF_TOKEN } : {},
  };
  fetch(API_BASE + "/api/leads", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(lead),
  }).catch((e) => console.warn("lead save failed (non-blocking):", e));
  return lead;
}

/* ============================ ENGINE ============================ */
const STEPS = ["hero", "child", "interests", "whatsapp", "experience", "aspirations",
  "reframe", "commitment", "parent", "offer", "checkout", "done"];

function LibrancyFunnel() {
  const v = VERTICALS.ai;
  const [step, setStep] = useState(0);
  const [data, setData] = useState({
    childName: "", ageBand: "", interests: [], experience: "", aspirations: [],
    commitment: 0, parentName: "", email: "", phone: "", consent: false, waConsent: false,
    selection: { type: "bundle" }, splitPay: false,
  });
  const set = (patch) => setData((d) => ({ ...d, ...patch }));
  const topRef = useRef(null);

  // Pull live catalog config from the API; fall back to the embedded config offline.
  useEffect(() => {
    fetch(API_BASE + "/api/verticals/ai")
      .then((r) => (r.ok ? r.json() : null))
      .then((cfg) => { if (cfg && cfg.config && cfg.config.hero) { Object.assign(VERTICALS.ai.hero, cfg.config.hero); } })
      .catch(() => {});
  }, []);

  const go = (dir) => {
    setStep((s) => {
      const nextStep = Math.max(0, Math.min(STEPS.length - 1, s + dir));
      if (dir === 1) {
        trackLead(STEPS[s], data);                            // every milestone is followable
        // Meta funnel events — build audiences + see drop-off in Ads Manager.
        const leaving = STEPS[s];
        if (leaving === "child")     lbrTrack("StartTrial", { content_name: "child_basics" });
        if (leaving === "interests") lbrTrack("Lead", { content_name: "interests_given" });
        if (leaving === "whatsapp" && (data.phone || "").trim()) lbrTrack("Contact", { content_name: "whatsapp_given" });
        if (leaving === "offer")     lbrTrack("AddToCart", { content_name: "reached_pricing" });
      }
      if (STEPS[s] === "parent" && dir === 1) saveLead(data); // full lead record as before
      return nextStep;
    });
  };

  /* Landing-page handoff: /onboarding/?child=Ada&age=10-12 skips the two steps
     the parent already answered on the ad page and drops them straight into the quiz. */
  useEffect(() => {
    const c = (QS.get("child") || "").trim().slice(0, 40);
    const a = (QS.get("age") || "").trim();
    const valid = v.ageBands.some((x) => x.id === a);
    if (c && valid) {
      setData((d) => ({ ...d, childName: c, ageBand: a }));
      setStep(STEPS.indexOf("interests"));
      trackLead("landing", { childName: c, ageBand: a });
    }
  }, []);
  useEffect(() => { topRef.current && topRef.current.scrollTo(0, 0); }, [step]);

  const screen = STEPS[step];
  const showBack = step > 0 && screen !== "done";

  return (
    <Shell wide={screen === "hero"}>
      <style>{`@keyframes fadein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
        input[type=range]{ -webkit-appearance:none; appearance:none; background:transparent; }
        input[type=range]::-webkit-slider-runnable-track{height:6px;border-radius:4px;background:${T.line};}
        input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; appearance:none; width:24px;height:24px;border-radius:50%;background:${T.navy};margin-top:-9px;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.2);}
      `}</style>
      <Progress step={step + 1} total={STEPS.length} />
      <div ref={topRef} style={{ overflowY: "auto", flex: 1, display: "flex", flexDirection: "column" }}>
        {screen !== "hero" && <TopBar onBack={() => go(-1)} showBack={showBack} />}
        {screen === "hero" && <Hero v={v} next={() => go(1)} />}
        {screen === "child" && <ChildBasics v={v} data={data} set={set} next={() => go(1)} />}
        {screen === "interests" && <Interests v={v} data={data} set={set} next={() => go(1)} />}
        {screen === "whatsapp" && <WhatsAppCapture data={data} set={set} next={() => go(1)} />}
        {screen === "experience" && <Experience data={data} set={set} next={() => go(1)} />}
        {screen === "aspirations" && <Aspirations v={v} data={data} set={set} next={() => go(1)} />}
        {screen === "reframe" && <ValueReframe data={data} next={() => go(1)} />}
        {screen === "commitment" && <Commitment data={data} set={set} next={() => go(1)} />}
        {screen === "parent" && <ParentDetails data={data} set={set} next={() => go(1)} />}
        {screen === "offer" && <Offer v={v} data={data} set={set} next={() => go(1)} />}
        {screen === "checkout" && <Checkout v={v} data={data} onPay={() => startCheckout(data)} />}
        {screen === "done" && <Handoff data={data} />}
      </div>
    </Shell>
  );
}

// Mount (no build step — React + Babel load from CDN in index.html).
ReactDOM.createRoot(document.getElementById("root")).render(<LibrancyFunnel />);
