// components.jsx — shared components

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

/* ─── Icons (monoline SVG) ─────────────────────────────────────── */
const Icon = ({ name, size = 20, stroke = 1.6 }) => {
  const props = {
    width: size, height: size, viewBox: "0 0 24 24",
    fill: "none", stroke: "currentColor", strokeWidth: stroke,
    strokeLinecap: "round", strokeLinejoin: "round",
    "aria-hidden": true,
  };
  const paths = {
    arrow:    <path d="M5 12h14M13 5l7 7-7 7"/>,
    arrowSm:  <path d="M5 12h12M11 7l5 5-5 5"/>,
    chevron:  <path d="M6 9l6 6 6-6"/>,
    check:    <path d="M5 12l4 4L19 7"/>,
    x:        <><path d="M6 6l12 12"/><path d="M18 6L6 18"/></>,
    plus:     <><path d="M12 5v14"/><path d="M5 12h14"/></>,
    minus:    <path d="M5 12h14"/>,
    search:   <><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></>,
    shield:   <path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6l8-3z"/>,
    cap:      <><path d="M12 4l10 5-10 5L2 9l10-5z"/><path d="M6 11v4c0 2 3 3.5 6 3.5s6-1.5 6-3.5v-4"/></>,
    pin:      <><path d="M12 22s7-7 7-12a7 7 0 0 0-14 0c0 5 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></>,
    screen:   <><rect x="3" y="4" width="18" height="13" rx="2"/><path d="M8 21h8M12 17v4"/></>,
    lang:     <><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.5 3 4 6.5 4 9s-1.5 6-4 9c-2.5-3-4-6.5-4-9s1.5-6 4-9z"/></>,
    leaf:     <path d="M11 20A7 7 0 0 1 4 13C4 8 7 4 12 3c6 0 9 3 9 9 0 6-4 8-10 8z"/>,
    whatsapp: <><path d="M20.5 12a8.5 8.5 0 1 1-15.6-4.7A8.5 8.5 0 0 1 20.5 12zM3.5 20.5l1.4-4.2"/><path d="M8.8 9.6c0-.6.4-1 1-1h.7l1 2.4-.9.9c.5 1.1 1.4 2 2.5 2.5l.9-.9 2.4 1v.7c0 .6-.4 1-1 1A6.6 6.6 0 0 1 8.8 9.6z"/></>,
    instagram:<><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="0.6" fill="currentColor"/></>,
    facebook: <path d="M14 8h2V5h-2c-1.7 0-3 1.3-3 3v2H9v3h2v8h3v-8h2.5l.5-3H14V8z"/>,
    mail:     <><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></>,
    bank:     <><path d="M3 10l9-5 9 5"/><path d="M5 10v8M9 10v8M15 10v8M19 10v8"/><path d="M3 19h18"/></>,
    map:      <><path d="M9 4l-6 2v14l6-2 6 2 6-2V4l-6 2-6-2z"/><path d="M9 4v14M15 6v14"/></>,
    star:     <path d="M12 3l2.7 5.5 6 .9-4.4 4.2 1 6-5.3-2.8-5.3 2.8 1-6L3.3 9.4l6-.9L12 3z"/>,
    clock:    <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    sparkle:  <><path d="M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z"/><path d="M19 15l.7 2 2 .7-2 .7-.7 2-.7-2-2-.7 2-.7.7-2z"/></>,
  };
  return <svg {...props}>{paths[name] || null}</svg>;
};

/* ─── Img: CSS-only abstract gradient placeholder ─────────────── */
/* `kind` selects a curated composition. Real photography goes here later. */
const IMG_KINDS = {
  portrait: (seed) => ({
    base: `radial-gradient(120% 80% at ${30 + (seed * 17) % 40}% ${20 + (seed * 13) % 40}%, var(--accent) 0%, var(--accent-soft) 35%, transparent 70%), linear-gradient(${135 + seed * 23}deg, var(--primary-soft) 0%, var(--cream-2) 60%, var(--paper) 100%)`,
    shape: "blob",
  }),
  hero: (seed) => ({
    base: `radial-gradient(80% 60% at 70% 30%, var(--accent-soft) 0%, transparent 60%), radial-gradient(70% 80% at 25% 70%, var(--primary-soft) 0%, transparent 60%), linear-gradient(160deg, var(--cream) 0%, var(--paper) 100%)`,
    shape: "leaf",
  }),
  meal: (seed) => ({
    base: `radial-gradient(60% 60% at 50% 50%, var(--accent-soft), transparent 70%), linear-gradient(135deg, var(--primary-soft), var(--cream-2))`,
    shape: "circle",
  }),
};

const Img = ({ kind = "portrait", seed = 0, alt = "", label = "portrait pending", aspect = "4/5", style, className = "", showLabel = true }) => {
  const conf = (IMG_KINDS[kind] || IMG_KINDS.portrait)(seed);
  return (
    <div className={"img-frame img-abstract " + className} style={{ aspectRatio: aspect, background: conf.base, ...style }} role="img" aria-label={alt || label}>
      <ImgShape kind={conf.shape} seed={seed} />
      {showLabel && <span className="img-label">{label}</span>}
    </div>
  );
};

