/* eslint-disable */
// dot+ — Long-press the recorder FAB to morph it into an AI chat sheet.
//
// Two gestures share one button:
//   - tap (≤ LONG_PRESS_MS):  start recording (brief inline pulse)
//   - long press:             FAB scales up, fills viewport, becomes AI chat
//
// The morph is one continuous transform: the FAB's bounding rect animates
// to the chat sheet's bounding rect via FLIP. No fade-cross. The dot in
// the middle becomes the loading orb in the chat header.

const { useState, useRef, useEffect, useCallback } = React;

// ---------- design tokens (dark theme primary) ----------
const C = {
  bg:        '#000000',           // pure black backdrop (matches screenshots)
  surface1:  '#0F0F14',           // mono.900
  surface2:  '#18181F',           // mono.800
  surface3:  '#222229',           // mono.700
  border:    '#2E2E38',           // mono.600
  text1:     '#FFFFFF',           // mono.0
  text2:     '#C8C8D4',           // mono.300
  text3:     '#6B6B78',           // mono.500
  textDim:   '#2E2E38',           // mono.600
  info:      '#276EF1',           // accent.info → AI/chat
  positive:  '#05944F',
  warning:   '#BB7A00',
  negative:  '#E11900',
};

// Brand icon — Part 1 of the dot+ logo system. White rounded square with a
// disc parked in the lower-left (a literal period on the baseline). Disc
// recolors per variant — same shape stays.
const BrandIcon = ({ size = 44, variant = 'default' }) => {
  const padding = size * 0.22;
  const disc = size * 0.33;
  const discColor =
    variant === 'info' ? C.info :       // AI surfaces
    variant === 'rec'  ? C.negative :   // active recording
                         '#000';        // default
  return (
    <div style={{
      width: size, height: size,
      background: '#fff',
      borderRadius: size * 0.22,
      position: 'relative',
      flexShrink: 0,
    }}>
      <div style={{
        position: 'absolute',
        left: padding, bottom: padding,
        width: disc, height: disc,
        borderRadius: '50%',
        background: discColor,
      }}/>
    </div>
  );
};

const HomeScreen = () => (
  <div style={{
    position:'absolute', inset:0, background: C.bg, color: C.text1,
    fontFamily:'Inter, -apple-system, system-ui, sans-serif',
    padding:'56px 20px 0', overflow:'hidden',
  }}>
    {/* header — brand icon (Part 1 of logo system) replaces "dot+" wordmark */}
    <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginTop: 12}}>
      <BrandIcon size={44}/>
      <div style={{
        width:36, height:36, borderRadius:'50%',
        background: C.surface2, border:`1px solid ${C.border}`,
        display:'flex', alignItems:'center', justifyContent:'center',
        fontSize:12, color: C.text2, fontWeight:500, letterSpacing:'.5px',
      }}>RA</div>
    </div>

    {/* search */}
    <div style={{
      marginTop: 22, height: 48, borderRadius: 14,
      background: C.surface2, display:'flex', alignItems:'center',
      padding:'0 16px', gap: 10,
    }}>
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={C.text3} strokeWidth="2" strokeLinecap="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
      <div style={{color: C.text3, fontSize: 15}}>Search meetings, todos…</div>
    </div>

    {/* category chips */}
    <div style={{display:'flex', gap: 8, marginTop: 16, overflow:'hidden'}}>
      {[
        {label:'All',     active:true},
        {label:'Recent',  active:false},
        {label:'Real Estate', active:false},
        {label:'Sales',   active:false},
        {label:'Software',active:false},
      ].map(c => (
        <div key={c.label} style={{
          padding:'8px 16px', borderRadius:999, fontSize:13, fontWeight:500,
          whiteSpace:'nowrap',
          background: c.active ? C.text1 : C.surface2,
          color: c.active ? '#000' : C.text2,
        }}>{c.label}</div>
      ))}
    </div>

    {/* stat strip */}
    <div style={{display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap: 8, marginTop: 16}}>
      <StatTile n="6" l="Meetings" />
      <StatTile n="2h" l="Recorded" />
      <StatTile n="4" l="Todos" accent={C.warning}/>
    </div>

    {/* RECENT */}
    <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginTop: 22}}>
      <div style={{display:'flex', gap: 10, alignItems:'baseline'}}>
        <span style={{fontSize:11, fontFamily:'ui-monospace, JetBrains Mono, monospace', color:C.text3, letterSpacing:'.16em', fontWeight:600}}>RECENT</span>
        <span style={{fontSize:11, color:C.text3, fontFamily:'ui-monospace, JetBrains Mono, monospace'}}>See all</span>
      </div>
      <span style={{color:C.text3, fontSize:14}}>›</span>
    </div>

    {/* meeting cards */}
    <div style={{display:'flex', flexDirection:'column', gap: 10, marginTop: 12}}>
      <MeetingCard status="Completed" statusColor={C.positive} date="MAY 21" title="Recording May 21, 2026 at 12:26 AM" mins="0m" actions="1 action"/>
      <MeetingCard status="Completed" statusColor={C.positive} date="MAY 20" title="Recording May 20, 2026 at 9:44 PM" mins="0m" actions="1 action"/>
      <MeetingCard status="Needs Review" statusColor={C.warning} date="MAY 18" title="Golf Course Planning" mins="45m" actions="2 actions"/>
    </div>
  </div>
);

