/* global React, Button, Card, Badge, Section, SectionHeader */
const { useState, useEffect, useRef } = React;

// ──────────────────────────────────────────
// VerticalRadioSlider — keyboard-navigable + draggable thumb
// Track has NO fill — only the thumb is colored. Snaps to N positions.
// ──────────────────────────────────────────
function VerticalRadioSlider({ label, options, value, onChange, ariaLabel, side = 'right', fillHeight = false, totalHeight = null }) {
  const idx = Math.max(0, options.findIndex(o => o.value === value));
  const trackRef = useRef(null);
  const [pingKey, setPingKey] = useState(0);
  const [dragging, setDragging] = useState(false);
  const [dragY, setDragY] = useState(null); // when dragging, raw Y offset (0..trackH)
  const N = options.length;
  const ROW = 44;        // each row height (used when not fillHeight)
  const TRACK_PAD = 6;   // top/bottom padding inside track for thumb
  // When fillHeight, the labels stretch to fill `totalHeight`. Track runs from
  // center-of-first-option to center-of-last-option (option half-height ≈ 11px).
  const labelsH = fillHeight && totalHeight ? totalHeight : N * ROW;
  const OPTION_HALF = fillHeight ? 11 : 0;
  const trackH = labelsH - 2 * OPTION_HALF;
  const thumbH = 28;

  const select = (newIdx) => {
    const clamped = Math.max(0, Math.min(N - 1, newIdx));
    onChange(options[clamped].value);
    setPingKey(k => k + 1);
  };

  const onKey = (e) => {
    if (e.key === 'ArrowDown' || e.key === 'ArrowRight') { e.preventDefault(); select(idx + 1); }
    else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') { e.preventDefault(); select(idx - 1); }
    else if (e.key === 'Home') { e.preventDefault(); select(0); }
    else if (e.key === 'End')  { e.preventDefault(); select(N - 1); }
  };

  const yToIdx = (clientY) => {
    const rect = trackRef.current.getBoundingClientRect();
    const y = clientY - rect.top - TRACK_PAD;
    const usable = rect.height - 2 * TRACK_PAD;
    return Math.round((y / usable) * (N - 1));
  };

  const onPointerDown = (e) => {
    e.preventDefault();
    trackRef.current.setPointerCapture(e.pointerId);
    setDragging(true);
    const rect = trackRef.current.getBoundingClientRect();
    setDragY(e.clientY - rect.top);
  };
  const onPointerMove = (e) => {
    if (!dragging) return;
    const rect = trackRef.current.getBoundingClientRect();
    const y = Math.max(0, Math.min(rect.height, e.clientY - rect.top));
    setDragY(y);
  };
  const onPointerUp = (e) => {
    if (!dragging) return;
    const newIdx = yToIdx(e.clientY);
    setDragging(false);
    setDragY(null);
    select(newIdx);
  };

  // Compute thumb position. When dragging: follow cursor. Otherwise: snap to idx.
  const usable = trackH - 2 * TRACK_PAD;
  const snapY = TRACK_PAD + (idx / Math.max(1, N - 1)) * usable - thumbH / 2;
  const thumbY = dragging && dragY != null
    ? Math.max(0, Math.min(trackH - thumbH, dragY - thumbH / 2))
    : snapY;

  const Track = (
    <div style={{
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', flexShrink: 0,
    }}>
      {/* Spacer matching the label header above + offset to align with first option center */}
      <div aria-hidden style={{
        height: `${13 + OPTION_HALF}px`,  /* mono header line-height + offset to first-option center */
        marginBottom: '8px',
      }}/>
      <div
        ref={trackRef}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
        style={{
          position: 'relative',
          width: '6px',
          height: `${trackH}px`,
          background: 'linear-gradient(90deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.85) 50%, rgba(0,0,0,0.55) 100%)',
          borderRadius: '999px',
          boxShadow: 'inset 0 1px 2px rgba(0,0,0,0.8), inset 0 -1px 0 rgba(255,255,255,0.04), 0 1px 0 rgba(255,255,255,0.04)',
          cursor: dragging ? 'grabbing' : 'pointer',
          touchAction: 'none',
        }}
      >
        {/* Tick marks at each option position */}
        {options.map((_, i) => {
          const ratio = (N - 1) === 0 ? 0 : i / (N - 1);
          return (
            <div key={i} aria-hidden style={{
              position: 'absolute',
              left: '50%',
              top: `${ratio * trackH}px`,
              transform: 'translate(-50%, -50%)',
              width: '12px',
              height: '1px',
              background: 'rgba(255,255,255,0.10)',
              pointerEvents: 'none',
            }}/>
          );
        })}
        <div
          key={pingKey}
          aria-hidden
          style={{
            position: 'absolute',
            top: `${thumbY}px`,
            left: '50%',
            transform: 'translateX(-50%)',
            width: '36px',
            height: `${thumbH}px`,
            background: 'linear-gradient(180deg, #2a2a2e 0%, #161618 50%, #0c0c0e 100%)',
            border: '1px solid rgba(255,255,255,0.18)',
            borderTopColor: 'rgba(255,255,255,0.28)',
            borderRadius: '5px',
            boxShadow: [
              '0 0 0 1px rgba(0,0,0,0.4)',           // outer hairline
              'inset 0 1px 0 rgba(255,255,255,0.10)', // top highlight
              'inset 0 -1px 0 rgba(0,0,0,0.45)',     // bottom shadow
              '0 4px 10px rgba(0,0,0,0.55)',          // drop
              '0 0 14px rgba(255,106,44,0.18)',       // soft signal halo
            ].join(', '),
            transition: dragging ? 'none' : 'top 0.25s cubic-bezier(0.32, 0.72, 0, 1)',
            display: 'flex',
            alignItems: 'center',
            gap: '8px',
            padding: '0 6px',
            cursor: 'grab',
            animation: dragging ? 'none' : 'thumbPing 0.32s ease-out',
          }}
        >
          {/* Left ember indicator dash */}
          <div style={{
            width: '4px', height: '12px',
            background: 'var(--color-signal)',
            borderRadius: '1px',
            boxShadow: '0 0 8px rgba(255,106,44,0.7)',
            flexShrink: 0,
          }}/>
          {/* Grip lines */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: '2px', flex: 1 }}>
            <div style={{ height: '1px', background: 'rgba(255,255,255,0.22)' }}/>
            <div style={{ height: '1px', background: 'rgba(255,255,255,0.22)' }}/>
            <div style={{ height: '1px', background: 'rgba(255,255,255,0.22)' }}/>
          </div>
        </div>
      </div>
    </div>
  );

  const Labels = (
    <div style={{ display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0 }}>
      <div style={{
        fontSize: '10px', fontFamily: 'IBM Plex Mono, monospace',
        letterSpacing: '0.22em', opacity: 0.45, marginBottom: '8px',
        color: 'rgba(255,255,255,0.65)',
        textTransform: 'uppercase',
        textAlign: 'center',
        position: 'relative',
      }}>
        <span style={{
          position: 'relative',
          padding: '0 8px',
          background: 'transparent',
        }}>{label}</span>
        {/* Hairlines flanking the label */}
        <span aria-hidden style={{
          position: 'absolute', top: '50%', left: 0, right: 0, height: '1px',
          background: 'rgba(255,255,255,0.10)', zIndex: -1,
        }}/>
      </div>
      <div style={{
        display: 'flex', flexDirection: 'column',
        height: fillHeight && totalHeight ? `${totalHeight}px` : 'auto',
        justifyContent: fillHeight ? 'space-between' : 'flex-start',
      }}>
        {options.map((opt, i) => {
          const active = i === idx;
          return (
            <button
              key={opt.value}
              role="radio"
              aria-checked={active}
              onClick={() => select(i)}
              style={{
                height: fillHeight ? 'auto' : `${ROW}px`,
                paddingTop: fillHeight ? '4px' : 0,
                paddingBottom: fillHeight ? '4px' : 0,
                background: 'transparent',
                border: 'none',
                textAlign: side === 'right' ? 'left' : 'right',
                paddingLeft: 0, paddingRight: 0,
                cursor: 'pointer',
                fontFamily: 'IBM Plex Mono, monospace',
                fontSize: '12px',
                fontWeight: active ? 600 : 400,
                letterSpacing: '0.10em',
                textTransform: 'uppercase',
                color: active ? 'rgba(250,247,242,0.98)' : 'rgba(250,247,242,0.32)',
                transition: 'color 0.2s ease',
                display: 'flex',
                alignItems: 'center',
                gap: '8px',
                justifyContent: side === 'right' ? 'flex-start' : 'flex-end',
                animation: active ? `labelPing-${pingKey} 0.3s ease-out` : 'none',
              }}
              onMouseEnter={e => { if (!active) e.currentTarget.style.color = 'rgba(250,247,242,0.65)'; }}
              onMouseLeave={e => { if (!active) e.currentTarget.style.color = 'rgba(250,247,242,0.32)'; }}
            >
              {opt.label}
            </button>
          );
        })}
      </div>
    </div>
  );

  return (
    <div role="radiogroup" aria-label={ariaLabel} onKeyDown={onKey} tabIndex={0}
      style={{ display: 'flex', gap: '18px', outline: 'none', flexDirection: side === 'right' ? 'row' : 'row-reverse' }}>
      {Track}{Labels}
    </div>
  );
}

