/* global React, ReactDOM, TweaksPanel, useTweaks, TweakSection, TweakText, TweakSlider, TweakToggle */

// ============================================================
// Camp Coyote · Inscripción multistep — v2 con info real
// 4 pasos: programa → participante/tutor → salud/permisos → revisar/anticipo
// Anticipo $800 MXN (no reembolsable) · Saldo en efectivo el día del camp
// ============================================================

const { useState, useEffect, useMemo, useRef } = React;

const ANTICIPO = 800;

// ============================================================
// Google Sheets · fuente dinámica de fechas y cupos
// ============================================================
// Publica tu hoja como CSV: Archivo → Compartir → Publicar en la web →
// (Pestaña) · Valores separados por comas (.csv) · Publicar.
// Pega aquí la URL que te da Google. Columnas esperadas (en este orden):
//
//   id | title | range | duration | ages | capacity | booked | price | preventa | preventaDate | state | descriptor
//
// state ∈ { ok, waitlist, full }.  Si la hoja no carga, usamos el fallback.
//
// La URL se puede cambiar desde el panel de Tweaks sin tocar código.
const DEFAULT_SHEET_CSV =
"https://docs.google.com/spreadsheets/d/e/2PACX-1vREEMPLAZAR_CON_TU_ID/pub?gid=0&single=true&output=csv";

const FALLBACK_PROGRAMS = [
{
  id: "verano-pro",
  title: "Verano Pro",
  range: "24 – 31 Julio 2026",
  duration: "8 días · 7 noches",
  ages: "9 – 17 años",
  capacity: 100,
  booked: 71,
  price: 7100,
  preventa: 6035,
  preventaDate: "20 mayo 2026",
  preventaPassed: true,
  descriptor: "Más reto físico, retos extendidos, búsqueda nocturna, noche disco.",
  state: "ok"
},
{
  id: "verano-basic",
  title: "Verano Basic",
  range: "3 – 8 Agosto 2026",
  duration: "6 días · 5 noches",
  ages: "6 – 14 años",
  capacity: 100,
  booked: 64,
  price: 5300,
  preventa: 4505,
  preventaDate: "20 mayo 2026",
  preventaPassed: true,
  descriptor: "Primera vez o niños más pequeños. Pista comando, polvos holi, noche disco.",
  state: "ok",
  featured: true
},
{
  id: "pascua",
  title: "Pascua 2027",
  range: "Marzo / Abril 2027 · TBD",
  duration: "6 días · 5 noches",
  ages: "6 – 14 años",
  capacity: 100,
  booked: 0,
  price: 5300,
  preventa: 4505,
  preventaDate: "—",
  descriptor: "Mini olimpiadas, noche de feria, búsqueda de huevos, talleres.",
  state: "waitlist"
},
{
  id: "invierno",
  title: "Invierno 2026",
  range: "Diciembre 2026 · TBD",
  duration: "3 días · 2 noches",
  ages: "6 – 14 años",
  capacity: 50,
  booked: 0,
  price: 2600,
  preventa: 2210,
  preventaDate: "—",
  descriptor: "Aventura corta con espíritu decembrino. Tiro con arco, caballos.",
  state: "waitlist"
}];


// ============================================================
// CSV parser ligero (sin libs) — maneja comillas y comas internas
// ============================================================
function parseCSV(text) {
  const rows = [];
  let row = [],cell = "",inQ = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i],n = text[i + 1];
    if (inQ) {
      if (c === '"' && n === '"') {cell += '"';i++;} else
      if (c === '"') inQ = false;else
      cell += c;
    } else {
      if (c === '"') inQ = true;else
      if (c === ",") {row.push(cell);cell = "";} else
      if (c === "\n") {row.push(cell);rows.push(row);row = [];cell = "";} else
      if (c === "\r") {/* skip */} else
      cell += c;
    }
  }
  if (cell !== "" || row.length) {row.push(cell);rows.push(row);}
  return rows.filter((r) => r.length > 1 || r[0] && r[0].trim() !== "");
}

function rowsToPrograms(rows) {
  if (!rows || rows.length < 2) return null;
  const header = rows[0].map((h) => h.trim().toLowerCase());
  const idx = (k) => header.indexOf(k);
  // Convierte "7,100.00" → 7100. Acepta strings con comas de miles, espacios y $.
  const num = (raw) => {
    if (raw == null) return 0;
    const cleaned = String(raw).replace(/[$\s,]/g, "");
    const n = parseFloat(cleaned);
    return Number.isFinite(n) ? n : 0;
  };
  const out = [];
  for (let r = 1; r < rows.length; r++) {
    const v = rows[r];
    if (!v[idx("id")]) continue;
    const cap = num(v[idx("capacity")]) || 100;
    const booked = num(v[idx("booked")]);
    const rawState = (v[idx("state")] || "").trim().toLowerCase();
    // Sólo "waitlist" y "full" son estados especiales; cualquier otra cosa = ok
    const state = rawState === "waitlist" || rawState === "full" ? rawState : "ok";
    out.push({
      id: v[idx("id")].trim(),
      title: v[idx("title")] || "",
      range: v[idx("range")] || "",
      duration: v[idx("duration")] || "",
      ages: v[idx("ages")] || "",
      capacity: cap,
      booked: booked,
      price: num(v[idx("price")]),
      preventa: num(v[idx("preventa")]),
      preventaDate: v[idx("preventadate")] || "—",
      preventaPassed: (v[idx("preventadate")] || "").toLowerCase().includes("pasó"),
      descriptor: v[idx("descriptor")] || "",
      state: state,
      featured: (v[idx("id")] || "").includes("basic")
    });
  }
  return out.length ? out : null;
}

const STEPS = [
{ num: "01", nm: "Programa", sub: "Elige campamento" },
{ num: "02", nm: "Participante", sub: "Datos + tutor" },
{ num: "03", nm: "Salud", sub: "Permisos + médico" },
{ num: "04", nm: "Anticipo", sub: "Revisar + apartar" }];


const ALLERGY_OPTS = ["Frutos secos", "Lácteos", "Gluten", "Mariscos", "Polen", "Picaduras de abeja"];

const STORAGE_KEY = "cc-enroll-v2";

function loadStored() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) return JSON.parse(raw);
  } catch (e) {}
  return null;
}

