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

// Currency config, overwritten from products.json on load. Prices in the
// catalog are stored in RON (lei); euro is derived via euroConversion.
let CURRENCY = { base: "RON", euroConversion: 5.26 };
const fmtLei = (n) => `${Math.round(n).toLocaleString("ro-RO")} lei`;
const fmtEur = (n) => `€${Math.round(n / (CURRENCY.euroConversion || 1))}`;

// ─────────── i18n ───────────
const I18N = {
  ro: {
    // announcement
    annc1: "Livrare gratuită în toată țara la orice comandă de peste 200 lei",
    // nav
    nav_home: "Acasă",
    nav_shop: "Magazin",
    nav_contact: "Contactează-ne",
    // shop page
    shop_h2_a: "Toate ",
    shop_h2_em: "creațiile noastre.",
    shop_sub: "Fiecare piesă, realizată manual în atelierul nostru.\nAlege și personalizează.",
    // shop filters
    filter_all: "Toate",
    filter_label_cat: "Categorie",
    filter_label_show: "Afișează",
    filter_sort: "Sortează",
    sort_featured: "Recomandate",
    sort_price_asc: "Preț crescător",
    sort_price_desc: "Preț descrescător",
    filter_empty: "Nicio creație nu corespunde filtrelor alese.",
    filter_clear: "Resetează filtrele",
    // header / search
    search_placeholder: "Caută un cadou, o idee, un sentiment…",
    aria_search: "Căutare",
    aria_account: "Cont",
    aria_wishlist: "Favorite",
    aria_close: "Închide",
    // hero
    hero_eyebrow: "Cadouri personalizate · Făcute în Iași",
    hero_h1_1: "Dacă o poți visa,",
    hero_h1_2: "noi o putem crea.",
    hero_lede: "La Artelier, transformăm ideile tale în amintiri palpabile. Combinăm tehnologia printării 3D de înaltă precizie cu magia lucrului făcut manual.\n\n\nFiecare piesă premium este finisată cu atenție și pictată manual, iar pentru un efect cu adevărat spectaculos, îi putem adăuga lumini LED integrate. \n\n\nOferă un cadou unic! Lasă-ne un mesaj cu ideea ta și o aducem la viață.",
    hero_cta_primary: "Începe să creezi",
    hero_cta_secondary: "Cum funcționează",
    hero_meta1_lbl: "obiecte ajunse acasă",
    hero_meta2_lbl: "recenzie medie",
    hero_meta3_lbl: "timp până la primul proiect",
    // floating cards
    float_pick: "Alege finisajul",
    float_lbl: "Cană personalizată",
    // categories
    cat_h2_a: "Explorează ",
    cat_h2_em: "categoriile noastre →",
    cat_sub: "Cadouri create din pasiune — pentru cei dragi.",
    cat_product: "produs",
    cat_products: "produse",
    // products
    prod_h2_a: "Piesele iubite de ",
    prod_h2_em: "clienții noștri.",
    prod_sub: "Fiecare cadou pictat manual este unic.",
    tab_best: "Cele mai vândute",
    tab_new: "Noutăți",
    tab_weddings: "Nunți",
    prod_inquire: "Comandă privat",
    wa_msg: "Bună! Aș dori să comand: ",
    from: "de la",
    // how it works
    how_eyebrow: "Procesul Artelier",
    how_h2_a: "Trei pași simpli. ",
    how_h2_em: "Un cadou unicat.",
    // testimonials
    testi_h2_a: "Note de la ",
    testi_h2_em: "destinatarii noștri.",
    testi_sub: "4,9 medie din peste 3.200 de recenzii · cumpărători verificați",
    // cta
    cta_h2_a: "Un cadou pentru tine ",
    cta_h2_em: "din partea noastră.",
    cta_p: "La orice comandă de minim 100 lei, vei primi un cadou din partea echipei\u00A0Artelier.",
    cta_placeholder: "adresa@email.ro",
    cta_btn: "Mă abonez →",
    cta_invalid: "Te rugăm să introduci un email valid.",
    cta_thanks: "Mulțumim — plasează o comandă și vei primi cadoul tău alături la livrare. ✦",
    // footer
    ftr_brand_p: "La Artelier aducem la realitate ideile tale. Dacă dorești un cadou personalizat, un obiect care nu se mai găsește sau este mai puțin costisitoare printarea acestuia, ai ajuns în locul potrivit. Scrie-ne pe WhatsApp ce îți dorești iar noi ne vom ocupa de restul.",
    ftr_addr: "© 2026 Artelier · Iași, România",
    ftr_menu: "Meniu",
    m_home: "Acasă",
    m_contact: "Contactează-ne",
    ftr_cats: "Categorii",
    c_flowers: "Buchete de flori",
    c_magnets: "Magneți personalizați",
    c_handpainted: "Obiecte pictate manual",
    c_print3d: "Obiecte printate 3D",
    c_design3d: "Proiectare 3D",
    ftr_social: "Rețele de socializare",
    // search suggestions
    sug: ["Cutii gravate", "Cadouri de nuntă", "Imprimeuri foto", "Pentru ea", "Sub 250 lei", "Noutăți"],
    // currency
    fmt: (n) => fmtLei(n),
    // categories
    cat_engraved: "Obiecte gravate",
    cat_photo: "Imprimeuri foto",
    cat_mugs: "Pahare & căni",
    cat_jewel: "Bijuterii",
    cat_home: "Casă & living",
    // category placeholders (English fine, they're maker notes)
    // product detail page
    pd_back: "Înapoi la magazin",
    pd_back_home: "Înapoi la pagina principală",
    pd_gallery: "Galerie",
    pd_dimensions: "Dimensiuni",
    pd_delivery: "Timp de livrare",
    pd_delivery_unit: "zile",
    pd_details: "Detalii",
    pd_price_on_request: "Preț la cerere",
    pd_inquire: "Comandă pe WhatsApp",
    pd_related: "Alte produse care ți-ar putea plăcea",
    pd_not_found: "Produsul nu a fost găsit.",
    // steps
    step1_t: "Concept", step1_b: "Împărtășește o idee, o fotografie, un nume, o frază. Cu cât detaliul este mai mic, cu atât contează mai mult.",
    step2_t: "Proiectare", step2_b: "Colegii noștri îți trimit machete în 48 de ore pentru rafinarea tipografiei, detaliilor, finisajului, până e exact cum îți dorești.",
    step3_t: "Realizare", step3_b: "Realizat în atelierul nostru din Iași și livrat în cel mult 14 zile, după complexitate.",
    // testimonials
    t1_q: "Cutia din nuc a sosit împachetată ca o bijuterie. Mama a plâns când a deschis-o.",
    t1_n: "Camelia R.", t1_l: "Cluj-Napoca, RO", t1_i: "CR",
    t2_q: "Le-am trimis o schiță făcută pe un șervețel. Au transformat-o în cel mai grijuliu cadou de aniversare.",
    t2_n: "Mihai S.", t2_l: "Timișoara, RO", t2_i: "MS",
    t3_q: "Trei runde de machete, zero presiune. Echipa chiar a ținut să iasă perfect spațierea literelor.",
    t3_n: "Ana T.", t3_l: "Iași, RO", t3_i: "AT"
  },
  en: {
    annc1: "Free nationwide delivery on any order over 200 lei",
    nav_home: "Home",
    nav_shop: "Shop",
    nav_contact: "Contact us",
    // shop page
    shop_h2_a: "All ",
    shop_h2_em: "our creations.",
    shop_sub: "Every piece handmade in our atelier.\nBrowse and personalize.",
    // shop filters
    filter_all: "All",
    filter_label_cat: "Category",
    filter_label_show: "Show",
    filter_sort: "Sort",
    sort_featured: "Featured",
    sort_price_asc: "Price: low to high",
    sort_price_desc: "Price: high to low",
    filter_empty: "No creations match the selected filters.",
    filter_clear: "Clear filters",
    search_placeholder: "Search for a gift, an idea, a feeling…",
    aria_search: "Search",
    aria_account: "Account",
    aria_wishlist: "Wishlist",
    aria_close: "Close",
    hero_eyebrow: "Custom gifts · Made in Iași",
    hero_h1_1: "If you can dream it,",
    hero_h1_2: "we can make it.",
    hero_lede: "At Artelier, we turn your ideas into tangible memories. We blend high-precision 3D printing with the magic of handcrafting.\n\n\nEvery premium piece is carefully finished and hand-painted — and for a truly spectacular effect, we can add integrated LED lights.\n\n\nGive a one-of-a-kind gift! Send us a message with your idea and we'll bring it to life.",
    hero_cta_primary: "Start designing",
    hero_cta_secondary: "How it works",
    hero_meta1_lbl: "pieces in homes",
    hero_meta2_lbl: "average review",
    hero_meta3_lbl: "proof turnaround",
    float_pick: "Pick your finish",
    float_lbl: "Custom mug",
    cat_h2_a: "Explore ",
    cat_h2_em: "our categories →",
    cat_sub: "Gifts created with passion — for the ones you love.",
    cat_product: "product",
    cat_products: "products",
    prod_h2_a: "Pieces our ",
    prod_h2_em: "customers love.",
    prod_sub: "Every hand-painted gift is one of a kind.",
    tab_best: "Bestsellers",
    tab_new: "New arrivals",
    tab_weddings: "Weddings",
    prod_inquire: "Order privately",
    wa_msg: "Hello! I'd like to order: ",
    from: "from",
    how_eyebrow: "The Artelier process",
    how_h2_a: "Three simple steps. ",
    how_h2_em: "One unique gift.",
    testi_h2_a: "Notes from ",
    testi_h2_em: "our recipients.",
    testi_sub: "4.9 average from 3,200+ reviews · verified buyers",
    cta_h2_a: "A gift for you, ",
    cta_h2_em: "from us.",
    cta_p: "On any order of at least 20 euro, you'll receive a gift from the Artelier\u00A0team.",
    cta_placeholder: "your@email.com",
    cta_btn: "Subscribe →",
    cta_invalid: "Please enter a valid email.",
    cta_thanks: "Thank you — place an order and you'll receive your gift along with your delivery. ✦",
    ftr_brand_p: "At Artelier we bring your ideas to life. Whether you want a personalized gift, an item that's no longer available, or a cheaper way to 3D-print one, you've come to the right place. Tell us what you'd like on WhatsApp and we'll take care of the rest.",
    ftr_addr: "© 2026 Artelier · Iași, România",
    ftr_menu: "Menu",
    m_home: "Home",
    m_contact: "Contact us",
    ftr_cats: "Categories",
    c_flowers: "Flower bouquets",
    c_magnets: "Personalized magnets",
    c_handpainted: "Hand-painted items",
    c_print3d: "3D printed items",
    c_design3d: "3D design",
    ftr_social: "Social media",
    sug: ["Engraved boxes", "Wedding gifts", "Photo prints", "For her", "Under €50", "New arrivals"],
    fmt: (n) => fmtEur(n),
    cat_engraved: "Engraved Keepsakes",
    cat_photo: "Photo Prints",
    cat_mugs: "Drinkware",
    cat_jewel: "Jewelry",
    cat_home: "Home & Living",
    // product detail page
    pd_back: "Back to shop",
    pd_back_home: "Back to home",
    pd_gallery: "Gallery",
    pd_dimensions: "Dimensions",
    pd_delivery: "Delivery time",
    pd_delivery_unit: "days",
    pd_details: "Details",
    pd_price_on_request: "Price on request",
    pd_inquire: "Order on WhatsApp",
    pd_related: "Other products you might like",
    pd_not_found: "Product not found.",
    step1_t: "Concept", step1_b: "Share an idea, a photo, a name, a phrase. The smaller the detail, the more it matters.",
    step2_t: "Design", step2_b: "Our team sends you proofs within 48 hours to refine the type, the details, the finish, until it's exactly how you want it.",
    step3_t: "Crafted", step3_b: "Crafted in our Iași atelier and delivered within 14 days at most, depending on complexity.",
    t1_q: "The walnut box arrived wrapped like a piece of jewelry. My mother cried opening it.",
    t1_n: "Camille R.", t1_l: "Paris, FR", t1_i: "CR",
    t2_q: "I sent a napkin sketch from a notebook. They turned it into the most thoughtful anniversary gift.",
    t2_n: "Mateo S.", t2_l: "Buenos Aires, AR", t2_i: "MS",
    t3_q: "Three rounds of proofs, zero pressure. The team genuinely cared about getting the kerning right.",
    t3_n: "Hana T.", t3_l: "Tokyo, JP", t3_i: "HT"
  }
};

