const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "cream",
  "heroVariant": "split",
  "battBgPositionX": 50,
  "battBgPositionY": 0,
  "sbBgPositionX": 50,
  "sbBgPositionY": 0
} /*EDITMODE-END*/;

const PALETTES = {
  cream: { bg: "#FFFFFF", surface: "#FFFFFF", ink: "#16181C", muted: "#5C5F66", line: "rgba(22,24,28,0.10)", accent: "#1FA9F0", accent2: "#1071CC", warm: "#F26B4E" },
  bone: { bg: "#FFFFFF", surface: "#FAFAF7", ink: "#161616", muted: "#5C5C5C", line: "rgba(0,0,0,0.10)", accent: "#1FA9F0", accent2: "#1071CC", warm: "#FF7A45" },
  paper: { bg: "#FFFFFF", surface: "#F7F7F4", ink: "#0E1116", muted: "#5A5E66", line: "rgba(0,0,0,0.09)", accent: "#1FA9F0", accent2: "#0F62D6", warm: "#FF6A3D" },
  ocean: { bg: "#FFFFFF", surface: "#F4F8FB", ink: "#0B1220", muted: "#475569", line: "rgba(11,18,32,0.10)", accent: "#1FA9F0", accent2: "#1071CC", warm: "#F08A5D" }
};

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const p = PALETTES[t.palette] || PALETTES.cream;

  React.useEffect(() => {
    const r = document.documentElement.style;
    r.setProperty("--bg", p.bg);
    r.setProperty("--surface", p.surface);
    r.setProperty("--ink", p.ink);
    r.setProperty("--muted", p.muted);
    r.setProperty("--line", p.line);
    r.setProperty("--accent", p.accent);
    r.setProperty("--accent2", p.accent2);
    r.setProperty("--warm", p.warm);
  }, [t.palette]);



  return (
    <React.Fragment>
      <Nav />
      {t.heroVariant === "split" ? <HeroSplit /> : <HeroBig />}
      <Marquee />
      <Services />
      <Process />
      <Portfolio t={t} />
      <Pricing />
      <Testimonials />
      <CTA />
      <Footer />
      <Tweaks t={t} setTweak={setTweak} />
    </React.Fragment>);

}

