/* Future Advisory — homepage build (shell / step 1).
   Header + footer built full; 8 content sections are empty labeled
   placeholders wired in order. Reuses the design-system bundle
   components (Logo, MenuItem, Button, SocialIcon, PartnerLogo) and
   the global reveal utility. No marketing copy in the placeholders. */

const NS = window.FutureAdvisoryDesignSystem_98dff1;
const { Logo, LogoMark, MenuItem, Button, SocialIcon, PartnerLogo, ImageTile, ComparisonRow } = NS;

const BASE = "./"; // homepage/ → project root, for assets/

/* Comparison-column logo: a self-contained copy of the header logo — white
   "future advisory" wordmark + yellow #FBEB4F triangle on the purple column.
   The header already renders FA_LOGO_SVG_DARK, so its internal clip-path IDs
   (clip0_134_9986) exist earlier in the DOM; reusing the same string would make
   url(#…) references bind to the header's clip and the copy could be clipped to
   nothing in some browsers. Rename the IDs so this copy is isolated. The DARK
   variant's own fills (white wordmark, yellow mark) are exactly what we want. */
const PP_LOGO_SVG = (window.FA_LOGO_SVG_DARK || "")
  .replace(/clip0_134_9986/g, "clip0_pp_fa");

/* Re-run the scroll-reveal binder after React paints. */
function useReveal() {
  React.useEffect(() => {
    if (window.FAReveal) window.FAReveal.init();
  });
}

/* ---------------- Header ---------------- */
/* Header colour auto-adapts to the section behind it. Every section
   declares data-header-theme="light" | "dark"; an IntersectionObserver
   detects which one sits under the header zone (top of viewport) and the
   header recolours to match. Adding new sections needs no changes here —
   just give the new section a data-header-theme attribute. */
const HEADER_H = 80;

