/* global React, ReactDOM, useTime, useTimeline, Sprite, Stage, Easing, interpolate, animate, clamp */
const { useMemo } = React;

const NAVY = '#0e203b', YELLOW = '#FACC15', WHITE = '#fff';
const G50 = '#F8FAFC', G100 = '#F1F5F9', G200 = '#E2E8F0', G300 = '#CBD5E1', G400 = '#94A3B8', G500 = '#64748B', G600 = '#475569', G700 = '#334155';
const FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
const MONO = "'SF Mono', 'Roboto Mono', ui-monospace, monospace";

// ─── Helpers ───
const typeOut = (text, t0, t1, currentT) => {
  if (currentT <= t0) return '';
  if (currentT >= t1) return text;
  const p = (currentT - t0) / (t1 - t0);
  const n = Math.floor(text.length * p);
  return text.slice(0, n);
};

// ─── Soundwave mark ───
const OM = ({ size = 28 }) => (
  <svg width={size} height={size} viewBox="0 0 96 96" style={{ display: 'block' }}>
    <circle cx="48" cy="48" r="44" fill={NAVY}/>
    <circle cx="32" cy="48" r="11" fill="none" stroke={YELLOW} strokeWidth="5"/>
    <g stroke="#fff" strokeWidth="4.5" strokeLinecap="round">
      <line x1="52" y1="40" x2="52" y2="56"/><line x1="60" y1="32" x2="60" y2="64"/>
      <line x1="68" y1="38" x2="68" y2="58"/><line x1="76" y1="44" x2="76" y2="52"/>
    </g>
  </svg>
);

const BarsAnimated = ({ listening }) => {
  const t = useTime();
  const bars = [{ x: 52, base: 16, off: 0 }, { x: 60, base: 32, off: 1.2 }, { x: 68, base: 20, off: 2.4 }, { x: 76, base: 8, off: 3.6 }];
  return (
    <g stroke="#fff" strokeWidth="4.5" strokeLinecap="round">
      {bars.map((b, i) => {
        const extra = listening ? Math.abs(Math.sin(t * 6 + b.off)) * 8 : 0;
        const h = b.base + extra * 2;
        return <line key={i} x1={b.x} y1={48 - h/2} x2={b.x} y2={48 + h/2}/>;
      })}
    </g>
  );
};

const DotPulse = () => {
  const t = useTime();
  const o = 0.45 + Math.abs(Math.sin(t * 6)) * 0.55;
  return <div style={{ width: 10, height: 10, borderRadius: 5, background: YELLOW, opacity: o, boxShadow: '0 0 0 4px rgba(250,204,21,0.3)' }}/>;
};

// ─── Mic button (canonical mark) ───
const MicBig = ({ listening, pressed }) => (
  <div style={{
    width: listening ? 220 : 184, height: listening ? 220 : 184, borderRadius: '50%',
    background: NAVY, display: 'flex', alignItems: 'center', justifyContent: 'center',
    boxShadow: listening
      ? '0 6px 24px rgba(14,32,59,0.3), 0 0 0 18px rgba(14,32,59,0.12), 0 0 0 36px rgba(250,204,21,0.18)'
      : '0 6px 24px rgba(14,32,59,0.3)',
    transition: 'all .25s ease', overflow: 'hidden',
    transform: pressed ? 'scale(0.97)' : 'scale(1)',
  }}>
    <svg viewBox="0 0 96 96" style={{ width: '62%', height: '62%' }}>
      <circle cx="32" cy="48" r="11" fill="none" stroke={YELLOW} strokeWidth="5"/>
      <BarsAnimated listening={listening}/>
    </svg>
  </div>
);

const MicDock = ({ listening }) => (
  <div style={{
    width: 56, height: 56, borderRadius: 28,
    background: NAVY, display: 'flex', alignItems: 'center', justifyContent: 'center',
    boxShadow: listening ? '0 2px 8px rgba(14,32,59,0.25), 0 0 0 6px rgba(14,32,59,0.15), 0 0 0 12px rgba(250,204,21,0.25)' : '0 2px 8px rgba(14,32,59,0.25)',
    transition: 'box-shadow .2s',
  }}>
    <svg viewBox="0 0 96 96" style={{ width: '62%', height: '62%' }}>
      <circle cx="32" cy="48" r="11" fill="none" stroke={YELLOW} strokeWidth="5"/>
      <BarsAnimated listening={listening}/>
    </svg>
  </div>
);

const Pressable = ({ pressed, children, style }) => (
  <div style={{ transform: pressed ? 'scale(0.97)' : 'scale(1)', transition: 'transform 120ms ease-out', ...style }}>
    {children}
  </div>
);

