/* ============================================================================
   Axion Studio — full landing page
   All data graphics are drawn in SVG/CSS. No photographic images.
   Runs as a classic Babel script; deps are on window (see HTML shell).
============================================================================ */
const { useState, useEffect, useRef } = React;

const EASE = "cubic-bezier(0.25,0.1,0.25,1)";
const ORANGE = "#F26522";

/* ----------------------------------------------------------------
   Shared primitives
---------------------------------------------------------------- */

// Hover "text roll" — duplicate text in an overflow-hidden column that
// translates -50% on group-hover so the second copy slides into view.
function TextRoll({ children, className = "" }) {
  return (
    <span className={"relative block overflow-hidden h-[20px] " + className}>
      <span
        className="flex flex-col transition-transform duration-500 group-hover:-translate-y-1/2"
        style={{ transitionTimingFunction: EASE }}
      >
        <span className="h-[20px] flex items-center">{children}</span>
        <span className="h-[20px] flex items-center">{children}</span>
      </span>
    </span>
  );
}

function StarburstIcon({ className = "" }) {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" className={className} aria-hidden="true">
      <path d="m19.6 66.5 19.7-11 .3-1-.3-.5h-1l-3.3-.2-11.2-.3L14 53l-9.5-.5-2.4-.5L0 49l.2-1.5 2-1.3 2.9.2 6.3.5 9.5.6 6.9.4L38 49.1h1.6l.2-.7-.5-.4-.4-.4L29 41l-10.6-7-5.6-4.1-3-2-1.5-2-.6-4.2 2.7-3 3.7.3.9.2 3.7 2.9 8 6.1L37 36l1.5 1.2.6-.4.1-.3-.7-1.1L33 25l-6-10.4-2.7-4.3-.7-2.6c-.3-1-.4-2-.4-3l3-4.2L28 0l4.2.6L33.8 2l2.6 6 4.1 9.3L47 29.9l2 3.8 1 3.4.3 1h.7v-.5l.5-7.2 1-8.7 1-11.2.3-3.2 1.6-3.8 3-2L61 2.6l2 2.9-.3 1.8-1.1 7.7L59 27.1l-1.5 8.2h.9l1-1.1 4.1-5.4 6.9-8.6 3-3.5L77 13l2.3-1.8h4.3l3.1 4.7-1.4 4.9-4.4 5.6-3.7 4.7-5.3 7.1-3.2 5.7.3.4h.7l12-2.6 6.4-1.1 7.6-1.3 3.5 1.6.4 1.6-1.4 3.4-8.2 2-9.6 2-14.3 3.3-.2.1.2.3 6.4.6 2.8.2h6.8l12.6 1 3.3 2 1.9 2.7-.3 2-5.1 2.6-6.8-1.6-16-3.8-5.4-1.3h-.8v.4l4.6 4.5 8.3 7.5L89 80.1l.5 2.4-1.3 2-1.4-.2-9.2-7-3.6-3-8-6.8h-.5v.7l1.8 2.7 9.8 14.7.5 4.5-.7 1.4-2.6 1-2.7-.6-5.8-8-6-9-4.7-8.2-.5.4-2.9 30.2-1.3 1.5-3 1.2-2.5-2-1.4-3 1.4-6.2 1.6-8 1.3-6.4 1.2-7.9.7-2.6v-.2H49L43 72l-9 12.3-7.2 7.6-1.7.7-3-1.5.3-2.8L24 86l10-12.8 6-7.9 4-4.6-.1-.5h-.3L17.2 77.4l-4.7.6-2-2 .2-3 1-1 8-5.5Z" />
    </svg>
  );
}

// Eyebrow row: "— LABEL" left, optional meta right. Monospace, tracked.
function Eyebrow({ label, meta }) {
  return (
    <div className="flex items-baseline justify-between gap-4 mb-7 sm:mb-9">
      <span className="eyebrow text-[11px] sm:text-[12px] text-gray-500">— {label}</span>
      {meta && <span className="eyebrow text-[11px] sm:text-[12px] text-gray-400 text-right">{meta}</span>}
    </div>
  );
}

function SectionBadge({ num, label, borderClass }) {
  return (
    <div className="flex items-center gap-3 mb-6 sm:mb-8">
      <span className="w-6 h-6 sm:w-7 sm:h-7 rounded-full bg-gray-900 text-white flex items-center justify-center text-[11px] sm:text-[12px] font-semibold">
        {num}
      </span>
      <span className={"whitespace-nowrap text-[12px] sm:text-[13px] font-medium border rounded-full px-3 sm:px-4 py-1 sm:py-1.5 " + borderClass}>
        {label}
      </span>
    </div>
  );
}

// Orange CTA with text-roll + rotating arrow circle.
function OrangeButton({ label, sizing = "sm" }) {
  const circle = sizing === "sm" ? "w-7 h-7 sm:w-8 sm:h-8" : "w-8 h-8";
  return (
    <button className="group inline-flex items-center gap-3 bg-[#F26522] hover:bg-[#e05a1a] text-white text-[13px] sm:text-[14px] rounded-full pl-5 sm:pl-6 pr-2 py-2 transition-colors duration-300">
      <TextRoll>{label}</TextRoll>
      <span className={"shrink-0 rounded-full bg-white flex items-center justify-center " + circle}>
        <ArrowRight size={16} className="text-[#F26522] transition-transform duration-500 group-hover:-rotate-45" style={{ transitionTimingFunction: EASE }} />
      </span>
    </button>
  );
}

// Dark pill button (text-roll + arrow circle).
function DarkButton({ label }) {
  return (
    <button className="group inline-flex items-center gap-3 bg-gray-900 hover:bg-black text-white text-[13px] sm:text-[14px] font-medium rounded-full pl-5 sm:pl-6 pr-2 py-2 transition-colors duration-300">
      <TextRoll>{label}</TextRoll>
      <span className="shrink-0 w-7 h-7 sm:w-8 sm:h-8 rounded-full bg-white flex items-center justify-center">
        <ArrowRight size={15} className="text-gray-900 transition-transform duration-500 group-hover:-rotate-45" style={{ transitionTimingFunction: EASE }} />
      </span>
    </button>
  );
}

function useLondonTime() {
  const [t, setT] = useState("");
  useEffect(() => {
    const fmt = () =>
      new Date().toLocaleTimeString("en-GB", { timeZone: "Europe/London", hour: "2-digit", minute: "2-digit", hour12: false });
    setT(fmt());
    const id = setInterval(() => setT(fmt()), 1000);
    return () => clearInterval(id);
  }, []);
  return t;
}

/* ----------------------------------------------------------------
   Animation infrastructure — scroll-triggered, reduced-motion aware
---------------------------------------------------------------- */
function prefersReduced() {
  try { return window.matchMedia("(prefers-reduced-motion: reduce)").matches; } catch (e) { return false; }
}

// Fires once when the element is (or scrolls) into view. Hardened to never
// leave content hidden: initial rect check, IntersectionObserver, a scroll/
// resize rect-check fallback (works even where IO doesn't), and a timeout.
function useInView(threshold = 0.3) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (prefersReduced() || !el || typeof IntersectionObserver === "undefined") { setSeen(true); return; }
    let done = false;
    const reveal = () => { if (!done) { done = true; setSeen(true); cleanup(); } };
    const inView = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight || 800;
      return r.top < vh * 0.92 && r.bottom > vh * 0.04;
    };
    if (inView()) { setSeen(true); return; }
    let watchRaf = 0;
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => { if (e.isIntersecting) reveal(); }),
      { threshold, rootMargin: "0px 0px -8% 0px" }
    );
    io.observe(el);
    const onScroll = () => requestAnimationFrame(() => { if (inView()) reveal(); });
    const watch = () => {
      if (done) return;
      if (inView()) reveal();
      else watchRaf = requestAnimationFrame(watch);
    };
    watchRaf = requestAnimationFrame(watch);
    window.addEventListener("scroll", onScroll, { passive: true });
    document.addEventListener("scroll", onScroll, { passive: true, capture: true });
    window.addEventListener("resize", onScroll);
    function cleanup() {
      io.disconnect();
      cancelAnimationFrame(watchRaf);
      window.removeEventListener("scroll", onScroll);
      document.removeEventListener("scroll", onScroll, { capture: true });
      window.removeEventListener("resize", onScroll);
    }
    return cleanup;
  }, [threshold]);
  return [ref, seen];
}