function defaultState() {
  const params = new URLSearchParams(window.location.search);
  const programId = params.get("program") || "verano-basic";
  return {
    step: 0,
    programId,
    waitlist: params.get("waitlist") === "1",
    discountType: "none", // 'none' | 'preventa' | 'siblings2' | 'siblings3' | 'cousins3' | 'returning'
    // child
    childFirstName: "",
    childLastName: "",
    childBirthdate: "",
    childSchool: "",
    childGrade: "",
    childGender: "",
    shirtSize: "10",
    previousVisits: "Nunca", // del form original: nunca / una vez / dos veces / 3 / 4 / 5+
    // tutor
    parent1Name: "",
    parent1Rel: "Madre",
    parent1Email: "",
    parent1Phone: "",
    parent2Name: "",
    parent2Phone: "",
    city: "",
    address: "",
    // emergency
    emergencyName: "",
    emergencyRel: "",
    emergencyPhone: "",
    pickupAuth: "",
    // health
    bloodType: "",
    allergies: [],
    allergyDetail: "",
    medications: "",
    conditions: "",
    insurance: "",
    doctorName: "",
    doctorPhone: "",
    diet: "ninguna", // 'ninguna' | 'vegetariana' | 'vegana' | 'sin gluten' | 'otra'
    dietDetail: "",
    // consents
    consentMed: false,
    consentPhotos: false,
    consentResponsiva: false,
    consentPolicies: false,
    consentDeposit: false,
    // payment (only $800 anticipo)
    payGateway: "card", // 'card' | 'spei' | 'cash'
    cardName: "",
    cardNum: "",
    cardExp: "",
    cardCvv: "",
    // notas
    notes: ""
  };
}

// ============================================================
// Pricing engine
// ============================================================
function calcPrice(s, programs) {
  const list = programs && programs.length ? programs : FALLBACK_PROGRAMS;
  const prog = list.find((p) => p.id === s.programId) || list[1] || list[0];
  const base = prog.price;
  let total = base;
  let discountLine = null;

  // Apply ONE discount only (per policies)
  switch (s.discountType) {
    case "preventa":
      total = prog.preventa;
      discountLine = { lbl: "Preventa (−15%)", amt: prog.preventa - base };
      break;
    case "siblings2":{
        const subtotal = Math.round(base * 2 * 0.9); // both kids at -10%
        total = subtotal; // this row represents per-family total
        discountLine = { lbl: "2 hermanos · total familia", amt: subtotal - base * 2, totalRow: true };
        break;
      }
    case "siblings3":{
        const subtotal = Math.round(base * 3 * 0.85);
        total = subtotal;
        discountLine = { lbl: "3 hermanos · total familia", amt: subtotal - base * 3, totalRow: true };
        break;
      }
    case "cousins3":
    case "returning":{
        total = Math.round(base * 0.95);
        discountLine = { lbl: s.discountType === "cousins3" ? "3+ primos (−5%)" : "Repetidor (−5%)", amt: total - base };
        break;
      }
    default:
      break;
  }

  const dueNow = ANTICIPO; // siempre $800 anticipo
  const dueAtCamp = Math.max(0, total - dueNow);

  return { prog, base, total, dueNow, dueAtCamp, discountLine };
}

