/* global React, ReactDOM */
const { useState, useEffect, createContext, useContext } = React;

const CONTENT_URL = (typeof window !== "undefined" && window.__FF_CONTENT_URL) || "content/site.json";
const ContentContext = createContext(null);
const useContent = () => useContext(ContentContext);

// ---------- Placeholder image helper ----------
function Placeholder({ label, ratio = "16/9", tone = "navy", className = "", children }) {
  const palettes = {
    navy:  { bg: "#0f2a3d", stripe: "#12354B", ink: "#c9d6df" },
    dust:  { bg: "#d9cbb3", stripe: "#c7b79a", ink: "#4a3f2a" },
    red:   { bg: "#8a1b1b", stripe: "#a12020", ink: "#f6d6d6" },
    paddock:{ bg: "#4a5a2f", stripe: "#3e4d27", ink: "#e5ecd1" },
    sky:   { bg: "#7a92a3", stripe: "#6a8395", ink: "#e9eff3" },
  };
  const p = palettes[tone] || palettes.navy;
  return (
    <div
      className={`ff-ph ${className}`}
      style={{
        aspectRatio: ratio,
        background: `repeating-linear-gradient(135deg, ${p.bg} 0 18px, ${p.stripe} 18px 36px)`,
        color: p.ink,
      }}
    >
      <div className="ff-ph-inner">
        <span className="ff-ph-dot" />
        <span className="ff-ph-label">{label}</span>
      </div>
      {children}
    </div>
  );
}

const html = (s) => ({ __html: s });

// ---------- Ad attribution capture ----------
// Captures click ids and UTM params from the landing URL (META, Google,
// TikTok, etc.) and keeps them in sessionStorage so they ride along with
// every form submission to the Nucleus receiver.
const FF_ATTR_KEY = "ff_attribution";
const FF_ATTR_PARAMS = [
  "utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term",
  "fbclid", "gclid", "ttclid", "li_fat_id", "msclkid", "twclid", "sccid",
  "ad_id", "adset_id", "campaign_id", "placement", "ref"
];
function captureAttribution() {
  if (typeof window === "undefined") return {};
  let stored = {};
  try { stored = JSON.parse(sessionStorage.getItem(FF_ATTR_KEY) || "{}"); } catch {}
  const url = new URL(window.location.href);
  const fresh = {};
  FF_ATTR_PARAMS.forEach(k => {
    const v = url.searchParams.get(k);
    if (v) fresh[k] = v;
  });
  if (Object.keys(fresh).length > 0) {
    fresh.landing_url = window.location.href;
    fresh.landing_referrer = document.referrer || "";
    fresh.landing_at = new Date().toISOString();
    try { sessionStorage.setItem(FF_ATTR_KEY, JSON.stringify(fresh)); } catch {}
    return fresh;
  }
  return stored;
}
function getAttribution() {
  if (typeof window === "undefined") return {};
  try { return JSON.parse(sessionStorage.getItem(FF_ATTR_KEY) || "{}"); } catch { return {}; }
}

// ---------- Top banner ----------
function TopBanner() {
  const c = useContent().topBanner;
  if (!c.enabled) return null;
  return (
    <div className="ff-topbanner">
      <div className="ff-wrap ff-topbanner-inner">
        <span className="ff-topbanner-pulse" />
        <span><strong>{c.boldText}</strong> {c.text}</span>
        <a href={c.linkHref} className="ff-topbanner-link">{c.linkText}</a>
      </div>
    </div>
  );
}

// ---------- Navigation ----------
function Nav({ onDonate }) {
  const c = useContent().nav;
  const [open, setOpen] = useState(false);
  const [scrolled, setScrolled] = useState(false);
  const [openMenu, setOpenMenu] = useState(null);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  useEffect(() => {
    if (!openMenu) return;
    const close = (e) => {
      if (!e.target.closest(".ff-nav-list")) setOpenMenu(null);
    };
    window.addEventListener("click", close);
    return () => window.removeEventListener("click", close);
  }, [openMenu]);
  const logoSrc = window.location.pathname.split("/").length > 2 ? "../assets/logo.png" : "assets/logo.png";
  const homeHref = "/";
  return (
    <nav className={`ff-nav ${scrolled ? "is-scrolled" : ""}`}>
      <div className="ff-wrap ff-nav-inner">
        <a href={homeHref} className="ff-logo" aria-label="Farmers Fightback home">
          <img src={logoSrc} alt="Farmers Fightback" />
        </a>
        <ul className="ff-nav-list">
          {c.items.map((i) => (
            <li key={i.label} className={`ff-nav-item ${i.children ? "has-children" : ""} ${openMenu === i.label ? "is-open" : ""}`}>
              {i.children ? (
                <>
                  <button
                    type="button"
                    className={`ff-nav-trigger ${i.active ? "is-active" : ""}`}
                    aria-haspopup="true"
                    aria-expanded={openMenu === i.label}
                    onClick={(e) => { e.stopPropagation(); setOpenMenu(openMenu === i.label ? null : i.label); }}
                  >
                    {i.label} <span className="ff-nav-caret" aria-hidden="true">▾</span>
                  </button>
                  <ul className="ff-nav-dropdown" role="menu">
                    {i.children.map((c2) => (
                      <li key={c2.label} role="none">
                        {c2.disabled
                          ? <span className="is-disabled" role="menuitem" aria-disabled="true" title="Paused">{c2.label}</span>
                          : <a href={c2.href} role="menuitem">{c2.label}</a>}
                      </li>
                    ))}
                  </ul>
                </>
              ) : (
                <a href={i.href} className={i.active ? "is-active" : ""}>{i.label}</a>
              )}
            </li>
          ))}
        </ul>
        <div className="ff-nav-actions">
          <button className="ff-btn ff-btn--red" onClick={onDonate}>{c.donateLabel}</button>
          <button
            className="ff-hamburger"
            aria-label="Open menu"
            aria-expanded={open}
            onClick={() => setOpen(v => !v)}
          >
            <span /><span /><span />
          </button>
        </div>
      </div>
      {open && (
        <div className="ff-mobile-menu">
          {c.items.flatMap((i) => i.children
            ? [
                <a key={i.label} href={i.href} className="is-parent" onClick={() => setOpen(false)}>{i.label}</a>,
                ...i.children.map((c2) => (
                  c2.disabled
                    ? <span key={i.label + c2.label} className="is-child is-disabled" aria-disabled="true">↳ {c2.label}</span>
                    : <a key={i.label + c2.label} href={c2.href} className="is-child" onClick={() => setOpen(false)}>↳ {c2.label}</a>
                ))
              ]
            : [<a key={i.label} href={i.href} onClick={() => setOpen(false)}>{i.label}</a>]
          )}
        </div>
      )}
    </nav>
  );
}

// ---------- Hero ----------
function Hero({ onWatch }) {
  const c = useContent().hero;
  return (
    <section id="home" className="ff-hero ff-hero--cinematic">
      {c.videoUrl ? (
        <video
          className="ff-hero-bg"
          autoPlay muted loop playsInline preload="metadata" aria-hidden="true"
          key={c.videoUrl}
          poster={c.heroImage || undefined}
        >
          <source src={c.videoUrl} type="video/mp4" />
        </video>
      ) : c.heroImage ? (
        <img className="ff-hero-bg" src={c.heroImage} alt="" aria-hidden="true" />
      ) : null}
      <div className="ff-hero-scrim" />
      <div className="ff-wrap ff-hero-content">
        <h1 className="ff-hero-title" dangerouslySetInnerHTML={html(c.titleHtml)} />
        <p className="ff-hero-sub">{c.subtitle}</p>
        <div className="ff-hero-cta">
          <a href={c.primaryCtaHref} className="ff-btn ff-btn--red ff-btn--lg">{c.primaryCtaLabel}</a>
        </div>
      </div>
      <button className="ff-hero-scroll" aria-label="Scroll to story" onClick={() => window.scrollTo({ top: window.innerHeight * 0.9, behavior: 'smooth' })}>
        <span>Scroll</span>
        <span className="ff-hero-scroll-line" />
      </button>
    </section>
  );
}

// ---------- Impact counter bar ----------
function useCountUp(target, duration = 1400) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    let raf;
    const start = performance.now();
    const tick = (t) => {
      const k = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - k, 3);
      setVal(Math.round(target * eased));
      if (k < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, duration]);
  return val;
}

function ImpactBar() {
  const stats = useContent().impactStats;
  return (
    <section className="ff-impact">
      <div className="ff-wrap ff-impact-inner">
        {stats.map((s, i) => <ImpactStat key={i} {...s} />)}
      </div>
    </section>
  );
}

function ImpactStat({ value, label, suffix, grow }) {
  const n = useCountUp(value);
  return (
    <div className="ff-impact-stat">
      <div className="ff-impact-num">{n.toLocaleString()}{suffix}</div>
      <div className="ff-impact-label">{label}</div>
      <div className="ff-impact-grow">{grow}</div>
    </div>
  );
}

// ---------- Intro video ----------
function IntroVideo() {
  const c = useContent().intro;
  return (
    <section className="ff-section ff-intro">
      <div className="ff-wrap ff-intro-inner">
        <div className="ff-intro-copy">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2">{c.heading}</h2>
          <p className="ff-lede">{c.lede}</p>
        </div>
        <div className="ff-intro-player">
          <video controls playsInline muted loop autoPlay preload="metadata" key={c.videoUrl}>
            <source src={c.videoUrl} type="video/mp4" />
            Your browser doesn't support embedded video.
          </video>
        </div>
      </div>
    </section>
  );
}

// ---------- Latest video ----------
function LatestVideo({ onOpen }) {
  const c = useContent().latestVideo;
  const [playing, setPlaying] = useState(false);
  return (
    <section id="evidence" className="ff-section ff-video">
      <div className="ff-wrap ff-video-inner">
        <div className="ff-video-copy">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2" dangerouslySetInnerHTML={html(c.headingHtml)} />
          <p className="ff-lede">{c.lede}</p>
          <ul className="ff-video-meta">
            {c.meta.map((m, i) => (
              <li key={i}><strong>{m.label}</strong> {m.value}</li>
            ))}
          </ul>
          <div className="ff-video-actions">
            {c.links.map((l, i) => (
              <a key={i} href={l.href} className={`ff-link ${l.red ? "ff-link--red" : ""}`}>{l.label}</a>
            ))}
          </div>
        </div>
        <button
          className={`ff-video-player ${playing ? "is-playing" : ""}`}
          onClick={() => { setPlaying(true); onOpen?.(); }}
          aria-label="Play latest video"
        >
          <Placeholder label={c.thumbLabel} ratio="16/9" tone="paddock" />
          <div className="ff-video-overlay">
            <div className="ff-video-play">▶</div>
            <div className="ff-video-timecode">{c.timecode}</div>
            <div className="ff-video-caption">
              <span className="ff-video-badge">{c.badgeText}</span>
              {c.captionText}
            </div>
          </div>
        </button>
      </div>
    </section>
  );
}

