/* global React, ReactDOM */
const { useState, useEffect, useRef, useMemo } = React;

/* ============================================================
   Tweakable defaults — host rewrites this block on disk
   ============================================================ */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "headlineVariant": "architects",
  "taglineVariant": "engines",
  "marqueeOn": true,
  "marqueeSpeed": 40,
  "marqueeContent": "manifesto",
  "motion": "full",
  "theme": "cream",
  "vermillion": "#D62828",
  "countersOn": true,
  "showCaseStudies": true,
  "showManifesto": true,
  "ampersandOpacity": 7,
  "heroAmpDrift": true,
  "denseHero": false
}/*EDITMODE-END*/;

/* ============================================================
   Copy library — multiple options for headlines / taglines
   ============================================================ */
const HEADLINES = {
  architects: { line1: "We're not marketing consultants.", line2: "We're revenue architects." },
  systems: { line1: "Most revenue problems aren't marketing problems.", line2: "They're system problems." },
  engines: { line1: "We don't run campaigns.", line2: "We build revenue engines." },
  compound: { line1: "Brand. Demand. Revenue.", line2: "Engineered to compound." },
  receipts: { line1: "Operators don't need decks.", line2: "They need receipts." }
};

const TAGLINES = {
  engines: <>We build <em>revenue engines</em>, not campaigns.</>,
  compounding: <>Brand, demand, and revenue — engineered as one <em>compounding</em> system.</>,
  install: <>We install the system. <em>Then we stay accountable to the numbers.</em></>,
  fractional: <><em>Fractional engagement.</em> Full-team output. Operator-grade execution.</>,
  loop: <>Brand creates the meaning. Demand builds the pipeline. Revenue <em>closes the loop.</em></>
};

const MARQUEE_SETS = {
  manifesto: ['Brand Strategy', 'Demand Generation', 'Revenue Engines', 'Compounding Systems', 'Operator-Grade'],
  receipts: ['$30M → $130M Scale-Up', '13 Concept Launches', '$50M+ VIP System', '10+ Years YoY Growth', '$500M+ Lifetime Sales'],
  verbs: ['Build', 'Install', 'Operate', 'Compound', 'Scale', 'Ship', 'Close', 'Engineer'],
  pillars: ['Strategy', 'Revenue', 'Brand']
};

/* ============================================================
   Hooks
   ============================================================ */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal, .reveal-stagger');
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  });
}

function useCounter(target, enabled, formatter, duration = 1600) {
  const [val, setVal] = useState(enabled ? 0 : target);
  const ref = useRef(null);
  useEffect(() => {
    if (!enabled) { setVal(target); return; }
    setVal(0);
    const node = ref.current;
    if (!node) return;
    let started = false;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started) {
          started = true;
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - start) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(target * eased);
            if (p < 1) requestAnimationFrame(tick);
            else setVal(target);
          };
          requestAnimationFrame(tick);
          io.disconnect();
        }
      });
    }, { threshold: 0.4 });
    io.observe(node);
    return () => io.disconnect();
  }, [target, enabled, duration]);
  return [val, ref];
}

function AnimCounter({ value, format, enabled }) {
  const [v, ref] = useCounter(value, enabled, format);
  return <span ref={ref}>{format(v)}</span>;
}

/* ============================================================
   Nav
   ============================================================ */
function Nav() {
  return (
    <nav className="nav">
      <div className="nav-inner">
        <a href="#home" className="nav-brand">Thomas James <span className="amp">&amp;</span> Co.</a>
        <ul className="nav-links">
          <li><a href="#approach">Approach</a></li>
          <li><a href="#work">Work</a></li>
          <li><a href="#engagements">Engagements</a></li>
          <li><a href="#contact" className="nav-cta">Book a Call</a></li>
        </ul>
      </div>
    </nav>
  );
}

/* ============================================================
   Hero — kinetic, with merged About credentials inline
   ============================================================ */