const ImgShape = ({ kind, seed }) => {
  if (kind === "blob") {
    const dx = (seed * 11) % 20 - 10;
    return (
      <svg viewBox="0 0 120 150" preserveAspectRatio="xMidYMid slice" className="img-shape">
        {/* simplified portrait silhouette in soft tone */}
        <ellipse cx={60 + dx} cy="56" rx="22" ry="26" fill="var(--primary)" opacity=".22" />
        <path d={`M${28 + dx} 150 C${28 + dx} 110, ${42 + dx} 96, ${60 + dx} 96 C${78 + dx} 96, ${92 + dx} 110, ${92 + dx} 150 Z`} fill="var(--primary)" opacity=".22" />
        <circle cx="22" cy="22" r="6" fill="var(--accent)" opacity=".5" />
      </svg>
    );
  }
  if (kind === "leaf") {
    return (
      <svg viewBox="0 0 200 250" preserveAspectRatio="xMidYMid slice" className="img-shape">
        <path d="M50 200 Q40 120 100 60 Q160 20 180 80 Q190 160 100 210 Q70 230 50 200 Z" fill="var(--primary)" opacity=".15" />
        <path d="M100 60 Q105 130 80 200" stroke="var(--primary)" strokeWidth="1.5" fill="none" opacity=".3" />
        <circle cx="155" cy="55" r="22" fill="var(--accent)" opacity=".35" />
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" className="img-shape">
      <circle cx="50" cy="50" r="32" fill="var(--primary)" opacity=".12" />
      <circle cx="50" cy="50" r="20" fill="var(--accent)" opacity=".25" />
    </svg>
  );
};

/* ─── Brand mark ───────────────────────────────────────────────── */
const Brandmark = ({ size = 32 }) => (
  <svg width={size} height={size} viewBox="0 0 40 40" fill="none" aria-hidden>
    <circle cx="20" cy="20" r="19" stroke="var(--primary)" strokeWidth="1.4"/>
    <path d="M20 11c-4 4-4 9 0 13 4-4 4-9 0-13z" fill="var(--primary)"/>
    <path d="M20 11c0 4 2 7 4 9-2-1-4-3-4-9z" fill="var(--accent)"/>
    <circle cx="20" cy="28" r="1.4" fill="var(--primary)"/>
  </svg>
);
const Logo = ({ t }) => (
  <a href="#/" className="logo" aria-label="Nutrition Consultation home">
    <Brandmark size={36} />
    <span className="logo-text">
      <span className="logo-en">{t.brand.logoTop}</span>
      <span className="logo-zh">{t.brand.logoBottom}</span>
    </span>
  </a>
);

/* ─── Nav ─────────────────────────────────────────────────────── */
const Nav = ({ t, route, lang, onLang, onEnquire }) => {
  const [scrolled, setScrolled] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  const links = [
    { href: "#/packages", label: t.nav.packages, key: "packages" },
    { href: "#/team",     label: t.nav.team,     key: "team" },
    { href: "#/faq",      label: t.nav.faq,      key: "faq" },
    { href: "#/contact",  label: t.nav.contact,  key: "contact" },
  ];
  return (
    <header className={"nav " + (scrolled ? "scrolled " : "") + (mobileOpen ? "mobile-open" : "")}>
      <div className="container nav-inner">
        <Logo t={t} />
        <nav className="nav-links" aria-label="Primary">
          {links.map(l => (
            <a key={l.key} href={l.href} className={route === l.key ? "active" : ""}>
              {l.label}
            </a>
          ))}
        </nav>
        <div className="nav-actions">
          <LanguageToggle lang={lang} onLang={onLang} />
          <button className="btn btn-ghost btn-sm nav-enquire" onClick={onEnquire}>
            {t.nav.enquire}
          </button>
          <button className="nav-burger" aria-label="menu" onClick={() => setMobileOpen(o => !o)}>
            <Icon name={mobileOpen ? "x" : "minus"} />
            <span className="sr-only">menu</span>
          </button>
        </div>
      </div>
      {mobileOpen && (
        <div className="mobile-menu">
          {links.map(l => (
            <a key={l.key} href={l.href} onClick={() => setMobileOpen(false)}>{l.label}</a>
          ))}
          <button className="btn btn-primary" onClick={() => { setMobileOpen(false); onEnquire(); }}>
            {t.nav.enquire}
          </button>
        </div>
      )}
    </header>
  );
};

const LanguageToggle = ({ lang, onLang }) => (
  <button
    type="button"
    className="lang-toggle"
    aria-label={lang === "zh" ? "Switch to English" : "切换到中文"}
    onClick={() => onLang(lang === "zh" ? "en" : "zh")}
  >
    <MIcon name="language" size={14} rounded />
    <span>{lang === "zh" ? "EN" : "中"}</span>
  </button>
);

/* ─── Footer ──────────────────────────────────────────────────── */
const Footer = ({ t, lang, onLang }) => (
  <footer className="footer">
    <div className="container footer-grid">
      <div className="footer-brand">
        <Logo t={t} />
        <p className="footer-tag">{t.footer.tagline}</p>
        <div className="footer-socials">
          <a href="https://wa.me/601121974872" target="_blank" rel="noopener noreferrer" aria-label="WhatsApp"><Icon name="whatsapp" /></a>
          <a href="mailto:bmi.nutritionist@gmail.com" aria-label="Email"><Icon name="mail" /></a>
        </div>
      </div>
      {t.footer.sections.map((s, i) => (
        <div key={i} className="footer-col">
          <h4>{s.h}</h4>
          <ul>
            {s.links.map(l => <li key={l}><a href="#">{l}</a></li>)}
          </ul>
        </div>
      ))}
      <div className="footer-col">
        <h4>{t.footer.langLabel}</h4>
        <LanguageToggle lang={lang} onLang={onLang} />
      </div>
    </div>
    <div className="container footer-bottom">
      <span>{t.footer.copyright}</span>
      <span className="footer-nsm">
        <Icon name="shield" size={14} /> NSM Registered
      </span>
    </div>
  </footer>
);

/* ─── PageHero ────────────────────────────────────────────────── */
const PageHero = ({ eyebrow, h1, sub, narrow }) => (
  <section className={"page-hero " + (narrow ? "narrow" : "")}>
    <div className="container">
      <div className="eyebrow">{eyebrow}</div>
      <h1 className="font-display-tight">{h1}</h1>
      {sub && <p className="lead">{sub}</p>}
    </div>
  </section>
);

/* ─── CTA Banner ──────────────────────────────────────────────── */
const CTABanner = ({ h, sub, primary, secondary, onPrimary, onSecondary }) => (
  <section className="cta-banner">
    <div className="container cta-banner-inner">
      <div>
        <h2 className="font-display-tight">{h}</h2>
        {sub && <p className="lead">{sub}</p>}
      </div>
      <div className="cta-banner-actions">
        <button className="btn btn-primary btn-lg" onClick={onPrimary}>{primary} <Icon name="arrowSm" size={18} /></button>
        <button className="btn btn-whatsapp btn-lg" onClick={onSecondary}><Icon name="whatsapp" size={18} /> {secondary}</button>
      </div>
    </div>
  </section>
);

/* ─── FAQ Item ────────────────────────────────────────────────── */
const FAQItem = ({ q, a, defaultOpen = false }) => {
  const [open, setOpen] = useState(defaultOpen);
  return (
    <div className={"faq-item " + (open ? "open" : "")}>
      <button className="faq-q" onClick={() => setOpen(o => !o)} aria-expanded={open}>
        <span>{q}</span>
        <span className="faq-icon"><Icon name={open ? "minus" : "plus"} size={18} /></span>
      </button>
      <div className="faq-a-wrap">
        <div className="faq-a">{a}</div>
      </div>
    </div>
  );
};

/* ─── Pricing Card (compact, for home preview) ────────────────── */
const PricingCard = ({ tier, onChoose, highlight }) => (
  <div className={"pricing-card " + (highlight ? "highlight" : "")}>
    {tier.badge && <span className="pricing-badge">{tier.badge}</span>}
    <div className="pricing-name">
      <span className="font-display" style={{ fontSize: 28 }}>{tier.name}</span>
      <span className="pricing-name-en">{tier.nameEn}</span>
    </div>
    <p className="pricing-tagline">{tier.tagline}</p>
    <div className="pricing-price">
      {tier.original && <span className="pricing-original">{tier.original}</span>}
      <span className="pricing-amt font-display">{tier.price}</span>
      <span className="pricing-unit">{tier.unit}</span>
    </div>
    <button className={"btn " + (highlight ? "btn-primary" : "btn-secondary")} onClick={onChoose}>
      {tier.cta} <Icon name="arrowSm" size={16} />
    </button>
  </div>
);

/* ─── Trust Strip ─────────────────────────────────────────────── */
const TrustStrip = ({ items }) => (
  <div className="trust-strip">
    <div className="container trust-inner">
      {items.map((it, i) => (
        <div key={i} className="trust-item">
          <Icon name={it.icon} size={18} stroke={1.4} />
          <span>{it.label}</span>
        </div>
      ))}
    </div>
  </div>
);

/* ─── Service Pillar ──────────────────────────────────────────── */
const ServicePillar = ({ item }) => (
  <div className="pillar card card-hover">
    {item.tag && <span className="pillar-tag">{item.tag}</span>}
    <div className="pillar-num font-display">{item.icon}</div>
    <div className="pillar-titles">
      <h3 className="font-display">{item.title}</h3>
      <span className="pillar-alt">{item.titleEn}</span>
    </div>
    <p className="pillar-desc">{item.desc}</p>
  </div>
);

/* ─── Nutritionist Card (preview, on home) ────────────────────── */
const NutritionistCard = ({ m, idx }) => (
  <div className="nutri-card card card-hover">
    {m.image
      ? <div className="nutri-portrait"><img src={m.image} alt={m.name} loading="lazy" /></div>
      : <Img kind="portrait" seed={idx + 1} aspect="3/4" label={`${m.name} · portrait pending`} />}
    <div className="nutri-meta">
      <h3 className="font-display">{m.name} <span className="nutri-alt">{m.nameEn}</span></h3>
      <span className="nutri-title">{m.title}</span>
      <span className="nutri-cred">{m.credential}</span>
      <div className="chips">
        {m.specialties.map(s => <span key={s} className="chip chip-primary">{s}</span>)}
      </div>
    </div>
  </div>
);

/* ─── Enquiry Modal ───────────────────────────────────────────── */
const EnquiryModal = ({ t, open, onClose, prefill = {} }) => {
  const [form, setForm] = useState({ name: "", whatsapp: "", email: "", goal: "", message: "", ...prefill });
  const [errors, setErrors] = useState({});
  const [phase, setPhase] = useState("idle"); // idle | submitting | success
  useEffect(() => {
    if (open) {
      setForm({ name: "", whatsapp: "", email: "", goal: "", message: "", ...prefill });
      setErrors({});
      setPhase("idle");
      document.body.style.overflow = "hidden";
    } else {
      document.body.style.overflow = "";
    }
    return () => { document.body.style.overflow = ""; };
  }, [open, JSON.stringify(prefill)]);
  if (!open) return null;
  const tf = t.contact.form;
  const validate = () => {
    const e = {};
    if (!form.name.trim()) e.name = "*";
    if (!form.whatsapp.trim()) e.whatsapp = "*";
    if (!form.goal) e.goal = "*";
    setErrors(e);
    return Object.keys(e).length === 0;
  };
  const submit = (ev) => {
    ev.preventDefault();
    if (!validate()) return;
    setPhase("submitting");
    setTimeout(() => setPhase("success"), 900);
  };
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} role="dialog" aria-modal="true">
        <button className="modal-close" onClick={onClose} aria-label="Close">
          <Icon name="x" />
        </button>
        {phase !== "success" ? (
          <>
            <h2 className="font-display-tight" style={{ margin: "0 0 8px", fontSize: 32 }}>
              {t.nav.enquire}
            </h2>
            <p className="lead" style={{ marginTop: 0, fontSize: 15 }}>{tf.h}</p>
            <form onSubmit={submit} noValidate>
              <div className="field">
                <label>{tf.name} {errors.name && <span className="field-error">{errors.name}</span>}</label>
                <input value={form.name} onChange={e => setForm({...form, name: e.target.value})} />
              </div>
              <div className="field-row">
                <div className="field">
                  <label>{tf.whatsapp} {errors.whatsapp && <span className="field-error">{errors.whatsapp}</span>}</label>
                  <input value={form.whatsapp} onChange={e => setForm({...form, whatsapp: e.target.value})} placeholder="+60…" />
                </div>
                <div className="field">
                  <label>{tf.email}</label>
                  <input type="email" value={form.email} onChange={e => setForm({...form, email: e.target.value})} />
                </div>
              </div>
              <div className="field">
                <label>{tf.goal} {errors.goal && <span className="field-error">{errors.goal}</span>}</label>
                <select value={form.goal} onChange={e => setForm({...form, goal: e.target.value})}>
                  <option value="">—</option>
                  {tf.goalOptions.map(o => <option key={o} value={o}>{o}</option>)}
                </select>
              </div>
              <div className="field">
                <label>{tf.message}</label>
                <textarea rows="3" value={form.message} onChange={e => setForm({...form, message: e.target.value})} />
              </div>
              <button type="submit" className="btn btn-primary btn-lg" style={{ width: "100%" }} disabled={phase === "submitting"}>
                {phase === "submitting" ? tf.submitting : tf.submit}
              </button>
            </form>
          </>
        ) : (
          <div className="success-state">
            <div className="success-mark"><Icon name="check" size={28} /></div>
            <h2 className="font-display-tight" style={{ margin: "16px 0 8px", fontSize: 28 }}>{tf.success}</h2>
            <p className="lead" style={{ fontSize: 15 }}>{tf.successSub}</p>
            <button className="btn btn-secondary" onClick={onClose}>OK</button>
          </div>
        )}
      </div>
    </div>
  );
};