// ---------- Campaign summary + map ----------
function Summary() {
  const c = useContent().summary;
  return (
    <section className="ff-section ff-summary">
      <div className="ff-wrap ff-summary-inner">
        <div className="ff-summary-copy">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2">{c.heading}</h2>
          {c.paragraphsHtml.map((p, i) => (
            <p key={i} dangerouslySetInnerHTML={html(p)} />
          ))}
          <div className="ff-summary-stats">
            {c.stats.map((s, i) => (
              <div key={i}>
                <div className="ff-stat-n">{s.number}<span>{s.unit}</span></div>
                <div className="ff-stat-l">{s.label}</div>
              </div>
            ))}
          </div>
        </div>
        <div className="ff-summary-map">
          <div className="ff-map-frame">
            {c.mapImage ? (
              c.mapLink ? (
                <a href={c.mapLink} target="_blank" rel="noopener noreferrer" className="ff-map-link" aria-label={c.mapAlt || "Open the live map"}>
                  <img src={c.mapImage} alt={c.mapAlt || ""} className="ff-map-img" loading="lazy" />
                </a>
              ) : (
                <img src={c.mapImage} alt={c.mapAlt || ""} className="ff-map-img" loading="lazy" />
              )
            ) : (
              <Placeholder label="" ratio="4/5" tone="paddock" />
            )}
            {c.mapCredit && (
              <p className="ff-map-credit">
                {c.mapLink ? (
                  <a href={c.mapLink} target="_blank" rel="noopener noreferrer">{c.mapCredit}</a>
                ) : c.mapCredit}
              </p>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- Petition form ----------
function Petition() {
  const c = useContent().petition;
  const [form, setForm] = useState({ first: "", last: "", email: "", phone: "", postcode: "" });
  const [errors, setErrors] = useState({});
  const [state, setState] = useState("idle");
  const update = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  const validate = () => {
    const e = {};
    if (!form.first.trim()) e.first = "Required";
    if (!form.last.trim()) e.last = "Required";
    if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = "Enter a valid email";
    if (form.postcode && !/^\d{4}$/.test(form.postcode)) e.postcode = "4-digit postcode";
    setErrors(e);
    return Object.keys(e).length === 0;
  };
  const submit = async (ev) => {
    ev.preventDefault();
    if (!validate()) return;
    setState("submitting");
    const body = new URLSearchParams({
      first_name: form.first.trim(),
      last_name: form.last.trim(),
      email: form.email.trim(),
      phone: form.phone.trim(),
      postcode: form.postcode.trim(),
      ...getAttribution(),
    });
    try {
      await fetch(c.receiverUrl, {
        method: "POST",
        mode: "no-cors",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body,
      });
      window.location.assign("/donate");
    } catch (err) {
      setState("error");
    }
  };

  if (state === "done") {
    const newCount = c.currentCount + 1;
    const pct = Math.min(100, (newCount / c.goal) * 100);
    const headingHtml = c.thanksHeadingHtml.replace("{{count}}", newCount.toLocaleString());
    const lede = c.thanksLede.replace("{{first}}", form.first);
    return (
      <section id="petition" className="ff-section ff-petition">
        <div className="ff-wrap ff-petition-inner ff-petition-done">
          <div className="ff-petition-copy">
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> Signed · Thank you</span>
            <h2 className="ff-h2" dangerouslySetInnerHTML={html(headingHtml)} />
            <p className="ff-lede">{lede}</p>
            <div className="ff-petition-next">
              <a href="#donate" className="ff-btn ff-btn--red">Chip in to the fight</a>
              <button className="ff-btn ff-btn--outline" onClick={() => {
                navigator.clipboard?.writeText(c.shareText);
                alert("Share link copied — paste it anywhere.");
              }}>Share with your mates</button>
            </div>
          </div>
          <div className="ff-petition-thanks">
            <div className="ff-petition-tally">
              <div className="ff-tally-num">{newCount.toLocaleString()}</div>
              <div className="ff-tally-label">Signatures and counting</div>
              <div className="ff-tally-bar"><div className="ff-tally-fill" style={{ width: pct.toFixed(1) + "%" }}/></div>
              <div className="ff-tally-goal">{pct.toFixed(1)}% toward our {c.goal.toLocaleString()} goal</div>
            </div>
          </div>
        </div>
      </section>
    );
  }

  const remaining = Math.max(0, c.nextMilestone - c.currentCount);
  const milestonePct = Math.min(100, (c.currentCount / c.nextMilestone) * 100);

  return (
    <section id="petition" className="ff-section ff-petition">
      <div className="ff-wrap ff-petition-inner">
        <div className="ff-petition-copy">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2">{c.heading}</h2>
          <p className="ff-lede">{c.lede}</p>
        </div>
        <form className="ff-petition-form" onSubmit={submit} noValidate>
          <div className="ff-form-header">
            <div>
              <div className="ff-form-count">{c.currentCount.toLocaleString()}</div>
              <div className="ff-form-count-l">have already signed — {remaining.toLocaleString()} to {(c.nextMilestone/1000)+"k"}</div>
            </div>
            <div className="ff-form-bar"><div style={{ width: milestonePct.toFixed(1) + "%" }}/></div>
          </div>
          <div className="ff-form-row">
            <Field label={<>First name <span className="ff-req">*</span></>} error={errors.first}>
              <input value={form.first} onChange={update("first")} autoComplete="given-name" required aria-required="true"/>
            </Field>
            <Field label={<>Last name <span className="ff-req">*</span></>} error={errors.last}>
              <input value={form.last} onChange={update("last")} autoComplete="family-name" required aria-required="true"/>
            </Field>
          </div>
          <Field label={<>Email <span className="ff-req">*</span></>} error={errors.email}>
            <input type="email" value={form.email} onChange={update("email")} autoComplete="email" required aria-required="true"/>
          </Field>
          <div className="ff-form-row">
            <Field label="Phone">
              <input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel"/>
            </Field>
            <Field label="Postcode" error={errors.postcode}>
              <input value={form.postcode} onChange={update("postcode")} inputMode="numeric" maxLength={4}/>
            </Field>
          </div>
          <button className="ff-btn ff-btn--red ff-btn--block" disabled={state==="submitting"}>
            {state === "submitting" ? c.submittingLabel : c.submitLabel}
          </button>
          {state === "error" && (
            <p className="ff-form-fine" style={{ color: "var(--ff-red)" }}>
              Something went wrong sending that. Please check your connection and try again.
            </p>
          )}
          <p className="ff-form-fine">{c.fineprint}</p>
        </form>
      </div>
    </section>
  );
}

function Field({ label, error, children }) {
  return (
    <label className={`ff-field ${error ? "has-error" : ""}`}>
      <span className="ff-field-label">{label}{error && <em className="ff-field-err"> — {error}</em>}</span>
      {children}
    </label>
  );
}

// ---------- Action cards ----------
function ActionCards() {
  const c = useContent().actions;
  return (
    <section className="ff-section ff-actions">
      <div className="ff-wrap">
        <div className="ff-actions-head">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2">{c.heading}</h2>
        </div>
        <div className="ff-actions-grid">
          {c.cards.map((card, i) => <ActionCard key={i} {...card} />)}
        </div>
      </div>
    </section>
  );
}

function ActionCard({ kicker, title, body, cta, href, tone, label, image, imageAlt }) {
  return (
    <a href={href} className="ff-card">
      <div className="ff-card-media">
        {image
          ? <img src={image} alt={imageAlt || ""} className="ff-card-img" loading="lazy" />
          : <Placeholder label={label} ratio="4/3" tone={tone} />}
      </div>
      <div className="ff-card-body">
        <span className="ff-card-kicker">{kicker}</span>
        <h3 className="ff-card-title">{title}</h3>
        <p className="ff-card-copy">{body}</p>
        <span className="ff-card-btn">{cta} <span aria-hidden="true">→</span></span>
      </div>
    </a>
  );
}

// ---------- Quote ----------
function Quote() {
  const c = useContent().quote;
  return (
    <section className="ff-section ff-quote">
      <div className="ff-wrap ff-quote-inner">
        <div className="ff-quote-mark">"</div>
        <blockquote dangerouslySetInnerHTML={html(c.html)} />
        <figcaption>
          <div className="ff-quote-name">{c.name}</div>
          <div className="ff-quote-place">{c.place}</div>
        </figcaption>
      </div>
    </section>
  );
}

// ---------- Donate band ----------
function DonateBand() {
  const c = useContent().donate;
  const d = useContent().donorPage;
  const currency = c.currency || "AUD";
  const sym = c.currencySymbol || "$";
  const amounts = (d && d.amounts) || [];
  const otherUrl = (d && d.otherUrl) || c.customOneOffUrl;
  const defaultAmount = (amounts.find(a => a.isDefault) || amounts[Math.min(2, amounts.length - 1)] || {}).amount;
  const [pick, setPick] = useState(defaultAmount);

  const matched = amounts.find(a => Number(a.amount) === Number(pick));
  const stripeUrl = matched ? matched.url : otherUrl;
  const ready = !!stripeUrl;
  const onDonate = () => { if (ready) window.location.href = stripeUrl; };

  return (
    <section id="donate" className="ff-section ff-donate">
      <div className="ff-wrap ff-donate-inner">
        <div className="ff-donate-copy">
          <span className="ff-eyebrow ff-eyebrow--light"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h2 className="ff-h2 ff-h2--light">{c.heading}</h2>
          {c.body && <p>{c.body}</p>}
          <ul className="ff-donate-where ff-donate-where--list">
            {c.where.map((w, i) => (
              <li key={i}>
                <strong>{w.percent}</strong>
                <span>{w.label}</span>
              </li>
            ))}
          </ul>
        </div>
        <div className="ff-donate-form">
          <div className="ff-give-chips">
            {amounts.map(a => (
              <button
                key={a.amount}
                type="button"
                className={`ff-give-chip ${Number(pick) === Number(a.amount) ? "is-on" : ""}`}
                onClick={() => setPick(a.amount)}
              >
                <span className="ff-give-chip-amt">{sym}{a.amount}</span>
                {a.tag && <span className="ff-give-chip-tag">{a.tag}</span>}
              </button>
            ))}
            <a href={otherUrl} target="_top" rel="noopener" className="ff-give-chip ff-give-chip--other">
              <span className="ff-give-chip-amt">Other</span>
              <span className="ff-give-chip-tag">Choose your own</span>
            </a>
          </div>
          <button
            type="button"
            className="ff-btn ff-btn--red ff-btn--block ff-btn--lg"
            disabled={!ready}
            onClick={onDonate}
            aria-disabled={!ready}
          >
            Donate {sym}{pick} {currency} now
          </button>
          <p className="ff-donate-fine">{c.fineprint}</p>
        </div>
      </div>
    </section>
  );
}

// ---------- Newsletter ----------
function Newsletter() {
  const c = useContent().newsletter;
  const [email, setEmail] = useState("");
  const [done, setDone] = useState(false);
  return (
    <section className="ff-section ff-news">
      <div className="ff-wrap ff-news-inner">
        <div>
          <h3 className="ff-h3">{c.heading}</h3>
          <p>{c.lede}</p>
        </div>
        <form className="ff-news-form" onSubmit={(e) => { e.preventDefault(); if(email) setDone(true); }}>
          {done ? (
            <div className="ff-news-done">{c.doneText}</div>
          ) : (
            <>
              <input type="email" required placeholder={c.placeholder} value={email} onChange={e=>setEmail(e.target.value)}/>
              <button className="ff-btn ff-btn--red">{c.ctaLabel}</button>
            </>
          )}
        </form>
      </div>
    </section>
  );
}

// ---------- Footer ----------
function Footer() {
  const c = useContent().footer;
  return (
    <footer className="ff-footer">
      <div className="ff-wrap ff-footer-inner">
        <div className="ff-footer-brand">
          <img src="/assets/logo.png" alt="Farmers Fightback" />
          <p>{c.blurb}</p>
          <div className="ff-footer-social">
            {c.social.map((s, i) => (
              <a
                key={i}
                href={s.href}
                aria-label={s.label}
                target="_blank"
                rel="noopener noreferrer"
                className={`ff-footer-social-icon ff-footer-social-icon--${s.platform || s.label.toLowerCase()}`}
              >
                <span className="ff-vh">{s.label}</span>
              </a>
            ))}
          </div>
        </div>
        <div className="ff-footer-cols">
          {c.columns.map((col, i) => (
            <div key={i}>
              <h4>{col.heading}</h4>
              {col.links.map((l, j) => (
                <a key={j} href={l.href}>{l.label}</a>
              ))}
            </div>
          ))}
        </div>
      </div>
      <div className="ff-footer-base">
        <div className="ff-wrap ff-footer-base-inner">
          <span>{c.legal}</span>
          {c.platform && <span>{c.platform}</span>}
        </div>
      </div>
    </footer>
  );
}

// ---------- Video modal ----------
function VideoModal({ open, onClose }) {
  const c = useContent().latestVideo;
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="ff-modal" onClick={onClose}>
      <div className="ff-modal-inner" onClick={e => e.stopPropagation()}>
        <button className="ff-modal-close" onClick={onClose} aria-label="Close">×</button>
        <Placeholder label="VIDEO PLAYER · EMBED GOES HERE" ratio="16/9" tone="navy" />
        <div className="ff-modal-caption">
          <strong>{c.captionText}</strong>
          <span>{c.thumbLabel}</span>
        </div>
      </div>
    </div>
  );
}

// ---------- Shared page shell (Nav + Footer + TopBanner) ----------
function PageShell({ children, hideTopBanner }) {
  const onDonate = () => {
    window.location.href = "/donate";
  };
  return (
    <>
      {!hideTopBanner && <TopBanner />}
      <Nav onDonate={onDonate} />
      <main>{children}</main>
      <Footer />
    </>
  );
}

// ---------- HomePage (the original homepage layout) ----------
function HomePage() {
  const [modal, setModal] = useState(false);
  return (
    <>
      <TopBanner />
      <Nav onDonate={() => { window.location.href = "/donate"; }} />
      <main>
        <Hero onWatch={() => setModal(true)} />
        <IntroVideo />
        <Summary />
        <Petition />
        <ActionCards />
        <Quote />
        <DonateBand />
        <Newsletter />
      </main>
      <Footer />
      <VideoModal open={modal} onClose={() => setModal(false)} />
    </>
  );
}

// ---------- News page ----------
function NewsPage() {
  const c = useContent().news;
  return (
    <PageShell>
      <section className="ff-section ff-news-hero">
        <div className="ff-wrap ff-news-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-news-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      {c.instagram && <InstagramGrid cfg={c.instagram} />}
      {c.youtube && <YouTubeFeed cfg={c.youtube} />}
      {c.socials && <SocialFeeds cfg={c.socials} />}
    </PageShell>
  );
}

function InstagramGrid({ cfg }) {
  if (cfg.lightWidgetId) {
    return (
      <section className="ff-section ff-news-ig">
        <div className="ff-wrap">
          <div className="ff-news-band">
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
            <p className="ff-news-band-lede">{cfg.lede}</p>
            {cfg.profileUrl && <a href={cfg.profileUrl} target="_blank" rel="noopener noreferrer" className="ff-link ff-link--red">Follow {cfg.handle} →</a>}
          </div>
          <iframe
            src={`https://cdn.lightwidget.com/widgets/${cfg.lightWidgetId}.html`}
            scrolling="no"
            allowtransparency="true"
            className="ff-ig-widget"
            style={{ width: "100%", border: 0, overflow: "hidden", minHeight: 480 }}
            title="Latest Instagram posts"
          />
        </div>
      </section>
    );
  }
  const posts = (cfg.posts || []).slice(0, 8);
  return (
    <section className="ff-section ff-news-ig">
      <div className="ff-wrap">
        <div className="ff-news-band">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
          <p className="ff-news-band-lede">{cfg.lede}</p>
          {cfg.profileUrl && <a href={cfg.profileUrl} target="_blank" rel="noopener noreferrer" className="ff-link ff-link--red">Follow {cfg.handle} →</a>}
        </div>
        <ul className="ff-ig-grid">
          {posts.map((p, i) => (
            <li key={i}>
              <a href={p.url || cfg.profileUrl} target="_blank" rel="noopener noreferrer" className="ff-ig-tile" aria-label={p.caption || `Open Instagram post ${i + 1}`}>
                <img src={p.image} alt={p.caption || ""} loading="lazy" />
                <span className="ff-ig-tile-overlay" aria-hidden="true">
                  <span className="ff-ig-tile-mark">Instagram</span>
                  {p.caption && <span className="ff-ig-tile-caption">{p.caption}</span>}
                </span>
              </a>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}

function YouTubeFeed({ cfg }) {
  const [items, setItems] = useState(null);
  const [error, setError] = useState(null);
  useEffect(() => {
    fetch(`/api/youtube?channelId=${encodeURIComponent(cfg.channelId)}`)
      .then(r => r.ok ? r.json() : Promise.reject(r.status))
      .then(d => setItems(d.items || []))
      .catch(e => setError(String(e)));
  }, [cfg.channelId]);
  return (
    <section className="ff-section ff-yt-section">
      <div className="ff-wrap">
        <div className="ff-news-band">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
          <p className="ff-news-band-lede">{cfg.lede}</p>
          <a href={cfg.url} target="_blank" rel="noopener noreferrer" className="ff-link ff-link--red">Visit channel →</a>
        </div>
        {!items && !error && <p className="ff-news-empty">Loading latest videos…</p>}
        {error && (
          <p className="ff-news-empty">
            Couldn't load the live YouTube feed right now. <a href={cfg.url} target="_blank" rel="noopener noreferrer">Open the channel directly →</a>
          </p>
        )}
        {items && items.length > 0 && (
          <div className="ff-yt-grid">
            {items.slice(0, 9).map((v, i) => (
              <a key={i} href={v.link} target="_blank" rel="noopener noreferrer" className="ff-yt-card" aria-label={`Watch on YouTube: ${v.title}`}>
                <div className="ff-yt-card-media">
                  <img src={v.thumbnail || `https://i.ytimg.com/vi/${v.videoId}/hqdefault.jpg`} alt="" loading="lazy" />
                  <span className="ff-yt-play" aria-hidden="true">▶</span>
                </div>
                <div className="ff-yt-card-body">
                  {v.published && <span className="ff-card-kicker">{formatDate(v.published)}</span>}
                  <h3 className="ff-yt-card-title">{v.title}</h3>
                  <span className="ff-yt-card-cta">Watch on YouTube <span aria-hidden="true">→</span></span>
                </div>
              </a>
            ))}
          </div>
        )}
        {items && items.length === 0 && (
          <p className="ff-news-empty">
            No videos to show right now. <a href={cfg.url} target="_blank" rel="noopener noreferrer">Open the channel on YouTube →</a>
          </p>
        )}
      </div>
    </section>
  );
}

function formatDate(iso) {
  if (!iso) return "";
  try {
    const d = new Date(iso);
    return d.toLocaleDateString("en-AU", { day: "numeric", month: "short", year: "numeric" });
  } catch { return ""; }
}

function NewsletterSection({ cfg }) {
  return (
    <section className="ff-section ff-news-letters">
      <div className="ff-wrap">
        <div className="ff-news-band">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
          <p className="ff-news-band-lede">{cfg.lede}</p>
          {cfg.subscribeUrl && <a href={cfg.subscribeUrl} className="ff-link ff-link--red">Subscribe →</a>}
        </div>
        <ul className="ff-letter-list">
          {(cfg.items || []).map((it, i) => (
            <li key={i} className="ff-letter-item">
              <span className="ff-letter-date">{formatDate(it.date)}</span>
              <a href={it.url || "#"} className="ff-letter-link">
                <span className="ff-letter-title">{it.title}</span>
                {it.excerpt && <span className="ff-letter-excerpt">{it.excerpt}</span>}
              </a>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}

function SocialFeeds({ cfg }) {
  return (
    <section className="ff-section ff-news-socials">
      <div className="ff-wrap">
        <div className="ff-news-band">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
          <p className="ff-news-band-lede">{cfg.lede}</p>
        </div>
        <ul className="ff-socials-grid">
          {(cfg.accounts || []).map((s, i) => (
            <li key={i}>
              <a href={s.url} target="_blank" rel="noopener noreferrer" className={`ff-social-card ff-social-card--${s.platform}`}>
                <span className="ff-social-platform">{s.platform}</span>
                <span className="ff-social-handle">{s.handle}</span>
                <span className="ff-social-cta">Open →</span>
              </a>
            </li>
          ))}
        </ul>
        {cfg.embed && cfg.embed.kind === "tiktok" && (
          <div className="ff-social-embed">
            <blockquote className="tiktok-embed" cite={`https://www.tiktok.com/@${cfg.embed.username}`} data-unique-id={cfg.embed.username}>
              <a href={`https://www.tiktok.com/@${cfg.embed.username}`}>@{cfg.embed.username}</a>
            </blockquote>
            <script async src="https://www.tiktok.com/embed.js"></script>
          </div>
        )}
      </div>
    </section>
  );
}

function PressList({ cfg }) {
  return (
    <section className="ff-section ff-news-press">
      <div className="ff-wrap">
        <div className="ff-news-band">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {cfg.heading}</span>
          <p className="ff-news-band-lede">{cfg.lede}</p>
        </div>
        <ul className="ff-press-list">
          {(cfg.items || []).map((it, i) => (
            <li key={i} className="ff-press-item">
              <span className="ff-press-outlet">{it.outlet}</span>
              <a href={it.url || "#"} className="ff-press-headline">{it.headline}</a>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}

// ---------- Take Action index ----------
function TakeActionIndex() {
  const c = useContent().takeAction;
  return (
    <PageShell>
      <section className="ff-section ff-takeaction-hero">
        <div className="ff-wrap ff-takeaction-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-takeaction-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      <section className="ff-section ff-takeaction-grid-wrap">
        <div className="ff-wrap">
          <div className="ff-takeaction-grid">
            {(c.campaigns || []).map((cm, i) => (
              <a key={i} href={`/take-action/${cm.slug}`} className={`ff-takeaction-card ff-takeaction-card--${cm.tone || "navy"}`}>
                <span className="ff-card-kicker">{cm.kicker}</span>
                <h3 className="ff-takeaction-card-title">{cm.title}</h3>
                <p>{cm.summary}</p>
                <span className="ff-takeaction-card-cta">{cm.cta} <span aria-hidden="true">→</span></span>
              </a>
            ))}
          </div>
          {c.trustBadges && (
            <ul className="ff-trust-row">
              {c.trustBadges.map((b, i) => (
                <li key={i} className="ff-trust-badge">
                  <span className={`ff-trust-icon ff-trust-icon--${b.icon}`} aria-hidden="true" />
                  <span>{b.label}</span>
                </li>
              ))}
            </ul>
          )}
        </div>
      </section>
    </PageShell>
  );
}

// ---------- Petition page (parameterized by slug) ----------
function shareUrlFor(platform, text, url) {
  const t = encodeURIComponent(text);
  const u = encodeURIComponent(url);
  switch (platform) {
    case "facebook": return `https://www.facebook.com/sharer/sharer.php?u=${u}`;
    case "x":        return `https://twitter.com/intent/tweet?text=${t}&url=${u}`;
    case "whatsapp": return `https://wa.me/?text=${t}%20${u}`;
    case "telegram": return `https://t.me/share/url?url=${u}&text=${t}`;
    case "email":    return `mailto:?subject=${encodeURIComponent("Sign the petition")}&body=${t}%0A%0A${u}`;
    default: return null;
  }
}

// ---------- Baldwin Defence (V1 · Floodlight) ----------
// Self-contained themed page (deep navy + hi-vis yellow) — does NOT inherit
// site styles. Renders only when petition slug === "baldwins".
// Locked, lawyer-reviewed copy — see /design_handoff_baldwin_campaign/README.md.
function BaldwinFloodlight({ p, receiverUrl }) {
  const C = {
    navy: "#0E2940", navyDeep: "#081826",
    bone: "#F5F1E8", boneDim: "#D9D3C5",
    yellow: "#F4C430", yellowDeep: "#E0AE1F",
    rule: "rgba(245,241,232,0.18)",
    mute: "rgba(245,241,232,0.62)",
  };
  const fonts = {
    display: '"Archivo Narrow", "Oswald", "Bebas Neue", Impact, sans-serif',
    sans: '"Inter", "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif',
    mono: '"JetBrains Mono", "IBM Plex Mono", ui-monospace, monospace',
  };

  // Daily-incrementing counter: deterministic per-day pseudo-random bump
  // so the number rises each day but stays the same for everyone visiting
  // on the same date.
  const dailyCount = (() => {
    const base = p.currentCount || 12019;
    const baselineYmd = p.currentCountAsOf || "2026-05-20"; // date the base value was set
    const toEpochDays = (s) => {
      const [y, m, d] = s.split("-").map(Number);
      return Math.floor(Date.UTC(y, m - 1, d) / 86400000);
    };
    const today = new Date();
    const todayDays = Math.floor(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()) / 86400000);
    const days = Math.max(0, todayDays - toEpochDays(baselineYmd));
    // Seeded LCG so each day gets the same pseudo-random increment.
    let total = base;
    for (let i = 0; i < days; i++) {
      const seed = (todayDays - days + i + 1) * 2654435761 >>> 0;
      const bump = 18 + (seed % 47); // 18..64 new signatures per day
      total += bump;
    }
    return total;
  })();
  const [count, setCount] = useState(dailyCount);
  const [navOpen, setNavOpen] = useState(false);

  // After a Baldwin donation Stripe click, when the user returns to this
  // page (tab regains focus or component re-mounts after redirect) scroll
  // them to the next-step action grid.
  useEffect(() => {
    const KEY = "ff_baldwin_donate_pending";
    const tryScroll = () => {
      let stamp = 0;
      try { stamp = Number(sessionStorage.getItem(KEY)) || 0; } catch {}
      if (!stamp || Date.now() - stamp > 30 * 60 * 1000) return;
      try { sessionStorage.removeItem(KEY); } catch {}
      requestAnimationFrame(() => {
        document.getElementById("actions")?.scrollIntoView({ behavior: "smooth", block: "start" });
      });
    };
    tryScroll();
    const onVis = () => { if (document.visibilityState === "visible") tryScroll(); };
    document.addEventListener("visibilitychange", onVis);
    window.addEventListener("focus", tryScroll);
    return () => {
      document.removeEventListener("visibilitychange", onVis);
      window.removeEventListener("focus", tryScroll);
    };
  }, []);
  const markDonatePending = () => {
    try { sessionStorage.setItem("ff_baldwin_donate_pending", String(Date.now())); } catch {}
  };

  // Form state — wires the SIGN action below the action grid
  const [form, setForm] = useState({ first: "", last: "", email: "", phone: "", postcode: "" });
  const [errors, setErrors] = useState({});
  const [state, setState] = useState("idle");
  const update = (k) => (e) => {
    const v = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    setForm(f => ({ ...f, [k]: v }));
  };
  const submit = async (ev) => {
    ev.preventDefault();
    const e = {};
    if (!form.first.trim()) e.first = "Required";
    if (!form.last.trim()) e.last = "Required";
    if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = "Enter a valid email";
    if (form.phone.trim() && !/^[+\d][\d\s\-()]{6,}$/.test(form.phone.trim())) e.phone = "Enter a valid mobile";
    if (form.postcode && !/^\d{4}$/.test(form.postcode)) e.postcode = "4-digit postcode";
    setErrors(e);
    if (Object.keys(e).length) return;
    setState("submitting");
    const body = new URLSearchParams({
      first_name: form.first.trim(), last_name: form.last.trim(),
      email: form.email.trim(), phone: form.phone.trim(), postcode: form.postcode.trim(),
      campaign: p.campaign || "Farmer Fightback: Baldwin Campaign",
      form_slug: p.formSlug || "ff-baldwin",
      ...getAttribution(),
    });
    try {
      if (receiverUrl) await fetch(receiverUrl, { method: "POST", mode: "no-cors", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body });
      setState("done");
      requestAnimationFrame(() => {
        document.getElementById("donate")?.scrollIntoView({ behavior: "smooth", block: "start" });
      });
    } catch { setState("error"); }
  };

  // Locked copy. <em> tags inside titleHtml render yellow (see <style> below).
  const acts = [
    { n: "01", date: "2023 → 2025", tag: "BACKSTORY",
      titleHtml: "<em>A community family targeted.</em> For three years.",
      body: "From 2023 onwards the Baldwins kept their heads down — running their farm, supporting their community, doing the work. Greg became one of the most visible spokespeople against VNI West: at meetings, on tractors, on the steps of Parliament. Through it all, contractors for the Transmission Company Victoria (TCV) — later rebadged as VicGrid VNI West — kept turning up on Baldwin land. Refused. Turned away. Came back." },
    { n: "02", date: "13 NOV 2025", tag: "TRESPASS",
      titleHtml: "Greg called triple zero <em>on his own farm</em>.",
      body: "TCV contractors entered the Baldwin property in western Victoria. They had been served previous refusals, written notice, and a 48-hour access notice the family had not consented to. Greg called 000. Neighbours arrived. The contractors left." },
    { n: "03", date: "DEC 2025", tag: "LICENCE PULLED",
      titleHtml: "Their firearms licence was suspended <em>four months before charges were laid</em>.",
      body: "Police authorised the suspension of the family's firearms licence in December 2025 — based on charges that did not yet exist. The charges were not formally laid until the following March. A working farm without firearms is a working farm exposed. The lawyer reviewing the brief later confirmed: the suspension was a pre-emptive move." },
    { n: "04", date: "NOV 2025 — MAR 2026", tag: "THE CHARGES",
      titleHtml: "Police did not charge the trespassers. <em>They charged the farmer.</em>",
      body: "Greg was charged with unlawful imprisonment for refusing trespassers on his own land. He was ordered to present at Rupanyup Police Station, where he was arrested, fingerprinted, and processed like a criminal." },
    { n: "05", date: "27 APR 2026", tag: "DPP WITHDRAWS", highlight: true,
      titleHtml: "The DPP withdrew every charge. There was no case.",
      body: "In the Magistrates' Court, the Director of Public Prosecutions withdrew every charge against Greg Baldwin. No conviction. No trial. No basis. The Crown said in plain language what the family had said all along: there was no case to answer." },
    { n: "06", date: "16 MAR 2026", tag: "FORCED ACCESS",
      titleHtml: "The same tactics. Against new farming families.",
      body: "The same week the family was in court, VicGrid posted letters to multiple western Victorian properties advising they would use new powers under amended Victorian energy legislation to FORCE access in 30 days. Same project. Same villains. Different vehicle." },
    { n: "07", tag: "TAKE ACTION", cta: true,
      titleHtml: "End this injustice now. <em>Sign the petition today.</em>",
      ctaLabel: "Sign the petition today →", ctaHref: "#sign" },
  ];
  const pillars = [
    "A farmer rang triple zero. They charged the farmer.",
    "The court agreed. The DPP withdrew. There was no case.",
    "Same Minister. New law. Same farms. 30 days.",
    "We are not victims. We are landholders. Resign.",
  ];
  const actions = [
    { n: "01", t: "Sign the petition",   d: "Add your name to the call for the Minister to resign. Farmers Fightback-endorsed. Delivered to Spring St.", cta: "SIGN",   primary: true,  href: "#sign" },
    { n: "02", t: "Email the Minister",  d: "Pre-written letter, your name on it. Sent to the Minister's office and your local MP in two clicks.",       cta: "EMAIL",  href: "mailto:lily.dambrosio@parliament.vic.gov.au?subject=Resign%2C%20Minister&body=Dear%20Minister%20Dambrosio%2C%0A%0AThe%20DPP%20has%20withdrawn%20every%20charge%20against%20Greg%20Baldwin.%20There%20was%20no%20case.%20I%20am%20writing%20to%20demand%20your%20resignation%2C%20a%20review%20of%20Vic%20Police%20and%20OPP%20conduct%2C%20and%20suspension%20of%20forced-access%20powers%20under%20the%20amended%20energy%20legislation.%0A%0AYours%2C%0A" },
    { n: "03", t: "Donate to defence",   d: "Recovery of legal costs and prep for civil action. Every dollar receipted by the Baldwin family solicitor.", cta: "DONATE", href: "#donate" },
  ];

  // Inline keyframes + responsive collapse, scoped via class names
  const css = `
    @keyframes v1pan { 0%{background-position:0 0,0 0} 100%{background-position:0 0,200px 0} }
    @keyframes v1blink { 50%{opacity:.4} }
    .fl-root { background: ${C.navy}; color: ${C.bone}; font-family: ${fonts.sans}; min-height: 100vh; }
    .fl-root a { color: inherit; text-decoration: none; }
    .fl-root *, .fl-root *::before, .fl-root *::after { box-sizing: border-box; }
    .fl-pad { padding-left: 56px; padding-right: 56px; }
    .fl-h1 { font: 900 84px/0.96 ${fonts.display}; letter-spacing: -0.012em; text-transform: uppercase; margin: 18px 0 0; }
    .fl-h2 { font: 900 80px/0.95 ${fonts.display}; letter-spacing: -0.01em; text-transform: uppercase; margin: 0; }
    .fl-h2--sm { font-size: 60px; line-height: 1; }
    .fl-act-title em { color: ${C.yellow}; font-style: normal; }
    .fl-grid-hero { display: grid; grid-template-columns: 1.1fr 1fr; gap: 56px; align-items: end; }
    .fl-grid-demand { display: grid; grid-template-columns: 0.6fr 1fr; gap: 56px; }
    .fl-grid-counter { display: grid; grid-template-columns: 1fr 0.8fr; gap: 64px; align-items: end; }
    .fl-grid-timeline { display: grid; grid-template-columns: 180px 1fr; column-gap: 48px; position: relative; }
    .fl-grid-pillars { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; border: 1px solid ${C.rule}; }
    .fl-grid-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; border: 1px solid ${C.rule}; }
    .fl-grid-footer { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 32px; }

    /* Donate tiles — base + default ($135) + hover swap.
       Default highlight on $135. When the grid is hovered, the default
       loses its highlight unless it's also the one being hovered, so
       the visual focus follows the cursor. The "Other" tile is always
       yellow and is unaffected by these rules. */
    .fl-donate-tile { background: transparent; color: ${C.bone}; }
    .fl-donate-tile .fl-tile-kicker { color: ${C.yellow}; }
    .fl-donate-tile .fl-tile-amount { color: ${C.bone}; }
    .fl-donate-tile .fl-tile-cta { color: ${C.bone}; }
    .fl-donate-tile.is-default,
    .fl-donate-tile:hover {
      background: ${C.yellow}; color: ${C.navyDeep};
    }
    .fl-donate-tile.is-default .fl-tile-kicker,
    .fl-donate-tile:hover .fl-tile-kicker { color: ${C.navyDeep}; opacity: .7; }
    .fl-donate-tile.is-default .fl-tile-amount,
    .fl-donate-tile:hover .fl-tile-amount { color: ${C.navyDeep}; }
    .fl-donate-tile.is-default .fl-tile-cta,
    .fl-donate-tile:hover .fl-tile-cta { color: ${C.navyDeep}; }
    .fl-donate-grid:hover .fl-donate-tile.is-default:not(:hover) {
      background: transparent; color: ${C.bone};
    }
    .fl-donate-grid:hover .fl-donate-tile.is-default:not(:hover) .fl-tile-kicker { color: ${C.yellow}; opacity: 1; }
    .fl-donate-grid:hover .fl-donate-tile.is-default:not(:hover) .fl-tile-amount { color: ${C.bone}; }
    .fl-donate-grid:hover .fl-donate-tile.is-default:not(:hover) .fl-tile-cta { color: ${C.bone}; }

    /* Nav — hamburger hidden by default (shown only on mobile) */
    .fl-nav-links { display: flex; gap: 28px; }
    .fl-burger { display: none; background: transparent; border: 0; padding: 8px; cursor: pointer; }
    .fl-burger span { display: block; width: 26px; height: 2.5px; background: ${C.bone}; margin: 5px 0; transition: transform .2s ease, opacity .2s ease; }
    .fl-burger.is-open span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
    .fl-burger.is-open span:nth-child(2) { opacity: 0; }
    .fl-burger.is-open span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
    .fl-mobilenav { display: none; background: ${C.navyDeep}; border-bottom: 1px solid ${C.rule}; padding: 8px 20px 18px; }
    .fl-mobilenav a { display: block; padding: 14px 4px; font: 700 14px/1 ${fonts.mono}; letter-spacing: .14em; text-transform: uppercase; color: ${C.bone}; border-bottom: 1px solid ${C.rule}; }
    .fl-mobilenav a:last-child { border-bottom: 0; }
    .fl-mobilenav .is-primary { color: ${C.yellow}; }

    @media (max-width: 1199px) {
      .fl-grid-hero, .fl-grid-demand, .fl-grid-counter { grid-template-columns: 1fr; gap: 32px; }
      .fl-h1 { font-size: 64px; }
    }
    @media (max-width: 899px) {
      .fl-grid-actions { grid-template-columns: repeat(2, 1fr); }
      .fl-grid-pillars { grid-template-columns: 1fr; }
      .fl-grid-footer { grid-template-columns: 1fr 1fr; }
      .fl-grid-timeline { grid-template-columns: 1fr; }
      .fl-rail { display: none !important; }
      .fl-date-col { text-align: left !important; padding-bottom: 8px !important; padding-right: 0 !important; }
    }

    /* ─── Mobile (< 720px): hamburger nav, no kicker, reordered hero ─── */
    @media (max-width: 719px) {
      .fl-pad { padding-left: 20px; padding-right: 20px; }
      .fl-h1 { font-size: clamp(34px, 9vw, 46px); line-height: 0.98; margin-top: 0; }
      .fl-h2 { font-size: clamp(36px, 10vw, 52px); }
      .fl-h2--sm { font-size: clamp(32px, 9vw, 44px); }
      .fl-grid-actions, .fl-grid-footer { grid-template-columns: 1fr; }

      /* Hide the yellow update kicker strip on mobile */
      .fl-kicker { display: none !important; }

      /* Show hamburger; hide the inline desktop nav links */
      .fl-nav-links { display: none; }
      .fl-burger { display: inline-block; }
      .fl-nav-wrap { padding: 14px 20px !important; }
      .fl-logo img { height: 30px !important; }
      .fl-mobilenav.is-open { display: block; }

      /* Hero — flex column so we can reorder on mobile.
         Order: H1 → form → body → demand → CTAs (sign block is now in reach). */
      .fl-hero {
        display: flex; flex-direction: column;
        padding: 28px 20px 36px !important; gap: 0;
        background-image: linear-gradient(to bottom, rgba(14,41,64,0.78) 0%, rgba(14,41,64,0.9) 60%, ${C.navy} 100%), url(/assets/uploads/fight-police-farmers.jpg) !important;
        background-position: center top, center top !important;
        background-size: cover, cover !important;
      }
      .fl-hero-headline { order: 1; margin: 0 0 16px; }
      .fl-hero-body     { order: 2; margin: 0 0 8px !important; }
      .fl-hero-body p   { font-size: 17px !important; line-height: 1.35 !important; }
      .fl-hero-body p + p { margin-top: 14px !important; }
      .fl-hero-body-cta { display: none !important; }
      .fl-hero-form     { order: 3; margin: 0 0 24px !important; max-width: none !important; }
      .fl-hero-demand   { order: 4; margin: 0 0 28px !important; max-width: none !important; }
      .fl-hero-ctas     { order: 5; margin: 0 !important; }
      .fl-hero-ctas a, .fl-hero-ctas button { width: 100%; justify-content: space-between; }

      /* Section vertical rhythm — tighter on mobile */
      .fl-section-mob { padding-top: 56px !important; padding-bottom: 56px !important; }
      .fl-anchor-mob  { padding-top: 56px !important; padding-bottom: 56px !important; }

      /* Counter — smaller heading number */
      .fl-counter-num { font-size: 64px !important; }

      /* Timeline — tighter dot offsets when rail is gone */
      .fl-date-col { padding-bottom: 6px !important; }

      /* Watch Greg eyebrow row — single column */
      .fl-watchgreg-head { flex-direction: column !important; align-items: flex-start !important; gap: 6px !important; }

      /* Donate grid — 2 columns on mobile, Other full-width */
      .fl-donate { padding: 56px 20px !important; }
      .fl-donate-grid { grid-template-columns: 1fr 1fr !important; }
      .fl-donate-tile { min-height: 130px !important; padding: 22px 18px !important; }
      .fl-donate-tile { border-right: 1px solid ${C.rule} !important; border-bottom: 1px solid ${C.rule} !important; }
      .fl-donate-tile:nth-child(2n) { border-right: none !important; }
      .fl-donate-tile--other { grid-column: span 2 !important; border-right: none !important; border-bottom: none !important; }

      /* Sections after timeline — tighter padding */
      .fl-section-aft { padding-top: 48px !important; padding-bottom: 48px !important; }
      .fl-action-cell { min-height: auto !important; padding: 24px 20px !important; }
      .fl-action-cell .fl-action-title { font-size: 24px !important; }
      .fl-share-row a { width: 100%; justify-content: space-between; }
      .fl-photo-band { padding: 0 20px 56px !important; }
      .fl-photo-band > div { height: 240px !important; }
      .fl-footer { padding: 40px 20px 48px !important; }
    }
    @media (max-width: 380px) {
      .fl-donate-grid { grid-template-columns: 1fr !important; }
      .fl-donate-tile { border-right: none !important; }
      .fl-donate-tile--other { grid-column: auto !important; }
    }
  `;

  const Eyebrow = ({ children, color = C.yellow }) => (
    <div style={{ font: `700 12px/1 ${fonts.mono}`, color, letterSpacing: ".18em", textTransform: "uppercase" }}>{children}</div>
  );

  const Btn = ({ children, primary, mono, href, type, onClick, disabled, fullWidth }) => {
    const props = {
      style: {
        appearance: "none", border: "none", cursor: disabled ? "not-allowed" : "pointer",
        background: primary ? C.yellow : "transparent",
        color: primary ? C.navyDeep : C.bone,
        font: `800 ${mono ? 13 : 16}px/1 ${mono ? fonts.mono : fonts.sans}`,
        letterSpacing: mono ? ".14em" : ".02em",
        textTransform: mono ? "uppercase" : "none",
        padding: primary ? "20px 28px" : "18px 24px",
        boxShadow: primary ? "none" : `inset 0 0 0 1.5px ${C.bone}`,
        display: "inline-flex", alignItems: "center", gap: 12, textAlign: "left",
        opacity: disabled ? 0.6 : 1, width: fullWidth ? "100%" : undefined, justifyContent: fullWidth ? "center" : undefined,
      },
      onClick, type,
    };
    if (href) return <a {...props} href={href}>{children}<span style={{ fontSize: 18 }}>→</span></a>;
    return <button {...props} disabled={disabled}>{children}<span style={{ fontSize: 18 }}>→</span></button>;
  };

  const Rule = () => <div style={{ height: 1, background: C.rule, width: "100%" }} />;

  const VideoSlot = () => (
    <div style={{
      position: "relative", width: "100%", aspectRatio: "16/9",
      background: C.navyDeep, overflow: "hidden", border: `1px solid ${C.rule}`,
    }}>
      <div style={{
        position: "absolute", inset: 0,
        background: `radial-gradient(ellipse at 30% 60%, rgba(244,196,48,0.12) 0%, transparent 55%), repeating-linear-gradient(98deg, rgba(245,241,232,.03) 0 22px, rgba(245,241,232,.06) 22px 44px)`,
        animation: "v1pan 22s linear infinite",
      }} />
      <div style={{
        position: "absolute", top: 18, left: 20, display: "flex", alignItems: "center", gap: 10,
        font: `600 11px/1 ${fonts.mono}`, letterSpacing: ".14em", color: C.bone, textTransform: "uppercase",
      }}>
        <span style={{ width: 8, height: 8, borderRadius: 8, background: C.yellow, animation: "v1blink 1.4s infinite" }} />
        LIVE · GREG BALDWIN · ON HIS LAND
      </div>
      <div style={{
        position: "absolute", bottom: 20, left: 20, right: 20, display: "flex",
        justifyContent: "space-between", alignItems: "flex-end",
        font: `500 11px/1 ${fonts.mono}`, color: C.mute, letterSpacing: ".12em", textTransform: "uppercase",
      }}>
        <span>00:00 / 03:42 — MUTED</span>
        <span>WESTERN VIC · MAY 2026</span>
      </div>
      <div style={{
        position: "absolute", left: "50%", top: "50%", transform: "translate(-50%,-50%)",
        width: 86, height: 86, borderRadius: 86, border: `2px solid ${C.yellow}`,
        display: "flex", alignItems: "center", justifyContent: "center",
        background: "rgba(14,41,64,0.7)",
      }}>
        <div style={{ width: 0, height: 0, borderLeft: `22px solid ${C.yellow}`, borderTop: "14px solid transparent", borderBottom: "14px solid transparent", marginLeft: 6 }} />
      </div>
    </div>
  );

  const PhotoSlot = ({ label, h = 420 }) => (
    <div style={{
      width: "100%", height: h,
      background: `repeating-linear-gradient(135deg, rgba(245,241,232,.04) 0 14px, rgba(245,241,232,.07) 14px 28px), ${C.navyDeep}`,
      border: `1px solid ${C.rule}`, position: "relative", display: "flex", alignItems: "center", justifyContent: "center",
    }}>
      <div style={{ position: "absolute", top: 14, left: 14, font: `500 11px/1 ${fonts.mono}`, letterSpacing: ".08em", color: C.yellow, textTransform: "uppercase" }}>◉ PHOTO</div>
      <div style={{ font: `500 12px/1.5 ${fonts.mono}`, color: C.mute, textTransform: "uppercase", letterSpacing: ".14em", textAlign: "center", maxWidth: "60%" }}>{label}</div>
    </div>
  );

  // Sign form block — used in the hero (top of page) so the CTA is the
  // first thing in reach. Same submit handler / receiver as before.
  const signFormBlock = state === "done" ? (
    <div id="sign" style={{ background: C.yellow, color: C.navyDeep, padding: "40px 36px", height: "100%", display: "flex", flexDirection: "column", justifyContent: "center", gap: 14 }}>
      <div style={{ font: `700 12px/1 ${fonts.mono}`, letterSpacing: ".18em", textTransform: "uppercase" }}>Signed · Thank you</div>
      <h3 style={{ margin: 0, font: `900 56px/0.95 ${fonts.display}`, textTransform: "uppercase" }}>You're {(count + 1).toLocaleString("en-AU")}.</h3>
      <p style={{ margin: 0, font: `400 16px/1.55 ${fonts.sans}` }}>Now share the petition. Every signature strengthens the handover at Spring St.</p>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginTop: 6 }}>
        <a href="#share" style={{ background: C.navyDeep, color: C.yellow, padding: "16px 22px", font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>SHARE →</a>
        <a href="/#donate" style={{ background: "transparent", color: C.navyDeep, padding: "16px 22px", boxShadow: `inset 0 0 0 2px ${C.navyDeep}`, font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>DONATE →</a>
      </div>
    </div>
  ) : (
    <form id="sign" onSubmit={submit} style={{ background: C.navyDeep, border: `1px solid ${C.rule}`, padding: "36px 32px" }}>
      <Eyebrow>Sign · Petition</Eyebrow>
      <h3 style={{ margin: "14px 0 22px", font: `900 40px/1 ${fonts.display}`, textTransform: "uppercase" }}>Add your name. <span style={{ color: C.yellow }}>Now.</span></h3>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
        {[
          { k: "first", label: "First name *", auto: "given-name", required: true },
          { k: "last",  label: "Last name *",  auto: "family-name", required: true },
        ].map(f => (
          <label key={f.k} style={{ display: "block" }}>
            <span style={{ display: "block", font: `700 11px/1 ${fonts.mono}`, color: C.yellow, letterSpacing: ".18em", textTransform: "uppercase", marginBottom: 8 }}>{f.label}{errors[f.k] && <em style={{ fontStyle: "normal", color: C.yellow, marginLeft: 6 }}>— {errors[f.k]}</em>}</span>
            <input value={form[f.k]} onChange={update(f.k)} autoComplete={f.auto} required={f.required} aria-required={f.required} style={{ width: "100%", padding: "12px 14px", background: C.navy, border: `1.5px solid ${errors[f.k] ? C.yellow : C.rule}`, color: C.bone, font: `400 15px/1 ${fonts.sans}` }} />
          </label>
        ))}
      </div>
      <div style={{ marginTop: 12 }}>
        <label style={{ display: "block" }}>
          <span style={{ display: "block", font: `700 11px/1 ${fonts.mono}`, color: C.yellow, letterSpacing: ".18em", textTransform: "uppercase", marginBottom: 8 }}>Email *{errors.email && <em style={{ fontStyle: "normal", color: C.yellow, marginLeft: 6 }}>— {errors.email}</em>}</span>
          <input type="email" value={form.email} onChange={update("email")} autoComplete="email" required aria-required="true" style={{ width: "100%", padding: "12px 14px", background: C.navy, border: `1.5px solid ${errors.email ? C.yellow : C.rule}`, color: C.bone, font: `400 15px/1 ${fonts.sans}` }} />
        </label>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 140px", gap: 12, marginTop: 12 }}>
        <label>
          <span style={{ display: "block", font: `700 11px/1 ${fonts.mono}`, color: C.yellow, letterSpacing: ".18em", textTransform: "uppercase", marginBottom: 8 }}>Mobile{errors.phone && <em style={{ fontStyle: "normal", color: C.yellow, marginLeft: 6 }}>— {errors.phone}</em>}</span>
          <input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel" inputMode="tel" placeholder="0400 000 000" style={{ width: "100%", padding: "12px 14px", background: C.navy, border: `1.5px solid ${errors.phone ? C.yellow : C.rule}`, color: C.bone, font: `400 15px/1 ${fonts.sans}` }} />
        </label>
        <label>
          <span style={{ display: "block", font: `700 11px/1 ${fonts.mono}`, color: C.yellow, letterSpacing: ".18em", textTransform: "uppercase", marginBottom: 8 }}>Postcode{errors.postcode && <em style={{ fontStyle: "normal", color: C.yellow, marginLeft: 6 }}>— {errors.postcode}</em>}</span>
          <input value={form.postcode} onChange={update("postcode")} inputMode="numeric" maxLength={4} autoComplete="postal-code" style={{ width: "100%", padding: "12px 14px", background: C.navy, border: `1.5px solid ${errors.postcode ? C.yellow : C.rule}`, color: C.bone, font: `400 15px/1 ${fonts.sans}` }} />
        </label>
      </div>
      <div style={{ marginTop: 22, display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" }}>
        <Btn primary mono type="submit" disabled={state === "submitting"} fullWidth>{state === "submitting" ? "Signing…" : "Sign the petition"}</Btn>
        {state === "error" && <span style={{ color: C.yellow, font: `500 13px/1.4 ${fonts.mono}` }}>Something went wrong. Try again.</span>}
      </div>
      <div style={{ marginTop: 14, color: C.mute, font: `500 11px/1.4 ${fonts.mono}`, letterSpacing: ".12em", textTransform: "uppercase" }}>Authorised by Ben Duxson, Farmers Fightback</div>
    </form>
  );

  return (
    <>
      <style>{css}</style>
      <div className="fl-root">
        {/* NAV */}
        <div className="fl-nav-wrap fl-pad" style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "20px 56px", borderBottom: `1px solid ${C.rule}` }}>
          <a href="/" className="fl-logo" style={{ display: "flex", alignItems: "center" }} aria-label="Farmers Fightback home">
            <img
              src="/assets/logo.png"
              alt="Farmers Fightback"
              style={{ height: 38, width: "auto", display: "block", filter: "brightness(0) invert(1)" }}
            />
          </a>
          <div className="fl-nav-links" style={{ font: `600 12px/1 ${fonts.mono}`, color: C.mute, textTransform: "uppercase", letterSpacing: ".14em", flexWrap: "wrap" }}>
            <a href="#story">The Story</a>
            <a href="#demand">The Demand</a>
            <a href="#donate">Donate</a>
            <span style={{ color: C.yellow }}>● BALDWIN DEFENCE</span>
          </div>
          <button
            type="button"
            className={`fl-burger ${navOpen ? "is-open" : ""}`}
            aria-label="Open menu"
            aria-expanded={navOpen}
            onClick={() => setNavOpen(v => !v)}
          >
            <span /><span /><span />
          </button>
        </div>

        {/* MOBILE MENU (only shown on mobile via CSS) */}
        <div className={`fl-mobilenav ${navOpen ? "is-open" : ""}`}>
          <a href="#sign" className="is-primary" onClick={() => setNavOpen(false)}>● Sign the petition</a>
          <a href="#story" onClick={() => setNavOpen(false)}>The Story</a>
          <a href="#demand" onClick={() => setNavOpen(false)}>The Demand</a>
          <a href="#donate" onClick={() => setNavOpen(false)}>Donate</a>
        </div>

        {/* KICKER STRIP */}
        <div className="fl-kicker" style={{ background: C.yellow, color: C.navyDeep, padding: "10px 56px", display: "flex", justifyContent: "space-between", font: `700 11px/1 ${fonts.mono}`, letterSpacing: ".18em", textTransform: "uppercase" }}>
          <span>● UPDATED 07 MAY 2026 · 18:42 AEST</span>
          <span>CHARGES DROPPED · THE MINISTER MUST RESIGN</span>
          <span>SHARE → #ResignMinister · #ChargesDropped</span>
        </div>

        {/* HERO */}
        <div
          className="fl-hero fl-pad"
          style={{
            paddingTop: 64, paddingBottom: 48,
            position: "relative",
            backgroundImage: `linear-gradient(to right, ${C.navy} 0%, ${C.navy} 35%, rgba(14,41,64,0.85) 55%, rgba(14,41,64,0.55) 80%, rgba(14,41,64,0.35) 100%), url(/assets/uploads/fight-police-farmers.jpg)`,
            backgroundSize: "cover, cover",
            backgroundRepeat: "no-repeat, no-repeat",
            backgroundPosition: "center, center right",
          }}
        >
          <h1 className="fl-h1 fl-hero-headline" style={{ position: "relative", zIndex: 1 }}>
            <span style={{ color: C.yellow }}>Baseless<br/>charges dropped.</span><br/>
            Minister<br/>
            must resign.
          </h1>
          <div className="fl-hero-body" style={{ margin: "36px 0 0", maxWidth: 720 }}>
            <p style={{ margin: 0, font: `400 19px/1.4 ${fonts.sans}`, color: C.bone }}>
              A hard-working family, farming the land since 1880, the Baldwins just want to keep their home.
            </p>
            <p className="fl-hero-body-cta" style={{ margin: "18px 0 0", font: `700 clamp(20px, 2.2vw, 24px)/1.25 ${fonts.sans}`, color: C.yellow, letterSpacing: "-0.005em" }}>
              FIRST THE BALDWIN'S HOME, YOURS NEXT: Sign the petition today!
            </p>
          </div>

          {/* DEMAND — pulled into the hero above the form */}
          <div id="demand" className="fl-hero-demand" style={{ marginTop: 56, maxWidth: 820 }}>
            <h2 className="fl-h2 fl-h2--sm">
              Resign. Investigate. <span style={{ color: C.yellow }}>Repeal.</span>
            </h2>
            <ol style={{ margin: "28px 0 0", padding: 0, listStyle: "none", display: "grid", gap: 18, font: `500 18px/1.55 ${fonts.sans}`, color: C.bone }}>
              {[
                ["01.", "Lily Dambrosio, Minister for Energy and Resources must resign immediately."],
                ["02.", "An independent review of VicGrid's conduct & trespass in the Baldwin matter."],
                ["03.", "Immediate repeal of the forced-access powers in Victoria's energy legislation."],
              ].map(([n, t]) => (
                <li key={n} style={{ display: "grid", gridTemplateColumns: "64px 1fr", gap: 8, alignItems: "baseline" }}>
                  <span style={{ font: `800 22px/1 ${fonts.mono}`, color: C.yellow }}>{n}</span>
                  <span>{t}</span>
                </li>
              ))}
            </ol>
          </div>

          <div className="fl-hero-form" style={{ marginTop: 48, maxWidth: 720 }}>
            {signFormBlock}
          </div>
        </div>

        <Rule />

        {/* COUNTER STRIP */}
        <div className="fl-pad" style={{ paddingTop: 56, paddingBottom: 64 }}>
          <div className="fl-grid-counter">
            <div style={{ display: "flex", alignItems: "baseline", gap: 14, flexWrap: "wrap" }}>
              <div className="fl-counter-num" style={{ font: `900 96px/0.9 ${fonts.display}`, color: C.yellow, fontVariantNumeric: "tabular-nums", letterSpacing: "-0.02em" }}>{count.toLocaleString("en-AU")}</div>
              <div style={{ font: `600 14px/1.4 ${fonts.mono}`, color: C.mute, textTransform: "uppercase", letterSpacing: ".12em" }}>signatures<br/>demanding the Minister resign</div>
            </div>
            <div>
              <Eyebrow>Goal · {(p.goal || 25000).toLocaleString("en-AU")}</Eyebrow>
              <div style={{ position: "relative", height: 18, background: "rgba(245,241,232,0.08)", marginTop: 14, overflow: "hidden" }}>
                <div style={{ position: "absolute", inset: 0, width: `${Math.min(100, (count / (p.goal || 25000)) * 100).toFixed(1)}%`, background: C.yellow, transition: "width .3s ease" }} />
                <div style={{ position: "absolute", right: -2, top: -10, bottom: -10, width: 2, background: C.bone }} />
              </div>
              <div style={{ font: `500 12px/1.5 ${fonts.mono}`, color: C.mute, marginTop: 12, textTransform: "uppercase", letterSpacing: ".12em" }}>
                {Math.max(0, (p.goal || 25000) - count).toLocaleString("en-AU")} signatures to go · handover at Spring St when we hit goal.
              </div>
            </div>
          </div>
        </div>

        <Rule />

        {/* HEADLINE ANCHOR */}
        <div className="fl-pad" style={{ paddingTop: 96, paddingBottom: 96, background: C.navyDeep, textAlign: "center" }}>
          <h2 className="fl-h2" style={{ fontSize: "clamp(56px, 8vw, 120px)", lineHeight: 0.95, margin: 0 }}>
            <span style={{ color: C.yellow }}>Refusal</span> criminalised.
          </h2>
          <p style={{ margin: "36px auto 0", maxWidth: 1000, font: `600 clamp(28px, 4vw, 44px)/1.2 ${fonts.sans}`, color: C.bone, letterSpacing: "-0.01em" }}>
            First the Baldwin's home. <span style={{ color: C.yellow }}>Yours next.</span>
          </p>
        </div>

        <Rule />

        {/* STORY TIMELINE */}
        <div id="story" className="fl-pad" style={{ paddingTop: 88, paddingBottom: 64 }}>
          <Eyebrow>The Story · One Page</Eyebrow>
          <h2 className="fl-h2" style={{ marginTop: 20, maxWidth: 980 }}>From Triple Zero to <span style={{ color: C.yellow }}>Charges Dropped</span>.</h2>
          <div className="fl-grid-timeline" style={{ marginTop: 64 }}>
            <div className="fl-rail" style={{ position: "absolute", left: 220, top: 0, bottom: 0, width: 2, background: C.rule }} />
            {acts.map((a, i) => (
              <React.Fragment key={a.n}>
                <div className="fl-date-col" style={{ paddingTop: 8, textAlign: "right", paddingRight: 24, font: `700 13px/1.4 ${fonts.mono}`, color: a.highlight ? C.yellow : C.bone, textTransform: "uppercase", letterSpacing: ".12em", paddingBottom: 64 }}>
                  {a.date && <div>{a.date}</div>}
                  <div style={{ marginTop: a.date ? 8 : 0, color: a.cta ? C.yellow : C.mute, fontWeight: a.cta ? 700 : 500 }}>{a.tag}</div>
                </div>
                <div style={{ position: "relative", paddingBottom: 64, paddingLeft: 36 }}>
                  <div style={{ position: "absolute", left: -7, top: 14, width: 16, height: 16, borderRadius: 16, background: (a.highlight || a.cta) ? C.yellow : C.navyDeep, boxShadow: (a.highlight || a.cta) ? `0 0 0 4px ${C.navy}` : `inset 0 0 0 2px ${C.bone}` }} />
                  <div style={{ font: `900 22px/1 ${fonts.mono}`, color: (a.highlight || a.cta) ? C.yellow : C.bone, letterSpacing: ".04em" }}>{a.n}</div>
                  <h3
                    className="fl-act-title"
                    style={{ margin: "14px 0 0", font: `700 32px/1.15 ${fonts.sans}`, letterSpacing: "-0.01em", color: a.highlight ? C.yellow : C.bone, maxWidth: 720 }}
                    dangerouslySetInnerHTML={{ __html: a.titleHtml }}
                  />
                  {a.body && <p style={{ margin: "14px 0 0", maxWidth: 680, font: `400 16px/1.65 ${fonts.sans}`, color: C.bone }}>{a.body}</p>}
                  {a.cta && a.ctaLabel && (
                    <div style={{ marginTop: 22 }}>
                      <Btn primary mono href={a.ctaHref || "#sign"}>{a.ctaLabel.replace(/\s*[→>]+\s*$/,"")}</Btn>
                    </div>
                  )}
                </div>
              </React.Fragment>
            ))}
          </div>
        </div>

        <Rule />

        {/* DONATE — Stripe payment links */}
        <div id="donate" className="fl-donate fl-pad" style={{ paddingTop: 88, paddingBottom: 88, background: C.navyDeep }}>
          <Eyebrow>Fund the fight</Eyebrow>
          <h2 className="fl-h2" style={{ margin: "18px 0 14px" }}>Defend Aussie Farmers. <span style={{ color: C.yellow }}>Pick an amount.</span></h2>
          <p style={{ margin: "0 0 36px", maxWidth: 720, font: `400 17px/1.55 ${fonts.sans}`, color: C.bone }}>
            <strong style={{ color: C.yellow, fontWeight: 700 }}>They have billions. We have you.</strong> Every dollar puts the Baldwin's story in front of Australians who haven't heard it yet — ads, video production, distribution, organising on the ground — and keeps the pressure on the Government until they back down. All amounts in AUD. Stripe-secured.
          </p>
          <div className="fl-donate-grid" style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 0, border: `1px solid ${C.rule}` }}>
            {[
              { amount: 35,   url: "https://buy.stripe.com/14AbJ0eNg0in96H2tqbV60Q" },
              { amount: 65,   url: "https://buy.stripe.com/28EdR85cG3uzaaL2tqbV60R" },
              { amount: 135,  url: "https://buy.stripe.com/dRm9AS7kOghlaaL2tqbV60S", isDefault: true },
              { amount: 265,  url: "https://buy.stripe.com/5kQeVcfRkghlfv5fgcbV60T" },
              { amount: 550,  url: "https://buy.stripe.com/7sY5kCgVo7KP0AbgkgbV60U" },
              { amount: 1500, url: "https://buy.stripe.com/7sY4gydJcaX1dmX1pmbV60V" },
            ].map((d, i, arr) => (
              <a key={d.amount} href={d.url} onClick={markDonatePending} target="_top" rel="noopener" className={`fl-donate-tile ${d.isDefault ? "is-default" : ""}`} style={{
                display: "flex", flexDirection: "column", justifyContent: "space-between",
                padding: "28px 24px", minHeight: 160,
                borderRight: ((i + 1) % 4 !== 0 && i !== arr.length - 1) ? `1px solid ${C.rule}` : "none",
                borderBottom: i < arr.length - 2 ? `1px solid ${C.rule}` : "none",
                transition: "background .15s ease, color .15s ease",
              }}>
                <div className="fl-tile-kicker" style={{ font: `700 11px/1 ${fonts.mono}`, letterSpacing: ".18em", textTransform: "uppercase" }}>Donate</div>
                <div className="fl-tile-amount" style={{ font: `900 clamp(38px, 4vw, 56px)/0.9 ${fonts.display}`, letterSpacing: "-0.02em" }}>${d.amount}</div>
                <div className="fl-tile-cta" style={{ display: "inline-flex", alignItems: "center", gap: 8, font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>Give <span style={{ fontSize: 18 }}>→</span></div>
              </a>
            ))}
            {/* Other amount cell — uses custom-amount payment link */}
            <a href="https://buy.stripe.com/8x2fZggVo6GL1Efec8bV608" target="_top" rel="noopener" className="fl-donate-tile fl-donate-tile--other" style={{
              display: "flex", flexDirection: "column", justifyContent: "space-between",
              padding: "28px 24px", minHeight: 160,
              gridColumn: "span 2",
              transition: "background .15s ease, color .15s ease",
            }}>
              <div className="fl-tile-kicker" style={{ font: `700 11px/1 ${fonts.mono}`, letterSpacing: ".18em", textTransform: "uppercase" }}>Choose your own</div>
              <div className="fl-tile-amount" style={{ font: `900 clamp(38px, 4vw, 56px)/0.9 ${fonts.display}`, letterSpacing: "-0.02em" }}>Other</div>
              <div className="fl-tile-cta" style={{ display: "inline-flex", alignItems: "center", gap: 8, font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>Enter any amount <span style={{ fontSize: 18 }}>→</span></div>
            </a>
          </div>
          <p style={{ margin: "20px 0 0", font: `500 12px/1.5 ${fonts.mono}`, color: C.mute, letterSpacing: ".12em", textTransform: "uppercase" }}>Stripe-secured · AUD</p>
        </div>

        <Rule />

        {/* ACTION GRID */}
        <div id="actions" className="fl-pad fl-section-aft" style={{ paddingTop: 88, paddingBottom: 56, scrollMarginTop: 60 }}>
          <Eyebrow>What you do today</Eyebrow>
          <h2 className="fl-h2" style={{ margin: "18px 0 48px" }}>Three moves. <span style={{ color: C.yellow }}>You choose.</span></h2>
          <div className="fl-grid-actions">
            {actions.map((a, i) => (
              <a key={a.n} href={a.href} className="fl-action-cell" style={{
                padding: "36px 32px",
                background: a.primary ? C.yellow : "transparent",
                color: a.primary ? C.navyDeep : C.bone,
                borderRight: i < actions.length - 1 ? `1px solid ${a.primary ? "rgba(14,41,64,.18)" : C.rule}` : "none",
                display: "flex", flexDirection: "column", justifyContent: "space-between", minHeight: 320,
              }}>
                <div>
                  <div style={{ font: `700 11px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase", opacity: .7 }}>Action {a.n}</div>
                  <div className="fl-action-title" style={{ font: `800 32px/1.1 ${fonts.sans}`, marginTop: 18, letterSpacing: "-0.01em" }}>{a.t}</div>
                  <div style={{ font: `400 14px/1.55 ${fonts.sans}`, marginTop: 14, color: a.primary ? "rgba(8,24,38,.78)" : C.bone, opacity: a.primary ? 1 : .82 }}>{a.d}</div>
                </div>
                <div style={{ marginTop: 24, display: "inline-flex", alignItems: "center", gap: 10, font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>{a.cta} <span style={{ fontSize: 18 }}>→</span></div>
              </a>
            ))}
          </div>
        </div>

        {/* SHARE ROW */}
        <div id="share" className="fl-pad fl-section-aft" style={{ paddingTop: 56, paddingBottom: 56 }}>
          <Eyebrow>Share the petition</Eyebrow>
          <div className="fl-share-row" style={{ marginTop: 14, display: "flex", flexWrap: "wrap", gap: 10 }}>
            {[
              { p: "facebook", l: "Facebook", brand: "#1877F2",
                icon: <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M24 12a12 12 0 1 0-13.875 11.854V15.469H7.078V12h3.047V9.356c0-3.007 1.792-4.668 4.533-4.668 1.313 0 2.686.234 2.686.234v2.953h-1.513c-1.491 0-1.956.925-1.956 1.875V12h3.328l-.532 3.469h-2.796v8.385A12.001 12.001 0 0 0 24 12z"/></svg> },
              { p: "x",        l: "X", brand: "#FFFFFF",
                icon: <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231 5.45-6.231zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77z"/></svg> },
              { p: "whatsapp", l: "WhatsApp", brand: "#25D366",
                icon: <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.817 11.817 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.338 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24z"/></svg> },
              { p: "telegram", l: "Telegram", brand: "#29B6F6",
                icon: <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M9.78 18.65l.28-4.23 7.68-6.92c.34-.31-.07-.46-.52-.19L7.74 13.3 3.64 12c-.88-.25-.89-.86.2-1.3l15.97-6.16c.73-.33 1.43.18 1.15 1.3l-2.72 12.81c-.19.91-.74 1.13-1.5.71L12.6 16.3l-1.99 1.93c-.23.23-.42.42-.83.42z"/></svg> },
              { p: "email",    l: "Email", brand: "#F4C430",
                icon: <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg> },
            ].map(s => {
              const pageUrl = "https://farmersfightback.com";
              return (
                <a key={s.p} href={shareUrlFor(s.p, p.shareText || "Charges dropped. The Minister must resign. #ResignMinister #ChargesDropped", pageUrl)} target="_blank" rel="noopener noreferrer"
                   style={{ display: "inline-flex", alignItems: "center", gap: 10, padding: "14px 18px", background: "transparent", boxShadow: `inset 0 0 0 1.5px ${C.bone}`, color: C.bone, font: `800 13px/1 ${fonts.mono}`, letterSpacing: ".16em", textTransform: "uppercase" }}>
                  <span style={{ color: s.brand, display: "inline-flex" }}>{s.icon}</span>
                  <span>{s.l}</span>
                  <span style={{ marginLeft: "auto", fontSize: 18 }}>→</span>
                </a>
              );
            })}
          </div>
        </div>

        <Rule />

        {/* FOOTER */}
        <div className="fl-pad fl-footer" style={{ paddingTop: 40, paddingBottom: 40, background: C.navyDeep }}>
          <div style={{ display: "flex", justifyContent: "space-between", flexWrap: "wrap", gap: 12, font: `500 11px/1.5 ${fonts.mono}`, color: C.mute, textTransform: "uppercase", letterSpacing: ".12em" }}>
            <span>© Farmers Fightback 2026 · Authorised by Ben Duxson, Farmers Fightback</span>
            <span>farmersfightback.com/take-action/baldwins</span>
          </div>
        </div>
      </div>
    </>
  );
}

function PetitionPage({ slug }) {
  const all = useContent().petitions || {};
  const p = all[slug];
  const defaultReceiverUrl = useContent().petition?.receiverUrl;
  const receiverUrl = (p && p.receiverUrl) || defaultReceiverUrl;

  // Slug-specific themed templates
  if (slug === "baldwins" && p) {
    return <BaldwinFloodlight p={p} receiverUrl={receiverUrl} />;
  }

  if (!p) {
    return (
      <PageShell>
        <section className="ff-section">
          <div className="ff-wrap" style={{ textAlign: "center" }}>
            <h1 className="ff-h2">Petition not found.</h1>
            <p className="ff-lede" style={{ marginInline: "auto" }}>Try the <a href="/take-action">Take Action page</a>.</p>
          </div>
        </section>
      </PageShell>
    );
  }

  const [form, setForm] = useState({ first: "", last: "", email: "", phone: "", postcode: "", country: "AU", consent: false });
  const [errors, setErrors] = useState({});
  const [state, setState] = useState("idle");
  const update = (k) => (e) => {
    const v = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    setForm(f => ({ ...f, [k]: v }));
  };
  const validate = () => {
    const e = {};
    if (!form.first.trim()) e.first = "Required";
    if (!form.last.trim()) e.last = "Required";
    if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = "Enter a valid email";
    if (form.country === "AU" && form.postcode && !/^\d{4}$/.test(form.postcode)) e.postcode = "4-digit postcode";
    setErrors(e);
    return Object.keys(e).length === 0;
  };
  const submit = async (ev) => {
    ev.preventDefault();
    if (!validate()) return;
    setState("submitting");
    const body = new URLSearchParams({
      first_name: form.first.trim(),
      last_name: form.last.trim(),
      email: form.email.trim(),
      phone: form.phone.trim(),
      postcode: form.postcode.trim(),
      country: form.country,
      campaign: p.campaign || p.slug,
      ...getAttribution(),
    });
    try {
      if (receiverUrl) {
        await fetch(receiverUrl, { method: "POST", mode: "no-cors", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body });
      }
      window.location.assign("/donate");
    } catch { setState("error"); }
  };

  if (state === "done") {
    const newCount = (p.currentCount || 0) + 1;
    const pct = Math.min(100, (newCount / (p.goal || 1)) * 100);
    const headingHtml = (p.thanksHeadingHtml || "").replace("{{first}}", form.first);
    const lede = (p.thanksLede || "").replace("{{first}}", form.first).replace("{{count}}", newCount.toLocaleString());
    const pageUrl = "https://farmersfightback.com";
    const copyShare = () => {
      navigator.clipboard?.writeText(`${p.shareText} ${pageUrl}`);
      alert("Share link copied — paste it anywhere.");
    };
    const platforms = [
      { platform: "facebook", label: "Facebook" },
      { platform: "x",        label: "X" },
      { platform: "whatsapp", label: "WhatsApp" },
      { platform: "telegram", label: "Telegram" },
      { platform: "email",    label: "Email" },
      { platform: "copy",     label: "Copy link" },
    ];
    return (
      <PageShell>
        <section className={`ff-section ff-petition-page ff-petition-page--${p.tone || "navy"} is-done`}>
          <div className="ff-wrap ff-petition-page-thanks">
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> Signed · Thank you</span>
            <h1 className="ff-h2" dangerouslySetInnerHTML={html(headingHtml)} />
            <p className="ff-lede">{lede}</p>
            <div className="ff-petition-tally">
              <div className="ff-tally-num">{newCount.toLocaleString()}</div>
              <div className="ff-tally-label">Signatures and counting</div>
              <div className="ff-tally-bar"><div className="ff-tally-fill" style={{ width: pct.toFixed(1) + "%" }} /></div>
              <div className="ff-tally-goal">{pct.toFixed(1)}% toward our {(p.goal || 0).toLocaleString()} goal</div>
            </div>
            <h3 className="ff-h3">Share the petition</h3>
            <div className="ff-share-row">
              {platforms.map((s, i) => {
                const cls = `ff-share-btn ff-share-btn--${s.platform}`;
                if (s.platform === "copy") return <button key={i} type="button" className={cls} onClick={copyShare}>{s.label}</button>;
                return <a key={i} href={shareUrlFor(s.platform, p.shareText, pageUrl)} target="_blank" rel="noopener noreferrer" className={cls}>{s.label}</a>;
              })}
            </div>
            <div className="ff-petition-page-next">
              <a href="/#donate" className="ff-btn ff-btn--red">Chip in to the fight</a>
              <a href={p.ctaHrefBack || "/take-action"} className="ff-btn ff-btn--outline">See other campaigns</a>
            </div>
          </div>
        </section>
      </PageShell>
    );
  }

  const remaining = Math.max(0, (p.nextMilestone || 0) - (p.currentCount || 0));
  const milestonePct = Math.min(100, ((p.currentCount || 0) / (p.nextMilestone || 1)) * 100);

  const formBlock = (
    <form id="sign" className="ff-action-form" onSubmit={submit} noValidate>
      <div className="ff-form-header">
        <div>
          <div className="ff-form-count">{(p.currentCount || 0).toLocaleString()}</div>
          <div className="ff-form-count-l">have signed — {remaining.toLocaleString()} to {(((p.nextMilestone || 0) / 1000) | 0) + "k"}</div>
        </div>
        <div className="ff-form-bar"><div style={{ width: milestonePct.toFixed(1) + "%" }} /></div>
      </div>
      <div className="ff-form-row">
        <Field label={<>First name <span className="ff-req">*</span></>} error={errors.first}><input value={form.first} onChange={update("first")} autoComplete="given-name" required aria-required="true" /></Field>
        <Field label={<>Last name <span className="ff-req">*</span></>} error={errors.last}><input value={form.last} onChange={update("last")} autoComplete="family-name" required aria-required="true" /></Field>
      </div>
      <Field label={<>Email <span className="ff-req">*</span></>} error={errors.email}><input type="email" value={form.email} onChange={update("email")} autoComplete="email" required aria-required="true" /></Field>
      <div className="ff-form-row">
        <Field label="Postcode" error={errors.postcode}>
          <input value={form.postcode} onChange={update("postcode")} inputMode="numeric" maxLength={4} autoComplete="postal-code" placeholder="3000" />
        </Field>
        <Field label="Phone">
          <input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel" placeholder="0400 000 000" />
        </Field>
      </div>
      <button className="ff-btn ff-btn--red ff-btn--block ff-btn--lg" disabled={state === "submitting"}>
        {state === "submitting" ? p.submittingLabel : p.submitLabel}
      </button>
      {state === "error" && <p className="ff-form-fine" style={{ color: "var(--ff-red)" }}>Something went wrong. Please try again.</p>}
    </form>
  );

  if (p.layout === "long-form") {
    return (
      <PageShell>
        {/* Hero — full-width navy */}
        <section className={`ff-petition-hero ff-petition-hero--${p.tone || "navy"} ${p.heroImage ? "ff-imghero ff-imghero--light" : ""}`} style={p.heroImage ? { backgroundImage: `url(${p.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
          {p.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
          <div className="ff-wrap">
            <h1 className="ff-petition-hero-title" dangerouslySetInnerHTML={html(p.headingHtml || p.heading || "")} />
            {p.subheading && <p className="ff-petition-hero-sub">{p.subheading}</p>}
          </div>
        </section>

        <div className="ff-petition-stack">
        {/* Context paragraphs */}
        {p.context && p.context.length > 0 && (
          <section className="ff-section ff-petition-context">
            <div className="ff-wrap ff-petition-context-inner">
              {p.context.map((para, i) => <p key={i} dangerouslySetInnerHTML={html(para)} />)}
            </div>
          </section>
        )}

        {/* Petition statement card + form */}
        <section className="ff-section ff-petition-form-section">
          <div className="ff-wrap ff-petition-form-grid">
            <div className="ff-petition-statement">
              {p.petitionDeclaration && (
                <div className="ff-petition-declaration">
                  {p.petitionDeclarationKicker && <span className="ff-petition-declaration-kicker">{p.petitionDeclarationKicker}</span>}
                  {p.petitionDeclarationLine1 && <p className="ff-petition-declaration-line1">{p.petitionDeclarationLine1}</p>}
                  <p className="ff-petition-declaration-body">{p.petitionDeclaration}</p>
                  {p.petitionAuthorised && <p className="ff-petition-declaration-auth">{p.petitionAuthorised}</p>}
                </div>
              )}
            </div>
            <div>{formBlock}</div>
          </div>
          {p.trustBadges && p.trustBadges.length > 0 && (
            <div className="ff-wrap ff-petition-trust-row">
              <ul className="ff-trust-row ff-trust-row--inline">
                {p.trustBadges.map((b, i) => (
                  <li key={i} className="ff-trust-badge ff-trust-badge--lg">
                    <span className={`ff-trust-icon ff-trust-icon--${b.icon}`} aria-hidden="true" />
                    <span>
                      <strong>{b.label}</strong>
                      {b.sub && <em>{b.sub}</em>}
                    </span>
                  </li>
                ))}
              </ul>
            </div>
          )}
        </section>
        </div>

        {/* Why this matters */}
        {p.whyMatters && p.whyMatters.length > 0 && (
          <section className="ff-section ff-why-matters">
            <div className="ff-wrap">
              {p.whyMattersHeading && (
                <header className="ff-why-matters-head">
                  <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> The case</span>
                  <h2 className="ff-h2">{p.whyMattersHeading}</h2>
                </header>
              )}
              <div className="ff-why-matters-grid">
                {p.whyMatters.map((wm, i) => (
                  <article key={i} className="ff-why-card">
                    {wm.image && (
                      <div className="ff-why-media">
                        <img src={wm.image} alt={wm.imageAlt || ""} loading="lazy" />
                      </div>
                    )}
                    <div className="ff-why-body">
                      <span className="ff-why-num">{String(i + 1).padStart(2, "0")}</span>
                      <h3 className="ff-why-h">{wm.heading}</h3>
                      <p>{wm.body}</p>
                    </div>
                  </article>
                ))}
              </div>
            </div>
          </section>
        )}

        {/* Bottom CTA */}
        {p.bottomCta && (
          <section className="ff-petition-bottom-cta">
            <div className="ff-wrap ff-petition-bottom-cta-inner">
              <h2 className="ff-h2 ff-h2--light">{p.bottomCta.heading}</h2>
              <p>{p.bottomCta.body}</p>
              <div className="ff-petition-bottom-actions">
                <a href={p.bottomCta.primaryAnchor || "#sign"} className="ff-btn ff-btn--red ff-btn--lg">{p.bottomCta.primaryLabel}</a>
                <a href={p.bottomCta.secondaryHref || "/#donate"} className="ff-btn ff-btn--ghost ff-btn--lg">{p.bottomCta.secondaryLabel}</a>
              </div>
              <div className="ff-petition-bottom-share">
                <span className="ff-petition-bottom-share-l">Share the petition</span>
                <div className="ff-share-row">
                  {[
                    { platform: "facebook", label: "Facebook" },
                    { platform: "x",        label: "X" },
                    { platform: "whatsapp", label: "WhatsApp" },
                    { platform: "email",    label: "Email" },
                  ].map((s, i) => {
                    return <a key={i} href={shareUrlFor(s.platform, p.shareText, "https://farmersfightback.com")} target="_blank" rel="noopener noreferrer" className={`ff-share-btn ff-share-btn--${s.platform}`}>{s.label}</a>;
                  })}
                </div>
              </div>
            </div>
          </section>
        )}
      </PageShell>
    );
  }

  return (
    <PageShell>
      <section className={`ff-section ff-petition-page ff-petition-page--${p.tone || "navy"}`}>
        <div className="ff-wrap ff-petition-page-inner">
          <div className="ff-petition-page-copy">
            <a href={p.ctaHrefBack || "/take-action"} className="ff-back-link">← All campaigns</a>
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {p.eyebrow}</span>
            <h1 className="ff-h2">{p.heading}</h1>
            <p className="ff-lede">{p.lede}</p>
            {p.demands && p.demands.length > 0 && (
              <div className="ff-demands">
                {p.demandsIntro && <p className="ff-demands-intro">{p.demandsIntro}</p>}
                <ol className="ff-demands-list">
                  {p.demands.map((d, i) => (
                    <li key={i} className="ff-demand">
                      <span className="ff-demand-numeral">{d.numeral}</span>
                      <span className="ff-demand-text">{d.text}</span>
                    </li>
                  ))}
                </ol>
              </div>
            )}
          </div>
          <form className="ff-action-form" onSubmit={submit} noValidate>
            <div className="ff-form-header">
              <div>
                <div className="ff-form-count">{(p.currentCount || 0).toLocaleString()}</div>
                <div className="ff-form-count-l">have signed — {remaining.toLocaleString()} to {(((p.nextMilestone || 0) / 1000) | 0) + "k"}</div>
              </div>
              <div className="ff-form-bar"><div style={{ width: milestonePct.toFixed(1) + "%" }} /></div>
            </div>
            <div className="ff-form-row">
              <Field label="First name" error={errors.first}><input value={form.first} onChange={update("first")} autoComplete="given-name" /></Field>
              <Field label="Last name" error={errors.last}><input value={form.last} onChange={update("last")} autoComplete="family-name" /></Field>
            </div>
            <Field label="Email" error={errors.email}><input type="email" value={form.email} onChange={update("email")} autoComplete="email" /></Field>
            <div className="ff-form-row">
              <Field label="Country">
                <select value={form.country} onChange={update("country")} autoComplete="country">
                  <option value="AU">Australia</option><option value="NZ">New Zealand</option><option value="GB">United Kingdom</option>
                  <option value="US">United States</option><option value="CA">Canada</option><option value="OTHER">Other</option>
                </select>
              </Field>
              <Field label="Postcode" error={errors.postcode}>
                <input value={form.postcode} onChange={update("postcode")} inputMode={form.country === "AU" ? "numeric" : "text"} maxLength={form.country === "AU" ? 4 : 10} autoComplete="postal-code" />
              </Field>
            </div>
            <Field label="Phone (optional)"><input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel" placeholder="0400 000 000" /></Field>
            <label className={`ff-consent ${errors.consent ? "has-error" : ""}`}>
              <input type="checkbox" checked={form.consent} onChange={update("consent")} />
              <span>I agree to receive campaign updates from Farmers Fightback. I can unsubscribe at any time.</span>
            </label>
            <button className="ff-btn ff-btn--red ff-btn--block ff-btn--lg" disabled={state === "submitting"}>
              {state === "submitting" ? p.submittingLabel : p.submitLabel}
            </button>
            {state === "error" && <p className="ff-form-fine" style={{ color: "var(--ff-red)" }}>Something went wrong. Please try again.</p>}
            <p className="ff-form-fine">Authorised by Ben Duxson, Farmers Fightback.</p>
          </form>
        </div>
      </section>
    </PageShell>
  );
}

// ---------- App (router) ----------
// ---------- The Fight page ----------
function TheFightPage() {
  const c = useContent().theFight;
  return (
    <PageShell>
      <section className={`ff-section ff-thefight-hero ${c.heroImage ? "ff-imghero" : ""}`} style={c.heroImage ? { backgroundImage: `url(${c.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
        {c.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
        <div className="ff-wrap ff-thefight-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-thefight-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      <section className="ff-section ff-thefight-grid-wrap">
        <div className="ff-wrap">
          <div className="ff-thefight-grid">
            {(c.panels || []).map((p, i) => {
              const href = p.href || (i === (c.panels.length - 1) ? "/take-action/baldwins#sign" : "/take-action/hold-the-gate#sign");
              return (
                <a key={i} href={href} className={`ff-thefight-panel ff-thefight-panel--${p.tone || "navy"}`}>
                  {p.image && (
                    <div className="ff-thefight-panel-media">
                      <img src={p.image} alt={p.imageAlt || ""} loading="lazy" />
                    </div>
                  )}
                  <div className="ff-thefight-panel-body">
                    <span className="ff-card-kicker">{p.kicker}</span>
                    <h3 className="ff-thefight-panel-title">{p.title}</h3>
                    <p>{p.body}</p>
                    <span className="ff-thefight-panel-cta">Sign the petition <span aria-hidden="true">→</span></span>
                  </div>
                </a>
              );
            })}
          </div>
        </div>
      </section>
      <section className="ff-section ff-thefight-cta">
        <div className="ff-wrap ff-thefight-cta-inner">
          <h2 className="ff-h2 ff-h2--light">{c.ctaHeading}</h2>
          <p>{c.ctaBody}</p>
          <div className="ff-thefight-cta-buttons">
            {(c.ctaButtons || []).map((b, i) => (
              <a key={i} href={b.href} className={`ff-btn ff-btn--lg ${b.primary ? "ff-btn--red" : "ff-btn--ghost"}`}>{b.label}</a>
            ))}
          </div>
        </div>
      </section>
    </PageShell>
  );
}

// ---------- Contact page ----------
function ContactPage() {
  const c = useContent().contact;
  const receiverUrl = c.receiverUrl || useContent().petition?.receiverUrl;
  const [form, setForm] = useState({ first: "", last: "", email: "", phone: "", message: "" });
  const [state, setState] = useState("idle");
  const [errors, setErrors] = useState({});
  const update = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));
  const submit = async (ev) => {
    ev.preventDefault();
    const e = {};
    if (!form.first.trim()) e.first = "Required";
    if (!form.last.trim()) e.last = "Required";
    if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = "Enter a valid email";
    if (!form.message.trim()) e.message = "Tell us what's going on";
    setErrors(e);
    if (Object.keys(e).length) return;
    setState("submitting");
    const body = new URLSearchParams({
      first_name: form.first.trim(),
      last_name: form.last.trim(),
      email: form.email.trim(),
      phone: form.phone.trim(),
      message: form.message.trim(),
      ...getAttribution(),
    });
    try {
      if (receiverUrl) await fetch(receiverUrl, { method: "POST", mode: "no-cors", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body });
      setState("done");
    } catch { setState("error"); }
  };
  return (
    <PageShell>
      <section className={`ff-section ff-contact-hero ${c.heroImage ? "ff-imghero" : ""}`} style={c.heroImage ? { backgroundImage: `url(${c.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
        {c.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
        <div className="ff-wrap ff-contact-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-contact-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      <section className="ff-section ff-contact-body">
        <div className="ff-wrap ff-contact-body-inner ff-contact-body-inner--single">
          <form className="ff-action-form ff-contact-form" onSubmit={submit} noValidate>
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.form?.heading || "Send us a message"}</span>
            {c.form?.lede && <p className="ff-lede" style={{ margin: "12px 0 22px", fontSize: 15 }}>{c.form.lede}</p>}
            {state === "done" ? (
              <div style={{ background: "var(--ff-paper-2)", padding: 28, borderRadius: 6, textAlign: "center" }}>
                <strong style={{ fontSize: 20, color: "var(--ff-navy)" }}>{c.form?.doneHeading}</strong>
                <p style={{ margin: "10px 0 0", color: "var(--ff-ink-2)" }}>{c.form?.doneBody}</p>
              </div>
            ) : (
              <>
                <div className="ff-form-row">
                  <Field label="First name *" error={errors.first}><input value={form.first} onChange={update("first")} autoComplete="given-name" required /></Field>
                  <Field label="Last name *" error={errors.last}><input value={form.last} onChange={update("last")} autoComplete="family-name" required /></Field>
                </div>
                <Field label="Email *" error={errors.email}><input type="email" value={form.email} onChange={update("email")} autoComplete="email" required /></Field>
                <Field label="Phone"><input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel" inputMode="tel" placeholder="0400 000 000" /></Field>
                <Field label="Message *" error={errors.message}>
                  <textarea value={form.message} onChange={update("message")} rows={6} required style={{ width: "100%", padding: "12px 14px", fontFamily: "var(--ff-sans)", fontSize: 15, border: "1.5px solid var(--ff-rule-2)", background: "#fff", borderRadius: "var(--ff-radius)", resize: "vertical" }} />
                </Field>
                <button className="ff-btn ff-btn--red ff-btn--block ff-btn--lg" type="submit" disabled={state === "submitting"}>
                  {state === "submitting" ? (c.form?.submittingLabel || "Sending…") : (c.form?.submitLabel || "Send message →")}
                </button>
                {state === "error" && <p className="ff-form-fine" style={{ color: "var(--ff-red)" }}>Something went wrong. Please try again.</p>}
              </>
            )}
          </form>
        </div>
      </section>
    </PageShell>
  );
}

// ---------- Media page ----------
function MediaPage() {
  const c = useContent().mediaPage;
  return (
    <PageShell>
      <section className={`ff-section ff-media-hero ${c.heroImage ? "ff-imghero" : ""}`} style={c.heroImage ? { backgroundImage: `url(${c.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
        {c.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
        <div className="ff-wrap ff-media-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-media-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      {c.primaryEmail && (
        <section className="ff-section ff-media-contact">
          <div className="ff-wrap ff-media-contact-inner">
            <div>
              <span className="ff-card-kicker">{c.primaryEmail.label}</span>
              <a href={`mailto:${c.primaryEmail.email}`} className="ff-media-email">{c.primaryEmail.email}</a>
              <p>{c.primaryEmail.blurb}</p>
            </div>
            <a href={`mailto:${c.primaryEmail.email}`} className="ff-btn ff-btn--red ff-btn--lg">Email the media team →</a>
          </div>
        </section>
      )}
      {c.spokespeople && c.spokespeople.length > 0 && (
        <section className="ff-section ff-media-spokes">
          <div className="ff-wrap">
            <h2 className="ff-h2" style={{ fontSize: "clamp(28px, 3.4vw, 42px)", marginBottom: 28 }}>Spokespeople.</h2>
            <ul className="ff-media-spokes-grid">
              {c.spokespeople.map((s, i) => (
                <li key={i} className="ff-media-spoke">
                  <h3>{s.name}</h3>
                  <span className="ff-card-kicker">{s.role}</span>
                  <p>{s.blurb}</p>
                </li>
              ))}
            </ul>
          </div>
        </section>
      )}
      {c.outlets && c.outlets.length > 0 && (
        <section className="ff-section ff-media-outlets">
          <div className="ff-wrap">
            <h2 className="ff-h2" style={{ fontSize: "clamp(28px, 3.4vw, 42px)" }}>{c.outletsHeading || "Recent coverage"}</h2>
            {c.outletsLede && <p className="ff-lede" style={{ margin: "12px 0 24px" }}>{c.outletsLede}</p>}
            <ul className="ff-media-outlets-list">
              {c.outlets.map((o, i) => (
                <li key={i} className="ff-media-outlet">
                  <span className="ff-media-outlet-name">{o.outlet}</span>
                  <a href={o.url || "#"} className="ff-media-outlet-headline">{o.headline}</a>
                </li>
              ))}
            </ul>
          </div>
        </section>
      )}
      {c.assets && c.assets.length > 0 && (
        <section className="ff-section ff-media-assets">
          <div className="ff-wrap">
            <h2 className="ff-h2" style={{ fontSize: "clamp(24px, 3vw, 36px)", marginBottom: 20 }}>Press kit & assets.</h2>
            <ul className="ff-media-assets-list">
              {c.assets.map((a, i) => (
                <li key={i}><a href={a.href} className="ff-link ff-link--red">{a.label}</a></li>
              ))}
            </ul>
          </div>
        </section>
      )}
      {c.fineprint && <p className="ff-aboutus-authorised">{c.fineprint}</p>}
    </PageShell>
  );
}

// ---------- Donor page ("They have billions. We have you.") ----------
function DonorPage() {
  const c = useContent().donorPage;
  const [monthly, setMonthly] = useState(false);
  const tiers = monthly ? (c.monthlyAmounts || []) : (c.amounts || []);
  const defaultPick = (tiers.find(t => t.isDefault) || tiers[Math.min(2, tiers.length - 1)] || {}).amount;
  const [picked, setPicked] = useState(defaultPick);
  useEffect(() => { setPicked(defaultPick); }, [monthly]);
  useEffect(() => {
    const el = document.getElementById("donate");
    if (!el) return;
    const t = setTimeout(() => el.scrollIntoView({ behavior: "smooth", block: "start" }), 80);
    return () => clearTimeout(t);
  }, []);
  const selected = tiers.find(t => t.amount === picked);
  const ctaUrl = selected ? selected.url : c.otherUrl;
  const ctaLabel = `Donate $${picked}${monthly ? " / month" : ""} →`;
  return (
    <PageShell>
      <section className={`ff-section ff-give-hero ${c.heroImage ? "ff-imghero ff-imghero--dark" : ""}`} style={c.heroImage ? { backgroundImage: `url(${c.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
        {c.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
        <div className="ff-wrap ff-give-hero-inner">
          <div className="ff-give-hero-copy">
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
            <h1 className="ff-h2 ff-give-h1">{c.heading}</h1>
            <p className="ff-give-lede">{c.lede}</p>
            <ul className="ff-give-trust">
              <li>SSL Secured</li><li>Stripe</li><li>All amounts in AUD</li>
            </ul>
          </div>
          <div id="donate" className="ff-give-widget">
            <div className="ff-give-freq" role="tablist" aria-label="Donation frequency">
              <button type="button" role="tab" aria-selected={!monthly} className={!monthly ? "is-on" : ""} onClick={() => setMonthly(false)}>One-off</button>
              <button type="button" role="tab" aria-selected={monthly}  className={monthly  ? "is-on" : ""} onClick={() => setMonthly(true)}>Monthly</button>
            </div>
            <div className="ff-give-chips">
              {tiers.map(t => (
                <button key={t.amount} type="button" className={`ff-give-chip ${picked === t.amount ? "is-on" : ""}`} onClick={() => setPicked(t.amount)}>
                  <span className="ff-give-chip-amt">${t.amount}{monthly && <small>/mo</small>}</span>
                  {t.tag && <span className="ff-give-chip-tag">{t.tag}</span>}
                </button>
              ))}
              <a href={c.otherUrl} target="_top" rel="noopener" className="ff-give-chip ff-give-chip--other">
                <span className="ff-give-chip-amt">Other</span>
                <span className="ff-give-chip-tag">Choose your own</span>
              </a>
            </div>
            <a href={ctaUrl} target="_top" rel="noopener" className="ff-btn ff-btn--red ff-btn--block ff-btn--lg ff-give-cta">{ctaLabel}</a>
            <p className="ff-give-fineprint">{c.fineprint}</p>
          </div>
        </div>
      </section>
      {c.amounts && c.amounts.some(a => a.tag) && (
        <section className="ff-section ff-give-where">
          <div className="ff-wrap">
            <h2 className="ff-h2 ff-give-where-h">Where it goes.</h2>
            <ul className="ff-give-where-list">
              {c.amounts.filter(a => a.tag).map(a => (
                <li key={a.amount} className="ff-give-where-row">
                  <span className="ff-give-where-amt">${a.amount}</span>
                  <span className="ff-give-where-tag">{a.tag}</span>
                </li>
              ))}
            </ul>
          </div>
        </section>
      )}
      {c.achievements && <DonorAchievements cfg={c.achievements} />}
    </PageShell>
  );
}

function DonorAchievements({ cfg }) {
  const [imgSrc, setImgSrc] = useState(cfg.image);
  const onErr = () => { if (cfg.imageFallback && imgSrc !== cfg.imageFallback) setImgSrc(cfg.imageFallback); };
  return (
    <section className="ff-section ff-give-wins">
      <div className="ff-wrap ff-give-wins-inner">
        <div className="ff-give-wins-media">
          <img src={imgSrc} alt={cfg.imageAlt || ""} onError={onErr} loading="lazy" />
        </div>
        <div className="ff-give-wins-copy">
          {cfg.heading && <h2 className="ff-h2 ff-give-wins-h">{cfg.heading}</h2>}
          <ul className="ff-give-wins-list">
            {(cfg.bullets || []).map((b, i) => (
              <li key={i}><span className="ff-give-wins-tick" aria-hidden="true">✓</span><span>{b}</span></li>
            ))}
          </ul>
          {cfg.kicker && <p className="ff-give-wins-kicker">{cfg.kicker}</p>}
        </div>
      </div>
    </section>
  );
}

// ---------- Volunteer page ----------
function VolunteerPage() {
  const c = useContent().volunteer;
  const [form, setForm] = useState({ first: "", last: "", email: "", phone: "", postcode: "", roles: [] });
  const [state, setState] = useState("idle");
  const [errors, setErrors] = useState({});
  const receiverUrl = useContent().petition?.receiverUrl;
  const toggleRole = (r) => setForm(f => ({ ...f, roles: f.roles.includes(r) ? f.roles.filter(x => x !== r) : [...f.roles, r] }));
  const submit = async (ev) => {
    ev.preventDefault();
    const e = {};
    if (!form.first.trim()) e.first = "Required";
    if (!form.last.trim()) e.last = "Required";
    if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = "Enter a valid email";
    if (!form.phone.trim()) e.phone = "Required";
    setErrors(e);
    if (Object.keys(e).length) return;
    setState("submitting");
    const body = new URLSearchParams({
      first_name: form.first.trim(), last_name: form.last.trim(),
      email: form.email.trim(), phone: form.phone.trim(), postcode: form.postcode.trim(),
      roles: form.roles.join(", "), campaign: "Volunteer",
      ...getAttribution(),
    });
    try {
      if (receiverUrl) await fetch(receiverUrl, { method: "POST", mode: "no-cors", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body });
      window.location.assign("/donate");
    } catch { setState("error"); }
  };
  return (
    <PageShell>
      <section className={`ff-section ff-vol-hero ${c.heroImage ? "ff-imghero" : ""}`} style={c.heroImage ? { backgroundImage: `url(${c.heroImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" } : undefined}>
        {c.heroImage && <span className="ff-imghero-scrim" aria-hidden="true" />}
        <div className="ff-wrap ff-vol-hero-inner">
          <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.eyebrow}</span>
          <h1 className="ff-h2 ff-vol-h1">{c.heading}</h1>
          <p className="ff-lede">{c.lede}</p>
        </div>
      </section>
      <section className="ff-section ff-vol-roles">
        <div className="ff-wrap">
          <h2 className="ff-h2" style={{ fontSize: "clamp(28px, 3.4vw, 44px)", marginBottom: 8 }}>{c.rolesHeading}</h2>
          <p className="ff-lede" style={{ marginBottom: 28 }}>{c.rolesIntro}</p>
          <ul className="ff-vol-roles-grid">
            {(c.roles || []).map((r, i) => (
              <li key={i} className="ff-vol-role">
                <h3>{r.title}</h3>
                <p>{r.body}</p>
              </li>
            ))}
          </ul>
        </div>
      </section>
      <section className="ff-section ff-vol-form-section">
        <div className="ff-wrap ff-vol-form-wrap">
          <div className="ff-vol-form-head">
            <span className="ff-eyebrow"><span className="ff-eyebrow-dot" /> {c.formHeading}</span>
            <h2 className="ff-h2" style={{ fontSize: "clamp(28px, 3.4vw, 44px)" }}>{c.formSubheading}</h2>
          </div>
          {state === "done" ? (
            <div className="ff-action-form" style={{ textAlign: "center" }}>
              <h3 className="ff-h3">{c.doneHeading}</h3>
              <p style={{ color: "var(--ff-ink-2)", marginTop: 8 }}>{c.doneBody}</p>
            </div>
          ) : (
            <form className="ff-action-form" onSubmit={submit} noValidate>
              <div className="ff-form-row">
                <Field label="First name *" error={errors.first}><input value={form.first} onChange={(e) => setForm(f => ({ ...f, first: e.target.value }))} autoComplete="given-name" required /></Field>
                <Field label="Last name *" error={errors.last}><input value={form.last} onChange={(e) => setForm(f => ({ ...f, last: e.target.value }))} autoComplete="family-name" required /></Field>
              </div>
              <Field label="Email *" error={errors.email}><input type="email" value={form.email} onChange={(e) => setForm(f => ({ ...f, email: e.target.value }))} autoComplete="email" required /></Field>
              <div className="ff-form-row">
                <Field label="Mobile *" error={errors.phone}><input type="tel" value={form.phone} onChange={(e) => setForm(f => ({ ...f, phone: e.target.value }))} autoComplete="tel" required placeholder="0400 000 000" /></Field>
                <Field label="Postcode"><input value={form.postcode} onChange={(e) => setForm(f => ({ ...f, postcode: e.target.value }))} inputMode="numeric" maxLength={4} autoComplete="postal-code" /></Field>
              </div>
              <div className={`ff-field ff-field--group`}>
                <span className="ff-field-label">{c.rolesFieldLabel || "Which roles interest you?"}</span>
                <div className="ff-vol-role-checks">
                  {(c.roles || []).map((r, i) => (
                    <label key={i} className={`ff-vol-role-check ${form.roles.includes(r.title) ? "is-on" : ""}`}>
                      <input type="checkbox" checked={form.roles.includes(r.title)} onChange={() => toggleRole(r.title)} />
                      <span className="ff-vol-role-check-l">{r.title}</span>
                    </label>
                  ))}
                </div>
              </div>
              <button className="ff-btn ff-btn--red ff-btn--block ff-btn--lg" disabled={state === "submitting"}>
                {state === "submitting" ? c.submittingLabel : c.submitLabel}
              </button>
            </form>
          )}
        </div>
      </section>
      <section className="ff-section ff-vol-alt">
        <div className="ff-wrap ff-vol-alt-inner">
          <h2 className="ff-h3">{c.altHeading}</h2>
          <p>{c.altBody}</p>
          <div className="ff-vol-alt-links">
            {(c.altLinks || []).map((l, i) => <a key={i} href={l.href} className="ff-link ff-link--red">{l.label}</a>)}
          </div>
        </div>
      </section>
    </PageShell>
  );
}

function App() {
  const [content, setContent] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    captureAttribution();
    fetch(CONTENT_URL, { cache: "no-cache" })
      .then(r => { if (!r.ok) throw new Error(r.status); return r.json(); })
      .then(setContent)
      .catch(e => setError(e.message || "Failed to load content"));
  }, []);

  if (error) {
    return (
      <div style={{ padding: "60px 24px", textAlign: "center", fontFamily: "system-ui" }}>
        <h2>Couldn't load site content</h2>
        <p style={{ color: "#666" }}>Could not fetch <code>{CONTENT_URL}</code> ({error}).</p>
      </div>
    );
  }
  if (!content) return null;

  const root = document.getElementById("root");
  const page = (root && root.dataset && root.dataset.page) || "home";
  const slug = (root && root.dataset && root.dataset.petition) || "";

  let view;
  if (page === "news") view = <NewsPage />;
  else if (page === "take-action") view = <TakeActionIndex />;
  else if (page === "petition") view = <PetitionPage slug={slug} />;
  else if (page === "the-fight") view = <TheFightPage />;
  else if (page === "contact") view = <ContactPage />;
  else if (page === "media") view = <MediaPage />;
  else if (page === "donate") view = <DonorPage />;
  else if (page === "volunteer") view = <VolunteerPage />;
  else view = <HomePage />;

  return <ContentContext.Provider value={content}>{view}</ContentContext.Provider>;
}

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