// M.M Sainte-Croix — site app (v2: dark + orange, editorial dispatch)

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

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#ff5b27",
  "headline": "playful",
  "showCursor": true,
  "grain": true
}/*EDITMODE-END*/;

const ACCENTS = ["#ff5b27", "#ff8a4a", "#e84a1c", "#d97757", "#ffb547"];

// ───────── Hooks ─────────
function useReveal() {
  useEffect(() => {
    const els = Array.from(document.querySelectorAll(".reveal"));
    if (!("IntersectionObserver" in window)) {
      els.forEach(e => e.classList.add("in"));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(en => {
        if (en.isIntersecting) {
          en.target.classList.add("in");
          io.unobserve(en.target);
        }
      });
    }, { threshold: 0.12 });
    els.forEach(e => io.observe(e));
    return () => io.disconnect();
  }, []);
}

function useScroll() {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const bar = document.getElementById("scrollBar");
    const onS = () => {
      setScrolled(window.scrollY > 8);
      if (bar) {
        const h = document.documentElement.scrollHeight - window.innerHeight;
        const p = h > 0 ? (window.scrollY / h) * 100 : 0;
        bar.style.width = p + "%";
      }
    };
    onS();
    window.addEventListener("scroll", onS, { passive: true });
    return () => window.removeEventListener("scroll", onS);
  }, []);
  return scrolled;
}