// ============================================================
// App
// ============================================================
function EnrollApp() {
  const ENROLL_TWEAKS = /*EDITMODE-BEGIN*/{
    "anticipo_amount": "800",
    "show_card_fields": true,
    "default_gateway": "card",
    "sheet_csv_url": "https://docs.google.com/spreadsheets/d/e/2PACX-1vQmamoxIz52nN7VHT4ABvzFkF0NF2swOSttUOSxPB74rMk8O5QOZhnzq8lPru6nUK05qvr9sl-D8L4K/pub?gid=1739074332&single=true&output=csv",
    "use_sheet": true
  } /*EDITMODE-END*/;

  const [tw, setTweak] = useTweaks(ENROLL_TWEAKS);
  const [s, setS] = useState(() => loadStored() || defaultState());
  const [programs, setPrograms] = useState(FALLBACK_PROGRAMS);
  const [sheetStatus, setSheetStatus] = useState("fallback"); // 'fallback' | 'loading' | 'live' | 'error'
  const [payProcessing, setPayProcessing] = useState(null); // null | { step:0..3, gateway, amount }

  // Cargar programas desde Google Sheets si el tweak está activo
  useEffect(() => {
    if (!tw.use_sheet) {setSheetStatus("fallback");setPrograms(FALLBACK_PROGRAMS);return;}
    const url = tw.sheet_csv_url || DEFAULT_SHEET_CSV;
    if (!url || url.includes("REEMPLAZAR_CON_TU_ID")) {setSheetStatus("fallback");return;}
    setSheetStatus("loading");
    fetch(url, { cache: "no-store" }).
    then((r) => {if (!r.ok) throw new Error("HTTP " + r.status);return r.text();}).
    then((txt) => {
      const parsed = rowsToPrograms(parseCSV(txt));
      if (parsed) {setPrograms(parsed);setSheetStatus("live");} else
      {setSheetStatus("error");}
    }).
    catch(() => setSheetStatus("error"));
  }, [tw.use_sheet, tw.sheet_csv_url]);

  useEffect(() => {
    try {localStorage.setItem(STORAGE_KEY, JSON.stringify(s));} catch (e) {}
  }, [s]);

  const set = (patch) => setS((cur) => ({ ...cur, ...patch }));
  const price = calcPrice(s, programs);
  const program = price.prog;
  const isWaitlist = program.state === "waitlist" || s.waitlist;

  function next() {
    if (!canAdvance()) return;
    setS((cur) => ({ ...cur, step: Math.min(STEPS.length - 1, cur.step + 1) }));
    window.scrollTo({ top: 0, behavior: "smooth" });
  }
  function back() {
    setS((cur) => ({ ...cur, step: Math.max(0, cur.step - 1) }));
    window.scrollTo({ top: 0, behavior: "smooth" });
  }
  function goto(i) {
    if (i > s.step) return;
    setS((cur) => ({ ...cur, step: i }));
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  function canAdvance() {
    if (s.step === 0) return !!s.programId;
    if (s.step === 1) return !!s.childFirstName && !!s.childLastName && !!s.childBirthdate &&
    !!s.parent1Name && !!s.parent1Email && !!s.parent1Phone;
    if (s.step === 2) return s.consentMed && s.consentResponsiva && !!s.emergencyName && !!s.emergencyPhone;
    if (s.step === 3) {
      const base = s.consentPolicies && s.consentDeposit;
      if (s.payGateway === "card") return base && !!s.cardName;
      return base;
    }
    return true;
  }

  return (
    <main>
      <div className="enr-shell">
        <div>
          <header className="enr-head">
            <div className="crumb">
              <a href="/">← Volver al sitio</a>
              <span style={{ color: "var(--cc-line)" }}>•</span>
              <span>{isWaitlist ? "Lista de espera" : "Inscripción 2026"}</span>
            </div>
            <h1>
              {s.step === 0 && (isWaitlist ? <>Únete a la <em>lista de espera.</em></> : <>Elige el <em>campamento.</em></>)}
              {s.step === 1 && <>Cuéntanos del <em>aventurero.</em></>}
              {s.step === 2 && <>Salud y <em>permisos.</em></>}
              {s.step === 3 && (isWaitlist ? <>Confirma tu <em>lugar en lista.</em></> : <>Revisa y <em>aparta con $800.</em></>)}
            </h1>
            <p className="lede">
              {s.step === 0 && "Cupos por orden de pago, sin excepción. Solo aparta tu lugar con $800 MXN — el saldo se paga en efectivo el día del campamento."}
              {s.step === 1 && "Datos del participante y del padre o tutor principal. Necesitamos un correo y WhatsApp activos para mandarte la confirmación y la responsiva."}
              {s.step === 2 && "Información médica y consentimientos. Solo la verán la enfermera y la dirección del campamento. Confidencial."}
              {s.step === 3 && (isWaitlist ?
              "Sin pago en este momento. Te avisaremos por correo cuando se publiquen fechas y precios oficiales para que confirmes el lugar." :
              "Anticipo de $800 MXN (no reembolsable) para apartar el lugar. Te llega comprobante al instante y la responsiva por correo para firmar.")}
            </p>
          </header>

          <div className="stepper">
            {STEPS.map((st, i) =>
            <div
              key={i}
              className={`st ${i === s.step ? "is-active" : ""} ${i < s.step ? "is-done is-clickable" : ""}`}
              onClick={() => goto(i)}>
              
                <span className="num">{i < s.step ? "✓" : st.num}</span>
                <span className="lbl">
                  <span className="nm">{st.nm}</span>
                  <span className="sub">{st.sub}</span>
                </span>
              </div>
            )}
          </div>

          <div className="enr-card">
            {s.step === 0 && <StepProgram s={s} set={set} programs={programs} sheetStatus={sheetStatus} />}
            {s.step === 1 && <StepChild s={s} set={set} />}
            {s.step === 2 && <StepHealth s={s} set={set} />}
            {s.step === 3 && <StepPay s={s} set={set} price={price} goto={goto} isWaitlist={isWaitlist} />}

            <div className="enr-nav">
              <div>
                {s.step > 0 &&
                <button className="btn ghost" onClick={back}>
                    ← Atrás
                  </button>
                }
              </div>
              <div className="save">
                {s.childFirstName ? <span className="ok">● Guardado</span> : "Tus datos se guardan automáticamente"}
              </div>
              <div>
                {s.step < STEPS.length - 1 &&
                <button
                  className="btn primary"
                  onClick={next}
                  disabled={!canAdvance()}
                  style={{ opacity: canAdvance() ? 1 : 0.4, cursor: canAdvance() ? "pointer" : "not-allowed" }}>
                  
                    Continuar <span className="arrow">→</span>
                  </button>
                }
                {s.step === STEPS.length - 1 &&
                <ConfirmButton s={s} price={price} canAdvance={canAdvance()} isWaitlist={isWaitlist} onProcess={setPayProcessing} />
                }
              </div>
            </div>
          </div>
        </div>

        <Summary s={s} price={price} isWaitlist={isWaitlist} />
      </div>

      {payProcessing && <PasarelaOverlay info={payProcessing} s={s} price={price} isWaitlist={isWaitlist} />}

      <SiteTweaksPanel tw={tw} setTweak={setTweak} sheetStatus={sheetStatus} />
    </main>);

}

// ============================================================
// STEP 0 · programa
// ============================================================
function StepProgram({ s, set, programs, sheetStatus }) {
  return (
    <div className="stack-2">
      <div className="blk">
        <div className="blk-lead" style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 }}>
          <span>A · Programa</span>
          {sheetStatus === "live" && <span style={{ color: "var(--cc-ok)", letterSpacing: "0.18em" }}>● En vivo · Google Sheets</span>}
          {sheetStatus === "loading" && <span style={{ color: "var(--cc-ink-3)", letterSpacing: "0.18em" }}>○ Cargando hoja…</span>}
          {sheetStatus === "error" && <span style={{ color: "var(--cc-bad)", letterSpacing: "0.18em" }}>⚠ Hoja no accesible · usando respaldo</span>}
        </div>
        <div className="blk-title">¿A qué <em>campamento</em> lo inscribes?</div>
        <div className="blk-sub">Verano Pro y Verano Basic tienen cupos abiertos para 2026. Las próximas ediciones de Pascua e Invierno abren lista de espera; te avisamos en cuanto se publiquen fechas.</div>

        <div className="wk-pick">
          {programs.map((p) =>
          <label key={p.id} className={`${p.state === "waitlist" ? "low" : ""} ${p.state === "full" ? "full disabled" : ""}`} style={{ gridTemplateColumns: "auto 1fr auto" }}>
              <input type="radio" name="program" value={p.id} checked={s.programId === p.id} onChange={() => set({ programId: p.id, waitlist: p.state === "waitlist" })} disabled={p.state === "full"} />
              <span className="ix" style={{ fontFamily: "var(--ff-display)", fontSize: 26, color: s.programId === p.id ? "var(--cc-pine)" : "var(--cc-amber-2)", paddingRight: 8 }}>
                {p.id.includes("pro") && "P"}{p.id.includes("basic") && "B"}{p.id.includes("pascua") && "✿"}{p.id.includes("invierno") && "❄"}
              </span>
              <span className="info">
                <span className="nm">{p.title} <em>· {p.range}</em></span>
                <span className="meta">
                  {p.duration} · {p.ages} · {p.state === "waitlist" ?
                "Lista de espera abierta" :
                p.state === "full" ?
                "Cupo lleno" :
                `${p.capacity - p.booked} cupos de ${p.capacity}`}
                </span>
              </span>
              <span className="avail">
                {p.state === "ok" && "● Cupos abiertos"}
                {p.state === "waitlist" && "● Lista de espera"}
                {p.state === "full" && "● Lleno"}
              </span>
            </label>
          )}
        </div>
      </div>

      {(s.programId === "verano-pro" || s.programId === "verano-basic") &&
      <div className="blk">
          <div className="blk-lead">B · Descuento aplicable</div>
          <div className="blk-title">¿Aplica algún <em>descuento?</em></div>
          <div className="blk-sub">Los descuentos no son acumulables: se aplica uno solo por participante. La preventa de Verano 2026 ya cerró; volverá a abrir para Verano 2027.</div>

          <div className="pay-grid" style={{ gridTemplateColumns: "1fr 1fr", marginTop: 8 }}>
            {[
          { v: "none", nm: "Sin descuento", desc: "Precio regular publicado." },
          { v: "preventa", nm: "Preventa", desc: "Cerrada · cupo ya cubierto.", disabled: true },
          { v: "siblings2", nm: "2 hermanos", desc: "Total familia: dos participantes con -10% c/u." },
          { v: "siblings3", nm: "3 hermanos", desc: "Total familia: tres participantes con -15% c/u." },
          { v: "returning", nm: "Repetidor", desc: "Ya asistió a un campamento de Camp Coyote. -5%." },
          { v: "cousins3", nm: "3+ primos", desc: "Tres o más primos inscritos. -5% individual." }].
          map((opt) =>
          <label key={opt.v} style={{ opacity: opt.disabled ? 0.45 : 1, pointerEvents: opt.disabled ? "none" : "auto" }}>
                <input type="radio" name="discount" value={opt.v} checked={s.discountType === opt.v} onChange={() => set({ discountType: opt.v })} disabled={opt.disabled} />
                <span className="nm">{opt.nm}</span>
                <span className="desc">{opt.desc}</span>
              </label>
          )}
          </div>
        </div>
      }
    </div>);

}