function useHeaderTheme() {
  const [theme, setTheme] = React.useState("light");
  const [blend, setBlend] = React.useState(false);
  React.useEffect(() => {
    const sections = Array.from(document.querySelectorAll("[data-header-theme]"));
    if (!sections.length) return;
    // Pick the section whose box currently spans a horizontal line at the
    // header's bottom edge. This is pure geometry off the current scroll
    // position, so it flips at the exact same point going up or down — no
    // directional lag. Driven by a scroll listener throttled with rAF.
    const line = HEADER_H + 1;
    let raf = 0;
    const resolve = () => {
      raf = 0;
      let current = null;
      for (const sec of sections) {
        const r = sec.getBoundingClientRect();
        if (r.top <= line && r.bottom > line) current = sec;
      }
      if (current) {
        setTheme(current.getAttribute("data-header-theme") || "light");
        // Blend-mode fallback: sections that clash with the header opt in via
        // data-header-blend="true" — toggle .header--blend (see Header + CSS).
        setBlend(current.getAttribute("data-header-blend") === "true");
      }
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(resolve); };
    resolve();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      if (raf) cancelAnimationFrame(raf);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, []);
  return { theme, blend };
}

/* Per-pixel legibility over the hero's moving photo tiles. Rather than flip the
   WHOLE header when a tile drifts behind it, we render a white-text copy of the
   header pinned on top (aria-hidden, pointer-events:none) and CSS-mask it to
   exactly the rectangles where the tiles intersect the header box. Result: only
   the glyphs actually sitting over an image turn white — a nav item half over a
   photo splits mid-word. A rAF loop rebuilds the mask each frame so it tracks the
   intro burst + scroll orbit (which keeps easing after scrolling stops). */
function useHeaderImageMask(overlayRef) {
  React.useEffect(() => {
    const overlay = overlayRef.current;
    if (!overlay) return;
    let raf = 0;
    const apply = () => {
      const header = document.querySelector(".fa-header");
      const tiles = header ? document.querySelectorAll(".fa-hero__tile") : [];
      const layers = [];
      if (header && tiles.length) {
        const hr = header.getBoundingClientRect();
        tiles.forEach((t) => {
          const r = t.getBoundingClientRect();
          const x1 = Math.max(r.left, hr.left), y1 = Math.max(r.top, hr.top);
          const x2 = Math.min(r.right, hr.right), y2 = Math.min(r.bottom, hr.bottom);
          if (x2 > x1 && y2 > y1) layers.push({ x: x1 - hr.left, y: y1 - hr.top, w: x2 - x1, h: y2 - y1 });
        });
      }
      if (!layers.length) {
        overlay.style.opacity = "0";
        overlay.style.webkitMaskImage = overlay.style.maskImage = "none";
      } else {
        overlay.style.opacity = "1";
        const img = layers.map(() => "linear-gradient(#000,#000)").join(",");
        const pos = layers.map((l) => l.x + "px " + l.y + "px").join(",");
        const size = layers.map((l) => l.w + "px " + l.h + "px").join(",");
        overlay.style.webkitMaskImage = overlay.style.maskImage = img;
        overlay.style.webkitMaskPosition = overlay.style.maskPosition = pos;
        overlay.style.webkitMaskSize = overlay.style.maskSize = size;
      }
      raf = requestAnimationFrame(apply);
    };
    raf = requestAnimationFrame(apply);
    return () => { if (raf) cancelAnimationFrame(raf); };
  }, []);
}

/* The header's row of controls — rendered twice: once as the live base layer
   (section-driven theme, interactive) and once as the white overlay copy that
   the image mask reveals. The overlay is inert; its Book-a-call button is hidden
   via CSS (a solid-fill button is already legible over any backdrop, so only the
   transparent-background logo + nav need per-pixel inversion). */
function HeaderInner({ nav, theme, overlay }) {
  return (
    <div className={"fa-header__inner" + (overlay ? " fa-header__inner--overlay" : "")}>
      <a href="#top" className="fa-logo" aria-label="Future Advisory — home">
        <span className="fa-logo__cut fa-logo__cut--light" aria-hidden="true"
              dangerouslySetInnerHTML={{ __html: window.FA_LOGO_SVG_LIGHT }} />
        <span className="fa-logo__cut fa-logo__cut--dark" aria-hidden="true"
              dangerouslySetInnerHTML={{ __html: window.FA_LOGO_SVG_DARK }} />
      </a>
      <nav className="fa-nav" aria-label="Primary">
        {nav.map(([label, href, caret]) => (
          <MenuItem key={label} href={href} hasCaret={caret}>{label}</MenuItem>
        ))}
      </nav>
      <Button
        variant={theme === "dark" ? "yellow" : "primary"}
        className="fa-btn-lift"
        style={{ height: 80 }}
        onClick={() => { /* booking flow wired in a later step */ }}
      >
        Book a call
      </Button>
      <button type="button" className="fa-hamburger" aria-label="Open menu">
        <svg width="26" height="26" viewBox="0 0 26 26" fill="none" aria-hidden="true">
          <path d="M3 7h20M3 13h20M3 19h20" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
        </svg>
      </button>
    </div>
  );
}

function Header() {
  const { theme, blend } = useHeaderTheme();
  const overlayRef = React.useRef(null);
  useHeaderImageMask(overlayRef);

  const nav = [
    ["Services", "#services", true],
    ["Pricing", "#problem-pricing", false],
    ["Industries", "#industries", false],
    ["About", "#proof", true],
    ["Insights", "#proof", true],
    ["Contact", "#footer", false],
  ];

  return (
    <React.Fragment>
      <header className={"fa-header" + (blend ? " header--blend" : "")} data-theme={theme}>
        {/* live, interactive layer — colour follows the section behind the header */}
        <HeaderInner nav={nav} theme={theme} overlay={false} />
        {/* white copy, revealed by the mask only where hero photo tiles sit behind it */}
        <div ref={overlayRef} className="fa-header__inner fa-header__inner--overlay" data-theme="dark" aria-hidden="true">
          <HeaderInner nav={nav} theme="dark" overlay={true} />
        </div>
      </header>
      {/* Blend fallback (desktop): .header--blend puts mix-blend-mode:difference on
          the fixed header so logo+nav invert against whatever scrolls behind it —
          the only place the blend reaches the page (content INSIDE the fixed header
          is isolated by its own stacking context). That would also invert the solid
          mint "Book a call" button, so this non-blended copy sits OUTSIDE the header
          and covers it — visual only (aria-hidden, pointer-events:none); clicks fall
          through to the real button underneath. Hidden on mobile/tablet via CSS. */}
      <div className={"fa-header__cta-cover" + (blend ? " is-on" : "")} aria-hidden="true">
        <Button variant="primary" className="fa-btn-lift" style={{ height: 80 }} tabIndex={-1}>Book a call</Button>
      </div>
      {/* Logo lockup, lifted OUT of the blended header so it NEVER inverts. The
          in-header .fa-logo stays put for layout (keeps nav position) but is
          hidden under blend; this fixed, non-blending copy renders in its place —
          mint triangle always, wordmark colour following the section theme
          (navy on light, white on dark). Nav keeps blending, untouched.
          Desktop-only: mobile never blends, so the in-header logo shows there. */}
      <a href="#top"
         className={"fa-header__logo-cover" + (blend ? " is-on" : "")}
         data-theme={theme}
         aria-label="Future Advisory — home"
         dangerouslySetInnerHTML={{ __html: window.FA_LOGO_SVG_MONO }} />
    </React.Fragment>
  );
}

/* ---------------- Hero ---------------- */
/* Six photo tiles frame the centred text. Tile CENTRES are responsive — each is
   computed from the viewport width (see heroRest), so tiles fan outward on wide
   screens and are always parked clear of the centred text (never overlapping),
   while the text block stays centred and on top.

   RANDOM SET: each entry of heroImageSets is a curated group of six photos in
   tile order (A→F); one whole set is chosen at random per load and mapped onto
   tiles A..F — sets are never split.

   INTRO: on load all six tiles burst out from the hero centre together (same
   start, duration, ease-out). ORBIT: afterwards a shared scroll-driven angle
   sweeps every tile around one oval (RX > RY), eased per frame. Both derive
   from the responsive resting centres, so they stay balanced at any width. */

// Per-tile spec: size (px) + vertical CENTRE (stage-y, 0..1000) + horizontal
// intent. side 'C' = centred (sits clear above/below the text); 'L'/'R' park it
// in the outer region on that side so it can't cover the text. out (0..1) = how
// far into that outer region (0 = just clear of text, 1 = toward the edge).
// cxFrac nudges a centred tile off-centre by a fraction of half the width.
const HERO_TILES = [
  { key: "A", w: 220, h: 220, cy: 94,  side: "C", cxFrac: 0.00 },
  { key: "B", w: 260, h: 260, cy: 204, side: "R", out: 0.50 },
  { key: "C", w: 280, h: 280, cy: 272, side: "L", out: 0.50 },
  { key: "D", w: 280, h: 280, cy: 710, side: "R", out: 0.58 },
  { key: "E", w: 260, h: 260, cy: 818, side: "L", out: 0.58 },
  { key: "F", w: 240, h: 240, cy: 976, side: "C", cxFrac: 0.06 },
];

const HERO_CY = 500, HERO_RX = 700, HERO_RY = 380, HERO_SWEEP = 0.6;
const HERO_TEXT_HALF = 500;   // keep-clear half-width around the centred text
const HERO_EDGE = 24;         // min gap from the viewport side

// Resting CENTRE {cx,cy} of each tile for a viewport width. Side tiles sit in the
// outer region beyond the text keep-clear zone (so they never cover the text
// where there's room); on screens too narrow to both clear the text and stay
// mostly on-screen they favour visibility (matching the prior look).
function heroRest(vw) {
  const CX = vw / 2;
  return HERO_TILES.map((t) => {
    const half = t.w / 2;
    if (t.side === "C") return { cx: CX + (t.cxFrac || 0) * (vw / 2), cy: t.cy };
    const clearOff = HERO_TEXT_HALF + half;               // clears the text
    const maxOff = vw / 2 - HERO_EDGE - half * 0.4;        // keep >=60% of tile on-screen
    const off = maxOff >= clearOff ? clearOff + (t.out || 0) * (maxOff - clearOff) : maxOff;
    return { cx: t.side === "L" ? CX - off : CX + off, cy: t.cy };
  });
}

const HERO_UPLOADS = BASE + "uploads/";
// Curated sets of six (tile order A,B,C,D,E,F); one whole set per page load.
const heroImageSets = [
  ["JARNI_FUTURE_0847.jpg", "JARNI_FUTURE_0861.jpg", "JARNI_FUTURE_1035.jpg", "JARNI_FUTURE_1044.jpg", "JARNI_FUTURE_1055.jpg", "JARNI_FUTURE_1152.jpg"],
  ["JARNI_FUTURE_1189.jpg", "JARNI_FUTURE_1238.jpg", "JARNI_FUTURE_1279.jpg", "JARNI_FUTURE_1309.jpg", "JARNI_FUTURE_1334.jpg", "JARNI_FUTURE_1408.jpg"],
  ["JOSEPHBYFORD-101358-1366 (1).jpg", "JOSEPHBYFORD-101358-1377.jpg", "SummerSeries_113.jpg", "SummerSeries_122.jpg", "SummerSeries_290.jpg", "SummerSeries_291.jpg"],
];

function Hero() {
  const sectionRef = React.useRef(null);
  const tilesRef = React.useRef([]);

  // One curated set chosen at random per page load (kept together as a group).
  const setIndex = React.useMemo(() => Math.floor(Math.random() * heroImageSets.length), []);
  const activeSet = heroImageSets[setIndex];

  React.useEffect(() => {
    const els = tilesRef.current;
    if (!els || els.length < HERO_TILES.length || els.some((e) => !e)) return;

    // Layout recomputed on load + resize: responsive resting centres → per-tile
    // orbit base angle + radial factor, all sharing one oval (RX > RY).
    let CX = 0, rest = [], base = [];
    const computeLayout = () => {
      const vw = sectionRef.current ? sectionRef.current.clientWidth : window.innerWidth;
      CX = vw / 2;
      rest = heroRest(vw);
      base = rest.map((r) => {
        const ex = (r.cx - CX) / HERO_RX;
        const ey = (r.cy - HERO_CY) / HERO_RY;
        return { a0: Math.atan2(ey, ex), k: Math.hypot(ex, ey) || 1 };
      });
    };
    computeLayout();

    const place = (angle) => {
      for (let i = 0; i < els.length; i++) {
        const a = base[i].a0 + angle;
        const cx = CX + base[i].k * HERO_RX * Math.cos(a);
        const cy = HERO_CY + base[i].k * HERO_RY * Math.sin(a);
        els[i].style.transform = "translate(" + (cx - HERO_TILES[i].w / 2) + "px, " + (cy - HERO_TILES[i].h / 2) + "px)";
      }
    };

    place(0);

    // ---- Tablet + mobile (≤768): six-tile ring BELOW the text, scroll-orbited ----
    // The stage is an in-flow block under the text (see CSS: order/relative). The
    // six tiles sit in an oval ring around the stage centre and share ONE scroll
    // angle (same approach as desktop), sized to fit the viewport with no overflow.
    if (window.matchMedia("(max-width: 1199px)").matches) {
      const stage = els[0].parentNode;
      const N = els.length;
      const baseA = els.map((_, i) => (i / N) * Math.PI * 2 - Math.PI / 2);
      let RCX = 0, RCY = 0, RR = 0, tsize = 180;
      const computeRing = () => {
        const hero = sectionRef.current;
        const vw = (hero && hero.clientWidth) || window.innerWidth;
        const heroH = (hero && hero.clientHeight) || window.innerHeight;
        tsize = vw < 600 ? 180 : Math.min(360, Math.round(vw * 0.32));                 // fixed, generous size — do NOT shrink to fit
        RR = Math.round(tsize * 1.45);                 // R ≥ √2·tile → tiles keep a clear gap, never overlap while rotating
        const innerEl = hero && hero.querySelector(".fa-hero__inner");
        const textBottom = innerEl ? innerEl.offsetTop + innerEl.offsetHeight : Math.round(heroH * 0.4);
        const spaceTop = textBottom + 24;              // 24px gap below the text/buttons to the highest tile
        const avail = Math.max(0, heroH - spaceTop);
        RCX = vw / 2;                                  // centred; side tiles bleed past the edges (clipped by overflow:hidden)
        RCY = Math.max(spaceTop + RR + tsize / 2, spaceTop + avail / 2);  // ring below the text; bottom bleed is clipped, adds no height
        els.forEach((el) => { el.style.width = tsize + "px"; el.style.height = tsize + "px"; });
      };
      const placeRing = (angle) => {
        for (let i = 0; i < N; i++) {
          const a = baseA[i] + angle;
          els[i].style.transform =
            "translate(" + (RCX + RR * Math.cos(a) - tsize / 2) + "px, " +
            (RCY + RR * Math.sin(a) - tsize / 2) + "px)";
        }
      };
      computeRing();
      placeRing(0);
      const reducedM = window.FAReveal && window.FAReveal.reduced;
      if (reducedM) {
        els.forEach((el) => { el.style.opacity = "1"; });
      } else {
        els.forEach((el, i) => {
          el.style.transition = "opacity 600ms cubic-bezier(0.16,1,0.3,1) " + (i * 80) + "ms";
          requestAnimationFrame(() => requestAnimationFrame(() => { el.style.opacity = "1"; }));
        });
      }
      // Shared scroll angle, eased per frame (transform only) — up and down.
      let rt = 0, rc = 0, rraf = null, rrun = false;
      // Mobile/tablet ring spins ~one full turn (2π) over a hero-height of scroll,
      // so all six tiles rotate through the visible top arc. (Desktop keeps the
      // gentler HERO_SWEEP.) Only the multiplier differs — orbit stays a circle.
      const RING_SWEEP = Math.PI * 2;
      const readS = () => {
        const h = (sectionRef.current && sectionRef.current.offsetHeight) || window.innerHeight;
        rt = Math.max(0, Math.min(1, window.scrollY / h)) * RING_SWEEP;
      };
      const rloop = () => {
        rc += (rt - rc) * 0.12;
        if (Math.abs(rt - rc) < 0.0002) { rc = rt; rrun = false; }
        placeRing(rc);
        if (rrun) rraf = requestAnimationFrame(rloop);
      };
      const rkick = () => { if (!rrun) { rrun = true; rraf = requestAnimationFrame(rloop); } };
      const onS = () => { readS(); rkick(); };
      const onR = () => { computeRing(); placeRing(rc); };
      readS(); rc = rt; placeRing(rc);
      if (!reducedM) window.addEventListener("scroll", onS, { passive: true });
      window.addEventListener("resize", onR);
      // Re-place the ring whenever the measured text height changes. The first
      // computeRing() runs before the web font loads; when it swaps in, the
      // heading/subtext reflow TALLER and the buttons drop — so a one-time
      // measurement leaves the top tile overlapping the buttons. ResizeObserver
      // (fires once on observe, after layout) + fonts.ready re-run onR, keeping
      // the top tile locked 24px below the ACTUAL button bottom.
      let ro = null;
      const innerNode = sectionRef.current && sectionRef.current.querySelector(".fa-hero__inner");
      if (window.ResizeObserver && innerNode) { ro = new ResizeObserver(onR); ro.observe(innerNode); }
      if (document.fonts && document.fonts.ready) document.fonts.ready.then(onR);
      return () => {
        if (!reducedM) window.removeEventListener("scroll", onS);
        window.removeEventListener("resize", onR);
        if (ro) ro.disconnect();
        if (rraf) cancelAnimationFrame(rraf);
      };
    }

    const reduced = window.FAReveal && window.FAReveal.reduced;
    if (reduced) {
      els.forEach((el) => { el.style.opacity = "1"; });
      const onR = () => { computeLayout(); place(0); };
      window.addEventListener("resize", onR);
      return () => window.removeEventListener("resize", onR);
    }

    // ---- Scroll-driven oval orbit (gated ON only after the intro burst) ----
    let target = 0, current = 0, raf = null, running = false, orbitOn = false;
    const readScroll = () => {
      const hero = sectionRef.current;
      const h = (hero && hero.offsetHeight) || window.innerHeight;
      target = Math.max(0, Math.min(1, window.scrollY / h)) * HERO_SWEEP * 1.5;   // desktop: 1.5× scroll-to-rotation speed (mobile/tablet use RING_SWEEP)
    };
    const setWC = (v) => { for (let i = 0; i < els.length; i++) els[i].style.willChange = v; };
    const loop = () => {
      current += (target - current) * 0.12;
      if (Math.abs(target - current) < 0.0002) { current = target; running = false; }
      place(current);
      if (running) raf = requestAnimationFrame(loop);
      else setWC("auto");                       // orbit settled → drop the GPU hint (no idle memory cost)
    };
    const kick = () => { if (orbitOn && !running) { running = true; setWC("transform"); raf = requestAnimationFrame(loop); } };
    const onScroll = () => { readScroll(); kick(); };
    const onResize = () => { computeLayout(); if (orbitOn) { readScroll(); place(current); kick(); } };

    // ---- One-time intro: all six tiles burst out from the centre together ----
    const INTRO_DUR = 850;      // ms of travel (all six tiles move together)
    const easeOut = (p) => 1 - Math.pow(1 - p, 3);
    els.forEach((el) => { el.style.transition = "none"; el.style.willChange = "transform, opacity"; });   // rAF owns transform+opacity; promote each tile to its own GPU layer for the intro
    HERO_TILES.forEach((t, i) => {
      els[i].style.opacity = "0";
      els[i].style.transform = "translate(" + (CX - t.w / 2) + "px, " + (HERO_CY - t.h / 2) + "px) scale(0.2)";
    });

    let introRaf = null, introStart = null;
    const introFrame = (ts) => {
      if (introStart === null) introStart = ts;
      const elapsed = ts - introStart;
      const p = Math.max(0, Math.min(1, elapsed / INTRO_DUR));
      const e = easeOut(p);
      const allDone = p >= 1;
      for (let i = 0; i < els.length; i++) {
        const t = HERO_TILES[i];
        const cx = CX + (rest[i].cx - CX) * e;
        const cy = HERO_CY + (rest[i].cy - HERO_CY) * e;
        const s = 0.2 + 0.8 * e;
        els[i].style.opacity = String(Math.min(1, p / 0.5));
        els[i].style.transform = "translate(" + (cx - t.w / 2) + "px, " + (cy - t.h / 2) + "px) scale(" + s + ")";
      }
      if (!allDone) {
        introRaf = requestAnimationFrame(introFrame);
      } else {
        introRaf = null;
        els.forEach((el) => { el.style.opacity = "1"; el.style.willChange = "auto"; });   // intro done — release the GPU layers
        orbitOn = true; current = 0;
        readScroll();
        window.addEventListener("scroll", onScroll, { passive: true });
        window.addEventListener("resize", onResize);
        kick();
      }
    };
    introRaf = requestAnimationFrame(introFrame);

    return () => {
      if (introRaf) cancelAnimationFrame(introRaf);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onResize);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <section id="hero" className="fa-hero" aria-label="Hero" data-header-theme="light" data-header-blend="true" ref={sectionRef}>
      <div className="fa-hero__stage" aria-hidden="true">
        {HERO_TILES.map((t, i) => (
          <div
            key={t.key}
            className="fa-hero__tile"
            ref={(el) => { tilesRef.current[i] = el; }}
            style={{ width: t.w, height: t.h }}
          >
            <img className="fa-hero__img" src={encodeURI(HERO_UPLOADS + activeSet[i])} alt="" width={t.w} height={t.h} loading="eager" decoding="async" />
          </div>
        ))}
      </div>
      <div className="fa-container fa-hero__inner">
        <div className="fa-hero__text">
          <span className="fa-eyebrow reveal" data-reveal-delay="0">Accounting &amp; advisory Australia</span>
          <h1 className="fa-h1 reveal" data-reveal-delay="100" style={{ maxWidth: 926 }}>
            Accounting and advisory for businesses with bigger plans
          </h1>
          <p className="fa-body reveal" data-reveal-delay="200" style={{ maxWidth: 720 }}>
            Clear numbers, proactive advice, and the confidence to make better decisions - from a team you actually like working with.
          </p>
          <div className="fa-hero__cta reveal" data-reveal-delay="300">
            <Button variant="primary" className="fa-btn-lift">Book a call</Button>
            <Button variant="outline" className="fa-btn-lift">View our services</Button>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------------- Empty section placeholder ---------------- */
function SectionShell({ id, label, theme = "light" }) {
  return (
    <section id={id} className="fa-section" aria-label={label + " (placeholder)"} data-header-theme={theme}>
      <div className="fa-container">
        <div className="fa-placeholder reveal">{id}</div>
      </div>
    </section>
  );
}

/* ---------------- Footer ---------------- */
/* Social icons — brand SVGs from the uploaded assets (viewBox 0 0 39.34 39.34).
   Rendered on the dark footer as a white disc (cls-1) with the ink glyph
   cut through it (cls-2). */
function SocialGlyph({ label, children }) {
  return (
    <a href="#" aria-label={label} className="fa-foot-link" style={{ display: "inline-flex" }}>
      <svg width="32" height="32" viewBox="0 0 39.3419928 39.3419869" style={{ display: "block" }} aria-hidden="true">
        {children}
      </svg>
    </a>
  );
}
const DISC = "M38.6399033,19.6710124c0,10.4762259-8.4926591,18.9688849-18.9688849,18.9688849h-.0000439C9.1947486,38.6398973.7020895,30.1472383.7020895,19.6710124v-.0000379C.7020895,9.1947486,9.1947486.7020895,19.6709745.7020895h.0000439c10.4762259,0,18.9688849,8.4926591,18.9688849,18.9688849v.0000379Z";
const INK = "#050E1E";

function FooterSocials() {
  return (
    <div style={{ display: "flex", gap: 16, paddingTop: 6 }}>
      <SocialGlyph label="Instagram">
        <path fill="#fff" d={DISC} />
        <path fill={INK} d="M24.8174729,9.7210076h-10.292953c-2.6521442,0-4.8033781,2.1512129-4.8033781,4.8033781v10.292953c0,2.6521442,2.1512339,4.8033781,4.8033781,4.8033781h10.292953c2.6521442,0,4.8033781-2.1512339,4.8033781-4.8033781v-10.292953c0-2.6521651-2.1512339-4.8033781-4.8033781-4.8033781ZM27.9053588,24.4742402c0,1.8938891-1.5370743,3.4309843-3.4309843,3.4309843h-9.6067561c-1.89391,0-3.4309843-1.5370952-3.4309843-3.4309843v-9.6067561c0-1.89391,1.5370743-3.4309843,3.4309843-3.4309843h9.6067561c1.89391,0,3.4309843,1.5370743,3.4309843,3.4309843v9.6067561Z" />
        <path fill={INK} d="M19.6807235,14.5243856c-2.8408651,0-5.1464765,2.3056114-5.1464765,5.1464765,0,2.8408441,2.3056114,5.1464765,5.1464765,5.1464765s5.1464765-2.3056324,5.1464765-5.1464765c0-2.8408651-2.3056114-5.1464765-5.1464765-5.1464765ZM19.6807235,23.1018465c-1.8904757,0-3.4309843-1.5405086-3.4309843-3.4309843s1.5405086-3.4309843,3.4309843-3.4309843,3.4309843,1.5405086,3.4309843,3.4309843-1.5405086,3.4309843-3.4309843,3.4309843Z" />
        <circle fill={INK} cx="25.1702984" cy="14.1812872" r="1.0292953" />
      </SocialGlyph>
      <SocialGlyph label="Facebook">
        <path fill="#fff" d={DISC} />
        <path fill={INK} d="M25.2911371,18.1994761l-.3160727,2.5373919c-.0531955.4243774-.4123349.7429784-.8379842.7429784h-4.1101162v10.6100492c-.433876.0392704-.8728203.0589055-1.3168329.0589055-.9925335,0-1.9622655-.0994439-2.8990635-.2881953v-10.3807595h-3.1612873c-.2900973,0-.5269875-.2381582-.5269875-.5288896v-3.1752241c0-.2907275.2368902-.5288857.5269875-.5288857h3.1612873v-4.7625191c0-2.9224989,2.3594073-5.2914049,5.2698715-5.2914049h3.688271c.2901012,0,.5269914.2381582.5269914.5288857v3.1752241c0,.2907313-.2368902.5288857-.5269914.5288857h-2.6349299c-1.1635517,0-2.1073161.9475647-2.1073161,2.1168186v3.7041098h4.4261811c.5079864,0,.9006977.4471788.8379919.9526291Z" />
      </SocialGlyph>
      <SocialGlyph label="LinkedIn">
        <path fill="#fff" d={DISC} />
        <circle fill={INK} cx="12.9523803" cy="12.1565846" r="2.4431331" />
        <rect fill={INK} x="10.916436" y="16.2284732" width="4.0718886" height="12.2156657" rx=".1819954" ry=".1819954" />
        <path fill={INK} d="M28.8327457,20.7075506v6.9222106c0,.4478978-.3664799.8143777-.8143777.8143777h-2.4431331c-.4478978,0-.8143777-.3664799-.8143777-.8143777v-5.700644c0-1.1238452-.9120991-2.0359443-2.0359443-2.0359443s-2.0359443.9120991-2.0359443,2.0359443v5.700644c0,.4478978-.3664799.8143777-.8143777.8143777h-2.4431331c-.4478978,0-.8143777-.3664799-.8143777-.8143777v-10.5869103c0-.4479227.3664799-.8143777.8143777-.8143777h2.4431331c.4478978,0,.8143777.3664551.8143777.8143777v.5211888c.8143777-1.0546052,2.1621718-1.7427554,3.6646997-1.7427554,2.2476904,0,4.4790774,1.6287554,4.4790774,4.8862663Z" />
      </SocialGlyph>
    </div>
  );
}

const FOOT_PARTNERS = [
  { name: "Xero — Platinum Partner", src: BASE + "assets/img/partners/xero.png", h: 52 },
  { name: "CPA Australia", src: BASE + "assets/img/partners/cpa.png", h: 52 },
  { name: "Trace", src: BASE + "assets/img/partners/trace.png", h: 60 },
  { name: "A2X — Bronze Partner", src: BASE + "assets/img/partners/a2x.png", h: 44 },
];

function Footer() {
  const [email, setEmail] = React.useState("");
  const cols = [
    ["Services", ["Accounting", "CFO", "Advisory", "Tax", "Payroll"]],
    ["Company", ["Our Team", "Case Studies", "Locations", "Careers", "About"]],
    ["Resources", ["Blog", "Podcast"]],
  ];
  const linkStyle = { font: "var(--fw-halbfett) 16px/1.2 var(--font-display)", letterSpacing: "-0.16px", color: "var(--fa-white)", textDecoration: "none" };
  const headStyle = { font: "400 16px/1.2 \"Epilogue\", var(--font-body)", color: "var(--fa-white)", opacity: 0.6, marginBottom: 6 };

  return (
    <footer id="footer" className="fa-footer" data-header-theme="dark" data-header-blend="true">
      <div className="fa-container" style={{ display: "flex", flexDirection: "column", gap: 40 }}>
        {/* 1. top row — white logo + newsletter */}
        <div className="reveal" style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 40, flexWrap: "wrap" }}>
          <a href="#top" className="fa-logo fa-logo--footer" aria-label="Future Advisory — home"
             style={{ color: "#FFFFFF" }}
             dangerouslySetInnerHTML={{ __html: window.FA_LOGO_SVG_MONO }} />
          <div style={{ width: 400, maxWidth: "100%", display: "flex", flexDirection: "column", gap: 16 }}>
            <label htmlFor="fa-nl" style={{ font: "var(--fw-halbfett) 20px/1.1 var(--font-display)", color: "var(--fa-white)" }}>
              Subscribe to our newsletter
            </label>
            <form
              onSubmit={(e) => { e.preventDefault(); /* subscribe wired later */ }}
              style={{ display: "flex", alignItems: "center", gap: 10, padding: "4px 4px 4px 12px", border: "1px solid rgba(255,255,255,0.2)" }}
            >
              <input id="fa-nl" className="fa-input" type="email" placeholder="Email"
                value={email} onChange={(e) => setEmail(e.target.value)} />
              <Button variant="yellow" size="sm" as="button" className="fa-btn-lift">
                Subscribe
              </Button>
            </form>
          </div>
        </div>

        <hr className="fa-divider" />

        {/* 3. link columns */}
        <div className="reveal fa-foot-cols" style={{ display: "flex", gap: 48, flexWrap: "wrap" }}>
          {cols.map(([title, links]) => (
            <nav key={title} aria-label={title} style={{ flex: "1 1 160px", display: "flex", flexDirection: "column", gap: 10 }}>
              <span style={headStyle}>{title}</span>
              {links.map((l) => <a key={l} href="#" className="fa-foot-link" style={linkStyle}>{l}</a>)}
            </nav>
          ))}
          <div style={{ flex: "1 1 200px", display: "flex", flexDirection: "column", gap: 10 }}>
            <span style={headStyle}>Contact info</span>
            <a href="tel:1300225888" className="fa-foot-link" style={linkStyle}>1300 225 888</a>
            <a href="mailto:hello@futureadvisory.com.au" className="fa-foot-link" style={linkStyle}>hello@futureadvisory.com.au</a>
            <FooterSocials />
          </div>
        </div>

        <hr className="fa-divider" />

        {/* 5. acknowledgement of country + certifications (two-column) */}
        <div className="reveal fa-foot-ack" style={{ display: "flex", rowGap: 40, columnGap: 40, alignItems: "flex-start", flexWrap: "wrap" }}>
          {/* LEFT — acknowledgement of country */}
          <div style={{ flex: "1 1 380px", minWidth: 0, maxWidth: 645, display: "flex", flexDirection: "column", gap: 32, alignItems: "flex-start" }}>
            <div style={{ display: "flex", flexDirection: "column", gap: 16, alignItems: "flex-start" }}>
              <img src={BASE + "assets/img/aboriginal-flag.svg"} alt="Aboriginal flag" width={37} height={24} style={{ display: "block", flexShrink: 0 }} />
              <span style={{ font: "400 14px/1.5 \"Epilogue\", var(--font-body)", color: "var(--fa-white)" }}>
                We live and work on the lands of the Wurundjeri people of the Kulin nation. We acknowledge their ownership of the land and pay respects to their elders past, present and future.
              </span>
            </div>
            <span style={{ font: "400 12px/1.4 \"Epilogue\", var(--font-body)", color: "var(--fa-white)", opacity: 0.6, letterSpacing: "-0.12px" }}>
              Liability Limited by a scheme approved under Professional Standards Legislation
            </span>
          </div>

          {/* RIGHT — certifications */}
          <div className="fa-foot-certs" style={{ flex: "0 1 555px", display: "flex", flexDirection: "column", gap: 20, alignItems: "flex-start" }}>
            <span style={{ font: "var(--fw-halbfett) 20px/1.2 var(--font-display)", letterSpacing: "-0.2px", color: "var(--fa-white)" }}>
              Our certifications
            </span>
            <div className="fa-foot-certs__grid" style={{ display: "flex", gap: 20, alignItems: "center", flexWrap: "wrap" }}>
              {FOOT_PARTNERS.map((p) => (
                <img key={p.name} src={p.src} alt={p.name} style={{ height: p.h, width: "auto", display: "block", flexShrink: 0 }} />
              ))}
            </div>
          </div>
        </div>

        <hr className="fa-divider" />

        {/* 7. bottom legal row */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 24, flexWrap: "wrap" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 24, flexWrap: "wrap" }}>
            <span style={{ font: "400 12px/1.4 \"Epilogue\", var(--font-body)", color: "var(--fa-white)", opacity: 0.6 }}>Copyright 2026 Future Advisory Pty Ltd.</span>
            <a href="#" className="fa-foot-link" style={{ font: "400 12px/1.4 \"Epilogue\", var(--font-body)", color: "var(--fa-white)", opacity: 0.6, textDecoration: "none" }}>Privacy Policy</a>
          </div>
          <span style={{ font: "400 12px/1.4 \"Epilogue\", var(--font-body)", color: "var(--fa-white)", opacity: 0.6 }}>Web &amp; SEO Melbourne by VEN</span>
        </div>
      </div>
    </footer>
  );
}

/* ---------------- Trust bar ---------------- */
/* Full-width purple band directly below the hero. Copy verbatim from Figma;
   yellow text, four items spaced with justify-between (no dividers). Bg spans
   the viewport; the row aligns to the 1400px content width. */
const TRUST_ITEMS = [
  "Director-led by Jason Robinson FCPA and Greg Bramich CPA",
  "A 28-strong team",
  "Xero-based cloud-first accounting",
  "As heard on The Numbers Game podcast",
];

function TrustBar() {
  return (
    <section id="trust-bar" className="fa-trustbar" data-header-theme="dark" aria-label="Trust bar">
      <div className="fa-container fa-trustbar__row reveal">
        <div className="fa-trustbar__track">
          {TRUST_ITEMS.map((t, i) => (
            <span className="fa-trustbar__item" key={"a" + i}>{t}</span>
          ))}
          {TRUST_ITEMS.map((t, i) => (
            <span className="fa-trustbar__item fa-trustbar__item--dup" key={"b" + i} aria-hidden="true">{t}</span>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------------- Social proof / logos ---------------- */
/* Light section. Copy verbatim from Figma; restyled to a light ground per
   brief (WHITE text). Real client logos rendered WHITE via CSS mask (the mask
   uses each PNG's alpha, so any source colour becomes solid white — matching
   the Figma, which masks + fills each logo white). */
const LOGO_H = 60;        // uniform render height (new source logos are all 900px tall)
const PROOF_LOGOS = [
  { name: "Threadheads",       file: "threadheads.png",       ar: 2.767 },
  { name: "Capital",           file: "capital.png",           ar: 4.057 },
  { name: "Salt Lab",          file: "salt-lab.png",          ar: 2.113 },
  { name: "Indigenous Wealth", file: "indigenous-wealth.png", ar: 2.49 },
  { name: "Soak",              file: "soak.png",              ar: 1.307 },
  { name: "2M Creative",       file: "2m-creative.png",       ar: 0.823 },
  { name: "WLKR Digital",      file: "wlkr-digital.png",      ar: 1.797 },
];

function ProofLogo({ name, file, ar }) {
  const w = Math.round(LOGO_H * ar);  // width auto from the uniform-height source
  const url = "url(" + BASE + "assets/img/logos/" + file + ")";
  return (
    <div className="fa-logo-item">
      <span className="fa-logo-item__mark" role="img" aria-label={name}
            style={{ width: w, height: LOGO_H, WebkitMaskImage: url, maskImage: url }} />
    </div>
  );
}

function ProofStar() {
  return (
    <svg className="fa-star" width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <path d="M12 2L14.2451 8.90983H21.5106L15.6327 13.1803L17.8779 20.0902L12 15.8197L6.12215 20.0902L8.36729 13.1803L2.48944 8.90983H9.75486L12 2Z" fill="var(--fa-yellow)" />
    </svg>
  );
}

function SocialProof() {
  const trackRef = React.useRef(null);
  const sectionRef = React.useRef(null);
  const headRef = React.useRef(null);
  const marqueeRef = React.useRef(null);
  const ctaRef = React.useRef(null);

  // Simple staggered reveal: ONE IntersectionObserver fires once when the section
  // enters view, then reveals content on a timer — title + rating immediately,
  // logos + button 400ms later (which also starts the marquee). Elements carry
  // .reveal for the base hidden style + data-reveal-bound so the global reveal
  // utility skips them; this component controls their timing.
  React.useEffect(() => {
    const head = headRef.current, marquee = marqueeRef.current, cta = ctaRef.current, section = sectionRef.current;
    if (!section) return;
    const reduced = window.FAReveal && window.FAReveal.reduced;
    if (reduced || !("IntersectionObserver" in window)) {
      [head, marquee, cta].forEach((el) => el && el.classList.add("is-visible"));
      return; // reduced motion: shown immediately; marquee movement stays off via CSS
    }
    const timers = [];
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (!e.isIntersecting) return;
        io.disconnect();                                     // reveal once
        head && head.classList.add("is-visible");            // step 1: title + rating (immediate)
        timers.push(setTimeout(() => {                       // step 2: logos + button, 400ms later
          marquee && marquee.classList.add("is-visible");    // (also starts the marquee auto-scroll)
          cta && cta.classList.add("is-visible");
        }, 400));
      });
    }, { threshold: 0.2 });
    io.observe(section);
    return () => { io.disconnect(); timers.forEach(clearTimeout); };
  }, []);

  // Seamless marquee: shift left by exactly the offset of the 2nd copy's first
  // item (= width of one set + its gaps), so the loop is invisible. Duration is
  // derived from that distance for a constant, gentle drift regardless of width.
  React.useEffect(() => {
    const track = trackRef.current;
    if (!track) return;
    const SPEED = 40; // px / second — slow, elegant
    const compute = () => {
      const kids = track.children;
      if (kids.length < PROOF_LOGOS.length + 1) return;
      const shift = kids[PROOF_LOGOS.length].offsetLeft; // start of the 2nd set
      if (!shift) return;
      track.style.setProperty("--fa-marquee-shift", "-" + shift + "px");
      track.style.setProperty("--fa-marquee-dur", (shift / SPEED) + "s");
    };
    compute();
    window.addEventListener("resize", compute);
    // Recompute once mask images decode (widths are fixed, but be safe).
    requestAnimationFrame(compute);
    return () => window.removeEventListener("resize", compute);
  }, []);

  return (
    <section id="logos" className="fa-social" data-header-theme="dark" data-header-blend="true" aria-label="Social proof" ref={sectionRef}>
      <div className="fa-container fa-social__wrap">
        <div className="fa-social__head reveal" data-reveal-bound="" ref={headRef}>
          <h2 className="fa-social__title">Trusted by established Australian businesses in e-commerce and professional services</h2>
          <div className="fa-social__rating">
            <span className="fa-social__score">4.9 out of 5</span>
            <ProofStar />
            <span className="fa-social__muted">Rated by 30 reviewers on Google</span>
          </div>
        </div>

        <div className="fa-marquee reveal" data-reveal-bound="" ref={marqueeRef} aria-label="Client logos">
          <div className="fa-marquee__track" ref={trackRef}>
            {PROOF_LOGOS.map((l, i) => <ProofLogo key={"a" + i} {...l} />)}
            {PROOF_LOGOS.map((l, i) => <ProofLogo key={"b" + i} {...l} />)}
          </div>
        </div>

        <div className="fa-social__cta reveal" data-reveal-bound="" ref={ctaRef}>
          <Button variant="outline-on-dark" className="fa-btn-lift">Explore case study</Button>
        </div>
      </div>
    </section>
  );
}

/* ---------------- Problem & pricing ---------------- */
/* Dark section (flat #050E1E, no stripes). Comparison table via the DS
   ComparisonRow (label + "Reactive" cell + highlighted purple FA column),
   header row carries the yellow logo lockup; then a flat-yellow pricing teaser
   with the highlighter mark behind the price. Copy verbatim from Figma.
   $800 is an UNCONFIRMED placeholder. */
const PP_ROWS = [
  "Regular reporting and check-ins",
  "Advice before decisions not after",
  "A senior contact who knows your business",
  "Pricing you can see before you call",
  "Year-round, not once-a-year",
];

function ProblemPricing() {
  return (
    <section id="problem-pricing" className="fa-pp" data-header-theme="dark" data-header-blend="true" aria-label="Problem and pricing">
      <div className="fa-container fa-pp__wrap">
        <h2 className="fa-pp__title reveal" data-reveal-delay="0">
          Most accountants tell you what happened.<br />We help you decide what is next.
        </h2>

        <div className="fa-pp__table fa-pp__table--desktop">
          <ComparisonRow
            height={80}
            highlight="#5A3AF5"
            className="reveal"
            data-reveal-delay="100"
            otherContent={<span className="fa-pp__colhead">Reactive</span>}
            faContent={<span className="fa-pp__glogo" aria-label="Future Advisory" dangerouslySetInnerHTML={{ __html: PP_LOGO_SVG }} />}
          />
          {PP_ROWS.map((r, i) => (
            <ComparisonRow
              key={i}
              label={r}
              other={false}
              fa={true}
              highlight="#5A3AF5"
              className="reveal"
              data-reveal-delay={180 + i * 80}
            />
          ))}
        </div>
        <div className="fa-pp__grid reveal" data-reveal-delay="100">
          <div className="fa-pp__gcell fa-pp__ghead"></div>
          <div className="fa-pp__gcell fa-pp__ghead"><span className="fa-pp__colhead">Reactive</span></div>
          <div className="fa-pp__gcell fa-pp__ghead fa-pp__gfa"><span className="fa-pp__glogo" aria-label="Future Advisory" dangerouslySetInnerHTML={{ __html: PP_LOGO_SVG }} /></div>
          {PP_ROWS.map((r, i) => (
            <React.Fragment key={i}>
              <div className="fa-pp__gcell fa-pp__glabel">{r}</div>
              <div className="fa-pp__gcell"><span className="fa-pp__badge fa-pp__badge--no"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M6 6L18 18M18 6L6 18" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" /></svg></span></div>
              <div className="fa-pp__gcell fa-pp__gfa"><span className="fa-pp__badge fa-pp__badge--yes"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M5 12.5L10 17.5L19 7" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" /></svg></span></div>
            </React.Fragment>
          ))}
        </div>

        <div className="fa-pp__pricing reveal" data-reveal-delay="200">
          <h3 className="fa-pp__pricing-title">We publish our pricing</h3>
          <div className="fa-pp__price">
            <span className="fa-pp__price-hl" aria-hidden="true">
              <svg viewBox="0 0 537 180" width="537" height="180" fill="none">
                <path d="M 275.644 18.407 L 274.788 23.219 L 339.765 28.011 L 338.102 36.516 L 357.329 41.197 L 371.098 24.654 L 423.218 43.988 L 438.804 19.329 L 537 34.217 L 528.44 154.248 L 465.792 152.258 L 451.065 175.562 L 352.939 159.893 L 353.765 152.08 L 336.417 148.105 L 307.428 180 L 213 157.881 L 214.257 151.447 L 189.378 146.274 L 168.19 176.688 L 70.708 161.222 L 71.803 138 L 0 111.622 L 64.097 11.807 L 142.783 51.256 L 178.493 0 L 275.644 18.407 Z" fill="currentColor" fillRule="nonzero" />
              </svg>
            </span>
            <span className="fa-pp__price-text">
              <span className="fa-pp__from">From </span>
              <span className="fa-pp__amt">$800</span>
              <span className="fa-pp__per">/per month</span>
            </span>
          </div>
          <button type="button" className="fa-pp__price-btn fa-btn-lift">See our pricing</button>
        </div>
      </div>
    </section>
  );
}

/* ---------------- Industries ---------------- */
/* Light section (flat #F2F2F2, no stripes). Two equal cards: purple
   E-commerce + near-black Professional Services. Each is a title/desc/
   "Learn more" block over a 300px image band where a coloured zigzag
   (Vector 138) sits behind a cut-out client photo. */
function IndArrow() {
  return (
    <svg className="fa-ind__learn-icon" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path d="M2 8L13.1429 8" stroke="currentColor" strokeWidth="1.5" />
      <path d="M8 14L14 8L8 2" stroke="currentColor" strokeWidth="1.5" />
    </svg>
  );
}

const IND_CARDS = [
  {
    id: "ecommerce",
    background: "#5939F5",
    zig: "var(--fa-yellow)",
    title: "E-commerce",
    desc: "Scale with integrated inventory and cross-border tax advice.",
    image: "../assets/img/industry-ecommerce.png",
  },
  {
    id: "proservices",
    background: "#050E1E",
    zig: "var(--fa-green)",
    title: "Professional Services",
    desc: "Consultancies and agencies ready for profitable growth.",
    image: "../assets/img/industry-proservices.png",
  },
  {
    id: "trade",
    background: "#50DDA4",
    zig: "var(--fa-purple)",
    ink: true,
    title: "Trade & Construction",
    desc: "Built for trade and construction businesses ready to grow.",
    image: "../uploads/Image-Trade-Construction.png",
  },
  {
    id: "tradies",
    background: "#FBEB4F",
    zig: "var(--fa-ink)",
    ink: true,
    title: "Tradies",
    desc: "Straightforward tax and accounting support for busy tradies.",
    image: "../uploads/Image-Tradies.png",
  },
];

function Industries() {
  return (
    <section id="industries" className="fa-ind" data-header-theme="light" data-header-blend="true">
      <div className="fa-container fa-ind__wrap">
        <h2 className="fa-ind__title reveal">We know your kind of business</h2>
        <div className="fa-ind__row">
          {IND_CARDS.map((c, i) => (
            <article
              key={c.id}
              className={"fa-ind__card reveal" + (c.ink ? " fa-ind__card--ink" : "")}
              data-reveal-delay={120 + i * 120}
              style={{ background: c.background }}
            >
              <div className="fa-ind__head">
                <h3 className="fa-ind__ctitle">{c.title}</h3>
                <div className="fa-ind__col">
                  <p className="fa-ind__desc">{c.desc}</p>
                  <a className="fa-ind__learn" href="#">
                    <span>Learn more</span>
                    <span className="fa-ind__learn-btn"><IndArrow /></span>
                  </a>
                </div>
              </div>
              <div className="fa-ind__media">
                {c.image
                  ? <img className="fa-ind__photo" src={c.image} alt="" aria-hidden="true" />
                  : <div className="fa-ind__ph" aria-hidden="true"><span className="fa-ind__ph-label">{c.title} photo — to be provided</span></div>}
              </div>
            </article>
          ))}
        </div>
        <div className="fa-ind__cta reveal" data-reveal-delay="360">
          <Button as="a" href="#" variant="primary" className="fa-btn-lift">View all industries</Button>
        </div>
      </div>
    </section>
  );
}

/* ---------------- Proof / case studies ---------------- */
/* Light section (white). Centered heading → featured testimonial band
   (mint #50DDA4) → row of 3 case-study cards. Client names, the 2M logo,
   the person, the quote, images and video are ALL Figma placeholders —
   kept verbatim, not final. */
function Chevron({ dir = "next" }) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"
         style={{ transform: dir === "prev" ? "scaleX(-1)" : "none" }}>
      <path d="M6 3L11 8L6 13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function ProofArrow() {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path d="M2 8L13.1429 8" stroke="currentColor" strokeWidth="1.5" />
      <path d="M8 14L14 8L8 2" stroke="currentColor" strokeWidth="1.5" />
    </svg>
  );
}