/* ─── Mobile sticky CTA ───────────────────────────────────────── */
const MobileCTA = ({ t, onEnquire, onWhatsApp, show }) => (
  <div className={"mobile-cta " + (show ? "show" : "")}>
    <button className="btn btn-whatsapp" onClick={onWhatsApp}><Icon name="whatsapp" size={16} /> WhatsApp</button>
    <button className="btn btn-primary" onClick={onEnquire}>{t.nav.enquire}</button>
  </div>
);

/* ─── Reveal on scroll wrapper ────────────────────────────────── */
const Reveal = ({ children, delay = 0 }) => {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) {
        setTimeout(() => el.classList.add("in"), delay);
        io.disconnect();
      }
    }, { threshold: 0.12 });
    io.observe(el);
    return () => io.disconnect();
  }, [delay]);
  return <div ref={ref} className="reveal">{children}</div>;
};

/* ─── Mission / Vision pair ───────────────────────────────────── */
const MissionVision = ({ data }) => (
  <section className="section section-tinted">
    <div className="container">
      <div className="eyebrow" style={{ marginBottom: 24 }}>{data.eyebrow}</div>
      <div className="mv-grid">
        {data.items.map((it, i) => (
          <Reveal key={i} delay={i * 100}>
            <div className="mv-card">
              <div className="mv-tag">
                <span className="mv-num font-display">{String(i + 1).padStart(2, "0")}</span>
                <span className="mv-tag-label">{it.tag}</span>
              </div>
              <p className="mv-text">{it.text}</p>
            </div>
          </Reveal>
        ))}
      </div>
    </div>
  </section>
);

