/* Voyage Fleet — New Tenant Wizard (stepper + live provisioning). Exports: NewTenantWizard. */

const { useState: useS_w, useEffect: useEf_w, useRef: useRef_w } = React;

const WIZ_STEPS = [
  { id: "1", label: "Customer" }, { id: "2", label: "Template" }, { id: "3", label: "Region" },
  { id: "4", label: "Cloudflare" }, { id: "5", label: "GitHub" }, { id: "6", label: "Review" },
  { id: "7", label: "Hand off" },
];
const MODULE_DEPS = { appointments: ["notifications"], "reporting-events": ["events", "reporting"], "reporting-finance": ["reporting"], kiosk: ["events"], "int-salesforce": ["integrations"], "int-stripe": ["integrations"], booking: ["notifications"], queuing: ["notifications"] };
const MODULE_CATS = ["Booking", "Events", "Communications", "Reporting", "Integrations"];

function Stepper({ current }) {
  const ci = WIZ_STEPS.findIndex(s => s.id === current);
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 0, padding: "0 4px" }}>
      {WIZ_STEPS.map((s, i) => {
        const done = i < ci, active = i === ci;
        return (
          <React.Fragment key={s.id}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span style={{ width: 26, height: 26, borderRadius: 999, display: "grid", placeItems: "center", flexShrink: 0, fontSize: 12, fontWeight: 700, fontFamily: "var(--jrni-font-family-mono)",
                background: done ? "var(--jrni-color-primary-1)" : active ? "var(--jrni-color-primary-1)" : "white",
                color: done || active ? "white" : "var(--jrni-color-neutral-3)",
                border: `1px solid ${done || active ? "var(--jrni-color-primary-1)" : "var(--jrni-color-neutral-4)"}` }}>
                {done ? <Icons.Check size={13} /> : s.id}
              </span>
              <span style={{ fontSize: 12.5, fontWeight: active ? 600 : 500, color: active ? "var(--jrni-color-neutral-1)" : "var(--jrni-color-text-soft)", whiteSpace: "nowrap" }}>{s.label}</span>
            </div>
            {i < WIZ_STEPS.length - 1 ? <span style={{ flex: 1, height: 1, background: done ? "var(--jrni-color-primary-1)" : "var(--jrni-color-surface-border)", margin: "0 12px", minWidth: 16 }} /> : null}
          </React.Fragment>
        );
      })}
    </div>
  );
}