const LangCtx = createContext({ lang: "ro", t: I18N.ro, setLang: () => {} });
const useT = () => useContext(LangCtx);

// ─────────── Data ───────────
// ─────────── Product catalog (loaded from products.json) ───────────
// Pick the right language out of a { ro, en } field (or pass through a plain string).
const L = (field, lang) => {
  if (field == null) return "";
  if (typeof field === "string") return field;
  return field[lang] || field.en || field.ro || "";
};

// Build a price string honoring priceVisible / fromPrice flags.
function priceLabel(p, t) {
  if (p.priceVisible === false) return t.pd_price_on_request;
  const value = t.fmt(p.price);
  return p.fromPrice ? { from: t.from, value } : { value };
}

const TESTIMONIALS_KEYS = [
{ qK: "t1_q", nK: "t1_n", lK: "t1_l", iK: "t1_i" },
{ qK: "t2_q", nK: "t2_n", lK: "t2_l", iK: "t2_i" },
{ qK: "t3_q", nK: "t3_n", lK: "t3_l", iK: "t3_i" }];


// ─────────── Routing helpers ───────────
// Hash routes: "#/" (home), "#/shop" (all products), or "#/product/<slug>".
const parseRoute = () => {
  const h = (window.location.hash || "").replace(/^#/, "");
  const m = h.match(/^\/product\/([^?]+)(?:\?from=(\w+))?$/);
  if (m) return { page: "product", slug: decodeURIComponent(m[1]), from: m[2] || null };
  const s = h.match(/^\/shop\/?(?:\?cat=([^&]+))?$/);
  if (s) return { page: "shop", cat: s[1] ? decodeURIComponent(s[1]) : null };
  return { page: "home" };
};
const goHome = () => {window.location.hash = "#/";};
const goShop = (cat) => {window.location.hash = "#/shop" + (cat ? "?cat=" + encodeURIComponent(cat) : "");};
const goProduct = (slug, from) => {window.location.hash = "#/product/" + encodeURIComponent(slug) + (from ? "?from=" + from : "");};

// ─────────── Helpers ───────────
const ImgPh = ({ label, style }) =>
<div className="img-ph" style={style}>{label}</div>;


const Stars = ({ n = 5 }) =>
<div className="stars">{Array.from({ length: n }, (_, i) => <span key={i}>★</span>)}</div>;


// ─────────── Components ───────────
function LangToggle({ lang, setLang }) {
  return (
    <div className="lang-toggle" role="group" aria-label="Language">
      <button
        className={lang === "ro" ? "on" : ""}
        onClick={() => setLang("ro")}
        aria-pressed={lang === "ro"}>
        RO</button>
      <span className="lang-sep">·</span>
      <button
        className={lang === "en" ? "on" : ""}
        onClick={() => setLang("en")}
        aria-pressed={lang === "en"}>
        EN</button>
    </div>);

}

function Header({ onNav, active, lang, setLang }) {
  const { t } = useT();
  const [searchOpen, setSearchOpen] = useState(false);
  const [socialsOpen, setSocialsOpen] = useState(false);
  const [scrolled, setScrolled] = useState(false);
  const [anim, setAnim] = useState(false);
  const [q, setQ] = useState("");
  const inputRef = useRef(null);
  const headerRef = useRef(null);
  const mounted = useRef(false);

  // Enable the logo pop animation only after the first real scroll toggle,
  // so the marks don't pop on initial page load.
  useEffect(() => {
    if (mounted.current) setAnim(true);else
    mounted.current = true;
  }, [scrolled]);

  useEffect(() => {
    if (searchOpen) setTimeout(() => inputRef.current?.focus(), 60);
  }, [searchOpen]);

  useEffect(() => {
    let ticking = false;
    const update = () => {
      ticking = false;
      const y = window.scrollY;
      // Continuous thinning: 0 at top -> 1 at 50px scrolled.
      const p = Math.min(1, Math.max(0, y / 50));
      if (headerRef.current) headerRef.current.style.setProperty("--p", p.toFixed(4));
      // Hysteresis: condense past 50px, expand only below 35px — avoids
      // flip-flopping (and the resulting shake) when hovering near the threshold.
      setScrolled((prev) => {
        if (!prev && y > 50) return true;
        if (prev && y < 35) return false;
        return prev;
      });
    };
    const onScroll = () => {
      if (!ticking) {ticking = true;requestAnimationFrame(update);}
    };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const navItems = [
  ["Home", t.nav_home],
  ["Shop", t.nav_shop]];

  // Navigate then close the socials popover.
  const navTo = (id) => {setSocialsOpen(false);onNav(id);};

  // Social icons — rendered both in the desktop header and the mobile menu.
  const socialLinks =
  <>
      <a className="icon-btn social" href="https://api.whatsapp.com/send/?phone=40770446732&text&type=phone_number&app_absent=0" target="_blank" rel="noopener" aria-label="WhatsApp">
        <svg viewBox="0 0 24 24"><path fillRule="evenodd" clipRule="evenodd" d="M12.04 2C6.58 2 2.13 6.45 2.13 11.91c0 1.75.46 3.45 1.32 4.95L2 22l5.25-1.38a9.9 9.9 0 0 0 4.79 1.22h.01c5.46 0 9.91-4.45 9.91-9.91 0-2.65-1.03-5.14-2.9-7.01A9.82 9.82 0 0 0 12.04 2zm4.52 11.97c-.25-.12-1.47-.72-1.69-.81-.23-.08-.39-.12-.56.13-.16.25-.64.81-.79.97-.14.17-.29.19-.54.06-.25-.12-1.05-.39-1.99-1.23-.74-.66-1.23-1.47-1.38-1.72-.14-.25-.01-.38.11-.51.11-.11.25-.29.37-.43.13-.14.17-.25.25-.41.08-.17.04-.31-.02-.43-.06-.12-.56-1.34-.76-1.84-.2-.48-.41-.42-.56-.43h-.48c-.17 0-.43.06-.66.31-.22.25-.86.85-.86 2.07 0 1.22.89 2.4 1.01 2.56.12.17 1.75 2.67 4.24 3.74.59.26 1.05.41 1.41.52.59.19 1.13.16 1.56.1.48-.07 1.47-.6 1.68-1.18.21-.58.21-1.07.14-1.18-.06-.1-.22-.16-.47-.28z"></path></svg>
      </a>
      <a className="icon-btn social" href="https://www.instagram.com/artelier_ig" target="_blank" rel="noopener" aria-label="Instagram">
        <svg viewBox="0 0 24 24"><path fillRule="evenodd" clipRule="evenodd" d="M7 2h10a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5V7a5 5 0 0 1 5-5zm5 5.2a4.8 4.8 0 1 0 0 9.6 4.8 4.8 0 0 0 0-9.6zm0 2a2.8 2.8 0 1 1 0 5.6 2.8 2.8 0 0 1 0-5.6zM17.6 5.3a1.3 1.3 0 1 0 0 2.6 1.3 1.3 0 0 0 0-2.6z"></path></svg>
      </a>
      <a className="icon-btn social" href="https://www.tiktok.com/@artelier_tt" target="_blank" rel="noopener" aria-label="TikTok">
        <svg viewBox="0 0 24 24"><path d="M16.6 5.82a4.28 4.28 0 0 1-1.06-2.82h-3.1v12.32a2.55 2.55 0 0 1-2.55 2.5 2.55 2.55 0 0 1-2.56-2.55 2.55 2.55 0 0 1 3.3-2.44V9.66a5.66 5.66 0 0 0-.74-.05A5.66 5.66 0 0 0 4.23 15.27a5.66 5.66 0 0 0 9.71 3.96 5.66 5.66 0 0 0 1.66-4V8.9a7.32 7.32 0 0 0 4.27 1.37V7.17a4.28 4.28 0 0 1-3.27-1.35z"></path></svg>
      </a>
      <a className="icon-btn social" href="https://www.facebook.com/profile.php?id=61586637300352" target="_blank" rel="noopener" aria-label="Facebook">
        <svg viewBox="0 0 24 24"><path d="M22 12.06C22 6.5 17.52 2 12 2S2 6.5 2 12.06c0 5.02 3.66 9.18 8.44 9.94v-7.03H7.9v-2.91h2.54V9.85c0-2.52 1.49-3.91 3.78-3.91 1.1 0 2.24.2 2.24.2v2.47h-1.26c-1.24 0-1.63.78-1.63 1.57v1.88h2.78l-.44 2.91h-2.34V22c4.78-.76 8.43-4.92 8.43-9.94z"></path></svg>
      </a>
    </>;


  return (
    <>
      <div className="annc">
        <div className="annc-track">
          {[0, 1].map((g) =>
          <div className="annc-group" key={g} aria-hidden={g === 1 ? "true" : undefined}>
              {[0, 1, 2].map((i) =>
            <span className="annc-item" key={i}>
                  {t.annc1}<span className="annc-dot">✦</span>
                </span>
            )}
            </div>
          )}
        </div>
      </div>
      <header ref={headerRef} className={"hdr" + (scrolled ? " condensed" : "") + (anim ? " anim" : "")}>
        <div className="hdr-inner">
          <div className="hdr-left">
            <nav className="nav">
              {navItems.map(([id, label]) =>
              <button
                key={id}
                className={active === id ? "active" : ""}
                onClick={() => onNav(id)}>

                  {label}
                </button>
              )}
            </nav>
          </div>
          <a href="#" className="logo" onClick={(e) => {e.preventDefault();setSocialsOpen(false);onNav("Home");window.scrollTo(0, 0);}}>
            <img className="logo-badge" src="assets/artelier-logo.png" alt="Artelier" />
            <img className="logo-text" src="assets/artelier-logo-text.png" alt="Artelier" />
          </a>
          <div className="hdr-icons">
            <LangToggle lang={lang} setLang={setLang} />
            <div className="socials">
              {socialLinks}
            </div>
          </div>
        </div>
        {searchOpen &&
        <div className="search-overlay">
            <div className="search-inner">
              <input
              ref={inputRef}
              className="search-input"
              placeholder={t.search_placeholder}
              value={q}
              onChange={(e) => setQ(e.target.value)}
              onKeyDown={(e) => e.key === "Escape" && setSearchOpen(false)} />
            
              <div className="search-sugs">
                {t.sug.map((s) =>
              <button key={s} className="pill" onClick={() => setQ(s)}>{s}</button>
              )}
              </div>
            </div>
          </div>
        }
      </header>

      {/* Mobile bottom tab bar — app-style navigation (hidden on desktop) */}
      {socialsOpen && <div className="botbar-scrim" onClick={() => setSocialsOpen(false)}></div>}
      <nav className="botbar" aria-label="Navigation">
        <button
          className={"botbar-btn" + (active === "Home" ? " active" : "")}
          onClick={() => {navTo("Home");window.scrollTo({ top: 0, behavior: "smooth" });}}>
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M11.29 3.6 3.4 10.7a1 1 0 0 0-.33.74V20a1 1 0 0 0 1 1h4.27v-5.1a.9.9 0 0 1 .9-.9h3.52a.9.9 0 0 1 .9.9V21H18a1 1 0 0 0 1-1v-8.56a1 1 0 0 0-.33-.74L12.71 3.6a1.06 1.06 0 0 0-1.42 0Z"></path></svg>
          <span>{t.nav_home}</span>
        </button>
        <button
          className={"botbar-btn" + (active === "Shop" ? " active" : "")}
          onClick={() => navTo("Shop")}>
          <svg viewBox="0 0 24 24" aria-hidden="true"><path fillRule="evenodd" clipRule="evenodd" d="M7.5 7.2a4.5 4.5 0 0 1 9 0V8h2.1a1 1 0 0 1 1 .92l.86 10.8A1.2 1.2 0 0 1 20.16 21H3.84a1.2 1.2 0 0 1-1.2-1.28L3.5 8.92A1 1 0 0 1 4.5 8h2v-.8Zm2 .8h5v-.8a2.5 2.5 0 0 0-5 0V8Z"></path></svg>
          <span>{t.nav_shop}</span>
        </button>
        <div className="botbar-soc">
          {socialsOpen &&
          <div className="botbar-pop">
              {socialLinks}
            </div>
          }
          <button
            className={"botbar-btn" + (socialsOpen ? " active" : "")}
            aria-expanded={socialsOpen}
            onClick={() => setSocialsOpen((v) => !v)}>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path className="ico-line" d="m8.3 10.8 6.6-3.6M8.3 13.2l6.6 3.6"></path><circle cx="6" cy="12" r="2.7"></circle><circle cx="17" cy="6" r="2.7"></circle><circle cx="17" cy="18" r="2.7"></circle></svg>
            <span>Social</span>
          </button>
        </div>
        <button
          className="botbar-btn botbar-lang"
          aria-label={"Switch language — " + lang.toUpperCase()}
          onClick={() => {setSocialsOpen(false);setLang(lang === "ro" ? "en" : "ro");}}>
          <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9.2"></circle><path className="ico-cut" d="M2.8 12h18.4M12 2.8c2.7 2.6 2.7 15.8 0 18.4M12 2.8c-2.7 2.6-2.7 15.8 0 18.4"></path></svg>
          <span>{lang.toUpperCase()}</span>
        </button>
      </nav>
    </>);

}

function Hero({ onShop, products }) {
  const { t, lang } = useT();

  // Products with a real photo to rotate through in the hero showcase.
  const showcase = (products || []).filter((p) => !p.draft && p.mainPhoto);
  const [idx, setIdx] = useState(0);

  // Advance every 3 seconds.
  useEffect(() => {
    if (showcase.length < 2) return;
    const id = setInterval(() => setIdx((i) => (i + 1) % showcase.length), 3000);
    return () => clearInterval(id);
  }, [showcase.length]);

  const active = showcase.length ? showcase[Math.min(idx, showcase.length - 1)] : null;
  const activeName = active ? L(active.name, lang) : t.float_lbl;
  const activeBadge = active && active.badge ? L(active.badge, lang) : "";
  const priceStr = active ? priceLabel(active, t) : null;

  return (
    <section className="hero">
      <div>
        <img className="hero-logo" src="assets/artelier-logo.png" alt="Artelier" />
        <div className="hero-eyebrow">
          {(() => {
            const parts = t.hero_eyebrow.split(" · ");
            return parts.length > 1 ?
            <span className="he-text">{parts[0]}<span className="he-loc"> · {parts.slice(1).join(" · ")}</span></span> :
            <span className="he-text">{t.hero_eyebrow}</span>;
          })()}
        </div>
        <h1>
          If you can dream it,<br /><em>we can make it.</em>
        </h1>
        <p className="lede">{t.hero_lede}</p>
        <div className="hero-cta">
          <button className="btn btn-primary" onClick={onShop}>
            {t.hero_cta_primary}
            <svg viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"></path></svg>
          </button>
        </div>
      </div>
      <div
        className="hero-art"
        onClick={() => active && goProduct(active.slug, "home")}
        style={{ cursor: active ? "pointer" : "default" }}>
        {showcase.length ?
        showcase.map((p, i) =>
        <img
          key={p.slug}
          className={"hero-photo" + (i === idx ? " on" : "")}
          src={p.mainPhoto}
          alt={L(p.name, lang)} />
        ) :
        <ImgPh label="hero photo · hands engraving wood" />
        }
        {activeBadge &&
        <span className={"product-tag" + (active.badgeAccent ? " accent" : "")}>{activeBadge}</span>
        }
        <div className="float-card br">
          <span className="lbl">{activeName}</span>
          {priceStr &&
          <span className="price">
            {typeof priceStr === "string" ?
            priceStr :
            (priceStr.from ? priceStr.from + " " : "") + priceStr.value}
          </span>
          }
        </div>
      </div>
    </section>);

}

function Categories({ categories = [] }) {
  const { t, lang } = useT();
  if (!categories.length) return null;
  return (
    <section className="section">
      <div className="section-hd">
        <h2 className="cat-h2">{t.cat_h2_a}<em style={{ fontSize: "50px" }}>{t.cat_h2_em}</em></h2>
        <div className="sub cat-sub">{t.cat_sub}</div>
      </div>
      <div className="cats">
        {categories.map((c) => <CategoryCard key={c.id} c={c} />)}
      </div>
    </section>);

}

// One category tile. If the category has products with photos, it cross-fades
// through their main photos (one per second). One photo → static. None →
// keeps the labelled placeholder.
function CategoryCard({ c }) {
  const { t, lang } = useT();
  const label = L(c.label, lang);
  const photos = c.photos || [];
  const [idx, setIdx] = useState(0);

  useEffect(() => {
    setIdx(0);
    if (photos.length < 2) return;
    const id = setInterval(
      () => setIdx((i) => (i + 1) % photos.length),
      3000
    );
    return () => clearInterval(id);
  }, [photos.length]);

  return (
    <div className="cat-wrap" onClick={() => goShop(c.id)}>
      <div className="cat">
        {photos.length ?
        photos.map((src, i) =>
        <img
          key={src + i}
          className={"cat-img" + (i === idx ? " on" : "")}
          src={src}
          alt={label} />
        ) :
        <ImgPh label={label} />
        }
        <div className="cat-overlay">
          <div className="cat-meta">
            <span>{c.count} {c.count === 1 ? t.cat_product : t.cat_products}</span>
            <span className="arrow">↗</span>
          </div>
        </div>
      </div>
      <div className="cat-label">{label}</div>
    </div>);

}

// Renders a product image, or a labelled placeholder when no src is set yet.
const ProductImage = ({ src, label, alt }) =>
src ?
<img className="product-img" src={src} alt={alt || ""} /> :

<ImgPh label={label} />;


// Price display honoring priceVisible / fromPrice.
function ProductPrice({ p, t, className }) {
  const lbl = priceLabel(p, t);
  if (typeof lbl === "string") {
    return <div className={(className || "") + " price-request"}>{lbl}</div>;
  }
  return (
    <div className={className}>
      {lbl.from && <span className="from">{lbl.from}</span>}{lbl.value}
    </div>);

}

function inquireOnWhatsApp(t, name) {
  const url =
  "https://api.whatsapp.com/send/?phone=40770446732&type=phone_number&app_absent=0&text=" +
  encodeURIComponent(t.wa_msg + name);
  window.open(url, "_blank", "noopener");
}

function ProductCard({ p, from }) {
  const { t, lang } = useT();
  const name = L(p.name, lang);
  const badge = p.badge ? L(p.badge, lang) : "";
  const mainLabel = p.gallery && p.gallery[0] ? p.gallery[0].label : name;
  return (
    <article className="product" onClick={() => goProduct(p.slug, from)}>
      <div className="product-media">
        <ProductImage src={p.mainPhoto} label={mainLabel} alt={name} />
        {badge &&
        <span className={"product-tag" + (p.badgeAccent ? " accent" : "")}>{badge}</span>
        }
        <button
          className="product-quick"
          onClick={(e) => {e.stopPropagation();inquireOnWhatsApp(t, name);}}>
          
          {t.prod_inquire}
        </button>
      </div>
      <div className="product-cat">{(p.categories || []).map((c) => L(c, lang)).join(" · ")}</div>
      <div className="product-name">{name}</div>
      {p.short && <div className="product-short">{L(p.short, lang)}</div>}
      <ProductPrice p={p} t={t} className="product-price" />
    </article>);

}

function Products({ products }) {
  const { t } = useT();
  const [tab, setTab] = useState("bestsellers");
  const tabs = [
  ["bestsellers", t.tab_best],
  ["new", t.tab_new]];

  const list = products.filter(
    (p) => !p.draft && (p.collections || []).includes(tab)
  );
  return (
    <section className="section" style={{ paddingTop: 24 }}>
      <div className="section-hd">
        <h2 className="cat-h2">{t.prod_h2_a}<em>{t.prod_h2_em}</em></h2>
        <div className="sub">{t.prod_sub}</div>
      </div>
      <div className="product-tabs">
        {tabs.map(([id, label]) =>
        <button key={id} className={tab === id ? "active" : ""} onClick={() => setTab(id)}>
            {label}
          </button>
        )}
      </div>
      <div className="products">
        {list.map((p) => <ProductCard key={p.id} p={p} from="home" />)}
      </div>
    </section>);

}

// ─────────── Shop page (all products) ───────────
function ShopPage({ products, categories, initialCat }) {
  const { t, lang } = useT();
  const [cat, setCat] = useState(initialCat || "all");        // category id or "all"
  const [show, setShow] = useState("all");       // "all" | "bestsellers" | "new"
  const [sort, setSort] = useState("featured");  // "featured" | "price-asc" | "price-desc"

  // Sync the active category when arriving via a deep link (e.g. clicking a
  // category tile on the home page) while the shop page is already mounted.
  useEffect(() => {
    setCat(initialCat || "all");
  }, [initialCat]);

  const all = (products || []).filter((p) => !p.draft);

  // Only show category chips for categories that actually contain products.
  const catChips = (categories || []).filter((c) => (c.count || 0) > 0);
  const showChips = [
  ["bestsellers", t.tab_best],
  ["new", t.tab_new]];

  let list = all.filter((p) => {
    if (cat !== "all" && !(p.categoryIds || []).includes(cat)) return false;
    if (show !== "all" && !(p.collections || []).includes(show)) return false;
    return true;
  });

  if (sort !== "featured") {
    // Products without a visible price sort to the end regardless of direction.
    const val = (p) => p.priceVisible === false || typeof p.price !== "number" ? null : p.price;
    list = [...list].sort((a, b) => {
      const va = val(a),bv = val(b);
      if (va == null && bv == null) return 0;
      if (va == null) return 1;
      if (bv == null) return -1;
      return sort === "price-asc" ? va - bv : bv - va;
    });
  }

  const dirty = cat !== "all" || show !== "all" || sort !== "featured";
  const reset = () => {setCat("all");setShow("all");setSort("featured");};

  return (
    <section className="section shop-page" style={{ paddingTop: 24 }}>
      <div className="section-hd">
        <h2>{t.shop_h2_a}<em>{t.shop_h2_em}</em></h2>
        <div className="sub" style={{ whiteSpace: "pre-line" }}>{t.shop_sub}</div>
      </div>

      <div className="shop-filters">
        <div className="filter-row">
          <span className="filter-label">{t.filter_label_cat}</span>
          <div className="filter-chips">
            <button
              className={"filter-chip" + (cat === "all" ? " active" : "")}
              onClick={() => setCat("all")}>
              {t.filter_all}
            </button>
            {catChips.map((c) =>
            <button
              key={c.id}
              className={"filter-chip" + (cat === c.id ? " active" : "")}
              onClick={() => setCat(c.id)}>
                {L(c.label, lang)}
              </button>
            )}
          </div>
          <div className="filter-select-wrap filter-select-mobile">
            <select
              className="filter-select"
              value={cat}
              onChange={(e) => setCat(e.target.value)}
              aria-label={t.filter_label_cat}>
              <option value="all">{t.filter_all}</option>
              {catChips.map((c) =>
              <option key={c.id} value={c.id}>{L(c.label, lang)}</option>
              )}
            </select>
            <svg viewBox="0 0 12 8" aria-hidden="true"><path d="M1 1.5 6 6.5 11 1.5" /></svg>
          </div>
        </div>

        <div className="filter-row">
          <span className="filter-label">{t.filter_label_show}</span>
          <div className="filter-chips">
            <button
              className={"filter-chip" + (show === "all" ? " active" : "")}
              onClick={() => setShow("all")}>
              {t.filter_all}
            </button>
            {showChips.map(([id, label]) =>
            <button
              key={id}
              className={"filter-chip" + (show === id ? " active" : "")}
              onClick={() => setShow(id)}>
                {label}
              </button>
            )}
          </div>
          <div className="filter-select-wrap filter-select-mobile">
            <select
              className="filter-select"
              value={show}
              onChange={(e) => setShow(e.target.value)}
              aria-label={t.filter_label_show}>
              <option value="all">{t.filter_all}</option>
              {showChips.map(([id, label]) =>
              <option key={id} value={id}>{label}</option>
              )}
            </select>
            <svg viewBox="0 0 12 8" aria-hidden="true"><path d="M1 1.5 6 6.5 11 1.5" /></svg>
          </div>

          <div className="filter-sort">
            <span className="filter-label">{t.filter_sort}</span>
            <div className="filter-select-wrap">
              <select
                className="filter-select"
                value={sort}
                onChange={(e) => setSort(e.target.value)}
                aria-label={t.filter_sort}>
                <option value="featured">{t.sort_featured}</option>
                <option value="price-asc">{t.sort_price_asc}</option>
                <option value="price-desc">{t.sort_price_desc}</option>
              </select>
              <svg viewBox="0 0 12 8" aria-hidden="true"><path d="M1 1.5 6 6.5 11 1.5" /></svg>
            </div>
            {dirty &&
            <button className="filter-clear" onClick={reset}>{t.filter_clear}</button>
            }
          </div>
        </div>
      </div>

      {list.length > 0 ?
      <div className="products">
          {list.map((p) => <ProductCard key={p.id} p={p} from="shop" />)}
        </div> :

      <div className="filter-empty">
          <p>{t.filter_empty}</p>
          <button className="filter-clear" onClick={reset}>{t.filter_clear}</button>
        </div>
      }
    </section>);

}

// ─────────── Related products carousel ───────────
// An infinite, auto-advancing carousel of other products. Shows 4 cards at a
// time (2 on mobile), prioritising pieces from the same category, then filling
// with the rest. Clones at both ends make the loop seamless in either
// direction; auto-play advances one card every 4s and pauses on hover.
const VISIBLE = 4;
function RelatedProducts({ product, products, from }) {
  const { t } = useT();

  const pool = useMemo(() => {
    const others = (products || []).filter((p) => !p.draft && p.id !== product.id);
    const catIds = product.categoryIds || [];
    const same = [], rest = [];
    others.forEach((p) =>
    ((p.categoryIds || []).some((id) => catIds.includes(id)) ? same : rest).push(p)
    );
    const shuffle = (arr) => {
      const a = [...arr];
      for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
      }
      return a;
    };
    return [...shuffle(same), ...shuffle(rest)];
  }, [product.id, products]);

  const [start, setStart] = useState(0);
  const [anim, setAnim] = useState(true);
  const [paused, setPaused] = useState(false);

  // Reset when the displayed product changes (navigating between products).
  useEffect(() => {setStart(0);setAnim(true);}, [product.id]);

  const looping = pool.length > VISIBLE;

  // Auto-play (paused on hover).
  useEffect(() => {
    if (!looping || paused) return;
    const id = setInterval(() => setStart((s) => s + 1), 4000);
    return () => clearInterval(id);
  }, [looping, paused, pool.length]);

  // Re-enable the transition on the frame after a no-anim wrap reset.
  useEffect(() => {
    if (!anim) {
      const r = requestAnimationFrame(() => requestAnimationFrame(() => setAnim(true)));
      return () => cancelAnimationFrame(r);
    }
  }, [anim]);

  // Safety net: if clicks/auto-play drift `start` clear past the cloned buffer
  // — e.g. mashing the arrow faster than each 720ms slide, which interrupts the
  // transitions so onTransitionEnd never fires to wrap — snap back into range.
  // The correction is a whole-loop multiple, so it shows identical cards and
  // never leaves a blank gap.
  useEffect(() => {
    if (pool.length > VISIBLE && (start >= 2 * pool.length - VISIBLE || start <= VISIBLE - pool.length)) {
      setAnim(false);
      setStart((s) => ((s % pool.length) + pool.length) % pool.length);
    }
  }, [start, pool.length]);

  if (!pool.length) return null;

  // Not enough to loop — just show a static row.
  if (!looping) {
    return (
      <section className="pd-related">
        <div className="pd-related-hd">
          <h2>{t.pd_related}</h2>
        </div>
        <div className="pd-related-viewport">
          <div className="pd-related-track no-anim" style={{ transform: "none" }}>
            {pool.map((p) => <ProductCard key={p.id} p={p} from={from} />)}
          </div>
        </div>
      </section>);

  }

  // A full copy of the pool on each side makes the loop seamless in both
  // directions and leaves a generous buffer for fast clicking.
  const items = [...pool, ...pool, ...pool];
  const offset = pool.length + start;

  // Once a slide settles outside the middle copy, rebase into [0, pool.length)
  // with no animation. Modulo handles an overshoot of any size in one step.
  const onEnd = () => {
    if (start < 0 || start >= pool.length) {
      setAnim(false);
      setStart((s) => ((s % pool.length) + pool.length) % pool.length);
    }
  };

  return (
    <section className="pd-related"
      onMouseEnter={() => setPaused(true)}
      onMouseLeave={() => setPaused(false)} >
      <div className="pd-related-hd">
        <h2>{t.pd_related}</h2>
        <div className="pd-related-nav">
          <button aria-label="Previous" onClick={() => setStart((s) => s - 1)}>
            <svg viewBox="0 0 24 24"><polyline points="15 5 8 12 15 19" /></svg>
          </button>
          <button aria-label="Next" onClick={() => setStart((s) => s + 1)}>
            <svg viewBox="0 0 24 24"><polyline points="9 5 16 12 9 19" /></svg>
          </button>
        </div>
      </div>
      <div className="pd-related-viewport">
        <div
          className={"pd-related-track" + (anim ? "" : " no-anim")}
          style={{ transform: "translateX(calc(var(--pd-step) * " + -offset + "))" }}
          onTransitionEnd={onEnd}>
          {items.map((p, i) => <ProductCard key={p.id + "-" + i} p={p} from={from} />)}
        </div>
      </div>
    </section>);

}

// ─────────── Product detail page ───────────
function ProductDetail({ product, from, products }) {
  const { t, lang } = useT();
  const [active, setActive] = useState(0);
  // Return to wherever the product was opened from: the shop if it came from
  // there, otherwise the home page (also the default for deep links).
  const goBack = () => from === "shop" ? goShop() : goHome();
  const backLabel = from === "shop" ? t.pd_back : t.pd_back_home;
  useEffect(() => {setActive(0);window.scrollTo(0, 0);}, [product && product.id]);

  if (!product) {
    return (
      <section className="section pd-missing">
        <p>{t.pd_not_found}</p>
        <button className="pd-back" onClick={goBack}>← {backLabel}</button>
      </section>);

  }

  const name = L(product.name, lang);
  const gallery = product.gallery && product.gallery.length ?
  product.gallery :
  [{ src: product.mainPhoto, label: name }];
  const current = gallery[Math.min(active, gallery.length - 1)];
  const d = product.delivery;

  return (
    <section className="pd">
      <button className="pd-back" onClick={goBack}>← {backLabel}</button>
      <div className="pd-grid">
        <div className="pd-gallery">
          <div className="pd-main">
            <ProductImage
              src={current && current.src ? current.src : product.mainPhoto}
              label={current ? current.label : name}
              alt={name} />
            
            {product.badge &&
            <span className={"product-tag" + (product.badgeAccent ? " accent" : "")}>
                {L(product.badge, lang)}
              </span>
            }
          </div>
          {gallery.length > 1 &&
          <div className="pd-thumbs">
              {gallery.map((g, i) =>
            <button
              key={i}
              className={"pd-thumb" + (i === active ? " active" : "")}
              onClick={() => setActive(i)}
              aria-label={g.label || name + " " + (i + 1)}>
              
                  <ProductImage src={g.src} label={g.label} alt={name} />
                </button>
            )}
            </div>
          }
        </div>

        <div className="pd-info">
          <div className="pd-cat">{(product.categories || []).map((c) => L(c, lang)).join(" · ")}</div>
          <h1 className="pd-name">{name}</h1>
          {product.short && <p className="pd-short">{L(product.short, lang)}</p>}
          <ProductPrice p={product} t={t} className="pd-price" />

          <dl className="pd-specs">
            {product.dimensions &&
            <div className="pd-spec">
                <dt>{t.pd_dimensions}</dt>
                <dd>{L(product.dimensions, lang)}</dd>
              </div>
            }
            {d &&
            <div className="pd-spec">
                <dt>{t.pd_delivery}</dt>
                <dd>{d.min}–{d.max} {t.pd_delivery_unit}</dd>
              </div>
            }
          </dl>

          <button className="pd-inquire" onClick={() => inquireOnWhatsApp(t, name)}>
            {t.pd_inquire}
          </button>
        </div>
      </div>

      {product.description &&
      <p className="pd-desc">{L(product.description, lang)}</p>
      }

      <RelatedProducts product={product} products={products} from={from} />
    </section>);

}

function HowItWorks() {
  const { t } = useT();
  const steps = [
  { num: "1", title: t.step1_t, body: t.step1_b },
  { num: "2", title: t.step2_t, body: t.step2_b },
  { num: "3", title: t.step3_t, body: t.step3_b }];

  return (
    <section className="how">
      <div className="how-wave" aria-hidden="true">
        <svg viewBox="0 0 1440 140" preserveAspectRatio="none">
          <path
            className="how-wave-fill"
            d="M0,0 H1440 V70 C1320,60 1230,112 1120,108 C980,103 940,54 820,60 C680,67 662,122 520,116 C380,110 360,70 240,78 C140,84 84,112 0,96 Z" />
        </svg>
      </div>
      <div className="how-inner">
        <div className="how-hd">
          <div className="eyebrow">{t.how_eyebrow}</div>
          <h2>{t.how_h2_a}<em>{t.how_h2_em}</em></h2>
        </div>
        <div className="steps">
          {steps.map((s) =>
          <div key={s.num} className="step">
              <div className="num">{s.num}</div>
              <h3>{s.title}</h3>
              <p>{s.body}</p>
            </div>
          )}
        </div>
      </div>
      <div className="how-drip" aria-hidden="true"></div>
    </section>);

}

function Testimonials() {
  const { t } = useT();
  return (
    <section className="section">
      <div className="section-hd">
        <h2>{t.testi_h2_a}<em>{t.testi_h2_em}</em></h2>
        <div className="sub">{t.testi_sub}</div>
      </div>
      <div className="testi">
        {TESTIMONIALS_KEYS.map((tk) =>
        <div key={tk.qK} className="quote">
            <Stars />
            <p>„{t[tk.qK]}"</p>
            <div className="by">
              <div className="avatar">{t[tk.iK]}</div>
              <div className="by-meta"><b>{t[tk.nK]}</b><span>{t[tk.lK]}</span></div>
            </div>
          </div>
        )}
      </div>
    </section>);

}

function CTA() {
  const { t } = useT();
  return (
    <section className="cta">
      <div className="cta-inner">
        <div className="cta-icon" aria-hidden="true">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <rect x="3" y="8" width="18" height="4" rx="1" />
            <path d="M12 8v13" />
            <path d="M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7" />
            <path d="M7.5 8a2.5 2.5 0 0 1 0-5A4.8 8 0 0 1 12 8a4.8 8 0 0 1 4.5-5 2.5 2.5 0 0 1 0 5" />
          </svg>
        </div>
        <div className="cta-text">
          <h2 className="cta-h2">{t.cta_h2_a}<em>{t.cta_h2_em}</em></h2>
          <p>{t.cta_p}</p>
        </div>
      </div>
    </section>);

}

function Footer({ categories = [] }) {
  const { t, lang } = useT();
  return (
    <footer className="ftr">
      <div className="ftr-inner">
        <div className="ftr-brand">
          <img className="ftr-logo" src="assets/artelier-logo.png" alt="Artelier" />
          <p>{t.ftr_brand_p}</p>
        </div>
        <div className="ftr-col">
          <h4>{t.ftr_menu}</h4>
          <ul>
            <li><a href="#" onClick={(e) => {e.preventDefault();goHome();window.scrollTo(0, 0);}}>{t.nav_home}</a></li>
            <li><a href="#" onClick={(e) => {e.preventDefault();goShop();}}>{t.nav_shop}</a></li>
          </ul>
        </div>
        <div className="ftr-col">
          <h4>{t.ftr_cats}</h4>
          <ul>
            {categories.map((c) =>
            <li key={c.id}><a href="#" onClick={(e) => {e.preventDefault();goShop(c.id);}}>{L(c.label, lang)}</a></li>
            )}
          </ul>
        </div>
        <div className="ftr-col">
          <h4>{t.ftr_social}</h4>
          <ul>
            <li><a href="https://api.whatsapp.com/send/?phone=40770446732&text&type=phone_number&app_absent=0" target="_blank" rel="noopener">WhatsApp</a></li>
            <li><a href="https://www.tiktok.com/@artelier_tt" target="_blank" rel="noopener">TikTok</a></li>
            <li><a href="https://www.instagram.com/artelier_ig" target="_blank" rel="noopener">Instagram</a></li>
            <li><a href="https://www.facebook.com/profile.php?id=61586637300352" target="_blank" rel="noopener">Facebook</a></li>
          </ul>
        </div>
      </div>
      <div className="ftr-bottom">
        <span>{t.ftr_addr}</span>
      </div>
    </footer>);

}

// ─────────── Tweaks ───────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": ["#B46161", "#000022", "#F7F3FC"],
  "displayFont": "Instrument Serif",
  "showAnnouncement": true,
  "ctaStyle": "accent"
} /*EDITMODE-END*/;

const FONT_STACKS = {
  "Instrument Serif": '"Instrument Serif", "Times New Roman", serif',
  "DM Serif Display": '"DM Serif Display", "Times New Roman", serif',
  "Cormorant": '"Cormorant Garamond", "Times New Roman", serif'
};

function applyTweaks(t) {
  const r = document.documentElement.style;
  r.setProperty("--accent", t.palette[0]);
  r.setProperty("--ink", t.palette[1]);
  r.setProperty("--bg", t.palette[2]);
  r.setProperty("--serif", FONT_STACKS[t.displayFont] || FONT_STACKS["Instrument Serif"]);
  const hex = t.palette[1].replace("#", "");
  const bigint = parseInt(hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex, 16);
  const rr = bigint >> 16 & 255,gg = bigint >> 8 & 255,bb = bigint & 255;
  r.setProperty("--ink-70", `rgba(${rr},${gg},${bb},0.7)`);
  r.setProperty("--ink-50", `rgba(${rr},${gg},${bb},0.5)`);
  r.setProperty("--ink-30", `rgba(${rr},${gg},${bb},0.3)`);
  r.setProperty("--ink-15", `rgba(${rr},${gg},${bb},0.15)`);
  r.setProperty("--ink-08", `rgba(${rr},${gg},${bb},0.08)`);
  r.setProperty("--ink-04", `rgba(${rr},${gg},${bb},0.04)`);
  const ax = t.palette[0].replace("#", "");
  const aint = parseInt(ax.length === 3 ? ax.split("").map((c) => c + c).join("") : ax, 16);
  const ar = aint >> 16 & 255,ag = aint >> 8 & 255,ab = aint & 255;
  r.setProperty("--accent-soft", `rgba(${ar},${ag},${ab},0.1)`);
}

const FONT_LINK_ID = "__extra-fonts";
function ensureFontLoaded(name) {
  if (name === "Instrument Serif") return;
  let link = document.getElementById(FONT_LINK_ID);
  if (!link) {
    link = document.createElement("link");
    link.rel = "stylesheet";
    link.id = FONT_LINK_ID;
    document.head.appendChild(link);
  }
  const family = name.replace(/ /g, "+");
  link.href = `https://fonts.googleapis.com/css2?family=${family}:ital,wght@0,400;0,500;1,400&display=swap`;
}

// ─────────── App ───────────
function App() {
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [lang, setLang] = useState("ro");
  const [products, setProducts] = useState(null);
  const [categories, setCategories] = useState([]);
  const [route, setRoute] = useState(parseRoute);

  // Load the catalog ("database") from products.json.
  useEffect(() => {
    fetch("products.json", { cache: "no-store" }).
    then((r) => r.json()).
    then((data) => {
      const list = Array.isArray(data) ? data : data.products || [];
      // Pick up currency config (base + euro conversion rate) from the catalog.
      if (data.currency) CURRENCY = { ...CURRENCY, ...data.currency };
      // Resolve each product's category id against the top-level categories list.
      const catMap = {};
      (data.categories || []).forEach((c) => {catMap[c.id] = c.label;});
      // Map each collection id to its badge label. A product's badge is derived
      // from the collections it belongs to (no per-product badge in the catalog).
      const collBadge = {};
      (data.collections || []).forEach((c) => {if (c.badge) collBadge[c.id] = c.badge;});
      // Priority: a product in "bestsellers" shows the Bestseller badge even if
      // it is also "new"; a product only in "new" shows the New badge.
      const badgeFor = (p) => {
        const ids = p.collections || [];
        if (ids.includes("bestsellers")) return { badge: collBadge["bestsellers"], badgeAccent: true };
        if (ids.includes("new")) return { badge: collBadge["new"], badgeAccent: false };
        return { badge: null, badgeAccent: false };
      };
      // Count how many (non-draft) products belong to each category id.
      const counts = {};
      // Collect each non-draft product's main photo per category id, so a
      // category tile can preview the actual pieces inside it.
      const photosByCat = {};
      list.forEach((p) => {
        if (p.draft) return;
        (p.categories || []).forEach((id) => {
          counts[id] = (counts[id] || 0) + 1;
          if (p.mainPhoto) (photosByCat[id] = photosByCat[id] || []).push(p.mainPhoto);
        });
      });
      setCategories(
        (data.categories || []).map((c) => ({
          ...c,
          count: counts[c.id] || 0,
          photos: photosByCat[c.id] || []
        }))
      );
      setProducts(
        list.map((p) => {
          const withBadge = { ...p, ...badgeFor(p) };
          return Array.isArray(p.categories) ?
          { ...withBadge, categoryIds: p.categories, categories: p.categories.map((id) => catMap[id] || id) } :
          withBadge;
        })
      );
    }).
    catch((err) => {console.error("Could not load products.json", err);setProducts([]);});
  }, []);

  // Keep the route in sync with the URL hash (back/forward + deep links).
  useEffect(() => {
    const onHash = () => setRoute(parseRoute());
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  // Land at the top of the page instantly whenever the route changes (home,
  // shop, category, or product) — no smooth scroll back up.
  useEffect(() => {window.scrollTo(0, 0);}, [route.page, route.cat]);

  useEffect(() => {applyTweaks(tw);}, [tw]);
  useEffect(() => {ensureFontLoaded(tw.displayFont);}, [tw.displayFont]);
  useEffect(() => {document.documentElement.lang = lang;}, [lang]);

  useEffect(() => {
    const el = document.querySelector(".annc");
    if (el) el.style.display = tw.showAnnouncement ? "" : "none";
  }, [tw.showAnnouncement]);

  useEffect(() => {
    const el = document.querySelector(".cta-inner");
    if (!el) return;
    if (tw.ctaStyle === "accent") {
      el.style.setProperty("--cta-bg", "var(--accent)");
      el.style.color = "#fff";
      el.style.border = "0";
    } else if (tw.ctaStyle === "ink") {
      el.style.setProperty("--cta-bg", "var(--ink)");
      el.style.color = "var(--bg)";
      el.style.border = "0";
    } else {
      el.style.setProperty("--cta-bg", "#fff");
      el.style.color = "var(--ink)";
      el.style.border = "1px solid var(--ink-08)";
    }
  }, [tw.ctaStyle, tw.palette]);

  const t = I18N[lang];
  const onProductPage = route.page === "product";
  const onShopPage = route.page === "shop";
  const activeProduct = onProductPage && products ?
  products.find((p) => p.slug === route.slug && !p.draft) :
  null;
  // Which top-nav item is highlighted (product detail keeps Shop lit).
  const activeNav = onShopPage || onProductPage ? "Shop" : "Home";

  // Handle top-nav clicks: route + scroll.
  const onNav = (n) => {
    if (n === "Shop") {
      goShop();
      window.scrollTo(0, 0);
    } else if (n === "Contact") {
      goHome();
      setTimeout(() => {
        const f = document.querySelector(".footer") || document.querySelector("footer");
        if (f) window.scrollTo({ top: f.getBoundingClientRect().top + window.scrollY - 20, behavior: "smooth" });
      }, 60);
    } else {
      goHome();
      window.scrollTo(0, 0);
    }
  };

  return (
    <LangCtx.Provider value={{ lang, t, setLang }}>
      <Header
        onNav={onNav}
        active={activeNav}
        lang={lang}
        setLang={setLang} />
      
      <main>
        {onProductPage ?
        products === null ?
        <section className="section pd-loading" /> :
        <ProductDetail product={activeProduct} from={route.from} products={products} /> :

        onShopPage ?
        products === null ?
        <section className="section pd-loading" /> :
        <ShopPage products={products} categories={categories} initialCat={route.cat} /> :

        <React.Fragment>
            <Hero products={products || []} onShop={() => {window.scrollTo({ top: window.innerHeight, behavior: "smooth" });}} />
            <HowItWorks />
            <Categories categories={categories} />
            {products && products.length > 0 && <Products products={products} />}
            <CTA />
          </React.Fragment>
        }
      </main>
      <Footer categories={categories} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Palette" />
        <TweakColor
          label="Theme"
          value={tw.palette}
          options={[
          ["#B46161", "#000022", "#F7F3FC"],
          ["#7B6A8F", "#1A1A2E", "#F4F1E8"],
          ["#3C7A60", "#0B1F1A", "#F2EFE6"],
          ["#1E3A5F", "#0A0E1A", "#EFEEEA"]]
          }
          onChange={(v) => setTweak("palette", v)} />
        
        <TweakSection label="Typography" />
        <TweakSelect
          label="Display font"
          value={tw.displayFont}
          options={["Instrument Serif", "DM Serif Display", "Cormorant"]}
          onChange={(v) => setTweak("displayFont", v)} />
        
        <TweakSection label="Layout" />
        <TweakToggle
          label="Announcement bar"
          value={tw.showAnnouncement}
          onChange={(v) => setTweak("showAnnouncement", v)} />
        
        <TweakRadio
          label="CTA style"
          value={tw.ctaStyle}
          options={["accent", "ink", "light"]}
          onChange={(v) => setTweak("ctaStyle", v)} />
        
      </TweaksPanel>
    </LangCtx.Provider>);

}

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