// Xedap.vn product detail — full storefront layout: gallery, buy box,
// features + specs, story block, reviews, and two related product rows.
const { Button, IconButton, Badge, PriceTag, Rating, ProductCard, ColorSwatches } = window.XedapVnDesignSystem_03b1c0;

const RAPTOR_SHOTS = [
  "https://api.xedap.vn/products/RAPTOR/rally-1-b-2026-metallicblack_2.jpg",
  "https://api.xedap.vn/products/RAPTOR/rally-2-b-2026-coolgrey.jpg",
  "https://api.xedap.vn/products/RAPTOR/hunter-4-n-red.jpg",
  "https://api.xedap.vn/products/RAPTOR/mocha-1-b-coffee.jpg",
  "https://api.xedap.vn/products/RAPTOR/cityn-gray.jpg",
];
const vnd = (n) => new Intl.NumberFormat("vi-VN").format(n) + " VND";
const wrap = { maxWidth: 1440, margin: "0 auto", padding: "0 16px" };

/* ---------- Reveal on scroll ---------- */
function Reveal({ children, delay = 0, y = 24, style }) {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setShown(true); io.disconnect(); } }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return <div ref={ref} style={{ ...style, opacity: shown ? 1 : 0, transform: shown ? "none" : `translateY(${y}px)`, transition: `opacity .6s ease ${delay}ms, transform .7s cubic-bezier(.22,.61,.36,1) ${delay}ms`, willChange: "opacity, transform" }}>{children}</div>;
}

/* ---------- Live countdown ---------- */
function Countdown({ seconds = 8 * 3600 + 14 * 60 + 5 }) {
  const [left, setLeft] = React.useState(seconds);
  React.useEffect(() => {
    const id = setInterval(() => setLeft((s) => (s > 0 ? s - 1 : 0)), 1000);
    return () => clearInterval(id);
  }, []);
  const p = (n) => String(n).padStart(2, "0");
  const box = { fontFamily: "var(--font-mono)", fontWeight: 700, color: "var(--foreground)", minWidth: 24, textAlign: "center", display: "inline-block" };
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
      <span style={box}>{p(Math.floor(left / 3600))}</span>:
      <span style={box}>{p(Math.floor((left % 3600) / 60))}</span>:
      <span style={box}>{p(left % 60)}</span>
    </span>
  );
}

/* ---------- Breadcrumb ---------- */
function brandOf(product) {
  return product.brand || (product.code || "").replace("Thương hiệu: ", "") || "RAPTOR";
}

function Breadcrumb({ product }) {
  const parts = ["Xe đạp", product.category || "Xe đạp địa hình", brandOf(product), "Rally 1B"];
  return (
    <nav style={{ display: "flex", flexWrap: "wrap", gap: 6, fontSize: 12, color: "var(--muted-foreground)" }}>
      {parts.map((p, i) => (
        <span key={i} style={{ display: "flex", gap: 6, alignItems: "center" }}>
          {i > 0 && <i className="ph ph-caret-right" style={{ fontSize: 10 }} />}
          <span style={{ color: i === parts.length - 1 ? "var(--foreground)" : "var(--muted-foreground)", fontWeight: i === parts.length - 1 ? 500 : 400 }}>{p}</span>
        </span>
      ))}
    </nav>
  );
}

/* ---------- Lightbox (coverflow slide viewer) ---------- */
function Lightbox({ images, index, product, onClose, onIndex }) {
  const count = images.length;
  const go = React.useCallback((d) => onIndex(((index + d) % count + count) % count), [index, count, onIndex]);
  const [dim, setDim] = React.useState({ w: 1280, h: 800 });
  React.useEffect(() => {
    const measure = () => setDim({ w: window.innerWidth, h: window.innerHeight });
    measure();
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      else if (e.key === "ArrowRight") go(1);
      else if (e.key === "ArrowLeft") go(-1);
    };
    window.addEventListener("resize", measure);
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("resize", measure); window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [go, onClose]);

  // Coverflow geometry — active card big & centered, others thin slats.
  const stageH = Math.max(280, dim.h - 210);
  const activeW = Math.min(dim.w * 0.56, 940, (stageH - 30) * 1.5);
  const activeH = Math.min(stageH - 20, activeW / 1.5);
  const restW = Math.max(70, Math.round(activeW * 0.16));
  const restH = Math.round(activeH * 0.78);
  const gap = 26;
  const R = Math.max(1, Math.min(6, Math.floor(count / 2)));
  const relOf = (i) => { let r = ((i - index) % count + count) % count; if (r > count / 2) r -= count; return r; };
  const xForRel = (rel) => {
    const ar = Math.abs(rel), c1 = activeW / 2 + gap + restW / 2, pitch = restW + gap;
    const mag = ar <= 1 ? ar * c1 : c1 + (ar - 1) * pitch;
    return (rel < 0 ? -1 : 1) * mag;
  };
  const ease = "transform .55s cubic-bezier(.32,.72,0,1), width .55s cubic-bezier(.32,.72,0,1), height .55s cubic-bezier(.32,.72,0,1), opacity .4s ease";
  const nav = (dir, aria) => (
    <button onClick={() => go(dir)} aria-label={aria} style={{ position: "absolute", [dir < 0 ? "left" : "right"]: 24, top: "50%", transform: "translateY(-50%)", width: 52, height: 52, borderRadius: 5, border: "1px solid rgba(255,255,255,.25)", background: "rgba(255,255,255,.1)", backdropFilter: "blur(8px)", color: "#fff", cursor: "pointer", display: "grid", placeItems: "center", fontSize: 22, zIndex: 2000 }}><i className={`ph ph-caret-${dir < 0 ? "left" : "right"}`} /></button>
  );

  return ReactDOM.createPortal(
    <div style={{ position: "fixed", inset: 0, zIndex: 3000, background: "rgba(12,14,16,.97)", backdropFilter: "blur(4px)", display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "18px 24px", color: "#fff", flexShrink: 0, zIndex: 10 }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
          <span style={{ fontFamily: "var(--font-heading)", fontWeight: 700, fontSize: 16 }}>{product.name}</span>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, opacity: .7 }}>{String(index + 1).padStart(2, "0")} / {String(count).padStart(2, "0")}</span>
        </div>
        <button onClick={onClose} aria-label="Đóng" style={{ width: 44, height: 44, borderRadius: 5, border: "1px solid rgba(255,255,255,.25)", background: "rgba(255,255,255,.1)", color: "#fff", cursor: "pointer", display: "grid", placeItems: "center", fontSize: 20 }}><i className="ph ph-x" /></button>
      </div>
      <div style={{ position: "relative", flex: 1, minHeight: 0 }}>
        <div style={{ position: "absolute", inset: 0, isolation: "isolate", overflow: "hidden" }}>
          {images.map((s, i) => {
            const rel = relOf(i), ar = Math.abs(rel), a = Math.min(ar, 1);
            const w = activeW + (restW - activeW) * a, h = activeH + (restH - activeH) * a;
            const op = ar >= R + 1 ? 0 : ar > R ? 1 - (ar - R) : 1;
            return (
              <div key={i} onClick={() => onIndex(i)} style={{ position: "absolute", left: "50%", top: "50%", transform: `translate(-50%,-50%) translateX(${xForRel(rel)}px)`, width: w, height: h, zIndex: Math.round(1000 - ar * 100), opacity: op, transition: ease, cursor: ar < .5 ? "default" : "pointer", borderRadius: 5, overflow: "hidden", background: "#1a1c1e", boxShadow: ar < .5 ? "0 30px 80px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.06)" : "0 16px 44px rgba(0,0,0,.5)", pointerEvents: op < .05 ? "none" : "auto" }}>
                <img src={s} alt="" draggable={false} style={{ width: "100%", height: "100%", objectFit: "cover", display: "block", userSelect: "none", pointerEvents: "none" }} />
              </div>
            );
          })}
        </div>
        {count > 1 && nav(-1, "Ảnh trước")}
        {count > 1 && nav(1, "Ảnh tiếp theo")}
      </div>
    </div>,
    document.body
  );
}