/* ─── Marquee ticker ──────────────────────────────────────────── */
const Marquee = ({ items, variant = "" }) => {
  const loop = [...items, ...items]; // duplicate for seamless scroll
  return (
    <div className={"marquee " + variant}>
      <div className="marquee-track">
        {loop.map((it, i) => (
          <span key={i} className={"marquee-item " + (it.solid ? "solid" : "")}>
            {it.text || it}
          </span>
        ))}
      </div>
    </div>
  );
};

/* ─── Kinetic display heading (word-by-word rise) ────────────── */
const KineticHeading = ({ rows }) => (
  <h1 className="kinetic-h">
    {rows.map((row, ri) => (
      <span key={ri} className="row">
        {row.map((w, wi) => (
          <span
            key={wi}
            className={"word " + (w.style || "")}
            style={{ animationDelay: `${(ri * row.length + wi) * 80 + 100}ms` }}
          >
            {w.text}{wi < row.length - 1 ? "\u00A0" : ""}
          </span>
        ))}
      </span>
    ))}
  </h1>
);

/* ─── Animated stat counter ───────────────────────────────────── */
const Counter = ({ to, suffix = "", duration = 1400 }) => {
  const [n, setN] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting && !started.current) {
        started.current = true;
        const start = performance.now();
        const tick = (t) => {
          const p = Math.min(1, (t - start) / duration);
          const eased = 1 - Math.pow(1 - p, 3);
          setN(Math.round(to * eased));
          if (p < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
      }
    }, { threshold: 0.4 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [to, duration]);
  return <span ref={ref} className="stat-num">{n.toLocaleString()}<span className="suffix">{suffix}</span></span>;
};