// ============================================================
// STEP 1 · participante + tutor
// ============================================================
function StepChild({ s, set }) {
  return (
    <div className="stack-2">
      <div className="blk">
        <div className="blk-lead">A · El participante</div>
        <div className="blk-title">Datos del <em>aventurero</em></div>

        <div className="fields-grid">
          <div className="field">
            <label>Nombre(s) <span className="req">*</span></label>
            <input name="childFirstName" type="text" value={s.childFirstName} onChange={(e) => set({ childFirstName: e.target.value })} placeholder="Camila" />
          </div>
          <div className="field">
            <label>Apellidos <span className="req">*</span></label>
            <input name="childLastName" type="text" value={s.childLastName} onChange={(e) => set({ childLastName: e.target.value })} placeholder="Ramírez Soto" />
          </div>
          <div className="field">
            <label>Fecha de nacimiento <span className="req">*</span></label>
            <input type="date" value={s.childBirthdate} onChange={(e) => set({ childBirthdate: e.target.value })} />
            <span className="hint">Edades aceptadas: 6 – 14 (Basic / Pascua / Invierno) · 9 – 17 (Pro)</span>
          </div>
          <div className="field">
            <label>Sexo</label>
            <select value={s.childGender} onChange={(e) => set({ childGender: e.target.value })}>
              <option value="">—</option>
              <option value="F">Femenino</option>
              <option value="M">Masculino</option>
              <option value="O">Otro / prefiero no decir</option>
            </select>
          </div>
          <div className="field">
            <label>Escuela</label>
            <input type="text" value={s.childSchool} onChange={(e) => set({ childSchool: e.target.value })} placeholder="Colegio Cervantes" />
          </div>
          <div className="field">
            <label>Grado escolar</label>
            <input type="text" value={s.childGrade} onChange={(e) => set({ childGrade: e.target.value })} placeholder="4° de primaria" />
          </div>
          <div className="field">
            <label>Talla de playera</label>
            <select value={s.shirtSize} onChange={(e) => set({ shirtSize: e.target.value })}>
              <option value="6">6 años</option>
              <option value="8">8 años</option>
              <option value="10">10 años</option>
              <option value="12">12 años</option>
              <option value="14">14 años</option>
              <option value="S">S adulto</option>
              <option value="M">M adulto</option>
              <option value="L">L adulto</option>
            </select>
          </div>
          <div className="field">
            <label>¿Ha asistido a Camp Coyote?</label>
            <select value={s.previousVisits} onChange={(e) => set({ previousVisits: e.target.value })}>
              <option>Nunca</option>
              <option>Una vez</option>
              <option>Dos veces</option>
              <option>Tres veces</option>
              <option>4 veces</option>
              <option>Más de 5 veces</option>
            </select>
            <span className="hint">Si ha asistido antes, puede aplicar descuento de repetidor.</span>
          </div>
        </div>
      </div>

      <div className="blk">
        <div className="blk-lead">B · Padre o tutor principal</div>
        <div className="blk-title">¿Con <em>quién</em> nos comunicamos?</div>
        <div className="blk-sub">A este contacto le mandaremos confirmación, responsiva, lista de cosas y actualizaciones diarias del álbum digital privado.</div>

        <div className="fields-grid">
          <div className="field">
            <label>Nombre completo <span className="req">*</span></label>
            <input name="parentName" type="text" value={s.parent1Name} onChange={(e) => set({ parent1Name: e.target.value })} placeholder="Mariana Ramírez" />
          </div>
          <div className="field">
            <label>Relación</label>
            <select value={s.parent1Rel} onChange={(e) => set({ parent1Rel: e.target.value })}>
              <option>Madre</option>
              <option>Padre</option>
              <option>Tutor(a)</option>
              <option>Abuelo(a)</option>
              <option>Otro</option>
            </select>
          </div>
          <div className="field">
            <label>Correo <span className="req">*</span></label>
            <input name="parentEmail" type="email" value={s.parent1Email} onChange={(e) => set({ parent1Email: e.target.value })} placeholder="mariana@correo.com" />
          </div>
          <div className="field">
            <label>WhatsApp <span className="req">*</span></label>
            <input type="tel" value={s.parent1Phone} onChange={(e) => set({ parent1Phone: e.target.value })} placeholder="+52 33 1234 5678" />
          </div>
          <div className="field">
            <label>Ciudad</label>
            <select value={s.city} onChange={(e) => set({ city: e.target.value })} data-comment-anchor="13a58bd82f-select-595-13">
              <option value="">—</option>
              <option>Guadalajara</option>
              <option>Zapopan</option>
              <option>Tlaquepaque</option>
              <option>Tlajomulco</option>
              <option>Tepatitlán</option>
              <option>Zapotlanejo</option>
              <option>Otra</option>
            </select>
          </div>
          <div className="field">
            <label>Domicilio</label>
            <input type="text" value={s.address} onChange={(e) => set({ address: e.target.value })} placeholder="Calle, número, colonia" />
          </div>
        </div>
      </div>

      <div className="blk">
        <div className="blk-lead">C · Segundo contacto (opcional)</div>
        <div className="blk-title">Otro adulto al que <em>podamos llamar</em></div>

        <div className="fields-grid">
          <div className="field">
            <label>Nombre</label>
            <input type="text" value={s.parent2Name} onChange={(e) => set({ parent2Name: e.target.value })} placeholder="Andrés Soto" />
          </div>
          <div className="field">
            <label>Teléfono</label>
            <input type="tel" value={s.parent2Phone} onChange={(e) => set({ parent2Phone: e.target.value })} placeholder="+52 33 ..." />
          </div>
        </div>
      </div>
    </div>);

}