/* ---------- Gallery ---------- */
function Gallery({ product }) {
  const main = product.img || RAPTOR_SHOTS[0];
  const shots = [main, ...RAPTOR_SHOTS.filter((s) => s !== main)].slice(0, 4);
  const life = "https://api.xedap.vn/products/RAPTOR/rally-3-bn-blackwhite_2.jpg";
  const all = [...shots, life];
  const [active, setActive] = React.useState(0);
  const [lightbox, setLightbox] = React.useState(false);
  const [zoom, setZoom] = React.useState(false);
  const [zpos, setZpos] = React.useState({ x: 50, y: 50 });
  const onMove = (e) => { const r = e.currentTarget.getBoundingClientRect(); setZpos({ x: ((e.clientX - r.left) / r.width) * 100, y: ((e.clientY - r.top) / r.height) * 100 }); };
  const [start, setStart] = React.useState(0);
  const mainRef = React.useRef(null);
  const [boxH, setBoxH] = React.useState(0);
  const THUMB = 132, GAP = 12;
  React.useEffect(() => {
    const el = mainRef.current;
    if (!el) return;
    const measure = () => setBoxH(el.clientWidth);
    measure();
    const ro = new ResizeObserver(measure); ro.observe(el);
    return () => ro.disconnect();
  }, []);
  const FOOTER = 44, FOOTER_GAP = 12;
  const per = boxH ? Math.max(1, Math.floor((boxH - FOOTER - FOOTER_GAP + GAP) / (THUMB + GAP))) : all.length;
  const maxStart = Math.max(0, all.length - per);
  const clamp = (n) => Math.min(maxStart, Math.max(0, n));
  const pick = (i) => { setActive(i); if (i < start) setStart(i); else if (i >= start + per) setStart(clamp(i - per + 1)); };
  return (
    <div style={{ display: "flex", flexDirection: "row", gap: 14, alignItems: "flex-start" }}>
      {lightbox && <Lightbox images={all} index={active} product={product} onClose={() => setLightbox(false)} onIndex={setActive} />}
      <div ref={mainRef} onMouseEnter={() => setZoom(true)} onMouseLeave={() => setZoom(false)} onMouseMove={onMove} style={{ position: "relative", flex: 1, aspectRatio: "1/1", overflow: "hidden", background: "var(--secondary)", border: "1px solid var(--border)" }}>
        <img src={all[active]} alt={product.name} onClick={() => setLightbox(true)} style={{ width: "100%", height: "100%", objectFit: "contain", cursor: "zoom-in", transformOrigin: `${zpos.x}% ${zpos.y}%`, transform: zoom ? "scale(2)" : "scale(1)", transition: zoom ? "transform .12s ease-out" : "transform .3s ease" }} />
        <button onClick={() => setLightbox(true)} aria-label="Xem toàn màn hình" style={{ position: "absolute", right: 14, bottom: 14, width: 34, height: 34, borderRadius: "var(--radius-md)", border: "1px solid var(--border)", background: "rgba(255,255,255,.92)", cursor: "pointer", color: "var(--foreground)", zIndex: 2 }}><i className="ph ph-arrows-out" /></button>
      </div>
      <div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", width: 132, flexShrink: 0, height: boxH || "auto" }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 12, overflow: "hidden" }}>
          {all.slice(start, start + per).map((s, k) => {
            const i = start + k;
            return (
              <button key={i} onClick={() => pick(i)} style={{ padding: 0, border: `2px solid ${i === active ? "var(--primary)" : "var(--border)"}`, overflow: "hidden", cursor: "pointer", aspectRatio: "1/1", background: "var(--secondary)", borderRadius: 0 }}>
                <img src={s} alt="" style={{ width: "100%", height: "100%", objectFit: "contain" }} />
              </button>
            );
          })}
        </div>
        {all.length > 1 && (
          <div style={{ marginTop: FOOTER_GAP, display: "flex", gap: 8, height: FOOTER }}>
            <button onClick={() => pick((active - 1 + all.length) % all.length)} aria-label="Ảnh trước" style={{ flex: 1, border: "1px solid var(--border)", background: "#fff", cursor: "pointer", color: "var(--foreground)", display: "grid", placeItems: "center" }}><i className="ph ph-arrow-up" /></button>
            <button onClick={() => pick((active + 1) % all.length)} aria-label="Ảnh tiếp theo" style={{ flex: 1, border: "1px solid var(--border)", background: "#fff", cursor: "pointer", color: "var(--foreground)", display: "grid", placeItems: "center" }}><i className="ph ph-arrow-down" /></button>
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- Buy box ---------- */
function OptionTiles({ label, note, items, sel, setSel }) {
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 10 }}>
        <span style={{ fontSize: 13, fontWeight: 600 }}>{label}</span>
        {note && <span style={{ fontSize: 12, color: "var(--muted-foreground)" }}>{note}</span>}
      </div>
      <div style={{ display: "flex", gap: 10 }}>
        {items.map((it, i) => (
          <button key={i} onClick={() => setSel(i)} title={it.label} style={{ position: "relative", width: 64, height: 64, padding: 4, borderRadius: "var(--radius-md)", border: `1.5px solid ${i === sel ? "var(--primary)" : "var(--border)"}`, background: "#fff", cursor: "pointer" }}>
            <img src={it.img} alt={it.label} style={{ width: "100%", height: "100%", objectFit: "contain" }} />
            {i === sel && <span style={{ position: "absolute", right: -6, top: -6, width: 18, height: 18, borderRadius: 5, background: "var(--primary)", color: "#fff", fontSize: 10, display: "grid", placeItems: "center" }}><i className="ph-fill ph-check" /></span>}
          </button>
        ))}
      </div>
    </div>
  );
}

const GIFT_ITEMS = [
  { name: "Nón bảo hiểm", img: "https://cdn.hstatic.net/files/200001086651/file/20_3c147254ff2e4d5bac50549308c5267f.png", colors: ["Trắng", "Đen"], sizes: ["XS", "S", "M"], price: 0, original: 259000 },
  { name: "Nón bảo hiểm", img: "https://cdn.hstatic.net/files/200001086651/file/21_cccd6ae164a5443789a487cdb0c0da9a.png", colors: ["Trắng", "Đen"], sizes: ["XS", "S", "M"], price: 0, original: 259000 },
  { name: "Găng tay", img: "https://api.xedap.vn/wp-content/uploads/2020/07/830000852-53-54-55-850.jpg", colors: ["Đen", "Xám"], sizes: ["M", "L"], price: 0, original: 149000 },
];
const COMBO_ITEMS = [
  { name: "Găng tay xe đạp SKMT", img: "https://api.xedap.vn/wp-content/uploads/2023/10/GangTaySKMT_White.jpg", colors: ["Trắng", "Đen"], sizes: ["M", "L", "XL"], price: 400000, original: 530000 },
  { name: "Giày đạp xe Shimano MX-101", img: "https://api.xedap.vn/products/SHIMANO/mx-101-black.jpg", colors: ["Đen"], sizes: ["39", "40", "41", "42"], price: 1500000, original: 1790000 },
  { name: "Nón bảo hiểm ACTIVE XQ-36", img: "https://api.xedap.vn/products/Ph%E1%BB%A5%20ki%E1%BB%87n/PK%20RAPTOR/a-1-denxanhduong.jpg", colors: ["Đen xanh dương", "Đen"], sizes: ["Tiêu chuẩn"], price: 299000, original: 359000 },
  { name: "Kính đi đường", img: "https://api.xedap.vn/products/ACTIVE/xq-36-apc-clearwhite-5.jpg", colors: ["Trắng", "Đen"], sizes: ["S", "M", "L"], price: 899000, original: 1190000 },
];
const dong = (n) => n === 0 ? "0đ" : new Intl.NumberFormat("vi-VN").format(n) + "đ";

const STORES = [
  { name: "Nguyễn Cơ Thạch", city: "TP. Hồ Chí Minh", district: "TP. Thủ Đức", stock: "in", address: "Shop B1-00.05, Sarimi, 72 Nguyễn Cơ Thạch, P. An Khánh, TP. Thủ Đức", phone: "1800 9473", hours: "08:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-nguyen-co-thach.jpg&w=384&q=75" },
  { name: "Nguyễn Duy Trinh", city: "TP. Hồ Chí Minh", district: "TP. Thủ Đức", stock: "in", address: "585 Nguyễn Duy Trinh, P. Bình Trưng, TP. Thủ Đức", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fcua-hang-xe-dap-thu-duc-nguyen-duy-trinh.jpg&w=384&q=75" },
  { name: "Võ Thị Sáu", city: "TP. Hồ Chí Minh", district: "Quận 3", stock: "low", address: "63C Võ Thị Sáu, P. Võ Thị Sáu", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-vo-thi-sau.jpg&w=384&q=75" },
  { name: "Đặng Văn Bi", city: "TP. Hồ Chí Minh", district: "TP. Thủ Đức", stock: "in", address: "200-202 Đặng Văn Bi, P. Thủ Đức, TP. Thủ Đức", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-dang-van-bi-thu-duc.jpg&w=384&q=75" },
  { name: "Nguyễn Thị Thập", city: "TP. Hồ Chí Minh", district: "Quận 7", stock: "in", address: "458 Nguyễn Thị Thập, P. Tân Hưng", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-nguyen-thi-thap.jpg&w=384&q=75" },
  { name: "Hải Thượng Lãn Ông", city: "TP. Hồ Chí Minh", district: "Quận 5", stock: "out", address: "100 Hải Thượng Lãn Ông, P. Chợ Lớn", phone: "1800 9473", hours: "09:00 - 19:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-hai-thuong-lan-ong.jpg&w=384&q=75" },
  { name: "Bờ Bao Tân Thắng", city: "TP. Hồ Chí Minh", district: "Tân Phú", stock: "in", address: "93C Bờ Bao Tân Thắng, P. Tân Thành", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-bo-bao-tan-thang.jpg&w=384&q=75" },
  { name: "Tên Lửa - Bình Tân", city: "TP. Hồ Chí Minh", district: "Bình Tân", stock: "low", address: "122 Tên Lửa, P. An Lạc", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-ten-lua-binh-tan.jpg&w=384&q=75" },
  { name: "Tô Ký - Hóc Môn", city: "TP. Hồ Chí Minh", district: "Hóc Môn", stock: "in", address: "14/1A Tô Ký, Xã Đông Thạnh", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-to-ky-hoc-mon.jpg&w=384&q=75" },
  { name: "Emart Gò Vấp", city: "TP. Hồ Chí Minh", district: "Gò Vấp", stock: "in", address: "366 Phan Văn Trị, P. An Nhơn", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Ftmp%2Femart-phan-va-n-tra.jpg&w=384&q=75" },
  { name: "Emart Phan Huy Ích", city: "TP. Hồ Chí Minh", district: "Gò Vấp", stock: "out", address: "385 Phan Huy Ích, P. An Hội Tây", phone: "1800 9473", hours: "07:30 - 22:30", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Ftmp%2Femart-phan-huy-a-ch.jpg&w=384&q=75" },
  { name: "Nguyễn Oanh - Gò Vấp", city: "TP. Hồ Chí Minh", district: "Gò Vấp", stock: "in", address: "144 Nguyễn Oanh, Gò Vấp", phone: "090 551 1144", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Ftmp%2Fc-0635-00-00-04-05-still-004_2.jpg&w=384&q=75" },
  { name: "Phạm Văn Đồng - Hà Nội", city: "Hà Nội", district: "Bắc Từ Liêm", stock: "low", address: "427 Phạm Văn Đồng, P. Xuân Đỉnh", phone: "1800 9473", hours: "09:00 - 21:00", img: "https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fwp-content%2Fuploads%2F2023%2F06%2Fxedapvn-pham-van-dong.jpg&w=384&q=75" },
];
const STOCK = {
  in: { label: "Còn hàng", color: "#07873c", bg: "color-mix(in srgb, #07c73c 14%, #fff)" },
  low: { label: "Sắp hết", color: "#b45309", bg: "color-mix(in srgb, #f59e0b 20%, #fff)" },
  out: { label: "Hết hàng", color: "var(--muted-foreground)", bg: "var(--secondary)" },
};
const STORE_GEO = {
  "Nguyễn Cơ Thạch": [10.767, 106.722], "Nguyễn Duy Trinh": [10.780, 106.775], "Võ Thị Sáu": [10.786, 106.687],
  "Đặng Văn Bi": [10.848, 106.762], "Nguyễn Thị Thập": [10.740, 106.703], "Hải Thượng Lãn Ông": [10.752, 106.658],
  "Bờ Bao Tân Thắng": [10.801, 106.618], "Tên Lửa - Bình Tân": [10.740, 106.611], "Tô Ký - Hóc Môn": [10.867, 106.606],
  "Emart Gò Vấp": [10.830, 106.687], "Emart Phan Huy Ích": [10.847, 106.638], "Nguyễn Oanh - Gò Vấp": [10.843, 106.678],
  "Phạm Văn Đồng - Hà Nội": [21.077, 105.783],
};
function haversine(a, b, c, d) {
  const R = 6371, r = Math.PI / 180;
  const dLat = (c - a) * r, dLon = (d - b) * r;
  const x = Math.sin(dLat / 2) ** 2 + Math.cos(a * r) * Math.cos(c * r) * Math.sin(dLon / 2) ** 2;
  return R * 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
}

function StorePicker({ product }) {
  const [open, setOpen] = React.useState(false);
  const cities = ["Tất cả", ...Array.from(new Set(STORES.map((s) => s.city)))];
  const [city, setCity] = React.useState("Tất cả");
  const [district, setDistrict] = React.useState("Tất cả");
  const [sel, setSel] = React.useState(0);
  const [pos, setPos] = React.useState(null);
  const [locating, setLocating] = React.useState(false);
  const [geoErr, setGeoErr] = React.useState("");
  const locate = () => {
    if (!navigator.geolocation) { setGeoErr("Trình duyệt không hỗ trợ định vị."); return; }
    setLocating(true); setGeoErr("");
    navigator.geolocation.getCurrentPosition(
      (p) => { setPos([p.coords.latitude, p.coords.longitude]); setLocating(false); },
      () => { setGeoErr("Không lấy được vị trí. Vui lòng cho phép truy cập vị trí."); setLocating(false); },
      { enableHighAccuracy: true, timeout: 8000 }
    );
  };
  const districts = city === "Tất cả" ? [] : ["Tất cả", ...Array.from(new Set(STORES.filter((s) => s.city === city).map((s) => s.district)))];
  const chooseCity = (c) => { setCity(c); setDistrict("Tất cả"); };
  let list = STORES.map((s, i) => ({ s, i, dist: pos && STORE_GEO[s.name] ? haversine(pos[0], pos[1], STORE_GEO[s.name][0], STORE_GEO[s.name][1]) : null })).filter(({ s }) => (city === "Tất cả" || s.city === city) && (district === "Tất cả" || s.district === district));
  if (pos) list = list.slice().sort((a, b) => (a.dist ?? 1e9) - (b.dist ?? 1e9));
  const selStore = STORES[sel];
  const selectStyle = { flex: 1, minWidth: 0, appearance: "none", WebkitAppearance: "none", padding: "10px 34px 10px 12px", borderRadius: "var(--radius-md)", border: "1px solid var(--border)", background: "#fff url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23666'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E\") no-repeat right 12px center/12px", fontFamily: "var(--font-sans)", fontSize: 13, color: "var(--foreground)", cursor: "pointer" };
  return (
    <div style={{ paddingTop: 8, marginTop: 4, borderTop: "1px solid var(--border)" }}>
      <span style={{ display: "block", fontSize: 12, fontWeight: 600, color: "var(--muted-foreground)", marginBottom: 8 }}>Chọn cửa hàng nhận xe</span>
      <button onClick={() => setOpen(true)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "11px 14px", borderRadius: "var(--radius-md)", border: "1.5px solid var(--border)", background: "#fff", cursor: "pointer", textAlign: "left" }}>
        <i className="ph ph-storefront" style={{ fontSize: 18, color: "var(--primary)", flexShrink: 0 }} />
        <span style={{ flex: 1, minWidth: 0, fontSize: 14, fontWeight: 600, color: "var(--foreground)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{selStore ? selStore.name : "Chọn cửa hàng"}</span>
        <i className="ph ph-caret-down" style={{ fontSize: 15, color: "var(--muted-foreground)", flexShrink: 0 }} />
      </button>
      {selStore && <span style={{ display: "block", fontSize: 12, color: "var(--muted-foreground)", marginTop: 6, lineHeight: 1.4 }}><i className="ph ph-map-pin" style={{ marginRight: 4 }} />{selStore.address}</span>}
      {open && (
        <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 100, background: "rgba(11,13,18,.5)", display: "flex", alignItems: "center", justifyContent: "center", padding: 20, backdropFilter: "blur(2px)" }}>
          <div onClick={(e) => e.stopPropagation()} style={{ width: "100%", maxWidth: 520, maxHeight: "85vh", display: "flex", flexDirection: "column", background: "#fff", borderRadius: "var(--radius-lg)", overflow: "hidden", boxShadow: "0 24px 60px rgba(0,0,0,.28)" }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: "18px 20px", borderBottom: "1px solid var(--border)" }}>
              <span style={{ fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 18 }}>Danh sách cửa hàng</span>
              <button onClick={() => setOpen(false)} aria-label="Đóng" style={{ width: 34, height: 34, borderRadius: 5, border: "1px solid var(--border)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", color: "var(--foreground)" }}><i className="ph ph-x" /></button>
            </div>
            <div style={{ padding: "16px 20px", display: "flex", flexDirection: "column", gap: 12, borderBottom: "1px solid var(--border)" }}>
              {product && (
                <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  {product.image && <img src={product.image} alt="" style={{ width: 44, height: 44, objectFit: "cover", borderRadius: 5, background: "var(--secondary)", flexShrink: 0 }} />}
                  <span style={{ fontSize: 14, fontWeight: 600, color: "var(--foreground)", lineHeight: 1.35 }}>{product.name}</span>
                </div>
              )}
              <div style={{ display: "flex", gap: 10 }}>
                <select value={city} onChange={(e) => chooseCity(e.target.value)} style={selectStyle}>
                  {cities.map((c) => <option key={c} value={c}>{c === "Tất cả" ? "Tỉnh/Thành phố" : c}</option>)}
                </select>
                <select value={district} onChange={(e) => setDistrict(e.target.value)} disabled={!districts.length} style={{ ...selectStyle, opacity: districts.length ? 1 : 0.5, cursor: districts.length ? "pointer" : "not-allowed" }}>
                  {(districts.length ? districts : ["Tất cả"]).map((d) => <option key={d} value={d}>{d === "Tất cả" ? "Quận/Huyện" : d}</option>)}
                </select>
              </div>
              <button onClick={locate} disabled={locating} style={{ alignSelf: "flex-start", display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 5, border: `1px solid ${pos ? "var(--primary)" : "var(--border)"}`, background: pos ? "color-mix(in srgb, var(--primary) 8%, #fff)" : "#fff", color: pos ? "var(--primary)" : "var(--foreground)", fontFamily: "var(--font-sans)", fontSize: 12, fontWeight: 600, cursor: locating ? "default" : "pointer" }}><i className={locating ? "ph ph-circle-notch" : "ph ph-crosshair"} style={{ animation: locating ? "spin 1s linear infinite" : "none" }} />{locating ? "Đang định vị…" : pos ? "Cửa hàng gần bạn" : "Tìm gần tôi"}</button>
              {geoErr && <span style={{ fontSize: 11.5, color: "var(--danger)" }}>{geoErr}</span>}
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8, overflowY: "auto", padding: "14px 20px 20px" }}>
              {list.map(({ s, i, dist }) => {
                const on = sel === i, out = s.stock === "out", st = (typeof STOCK !== "undefined" && STOCK[s.stock]) || { label: "Còn hàng", color: "#07873c", bg: "color-mix(in srgb, #07c73c 14%, #fff)" };
                return (
                  <button key={i} onClick={() => { if (!out) { setSel(i); setOpen(false); } }} disabled={out} style={{ display: "flex", gap: 12, textAlign: "left", padding: 10, borderRadius: "var(--radius-md)", border: `1.5px solid ${on ? "var(--primary)" : "var(--border)"}`, background: on ? "color-mix(in srgb, var(--primary) 6%, #fff)" : "#fff", color: "var(--foreground)", fontFamily: "var(--font-sans)", cursor: out ? "not-allowed" : "pointer", alignItems: "flex-start", opacity: out ? 0.6 : 1 }}>
                    <img src={s.img} alt={s.name} onError={(e) => { e.target.onerror = null; e.target.src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56 56'%3E%3Crect width='56' height='56' rx='6' fill='%23f1f5f9'/%3E%3Cpath d='M28 17a5 5 0 00-5 5v3h-2a2 2 0 00-2 2v10a2 2 0 002 2h14a2 2 0 002-2V25a2 2 0 00-2-2h-2v-3a5 5 0 00-5-5zm-3 5a3 3 0 116 0v3h-6v-3z' fill='%2394a3b8'/%3E%3C/svg%3E"; }} style={{ width: 56, height: 56, objectFit: "cover", borderRadius: 5, flexShrink: 0, background: "var(--secondary)", filter: out ? "grayscale(1)" : "none" }} />
                    <div style={{ display: "flex", flexDirection: "column", gap: 3, minWidth: 0, flex: 1 }}>
                      <span style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                        <span style={{ fontSize: 13, fontWeight: 700, color: "var(--foreground)" }}>{s.name}</span>
                        <span style={{ fontSize: 10.5, fontWeight: 600, padding: "2px 7px", borderRadius: 5, color: st.color, background: st.bg, whiteSpace: "nowrap" }}><i className={out ? "ph ph-x-circle" : "ph-fill ph-circle"} style={{ fontSize: 8, marginRight: 4, verticalAlign: "middle" }} />{st.label}</span>
                      </span>
                      <span style={{ fontSize: 12, color: "var(--muted-foreground)", lineHeight: 1.4, textWrap: "pretty" }}>{s.address}</span>
                      <span style={{ fontSize: 11, color: "var(--muted-foreground)", display: "flex", gap: 12, flexWrap: "wrap" }}><span><i className="ph ph-clock" style={{ marginRight: 3 }} />{s.hours}</span><span><i className="ph ph-phone" style={{ marginRight: 3 }} />{s.phone}</span>{dist != null && <span style={{ color: "var(--primary)", fontWeight: 600 }}><i className="ph-fill ph-map-pin" style={{ marginRight: 3 }} />{dist < 10 ? dist.toFixed(1) : Math.round(dist)} km</span>}</span>
                    </div>
                    <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: 5, border: `1.5px solid ${on ? "var(--primary)" : "var(--border)"}`, display: "grid", placeItems: "center", marginTop: 2 }}>{on && <span style={{ width: 9, height: 9, borderRadius: 5, background: "var(--primary)" }} />}</span>
                  </button>
                );
              })}
              {list.length === 0 && <span style={{ fontSize: 13, color: "var(--muted-foreground)", padding: "8px 2px" }}>Không có cửa hàng phù hợp.</span>}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function AddonSelect({ options }) {
  return (
    <div style={{ position: "relative", display: "flex", flex: 1, minWidth: 0 }} onClick={(e) => e.stopPropagation()}>
      <select onClick={(e) => e.stopPropagation()} style={{ appearance: "none", WebkitAppearance: "none", padding: "5px 20px 5px 9px", border: "1px solid var(--border)", borderRadius: 5, background: "#fff", fontFamily: "var(--font-sans)", fontSize: 11, color: "var(--foreground)", cursor: "pointer", minWidth: 52, width: "100%" }}>
        {options.map((o) => <option key={o}>{o}</option>)}
      </select>
      <i className="ph ph-caret-down" style={{ position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", fontSize: 9, pointerEvents: "none", color: "var(--muted-foreground)" }} />
    </div>
  );
}

function AddonOption({ item, selected, onSelect, priceLabel, basis = "calc(50% - 6px)", bordered, multi }) {
  return (
    <div onClick={onSelect} style={{ display: "flex", alignItems: "center", gap: 8, cursor: "pointer", flex: `0 0 ${basis}`, minWidth: 0, boxSizing: "border-box", ...(bordered ? { padding: 12, borderRadius: "var(--radius-md)", border: `1.5px solid ${selected ? "var(--primary)" : "var(--border)"}`, background: selected ? "color-mix(in srgb, var(--primary) 5%, #fff)" : "#fff" } : {}) }}>
      <span style={{ flexShrink: 0, width: 18, height: 18, borderRadius: 5, border: `2px solid ${selected ? (multi ? "#16a34a" : "var(--primary)") : "var(--border)"}`, display: "grid", placeItems: "center", background: "#fff", overflow: "visible", position: "relative" }}>
        {selected && (multi ? <i className="ph-fill ph-check" style={{ fontSize: 16, color: "#16a34a", position: "absolute", left: "50%", top: "45%", transform: "translate(-50%,-50%)", lineHeight: 1 }} /> : <span style={{ width: 9, height: 9, borderRadius: 5, background: "var(--primary)" }} />)}
      </span>
      <img src={item.img} alt={item.name} style={{ flexShrink: 0, width: 56, height: 56, objectFit: "contain", mixBlendMode: "multiply" }} />
      <div style={{ display: "flex", flexDirection: "column", gap: 5, minWidth: 0, flex: 1 }}>
        <span style={{ fontSize: 12, fontWeight: 500 }}>{item.name}</span>
        <div style={{ display: "flex", gap: 6 }}>
          <AddonSelect options={item.colors} />
          <AddonSelect options={item.sizes} />
        </div>
        <div style={{ display: "flex", alignItems: "baseline", gap: 5, marginTop: 1, flexWrap: "wrap" }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 700 }}>{priceLabel(item.price)}</span>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--muted-foreground)", textDecoration: "line-through" }}>{dong(item.original)}</span>
        </div>
      </div>
    </div>
  );
}

function AddonCard({ title, items, priceLabel, required, per = 2, basis, bordered, multi }) {
  const [sel, setSel] = React.useState(required ? 0 : -1);
  const [picked, setPicked] = React.useState(() => new Set());
  const [page, setPage] = React.useState(0);
  const pages = Math.ceil(items.length / per);
  const shown = items.map((it, i) => ({ it, i })).slice(page * per, page * per + per);
  const toggle = (i) => setPicked((s) => { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });
  const allPicked = multi && items.length > 0 && picked.size === items.length;
  const toggleAll = () => setPicked(allPicked ? new Set() : new Set(items.map((_, i) => i)));
  return (
    <div style={{ border: "1px solid var(--border)", borderRadius: "var(--radius-md)", overflow: "hidden" }}>
      <div style={{ padding: "10px 16px", background: "var(--muted, #c7ccd0)", color: "var(--foreground)", fontSize: 15, fontWeight: 700, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }}>
        <span>{title}</span>
        {multi && (
          <button onClick={toggleAll} style={{ flexShrink: 0, display: "inline-flex", alignItems: "center", gap: 6, height: 28, padding: "0 12px", borderRadius: "var(--radius-pill)", border: "1px solid var(--border)", background: allPicked ? "var(--primary)" : "#fff", color: allPicked ? "var(--primary-foreground)" : "var(--foreground)", fontSize: 12.5, fontWeight: 600, cursor: "pointer" }}>
            <i className={allPicked ? "ph-fill ph-check-square" : "ph ph-check-square"} style={{ fontSize: 15 }} />
            {allPicked ? "Bỏ chọn tất cả" : "Chọn tất cả"}
          </button>
        )}
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "16px 10px" }}>
        {pages > 1 && page > 0 && (
          <button onClick={() => setPage((p) => Math.max(0, p - 1))} aria-label="Trước" style={{ flexShrink: 0, width: 26, height: 26, borderRadius: 5, border: "1px solid var(--border)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", color: "var(--foreground)" }}><i className="ph ph-caret-left" style={{ fontSize: 13 }} /></button>
        )}
        <div style={{ display: "flex", gap: 12, flex: 1, minWidth: 0 }}>
          {shown.map(({ it, i }) => (
            <AddonOption key={i} item={it} selected={multi ? picked.has(i) : sel === i} onSelect={() => multi ? toggle(i) : setSel(required && sel === i ? i : (sel === i ? -1 : i))} priceLabel={priceLabel} basis={basis} bordered={bordered} multi={multi} />
          ))}
        </div>
        {pages > 1 && (
          <button onClick={() => setPage((p) => Math.min(pages - 1, p + 1))} disabled={page === pages - 1} aria-label="Tiếp" style={{ flexShrink: 0, width: 26, height: 26, borderRadius: 5, border: "1px solid var(--border)", background: "#fff", cursor: page === pages - 1 ? "default" : "pointer", opacity: page === pages - 1 ? 0.3 : 1, display: "grid", placeItems: "center", color: "var(--foreground)" }}><i className="ph ph-caret-right" style={{ fontSize: 13 }} /></button>
        )}
      </div>
    </div>
  );
}

function ComboSection() {
  return (
    <div>
      <h2 style={{ margin: "0 0 20px", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 24 }}>Giảm giá khi mua kèm</h2>
      <AddonCard title="Chọn phụ kiện mua kèm để nhận ưu đãi" items={COMBO_ITEMS} priceLabel={vnd} per={4} basis="calc(25% - 9px)" bordered multi />
    </div>
  );
}

function BuyBox({ product, onAdd }) {
  const colors = product.colors || ["#142ff7", "#333333", "#07c73c", "#b91c1c"];
  const sizes = ["XS", "S", "M", "L", "XL"];
  const [ci, setCi] = React.useState(0);
  const [si, setSi] = React.useState(2);
  const [qty, setQty] = React.useState(1);
  const [ship, setShip] = React.useState(0);
  const [added, setAdded] = React.useState(false);
  const handleAdd = () => { onAdd(product); setAdded(true); clearTimeout(handleAdd._t); handleAdd._t = setTimeout(() => setAdded(false), 1700); };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
      <Breadcrumb product={product} />
      <div>
        <span style={{ fontSize: 12, fontWeight: 500, textTransform: "uppercase", letterSpacing: ".05em", color: "var(--muted-foreground)" }}>Thương hiệu: {brandOf(product)}</span>
        <h1 style={{ margin: "6px 0 0", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 26, letterSpacing: "-0.01em", lineHeight: 1.2 }}>{product.name}</h1>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 12 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 30, fontWeight: 600, color: "var(--danger)" }}>{vnd(product.price)}</span>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 16, color: "var(--muted-foreground)", textDecoration: "line-through" }}>{vnd(product.originalPrice)}</span>
        </div>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 13, fontWeight: 500, color: "var(--foreground)" }}>Flash sale · kết thúc trong <Countdown /></span>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 16, paddingBottom: 20, borderBottom: "1px solid var(--border)" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 14 }}><i className="ph-fill ph-star" style={{ color: "var(--warning, #f5a623)", fontSize: 16 }} /><span style={{ fontWeight: 700, color: "var(--foreground)" }}>5.0</span><span style={{ color: "var(--muted-foreground)" }}>(288 đánh giá)</span></span>
        <button style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "none", background: "none", cursor: "pointer", fontSize: 13, color: "var(--muted-foreground)" }}><i className="ph ph-heart" /> Lưu lại</button>
        <button style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "none", background: "none", cursor: "pointer", fontSize: 13, color: "var(--muted-foreground)" }}><i className="ph ph-share-network" /> Chia sẻ</button>
      </div>

      <div>
        <div style={{ marginBottom: 10, fontSize: 13, fontWeight: 600 }}>Màu sắc</div>
        <ColorSwatches colors={colors} value={ci} onChange={setCi} size={32} />
      </div>

      <div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 10 }}>
          <span style={{ fontSize: 13, fontWeight: 600 }}>Kích thước</span>
          <a href="#" style={{ fontSize: 12 }}>Hướng dẫn chọn size</a>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          {sizes.map((s, i) => (
            <button key={s} onClick={() => setSi(i)} style={{ minWidth: 48, height: 44, padding: "0 14px", borderRadius: "var(--radius-md)", border: `1.5px solid ${i === si ? "var(--primary)" : "var(--border)"}`, background: i === si ? "var(--primary)" : "#fff", color: i === si ? "#fff" : "var(--foreground)", fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>{s}</button>
          ))}
        </div>
      </div>

      <AddonCard title="Quà tặng khi mua xe" items={GIFT_ITEMS} priceLabel={dong} required />

      <div style={{ display: "flex", flexDirection: "column", gap: 12, padding: 16, borderRadius: "var(--radius-md)", background: "var(--secondary)" }}>
        <span style={{ fontSize: 13, fontWeight: 600 }}>Hình thức mua hàng</span>
        {["Giao hàng tận nơi · 2-4 giờ nội thành", "Nhận tại cửa hàng · miễn phí"].map((t, i) => (
          <label key={i} style={{ display: "flex", alignItems: "center", gap: 10, fontSize: 14, cursor: "pointer" }}>
            <input type="radio" name="ship" checked={ship === i} onChange={() => setShip(i)} style={{ accentColor: "var(--primary)", width: 16, height: 16 }} />
            {t}
          </label>
        ))}
        <div style={{ overflow: "hidden", maxHeight: ship === 1 ? 240 : 0, opacity: ship === 1 ? 1 : 0, transition: "max-height .45s cubic-bezier(.22,.61,.36,1), opacity .3s ease" }}>
          <StorePicker product={product} />
        </div>
      </div>

      <div style={{ display: "flex", gap: 12 }}>
        <div style={{ display: "flex", alignItems: "stretch", border: "1.5px solid var(--border)", borderRadius: "var(--radius-md)", overflow: "hidden" }}>
          <button onClick={() => setQty((q) => Math.max(1, q - 1))} style={{ width: 44, height: "100%", border: "none", background: "#fff", cursor: "pointer", fontSize: 18 }}>−</button>
          <span style={{ width: 44, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-mono)", fontSize: 15 }}>{qty}</span>
          <button onClick={() => setQty((q) => q + 1)} style={{ width: 44, height: "100%", border: "none", background: "#fff", cursor: "pointer", fontSize: 18 }}>+</button>
        </div>
        <Button size="lg" style={{ flex: 1, boxShadow: "none", transition: "transform .18s cubic-bezier(.34,1.56,.64,1), background .2s", transform: added ? "scale(1.03)" : "none", ...(added ? { background: "#07c73c", borderColor: "#07c73c" } : {}) }} onClick={handleAdd}>{added ? <React.Fragment><i className="ph-fill ph-check-circle" style={{ marginRight: 8 }} />Đã thêm vào giỏ</React.Fragment> : <React.Fragment><i className="ph ph-shopping-cart-simple" style={{ marginRight: 8 }} />Thêm vào giỏ</React.Fragment>}</Button>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, paddingTop: 4 }}>
        {[["truck", "Miễn phí giao hàng"], ["arrow-counter-clockwise", "Đổi trả trong 7 ngày"], ["credit-card", "Trả góp 0% lãi suất"], ["shield-check", "Bảo hành chính hãng 24 tháng"]].map(([ic, t]) => (
          <span key={t} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: "var(--muted-foreground)" }}><i className={`ph ph-${ic}`} style={{ color: "var(--primary)", fontSize: 16 }} /> {t}</span>
        ))}
      </div>

      <img src="https://xedap.vn/_next/image/?url=https%3A%2F%2Fapi.xedap.vn%2Fhome%2Fctkm-t-6-pop-up-trang-chu-website.jpg&w=828&q=75" alt="Banner khuyến mãi" style={{ display: "block", width: "100%", aspectRatio: "1/1", objectFit: "cover", borderRadius: "var(--radius-md)", marginTop: 4 }} />
    </div>
  );
}