// Splits "−41%", "×2.4", "1.4M", "140+" into prefix / number / suffix.
function parseStat(str) {
  const m = String(str).match(/^([^\d]*?)(-?[\d,]*\.?\d+)(.*)$/);
  if (!m) return { prefix: "", num: null, suffix: String(str), decimals: 0, minDigits: 0 };
  const raw = m[2].replace(/,/g, "");
  return { prefix: m[1], num: parseFloat(raw), suffix: m[3], decimals: (raw.split(".")[1] || "").length, minDigits: (raw.split(".")[0] || "").replace("-", "").length };
}
function fmtNum(n, decimals, minDigits = 0) {
  if (decimals === 0 && n >= 1000) return Math.round(n).toLocaleString("en-US");
  const fixed = n.toFixed(decimals);
  if (decimals === 0 && minDigits > 1) return fixed.padStart(minDigits, "0");
  return fixed;
}

// Number that counts up from 0 → value when scrolled into view.
function AnimatedStat({ value, className = "", duration = 1150 }) {
  const [ref, seen] = useInView(0.5);
  const { prefix, num, suffix, decimals, minDigits } = parseStat(value);
  const [disp, setDisp] = useState(num === null ? value : fmtNum(0, decimals, minDigits));
  useEffect(() => {
    if (num === null || !seen) return;
    if (prefersReduced()) { setDisp(fmtNum(num, decimals, minDigits)); return; }
    let raf;
    const start = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const e = 1 - Math.pow(1 - p, 3);
      setDisp(fmtNum(num * e, decimals, minDigits));
      if (p < 1) raf = requestAnimationFrame(tick);
      else setDisp(fmtNum(num, decimals, minDigits));
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [seen]);
  return <span ref={ref} className={className}>{num === null ? value : prefix + disp + suffix}</span>;
}

// Fade-and-rise wrapper for card entrances.
function Reveal({ children, delay = 0, className = "", style = {} }) {
  const [ref, seen] = useInView(0.15);
  return (
    <div ref={ref} className={className}
      style={{ ...style, opacity: seen ? 1 : 0, transform: seen ? "none" : "translateY(20px)", transition: `opacity .75s ${EASE} ${delay}ms, transform .85s ${EASE} ${delay}ms` }}>
      {children}
    </div>
  );
}

/* ----------------------------------------------------------------
   Service mock UIs — self-contained state machines on setInterval.
---------------------------------------------------------------- */

// 1. FocusTimerMock — SVG ring countdown + equalizer bars
function FocusTimerMock() {
  const TOTAL = 25 * 60;
  const [s, setS] = useState(TOTAL - 137);
  useEffect(() => { const id = setInterval(() => setS(v => v <= 1 ? TOTAL : v - 1), 1000); return () => clearInterval(id); }, []);
  const r = 28, C = 2 * Math.PI * r;
  const progress = 1 - s / TOTAL;
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
  const ss = String(s % 60).padStart(2, "0");
  return (
    <div className="rounded-xl bg-[#0E0E10] text-white p-4 flex items-center gap-4">
      <div className="relative w-[72px] h-[72px]">
        <svg viewBox="0 0 72 72" className="w-full h-full -rotate-90">
          <circle cx="36" cy="36" r={r} stroke="rgba(255,255,255,0.12)" strokeWidth="4" fill="none" />
          <circle cx="36" cy="36" r={r} stroke="#F26522" strokeWidth="4" fill="none" strokeLinecap="round" strokeDasharray={C} strokeDashoffset={C * (1 - progress)} style={{ transition: "stroke-dashoffset 1s linear" }} />
        </svg>
        <div className="absolute inset-0 flex items-center justify-center serif text-[14px] num-display tabular-nums">{mm}:{ss}</div>
      </div>
      <div className="flex-1">
        <div className="eyebrow text-[9px] text-white/45 mb-1.5">Deep focus</div>
        <div className="flex items-end gap-[3px] h-7">
          {Array.from({ length: 14 }).map((_, i) => (
            <span key={i} className="flex-1 rounded-sm bg-white/55 ax-eq-bar" style={{ height: "100%", animationDelay: (i * 80) + "ms", animationDuration: (900 + (i % 4) * 120) + "ms" }} />
          ))}
        </div>
      </div>
    </div>
  );
}

// 2. NotificationsMock — rolling list with notifIn entrance
function NotificationsMock() {
  const all = [
    { who: "Nadia", txt: "Homepage v2 is ready — want to review?" },
    { who: "Wei Jian", txt: "Traffic up 18% this week." },
    { who: "Inbox", txt: "3 new qualified leads." },
    { who: "Rosaline", txt: "Brand book has been approved." },
    { who: "Darrell", txt: "Q3 retainer has been signed." },
  ];
  const [start, setStart] = useState(0);
  useEffect(() => { const id = setInterval(() => setStart(s => (s + 1) % all.length), 2600); return () => clearInterval(id); }, []);
  const visible = [0, 1, 2].map(i => all[(start + i) % all.length]);
  return (
    <div className="rounded-xl bg-white border border-black/[0.06] p-3 flex flex-col gap-1.5">
      {visible.map((n, i) => (
        <div key={start + "-" + i} className="ax-notif-in flex items-center gap-2.5 px-2.5 py-2 rounded-lg bg-[#FBFBF9]" style={{ animationDelay: (i * 90) + "ms" }}>
          <span className="w-6 h-6 rounded-full bg-gray-900 text-white text-[9px] font-semibold flex items-center justify-center">{n.who[0]}</span>
          <span className="text-[11.5px] text-gray-900 truncate flex-1">{n.txt}</span>
          <span className="w-1.5 h-1.5 rounded-full bg-[#F26522]" />
        </div>
      ))}
    </div>
  );
}

// 3. RitualsMock — ticking checklist
function RitualsMock() {
  const labels = ["Morning audit", "Stand-up", "Focus work", "Send draft"];
  const [tick, setTick] = useState(0);
  useEffect(() => { const id = setInterval(() => setTick(t => (t + 1) % (labels.length + 1)), 1800); return () => clearInterval(id); }, []);
  return (
    <div className="rounded-xl bg-[#FBFBF9] border border-black/[0.06] p-4">
      <div className="eyebrow text-[9px] text-gray-400 mb-2.5">Daily rituals</div>
      <ul className="flex flex-col gap-2">
        {labels.map((l, i) => {
          const done = i < tick;
          return (
            <li key={l} className="flex items-center gap-2.5">
              <span className={"w-4 h-4 rounded-[4px] border flex items-center justify-center transition-colors duration-300 " + (done ? "bg-[#F26522] border-[#F26522]" : "bg-white border-black/15")}>
                {done && <svg viewBox="0 0 12 12" className="w-2.5 h-2.5"><path d="M2 6.5 L5 9 L10 3.5" stroke="white" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" /></svg>}
              </span>
              <span className={"text-[12px] transition-colors duration-300 " + (done ? "text-gray-400 line-through" : "text-gray-900")}>{l}</span>
            </li>
          );
        })}
      </ul>
    </div>
  );
}

// 4. NotesMock — typewriter
function NotesMock() {
  const full = "A strategy-led studio building digital experiences for Malaysian brands.";
  const [i, setI] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setI(v => v >= full.length ? 0 : v + 1), 55);
    return () => clearInterval(id);
  }, []);
  return (
    <div className="rounded-xl bg-white border border-black/[0.06] p-4 min-h-[96px]">
      <div className="eyebrow text-[9px] text-gray-400 mb-2">Brief · draft</div>
      <p className="text-[12.5px] text-gray-900 leading-relaxed">
        {full.slice(0, i)}
        <span className="inline-block w-[6px] h-[12px] bg-gray-900 align-[-2px] ml-0.5 ax-soft-pulse" />
      </p>
    </div>
  );
}

/* ----------------------------------------------------------------
   Process mock UIs
---------------------------------------------------------------- */