const StatTile = ({n,l,accent}) => (
  <div style={{
    background: C.surface2, borderRadius: 14, padding:'18px 0 14px',
    textAlign:'center',
  }}>
    <div style={{fontSize: 28, fontWeight: 600, letterSpacing:'-1px', color: accent || C.text1, lineHeight:1}}>{n}</div>
    <div style={{fontSize: 12, color: C.text3, marginTop: 6}}>{l}</div>
  </div>
);

const MeetingCard = ({status, statusColor, date, title, mins, actions}) => (
  <div style={{
    background: C.surface2, borderRadius: 14, padding:'12px 14px',
  }}>
    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center'}}>
      <span style={{
        fontSize: 11, fontWeight: 600, color: statusColor,
        background: `${statusColor}1F`, padding:'3px 8px', borderRadius: 4,
      }}>{status}</span>
      <span style={{fontSize: 11, fontFamily:'ui-monospace, JetBrains Mono, monospace', color: C.text3, letterSpacing:'.08em'}}>{date}</span>
    </div>
    <div style={{fontSize: 16, fontWeight: 500, marginTop: 8, color: C.text1, letterSpacing:'-.2px'}}>{title}</div>
    <div style={{display:'flex', gap: 14, marginTop: 8, alignItems:'center'}}>
      <span style={{display:'inline-flex', gap: 6, alignItems:'center', fontSize: 12, color: C.text3}}>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>{mins}
      </span>
      <span style={{display:'inline-flex', gap: 6, alignItems:'center', fontSize: 12, color: C.text3}}>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="9"/><path d="m8 12 3 3 5-6"/></svg>{actions}
      </span>
    </div>
  </div>
);