/* ---------- Features + Specs ---------- */
const FEATURES = [
  { img: "https://cdn.hstatic.net/files/200001086651/file/tinh_nang_1.png", title: "Khung thép cứng cáp, bền bỉ", body: "Khung xe được chế tạo bằng thép Raptor STL chắc chắn, chịu lực tốt, mang lại sự ổn định tốt mỗi khi di chuyển cho dù ở bất kì địa hình nào." },
  { img: "https://cdn.hstatic.net/files/200001086651/file/tinh_nang_2.png", title: "Phuộc nhún 100mm ổn định", body: "Trang bị phuộc trước Raptor STL với hành trình 100mm giúp xe hấp thụ chấn động hiệu quả và đem lại sự thoải mái khi di chuyển cho người đạp." },
  { img: "https://cdn.hstatic.net/files/200001086651/file/tinh_nang_3.png", title: "Hệ truyền động 21 tốc độ linh hoạt", body: "Tay đề 21 tốc độ với bộ chuyển líp 7 tầng và gạt đĩa 3 tầng, Rally 1B mang đến dải số 3x7 linh hoạt. Người lái có thể dễ dàng chuyển đổi giữa nhiều địa hình từ phố xá bằng phẳng đến những con dốc nhẹ." },
  { img: "https://cdn.hstatic.net/files/200001086651/file/tinh_nang_1.png", title: "Phanh đĩa cơ – kiểm soát an toàn", body: "Hệ thống phanh đĩa cơ mang lại lực phanh ổn định, dễ dàng kiểm soát tốc độ trong cả môi trường đô thị đông đúc và những chuyến đi trên địa hình phức tạp." },
];
function FeatureGrid() {
  return (
    <div>
      <h2 style={{ margin: "0 0 24px", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 24 }}>Các tính năng chính</h2>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32 }}>
        {FEATURES.map((f, k) => (
          <Reveal key={f.title} delay={(k % 2) * 90}>
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            <div style={{ aspectRatio: "4/3", overflow: "hidden", background: "var(--secondary)" }}>
              <img src={f.img} alt={f.title} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
            </div>
            <h3 style={{ margin: 0, fontSize: 17, fontWeight: 700 }}>{f.title}</h3>
            <p style={{ margin: 0, fontSize: 14, lineHeight: 1.6, color: "var(--muted-foreground)", textWrap: "pretty" }}>{f.body}</p>
          </div>
          </Reveal>
        ))}
      </div>
    </div>
  );
}