// WaveformMock — 42 bars, organic motion via per-bar delays
function WaveformMock() {
  const N = 42;
  return (
    <div className="rounded-xl bg-[#FBFBF9] border border-black/[0.06] p-3 flex items-end gap-[2px] h-[64px]">
      {Array.from({ length: N }).map((_, i) => {
        const h = (Math.abs(Math.sin(i * 0.6)) * 0.6 + 0.35) * 100;
        return <span key={i} className="flex-1 rounded-sm bg-gray-900 ax-eq-bar" style={{ height: h + "%", animationDelay: (i * 55) + "ms", animationDuration: (900 + (i % 6) * 110) + "ms" }} />;
      })}
    </div>
  );
}

// BlueprintMock — staggered drawIn paths
function BlueprintMock() {
  return (
    <div className="rounded-xl bg-white border border-black/[0.06] p-3">
      <svg viewBox="0 0 220 80" className="w-full h-[64px]" aria-hidden="true">
        <path d="M10 60 L60 60 L60 20 L120 20 L120 60 L210 60" fill="none" stroke="#111" strokeWidth="1.2" className="ax-draw" style={{ animationDelay: "0s" }} />
        <path d="M10 70 L210 70" fill="none" stroke="#F26522" strokeWidth="1.2" className="ax-draw" style={{ animationDelay: "0.3s" }} />
        <path d="M40 40 L80 40 M140 40 L180 40" fill="none" stroke="#111" strokeWidth="1" className="ax-draw" style={{ animationDelay: "0.6s" }} />
      </svg>
    </div>
  );
}

// InhabitMock — live scrolling sine chart
function InhabitMock() {
  const [t, setT] = useState(0);
  useEffect(() => { const id = setInterval(() => setT(v => v + 1), 1000); return () => clearInterval(id); }, []);
  const W = 220, H = 64;
  const pts = Array.from({ length: 30 }, (_, i) => {
    const x = (i / 29) * W;
    const y = H / 2 - Math.sin((i + t) * 0.4) * (H / 2.6);
    return x.toFixed(1) + "," + y.toFixed(1);
  }).join(" ");
  return (
    <div className="rounded-xl bg-[#0E0E10] p-3">
      <svg viewBox={`0 0 ${W} ${H}`} className="w-full h-[64px]" aria-hidden="true">
        <polyline points={pts} fill="none" stroke="#F26522" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ transition: "all .9s ease" }} />
      </svg>
    </div>
  );
}

/* ----------------------------------------------------------------
   Case-study mocks (Featured Work)
---------------------------------------------------------------- */
function CaseClockMock() {
  const [tick, setTick] = useState(0);
  useEffect(() => { const id = setInterval(() => setTick(v => v + 1), 1500); return () => clearInterval(id); }, []);
  const angle = (tick % 24) * 15 - 90;
  return (
    <div className="flex items-center justify-center py-6">
      <svg viewBox="0 0 120 120" className="w-28 h-28">
        <circle cx="60" cy="60" r="52" fill="none" stroke="#111" strokeWidth="1" />
        {Array.from({ length: 12 }).map((_, i) => {
          const a = (i / 12) * Math.PI * 2 - Math.PI / 2;
          return <line key={i} x1={60 + Math.cos(a) * 46} y1={60 + Math.sin(a) * 46} x2={60 + Math.cos(a) * 52} y2={60 + Math.sin(a) * 52} stroke="#111" strokeWidth="1" />;
        })}
        <line x1="60" y1="60" x2={60 + Math.cos(angle * Math.PI / 180) * 40} y2={60 + Math.sin(angle * Math.PI / 180) * 40} stroke="#F26522" strokeWidth="2" strokeLinecap="round" style={{ transition: "all 1.4s cubic-bezier(.25,.1,.25,1)" }} />
        <circle cx="60" cy="60" r="3" fill="#111" />
      </svg>
    </div>
  );
}

function CaseSilenceMock() {
  const [n, setN] = useState(28);
  useEffect(() => { const id = setInterval(() => setN(v => v <= 3 ? 28 : v - 1), 140); return () => clearInterval(id); }, []);
  return (
    <div className="flex flex-col items-center justify-center py-6">
      <div className="serif text-[64px] sm:text-[76px] leading-none text-white num-display tabular-nums">{n}</div>
      <div className="eyebrow text-[10px] text-white/45 mt-3">Minutes saved · live</div>
    </div>
  );
}

/* ----------------------------------------------------------------
   Reveal helper using CSS class (.ax-reveal)
---------------------------------------------------------------- */
function RevealClass({ children, delay = 1, className = "" }) {
  const [ref, seen] = useInView(0.12);
  return <div ref={ref} className={`ax-reveal delay-${delay} ${seen ? "is-in" : ""} ${className}`}>{children}</div>;
}

/* ----------------------------------------------------------------
   FAQ — native <details>/<summary>, CSS-only expansion
---------------------------------------------------------------- */
function FAQ() {
  const qs = [
    { q: "How long does a project usually take?", a: "Most strategy + brand + website projects take 8–14 weeks, depending on scope. We set the timeline together during the discovery session." },
    { q: "Do you work with in-house teams?", a: "Yes — we partner with founders, product and marketing teams, and hand over a tidy system you can grow on your own. No problem, lah." },
    { q: "How much does it cost?", a: "Projects start from RM18,000 for one focused sprint and scale from there. Monthly retainers start at RM4,500 a month." },
    { q: "Where are you based?", a: "Kuala Lumpur, and we work remotely with brands across Malaysia." },
  ];
  return (
    <section data-screen-label="FAQ" className="bg-white pt-16 sm:pt-20 lg:pt-28 pb-16 sm:pb-20 lg:pb-28">
      <div className="max-w-[1100px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="FAQ" meta="Quick answers" />
        <h2 className="h-about font-medium leading-[1.12] tracking-[-0.02em] text-gray-900 mb-10 sm:mb-14">Frequently asked questions.</h2>
        <div className="border-t border-black/10">
          {qs.map((it, i) => (
            <RevealClass key={it.q} delay={Math.min(4, i + 1)}>
              <details className="ax-faq border-b border-black/10 py-5 group">
                <summary className="flex items-center justify-between gap-6">
                  <span className="text-[16px] sm:text-[18px] font-medium text-gray-900">{it.q}</span>
                  <span className="relative w-5 h-5 shrink-0">
                    <span className="plus absolute inset-0 flex items-center justify-center text-gray-900 text-[20px] leading-none">+</span>
                  </span>
                </summary>
                <div className="answer">
                  <p className="text-[13.5px] sm:text-[14px] text-gray-500 leading-relaxed pt-4 max-w-[68ch]">{it.a}</p>
                </div>
              </details>
            </RevealClass>
          ))}
        </div>
      </div>
    </section>
  );
}

