// Kahla Labs — Voice Agent demo
// A scripted, realistic inbound-call experience. Shows a prospect exactly
// what a Kahla-built voice receptionist sounds like. Same KAHLA_SYSTEM_PROMPT
// as the chat concierge — proving one prompt works across text + voice.

(function () {
const { useState, useEffect, useRef } = React;

// ── Three scripted scenarios. Each turn lands after `at` ms. ─────────────
const SCENARIOS = {
  hvac: {
    num: '01',
    title: 'After-hours HVAC emergency',
    desc: 'Tuesday, 11:47 PM. No AC, 94°F inside. Books an appointment, collects deposit, dispatches tech.',
    caller: 'Inbound · Glendale, CA',
    agent: 'Kahla Concierge · Air Flow Pros',
    turns: [
      { at: 800,   who: 'action', body: '● Call connected · 415-555-0182',                                      duration: 0 },
      { at: 1400,  who: 'agent',  body: 'Air Flow Pros, this is Nora — Kahla concierge after-hours. How can I help?', duration: 3.8 },
      { at: 5800,  who: 'caller', body: 'Hi, uh, my AC just died. It\'s like 94 in my house. Can someone come tonight?', duration: 4.2 },
      { at: 10400, who: 'agent',  body: 'Sorry about that. I can get a tech to you. What\'s the zip code?', duration: 3.2 },
      { at: 14200, who: 'caller', body: '91205, Glendale.', duration: 1.8 },
      { at: 16500, who: 'agent',  body: 'Got it. We have an emergency slot at 1:15 AM tonight, $149 dispatch plus parts. I can hold that, or we can do first thing tomorrow at 7 AM for the standard rate. Which works?', duration: 8.4 },
      { at: 25400, who: 'caller', body: 'Tonight. It\'s too hot.', duration: 1.8 },
      { at: 27600, who: 'agent',  body: 'Understood. I\'ll text you a payment link to hold the slot — the $149 is refundable if the tech can\'t diagnose anything. What\'s the best number?', duration: 7.1 },
      { at: 35200, who: 'caller', body: 'This one. 818-555-0182.', duration: 2.1 },
      { at: 37800, who: 'action', body: '→ CRM · Lead created · Job #AFP-2847 · priority=emergency',               duration: 0 },
      { at: 38800, who: 'action', body: '→ Payment · $149 hold link sent via SMS',                                  duration: 0 },
      { at: 39800, who: 'action', body: '→ Dispatch · Tech "Marco" notified · ETA 1:15 AM',                          duration: 0 },
      { at: 40800, who: 'agent',  body: 'Link is on its way. Marco will call you when he\'s 15 minutes out. Anything else?', duration: 5.2 },
      { at: 46400, who: 'caller', body: 'No, that\'s great. Thanks.', duration: 1.6 },
      { at: 48400, who: 'agent',  body: 'Hang in there. Goodnight.', duration: 2.0 },
      { at: 51000, who: 'action', body: '● Call ended · duration 0:50 · resolved without human escalation',       duration: 0 },
    ]
  },

  booking: {
    num: '02',
    title: 'Buyer — restored camera inquiry',
    desc: 'Buyer calls Measure Joy about a restored Y2K digital camera. Concierge confirms condition, inspection, and warranty, offers split-pay, captures the order on Christian\'s own checkout.',
    caller: 'Inbound · camera buyer',
    agent: 'Kahla Concierge · Measure Joy',
    turns: [
      { at: 500,   who: 'action', body: '● Call connected · 626-555-0099',                                        duration: 0 },
      { at: 1200,  who: 'agent',  body: 'Measure Joy, this is June. How can I help?',                             duration: 2.4 },
      { at: 4000,  who: 'caller', body: 'Hey, is the silver Canon PowerShot from the new drop still in stock?',  duration: 3.6 },
      { at: 8000,  who: 'agent',  body: 'Let me check — yes, the silver PowerShot ELPH is in stock, restored and tested. It\'s $189.', duration: 6.4 },
      { at: 15000, who: 'caller', body: 'Is it actually been gone through? I got burned on eBay last time.',     duration: 3.4 },
      { at: 19000, who: 'agent',  body: 'Totally fair. Every camera goes through our 12-point inspection and a full restoration before it lists, and it ships with a 90-day warranty. If anything\'s off, you\'re covered.', duration: 9.6 },
      { at: 29200, who: 'caller', body: 'Nice. Can I split the payment?',                                         duration: 1.8 },
      { at: 31400, who: 'agent',  body: 'Yep — checkout has buy-now-pay-later, so you can split it into four. I\'ll text you a secure link to complete it whenever you\'re ready.', duration: 8.6 },
      { at: 40600, who: 'caller', body: 'Perfect, send it.',                                                      duration: 1.2 },
      { at: 42000, who: 'action', body: '→ Inventory · PowerShot-ELPH-silver → reserved 30 min',                   duration: 0 },
      { at: 43000, who: 'action', body: '→ Checkout · Stripe payment link (BNPL enabled) sent via SMS',            duration: 0 },
      { at: 44000, who: 'action', body: '→ Team alert · "@christian — PowerShot ELPH reserved by +16265550099"',   duration: 0 },
      { at: 45200, who: 'agent',  body: 'Sent. It\'s reserved for 30 minutes so no one grabs it while you check out. Anything else I can help with?', duration: 7.4 },
      { at: 53200, who: 'caller', body: 'No, that\'s it. Thanks.',                                                duration: 1.8 },
      { at: 55400, who: 'agent',  body: 'Thanks for calling Measure Joy.',                                        duration: 2.2 },
      { at: 58000, who: 'action', body: '● Call ended · duration 0:58 · order link sent · own Stripe checkout',   duration: 0 },
    ]
  },

  qualify: {
    num: '03',
    title: 'Qualification — Kahla itself',
    desc: 'Prospect calls Kahla Labs to ask about a build. Concierge qualifies, scopes the engagement, books the Systems Audit.',
    caller: 'Inbound · pilates studio',
    agent: 'Kahla Concierge · Kahla Labs',
    turns: [
      { at: 500,   who: 'action', body: '● Call connected · 310-555-0410',                                        duration: 0 },
      { at: 1200,  who: 'agent',  body: 'Kahla Labs, this is the concierge. What are you building?',            duration: 3.4 },
      { at: 5000,  who: 'caller', body: 'Hi, I run a boutique pilates studio. Bookings are a mess. Four staff, three calendars, we\'re double-booking every week.', duration: 8.2 },
      { at: 13800, who: 'agent',  body: 'Sounds like the classic three-leak stack: no unified calendar, no deposit logic, and no SMS reminders. Is that close?', duration: 7.1 },
      { at: 21400, who: 'caller', body: 'Yeah — exactly.',                                                        duration: 1.4 },
      { at: 23200, who: 'agent',  body: 'Sounds like a fit. Every engagement is custom-scoped — we send a written SOW within 24 hours of the Systems Audit. A monthly retainer covers the operator work after launch: hosting, AI agents, booking, monitoring. Twelve-month minimum.', duration: 13.8 },
      { at: 37800, who: 'caller', body: 'What\'s the catch?',                                                     duration: 1.8 },
      { at: 39800, who: 'agent',  body: 'No catch. The same senior team that scopes your build operates it after launch — no account-manager layer, no offshore handoff. The Systems Audit is free, 30 minutes. You leave with a written Leak Map even if you don\'t hire us.', duration: 13.6 },
      { at: 53800, who: 'caller', body: 'Okay, let\'s book it.',                                                  duration: 1.8 },
      { at: 56000, who: 'agent',  body: 'Great. Tuesday 10 AM or Wednesday 2 PM work for you?',                   duration: 3.4 },
      { at: 59800, who: 'caller', body: 'Wednesday 2.',                                                           duration: 1.0 },
      { at: 61200, who: 'action', body: '→ Calendar · Wed Mar 11, 2:00 PM booked · Systems Audit',                  duration: 0 },
      { at: 62200, who: 'action', body: '→ Email · Confirm + Kahla prep doc sent',                                    duration: 0 },
      { at: 63200, who: 'action', body: '→ Team alert · qualified prospect, full-stack engagement',                   duration: 0 },
      { at: 64400, who: 'agent',  body: 'Done. Calendar invite is in your inbox with a short prep doc. We will review it before the call. Anything else?', duration: 7.2 },
      { at: 72000, who: 'caller', body: 'Nope, thank you.',                                                       duration: 1.4 },
      { at: 73800, who: 'agent',  body: 'Talk Wednesday.',                                                         duration: 1.4 },
      { at: 75600, who: 'action', body: '● Call ended · duration 1:15 · qualified · Systems Audit booked',          duration: 0 },
    ]
  }
};

// ── Helpers ──────────────────────────────────────────────────────────────
const fmtTime = (ms) => {
  const s = Math.floor(ms / 1000);
  const m = Math.floor(s / 60);
  return `${m}:${String(s % 60).padStart(2, '0')}`;
};
const fmtClock = (offsetSec) => {
  const d = new Date(Date.now() + offsetSec * 1000);
  return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: false });
};