const SPEC_GROUPS = [
  { group: "Khung & phuộc", rows: [["Chất liệu khung", "Hợp kim nhôm 6061"], ["Phuộc trước", "Hành trình 100mm, có khóa"], ["Cỡ bánh", "24 inch"], ["Kích cỡ khung", "S / M / L"], ["Trọng lượng", "13.8 kg"]] },
  { group: "Truyền động", rows: [["Bộ đề", "Shimano Altus"], ["Tay đề", "Shimano EF500"], ["Số tốc độ", "24 tốc độ"], ["Bộ đùi đĩa", "Prowheel 3 tầng"], ["Xích", "KMC Z7"]] },
  { group: "Bánh & phanh", rows: [["Vành", "AlexRims MD25, hợp kim nhôm"], ["Moay ơ trước", "Shimano MT400"], ["Phanh", "Đĩa thủy lực"], ["Lốp", "Kenda 24×2.10"], ["Nan hoa", "Thép mạ inox"]] },
  { group: "Tiện ích & bảo hành", rows: [["Yên xe", "Velo thể thao"], ["Phụ kiện kèm", "Chắn bùn, chân chống"], ["Bảo hành khung", "5 năm"], ["Bảo hành linh kiện", "12 tháng"], ["Xuất xứ", "Chính hãng RAPTOR"]] },
];
function SpecTable() {
  return (
    <div>
      <h2 style={{ margin: "0 0 24px", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 24 }}>Thông số kỹ thuật</h2>
      <div style={{ border: "1px solid var(--border)", borderRadius: "var(--radius-lg)", overflow: "hidden" }}>
        {SPEC_GROUPS.map((g) => (
          <div key={g.group}>
            <div style={{ padding: "10px 16px", background: "var(--secondary)", fontSize: 13, fontWeight: 700 }}>{g.group}</div>
            {g.rows.map(([k, v], i) => (
              <div key={k} style={{ display: "flex", justifyContent: "space-between", gap: 16, padding: "12px 16px", borderTop: "1px solid var(--border)" }}>
                <span style={{ fontSize: 14, color: "var(--muted-foreground)" }}>{k}</span>
                <span style={{ fontSize: 14, fontWeight: 500, textAlign: "right" }}>{v}</span>
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- Story block ---------- */
function StoryBlock() {
  const [open, setOpen] = React.useState(false);
  return (
    <div style={{ marginTop: 56 }}>
      <h2 style={{ margin: "0 0 20px", maxWidth: 760, fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 30, letterSpacing: "-0.02em", lineHeight: 1.25, textWrap: "balance" }}>Những chuyến phiêu lưu đòi hỏi nhiều hơn. Chiếc Rally 1B đáp ứng được điều đó.</h2>
      <p style={{ margin: 0, maxWidth: 760, fontSize: 16, lineHeight: 1.7, color: "var(--muted-foreground)", textWrap: "pretty" }}>
        Dành cho những ai nghe thấy tiếng gọi của thiên nhiên hoang dã. RAPTOR Rally 1B là người bạn đồng hành đưa bạn vượt ra khỏi những con đường trải nhựa — nơi những khu rừng thâm u, chân trời trải dài và con dốc trở thành ký ức.{open && " Đi sâu hơn vào thiên nhiên và xa hơn bao giờ hết. Hãy để sức mạnh, sự thoải mái và khả năng vượt địa hình của Rally 1B đưa những vùng đất chưa được khám phá đến gần bạn hơn — từ những buổi sáng sương mù trên đỉnh đồi đến hoàng hôn rực rỡ bên bờ suối."}
      </p>
      <Button variant="outline" style={{ marginTop: 20 }} onClick={() => setOpen((o) => !o)}>{open ? "Thu gọn" : "Xem thêm"}</Button>
    </div>
  );
}

/* ---------- Reviews ---------- */
const DIST = [["5 sao", 51], ["4 sao", 9], ["3 sao", 6], ["2 sao", 5], ["1 sao", 11]];
const REVIEWS = [
  { name: "Nguyễn Minh Tuấn", date: "6 tháng 2, 2026", stars: 5, text: "Xe giao nhanh, đóng gói kỹ. Đạp thử quanh khu đô thị thấy sang số rất ngọt, khung nhôm nhẹ nên bê lên tầng gửi xe cũng dễ. Rất đáng tiền trong tầm giá này.", photos: true },
  { name: "Trần Thị Thu Hà", date: "15 tháng 11, 2025", stars: 5, text: "Mình mua cho con gái đi học, yên rất êm và phanh đĩa ăn. Nhân viên tư vấn size nhiệt tình, lắp ráp sẵn giao tận nhà. Cả nhà hài lòng." },
  { name: "Lê Hoàng Nam", date: "21 tháng 9, 2025", stars: 4, text: "Đạp đường đèo cuối tuần rất đã, phuộc ăn sóc tốt. Trừ một ít là lốp zin hơi trơn khi qua đường ướt, còn lại ổn áp trong tầm giá." },
  { name: "Phạm Quốc Đạt", date: "4 tháng 9, 2025", stars: 5, text: "Chiếc thứ hai mình mua ở Xedap.vn rồi. Chất lượng hoàn thiện tốt, mối hàn đẹp, bảo hành rõ ràng. Sẽ giới thiệu bạn bè ủng hộ shop." },
];
function Stars({ n }) {
  return <span style={{ display: "inline-flex", gap: 2 }}>{Array.from({ length: 5 }).map((_, i) => <i key={i} className={i < n ? "ph-fill ph-star" : "ph ph-star"} style={{ fontSize: 14, color: "var(--warning)" }} />)}</span>;
}
function ReviewsSection() {
  const [hover, setHover] = React.useState(0);
  const [rated, setRated] = React.useState(0);
  const total = DIST.reduce((s, [, n]) => s + n, 0);
  return (
    <section style={{ background: "color-mix(in srgb, var(--secondary) 40%, #fff)", borderTop: "1px solid var(--border)" }}>
      <div style={{ ...wrap, padding: "56px 16px" }}>
        <h2 style={{ margin: "0 0 28px", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 24 }}>Đánh giá</h2>
        <div style={{ display: "grid", gridTemplateColumns: "180px 1fr 300px", gap: 40, alignItems: "start" }}>
          <div style={{ textAlign: "center" }}>
            <div style={{ fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 56, lineHeight: 1 }}>4.9</div>
            <div style={{ margin: "10px 0 6px" }}><Stars n={5} /></div>
            <div style={{ fontSize: 13, color: "var(--muted-foreground)" }}>82 đánh giá</div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {DIST.map(([lbl, n]) => (
              <div key={lbl} style={{ display: "flex", alignItems: "center", gap: 12, fontSize: 13 }}>
                <span style={{ width: 42, color: "var(--muted-foreground)" }}>{lbl}</span>
                <div style={{ flex: 1, height: 8, borderRadius: 5, background: "var(--border)", overflow: "hidden" }}>
                  <div style={{ width: `${(n / total) * 100}%`, height: "100%", background: "var(--primary)" }} />
                </div>
                <span style={{ width: 24, textAlign: "right", fontFamily: "var(--font-mono)", color: "var(--muted-foreground)" }}>{n}</span>
              </div>
            ))}
          </div>
          <div style={{ padding: 20, borderRadius: "var(--radius-lg)", background: "#fff", border: "1px solid var(--border)" }}>
            <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 12 }}>Viết đánh giá</div>
            <div style={{ display: "flex", gap: 6, marginBottom: 12 }} onMouseLeave={() => setHover(0)}>
              {Array.from({ length: 5 }).map((_, i) => (
                <button key={i} onMouseEnter={() => setHover(i + 1)} onClick={() => setRated(i + 1)} style={{ border: "none", background: "none", cursor: "pointer", padding: 0 }}>
                  <i className={i < (hover || rated) ? "ph-fill ph-star" : "ph ph-star"} style={{ fontSize: 28, color: "var(--warning)" }} />
                </button>
              ))}
            </div>
            <p style={{ margin: 0, fontSize: 13, lineHeight: 1.5, color: "var(--muted-foreground)" }}>Việc thêm đánh giá yêu cầu bạn cung cấp địa chỉ email hợp lệ để xác minh.</p>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 20, marginTop: 40 }}>
          {REVIEWS.map((r) => (
            <div key={r.name} style={{ display: "flex", flexDirection: "column", gap: 10, padding: 20, borderRadius: "var(--radius-lg)", background: "#fff", border: "1px solid var(--border)" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 8 }}>
                <span style={{ fontSize: 14, fontWeight: 700 }}>{r.name}</span>
                <span style={{ fontSize: 12, color: "var(--muted-foreground)", whiteSpace: "nowrap" }}>{r.date}</span>
              </div>
              <Stars n={r.stars} />
              <p style={{ margin: 0, fontSize: 13, lineHeight: 1.6, color: "var(--foreground)", textWrap: "pretty" }}>{r.text}</p>
              {r.photos && (
                <div style={{ display: "flex", gap: 8 }}>
                  {[0, 1].map((i) => <div key={i} style={{ width: 56, height: 56, overflow: "hidden", background: "var(--secondary)" }}><img src={RAPTOR_SHOTS[i + 1]} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} /></div>)}
                </div>
              )}
              <a href="#" style={{ fontSize: 12, marginTop: "auto" }}>Đánh giá bản dịch</a>
            </div>
          ))}
        </div>
        <div style={{ display: "flex", justifyContent: "center", marginTop: 28 }}>
          <Button variant="outline"><i className="ph ph-chat-circle-dots" style={{ marginRight: 8 }} />Xem tất cả 82 đánh giá</Button>
        </div>
      </div>
    </section>
  );
}

/* ---------- Product rows ---------- */
function ProductRow({ title, items, onAdd, onOpen }) {
  const { IMG } = window.KitData;
  return (
    <section style={{ ...wrap, padding: "56px 16px" }}>
      <h2 style={{ margin: "0 0 28px", fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 24 }}>{title}</h2>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 20 }}>
        {items.map((p, k) => <Reveal key={p.slug} delay={k * 80}><ProductCard product={{ ...p, image: p.img || IMG(p.seed) }} onAdd={onAdd} onClick={() => onOpen && onOpen(p)} /></Reveal>)}
      </div>
    </section>
  );
}

/* ---------- Sticky buy bar ---------- */
function StickyBuyBar({ product, onAdd, visible }) {
  const [added, setAdded] = React.useState(false);
  const add = () => { onAdd(product); setAdded(true); clearTimeout(add._t); add._t = setTimeout(() => setAdded(false), 1700); };
  return (
    <div style={{ position: "fixed", left: 0, right: 0, bottom: 0, zIndex: 900, transform: visible ? "translateY(0)" : "translateY(115%)", transition: "transform .38s cubic-bezier(.22,.61,.36,1)", background: "rgba(255,255,255,.97)", backdropFilter: "blur(8px)", borderTop: "1px solid var(--border)", boxShadow: "0 -8px 30px rgba(0,0,0,.09)" }}>
      <div style={{ ...wrap, display: "flex", alignItems: "center", gap: 16, padding: "12px 16px" }}>
        <img src={product.img || RAPTOR_SHOTS[0]} alt="" style={{ width: 52, height: 52, objectFit: "cover", borderRadius: "var(--radius-md)", flexShrink: 0, background: "var(--secondary)" }} />
        <div style={{ display: "flex", flexDirection: "column", gap: 2, minWidth: 0, flex: 1 }}>
          <span style={{ fontSize: 14, fontWeight: 700, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{product.name}</span>
          <span style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 16, fontWeight: 600, color: "var(--danger)" }}>{vnd(product.price)}</span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--muted-foreground)", textDecoration: "line-through" }}>{vnd(product.originalPrice)}</span>
          </span>
        </div>
        <Button size="lg" style={{ flexShrink: 0, boxShadow: "none", transition: "transform .18s cubic-bezier(.34,1.56,.64,1), background .2s", transform: added ? "scale(1.03)" : "none", ...(added ? { background: "#07c73c", borderColor: "#07c73c" } : {}) }} onClick={add}>{added ? <React.Fragment><i className="ph-fill ph-check-circle" style={{ marginRight: 8 }} />Đã thêm</React.Fragment> : <React.Fragment><i className="ph ph-shopping-cart-simple" style={{ marginRight: 8 }} />Thêm vào giỏ</React.Fragment>}</Button>
      </div>
    </div>
  );
}