function useCursorBlob(enabled) {
  useEffect(() => {
    const blob = document.getElementById("cursorBlob");
    if (!blob) return;
    const fine = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
    document.body.classList.toggle("has-fine-pointer", fine && enabled);
    if (!fine || !enabled) {
      blob.classList.remove("is-on", "is-hot");
      return;
    }

    let raf = 0;
    let x = innerWidth / 2, y = innerHeight / 2, tx = x, ty = y;
    const tick = () => {
      x += (tx - x) * 0.22;
      y += (ty - y) * 0.22;
      blob.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%) scale(var(--s,0))`;
      raf = requestAnimationFrame(tick);
    };
    const onMove = (e) => { tx = e.clientX; ty = e.clientY; blob.classList.add("is-on"); };
    const onLeave = () => blob.classList.remove("is-on");
    const onOver = (e) => {
      const t = e.target;
      if (!(t instanceof Element)) return;
      const hot = t.closest("a, button, .svc-toc-item, .work-card, .interest-chip, .plan, .nav-cta");
      blob.classList.toggle("is-hot", !!hot);
    };
    addEventListener("mousemove", onMove);
    addEventListener("mouseleave", onLeave);
    addEventListener("mouseover", onOver);
    raf = requestAnimationFrame(tick);
    return () => {
      cancelAnimationFrame(raf);
      removeEventListener("mousemove", onMove);
      removeEventListener("mouseleave", onLeave);
      removeEventListener("mouseover", onOver);
      blob.classList.remove("is-on", "is-hot");
    };
  }, [enabled]);
}

function useClock() {
  const [t, setT] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setT(new Date()), 1000 * 30);
    return () => clearInterval(id);
  }, []);
  // Martinique time (GMT-4)
  const fmt = new Intl.DateTimeFormat("en-GB", {
    hour: "2-digit", minute: "2-digit", hour12: false, timeZone: "America/Martinique"
  });
  return fmt.format(t);
}

// ───────── Status strip ─────────
function StatusStrip() {
  const time = useClock();
  return (
    <div className="status">
      <div className="shell status-inner">
        <div className="status-left">
          <span className="status-pulse">Open · accepting briefs</span>
          <span className="hide-sm status-sep">/</span>
          <span className="hide-sm">Fort-de-France · GMT-4</span>
        </div>
        <div className="status-right">
          <span className="hide-sm">Practice opened 2026</span>
          <span className="status-sep">/</span>
          <span>{time} FDF</span>
        </div>
      </div>
    </div>
  );
}

// ───────── Nav ─────────
function Nav() {
  const scrolled = useScroll();
  return (
    <nav className={"nav" + (scrolled ? " is-scrolled" : "")} data-screen-label="nav">
      <div className="shell nav-inner">
        <a href="#top" className="brand" aria-label="M.M Sainte-Croix home">
          <span className="brand-mark">M.M Sainte<span className="amp">–</span>Croix</span>
          <span className="brand-meta">Independent operator · Est. 2026</span>
        </a>
        <div className="nav-links">
          <a href="#services"   data-no="02">Services</a>
          <a href="#approach"   data-no="03">Approach</a>
          <a href="#manifesto"  data-no="04">Manifesto</a>
          <a href="#engagement" data-no="05">Engagement</a>
          <a href="#operations" data-no="06">Compliance</a>
        </div>
        <a href="#contact" className="nav-cta">
          Start a project
          <span className="nav-cta-arrow">→</span>
        </a>
      </div>
    </nav>
  );
}

// ───────── Hero ─────────
function Hero({ headlineVariant }) {
  return (
    <section className="shell hero" id="top" data-screen-label="01 Hero">
      <div className="hero-tags">
        <span className="hero-tag is-accent">
          <span className="hero-tag-dot" />
          Open · taking briefs
        </span>
        <span className="hero-tag">B2B SaaS</span>
        <span className="hero-tag">Developer tools</span>
        <span className="hero-tag">AI infrastructure</span>
        <span className="hero-tag">Fintech</span>
        <span className="hero-tag">Vertical software</span>
      </div>

      {headlineVariant === "direct" ? (
        <h1 className="h1">
          Marketing that <em>compounds.</em><br/>
          Built like <span className="accent-word">software.</span>
        </h1>
      ) : headlineVariant === "bold" ? (
        <h1 className="h1">
          We <em>operate</em><br/>
          your <span className="accent-word">growth stack.</span>
        </h1>
      ) : (
        <h1 className="h1">
          A marketing studio<br/>
          that <em>thinks</em> like a<br/>
          <span className="accent-word">product team.</span>
        </h1>
      )}

      <div className="hero-foot">
        <div>
          <p className="hero-lede">
            <strong>M.M Sainte-Croix</strong> is an independent operator based
            in Fort-de-France, Martinique, designing, shipping and running
            modern growth systems for software companies — from positioning
            and brand to lifecycle, paid, and the in-house dashboards that
            keep it all honest.
          </p>
          <div className="hero-actions">
            <a className="btn-primary" href="#contact">
              Book an intro call
              <span className="pip">→</span>
            </a>
            <a className="btn-ghost" href="#engagement">
              See how I work
            </a>
          </div>
        </div>

        <aside className="hero-side">
          <div className="hero-side-row">
            <span className="k">Based</span>
            <span className="v">Fort-de-France, Martinique <em>· Remote-first.</em><br/><small>EU &amp; US time zones, async-first.</small></span>
          </div>
          <div className="hero-side-row">
            <span className="k">Operating model</span>
            <span className="v"><em>Retainer · Sprint · Embedded.</em></span>
          </div>
          <div className="hero-side-row">
            <span className="k">Capacity</span>
            <span className="v">One engagement <em>at a time.</em></span>
          </div>
        </aside>
      </div>
    </section>
  );
}

// ───────── Marquee ─────────
const MARQUEE_WORDS = [
  ["01", "Positioning"], ["02", "Brand systems"], ["03", "Lifecycle"],
  ["04", "Paid acquisition"], ["05", "Content engines"], ["06", "SEO architecture"],
  ["07", "RevOps"], ["08", "Attribution"], ["09", "Pricing & packaging"],
  ["10", "Landing pages"], ["11", "Sales enablement"], ["12", "Product marketing"]
];

function Marquee() {
  const items = [...MARQUEE_WORDS, ...MARQUEE_WORDS];
  return (
    <div className="marquee" aria-hidden="true">
      <div className="marquee-track">
        {items.map(([n, w], i) => (
          <span className="marquee-item" key={i}>
            <span className="marquee-num">{n}</span>
            {i % 2 === 0 ? w : <em>{w}</em>}
            <span className="marquee-dot" />
          </span>
        ))}
      </div>
    </div>
  );
}

// ───────── Services ─────────
const SERVICES = [
  {
    no: "01",
    name: "Positioning & Brand",
    italic: "& Brand",
    blurb: "Sharpening what you are, who it's for, and why it matters — then expressing it in a system your team can run without us in the room.",
    period: "4–8 weeks",
    output: "Brand book + site",
    tiles: [
      { k: "01", t: "Narrative", d: "Story, category and message hierarchy." },
      { k: "02", t: "Identity",  d: "Logo system, type, color, motion principles." },
      { k: "03", t: "Guidelines", d: "A brand book teams will actually use." },
      { k: "04", t: "Audit",     d: "Where you've drifted, and what to fix first." }
    ]
  },
  {
    no: "02",
    name: "Growth & Acquisition",
    italic: "& Acquisition",
    blurb: "Channel strategy, paid media operations, and the testing rigor that turns spend into a compounding learning loop — not a monthly bonfire.",
    period: "Ongoing",
    output: "Operating cadence",
    tiles: [
      { k: "01", t: "Channel mix", d: "Where to play, where to compound." },
      { k: "02", t: "Paid ops",    d: "Search, social and sponsorships — weekly." },
      { k: "03", t: "Experiments", d: "Hypothesis-driven tests, shared logs." },
      { k: "04", t: "Creative",    d: "Ad systems built to ship, not to win awards." }
    ]
  },
  {
    no: "03",
    name: "Lifecycle & Retention",
    italic: "& Retention",
    blurb: "Onboarding, activation and retention systems wired directly into your product data — not a marketing tool's fantasy of your CRM.",
    period: "6–10 weeks",
    output: "Live journeys",
    tiles: [
      { k: "01", t: "Journeys",       d: "Triggered flows tied to product events." },
      { k: "02", t: "Behavioral email", d: "Copy, design and warm-up plan." },
      { k: "03", t: "Win-back",       d: "Reactivation programs that earn their cost." },
      { k: "04", t: "Activation",     d: "First-week milestones that predict retention." }
    ]
  },
  {
    no: "04",
    name: "Content & SEO",
    italic: "& SEO",
    blurb: "An editorial engine, and the technical foundation underneath, so that both search and AI find you for the things you actually want to be known for.",
    period: "8–12 weeks",
    output: "Publishing engine",
    tiles: [
      { k: "01", t: "Editorial system", d: "Pillars, briefs, publishing cadence." },
      { k: "02", t: "Programmatic SEO", d: "Templates that compound at scale." },
      { k: "03", t: "LLM visibility",   d: "Structured content for AI surfaces." },
      { k: "04", t: "Distribution",     d: "Newsletter, podcast, syndication ops." }
    ]
  },
  {
    no: "05",
    name: "RevOps & Attribution",
    italic: "& Attribution",
    blurb: "The plumbing under everything else — a tracking plan, a warehouse model, and dashboards the whole company can actually agree on.",
    period: "4–6 weeks",
    output: "Tracking + dashboards",
    tiles: [
      { k: "01", t: "Tracking plan",   d: "Event schema, naming, governance." },
      { k: "02", t: "Warehouse models", d: "dbt-style models for marketing data." },
      { k: "03", t: "Dashboards",       d: "One source of truth, exec to operator." },
      { k: "04", t: "Attribution",      d: "Self-reported + modeled, side-by-side." }
    ]
  },
  {
    no: "06",
    name: "Pricing & Packaging",
    italic: "& Packaging",
    blurb: "Tiers, plans and pricing pages designed to fit how customers actually buy — and how your business actually compounds over time.",
    period: "6–10 weeks",
    output: "Model + rollout",
    tiles: [
      { k: "01", t: "Discovery",  d: "Interviews, WTP, ICP segmentation." },
      { k: "02", t: "Model",      d: "Tiering, metric, packaging design." },
      { k: "03", t: "Rollout",    d: "Page redesign + migration plan." },
      { k: "04", t: "Enablement", d: "Sales playbook and objection responses." }
    ]
  }
];

function Services() {
  const [active, setActive] = useState(0);
  const sv = SERVICES[active];
  return (
    <section className="shell s" id="services" data-screen-label="02 Services">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">02<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 02</span>
            <b>Services</b>
            <span>Six disciplines</span>
          </div>
        </div>
        <h2 className="s-title">
          Six disciplines, run as <em>one</em> <span className="underline-accent">operating system.</span>
        </h2>
      </div>

      <div className="svc reveal d1">
        <div className="svc-toc" role="list">
          {SERVICES.map((s, i) => (
            <div
              key={s.no}
              role="listitem"
              className={"svc-toc-item" + (i === active ? " is-active" : "")}
              onMouseEnter={() => setActive(i)}
              onClick={() => setActive(i)}
            >
              <span className="n">/{s.no}</span>
              <span className="name">{s.name.replace(s.italic, "")}<em>{s.italic}</em></span>
              <span className="arrow">→</span>
            </div>
          ))}
        </div>

        <aside className="svc-detail" key={sv.no}>
          <div className="svc-detail-head">
            <div>
              <div className="svc-detail-no">Discipline · {sv.no}</div>
              <h3 className="svc-detail-title">{sv.name.replace(sv.italic, "")}<em>{sv.italic}</em></h3>
            </div>
          </div>
          <p className="svc-detail-blurb">{sv.blurb}</p>
          <div className="svc-detail-tiles">
            {sv.tiles.map(tile => (
              <div className="svc-tile" key={tile.k}>
                <span className="k">/{tile.k}</span>
                <span className="t">{tile.t}</span>
                <span className="d">{tile.d}</span>
              </div>
            ))}
          </div>
          <div className="svc-detail-foot">
            <div style={{display:"flex", gap:24}}>
              <span className="pair"><small>Period</small>&nbsp;{sv.period}</span>
              <span className="pair"><small>Output</small>&nbsp;{sv.output}</span>
            </div>
            <a className="svc-cta" href="#contact">Scope this <span>↗</span></a>
          </div>
        </aside>
      </div>
    </section>
  );
}

// ───────── Methodology ─────────
const METHOD = [
  {
    n: "I",
    name: "Diagnose",
    italic: null,
    period: "Weeks 1–2",
    artefact: "Diagnostic memo",
    body: "We start with a deep, unsparing read of your product, market, funnel and analytics. Every recommendation we make from then on has a paper trail back to a finding here.",
    bullets: [
      ["a", "Stakeholder interviews and customer calls"],
      ["b", "Analytics, funnel and pricing teardown"],
      ["c", "Competitive and category positioning audit"]
    ]
  },
  {
    n: "II",
    name: "Architect",
    italic: null,
    period: "Weeks 2–4",
    artefact: "Operating plan",
    body: "We design the system — channels, messaging, lifecycle, measurement — as a single connected operating model, with quarterly bets and weekly cadence baked in.",
    bullets: [
      ["a", "Channel and lifecycle architecture"],
      ["b", "Messaging hierarchy and content engine"],
      ["c", "Measurement plan, KPI tree and dashboards"]
    ]
  },
  {
    n: "III",
    name: "Ship",
    italic: null,
    period: "Weeks 3–8",
    artefact: "Live system",
    body: "We build and launch in vertical slices. Real pages, campaigns and journeys ship in week one, not month three — and they keep getting sharper from there.",
    bullets: [
      ["a", "Site, landing pages, pricing redesign"],
      ["b", "Paid, lifecycle, content systems live"],
      ["c", "Tracking, attribution and dashboards online"]
    ]
  },
  {
    n: "IV",
    name: "Operate",
    italic: null,
    period: "Ongoing",
    artefact: "Operating cadence",
    body: "We run the system with you, in weekly cycles, until your in-house team is comfortable owning every layer of it. The end-state is independence, not lock-in.",
    bullets: [
      ["a", "Weekly cycle reviews, monthly readouts"],
      ["b", "Hiring plan and internal handover"],
      ["c", "Playbooks, SOPs and team enablement"]
    ]
  }
];

function Methodology() {
  return (
    <section className="shell s" id="approach" data-screen-label="03 Approach">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">03<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 03</span>
            <b>Approach</b>
            <span>Four phases</span>
          </div>
        </div>
        <h2 className="s-title">
          A four-phase <em>operating loop,</em> not a deck of pretty slides.
        </h2>
      </div>

      <div className="method-wrap reveal d1">
        <div className="method-track">
          {METHOD.map((m, i) => (
            <div className="method-row" key={m.n}>
              <div className="method-numeral">
                {m.n}<span className="slash">/</span>
              </div>
              <div className="method-name">{m.name}</div>
              <div className="method-body">
                <p>{m.body}</p>
                <ul>
                  {m.bullets.map(([k, v]) => (
                    <li key={k} data-no={k.toUpperCase() + "."}>{v}</li>
                  ))}
                </ul>
              </div>
              <div className="method-meta">
                <span>Phase {m.n}</span>
                <b>{m.period}</b>
                <span>{m.artefact}</span>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ───────── Work (intentionally not rendered: practice opened 2026, no public case studies yet) ─────────

// ───────── Manifesto ─────────
function Manifesto() {
  return (
    <section className="shell s" id="manifesto" data-screen-label="04 Manifesto">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">04<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 04</span>
            <b>Manifesto</b>
            <span>What we believe</span>
          </div>
        </div>
        <h2 className="s-title" style={{visibility:"hidden", position:"absolute"}}>Manifesto</h2>
      </div>

      <div className="manifesto-wrap">
        <p className="manifesto-line r1 reveal">
          We don't <em>do</em> <span className="strike">campaigns.</span>
        </p>
        <p className="manifesto-line r2 reveal d1">
          We build the <em>system</em> that decides which campaigns are worth running.
        </p>
        <p className="manifesto-line r3 reveal d2">
          Good marketing is a <em>function of</em> <span className="mark">the product.</span>
        </p>
        <p className="manifesto-line r4 reveal d3">
          Our job is to make the cheap, fast thing also be the <em>right thing</em> — and to leave you with the operating model to keep doing it without us.
        </p>

        <div className="manifesto-sig reveal d4">
          <span>Filed under · House rules</span>
          <span className="name">— The studio, 2026</span>
        </div>
      </div>
    </section>
  );
}

// ───────── Engagement ─────────
const PLANS = [
  {
    no: "01",
    cap: "Sprint",
    name: "Foundations",
    italic: null,
    rate: "On request · Fixed-scope, 6 weeks",
    desc: "A focused engagement to reset positioning, brand and your highest-leverage funnel surfaces — for teams between rounds or pre-rebrand. Scope, fee and payment terms are agreed in writing after an intro call.",
    bullets: [
      ["a", "Positioning, narrative and messaging system"],
      ["b", "Brand identity refresh or rebuild"],
      ["c", "Marketing site or pricing page rebuild"],
      ["d", "Async-first, two-week response cadence"]
    ],
    cta: "Scope a sprint",
    badge: null
  },
  {
    no: "02",
    cap: "Retainer",
    name: "Operator",
    italic: null,
    rate: "On request · Monthly, 3-month minimum",
    desc: "An embedded operator running your acquisition, lifecycle and content motions week-in, week-out — and helping you build the in-house muscle to keep going. Fee and cadence scoped after an intro call.",
    bullets: [
      ["a", "Direct work from me, the operator"],
      ["b", "Paid, lifecycle, content and SEO ops"],
      ["c", "Weekly cycle reviews and quarterly readouts"],
      ["d", "Shared workspace, dashboards and docs"],
      ["e", "Hiring plan and internal handover built-in"]
    ],
    cta: "Talk about a retainer",
    badge: null,
    featured: true
  },
  {
    no: "03",
    cap: "Embedded",
    name: "Fractional CMO",
    italic: null,
    rate: "On request · Quarterly engagement",
    desc: "Senior marketing leadership inside your team — strategy, hiring and operating cadence — without the full-time cost or commitment. Fee scoped after an intro call.",
    bullets: [
      ["a", "Operating partner for the founding team"],
      ["b", "Marketing hiring plan and team architecture"],
      ["c", "Board, narrative and fundraising support"],
      ["d", "Quarterly readouts and operating cadence"]
    ],
    cta: "Book a leadership chat",
    badge: null
  }
];

function Engagement() {
  return (
    <section className="shell s" id="engagement" data-screen-label="05 Engagement">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">05<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 05</span>
            <b>Engagement</b>
            <span>How to work with me</span>
          </div>
        </div>
        <h2 className="s-title">
          Three ways in. <em>Pick the one</em> that fits where you are.
        </h2>
      </div>

      <div className="plans">
        {PLANS.map((p, i) => (
          <div key={p.no} className={"plan reveal d" + (i+1) + (p.featured ? " is-featured" : "")}>
            {p.badge && <span className="plan-badge">{p.badge}</span>}
            <div className="plan-chrome">
              <span className="plan-cap">{p.cap}</span>
              <span className="plan-no">/{p.no}</span>
            </div>
            <h3 className="plan-name">{p.name}</h3>
            <div className="plan-rate">
              <b>{p.rate.split(" · ")[0]}</b> · {p.rate.split(" · ")[1]}
            </div>
            <p className="plan-desc">{p.desc}</p>
            <hr className="plan-rule" />
            <ul className="plan-list">
              {p.bullets.map(([k, v]) => <li key={k} data-no={k.toUpperCase() + "."}>{v}</li>)}
            </ul>
            <a href="#contact" className="plan-cta">
              {p.cta}
              <span className="pip">→</span>
            </a>
          </div>
        ))}
      </div>
    </section>
  );
}

// ───────── Operations & Compliance ─────────
const OPS_CARDS = [
  {
    no: "01",
    label: "Who you contract with",
    title: "Independent operator.",
    rows: [
      ["Trading name",   "M.M Sainte-Croix"],
      ["Status",         "Independent professional"],
      ["Based in",       "Fort-de-France, Martinique (France)"],
      ["Activity",       "B2B marketing & growth consulting"]
    ],
    foot: "Imprint & contact",
    href: "legal/imprint.html"
  },
  {
    no: "02",
    label: "Banking & invoicing",
    title: "How payments work.",
    rows: [
      ["Method",            "SWIFT / SEPA bank transfer"],
      ["Cards",             "Stripe (regulated processor)"],
      ["Currencies",        "EUR · USD"],
      ["Invoicing",         "Numbered invoice · scoped per engagement"]
    ],
    foot: "Commercial terms",
    href: "legal/terms.html"
  },
  {
    no: "03",
    label: "AML / KYC",
    title: "Every counter-party, screened.",
    rows: [
      ["Onboarding",        "Client ID + sanctions screening"],
      ["Sanctions lists",   "OFAC · EU · UN · UK HMT"],
      ["Records",           "Retained per applicable law"],
      ["No cash · No crypto", "Bank transfer or card only"]
    ],
    foot: "AML / KYC policy",
    href: "legal/aml-kyc.html"
  },
  {
    no: "04",
    label: "Signatory",
    title: "One person, one signature.",
    rows: [
      ["Operator",         "Sole founder & only signatory"],
      ["Scope",             "Quote → signed engagement → invoice"],
      ["Capacity",          "One engagement at a time"],
      ["Compliance",        "compliance@msaintecroix.com"]
    ],
    foot: "Talk to compliance",
    href: "mailto:compliance@msaintecroix.com"
  }
];

function Operations() {
  return (
    <section className="shell s" id="operations" data-screen-label="06 Operations">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">06<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 06</span>
            <b>Operations &amp; Compliance</b>
            <span>How the practice runs</span>
          </div>
        </div>
        <h2 className="s-title">
          A solo practice, run like <em>an institution.</em> <span className="underline-accent">Boring on purpose.</span>
        </h2>
        <p className="ops-lede">
          One independent operator. Written quotes. Numbered invoices. A regulated banking partner.
          A documented AML / KYC posture. No cash, no crypto, no third-party payors &mdash; so my
          clients, and my bank, never have a question to answer.
        </p>
      </div>

      <div className="ops-grid">
        {OPS_CARDS.map((c, i) => (
          <article className={"ops-card reveal d" + ((i % 4) + 1)} key={c.no}>
            <header className="ops-card-head">
              <span className="ops-card-no">/{c.no}</span>
              <span className="ops-card-label">{c.label}</span>
            </header>
            <h3 className="ops-card-title">{c.title}</h3>
            <dl className="ops-card-rows">
              {c.rows.map(([k, v]) => (
                <div className="ops-row" key={k}>
                  <dt>{k}</dt><dd>{v}</dd>
                </div>
              ))}
            </dl>
            <a className="ops-card-foot" href={c.href}>
              <span>{c.foot}</span>
              <span className="ops-arrow">↗</span>
            </a>
          </article>
        ))}
      </div>

      <div className="ops-strip reveal d2">
        <div className="ops-strip-item"><span className="k">Pricing</span><span className="v">On request</span></div>
        <div className="ops-strip-item"><span className="k">Currencies</span><span className="v">EUR · USD</span></div>
        <div className="ops-strip-item"><span className="k">Cash / Crypto</span><span className="v">Not accepted</span></div>
        <div className="ops-strip-item"><span className="k">Records</span><span className="v">Kept per law</span></div>
        <div className="ops-strip-item"><span className="k">Reply window</span><span className="v">≤ 1 business day</span></div>
      </div>
    </section>
  );
}

// ───────── Contact ─────────
const INTERESTS = [
  "Positioning", "Brand identity", "Marketing site",
  "Lifecycle", "Paid acquisition", "SEO & content",
  "Pricing", "RevOps & data", "Fractional CMO"
];

function Contact() {
  const [form, setForm] = useState({
    name: "", company: "", email: "", role: "Founder / CEO", stage: "Seed", budget: "Exploring", details: "",
    interests: []
  });
  const [errors, setErrors] = useState({});
  const [submitting, setSubmitting] = useState(false);
  const [sent, setSent] = useState(false);

  const update = (k, v) => setForm(s => ({ ...s, [k]: v }));
  const toggle = (v) => setForm(s => ({
    ...s,
    interests: s.interests.includes(v) ? s.interests.filter(x => x !== v) : [...s.interests, v]
  }));

  const validate = () => {
    const e = {};
    if (!form.name.trim()) e.name = "Required";
    if (!form.company.trim()) e.company = "Required";
    if (!form.email.trim()) e.email = "Required";
    else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) e.email = "Looks off";
    if (!form.details.trim() || form.details.trim().length < 20) e.details = "Tell us a little more";
    setErrors(e);
    return Object.keys(e).length === 0;
  };

  const onSubmit = (e) => {
    e.preventDefault();
    if (!validate()) return;
    setSubmitting(true);
    setTimeout(() => { setSubmitting(false); setSent(true); }, 900);
  };

  return (
    <section className="shell s" id="contact" data-screen-label="07 Contact">
      <div className="reveal">
        <div className="s-marker">
          <span className="ix">07<em>i</em></span>
          <div className="s-marker-meta">
            <span>Section · 07</span>
            <b>Get in touch</b>
            <span>Send a brief — quotes on request</span>
          </div>
        </div>
        <h2 className="s-title">
          Tell us <em>where you are</em> and where you'd <span className="underline-accent">like to be.</span>
        </h2>
      </div>

      <div className="contact-card reveal d1">
        <div className="contact-card-head">
          <span><b>TRANSMISSION · 07/IN</b> &nbsp;·&nbsp; New brief intake</span>
          <div className="right">
            <span>Encrypted in transit</span>
            <span>Reply within one business day</span>
          </div>
        </div>
        <div className="contact-card-body">
          <div className="contact-side">
            <h3 className="lede">
              Send us a <em>short</em><br/>
              brief. We read <span className="accent">every one</span> ourselves.
            </h3>
            <p>
              One short form. No bots, no qualifying funnel. If we're not the
              right fit we'll say so — and, where we can, point you somewhere
              better.
            </p>
            <div className="contact-meta">
              <div className="contact-meta-row">
                <span className="k">General</span>
                <span className="v"><a href="mailto:hello@msaintecroix.com">hello@msaintecroix.com</a></span>
              </div>
              <div className="contact-meta-row">
                <span className="k">Billing</span>
                <span className="v"><a href="mailto:billing@msaintecroix.com">billing@msaintecroix.com</a></span>
              </div>
              <div className="contact-meta-row">
                <span className="k">Compliance / KYB</span>
                <span className="v"><a href="mailto:compliance@msaintecroix.com">compliance@msaintecroix.com</a></span>
              </div>
              <div className="contact-meta-row">
                <span className="k">Operator</span>
                <span className="v">Independent · Martinique (France)</span>
              </div>
              <div className="contact-meta-row">
                <span className="k">Address</span>
                <span className="v">18 Lotissement Les Tropiques<br/>97200 Fort-de-France, Martinique</span>
              </div>
              <div className="contact-meta-row">
                <span className="k">Hours</span>
                <span className="v">Mon — Fri · 09:00 — 18:00 AST (GMT-4)</span>
              </div>
            </div>
          </div>

          {sent ? (
            <div className="form-shell">
              <div className="form-success">
                <div className="fs-eyebrow">Transmission received · 07/OUT</div>
                <h3 className="fs-title">Your brief is in the queue.</h3>
                <p className="fs-body">
                  We'll come back with either a no, a referral, or a 30-minute
                  call to dig in — and a short note on whether we think we're
                  the right fit.
                </p>
              </div>
              <button
                className="form-submit"
                onClick={() => { setSent(false); setForm({ name: "", company: "", email: "", role: "Founder / CEO", stage: "Seed", budget: "Exploring", details: "", interests: [] }); }}>
                Send another brief
                <span className="pip">↻</span>
              </button>
            </div>
          ) : (
            <form className="form-shell" onSubmit={onSubmit} noValidate>
              <div className="form-grid-2">
                <div className={"field" + (errors.name ? " is-error" : "")}>
                  <label><span className="lno">001</span> Your name <span className="req">required</span></label>
                  <input type="text" value={form.name} onChange={e => update("name", e.target.value)} placeholder="Your full name" />
                  {errors.name && <div className="field-error">{errors.name}</div>}
                </div>
                <div className={"field" + (errors.company ? " is-error" : "")}>
                  <label><span className="lno">002</span> Company <span className="req">required</span></label>
                  <input type="text" value={form.company} onChange={e => update("company", e.target.value)} placeholder="Your company" />
                  {errors.company && <div className="field-error">{errors.company}</div>}
                </div>
              </div>

              <div className={"field" + (errors.email ? " is-error" : "")}>
                <label><span className="lno">003</span> Work email <span className="req">required</span></label>
                <input type="email" value={form.email} onChange={e => update("email", e.target.value)} placeholder="you@company.com" />
                {errors.email && <div className="field-error">{errors.email}</div>}
              </div>

              <div className="form-grid-2">
                <div className="field">
                  <label><span className="lno">004</span> Your role</label>
                  <select value={form.role} onChange={e => update("role", e.target.value)}>
                    <option>Founder / CEO</option>
                    <option>Head of Marketing</option>
                    <option>Head of Product</option>
                    <option>Head of Growth</option>
                    <option>Operator / Other</option>
                  </select>
                </div>
                <div className="field">
                  <label><span className="lno">005</span> Stage</label>
                  <select value={form.stage} onChange={e => update("stage", e.target.value)}>
                    <option>Pre-seed</option>
                    <option>Seed</option>
                    <option>Series A</option>
                    <option>Series B+</option>
                    <option>Public / Established</option>
                  </select>
                </div>
              </div>

              <div className="field">
                <label><span className="lno">006</span> What are you interested in?</label>
                <div className="chips-input">
                  {INTERESTS.map(it => (
                    <button
                      type="button"
                      key={it}
                      className={"interest-chip" + (form.interests.includes(it) ? " is-on" : "")}
                      onClick={() => toggle(it)}
                    >
                      {it}
                    </button>
                  ))}
                </div>
              </div>

              <div className="field">
                <label><span className="lno">007</span> Engagement type</label>
                <select value={form.budget} onChange={e => update("budget", e.target.value)}>
                  <option>Exploring</option>
                  <option>Sprint (one-off, fixed scope)</option>
                  <option>Monthly retainer</option>
                  <option>Fractional leadership</option>
                  <option>Not sure yet</option>
                </select>
              </div>

              <div className={"field" + (errors.details ? " is-error" : "")}>
                <label><span className="lno">008</span> What are you trying to do? <span className="req">required</span></label>
                <textarea
                  value={form.details}
                  onChange={e => update("details", e.target.value)}
                  placeholder="A short paragraph is fine. Where you are, what's not working, what would great look like."
                />
                {errors.details && <div className="field-error">{errors.details}</div>}
              </div>

              <div className="form-actions">
                <button className="form-submit" type="submit" disabled={submitting}>
                  {submitting ? <span className="spin" /> : null}
                  {submitting ? "Sending…" : "Send brief"}
                  {!submitting && <span className="pip">↗</span>}
                </button>
                <div className="form-fineprint">
                  We'll only use this to reply. No sequences, no nurture flows — promise.
                </div>
              </div>
            </form>
          )}
        </div>
      </div>
    </section>
  );
}

// ───────── Footer ─────────
function Footer() {
  const year = new Date().getFullYear();
  return (
    <footer className="shell foot" data-screen-label="08 Footer">
      <div className="foot-grid">
        <div className="foot-brand">
          <p className="b-tag">
            An independent operator building <em>modern growth systems</em> for software companies, one engagement at a time.
          </p>
          <div className="foot-newsletter">
            <input type="email" placeholder="you@company.com" aria-label="Email for field notes" />
            <button>Field notes →</button>
          </div>
        </div>
        <div className="foot-col">
          <h4>Practice</h4>
          <ul>
            <li><a href="#approach">Approach</a></li>
            <li><a href="#engagement">Engagement</a></li>
            <li><a href="#manifesto">Manifesto</a></li>
            <li><a href="#operations">Compliance</a></li>
            <li><a href="#contact">Contact</a></li>
          </ul>
        </div>
        <div className="foot-col">
          <h4>Services</h4>
          <ul>
            <li><a href="#services">Positioning & Brand</a></li>
            <li><a href="#services">Growth & Acquisition</a></li>
            <li><a href="#services">Lifecycle & Retention</a></li>
            <li><a href="#services">Content & SEO</a></li>
            <li><a href="#services">RevOps & Attribution</a></li>
            <li><a href="#services">Pricing & Packaging</a></li>
          </ul>
        </div>
        <div className="foot-col">
          <h4>Contact</h4>
          <ul>
            <li><a href="mailto:hello@msaintecroix.com">hello@msaintecroix.com</a> <span className="small">General</span></li>
            <li><a href="mailto:billing@msaintecroix.com">billing@msaintecroix.com</a> <span className="small">Billing</span></li>
            <li><a href="mailto:compliance@msaintecroix.com">compliance@msaintecroix.com</a> <span className="small">KYB / AML</span></li>
            <li><a href="#contact">Send a brief <span className="small">↘</span></a></li>
          </ul>
        </div>
        <div className="foot-col">
          <h4>Legal</h4>
          <ul>
            <li><a href="legal/imprint.html">Imprint &amp; company</a></li>
            <li><a href="legal/terms.html">Terms of service</a></li>
            <li><a href="legal/privacy.html">Privacy policy</a></li>
            <li><a href="legal/aml-kyc.html">AML / KYC policy</a></li>
            <li><a href="legal/refund.html">Refund policy</a></li>
          </ul>
        </div>
      </div>

      <div className="foot-wordmark" aria-hidden="true">
        Sainte<span className="ital">–</span>Croix<span className="dot">.</span>
      </div>

      <div className="foot-meta">
        <span>© {year} M.M Sainte-Croix · Independent operator · 18 Lotissement Les Tropiques, 97200 Fort-de-France, Martinique</span>
        <div className="links">
          <a href="legal/privacy.html">Privacy</a>
          <a href="legal/terms.html">Terms</a>
          <a href="legal/imprint.html">Imprint</a>
          <a href="legal/aml-kyc.html">AML / KYC</a>
        </div>
      </div>
    </footer>
  );
}

// ───────── Tweaks ─────────
function applyTokens(t) {
  const root = document.documentElement.style;
  root.setProperty("--accent", t.accent);
  document.body.style.setProperty("--grain", t.grain ? "0.55" : "0");
  document.body.classList.toggle("no-grain", !t.grain);
}

// ───────── App ─────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  useEffect(() => { applyTokens(t); }, [t.accent, t.grain]);
  useEffect(() => {
    if (!t.grain) {
      const s = document.createElement("style");
      s.id = "no-grain-style";
      s.textContent = "body::before { display: none !important; }";
      document.head.appendChild(s);
      return () => { s.remove(); };
    }
  }, [t.grain]);

  useReveal();
  useCursorBlob(t.showCursor);

  return (
    <React.Fragment>
      <StatusStrip />
      <Nav />
      <Hero headlineVariant={t.headline} />
      <Marquee />
      <Services />
      <Methodology />
      <Manifesto />
      <Engagement />
      <Operations />
      <Contact />
      <Footer />

      <TweaksPanel>
        <TweakSection label="Brand" />
        <TweakColor
          label="Accent"
          value={t.accent}
          options={ACCENTS}
          onChange={(v) => setTweak("accent", v)}
        />

        <TweakSection label="Hero" />
        <TweakRadio
          label="Headline"
          value={t.headline}
          options={[
            { value: "playful", label: "Playful" },
            { value: "direct",  label: "Direct" },
            { value: "bold",    label: "Bold" }
          ]}
          onChange={(v) => setTweak("headline", v)}
        />

        <TweakSection label="Motion & texture" />
        <TweakToggle
          label="Cursor blob"
          value={t.showCursor}
          onChange={(v) => setTweak("showCursor", v)}
        />
        <TweakToggle
          label="Film grain"
          value={t.grain}
          onChange={(v) => setTweak("grain", v)}
        />
      </TweaksPanel>
    </React.Fragment>
  );
}

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