// maven-app.jsx — Project Maven, editorial / aerospace edition (production)

const { useState, useEffect, useRef } = React;

// ── Starfield (sparse, slow) ─────────────────────────────────────────
function useStarfield(enabled) {
  useEffect(() => {
    const canvas = document.getElementById('starfield');
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf, w, h, stars = [], dpr = Math.min(window.devicePixelRatio || 1, 2);
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    function resize() {
      w = canvas.width = window.innerWidth * dpr;
      h = canvas.height = window.innerHeight * dpr;
      canvas.style.width = window.innerWidth + 'px';
      canvas.style.height = window.innerHeight + 'px';
      const count = Math.floor((window.innerWidth * window.innerHeight) / 26000);
      stars = Array.from({ length: count }, () => ({
        x: Math.random() * w, y: Math.random() * h,
        z: Math.random(), tw: Math.random() * Math.PI * 2,
      }));
    }
    function frame() {
      ctx.clearRect(0, 0, w, h);
      for (const s of stars) {
        s.y += (0.02 + s.z * 0.05) * dpr;
        if (s.y > h) { s.y = 0; s.x = Math.random() * w; }
        s.tw += 0.015;
        const r = (s.z * 1.1 + 0.25) * dpr;
        const a = (0.12 + s.z * 0.32 + Math.sin(s.tw) * 0.10);
        ctx.beginPath();
        ctx.arc(s.x, s.y, r, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(255,255,255,${Math.max(0, a)})`;
        ctx.fill();
      }
      raf = requestAnimationFrame(frame);
    }
    resize();
    if (!reduced && enabled) frame();
    else ctx.clearRect(0, 0, w, h);
    window.addEventListener('resize', resize);
    return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); };
  }, [enabled]);
}

// ── Reveal-on-scroll + nav state ─────────────────────────────────────
function useScrollFx() {
  useEffect(() => {
    const check = () => {
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll('.reveal:not([data-in]), .clip:not([data-in]), .timeline:not([data-in])').forEach((el) => {
        const r = el.getBoundingClientRect();
        if (r.top < vh * 0.92 && r.bottom > 0) el.setAttribute('data-in', '');
      });
      const shell = document.querySelector('.nav-shell');
      if (shell) shell.classList.toggle('scrolled', window.scrollY > 24);
    };
    const onScroll = () => requestAnimationFrame(check);
    check();
    const timers = [requestAnimationFrame(check), setTimeout(check, 120), setTimeout(check, 400), setTimeout(check, 900)];
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    window.addEventListener('load', check);
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
      window.removeEventListener('load', check);
      timers.forEach((t) => clearTimeout(t));
    };
  }, []);
}

// ── Nav ──────────────────────────────────────────────────────────────
function Nav() {
  return (
    <div className="nav-shell">
      <nav className="nav">
        <a className="brand" href="#top"><span className="logo"><span className="p">P</span><span className="m">M</span><span className="v">V</span></span></a>
        <ul>
          <li><a href="#services">Services</a></li>
          <li><a href="#work">Work</a></li>
          <li><a href="#process">Process</a></li>
          <li><a href="#pricing">Pricing</a></li>
          <li><a href="#faq">FAQ</a></li>
        </ul>
        <a className="nav-cta" href="#contact">Book a meeting</a>
      </nav>
    </div>
  );
}

// ── Hero ─────────────────────────────────────────────────────────────
function Hero({ t }) {
  const vref = useRef(null);
  useEffect(() => {
    const v = vref.current;
    if (!v) return;
    v.muted = true; v.defaultMuted = true; v.volume = 0;
    v.playbackRate = 1.4;
    const go = () => { v.muted = true; v.play && v.play().catch(() => {}); };
    go();
    v.addEventListener('loadeddata', go);
    return () => v.removeEventListener('loadeddata', go);
  }, []);
  return (
    <header className="hero" id="top">
      <div className="wrap">
        <div className="hero-top reveal">
          <span>Project Maven / Ops</span>
          <span className="live"><span className="dot"></span>System online</span>
          <span>Est. 2021 / Barcelona</span>
        </div>

        <div className="hero-grid">
          <div>
            <div className="hero-eyebrow reveal"><span className="bar"></span>Google Ads management for revenue teams</div>
            <h1>
              <span className="welcome reveal">{t.welcome}</span>
              <span className="glitch" data-text={t.headline}>{t.headline}</span>
            </h1>
            <p className="hero-sub reveal">
              We run Google Ads for companies that measure success in revenue, not clicks.
              <strong> Search, Performance Max, and YouTube</strong>, managed by people who
              did this work inside Google.
            </p>
            <div className="hero-ctas reveal">
              <a className="btn btn-primary" href="#contact">Book a meeting <span className="tick">→</span></a>
              <a className="btn btn-ghost" href="#work">See results <span className="tick">→</span></a>
            </div>
            <div className="hero-readout reveal">
              <div><div className="v">3.8<span className="u">x</span></div><div className="k">Avg return on spend</div></div>
              <div><div className="v">14<span className="u">d</span></div><div className="k">To first results</div></div>
              <div><div className="v">500<span className="u">+</span></div><div className="k">Accounts managed</div></div>
            </div>
          </div>

          <div className="feed-wrap reveal">
            <div className="feed">
              <span className="tag"><span className="sq"></span>Live</span>
              <video ref={vref} src="mascot.mp4" autoPlay loop muted playsInline preload="auto" />
              <div className="wash"></div>
              <div className="inner-vig"></div>
              <div className="scan"></div>
            </div>
          </div>
        </div>
      </div>
    </header>
  );
}

// ── Scroll-fill text ─────────────────────────────────────────────────
function FillText({ sentence }) {
  const ref = useRef(null);
  const [count, setCount] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const onScroll = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const start = vh * 0.82, end = vh * 0.32;
      const p = (start - r.top) / (start - end);
      setCount(Math.max(0, Math.min(sentence.length, Math.round(p * sentence.length))));
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
  }, [sentence.length]);
  return (
    <p className="fill" ref={ref}>
      {sentence.map((w, i) => (
        <span key={i} className={`fw${w.acc ? ' acc' : ''}${i < count ? ' on' : ''}`}>{w.t}{' '}</span>
      ))}
    </p>
  );
}

// ── Moving word band ─────────────────────────────────────────────────
function Band() {
  const words = ['Revenue', 'Google Search', 'Performance Max', 'YouTube', 'Measurement', 'Pipeline'];
  const row = [...words, ...words];
  return (
    <div className="band" aria-hidden="true">
      <div className="band-track">
        {row.map((w, i) => (
          <React.Fragment key={i}>
            <span className="w">{w}</span>
            <span className="dot"></span>
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

// ── Stats ────────────────────────────────────────────────────────────
function Stats() {
  const stats = [
    { v: <>10<span className="u">+</span></>, k: 'Years running paid search' },
    { v: <>500<span className="u">+</span></>, k: 'Accounts managed to date' },
    { v: <>€300K<span className="u">+</span></>, k: 'Monthly budget managed' },
    { v: <>Ex<span className="u">/</span>Google</>, k: 'Founding team, ads division' },
  ];
  return (
    <section className="stats">
      <div className="wrap">
        <div className="stats-grid">
          {stats.map((s, i) => (
            <div className="stat reveal" style={{ transitionDelay: `${i * 0.07}s` }} key={i}>
              <div className="v">{s.v}</div>
              <div className="k">{s.k}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Services ─────────────────────────────────────────────────────────
function Services() {
  const items = [
    { n: '01', t: 'Google Search', d: 'Intent based keyword structure with strict negative keyword hygiene. Built to convert, not to fill a dashboard.', tag: 'Search' },
    { n: '02', t: 'Performance Max', d: 'Clean asset groups and deliberate audience signals. We decide where the budget goes, not the algorithm alone.', tag: 'PMax' },
    { n: '03', t: 'YouTube', d: 'Scripted video built around a measurement plan. We track booked calls and revenue, never view counts.', tag: 'Video' },
    { n: '04', t: 'Conversion Tracking', d: 'GA4, server side tagging, and offline conversion imports. The foundation most accounts are missing.', tag: 'Measurement' },
  ];
  return (
    <section className="section" id="services">
      <div className="wrap">
        <div className="section-head">
          <div className="label reveal"><span className="idx">01</span><span className="bar"></span>What we do</div>
          <FillText sentence={[
            {t:'We'},{t:'turn'},{t:'paid'},{t:'search'},{t:'into'},
            {t:'predictable',acc:true},{t:'revenue.',acc:true},
            {t:'Every'},{t:'euro'},{t:'is'},{t:'tracked.'},{t:'Every'},{t:'campaign'},
            {t:'reports'},{t:'into'},{t:'one',acc:true},{t:'number.',acc:true},{t:'Nothing'},
            {t:'runs'},{t:'on'},{t:'guesswork.'}
          ]} />
        </div>
        <div className="svc-list">
          {items.map((s, i) => (
            <div className="svc-row reveal" style={{ transitionDelay: `${i * 0.06}s` }} key={s.n}>
              <div className="si">{s.n}</div>
              <h3>{s.t}</h3>
              <div className="sd">{s.d}</div>
              <div className="stag">{s.tag}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Process ──────────────────────────────────────────────────────────
function Process() {
  const steps = [
    { n: '01', t: 'Audit', dur: '2 weeks', d: 'A full review of your account, analytics, and competitive position. Fixed fee. You keep the findings whether or not we continue.' },
    { n: '02', t: 'Strategy', dur: '1 week', d: 'A 90 day plan with target costs, channel mix, and a tracking diagram. Reviewed with you line by line before anything goes live.' },
    { n: '03', t: 'Launch', dur: '3 days', d: 'We build, test, and ship. Conversion tracking is verified end to end before a single euro of budget is spent.' },
    { n: '04', t: 'Scale', dur: 'Ongoing', d: 'Weekly working sessions and monthly reviews. Budget moves toward what performs, and we show the data behind every decision.' },
  ];
  return (
    <section className="section process" id="process">
      <div className="wrap">
        <div className="section-head">
          <div className="label reveal"><span className="idx">02</span><span className="bar"></span>Process</div>
          <h2 className="clip">Kickoff to first results in <em>two weeks</em>.</h2>
          <p className="sub reveal">No long onboarding. No discovery phase billed by the hour. A defined sequence with a written plan at the end.</p>
        </div>
        <div className="timeline">
          <div className="timeline-rail"></div>
          {steps.map((s, i) => (
            <div className="t-step reveal" style={{ transitionDelay: `${i * 0.08}s` }} key={s.n}>
              <div className="t-node">{s.n}</div>
              <div className="t-body">
                <div className="t-head"><h3>{s.t}</h3><span className="t-dur">{s.dur}</span></div>
                <p>{s.d}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Cases ────────────────────────────────────────────────────────────
function Cases() {
  const cases = [
    { id: 'Case 01', when: 'Q3 2025', num: <>3.2<span className="u">x</span></>, label: 'Return on ad spend', desc: 'Cost per demo fell 61 percent in 60 days after we rebuilt the Performance Max feed and removed 80 percent of legacy keywords.', ind: 'B2B SaaS / EU' },
    { id: 'Case 02', when: 'Q1 2026', num: <>+412<span className="u">%</span></>, label: 'Revenue growth', desc: 'A reworked shopping feed segmented by margin and a tested video library produced their strongest quarter in five years.', ind: 'DTC Apparel / UK' },
    { id: 'Case 03', when: 'Q4 2025', num: <>€18<span className="u"> cpl</span></>, label: 'Down from €74', desc: 'We moved off broad match, built proper offline conversions, and gave the system a real signal to optimize against.', ind: 'Marketplace / US' },
  ];
  return (
    <section className="section" id="work">
      <div className="wrap">
        <div className="section-head">
          <div className="label reveal"><span className="idx">03</span><span className="bar"></span>Selected work</div>
        </div>
        <div className="cases-grid">
          {cases.map((c, i) => (
            <div className="case reveal" style={{ transitionDelay: `${i * 0.08}s` }} key={c.id}>
              <div className="ctop"><span>{c.id}</span><span>{c.when}</span></div>
              <div className="cnum">{c.num}</div>
              <div className="clabel">{c.label}</div>
              <div className="cdesc">{c.desc}</div>
              <div className="cind">{c.ind}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Manifesto ────────────────────────────────────────────────────────
function Manifesto() {
  return (
    <section className="section manifesto">
      <div className="wrap">
        <div className="label reveal"><span className="idx">04</span><span className="bar"></span>Principle</div>
        <q className="clip">Your finance team cannot deposit impressions. We optimize for the <span className="hl">one number</span> that lands in the bank.</q>
        <div className="sig reveal">Project Maven, founding team</div>
      </div>
    </section>
  );
}

// ── Pricing ──────────────────────────────────────────────────────────
function Pricing() {
  const tiers = [
    { name: 'Audit', mark: '', price: '€2,400', unit: 'one time', desc: 'A two week teardown of your account. You leave with a 90 day plan and a tracking diagram.', features: ['Account and GA4 review', 'Competitive analysis', 'Tracking architecture audit', '90 day strategy document', 'No retainer required'], cta: 'Book audit', primary: false, featured: false },
    { name: 'Operator', mark: 'Most chosen', price: '€6,800', unit: 'per month', desc: 'Full management for teams spending €30k to €150k per month. Weekly sessions, monthly reviews.', features: ['Strategy and creative direction', 'Search, PMax, and YouTube', 'Conversion tracking maintained', 'Weekly call and shared channel', 'Monthly performance review'], cta: 'Book a meeting', primary: true, featured: true },
    { name: 'Embedded', mark: '', price: 'From €14,000', unit: 'per month', desc: 'An embedded growth team for companies scaling past €200k per month. Includes a dedicated analyst.', features: ['Everything in Operator', 'Dedicated growth analyst', 'Custom reporting and BI', 'Landing page and CRO sprints', 'Quarterly board preparation'], cta: 'Talk to founders', primary: false, featured: false },
  ];
  return (
    <section className="section" id="pricing">
      <div className="wrap">
        <div className="section-head">
          <div className="label reveal"><span className="idx">05</span><span className="bar"></span>Engagements</div>
          <h2 className="clip">Three ways to work <em>together</em>.</h2>
          <p className="sub reveal">Defined scope and defined pricing. No retainer creep. Cancel any month with thirty days of notice.</p>
        </div>
        <div className="tiers">
          {tiers.map((tier, i) => (
            <div className={`tier reveal${tier.featured ? ' featured' : ''}`} style={{ transitionDelay: `${i * 0.07}s` }} key={i}>
              <div className="tname"><span>{tier.name}</span>{tier.mark && <span className="mark">{tier.mark}</span>}</div>
              <div className="price">{tier.price} <span className="u">{tier.unit}</span></div>
              <p className="tdesc">{tier.desc}</p>
              <ul>{tier.features.map((f, j) => <li key={j}><span>{f}</span></li>)}</ul>
              <a className={`btn ${tier.primary ? 'btn-primary' : 'btn-ghost'}`} href="#contact">{tier.cta} <span className="tick">→</span></a>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── FAQ ──────────────────────────────────────────────────────────────
function FAQ() {
  const items = [
    { q: 'How long until I see results?', a: 'First numbers land within 14 days of launch. Meaningful trend lines settle around day 30, and compounding starts near day 60. You have access to dashboards from the first day.' },
    { q: 'Do I keep ownership of my ad accounts?', a: 'Always. We work inside your Google Ads, GA4, and Tag Manager properties, never our own. If we stop working together, you keep the account, the structure, and the documentation.' },
    { q: 'What is your minimum monthly ad spend?', a: 'For ongoing management, €30,000 per month in media. Below that, the Audit is usually the right starting point. You get a clear plan and can run it in house if you prefer.' },
    { q: 'Do you work with my industry?', a: 'We focus on SaaS, e-commerce above €1M in annual revenue, and high intent service businesses. We decline crypto, gambling, and multi level marketing.' },
    { q: 'How is this different from a freelancer?', a: 'A freelancer optimizes the campaigns you ask for. We address the offer, the landing page, the tracking, and the follow up that actually cap your numbers. Same cost, different scope.' },
    { q: 'Can I see the work before committing?', a: 'Yes. The Audit is the work. You see the strategy, the tracking diagram, and the creative direction before any ongoing agreement. Around 40 percent of audit clients run it themselves afterward.' },
  ];
  const [open, setOpen] = useState(0);
  return (
    <section className="section" id="faq">
      <div className="wrap">
        <div className="section-head">
          <div className="label reveal"><span className="idx">06</span><span className="bar"></span>Questions</div>
          <h2 className="clip">The answers, before you <em>book</em>.</h2>
          <p className="sub reveal">If something is not covered here, ask on the call. We answer directly.</p>
        </div>
        <div className="faq">
          {items.map((it, i) => (
            <div key={i} className={`faq-item reveal${open === i ? ' open' : ''}`} onClick={() => setOpen(open === i ? -1 : i)}>
              <div className="faq-q">
                <span className="qi">{String(i + 1).padStart(2, '0')}</span>
                <span className="qt">{it.q}</span>
                <span className="qx">+</span>
              </div>
              {open === i && <div className="faq-a">{it.a}</div>}
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Final CTA ────────────────────────────────────────────────────────
function FinalCTA() {
  return (
    <section className="section final" id="contact">
      <div className="wrap">
        <div className="label reveal"><span className="idx">07</span><span className="bar"></span>Contact</div>
        <h2 className="clip">Let us look at your <span className="hl">account</span>.</h2>
        <p className="reveal">A 30 minute call. We review your account live, tell you what we would change, and you decide if there is a fit. No deck, no handoff to a junior.</p>
        <div className="ctas reveal">
          <a className="btn btn-primary" href="#">Book a meeting <span className="tick">→</span></a>
          <a className="btn btn-ghost" href="#">Request an audit</a>
        </div>
      </div>
    </section>
  );
}

// ── Footer ───────────────────────────────────────────────────────────
function Footer() {
  return (
    <footer>
      <div className="wrap">
        <div className="foot-grid">
          <div className="foot-brand">
            <div className="brand"><span className="logo"><span className="p">P</span><span className="m">M</span><span className="v">V</span></span></div>
            <p>Google Ads management for companies that measure success in revenue. Built and run by a small team in Barcelona.</p>
          </div>
          <div>
            <h4>Work</h4>
            <ul>
              <li><a href="#services">Services</a></li>
              <li><a href="#work">Case studies</a></li>
              <li><a href="#process">Process</a></li>
              <li><a href="#pricing">Pricing</a></li>
            </ul>
          </div>
          <div>
            <h4>Company</h4>
            <ul>
              <li><a href="#">About</a></li>
              <li><a href="#">Notes</a></li>
              <li><a href="#">Careers</a></li>
              <li><a href="#contact">Contact</a></li>
            </ul>
          </div>
          <div>
            <h4>Direct</h4>
            <ul>
              <li><a href="#">LinkedIn</a></li>
              <li><a href="mailto:ops@projectmaven.co">ops@projectmaven.co</a></li>
              <li><a href="#">Privacy</a></li>
              <li><a href="#">Terms</a></li>
            </ul>
          </div>
        </div>
        <div className="foot-wordmark">Maven</div>
        <div className="foot-bottom">
          <span>© 2026 Project Maven SL</span>
          <span>Google Partner / Made in Barcelona</span>
        </div>
      </div>
    </footer>
  );
}

// ── App ──────────────────────────────────────────────────────────────
function App() {
  const t = window.MAVEN;
  useStarfield(t.starfield);
  useScrollFx();

  useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty('--pink', t.accent);
    r.style.setProperty('--display', `'${t.displayFont}', system-ui, sans-serif`);
    const sl = document.querySelector('.fx-scanlines');
    if (sl) sl.style.opacity = t.scanlines ? '1' : '0';
    const sf = document.getElementById('starfield');
    if (sf) sf.style.display = t.starfield ? 'block' : 'none';
  }, [t.accent, t.displayFont, t.scanlines, t.starfield]);

  return (
    <div className="page">
      <Nav />
      <Hero t={t} />
      <Stats />
      <Services />
      <Process />
      <Cases />
      <Manifesto />
      <Pricing />
      <FAQ />
      <FinalCTA />
      <Footer />
    </div>
  );
}

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