function StarterCard({ seam, selected, recommended, onClick }) {
  return (
    <button onClick={onClick} style={{
      textAlign: "left", cursor: "pointer", padding: 16, borderRadius: 8, position: "relative",
      background: selected ? "var(--jrni-color-primary-4)" : "white",
      border: `${selected ? 2 : 1}px solid ${selected ? "var(--jrni-color-primary-1)" : "var(--jrni-color-surface-border)"}`,
      margin: selected ? 0 : 1, fontFamily: "var(--jrni-font-family-sans)",
    }}>
      {recommended ? <span style={{ position: "absolute", top: 12, right: 12, fontSize: 10, fontWeight: 700, color: "var(--jrni-color-primary-1)", background: "white", border: "1px solid var(--jrni-color-primary-2)", borderRadius: 4, padding: "2px 7px", letterSpacing: 0.03 }}>RECOMMENDED</span> : null}
      <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
        <span style={{ width: 30, height: 30, borderRadius: 7, background: "var(--jrni-color-primary-3)", color: "var(--jrni-color-primary-1)", display: "grid", placeItems: "center" }}><Icons.Layers size={16} /></span>
        <div><div style={{ fontSize: 14, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>{seam.name}</div><div style={{ fontSize: 11, color: "var(--jrni-color-text-soft)" }}>Starter template</div></div>
      </div>
      <div style={{ fontSize: 12.5, color: "var(--jrni-color-text-soft)", marginTop: 10, lineHeight: 1.45 }}>{seam.desc}</div>
      <div style={{ fontSize: 11.5, color: "var(--jrni-color-neutral-3)", marginTop: 12 }}>{seam.tenants} tenants started from this template</div>
    </button>
  );
}

function Row({ children, cols = "1fr 1fr" }) { return <div style={{ display: "grid", gridTemplateColumns: cols, gap: 14 }}>{children}</div>; }
function ReviewRow({ k, v }) { return <div style={{ display: "flex", justifyContent: "space-between", gap: 12, padding: "9px 0", borderBottom: "1px solid var(--jrni-color-surface-border)", fontSize: 13 }}><span style={{ color: "var(--jrni-color-text-soft)" }}>{k}</span><span style={{ color: "var(--jrni-color-neutral-1)", fontWeight: 500, textAlign: "right", fontFamily: /[\/@\.]/.test(String(v)) ? "var(--jrni-font-family-mono)" : "inherit", fontSize: 12.5 }}>{v}</span></div>; }

function NewTenantWizard({ params }) {
  const step = params.step || "1";
  const [form, setForm] = useS_w({ name: "Ashford University", slug: "ashford", contact: "Dana Pryce", email: "dana@ashford.edu", industry: "Education", env: "dev", seam: "events-suite", region: "EU-West", account: "Voyage (production)", repoName: "voyage-ashford", visibility: "private", ack1: false, ack2: false, customModules: ["appointments", "notifications"] });
  const upd = patch => setForm(f => ({ ...f, ...patch }));
  const toggleModule = (id) => setForm(f => {
    let set = new Set(f.customModules);
    if (set.has(id)) { set.delete(id); }
    else { set.add(id); (MODULE_DEPS[id] || []).forEach(d => set.add(d)); }
    return { ...f, customModules: [...set] };
  });
  const go = s => navigate("/new", { step: s });
  const seam = window.FLEET.SEAMS.find(s => s.id === form.seam) || window.FLEET.SEAMS[0];

  const footer = (back, next, nextLabel, nextDisabled, primary) => (
    <div style={{ flexShrink: 0, borderTop: "1px solid var(--jrni-color-surface-border)", background: "white", padding: "12px 24px", display: "flex", alignItems: "center", gap: 8 }}>
      {back ? <Button variant="tertiary" icon={<Icons.Chevron dir="left" size={12} />} onClick={() => go(back)}>Back</Button> : null}
      <button onClick={() => navigate("/")} style={{ background: "none", border: "none", color: "var(--jrni-color-text-soft)", fontSize: 13, fontWeight: 500, cursor: "pointer", fontFamily: "var(--jrni-font-family-sans)" }}>Cancel</button>
      <div style={{ flex: 1 }} />
      {next ? <Button variant={primary ? "primary" : "primary"} icon={primary ? <Icons.Rocket size={13} /> : null} iconRight={!primary ? <Icons.Chevron dir="right" size={12} color="white" /> : null} disabled={nextDisabled} onClick={() => go(next)}>{nextLabel || "Next"}</Button> : null}
    </div>
  );

  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div style={{ flexShrink: 0, padding: "18px 24px 16px", borderBottom: "1px solid var(--jrni-color-surface-border)", background: "white" }}>
        <h1 style={{ margin: "0 0 14px", fontSize: 20, fontWeight: 700, color: "var(--jrni-color-neutral-1)", letterSpacing: -0.3 }}>New tenant</h1>
        <Stepper current={step === "2b" ? "2" : step} />
      </div>

      <div style={{ flex: 1, overflowY: "auto", padding: "24px", background: "var(--jrni-color-surface-canvas)" }}>
        <div style={{ maxWidth: step === "2" ? 920 : 720, margin: "0 auto" }}>

          {step === "1" && (
            <Card padding={22}>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Customer info</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>Who is this deployment for? The industry tag drives the recommended starter template.</p>
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <Row>
                  <Field label="Customer name"><Input value={form.name} onChange={e => upd({ name: e.target.value })} /></Field>
                  <Field label="Tenant slug" hint="Checked against existing tenants — available."><Input value={form.slug} onChange={e => upd({ slug: e.target.value })} style={{ fontFamily: "var(--jrni-font-family-mono)" }} /></Field>
                </Row>
                <Row>
                  <Field label="Primary contact"><Input value={form.contact} onChange={e => upd({ contact: e.target.value })} /></Field>
                  <Field label="Contact email"><Input value={form.email} onChange={e => upd({ email: e.target.value })} /></Field>
                </Row>
                <Row>
                  <Field label="Industry / use-case"><Select value={form.industry} onChange={v => upd({ industry: v })} options={["Education", "Financial services", "Hospitality", "Retail", "Healthcare", "Events"].map(o => ({ value: o, label: o }))} /></Field>
                  <Field label="Environment">
                    <div style={{ display: "flex", gap: 16, paddingTop: 8 }}>
                      <Radio checked={form.env === "dev"} onChange={() => upd({ env: "dev" })} label="Dev (promote to prod later)" />
                      <Radio checked={form.env === "prod"} onChange={() => upd({ env: "prod" })} label="Production" />
                    </div>
                  </Field>
                </Row>
              </div>
            </Card>
          )}

          {step === "2" && (
            <div>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Choose a starter template</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>A starter template bundles a set of components, integrations and Cloudflare defaults. Recommended for <b>{form.industry}</b>: Events Suite. Prefer to hand-pick? Start from a custom composition below.</p>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12 }}>
                {window.FLEET.SEAMS.map(s => <StarterCard key={s.id} seam={s} selected={form.seam === s.id} recommended={s.id === "events-suite"} onClick={() => upd({ seam: s.id })} />)}
              </div>
              <button onClick={() => go("2b")} style={{ marginTop: 16, background: "none", border: "none", color: "var(--jrni-color-primary-1)", fontSize: 13, fontWeight: 600, cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 6 }}><Icons.Plus size={13} />Start from custom composition</button>
            </div>
          )}

          {step === "2b" && (() => {
            const sel = new Set(form.customModules);
            const conflicts = form.customModules.filter(id => (MODULE_DEPS[id] || []).some(d => !sel.has(d)));
            const n = form.customModules.length;
            const res = { d1: Math.max(1, Math.ceil(n / 2)), kv: n, r2: form.customModules.filter(m => ["booking", "kiosk", "reporting-events", "int-stripe"].includes(m)).length, queues: Math.max(1, Math.ceil(n / 3)), do: form.customModules.filter(m => ["queuing"].includes(m)).length };
            return (
              <div>
                <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
                  <button onClick={() => go("2")} style={{ background: "none", border: "none", color: "var(--jrni-color-primary-1)", fontSize: 12.5, fontWeight: 600, cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 4 }}><Icons.Chevron dir="left" size={11} />Back to seams</button>
                </div>
                <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Custom composition</h2>
                <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>Pick the modules this tenant runs. Module source isn't edited here — this is a selection the provisioning pipeline consumes.</p>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 280px", gap: 16, alignItems: "start" }}>
                  <Card padding={18}>
                    {MODULE_CATS.map(cat => {
                      const mods = window.FLEET.MODULES.filter(m => m.cat === cat);
                      if (!mods.length) return null;
                      return (
                        <div key={cat} style={{ marginBottom: 16 }}>
                          <div style={{ fontSize: 10.5, fontWeight: 700, color: "var(--jrni-color-text-soft)", textTransform: "uppercase", letterSpacing: 0.05, marginBottom: 8 }}>{cat}</div>
                          {mods.map(m => {
                            const checked = sel.has(m.id);
                            const isDep = !checked && form.customModules.some(s => (MODULE_DEPS[s] || []).includes(m.id));
                            return (
                              <div key={m.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "7px 0" }}>
                                <Checkbox checked={checked} onChange={() => toggleModule(m.id)} />
                                <Tooltip label={m.desc} width={220}><span style={{ fontFamily: "var(--jrni-font-family-mono)", fontSize: 12.5, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>{m.name}</span></Tooltip>
                                <Mono>{`^${m.latest}`}</Mono>
                                {checked && (MODULE_DEPS[m.id] || []).length ? <span style={{ fontSize: 10.5, color: "var(--jrni-color-text-soft)" }}>+ deps</span> : null}
                                <div style={{ flex: 1 }} />
                                {isDep ? <Pill tone="primary">auto-added dep</Pill> : null}
                              </div>
                            );
                          })}
                        </div>
                      );
                    })}
                  </Card>
                  <Card padding={16} style={{ position: "sticky", top: 0 }}>
                    <SectionLabel>Composition summary</SectionLabel>
                    <div style={{ fontSize: 26, fontWeight: 700, color: "var(--jrni-color-neutral-1)", marginTop: 6 }}>{n}<span style={{ fontSize: 13, fontWeight: 500, color: "var(--jrni-color-text-soft)" }}> modules</span></div>
                    <div style={{ marginTop: 12 }}>
                      <div style={subLbl}>Cloudflare footprint</div>
                      <div style={{ display: "flex", flexWrap: "wrap", gap: 5, marginTop: 6 }}>
                        {[["D1", res.d1], ["KV", res.kv], ["R2", res.r2], ["Queue", res.queues], ["DO", res.do]].map(b => <span key={b[0]} style={{ fontSize: 11, fontFamily: "var(--jrni-font-family-mono)", background: "var(--jrni-color-neutral-6)", border: "1px solid var(--jrni-color-surface-border)", borderRadius: 4, padding: "2px 7px", color: "var(--jrni-color-neutral-2)" }}>{b[0]} {b[1]}</span>)}
                      </div>
                    </div>
                    <div style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--jrni-color-surface-border)", display: "flex", justifyContent: "space-between" }}><span style={{ fontSize: 13, color: "var(--jrni-color-text-soft)" }}>Est. monthly cost</span><span style={{ fontSize: 14, fontWeight: 700, color: "var(--jrni-color-neutral-1)" }}>${8 + n * 6} / mo</span></div>
                    {conflicts.length ? <div style={{ marginTop: 12, padding: "9px 11px", background: "var(--jrni-color-status-warning-bg)", borderRadius: 6, fontSize: 11.5, color: "var(--jrni-color-semantic-orange-1)", display: "flex", gap: 6 }}><Icons.Warning size={13} />Unmet dependency — re-check to resolve.</div> : <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--jrni-color-semantic-green-1)", display: "flex", alignItems: "center", gap: 5 }}><Icons.Check size={12} />Dependencies satisfied</div>}
                  </Card>
                </div>
              </div>
            );
          })()}

          {step === "3" && (
            <Card padding={22}>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Region &amp; residency</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>D1, R2, and Workers will be pinned to this region.</p>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
                {window.FLEET.REGIONS.map(r => (
                  <button key={r} onClick={() => upd({ region: r })} style={{ textAlign: "left", padding: 14, borderRadius: 8, cursor: "pointer", background: form.region === r ? "var(--jrni-color-primary-4)" : "white", border: `${form.region === r ? 2 : 1}px solid ${form.region === r ? "var(--jrni-color-primary-1)" : "var(--jrni-color-surface-border)"}`, margin: form.region === r ? 0 : 1, display: "flex", alignItems: "center", gap: 10, fontFamily: "var(--jrni-font-family-sans)" }}>
                    <Icons.Region size={18} color={form.region === r ? "var(--jrni-color-primary-1)" : "var(--jrni-color-text-soft)"} />
                    <div><div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>{r}</div><div style={{ fontSize: 11.5, color: "var(--jrni-color-text-soft)" }}>Cloudflare {r} regions</div></div>
                  </button>
                ))}
              </div>
              {form.region === "EU-West" ? (
                <div style={{ display: "flex", gap: 10, padding: "12px 14px", marginTop: 14, background: "var(--jrni-color-status-info-bg)", borderRadius: 8 }}>
                  <Icons.Info size={16} color="var(--jrni-color-semantic-blue-1)" />
                  <span style={{ fontSize: 12.5, color: "var(--jrni-color-neutral-1)" }}><b>EU data residency.</b> D1 + R2 + Workers will all be pinned to EU regions. No data leaves the EU.</span>
                </div>
              ) : null}
            </Card>
          )}

          {step === "4" && (
            <Card padding={22}>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Cloudflare binding</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>Which Cloudflare account does this tenant deploy into?</p>
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <Field label="Cloudflare account"><Select value={form.account} onChange={v => upd({ account: v })} options={["Voyage (production)", "Voyage (staging)", "Customer-hosted (advanced)"].map(o => ({ value: o, label: o }))} /></Field>
                <Field label="DNS zone" hint="Auto-suggested from slug."><Input value={`${form.slug}.vxge.porivo.com`} readOnly style={{ fontFamily: "var(--jrni-font-family-mono)" }} /></Field>
                <Field label="Custom domain" optional hint="Post-launch task in v1."><Input placeholder="events.ashford.edu" /></Field>
              </div>
            </Card>
          )}

          {step === "5" && (
            <Card padding={22}>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>GitHub repo setup</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>A new repo holds this tenant's deployment artifact.</p>
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <Row>
                  <Field label="Target org"><Select value="ryanbreen" onChange={() => {}} options={[{ value: "ryanbreen", label: "ryanbreen" }, { value: "voyage-fleet", label: "voyage-fleet" }]} /></Field>
                  <Field label="Repo name"><Input value={form.repoName} onChange={e => upd({ repoName: e.target.value })} style={{ fontFamily: "var(--jrni-font-family-mono)" }} /></Field>
                </Row>
                <Row>
                  <Field label="Visibility"><Select value={form.visibility} onChange={v => upd({ visibility: v })} options={[{ value: "private", label: "Private" }, { value: "internal", label: "Internal" }]} /></Field>
                  <Field label="Default branch"><Input value="main" readOnly style={{ fontFamily: "var(--jrni-font-family-mono)" }} /></Field>
                </Row>
                <div style={{ padding: 14, background: "var(--jrni-color-surface-card-soft)", border: "1px solid var(--jrni-color-surface-border)", borderRadius: 8 }}>
                  <div style={subLbl}>Files committed on creation</div>
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginTop: 6 }}>
                    {["package.json", "wrangler.toml", ".github/workflows/", "overrides/", "brand-tokens.json", "README.md"].map(f => <Mono key={f} color="var(--jrni-color-neutral-1)">{f}</Mono>)}
                  </div>
                </div>
              </div>
            </Card>
          )}

          {step === "6" && (
            <Card padding={22}>
              <h2 style={{ margin: "0 0 4px", fontSize: 17, fontWeight: 600, color: "var(--jrni-color-neutral-1)" }}>Review</h2>
              <p style={{ margin: "0 0 18px", fontSize: 13, color: "var(--jrni-color-text-soft)" }}>Everything the provisioning spec will create. The next step hands this to Claude Code to run.</p>
              <Row cols="1fr 1fr">
                <div>
                  <div style={subLbl}>GitHub</div>
                  <ReviewRow k="Repo" v={`ryanbreen/${form.repoName}`} />
                  <ReviewRow k="Commit" v="chore: scaffold tenant" />
                  <div style={{ ...subLbl, marginTop: 16 }}>Voyage modules</div>
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 4, padding: "9px 0" }}>{seam.modules.map(m => <Mono key={m} color="var(--jrni-color-neutral-1)">{m}</Mono>)}</div>
                  <ReviewRow k="Started from" v={seam.name} />
                  <ReviewRow k="Migrations" v={`${seam.modules.length * 3} initial`} />
                </div>
                <div>
                  <div style={subLbl}>Cloudflare resources</div>
                  <ReviewRow k="D1 databases" v={seam.res.d1} />
                  <ReviewRow k="KV namespaces" v={seam.res.kv} />
                  <ReviewRow k="R2 buckets" v={seam.res.r2} />
                  <ReviewRow k="Queue bindings" v={seam.res.queues} />
                  <ReviewRow k="DO namespaces" v={seam.res.do} />
                  <div style={{ ...subLbl, marginTop: 16 }}>Estimate</div>
                  <ReviewRow k="Provisioning time" v="~6 min" />
                  <ReviewRow k="Est. monthly cost" v="$42 / mo" />
                </div>
              </Row>
              <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: 18, padding: 14, background: "var(--jrni-color-surface-card-soft)", borderRadius: 8 }}>
                <Checkbox checked={form.ack1} onChange={v => upd({ ack1: v })} label="I have reviewed the resource list." />
                <Checkbox checked={form.ack2} onChange={v => upd({ ack2: v })} label={`I have authority to provision in the ${form.account} Cloudflare account.`} />
              </div>
            </Card>
          )}

          {step === "7" && (() => {
            return (
              <Card padding={26} style={{ textAlign: "center" }}>
                <span style={{ width: 52, height: 52, borderRadius: 12, background: "var(--jrni-color-primary-1)", color: "white", display: "grid", placeItems: "center", margin: "0 auto 14px" }}><Icons.GitPr size={26} /></span>
                <h2 style={{ margin: "0 0 4px", fontSize: 19, fontWeight: 700, color: "var(--jrni-color-neutral-1)" }}>Open the provisioning PR</h2>
                <p style={{ margin: "0 0 18px", fontSize: 13.5, color: "var(--jrni-color-text-soft)", maxWidth: 470, marginLeft: "auto", marginRight: "auto", lineHeight: 1.5 }}>This files a PR that creates <Mono>ryanbreen/{form.repoName}</Mono> with the scaffold + Cloudflare config. Merging it wakes GitHub Actions, which provisions resources and deploys. You watch the result on the tenant's CI/CD tab.</p>
                <div style={{ maxWidth: 480, margin: "0 auto", textAlign: "left" }}>
                  <div style={{ display: "flex", gap: 8 }}>
                    <Button variant="primary" icon={<Icons.GitPr size={13} />} onClick={() => navigate("/tenant", { slug: form.slug })}>Open provisioning PR</Button>
                    <Button variant="secondary" icon={<Icons.Gauge size={13} />} onClick={() => navigate("/")}>Back to Fleet Overview</Button>
                  </div>
                  <div style={{ marginTop: 18 }}>
                    <div style={subLbl}>What the pipeline does on merge</div>
                    {["Create the GitHub repo + commit scaffold", "Provision Cloudflare resources", "Run initial migrations + deploy", "Return live URLs + first-login credentials"].map((s, i) => (
                      <div key={i} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 0", fontSize: 13, color: "var(--jrni-color-neutral-1)" }}><span style={{ width: 18, height: 18, borderRadius: 999, background: "var(--jrni-color-neutral-6)", color: "var(--jrni-color-text-soft)", display: "grid", placeItems: "center", fontSize: 10, fontWeight: 700, flexShrink: 0 }}>{i + 1}</span>{s}</div>
                    ))}
                  </div>
                  <div style={{ marginTop: 14, fontSize: 12, color: "var(--jrni-color-text-soft)", lineHeight: 1.5, padding: "10px 12px", background: "var(--jrni-color-surface-card-soft)", borderRadius: 8 }}>Once the PR is open, <Mono>{form.slug}</Mono> appears in the fleet with a <b>provisioning</b> status. For a staged rollout or anything more complex, drive it from a Claude Code session.</div>
                </div>
              </Card>
            );
          })()}
        </div>
      </div>

      {/* sticky bottom bar */}
      {step === "1" && footer(null, "2")}
      {step === "2" && footer("1", "3")}
      {step === "2b" && footer("2", "3")}
      {step === "3" && footer("2", "4")}
      {step === "4" && footer("3", "5")}
      {step === "5" && footer("4", "6")}
      {step === "6" && footer("5", "7", "Continue to hand-off", !(form.ack1 && form.ack2))}
    </div>
  );
}

window.NewTenantWizard = NewTenantWizard;
