// Cart page + Checkout (met ophalen/bezorgen + Supabase) + About page
const { useState, useEffect, useContext } = React;

/* ============ CART PAGE (full view) ============ */
const PageCart = ({ setPage }) => {
  const cart = useContext(CartContext);
  const langCtx = useContext(window.LangContext || React.createContext({ lang:"nl", t: (nl)=>nl }));
  const t = langCtx.t || ((nl) => nl);
  const lang = langCtx.lang || "nl";
  const LP = window.LP || ((o, f) => o && o[f]);
  const vatAmt = (window.vatPortion ? window.vatPortion(cart.total) : 0);
  const threshold = Number(cart.freeShippingThreshold || 0);
  return (
    <div className="page">
      <section style={{padding:"40px 0 16px", borderBottom:"1px solid var(--line)"}}>
        <div className="wrap">
          <div className="eyebrow" style={{marginBottom:10}}>{t("Winkelmand","Cart")}</div>
          <h1 className="h-display" style={{fontSize:"clamp(34px,5vw,52px)"}}>
            {t("Jouw winkelmand","Your cart")} · {cart.count} {t(cart.count === 1 ? "product" : "producten", cart.count === 1 ? "item" : "items")}
          </h1>
        </div>
      </section>
      <section className="section-sm">
        <div className="wrap">
          {cart.items.length === 0 ? (
            <div className="card" style={{padding:80, textAlign:"center"}}>
              <div style={{width:80, height:80, borderRadius:50, background:"var(--bg)", margin:"0 auto 18px", display:"grid", placeItems:"center", color:"var(--ink-mute)"}}>
                <Icon name="cart" size={32}/>
              </div>
              <h3 className="h-display" style={{fontSize:26, marginBottom:10}}>{t("Je winkelmand is leeg","Your cart is empty")}</h3>
              <p style={{color:"var(--ink-dim)", maxWidth:380, margin:"0 auto 24px"}}>{t("Voeg een Zyro of accessoire toe om verder te gaan.","Add a Zyro or accessory to continue.")}</p>
              <button className="btn btn-primary" onClick={()=>setPage("shop")}>{t("Naar de webshop","To the shop")} <Icon name="arrow" size={15}/></button>
            </div>
          ) : (
            <div style={{display:"grid", gridTemplateColumns:"1.5fr 1fr", gap:24}} className="cart-cols">
              <div className="card" style={{padding:8}}>
                {cart.items.map(it => {
                  const p = ALL_ITEMS[it.id];
                  if (!p) return null;
                  const showDiscount = window.hasDiscount && window.hasDiscount(p);
                  return (
                    <div key={it.id} className="cart-row" style={{gridTemplateColumns:"100px 1fr auto"}}>
                      <div className="cart-thumb" style={{width:100, height:100}}><CartThumb id={it.id}/></div>
                      <div>
                        <h4 style={{fontSize:16, marginBottom:4}}>{LP(p,"name",lang) || LP(p,"short",lang) || p.name || p.short}</h4>
                        <div className="meta">{LP(p,"color",lang) || LP(p,"type",lang)}</div>
                        <div className="qty-stepper" style={{marginTop:8}}>
                          <button onClick={()=>cart.setQty(it.id, it.qty - 1)}>−</button>
                          <span>{it.qty}</span>
                          <button onClick={()=>cart.setQty(it.id, it.qty + 1)}>+</button>
                        </div>
                      </div>
                      <div style={{textAlign:"right"}}>
                        {showDiscount && <div className="mono" style={{fontSize:11, color:"var(--ink-mute)", textDecoration:"line-through"}}>{formatEUR(p.oldPrice * it.qty)}</div>}
                        <div style={{fontFamily:"var(--f-display)", fontWeight:700, fontSize:18}}>{formatEUR(p.price * it.qty)}</div>
                        {showDiscount && <span className="tag warn" style={{fontSize:10, marginTop:4}}>{window.discountLabel(p, lang)}</span>}
                        <button onClick={()=>cart.remove(it.id)} style={{color:"var(--ink-mute)", fontSize:11, textTransform:"uppercase", letterSpacing:".1em", fontFamily:"var(--f-mono)", marginTop:8}}>{t("Verwijder","Delete")}</button>
                      </div>
                    </div>
                  );
                })}
              </div>
              <div className="card" style={{padding:24, height:"fit-content", position:"sticky", top:88}}>
                <h3 className="h-display" style={{fontSize:20, marginBottom:16}}>{t("Overzicht","Overview")}</h3>
                <div className="cart-totals" style={{fontSize:14}}>
                  <div className="row"><span>{t("Subtotaal","Subtotal")}</span><span>{formatEUR(cart.subtotal)}</span></div>
                  <div className="row"><span>{t("Verzendkosten","Shipping costs")}</span><span>{cart.shipping === 0 ? <strong style={{color:"var(--ok)"}}>{t("Gratis","Free")}</strong> : formatEUR(cart.shipping)}</span></div>
                  {threshold > 0 && cart.subtotal > 0 && cart.subtotal < threshold && (
                    <div className="row" style={{color:"var(--ink-mute)", fontSize:11.5}}>
                      <span>{t("Gratis verzending vanaf","Free shipping from")} {formatEUR(threshold)}</span>
                      <span>{t("nog","still")} {formatEUR(threshold - cart.subtotal)}</span>
                    </div>
                  )}
                  <div className="row total"><span>{t("Totaal","Total")}</span><span>{formatEUR(cart.total)}</span></div>
                  {cart.total > 0 && window.vatRowLabel && (
                    <div className="row" style={{color:"var(--ink-mute)", fontSize:11.5}}>
                      <span>{window.vatRowLabel(langCtx.lang)}</span><span>{formatEUR(vatAmt)}</span>
                    </div>
                  )}
                </div>
                {cart.hasUnavailable && (
                  <div style={{marginTop:14, padding:"10px 12px", borderRadius:8, background:"#fbe9e9", border:"1px solid #efc5c5", color:"#9a2222", fontSize:13}}>
                    {t("Een product in je winkelmand is niet meer beschikbaar.","An item in your cart is no longer available.")}
                  </div>
                )}
                <button className="btn btn-accent btn-lg btn-block" style={{marginTop:18}} onClick={()=>setPage("checkout")} disabled={cart.hasUnavailable}>
                  {t("Verder naar checkout","Continue to checkout")} <Icon name="arrow" size={16}/>
                </button>
                <button className="btn btn-ghost btn-block btn-sm" style={{marginTop:8}} onClick={()=>setPage("shop")}>{t("Doorgaan met winkelen","Continue shopping")}</button>
                <div style={{marginTop:18, padding:14, background:"var(--bg)", borderRadius:8, fontSize:12, color:"var(--ink-dim)"}}>
                  <div style={{display:"flex", gap:8, alignItems:"center", marginBottom:6}}>
                    <Icon name="shield" size={14} style={{color:"var(--accent)"}}/>
                    <strong style={{color:"var(--ink)"}}>{t("Veilig betalen","Secure payment")}</strong>
                  </div>
                  {t("Betaal veilig via Mollie","Pay securely with Mollie")} · iDEAL · Visa · Mastercard · Apple Pay
                </div>
              </div>
              <style>{`@media (max-width:900px){.cart-cols{grid-template-columns:1fr !important}}`}</style>
            </div>
          )}
        </div>
      </section>
    </div>
  );
};