// Progress bar that fills 0 → value% when scrolled into view.
function AnimatedBar({ value = 100, color = "#111", track = "rgba(0,0,0,0.08)", height = 4, duration = 1200, delay = 0, showLabel = false, label = "Progress", labelClassName = "", className = "" }) {
  const [ref, seen] = useInView(0.4);
  const [pct, setPct] = useState(0);
  useEffect(() => {
    if (!seen) return;
    if (prefersReduced()) { setPct(value); return; }
    let raf;
    const start = performance.now() + delay;
    const tick = (t) => {
      const elapsed = t - start;
      if (elapsed < 0) { raf = requestAnimationFrame(tick); return; }
      const p = Math.min(1, elapsed / duration);
      const e = 1 - Math.pow(1 - p, 3);
      setPct(value * e);
      if (p < 1) raf = requestAnimationFrame(tick);
      else setPct(value);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [seen, value, duration, delay]);
  return (
    <div ref={ref} className={className}>
      {showLabel && (
        <div className={"flex items-baseline justify-between mb-1.5 " + labelClassName}>
          <span className="eyebrow text-[10px] opacity-60">{label}</span>
          <span className="eyebrow text-[10px] tabular-nums">{Math.round(pct)}%</span>
        </div>
      )}
      <div className="w-full rounded-full overflow-hidden" style={{ height, background: track }}>
        <div style={{ width: pct + "%", height: "100%", background: color, transition: prefersReduced() ? "none" : "none" }} />
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------
   Code-drawn chart primitives (no images)
---------------------------------------------------------------- */

// Radiating tick dial with a center slash — the "DAY SHAPE" gauge.
function RadialDial({ stroke = "#1a1a1a", className = "w-28 h-28" }) {
  const [ref, seen] = useInView(0.4);
  const N = 44, cx = 60, cy = 60, r1 = 38;
  const ticks = [];
  for (let i = 0; i < N; i++) {
    const a = (i / N) * Math.PI * 2 - Math.PI / 2;
    const len = i % 11 === 0 ? 13 : i % 4 === 0 ? 8 : 5;
    const r2 = r1 + len;
    const base = i % 4 === 0 ? 0.85 : 0.45;
    ticks.push(
      <line key={i} x1={cx + Math.cos(a) * r1} y1={cy + Math.sin(a) * r1} x2={cx + Math.cos(a) * r2} y2={cy + Math.sin(a) * r2}
        stroke={stroke} strokeWidth="1"
        style={{ opacity: seen ? base : 0, transition: `opacity .5s ${EASE} ${i * 16}ms` }} />
    );
  }
  return (
    <svg ref={ref} viewBox="0 0 120 120" className={className} aria-hidden="true">
      {ticks}
      <line x1="48" y1="72" x2="72" y2="48" stroke={stroke} strokeWidth="1.4" strokeLinecap="round"
        style={{ opacity: seen ? 1 : 0, transform: seen ? "none" : "scale(0.6)", transformOrigin: "60px 60px", transition: `opacity .5s ${EASE} ${N * 16}ms, transform .6s ${EASE} ${N * 16}ms` }} />
    </svg>
  );
}

// Vertical bar chart, M–S, descending grayscale (the "INBOX · 7D" chart).
function WeekBars({ vals = [62, 92, 54, 30, 20, 14, 8], days = ["M", "T", "W", "T", "F", "S", "S"] }) {
  const [ref, seen] = useInView(0.35);
  const shades = ["#c9c9c7", "#b3b3b1", "#9a9a98", "#7c7c7a", "#5a5a58", "#3d3d3b", "#262624"];
  return (
    <div ref={ref}>
      <div className="flex items-end gap-2 h-[124px]">
        {vals.map((v, i) => (
          <div key={i} className="flex-1 rounded-t-[3px]" style={{ height: (seen ? v : 0) + "%", background: shades[i % shades.length], transition: `height .9s ${EASE} ${i * 75}ms` }} />
        ))}
      </div>
      <div className="flex gap-2 mt-2.5">
        {days.map((d, i) => (
          <div key={i} className="flex-1 text-center eyebrow text-[10px] text-gray-400">{d}</div>
        ))}
      </div>
    </div>
  );
}

// Smooth-ish area chart with gradient fill (used in About). Line draws on view.
function AreaChart({ stroke = "#111", fillId = "axArea", color = "#111", className = "w-full h-full" }) {
  const [ref, seen] = useInView(0.35);
  const pts = [14, 26, 20, 40, 34, 56, 50, 72, 66, 88, 96];
  const W = 320, H = 160, pad = 6;
  const step = (W - pad * 2) / (pts.length - 1);
  const xy = pts.map((p, i) => [pad + i * step, H - pad - (p / 100) * (H - pad * 2)]);
  const line = xy.map((p, i) => (i === 0 ? "M" : "L") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L ${W - pad} ${H - pad} L ${pad} ${H - pad} Z`;
  const last = xy[xy.length - 1];
  return (
    <svg ref={ref} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" className={className} aria-hidden="true">
      <defs>
        <linearGradient id={fillId} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.16" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#${fillId})`} style={{ opacity: seen ? 1 : 0, transition: `opacity 1s ${EASE} .35s` }} />
      <path d={line} fill="none" stroke={stroke} strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round"
        pathLength="1" strokeDasharray="1" style={{ strokeDashoffset: seen ? 0 : 1, transition: `stroke-dashoffset 1.5s ${EASE}` }} />
      <circle cx={last[0]} cy={last[1]} r="3" fill={stroke} style={{ opacity: seen ? 1 : 0, transition: `opacity .4s ${EASE} 1.3s` }} />
    </svg>
  );
}

// Donut / ring gauge with a value arc that sweeps in + counts up on view.
function Donut({ value = 0.96, label, color = "#111", track = "#e6e6e3", size = 132 }) {
  const [ref, seen] = useInView(0.45);
  const r = 54, c = 2 * Math.PI * r;
  const [pct, setPct] = useState(0);
  useEffect(() => {
    if (!seen) return;
    if (prefersReduced()) { setPct(value); return; }
    let raf;
    const start = performance.now(), dur = 1300;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / dur);
      const e = 1 - Math.pow(1 - p, 3);
      setPct(value * e);
      if (p < 1) raf = requestAnimationFrame(tick); else setPct(value);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [seen]);
  return (
    <div ref={ref} className="relative" style={{ width: size, height: size }}>
      <svg viewBox="0 0 128 128" className="w-full h-full -rotate-90" aria-hidden="true">
        <circle cx="64" cy="64" r={r} fill="none" stroke={track} strokeWidth="7" />
        <circle cx="64" cy="64" r={r} fill="none" stroke={color} strokeWidth="7" strokeLinecap="round" strokeDasharray={c}
          strokeDashoffset={c * (1 - (seen ? value : 0))} style={{ transition: `stroke-dashoffset 1.3s ${EASE}` }} />
      </svg>
      <div className="absolute inset-0 flex flex-col items-center justify-center">
        <span className="serif text-[34px] leading-none text-gray-900 num-display">{Math.round(pct * 100)}<span className="text-[18px] align-super">%</span></span>
        {label && <span className="eyebrow text-[9px] text-gray-400 mt-1.5">{label}</span>}
      </div>
    </div>
  );
}

// Tiny equalizer bars for the dark "live" card.
function Equalizer({ bars = 18, color = "rgba(255,255,255,0.5)" }) {
  const heights = useRef(Array.from({ length: bars }, () => 20 + Math.random() * 70));
  const [, force] = useState(0);
  useEffect(() => {
    const id = setInterval(() => {
      heights.current = heights.current.map(() => 16 + Math.random() * 78);
      force((n) => n + 1);
    }, 900);
    return () => clearInterval(id);
  }, []);
  return (
    <div className="flex items-end gap-[3px] h-9">
      {heights.current.map((h, i) => (
        <div key={i} className="flex-1 rounded-[1px] transition-[height] duration-700 ease-out" style={{ height: h + "%", background: color }} />
      ))}
    </div>
  );
}

/* ----------------------------------------------------------------
   Navigation + mobile menu
---------------------------------------------------------------- */
const NAV_LINKS = ["Work", "About", "Services"];

function Nav({ onOpenMenu }) {
  const time = useLondonTime();
  return (
    <div className="relative z-20 max-w-[1200px] mx-auto px-4 sm:px-6 pt-4 sm:pt-5">
      <nav className="bg-white rounded-full p-2 flex items-center justify-between gap-4 shadow-[0_2px_18px_rgba(0,0,0,0.06)] border border-black/[0.04]">
        {/* Left: wordmark */}
        <a href="#" className="flex items-center gap-2.5 pl-1 shrink-0">
          <span className="w-9 h-9 bg-gray-900 rounded-full flex items-center justify-center">
            <span className="text-white text-[10px] font-bold tracking-tight">PL</span>
          </span>
          <span className="hidden sm:inline text-[14px] font-medium text-gray-900 tracking-tight whitespace-nowrap">Pixel Lah Studio</span>
        </a>

        {/* Center: links */}
        <div className="hidden md:flex items-center gap-8 flex-1 justify-center">
          {NAV_LINKS.map((l) => (
            <a
              key={l}
              href="#"
              className="group relative text-[13px] text-gray-700 hover:text-gray-900"
            >
              <TextRoll>{l}</TextRoll>
              <span
                className="pointer-events-none absolute left-0 -bottom-1 h-px w-full origin-left scale-x-0 bg-gray-900 transition-transform duration-500 group-hover:scale-x-100"
                style={{ transitionTimingFunction: EASE }}
              />
            </a>
          ))}
        </div>

        {/* Right: CTA */}
        <button className="hidden md:inline-flex shrink-0 group items-center gap-3 bg-gray-900 text-white text-[13px] font-medium rounded-full pl-5 pr-2 py-2 hover:bg-black transition-colors duration-300">
          <TextRoll>Contact Us</TextRoll>
          <span className="shrink-0 w-7 h-7 rounded-full bg-white flex items-center justify-center">
            <ArrowRight size={13} className="text-gray-900 transition-transform duration-500 group-hover:-rotate-45" style={{ transitionTimingFunction: EASE }} />
          </span>
        </button>

        {/* Mobile menu */}
        <button onClick={onOpenMenu} aria-label="Open menu" className="md:hidden w-9 h-9 rounded-full bg-gray-900 text-white flex items-center justify-center">
          <Menu size={16} />
        </button>
      </nav>
    </div>
  );
}

function MobileMenu({ open, onClose }) {
  const time = useLondonTime();
  return (
    <div className={"fixed inset-0 z-50 md:hidden " + (open ? "" : "pointer-events-none")}>
      <div onClick={onClose} className={"absolute inset-0 bg-black/60 transition-opacity duration-500 " + (open ? "opacity-100" : "opacity-0")} />
      <div className="absolute inset-x-0 bottom-0 bg-white rounded-2xl mx-3 mb-3 p-5 transition-transform duration-500"
        style={{ transform: open ? "translateY(0)" : "translateY(110%)", transitionTimingFunction: "cubic-bezier(0.32,0.72,0,1)" }}>
        <div className="flex items-center justify-between mb-6">
          <span className="flex items-center gap-1.5 text-[13px] text-gray-600 border border-gray-200 rounded-full px-3 py-1.5">
            <Clock size={14} />
            {time} in KL
          </span>
          <button onClick={onClose} className="flex items-center gap-2 bg-gray-900 text-white text-[13px] font-medium rounded-full pl-4 pr-2 py-2">
            Close
            <span className="w-6 h-6 rounded-full bg-white flex items-center justify-center">
              <X size={14} className="text-gray-900" />
            </span>
          </button>
        </div>
        <div className="flex flex-col">
          {NAV_LINKS.map((l) => (
            <a key={l} href="#" onClick={onClose} className="text-[28px] leading-[32px] font-medium text-gray-900 py-2">{l}</a>
          ))}
        </div>
        <button className="group mt-6 w-full inline-flex items-center justify-between bg-[#F26522] text-white text-[15px] font-medium rounded-full pl-6 pr-2 py-3">
          Start a Project
          <span className="w-9 h-9 rounded-full bg-white flex items-center justify-center">
            <ArrowRight size={16} className="text-[#F26522] transition-transform duration-500 group-hover:-rotate-45" style={{ transitionTimingFunction: EASE }} />
          </span>
        </button>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------
   1 — Hero
---------------------------------------------------------------- */
function ShaderStack() {
  const fill = { width: "100%", height: "100%" };
  return (
    <div className="absolute inset-0 z-10 pointer-events-none overflow-hidden">
      <Shader style={fill}>
        <Swirl colorA="#ffffff" colorB="#f0f0f0" detail={1.7} />
        <ChromaFlow baseColor="#ffffff" downColor="#ff5f03" leftColor="#ff5f03" rightColor="#ff5f03" upColor="#ff5f03" momentum={13} radius={3.5} />
        <FlutedGlass aberration={0.61} angle={31} frequency={8} highlight={0.12} highlightSoftness={0} lightAngle={-90} refraction={4} shape="rounded" softness={1} speed={0.15} />
        <FilmGrain strength={0.05} />
      </Shader>
    </div>
  );
}

function Hero({ onOpenMenu }) {
  return (
    <section data-screen-label="Hero" className="relative min-h-[900px] flex flex-col bg-[#EFEFEF] overflow-hidden">
      <ShaderStack />
      <Nav onOpenMenu={onOpenMenu} />
      <div className="flex-1" />
      <div className="relative z-20 w-full max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12 pb-14 sm:pb-16 lg:pb-20">
        <p className="text-[13px] sm:text-[14px] text-gray-900 tracking-wide mb-5 sm:mb-8">Pixel Lah Studio · We craft digital experiences.</p>
        <h1 className="h-display font-medium leading-[1.08] tracking-[-0.03em] text-gray-900">
          We craft digital experiences, lah
          <br className="hidden sm:block" /><span className="sm:hidden"> </span>
          for Malaysian brands ready to dominate
          <br className="hidden sm:block" /><span className="sm:hidden"> </span>
          their category online.
        </h1>
        <div className="mt-8 sm:mt-12 flex flex-col sm:flex-row gap-4 sm:gap-5 items-start sm:items-center">
          <OrangeButton label="Start a Project" sizing="sm" />
          <button className="group inline-flex items-center gap-2.5 bg-white rounded-[4px] pl-3 pr-2.5 py-2 transition-shadow duration-300"
            style={{ boxShadow: "0 2px 8px rgba(0,0,0,0.08)" }}
            onMouseEnter={(e) => (e.currentTarget.style.boxShadow = "0 4px 16px rgba(0,0,0,0.12)")}
            onMouseLeave={(e) => (e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.08)")}>
            <StarburstIcon className="w-5 h-5 sm:w-6 sm:h-6 fill-current text-[#E8704E]" />
            <span className="text-[13px] sm:text-[14px] font-medium text-gray-900">KL's Web Studio of Choice</span>
            <span className="text-[10px] sm:text-[11px] bg-gray-900 text-white px-1.5 sm:px-2 py-0.5 rounded">Featured</span>
          </button>
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   2 — Trusted-by marquee
---------------------------------------------------------------- */
function Marquee() {
  const names = ["NUSANTARA", "JERNANG", "TEMENGGOR", "SELASIH", "RANTAU", "KETUMBIT", "MERDEKA", "ANGSANA", "KINTA", "SERUNAI"];
  const row = [...names, ...names];
  return (
    <section className="bg-white border-y border-black/[0.06] py-7 sm:py-9 overflow-hidden">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12 mb-5">
        <span className="eyebrow text-[11px] text-gray-400">— Trusted by Malaysian brands that dominate their category</span>
      </div>
      <div className="relative">
        <div className="flex w-max marquee-track">
          {row.map((n, i) => (
            <span key={i} className="eyebrow text-[15px] sm:text-[17px] text-gray-300 px-7 sm:px-10 whitespace-nowrap select-none">{n}</span>
          ))}
        </div>
        <div className="pointer-events-none absolute inset-y-0 left-0 w-16 sm:w-28 bg-gradient-to-r from-white to-transparent" />
        <div className="pointer-events-none absolute inset-y-0 right-0 w-16 sm:w-28 bg-gradient-to-l from-white to-transparent" />
      </div>
    </section>
  );
}

// Scroll-driven marquee: subtle horizontal parallax tied to the section's
// position in the viewport. Works inside an iframe by reading
// getBoundingClientRect() and polling via rAF while in view.
function ScrollMarquee({ text = "What we do", direction = -1, className = "" }) {
  const ref = useRef(null);
  const innerRef = useRef(null);
  useEffect(() => {
    const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) return;

    let raf = 0;
    let inView = true;
    const DRIFT = 160; // px each side — subtle parallax

    const update = () => {
      const el = ref.current;
      const inner = innerRef.current;
      if (el && inner) {
        const r = el.getBoundingClientRect();
        const vh =
          window.innerHeight ||
          document.documentElement.clientHeight ||
          800;
        // 0 when the section sits at the bottom edge, 1 when it leaves the top
        let p = 1 - (r.top + r.height) / (vh + r.height);
        if (p < 0) p = 0;
        if (p > 1) p = 1;
        // center the drift so the section is at offset 0 when mid-viewport
        const offset = (p - 0.5) * 2 * DRIFT * direction;
        inner.style.transform = `translate3d(${offset.toFixed(1)}px,0,0)`;
      }
      if (inView) raf = requestAnimationFrame(update);
    };

    // Only animate while in view (saves work, also guarantees first paint sync).
    let io;
    if ("IntersectionObserver" in window && ref.current) {
      io = new IntersectionObserver(
        (entries) => {
          const visible = entries[0]?.isIntersecting;
          if (visible && !inView) {
            inView = true;
            raf = requestAnimationFrame(update);
          } else if (!visible) {
            inView = false;
            cancelAnimationFrame(raf);
          }
        },
        { rootMargin: "200px 0px" }
      );
      io.observe(ref.current);
    }

    raf = requestAnimationFrame(update);
    return () => {
      inView = false;
      cancelAnimationFrame(raf);
      if (io) io.disconnect();
    };
  }, [direction]);

  const items = Array.from({ length: 12 });
  return (
    <div ref={ref} className={"relative overflow-hidden py-2 " + className}>
      <div ref={innerRef} className="flex w-max will-change-transform">
        {items.map((_, i) => (
          <span
            key={i}
            className="eyebrow text-[28px] sm:text-[36px] lg:text-[44px] text-gray-300 px-6 sm:px-10 whitespace-nowrap select-none flex items-center"
          >
            <span className="text-gray-400 mr-6 sm:mr-10">—</span>
            {text}
          </span>
        ))}
      </div>
      <div className="pointer-events-none absolute inset-y-0 left-0 w-16 sm:w-28 bg-gradient-to-r from-white to-transparent" />
      <div className="pointer-events-none absolute inset-y-0 right-0 w-16 sm:w-28 bg-gradient-to-l from-white to-transparent" />
    </div>
  );
}

/* ----------------------------------------------------------------
   3 — About (images replaced by data cards)
---------------------------------------------------------------- */
function StatCard({ children }) {
  return (
    <div className="rounded-2xl border border-black/[0.07] bg-[#FBFBF9] shadow-[0_2px_18px_rgba(0,0,0,0.04)] overflow-hidden">{children}</div>
  );
}

function AboutGrowthCard() {
  return (
    <StatCard>
      <div className="p-5 sm:p-6 h-full flex flex-col" style={{ minHeight: 0 }}>
        <div className="flex items-baseline justify-between">
          <span className="eyebrow text-[11px] text-gray-400">Client growth · index</span>
          <span className="eyebrow text-[11px] text-gray-400">24 mo</span>
        </div>
        <div className="flex-1 mt-4 min-h-[150px]">
          <AreaChart stroke="#111" color="#111" className="w-full h-full" />
        </div>
        <div className="flex items-end justify-between mt-4 pt-4 border-t border-black/[0.07]">
          <div>
            <AnimatedStat value="+312%" className="serif text-[30px] sm:text-[34px] leading-none text-gray-900 block" />
            <div className="eyebrow text-[10px] text-gray-400 mt-2">Avg organic reach</div>
          </div>
          <div className="text-right">
            <AnimatedStat value="×2.4" className="serif text-[30px] sm:text-[34px] leading-none text-[#F26522] block" />
            <div className="eyebrow text-[10px] text-gray-400 mt-2">Revenue / quarter</div>
          </div>
        </div>
      </div>
    </StatCard>
  );
}

function AboutSatisfactionCard() {
  return (
    <StatCard>
      <div className="p-5 sm:p-6 h-full flex flex-col items-center justify-center text-center" style={{ minHeight: 0 }}>
        <span className="eyebrow text-[11px] text-gray-400 self-start">Client satisfaction</span>
        <div className="flex-1 flex items-center justify-center py-4">
          <Donut value={0.98} label="Would recommend" color="#111" />
        </div>
        <div className="eyebrow text-[10px] text-gray-400">Across <AnimatedStat value="140+" /> projects</div>
      </div>
    </StatCard>
  );
}

function About() {
  return (
    <section data-screen-label="About" className="bg-white pt-16 sm:pt-20 lg:pt-32 pb-12 sm:pb-16 lg:pb-24 overflow-hidden">
      <ScrollMarquee text="Meet Pixel Lah" direction={1} className="mb-10 sm:mb-14 lg:mb-20" />
      <div className="max-w-[1440px] mx-auto">
        <div className="px-5 sm:px-8 lg:px-12">
          <SectionBadge num="1" label="Meet Pixel Lah" borderClass="border-gray-200" />
          <h2 className="h-about font-medium leading-[1.12] tracking-[-0.02em] text-gray-900 mb-12 sm:mb-16 lg:mb-28">
            A strategy-led web studio,
            <br />
            driving real results for Malaysian brands.
          </h2>
        </div>

        {/* mobile / tablet */}
        <div className="lg:hidden px-5 sm:px-8">
          <p className="text-[15px] leading-[1.6] font-medium text-gray-900">
            Through research, creative thinking and iteration, we help Malaysian brands reach the full potential of their website — confirm your online presence goes up, lah.
          </p>
          <div className="mt-6"><OrangeButton label="About Our Studio" sizing="sm" /></div>
          <div className="mt-8 flex flex-col sm:flex-row gap-4 sm:gap-5">
            <Reveal className="sm:w-[45%] w-full" style={{ aspectRatio: "438 / 346" }}><AboutSatisfactionCard /></Reveal>
            <Reveal delay={120} className="sm:w-[55%] w-full" style={{ aspectRatio: "900 / 600" }}><AboutGrowthCard /></Reveal>
          </div>
        </div>

        {/* desktop */}
        <div className="hidden lg:grid items-end gap-6 xl:gap-8 px-12" style={{ gridTemplateColumns: "26% 1fr 48%" }}>
          <Reveal className="self-end" style={{ aspectRatio: "438 / 346" }}><AboutSatisfactionCard /></Reveal>
          <div className="self-start flex justify-end">
            <div className="flex flex-col items-start">
              <p className="text-[16px] leading-[1.65] font-medium text-gray-900 whitespace-nowrap">
                Through research, creative thinking and
                <br />
                iteration, we help Malaysian brands reach
                <br />
                the full potential of their website.
              </p>
              <div className="mt-6"><OrangeButton label="About Our Studio" sizing="md" /></div>
            </div>
          </div>
          <Reveal delay={140} className="self-end" style={{ aspectRatio: "3 / 2" }}><AboutGrowthCard /></Reveal>
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   4 — Services
---------------------------------------------------------------- */
function ServiceGlyph({ kind }) {
  const s = "#111";
  if (kind === "strategy")
    return <svg viewBox="0 0 48 48" className="w-9 h-9"><circle cx="24" cy="24" r="20" fill="none" stroke={s} strokeWidth="1.5" /><circle cx="24" cy="24" r="11" fill="none" stroke={s} strokeWidth="1.5" /><circle cx="24" cy="24" r="2.5" fill={s} /></svg>;
  if (kind === "brand")
    return <svg viewBox="0 0 48 48" className="w-9 h-9"><rect x="6" y="6" width="36" height="36" rx="3" fill="none" stroke={s} strokeWidth="1.5" /><path d="M6 28 L20 14 L34 28 L42 20" fill="none" stroke={s} strokeWidth="1.5" /></svg>;
  if (kind === "product")
    return <svg viewBox="0 0 48 48" className="w-9 h-9"><rect x="6" y="9" width="36" height="26" rx="2" fill="none" stroke={s} strokeWidth="1.5" /><line x1="6" y1="17" x2="42" y2="17" stroke={s} strokeWidth="1.5" /><line x1="18" y1="40" x2="30" y2="40" stroke={s} strokeWidth="1.5" /></svg>;
  return <svg viewBox="0 0 48 48" className="w-9 h-9"><path d="M24 4 L44 24 L24 44 L4 24 Z" fill="none" stroke={s} strokeWidth="1.5" /><path d="M24 16 L32 24 L24 32 L16 24 Z" fill={s} /></svg>;
}

function Services() {
  const items = [
    { n: "01", kind: "strategy", title: "Strategy & Positioning", desc: "Research, narrative and category strategy that define where your brand wins before a single pixel is drawn.", tags: ["Audit", "Naming", "Messaging"], cap: 96, Mock: FocusTimerMock },
    { n: "02", kind: "brand", title: "Brand Identity", desc: "A distinctive visual system — typography, colour, motion and voice — designed to scale across every platform.", tags: ["Logo", "System", "Guidelines"], cap: 92, Mock: NotificationsMock },
    { n: "03", kind: "product", title: "Website Design", desc: "High-quality interfaces and design systems, built to convert and ready to hand over to engineering.", tags: ["UX", "UI", "Design system"], cap: 98, Mock: RitualsMock },
    { n: "04", kind: "motion", title: "Animation & 3D", desc: "Shaders, animation and real-time visuals that make your homepage feel alive and truly one of a kind, lah.", tags: ["WebGL", "Animation", "Direction"], cap: 88, Mock: NotesMock },
  ];
  return (
    <section data-screen-label="Services" className="bg-[#F5F5F5] pt-16 sm:pt-20 lg:pt-28 pb-16 sm:pb-20 lg:pb-28">
      <ScrollMarquee text="What We Do" direction={-1} className="mb-10 sm:mb-14" />
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="What we do" meta="Capabilities" />
        <h2 className="h-about font-medium leading-[1.12] tracking-[-0.02em] text-gray-900 max-w-[18ch] mb-12 sm:mb-16">
          Everything a Malaysian brand needs, in one place.
        </h2>
        <Reveal>
          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-px bg-black/[0.08] border border-black/[0.08] rounded-2xl overflow-hidden">
            {items.map((it) => (
              <div key={it.n} className="group bg-white hover:bg-[#FBFBF9] transition-colors duration-300 p-6 sm:p-7 flex flex-col">
                <div className="flex items-start justify-between">
                  <ServiceGlyph kind={it.kind} />
                  <span className="eyebrow text-[11px] text-gray-300">{it.n}</span>
                </div>
                <h3 className="text-[17px] sm:text-[18px] font-medium text-gray-900 mt-7 leading-snug">{it.title}</h3>
                <p className="text-[13.5px] text-gray-500 leading-relaxed mt-3 flex-1">{it.desc}</p>
                <div className="mt-5"><it.Mock /></div>
                <AnimatedBar value={it.cap} color="#F26522" track="rgba(0,0,0,0.07)" showLabel label="Capability" className="mt-5" />
                <div className="flex flex-wrap gap-1.5 mt-5">
                  {it.tags.map((t) => (
                    <span key={t} className="eyebrow text-[10px] text-gray-500 border border-black/10 rounded-full px-2.5 py-1">{t}</span>
                  ))}
                </div>
              </div>
            ))}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   5 — Featured work (editorial + data dashboard cards)
---------------------------------------------------------------- */
function CardFrame({ dark, children }) {
  return (
    <div className={"rounded-[20px] overflow-hidden flex flex-col " + (dark ? "bg-[#0E0E10]" : "bg-[#FBFBF9] border border-black/[0.07] shadow-[0_2px_22px_rgba(0,0,0,0.05)]")}>
      {children}
    </div>
  );
}

function FootStat({ a, b, dark }) {
  return (
    <div className="flex">
      {[a, b].map((s, i) => (
        <div key={i} className={"flex-1 px-5 py-4 sm:px-6 sm:py-5 " + (i === 0 ? (dark ? "border-r border-white/10" : "border-r border-black/[0.07]") : "")}>
          <AnimatedStat value={s.v} className={"serif text-[26px] sm:text-[30px] leading-none num-display block " + (s.accent ? "text-[#F26522]" : dark ? "text-white" : "text-gray-900")} />
          <div className={"eyebrow text-[10px] mt-2 " + (dark ? "text-white/40" : "text-gray-400")}>{s.l}</div>
        </div>
      ))}
    </div>
  );
}

function WorkCardEngagement() {
  return (
    <CardFrame>
      <div className="p-5 sm:p-6 flex items-center justify-between">
        <span className="eyebrow text-[11px] text-gray-400">Engagement</span>
        <span className="eyebrow text-[11px] text-gray-400">Before → After</span>
      </div>
      <CaseClockMock />
      <FootStat a={{ v: "+2.1×", l: "Time on site" }} b={{ v: "−41%", l: "Bounce rate", accent: true }} />
    </CardFrame>
  );
}

function WorkCardConversion() {
  return (
    <CardFrame dark>
      <div className="p-5 sm:p-6 flex items-center justify-between">
        <span className="eyebrow text-[11px] text-white/50">Conversion</span>
        <span className="flex items-center gap-2 eyebrow text-[11px] text-white/70">
          <span className="w-2 h-2 rounded-full bg-white inline-block ax-soft-pulse" />live
        </span>
      </div>
      <CaseSilenceMock />
      <div className="w-2/3 mx-auto pb-4"><Equalizer /></div>
      <FootStat dark a={{ v: "−86%", l: "Cost per lead" }} b={{ v: "×2.4", l: "Inbound sales", accent: true }} />
    </CardFrame>
  );
}

function WorkCardTraffic() {
  return (
    <CardFrame>
      <div className="p-5 sm:p-6 flex items-center justify-between">
        <span className="eyebrow text-[11px] text-gray-400">Traffic · 7D</span>
        <span className="eyebrow text-[10px] text-gray-600 bg-black/[0.05] rounded-full px-3 py-1">all ok</span>
      </div>
      <div className="flex-1 px-5 sm:px-6 flex items-end pb-2">
        <div className="w-full"><WeekBars /></div>
      </div>
      <FootStat a={{ v: "1.4M", l: "Sessions / month" }} b={{ v: "0", l: "Downtime" }} />
    </CardFrame>
  );
}

function FeaturedWork() {
  const works = [
    { Card: WorkCardEngagement, title: "Nusantara", desc: "Site of the Month 2025 winner — an interactive 3D showcase that set record engagement for a KL F&B brand." },
    { Card: WorkCardConversion, title: "Jernang", desc: "Turned a legacy platform into a conversion-focused brand experience. It really took off, lah." },
    { Card: WorkCardTraffic, title: "Temenggor", desc: "A content engine rebuild that tripled organic reach in two quarters." },
  ];
  return (
    <section data-screen-label="Featured Work" className="bg-[#F4F3EE] pt-20 sm:pt-24 lg:pt-32 pb-16 sm:pb-20 lg:pb-28 overflow-hidden">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="Featured work" meta="Selected cases, 2025–2026" />
        <h2 className="h-display font-medium leading-[1.08] tracking-[-0.03em] text-gray-900 mb-12 sm:mb-16 lg:mb-20">
          Stories of Malaysian brands <span className="text-gray-400">bold enough to stand apart.</span>
        </h2>
        <div className="grid grid-cols-1 md:grid-cols-3 gap-5 sm:gap-6">
          {works.map(({ Card, title, desc }, i) => (
            <Reveal key={title} delay={i * 130} className="flex flex-col">
              <Card />
              <p className="text-[13px] sm:text-[14px] text-gray-500 mt-5 leading-relaxed">{desc}</p>
              <div className="flex items-center justify-between mt-2">
                <h3 className="text-[14px] sm:text-[15px] font-semibold text-gray-900">{title}</h3>
                <a href="#" className="group inline-flex items-center gap-1.5 eyebrow text-[10px] text-gray-500 hover:text-gray-900 transition-colors">
                  Case study
                  <ArrowRight size={12} className="transition-transform duration-500 group-hover:-rotate-45" style={{ transitionTimingFunction: EASE }} />
                </a>
              </div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   6 — Metrics band (dark)
---------------------------------------------------------------- */
function MetricsBand() {
  const m = [
    { v: "12", l: "Years of experience" },
    { v: "140+", l: "Projects delivered" },
    { v: "27", l: "Industry awards" },
    { v: "4.9", l: "Average client rating" },
  ];
  return (
    <section className="bg-[#0E0E10] text-white py-16 sm:py-20 lg:py-24">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="By the numbers" meta="Updated Q1 2026" />
        <div className="grid grid-cols-2 lg:grid-cols-4 gap-y-10 gap-x-6 mt-2">
          {m.map((x, i) => (
            <Reveal key={x.l} delay={i * 100} className="border-l border-white/15 pl-5 sm:pl-6">
              <AnimatedStat value={x.v} className="serif text-[44px] sm:text-[60px] lg:text-[72px] leading-none num-display block" />
              <div className="eyebrow text-[10px] sm:text-[11px] text-white/45 mt-3">{x.l}</div>
              <AnimatedBar value={[78, 92, 64, 98][i] || 80} color="#F26522" track="rgba(255,255,255,0.12)" height={3} delay={300 + i * 100} showLabel label="Progress" labelClassName="text-white/55" className="mt-4" />
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   7 — Process
---------------------------------------------------------------- */
function Process() {
  const steps = [
    { n: "01", t: "Immerse", d: "We dive into your market, audience and data to find the edge only you can own.", Mock: InhabitMock },
    { n: "02", t: "Define", d: "Strategy, narrative and scope are shaped into one sharp, clear creative direction.", Mock: BlueprintMock },
    { n: "03", t: "Design", d: "We build the system — interface, brand and motion — in tight, transparent iterations.", Mock: WaveformMock },
    { n: "04", t: "Deliver", d: "Production-ready files, design system and launch support, handed over neatly.", Mock: BlueprintMock },
  ];
  return (
    <section data-screen-label="Process" className="bg-white pt-16 sm:pt-20 lg:pt-28 pb-16 sm:pb-20 lg:pb-28">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="How we work" meta="Four clear stages" />
        <h2 className="h-about font-medium leading-[1.12] tracking-[-0.02em] text-gray-900 max-w-[16ch] mb-12 sm:mb-16">
          A process built for momentum.
        </h2>
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-10">
          {steps.map((s, i) => (
            <Reveal key={s.n} delay={i * 100} className="border-t border-black/10 pt-5">
              <div className="flex items-baseline justify-between">
                <AnimatedStat value={s.n} className="serif text-[40px] sm:text-[48px] leading-none text-gray-900 num-display" duration={900} />
                <span className="w-2 h-2 rounded-full bg-[#F26522]" />
              </div>
              <h3 className="text-[18px] font-medium text-gray-900 mt-6">{s.t}</h3>
              <p className="text-[13.5px] text-gray-500 leading-relaxed mt-2.5">{s.d}</p>
              <div className="mt-5"><s.Mock /></div>
              <AnimatedBar value={25 * (i + 1)} color="#F26522" track="rgba(0,0,0,0.07)" height={3} delay={200 + i * 120} duration={1100} showLabel label="Progress" className="mt-5" />
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   8 — Testimonials
---------------------------------------------------------------- */
function Testimonials() {
  const quotes = [
    { q: "Pixel Lah didn't just redesign our website — they changed how the market sees our brand. Inbound sales doubled in a single quarter. Really powerful stuff, lah.", a: "Naomi Aina", r: "CEO, Jernang", score: 0.99 },
    { q: "The most meticulous studio we've ever worked with. Strategy first, beautiful craft second, ego never. Our new site confirm boosts our online presence.", a: "Rosaline Tan", r: "Founder, Nusantara", score: 0.97 },
  ];
  return (
    <section data-screen-label="Testimonials" className="bg-[#F5F5F5] pt-16 sm:pt-20 lg:pt-28 pb-16 sm:pb-20 lg:pb-28">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <Eyebrow label="What clients say" meta="Selected, verified" />
        <div className="grid grid-cols-1 md:grid-cols-2 gap-5 sm:gap-6">
          {quotes.map((c, i) => (
            <Reveal key={c.a} delay={i * 120}>
              <figure className="bg-white rounded-2xl border border-black/[0.07] p-7 sm:p-9 flex flex-col h-full">
                <blockquote className="serif text-[24px] sm:text-[30px] leading-[1.28] tracking-[-0.01em] text-gray-900 flex-1">
                  “{c.q}”
                </blockquote>
                <figcaption className="flex items-center justify-between mt-8 pt-6 border-t border-black/[0.07]">
                  <div>
                    <div className="text-[14px] font-semibold text-gray-900">{c.a}</div>
                    <div className="eyebrow text-[10px] text-gray-400 mt-1.5">{c.r}</div>
                  </div>
                  <div className="scale-75 origin-right"><Donut value={c.score} label="Satisfied" color="#F26522" /></div>
                </figcaption>
              </figure>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   9 — Closing CTA
---------------------------------------------------------------- */
function CTA() {
  const time = useLondonTime();
  return (
    <section data-screen-label="CTA" className="relative bg-[#EFEFEF] pt-20 sm:pt-28 lg:pt-36 pb-20 sm:pb-28 lg:pb-36 overflow-hidden">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12 text-center">
        <span className="eyebrow text-[11px] text-gray-400">— Let's build</span>
        <h2 className="h-display font-medium leading-[1.08] tracking-[-0.03em] text-gray-900 mt-6 max-w-[20ch] mx-auto">
          Let's make the next category leader <span className="text-[#F26522]">yours.</span>
        </h2>
        <div className="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4 sm:gap-5">
          <OrangeButton label="Start a Project" sizing="md" />
          <DarkButton label="Contact Us" />
        </div>
        <div className="mt-8 flex items-center justify-center gap-1.5 text-[13px] text-gray-500">
          <Clock size={14} />
          {time} in KL · we usually reply within a day
        </div>
      </div>
    </section>
  );
}

/* ----------------------------------------------------------------
   10 — Footer
---------------------------------------------------------------- */
function Footer() {
  const cols = [
    { h: "Studio", items: ["About", "Team", "Careers", "Journal"] },
    { h: "Work", items: ["Nusantara", "Jernang", "Temenggor", "All cases"] },
    { h: "Contact", items: ["WhatsApp", "Instagram", "LinkedIn", "Dribbble"] },
  ];
  return (
    <footer className="bg-[#0E0E10] text-white pt-16 sm:pt-20 pb-8">
      <div className="max-w-[1440px] mx-auto px-5 sm:px-8 lg:px-12">
        <div className="grid grid-cols-2 lg:grid-cols-[1.4fr_1fr_1fr_1fr] gap-10 lg:gap-8">
          <div className="col-span-2 lg:col-span-1">
            <div className="flex items-center gap-3">
              <div className="w-10 h-10 bg-white rounded-full flex items-center justify-center">
                <span className="text-gray-900 text-[11px] font-bold tracking-tight">PL</span>
              </div>
              <span className="text-[15px] font-medium">Pixel Lah Studio</span>
            </div>
            <p className="text-[14px] text-white/50 leading-relaxed mt-5 max-w-[34ch]">
              A boutique web studio in KL building digital experiences for Malaysian brands ready to dominate their category. We craft digital experiences, lah.
            </p>
            <div className="mt-6"><OrangeButton label="Start a Project" sizing="sm" /></div>
          </div>
          {cols.map((c) => (
            <div key={c.h}>
              <div className="eyebrow text-[10px] text-white/40 mb-5">{c.h}</div>
              <ul className="flex flex-col gap-3">
                {c.items.map((it) => (
                  <li key={it}><a href="#" className="text-[14px] text-white/70 hover:text-white transition-colors duration-300">{it}</a></li>
                ))}
              </ul>
            </div>
          ))}
        </div>
        <div className="mt-14 sm:mt-20 pt-6 border-t border-white/10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
          <span className="eyebrow text-[10px] text-white/35">© 2026 Pixel Lah Studio — All rights reserved</span>
          <span className="eyebrow text-[10px] text-white/35">Kuala Lumpur · Selangor · Remote</span>
        </div>
      </div>
    </footer>
  );
}

/* ----------------------------------------------------------------
   App
---------------------------------------------------------------- */
function App() {
  const [menuOpen, setMenuOpen] = useState(false);
  useEffect(() => {
    const b = document.getElementById("boot");
    const id = setTimeout(() => b && b.classList.add("hide"), 400);
    return () => clearTimeout(id);
  }, []);
  return (
    <>
      <Hero onOpenMenu={() => setMenuOpen(true)} />
      <MobileMenu open={menuOpen} onClose={() => setMenuOpen(false)} />
      <Marquee />
      <About />
      <Services />
      <FeaturedWork />
      <MetricsBand />
      <Process />
      <Testimonials />
      <FAQ />
      <CTA />
      <Footer />
    </>
  );
}

function __boot() {
  createRoot(document.getElementById("root")).render(<App />);
}
if (window.__AXION_DEPS__) __boot();
else window.addEventListener("axion-deps-ready", __boot);