// ──────────────────────────────────────────
// Horizontal pill row — used as the mobile collapse for vertical radio
// ──────────────────────────────────────────
function HorizontalPillRow({ label, options, value, onChange }) {
  return (
    <div>
      <div style={{
        fontSize: '11px', fontFamily: 'IBM Plex Mono, monospace',
        letterSpacing: '0.14em', opacity: 0.55, marginBottom: '10px',
        color: 'rgba(255,255,255,0.65)',
      }}>{label}</div>
      <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
        {options.map(opt => {
          const active = opt.value === value;
          return (
            <button key={opt.value} onClick={() => onChange(opt.value)}
              style={{
                height: '36px', padding: '0 14px',
                borderRadius: '999px',
                border: '1px solid ' + (active ? 'var(--color-signal)' : 'rgba(255,255,255,0.15)'),
                background: active ? 'rgba(255,106,44,0.12)' : 'transparent',
                color: active ? 'var(--color-signal)' : 'rgba(250,247,242,0.7)',
                fontWeight: active ? 600 : 400,
                fontSize: '13px',
                fontFamily: 'inherit',
                cursor: 'pointer',
                transition: 'all 0.18s ease',
              }}>
              {opt.label}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────
// Waveform header — gentle idle pulse + active mode
// ──────────────────────────────────────────
function Waveform({ active, intensity = 0.5 }) {
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const i = setInterval(() => setTick(t => t + 1), active ? 60 : 110);
    return () => clearInterval(i);
  }, [active]);
  const N = 64;
  const bars = Array.from({ length: N }).map((_, i) => {
    if (active) {
      const phase = i * 0.34 + tick * 0.22;
      return 6 + Math.abs(Math.sin(phase)) * 28 * intensity + Math.abs(Math.sin(phase * 0.5 + tick * 0.1)) * 18 * intensity;
    } else {
      // Sine wave with phase offset per bar, gentle, around 4–10px tall idle
      const phase = i * 0.18 + tick * 0.06;
      return 4 + (Math.sin(phase) + 1) * 3; // 4..10
    }
  });
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      gap: '3px', height: '64px',
    }}>
      {bars.map((h, i) => (
        <div key={i} style={{
          width: '3px', height: `${h}px`,
          background: 'var(--color-signal)',
          borderRadius: '2px',
          transition: active ? 'height 60ms linear' : 'height 0.4s ease',
          opacity: active ? 1 : 0.55,
        }}/>
      ))}
    </div>
  );
}

// ──────────────────────────────────────────
// ScreenPane — the "monitor" on the right side of the hardware unit
// Dark interior, signal-orange horizon glow band, tab strip, brand mark
// ──────────────────────────────────────────
function ScreenPane({
  messages, isLive, currentSpeaker, mockMessages, mockOverlay, loc,
  phase, callTime, voiceLabel, voiceDesc, industryLabel,
}) {
  const c = window.BD.COPY[loc];
  const scrollRef = useRef(null);
  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages.length]);

  const showMock = !isLive && messages.length === 0;
  const list = showMock ? mockMessages : messages;
  const fmtTime = (s) => `${String(Math.floor(s/60)).padStart(2,'0')}:${String(s%60).padStart(2,'0')}`;

  // Glow intensity: idle = soft, live = bright, done = mid
  const glowIntensity = phase === 'live' ? 1 : phase === 'done' ? 0.55 : 0.32;

  return (
    <div style={{
      position: 'relative',
      display: 'flex', flexDirection: 'column',
      // Recessed monitor — darker than bezel, with inset shadow
      background: 'linear-gradient(180deg, #0a0a0c 0%, #050507 100%)',
      borderRadius: '14px',
      overflow: 'hidden',
      minHeight: '540px',
      boxShadow: [
        'inset 0 2px 4px rgba(0,0,0,0.85)',
        'inset 0 -1px 0 rgba(255,255,255,0.04)',
        'inset 0 0 0 1px rgba(0,0,0,0.6)',
        '0 0 0 1px rgba(255,255,255,0.06)',
      ].join(', '),
    }}>
      {/* HORIZON GLOW — radial signal-orange band, animated on live */}
      <div aria-hidden style={{
        position: 'absolute',
        left: '-10%', right: '-10%',
        top: '34%',
        height: '180px',
        background: `radial-gradient(ellipse 60% 100% at center, rgba(255,140,80,${0.55 * glowIntensity}) 0%, rgba(255,106,44,${0.35 * glowIntensity}) 30%, rgba(255,106,44,${0.10 * glowIntensity}) 55%, transparent 80%)`,
        filter: 'blur(2px)',
        pointerEvents: 'none',
        transition: 'opacity 0.6s ease',
        animation: isLive ? 'horizonPulse 2.4s ease-in-out infinite' : 'none',
      }}/>
      {/* Bright horizon line */}
      <div aria-hidden style={{
        position: 'absolute',
        left: 0, right: 0,
        top: 'calc(34% + 86px)',
        height: '1px',
        background: `linear-gradient(90deg, transparent 0%, rgba(255,170,110,${0.5 * glowIntensity}) 30%, rgba(255,170,110,${0.7 * glowIntensity}) 50%, rgba(255,170,110,${0.5 * glowIntensity}) 70%, transparent 100%)`,
        boxShadow: `0 0 12px rgba(255,140,80,${0.6 * glowIntensity})`,
        pointerEvents: 'none',
      }}/>
      {/* Faint scanlines */}
      <div aria-hidden style={{
        position: 'absolute', inset: 0,
        background: 'repeating-linear-gradient(180deg, transparent 0px, transparent 2px, rgba(255,255,255,0.012) 2px, rgba(255,255,255,0.012) 3px)',
        pointerEvents: 'none',
        mixBlendMode: 'overlay',
      }}/>

      {/* Tab strip — DEMO / CODE */}
      <div style={{
        position: 'relative',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '14px 18px 10px',
        borderBottom: '1px solid rgba(255,255,255,0.05)',
      }}>
        <div style={{ display: 'flex', gap: '20px', alignItems: 'center' }}>
          <div style={{
            display: 'flex', alignItems: 'center', gap: '6px',
            fontFamily: 'IBM Plex Mono, monospace',
            fontSize: '10px', letterSpacing: '0.20em',
            color: 'rgba(250,247,242,0.95)',
            textTransform: 'uppercase',
          }}>
            <span aria-hidden style={{
              width: '6px', height: '6px', borderRadius: '50%',
              background: isLive ? '#7CFFA0' : 'rgba(124,255,160,0.7)',
              boxShadow: isLive ? '0 0 8px rgba(124,255,160,0.9)' : '0 0 4px rgba(124,255,160,0.3)',
              animation: isLive ? 'idle-pulse 1.5s infinite' : 'none',
            }}/>
            DEMO
          </div>
          <div style={{
            fontFamily: 'IBM Plex Mono, monospace',
            fontSize: '10px', letterSpacing: '0.20em',
            color: 'rgba(250,247,242,0.30)',
            textTransform: 'uppercase',
            cursor: 'default',
          }}>
            <span style={{ marginRight: '6px', opacity: 0.5 }}>·</span>CODE
          </div>
        </div>
        <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
          <span style={{
            fontFamily: 'IBM Plex Mono, monospace',
            fontSize: '10px', letterSpacing: '0.18em',
            color: 'rgba(250,247,242,0.45)',
            textTransform: 'uppercase',
          }}>
            {phase === 'idle' ? c.demo.ready
              : phase === 'live' ? c.demo.live
              : c.demo.ended}
          </span>
          <span className="tabular" style={{
            fontFamily: 'IBM Plex Mono, monospace',
            fontSize: '11px',
            color: 'rgba(250,247,242,0.55)',
          }}>{fmtTime(callTime)}</span>
        </div>
      </div>

      {/* Header strip — voice + industry context */}
      <div style={{
        position: 'relative',
        padding: '10px 18px 6px',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        fontFamily: 'IBM Plex Mono, monospace',
        fontSize: '10px',
        letterSpacing: '0.16em',
        textTransform: 'uppercase',
        color: 'rgba(250,247,242,0.45)',
      }}>
        <span>{c.demo.useCase}: <span style={{ color: 'rgba(250,247,242,0.85)' }}>{industryLabel}</span></span>
        <span>{c.demo.voice}: <span style={{ color: 'rgba(250,247,242,0.85)' }}>{voiceLabel}</span> · <span style={{ opacity: 0.7 }}>{voiceDesc}</span></span>
      </div>

      {/* Conversation area */}
      <div
        ref={scrollRef}
        className="thin-scroll"
        style={{
          position: 'relative',
          marginTop: '8px',
          flex: 1, minHeight: '320px',
          overflowY: 'auto',
          padding: '14px 22px 76px',
          display: 'flex', flexDirection: 'column', gap: '10px',
          opacity: showMock ? 0.55 : 1,
          transition: 'opacity 0.3s ease',
          zIndex: 2,
        }}
      >
        {list.map((m, i) => {
          const isUser = m.role === 'user';
          return (
            <div key={`${showMock ? 'mock' : 'live'}-${i}`} style={{
              alignSelf: isUser ? 'flex-end' : 'flex-start',
              maxWidth: '78%',
              display: 'flex', flexDirection: 'column',
              alignItems: isUser ? 'flex-end' : 'flex-start',
            }}>
              <div style={{
                fontFamily: 'IBM Plex Mono, monospace',
                fontSize: '9px',
                color: 'rgba(250,247,242,0.40)',
                marginBottom: '4px', letterSpacing: '0.20em',
                textTransform: 'uppercase',
                paddingLeft: isUser ? 0 : '4px',
                paddingRight: isUser ? '4px' : 0,
              }}>
                {isUser ? c.demo.caller : c.demo.ai}
              </div>
              <div style={{
                background: isUser
                  ? 'rgba(255,255,255,0.09)'
                  : 'rgba(255,140,80,0.14)',
                color: 'rgba(250,247,242,0.95)',
                padding: '12px 15px',
                borderRadius: isUser ? '12px 12px 3px 12px' : '12px 12px 12px 3px',
                fontSize: '13.5px',
                lineHeight: 1.55,
                letterSpacing: '-0.005em',
                border: isUser
                  ? '1px solid rgba(255,255,255,0.12)'
                  : '1px solid rgba(255,140,80,0.22)',
                backdropFilter: 'blur(2px)',
              }}>{m.text}</div>
            </div>
          );
        })}
        {isLive && currentSpeaker === 'ai' && (
          <div style={{
            alignSelf: 'flex-start',
            background: 'rgba(255,140,80,0.10)',
            border: '1px solid rgba(255,140,80,0.18)',
            padding: '12px 16px', borderRadius: '12px 12px 12px 3px',
          }}>
            <span className="typing-dot" style={{ background: 'rgba(255,170,110,0.95)' }}/>
            <span className="typing-dot" style={{ background: 'rgba(255,170,110,0.95)' }}/>
            <span className="typing-dot" style={{ background: 'rgba(255,170,110,0.95)' }}/>
          </div>
        )}
      </div>

      {/* Overlay CTA pill — anchored to BOTTOM */}
      {showMock && (
        <div aria-hidden style={{
          position: 'absolute',
          left: '50%',
          bottom: '20px',
          transform: 'translateX(-50%)',
          pointerEvents: 'none',
          zIndex: 3,
        }}>
          <div style={{
            background: 'rgba(8,8,10,0.85)',
            backdropFilter: 'blur(8px)',
            WebkitBackdropFilter: 'blur(8px)',
            color: 'rgba(250,247,242,0.95)',
            padding: '10px 18px',
            borderRadius: '999px',
            border: '1px solid rgba(255,140,80,0.35)',
            fontSize: '12px',
            fontFamily: 'IBM Plex Mono, monospace',
            letterSpacing: '0.10em',
            textTransform: 'uppercase',
            boxShadow: '0 4px 20px rgba(0,0,0,0.5), 0 0 24px rgba(255,106,44,0.15)',
            whiteSpace: 'nowrap',
          }}>
            {mockOverlay}
          </div>
        </div>
      )}

      {/* Brand mark in bottom-right corner */}
      <div aria-hidden style={{
        position: 'absolute',
        bottom: '14px',
        right: '16px',
        zIndex: 1,
        opacity: 0.35,
      }}>
        <svg width="22" height="22" viewBox="0 0 22 22" fill="none">
          <circle cx="11" cy="11" r="9.5" stroke="rgba(250,247,242,0.6)" strokeWidth="1"/>
          <path d="M 4 11 L 18 11" stroke="rgba(250,247,242,0.6)" strokeWidth="1" strokeLinecap="round"/>
        </svg>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────
// HardwareStartButton — dark recessed button with mic icon
// ──────────────────────────────────────────
function HardwareStartButton({ phase, onStart, onEnd, onReplay, onReset, copy, isLive }) {
  if (phase === 'live') {
    return (
      <button
        onClick={onEnd}
        style={{
          width: '100%',
          height: '64px',
          background: 'linear-gradient(180deg, #1e1e22 0%, #0e0e10 100%)',
          color: 'rgba(250,247,242,0.95)',
          border: '1px solid rgba(255,255,255,0.10)',
          borderRadius: '12px',
          fontFamily: 'IBM Plex Mono, monospace',
          fontWeight: 600,
          fontSize: '13px',
          letterSpacing: '0.20em',
          textTransform: 'uppercase',
          cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '12px',
          boxShadow: [
            'inset 0 1px 0 rgba(255,255,255,0.08)',
            'inset 0 -1px 0 rgba(0,0,0,0.5)',
            '0 4px 10px rgba(0,0,0,0.4)',
          ].join(', '),
        }}>
        <span style={{
          width: '10px', height: '10px', borderRadius: '2px',
          background: 'var(--color-signal)',
          boxShadow: '0 0 8px rgba(255,106,44,0.8)',
        }}/>
        {copy.end}
      </button>
    );
  }
  if (phase === 'done') {
    return (
      <div style={{ display: 'flex', gap: '10px' }}>
        <button onClick={onReplay} style={hardwareBtnStyle(false)}>
          <MicIcon />
          {copy.replay}
        </button>
        <button onClick={onReset} style={{ ...hardwareBtnStyle(true), flex: 'unset', width: '64px' }}>
          ↺
        </button>
      </div>
    );
  }
  return (
    <button
      onClick={onStart}
      style={hardwareBtnStyle(false)}
      onMouseEnter={e => {
        const dot = e.currentTarget.querySelector('[data-led]');
        if (dot) dot.style.boxShadow = '0 0 14px rgba(255,106,44,0.95)';
      }}
      onMouseLeave={e => {
        const dot = e.currentTarget.querySelector('[data-led]');
        if (dot) dot.style.boxShadow = '0 0 8px rgba(255,106,44,0.6)';
      }}
    >
      <MicIcon />
      <span style={{
        fontFamily: 'IBM Plex Mono, monospace',
        fontWeight: 600,
        fontSize: '13px',
        letterSpacing: '0.22em',
        textTransform: 'uppercase',
      }}>{copy.startShort || 'START'}</span>
      <span data-led aria-hidden style={{
        marginLeft: 'auto',
        width: '8px', height: '8px', borderRadius: '50%',
        background: 'var(--color-signal)',
        boxShadow: '0 0 8px rgba(255,106,44,0.6)',
        transition: 'box-shadow 0.2s ease',
      }}/>
    </button>
  );
}
function hardwareBtnStyle(square) {
  return {
    flex: 1,
    height: '64px',
    background: 'linear-gradient(180deg, #1e1e22 0%, #0e0e10 100%)',
    color: 'rgba(250,247,242,0.95)',
    border: '1px solid rgba(255,255,255,0.10)',
    borderRadius: '12px',
    cursor: 'pointer',
    display: 'flex', alignItems: 'center', justifyContent: square ? 'center' : 'flex-start',
    gap: '14px',
    padding: square ? '0' : '0 18px',
    fontFamily: 'IBM Plex Mono, monospace',
    fontSize: square ? '18px' : '13px',
    letterSpacing: '0.20em',
    textTransform: 'uppercase',
    boxShadow: [
      'inset 0 1px 0 rgba(255,255,255,0.08)',
      'inset 0 -1px 0 rgba(0,0,0,0.5)',
      '0 4px 10px rgba(0,0,0,0.4)',
    ].join(', '),
    transition: 'transform 0.12s ease',
  };
}
function MicIcon() {
  return (
    <svg width="14" height="18" viewBox="0 0 14 18" fill="none" aria-hidden>
      <rect x="4" y="1" width="6" height="10" rx="3" stroke="rgba(250,247,242,0.85)" strokeWidth="1.4"/>
      <path d="M 1 9 C 1 12.3 3.7 15 7 15 C 10.3 15 13 12.3 13 9" stroke="rgba(250,247,242,0.85)" strokeWidth="1.4" strokeLinecap="round" fill="none"/>
      <path d="M 7 15 L 7 17.5" stroke="rgba(250,247,242,0.85)" strokeWidth="1.4" strokeLinecap="round"/>
    </svg>
  );
}

// ──────────────────────────────────────────
// Live conversation scripts
// ──────────────────────────────────────────
const SCRIPTS = {
  ko: {
    dental: [
      { role: 'ai',   text: '안녕하세요, ○○치과입니다. AI 안내원이 응대 도와드립니다.', delay: 1800 },
      { role: 'user', text: '임플란트 가격이 얼마예요?', delay: 1500 },
      { role: 'ai',   text: '국산은 100만원부터, 수입산은 130만원부터입니다. 첫 진료 예약 도와드릴까요?', delay: 2200 },
      { role: 'user', text: '네, 토요일 가능한가요?', delay: 1500 },
      { role: 'ai',   text: '토요일 오전 10시 가능하세요. 성함 알려주시겠어요?', delay: 2000 },
      { role: 'user', text: '김민지입니다.', delay: 1200 },
      { role: 'ai',   text: '네 김민지님, 카카오톡으로 예약 확정 보내드리겠습니다. 감사합니다.', delay: 2200 },
    ],
    academy: [
      { role: 'ai',   text: '안녕하세요, ○○학원입니다. AI 안내원이 응대 도와드립니다.', delay: 1800 },
      { role: 'user', text: '중3 수학반 시간표 좀 알 수 있을까요?', delay: 1700 },
      { role: 'ai',   text: '심화반은 월·수·금 7시, 종합반은 화·목 8시입니다. 자녀분 성함 알려주시겠어요?', delay: 2300 },
      { role: 'user', text: '박지호, 중3이에요.', delay: 1300 },
      { role: 'ai',   text: '목요일 오후 6시 상담 가능하세요. 카카오톡으로 안내드리겠습니다.', delay: 2200 },
    ],
    tax: [
      { role: 'ai',   text: '안녕하세요, ○○세무사 사무실입니다.', delay: 1700 },
      { role: 'user', text: '간이과세자 부가세 신고 의뢰하려고 합니다.', delay: 1700 },
      { role: 'ai',   text: '네, 사업자등록번호 알려주시면 견적 안내드리겠습니다.', delay: 2200 },
      { role: 'user', text: '오늘 통화 가능한가요?', delay: 1300 },
      { role: 'ai',   text: '오후 4시 30분 세무사님과 통화 가능하세요. 카카오톡으로 안내드릴게요.', delay: 2300 },
    ],
    vet: [
      { role: 'ai',   text: '안녕하세요, ○○동물병원입니다. AI 안내원입니다.', delay: 1900 },
      { role: 'user', text: '강아지가 사료를 안 먹는데 진료 가능할까요?', delay: 1900 },
      { role: 'ai',   text: '네 보호자님, 오늘 오후 4시 30분 또는 5시 30분 가능하세요.', delay: 2200 },
      { role: 'user', text: '4시 30분으로 부탁드립니다.', delay: 1500 },
      { role: 'ai',   text: '카카오톡으로 예약 확정 보내드리겠습니다.', delay: 2000 },
    ],
    pension: [
      { role: 'ai',   text: '안녕하세요, ○○펜션입니다. AI 안내원이 응대 도와드립니다.', delay: 1800 },
      { role: 'user', text: '이번 주말 4인실 빈 방 있나요?', delay: 1500 },
      { role: 'ai',   text: '토요일 한 자리, 일요일 두 자리 가능하세요.', delay: 2000 },
      { role: 'user', text: '토요일로 예약할게요.', delay: 1300 },
      { role: 'ai',   text: '카카오톡으로 예약 확정 안내드리겠습니다. 감사합니다.', delay: 2200 },
    ],
  },
  en: {
    dental: [
      { role: 'ai',   text: 'Hello, this is ○○ Dental. You\'re speaking with our AI receptionist.', delay: 1900 },
      { role: 'user', text: 'How much is an implant?', delay: 1500 },
      { role: 'ai',   text: 'Domestic from ₩1M, imported from ₩1.3M. Shall I book your first visit?', delay: 2200 },
      { role: 'user', text: 'Yes, are Saturdays open?', delay: 1500 },
      { role: 'ai',   text: 'Saturday 10am works. May I have your name?', delay: 2000 },
      { role: 'user', text: 'Kim Minji.', delay: 1100 },
      { role: 'ai',   text: 'Confirmation will arrive via KakaoTalk shortly. Thank you.', delay: 2100 },
    ],
    academy: [
      { role: 'ai',   text: 'Hello, ○○ Academy — AI receptionist speaking.', delay: 1800 },
      { role: 'user', text: 'Could I get the 9th-grade math schedule?', delay: 1700 },
      { role: 'ai',   text: 'Advanced runs Mon/Wed/Fri 7pm, comprehensive Tue/Thu 8pm. Your child\'s name?', delay: 2300 },
      { role: 'user', text: 'Park Jiho, grade 9.', delay: 1200 },
      { role: 'ai',   text: 'Thursday 6pm consult works. I\'ll send details via KakaoTalk.', delay: 2200 },
    ],
    tax: [
      { role: 'ai',   text: 'Hello, ○○ Tax Office.', delay: 1600 },
      { role: 'user', text: 'I need help filing simplified-taxpayer VAT.', delay: 1700 },
      { role: 'ai',   text: 'Sure — please send your business reg number, we\'ll send a quote.', delay: 2200 },
      { role: 'user', text: 'Can I speak with the accountant today?', delay: 1500 },
      { role: 'ai',   text: 'The accountant is available at 4:30pm. I\'ll confirm via KakaoTalk.', delay: 2300 },
    ],
    vet: [
      { role: 'ai',   text: 'Hello, ○○ Vet — AI receptionist speaking.', delay: 1900 },
      { role: 'user', text: 'My dog won\'t eat — can we come in today?', delay: 1900 },
      { role: 'ai',   text: '4:30pm or 5:30pm are available this afternoon.', delay: 2100 },
      { role: 'user', text: '4:30pm, please.', delay: 1100 },
      { role: 'ai',   text: 'Confirmation will arrive via KakaoTalk shortly.', delay: 2000 },
    ],
    pension: [
      { role: 'ai',   text: 'Hello, ○○ Pension — AI receptionist speaking.', delay: 1800 },
      { role: 'user', text: 'Any 4-person rooms open this weekend?', delay: 1500 },
      { role: 'ai',   text: 'Saturday has one, Sunday has two open.', delay: 1900 },
      { role: 'user', text: 'I\'ll take Saturday.', delay: 1100 },
      { role: 'ai',   text: 'Confirmation will arrive via KakaoTalk. Thank you.', delay: 2100 },
    ],
  },
};

// ──────────────────────────────────────────
// DemoWidget
// ──────────────────────────────────────────
function DemoWidget({ industryId, setIndustryId, voice, setVoice }) {
  const [loc] = window.BD.useLocale();
  const c = window.BD.COPY[loc];

  // Demo only supports 5 industries (omakase excluded). Coerce.
  const demoIds = window.BD.DEMO_INDUSTRY_IDS;
  const effectiveId = demoIds.includes(industryId) ? industryId : demoIds[0];
  const industry = window.BD.localIndustry(effectiveId, loc);
  const setIndustryIdSafe = (id) => setIndustryId(id);

  const voiceObj = window.BD.VOICES.find(v => v.value === voice) || window.BD.VOICES[0];

  const [phase, setPhase] = useState('idle');
  const [messages, setMessages] = useState([]);
  const [currentSpeaker, setCurrentSpeaker] = useState(null);
  const [callTime, setCallTime] = useState(0);
  const timerRef = useRef(null);
  const scriptIdxRef = useRef(0);
  const stepTimerRef = useRef(null);
  const [viewportW, setViewportW] = useState(typeof window !== 'undefined' ? window.innerWidth : 1280);

  useEffect(() => {
    const onR = () => setViewportW(window.innerWidth);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);

  const startCall = () => {
    setPhase('live'); setMessages([]); setCallTime(0); scriptIdxRef.current = 0;
    timerRef.current = setInterval(() => setCallTime(t => t + 1), 1000);
    advance();
  };
  const advance = () => {
    const script = (SCRIPTS[loc] && SCRIPTS[loc][effectiveId]) || SCRIPTS[loc].dental;
    const i = scriptIdxRef.current;
    if (i >= script.length) { endCall(); return; }
    const step = script[i];
    setCurrentSpeaker(step.role);
    stepTimerRef.current = setTimeout(() => {
      setMessages(prev => [...prev, { id: `${Date.now()}-${i}`, role: step.role, text: step.text, ts: Date.now() }]);
      scriptIdxRef.current = i + 1;
      stepTimerRef.current = setTimeout(advance, 600);
    }, step.delay);
  };
  const endCall = () => { setPhase('done'); setCurrentSpeaker(null); if (timerRef.current) clearInterval(timerRef.current); };
  const reset = () => {
    setPhase('idle'); setMessages([]); setCallTime(0); setCurrentSpeaker(null);
    if (timerRef.current) clearInterval(timerRef.current);
    if (stepTimerRef.current) clearTimeout(stepTimerRef.current);
  };
  useEffect(() => () => {
    if (timerRef.current) clearInterval(timerRef.current);
    if (stepTimerRef.current) clearTimeout(stepTimerRef.current);
  }, []);
  useEffect(() => { reset(); /* eslint-disable-next-line */ }, [effectiveId, voice, loc]);

  const isLive = phase === 'live';

  const industryOptions = demoIds.map(id => {
    const ind = window.BD.localIndustry(id, loc);
    return { value: id, label: ind.label };
  });
  const voiceOptions = window.BD.VOICES.map(v => ({ value: v.value, label: v[loc].name }));
  const mockList = (window.BD.MOCK_CONVOS[loc] && window.BD.MOCK_CONVOS[loc][effectiveId]) || window.BD.MOCK_CONVOS[loc].dental;

  const isNarrow = viewportW < 1024;

  return (
    <Section id="demo" bg="ivory" style={{ paddingTop: '96px' }}>
      <SectionHeader eyebrow={c.demo.eyebrow} title={c.demo.title} subtitle={c.demo.sub} />

      {/* Disclosure ABOVE container, charcoal/50 */}
      <div style={{
        maxWidth: '768px', margin: '0 auto 24px', padding: '12px 16px',
        textAlign: 'center', fontSize: '14px', lineHeight: 1.55,
        color: 'rgba(26,26,26,0.5)',
      }}>
        {c.demo.disclosure}
      </div>

      {/* HARDWARE BEZEL — deep near-black with inner bevel + speaker grille up top */}
      <div style={{
        position: 'relative',
        background: 'radial-gradient(ellipse at top, #1a1a1d 0%, #0d0d0f 60%, #050506 100%)',
        color: 'var(--color-ivory)',
        borderRadius: '24px',
        padding: isNarrow ? '20px 18px' : '28px',
        overflow: 'hidden',
        // Outer drop + inner bevel: bright top edge, dark bottom edge, soft inner shadow
        boxShadow: [
          '0 30px 60px rgba(0,0,0,0.45)',
          '0 8px 20px rgba(0,0,0,0.35)',
          'inset 0 1px 0 rgba(255,255,255,0.08)',
          'inset 0 -1px 0 rgba(0,0,0,0.6)',
          'inset 0 0 0 1px rgba(255,255,255,0.03)',
        ].join(', '),
      }}>
        {/* Speaker grille — dotted texture across top */}
        <div aria-hidden style={{
          position: 'absolute', top: 0, left: 0, right: 0,
          height: '60px',
          backgroundImage: 'radial-gradient(rgba(255,255,255,0.10) 1px, transparent 1.2px)',
          backgroundSize: '6px 6px',
          backgroundPosition: '3px 3px',
          maskImage: 'linear-gradient(180deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.5) 60%, transparent 100%)',
          WebkitMaskImage: 'linear-gradient(180deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.5) 60%, transparent 100%)',
          pointerEvents: 'none',
        }}/>

        {/* DESKTOP: 2-column hardware layout — CONTROLS (left) | SCREEN (right) */}
        {!isNarrow && (
          <div style={{
            position: 'relative',
            paddingTop: '40px',  /* breathing room under speaker grille */
            display: 'grid',
            gridTemplateColumns: 'minmax(320px, 0.7fr) 1fr',
            columnGap: '36px',
            alignItems: 'stretch',
            minHeight: '540px',
          }}>
            {/* LEFT — Controls panel */}
            <div style={{
              display: 'flex', flexDirection: 'column',
              gap: '24px',
            }}>
              {/* Sliders row */}
              <div style={{
                display: 'grid',
                gridTemplateColumns: '1fr 1fr',
                gap: '20px',
                flex: 1,
              }}>
                <VerticalRadioSlider
                  label={c.demo.useCase}
                  options={industryOptions}
                  value={effectiveId}
                  onChange={setIndustryIdSafe}
                  ariaLabel={c.demo.useCase}
                  side="right"
                  fillHeight
                  totalHeight={420}
                />
                <VerticalRadioSlider
                  label={c.demo.voice}
                  options={voiceOptions}
                  value={voice}
                  onChange={setVoice}
                  ariaLabel={c.demo.voice}
                  side="right"
                  fillHeight
                  totalHeight={420}
                />
              </div>

              {/* START button — hardware play button, dark with mic icon */}
              <HardwareStartButton
                phase={phase}
                onStart={startCall}
                onEnd={endCall}
                onReplay={startCall}
                onReset={reset}
                copy={c.demo}
                isLive={isLive}
              />
            </div>

            {/* RIGHT — Screen */}
            <ScreenPane
              messages={messages}
              isLive={isLive}
              currentSpeaker={currentSpeaker}
              mockMessages={mockList}
              mockOverlay={c.demo.mockOverlay}
              loc={loc}
              phase={phase}
              callTime={callTime}
              voiceLabel={voiceObj[loc].name}
              voiceDesc={voiceObj[loc].desc}
              industryLabel={industry.label}
            />
          </div>
        )}

        {/* MOBILE: stacked */}
        {isNarrow && (
          <div style={{
            position: 'relative',
            paddingTop: '36px',
            display: 'flex', flexDirection: 'column',
            gap: '20px',
          }}>
            <ScreenPane
              messages={messages}
              isLive={isLive}
              currentSpeaker={currentSpeaker}
              mockMessages={mockList}
              mockOverlay={c.demo.mockOverlay}
              loc={loc}
              phase={phase}
              callTime={callTime}
              voiceLabel={voiceObj[loc].name}
              voiceDesc={voiceObj[loc].desc}
              industryLabel={industry.label}
            />
            <HorizontalPillRow
              label={c.demo.useCase}
              options={industryOptions}
              value={effectiveId}
              onChange={setIndustryIdSafe}
            />
            <HorizontalPillRow
              label={c.demo.voice}
              options={voiceOptions}
              value={voice}
              onChange={setVoice}
            />
            <HardwareStartButton
              phase={phase}
              onStart={startCall}
              onEnd={endCall}
              onReplay={startCall}
              onReset={reset}
              copy={c.demo}
              isLive={isLive}
            />
          </div>
        )}
      </div>

      {/* Booking confirmation card */}
      {phase === 'done' && (
        <div style={{
          marginTop: '20px', padding: '20px 24px',
          background: 'rgba(184,197,166,0.18)',
          border: '1px solid rgba(184,197,166,0.4)',
          borderRadius: '16px',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          flexWrap: 'wrap', gap: '16px',
          color: 'var(--color-charcoal)',
        }}>
          <div>
            <Badge variant="sage">{c.demo.bookingConfirmed}</Badge>
            <div style={{ marginTop: '8px', fontSize: '15px', lineHeight: 1.5 }}>{c.demo.summary}</div>
          </div>
          <div className="tabular" style={{ fontSize: '14px', opacity: 0.6 }}>
            {c.demo.sentAt(new Date().toLocaleTimeString(loc === 'ko' ? 'ko-KR' : 'en-US'))}
          </div>
        </div>
      )}
    </Section>
  );
}

Object.assign(window, { DemoWidget });
