/* OpSpot — UI building blocks and section components */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- helpers ---------- */
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // If already in viewport at mount, reveal immediately.
    const checkInView = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * 0.95 && r.bottom > 0) {
        el.classList.add('in');
        return true;
      }
      return false;
    };
    if (checkInView()) return;
    // Safety: even if IO never fires (background tab, throttled), reveal after 1.2s.
    const safety = setTimeout(() => el.classList.add('in'), 1200);
    let io;
    if ('IntersectionObserver' in window) {
      io = new IntersectionObserver((entries) => {
        entries.forEach(e => {
          if (e.isIntersecting) {
            el.classList.add('in');
            io.unobserve(el);
            clearTimeout(safety);
          }
        });
      }, { threshold: 0.05, rootMargin: '0px 0px -5% 0px' });
      io.observe(el);
    }
    return () => { clearTimeout(safety); if (io) io.disconnect(); };
  }, []);
  return ref;
}

function Reveal({ as: Tag = 'div', delay = 0, className = '', children, ...rest }) {
  const ref = useReveal();
  const d = delay ? ` d${delay}` : '';
  return <Tag ref={ref} className={`reveal${d} ${className}`} {...rest}>{children}</Tag>;
}

/* ---------- Spotlight (removed for light theme — too flashy for the audience) ---------- */
function Spotlight() {
  return null;
}

/* ---------- Logo mark ---------- */
function OpSpotMark({ size = 30 }) {
  const positions = [
    { x: 50, y: 14, kind: 'a' },
    { x: 86, y: 50, kind: 'a' },
    { x: 50, y: 86, kind: 'a' },
    { x: 14, y: 50, kind: 'a' },
    { x: 75.5, y: 24.5, kind: 'b' },
    { x: 75.5, y: 75.5, kind: 'b' },
    { x: 24.5, y: 75.5, kind: 'b' },
    { x: 24.5, y: 24.5, kind: 'b' },
  ];
  const orange = '#ED7B1C';
  const tan = '#F5C28A';
  const brown = '#7D2F17';
  const bg = '#fafaf7';
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" aria-hidden="true" className="opspot-mark">
      {positions.map((p, i) => (
        <line key={i} x1="50" y1="50" x2={p.x} y2={p.y}
              stroke={tan} strokeWidth="1.4" strokeDasharray="2 2.4" strokeLinecap="round" />
      ))}
      <circle cx="50" cy="50" r="12" fill={brown} />
      {positions.map((p, i) => {
        const c = p.kind === 'a' ? orange : tan;
        return (
          <g key={`n${i}`}>
            <circle cx={p.x} cy={p.y} r="6.5" fill={bg} stroke={c} strokeWidth="1.6" />
            <circle cx={p.x} cy={p.y} r="2.8" fill={c} />
          </g>
        );
      })}
    </svg>
  );
}

/* ---------- Nav ---------- */
const CAL = 'https://calendly.com/colton-opspot/30min';

function Nav() {
  return (
    <nav className="nav">
      <div className="nav-inner">
        <a href="#" className="brand">
          <OpSpotMark size={30} />
          <span>OpSpot</span>
        </a>
        <div className="nav-links">
          <a href="#enemy">The enemy</a>
          <a href="#fleet">Workers</a>
          <a href="#timeline">Install</a>
          <a href="#center">Command Center</a>
          <a href="#trust">Receipts</a>
        </div>
        <div className="nav-spacer" />
        <div className="nav-cta">
          <a href={CAL} target="_blank" rel="noopener" className="btn btn-primary">Book a free audit →</a>
        </div>
      </div>
    </nav>
  );
}