const StatRow = ({ items }) => (
  <div className="stat-row">
    {items.map((it, i) => (
      <div key={i} className="stat-cell">
        <Counter to={it.value} suffix={it.suffix} />
        <div className="stat-label">{it.label}</div>
      </div>
    ))}
  </div>
);

/* ─── Editorial pull-quote section ───────────────────────────── */
const Editorial = ({ mark = "“", quote, attr, accents = [] }) => {
  // Highlight any accent words by wrapping in <em>
  let html = quote;
  accents.forEach(w => {
    html = html.replaceAll(w, `__EM__${w}__/EM__`);
  });
  const parts = html.split(/(__EM__.+?__\/EM__)/g);
  return (
    <section className="editorial">
      <span className="editorial-mark" aria-hidden="true">{mark}</span>
      <div className="container">
        <p className="editorial-quote">
          {parts.map((p, i) => {
            const m = p.match(/^__EM__(.+?)__\/EM__$/);
            return m ? <em key={i}>{m[1]}</em> : <span key={i}>{p}</span>;
          })}
        </p>
        <div className="editorial-attr">{attr}</div>
      </div>
    </section>
  );
};

/* ─── Aurora orb background (drifting blurred gradients) ───── */
const Aurora = () => (
  <div className="aurora" aria-hidden="true">
    <div className="aurora-orb a"></div>
    <div className="aurora-orb b"></div>
    <div className="aurora-orb c"></div>
  </div>
);

/* ─── Hero Flow Animation (Wispr-style hero_animation-wrapper-v2) ───
   Left curve: messy stream-of-thought text following an S-curve (low contrast)
   Center: CSS-only "device" with toast notifications popping in (replaces Lottie)
   Right curve: structured/clean text knocked out of a thick green stroke      */