// ─── Phone shell ───
const PhoneShell = ({ children }) => (
  <div style={{
    position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%, -50%)',
    width: 391, height: 776, background: NAVY, borderRadius: 38, padding: 8,
    boxShadow: '0 24px 60px rgba(0,0,0,0.4)',
  }}>
    <div style={{ width: '100%', height: '100%', background: '#fff', borderRadius: 30, overflow: 'hidden', position: 'relative', display: 'flex', flexDirection: 'column', fontFamily: FONT, color: NAVY }}>
      <div style={{ height: 24, padding: '0 20px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 11, fontWeight: 600, color: NAVY, flexShrink: 0 }}>
        <span>7:14</span>
        <span style={{ width: 14, height: 8, border: `1px solid ${NAVY}`, borderRadius: 2, position: 'relative' }}>
          <span style={{ position: 'absolute', inset: 1, background: NAVY, width: 8, display: 'block' }}/>
        </span>
      </div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', position: 'relative' }}>{children}</div>
    </div>
  </div>
);

const Header = ({ title, back = true }) => (
  <div style={{ height: 56, display: 'flex', alignItems: 'center', padding: '0 8px', borderBottom: `1px solid ${G200}`, background: '#fff', flexShrink: 0 }}>
    <div style={{ width: 44, height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 20, color: back ? NAVY : 'transparent' }}>‹</div>
    <div style={{ flex: 1, textAlign: 'center', fontSize: 17, fontWeight: 700 }}>{title}</div>
    <div style={{ width: 44 }}/>
  </div>
);

const Progress = ({ step, total, label, pct }) => (
  <div style={{ padding: '12px 24px', background: G50, flexShrink: 0 }}>
    <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
      <span style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase', letterSpacing: '0.05em' }}>Step {step} of {total}</span>
      <span style={{ fontSize: 11, color: G500 }}>{label}</span>
    </div>
    <div style={{ height: 6, background: G200, borderRadius: 4, overflow: 'hidden' }}>
      <div style={{ width: `${pct}%`, height: '100%', background: YELLOW, transition: 'width .3s' }}/>
    </div>
  </div>
);

// ─── Scenes ───
const HomeScreen = ({ tapping }) => (
  <>
    <div style={{ padding: '20px 24px 12px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <OM size={28}/><span style={{ fontSize: 17, fontWeight: 700 }}>OscarMic</span>
      </div>
      <div style={{ width: 36, height: 36, borderRadius: 18, background: G100, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13, fontWeight: 700 }}>SK</div>
    </div>
    <div style={{ padding: '0 24px 12px' }}>
      <div style={{ fontSize: 22, fontWeight: 700 }}>Good morning, Sam</div>
      <div style={{ fontSize: 13, color: G600, marginTop: 4 }}>Maple Roofing · West Roof section</div>
    </div>
    <div style={{ padding: '0 24px 16px' }}>
      <div style={{ background: G50, border: `1px solid ${G200}`, borderRadius: 8, padding: 14, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Today</div>
          <div style={{ fontSize: 16, fontWeight: 700, marginTop: 4 }}>No check-in yet</div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontSize: 11, color: G600 }}>Last check-in</div>
          <div style={{ fontFamily: MONO, fontSize: 11, color: G400, marginTop: 2 }}>Yesterday, 6:48 AM</div>
        </div>
      </div>
    </div>
    <div style={{ padding: '0 24px' }}>
      <Pressable pressed={tapping}>
        <div style={{ width: '100%', height: 64, borderRadius: 8, background: YELLOW, color: NAVY, fontWeight: 700, fontSize: 17, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 2px 8px rgba(0,0,0,0.08)' }}>Start a check-in</div>
      </Pressable>
    </div>
  </>
);

const ContextScreen = ({ tapping }) => (
  <>
    <Header title="New check-in"/>
    <div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 14, flex: 1 }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Job / site</div>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, padding: 16 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
          <div style={{ fontSize: 18, fontWeight: 700 }}>West Roof section</div>
          <span style={{ fontSize: 12, fontWeight: 600, color: NAVY, textDecoration: 'underline' }}>Change</span>
        </div>
        <div style={{ fontSize: 12, color: G600, marginTop: 6 }}>Maple St renovation · 123 Maple St, Toronto</div>
        <div style={{ height: 1, background: G200, margin: '12px 0' }}/>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <div style={{ fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Crew</div>
            <div style={{ fontSize: 13, fontWeight: 600, marginTop: 2 }}>Roofing crew A · 3 workers</div>
          </div>
          <span style={{ fontSize: 12, fontWeight: 600, color: NAVY, textDecoration: 'underline' }}>Change</span>
        </div>
      </div>
      <div style={{ flex: 1 }}/>
      <Pressable pressed={tapping}>
        <div style={{ width: '100%', height: 56, borderRadius: 8, background: YELLOW, color: NAVY, fontWeight: 700, fontSize: 16, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Continue</div>
      </Pressable>
    </div>
  </>
);

const RecordTypeScreen = ({ tapping }) => (
  <>
    <Header title="New check-in"/>
    <div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 12, flex: 1, overflow: 'hidden' }}>
      <div style={{ fontSize: 20, fontWeight: 700 }}>What are you recording?</div>
      <div style={{ fontSize: 13, color: G600 }}>Pick the type. You just talk — OscarMic builds the record.</div>
      <div style={{ background: G100, borderRadius: 8, borderLeft: `4px solid ${YELLOW}`, padding: '16px 14px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 18, fontWeight: 700 }}>Pre-job hazard review</div>
          <div style={{ fontSize: 12, color: G600, marginTop: 4 }}>The pre-work check your crew already does — captured by voice.</div>
        </div>
        <span style={{ color: NAVY, fontSize: 18, fontWeight: 700 }}>›</span>
      </div>
      <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase', marginTop: 4 }}>Or another update</div>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, padding: '0 12px' }}>
        {['Start-of-day check-in', 'Site note', 'Progress note', 'Reported concern', 'Delay note'].map((t, i, a) => (
          <div key={t} style={{ padding: '12px 4px', borderBottom: i < a.length - 1 ? `1px solid ${G200}` : 'none', fontSize: 14, display: 'flex', justifyContent: 'space-between' }}>
            <span>{t}</span><span style={{ color: G300 }}>›</span>
          </div>
        ))}
      </div>
      <div style={{ flex: 1 }}/>
      <Pressable pressed={tapping}>
        <div style={{ width: '100%', height: 56, borderRadius: 8, background: YELLOW, color: NAVY, fontWeight: 700, fontSize: 16, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Start</div>
      </Pressable>
    </div>
  </>
);

// Speak the update — voice transcript types out word by word
const SpeakScreen = ({ phase, tapping, local }) => {
  const transcript = '"Okay, day five on the west roof. Got the ladders up and the boom lift going. Wind\'s picking up though, gusting maybe 28."';
  // local 1.5–4.5 = listening; type out 1.6→4.4
  const visibleText = typeOut(transcript, 1.7, 4.4, local);
  const showTranscript = local >= 1.7;
  return (
    <>
      <Header title="Pre-job hazard review"/>
      <Progress step={1} total={3} label="Describe the work" pct={33}/>
      <div style={{ padding: 24, flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div style={{ fontSize: 20, fontWeight: 700 }}>Tell us about today's work</div>
        <div style={{ fontSize: 13, color: G600, marginTop: 6 }}>Tap the mic and say it in your own words.</div>
        {!showTranscript && (
          <div style={{ background: G50, border: `1px solid ${G200}`, borderRadius: 8, padding: 12, display: 'flex', gap: 8, alignItems: 'flex-start', marginTop: 16, fontSize: 12, color: G600, lineHeight: 1.5 }}>
            <span style={{ color: G500, fontWeight: 700 }}>ⓘ</span>
            <span>Mention the task, where on site, equipment, conditions, and anything different from yesterday.</span>
          </div>
        )}
        {showTranscript && (
          <div style={{ marginTop: 20, background: G100, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>What you said</div>
            <div style={{ fontSize: 15, color: NAVY, lineHeight: 1.5, marginTop: 6, fontStyle: 'italic' }}>{visibleText}<Caret on={phase === 'listening'}/></div>
          </div>
        )}
        <div style={{ flex: 1 }}/>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14, padding: '8px 0 20px' }}>
          <Pressable pressed={tapping}><MicBig listening={phase === 'listening'} pressed={tapping}/></Pressable>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: phase === 'listening' ? 16 : 14, fontWeight: phase === 'listening' ? 700 : 500, color: NAVY }}>
            {phase === 'listening' && <DotPulse/>}
            {phase === 'idle' && 'Tap to speak'}
            {phase === 'listening' && 'Listening…'}
            {phase === 'done' && 'Tap to redo'}
          </div>
        </div>
        {phase === 'done' && (
          <div style={{ padding: 16, background: '#fff', boxShadow: '0 -4px 12px rgba(0,0,0,0.08)', margin: '0 -24px -24px' }}>
            <div style={{ width: '100%', height: 56, borderRadius: 8, background: YELLOW, color: NAVY, fontWeight: 700, fontSize: 16, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Continue</div>
          </div>
        )}
      </div>
    </>
  );
};

const Caret = ({ on }) => {
  const t = useTime();
  if (!on) return null;
  const v = Math.sin(t * 8) > 0 ? 1 : 0;
  return <span style={{ display: 'inline-block', width: 2, height: 16, background: NAVY, marginLeft: 2, verticalAlign: 'text-bottom', opacity: v }}/>;
};

// Baseline Q2 — voice answers the question. Show mic listening, transcript "Yes" then highlights button
const BaselineQ2 = ({ tapping, local }) => {
  const listening = local >= 0.4 && local < 2.0;
  const answered = local >= 2.0;
  const transcript = '"Yep, went over it all at the truck this morning."';
  const visible = typeOut(transcript, 0.8, 1.9, local);
  return (
    <>
      <Header title="Pre-job hazard review"/>
      <Progress step={2} total={3} label="Question 2 of 6" pct={50}/>
      <div style={{ padding: 24, flex: 1, display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ background: G100, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 16 }}>
          <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Safety baseline</div>
          <div style={{ fontSize: 18, fontWeight: 700, lineHeight: 1.4, marginTop: 6 }}>Have hazards been reviewed before work started?</div>
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          <div style={{ flex: 1, height: 56, borderRadius: 8, fontSize: 16, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', background: answered ? YELLOW : '#fff', color: NAVY, border: answered ? 'none' : `2px solid ${G300}`, transition: 'all .3s' }}>Yes</div>
          <div style={{ flex: 1, height: 56, borderRadius: 8, fontSize: 16, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#fff', color: NAVY, border: `2px solid ${G300}` }}>No</div>
          <div style={{ flex: 1, height: 56, borderRadius: 8, fontSize: 16, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#fff', color: NAVY, border: `2px solid ${G300}` }}>N/A</div>
        </div>
        {listening && (
          <div style={{ background: G100, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 12 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Listening…</div>
            <div style={{ fontSize: 14, color: NAVY, lineHeight: 1.5, marginTop: 4, fontStyle: 'italic' }}>{visible}<Caret on/></div>
          </div>
        )}
        <div style={{ flex: 1 }}/>
      </div>
      <div style={{ padding: '10px 14px 14px', background: '#fff', borderTop: `1px solid ${G200}`, boxShadow: '0 -4px 12px rgba(0,0,0,0.08)', display: 'flex', alignItems: 'center', gap: 12 }}>
        <MicDock listening={listening}/>
        <Pressable pressed={tapping} style={{ marginLeft: 'auto' }}>
          <div style={{ height: 48, padding: '0 22px', borderRadius: 8, background: answered ? YELLOW : G200, color: answered ? NAVY : G500, fontWeight: 600, fontSize: 14, display: 'flex', alignItems: 'center' }}>Next</div>
        </Pressable>
      </div>
    </>
  );
};

// Guided question (Jesse-A) — voice answers with transcript building word-by-word
const GuidedQ = ({ tapping, local }) => {
  const listening = local >= 0.4 && local < 2.5;
  const answered = local >= 2.5;
  const transcript = '"Yeah, harnesses are on and everyone\'s tied off. Checked all the anchors."';
  const visible = typeOut(transcript, 0.7, 2.4, local);
  return (
    <>
      <Header title="Pre-job hazard review"/>
      <Progress step={3} total={3} label="A few details" pct={91}/>
      <div style={{ padding: 24, flex: 1, display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ background: G100, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 16 }}>
          <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Question 2 of 3</div>
          <div style={{ fontSize: 18, fontWeight: 700, lineHeight: 1.3, marginTop: 6 }}>Is fall protection set up and checked?</div>
        </div>
        {(listening || answered) && (
          <div style={{ background: G100, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>{listening ? 'Listening…' : 'Your answer'}</div>
            <div style={{ fontSize: 14, color: NAVY, lineHeight: 1.5, marginTop: 6, fontStyle: 'italic' }}>{visible}{listening && <Caret on/>}</div>
          </div>
        )}
        <div style={{ flex: 1 }}/>
      </div>
      <div style={{ padding: '10px 14px 14px', background: '#fff', borderTop: `1px solid ${G200}`, display: 'flex', alignItems: 'center', gap: 12 }}>
        <MicDock listening={listening}/>
        <Pressable pressed={tapping} style={{ marginLeft: 'auto' }}>
          <div style={{ height: 48, padding: '0 22px', borderRadius: 8, background: answered ? YELLOW : G200, color: answered ? NAVY : G500, fontWeight: 600, fontSize: 14, display: 'flex', alignItems: 'center' }}>Next</div>
        </Pressable>
      </div>
    </>
  );
};

const ReviewScreen = ({ tapping }) => (
  <>
    <Header title="Review record"/>
    <div style={{ padding: 14, flex: 1, display: 'flex', flexDirection: 'column', gap: 10, overflow: 'hidden' }}>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 12 }}>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
          <span style={{ background: G50, border: `1px solid ${G200}`, fontSize: 10, fontWeight: 600, padding: '3px 7px', borderRadius: 4 }}>Pre-job hazard review</span>
          <span style={{ background: G100, color: G700, fontSize: 10, fontWeight: 600, padding: '3px 7px', borderRadius: 4, textTransform: 'uppercase' }}>In progress</span>
        </div>
        <div style={{ fontSize: 17, fontWeight: 700, marginTop: 8 }}>West Roof section · Day 5</div>
        <div style={{ fontSize: 11, color: G600, marginTop: 4 }}>Roofing crew A · 3 workers</div>
        <div style={{ fontFamily: MONO, fontSize: 11, color: G400, marginTop: 4 }}>OM-2026-0517-014</div>
      </div>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, overflow: 'hidden' }}>
        <div style={{ background: G100, padding: '10px 12px', borderBottom: `1px solid ${G200}` }}>
          <div style={{ fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>Your notes</div>
          <div style={{ fontSize: 11.5, color: G600, lineHeight: 1.5, marginTop: 4, fontStyle: 'italic' }}>"Okay, day five on the west roof. Wind's picking up though, gusting maybe 28."</div>
        </div>
        <div style={{ padding: 12 }}>
          <div style={{ fontSize: 10, fontWeight: 600, color: NAVY, textTransform: 'uppercase', display: 'flex', alignItems: 'center', gap: 6 }}><OM size={13}/> Cleaned up by OscarMic</div>
          <div style={{ fontSize: 12, color: NAVY, lineHeight: 1.55, marginTop: 6 }}>Day 5 pre-job hazard review at the west roof section. Roofing crew A continuing with ladders and the boom lift. Wind gusts to 28 km/h. Tailgate done, PPE in use, fall protection set up and checked.</div>
        </div>
      </div>
      <div style={{ fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase', marginTop: 4 }}>Safety baseline · 6 of 6</div>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, padding: '4px 12px' }}>
        {[
          ['Hazards reviewed?', 'Yes'],
          ['PPE in use?', 'Yes'],
          ['Crew informed?', 'Yes'],
          ['Damaged equipment?', 'No'],
          ['Anything changed?', 'Yes — wind'],
        ].map(([q, a], i, arr) => (
          <div key={q} style={{ display: 'flex', justifyContent: 'space-between', padding: '7px 0', borderBottom: i < arr.length - 1 ? `1px solid ${G200}` : 'none', fontSize: 12 }}>
            <span style={{ color: NAVY }}>{q}</span>
            <span style={{ fontWeight: 700, color: NAVY }}>{a}</span>
          </div>
        ))}
      </div>
      <div style={{ fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase', marginTop: 2 }}>A few details</div>
      <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, padding: '4px 12px' }}>
        {[
          ['Weather / surface', 'Wind gusts 28 km/h'],
          ['Fall protection?', 'Yes — anchors confirmed'],
          ['Blocking the start?', 'No'],
        ].map(([q, a], i, arr) => (
          <div key={q} style={{ padding: '8px 0', borderBottom: i < arr.length - 1 ? `1px solid ${G200}` : 'none' }}>
            <div style={{ fontSize: 11, color: G500 }}>{q}</div>
            <div style={{ fontSize: 13, color: NAVY, marginTop: 2 }}>{a}</div>
          </div>
        ))}
      </div>
    </div>
    <div style={{ padding: 14, background: '#fff', boxShadow: '0 -4px 12px rgba(0,0,0,0.08)' }}>
      <Pressable pressed={tapping}>
        <div style={{ width: '100%', height: 52, borderRadius: 8, background: YELLOW, color: NAVY, fontWeight: 700, fontSize: 16, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Send</div>
      </Pressable>
    </div>
  </>
);

const LoggedScreen = ({ local }) => {
  const scale = Math.min(1, 0.85 + (1 - Math.cos(Math.min(local, 0.6) * Math.PI / 0.6)) / 2 * 0.15);
  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', padding: 24, textAlign: 'center' }}>
      <div style={{ flex: 1 }}/>
      <div style={{ transform: `scale(${scale})` }}><OM size={72}/></div>
      <div style={{ width: 80, height: 80, borderRadius: 40, border: `3px solid ${NAVY}`, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '20px 0', fontSize: 32, color: NAVY, fontWeight: 700 }}>✓</div>
      <div style={{ fontSize: 22, fontWeight: 700 }}>Logged</div>
      <div style={{ fontSize: 14, color: G600, marginTop: 8, maxWidth: 280 }}>Your pre-job hazard review is logged.</div>
      <div style={{ fontFamily: MONO, fontSize: 12, color: G400, marginTop: 14 }}>OM-2026-0517-014</div>
      <div style={{ flex: 1 }}/>
    </div>
  );
};

// ─── Admin desktop view ───
const AdminDesktop = ({ local }) => {
  // Beat A: 0–4.5  — the record-detail card lands (matching report screen quality)
  // Beat B: 4.5–10 — "Admins decide what gets logged" — show the template list
  const phase = local < 4.8 ? 'detail' : 'templates';
  return (
    <div style={{
      position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%, -50%)',
      width: 940, height: 600, background: '#fff', borderRadius: 16, overflow: 'hidden',
      boxShadow: '0 24px 60px rgba(0,0,0,0.4)', display: 'flex', fontFamily: FONT, color: NAVY,
    }}>
      {/* Sidebar */}
      <div style={{ width: 200, background: '#fff', borderRight: `1px solid ${G200}`, padding: 20, display: 'flex', flexDirection: 'column' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 24 }}>
          <OM size={24}/>
          <span style={{ fontSize: 15, fontWeight: 700 }}>OscarMic</span>
        </div>
        <div style={{ fontSize: 10, fontWeight: 600, color: G500, marginBottom: 14, letterSpacing: '0.04em' }}>Maple Roofing Inc.</div>
        {[
          ['Today', phase === 'detail'],
          ['Records', false],
          ['Concerns', false],
          ['Follow-ups', false],
          ['Templates', phase === 'templates'],
          ['Settings', false],
        ].map(([label, active]) => (
          <div key={label} style={{ padding: '8px 10px', borderRadius: 6, fontSize: 13, fontWeight: active ? 600 : 500, background: active ? G100 : 'transparent', marginBottom: 2, transition: 'background .3s' }}>{label}</div>
        ))}
        <div style={{ flex: 1 }}/>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0', borderTop: `1px solid ${G200}` }}>
          <div style={{ width: 28, height: 28, borderRadius: 14, background: G100, fontSize: 11, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>JR</div>
          <div>
            <div style={{ fontSize: 11, fontWeight: 600 }}>Jamie Reyes</div>
            <div style={{ fontSize: 10, color: G500 }}>Owner</div>
          </div>
        </div>
      </div>
      {/* Main */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
        {phase === 'detail' && <AdminDetailView local={local}/>}
        {phase === 'templates' && <AdminTemplatesView local={local - 4.8}/>}
      </div>
    </div>
  );
};

const AdminDetailView = ({ local }) => {
  // Pop in with a slight up-from-bottom slide; record from Sam highlighted at top
  const cardOp = Math.min(1, local / 0.5);
  const cardTy = (1 - Math.min(1, local / 0.5)) * 20;
  const liveOp = local > 0.6 ? Math.min(1, (local - 0.6) / 0.4) : 0;
  return (
    <>
      <div style={{ height: 52, borderBottom: `1px solid ${G200}`, padding: '0 24px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <span style={{ fontSize: 12, fontWeight: 600, color: G600 }}>‹ Today</span>
        <span style={{ fontFamily: MONO, fontSize: 11, color: G500, marginLeft: 8 }}>OM-2026-0517-014</span>
        <div style={{ flex: 1 }}/>
        <span style={{ background: YELLOW, color: NAVY, fontSize: 10, fontWeight: 700, padding: '4px 8px', borderRadius: 4, textTransform: 'uppercase', opacity: liveOp }}>● Just logged</span>
      </div>
      <div style={{ flex: 1, padding: 20, overflow: 'hidden', opacity: cardOp, transform: `translateY(${cardTy}px)` }}>
        {/* Record header card — mirrors worker review */}
        <div style={{ background: '#fff', border: `1px solid ${G200}`, borderLeft: `4px solid ${YELLOW}`, borderRadius: 8, padding: 16, marginBottom: 12 }}>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
            <span style={{ background: G50, border: `1px solid ${G200}`, fontSize: 11, fontWeight: 600, padding: '3px 8px', borderRadius: 4 }}>Pre-job hazard review</span>
            <span style={{ background: NAVY, color: '#fff', fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 4, textTransform: 'uppercase' }}>Logged</span>
            <span style={{ fontFamily: MONO, fontSize: 11, color: G500, marginLeft: 'auto' }}>Today, 7:14 AM</span>
          </div>
          <div style={{ fontSize: 22, fontWeight: 700, marginTop: 10 }}>West Roof section · Day 5</div>
          <div style={{ display: 'flex', gap: 16, marginTop: 8, fontSize: 12, color: G600 }}>
            <span><b>Sam Khoury</b> · Roofing crew A · 3 workers</span>
            <span>Maple St renovation · 123 Maple St</span>
          </div>
        </div>
        {/* Notes + cleaned-up — same pattern as worker review */}
        <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, overflow: 'hidden' }}>
          <div style={{ background: G100, padding: '10px 14px', borderBottom: `1px solid ${G200}` }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase' }}>What Sam said</div>
            <div style={{ fontSize: 12, color: G600, lineHeight: 1.5, marginTop: 4, fontStyle: 'italic' }}>"Okay, day five on the west roof. Got the ladders up and the boom lift going. Wind's picking up though, gusting maybe 28."</div>
          </div>
          <div style={{ padding: 14 }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: NAVY, textTransform: 'uppercase', display: 'flex', alignItems: 'center', gap: 6 }}><OM size={14}/> Cleaned up by OscarMic</div>
            <div style={{ fontSize: 13, color: NAVY, lineHeight: 1.6, marginTop: 8 }}>Day 5 pre-job hazard review at the west roof section. Roofing crew A (3 workers) continuing with ladders and the boom lift. Wind gusts to 28 km/h. Tailgate done, PPE in use, fall protection set up and checked.</div>
          </div>
        </div>
      </div>
    </>
  );
};

const AdminTemplatesView = ({ local }) => {
  const types = [
    { name: 'Pre-job hazard review', tag: 'Safety', on: true },
    { name: 'Start-of-day check-in', tag: 'Operations', on: true },
    { name: 'Site note', tag: 'Operations', on: true },
    { name: 'Delay note', tag: 'Billing', on: true },
    { name: 'End-of-day summary', tag: 'Operations', on: true },
    { name: 'Material & equipment need', tag: 'Billing', on: true },
    { name: 'Reported concern', tag: 'Compliance', on: true },
    { name: 'Follow-up item', tag: 'Operations', on: false },
  ];
  const tagColor = { Safety: YELLOW, Operations: G200, Billing: '#DBEAFE', Compliance: NAVY };
  const tagText = { Safety: NAVY, Operations: G700, Billing: '#1E40AF', Compliance: '#fff' };
  return (
    <>
      <div style={{ height: 52, borderBottom: `1px solid ${G200}`, padding: '0 24px', display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ fontSize: 17, fontWeight: 700 }}>Templates</div>
        <span style={{ fontSize: 12, color: G500 }}>What your crews can log</span>
        <div style={{ flex: 1 }}/>
        <span style={{ height: 30, padding: '0 12px', background: NAVY, color: '#fff', fontSize: 12, fontWeight: 600, borderRadius: 6, display: 'inline-flex', alignItems: 'center' }}>+ New template</span>
      </div>
      <div style={{ flex: 1, padding: 20, overflow: 'hidden' }}>
        <div style={{ background: '#fff', border: `1px solid ${G200}`, borderRadius: 8, overflow: 'hidden' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 0.6fr', padding: '10px 16px', background: G50, borderBottom: `1px solid ${G200}`, fontSize: 10, fontWeight: 600, color: G500, textTransform: 'uppercase', letterSpacing: '0.04em' }}>
            <div>Template</div><div>Used for</div><div>On</div>
          </div>
          {types.map((t, i) => {
            // Stagger each row in
            const rowT = i * 0.12;
            const rowOp = Math.min(1, Math.max(0, (local - rowT) / 0.4));
            const rowTy = (1 - rowOp) * 8;
            return (
              <div key={t.name} style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 0.6fr', padding: '12px 16px', borderBottom: i < types.length - 1 ? `1px solid ${G200}` : 'none', fontSize: 13, alignItems: 'center', opacity: rowOp, transform: `translateY(${rowTy}px)` }}>
                <div style={{ fontWeight: 600 }}>{t.name}</div>
                <div>
                  <span style={{ background: tagColor[t.tag], color: tagText[t.tag], fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 3, letterSpacing: '0.04em', textTransform: 'uppercase' }}>{t.tag}</span>
                </div>
                <div>
                  <div style={{ width: 36, height: 22, borderRadius: 11, background: t.on ? YELLOW : G200, position: 'relative' }}>
                    <div style={{ position: 'absolute', top: 2, left: t.on ? 16 : 2, width: 18, height: 18, borderRadius: 9, background: '#fff', transition: 'left .2s' }}/>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
        <div style={{ marginTop: 14, fontSize: 13, color: G600, lineHeight: 1.5 }}>You pick what matters — safety, billing, compliance, or anything else.</div>
      </div>
    </>
  );
};


// ─── Sam character ───
const SamFigure = ({ local }) => {
  const hands = null;
  const t = useTime();
  const enter = Math.min(1, Math.max(0, (local - 0.1) / 0.6));
  const e = Easing.easeOutCubic(enter);
  const bob = Math.sin(t * 2.2) * 3;
  const blink = (local % 3.1) > 2.95 ? 0.15 : 1;
  const hot = !hands && local >= 2.8;
  const busy = !hands && local >= 4.3;
  const shake = 0;
  const droop = busy ? Easing.easeInOutCubic(Math.min(1, (local - 4.3) / 0.8)) : 0;
  const lid = busy ? 1 - 0.55 * droop : (hands ? 0.8 : 1);
  const gx = hands ? 3 : 0, gy = hands ? 3 : 0;
  const dropT = hot ? ((local - 2.8) % 1.6) / 1.6 : 0;
  const NAVY2 = '#1a2d4d';
  const SKIN = '#D49C74', SKIN2 = '#B98058', CAP = '#2F3A4A', CAP2 = '#232C39', TEE = '#E9EDF2', TEE2 = '#D3DAE3', STRAP = '#E5B712';
  return (
    <svg viewBox="0 0 320 440" width={340} height={468} style={{ position: 'absolute', right: 60, top: '50%', marginTop: -234, opacity: e, transform: `translateY(${(1 - e) * 40 + bob}px)`, overflow: 'visible' }}>
      <ellipse cx="160" cy="434" rx="130" ry="8" fill={G200}/>
      <g transform={`rotate(${-droop * 2} 160 280) translate(0 ${droop * 4})`}>
        {/* torso: t-shirt */}
        <path d="M20 430 L22 330 Q26 268 92 252 L132 244 L188 244 L228 252 Q294 268 298 330 L300 430 Z" fill={TEE}/>
        <path d="M22 330 Q26 268 92 252 L100 300 Q60 320 40 430 L20 430 Z" fill={TEE2} opacity="0.7"/>
        <path d="M298 330 Q294 268 228 252 L220 300 Q260 320 280 430 L300 430 Z" fill={TEE2} opacity="0.7"/>
        <path d="M134 244 Q160 268 186 244" fill="none" stroke={TEE2} strokeWidth="6" strokeLinecap="round"/>
        {/* harness */}
        <path d="M104 254 L128 430" stroke={STRAP} strokeWidth="16" strokeLinecap="round"/>
        <path d="M216 254 L192 430" stroke={STRAP} strokeWidth="16" strokeLinecap="round"/>
        <path d="M114 338 L206 338" stroke={STRAP} strokeWidth="13" strokeLinecap="round"/>
        <rect x="148" y="328" width="24" height="20" rx="4" fill={NAVY}/>
        <rect x="154" y="334" width="12" height="8" rx="2" fill={G400}/>
        <rect x="113" y="296" width="12" height="16" rx="3" fill={G500}/>
        <rect x="195" y="296" width="12" height="16" rx="3" fill={G500}/>
        {/* neck */}
        <path d="M136 206 L136 250 Q160 262 184 250 L184 206 Z" fill={SKIN2}/>
        <g transform={`translate(0 ${droop * 6 + (hands ? 3 : 0)}) rotate(${droop * 4 + (hands ? 5 : 0)} 160 230)`}>
          {/* ears */}
          <ellipse cx="111" cy="160" rx="10" ry="14" fill={SKIN2}/>
          <ellipse cx="209" cy="160" rx="10" ry="14" fill={SKIN2}/>
          {/* head, squarer jaw */}
          <path d="M112 132 Q112 92 160 90 Q208 92 208 132 L206 172 Q202 206 176 218 Q160 224 144 218 Q118 206 114 172 Z" fill={SKIN}/>
          {/* stubble */}
          <path d="M114 168 Q118 206 144 218 Q160 224 176 218 Q202 206 206 168 Q198 186 182 192 Q160 184 138 192 Q122 186 114 168 Z" fill="#6E4F3A" opacity="0.32"/>
          <path d="M140 192 Q160 186 180 192" fill="none" stroke="#6E4F3A" strokeWidth="5" strokeLinecap="round" opacity="0.45"/>
          {/* brows */}
          <path d={busy ? 'M128 145 L152 139' : 'M128 141 L152 140'} stroke="#4A3526" strokeWidth="6" strokeLinecap="round"/>
          <path d={busy ? 'M168 139 L192 145' : 'M168 140 L192 141'} stroke="#4A3526" strokeWidth="6" strokeLinecap="round"/>
          {/* eyes */}
          <ellipse cx={141 + gx} cy={156 + gy + (1 - lid) * 2} rx="4.5" ry={5 * blink * lid} fill={NAVY}/>
          <ellipse cx={179 + gx} cy={156 + gy + (1 - lid) * 2} rx="4.5" ry={5 * blink * lid} fill={NAVY}/>
          {busy && <g opacity={droop}><path d="M135 153 L147 153 M173 153 L185 153" stroke={SKIN2} strokeWidth="3" strokeLinecap="round"/><path d="M134 166 Q141 170 148 166 M172 166 Q179 170 186 166" fill="none" stroke="#8C5E42" strokeWidth="2.5" strokeLinecap="round" opacity="0.6"/></g>}
          {/* safety glasses */}
          <rect x="124" y="145" width="34" height="22" rx="8" fill="#fff" fillOpacity="0.28" stroke={NAVY} strokeWidth="3"/>
          <rect x="162" y="145" width="34" height="22" rx="8" fill="#fff" fillOpacity="0.28" stroke={NAVY} strokeWidth="3"/>
          <path d="M158 153 L162 153 M124 152 L113 150 M196 152 L207 150" stroke={NAVY} strokeWidth="3" strokeLinecap="round"/>
          {/* nose + mouth */}
          <path d="M160 160 Q154 176 162 179" fill="none" stroke={SKIN2} strokeWidth="4" strokeLinecap="round"/>
          <path d={busy ? 'M148 201 Q160 199 172 202' : 'M144 197 Q160 206 176 197'} fill="none" stroke="#3E2C20" strokeWidth="4.5" strokeLinecap="round"/>
          {/* ball cap */}
          <path d="M110 128 Q108 76 160 74 Q212 76 210 128 Z" fill={CAP}/>
          <path d="M160 74 Q164 100 162 128" fill="none" stroke={CAP2} strokeWidth="3"/>
          <path d="M106 126 Q160 116 226 124 Q238 128 230 136 Q170 130 106 136 Z" fill={CAP2}/>
          <circle cx="160" cy="76" r="5" fill={CAP2}/>
          <rect x="128" y="98" width="30" height="16" rx="3" fill={NAVY}/>
          <circle cx="137" cy="106" r="4" fill="none" stroke={YELLOW} strokeWidth="2"/>
          <g stroke="#fff" strokeWidth="1.8" strokeLinecap="round"><line x1="145" y1="103" x2="145" y2="109"/><line x1="149" y1="101" x2="149" y2="111"/><line x1="153" y1="103" x2="153" y2="109"/></g>
          {hot && <path d="M204 108 Q212 122 204 128 Q196 122 204 108 Z" fill="#BFDBFE" stroke={NAVY} strokeWidth="2" opacity={1 - dropT} transform={`translate(0 ${dropT * 30})`}/>}
        </g>

      </g>
    </svg>
  );
};


// ─── Coffee + phone hands ───
const HandsFigure = ({ local, cupAt = 0.15, phoneAt = 0.7, liveAt = 1.4 }) => {
  const t = useTime();
  const cupE = Easing.easeOutCubic(Math.min(1, Math.max(0, (local - cupAt) / 0.7)));
  const phE = Easing.easeOutCubic(Math.min(1, Math.max(0, (local - phoneAt) / 0.7)));
  const live = local >= liveAt;
  const liveE = Math.min(1, Math.max(0, (local - liveAt) / 0.35));
  const floatC = Math.sin(t * 1.4) * 5, floatP = Math.sin(t * 1.4 + 1.6) * 5;
  const CUP = '#B91C2C';
  return (
    <div style={{ position: 'absolute', right: 70, top: '50%', width: 340, height: 520, marginTop: -260 }}>
      <div style={{ position: 'absolute', left: 6, bottom: 34, width: 300, height: 26, borderRadius: '50%', background: 'radial-gradient(closest-side, rgba(14,32,59,0.16), rgba(14,32,59,0))' }}/>
      {/* cup */}
      <div style={{ position: 'absolute', left: 0, bottom: 52, width: 132, height: 210, opacity: cupE, transform: `translateY(${(1 - cupE) * 60 + floatC}px) rotate(-5deg)`, transformOrigin: 'bottom center' }}>
        {[0, 1, 2].map(i => { const p = (t * 0.5 + i / 3) % 1; return (
          <div key={i} style={{ position: 'absolute', left: 46 + i * 16, top: -48 - p * 30, width: 6, height: 34, borderRadius: 3, background: 'linear-gradient(rgba(148,163,184,0), rgba(148,163,184,0.55))', opacity: 1 - p, transform: `translateX(${Math.sin(t * 3 + i) * 4}px)` }}/>
        ); })}
        <div style={{ position: 'absolute', left: 4, right: 4, top: 0, height: 22, borderRadius: '10px 10px 4px 4px', background: 'linear-gradient(#FBF8F2, #E7DFD2)', boxShadow: 'inset 0 -2px 0 rgba(0,0,0,0.06)' }}/>
        <div style={{ position: 'absolute', left: 0, right: 0, top: 18, height: 8, borderRadius: 4, background: '#E2D9CA' }}/>
        <div style={{ position: 'absolute', left: 8, right: 8, top: 26, bottom: 0, clipPath: 'polygon(0 0, 100% 0, 91% 100%, 9% 100%)', background: `linear-gradient(90deg, #9F1724 0%, ${CUP} 30%, #CF3140 55%, ${CUP} 80%, #9A1622 100%)`, borderRadius: '0 0 10px 10px' }}>
          <div style={{ position: 'absolute', left: 0, right: 0, top: 58, height: 46, background: 'linear-gradient(90deg, #E9E4DC, #FFFFFF 40%, #F3EFE9 75%, #DDD6CC)' }}/>
          <div style={{ position: 'absolute', left: '50%', top: 69, width: 24, height: 24, marginLeft: -12, borderRadius: 12, background: CUP, opacity: 0.9 }}/>
        </div>
      </div>
      {/* phone */}
      <div style={{ position: 'absolute', right: 0, bottom: 58, width: 196, height: 396, borderRadius: 32, padding: 7, background: 'linear-gradient(145deg, #2A3E62, #0e203b 45%, #0A1830)', boxShadow: '0 30px 50px -20px rgba(14,32,59,0.55), inset 0 0 0 1.5px rgba(255,255,255,0.08)', opacity: phE, transform: `translateY(${(1 - phE) * 70 + floatP}px) rotate(6deg)`, transformOrigin: 'bottom center' }}>
        <div style={{ width: '100%', height: '100%', borderRadius: 26, background: live ? '#fff' : '#13284a', overflow: 'hidden', position: 'relative', transition: 'background .3s', fontFamily: FONT }}>
          <div style={{ position: 'absolute', top: 9, left: '50%', width: 56, height: 16, marginLeft: -28, borderRadius: 8, background: NAVY }}/>
          {live && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '44px 16px 20px', opacity: liveE }}>
              <div style={{ fontSize: 13, fontWeight: 700, color: NAVY }}>Pre-job safety check</div>
              <div style={{ width: '100%', height: 4, background: G200, borderRadius: 2, marginTop: 10, overflow: 'hidden' }}><div style={{ width: '34%', height: '100%', background: YELLOW }}/></div>
              <div style={{ flex: 1 }}/>
              <div style={{ width: 104, height: 104, borderRadius: 52, background: NAVY, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: `0 0 0 ${9 + Math.abs(Math.sin(t * 3)) * 5}px rgba(14,32,59,0.10), 0 0 0 ${18 + Math.abs(Math.sin(t * 3)) * 8}px rgba(250,204,21,0.22)` }}>
                <svg viewBox="0 0 96 96" style={{ width: '64%', height: '64%' }}>
                  <circle cx="32" cy="48" r="11" fill="none" stroke={YELLOW} strokeWidth="5"/>
                  <BarsAnimated listening/>
                </svg>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 26, fontSize: 13, fontWeight: 700, color: NAVY }}>
                <span style={{ width: 8, height: 8, borderRadius: 4, background: YELLOW, opacity: 0.5 + Math.abs(Math.sin(t * 6)) * 0.5 }}/>Listening…
              </div>
              <div style={{ flex: 1 }}/>
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

// ─── Intro: meet Sam ───
const IntroScene = ({ local }) => {
  const lines = [
    { t: 0.2, txt: 'Meet Sam.', size: 96 },
    { t: 1.5, txt: 'Foreman at Maple Roofing.', size: 42 },
    { t: 2.8, txt: 'Worked 10 hours yesterday in 30° heat.', size: 31 },
    { t: 4.3, txt: 'Sam has no time for admin.', size: 62, yellow: true },
  ];
  return (
    <div style={{
      position: 'absolute', inset: 0,
      display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'flex-start',
      padding: '0 370px 0 80px', gap: 18, fontFamily: FONT, color: NAVY,
    }}>
      <SamFigure local={local}/>
      {lines.map((l, i) => {
        const visible = local >= l.t;
        const opacity = visible ? Math.min(1, (local - l.t) / 0.4) : 0;
        const ty = visible ? (1 - Math.min(1, (local - l.t) / 0.4)) * 14 : 14;
        return (
          <div key={i} style={{
            opacity, transform: `translateY(${ty}px)`,
            fontSize: l.size,
            fontWeight: 700, letterSpacing: '-0.025em', lineHeight: 1.0,
            color: l.yellow ? YELLOW : NAVY,
          }}>{l.txt}</div>
        );
      })}
    </div>
  );
};

// ─── "What if" promise scene ───
const WhatIfScene = ({ local }) => {
  const opacity = Math.min(1, local / 0.6);
  const ty = (1 - Math.min(1, local / 0.6)) * 16;
  const op2 = local >= 1.4 ? Math.min(1, (local - 1.4) / 0.5) : 0;
  const ty2 = local >= 1.4 ? (1 - Math.min(1, (local - 1.4) / 0.5)) * 16 : 16;
  return (
    <div style={{
      position: 'absolute', inset: 0,
      display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'flex-start',
      padding: '0 120px', fontFamily: FONT, color: NAVY,
    }}>
      <div style={{ opacity, transform: `translateY(${ty}px)`, fontSize: 56, fontWeight: 500, color: G600, letterSpacing: '-0.02em', lineHeight: 1.1 }}>What if Sam could keep<br/>the office informed</div>
      <div style={{ opacity: op2, transform: `translateY(${ty2}px)`, fontSize: 84, fontWeight: 700, color: YELLOW, letterSpacing: '-0.025em', lineHeight: 1.1, marginTop: 18 }}>just by talking?</div>
    </div>
  );
};

// ─── Coffee/phone setup scene ───
const CoffeeScene = ({ local }) => {
  const op1 = Math.min(1, local / 0.5);
  const ty1 = (1 - Math.min(1, local / 0.5)) * 16;
  const op2 = local >= 1.4 ? Math.min(1, (local - 1.4) / 0.5) : 0;
  const ty2 = local >= 1.4 ? (1 - Math.min(1, (local - 1.4) / 0.5)) * 16 : 16;
  return (
    <div style={{
      position: 'absolute', inset: 0,
      display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'flex-start',
      padding: '0 370px 0 80px', fontFamily: FONT, color: NAVY,
    }}>
      <HandsFigure local={local}/>
      <div style={{ opacity: op1, transform: `translateY(${ty1}px)`, fontSize: 56, fontWeight: 700, color: NAVY, letterSpacing: '-0.02em', lineHeight: 1.1 }}>Coffee in one hand.<br/>Phone in the other.</div>
      <div style={{ opacity: op2, transform: `translateY(${ty2}px)`, fontSize: 50, fontWeight: 700, color: YELLOW, letterSpacing: '-0.02em', lineHeight: 1.1, marginTop: 24 }}>OscarMic does the rest.</div>
    </div>
  );
};

// ─── Outro ───
const OutroScene = ({ local }) => {
  const op1 = Math.min(1, local / 0.6);
  const sc1 = 0.92 + Math.min(1, local / 0.6) * 0.08;
  const op2 = local >= 0.9 ? Math.min(1, (local - 0.9) / 0.4) : 0;
  const ty2 = local >= 0.9 ? (1 - Math.min(1, (local - 0.9) / 0.4)) * 10 : 10;
  const op3 = local >= 1.5 ? Math.min(1, (local - 1.5) / 0.4) : 0;
  const op4 = local >= 2.3 ? Math.min(1, (local - 2.3) / 0.4) : 0;
  return (
    <div style={{
      position: 'absolute', inset: 0,
      display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center',
      gap: 28, fontFamily: FONT, color: NAVY,
    }}>
      <div style={{ opacity: op1, transform: `scale(${sc1})` }}><OM size={160}/></div>
      <div style={{ opacity: op2, transform: `translateY(${ty2}px)`, fontSize: 96, fontWeight: 700, letterSpacing: '-0.025em', lineHeight: 1, color: NAVY }}>OscarMic</div>
      <div style={{ opacity: op3, fontSize: 44, fontWeight: 500, letterSpacing: '-0.01em', color: YELLOW, fontStyle: 'italic' }}>Admin on the move.</div>
    </div>
  );
};

// ─── Script ───
const SCENES = [
  { id: 'intro',   start: 0.0,  end: 6.0,  Comp: IntroScene,       tapAt: [], desktop: true, noPhone: true },
  { id: 'whatif',  start: 6.0,  end: 9.5,  Comp: WhatIfScene,      tapAt: [], desktop: true, noPhone: true },
  { id: 'coffee',  start: 9.5,  end: 13.0, Comp: CoffeeScene,      tapAt: [], desktop: true, noPhone: true },
  { id: 'home',    start: 13.0, end: 16.0, Comp: HomeScreen,       tapAt: [{ t: 15.1 }] },
  { id: 'ctx',     start: 16.0, end: 19.0, Comp: ContextScreen,    tapAt: [{ t: 18.3 }] },
  { id: 'type',    start: 19.0, end: 22.0, Comp: RecordTypeScreen, tapAt: [{ t: 21.3 }] },
  { id: 'speak',   start: 22.0, end: 28.5, Comp: SpeakScreen,      tapAt: [{ t: 23.2 }, { t: 27.8 }] },
  { id: 'q2',      start: 28.5, end: 32.5, Comp: BaselineQ2,       tapAt: [{ t: 31.5 }] },
  { id: 'guided',  start: 32.5, end: 37.0, Comp: GuidedQ,          tapAt: [{ t: 36.0 }] },
  { id: 'review',  start: 37.0, end: 41.0, Comp: ReviewScreen,     tapAt: [{ t: 40.2 }] },
  { id: 'logged',  start: 41.0, end: 44.0, Comp: LoggedScreen,     tapAt: [] },
  { id: 'admin',   start: 44.0, end: 54.0, Comp: AdminDesktop,     tapAt: [], desktop: true },
  { id: 'outro',   start: 54.0, end: 59.0, Comp: OutroScene,       tapAt: [], desktop: true, noPhone: true },
];

const SceneSprite = ({ scene }) => {
  const t = useTime();
  if (t < scene.start || t >= scene.end) return null;
  const local = t - scene.start;
  let tapping = false;
  if (scene.tapAt && scene.tapAt.length > 0) {
    for (const ta of scene.tapAt) {
      const localTaT = ta.t - scene.start;
      if (Math.abs(local - localTaT) < 0.18 && local >= localTaT - 0.08) tapping = true;
    }
  }
  let extraProps = { tapping, local };
  if (scene.id === 'speak') {
    let phase = 'idle';
    if (local >= 1.2 && local < 4.5) phase = 'listening';
    else if (local >= 4.5) phase = 'done';
    extraProps.phase = phase;
  }
  const Comp = scene.Comp;
  if (scene.desktop) return <Comp {...extraProps}/>;
  return <PhoneShell><Comp {...extraProps}/></PhoneShell>;
};

const Caption = () => {
  const t = useTime();
  const captions = [
    { start: 0,    end: 6.0,  text: '' },
    { start: 6.0,  end: 9.5,  text: '' },
    { start: 9.5,  end: 13.0, text: '' },
    { start: 13.0, end: 16.0, text: 'He pulls up to the site.' },
    { start: 16.0, end: 19.0, text: 'He picks his site and crew.' },
    { start: 19.0, end: 22.0, text: 'And the update — set up by his admin.' },
    { start: 22.0, end: 28.5, text: 'He walks the site, talking through the day\'s work.' },
    { start: 28.5, end: 37.0, text: 'OscarMic asks smart follow-ups.' },
    { start: 37.0, end: 41.0, text: 'It cleans the whole thing into a record.' },
    { start: 41.0, end: 44.0, text: 'Logged in seconds.' },
    { start: 44.0, end: 48.8, text: 'His admin sees the record the moment it lands.' },
    { start: 48.8, end: 54.0, text: 'Admins pick what gets logged. Safety. Billing. Compliance.' },
    { start: 54.0, end: 59.0, text: '' },
  ];
  const active = captions.find(c => t >= c.start && t < c.end);
  if (!active) return null;
  const local = t - active.start;
  const localEnd = active.end - t;
  const inDur = 0.35, outDur = 0.35;
  let opacity = 1;
  if (local < inDur) opacity = Easing.easeOutCubic(local / inDur);
  else if (localEnd < outDur) opacity = Easing.easeInCubic(localEnd / outDur);
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, top: 50,
      textAlign: 'center', opacity,
      fontFamily: FONT, fontSize: 30, fontWeight: 700, color: NAVY,
      letterSpacing: '-0.02em',
      pointerEvents: 'none',
    }}>{active.text}</div>
  );
};

const Chrome = () => (
  <>
    <div style={{ position: 'absolute', left: 40, bottom: 40, display: 'flex', alignItems: 'center', gap: 12, color: NAVY }}>
      <OM size={36}/>
      <div>
        <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.01em', lineHeight: 1 }}>OscarMic</div>
        <div style={{ fontSize: 12, color: G600, marginTop: 4 }}>Admin on the move</div>
      </div>
    </div>
  </>
);

const App = () => (
  <Stage width={1080} height={1080} duration={59} background={'#FAFAF7'}>
    <Chrome/>
    {SCENES.map(s => <SceneSprite key={s.id} scene={s}/>)}
    <Caption/>
  </Stage>
);

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
requestAnimationFrame(() => requestAnimationFrame(() => document.body.classList.add('ready')));