/* ---------- Sparkline (deterministic) ---------- */
function Spark({ seed = 1, color = 'var(--violet)' }) {
  const pts = useMemo(() => {
    const arr = [];
    let v = 28;
    for (let i = 0; i < 24; i++) {
      v += (Math.sin(i * 1.3 + seed) + Math.cos(i * 0.7 + seed * 2)) * 4 + (i * 0.3);
      arr.push(Math.max(4, Math.min(40, v)));
    }
    return arr;
  }, [seed]);
  const path = pts.map((y, i) => `${i === 0 ? 'M' : 'L'} ${(i / (pts.length - 1)) * 100} ${44 - y}`).join(' ');
  return (
    <svg viewBox="0 0 100 44" preserveAspectRatio="none">
      <defs>
        <linearGradient id={`sp${seed}`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={color} stopOpacity="0.5" />
          <stop offset="1" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={path + ` L 100 44 L 0 44 Z`} fill={`url(#sp${seed})`} />
      <path d={path} fill="none" stroke={color} strokeWidth="1.2" strokeLinecap="round" />
    </svg>
  );
}

/* ---------- Hero ---------- */
const FEED_DATA = [
  { who: 'Receptionist', tag: 'Calls', msg: 'Booked oil change for D. Park · Tue 9:30am', tagCls: 'ok', ts: '0s', c: 'oklch(0.75 0.18 290)' },
  { who: 'Follow-up', tag: 'SMS', msg: 'Sent 14 quote nudges · 4 replies, 2 booked', tagCls: 'ok', ts: '6s', c: 'oklch(0.78 0.16 250)' },
  { who: 'Sales', tag: 'Email', msg: 'Drafted proposal for Ridge HVAC · awaiting approval', tagCls: 'hold', ts: '12s', c: 'oklch(0.78 0.17 75)' },
  { who: 'Inventory', tag: 'Stock', msg: 'Reorder triggered · 6mm gasket × 200', tagCls: 'ok', ts: '21s', c: 'oklch(0.82 0.14 200)' },
  { who: 'Ads', tag: 'Meta', msg: 'Paused underperforming creative · CTR 0.71%', tagCls: 'live', ts: '33s', c: 'oklch(0.7 0.21 35)' },
  { who: 'Ops', tag: 'Cal', msg: 'Re-routed Wed tech runs · 14 stops optimized', tagCls: 'live', ts: '47s', c: 'oklch(0.7 0.2 240)' },
  { who: 'Receptionist', tag: 'Calls', msg: 'After-hours quote captured · Mrs. Alvarez', tagCls: 'ok', ts: '1m', c: 'oklch(0.75 0.18 290)' },
  { who: 'Content', tag: 'Post', msg: 'Drafted 3 IG reels from this week\'s jobs', tagCls: 'hold', ts: '1m', c: 'oklch(0.78 0.16 155)' },
];

const TRANSCRIPT = [
  "Hi, thanks for calling Ridge Plumbing — this is Avery, the AI assistant.",
  "I can absolutely book you for a leak inspection. What's the address?",
  "Got it. Tuesday at 9:30 with Marco works — sending a confirmation now."
];

function CommandStage() {
  const [feed, setFeed] = useState(FEED_DATA.slice(0, 5));
  const [callIdx, setCallIdx] = useState(0);
  const [typed, setTyped] = useState('');
  const idx = useRef(0);

  // rotating feed
  useEffect(() => {
    const id = setInterval(() => {
      idx.current = (idx.current + 1) % FEED_DATA.length;
      setFeed(prev => {
        const next = FEED_DATA[idx.current];
        return [next, ...prev.slice(0, 4)];
      });
    }, 3200);
    return () => clearInterval(id);
  }, []);

  // typing transcript
  useEffect(() => {
    const line = TRANSCRIPT[callIdx];
    let i = 0;
    setTyped('');
    const id = setInterval(() => {
      i++;
      setTyped(line.slice(0, i));
      if (i >= line.length) {
        clearInterval(id);
        setTimeout(() => setCallIdx(c => (c + 1) % TRANSCRIPT.length), 2400);
      }
    }, 28);
    return () => clearInterval(id);
  }, [callIdx]);

  return (
    <div className="stage">
      <div className="stage-head">
        <div className="dots"><span /><span /><span /></div>
        <span className="stage-title">opspot.command — ridge-plumbing.workspace</span>
        <span className="stage-pill"><span className="dot" /> 8 agents live</span>
      </div>
      <div className="stage-body">
        <aside className="stage-sidebar">
          <div className="side-h">Fleet</div>
          <div className="side-item active" style={{'--c1':'oklch(0.75 0.18 290)','--c2':'oklch(0.6 0.22 270)'}}>
            <span className="ag" /> Receptionist <span className="count">42</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.78 0.16 250)','--c2':'oklch(0.6 0.18 230)'}}>
            <span className="ag" /> Follow-up <span className="count">128</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.78 0.17 75)','--c2':'oklch(0.65 0.2 50)'}}>
            <span className="ag" /> Sales <span className="count">19</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.78 0.16 155)','--c2':'oklch(0.6 0.18 145)'}}>
            <span className="ag" /> Booking <span className="count">31</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.82 0.14 200)','--c2':'oklch(0.6 0.16 220)'}}>
            <span className="ag" /> Inventory <span className="count">6</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.7 0.21 35)','--c2':'oklch(0.6 0.22 25)'}}>
            <span className="ag" /> Ads <span className="count">3</span>
          </div>
          <div className="side-item" style={{'--c1':'oklch(0.7 0.2 240)','--c2':'oklch(0.6 0.22 260)'}}>
            <span className="ag" /> Ops <span className="count">11</span>
          </div>
          <div className="side-h">Workspaces</div>
          <div className="side-item" style={{'--c1':'oklch(0.5 0.05 280)','--c2':'oklch(0.3 0.02 270)'}}>
            <span className="ag off" /> Ridge Plumbing
          </div>
        </aside>

        <main className="stage-main">
          <div className="kpi-row">
            <div className="kpi">
              <div className="label">Calls handled today</div>
              <div className="val">142 <span className="delta">+38</span></div>
              <div className="spark"><Spark seed={1} color="oklch(0.75 0.18 290)" /></div>
            </div>
            <div className="kpi">
              <div className="label">Booked jobs · this week</div>
              <div className="val">86 <span className="delta">+12</span></div>
              <div className="spark"><Spark seed={3} color="oklch(0.78 0.16 250)" /></div>
            </div>
            <div className="kpi">
              <div className="label">Pipeline value</div>
              <div className="val">$184k <span className="delta">+$22k</span></div>
              <div className="spark"><Spark seed={5} color="oklch(0.78 0.17 75)" /></div>
            </div>
          </div>

          <div className="feed">
            <div className="feed-head">
              <span>Live activity</span>
              <span className="tabs"><span className="on">All</span><span>Calls</span><span>Approvals</span><span>Receipts</span></span>
            </div>
            {feed.map((r, i) => (
              <div className="row" key={r.ts + i} style={{ '--ac': r.c }}>
                <div className="agent-dot" />
                <div className="ts mono">{r.ts} · {r.who}</div>
                <div className="msg">{r.msg}</div>
                <div className={`tag ${r.tagCls}`}>{r.tag}</div>
                <div className="right">✓ logged</div>
              </div>
            ))}
          </div>
        </main>

        <aside className="stage-right">
          <div className="now-card">
            <div className="h">● Live call · 02:14</div>
            <div className="live-call">
              <div className="avatar">AV</div>
              <div className="wave">
                {Array.from({ length: 18 }).map((_, i) =>
                  <span key={i} style={{ animationDelay: `${i * 60}ms` }} />
                )}
              </div>
            </div>
            <div className="transcript">
              <span className="who">Avery</span>
              {typed}
              <span className="cursor" />
            </div>
          </div>
          <div className="approval">
            <div className="h">⏸ Awaiting approval</div>
            <div className="body">
              Sales agent wants to send <b>$8,400 proposal</b> to Ridge HVAC.
              Outside auto-send threshold.
            </div>
            <div className="acts">
              <button className="mini-btn ok">Approve & send</button>
              <button className="mini-btn no">Edit</button>
            </div>
          </div>
        </aside>
      </div>
    </div>
  );
}