/* ============ CHECKOUT ============ */
const PageCheckout = ({ setPage }) => {
  const cart = useContext(CartContext);
  const auth = useContext(window.AuthContext || React.createContext({ user: null, profile: null, ready: true }));
  const langCtx = useContext(window.LangContext || React.createContext({ lang:"nl", t: (nl)=>nl }));
  const t = langCtx.t || ((nl) => nl);
  const lang = langCtx.lang || "nl";
  const LP = window.LP || ((o, f) => o && o[f]);
  const cfg = window.ZYRO_CONFIG || {};
  const shippingCfg = window.getShippingConfig ? window.getShippingConfig() : {
    nl:19, be:29, de:29, free_shipping_threshold:500, default_country:"NL",
    pickup_enabled:true, delivery_enabled:true,
  };
  const pickupEnabled = shippingCfg.pickup_enabled !== false;
  const deliveryEnabled = shippingCfg.delivery_enabled !== false;
  const initialCountry = String(shippingCfg.default_country || "NL").toUpperCase();

  const [step, setStep] = useState(1);
  const [pay, setPay] = useState("creditcard");
  // Payment method choice on step 3. "online" = Mollie, "cash" = contant betalen
  // bij ophalen. Cash is only selectable for pickup orders under €3000 (see
  // cashEligible below); we defensively reset to "online" when it becomes
  // ineligible so a stale "cash" selection can never reach the Mollie/cash fork.
  const [payMethod, setPayMethod] = useState("online"); // "online" | "cash"

  // Contact / address
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");
  const [confirmEmail, setConfirmEmail] = useState("");
  const [phone, setPhone] = useState("");
  const [confirmPhone, setConfirmPhone] = useState("");
  const [note, setNote] = useState("");

  // Fulfillment
  const [fulfillment, setFulfillment] = useState(""); // "" | "ophalen" | "bezorgen"
  const [pickupDate, setPickupDate] = useState("");

  // Delivery (Google Places autocomplete flow). The customer MUST select a
  // suggestion before payment — manual typing alone is not enough. If the
  // address input is edited after a selection, addressVerified flips back to
  // false and payment is blocked again.
  const [deliveryName, setDeliveryName] = useState("");
  const [deliveryPhoneRecipient, setDeliveryPhoneRecipient] = useState("");
  const [addrInput, setAddrInput] = useState("");
  const [addrSuggestions, setAddrSuggestions] = useState([]);
  const [addrLoading, setAddrLoading] = useState(false);
  const [addrError, setAddrError] = useState(null);
  const [selectedAddress, setSelectedAddress] = useState(null);
  // shape: { delivery_place_id, delivery_formatted_address, delivery_street,
  //          delivery_postcode, delivery_city, delivery_country, delivery_lat, delivery_lng }
  const [addressVerified, setAddressVerified] = useState(false);
  // One UUID per checkout session — Google bills the whole autocomplete +
  // details sequence as a single session when this is consistent.
  const [addrSessionToken] = useState(() => {
    try {
      if (window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID();
    } catch (_) {}
    return "s-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
  });

  // Checkbox confirmation — BOTH are required before an order/payment may start.
  const [detailsConfirmed, setDetailsConfirmed] = useState(false);
  const [acceptedTerms, setAcceptedTerms] = useState(false);

  // "Submit attempted" flags. When true, empty/invalid required fields show
  // their red error even before the field has been touched.
  const [step1Submitted, setStep1Submitted] = useState(false);
  const [confirmSubmitted, setConfirmSubmitted] = useState(false);

  // Refs to focus + scroll the first invalid contact field on a failed submit.
  const firstNameRef = React.useRef(null);
  const lastNameRef = React.useRef(null);
  const emailRef = React.useRef(null);
  const confirmEmailRef = React.useRef(null);
  const phoneRef = React.useRef(null);
  const confirmPhoneRef = React.useRef(null);

  // Result of save
  const [savedOrderId, setSavedOrderId] = useState(null);
  const [saveError, setSaveError] = useState(null);
  const [saving, setSaving] = useState(false);
  const [paymentBusy, setPaymentBusy] = useState(false);

  // Country for shipping-fee calculation comes from the verified Google
  // delivery address. Until the customer picks an address, default to NL.
  const deliveryCountryForFee = (selectedAddress && selectedAddress.delivery_country)
    || (initialCountry === "BE" || initialCountry === "DE" ? initialCountry : "NL");
  const effectiveShipping = fulfillment === "ophalen"
    ? 0
    : fulfillment === "bezorgen"
      ? (window.shippingFeeFor ? window.shippingFeeFor(cart.subtotal, deliveryCountryForFee, "bezorgen") : cart.shipping)
      : cart.shipping;
  const checkoutTotal = cart.subtotal + effectiveShipping;
  const checkoutVat = window.vatPortion ? window.vatPortion(checkoutTotal) : 0;
  const freeThreshold = Number(shippingCfg.free_shipping_threshold || 0);

  // ----- Cash-on-pickup eligibility (mirrors the server-side gate) ----------
  // Cash ("contant betalen bij ophalen") is ONLY allowed when the order is a
  // pickup order AND the total is under €3000. Delivery is always online-only.
  // The server (/api/send-cash-confirmation) re-validates both rules; this is
  // purely the UI gate.
  const CASH_LIMIT = 3000;
  const cashEligible = fulfillment === "ophalen" && checkoutTotal < CASH_LIMIT;
  const cashBlockedByAmount = fulfillment === "ophalen" && checkoutTotal >= CASH_LIMIT;

  // If the customer had picked cash and then made it ineligible (switched to
  // delivery, or the total rose to >= €3000), snap the choice back to online.
  useEffect(() => {
    if (payMethod === "cash" && !cashEligible) setPayMethod("online");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [cashEligible, payMethod]);

  // Email validation helper
  const isEmailValid = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e.trim());

  // Phone validation/normalization helper
  const validateAndNormalizePhone = (num, country) => {
    if (!num) return { isValid: false, normalized: "" };
    let clean = num.replace(/[\s\-\(\)\.]/g, "");
    if (clean.startsWith("00")) {
      clean = "+" + clean.slice(2);
    }
    if (clean.startsWith("0") && !clean.startsWith("00")) {
      const prefix = country === "BE" ? "+32" : country === "DE" ? "+49" : "+31";
      clean = prefix + clean.slice(1);
    }
    if (clean.startsWith("+31")) {
      const digits = clean.slice(3);
      const isValid = /^[1-9]\d{8,9}$/.test(digits);
      return { isValid, normalized: isValid ? clean : num };
    }
    if (clean.startsWith("+32")) {
      const digits = clean.slice(3);
      const isValid = /^[1-9]\d{7,9}$/.test(digits);
      return { isValid, normalized: isValid ? clean : num };
    }
    if (clean.startsWith("+49")) {
      const digits = clean.slice(3);
      const isValid = /^[1-9]\d{9,11}$/.test(digits);
      return { isValid, normalized: isValid ? clean : num };
    }
    const isValid = /^\+[1-9]\d{7,14}$/.test(clean);
    return { isValid, normalized: isValid ? clean : num };
  };

  const phoneRes = validateAndNormalizePhone(phone, deliveryCountryForFee);
  const isPhoneValid = phoneRes.isValid;
  const normalizedPhone = phoneRes.normalized;

  // Recipient phone for the delivery address — separate from the contact
  // phone collected in Step 1. Defaults to the contact phone if empty.
  const recipientCountryHint = (selectedAddress && selectedAddress.delivery_country) || "NL";
  const recipientCountry = (recipientCountryHint === "België" || recipientCountryHint === "Belgium" || recipientCountryHint === "BE") ? "BE"
                         : (recipientCountryHint === "Duitsland" || recipientCountryHint === "Germany" || recipientCountryHint === "DE") ? "DE"
                         : "NL";
  const recipientPhoneRes = validateAndNormalizePhone(deliveryPhoneRecipient || phone, recipientCountry);
  const isRecipientPhoneValid = recipientPhoneRes.isValid;
  const normalizedRecipientPhone = recipientPhoneRes.normalized;

  const isFirstNameValid = firstName.trim().length >= 2;
  const isLastNameValid = lastName.trim().length >= 2;
  const isEmailMatch = email.trim().toLowerCase() === confirmEmail.trim().toLowerCase() && confirmEmail.trim() !== "";
  const isPhoneMatch = phone.trim() === confirmPhone.trim() && confirmPhone.trim() !== "";

  const step1Valid = isFirstNameValid && isLastNameValid && isEmailValid(email) && isEmailMatch && isPhoneValid && isPhoneMatch;

  // ----- Red error rendering for the contact step ---------------------------
  // #ef4444 is a bright red that stays legible in both light and dark mode.
  const ERR_RED = "#ef4444";
  const errBorder = (hasErr) => hasErr ? { borderColor: ERR_RED } : undefined;

  // Per-field error text (null when the field is valid). Empty vs invalid get
  // distinct messages so the customer knows exactly what's wrong.
  const firstNameErrMsg = isFirstNameValid ? null : t("Vul je voornaam in.","Enter your first name.");
  const lastNameErrMsg  = isLastNameValid  ? null : t("Vul je achternaam in.","Enter your last name.");
  const emailErrMsg = isEmailValid(email) ? null
    : (email.trim() === "" ? t("Vul je e-mailadres in.","Enter your email address.")
                           : t("Vul een geldig e-mailadres in.","Enter a valid email address."));
  const confirmEmailErrMsg = isEmailMatch ? null
    : (confirmEmail.trim() === "" ? t("Bevestig je e-mailadres.","Confirm your email address.")
                                  : t("De e-mailadressen komen niet overeen.","The email addresses do not match."));
  const phoneErrMsg = isPhoneValid ? null
    : (phone.trim() === "" ? t("Vul je telefoonnummer in.","Enter your phone number.")
                           : t("Vul een geldig telefoonnummer in.","Enter a valid phone number."));
  const confirmPhoneErrMsg = isPhoneMatch ? null
    : (confirmPhone.trim() === "" ? t("Bevestig je telefoonnummer.","Confirm your phone number.")
                                  : t("De telefoonnummers komen niet overeen.","The phone numbers do not match."));

  // A field surfaces its error once a submit was attempted OR it was typed in.
  const seen = (val) => step1Submitted || String(val).trim() !== "";
  const dFirstName    = seen(firstName)    ? firstNameErrMsg    : null;
  const dLastName     = seen(lastName)     ? lastNameErrMsg     : null;
  const dEmail        = seen(email)        ? emailErrMsg        : null;
  const dConfirmEmail = seen(confirmEmail) ? confirmEmailErrMsg : null;
  const dPhone        = seen(phone)        ? phoneErrMsg        : null;
  const dConfirmPhone = seen(confirmPhone) ? confirmPhoneErrMsg : null;

  // Focus + scroll the first invalid contact field (visual order).
  const focusFirstContactError = () => {
    const seq = [
      [!isFirstNameValid, firstNameRef],
      [!isLastNameValid, lastNameRef],
      [!isEmailValid(email), emailRef],
      [!isEmailMatch, confirmEmailRef],
      [!isPhoneValid, phoneRef],
      [!isPhoneMatch, confirmPhoneRef],
    ];
    const bad = seq.find(function (e) { return e[0]; });
    if (bad && bad[1] && bad[1].current) {
      try { bad[1].current.focus(); bad[1].current.scrollIntoView({ behavior: "smooth", block: "center" }); } catch (_) {}
    }
  };

  // Step-1 "Doorgaan naar levering": stays clickable. On invalid it reveals the
  // red errors, focuses the first bad field, and refuses to advance.
  const continueToDelivery = () => {
    setStep1Submitted(true);
    if (step1Valid) { setStep(2); return; }
    focusFirstContactError();
  };

  // Shared guard for BOTH place-order paths (Mollie + cash). Blocks the action
  // and surfaces the red errors when contact data is incomplete or a required
  // checkbox is unchecked. Returns true only when it is safe to create an order.
  const checkoutGuard = () => {
    if (!step1Valid) {
      setStep1Submitted(true);
      setSaveError(t("Vul eerst al je contactgegevens correct in.","Please complete all your contact details first."));
      setStep(1); // step-1 inputs aren't mounted this tick — don't focus here.
      return false;
    }
    if (!detailsConfirmed || !acceptedTerms) {
      setConfirmSubmitted(true);
      setSaveError(null); // the per-checkbox red text is the visible signal
      return false;
    }
    return true;
  };

  const isDeliveryNameValid = deliveryName.trim().length >= 2;
  const isDeliveryAddressValid = !!(
    addressVerified
    && selectedAddress
    && selectedAddress.delivery_place_id
    && selectedAddress.delivery_street
    && selectedAddress.delivery_postcode
    && selectedAddress.delivery_city
    && selectedAddress.delivery_country
  );

  const step2Valid = fulfillment === "ophalen"
    ? pickupEnabled
    : fulfillment === "bezorgen"
      ? (deliveryEnabled && isDeliveryNameValid && isRecipientPhoneValid && isDeliveryAddressValid)
      : false;

  // Prefill from profile when logged in
  useEffect(() => {
    if (auth && auth.user) {
      setEmail(auth.user.email || "");
      setConfirmEmail(auth.user.email || "");
      const fn = (auth.profile && auth.profile.full_name) || "";
      if (fn && !firstName && !lastName) {
        const parts = fn.split(" ");
        setFirstName(parts[0] || "");
        setLastName(parts.slice(1).join(" ") || "");
      }
      if (auth.profile && auth.profile.phone && !phone) {
        setPhone(auth.profile.phone);
        setConfirmPhone(auth.profile.phone);
      }
    }
    // eslint-disable-next-line
  }, [auth && auth.user, auth && auth.profile]);

  // Prefill the recipient name from contact details (customer can override).
  useEffect(() => {
    if (!deliveryName && (firstName || lastName)) {
      const full = (firstName + " " + lastName).trim();
      if (full) setDeliveryName(full);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [firstName, lastName]);

  // Debounced Google Places autocomplete.
  useEffect(() => {
    if (fulfillment !== "bezorgen") return;
    const q = addrInput.trim();
    if (!q || q.length < 3) { setAddrSuggestions([]); setAddrLoading(false); return; }
    if (addressVerified) return; // don't re-query while showing a confirmed selection
    let cancelled = false;
    setAddrLoading(true);
    const tmr = setTimeout(async () => {
      const r = await window.zsb.addressAutocomplete(q, addrSessionToken);
      if (cancelled) return;
      setAddrLoading(false);
      if (r && r.error) { setAddrError(r.error); setAddrSuggestions([]); return; }
      setAddrError(null);
      setAddrSuggestions((r && r.predictions) || []);
    }, 240);
    return () => { cancelled = true; clearTimeout(tmr); };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [addrInput, fulfillment, addrSessionToken, addressVerified]);

  const handleSelectSuggestion = async (pred) => {
    if (!pred || !pred.place_id) return;
    setAddrSuggestions([]);
    setAddrLoading(true);
    setAddrError(null);
    const r = await window.zsb.addressDetails(pred.place_id, addrSessionToken);
    setAddrLoading(false);
    if (!r || !r.ok || !r.delivery_street || !r.delivery_postcode || !r.delivery_city) {
      setAddrError(t(
        "Kon adresgegevens niet ophalen. Kies een ander adres.",
        "Could not fetch address details. Try a different address."
      ));
      return;
    }
    setSelectedAddress(r);
    setAddrInput(r.delivery_formatted_address || pred.description);
    setAddressVerified(true);
  };

  const handleAddrInputChange = (e) => {
    const v = e.target.value;
    setAddrInput(v);
    setAddrError(null);
    if (addressVerified) {
      // Customer is editing after a confirmed selection — un-verify so the
      // payment button blocks until they pick a new suggestion.
      setAddressVerified(false);
      setSelectedAddress(null);
    }
  };

  const handleClearAddress = () => {
    setSelectedAddress(null);
    setAddressVerified(false);
    setAddrInput("");
    setAddrSuggestions([]);
    setAddrError(null);
  };

  // Invalidate the cached savedOrderId whenever the cart changes OR the
  // signed-in user changes. Reusing a stale order id after the cart has
  // moved on (item added/removed/qty bumped/unavailable cleaned out) would
  // either pay for the wrong total or hit "Order not found".
  useEffect(() => {
    if (savedOrderId) setSavedOrderId(null);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [JSON.stringify(cart.items)]);
  useEffect(() => {
    if (savedOrderId) setSavedOrderId(null);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth && auth.user && auth.user.id]);

  // Build the order payload from cart
  const buildOrderPayload = () => {
    const bikeIds = ["v20", "gt2000"];
    // Treat svc-assembly AND svc-assembly-<slug> all as "assembly" — split them
    // out of `products` and sum into a single assembly_fee.
    const isAssembly = (id) => id === "svc-assembly" || (typeof id === "string" && id.startsWith("svc-assembly-"));
    const products = cart.items
      .filter(it => !isAssembly(it.id))
      .map(it => {
        const p = ALL_ITEMS[it.id] || {};
        return { id: it.id, name: LP(p,"name",lang) || LP(p,"short",lang) || p.name || p.short || it.id, price: p.price, qty: it.qty };
      });
    const assemblyItems = cart.items.filter(it => isAssembly(it.id));
    const assembly_fee = assemblyItems.reduce((sum, it) => {
      const p = ALL_ITEMS[it.id];
      return sum + ((p && Number(p.price)) || 0) * it.qty;
    }, 0);
    const containsBike = cart.items.some(it => bikeIds.includes(it.id));
    const isDelivery = fulfillment === "bezorgen";
    const isCash = payMethod === "cash" && cashEligible;
    const addr = selectedAddress || {};
    return {
      user_id: (auth && auth.user) ? auth.user.id : null,
      customer_name: `${firstName} ${lastName}`.trim(),
      customer_email: email.trim(),
      customer_phone: normalizedPhone,
      order_type: containsBike && fulfillment === "ophalen" && pickupDate ? "reservering" : "bestelling",
      fulfillment_method: fulfillment,
      pickup_location: fulfillment === "ophalen"
        ? `${cfg.PICKUP_LOCATION.street}, ${cfg.PICKUP_LOCATION.postcode} ${cfg.PICKUP_LOCATION.city}${pickupDate ? " · gewenste datum: " + pickupDate : ""}`
        : null,

      // Customer-verified delivery address (Google Places). All NULL when
      // fulfillment is "ophalen" — we never write the company address into
      // delivery_* fields.
      delivery_name:               isDelivery ? deliveryName.trim() : null,
      delivery_phone:              isDelivery ? normalizedRecipientPhone : null,
      delivery_place_id:           isDelivery ? (addr.delivery_place_id || null) : null,
      delivery_formatted_address:  isDelivery ? (addr.delivery_formatted_address || null) : null,
      delivery_street:             isDelivery ? (addr.delivery_street || null) : null,
      delivery_postcode:           isDelivery ? (addr.delivery_postcode || null) : null,
      delivery_city:               isDelivery ? (addr.delivery_city || null) : null,
      delivery_country:            isDelivery ? (addr.delivery_country || null) : null,
      delivery_lat:                isDelivery ? (addr.delivery_lat ?? null) : null,
      delivery_lng:                isDelivery ? (addr.delivery_lng ?? null) : null,
      delivery_address_verified:   isDelivery ? !!addressVerified : false,

      shipping_country:            isDelivery ? (addr.delivery_country || "Nederland") : "NL",

      products,
      subtotal: cart.subtotal - assembly_fee,
      assembly_fee,
      shipping_fee: effectiveShipping,
      vat_amount: checkoutVat,
      total: checkoutTotal,
      status: "in_behandeling",

      // Cash on pickup: stamp the payment columns at creation time so the order
      // is authoritative immediately. The /api/send-cash-confirmation endpoint
      // re-asserts these server-side. Online orders are left UNCHANGED (no
      // payment_* keys) so the existing Mollie flow is not touched at all.
      ...(isCash ? { payment_method: "cash", payment_status: "pending_cash" } : {}),
    };
  };

  const finalizeOrder = async () => {
    setSaving(true); setSaveError(null);

    // Guard: never create (or reuse) a € 0,00 order. subtotal / vat_amount /
    // total all derive from cart.subtotal, which is 0 when the cart holds no
    // priced items at submit time — e.g. the item was added as a guest and the
    // login that checkout requires reloaded the (un-merged) per-user cart empty.
    // Online masks this because Mollie rejects a € 0 amount; cash has no gateway,
    // so a € 0 order would persist silently. Refuse here, before any order row is
    // written. Shared by the online and cash paths; does NOT touch Mollie.
    const hasPricedItem = cart.items.some(it => Number((ALL_ITEMS[it.id] || {}).price) > 0);
    if (!hasPricedItem || !(checkoutTotal > 0)) {
      setSaveError(t(
        "Je winkelmand is leeg of het totaal is € 0,00. Voeg een product toe en probeer opnieuw.",
        "Your cart is empty or the total is € 0.00. Add a product and try again."
      ));
      setSaving(false);
      return null;
    }

    // Reuse a previously created order ONLY if it still exists in Supabase AND
    // still has a real (> 0) total. A stale savedOrderId can survive in state
    // across cart edits, logins, or DB cleanups — reusing a € 0 / missing order
    // would persist the wrong total or hit "Order not found". When in doubt we
    // drop it and create a fresh order from the current (guarded) cart.
    if (savedOrderId) {
      const existing = await window.zsb.getOrder(savedOrderId);
      if (existing && existing.data && existing.data.id && Number(existing.data.total) > 0) {
        setSaving(false);
        return { id: savedOrderId };
      }
      setSavedOrderId(null);
    }

    if (!auth || !auth.user) {
      setSaveError(t("Log in om veilig via Mollie te betalen en je bestelling te volgen.","Sign in to pay securely with Mollie and track your order."));
      setSaving(false);
      return null;
    }
    if (!window.zsb || !window.zsb.isConfigured) {
      setSaveError(t("Supabase is nog niet geconfigureerd. Betalen kan nu niet gestart worden.","Supabase is not configured yet. Payment cannot be started."));
      setSaving(false);
      return null;
    }
    // Final guard: refuse to create an order with sold-out / unavailable items.
    if (cart.hasUnavailable || (window.hasUnavailableCartItem && window.hasUnavailableCartItem(cart.items))) {
      setSaveError(t("Een product in je winkelmand is niet meer beschikbaar.","An item in your cart is no longer available."));
      setSaving(false);
      return null;
    }
    const payload = buildOrderPayload();
    const r = await window.zsb.createOrder(payload);
    if (r.error) { setSaveError(r.error); setSaving(false); return null; }
    const orderId = r.data && r.data.id ? r.data.id : null;
    if (!orderId) {
      setSaveError(t("Bestelling kon niet opgeslagen worden. Probeer opnieuw.","Order could not be saved. Please try again."));
      setSaving(false);
      return null;
    }
    console.log("[checkout] created order id:", orderId);
    setSavedOrderId(orderId);
    setSaving(false);
    return r.data;
  };

  const startMolliePayment = async () => {
    // Block incomplete checkout BEFORE any order row is created or payment starts.
    if (!checkoutGuard()) return;
    setPaymentBusy(true);
    setSaveError(null);
    const order = await finalizeOrder();
    if (!order || !order.id) {
      setPaymentBusy(false);
      return;
    }

    // Strict auth guard: must have a real, JWT-shaped Supabase access token
    // before we touch /api. No token => stop here and ask the user to sign in.
    const ZSB = window.ZSB || window.zsb;
    const token = ZSB && ZSB.getAccessToken ? await ZSB.getAccessToken() : null;
    // Debug breadcrumb only — never log the token itself.
    console.log("[checkout] has access token:", !!token);
    if (!token) {
      setSaveError(lang === "en" ? "Sign in to pay securely." : "Log in om veilig te betalen.");
      setPaymentBusy(false);
      return;
    }

    console.log("[checkout] sending Mollie order id:", order.id);
    try {
      const response = await fetch("/api/create-mollie-payment", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${token}`,
        },
        body: JSON.stringify({
          order_id: order.id,
          locale: lang === "en" ? "en_GB" : "nl_NL",
          // Confirmation flags — the server re-validates and refuses the payment
          // when these aren't true (defense in depth; see /api/create-mollie-payment).
          confirmed_details: true,
          accepted_terms: true,
        }),
      });
      const json = await response.json().catch(() => ({}));
      setPaymentBusy(false);
      if (!response.ok) {
        setSaveError(json.error || t("Betaling kon niet gestart worden.","Payment could not be started."));
        return;
      }
      if (json.checkoutUrl) {
        window.location.href = json.checkoutUrl;
      } else {
        setSaveError(t("Betaling kon niet gestart worden.","Payment could not be started."));
      }
    } catch (e) {
      setPaymentBusy(false);
      setSaveError(t("Betaling kon niet gestart worden. Controleer je internet en probeer opnieuw.","Payment could not be started. Check your connection and try again."));
    }
  };

  // Cash-on-pickup path. NEVER calls /api/create-mollie-payment. Creates the
  // order (payment_method="cash", payment_status="pending_cash"), then calls
  // /api/send-cash-confirmation which re-validates the cash rules server-side,
  // mints a confirmation number and sends the "bestelling ontvangen – contant
  // betalen" email. On success we route to the payment-success page (cash
  // variant) which shows the "pay on pickup" state without polling.
  const startCashOrder = async () => {
    // Block incomplete checkout BEFORE any order row is created.
    if (!checkoutGuard()) return;
    setPaymentBusy(true);
    setSaveError(null);

    // Client-side guard (the server re-checks both rules independently).
    if (fulfillment !== "ophalen") {
      setSaveError(t("Contant betalen is alleen mogelijk bij ophalen.","Cash payment is only possible for pickup."));
      setPaymentBusy(false);
      return;
    }
    if (checkoutTotal >= CASH_LIMIT) {
      setSaveError("Contant betalen is niet mogelijk voor bedragen vanaf €3.000. Kies online betalen.");
      setPaymentBusy(false);
      return;
    }
    if (!auth || !auth.user) {
      setSaveError(lang === "en"
        ? "Sign in to place your order and pay cash on pickup."
        : "Log in om je bestelling te plaatsen en contant te betalen bij ophalen.");
      setPaymentBusy(false);
      return;
    }

    const order = await finalizeOrder();
    if (!order || !order.id) {
      setPaymentBusy(false);
      return;
    }

    const ZSB = window.ZSB || window.zsb;
    const token = ZSB && ZSB.getAccessToken ? await ZSB.getAccessToken() : null;
    console.log("[checkout] cash order, has access token:", !!token);
    if (!token) {
      setSaveError(lang === "en" ? "Sign in to place your order." : "Log in om je bestelling te plaatsen.");
      setPaymentBusy(false);
      return;
    }

    console.log("[checkout] sending cash confirmation for order id:", order.id);
    const r = await ZSB.sendCashOrderConfirmation(order.id, { confirmed_details: true, accepted_terms: true });
    setPaymentBusy(false);
    if (r && r.error) {
      setSaveError(r.error);
      return;
    }
    // Order is placed and the confirmation email is on its way. Clear the cart
    // and route to the success page (cash variant). The hash router splits the
    // slug on [&?], so "payment-success?order_id=…" resolves to PagePaymentSuccess.
    cart.clear();
    window.location.hash = "payment-success?order_id=" + order.id;
  };

  const whatsappOrderText = () => {
    const lines = [
      t("Ik wil een bestelling plaatsen via Zyro Electric.","I want to place an order with Zyro Electric."),
      "",
      `${t("Naam","Name")}: ${firstName} ${lastName}`,
      `${t("E-mail","Email")}: ${email}`,
      `${t("Telefoon","Phone")}: ${phone}`,
      "",
      t("Producten:","Products:"),
      ...cart.items.map(it => {
        const p = ALL_ITEMS[it.id] || {};
        return `• ${it.qty}× ${LP(p,"name",lang) || LP(p,"short",lang) || p.name || p.short || it.id} — ${formatEUR((p.price || 0) * it.qty)}`;
      }),
      "",
      `${t("Totaal","Total")}: ${formatEUR(checkoutTotal)}`,
      "",
      fulfillment === "ophalen"
        ? `${t("Ophalen op","Pickup at")} ${cfg.PICKUP_LOCATION.street}, ${cfg.PICKUP_LOCATION.postcode} ${cfg.PICKUP_LOCATION.city}` + (pickupDate ? ` (${t("voorkeur","preferred")} ${pickupDate})` : "")
        : `${t("Bezorgen op","Deliver to")} ${(selectedAddress && selectedAddress.delivery_formatted_address) || ""}`,
      note ? "" : null,
      note ? `${t("Opmerking","Note")}: ${note}` : null,
    ].filter(Boolean);
    return getWhatsAppHref(lines.join("\n"));
  };

  return (
    <div className="page">
      <section style={{padding:"32px 0 24px", borderBottom:"1px solid var(--line)", background:"var(--paper)"}}>
        <div className="wrap" style={{display:"flex", alignItems:"center", justifyContent:"space-between", flexWrap:"wrap", gap:16}}>
          <Logo onClick={()=>setPage("home")}/>
          <div className="gap-8" style={{flexWrap:"wrap"}}>
            {[
              t("Gegevens","Details"),
              t("Levering","Delivery"),
              t("Bevestigen","Confirm"),
              t("Klaar","Done"),
            ].map((s,i) => (
              <React.Fragment key={s}>
                <div className="gap-8">
                  <div style={{
                    width:26, height:26, borderRadius:50, display:"grid", placeItems:"center",
                    background: step >= i+1 ? "var(--accent)" : "var(--bg)",
                    color: step >= i+1 ? "#fff" : "var(--ink-mute)",
                    fontFamily:"var(--f-display)", fontWeight:700, fontSize:12,
                    border: step === i+1 ? "2px solid var(--accent)" : "1px solid var(--line)"
                  }}>{i+1}</div>
                  <span style={{fontSize:13, fontWeight: step === i+1 ? 600 : 500, color: step >= i+1 ? "var(--ink)" : "var(--ink-mute)"}}>{s}</span>
                </div>
                {i < 3 && <div style={{width:30, height:1, background:"var(--line)"}}/>}
              </React.Fragment>
            ))}
          </div>
          <div className="mono" style={{fontSize:11, color:"var(--ink-mute)", letterSpacing:".1em"}}>
            <Icon name="lock" size={11} style={{display:"inline-block", verticalAlign:"-1px", marginRight:4}}/>{t("SSL VEILIG","SSL SECURE")}
          </div>
        </div>
      </section>

      <section className="section-sm">
        <div className="wrap" style={{display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:32}} className="co-grid">
          <div>
            {step === 1 && (
              <div className="card" style={{padding:32}}>
                <h2 className="h-display" style={{fontSize:24, marginBottom:6}}>{t("Contactgegevens","Contact details")}</h2>
                {auth && auth.user ? (
                  <p style={{color:"var(--ink-dim)", fontSize:14, marginBottom:24}}>
                    {t("Ingelogd als","Signed in as")} <strong>{auth.user.email}</strong> · {t("je bestelling wordt zichtbaar in","your order will appear in")} <a className="accent" onClick={()=>setPage("account")} style={{cursor:"pointer"}}>{t("Mijn account","My account")}</a>.
                  </p>
                ) : (
                  <p style={{color:"var(--ink-dim)", fontSize:14, marginBottom:24}}>
                    {t("Heb je al een account?","Already have an account?")} <a className="accent" onClick={()=>setPage("login")} style={{cursor:"pointer"}}>{t("Log in","Sign in")}</a> {t("om je bestelling te kunnen volgen.","to track your order.")}
                  </p>
                )}
                <div className="grid-2" style={{marginBottom:14}}>
                  <div className="field">
                    <label className="field-label">{t("Voornaam","First name")}</label>
                    <input ref={firstNameRef} className="input" style={errBorder(!!dFirstName)} value={firstName} onChange={e=>setFirstName(e.target.value)} placeholder={t("Jan","John")} autoComplete="given-name" required/>
                    {dFirstName && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dFirstName}</div>}
                  </div>
                  <div className="field">
                    <label className="field-label">{t("Achternaam","Last name")}</label>
                    <input ref={lastNameRef} className="input" style={errBorder(!!dLastName)} value={lastName} onChange={e=>setLastName(e.target.value)} placeholder={t("de Vries","Doe")} autoComplete="family-name" required/>
                    {dLastName && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dLastName}</div>}
                  </div>
                </div>
                <div className="grid-2" style={{marginBottom:14}}>
                  <div className="field">
                    <label className="field-label">{t("E-mail","Email")}</label>
                    <input ref={emailRef} className="input" style={errBorder(!!dEmail)} type="email" value={email} onChange={e=>setEmail(e.target.value)} placeholder={t("jan@email.nl","you@email.com")} autoComplete="email" required/>
                    {dEmail && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dEmail}</div>}
                  </div>
                  <div className="field">
                    <label className="field-label">{t("Bevestig e-mail","Confirm email")}</label>
                    <input ref={confirmEmailRef} className="input" style={errBorder(!!dConfirmEmail)} type="email" value={confirmEmail} onChange={e=>setConfirmEmail(e.target.value)} placeholder={t("jan@email.nl","you@email.com")} autoComplete="email" required/>
                    {dConfirmEmail && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dConfirmEmail}</div>}
                  </div>
                </div>
                <div className="grid-2" style={{marginBottom:14}}>
                  <div className="field">
                    <label className="field-label">{t("Telefoonnummer","Phone number")}</label>
                    <input ref={phoneRef} className="input" style={errBorder(!!dPhone)} type="tel" value={phone} onChange={e=>setPhone(e.target.value)} placeholder="+31 6 ..." autoComplete="tel" required/>
                    {dPhone && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dPhone}</div>}
                  </div>
                  <div className="field">
                    <label className="field-label">{t("Bevestig telefoonnummer","Confirm phone number")}</label>
                    <input ref={confirmPhoneRef} className="input" style={errBorder(!!dConfirmPhone)} type="tel" value={confirmPhone} onChange={e=>setConfirmPhone(e.target.value)} placeholder="+31 6 ..." autoComplete="tel" required/>
                    {dConfirmPhone && <div style={{color:ERR_RED, fontSize:12, marginTop:4}}>{dConfirmPhone}</div>}
                  </div>
                </div>
                <div className="field" style={{marginBottom:24}}>
                  <label className="field-label">{t("Opmerkingen (optioneel)","Notes (optional)")}</label>
                  <textarea className="textarea" rows={3} value={note} onChange={e=>setNote(e.target.value)} placeholder={t("Bijv. bezorgvoorkeur of afleverinstructies.","E.g. delivery preferences or instructions.")}/>
                </div>
                <div className="gap-12" style={{justifyContent:"space-between"}}>
                  <button className="btn btn-ghost" onClick={()=>setPage("cart")}>← {t("Terug naar mand","Back to cart")}</button>
                  <button className="btn btn-primary btn-lg" onClick={continueToDelivery}>{t("Doorgaan naar levering","Continue to delivery")} <Icon name="arrow" size={15}/></button>
                </div>
              </div>
            )}

            {step === 2 && (
              <div className="card" style={{padding:32}}>
                <h2 className="h-display" style={{fontSize:24, marginBottom:6}}>{t("Levering","Delivery")}</h2>
                <p style={{color:"var(--ink-dim)", fontSize:14, marginBottom:22}}>{t("Kies of je je bestelling komt ophalen of laat bezorgen.","Choose whether to pick up your order or have it delivered.")} <strong>{t("Vereist.","Required.")}</strong></p>

                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:10, marginBottom:18}}>
                  {[
                    {id:"ophalen", disabled:!pickupEnabled, t:t("Ophalen","Pickup"), s:t("Gratis ophalen · Showroom Utrecht","Free pickup · Showroom Utrecht"), icon:"pin"},
                    {id:"bezorgen", disabled:!deliveryEnabled, t:t("Bezorgen","Delivery"), s:effectiveShipping === 0 ? t("Gratis verzending","Free shipping") : `${t("Verzendkosten","Shipping costs")}: ${formatEUR(effectiveShipping)}`, icon:"truck"},
                  ].map(opt => (
                    <label key={opt.id} style={{
                      display:"flex", alignItems:"center", gap:12, padding:"16px 18px",
                      border: fulfillment === opt.id ? "2px solid var(--accent)" : "1px solid var(--line)",
                      borderRadius:10, background: fulfillment === opt.id ? "var(--accent-soft)" : "#fff",
                      cursor: opt.disabled ? "not-allowed" : "pointer", opacity: opt.disabled ? .55 : 1
                    }}>
                      <input type="radio" name="fulfillment" checked={fulfillment === opt.id} onChange={()=>!opt.disabled && setFulfillment(opt.id)} disabled={opt.disabled} style={{accentColor:"var(--accent)"}}/>
                      <div style={{width:36, height:36, borderRadius:8, background:"#fff", color:"var(--accent)", display:"grid", placeItems:"center", border:"1px solid var(--line)"}}>
                        <Icon name={opt.icon} size={16}/>
                      </div>
                      <div style={{flex:1}}>
                        <div style={{fontWeight:600, fontSize:15}}>{opt.t}</div>
                        <div style={{fontSize:12.5, color:"var(--ink-dim)"}}>{opt.s}</div>
                      </div>
                    </label>
                  ))}
                </div>

                {fulfillment === "ophalen" && (
                  <div className="card" style={{padding:18, background:"var(--bg)", marginBottom:16}}>
                    <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", letterSpacing:".1em", textTransform:"uppercase", marginBottom:8}}>{t("Ophaaladres","Pickup address")}</div>
                    <div style={{fontSize:14.5, lineHeight:1.6, marginBottom:14}}>
                      <strong>{cfg.PICKUP_LOCATION.street}</strong><br/>
                      {cfg.PICKUP_LOCATION.postcode} {cfg.PICKUP_LOCATION.city}<br/>
                      {cfg.PICKUP_LOCATION.country}
                    </div>
                    <div className="field">
                      <label className="field-label">{t("Voorkeur ophaaldatum / tijd (optioneel)","Preferred pickup date / time (optional)")}</label>
                      <input className="input" value={pickupDate} onChange={e=>setPickupDate(e.target.value)} placeholder={t("Bijv. zaterdag 14:00","e.g. Saturday 14:00")}/>
                    </div>
                    <p style={{fontSize:12, color:"var(--ink-dim)", marginTop:10}}>{t("We bevestigen je afspraak per e-mail of telefoon.","We'll confirm your appointment by email or phone.")}</p>
                  </div>
                )}

                {fulfillment === "bezorgen" && (
                  <div className="card" style={{padding:18, background:"var(--bg)", marginBottom:16}}>
                    <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", letterSpacing:".1em", textTransform:"uppercase", marginBottom:8}}>{t("Bezorgadres","Delivery address")}</div>

                    <div className="grid-2" style={{marginBottom:12}}>
                      <div className="field">
                        <label className="field-label">{t("Naam ontvanger","Recipient name")}</label>
                        <input className="input" value={deliveryName} onChange={e=>setDeliveryName(e.target.value)} placeholder={t("Naam op deurbel/box","Name on doorbell/box")} autoComplete="name" required/>
                        {!isDeliveryNameValid && deliveryName.trim() !== "" && <div style={{color:"var(--bad)", fontSize:12, marginTop:4}}>{t("Vul de volledige naam in.","Enter the full name.")}</div>}
                      </div>
                      <div className="field">
                        <label className="field-label">{t("Telefoonnummer ontvanger","Recipient phone")}</label>
                        <input className="input" type="tel" value={deliveryPhoneRecipient} onChange={e=>setDeliveryPhoneRecipient(e.target.value)} placeholder="+31 6 ..." autoComplete="tel" required/>
                        {!isRecipientPhoneValid && deliveryPhoneRecipient.trim() !== "" && <div style={{color:"var(--bad)", fontSize:12, marginTop:4}}>{t("Vul een geldig telefoonnummer in.","Enter a valid phone number.")}</div>}
                      </div>
                    </div>

                    <div className="field" style={{position:"relative", marginBottom:8}}>
                      <label className="field-label">{t("Zoek je adres","Search for your address")}</label>
                      <input
                        className="input"
                        value={addrInput}
                        onChange={handleAddrInputChange}
                        placeholder={t("Begin met typen — straat, postcode of plaats","Start typing — street, postal code or city")}
                        autoComplete="off"
                        spellCheck="false"
                      />
                      {addrLoading && (
                        <div style={{position:"absolute", right:12, top:34, fontSize:11, color:"var(--ink-mute)"}}>{t("Zoeken…","Searching…")}</div>
                      )}
                      {!addressVerified && addrSuggestions.length > 0 && (
                        <ul style={{
                          listStyle:"none", margin:"6px 0 0", padding:0,
                          position:"absolute", left:0, right:0, top:"100%", zIndex:30,
                          background:"#fff", border:"1px solid var(--line)", borderRadius:8,
                          boxShadow:"0 12px 24px rgba(0,0,0,.08)", overflow:"hidden",
                        }}>
                          {addrSuggestions.map(p => (
                            <li key={p.place_id}
                                onMouseDown={(e)=>{ e.preventDefault(); handleSelectSuggestion(p); }}
                                style={{padding:"10px 14px", cursor:"pointer", fontSize:13.5, borderBottom:"1px solid var(--line)"}}>
                              {p.description}
                            </li>
                          ))}
                        </ul>
                      )}
                    </div>

                    {addrError && (
                      <div style={{color:"var(--bad)", fontSize:12, marginBottom:8}}>{addrError}</div>
                    )}

                    {!addressVerified && addrInput.trim().length >= 3 && addrSuggestions.length === 0 && !addrLoading && (
                      <div style={{color:"var(--bad)", fontSize:12, marginBottom:8}}>
                        {t(
                          "Selecteer een geldig bestaand bezorgadres voordat je verdergaat met betalen.",
                          "Select a valid existing delivery address before continuing to payment."
                        )}
                      </div>
                    )}

                    {selectedAddress && addressVerified && (
                      <div className="card" style={{padding:12, marginTop:6, marginBottom:8, background:"#e7f4ec", border:"1px solid #bfe0cb"}}>
                        <div style={{display:"flex", justifyContent:"space-between", alignItems:"flex-start", gap:14}}>
                          <div style={{fontSize:13, lineHeight:1.5}}>
                            <div style={{fontWeight:600, color:"#1f6b3a"}}>✓ {t("Geselecteerd adres","Selected address")}</div>
                            <div style={{marginTop:4, color:"var(--ink)"}}>{selectedAddress.delivery_formatted_address || (selectedAddress.delivery_street + ", " + (selectedAddress.delivery_postcode||"") + " " + (selectedAddress.delivery_city||""))}</div>
                          </div>
                          <button type="button" className="btn btn-ghost btn-sm" onClick={handleClearAddress}>{t("Wijzigen","Change")}</button>
                        </div>
                      </div>
                    )}

                    <div className="cart-totals" style={{fontSize:12.5, marginTop:12}}>
                      <div className="row">
                        <span>{t("Verzendkosten","Shipping costs")}</span>
                        <span>{effectiveShipping === 0 ? <strong style={{color:"var(--ok)"}}>{t("Gratis","Free")}</strong> : formatEUR(effectiveShipping)}</span>
                      </div>
                      {freeThreshold > 0 && cart.subtotal < freeThreshold && (
                        <div className="row" style={{color:"var(--ink-mute)"}}>
                          <span>{t("Gratis verzending vanaf","Free shipping from")} {formatEUR(freeThreshold)}</span>
                          <span>{t("nog","still")} {formatEUR(freeThreshold - cart.subtotal)}</span>
                        </div>
                      )}
                    </div>
                    <p style={{fontSize:12, color:"var(--ink-dim)", marginTop:10}}>{t("Levertijd 1-3 werkdagen. We nemen telefonisch contact op voor het bezorgmoment.","Delivery in 1-3 business days. We'll call to arrange the delivery time.")}</p>
                  </div>
                )}

                <div className="gap-12" style={{justifyContent:"space-between"}}>
                  <button className="btn btn-ghost" onClick={()=>setStep(1)}>← {t("Vorige","Previous")}</button>
                  <button className="btn btn-primary btn-lg" onClick={()=>setStep(3)} disabled={!step2Valid}>
                    {t("Doorgaan naar bevestigen","Continue to confirm")} <Icon name="arrow" size={15}/>
                  </button>
                </div>
              </div>
            )}

            {step === 3 && (
              <div className="card" style={{padding:32}}>
                <h2 className="h-display" style={{fontSize:24, marginBottom:16}}>{t("Bevestig je bestelling","Confirm your order")}</h2>

                <div className="card" style={{padding:18, background:"var(--bg)", marginBottom:18}}>
                  <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", letterSpacing:".1em", textTransform:"uppercase", marginBottom:8}}>{t("Levering","Delivery")}</div>
                  {fulfillment === "ophalen" ? (
                    <div style={{fontSize:14, lineHeight:1.6}}>
                      <strong>{t("Ophalen","Pickup")}:</strong> {cfg.PICKUP_LOCATION.street}, {cfg.PICKUP_LOCATION.postcode} {cfg.PICKUP_LOCATION.city}
                      {pickupDate && <><br/><span style={{color:"var(--ink-dim)"}}>{t("Voorkeur","Preferred")}: {pickupDate}</span></>}
                    </div>
                  ) : (
                    <div style={{fontSize:14, lineHeight:1.6}}>
                      <strong>{t("Bezorgen","Delivery")}:</strong> {(selectedAddress && selectedAddress.delivery_formatted_address) || (t("Geen adres gekozen","No address selected"))}{deliveryName ? <><br/>{t("T.a.v.","Attn.")} {deliveryName}</> : null}
                    </div>
                  )}
                </div>

                {/* ----- Betaalmethode (online vs contant bij ophalen) ----- */}
                <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", letterSpacing:".1em", textTransform:"uppercase", marginBottom:8}}>{t("Betaalmethode","Payment method")}</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:10, marginBottom:12}} className="pay-cols">
                  <label style={{
                    display:"flex", alignItems:"center", gap:12, padding:"14px 16px",
                    border: payMethod === "online" ? "2px solid var(--accent)" : "1px solid var(--line)",
                    borderRadius:10, background: payMethod === "online" ? "var(--accent-soft)" : "#fff", cursor:"pointer"
                  }}>
                    <input type="radio" name="paymethod" checked={payMethod === "online"} onChange={()=>setPayMethod("online")} style={{accentColor:"var(--accent)"}}/>
                    <div style={{width:34, height:34, borderRadius:8, background:"#fff", color:"var(--accent)", display:"grid", placeItems:"center", border:"1px solid var(--line)"}}>
                      <Icon name="lock" size={15}/>
                    </div>
                    <div style={{flex:1}}>
                      <div style={{fontWeight:600, fontSize:14.5}}>{t("Online betalen","Pay online")}</div>
                      <div style={{fontSize:11.5, color:"var(--ink-dim)"}}>iDEAL · Visa · Mastercard · Apple Pay</div>
                    </div>
                  </label>

                  {fulfillment === "ophalen" && (
                    <label style={{
                      display:"flex", alignItems:"center", gap:12, padding:"14px 16px",
                      border: payMethod === "cash" ? "2px solid var(--accent)" : "1px solid var(--line)",
                      borderRadius:10, background: payMethod === "cash" ? "var(--accent-soft)" : "#fff",
                      cursor: cashEligible ? "pointer" : "not-allowed", opacity: cashEligible ? 1 : .55
                    }}>
                      <input type="radio" name="paymethod" checked={payMethod === "cash"} onChange={()=>cashEligible && setPayMethod("cash")} disabled={!cashEligible} style={{accentColor:"var(--accent)"}}/>
                      <div style={{width:34, height:34, borderRadius:8, background:"#fff", color:"var(--accent)", display:"grid", placeItems:"center", border:"1px solid var(--line)"}}>
                        <Icon name="pin" size={15}/>
                      </div>
                      <div style={{flex:1}}>
                        <div style={{fontWeight:600, fontSize:14.5}}>{t("Contant bij ophalen","Cash on pickup")}</div>
                        <div style={{fontSize:11.5, color:"var(--ink-dim)"}}>{t("Je betaalt contant in de showroom","Pay cash in the showroom")}</div>
                      </div>
                    </label>
                  )}
                </div>

                {cashBlockedByAmount && (
                  <div style={{padding:"10px 12px", borderRadius:8, background:"#fff8e6", border:"1px solid #f0d985", color:"#7a5a14", fontSize:12.5, marginBottom:14}}>
                    {t("Contant betalen is niet mogelijk voor bedragen vanaf €3.000. Kies online betalen.","Cash payment is not possible for amounts of €3,000 or more. Choose online payment.")}
                  </div>
                )}

                {/* Intro line — adapts to the chosen payment method */}
                <p style={{fontSize:13.5, color:"var(--ink-dim)", marginBottom:18}}>
                  {payMethod === "cash"
                    ? t(
                        "Je betaalt het totaalbedrag contant bij het ophalen in onze showroom. Je ontvangt direct een bevestiging per e-mail en een aparte e-mail zodra je bestelling klaarstaat om opgehaald te worden.",
                        "You'll pay the total amount in cash on pickup at our showroom. You'll receive a confirmation email right away and a separate email as soon as your order is ready for pickup."
                      )
                    : t(
                        "Je betaalt veilig via Mollie. We gebruiken het totaalbedrag uit je opgeslagen bestelling; bedragen uit de browser worden niet vertrouwd.",
                        "You pay securely with Mollie. We use the total from your saved order; amounts from the browser are not trusted."
                      )}{" "}
                  {auth && auth.user
                    ? t("Je bestelling verschijnt direct in Mijn account met statusupdates.","Your order will appear in My account with status updates.")
                    : t("Log in of maak een account aan om je bestelling te volgen.","Sign in or create an account to track your order.")}
                </p>

                <label style={{display:"flex", alignItems:"flex-start", gap:10, marginBottom: (confirmSubmitted && !detailsConfirmed) ? 4 : 12, fontSize:12.5, color:"var(--ink-dim)"}}>
                  <input type="checkbox" checked={detailsConfirmed} onChange={e=>setDetailsConfirmed(e.target.checked)} style={{marginTop:3, accentColor:"var(--accent)"}}/>
                  <span>
                    {t(
                      "Ik heb mijn gegevens gecontroleerd en bevestig dat deze kloppen.",
                      "I have checked my details and confirm they are correct."
                    )}
                  </span>
                </label>
                {confirmSubmitted && !detailsConfirmed && (
                  <div style={{color:ERR_RED, fontSize:12, margin:"0 0 12px 26px"}}>{t("Bevestig dat je gegevens kloppen.","Confirm that your details are correct.")}</div>
                )}

                {/* Bound to acceptedTerms state (was an unenforced defaultChecked box). */}
                <label style={{display:"flex", alignItems:"flex-start", gap:10, marginBottom: (confirmSubmitted && !acceptedTerms) ? 4 : 18, fontSize:12.5, color:"var(--ink-dim)"}}>
                  <input type="checkbox" checked={acceptedTerms} onChange={e=>setAcceptedTerms(e.target.checked)} style={{marginTop:3, accentColor:"var(--accent)"}}/>
                  <span>
                    {t("Ik ga akkoord met de","I agree to the")} <a className="accent" onClick={()=>setPage("regels")} style={{cursor:"pointer"}}>{t("algemene voorwaarden","terms & conditions")}</a> {t("en privacybeleid.","and privacy policy.")}
                  </span>
                </label>
                {confirmSubmitted && !acceptedTerms && (
                  <div style={{color:ERR_RED, fontSize:12, margin:"0 0 18px 26px"}}>{t("Ga akkoord met de algemene voorwaarden en het privacybeleid.","Please accept the terms & conditions and privacy policy.")}</div>
                )}

                {cart.hasUnavailable && (
                  <div style={{padding:"10px 12px", borderRadius:8, background:"#fbe9e9", border:"1px solid #efc5c5", color:"#9a2222", fontSize:13, marginBottom:12}}>
                    {t("Een product in je winkelmand is niet meer beschikbaar.","An item in your cart is no longer available.")}
                  </div>
                )}
                {saveError && <div style={{color:"var(--bad)", fontSize:13, marginBottom:12}}>{saveError}</div>}

                <div className="gap-12" style={{justifyContent:"space-between", flexWrap:"wrap"}}>
                  <button className="btn btn-ghost" onClick={()=>setStep(2)}>← {t("Vorige","Previous")}</button>
                  <div className="gap-8">
                    <a className="btn btn-whats" href={whatsappOrderText()} target="_blank" rel="noopener">
                      <Icon name="whatsapp" size={16} fill="#06281a"/> {t("Direct via WhatsApp","Direct via WhatsApp")}
                    </a>
                    {payMethod === "cash" ? (
                      <button className="btn btn-accent btn-lg" onClick={startCashOrder} disabled={saving || paymentBusy || cart.hasUnavailable}>
                        {(saving || paymentBusy)
                          ? t("Bestelling plaatsen...","Placing order...")
                          : <><Icon name="check" size={15}/> {t("Bestelling plaatsen — contant bij ophalen","Place order — cash on pickup")}</>}
                      </button>
                    ) : (
                      <button className="btn btn-accent btn-lg" onClick={startMolliePayment} disabled={saving || paymentBusy || cart.hasUnavailable}>
                        {(saving || paymentBusy)
                          ? t("Betaling voorbereiden...","Preparing payment...")
                          : <><Icon name="lock" size={15}/> {t("Betaal veilig via Mollie","Pay securely with Mollie")}</>}
                      </button>
                    )}
                  </div>
                </div>
              </div>
            )}

            {step === 4 && (
              <div className="card" style={{padding:48, textAlign:"center"}}>
                <div style={{width:80, height:80, borderRadius:50, background:"var(--accent-soft)", color:"var(--accent)", display:"grid", placeItems:"center", margin:"0 auto 22px"}}>
                  <Icon name="check" size={36}/>
                </div>
                <h2 className="h-display" style={{fontSize:32, marginBottom:10}}>{t("Bedankt voor je bestelling!","Thanks for your order!")}</h2>
                <p style={{color:"var(--ink-dim)", maxWidth:480, margin:"0 auto 18px"}}>
                  {t("We hebben je bestelling ontvangen. Je ontvangt binnen 1 werkdag een bevestiging op","We've received your order. You'll get a confirmation within 1 business day at")} <strong>{email}</strong>.
                </p>
                <div className="mono" style={{fontSize:13, color:"var(--ink-mute)", marginBottom:24}}>
                  {t("BESTELNUMMER","ORDER NUMBER")} · {savedOrderId
                    ? savedOrderId.slice(0,8).toUpperCase()
                    : "ZYR-" + new Date().getFullYear() + "-" + Math.floor(Math.random()*9000+1000)}
                </div>
                {auth && auth.user ? (
                  <div className="gap-12" style={{justifyContent:"center", flexWrap:"wrap"}}>
                    <button className="btn btn-primary" onClick={()=>{ cart.clear(); setPage("account"); }}>{t("Bekijk in Mijn account","View in My account")}</button>
                    <button className="btn btn-ghost" onClick={()=>{ cart.clear(); setPage("home"); }}>{t("Terug naar home","Back to home")}</button>
                  </div>
                ) : (
                  <>
                    <div className="card" style={{padding:14, background:"var(--bg)", marginBottom:18, maxWidth:480, margin:"0 auto 18px", fontSize:13.5}}>
                      {t("Wil je je bestelling kunnen volgen + aankoopbewijs ontvangen?","Want to track your order and get a receipt?")} <a className="accent" onClick={()=>{ cart.clear(); setPage("login"); }} style={{cursor:"pointer", fontWeight:600}}>{t("Maak een account aan","Create an account")}</a>.
                    </div>
                    <div className="gap-12" style={{justifyContent:"center", flexWrap:"wrap"}}>
                      <button className="btn btn-primary" onClick={()=>{ cart.clear(); setPage("home"); }}>{t("Terug naar home","Back to home")}</button>
                      <button className="btn btn-ghost" onClick={()=>{ cart.clear(); setPage("shop"); }}>{t("Verder winkelen","Continue shopping")}</button>
                    </div>
                  </>
                )}
              </div>
            )}
          </div>

          {/* Order summary */}
          {step < 4 && (
            <div className="card" style={{padding:24, height:"fit-content", position:"sticky", top:88}}>
              <h3 className="h-display" style={{fontSize:18, marginBottom:16}}>{t("Jouw bestelling","Your order")}</h3>
              <div style={{display:"flex", flexDirection:"column", gap:12, marginBottom:18}}>
                {cart.items.map(it => {
                  const p = ALL_ITEMS[it.id];
                  if (!p) return null;
                  const showDiscount = window.hasDiscount && window.hasDiscount(p);
                  return (
                    <div key={it.id} style={{display:"grid", gridTemplateColumns:"56px 1fr auto", gap:10, alignItems:"center"}}>
                      <div style={{width:56, height:56, borderRadius:8, background:"var(--bg)", display:"grid", placeItems:"center", overflow:"hidden"}}>
                        <CartThumb id={it.id}/>
                      </div>
                      <div>
                        <div style={{fontSize:13, fontWeight:600, lineHeight:1.2}}>{LP(p,"short",lang) || LP(p,"name",lang) || p.short || p.name}</div>
                        <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", letterSpacing:".05em"}}>{it.qty}× · {LP(p,"color",lang) || LP(p,"type",lang)}</div>
                      </div>
                      <div style={{textAlign:"right"}}>
                        {showDiscount && <div className="mono" style={{fontSize:10.5, color:"var(--ink-mute)", textDecoration:"line-through"}}>{formatEUR(p.oldPrice * it.qty)}</div>}
                        <div style={{fontFamily:"var(--f-display)", fontWeight:700, fontSize:13}}>{formatEUR(p.price * it.qty)}</div>
                      </div>
                    </div>
                  );
                })}
              </div>
              <hr style={{border:0, borderTop:"1px solid var(--line)", margin:"10px 0"}}/>
              <div className="cart-totals" style={{fontSize:13.5}}>
                <div className="row"><span>{t("Subtotaal","Subtotal")}</span><span>{formatEUR(cart.subtotal)}</span></div>
                <div className="row"><span>{t("Verzendkosten","Shipping costs")}</span><span>{effectiveShipping === 0 ? <span style={{color:"var(--ok)"}}>{fulfillment === "ophalen" ? t("Gratis ophalen","Free pickup") : t("Gratis","Free")}</span> : formatEUR(effectiveShipping)}</span></div>
                <div className="row total" style={{fontSize:18}}><span>{t("Totaal","Total")}</span><span>{formatEUR(checkoutTotal)}</span></div>
                {checkoutTotal > 0 && window.vatRowLabel && (
                  <div className="row" style={{color:"var(--ink-mute)", fontSize:11.5}}>
                    <span>{window.vatRowLabel(langCtx.lang)}</span><span>{formatEUR(checkoutVat)}</span>
                  </div>
                )}
              </div>
            </div>
          )}
          <style>{`@media (max-width:900px){.co-grid{grid-template-columns:1fr !important}}`}</style>
        </div>
      </section>
    </div>
  );
};

/* ============ ABOUT page (small) ============ */
const PageAbout = ({ setPage }) => {
  const langCtx = useContext(window.LangContext || React.createContext({ lang:"nl", t: (nl)=>nl }));
  const t = langCtx.t || ((nl) => nl);
  return (
    <div className="page">
      <section style={{padding:"56px 0 40px", background:"var(--paper)", borderBottom:"1px solid var(--line)"}}>
        <div className="wrap-narrow">
          <div className="eyebrow" style={{marginBottom:14}}>{t("Over Zyro Electric","About Zyro Electric")}</div>
          <h1 className="h-display" style={{fontSize:"clamp(36px,5.5vw,64px)", marginBottom:18}}>
            {t("Over Zyro Electric","About Zyro Electric")}
          </h1>
          <p style={{color:"var(--ink-dim)", fontSize:17, lineHeight:1.65, maxWidth:680}}>
            {t(
              "Zyro Electric Nederland is een nieuw bedrijf uit Utrecht Overvecht, gespecialiseerd in legale elektrische fatbikes voor dagelijks gebruik in Nederland.",
              "Zyro Electric Nederland is a new company from Utrecht Overvecht, specialised in legal electric fat-bikes for everyday use in the Netherlands."
            )}
          </p>
        </div>
      </section>

      <section className="section-sm">
        <div className="wrap-narrow" style={{display:"flex", flexDirection:"column", gap:18, color:"var(--ink-dim)", fontSize:16, lineHeight:1.7}}>
          <p>{t(
            "Wij zijn gestart met een duidelijke missie: elektrische fietsen aanbieden op een eerlijke, overzichtelijke en betrouwbare manier. Geen overdreven verkooppraatjes, maar duidelijke informatie over prijs, levering, betaling en wat je precies koopt.",
            "We started with a clear mission: offering electric bikes in an honest, transparent and reliable way. No over-the-top sales talk, but clear information about price, delivery, payment and exactly what you're buying."
          )}</p>
          <p>{t(
            "Klanten kunnen online bestellen en kiezen voor ophalen in de showroom of bezorgen waar beschikbaar. Bij ophalen is contant betalen mogelijk. Na betaling ontvangt de klant een duidelijke factuur/kassabon.",
            "Customers can order online and choose pickup at the showroom or delivery where available. Cash payment is possible on pickup. After payment, the customer receives a clear invoice/receipt."
          )}</p>
          <p>{t(
            "Omdat Zyro Electric nog nieuw is, bouwen we onze voorraad, service en klantrelaties stap voor stap op. Daarom communiceren we liever eerlijk en duidelijk dan groter te doen dan we zijn.",
            "Because Zyro Electric is still new, we are building our stock, service and customer relationships step by step. That's why we'd rather communicate honestly and clearly than pretend to be bigger than we are."
          )}</p>
        </div>
      </section>

      <section className="section">
        <div className="wrap-narrow">
          <h2 className="h-display" style={{fontSize:32, marginBottom:24}}>{t("Kernpunten","Key points")}</h2>
          <ul style={{listStyle:"none", padding:0, margin:0, display:"flex", flexDirection:"column", gap:14}}>
            {[
              t("Nieuw bedrijf uit Utrecht Overvecht","New company from Utrecht Overvecht"),
              t("Gericht op legale elektrische fatbikes","Focused on legal electric fat-bikes"),
              t("Duidelijke prijzen en betaalmogelijkheden","Clear prices and payment options"),
              t("Ophalen of bezorgen waar beschikbaar","Pickup or delivery where available"),
              t("Factuur/kassabon na betaling","Invoice/receipt after payment"),
              t("Eerlijk advies zonder overdreven claims","Honest advice without exaggerated claims"),
            ].map((item, i) => (
              <li key={i} style={{display:"flex", alignItems:"flex-start", gap:12, color:"var(--ink-dim)", fontSize:16, lineHeight:1.6}}>
                <span style={{flexShrink:0, marginTop:2, color:"var(--accent)"}}><Icon name="check" size={18}/></span>
                <span>{item}</span>
              </li>
            ))}
          </ul>
        </div>
      </section>
    </div>
  );
};

window.PageCart = PageCart;
window.PageCheckout = PageCheckout;
window.PageAbout = PageAbout;