// ---------- AI CHAT CONTENT (rendered inside the morphing surface) ----------
const ChatContent = ({onClose, opacity}) => {
  const [draft, setDraft] = useState('');
  const [messages, setMessages] = useState([]);
  const [thinking, setThinking] = useState(false);
  const scrollRef = useRef(null);

  const suggestions = [
    'Summarize my meetings this week',
    'What did Bobby say about drainage?',
    'Show me open todos from Golf Course Planning',
    'Find action items I owe Sarah',
  ];

  const send = useCallback((text) => {
    if (!text.trim()) return;
    setMessages(m => [...m, {role:'user', text}]);
    setDraft('');
    setThinking(true);
    setTimeout(() => {
      setThinking(false);
      setMessages(m => [...m, {role:'ai', text: sampleReply(text)}]);
    }, 1400);
  }, []);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, thinking]);

  return (
    <div style={{
      position:'absolute', inset: 0, display:'flex', flexDirection:'column',
      opacity, transition:'opacity .18s ease-out',
      pointerEvents: opacity > 0.5 ? 'auto' : 'none',
    }}>
      {/* header — `.plus` wordmark in info accent (the morphing blue orb on
          the left IS the leading dot) + close button on the right. */}
      <div style={{
        height: 64, padding:'0 16px 0 24px',
        display:'flex', alignItems:'center', justifyContent:'space-between',
        borderBottom:`1px solid ${C.border}`,
      }}>
        <div style={{display:'flex', alignItems:'baseline', gap: 8}}>
          {/* invisible spacer the width of the leading dot, so "plus" lands
              in the exact spot regardless of which phase paints the dot. */}
          <span style={{display:'inline-block', width: 16, height: 16}}/>
          <span style={{
            fontFamily:'Inter, sans-serif',
            fontWeight: 900,
            fontSize: 28,
            letterSpacing:'-1.4px',
            color: C.text1,
            lineHeight: 1,
          }}>plus</span>
        </div>
        <button onClick={onClose} style={{
          width:32, height:32, borderRadius:'50%', border:'none',
          background: C.surface3, color: C.text2, fontSize: 14,
          display:'flex', alignItems:'center', justifyContent:'center', cursor:'pointer',
        }}>✕</button>
      </div>

      {/* conversation */}
      <div ref={scrollRef} style={{
        flex: 1, overflowY:'auto', padding:'20px 16px',
        display:'flex', flexDirection:'column', gap: 12,
      }}>
        {messages.length === 0 && (
          <div style={{paddingTop: 12}}>
            <div style={{fontSize: 28, fontWeight: 600, color: C.text1, letterSpacing:'-1px', lineHeight: 1.15}}>
              Ask your meetings<br/>anything.
            </div>
            <div style={{fontSize: 14, color: C.text3, marginTop: 8, lineHeight: 1.5}}>
              I have transcripts for 6 meetings this week. Try one of these:
            </div>
          </div>
        )}

        {messages.map((m, i) => (
          <Bubble key={i} role={m.role} text={m.text}/>
        ))}
        {thinking && <Bubble role="ai" thinking/>}
      </div>

      {/* suggestion chips (only before the first message) */}
      {messages.length === 0 && (
        <div style={{
          padding:'0 16px 12px', display:'flex', gap: 8, overflowX:'auto',
          scrollbarWidth:'none',
        }}>
          {suggestions.map((s,i) => (
            <button key={i} onClick={() => send(s)} style={{
              flex:'0 0 auto', padding:'10px 14px', borderRadius: 999,
              background: C.surface2, color: C.text2, border:`1px solid ${C.border}`,
              fontSize: 13, fontWeight: 500, cursor:'pointer',
              fontFamily:'inherit',
            }}>{s}</button>
          ))}
        </div>
      )}

      {/* input bar */}
      <form onSubmit={(e)=>{e.preventDefault(); send(draft);}} style={{
        padding:'12px 16px 24px', display:'flex', gap: 8, alignItems:'flex-end',
        borderTop:`1px solid ${C.border}`, background: C.surface1,
      }}>
        <div style={{
          flex: 1, background: C.surface2, borderRadius: 22,
          padding:'10px 14px', display:'flex', alignItems:'center', gap: 8,
          minHeight: 44,
        }}>
          <input
            value={draft}
            onChange={e => setDraft(e.target.value)}
            placeholder="Ask anything…"
            style={{
              flex:1, background:'transparent', border:'none', outline:'none',
              color: C.text1, fontSize: 15, fontFamily:'inherit',
            }}
          />
        </div>
        <button type="submit" disabled={!draft.trim()} style={{
          width: 44, height: 44, borderRadius: '50%', border:'none',
          background: draft.trim() ? C.info : C.surface3,
          color:'#fff', cursor: draft.trim() ? 'pointer' : 'default',
          display:'flex', alignItems:'center', justifyContent:'center',
          transition:'background .15s',
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
            <path d="M5 12h14M13 6l6 6-6 6"/>
          </svg>
        </button>
      </form>
    </div>
  );
};

const Bubble = ({role, text, thinking}) => {
  const isUser = role === 'user';
  return (
    <div style={{
      alignSelf: isUser ? 'flex-end' : 'flex-start',
      maxWidth: '82%',
      background: isUser ? C.info : C.surface2,
      color: isUser ? '#fff' : C.text1,
      padding: thinking ? '14px 16px' : '10px 14px',
      borderRadius: 18,
      borderBottomRightRadius: isUser ? 6 : 18,
      borderBottomLeftRadius: isUser ? 18 : 6,
      fontSize: 14, lineHeight: 1.5,
      whiteSpace: 'pre-wrap',
    }}>
      {thinking ? <ThinkingDots/> : text}
    </div>
  );
};

const ThinkingDots = () => (
  <div style={{display:'flex', gap: 4, alignItems:'center'}}>
    {[0,1,2].map(i => (
      <span key={i} style={{
        width: 6, height: 6, borderRadius:'50%',
        background: C.text3,
        animation: `dot-pulse 1.2s ${i*0.18}s infinite ease-in-out`,
      }}/>
    ))}
  </div>
);

// =============================================================
//                FLOATING RECORDER + MORPH ENGINE
// =============================================================
//
// Geometry constants (frame is 390×844; matches IOSDevice props)
const FRAME = { w: 390, h: 844 };
const FAB   = { size: 64, right: 18, bottom: 96 };
const PRESS_SCALE = 1.10;
const SHEET = { top: 60, left: 12, right: 12, bottom: 12, radius: 28 };

// Pre-computed sheet and FAB rects in (top, left, width, height) form so the
// morph animates a single, consistent property set. Mixing bottom/right with
// width:auto across phases breaks CSS transitions (auto isn't interpolable).
const FAB_TOP    = FRAME.h - FAB.bottom - FAB.size;          // 684
const FAB_LEFT   = FRAME.w - FAB.right  - FAB.size;          // 308
const SHEET_W    = FRAME.w - SHEET.left - SHEET.right;       // 366
const SHEET_H    = FRAME.h - SHEET.top  - SHEET.bottom;      // 772

const LONG_PRESS_MS = 380;
const MORPH_MS      = 520;

const Recorder = ({ onOpenChat, tweaks }) => {
  const [phase, setPhase] = useState('idle');   // idle | pressing | recording | opening | chat | closing
  const [pressProgress, setPressProgress] = useState(0); // 0..1 during pressing phase
  const pressTimer = useRef(null);
  const progressRAF = useRef(null);
  const pressStart = useRef(0);

  const longPressMs = LONG_PRESS_MS / tweaks.speed;
  const morphMs     = MORPH_MS / tweaks.speed;

  // -------- gesture handlers ----------
  const startPress = useCallback((e) => {
    e.preventDefault();
    if (phase !== 'idle' && phase !== 'recording') return;
    pressStart.current = performance.now();
    setPhase('pressing');
    setPressProgress(0);

    const tick = () => {
      const t = Math.min(1, (performance.now() - pressStart.current) / longPressMs);
      setPressProgress(t);
      if (t < 1) progressRAF.current = requestAnimationFrame(tick);
    };
    progressRAF.current = requestAnimationFrame(tick);

    pressTimer.current = setTimeout(() => {
      // long-press fired — morph into chat
      navigator.vibrate?.(15);
      setPhase('opening');
      setTimeout(() => setPhase('chat'), morphMs);
    }, longPressMs);
  }, [phase, longPressMs, morphMs]);

  const endPress = useCallback((e) => {
    e?.preventDefault?.();
    if (phase !== 'pressing') return;
    cancelAnimationFrame(progressRAF.current);
    clearTimeout(pressTimer.current);
    const heldFor = performance.now() - pressStart.current;
    setPressProgress(0);
    if (heldFor < longPressMs) {
      // it was a tap — start recording (brief flash)
      navigator.vibrate?.(8);
      setPhase('recording');
      setTimeout(() => setPhase('idle'), 1800);
    } // otherwise the long-press timer already moved us to 'opening'
  }, [phase, longPressMs]);

  const cancelPress = useCallback(() => {
    if (phase !== 'pressing') return;
    cancelAnimationFrame(progressRAF.current);
    clearTimeout(pressTimer.current);
    setPressProgress(0);
    setPhase('idle');
  }, [phase]);

  const closeChat = useCallback(() => {
    setPhase('closing');
    setTimeout(() => setPhase('idle'), morphMs);
  }, [morphMs]);

  // ---- morph geometry ---------
  // The surface element animates between FAB rect and SHEET rect.
  // We render it absolutely positioned within the frame.
  const inMorph = phase === 'opening' || phase === 'chat' || phase === 'closing';
  const isSheet = phase === 'chat' || phase === 'opening';
  const isClosing = phase === 'closing';
  const isPressing = phase === 'pressing';

  // for resting + recording + pressing, surface sits as FAB
  // for opening, surface transitions to SHEET
  // for chat, surface stays at SHEET
  // for closing, surface returns to FAB

  // Compute the surface rect for current phase
  const fabScale = isPressing ? (1 + (PRESS_SCALE - 1) * pressProgress) : 1;
  const fabSize = FAB.size * fabScale;

  const surfaceStyle = isSheet ? {
    top: SHEET.top, left: SHEET.left, right: SHEET.right, bottom: SHEET.bottom,
    width: 'auto', height: 'auto',
    borderRadius: SHEET.radius,
    background: C.surface1,
    boxShadow: `0 24px 60px -10px rgba(0,0,0,.6), 0 0 0 1px ${C.border}`,
  } : isClosing ? {
    bottom: FAB.bottom, right: FAB.right,
    width: FAB.size, height: FAB.size,
    borderRadius: 18,
    background: '#fff',
    boxShadow: '0 8px 32px rgba(39,110,241,.30)',
  } : {
    bottom: FAB.bottom - (fabSize - FAB.size) / 2,
    right:  FAB.right  - (fabSize - FAB.size) / 2,
    width:  fabSize, height: fabSize,
    borderRadius: 14 + 8 * pressProgress, // 14 → 22
    background: '#fff',
    boxShadow: isPressing
      ? `0 0 ${20 + 60*pressProgress}px ${4 + 8*pressProgress}px rgba(39,110,241,${0.25 + 0.45*pressProgress})`
      : phase === 'recording'
        ? `0 0 0 ${4 + 8*Math.sin(Date.now()/200)}px rgba(225,25,0,.18), 0 8px 24px rgba(0,0,0,.4)`
        : '0 8px 24px rgba(0,0,0,.35)',
  };

  return (
    <>
      {/* scrim during chat */}
      <div style={{
        position:'absolute', inset: 0, background: 'rgba(0,0,0,.45)',
        opacity: inMorph && !isClosing ? 1 : 0,
        transition: `opacity ${morphMs}ms cubic-bezier(.22,.61,.36,1)`,
        pointerEvents: inMorph ? 'auto' : 'none',
      }} onClick={isSheet ? closeChat : undefined}/>

      {/* The morphing surface — single element across all phases */}
      <div style={{
        position:'absolute',
        transition: `all ${morphMs}ms cubic-bezier(.22,.61,.36,1)`,
        overflow: 'hidden',
        ...surfaceStyle,
        // when pressing, override the CSS transition so the scale tracks RAF
        ...(isPressing ? { transition: 'border-radius 80ms, box-shadow 120ms' } : {}),
      }}>
        {/* The dot — lives inside the surface, morphs from center to header */}
        <DotOrb phase={phase} pressProgress={pressProgress}/>

        {/* Chat content cross-fades in once we're (almost) sheet-sized */}
        {(phase === 'chat' || phase === 'opening') && (
          <ChatContent
            onClose={closeChat}
            opacity={phase === 'chat' ? 1 : 0}
          />
        )}
      </div>

      {/* Invisible hit target on top of the FAB position (only when idle/recording) */}
      {!inMorph && (
        <div
          onPointerDown={startPress}
          onPointerUp={endPress}
          onPointerLeave={cancelPress}
          onPointerCancel={cancelPress}
          onContextMenu={e => e.preventDefault()}
          style={{
            position:'absolute',
            bottom: FAB.bottom - 8, right: FAB.right - 8,
            width: FAB.size + 16, height: FAB.size + 16,
            cursor: 'pointer', touchAction:'none',
            userSelect:'none',
          }}
        />
      )}

      {/* "Recording…" toast on tap */}
      <div style={{
        position:'absolute', left:'50%', bottom: 180,
        transform: `translateX(-50%) translateY(${phase === 'recording' ? 0 : 12}px)`,
        opacity: phase === 'recording' ? 1 : 0,
        transition: 'all .25s cubic-bezier(.22,.61,.36,1)',
        background: '#000', border: `1px solid ${C.border}`,
        padding:'10px 14px', borderRadius: 999,
        display:'flex', alignItems:'center', gap: 8,
        fontSize: 13, color: C.text1, fontWeight: 500,
        pointerEvents:'none',
      }}>
        <span style={{
          width: 8, height: 8, borderRadius:'50%', background: C.negative,
          animation:'rec-blink 1s infinite',
        }}/>
        Recording started
      </div>

      {/* Long-press hint label */}
      <div style={{
        position:'absolute', right: FAB.right + FAB.size + 14,
        bottom: FAB.bottom + 18,
        opacity: isPressing ? Math.min(1, pressProgress * 2) : 0,
        transition:'opacity .12s',
        fontSize: 11, fontFamily:'ui-monospace, JetBrains Mono, monospace',
        color: C.info, letterSpacing:'.08em', fontWeight: 600,
        textTransform:'uppercase', pointerEvents:'none',
        background:'rgba(39,110,241,.1)', padding:'4px 8px', borderRadius: 4,
        whiteSpace:'nowrap',
      }}>
        Hold for AI →
      </div>
    </>
  );
};

// The dot — lives inside the morphing surface. In FAB phase it sits in the
// lower-left like a period on baseline (Part 1 of the logo system). In chat
// phase it slides to the upper-left of the sheet and becomes the leading dot
// of the ".plus" wordmark (Part 2 of the logo system) in info accent.
const DotOrb = ({phase, pressProgress}) => {
  const isSheet = phase === 'chat' || phase === 'opening';
  const isPressing = phase === 'pressing';

  // color: black (mark-ink) idle → info-blue at AI · negative-red while recording
  const color =
    phase === 'recording' ? C.negative :
    isPressing            ? blend('#000000', C.info, pressProgress) :
    isSheet || phase === 'closing' ? C.info :
    '#000000';

  // Brand spec sizes:
  //  FAB resting:   33% of 64px → 21px (matches `.ico .d` ratio in brand book)
  //  Pressing:      grows to ~26px to telegraph intent
  //  In chat:       ~16px — leading-dot proportion of ".plus" wordmark
  const size =
    isPressing ? 21 + 5 * pressProgress :
    isSheet    ? 16 :
                 21;

  // Position — measured from the morphing surface's top-left.
  //  FAB:   lower-left padding of 22% (≈14px on a 64px FAB)
  //  Sheet: top-left of header so it reads as the leading dot of "plus"
  const fabPad = 14;          // 22% of 64
  const sheetX = 24;          // matches "plus" text x-anchor (see ChatContent)
  const sheetY = 24;          // baseline-aligns with "plus" text below

  const posStyle = isSheet ? {
    left: sheetX, top: sheetY, right: 'auto', bottom: 'auto',
  } : {
    left: fabPad, bottom: fabPad, right: 'auto', top: 'auto',
  };

  return (
    <div style={{
      position:'absolute',
      width: size, height: size, borderRadius:'50%',
      background: color,
      boxShadow: isSheet || isPressing
        ? `0 0 ${10 + 20*(isPressing ? pressProgress : 1)}px ${color}80`
        : 'none',
      transition: 'all 520ms cubic-bezier(.22,.61,.36,1), background 280ms, box-shadow 280ms, width 520ms cubic-bezier(.22,.61,.36,1), height 520ms cubic-bezier(.22,.61,.36,1)',
      ...posStyle,
      animation: phase === 'recording' ? 'rec-blink 1s infinite' : 'none',
    }}/>
  );
};

// linear interpolate between two hex colors
function blend(a, b, t) {
  const pa = parseInt(a.slice(1), 16), pb = parseInt(b.slice(1), 16);
  const ar = (pa>>16)&255, ag=(pa>>8)&255, ab=pa&255;
  const br = (pb>>16)&255, bg=(pb>>8)&255, bb=pb&255;
  const r = Math.round(ar + (br-ar)*t);
  const g = Math.round(ag + (bg-ag)*t);
  const bl= Math.round(ab + (bb-ab)*t);
  return `rgb(${r},${g},${bl})`;
}

// canned replies
function sampleReply(prompt) {
  const p = prompt.toLowerCase();
  if (p.includes('bobby') || p.includes('drainage')) {
    return 'In the Golf Course Planning meeting on May 18, Bobby flagged drainage on the west slope as a concern — he saw standing water after the April 9 rain. He suggested adding a French drain along the cart path before the green is shaped. Want me to add it as a todo?';
  }
  if (p.includes('todo') || p.includes('action')) {
    return 'You have 4 open todos:\n• Golf Course Planning — get drainage quote (3 days overdue)\n• Q3 Software Sync — review architecture doc\n• Vacation Club Sales — send proposal v2 to Marcus\n• Investor Follow-up — confirm Tuesday slot';
  }
  if (p.includes('summar') || p.includes('week')) {
    return 'This week (May 17–21) you recorded 2 hours across 6 meetings. Themes: real-estate underwriting, golf course logistics, and one investor follow-up. The Golf Course Planning meeting still needs review.';
  }
  if (p.includes('sarah')) {
    return 'I don\'t see a Sarah in this week\'s transcripts. The closest match is Sara Chen from your April 30 investor call — she asked you to send a 1-pager on unit economics by mid-May. That one\'s still open.';
  }
  return 'Got it — let me look across your transcripts. I\'ll pull the most relevant snippets in a moment.';
}

// =============================================================
//                          APP
// =============================================================

const App = () => {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  return (
    <>
      {/* keyframes */}
      <style>{`
        @keyframes rec-blink   { 0%,100% { opacity: 1 } 50% { opacity: .3 } }
        @keyframes dot-pulse   { 0%,80%,100% { opacity:.3; transform: scale(.7) } 40% { opacity:1; transform: scale(1) } }
        @keyframes orb-pulse   { 0%,100% { transform: translate(0,0) scale(1); box-shadow: 0 0 14px ${C.info}80 }
                                  50%      { transform: translate(0,0) scale(1.12); box-shadow: 0 0 24px ${C.info}b0 } }
        body, html { background:#000; }
      `}</style>

      <IOSDevice dark width={390} height={844}>
        <div style={{position:'relative', width:'100%', height:'100%', overflow:'hidden', background: C.bg}}>
          <HomeScreen/>
          <Recorder tweaks={{speed: t.speed}}/>
        </div>
      </IOSDevice>

      <TweaksPanel title="Tweaks">
        <TweakSection label="Animation">
          <TweakSlider label="Speed" value={t.speed} min={0.4} max={2.0} step={0.1} unit="×"
                       onChange={(v) => setTweak('speed', v)}/>
        </TweakSection>
        <TweakSection label="Try it">
          <div style={{fontSize: 12, color: 'rgba(60,50,40,.75)', lineHeight: 1.5, padding:'4px 12px 12px'}}>
            <strong style={{color:'#2a251f'}}>Tap</strong> the white square in the bottom-right to start a recording. <strong style={{color:'#2a251f'}}>Press &amp; hold</strong> it to expand into the dot+ AI chat.
          </div>
        </TweakSection>
      </TweaksPanel>
    </>
  );
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "speed": 1.0
}/*EDITMODE-END*/;

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