function Hero() {
  return (
    <section className="hero">
      <div className="hero-grid" />
      <div className="hero-beams" />
      <div className="hero-inner">
        <Reveal className="hero-copy">
          <span className="eyebrow"><span className="dot" /> AI employees for business operations</span>
          <h1 className="display">
            <span className="grad">AI employees that</span>{' '}
            <span className="accent">actually show up for work.</span>
          </h1>
          <p className="hero-sub">
            Follow-ups, docs, inboxes, customer updates — handled by AI employees with
            approvals, receipts, and humans in control. We design, deploy, and operate them.
            You buy back your time.
          </p>
          <div className="hero-actions">
            <a href={CAL} target="_blank" rel="noopener" className="btn btn-primary btn-xl">Book a free 30-min audit →</a>
            <a href="#fleet" className="btn btn-ghost">See the workers</a>
          </div>
          <div className="hero-meta">
            <div><b>Workers,</b> not another dashboard</div>
            <div className="sep" />
            <div><b>Receipts</b> on every action</div>
            <div className="sep" />
            <div><b>Approval gates</b> on anything that matters</div>
          </div>
        </Reveal>
        <Reveal delay={2}>
          <CommandStage />
        </Reveal>
      </div>
    </section>
  );
}

/* ---------- Invisible Work (the enemy) ---------- */
const INVISIBLE = [
  { k: 'L-04127', who: 'the lead', verb: 'nobody answered', meta: 'inbound web form · tue 4:48pm', c: 'oklch(0.78 0.17 75)' },
  { k: 'I-00891', who: 'the invoice', verb: 'nobody filed', meta: 'Stripe → books · 7 days overdue', c: 'oklch(0.7 0.21 35)' },
  { k: 'U-12203', who: 'the customer update', verb: 'nobody sent', meta: 'job complete · photos in inbox', c: 'oklch(0.7 0.2 240)' },
  { k: 'F-08877', who: 'the follow-up', verb: 'nobody owned', meta: 'quote sent fri · no reply', c: 'oklch(0.65 0.22 295)' },
  { k: 'D-00342', who: 'the doc', verb: 'sitting in someone’s inbox', meta: 'COI · needs forwarding to GC', c: 'oklch(0.78 0.16 155)' },
];