/* Carousel of featured testimonials. One placeholder slide for now; the
   structure supports more — prev/next are inert (disabled) at a single slide. */
const PROOF_TESTIMONIALS = [
  {
    eyebrow: "Financial Planning",
    quote: "2M Creative is a Melbourne based design practice known for delivering creative, detailed and high-quality solutions.",
    logo: BASE + "assets/img/client-2m.png",
    name: "Name",
    role: "CEO at [company]",
    media: BASE + "assets/img/video-thumb.png",
  },
];

const PROOF_CASES = [
  { title: "Threadheads", desc: "2M Creative is a Melbourne based design practice known for delivering creative, detailed and high-quality solutions.", image: BASE + "assets/img/casestudy.png" },
  { title: "Threadheads", desc: "2M Creative is a Melbourne based design practice known for delivering creative, detailed and high-quality solutions.", image: BASE + "assets/img/casestudy-2.png" },
  { title: "Threadheads", desc: "2M Creative is a Melbourne based design practice known for delivering creative, detailed and high-quality solutions.", image: BASE + "assets/img/casestudy-3.png" },
];

function Proof() {
  const [i, setI] = React.useState(0);
  const count = PROOF_TESTIMONIALS.length;
  const t = PROOF_TESTIMONIALS[i];
  const prev = () => setI((n) => (n - 1 + count) % count);
  const next = () => setI((n) => (n + 1) % count);
  const single = count < 2;
  const cardsRef = React.useRef(null);
  const [activeCard, setActiveCard] = React.useState(0);
  React.useEffect(() => {
    const tr = cardsRef.current;
    if (!tr) return;
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const kids = Array.from(tr.children);
        const sl = tr.scrollLeft;
        let best = 0, bestD = Infinity;
        kids.forEach((k, idx) => {
          const d = Math.abs((k.offsetLeft - tr.offsetLeft) - sl);
          if (d < bestD) { bestD = d; best = idx; }
        });
        setActiveCard(best);
      });
    };
    tr.addEventListener("scroll", onScroll, { passive: true });
    return () => { tr.removeEventListener("scroll", onScroll); cancelAnimationFrame(raf); };
  }, []);

  return (
    <section id="proof" className="fa-proof" data-header-theme="light" data-header-blend="true">
      <div className="fa-container fa-proof__wrap">
        <h2 className="fa-proof__title reveal">Real businesses. Real numbers. Real results.</h2>

        <div className="fa-proof__feature reveal" data-reveal-delay="120">
          <div className="fa-proof__content">
            <p className="fa-proof__eyebrow">{t.eyebrow}</p>
            <div className="fa-proof__lower">
              <blockquote className="fa-proof__quote">{t.quote}</blockquote>
              <div className="fa-proof__attrib">
                <img className="fa-proof__clogo" src={t.logo} alt="" aria-hidden="true" />
                <span className="fa-proof__divider" />
                <span className="fa-proof__name-block">
                  <span className="fa-proof__name">{t.name}</span>
                  <span className="fa-proof__role">{t.role}</span>
                </span>
              </div>
              <div className="fa-proof__nav">
                <button type="button" className="fa-proof__navbtn" aria-label="Previous testimonial"
                        onClick={prev} disabled={single}><Chevron dir="prev" /></button>
                <button type="button" className="fa-proof__navbtn" aria-label="Next testimonial"
                        onClick={next} disabled={single}><Chevron dir="next" /></button>
              </div>
            </div>
          </div>
          <div className="fa-proof__media">
            <img src={t.media} alt="" aria-hidden="true" />
            <button type="button" className="fa-proof__play" aria-label="Play video case study">
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
                <path d="M8 5.5L18 12L8 18.5V5.5Z" fill="#5939F5" />
              </svg>
            </button>
          </div>
        </div>

        <div className="fa-proof__cards" ref={cardsRef}>
          {PROOF_CASES.map((c, idx) => (
            <a key={idx} className="fa-proof__card reveal" data-reveal-delay={240 + idx * 120} href="#">
              <div className="fa-proof__thumb">
                <img src={c.image} alt="" aria-hidden="true" />
              </div>
              <div className="fa-proof__ctext">
                <h3 className="fa-proof__ctitle">{c.title}</h3>
                <p className="fa-proof__cdesc">{c.desc}</p>
                <span className="fa-proof__cta">
                  <span className="fa-proof__cta-label">View case study</span>
                  <span className="fa-proof__cta-btn"><ProofArrow /></span>
                </span>
              </div>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------------- Final CTA ---------------- */
/* Split purple #5939F5 band: left = looping image cluster (4 layers pop in in
   order, hold, all disappear together, repeat) with a "Meet our team" mint
   circle that appears on hover while the loop keeps running; right = heading /
   subhead / yellow "Book a call". Copy verbatim. Cluster assets + positions
   are the Figma files/coords supplied by the user (node 179:27680). */
function FinalCTA() {
  const leftRef = React.useRef(null);
  const circleRef = React.useRef(null);
  const [active, setActive] = React.useState(false);
  // target (cursor) and current (eased) positions, in px relative to the panel
  const target = React.useRef({ x: 0, y: 0 });
  const pos = React.useRef({ x: 0, y: 0 });
  const raf = React.useRef(null);
  const R = 94; // half of the 188px circle

  React.useEffect(() => {
    const tick = () => {
      pos.current.x += (target.current.x - pos.current.x) * 0.18;
      pos.current.y += (target.current.y - pos.current.y) * 0.18;
      const c = circleRef.current;
      if (c) c.style.transform = `translate(${pos.current.x}px, ${pos.current.y}px) translate(-50%, -50%)`;
      raf.current = requestAnimationFrame(tick);
    };
    raf.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf.current);
  }, []);

  const onMove = (e) => {
    const el = leftRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    // clamp the centre so the circle never spills past the panel edges
    const x = Math.max(R, Math.min(r.width - R, e.clientX - r.left));
    const y = Math.max(R, Math.min(r.height - R, e.clientY - r.top));
    target.current = { x, y };
  };

  const onEnter = (e) => {
    // seed both target and current at the entry point so it doesn't glide in from a corner
    const el = leftRef.current;
    if (el) {
      const r = el.getBoundingClientRect();
      const x = Math.max(R, Math.min(r.width - R, e.clientX - r.left));
      const y = Math.max(R, Math.min(r.height - R, e.clientY - r.top));
      target.current = { x, y };
      pos.current = { x, y };
    }
    setActive(true);
  };

  return (
    <section id="final-cta" className="fa-finalcta" data-header-theme="dark" data-header-blend="true" aria-label="Book a call">
      {/* LEFT — image cluster */}
      <div
        className="fa-finalcta__half fa-finalcta__left"
        ref={leftRef}
        onMouseEnter={onEnter}
        onMouseMove={onMove}
        onMouseLeave={() => setActive(false)}
      >
        <div className="fa-finalcta__cluster" aria-hidden="true">
          {/* 1. black block (CSS) */}
          <div className="fa-finalcta__layer fa-finalcta__l1"></div>
          {/* 2. yellow accent (Vector 138) */}
          <div className="fa-finalcta__layer fa-finalcta__l2">
            <img src={BASE + "assets/img/cta-accent.png"} alt="" />
          </div>
          {/* 3. large team photo (Subtract mask) */}
          <div className="fa-finalcta__layer fa-finalcta__l3">
            <img src={BASE + "assets/img/cta-large.png"} alt="" />
          </div>
          {/* 4. small b&w photo */}
          <div className="fa-finalcta__layer fa-finalcta__l4">
            <img src={BASE + "assets/img/cta-small.png"} alt="" />
          </div>
        </div>
        <button
          type="button"
          ref={circleRef}
          className={"fa-finalcta__team" + (active ? " is-active" : "")}
        >
          Meet our team
        </button>
      </div>

      {/* RIGHT — text */}
      <div className="fa-finalcta__half fa-finalcta__right">
        <h2 className="fa-finalcta__title reveal" data-reveal-delay="0">
          Ready for accounting that keeps up with your business
        </h2>
        <p className="fa-finalcta__sub reveal" data-reveal-delay="120">
          Book a no-obligation call and see if we are the right fit.
        </p>
        <div className="fa-finalcta__ctas reveal" data-reveal-delay="240">
          <button type="button" className="fa-btn fa-btn--primary fa-finalcta__btn">
            Book a call
          </button>
          <button type="button" className="fa-finalcta__btn2">
            Meet our team
          </button>
        </div>
      </div>
    </section>
  );
}

/* ---------------- App shell ---------------- */
const SECTIONS = [
  ["trust-bar", "Trust bar"],
  ["logos", "Social proof — logos"],
  ["services", "Our services"],
  ["problem-pricing", "Problem & pricing"],
  ["industries", "Industries"],
  ["proof", "Proof — case studies"],
  ["final-cta", "Final CTA"],
];

function App() {
  useReveal();
  return (
    <div className="fa-page" id="top">
      <Header />
      <main>
        <Hero />
        {SECTIONS.map(([id, label]) => id === "logos"
          ? <SocialProof key={id} />
          : id === "trust-bar"
          ? <TrustBar key={id} />
          : id === "services"
          ? <window.ServicesSection key={id} />
          : id === "problem-pricing"
          ? <ProblemPricing key={id} />
          : id === "industries"
          ? <Industries key={id} />
          : id === "proof"
          ? <Proof key={id} />
          : id === "final-cta"
          ? <FinalCTA key={id} />
          : <SectionShell key={id} id={id} label={label} />)}
      </main>
      <Footer />
    </div>
  );
}

/* Mount into the homepage's own container. The compiled bundle also ships a
   self-executing copy of this file that runs BEFORE the bundle assigns its
   component namespace — so at that point the destructured DS components are
   still undefined. Only mount once the components are actually available
   (true for the live <script>, which runs after the bundle finishes); the
   bundle's premature copy no-ops. Reuse one root so there's never a second
   createRoot on the same node. */
const faHomeRoot = document.getElementById("fa-home-app");
if (faHomeRoot && Button && MenuItem && ImageTile && LogoMark) {
  if (!faHomeRoot.__faRoot) faHomeRoot.__faRoot = ReactDOM.createRoot(faHomeRoot);
  faHomeRoot.__faRoot.render(<App />);
}