// ============================================================
// STEP 2 · salud + emergencia + permisos
// ============================================================
function StepHealth({ s, set }) {
  function toggleAllergy(a) {
    const has = s.allergies.includes(a);
    set({ allergies: has ? s.allergies.filter((x) => x !== a) : [...s.allergies, a] });
  }
  return (
    <div className="stack-2">
      <div className="blk">
        <div className="blk-lead">A · Contacto de emergencia</div>
        <div className="blk-title">Si <em>no podemos</em> localizar al tutor principal</div>
        <div className="blk-sub">Idealmente alguien distinto al contacto principal: tío, abuelo, vecino, amigo cercano de la familia.</div>

        <div className="fields-grid">
          <div className="field">
            <label>Nombre completo <span className="req">*</span></label>
            <input type="text" value={s.emergencyName} onChange={(e) => set({ emergencyName: e.target.value })} placeholder="Patricia Soto" />
          </div>
          <div className="field">
            <label>Relación</label>
            <input type="text" value={s.emergencyRel} onChange={(e) => set({ emergencyRel: e.target.value })} placeholder="Abuela materna" />
          </div>
          <div className="field span-2">
            <label>Teléfono <span className="req">*</span></label>
            <input type="tel" value={s.emergencyPhone} onChange={(e) => set({ emergencyPhone: e.target.value })} placeholder="+52 33 ..." />
          </div>
          <div className="field span-2">
            <label>Personas autorizadas a recoger</label>
            <textarea rows="2" value={s.pickupAuth} onChange={(e) => set({ pickupAuth: e.target.value })} placeholder="Nombres completos. Pediremos identificación al recoger. (Padres del primer contacto siempre autorizados.)" />
          </div>
        </div>
      </div>

      <div className="blk">
        <div className="blk-lead">B · Salud</div>
        <div className="blk-title">Lo que la <em>enfermera</em> debe saber</div>
        <div className="blk-sub">Esta información es confidencial. Solo la verán la enfermera del campamento y la dirección. La cocina recibe solo las alergias y restricciones alimentarias.</div>

        <div className="fields-grid">
          <div className="field">
            <label>Tipo de sangre</label>
            <select value={s.bloodType} onChange={(e) => set({ bloodType: e.target.value })}>
              <option value="">—</option>
              <option>O+</option><option>O−</option>
              <option>A+</option><option>A−</option>
              <option>B+</option><option>B−</option>
              <option>AB+</option><option>AB−</option>
              <option>No sé</option>
            </select>
          </div>
          <div className="field">
            <label>Aseguradora médica</label>
            <input type="text" value={s.insurance} onChange={(e) => set({ insurance: e.target.value })} placeholder="GNP, AXA, ... (opcional)" />
          </div>

          <div className="field span-2">
            <label>Alergias frecuentes</label>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 4 }}>
              {ALLERGY_OPTS.map((a) => {
                const on = s.allergies.includes(a);
                return (
                  <button
                    key={a}
                    type="button"
                    onClick={() => toggleAllergy(a)}
                    style={{
                      padding: "8px 14px",
                      borderRadius: 999,
                      border: `1px solid ${on ? "var(--cc-pine)" : "var(--cc-line)"}`,
                      background: on ? "var(--cc-pine)" : "var(--cc-paper)",
                      color: on ? "var(--cc-bone)" : "var(--cc-ink-2)",
                      fontFamily: "var(--ff-mono)",
                      fontSize: 11,
                      letterSpacing: "0.06em",
                      cursor: "pointer"
                    }}>
                    
                    {a}
                  </button>);

              })}
            </div>
          </div>

          <div className="field span-2">
            <label>Otras alergias o detalles</label>
            <input type="text" value={s.allergyDetail} onChange={(e) => set({ allergyDetail: e.target.value })} placeholder="Especifica severidad, reacción típica, qué hacer" />
          </div>

          <div className="field">
            <label>Restricción alimenticia</label>
            <select value={s.diet} onChange={(e) => set({ diet: e.target.value })}>
              <option value="ninguna">Ninguna</option>
              <option value="vegetariana">Vegetariana</option>
              <option value="vegana">Vegana</option>
              <option value="sin gluten">Sin gluten</option>
              <option value="otra">Otra</option>
            </select>
          </div>
          <div className="field">
            <label>Detalle (si aplica)</label>
            <input type="text" value={s.dietDetail} onChange={(e) => set({ dietDetail: e.target.value })} placeholder="Detalles para la cocina" />
          </div>

          <div className="field span-2">
            <label>Medicamentos diarios o de rescate</label>
            <textarea rows="2" value={s.medications} onChange={(e) => set({ medications: e.target.value })} placeholder="Nombre, dosis y horario. Todo medicamento se entrega al staff médico al iniciar el camp y se administra solo bajo su control." />
          </div>
          <div className="field span-2">
            <label>Condiciones, cirugías recientes, restricciones físicas</label>
            <textarea rows="2" value={s.conditions} onChange={(e) => set({ conditions: e.target.value })} placeholder="Asma, epilepsia, fractura reciente, marcapasos, etc." />
          </div>

          <div className="field">
            <label>Médico de cabecera</label>
            <input type="text" value={s.doctorName} onChange={(e) => set({ doctorName: e.target.value })} placeholder="Nombre" />
          </div>
          <div className="field">
            <label>Teléfono del médico</label>
            <input type="tel" value={s.doctorPhone} onChange={(e) => set({ doctorPhone: e.target.value })} />
          </div>
        </div>
      </div>

      <div className="blk">
        <div className="blk-lead">C · Permisos y consentimientos</div>
        <div className="blk-title">Lo que <em>autorizas</em></div>

        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          <label className="check">
            <input type="checkbox" checked={s.consentMed} onChange={(e) => set({ consentMed: e.target.checked })} />
            <span className="lbl">
              <b>Autorizo atención médica de emergencia. <span style={{ color: "var(--cc-amber-2)" }}>*</span></b>
              <small>Camp Coyote puede llamar paramédico, ambulancia y trasladar a mi hijo al hospital de referencia si la enfermera lo determina urgente. Se me notificará de inmediato.</small>
            </span>
          </label>
          <label className="check">
            <input type="checkbox" checked={s.consentPhotos} onChange={(e) => set({ consentPhotos: e.target.checked })} />
            <span className="lbl">
              <b>Autorizo uso de fotos y video.</b>
              <small>Doy permiso para que mi hijo aparezca en el álbum digital privado del camp, redes sociales y material promocional de Camp Coyote. (Si declinas, evitaremos imágenes identificables.)</small>
            </span>
          </label>
          <label className="check">
            <input type="checkbox" checked={s.consentResponsiva} onChange={(e) => set({ consentResponsiva: e.target.checked })} />
            <span className="lbl">
              <b>Acepto firmar la carta responsiva. <span style={{ color: "var(--cc-amber-2)" }}>*</span></b>
              <small>Recibo por correo el formato de responsiva, lista de cosas y políticas. Me comprometo a firmarla y entregarla impresa el día del campamento.</small>
            </span>
          </label>
        </div>
      </div>
    </div>);

}