function InvisibleWork() {
  return (
    <section className="section-pad enemy" id="enemy" style={{ paddingTop: 80 }}>
      <div className="container">
        <div className="enemy-layout">
          <Reveal className="sec-head" style={{ marginBottom: 0 }}>
            <span className="eyebrow">01 · The enemy</span>
            <h2 className="display">
              The enemy isn’t manual work.<br />
              <span className="display-muted">It’s invisible work.</span>
            </h2>
            <p>The work that never makes it onto a calendar. The dropped lead, the unsent update, the doc no one forwarded. It’s where your money quietly leaks. OpSpot makes the work visible, assigned, and handled.</p>
            <div className="enemy-meta mono">
              <span>› OPSPOT MAKES THE WORK <b>VISIBLE</b></span>
              <span>› ASSIGNED TO A WORKER</span>
              <span>› <b>HANDLED</b> WITH A RECEIPT</span>
            </div>
          </Reveal>

          <Reveal delay={1} className="invisible-list">
            <div className="il-head mono">
              <span>STATUS</span><span>WORK</span><span>WHO</span><span>OWNED BY</span>
            </div>
            {INVISIBLE.map((it, i) => (
              <div key={it.k} className="il-row" style={{ '--c': it.c, animationDelay: `${i * 80}ms` }}>
                <span className="il-status"><span className="dot" /> dropped</span>
                <span className="il-work">{it.who} <em>{it.verb}</em><small>{it.meta}</small></span>
                <span className="il-key mono">{it.k}</span>
                <span className="il-owner">— nobody</span>
              </div>
            ))}
            <div className="il-foot">
              <span className="mono">+ OPSPOT</span>
              <span>Every row above gets a named worker, a rule, and a signed receipt.</span>
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

/* ---------- Fleet ---------- */
function FleetSection() {
  return (
    <section className="section-pad" id="fleet">
      <div className="container">
        <Reveal className="sec-head">
          <span className="eyebrow">02 · The workers</span>
          <h2 className="display">Named workers. Real jobs.</h2>
          <p>Eight AI employees, mixed and matched to your business. Each one is connected to your phones, inbox, calendar, CRM, and tools — not a chatbot floating beside them. They log every action and ask before they spend money or speak for you.</p>
        </Reveal>

        <div className="fleet-grid">
          <Reveal className="cell span-6 tall" style={{'--c1':'oklch(0.75 0.18 290)','--c2':'oklch(0.6 0.22 270)'}}>
            <div className="h"><span className="ag" /> AI Receptionist</div>
            <h3>Answers every call.<br />Books the job. Never sleeps.</h3>
            <p>Picks up in two rings, qualifies the caller, books to your calendar, and texts a confirmation — at 2pm or 2am.</p>
            <div className="viz">
              <div className="recep-wave">
                {Array.from({ length: 32 }).map((_, i) => (
                  <span key={i} style={{ animationDelay: `${i * 50}ms`, height: `${20 + Math.sin(i) * 30 + 30}%` }} />
                ))}
              </div>
            </div>
          </Reveal>

          <Reveal delay={1} className="cell span-6 tall" style={{'--c1':'oklch(0.78 0.17 75)','--c2':'oklch(0.65 0.2 50)'}}>
            <div className="h"><span className="ag" /> Sales Agent</div>
            <h3>Quotes, proposals, and chase.<br />Approvals on the big ones.</h3>
            <p>Drafts quotes from your price book, replies to inbound leads, and runs nurture sequences. You approve anything over your set threshold.</p>
            <div className="viz">
              <div className="pipe">
                <div className="col">Intake
                  <div className="card">L. Cheng · roof quote</div>
                </div>
                <div className="col">Qualified
                  <div className="card b">Ridge HVAC · $8.4k</div>
                </div>
                <div className="col">Proposal
                  <div className="card b">Bayside Café · $2.1k</div>
                </div>
                <div className="col">Won
                  <div className="card c">Northgate Auto · $4.6k</div>
                </div>
              </div>
            </div>
          </Reveal>

          <Reveal delay={2} className="cell span-4" style={{'--c1':'oklch(0.78 0.16 250)','--c2':'oklch(0.6 0.18 230)'}}>
            <div className="h"><span className="ag" /> Follow-up Agent</div>
            <h3>Nudges every lead until it converts or dies.</h3>
            <div className="viz">
              <div className="thread">
                <div className="bub"><small>Day 1 · SMS</small>Hey Dana — quote ready when you are.</div>
                <div className="bub me"><small>Day 3 · SMS</small>Holding the Tue 9:30 slot for you?</div>
                <div className="bub"><small>Day 3 · Reply</small>Yes please. Book it.</div>
              </div>
            </div>
          </Reveal>

          <Reveal delay={3} className="cell span-4" style={{'--c1':'oklch(0.78 0.16 155)','--c2':'oklch(0.6 0.18 145)'}}>
            <div className="h"><span className="ag" /> Booking Agent</div>
            <h3>Owns your calendar. Routes the right tech to the right job.</h3>
            <div className="viz">
              <div className="cal">
                {Array.from({ length: 14 }).map((_, i) => {
                  const isBook = [1, 3, 5, 8, 10, 12].includes(i);
                  const isNew = [9, 13].includes(i);
                  return <div key={i} className={`d ${isBook ? 'book' : ''} ${isNew ? 'new' : ''}`}>{(i % 7) + 9}</div>;
                })}
              </div>
            </div>
          </Reveal>

          <Reveal delay={4} className="cell span-4" style={{'--c1':'oklch(0.82 0.14 200)','--c2':'oklch(0.6 0.16 220)'}}>
            <div className="h"><span className="ag" /> Inventory Tracker</div>
            <h3>Watches stock. Reorders before you run out.</h3>
            <div className="viz">
              <div className="inv">
                <div className="ir"><span>Gaskets 6mm</span><div className="bar"><span style={{ width: '18%' }} className="low" /></div><span>18%</span></div>
                <div className="ir"><span>Filter A-12</span><div className="bar"><span style={{ width: '64%' }} /></div><span>64%</span></div>
                <div className="ir"><span>Pipe 1/2&quot;</span><div className="bar"><span style={{ width: '82%' }} /></div><span>82%</span></div>
                <div className="ir"><span>Coupler 3/4</span><div className="bar"><span style={{ width: '22%' }} className="low" /></div><span>22%</span></div>
                <div className="ir"><span>Sealant T-7</span><div className="bar"><span style={{ width: '71%' }} /></div><span>71%</span></div>
              </div>
            </div>
          </Reveal>

          <Reveal className="cell span-6" style={{'--c1':'oklch(0.78 0.16 155)','--c2':'oklch(0.55 0.18 130)'}}>
            <div className="h"><span className="ag" /> Content & Ads Agent</div>
            <h3>Posts the work. Pauses the losers.</h3>
            <p>Turns this week's completed jobs into reels and posts. Manages Meta/Google ads with hard daily caps.</p>
            <div className="viz">
              <div className="ads">
                <div className="tile">
                  <div className="meta"><span>Reel · Draft</span><span className="ctr">queued</span></div>
                  Before/after — kitchen reno walkthrough
                </div>
                <div className="tile">
                  <div className="meta"><span>Meta · Live</span><span className="ctr">CTR 2.4%</span></div>
                  "Same-day plumbing" — radius 12mi
                </div>
              </div>
            </div>
          </Reveal>

          <Reveal delay={1} className="cell span-6" style={{'--c1':'oklch(0.7 0.2 240)','--c2':'oklch(0.6 0.22 260)'}}>
            <div className="h"><span className="ag" /> Ops Coordinator + Custom CRM/Software</div>
            <h3>The wiring between everything. Built to your shape.</h3>
            <p>Routes work between agents, syncs to your tools, and — when an off-the-shelf CRM doesn't fit — we ship custom software in the same install.</p>
            <div className="ops">
              <svg viewBox="0 0 400 160" preserveAspectRatio="none">
                <defs>
                  <linearGradient id="opg" x1="0" y1="0" x2="1" y2="0">
                    <stop offset="0" stopColor="oklch(0.6 0.20 240)" stopOpacity=".75" />
                    <stop offset="1" stopColor="oklch(0.65 0.14 200)" stopOpacity=".75" />
                  </linearGradient>
                </defs>
                {[
                  ['M 40 80 C 100 30, 160 30, 200 80', 0],
                  ['M 40 80 C 100 130, 160 130, 200 80', .3],
                  ['M 200 80 C 260 30, 320 30, 360 80', .6],
                  ['M 200 80 C 260 130, 320 130, 360 80', .9],
                ].map(([d, dly], i) => (
                  <path key={i} d={d} fill="none" stroke="url(#opg)" strokeWidth="1.5" strokeDasharray="4 6" style={{ animation: `dash 4s linear infinite`, animationDelay: `${dly}s` }} />
                ))}
                {[[40, 80], [200, 80], [360, 80], [120, 30], [120, 130], [280, 30], [280, 130]].map(([x, y], i) => (
                  <g key={i}>
                    <circle cx={x} cy={y} r="14" fill="#ffffff" stroke="oklch(0.6 0.20 240 / .55)" strokeWidth="1" />
                    <circle cx={x} cy={y} r="4" fill="oklch(0.55 0.20 250)" />
                  </g>
                ))}
              </svg>
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

/* ---------- Timeline ---------- */
const TL = [
  { num: '01', when: 'Hour 0', title: 'Audit', body: 'We sit down with you and map every call, lead, message, and bottleneck — by hand. You leave with a written install plan.', c: 'oklch(0.75 0.18 290)' },
  { num: '02', when: 'Hour 0–8', title: 'Build', body: 'We configure your agents on our stack, connect your phone, calendar, inbox, CRM, and tools. We write your scripts and approval rules.', c: 'oklch(0.7 0.2 240)' },
  { num: '03', when: 'Hour 8–18', title: 'Install', body: 'Number ported or forwarded, inbox routed, calendar synced. Quiet-hours and sender policies dialed in. Kill switch tested.', c: 'oklch(0.82 0.14 200)' },
  { num: '04', when: 'Hour 18–24', title: 'Run', body: 'Agents go live with a human on the bridge. Receipts stream into your Command Center. You approve, edit, or watch.', c: 'oklch(0.78 0.17 75)' },
];

const RECEIPTS = [
  { c: 'oklch(0.75 0.18 290)', h: 'AUDIT.LOG', l1: 'business · Ridge Plumbing', l2: 'phone · 412 calls/wk', l3: 'install · Receptionist, Booking, Follow-up', sig: 'op-aud-04A1' },
  { c: 'oklch(0.7 0.2 240)', h: 'BUILD.LOG', l1: 'scripts · 14 intents trained', l2: 'tools · Jobber, Stripe, Twilio', l3: 'rules · auto-quote ≤ $2,500', sig: 'op-bld-72C3' },
  { c: 'oklch(0.82 0.14 200)', h: 'INSTALL.LOG', l1: 'port · +1 412-555-0114', l2: 'inbox · service@ridge → routed', l3: 'killswitch · /kill verified', sig: 'op-ins-91F4' },
  { c: 'oklch(0.78 0.17 75)', h: 'RUN.LOG', l1: 't+0:14 · first call answered', l2: 't+1:02 · first job booked', l3: 't+3:48 · first quote approved', sig: 'op-run-A8E2' },
];

function Timeline() {
  return (
    <section className="section-pad" id="timeline" style={{ paddingTop: 80 }}>
      <div className="container">
        <Reveal className="sec-head">
          <span className="eyebrow">03 · The install</span>
          <h2 className="display">From hire to handling work — in a day.</h2>
          <p>We do the work. You watch it land. Every step writes a receipt — so the install is auditable, not magical.</p>
        </Reveal>
        <Reveal delay={1} className="timeline-wrap">
          <div className="tl-track">
            <div className="tl-line" />
            <div className="tl-steps">
              {TL.map((s) => (
                <div className="tl-step" key={s.num} style={{ '--c': s.c }}>
                  <div className="num mono">{s.num}</div>
                  <div className="when" style={{ marginTop: 18 }}>{s.when}</div>
                  <h4>{s.title}</h4>
                  <p>{s.body}</p>
                </div>
              ))}
            </div>
          </div>
          <div className="receipts">
            {RECEIPTS.map((r, i) => (
              <div className="receipt" key={i} style={{ '--c': r.c }}>
                <div className="rh"><span>{r.h}</span><span>{r.sig}</span></div>
                <div><span className="k">› </span><b>{r.l1.split(' · ')[0]}</b> · {r.l1.split(' · ')[1]}</div>
                <div><span className="k">› </span><b>{r.l2.split(' · ')[0]}</b> · {r.l2.split(' · ')[1]}</div>
                <div><span className="k">› </span><b>{r.l3.split(' · ')[0]}</b> · {r.l3.split(' · ')[1]}</div>
              </div>
            ))}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

/* ---------- System map ---------- */
function SystemMap() {
  // 8 satellites around center node
  const nodes = [
    { x: 159, y: 129, l: 'Calls', c: 'oklch(0.55 0.22 295)' },
    { x: 300, y: 70,  l: 'Inbox', c: 'oklch(0.6 0.20 245)' },
    { x: 441, y: 129, l: 'Calendar', c: 'oklch(0.58 0.16 155)' },
    { x: 500, y: 270, l: 'CRM', c: 'oklch(0.55 0.20 240)' },
    { x: 441, y: 411, l: 'Inventory', c: 'oklch(0.62 0.14 200)' },
    { x: 300, y: 470, l: 'Ads', c: 'oklch(0.60 0.21 35)' },
    { x: 159, y: 411, l: 'Content', c: 'oklch(0.58 0.16 155)' },
    { x: 100, y: 270, l: 'Approvals', c: 'oklch(0.65 0.17 75)' },
  ];
  const cx = 300, cy = 270;
  return (
    <section className="section-pad" id="map">
      <div className="container">
        <Reveal className="sec-head">
          <span className="eyebrow">04 · The business layer</span>
          <h2 className="display">We run the wiring between everything.</h2>
          <p>Your phones, your inbox, your calendar, your CRM, your inventory, your ads, your content — all routed through one operational layer that knows your business.</p>
        </Reveal>
        <Reveal delay={1} className="map-wrap">
          <div className="map-grid" />
          <svg viewBox="0 0 600 540" className="map-svg" preserveAspectRatio="xMidYMid meet">
            <defs>
              <radialGradient id="core" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0" stopColor="oklch(0.55 0.22 290)" stopOpacity=".30" />
                <stop offset=".5" stopColor="oklch(0.55 0.22 270)" stopOpacity=".12" />
                <stop offset="1" stopColor="transparent" />
              </radialGradient>
              <linearGradient id="link" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0" stopColor="oklch(0.55 0.22 290)" stopOpacity=".10" />
                <stop offset=".5" stopColor="oklch(0.55 0.22 290)" stopOpacity=".55" />
                <stop offset="1" stopColor="oklch(0.55 0.22 290)" stopOpacity=".10" />
              </linearGradient>
            </defs>
            {/* core halo */}
            <circle cx={cx} cy={cy} r="120" fill="url(#core)" />
            {/* links */}
            {nodes.map((n, i) => (
              <g key={i}>
                <line x1={n.x} y1={n.y} x2={cx} y2={cy}
                      stroke="rgba(15,17,22,.08)" strokeWidth="1" />
                <line x1={n.x} y1={n.y} x2={cx} y2={cy}
                      stroke="url(#link)" strokeWidth="1.3" strokeDasharray="3 8"
                      style={{ animation: `dash 6s linear infinite`, animationDelay: `${i * .4}s` }} />
              </g>
            ))}
            {/* core */}
            <circle cx={cx} cy={cy} r="42" fill="#ffffff" stroke="oklch(0.55 0.22 290 / .55)" strokeWidth="1.2" />
            <circle cx={cx} cy={cy} r="6" fill="oklch(0.55 0.22 290)">
              <animate attributeName="r" values="6;10;6" dur="2.6s" repeatCount="indefinite" />
              <animate attributeName="opacity" values="1;.4;1" dur="2.6s" repeatCount="indefinite" />
            </circle>
            <text x={cx} y={cy + 4} textAnchor="middle" fill="#0e1116" fontFamily="Space Grotesk" fontSize="13" fontWeight="600">OpSpot</text>
            <text x={cx} y={cy + 22} textAnchor="middle" fill="#8a90a0" fontFamily="JetBrains Mono" fontSize="9" letterSpacing="1.5">CORE</text>
            {/* nodes */}
            {nodes.map((n, i) => (
              <g key={i}>
                <circle cx={n.x} cy={n.y} r="22" fill="#ffffff" stroke={n.c} strokeOpacity=".6" strokeWidth="1.2" />
                <circle cx={n.x} cy={n.y} r="5" fill={n.c}>
                  <animate attributeName="opacity" values="1;.3;1" dur={`${2 + (i * .2)}s`} repeatCount="indefinite" />
                </circle>
                <text x={n.x} y={n.y + (n.y > cy ? 44 : -32)} textAnchor="middle" fill="#0e1116" fontFamily="Space Grotesk" fontSize="14" fontWeight="500">{n.l}</text>
              </g>
            ))}
          </svg>
        </Reveal>
      </div>
    </section>
  );
}

/* ---------- Command Center (jobs flowing) ---------- */
const JOB_TEMPLATES = [
  { t: 'After-hours call · leak inspection', who: 'Receptionist', ag: 'oklch(0.75 0.18 290)' },
  { t: 'Quote follow-up · Bayside Café', who: 'Follow-up', ag: 'oklch(0.78 0.16 250)' },
  { t: 'Proposal draft · Ridge HVAC', who: 'Sales', ag: 'oklch(0.78 0.17 75)' },
  { t: 'Reorder · 6mm gaskets ×200', who: 'Inventory', ag: 'oklch(0.82 0.14 200)' },
  { t: 'Reroute Wed tech runs', who: 'Ops', ag: 'oklch(0.7 0.2 240)' },
  { t: 'New 5★ review reply', who: 'Content', ag: 'oklch(0.78 0.16 155)' },
  { t: 'Pause underperforming creative', who: 'Ads', ag: 'oklch(0.7 0.21 35)' },
  { t: 'Quote · Northgate Auto rebuild', who: 'Sales', ag: 'oklch(0.78 0.17 75)' },
];

function CommandCenter() {
  const [intake, setIntake] = useState([0, 1, 2]);
  const [working, setWorking] = useState([3, 4]);
  const [done, setDone] = useState([5, 6, 7]);
  const counter = useRef(8);

  useEffect(() => {
    const tick = setInterval(() => {
      // move one from working → done
      setDone(prev => {
        setWorking(w => {
          if (w.length === 0) return w;
          const [first, ...rest] = w;
          setTimeout(() => setDone(d => [first, ...d].slice(0, 4)), 0);
          return rest;
        });
        return prev;
      });
      // intake → working
      setWorking(prev => {
        setIntake(it => {
          if (it.length === 0) return it;
          const [first, ...rest] = it;
          setTimeout(() => setWorking(w => [...w, first]), 0);
          return rest;
        });
        return prev;
      });
      // new into intake
      setIntake(it => {
        const next = counter.current++;
        return [next, ...it].slice(0, 4);
      });
    }, 3000);
    return () => clearInterval(tick);
  }, []);

  const renderJob = (id) => {
    const j = JOB_TEMPLATES[id % JOB_TEMPLATES.length];
    return (
      <div key={id} className="job ent">
        <div className="jh"><span>JOB-{String(1240 + id).padStart(4, '0')}</span><span>{(id % 13) + 1}m</span></div>
        <div>{j.t}</div>
        <div className="who"><span className="ag" style={{ '--c1': j.ag, '--c2': j.ag }} /> {j.who}</div>
      </div>
    );
  };

  return (
    <section className="section-pad" id="center">
      <div className="container">
        <Reveal className="sec-head">
          <span className="eyebrow">05 · Command Center</span>
          <h2 className="display">One queue for the whole business.</h2>
          <p>Jobs land from anywhere — a phone call, a form, an email, a stock alert — and move from intake to done. You see everything, approve what matters, and ignore the rest.</p>
        </Reveal>

        <Reveal delay={1} className="cmd-mock">
          <div className="cmd-head">
            <div className="dots"><span /><span /><span /></div>
            <span className="stage-title">command-center · live</span>
            <div className="cmd-tabs"><span className="on">Queue</span><span>Approvals</span><span>Receipts</span><span>Agents</span></div>
          </div>
          <div className="cmd-body">
            <div className="lane">
              <div className="lane-h"><span style={{ width: 6, height: 6, borderRadius: '50%', background: 'oklch(0.78 0.17 75)', boxShadow: '0 0 8px oklch(0.78 0.17 75)' }} /> Intake <span className="ct">{intake.length} new</span></div>
              {intake.map(renderJob)}
            </div>
            <div className="lane">
              <div className="lane-h"><span style={{ width: 6, height: 6, borderRadius: '50%', background: 'oklch(0.7 0.2 240)', boxShadow: '0 0 8px oklch(0.7 0.2 240)' }} /> Working <span className="ct">{working.length} active</span></div>
              {working.map(renderJob)}
            </div>
            <div className="lane">
              <div className="lane-h"><span style={{ width: 6, height: 6, borderRadius: '50%', background: 'oklch(0.78 0.16 155)', boxShadow: '0 0 8px oklch(0.78 0.16 155)' }} /> Done · today <span className="ct">{done.length + 142} ✓</span></div>
              {done.map(renderJob)}
            </div>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

/* ---------- Trust ---------- */
function Trust() {
  return (
    <section className="section-pad" id="trust">
      <div className="container">
        <Reveal className="sec-head">
          <span className="eyebrow">06 · Trust & safety</span>
          <h2 className="display">AI that asks before it acts.</h2>
          <p>Every dollar, every send, every commitment runs through a rule you control. The agents work for you — not the other way around.</p>
        </Reveal>
        <div className="trust-grid">
          {[
            { i: '✓', t: 'Human approval gates', d: 'Set thresholds per agent — proposals over $X, refunds, anything outside script. The agent drafts; you approve.',
              ex: (<><span className="key">RULE › </span><b>Sales</b>: auto-send ≤ $2,500 · else <b>approve</b></>) },
            { i: '⌚', t: 'Quiet hours & sender policy', d: 'Hard windows for SMS, email, and calls. Per-channel daily caps. No more 11pm "just checking in" messages.',
              ex: (<><span className="key">SMS › </span>09:00–19:00 · cap <b>3/contact/week</b></>) },
            { i: '◷', t: 'Receipts on everything', d: 'Every call, message, booking, and reorder writes a signed receipt. Searchable, exportable, auditable.',
              ex: (<><span className="key">RCPT › </span>op-run-A8E2 · <b>signed</b> · 23 events</>) },
            { i: '✕', t: 'Kill switch', d: 'One click pauses every agent across every channel. The phones forward to you. The work doesn\'t restart until you say so.',
              ex: (<><span className="key">/kill › </span>all agents <b>paused</b> · phones → owner</>) },
            { i: 'Σ', t: 'Your data, your tools', d: 'We connect to what you already run — Jobber, HubSpot, Square, Sheets, your own DB. No lock-in. Export anytime.',
              ex: (<><span className="key">CONN › </span>jobber · stripe · twilio · <b>read-write</b></>) },
            { i: '~', t: 'Founder-led, not handed off', d: 'You get the people who built it. We run point through install and stay on your bridge for the first two weeks.',
              ex: (<><span className="key">ON-CALL › </span>founders · <b>14 days</b> post-launch</>) },
          ].map((c, i) => (
            <Reveal delay={(i % 3) + 1} className="trust-card" key={i}>
              <div className="ico"><span style={{ fontFamily: 'Space Grotesk', fontSize: 16 }}>{c.i}</span></div>
              <h4>{c.t}</h4>
              <p>{c.d}</p>
              <div className="ex">{c.ex}</div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------- Final CTA ---------- */
function FinalCTA() {
  return (
    <section className="cta-scene">
      <div className="cta-inner">
        <Reveal>
          <span className="eyebrow"><span className="dot" /> Hire your first worker</span>
        </Reveal>
        <Reveal delay={1}>
          <h2 className="display" style={{ marginTop: 20 }}>
            Buy back your time.<br />
            <span style={{ background: 'linear-gradient(110deg, oklch(0.85 0.05 80), oklch(0.78 0.18 55) 40%, oklch(0.68 0.21 35))', WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent' }}>Hire an AI employee.</span>
          </h2>
        </Reveal>
        <Reveal delay={2}>
          <p>90-minute audit. Written install plan. If it makes sense, we start building the same day and your first worker is on the job within 24 hours.</p>
          <div className="acts">
            <a href={CAL} target="_blank" rel="noopener" className="btn btn-primary btn-xl">Book your free audit →</a>
            <a href="mailto:colton@opspot.ai" className="btn btn-ghost">Email a founder</a>
          </div>
        </Reveal>
        <Reveal delay={3} className="cta-stage">
          <div className="ck"><span className="b">✓</span> 90-min audit</div>
          <div className="sep" />
          <div className="ck"><span className="b">✓</span> Written install plan</div>
          <div className="sep" />
          <div className="ck"><span className="b">✓</span> Worker live in 24 hours</div>
          <div className="sep" />
          <div className="ck"><span className="b">✓</span> Cancel anytime · own your data</div>
        </Reveal>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div className="footer-inner">
        <a href="#" className="brand">
          <OpSpotMark size={26} />
          <span>OpSpot</span>
        </a>
        <span className="foot-meta">opspot.ai · Wilmington-built business ops agents · 2026</span>
        <div className="links">
          <a href="mailto:colton@opspot.ai">colton@opspot.ai</a>
          <a href={CAL} target="_blank" rel="noopener">Book an audit</a>
        </div>
      </div>
    </footer>
  );
}

/* ---------- App ---------- */
function App() {
  return (
    <div className="app">
      <Spotlight />
      <Nav />
      <Hero />
      <InvisibleWork />
      <FleetSection />
      <Timeline />
      <SystemMap />
      <CommandCenter />
      <Trust />
      <FinalCTA />
      <Footer />
    </div>
  );
}

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