/* =================== NAV =================== */
function Nav() {
  const [open, setOpen] = React.useState(false);
  const [pinned, setPinned] = React.useState(false);
  const [mobileOpen, setMobileOpen] = React.useState(false);
  const closeTimer = React.useRef(null);
  const menuRef = React.useRef(null);

  // Click outside to close
  React.useEffect(() => {
    const handler = (e) => {
      if (menuRef.current && !menuRef.current.contains(e.target)) {
        setPinned(false);
        setOpen(false);
      }
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, []);

  const handleMouseEnter = () => {
    clearTimeout(closeTimer.current);
    setOpen(true);
  };
  const handleMouseLeave = () => {
    if (!pinned) {
      closeTimer.current = setTimeout(() => setOpen(false), 200);
    }
  };
  const handleButtonClick = () => {
    const next = !pinned;
    setPinned(next);
    setOpen(next);
  };

  return (
    <header className="nav">
      <a className="brand" href="#" aria-label="Quantum Design home">
        <img src="assets/qd-logo.png" alt="Quantum Design" />
      </a>
      <nav className="nav-links">
        <a href="#" className="active">Home</a>
        <a href="about.html">About</a>
        <div
          ref={menuRef}
          className={"has-menu" + (open ? " open" : "")}
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}>
          
          <button className="menu-trigger" onClick={handleButtonClick}>
            Services
            <svg width="10" height="10" viewBox="0 0 10 10"><path d="M1 3.5L5 7.5L9 3.5" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" /></svg>
          </button>
          <div className="menu">
            <a href="web-design.html">
              <div className="menu-icon" style={{ background: "var(--accent)" }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="14" rx="2" /><path d="M3 10h18" /></svg>
              </div>
              <div>
                <div className="menu-title">Web Design</div>
                <div className="menu-sub">Custom builds that convert</div>
              </div>
            </a>
            <a href="marketing.html">
              <div className="menu-icon" style={{ background: "var(--warm)", backgroundColor: "rgb(184, 225, 246)" }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 17l6-6 4 4 8-8" /><path d="M21 7v5h-5" /></svg>
              </div>
              <div>
                <div className="menu-title">Marketing &amp; SEO</div>
                <div className="menu-sub">Google + Meta ads, SEO</div>
              </div>
            </a>
            <div className="menu-foot">
              <a href="#pricing" className="menu-foot-link">See packages &amp; pricing →</a>
            </div>
          </div>
        </div>
        <a href="portfolio.html">Portfolio</a>
        <a href="contact.html">Contact</a>
      </nav>
      <a href="contact.html" className="nav-icon-btn" aria-label="Contact us">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="5" width="18" height="14" rx="2" />
          <path d="M3 7l9 6 9-6" />
        </svg>
      </a>
      <MobileNavToggle onClick={() => setMobileOpen(true)} />
      <MobileNavMenu open={mobileOpen} onClose={() => setMobileOpen(false)} active="home" />
    </header>);

}

/* =================== HERO (split) =================== */
function HeroSplit() {
  const visualRef = React.useRef(null);
  const scalerRef = React.useRef(null);
  React.useLayoutEffect(() => {
    const scaler = scalerRef.current;
    if (!scaler) return;
    const fit = scaler.parentElement;
    const compute = () => {
      const inner = scaler.firstElementChild;
      if (inner) inner.style.width = '';
      scaler.style.transform = 'none';
      scaler.style.width = '';
      scaler.style.height = '';
      scaler.style.marginBottom = '0px';
      if (window.innerWidth > 820) return;
      const natW = inner ? inner.offsetWidth : scaler.offsetWidth;
      const natH = inner ? inner.offsetHeight : scaler.offsetHeight;
      if (!natW || !fit) return;
      const avail = fit.clientWidth;
      const s = Math.min(1, (avail - 12) / natW);
      if (s < 1) {
        if (inner) inner.style.width = natW + 'px';
        scaler.style.transformOrigin = 'top left';
        scaler.style.transform = `scale(${s})`;
        scaler.style.width = Math.round(natW * s) + 'px';
        scaler.style.height = Math.round(natH * s) + 'px';
      }
    };
    compute();
    let ro;
    if (typeof ResizeObserver !== 'undefined') {ro = new ResizeObserver(compute);ro.observe(fit);}
    window.addEventListener('resize', compute);
    const t = setTimeout(compute, 300);
    return () => {if (ro) ro.disconnect();window.removeEventListener('resize', compute);clearTimeout(t);};
  }, []);
  React.useEffect(() => {
    const el = visualRef.current;
    if (!el) return;
    const handler = (e) => {
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      const dx = (e.clientX - cx) / r.width;
      const dy = (e.clientY - cy) / r.height;
      el.style.setProperty('--mx', dx.toFixed(3));
      el.style.setProperty('--my', dy.toFixed(3));
    };
    window.addEventListener('mousemove', handler);
    return () => window.removeEventListener('mousemove', handler);
  }, []);
  return (
    <section className="hero hero-animated" style={{ fontFamily: "\"Inter Tight\"" }}>
      <div className="hero-eyebrow hero-fade" style={{ animationDelay: '0.05s', fontFamily: "\"Inter Tight\"" }}>
        <span className="dot"></span>
        Booking July 2026 — 2 spots left
      </div>
      <h1 className="hero-h1">
        <span className="hero-line hero-fade" style={{ animationDelay: '0.15s' }}>Web Design <em>&amp;</em></span><br />
        <span className="hero-line hero-fade" style={{ animationDelay: '0.30s' }}>Marketing that</span><br />
        <span className="hero-line hero-fade hero-accent" style={{ animationDelay: '0.45s', fontFamily: "\"Inter Tight\"" }}>earns its keep.</span>
      </h1>
      <div className="hero-foot" style={{ fontFamily: "\"Inter Tight\"" }}>
        <p className="hero-sub hero-fade" style={{ animationDelay: '0.6s', fontFamily: "\"Inter Tight\"" }}>We design Websites and run Marketing for businesses and service pros with measurable results.

        </p>
        <div className="hero-actions hero-fade" style={{ animationDelay: '0.75s' }}>
          <a href="#pricing" className="btn-primary">See packages</a>
          <a href="portfolio.html" className="btn-link">View work <span className="arrow">↗</span></a>
        </div>
      </div>

      <div className="hero-visual hero-visual-desktop hero-parallax" ref={visualRef}>
        <StatCycler />
        <div className="hero-mock-fit">
          <div className="hero-mock-scaler" ref={scalerRef}>
            <div className="hero-mockups-container hero-float hero-reveal" style={{ fontFamily: "\"Inter Tight\"" }}>
              <PhoneMock />
              <LaptopMock />
            </div>
          </div>
        </div>
        <FloatingMetric label="Cost / lead" value="$11.20" delta="−24%" />
        <FloatingMetric2 label="ROAS" value="5.1×" delta="+18%" />
      </div>
    </section>);

}

function HeroBig() {
  return (
    <section className="hero hero-big">
      <div className="hero-eyebrow">
        <span className="dot"></span>
        Booking June 2026 — 2 spots left
      </div>
      <h1 className="hero-h1 hero-h1-big">
        Sites that<br />
        <span className="hero-accent">convert.</span> Ads<br />
        that <em>pay back.</em>
      </h1>
      <p className="hero-sub hero-sub-center">
        A boutique design + marketing studio for small businesses and service pros.
      </p>
      <div className="hero-actions hero-actions-center">
        <a href="#pricing" className="btn-primary">See packages</a>
        <a href="portfolio.html" className="btn-link">View work <span className="arrow">↗</span></a>
      </div>
    </section>);

}

/* mock visuals */
function LaptopMock() {
  return (
    <div className="laptop-mock">
      <div className="laptop-lid">
        <div className="laptop-screen">
          <div className="laptop-bar">
            <span className="laptop-dot r"></span>
            <span className="laptop-dot y"></span>
            <span className="laptop-dot g"></span>
            <div className="laptop-url">yourwebsite.com</div>
          </div>
          <div className="laptop-body">
            <div className="laptop-hero" style={{ fontFamily: "\"Instrument Serif\"" }}>
              <div className="laptop-h">Your Business Name</div>
              <div className="laptop-p" style={{ fontFamily: "\"Inter Tight\"" }}>A professional, converting website that showcases your offer.</div>
              <div className="laptop-btn" style={{ fontFamily: "\"Inter Tight\"" }}>Get Started →</div>
            </div>
            <div className="laptop-img" style={{ backgroundImage: "url(assets/qd-logo.png)", backgroundRepeat: "no-repeat", backgroundPosition: "center", backgroundSize: "42%" }}></div>
          </div>
        </div>
      </div>
      <div className="laptop-bezel">
        <div className="laptop-chin"></div>
      </div>
    </div>);
}

function PhoneMock() {
  return (
    <div className="mock phone-mock">
      <div className="phone-notch"></div>
      <div className="phone-screen" style={{ fontFamily: "\"Inter Tight\"" }}>
        <div className="phone-app">
          <div className="phone-row">
            <div className="phone-avatar"></div>
            <div className="phone-name">Your.Brand</div>
            <div className="phone-spons">Sponsored</div>
          </div>
          <div className="phone-img" style={{ backgroundImage: "url(assets/qd-logo.png)", backgroundRepeat: "no-repeat", backgroundPosition: "center", backgroundSize: "55%" }}></div>
          <div className="phone-cta">Get Started →</div>
          <div className="phone-meta">
            <span>★ 4.9</span>
            <span>·</span>
            <span>99 conversions</span>
          </div>
        </div>
      </div>
    </div>);

}

function FloatingMetric({ label, value, delta }) {
  return (
    <div className="float-metric m1">
      <div className="fm-label">{label}</div>
      <div className="fm-value">{value}</div>
      <div className="fm-delta good">{delta}</div>
    </div>);

}
function FloatingMetric2({ label, value, delta }) {
  return (
    <div className="float-metric m2">
      <div className="fm-label">{label}</div>
      <div className="fm-value">{value}</div>
      <div className="fm-delta good">{delta}</div>
    </div>);

}

function StatCycler() {
  const STATS = [
  { v: "10+", l: "Websites launched" },
  { v: "99%", l: "Client retention" },
  { v: "2 Week", l: "Turn around" },
  { v: "48 hr", l: "Reply window" },
  { v: "2026", l: "Booking now" }];

  const CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789#*+×%·";
  const [idx, setIdx] = React.useState(0);
  const vRef = React.useRef(null);
  const lRef = React.useRef(null);

  React.useEffect(() => {
    const cur = STATS[idx];
    const next = STATS[(idx + 1) % STATS.length];
    let raf = 0;
    let alive = true;

    const splitInto = (el, str) => {
      el.innerHTML = "";
      [...str].forEach((c) => {
        const s = document.createElement("span");
        s.className = "sc-char";
        s.textContent = c;
        el.appendChild(s);
      });
    };

    const scramble = (el, from, to, dur, done) => {
      const start = performance.now();
      const max = Math.max(from.length, to.length);
      const toArr = [...to.padEnd(max, " ")];
      const fromArr = [...from.padEnd(max, " ")];
      const reveals = toArr.map((_, i) => {
        const r = Math.random();
        return Math.floor(dur * (0.2 + r * 0.6));
      });
      splitInto(el, from.padEnd(max, " "));
      const tick = (now) => {
        if (!alive) return;
        const t = now - start;
        const spans = el.querySelectorAll(".sc-char");
        let allDone = true;
        toArr.forEach((tch, i) => {
          const span = spans[i];
          if (!span) return;
          if (t >= reveals[i]) {
            span.textContent = tch;
            span.classList.add("resolved");
          } else {
            allDone = false;
            if (tch === " ") {
              span.textContent = " ";
            } else {
              span.textContent = CHARS[Math.floor(Math.random() * CHARS.length)];
            }
          }
        });
        if (t < dur && !allDone) {
          raf = requestAnimationFrame(tick);
        } else {
          // Trim only TRAILING spaces visually; keep internal spaces visible
          const spans = el.querySelectorAll(".sc-char");
          for (let i = spans.length - 1; i >= 0; i--) {
            if (spans[i].textContent === " ") spans[i].classList.add("blank");else
            break;
          }
          done && done();
        }
      };
      raf = requestAnimationFrame(tick);
    };

    const hold = setTimeout(() => {
      if (!alive) return;
      scramble(vRef.current, cur.v, next.v, 700);
      scramble(lRef.current, cur.l, next.l, 800, () => {
        setTimeout(() => alive && setIdx((i) => (i + 1) % STATS.length), 100);
      });
    }, 2600);

    // Initial paint on mount
    if (idx === 0 && vRef.current && !vRef.current.firstChild) {
      splitInto(vRef.current, cur.v);
      splitInto(lRef.current, cur.l);
    }

    return () => {
      alive = false;
      cancelAnimationFrame(raf);
      clearTimeout(hold);
    };
  }, [idx]);

  return (
    <div className="stat-cycler" aria-live="polite">
      <div className="sc-dot"></div>
      <div className="sc-value" ref={vRef}></div>
      <div className="sc-label" ref={lRef}></div>
    </div>);

}

/* =================== MARQUEE =================== */
function Marquee() {
  const items = ["Website Design", "Website Hosting", "Google Ads", "Meta Ads", "SEO", "Google Business", "Analytics"];
  return (
    <div className="marquee">
      <div className="marquee-track">
        {[...items, ...items, ...items].map((x, i) =>
        <span key={i} className="marquee-item">{x} <span className="marquee-star">✦</span></span>
        )}
      </div>
    </div>);

}

/* =================== SERVICES =================== */
function ServiceCard({ item, index }) {
  const ref = React.useRef(null);

  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = e.clientX - r.left;
    const y = e.clientY - r.top;
    const px = x / r.width;
    const py = y / r.height;
    const rotY = (px - 0.5) * 10; // -5..5deg
    const rotX = (0.5 - py) * 8; // -4..4deg
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(900px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${x}px`);
    el.style.setProperty("--my", `${y}px`);
  };

  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(900px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };

  return (
    <article
      ref={ref}
      className="service-card service-card-stagger"
      style={{ animationDelay: `${0.08 * index}s` }}>
      
      <div className="service-inner">
        <div className="service-tag">
          <span className={"tag-pill tag-" + item.color}>{item.tag}</span>
        </div>
        <h3 className="service-title">{item.title}</h3>
        <p className="service-body">{item.body}</p>
        <ul className="service-bullets">
          {item.bullets.map((b, j) =>
          <li key={j}><span className="b-tick"></span>{b}</li>
          )}
        </ul>
      </div>
    </article>);

}

function Services() {
  const items = [
  { tag: "01", title: "Website Design", body: "Mobile-first sites that load fast, look sharp, and route visitors straight to your business.", bullets: ["Custom-built", "Mobile friendly", "Google Business setup"], color: "accent" },
  { tag: "02", title: "Google Ads (Search)", body: "We capture demand from people actively searching. Lead-quality tracking, not vanity clicks.", bullets: ["Search", "Conversion tracking", "Monthly tuning"], color: "warm" },
  { tag: "03", title: "Meta Ads (Facebook/Instagram)", body: "Creative-first campaigns that don’t feel like ads. Built around the offer, not the algorithm.", bullets: ["Static + reels", "Lookalike audiences", "Creative testing"], color: "ink" },
  { tag: "04", title: "SEO", body: "Google SEO so your best pages draw traffic over the next 12 months - not the next 12 days.", bullets: ["Keyword strategy", "On-page SEO", "Google Business setup"], color: "accent" },
  { tag: "05", title: "Google Business", body: "Get found on Google Maps and local search — the profile that turns nearby searches into calls and visits.", bullets: ["Profile setup + optimisation", "Reviews + posts", "Local search ranking"], color: "warm" },
  { tag: "06", title: "Website Hosting", body: "Fast, secure managed hosting with a local person on call — so your site stays live and you never think about it.", bullets: ["24/7 Managed Hosting", "Backups + Monitoring", "SSL Certificate Security"], color: "ink" }];

  return (
    <section id="services" className="services">
      <div className="section-head">
        <div className="eyebrow"><span className="eyebrow-dot" style={{ backgroundColor: "rgb(31, 169, 240)" }}></span> Services</div>
        <h2 className="section-h2">
          Everything a business<br />needs to get found, look good,<br />and <em><span style={{ color: "#1fa9f0" }}>Get Results.</span></em>
        </h2>
      </div>
      <div className="services-grid">
        {items.map((it, i) =>
        <ServiceCard key={i} item={it} index={i} />
        )}
      </div>
    </section>);

}

function ProcessStep({ s }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const xp = e.clientX - r.left;
    const yp = e.clientY - r.top;
    const px = xp / r.width;
    const py = yp / r.height;
    const rotY = (px - 0.5) * 10;
    const rotX = (0.5 - py) * 8;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(900px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${xp}px`);
    el.style.setProperty("--my", `${yp}px`);
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(900px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <div ref={ref} className="process-step" style={{ position: "relative", isolation: "isolate", overflow: "hidden" }}>
      <div className="step-num" style={{ position: "relative", zIndex: 1 }}>{s.n}</div>
      <div className="step-rule" style={{ backgroundColor: "rgb(22, 24, 28)", position: "relative", zIndex: 1 }}></div>
      <h3 className="step-title" style={{ position: "relative", zIndex: 1 }}>{s.title}</h3>
      <p className="step-body" style={{ position: "relative", zIndex: 1 }}>{s.body}</p>
    </div>);

}

/* =================== PROCESS =================== */
function Process() {
  const steps = [
  { n: "01", title: "Get in touch", body: "Tell us about your business and what you're looking for - we'll take it from there." },
  { n: "02", title: "Design & build", body: "With your branding, colours, and direction locked in, we get to work. You'll review as we go so the final result feels exactly like yours." },
  { n: "03", title: "Launch & go live!", body: "Once you're happy and everything's signed off, we push it live. Your site is out in the world and working for you." }];

  return (
    <section className="process">
      <div className="section-head process-head">
        <div className="eyebrow"><span className="eyebrow-dot" style={{ backgroundColor: "rgb(31, 169, 240)" }}></span> Process</div>
        <h2 className="section-h2" style={{ color: "rgb(22, 24, 28)" }}>
          Three steps. <em><span style={{ color: "#1fa9f0" }}>No Mysterys.</span></em><br />
        </h2>
      </div>
      <div className="process-grid">
        {steps.map((s, i) =>
        <ProcessStep key={i} s={s} />
        )}
      </div>
    </section>);

}


/* =================== PORTFOLIO =================== */
function Portfolio({ t }) {
  const cases = [
  { name: "SB Group Ltd", tag: "Construction · Kapiti", stat: "+60%", statLabel: "online enquiries", colorA: "#1F2A36", colorB: "#3A4A5C", img: "sbgroup.co.nz", isSBWebsite: true, sbImg: "assets/sbgroup-website.jpg", url: "https://sbgroup.co.nz" },
  { name: "MM Decorative Concrete", tag: "Concrete · Kapiti", stat: "+38", statLabel: "qualified leads / mo", colorA: "#1071CC", colorB: "#C7DDF3", img: "mm decorative concrete website", isMMWebsite: true, mmImg: "assets/mm-concrete-website.jpg" },
  { name: "YOU Recruit", tag: "Consulting · Wellington", stat: "5.1×", statLabel: "ROAS in month 2", colorA: "#16181C", colorB: "#D6D3CC", img: "you recruit website", isYRWebsite: true, yrImg: "assets/yourecruit-website.jpg", url: "https://www.yourecruit.co.nz" },
  { name: "Batt Specialists", tag: "Insulation · Kapiti", stat: "+80%", statLabel: "online enquiries", colorA: "#1FA9F0", colorB: "#BDE3F8", img: "batt specialists website", isBattWebsite: true, battImg: "assets/batt-specialists.jpg" }];

  return (
    <section id="portfolio" className="portfolio">
      <div className="section-head portfolio-head">
        <div>
          <div className="eyebrow"><span className="eyebrow-dot" style={{ backgroundColor: "rgb(31, 169, 240)" }}></span> Recent work</div>
          <h2 className="section-h2">Work we've done for <em><span style={{ color: "#1fa9f0" }}>Clients.</span></em></h2>
        </div>
        <a href="portfolio.html" className="btn-link">All case studies <span className="arrow">↗</span></a>
      </div>
      <div className="portfolio-grid">
        {cases.map((c, i) =>
        <CaseCard key={i} c={c} t={t} />
        )}
      </div>
    </section>);

}

function CaseCard({ c, t }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = e.clientX - r.left;
    const y = e.clientY - r.top;
    const px = x / r.width;
    const py = y / r.height;
    const rotY = (px - 0.5) * 8;
    const rotX = (0.5 - py) * 6;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(900px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${x}px`);
    el.style.setProperty("--my", `${y}px`);
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(900px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <article ref={ref} className={"case-card" + (c.url ? " case-card-link" : "")}>
      {c.url && <a className="case-link-overlay" href={c.url} target="_blank" rel="noopener noreferrer" aria-label={`Visit ${c.name} website`}></a>}
      {c.isSBWebsite ?
      <div className="case-img" style={{ background: `url(${c.sbImg}) ${t?.sbBgPositionX || 50}% ${t?.sbBgPositionY || 0}% / cover no-repeat` }}>
        </div> : c.isBattWebsite ?
      <div className="case-img" style={{ background: `url(${c.battImg}) ${t?.battBgPositionX || 50}% ${t?.battBgPositionY || 0}% / cover no-repeat` }}>
        </div> : c.isYRWebsite ?
      <div className="case-img" style={{ background: `url(${c.yrImg}) 50% 0% / cover no-repeat` }}>
        </div> : c.isMMWebsite ?
      <div className="case-img" style={{ background: `#FFFFFF url(${c.mmImg}) 50% 0% / 100% auto no-repeat` }}>
        </div> :
      <div className="case-img" style={{ background: `linear-gradient(135deg, ${c.colorA} 0%, ${c.colorB} 100%)` }}>
          <div className="case-img-label">{c.img}</div>
          <div className="case-stat">
            <div className="case-stat-v">{c.stat}</div>
            <div className="case-stat-l">{c.statLabel}</div>
          </div>
        </div>
      }
      <div className="case-meta">
        <div>
          <div className="case-name">{c.name}</div>
          <div className="case-tag">{c.tag}</div>
        </div>
      </div>
    </article>);

}

/* =================== PRICING (teaser linking to service pages) =================== */
const BUILD_TIERS = [
{
  name: "Starter",
  price: "$400",
  note: "one-time build fee",
  then: "Hosting from $35/mo",
  blurb: "A single-page site that gets you online and looking legit. Perfect for sole traders.",
  features: ["One-page scrolling website", "All key sections — home, about, services, contact", "Tap-to-call button", "Mobile-first design", "Contact form + Google Business setup", "1 round of revisions", "1 week turnaround"],
  cta: "Start with Starter",
  featured: false
},
{
  name: "Foundation",
  price: "$750",
  note: "one-time build fee",
  then: "Hosting from $35/mo",
  blurb: "A clean, well-built site for service businesses ready to look the part (perfect for tradies).",
  features: ["Up-to 5-page website", "Mobile-first design", "Project gallery/portfolio to showcase your work", "Contact form + Google Business setup", "Basic on-page SEO", "Copywriting for every page", "1 round of revisions", "2 week turnaround"],
  cta: "Start with Foundation",
  featured: true
},
{
  name: "Foundation Plus",
  price: "$1,250",
  note: "one-time build fee",
  then: "Hosting from $35/mo",
  blurb: "Built to showcase your work, convert visitors, and win bigger jobs.",
  features: ["Up to 8 pages, custom layout", "Mobile-first design", "Project gallery/portfolio to showcase your work", "Contact form + Google Business setup", "Advanced local SEO", "Copywriting for every page", "Google Reviews pulled live onto your site", "Custom icons & graphics to match your brand", "2 rounds of revisions", "30 days of free tweaks after launch", "2-4 week turnaround"],
  cta: "Start with Plus",
  featured: false
}];

const CARE_TIERS = [
{
  name: "Essential Care",
  price: "$35",
  note: "/mo",
  blurb: "Set it and forget it. Your site kept live, fast and secure.",
  features: ["Managed hosting on enterprise infrastructure", "SSL certificate & DDoS protection", "Automatic backups", "Uptime monitoring", "A local person monitoring your website"],
  cta: "Keep mine running",
  featured: false
},
{
  name: "Standard Care",
  price: "$70",
  note: "/mo",
  blurb: "For when your work changes and your site needs to keep up.",
  features: ["Everything in Essential Care", "Up to 1 hour of content updates each month including:", "sub:Adding/removing text & photos", "sub:Updating prices or service listings", "sub:Adding new projects to the gallery", "sub:Swapping testimonials or reviews", "sub:Updating hours, contact details or service areas", "sub:Seasonal changes & banners", "sub:Adding or updating team member profiles", "sub:Updating certifications & association badges", "sub:Posting a news item or announcement", "sub:Minor layout tweaks", "Priority response"],
  cta: "Stay looked after",
  featured: true
},
{
  name: "Priority Care",
  price: "$130",
  note: "/mo",
  blurb: "For businesses on the grow.",
  features: ["Everything in Standard Care", "Up to 3 hours of updates each month including:", "sub:Adding/removing text & photos", "sub:Updating prices or service listings", "sub:Adding new projects to the gallery", "sub:Swapping testimonials or reviews", "sub:Updating hours, contact details or service areas", "sub:Seasonal changes & banners", "sub:Adding or updating team member profiles", "sub:Updating certifications & association badges", "sub:Posting a news item or announcement", "sub:Minor layout tweaks", "First-in-line support"],
  cta: "Go Priority",
  featured: false
}];

function PriceCard({ tier }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width;
    const py = (e.clientY - r.top) / r.height;
    const rotY = (px - 0.5) * 6;
    const rotX = (0.5 - py) * 4;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(1100px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(1100px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <div ref={ref} className={"hp-price-card" + (tier.featured ? " featured" : "")} onMouseMove={onMove} onMouseLeave={onLeave} style={{ transformStyle: "preserve-3d", willChange: "transform" }}>
      {tier.featured && <div className="hp-price-flag">Most picked</div>}
      <div className="hp-price-name">{tier.name}</div>
      <div className="hp-price-row">
        <span className="hp-price-amt">{tier.price}</span>
        <span className="hp-price-note">{tier.note}</span>
      </div>
      {tier.then && <div className="hp-price-then">{tier.then}</div>}
      <p className="hp-price-blurb">{tier.blurb}</p>
      <div className="hp-price-rule"></div>
      <ul className="hp-price-features">
        {tier.features.map((f, j) =>
        f.startsWith("sub:") ?
        <li key={j} className="hp-feature-sub">{f.slice(4)}</li> :
        <li key={j}>
            <span className="hp-tick">
              <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="5 12 10 17 19 7" /></svg>
            </span>
            {f}
          </li>
        )}
      </ul>
      <a href="contact.html" className="hp-price-btn">{tier.cta}</a>
    </div>);
}

function Pricing() {
  return (
    <section id="pricing" className="pricing">
      <div className="section-head pricing-head">
        <div className="eyebrow"><span className="eyebrow-dot" style={{ backgroundColor: "rgb(31, 169, 240)" }}></span> Packages &amp; pricing</div>
        <h2 className="section-h2" style={{ color: "rgb(22, 24, 28)" }}>Pick your build. <em style={{ color: "rgb(31, 169, 240)" }}>We handle the rest.</em></h2>
        <p className="pricing-sub">One time build fee, then a simple monthly plan to keep it live and looked after.
</p>
      </div>
      <div className="hp-price-grid">
        {BUILD_TIERS.map((tier, i) => <PriceCard key={i} tier={tier} />)}
      </div>
      <div className="hp-price-line">Every build includes your first month of care free.</div>

      <div className="section-head pricing-head hp-pricing-head-2">
        <h2 className="section-h2" style={{ color: "rgb(22, 24, 28)" }}>Then we <em style={{ color: "rgb(31, 169, 240)" }}>keep it running.</em></h2>
        <p className="pricing-sub">Hosting, security and a local person you can actually talk to — so you never have to worry about your website again.</p>
      </div>
      <div className="hp-price-grid">
        {CARE_TIERS.map((tier, i) => <PriceCard key={i} tier={tier} />)}
      </div>
      <div className="hp-price-line">Save two months — pay annually.</div>

      <div className="hp-price-footnote">All prices NZD, excl. GST.</div>
    </section>);}

function TeaserCard({ p, index }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = e.clientX - r.left;
    const y = e.clientY - r.top;
    const px = x / r.width;
    const py = y / r.height;
    const rotY = (px - 0.5) * 8;
    const rotX = (0.5 - py) * 6;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(1000px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${x}px`);
    el.style.setProperty("--my", `${y}px`);
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(1000px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <a ref={ref} href={p.href} className="teaser-card service-card-stagger" style={{ animationDelay: `${0.08 * index}s` }}>
      <div className="teaser-head">
        <div className="teaser-icon" style={{ background: p.iconBg }}>{p.icon}</div>
        <div className="teaser-price">
          <span className="teaser-from">from</span>
          <span className="teaser-amt">{p.from}</span>
          <span className="teaser-note">{p.note}</span>
        </div>
      </div>
      <h3 className="teaser-name">{p.name}</h3>
      <p className="teaser-blurb">{p.blurb}</p>
      <ul className="teaser-bullets">
        {p.bullets.map((b, j) => <li key={j}><span className="b-tick"></span>{b}</li>)}
      </ul>
      <span className="teaser-link">Explore packages <span className="arrow">→</span></span>
    </a>);
}

/* =================== TESTIMONIALS =================== */

function Testimonials() {
  const t = [
  { quote: "\"Quantum Design blew me away with their creativity and professionalism. My website has received so many compliments - it exceeded every expectation. They took the time to understand our construction business and displayed everything perfectly. Highly recommend!\"", name: "SB Group Limited", role: "Construction | Kapiti", initials: "BS", color: "#F26B4E", logo: "assets/sb-group-logo.png" },
  { quote: "Best money we've spent on the business. Quantum Design handled everything - the design, hosting, the lot. So we could stay on the tools. Within weeks of launching we were getting enquiries straight through the site. Easy to deal with and genuine.", name: "BattSpecialists Limited", role: "Insulation | Kapiti", initials: "BS", logo: "assets/battspecialists-logo.jpg", color: "#1FA9F0" },
  { quote: "", name: "MM Decorative Concrete", role: "Concrete | Kapiti", initials: "MM", logo: "assets/mmconcrete-logo.jpg", color: "#1071CC" }];

  const [idx, setIdx] = React.useState(0);
  const [perPage, setPerPage] = React.useState(() => typeof window !== "undefined" && window.innerWidth <= 600 ? 1 : 2);
  React.useEffect(() => {
    const onResize = () => setPerPage(window.innerWidth <= 600 ? 1 : 2);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  const n = t.length;
  const pages = n;
  const go = (d) => setIdx((i) => (i + d + pages) % pages);
  const loopT = perPage > 1 ? [...t, ...t.slice(0, perPage - 1)] : t;

  return (
    <section className="testimonials">
      <div className="section-head">
        <div className="eyebrow"><span className="eyebrow-dot" style={{ backgroundColor: "rgb(31, 169, 240)" }}></span> Testimonials</div>
        <h2 className="section-h2" style={{ fontFamily: "\"Inter Tight\"" }}>Real businesses.<em> <span style={{ color: "#1fa9f0" }}>Real Numbers.</span></em></h2>
      </div>
      <div className="t-carousel">
        <button className="t-arrow" onClick={() => go(-1)} aria-label="Previous testimonial">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6" /></svg>
        </button>
        <div className="t-viewport">
          <div className="t-track" style={{ transform: `translateX(-${idx * (100 / perPage)}%)` }}>
            {loopT.map((x, i) =>
            <div className="t-slide" key={i} aria-hidden={i < idx || i >= idx + perPage}>
                <TestimonialCard x={x} index={0} />
              </div>
            )}
          </div>
        </div>
        <button className="t-arrow" onClick={() => go(1)} aria-label="Next testimonial">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18l6-6-6-6" /></svg>
        </button>
      </div>
      <div className="t-dots">
        {Array.from({ length: pages }).map((_, i) =>
        <button
          key={i}
          className={"t-dot" + (i === idx ? " active" : "")}
          onClick={() => setIdx(i)}
          aria-label={`Go to testimonials page ${i + 1}`} />
        )}
      </div>
    </section>);

}

function TestimonialCard({ x, index }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const xp = e.clientX - r.left;
    const yp = e.clientY - r.top;
    const px = xp / r.width;
    const py = yp / r.height;
    const rotY = (px - 0.5) * 8;
    const rotX = (0.5 - py) * 6;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(900px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${xp}px`);
    el.style.setProperty("--my", `${yp}px`);
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(900px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <figure ref={ref} className="t-card service-card-stagger" style={{ animationDelay: `${0.1 * (index || 0)}s` }}>
      <div className="t-quote-mark" style={{ color: "rgb(31, 169, 240)" }}>“</div>
      <blockquote>{x.quote}</blockquote>
      <figcaption>
        <div className="t-avatar" style={x.logo ? { padding: 0, background: "#000" } : { ...{ background: x.color }, background: "rgb(31, 169, 240)" }}>
          {x.logo ? <img src={x.logo} alt={x.name} style={{ width: "100%", height: "100%", borderRadius: "50%", objectFit: "cover" }} /> : x.initials}
        </div>
        <div>
          <div className="t-name-row">
            <div className="t-name">{x.name}</div>
            <span className="t-stars" aria-label="5 out of 5 stars">★★★★★</span>
          </div>
          <div className="t-role">{x.role}</div>
        </div>
      </figcaption>
    </figure>);

}

/* =================== CTA =================== */
function CTA() {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = e.clientX - r.left;
    const y = e.clientY - r.top;
    const px = x / r.width;
    const py = y / r.height;
    const rotY = (px - 0.5) * 8;
    const rotX = (0.5 - py) * 6;
    el.style.transition = "transform 80ms linear";
    el.style.transform = `perspective(1200px) rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg) translateY(-4px)`;
    el.style.setProperty("--mx", `${x}px`);
    el.style.setProperty("--my", `${y}px`);
  };
  const onLeave = () => {
    const el = ref.current;
    if (!el) return;
    el.style.transition = "transform 500ms cubic-bezier(.22,1.4,.36,1)";
    el.style.transform = "perspective(1200px) rotateX(0deg) rotateY(0deg) translateY(0)";
  };
  return (
    <section id="contact" className="cta">
      <div className="cta-card" ref={ref} style={{ position: "relative", isolation: "isolate", overflow: "hidden" }}>
        <div className="cta-grid">
          <div>
            <div className="eyebrow eyebrow-light"><span className="eyebrow-dot"></span> Let’s talk</div>
            <h2 className="cta-h2" style={{ fontSize: "64px" }}>
              Got a project in mind?<br />No calls needed.<br />
              <span className="cta-accent">Just say hello.</span>
            </h2>
            <div className="cta-actions">
              <a href="contact.html" className="btn-primary btn-primary-light">Contact Us</a>
            </div>
          </div>
          <div className="cta-right">
            <div className="cta-stat">
              <div className="cta-stat-v">48h</div>
              <div className="cta-stat-l">Reply window</div>
            </div>
            <div className="cta-stat">
              <div className="cta-stat-v">Flexible</div>
              <div className="cta-stat-l">Retainer options</div>
            </div>
            <div className="cta-stat">
              <div className="cta-stat-v">Flat</div>
              <div className="cta-stat-l">Transparent fees</div>
            </div>
            <div className="cta-stat">
              <div className="cta-stat-v">2026</div>
              <div className="cta-stat-l">Booking now</div>
            </div>
          </div>
        </div>
      </div>
    </section>);
}

/* =================== FOOTER =================== */
function Footer() {
  return (
    <footer className="footer">
      <div className="footer-top">
        <div className="footer-brand">
          <div className="brand">
            <img src="assets/qd-logo.png" alt="Quantum Design" style={{ width: "40px", height: "40px" }} />
            <span>Quantum Design</span>
          </div>
          <p className="footer-tag">Design and Marketing for businesses that want to grow.</p>
        </div>
        <div className="footer-cols">
          <div>
            <div className="footer-h" style={{ color: "rgb(31, 169, 240)" }}>Services</div>
            <a href="web-design.html">Web Design</a>
            <a href="marketing.html">Marketing &amp; SEO</a>
          </div>
          <div>
            <div className="footer-h" style={{ color: "rgb(31, 169, 240)" }}>The Studio</div>
            <a href="about.html">About</a>
            <a href="index.html#services">Services</a>
            <a href="portfolio.html">Portfolio</a>
            <a href="contact.html">Contact</a>
          </div>
          <div>
            <div className="footer-h" style={{ color: "rgb(31, 169, 240)" }}>SAY HELLO</div>
            <a href="mailto:quantumdesignnz@gmail.com">QuantumDesignNZ@gmail.com</a>
            <a href="https://www.facebook.com/quantumdesignnz" target="_blank" rel="noopener noreferrer">Facebook</a>
            <a href="https://www.instagram.com/quantumdesign.co.nz" target="_blank" rel="noopener noreferrer">Instagram</a>
          </div>
        </div>
      </div>
      <div className="footer-bot">
        <span>© 2025-2026 Quantum Design</span>
        <span></span>
      </div>
    </footer>);

}

/* =================== TWEAKS =================== */
function Tweaks({ t, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Palette">
        <TweakColor
          value={t.palette}
          onChange={(v) => setTweak("palette", v)}
          options={[
          { value: "cream", label: "Cream", swatch: ["#F4EFE7", "#16181C", "#1FA9F0", "#F26B4E"] },
          { value: "bone", label: "Bone", swatch: ["#EFEDE6", "#161616", "#1FA9F0", "#FF7A45"] },
          { value: "paper", label: "Paper", swatch: ["#F2F2EE", "#0E1116", "#1FA9F0", "#FF6A3D"] },
          { value: "ocean", label: "Ocean", swatch: ["#EAF1F6", "#0B1220", "#1FA9F0", "#F08A5D"] }]
          } />
        
      </TweakSection>
      <TweakSection title="Hero">
        <TweakRadio
          value={t.heroVariant}
          onChange={(v) => setTweak("heroVariant", v)}
          options={[
          { value: "split", label: "Split + mockup" },
          { value: "big", label: "Big type only" }]
          } />
        
      </TweakSection>
      <TweakSection title="Batt Image Position">
        <TweakSlider
          value={t.battBgPositionX}
          onChange={(v) => setTweak("battBgPositionX", v)}
          min={0}
          max={100}
          step={1}
          label="Horizontal" />
        <TweakSlider
          value={t.battBgPositionY}
          onChange={(v) => setTweak("battBgPositionY", v)}
          min={0}
          max={100}
          step={1}
          label="Vertical" />
      </TweakSection>
      <TweakSection title="SB Group Image Position">
        <TweakSlider
          value={t.sbBgPositionX}
          onChange={(v) => setTweak("sbBgPositionX", v)}
          min={0}
          max={100}
          step={1}
          label="Horizontal" />
        <TweakSlider
          value={t.sbBgPositionY}
          onChange={(v) => setTweak("sbBgPositionY", v)}
          min={0}
          max={100}
          step={1}
          label="Vertical" />
      </TweakSection>
    </TweaksPanel>);

}

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