/* ---------- Page ---------- */
function ProductDetail({ product, onAdd, onOpen, onBack, cartOpen }) {
  const { PRODUCTS } = window.KitData;
  const others = PRODUCTS.filter((p) => p.slug !== product.slug);
  const boughtTogether = [
    { slug: "acc-shimano-shoes", name: "Giày Đạp Xe Thể Thao Nam SHIMANO SH-GE700 Cycling Shoes", code: "Thương hiệu: SHIMANO", brand: "SHIMANO", price: 3790000, badge: "Phụ kiện", colors: [], rating: 4.8, count: 42, img: "https://cdn.hstatic.net/files/200001086651/file/27_2f8b64b9dc5241b0b8664af2c39c7d12.png" },
    { slug: "acc-giant-bottle", name: "Bình Nước Xe Đạp 750cc GIANT Cleanspring Water Bottle", code: "Thương hiệu: GIANT", brand: "GIANT", price: 319000, badge: "Phụ kiện", colors: [], rating: 4.7, count: 96, img: "https://cdn.hstatic.net/files/200001086651/file/28_fc78141de6c943fc833a36aa0e710a19.png" },
    { slug: "acc-handlebar-bag", name: "Túi Ghi Đông Xe Đạp 190x110x35mm GI59 Bicycle Handlebar Bag", code: "Phụ kiện", brand: "GI59", price: 299000, badge: "Phụ kiện", colors: [], rating: 4.6, count: 58, img: "https://cdn.hstatic.net/files/200001086651/file/29_63bdd217cbe6431298a63db5848206c5.png" },
    { slug: "acc-baimei-pump", name: "Ống Bơm Xe Đạp BAIMEI Air B-4518 Bicycle Mini Floor Pump", code: "Thương hiệu: BAIMEI", brand: "BAIMEI", price: 139000, badge: "Phụ kiện", colors: [], rating: 4.5, count: 73, img: "https://cdn.hstatic.net/files/200001086651/file/30_f25d9805d7f04a7fb48ed89de3f00512.png" },
  ];
  const buyRef = React.useRef(null);
  const [showBar, setShowBar] = React.useState(false);
  React.useEffect(() => {
    const el = buyRef.current;
    const footer = document.querySelector("footer");
    let buyOut = false, footerIn = false;
    const upd = () => setShowBar(buyOut && !footerIn);
    const io1 = new IntersectionObserver(([e]) => { buyOut = !e.isIntersecting && e.boundingClientRect.top < 0; upd(); }, { threshold: 0 });
    if (el) io1.observe(el);
    let io2;
    if (footer) { io2 = new IntersectionObserver(([e]) => { footerIn = e.isIntersecting; upd(); }, { threshold: 0, rootMargin: "0px 0px 40px 0px" }); io2.observe(footer); }
    return () => { io1.disconnect(); io2 && io2.disconnect(); };
  }, [product.slug]);
  return (
    <main>
      <div style={{ ...wrap, padding: "20px 16px 8px" }}>
        <button onClick={onBack} style={{ display: "flex", alignItems: "center", gap: 6, border: "none", background: "none", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 14, color: "var(--muted-foreground)" }}><i className="ph ph-arrow-left" /> Quay lại cửa hàng</button>
      </div>
      <div style={{ ...wrap, padding: "12px 16px 56px", display: "grid", gridTemplateColumns: "2fr 1fr", gap: 48, alignItems: "start" }}>
        <div style={{ position: "sticky", top: 84 }}><Gallery product={product} /></div>
        <div ref={buyRef}><BuyBox product={product} onAdd={onAdd} /></div>
      </div>
      <div style={{ ...wrap, padding: "0 16px 56px" }}>
        <ComboSection />
      </div>
      <div style={{ borderTop: "1px solid var(--border)" }}>
        <div style={{ ...wrap, padding: "56px 16px", display: "grid", gridTemplateColumns: "2fr 1fr", gap: 48, alignItems: "start" }}>
          <div><FeatureGrid /><StoryBlock /></div>
          <div style={{ position: "sticky", top: 84 }}><SpecTable /></div>
        </div>
      </div>
      <ReviewsSection />
      <ProductRow title="Các lựa chọn tương tự" items={others.slice(0, 4)} onAdd={onAdd} onOpen={onOpen} />
      <div style={{ background: "color-mix(in srgb, var(--secondary) 40%, #fff)", borderTop: "1px solid var(--border)" }}>
        <ProductRow title="Trang bị thêm cho hành trình" items={boughtTogether} onAdd={onAdd} onOpen={onOpen} />
      </div>
      <StickyBuyBar product={product} onAdd={onAdd} visible={showBar && !cartOpen} />
    </main>
  );
}

Object.assign(window, { ProductDetail });