function Hero({ tweaks }) {
  const ampRef = useRef(null);
  const heroRef = useRef(null);

  useEffect(() => {
    const id = requestAnimationFrame(() => {
      if (heroRef.current) heroRef.current.classList.add('in');
    });
    return () => cancelAnimationFrame(id);
  }, []);

  useEffect(() => {
    if (!tweaks.heroAmpDrift || tweaks.motion === 'off') {
      if (ampRef.current) ampRef.current.style.setProperty('--amp-shift', '0px');
      return;
    }
    let raf;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const y = window.scrollY;
        const shift = Math.min(y * 0.18, 280);
        if (ampRef.current) ampRef.current.style.setProperty('--amp-shift', `${shift}px`);
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); };
  }, [tweaks.heroAmpDrift, tweaks.motion]);

  const h = HEADLINES[tweaks.headlineVariant] || HEADLINES.architects;
  const tag = TAGLINES[tweaks.taglineVariant] || TAGLINES.engines;

  // headline: render with em emphasis on second line if applicable
  const renderLine = (text) => {
    // Highlight specific phrases by wrapping in em
    const phrases = ['revenue architects', 'system problems', 'revenue engines', 'compound', 'receipts'];
    for (const p of phrases) {
      const idx = text.toLowerCase().indexOf(p);
      if (idx >= 0) {
        return <>
          {text.slice(0, idx)}
          <em>{text.slice(idx, idx + p.length)}</em>
          {text.slice(idx + p.length)}
        </>;
      }
    }
    return text;
  };

  return (
    <section id="home" className="hero" ref={heroRef}>
      <div
        ref={ampRef}
        className="hero-amp"
        style={{ opacity: (tweaks.ampersandOpacity ?? 7) / 100 }}
      >&amp;</div>

      <div className="eyebrow hero-eyebrow">Thomas James &amp; Co. — Strategy / Revenue / Brand</div>

      <h1 className="hero-h1 serif">
        <span className="line"><span className="line-inner">{renderLine(h.line1)}</span></span>
        <span className="line"><span className="line-inner">{renderLine(h.line2)}</span></span>
      </h1>

      <div className="hero-sub serif">{tag}</div>

      <div className="hero-actions">
        <a href="#contact" className="btn btn-primary">Book a 15-min Call</a>
        <a href="#approach" className="btn btn-secondary">See the Approach</a>
      </div>

      <div className="hero-receipts">
        <div className="receipt">
          <div className="receipt-num">
            <AnimCounter value={130} enabled={tweaks.countersOn} format={(v) => `$30M → $${Math.round(v)}M`} />
          </div>
          <div className="receipt-label">Company Scaled<br/>Over Tenure</div>
        </div>
        <div className="receipt">
          <div className="receipt-num">
            <AnimCounter value={10} enabled={tweaks.countersOn} format={(v) => `${Math.round(v)}+ Years`} />
          </div>
          <div className="receipt-label">Consecutive YoY<br/>Revenue Growth</div>
        </div>
        <div className="receipt">
          <div className="receipt-num">
            <AnimCounter value={13} enabled={tweaks.countersOn} format={(v) => `${Math.round(v)}`} />
          </div>
          <div className="receipt-label">Concept Launches<br/>Brand → Revenue</div>
        </div>
        <div className="receipt">
          <div className="receipt-num">
            <AnimCounter value={50} enabled={tweaks.countersOn} format={(v) => `$${Math.round(v)}M+ VIP`} />
          </div>
          <div className="receipt-label">Built in 2 Years<br/>6% → 25%+ Conversion</div>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   Marquee strip
   ============================================================ */
function Marquee({ items, variant = 'ink', alt = false }) {
  const list = [...items, ...items, ...items];
  return (
    <div className={`marquee ${variant === 'cream' ? 'cream' : variant === 'vermillion' ? 'vermillion' : ''}`}>
      <div className={`marquee-track ${alt ? 'alt' : ''}`}>
        {list.map((t, i) => (
          <span className="marquee-item" key={i}>
            <span>{t}</span>
            <span className="dot">&amp;</span>
          </span>
        ))}
      </div>
    </div>
  );
}

/* ============================================================
   Approach — diagnostic + pillars
   ============================================================ */
function Approach() {
  const diagnostics = [
    "You're pulling every lever — and none of them are moving the needle.",
    "Top of funnel is full. Bottom of funnel is leaking. Nobody can tell you why.",
    "Your sales team is fielding tire-kickers — because nobody owns lead quality.",
    "Discounts have become the strategy — and margin is paying the price.",
    "Brand, marketing, and sales running on three scoreboards — and the math doesn't add up.",
    "Every quarter starts at zero. Nothing compounds. Nothing carries forward."
  ];

  const renderDiagnostic = (text) => {
    // Italicize the second clause after the dash
    const dashIdx = text.indexOf('—');
    if (dashIdx > 0) {
      return <>{text.slice(0, dashIdx + 1)}<em>{text.slice(dashIdx + 1)}</em></>;
    }
    return text;
  };

  return (
    <section id="approach" className="block">
      <div className="section-inner">
        <div className="eyebrow reveal">The Approach</div>

        <div className="diagnostic-wrap">
          <h2 className="diagnostic-headline reveal">
            <span className="diagnostic-setup">Most revenue problems aren't <em>marketing</em> problems.</span>
            <span className="diagnostic-hit">They're <em>system</em> problems.</span>
          </h2>

          <div className="diagnostic-list reveal-stagger">
            {diagnostics.map((d, i) => (
              <div className="diagnostic-item" key={i}>
                <span className="diagnostic-num">{String(i + 1).padStart(2, '0')}</span>
                {renderDiagnostic(d)}
              </div>
            ))}
          </div>
        </div>

        <div className="pillars-section">
          <div className="eyebrow reveal" style={{ marginBottom: 18 }}>The Architecture</div>
          <h3 className="pillars-headline reveal">
            We engineer all three pillars into one <em>compounding</em> system.
          </h3>

          <div className="pillars-grid reveal-stagger">
            <div className="pillar">
              <div className="pillar-num">01</div>
              <div className="pillar-name"><em>Brand</em> Strategy</div>
              <div className="pillar-desc">Positioning, identity, and pricing architecture that creates <em>meaning</em> — and the margin that meaning earns.</div>
            </div>
            <div className="pillar">
              <div className="pillar-num">02</div>
              <div className="pillar-name"><em>Demand</em> Generation</div>
              <div className="pillar-desc">Marketing strategy, channel design, and go-to-market that builds qualified <em>pipeline</em> — not vanity reach.</div>
            </div>
            <div className="pillar">
              <div className="pillar-num">03</div>
              <div className="pillar-name"><em>Revenue</em> Engine</div>
              <div className="pillar-desc">Sales infrastructure, conversion systems, and accountability that close the loop — and <em>compound</em> over time.</div>
            </div>
          </div>

          <div className="architecture-flow reveal">
            Brand creates the <em>meaning</em>. Demand creates the <em>pipeline</em>. Revenue closes the <em>loop</em>.
          </div>

          <div className="ai-band reveal">
            <div className="ai-band-label">— Powered by</div>
            <div className="ai-band-text">
              AI-augmented engineering, optimization, and automation. <em>Fractional engagement. Full-team output.</em>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   Case studies
   ============================================================ */
function CaseStudies({ tweaks }) {
  if (!tweaks.showCaseStudies) return null;

  const cases = [
    {
      tag: '— Multi-Unit Hospitality · 6-Year Tenure',
      headline: <>From <em>$30M</em> to <em>$130M</em>, scaled.</>,
      detail: 'Six years as VP of Sales & Marketing, leading both functions at the executive level through a four-fold revenue scale-up. Brand, demand, and revenue rebuilt as one compounding system.',
      stats: [{ n: '$30→$130M', l: 'Revenue' }, { n: '10+ yrs', l: 'YoY Growth' }],
      meta: ['Hospitality', 'Multi-unit'],
      alt: false
    },
    {
      tag: '— VIP Conversion · 2-Year Build',
      headline: <>The <em>$50M+</em> VIP system.</>,
      detail: 'Built end-to-end in 24 months. Conversion ramped from 6% to 25%+. Pricing, positioning, sales process, retention loop — installed once, compounded quarterly.',
      stats: [{ n: '6 → 25%+', l: 'Conversion' }, { n: '$50M+', l: 'System Value' }],
      meta: ['VIP', '2 years'],
      alt: true
    },
    {
      tag: '— Concept Launches · 13 Successful',
      headline: <>Thirteen launches. <em>Zero misfires.</em></>,
      detail: 'Pre-revenue concepts taken from blank page to opening day with revenue already flowing. Hospitality, nightlife, experiential. Brand strategy, GTM, and day-one revenue playbooks.',
      stats: [{ n: '13', l: 'Concepts' }, { n: '$500M+', l: 'Lifetime Sales' }],
      meta: ['Launch', 'Pre-revenue'],
      alt: true
    },
    {
      tag: '— Margin Architecture · Pricing Reset',
      headline: <>Discounting wasn't strategy. <em>It was leakage.</em></>,
      detail: 'Margin protection through positioning, offer architecture, and channel discipline. Replaced the discount reflex with a pricing system that holds — and a sales process that closes without it.',
      stats: [{ n: '+12pts', l: 'Gross Margin' }, { n: '0', l: 'Discount Reliance' }],
      meta: ['Pricing', 'Channel'],
      alt: false
    }
  ];

  return (
    <section id="work" className="block warm">
      <div className="section-inner">
        <div className="eyebrow reveal">Receipts in the Wild</div>
        <h2 className="section-h2 reveal serif">
          The work behind the <em>numbers</em>.
        </h2>
        <p className="section-lede reveal">
          Anonymized examples of installed systems. <em>References available on request.</em>
        </p>

        <div className="case-grid reveal-stagger">
          {cases.map((c, i) => (
            <article key={i} className={`case-card ${c.alt ? 'alt' : ''}`}>
              <div className="case-amp">&amp;</div>
              <div className="case-tag">{c.tag}</div>
              <h3 className="case-headline serif">{c.headline}</h3>
              <div className="case-detail">{c.detail}</div>
              <div className="case-stats">
                {c.stats.map((s, j) => (
                  <div key={j}>
                    <div className="case-stat-num">{s.n}</div>
                    <div className="case-stat-label">{s.l}</div>
                  </div>
                ))}
              </div>
              <div className="case-meta">
                <span>{c.meta[0]}</span>
                <span>{c.meta[1]}</span>
              </div>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   Manifesto slab
   ============================================================ */
function Manifesto({ tweaks }) {
  if (!tweaks.showManifesto) return null;
  return (
    <section className="manifesto">
      <div className="manifesto-inner">
        <div className="manifesto-eyebrow">Manifesto</div>
        <h2 className="manifesto-h2">
          We come in. We diagnose where deals are dying. We build the systems to fix it. <em>And we stay accountable to the numbers.</em>
        </h2>
      </div>
    </section>
  );
}

/* ============================================================
   Engagements
   ============================================================ */
function Engagements() {
  return (
    <section id="engagements" className="block">
      <div className="section-inner">
        <div className="eyebrow reveal">Engagements</div>
        <h2 className="section-h2 reveal serif">
          Three packages. Built for <em>immediate impact</em> — and <em>lasting partnerships</em>.
        </h2>
        <p className="section-lede reveal">
          Every engagement begins with a <em>diagnostic</em> — never a generic plan. Start where you are. Scale as the relationship proves itself.
        </p>

        <div className="engagements-grid reveal-stagger">
          <div className="engagement-card">
            <div className="engagement-num">01</div>
            <div className="engagement-tag">— Project</div>
            <h3 className="engagement-name"><em>Brand</em> &amp; Go-to-Market</h3>
            <p className="engagement-pitch">For founders launching a new concept or operators repositioning an existing one — from blank page to opening day with revenue already flowing.</p>
            <ul className="engagement-list">
              <li>Brand strategy &amp; positioning</li>
              <li>Target market &amp; ICP definition</li>
              <li>Pricing &amp; offer architecture</li>
              <li>Pre-revenue conversion strategy</li>
              <li>Launch campaign &amp; channel plan</li>
              <li>Day-one revenue playbook</li>
            </ul>
            <div className="engagement-meta">
              <span>6–12 wks</span>
              <span>Project</span>
            </div>
            <div className="engagement-price">$15K–$40K</div>
            <div className="engagement-price-label">Per project</div>
          </div>

          <div className="engagement-card">
            <div className="engagement-num">02</div>
            <div className="engagement-tag">— Sprint</div>
            <h3 className="engagement-name"><em>Revenue</em> Growth Sprint</h3>
            <p className="engagement-pitch">For operators who need a step-change in pipeline, conversion, or channel performance — built to install systems, not just deliver decks.</p>
            <ul className="engagement-list">
              <li>Revenue diagnostic &amp; gap analysis</li>
              <li>ICP refinement &amp; segmentation</li>
              <li>Demand generation system design</li>
              <li>Pricing &amp; margin optimization</li>
              <li>High-margin channel development</li>
              <li>90-day execution roadmap</li>
            </ul>
            <div className="engagement-meta">
              <span>90 days</span>
              <span>Sprint</span>
            </div>
            <div className="engagement-price">$25K–$60K</div>
            <div className="engagement-price-label">Per quarter</div>
          </div>

          <div className="engagement-card">
            <div className="engagement-num">03</div>
            <div className="engagement-tag">— Retainer</div>
            <h3 className="engagement-name"><em>Fractional</em> CMO / CRO</h3>
            <p className="engagement-pitch">For operators who need executive-grade marketing and revenue leadership without full-time overhead — embedded in your leadership team.</p>
            <ul className="engagement-list">
              <li>Embedded executive presence</li>
              <li>Marketing &amp; sales org leadership</li>
              <li>Revenue &amp; KPI accountability</li>
              <li>Team coaching &amp; development</li>
              <li>Vendor &amp; agency management</li>
              <li>Board &amp; investor reporting</li>
            </ul>
            <div className="engagement-meta">
              <span>~1–2 days/wk</span>
              <span>Retainer</span>
            </div>
            <div className="engagement-price">$8K–$15K</div>
            <div className="engagement-price-label">Per month · 3-mo min.</div>
          </div>
        </div>

        <div className="equity-note reveal">
          § Equity-based or hybrid engagements considered for select pre-revenue concepts with the right founder, cap table, and conviction. <em>Inquire separately.</em>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   Contact
   ============================================================ */
function Contact() {
  React.useEffect(() => {
    if (document.querySelector('script[src*="fillout.com/embed"]')) return;
    const s = document.createElement('script');
    s.src = 'https://server.fillout.com/embed/v1/';
    s.async = true;
    document.body.appendChild(s);
  }, []);

  return (
    <section id="contact" className="contact-section">
      <div className="contact-grid">
        <div>
          <div className="eyebrow" style={{ color: 'var(--gold)', marginBottom: 24 }}>Next Step</div>
          <h2 className="contact-h2 serif">Start with a <em>15-minute<br/>diagnostic call.</em></h2>
          <p className="contact-sub">
            Bring the situation. We'll bring the operator perspective. We'll know within fifteen minutes whether there's a fit — and if there is, <em>what the right engagement looks like.</em>
          </p>
          <div className="contact-actions">
            <a href="mailto:thomas@thomasjamesandco.com" className="btn btn-primary">Email Direct</a>
            <a href="https://www.linkedin.com/in/thomashansonandco" target="_blank" rel="noopener" className="btn contact-btn-secondary">Connect on LinkedIn</a>
          </div>
        </div>
        <div
          style={{ width: '100%', minHeight: 500 }}
          data-fillout-id="hBgvSJjcgTus"
          data-fillout-embed-type="standard"
          data-fillout-inherit-parameters=""
          data-fillout-dynamic-resize=""
        />
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer>
      <div className="footer-inner">
        <div className="footer-brand">Thomas James <span className="amp">&amp;</span> Co. · 2026</div>
        <div className="footer-meta">
          <a href="mailto:thomas@thomasjamesandco.com">thomas@thomasjamesandco.com</a><br/>
          Strategy <span style={{ color: 'var(--vermillion)' }}>/</span> Revenue <span style={{ color: 'var(--vermillion)' }}>/</span> Brand
        </div>
      </div>
    </footer>
  );
}

/* ============================================================
   Tweaks panel
   ============================================================ */
function Tweaks({ tweaks, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Hero copy" />
      <TweakSelect
        label="Headline"
        value={tweaks.headlineVariant}
        onChange={(v) => setTweak('headlineVariant', v)}
        options={[
          { value: 'architects', label: "Revenue architects" },
          { value: 'systems', label: "System problems" },
          { value: 'engines', label: "Engines, not campaigns" },
          { value: 'compound', label: "Engineered to compound" },
          { value: 'receipts', label: "Operators need receipts" }
        ]}
      />
      <TweakSelect
        label="Tagline"
        value={tweaks.taglineVariant}
        onChange={(v) => setTweak('taglineVariant', v)}
        options={[
          { value: 'engines', label: 'Revenue engines' },
          { value: 'compounding', label: 'Compounding system' },
          { value: 'install', label: 'Install. Stay accountable' },
          { value: 'fractional', label: 'Fractional engagement' },
          { value: 'loop', label: 'Closes the loop' }
        ]}
      />

      <TweakSection label="Theme & color" />
      <TweakRadio
        label="Surface"
        value={tweaks.theme}
        onChange={(v) => setTweak('theme', v)}
        options={['cream', 'dark']}
      />
      <TweakColor
        label="Vermillion"
        value={tweaks.vermillion}
        onChange={(v) => setTweak('vermillion', v)}
      />
      <TweakSlider
        label="Hero & opacity"
        min={3} max={28} step={1} unit="%"
        value={tweaks.ampersandOpacity}
        onChange={(v) => setTweak('ampersandOpacity', v)}
      />
      <TweakToggle
        label="Hero & drifts"
        value={tweaks.heroAmpDrift}
        onChange={(v) => setTweak('heroAmpDrift', v)}
      />

      <TweakSection label="Marquee" />
      <TweakToggle
        label="Marquee on"
        value={tweaks.marqueeOn}
        onChange={(v) => setTweak('marqueeOn', v)}
      />
      <TweakSlider
        label="Speed"
        min={15} max={90} step={5} unit="s"
        value={tweaks.marqueeSpeed}
        onChange={(v) => setTweak('marqueeSpeed', v)}
      />
      <TweakSelect
        label="Content"
        value={tweaks.marqueeContent}
        onChange={(v) => setTweak('marqueeContent', v)}
        options={[
          { value: 'manifesto', label: 'Manifesto' },
          { value: 'receipts', label: 'Receipts' },
          { value: 'verbs', label: 'Verbs' },
          { value: 'pillars', label: 'Pillars' }
        ]}
      />

      <TweakSection label="Motion & sections" />
      <TweakRadio
        label="Motion"
        value={tweaks.motion}
        onChange={(v) => setTweak('motion', v)}
        options={['off', 'subtle', 'full']}
      />
      <TweakToggle
        label="Counter animation"
        value={tweaks.countersOn}
        onChange={(v) => setTweak('countersOn', v)}
      />
      <TweakToggle
        label="Case studies"
        value={tweaks.showCaseStudies}
        onChange={(v) => setTweak('showCaseStudies', v)}
      />
      <TweakToggle
        label="Manifesto slab"
        value={tweaks.showManifesto}
        onChange={(v) => setTweak('showManifesto', v)}
      />
    </TweaksPanel>
  );
}

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

  // Apply theme + motion + speed + vermillion + marquee on/off via body class & CSS vars
  useEffect(() => {
    document.body.classList.toggle('theme-dark', t.theme === 'dark');
    document.body.classList.toggle('motion-off', t.motion === 'off');
    document.body.classList.toggle('motion-subtle', t.motion === 'subtle');
    document.body.classList.toggle('marquee-off', !t.marqueeOn);
    document.documentElement.style.setProperty('--marquee-speed', `${t.marqueeSpeed}s`);
    document.documentElement.style.setProperty('--vermillion', t.vermillion);
    // recompute deep variant
    const c = t.vermillion;
    document.documentElement.style.setProperty('--vermillion-deep', shade(c, -0.18));
  }, [t.theme, t.motion, t.marqueeOn, t.marqueeSpeed, t.vermillion]);

  const marqueeItems = MARQUEE_SETS[t.marqueeContent] || MARQUEE_SETS.manifesto;

  return (
    <>
      <Nav />
      <Hero tweaks={t} />
      {t.marqueeOn && <Marquee items={marqueeItems} variant="ink" />}
      <Approach />
      {t.marqueeOn && <Marquee items={MARQUEE_SETS.receipts} variant="vermillion" alt />}
      <CaseStudies tweaks={t} />
      <Manifesto tweaks={t} />
      <Engagements />
      <Contact />
      <Footer />
      <Tweaks tweaks={t} setTweak={setTweak} />
    </>
  );
}

/* tiny color shade helper */
function shade(hex, pct) {
  const m = hex.replace('#', '');
  const r = parseInt(m.slice(0, 2), 16);
  const g = parseInt(m.slice(2, 4), 16);
  const b = parseInt(m.slice(4, 6), 16);
  const f = (x) => Math.max(0, Math.min(255, Math.round(x + (pct < 0 ? x * pct : (255 - x) * pct))));
  const h = (x) => f(x).toString(16).padStart(2, '0');
  return `#${h(r)}${h(g)}${h(b)}`;
}

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