// ============================================================
// STEP 3 · revisar + anticipo $800
// ============================================================
function StepPay({ s, set, price, goto, isWaitlist }) {
  return (
    <div className="stack-2">
      {/* Hidden inputs para la pasarela de pago */}
      {/* Participante */}
      <input type="hidden" name="childFirstName" value={s.childFirstName} />
      <input type="hidden" name="childLastName"  value={s.childLastName} />
      <input type="hidden" name="childBirthdate" value={s.childBirthdate} />
      <input type="hidden" name="childSchool"    value={s.childSchool} />
      <input type="hidden" name="childGrade"     value={s.childGrade} />
      <input type="hidden" name="shirtSize"      value={s.shirtSize} />
      {/* Tutor principal */}
      <input type="hidden" name="parentName"     value={s.parent1Name} />
      <input type="hidden" name="parentEmail"    value={s.parent1Email} />
      <input type="hidden" name="parentPhone"    value={s.parent1Phone} />
      {/* Tutor secundario */}
      <input type="hidden" name="parent2Name"    value={s.parent2Name} />
      <input type="hidden" name="parent2Phone"   value={s.parent2Phone} />
      {/* Contacto de emergencia */}
      <input type="hidden" name="emergencyName"  value={s.emergencyName} />
      <input type="hidden" name="emergencyRel"   value={s.emergencyRel} />
      <input type="hidden" name="emergencyPhone" value={s.emergencyPhone} />
      {/* Salud */}
      <input type="hidden" name="bloodType"      value={s.bloodType} />
      <input type="hidden" name="allergies"      value={[...s.allergies, s.allergyDetail].filter(Boolean).join(', ')} />
      <input type="hidden" name="medications"    value={s.medications} />
      <input type="hidden" name="doctorPhone"    value={s.doctorPhone} />
      {/* Pago */}
      <input type="hidden" name="sessionName"    value={price.prog.title + " · " + price.prog.range} />
      <input type="hidden" name="amount"         value={isWaitlist ? 0 : ANTICIPO} />
      <input type="hidden" name="programId"      value={s.programId} />
      <input type="hidden" name="totalAmount"    value={price.total} />
      <div className="blk">
        <div className="blk-lead">A · Revisar</div>
        <div className="blk-title">Confirma <em>todo</em> antes de continuar</div>
        <div className="blk-sub">Si necesitas corregir algo, da clic en el paso correspondiente arriba o en "Editar".</div>

        <div className="review-grid" style={{ marginTop: 20 }}>
          <div className="review-blk">
            <div className="review-head"><h4>Participante</h4><button className="edit" onClick={() => goto(1)}>Editar</button></div>
            <dl>
              <div><dt>Nombre</dt><dd>{s.childFirstName ? `${s.childFirstName} ${s.childLastName}` : <span className="placeholder">Falta</span>}</dd></div>
              <div><dt>Fecha de nacimiento</dt><dd>{s.childBirthdate || <span className="placeholder">—</span>}</dd></div>
              <div><dt>Escuela · Grado</dt><dd>{s.childSchool ? `${s.childSchool} · ${s.childGrade}` : <span className="placeholder">—</span>}</dd></div>
              <div><dt>Talla playera</dt><dd>{s.shirtSize}</dd></div>
            </dl>
          </div>

          <div className="review-blk">
            <div className="review-head"><h4>Tutor / Emergencia</h4><button className="edit" onClick={() => goto(1)}>Editar</button></div>
            <dl>
              <div>
                <dt>Tutor principal</dt>
                <dd>
                  {s.parent1Name || <span className="placeholder">Falta</span>}<br />
                  <span style={{ fontFamily: "var(--ff-mono)", fontSize: 11, color: "var(--cc-ink-3)", fontWeight: 400 }}>{s.parent1Email} · {s.parent1Phone}</span>
                </dd>
              </div>
              <div>
                <dt>Emergencia</dt>
                <dd>
                  {s.emergencyName || <span className="placeholder">Falta</span>}<br />
                  <span style={{ fontFamily: "var(--ff-mono)", fontSize: 11, color: "var(--cc-ink-3)", fontWeight: 400 }}>{s.emergencyPhone}</span>
                </dd>
              </div>
            </dl>
          </div>

          <div className="review-blk">
            <div className="review-head"><h4>Salud</h4><button className="edit" onClick={() => goto(2)}>Editar</button></div>
            <dl>
              <div>
                <dt>Alergias</dt>
                <dd>
                  {s.allergies.length || s.allergyDetail ?
                  <span style={{ fontSize: 14 }}>{[...s.allergies, s.allergyDetail].filter(Boolean).join(", ")}</span> :
                  <span className="placeholder">Ninguna declarada</span>}
                </dd>
              </div>
              <div>
                <dt>Dieta</dt>
                <dd><span style={{ fontSize: 14 }}>{s.diet === "ninguna" ? "Sin restricción" : s.diet}{s.dietDetail ? ` · ${s.dietDetail}` : ""}</span></dd>
              </div>
              <div>
                <dt>Medicación</dt>
                <dd><span style={{ fontSize: 14 }}>{s.medications || <span className="placeholder">Ninguna</span>}</span></dd>
              </div>
            </dl>
          </div>

          <div className="review-blk">
            <div className="review-head"><h4>Programa</h4><button className="edit" onClick={() => goto(0)}>Editar</button></div>
            <dl>
              <div><dt>Edición</dt><dd>{price.prog.title} <em>· {price.prog.range}</em></dd></div>
              <div><dt>Duración</dt><dd><span style={{ fontSize: 14 }}>{price.prog.duration}</span></dd></div>
              <div><dt>Descuento</dt><dd><span style={{ fontSize: 14 }}>{discountLabel(s.discountType)}</span></dd></div>
            </dl>
          </div>
        </div>
      </div>

      {!isWaitlist &&
      <div className="blk">
          <div className="blk-lead">B · Anticipo</div>
          <div className="blk-title">Apartas con <em>$800 MXN</em></div>
          <div className="blk-sub">El anticipo no es reembolsable y reserva tu cupo en el campamento. El saldo restante se paga en efectivo el primer día del camp, antes de la inauguración.</div>

          <div className="pay-grid">
            <label>
              <input type="radio" name="gateway" checked={s.payGateway === "card"} onChange={() => set({ payGateway: "card" })} />
              <span className="nm">Tarjeta <em>en línea</em></span>
              <span className="sub">Crédito · débito · MSI 3</span>
              <span className="desc">Visa, MasterCard, Amex. Confirmación inmediata. Procesado por Mercado Pago.</span>
            </label>
            <label>
              <input type="radio" name="gateway" checked={s.payGateway === "spei"} onChange={() => set({ payGateway: "spei" })} />
              <span className="nm">Transferencia <em>SPEI</em></span>
              <span className="sub">Manual · 24 hrs</span>
              <span className="desc">Recibirás CLABE por correo. El cupo se reserva al confirmar el depósito.</span>
            </label>
            <label>
              <input type="radio" name="gateway" checked={s.payGateway === "cash"} onChange={() => set({ payGateway: "cash" })} />
              <span className="nm">Efectivo <em>en hacienda</em></span>
              <span className="sub">7 días para pagar</span>
              <span className="desc">Recibe folio temporal. Tu lugar se aparta al recibir el efectivo en oficinas.</span>
            </label>
          </div>

          {s.payGateway === "card" &&
        <div className="card-mock">
              <div className="field">
                <label>Nombre del titular <span className="req">*</span></label>
                <input type="text" value={s.cardName} onChange={(e) => set({ cardName: e.target.value })} placeholder="Como aparece en la tarjeta" />
              </div>
              <div className="field">
                <label>Número de tarjeta</label>
                <input type="text" value={s.cardNum} onChange={(e) => set({ cardNum: e.target.value })} placeholder="•••• •••• •••• ••••" maxLength={19} />
              </div>
              <div className="row">
                <div className="field">
                  <label>Vencimiento</label>
                  <input type="text" value={s.cardExp} onChange={(e) => set({ cardExp: e.target.value })} placeholder="MM / AA" maxLength={7} />
                </div>
                <div className="field">
                  <label>CVV</label>
                  <input type="text" value={s.cardCvv} onChange={(e) => set({ cardCvv: e.target.value })} placeholder="•••" maxLength={4} />
                </div>
              </div>
              <p style={{ fontFamily: "var(--ff-mono)", fontSize: 10.5, color: "var(--cc-ink-3)", letterSpacing: "0.06em" }}>
                ⌁ Procesado en línea por Mercado Pago. Camp Coyote no almacena los datos de tu tarjeta.
              </p>
            </div>
        }

          {s.payGateway === "spei" &&
        <div style={{ background: "var(--cc-wash)", border: "1px solid var(--cc-line)", borderRadius: "var(--r-md)", padding: "18px 22px", marginTop: 14, fontSize: 13, color: "var(--cc-ink-2)", lineHeight: 1.55 }}>
              Te enviaremos al correo <b style={{ color: "var(--cc-pine)", fontFamily: "var(--ff-display)" }}>{s.parent1Email || "tu correo"}</b> los datos para SPEI:
              banco, CLABE y referencia. Tu lugar se aparta cuando recibamos el depósito (suele tardar menos de 24 horas).
            </div>
        }

          {s.payGateway === "cash" &&
        <div style={{ background: "var(--cc-wash)", border: "1px solid var(--cc-line)", borderRadius: "var(--r-md)", padding: "18px 22px", marginTop: 14, fontSize: 13, color: "var(--cc-ink-2)", lineHeight: 1.55 }}>
              Te llega un folio temporal por correo. Tienes 7 días para pasar a oficinas de la Hacienda Coyotes (Km 15 Carr. Zapotlanejo – Tototlán, Zapotlanejo) y pagar el anticipo en efectivo.
              Si no se cubre en ese plazo, el lugar se libera automáticamente.
            </div>
        }
        </div>
      }

      <div className="blk">
        <div className="blk-lead">{isWaitlist ? "B · " : "C · "}Términos</div>
        <div className="blk-title">{isWaitlist ? <>Confirma <em>lista de espera</em></> : <>Lo último: <em>políticas</em></>}</div>

        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          <label className="check">
            <input type="checkbox" checked={s.consentPolicies} onChange={(e) => set({ consentPolicies: e.target.checked })} />
            <span className="lbl">
              <b>Acepto las políticas del campamento. <span style={{ color: "var(--cc-amber-2)" }}>*</span></b>
              <small>
                Políticas generales · de venta · de cancelación. Cancelaciones hasta 7 días antes del inicio.
                <a href="https://www.hdacoyotes.com/campamentos-infantiles/" target="_blank" rel="noopener" style={{ color: "var(--cc-pine)", textDecoration: "underline", textUnderlineOffset: 2, marginLeft: 4 }}>Ver políticas completas</a>.
              </small>
            </span>
          </label>
          {!isWaitlist &&
          <label className="check">
              <input type="checkbox" checked={s.consentDeposit} onChange={(e) => set({ consentDeposit: e.target.checked })} />
              <span className="lbl">
                <b>Entiendo que el anticipo de $800 MXN no es reembolsable. <span style={{ color: "var(--cc-amber-2)" }}>*</span></b>
                <small>
                  Si cancelo más de 7 días antes, recibo un voucher electrónico válido por 6 meses para usar en cualquier servicio del grupo
                  (Hacienda Coyotes, Kavala o Taanah). Después no hay reembolso.
                </small>
              </span>
            </label>
          }
        </div>
      </div>
    </div>);

}