const HeroFlowAnimation = ({ data }) => {
  if (!data) return null;
  const messy = (data.curveMessy || "").repeat(2);   // ensure marquee tail covers viewport
  const clean = (data.curveClean || "").repeat(6);
  const initials = (data.device?.name || "Y").trim().slice(0, 1).toUpperCase();
  return (
    <div className="flow-anim-wrapper" aria-hidden="true">
      {/* LEFT — messy speech on swooping curve. SVG aspect ratio (1048:594) governs height; 50% width container handles placement */}
      <div className="flow-anim-side flow-anim-left">
        <svg viewBox="0 0 1048 594">
          <defs>
            <path id="flow-curve-1"
              d="M0.59 50.92 C17.46 143.30, 97.85 293.14, 284.51 353.55 C440.83 399.06, 583.84 294.07, 500.62 184.75 C417.40 75.43, 238.22 282.10, 499.26 441.67 C551.91 477.80, 817.47 561.26, 1046.43 565.24" />
          </defs>
          <text>
            <textPath href="#flow-curve-1" xlinkHref="#flow-curve-1" startOffset="0">
              {messy}
            </textPath>
            <animate attributeName="x" dur="48s" values="-2400; 0" repeatCount="indefinite" />
          </text>
        </svg>
      </div>

      {/* GLOW behind device (replaces hero_animation-lottie-bg) */}
      <div className="flow-anim-bg" />

      {/* CENTER — CSS device w/ toast cascade (replaces hero_animation-lottie) */}
      <div className="flow-anim-center">
        <div className="flow-device">
          <span className="flow-device-notch" />
          <div className="flow-device-head">
            <div className="flow-device-avatar">{initials}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div className="flow-device-name">{data.device?.name}</div>
              <div className="flow-device-sub"><span className="flow-device-dot" />{data.device?.status}</div>
            </div>
            <MIcon name="more_horiz" size={18} rounded />
          </div>
          <div className="flow-toasts">
            {(data.toasts || []).map((t, i) => (
              <div key={i} className={"flow-toast " + (t.tone || "primary")} style={{ "--i": i }}>
                <span className="flow-toast-ico">
                  <MIcon name={t.icon} size={18} rounded />
                </span>
                <div className="flow-toast-body">
                  <div className="flow-toast-title">{t.title}</div>
                  <div className="flow-toast-meta">{t.meta}</div>
                </div>
                {t.chip && <span className="flow-toast-chip">{t.chip}</span>}
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* RIGHT — clean structured text on thick green stroke */}
      <div className="flow-anim-side flow-anim-right">
        <svg viewBox="0 0 1024 620">
          <defs>
            <path id="flow-curve-2"
              d="M2.04 563.87 C111.59 558.27, 316.49 554.02, 517.96 490.06 C703.02 431.32, 875.32 444.53, 1021.88 453.22" />
          </defs>
          <use href="#flow-curve-2" xlinkHref="#flow-curve-2" className="flow-curve-stroke" />
          <text>
            <textPath href="#flow-curve-2" xlinkHref="#flow-curve-2" startOffset="0">
              {clean}
            </textPath>
            <animate attributeName="x" dur="60s" values="-3200; 0" repeatCount="indefinite" />
          </text>
        </svg>
      </div>
    </div>
  );
};

/* ─── Editorial hero (Wispr/Apple-style centered) ────────────── */
const HeroEditorial = ({ eyebrow, status, rows, sub, ctaPrimary, ctaSecondary, onPrimary, onSecondary, meta, dark = false }) => (
  <section className={"hero-editorial " + (dark ? "dark" : "")}>
    <Aurora />
    <div className="hero-editorial-inner">
      <div className="hero-ed-eyebrow">
        <span className="dot"></span>
        <span>{eyebrow}</span>
      </div>
      <h1 className="hero-ed-h1">
        {rows.map((row, ri) => (
          <span key={ri} className="row" style={{ animationDelay: `${ri * 180 + 200}ms` }}>
            {row.map((w, wi) => (
              <React.Fragment key={wi}>
                {w.style === "accent" ? <span className="accent">{w.text}</span> : w.text}
                {wi < row.length - 1 ? "\u00A0" : ""}
              </React.Fragment>
            ))}
          </span>
        ))}
      </h1>
      <p className="hero-ed-sub">{sub}</p>
      <div className="hero-ed-actions">
        <Magnetic>
          <button className="btn btn-primary btn-lg btn-pill" onClick={onPrimary}>
            {ctaPrimary} <Icon name="arrowSm" size={18} />
          </button>
        </Magnetic>
        <Magnetic>
          <button className="btn btn-ghost btn-lg btn-pill" onClick={onSecondary}>
            <Icon name="whatsapp" size={18} /> {ctaSecondary}
          </button>
        </Magnetic>
      </div>
      {meta && <div className="hero-ed-meta">{meta}</div>}
    </div>
  </section>
);

/* ─── Sticky scroll-driven story ──────────────────────────────── */
const StickyStory = ({ eyebrow, h2, sub, steps }) => (
  <section className="container">
    <div className="sticky-story">
      <div className="sticky-story-text">
        <div className="eyebrow-rule">{eyebrow}</div>
        <h2 className="bigh">{h2}</h2>
        <p className="lead">{sub}</p>
      </div>
      <div className="sticky-story-list">
        {steps.map((s, i) => (
          <Reveal key={i} delay={i * 80}>
            <div className="sticky-step">
              <div className="sticky-step-num">{String(i + 1).padStart(2, "0")} / {String(steps.length).padStart(2, "0")}</div>
              <h3>{s.h}</h3>
              <p>{s.p}</p>
            </div>
          </Reveal>
        ))}
      </div>
    </div>
  </section>
);

/* ─── Feature card with cursor-tracked gradient ──────────────── */
const FeatureCard = ({ icon, title, body }) => {
  const ref = useRef(null);
  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    el.style.setProperty("--mx", `${e.clientX - r.left}px`);
    el.style.setProperty("--my", `${e.clientY - r.top}px`);
  };
  return (
    <div ref={ref} className="feature-card" onMouseMove={onMove}>
      <div className="feature-card-icon"><Icon name={icon} size={26} /></div>
      <h3>{title}</h3>
      <p>{body}</p>
    </div>
  );
};

/* ─── Scroll progress bar ─────────────────────────────────────── */
const ScrollProgress = () => {
  const [w, setW] = useState(0);
  useEffect(() => {
    const handler = () => {
      const h = document.documentElement;
      const max = h.scrollHeight - h.clientHeight;
      setW(max > 0 ? (h.scrollTop / max) * 100 : 0);
    };
    window.addEventListener("scroll", handler, { passive: true });
    handler();
    return () => window.removeEventListener("scroll", handler);
  }, []);
  return <div className="scroll-progress" style={{ width: w + "%" }} />;
};

/* ─── Magnetic button wrapper ─────────────────────────────────── */
const Magnetic = ({ children, strength = 0.25 }) => {
  const ref = useRef(null);
  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (e.clientX - (r.left + r.width / 2)) * strength;
    const y = (e.clientY - (r.top + r.height / 2)) * strength;
    el.style.transform = `translate(${x}px, ${y}px)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ""; };
  return (
    <span ref={ref} className="magnetic" onMouseMove={onMove} onMouseLeave={onLeave} style={{ display: "inline-block" }}>
      {children}
    </span>
  );
};

/* ─── Material Symbol icon (Google Fonts) ─────────────────────── */
const MIcon = ({ name, size = 24, fill = false, rounded = false, className = "", style }) => (
  <span
    className={"msym " + (fill ? "filled " : "") + (rounded ? "rounded " : "") + className}
    style={{ fontSize: size, ...style }}
    aria-hidden="true"
  >
    {name}
  </span>
);

/* ─── Botanical line-art decorations ──────────────────────────── */
const Botanical = ({ kind = "leaf", className = "", style }) => {
  const shapes = {
    leafBranch: (
      <svg viewBox="0 0 200 240" fill="none">
        <path d="M100 230 Q90 180 100 130 Q108 80 96 30" />
        <path d="M100 200 Q70 195 50 175 Q40 160 50 145 Q75 150 95 175" className="fill-leaf" />
        <path d="M100 170 Q130 165 150 145 Q160 130 150 115 Q125 120 105 145" className="fill-leaf" />
        <path d="M100 140 Q72 135 55 115 Q47 100 56 88 Q80 92 98 115" className="fill-leaf" />
        <path d="M100 110 Q126 105 142 85 Q150 70 140 58 Q116 64 100 85" className="fill-leaf" />
        <path d="M100 80 Q80 76 67 60 Q60 48 68 38 Q86 42 98 60" className="fill-leaf" />
      </svg>
    ),
    sprig: (
      <svg viewBox="0 0 64 24" fill="none">
        <path d="M2 12 H62" />
        <path d="M22 12 Q26 6 32 6" />
        <path d="M42 12 Q38 18 32 18" />
        <circle cx="32" cy="12" r="2" className="fill-soft" />
      </svg>
    ),
    citrus: (
      <svg viewBox="0 0 80 80" fill="none">
        <circle cx="40" cy="40" r="32" />
        <circle cx="40" cy="40" r="24" className="fill-soft" />
        <path d="M40 16 L40 64 M16 40 L64 40 M23 23 L57 57 M23 57 L57 23" strokeWidth="0.8" />
        <path d="M30 12 Q34 6 42 6" />
      </svg>
    ),
    bowl: (
      <svg viewBox="0 0 100 80" fill="none">
        <path d="M10 36 Q10 70 50 70 Q90 70 90 36 Z" className="fill-leaf" />
        <path d="M10 36 Q10 70 50 70 Q90 70 90 36" />
        <path d="M5 36 H95" />
        <path d="M30 16 Q32 26 30 30 M50 12 Q52 24 50 28 M70 16 Q72 26 70 30" strokeWidth="0.9" />
      </svg>
    ),
    herb: (
      <svg viewBox="0 0 60 120" fill="none">
        <path d="M30 116 Q28 80 30 50 Q32 22 30 6" />
        <path d="M30 90 Q14 86 8 70" /><path d="M30 90 Q46 86 52 70" />
        <path d="M30 70 Q16 66 12 52" /><path d="M30 70 Q44 66 48 52" />
        <path d="M30 50 Q20 46 18 36" /><path d="M30 50 Q40 46 42 36" />
        <ellipse cx="14" cy="74" rx="6" ry="3" className="fill-leaf" />
        <ellipse cx="46" cy="74" rx="6" ry="3" className="fill-leaf" />
        <ellipse cx="18" cy="55" rx="5" ry="3" className="fill-leaf" />
        <ellipse cx="42" cy="55" rx="5" ry="3" className="fill-leaf" />
      </svg>
    ),
    seed: (
      <svg viewBox="0 0 60 60" fill="none">
        <ellipse cx="30" cy="30" rx="18" ry="10" transform="rotate(-30 30 30)" className="fill-leaf" />
        <ellipse cx="30" cy="30" rx="18" ry="10" transform="rotate(-30 30 30)" />
        <path d="M14 38 Q30 22 46 22" strokeWidth="0.8" />
      </svg>
    ),
    spoon: (
      <svg viewBox="0 0 32 80" fill="none">
        <ellipse cx="16" cy="14" rx="10" ry="12" className="fill-soft" />
        <ellipse cx="16" cy="14" rx="10" ry="12" />
        <path d="M16 26 V76" />
      </svg>
    ),
    waterDrop: (
      <svg viewBox="0 0 40 60" fill="none">
        <path d="M20 4 Q4 30 4 42 Q4 56 20 56 Q36 56 36 42 Q36 30 20 4 Z" className="fill-soft" />
        <path d="M20 4 Q4 30 4 42 Q4 56 20 56 Q36 56 36 42 Q36 30 20 4 Z" />
      </svg>
    ),
  };
  return (
    <div className={"botanical " + className} style={style} aria-hidden="true">
      {shapes[kind]}
    </div>
  );
};

/* ─── Ingredients strip — Material Symbols ─────────────────────── */
const IngredientsStrip = ({ items }) => (
  <div className="ingredients-strip">
    {items.map((it, i) => (
      <div key={i} className="ing">
        <MIcon name={it.icon} size={38} rounded />
        <span className="lbl">{it.label}</span>
      </div>
    ))}
  </div>
);

/* ─── Warm feature card with Material Symbol ──────────────────── */
const WarmCard = ({ icon, title, body, tag }) => (
  <div className="warm-card">
    <MIcon name={icon} size={56} rounded className="warm-card-illus msym-large" />
    <h3>{title}</h3>
    <p>{body}</p>
    {tag && <span className="warm-card-tag">— {tag}</span>}
  </div>
);

/* ─── Testimonial row ─────────────────────────────────────────── */
const TestimonialRow = ({ quote, name, role, seed = 7 }) => (
  <div className="testimonial-row">
    <Img kind="portrait" seed={seed} aspect="1" label="" showLabel={false} />
    <div>
      <p className="testimonial-quote">"{quote}"</p>
      <div className="testimonial-attr">
        <strong>{name}</strong>
        <span className="sep"></span>
        <span>{role}</span>
      </div>
    </div>
  </div>
);

/* ─── Numbered approach list ──────────────────────────────────── */
const ApproachList = ({ items }) => (
  <div className="approach-list">
    {items.map((it, i) => (
      <React.Fragment key={i}>
        <div className="approach-num">{String(i + 1).padStart(2, "0")}</div>
        <div className="approach-body">
          <h3>{it.h}</h3>
          <p>{it.p}</p>
        </div>
      </React.Fragment>
    ))}
  </div>
);

/* ─── Section divider sprig ───────────────────────────────────── */
const SectionDivider = () => (
  <div className="section-divider">
    <svg viewBox="0 0 64 24" fill="none" stroke="currentColor" strokeWidth="1.2">
      <path d="M2 12 H26" />
      <path d="M38 12 H62" />
      <path d="M30 12 Q32 6 36 6" />
      <path d="M34 12 Q32 18 28 18" />
      <circle cx="32" cy="12" r="2.5" fill="currentColor" />
    </svg>
  </div>
);

/* Expose */
Object.assign(window, {
  Icon, Img, Brandmark, Logo, Nav, Footer, PageHero, CTABanner,
  FAQItem, PricingCard, TrustStrip, ServicePillar, NutritionistCard,
  EnquiryModal, MobileCTA, Reveal, LanguageToggle, MissionVision,
  Marquee, KineticHeading, Counter, StatRow, Editorial, Magnetic,
  Aurora, HeroFlowAnimation, HeroEditorial, StickyStory, FeatureCard, ScrollProgress,
  Botanical, IngredientsStrip, WarmCard, TestimonialRow, ApproachList, SectionDivider, MIcon,
});