// ── Component ────────────────────────────────────────────────────────────
function VoiceAgentPage() {
  const [scenarioKey, setScenarioKey] = useState('hvac');
  const [playing, setPlaying] = useState(false);
  const [elapsed, setElapsed] = useState(0);
  const [visibleTurns, setVisibleTurns] = useState([]);
  const [currentSpeaker, setCurrentSpeaker] = useState(null);
  const [muted, setMuted] = useState(false);
  const [keypadOpen, setKeypadOpen] = useState(false);
  const rafRef = useRef(null);
  const startRef = useRef(0);
  const transcriptRef = useRef(null);

  // Live call state (real voice via Vapi web SDK)
  const [liveMode, setLiveMode] = useState('idle'); // idle | connecting | live | ended | error
  const [liveTranscript, setLiveTranscript] = useState([]);
  const [liveSpeaker, setLiveSpeaker] = useState(null); // 'agent' | 'caller' | null
  const [liveError, setLiveError] = useState(null);
  const [liveDuration, setLiveDuration] = useState(0);
  const vapiRef = useRef(null);
  const liveStartRef = useRef(0);
  const isLive = liveMode === 'live' || liveMode === 'connecting';

  const scenario = SCENARIOS[scenarioKey];

  // Playback loop
  useEffect(() => {
    if (!playing) { cancelAnimationFrame(rafRef.current); return; }
    const tick = (now) => {
      if (!startRef.current) startRef.current = now - elapsed;
      const t = now - startRef.current;
      setElapsed(t);

      const shouldBeVisible = scenario.turns.filter(tu => tu.at <= t);
      setVisibleTurns(shouldBeVisible);

      // Find who is "speaking" (any turn whose window [at, at+duration*1000] contains t)
      const speaking = shouldBeVisible.find(tu => tu.duration > 0 && t >= tu.at && t < tu.at + tu.duration * 1000);
      setCurrentSpeaker(speaking ? speaking.who : null);

      const lastTurn = scenario.turns[scenario.turns.length - 1];
      if (t > lastTurn.at + 2000) { setPlaying(false); return; }
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [playing, scenario, elapsed]);

  // Auto-scroll transcript
  useEffect(() => {
    if (transcriptRef.current) {
      transcriptRef.current.scrollTop = transcriptRef.current.scrollHeight;
    }
  }, [visibleTurns]);

  const reset = () => {
    setPlaying(false);
    setElapsed(0);
    startRef.current = 0;
    setVisibleTurns([]);
    setCurrentSpeaker(null);
  };

  // ── Live call (OpenAI Realtime over WebRTC) ────────────────────────────
  const teardownLive = () => {
    const vapi = vapiRef.current;
    if (vapi) {
      try { vapi.removeAllListeners && vapi.removeAllListeners(); } catch {}
      try { vapi.stop(); } catch {}
    }
    vapiRef.current = null;
    setLiveSpeaker(null);
  };

  const startLiveCall = async () => {
    setLiveMode('connecting');
    setLiveTranscript([]);
    setLiveError(null);
    setLiveDuration(0);

    try {
      const Vapi = window.VapiClient;
      if (!Vapi) throw new Error('Voice is still loading — give it a second and try again.');

      // Publishable config (public key + assistant id) from our backend. The
      // public key is safe in the browser; the private key never leaves Vercel.
      const cfgResp = await fetch('/api/voice-session');
      if (!cfgResp.ok) {
        const err = await cfgResp.json().catch(() => ({}));
        throw new Error(err.error || `Voice agent unavailable (${cfgResp.status})`);
      }
      const { publicKey, assistantId } = await cfgResp.json();
      if (!publicKey || !assistantId) throw new Error('Voice agent is not configured yet.');

      const vapi = new Vapi(publicKey);
      vapiRef.current = vapi;

      // Vapi handles mic capture + audio playback internally.
      vapi.on('call-start', () => {
        liveStartRef.current = performance.now();
        setLiveMode('live');
      });
      vapi.on('call-end', () => {
        setLiveSpeaker(null);
        vapiRef.current = null;
        setLiveMode('ended');
      });
      vapi.on('speech-start', () => setLiveSpeaker('agent'));
      vapi.on('speech-end', () => setLiveSpeaker(null));
      vapi.on('message', (msg) => {
        if (!msg || msg.type !== 'transcript' || msg.transcriptType !== 'final') return;
        const text = (msg.transcript || '').trim();
        if (!text) return;
        const who = msg.role === 'assistant' ? 'agent' : 'caller';
        setLiveSpeaker(who);
        setLiveTranscript(prev => [...prev, { who, body: text, at: Date.now() }]);
      });
      vapi.on('error', (e) => {
        console.error('Vapi error', e);
        setLiveError((e && (e.message || e.error || e.msg)) || 'Voice connection error');
        setLiveMode('error');
        teardownLive();
      });

      await vapi.start(assistantId);
    } catch (err) {
      console.error('Live call failed', err);
      setLiveError(err.message || String(err));
      setLiveMode('error');
      teardownLive();
    }
  };

  const endLiveCall = () => {
    teardownLive();
    setLiveMode('ended');
  };

  // Cleanup any lingering connection on unmount
  useEffect(() => () => teardownLive(), []);

  // Live call duration ticker
  useEffect(() => {
    if (liveMode !== 'live') return;
    const id = setInterval(() => {
      setLiveDuration(performance.now() - liveStartRef.current);
    }, 250);
    return () => clearInterval(id);
  }, [liveMode]);

  // Apply the mute toggle to the live Vapi call.
  useEffect(() => {
    if (liveMode === 'live' && vapiRef.current) {
      try { vapiRef.current.setMuted(muted); } catch {}
    }
  }, [muted, liveMode]);

  // Auto-scroll live transcript
  useEffect(() => {
    if (isLive && transcriptRef.current) {
      transcriptRef.current.scrollTop = transcriptRef.current.scrollHeight;
    }
  }, [liveTranscript, isLive]);

  const togglePlay = () => {
    if (!playing && elapsed >= (scenario.turns[scenario.turns.length - 1].at + 2000)) {
      // at end, restart
      startRef.current = 0;
      setElapsed(0);
      setVisibleTurns([]);
    } else if (!playing) {
      startRef.current = 0;
    }
    setPlaying(!playing);
  };

  const selectScenario = (k) => {
    setScenarioKey(k);
    reset();
  };

  const lastTurnAt = scenario.turns[scenario.turns.length - 1].at;
  const progress = Math.min(100, (elapsed / (lastTurnAt + 2000)) * 100);
  const isEnded = elapsed >= (lastTurnAt + 2000);

  return (
    <div className="va-page">
      <div className="va-hero">
        <div>
          <div className="tag">Demo · 002 · Voice</div>
          <h1>A phone that <em>answers itself,</em> correctly.</h1>
          <p>Press play on any scripted scenario — or skip straight to a real call. The Talk live button opens a direct line to Kahla's concierge over your browser mic. What you hear is what your callers would hear, every hour, every day, with no after-hours gap. Built once, operated by us.</p>
          <div className="va-live-cta-row">
            <button
              className={`va-live-cta ${liveMode}`}
              onClick={isLive ? endLiveCall : startLiveCall}
              disabled={liveMode === 'connecting'}
            >
              {liveMode === 'idle' && <>◉ Talk live with Kahla</>}
              {liveMode === 'connecting' && <>Connecting…</>}
              {liveMode === 'live' && <>● Hang up · {fmtTime(liveDuration)}</>}
              {liveMode === 'ended' && <>◉ Talk live again</>}
              {liveMode === 'error' && <>◉ Try again</>}
            </button>
            <span className="va-live-cta-meta">
              {liveMode === 'idle' && 'Browser mic · ~30 seconds to connect'}
              {liveMode === 'connecting' && 'Requesting mic permission & opening session…'}
              {liveMode === 'live' && 'Live · speak naturally, interrupt if you want'}
              {liveMode === 'ended' && 'Call ended · try another scenario below'}
              {liveMode === 'error' && (liveError || 'Something went wrong')}
            </span>
          </div>
        </div>
        <div style={{display:'flex', flexDirection:'column', gap:'var(--k-3)', alignItems:'flex-end', textAlign:'right'}}>
          <div style={{fontFamily:'var(--k-mono)',fontSize:10,letterSpacing:'0.2em',color:'rgba(245,239,226,0.55)',textTransform:'uppercase'}}>What it does</div>
          <div style={{fontFamily:'var(--k-display)',fontStyle:'italic',fontSize:22,color:'var(--k-gold)',lineHeight:1.35,maxWidth:280}}>
            Answers. Qualifies. Books.<br/>
            <span style={{color:'#F5EFE2',fontStyle:'normal',fontSize:15,fontFamily:'var(--k-body)',fontWeight:400}}>Writes to your calendar, CRM, and payment flow automatically.</span>
          </div>
        </div>
      </div>

      <div className="va-stage">
        {/* Phone */}
        <div className="phone">
          <div className="phone-screen">
            <div className="phone-status">
              <span>{new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: false })}</span>
              <span>{isLive ? <span style={{color:'#C9A34F'}}>● LIVE</span> : '●●●● 5G ▮'}</span>
            </div>
            {isLive ? (
              <>
                <div className="phone-meta">
                  <div className="phone-caller">You</div>
                  <div className="phone-caller-sub">CALLING KAHLA CONCIERGE</div>
                  <div className="phone-caller-time">{liveMode === 'connecting' ? '— : —' : fmtTime(liveDuration)}</div>
                </div>
                <div className="phone-orb-wrap">
                  <div className="phone-orb">
                    <div className="phone-orb-ring" />
                    <div className="phone-orb-ring" />
                    <div className="phone-orb-ring" />
                    <div className={`phone-orb-core ${liveSpeaker === 'agent' ? 'speaking' : ''}`}>
                      {liveSpeaker === 'agent' && <div className="va-eq" style={{color:'var(--k-ink)'}}><span/><span/><span/><span/><span/></div>}
                    </div>
                  </div>
                </div>
                <div className="phone-status-line">
                  {liveMode === 'connecting' && '◉ Connecting to Kahla…'}
                  {liveMode === 'live' && liveSpeaker === 'agent' && '◉ Concierge speaking'}
                  {liveMode === 'live' && liveSpeaker === 'caller' && '◉ Listening to you'}
                  {liveMode === 'live' && !liveSpeaker && '◉ Connected · go ahead'}
                </div>
                <div className="phone-controls">
                  <button className="phone-ctrl is-danger" onClick={endLiveCall} title="Hang up" style={{width:'auto', padding:'0 24px', borderRadius:28}}>
                    Hang up
                  </button>
                </div>
              </>
            ) : (
              <>
                <div className="phone-meta">
                  <div className="phone-caller">{scenario.caller.split('·')[0].trim()}</div>
                  <div className="phone-caller-sub">{scenario.caller.split('·')[1]?.trim() || ''}</div>
                  <div className="phone-caller-time">{playing || elapsed > 0 ? (isEnded ? 'Call ended · ' + fmtTime(lastTurnAt) : fmtTime(elapsed)) : '— : —'}</div>
                </div>
                <div className="phone-orb-wrap">
                  <div className="phone-orb">
                    <div className="phone-orb-ring" />
                    <div className="phone-orb-ring" />
                    <div className="phone-orb-ring" />
                    <div className={`phone-orb-core ${currentSpeaker === 'agent' ? 'speaking' : ''}`}>
                      {currentSpeaker === 'agent' && <div className="va-eq" style={{color:'var(--k-ink)'}}><span/><span/><span/><span/><span/></div>}
                    </div>
                  </div>
                </div>
                <div className="phone-status-line">
                  {!playing && elapsed === 0 && 'Ready — press play'}
                  {playing && currentSpeaker === 'agent' && '◉ Concierge speaking'}
                  {playing && currentSpeaker === 'caller' && '◉ Caller speaking'}
                  {playing && !currentSpeaker && '◉ Listening'}
                  {!playing && elapsed > 0 && !isEnded && '❚❚ Paused'}
                  {isEnded && 'Call complete'}
                </div>
                <div className="phone-controls">
                  <button className="phone-ctrl" onClick={() => setMuted(!muted)} title="Mute">
                    {muted ? (
                      <svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M9 9v3a3 3 0 006 0V9M12 2v4M5 11a7 7 0 0014 0M3 3l18 18" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square"/></svg>
                    ) : (
                      <svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M12 2a3 3 0 00-3 3v7a3 3 0 006 0V5a3 3 0 00-3-3zM5 11a7 7 0 0014 0M12 18v4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square"/></svg>
                    )}
                  </button>
                  <button className="phone-ctrl is-primary" onClick={togglePlay} title={playing ? 'Pause' : 'Play'}>
                    {playing ? (
                      <svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M8 5v14M16 5v14" stroke="currentColor" strokeWidth="2" strokeLinecap="square"/></svg>
                    ) : (
                      <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5v14l12-7z"/></svg>
                    )}
                  </button>
                  <button className="phone-ctrl is-danger" onClick={reset} title="End / restart">
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M3 10c4-3 14-3 18 0l-2 4a3 3 0 01-4 1l-2-1c-1 0-3 0-4 1l-2 1a3 3 0 01-4-1z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square" transform="rotate(135 12 12)"/></svg>
                  </button>
                </div>
              </>
            )}
          </div>
        </div>

        {/* Transcript panel */}
        <div className="va-panel">
          {isLive ? (
            <>
              <div className="va-panel-head">
                <div>
                  <div style={{fontFamily:'var(--k-mono)',fontSize:10,letterSpacing:'0.2em',color:'#C9A34F',textTransform:'uppercase'}}>
                    ● Live · real call
                  </div>
                  <div className="va-panel-title">Talking to Kahla concierge</div>
                </div>
                <div className="va-panel-meta">
                  {liveMode === 'connecting' ? 'Negotiating audio…' : `Connected · ${fmtTime(liveDuration)}`}
                </div>
              </div>

              <div className="va-transcript" ref={transcriptRef}>
                {liveTranscript.length === 0 && (
                  <div style={{color:'var(--k-muted)',textAlign:'center',padding:'var(--k-10) 0',fontStyle:'italic',fontFamily:'var(--k-display)',fontSize:18}}>
                    {liveMode === 'connecting'
                      ? 'Connecting…'
                      : 'Say hello to start. Speak naturally — interrupt if you want.'}
                  </div>
                )}
                {liveTranscript.map((turn, i) => {
                  const isCaller = turn.who === 'caller';
                  return (
                    <div key={i} className="va-turn">
                      <div className="va-turn-meta">
                        <div className={`va-turn-who ${isCaller ? 'is-caller' : 'is-agent'}`}>
                          {isCaller ? 'You' : 'Concierge'}
                        </div>
                      </div>
                      <div className="va-turn-body">
                        {turn.body}
                        {!isCaller && i === liveTranscript.length - 1 && liveSpeaker === 'agent' && (
                          <span className="va-tag"><span className="va-eq" style={{color:'var(--k-gold)',marginRight:4,verticalAlign:'baseline'}}><span/><span/><span/><span/><span/></span>speaking</span>
                        )}
                      </div>
                    </div>
                  );
                })}
              </div>
            </>
          ) : (
            <>
              <div className="va-panel-head">
                <div>
                  <div style={{fontFamily:'var(--k-mono)',fontSize:10,letterSpacing:'0.2em',color:'var(--k-gold)',textTransform:'uppercase'}}>
                    Scenario · {scenario.num}
                  </div>
                  <div className="va-panel-title">{scenario.title}</div>
                </div>
                <div className="va-panel-meta">
                  {scenario.agent} · live transcript
                </div>
              </div>

              <div style={{height:'3px',background:'rgba(245,239,226,0.04)',borderRadius:2,overflow:'hidden'}}>
                <div style={{width: progress+'%', height:'100%', background:'var(--k-gold)', transition:'width 0.1s linear'}} />
              </div>

              <div className="va-transcript" ref={transcriptRef}>
                {visibleTurns.length === 0 && (
                  <div style={{color:'var(--k-muted)',textAlign:'center',padding:'var(--k-10) 0',fontStyle:'italic',fontFamily:'var(--k-display)',fontSize:18}}>
                    Press play to hear {scenario.agent.split('·')[1].trim()}.<br/>
                    <span style={{fontSize:12,fontFamily:'var(--k-mono)',fontStyle:'normal',letterSpacing:'0.1em',color:'var(--k-faint)',textTransform:'uppercase',marginTop:12,display:'block'}}>
                      Est. duration {fmtTime(lastTurnAt)}
                    </span>
                  </div>
                )}
                {visibleTurns.map((turn, i) => {
                  if (turn.who === 'action') {
                    return (
                      <div key={i} className="va-turn va-turn--action">
                        <div className="va-turn-meta">
                          <div className="va-turn-time">{fmtTime(turn.at)}</div>
                        </div>
                        <div className="va-turn-body">
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" style={{flexShrink:0}}><circle cx="12" cy="12" r="3" fill="currentColor"/><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1" opacity="0.4"/></svg>
                          {turn.body}
                        </div>
                      </div>
                    );
                  }
                  const isCaller = turn.who === 'caller';
                  return (
                    <div key={i} className="va-turn">
                      <div className="va-turn-meta">
                        <div className={`va-turn-who ${isCaller ? 'is-caller' : 'is-agent'}`}>
                          {isCaller ? 'Caller' : 'Concierge'}
                        </div>
                        <div className="va-turn-time">{fmtTime(turn.at)}</div>
                      </div>
                      <div className="va-turn-body">
                        {turn.body}
                        {!isCaller && turn === visibleTurns[visibleTurns.length-1] && currentSpeaker === 'agent' && (
                          <span className="va-tag"><span className="va-eq" style={{color:'var(--k-gold)',marginRight:4,verticalAlign:'baseline'}}><span/><span/><span/><span/><span/></span>speaking</span>
                        )}
                      </div>
                    </div>
                  );
                })}
              </div>
            </>
          )}
        </div>
      </div>

      {/* Call stats */}
      <div className="va-bar">
        <div className="va-stat">
          <div className="va-stat-label">Response latency</div>
          <div className="va-stat-value gold">0.8s</div>
          <div className="va-stat-sub">faster than a human</div>
        </div>
        <div className="va-stat">
          <div className="va-stat-label">Available</div>
          <div className="va-stat-value">24 / 7</div>
          <div className="va-stat-sub">no after-hours gap</div>
        </div>
        <div className="va-stat">
          <div className="va-stat-label">Handled autonomously</div>
          <div className="va-stat-value">83%</div>
          <div className="va-stat-sub">the rest routed to human</div>
        </div>
        <div className="va-stat">
          <div className="va-stat-label">Cost per call</div>
          <div className="va-stat-value">$0.14</div>
          <div className="va-stat-sub">vs $12 human receptionist</div>
        </div>
      </div>

      {/* Scenarios */}
      <div className="va-scenarios">
        <h3>Try a <em>different call.</em></h3>
        <div className="va-scenario-grid">
          {Object.entries(SCENARIOS).map(([k, s]) => (
            <div key={k} className={`va-scenario ${scenarioKey === k ? 'is-on' : ''}`} onClick={() => selectScenario(k)}>
              <div className="va-scenario-num">Scenario · {s.num}</div>
              <div className="va-scenario-title">{s.title}</div>
              <div className="va-scenario-desc">{s.desc}</div>
            </div>
          ))}
        </div>
      </div>

      {/* CTA */}
      <section className="cta-band">
        <h2 className="cta-title">Want <em>this</em> answering your phone?</h2>
        <a href="contact.html" className="k-btn k-btn--primary">Book your free Systems Audit →</a>
        <a href="services-local.html#chat" className="k-btn k-btn--ghost">How it's built</a>
      </section>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('va-root')).render(<VoiceAgentPage />);
})();