// ============================================================
// CONFIRM BUTTON
// ============================================================
function ConfirmButton({ s, price, canAdvance, isWaitlist, onProcess }) {
  function go() {
    if (!canAdvance) return;
    if (isWaitlist) {
      // Lista de espera no usa pasarela
      const params = new URLSearchParams({
        child: `${s.childFirstName} ${s.childLastName}`,
        email: s.parent1Email,
        program: s.programId,
        progTitle: price.prog.title || "",
        progRange: price.prog.range || "",
        amount: "0",
        total: String(price.total),
        method: s.payGateway,
        discount: s.discountType,
        waitlist: "1"
      });
      window.location.href = `/confirmacion?${params.toString()}`;
      return;
    }
    onProcess({ gateway: s.payGateway, amount: ANTICIPO });
  }
  return (
    <button
      data-action="pagar"
      className="btn primary lg"
      onClick={go}
      disabled={!canAdvance}
      style={{ opacity: canAdvance ? 1 : 0.4, cursor: canAdvance ? "pointer" : "not-allowed" }}>
      
      {isWaitlist ?
      <>Confirmar lista de espera <span className="arrow">→</span></> :
      <>Pagar ${ANTICIPO} y apartar <span className="arrow">→</span></>}
    </button>);

}

// ============================================================
// PASARELA OVERLAY · simulación de checkout seguro
// ============================================================
const PASARELA_STAGES = [
{ lbl: "Conectando con la pasarela", note: "Estableciendo conexión cifrada TLS 1.3 con el procesador de pagos." },
{ lbl: "Validando datos de la tarjeta", note: "Verificando emisor, BIN y disponibilidad de fondos." },
{ lbl: "Autenticación 3-D Secure", note: "Tu banco confirma la transacción. Esto suele tardar unos segundos." },
{ lbl: "Pago autorizado", note: "Generando comprobante y disparando correo de confirmación." }];


const GATEWAY_INFO = {
  card: { brand: "Pago en línea seguro", proc: "Procesado por Mercado Pago · cifrado SSL 256-bit" },
  spei: { brand: "Transferencia SPEI", proc: "Generando referencia interbancaria — BBVA México" },
  cash: { brand: "Folio de pago en efectivo", proc: "Generando folio temporal de 7 días — Hacienda Coyotes" }
};

function PasarelaOverlay({ info, s, price, isWaitlist }) {
  const [stage, setStage] = useState(0);
  const stages = info.gateway === "card" ?
  PASARELA_STAGES :
  info.gateway === "spei" ?
  [
  { lbl: "Generando referencia SPEI", note: "Creando CLABE única para tu lugar." },
  { lbl: "Reservando cupo temporal", note: "Tu lugar queda apartado por 24 horas mientras llega el depósito." },
  { lbl: "Enviando datos por correo", note: "Banco, CLABE y referencia van directo a tu inbox." },
  { lbl: "Reservación pre-confirmada", note: "El pago se confirma automáticamente al recibir el depósito." }] :

  [
  { lbl: "Generando folio de pago", note: "Folio único de 7 días para pagar en oficinas de la Hacienda." },
  { lbl: "Reservando cupo temporal", note: "Tu lugar queda apartado mientras pasas a pagar." },
  { lbl: "Enviando folio por correo", note: "Dirección y horario para pagar en efectivo." },
  { lbl: "Reservación pre-confirmada", note: "Pasa a la Hacienda con tu folio dentro de los próximos 7 días." }];


  useEffect(() => {
    if (stage >= stages.length) {
      const params = new URLSearchParams({
        child: `${s.childFirstName} ${s.childLastName}`,
        email: s.parent1Email,
        program: s.programId,
        progTitle: price.prog.title || "",
        progRange: price.prog.range || "",
        amount: String(ANTICIPO),
        total: String(price.total),
        method: s.payGateway,
        discount: s.discountType,
        waitlist: "0"
      });
      window.location.href = `/confirmacion?${params.toString()}`;
      return;
    }
    const ms = stage === 2 ? 1800 : 950; // 3DS un poquito más lento
    const t = setTimeout(() => setStage(stage + 1), ms);
    return () => clearTimeout(t);
  }, [stage]);

  const g = GATEWAY_INFO[info.gateway] || GATEWAY_INFO.card;
  const childFirst = s.childFirstName || "tu hijo";

  return (
    <div className="pasarela-overlay" role="dialog" aria-modal="true">
      <div className="pasarela-card">
        <div className="pasarela-head">
          <div className="pasarela-brand">
            <img src="assets/brand/logo-camp-coyote.png" alt="" />
            <div>
              <div className="nm">Camp <em>Coyote</em> · Pasarela</div>
              <div className="sub">{g.brand}</div>
            </div>
          </div>
          <div className="pasarela-amt">
            <div className="lbl">A pagar</div>
            <div className="amt">${info.amount.toLocaleString("es-MX")}<small>MXN</small></div>
          </div>
        </div>

        <div className="pasarela-trans">
          Apartando lugar para <b>{childFirst}</b> en <em>{price.prog.title}</em> · {price.prog.range}
        </div>

        <ul className="pasarela-stages">
          {stages.map((st, i) => {
            const done = i < stage;
            const active = i === stage;
            return (
              <li key={i} className={done ? "done" : active ? "active" : "pending"}>
                <span className="dot">
                  {done && <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3"><polyline points="4 12 10 18 20 6" /></svg>}
                  {active && <span className="spin-dot" />}
                </span>
                <span className="lbl">
                  <b>{st.lbl}</b>
                  <small>{st.note}</small>
                </span>
                {active && <span className="tag">En curso…</span>}
                {done && <span className="tag ok">OK</span>}
              </li>);

          })}
        </ul>

        <div className="pasarela-foot">
          <span>
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-4z" /></svg>
            {g.proc}
          </span>
          <span>No cierres esta ventana</span>
        </div>
      </div>
    </div>);

}

// ============================================================
// SUMMARY (right column)
// ============================================================
function Summary({ s, price, isWaitlist }) {
  return (
    <aside className="summary">
      <h3>Resumen <em>en vivo</em></h3>
      <div className="child">
        {s.childFirstName ? <>{s.childFirstName} <em>{s.childLastName}</em></> : <span className="placeholder">Nombre del participante</span>}
      </div>

      <dl>
        <div><dt>Programa</dt><dd>{price.prog.title}</dd></div>
        <div><dt>Fechas</dt><dd>{price.prog.range}</dd></div>
        <div><dt>Duración</dt><dd style={{ fontSize: 14 }}>{price.prog.duration}</dd></div>
        <div><dt>Edades</dt><dd style={{ fontSize: 14 }}>{price.prog.ages}</dd></div>
        <div><dt>Hospedaje</dt><dd style={{ fontSize: 14 }}>Glamping</dd></div>
      </dl>

      {!isWaitlist &&
      <>
          <div className="totals">
            <div className="ln"><span>Tarifa base</span> <b>${price.base.toLocaleString("es-MX")}</b></div>
            {price.discountLine &&
          <div className="ln disc">
                <span>{price.discountLine.lbl}</span>
                <b>{price.discountLine.amt < 0 ? "−" : ""}${Math.abs(price.discountLine.amt).toLocaleString("es-MX")}</b>
              </div>
          }
            <div className="grand">
              <span className="lbl">Total {price.discountLine && price.discountLine.totalRow ? "familia" : "campamento"}</span>
              <span className="amt">${price.total.toLocaleString("es-MX")}<small>MXN</small></span>
            </div>
          </div>

          <div className="due">
            <div className="lbl">Anticipo · no reembolsable</div>
            <div className="amt">${ANTICIPO} <span style={{ fontFamily: "var(--ff-mono)", fontSize: 11, color: "oklch(0.78 0.04 90)" }}>MXN</span></div>
            <div className="note">Saldo de ${price.dueAtCamp.toLocaleString("es-MX")} en efectivo el día del campamento.</div>
          </div>
        </>
      }

      {isWaitlist &&
      <div className="due" style={{ background: "oklch(0.18 0.025 145 / 0.5)" }}>
          <div className="lbl" style={{ color: "var(--cc-amber)" }}>Lista de espera</div>
          <div className="amt">Sin cargo</div>
          <div className="note">Te avisamos por correo cuando se publiquen fechas y precios oficiales.</div>
        </div>
      }

      <div className="trust">
        <div className="it">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M12 2l8 4v6c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-4z" /></svg>
          <span>Pago<br />cifrado</span>
        </div>
        <div className="it">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="12" cy="12" r="9" /><path d="M9 12l2 2 4-4" /></svg>
          <span>Confirma<br />al instante</span>
        </div>
        <div className="it">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M3 10h18M5 6h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2z" /></svg>
          <span>Tarjeta o<br />transfer</span>
        </div>
      </div>

      <div className="help">
        ¿Dudas? Llámanos al <b style={{ color: "var(--cc-bone)" }}>33 2101 2205</b> o <a href="https://wa.me/523316990962" target="_blank" rel="noopener">escríbenos por WhatsApp</a>.
      </div>
    </aside>);

}

// ============================================================
// TWEAKS PANEL
// ============================================================
function SiteTweaksPanel({ tw, setTweak, sheetStatus }) {
  const statusLabel = {
    fallback: "○ Modo respaldo (datos hardcoded)",
    loading: "○ Cargando hoja…",
    live: "● Conectado en vivo",
    error: "⚠ Hoja no accesible — revisa la URL"
  }[sheetStatus] || "—";

  return (
    <TweaksPanel title="Tweaks · Inscripción">
      <TweakSection title="Google Sheets · fechas en vivo">
        <div style={{ fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: sheetStatus === "live" ? "var(--cc-ok)" : sheetStatus === "error" ? "var(--cc-bad)" : "var(--cc-ink-3)", marginBottom: 8 }}>
          Estado: {statusLabel}
        </div>
        <TweakToggle label="Usar hoja de cálculo" value={tw.use_sheet} onChange={(v) => setTweak('use_sheet', v)} />
        <TweakText label="URL CSV publicada" value={tw.sheet_csv_url} onChange={(v) => setTweak('sheet_csv_url', v)} />
        <div style={{ fontSize: 11, color: "var(--cc-ink-3)", lineHeight: 1.5, marginTop: 6 }}>
          En tu hoja: Archivo → Compartir → Publicar en la web → CSV. Columnas: <code>id, title, range, duration, ages, capacity, booked, price, preventa, preventaDate, state, descriptor</code>.
        </div>
      </TweakSection>
      <TweakSection title="Pago">
        <TweakText label="Anticipo (MXN)" value={tw.anticipo_amount} onChange={(v) => setTweak('anticipo_amount', v)} />
        <TweakToggle label="Mostrar campos de tarjeta" value={tw.show_card_fields} onChange={(v) => setTweak('show_card_fields', v)} />
      </TweakSection>
    </TweaksPanel>);

}

// ============================================================
// utils
// ============================================================
function discountLabel(d) {
  return {
    none: "Sin descuento",
    preventa: "Preventa",
    siblings2: "2 hermanos",
    siblings3: "3 hermanos",
    cousins3: "3+ primos",
    returning: "Repetidor"
  }[d] || "—";
}

ReactDOM.createRoot(document.getElementById("root")).render(<EnrollApp />);