// translation.jsx — Fire Lingo Face-to-Face live translation screen
// Walkie-talkie model. Utterance lifecycle per speaker:
//   idle → listening (while held) → processing → translating → idle
// Transcript OFF by default — toggle in the status-card corner.

function TranslationScreen({ language, onBack, onFinish, brand }) {
  const lang = language || LANGUAGES[0];
  const rtl = lang.script === 'rtl';

  const [arriving, setArriving] = React.useState(true);

  // Per-speaker phase: 'idle' | 'listening' | 'processing' | 'translating'
  // (employeePhase retained internally so the AI can flip the active speaker)
  const [memberPhase, setMemberPhase] = React.useState('idle');
  const [employeePhase, setEmployeePhase] = React.useState('idle');

  // Which side the AI thinks is currently speaking (alternates by utterance)
  const turnRef = React.useRef('member');

  // Last completed transcript (mock). Cleared on new utterance start.
  const [lastTranscript, setLastTranscript] = React.useState(null);
  // { speaker: 'member'|'employee', source: string, translated: string, at: number }

  // Transcript visible to employee? OFF by default.
  const [transcriptOn, setTranscriptOn] = React.useState(false);

  // Live audio level while listening (for reactive animation)
  const [memberLevel, setMemberLevel] = React.useState(0);
  const [employeeLevel, setEmployeeLevel] = React.useState(0);

  // Mock utterances — cycle so repeated taps feel realistic
  const MEMBER_UTTERANCES = [
    { source: 'Hola, quiero hablar de mi préstamo de auto. Me preocupa que la tasa de interés sea más alta de lo que esperaba, y quisiera entender todas mis opciones antes de decidir qué hacer.', translated: 'Hi, I\u2019d like to talk about my auto loan. I\u2019m worried that the interest rate is higher than I expected, and I\u2019d like to understand all of my options before deciding what to do.' },
    { source: '¿Cuál es el saldo actual, por favor?',        translated: 'What\u2019s the current balance, please?' },
    { source: 'Gracias por su ayuda.',                        translated: 'Thank you for your help.' },
  ];
  const EMPLOYEE_UTTERANCES = [
    { source: 'Of course — I can pull up your account right now and walk you through the current rate, your remaining balance, and a couple of refinancing options that might lower your monthly payment.', translated: 'Por supuesto — puedo abrir su cuenta ahora mismo y explicarle la tasa actual, el saldo restante y algunas opciones de refinanciamiento que podrían reducir su pago mensual.' },
    { source: 'Your current balance is three thousand four hundred.', translated: 'Su saldo actual es de tres mil cuatrocientos.' },
    { source: 'Happy to help — have a great day.',                    translated: 'Con gusto — que tenga un buen día.' },
  ];
  const memberIdxRef = React.useRef(0);
  const employeeIdxRef = React.useRef(0);

  React.useEffect(() => {
    const t = setTimeout(() => setArriving(false), 900);
    return () => clearTimeout(t);
  }, []);

  // Audio-level simulation — runs while either side is listening
  React.useEffect(() => {
    const active = memberPhase === 'listening' || employeePhase === 'listening';
    if (!active) { setMemberLevel(0); setEmployeeLevel(0); return; }
    let raf; let last = performance.now();
    const tick = (now) => {
      const dt = now - last; last = now;
      const step = (l) => {
        const target = 0.55 + 0.35 * Math.sin(now / 230) + (Math.random() - 0.5) * 0.4;
        return Math.max(0.14, Math.min(1, l + (target - l) * (dt / 90)));
      };
      if (memberPhase === 'listening')   setMemberLevel(step);   else setMemberLevel(0);
      if (employeePhase === 'listening') setEmployeeLevel(step); else setEmployeeLevel(0);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [memberPhase, employeePhase]);

  // Run processing → translating → done pipeline after a release
  const runPipeline = React.useCallback((speaker, utterance) => {
    const setPhase = speaker === 'member' ? setMemberPhase : setEmployeePhase;
    setPhase('processing');
    setTimeout(() => {
      setPhase('translating');
      setTimeout(() => {
        setPhase('idle');
        setLastTranscript({ speaker, ...utterance, at: Date.now() });
      }, 1400);
    }, 1100);
  }, []);

  // Member press handlers — single button serves both speakers (AI detects language)
  const memberDown = (e) => {
    e.preventDefault();
    if (memberPhase !== 'idle' || employeePhase !== 'idle') return;
    setLastTranscript(null);
    // Alternate turns so the demo shows both directions
    if (turnRef.current === 'member') setMemberPhase('listening');
    else                              setEmployeePhase('listening');
  };
  const memberUp = (e) => {
    e.preventDefault();
    if (memberPhase === 'listening') {
      const u = MEMBER_UTTERANCES[memberIdxRef.current % MEMBER_UTTERANCES.length];
      memberIdxRef.current += 1;
      runPipeline('member', u);
      turnRef.current = 'employee';
    } else if (employeePhase === 'listening') {
      const u = EMPLOYEE_UTTERANCES[employeeIdxRef.current % EMPLOYEE_UTTERANCES.length];
      employeeIdxRef.current += 1;
      runPipeline('employee', u);
      turnRef.current = 'member';
    }
  };

  const nativeFont =
    lang.script === 'cjk' ? '"Noto Sans SC", "Noto Sans KR", system-ui' :
    lang.script === 'devanagari' ? '"Noto Sans Devanagari", var(--font-display)' :
    lang.script === 'rtl' ? '"Noto Naskh Arabic", var(--font-display)' :
    'var(--font-display)';

  // Localized hold / release labels for the big member button
  const btnLabels = {
    es: { hold: 'Mantén presionado', release: 'Habla ahora' },
    zh: { hold: '按住说话',           release: '正在聆听' },
    vi: { hold: 'Nhấn giữ',           release: 'Đang nghe' },
    ko: { hold: '길게 누르세요',       release: '듣는 중' },
    ht: { hold: 'Kenbe peze',         release: 'N ap koute' },
    ar: { hold: 'اضغط مع الاستمرار',  release: 'نستمع الآن' },
    fr: { hold: 'Maintenir appuyé',   release: 'Parlez' },
    pt: { hold: 'Toque e segure',     release: 'A ouvir' },
    ru: { hold: 'Нажмите и держите',  release: 'Слушаю' },
    hi: { hold: 'दबाकर रखें',          release: 'सुन रहे हैं' },
    tl: { hold: 'Pindutin at hawakan',release: 'Nakikinig' },
    sw: { hold: 'Bonyeza na ushikilie',release: 'Tunasikiliza' },
  };
  const btn = btnLabels[lang.code] || btnLabels.es;

  const memberSpeaking = memberPhase === 'listening' || employeePhase === 'listening';

  return (
    <div style={{
      width: '100%', height: '100%', display: 'flex',
      background: 'linear-gradient(180deg, var(--td-navy) 0%, var(--td-navy) 55%, var(--td-blue-600) 100%)',
      color: '#fff', position: 'relative', overflow: 'hidden',
    }}>
      {/* ambient dots */}
      <div style={{
        position: 'absolute', inset: 0, opacity: 0.08,
        backgroundImage: 'radial-gradient(circle, #fff 1px, transparent 1px)',
        backgroundSize: '32px 32px',
      }} />

      {/* ==================== Member side ==================== */}
      <div style={{
        flex: 1.4, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: '24px 40px 32px', position: 'relative', zIndex: 1,
        direction: rtl ? 'rtl' : 'ltr',
      }}>
        {brand && brand.useDefaultMark === false ? (
          // White-labeled customer: render their logo. Sized to match the
          // visual weight of the default BrandMark (~64px tall) so the header
          // doesn't look orphaned above the greeting. Wide logos get a wider
          // chip; square-ish marks stay compact.
          <div style={{
            height: 64,
            width: brand.logoAspect === 'wide' ? 'auto' : 'auto',
            maxWidth: brand.logoAspect === 'wide' ? 280 : 200,
            minWidth: brand.logoAspect === 'wide' ? 200 : 64,
            padding: brand.logoAspect === 'wide' ? '10px 22px' : '10px 14px',
            borderRadius: 'var(--radius-md)',
            background: 'rgba(255,255,255,0.10)',
            border: '1px solid rgba(255,255,255,0.18)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            transform: `scale(${memberSpeaking ? 1.04 : 1})`,
            transition: 'transform 220ms var(--ease-out)',
          }}>
            <img src={brand.logoWhite} alt={brand.name} style={{
              height: '100%', width: 'auto', maxWidth: '100%', objectFit: 'contain',
              display: 'block',
            }} />
          </div>
        ) : (
          <BrandMark size={44} pulse={memberSpeaking} tone="dark" />
        )}

        <div style={{
          marginTop: 10,
          fontFamily: nativeFont, fontSize: 34, fontWeight: 800,
          letterSpacing: lang.script === 'cjk' ? 0 : '-0.02em',
          lineHeight: 1.1, textAlign: 'center', color: '#fff',
          opacity: arriving ? 0 : 1,
          transform: arriving ? 'translateY(12px)' : 'translateY(0)',
          transition: 'all 600ms var(--ease-out) 150ms',
        }}>
          {lang.greeting}
        </div>

        <div style={{
          marginTop: 8, maxWidth: 560,
          fontFamily: nativeFont, fontSize: 19, fontWeight: 500,
          color: 'rgba(255,255,255,0.85)', textAlign: 'center',
          lineHeight: 1.35, textWrap: 'balance',
          opacity: arriving ? 0 : 1,
          transform: arriving ? 'translateY(12px)' : 'translateY(0)',
          transition: 'all 600ms var(--ease-out) 280ms',
        }}>
          {lang.listening}
        </div>

        {/* Big push-to-talk button */}
        <div style={{
          marginTop: 24, position: 'relative',
          width: 440, height: 440, flexShrink: 0,
          opacity: arriving ? 0 : 1,
          transition: 'opacity 500ms var(--ease-out) 420ms',
        }}>
          {memberSpeaking && (
            <>
              <div style={{
                position: 'absolute', inset: 0, borderRadius: 9999,
                background: 'radial-gradient(circle, rgba(70,137,200,0.35) 45%, rgba(70,137,200,0) 58%)',
                transform: `scale(${1 + memberLevel * 0.08})`,
                transition: 'transform 120ms var(--ease-out)',
                pointerEvents: 'none',
              }} />
              <div style={{
                position: 'absolute', inset: 6, borderRadius: 9999,
                border: '2px solid rgba(120,168,214,0.55)',
                transform: `scale(${1 + memberLevel * 0.05})`,
                transition: 'transform 90ms var(--ease-out)',
                pointerEvents: 'none',
              }} />
            </>
          )}

          <button
            onPointerDown={memberDown}
            onPointerUp={memberUp}
            onPointerLeave={memberUp}
            onPointerCancel={memberUp}
            disabled={employeePhase !== 'idle'}
            style={{
              position: 'absolute', inset: 0, borderRadius: 9999,
              border: 'none',
              cursor: employeePhase !== 'idle' ? 'not-allowed' : 'pointer',
              background: memberSpeaking
                ? 'radial-gradient(circle at 30% 30%, #e27a3f 0%, var(--td-orange) 60%, #a64d1e 100%)'
                : 'radial-gradient(circle at 30% 30%, var(--td-blue-300) 0%, var(--td-blue) 55%, var(--td-blue-600) 100%)',
              boxShadow: memberSpeaking
                ? '0 20px 50px rgba(207,99,40,0.45), inset 0 -6px 16px rgba(0,0,0,0.18), inset 0 4px 10px rgba(255,255,255,0.25)'
                : '0 20px 50px rgba(70,137,200,0.35), inset 0 -6px 16px rgba(0,0,0,0.18), inset 0 4px 10px rgba(255,255,255,0.25)',
              transform: memberSpeaking ? 'translateY(2px)' : 'translateY(0)',
              transition: 'background 200ms var(--ease-out), box-shadow 200ms var(--ease-out), transform 120ms var(--ease-out)',
              WebkitTapHighlightColor: 'transparent',
              touchAction: 'none', outline: 'none',
              opacity: employeePhase !== 'idle' ? 0.55 : 1,
            }}>
            <svg width="136" height="136" viewBox="0 0 24 24" fill="none"
              stroke="#fff" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"
              style={{ filter: 'drop-shadow(0 3px 6px rgba(0,0,0,0.3))' }}>
              <rect x="9" y="2" width="6" height="12" rx="3" fill="rgba(255,255,255,0.22)"/>
              <path d="M5 11a7 7 0 0 0 14 0"/>
              <path d="M12 18v3M9 21h6"/>
            </svg>
          </button>
        </div>

        {/* Button label — localized */}
        <div style={{
          marginTop: 14,
          fontFamily: nativeFont, fontSize: 24, fontWeight: 800,
          letterSpacing: lang.script === 'cjk' ? 0 : '-0.01em',
          color: memberSpeaking ? '#ffd4b7' : '#fff',
          transition: 'color 200ms var(--ease-out)',
          display: 'flex', alignItems: 'center', gap: 12, textAlign: 'center',
        }}>
          {memberSpeaking && <span style={{
            width: 14, height: 14, borderRadius: 999,
            background: 'var(--td-orange)',
            boxShadow: '0 0 0 5px rgba(207,99,40,0.25)',
            animation: 'fl-live-pulse 1.4s var(--ease-in-out) infinite',
          }} />}
          {memberSpeaking ? btn.release : btn.hold}
        </div>
      </div>

      {/* ==================== Employee side ==================== */}
      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        background: 'rgba(255,255,255,0.05)',
        borderLeft: '1px solid rgba(255,255,255,0.1)',
        padding: '32px 36px', position: 'relative', zIndex: 1,
      }}>
        <div className="eyebrow" style={{
          fontSize: 10, fontWeight: 700, textTransform: 'uppercase',
          letterSpacing: '0.18em', color: 'rgba(255,255,255,0.55)',
          fontFamily: 'var(--font-sans)',
        }}>
          Employee view — English
        </div>

        <div style={{
          marginTop: 12,
          fontFamily: 'var(--font-display)', fontSize: 32, fontWeight: 800,
          letterSpacing: '-0.02em', lineHeight: 1.15,
        }}>
          Connected in <span style={{ color: 'var(--td-blue-300)' }}>{lang.english}</span>
        </div>

        <div style={{
          marginTop: 10,
          fontFamily: 'var(--font-sans)', fontSize: 14, fontWeight: 500,
          color: 'rgba(255,255,255,0.7)', lineHeight: 1.5, maxWidth: 360,
        }}>
          Either of you taps and holds the big button to speak — Fire Lingo detects your language automatically.
        </div>

        {/* Status card — lifecycle + transcript toggle */}
        <StatusCard
          memberPhase={memberPhase}
          employeePhase={employeePhase}
          memberLevel={memberLevel}
          employeeLevel={employeeLevel}
          lang={lang}
          transcriptOn={transcriptOn}
          setTranscriptOn={setTranscriptOn}
          lastTranscript={lastTranscript}
        />

        {/* Finish-session — big, prominent. Tapping triggers feedback flow. */}
        <button
          onClick={() => (onFinish || onBack)()}
          disabled={memberPhase !== 'idle' || employeePhase !== 'idle'}
          style={{
            marginTop: 18, width: '100%',
            minHeight: 128, padding: '24px 22px',
            background: 'linear-gradient(180deg, var(--td-blue-300) 0%, var(--td-blue) 55%, var(--td-blue-600) 100%)',
            color: '#fff', border: 'none', borderRadius: 'var(--radius-lg)',
            fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 800,
            letterSpacing: '-0.01em',
            cursor: (memberPhase !== 'idle' || employeePhase !== 'idle') ? 'not-allowed' : 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 14,
            boxShadow: '0 12px 28px rgba(37,100,152,0.4), inset 0 -4px 10px rgba(0,0,0,0.2), inset 0 2px 4px rgba(255,255,255,0.18)',
            opacity: (memberPhase !== 'idle' || employeePhase !== 'idle') ? 0.5 : 1,
            transition: 'all 180ms var(--ease-out)',
            WebkitTapHighlightColor: 'transparent',
          }}>
          <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"
            style={{ filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.25))' }}>
            <path d="M20 6 9 17l-5-5"/>
          </svg>
          Finish serving member
        </button>

        {/* Mode footer */}
        <div style={{
          marginTop: 'auto', paddingTop: 14,
          fontFamily: 'var(--font-sans)', fontSize: 12,
          color: 'rgba(255,255,255,0.45)', textAlign: 'center',
        }}>
          Fire Lingo mode: <strong style={{ color: 'rgba(255,255,255,0.78)' }}>Turn-based</strong>
        </div>
      </div>
    </div>
  );
}

// ------- Status card ----------------------------------------------------

function StatusCard({ memberPhase, employeePhase, memberLevel, employeeLevel, lang, transcriptOn, setTranscriptOn, lastTranscript }) {
  // Determine the active speaker / phase to display
  const activeSpeaker =
    memberPhase !== 'idle' ? 'member' :
    employeePhase !== 'idle' ? 'employee' : null;
  const phase = activeSpeaker === 'member' ? memberPhase
              : activeSpeaker === 'employee' ? employeePhase
              : 'idle';
  const level = activeSpeaker === 'member' ? memberLevel
              : activeSpeaker === 'employee' ? employeeLevel
              : 0;

  // Header tone
  const tone =
    phase === 'listening'   ? { bg: 'rgba(70,137,200,0.18)', border: 'rgba(120,168,214,0.45)', eyebrow: '#fff',               dot: '#fff' } :
    phase === 'processing'  ? { bg: 'rgba(255,255,255,0.08)', border: 'rgba(255,255,255,0.18)', eyebrow: 'rgba(255,255,255,0.8)', dot: 'rgba(255,255,255,0.7)' } :
    phase === 'translating' ? { bg: 'rgba(207,99,40,0.14)',  border: 'rgba(207,99,40,0.45)',   eyebrow: '#ffd4b7',            dot: 'var(--td-orange)' } :
                              { bg: 'rgba(255,255,255,0.07)', border: 'rgba(255,255,255,0.12)', eyebrow: 'var(--td-blue-300)', dot: 'var(--td-blue-300)' };

  const eyebrowLabel =
    activeSpeaker === 'member'   && phase === 'listening'   ? `${lang.native} speaking` :
    activeSpeaker === 'employee' && phase === 'listening'   ? 'English speaking' :
    phase === 'processing'  ? 'Processing' :
    phase === 'translating' ? 'Translating' :
                              'Member idle';

  // Main body copy per phase
  let body;
  if (phase === 'listening') {
    body = activeSpeaker === 'member'
      ? `Listening to ${lang.english}…`
      : 'Listening to English…';
  } else if (phase === 'processing') {
    body = 'Processing — please wait.';
  } else if (phase === 'translating') {
    body = activeSpeaker === 'member'
      ? `Translating into English…`
      : `Translating into ${lang.english}…`;
  } else {
    body = 'Waiting for the member to press and hold their button.';
  }

  return (
    <div style={{
      marginTop: 24, padding: 20,
      background: tone.bg,
      border: `1px solid ${tone.border}`,
      borderRadius: 'var(--radius-lg)',
      transition: 'background 220ms var(--ease-out), border-color 220ms var(--ease-out)',
      position: 'relative',
      flex: 1, minHeight: 360,
      display: 'flex', flexDirection: 'column',
      overflow: 'hidden',
    }}>
      {/* Header row: status eyebrow + transcript toggle */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flex: 1, minWidth: 0 }}>
          <span style={{
            width: 8, height: 8, borderRadius: 999,
            background: tone.dot,
            boxShadow: phase === 'listening' ? `0 0 0 4px ${tone.dot}33` : 'none',
            animation: phase === 'processing' || phase === 'translating'
              ? 'fl-live-pulse 1.2s var(--ease-in-out) infinite' : 'none',
          }} />
          <div style={{
            fontFamily: 'var(--font-sans)', fontSize: 12, fontWeight: 700,
            textTransform: 'uppercase', letterSpacing: '0.12em',
            color: tone.eyebrow,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          }}>
            {eyebrowLabel}
          </div>
        </div>
        <TranscriptToggle on={transcriptOn} onChange={setTranscriptOn} />
      </div>

      {/* Body copy */}
      <div style={{
        marginTop: 12, fontFamily: 'var(--font-display)',
        fontSize: 18, fontWeight: 600, color: 'rgba(255,255,255,0.92)', lineHeight: 1.4,
      }}>
        {body}
      </div>

      {/* Level bars (only while listening) */}
      <div style={{
        marginTop: 14, display: 'flex', alignItems: 'flex-end', gap: 4, height: 32,
        opacity: phase === 'listening' ? 1 : 0.18,
        transition: 'opacity 220ms var(--ease-out)',
      }}>
        {Array.from({ length: 22 }).map((_, i) => {
          const phaseShift = (Math.sin((i / 22) * Math.PI * 2 + performance.now() / 300) + 1) / 2;
          const h = phase === 'listening' ? 6 + phaseShift * level * 26 : 4;
          return (
            <div key={i} style={{
              flex: 1, height: h, borderRadius: 2,
              background: phase === 'listening'
                ? (activeSpeaker === 'employee'
                  ? 'linear-gradient(180deg, #ffd4b7, var(--td-orange))'
                  : 'linear-gradient(180deg, var(--td-blue-300), var(--td-blue))')
                : 'rgba(255,255,255,0.15)',
              transition: 'height 80ms var(--ease-out)',
            }} />
          );
        })}
      </div>

      {/* Processing progress indicator */}
      {(phase === 'processing' || phase === 'translating') && (
        <ProcessingBar phase={phase} />
      )}

      {/* Transcript area — takes the remaining height and scrolls for very long utterances. */}
      <div className="fl-transcript-scroll" style={{
        marginTop: 14, flex: 1, minHeight: 0,
        overflowY: 'auto', overflowX: 'hidden',
        WebkitOverflowScrolling: 'touch',
      }}>
        {transcriptOn && lastTranscript && phase === 'idle'
          ? <TranscriptBlock tx={lastTranscript} lang={lang} />
          : <TranscriptPlaceholder transcriptOn={transcriptOn} phase={phase} />}
      </div>
    </div>
  );
}

function TranscriptPlaceholder({ transcriptOn, phase }) {
  if (!transcriptOn) {
    return (
      <div style={{
        height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexDirection: 'column', gap: 8, padding: '8px 20px',
        color: 'rgba(255,255,255,0.35)',
        fontFamily: 'var(--font-sans)', fontSize: 12, textAlign: 'center',
        lineHeight: 1.5,
      }}>
        <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.7 }}>
          <path d="M4 6h16M4 12h16M4 18h10"/>
        </svg>
        Transcript is off. Turn it on to see each translation after it plays.
      </div>
    );
  }
  if (phase !== 'idle') return null;
  return (
    <div style={{
      height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: 'rgba(255,255,255,0.32)',
      fontFamily: 'var(--font-sans)', fontSize: 12, textAlign: 'center', padding: '0 16px',
    }}>
      Transcript will appear here once the first translation finishes.
    </div>
  );
}

function TranscriptToggle({ on, onChange }) {
  return (
    <button
      onClick={() => onChange(!on)}
      style={{
        display: 'flex', alignItems: 'center', gap: 6,
        padding: '5px 9px 5px 7px',
        background: on ? 'rgba(70,137,200,0.25)' : 'rgba(255,255,255,0.06)',
        border: `1px solid ${on ? 'rgba(120,168,214,0.5)' : 'rgba(255,255,255,0.15)'}`,
        borderRadius: 999,
        fontFamily: 'var(--font-sans)', fontSize: 10, fontWeight: 700,
        letterSpacing: '0.1em', textTransform: 'uppercase',
        color: on ? '#fff' : 'rgba(255,255,255,0.65)',
        cursor: 'pointer', transition: 'all 160ms var(--ease-out)',
        WebkitTapHighlightColor: 'transparent',
      }}
      aria-pressed={on}
      title={on ? 'Hide transcript' : 'Show transcript after each translation'}
    >
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M4 6h16M4 12h16M4 18h10"/>
      </svg>
      Transcript · {on ? 'On' : 'Off'}
    </button>
  );
}

function ProcessingBar({ phase }) {
  // Indeterminate bar that slides across
  return (
    <div style={{
      marginTop: 12, height: 3, width: '100%', borderRadius: 999,
      background: 'rgba(255,255,255,0.1)', overflow: 'hidden', position: 'relative',
    }}>
      <div style={{
        position: 'absolute', top: 0, bottom: 0,
        width: '40%',
        background: phase === 'translating'
          ? 'linear-gradient(90deg, transparent, var(--td-orange), transparent)'
          : 'linear-gradient(90deg, transparent, var(--td-blue-300), transparent)',
        animation: 'fl-indet 1.4s linear infinite',
      }} />
    </div>
  );
}

function TranscriptBlock({ tx, lang }) {
  const isMember = tx.speaker === 'member';
  return (
    <div style={{
      fontFamily: 'var(--font-sans)',
      animation: 'fl-fade-in 300ms var(--ease-out) both',
    }}>
      <div style={{
        fontSize: 10, fontWeight: 700, textTransform: 'uppercase',
        letterSpacing: '0.14em', color: 'rgba(255,255,255,0.5)',
        marginBottom: 8,
        display: 'flex', alignItems: 'center', gap: 6,
      }}>
        <span style={{
          width: 6, height: 6, borderRadius: 999,
          background: isMember ? 'var(--td-blue-300)' : 'var(--td-orange)',
        }} />
        {isMember ? `${lang.native} → English` : `English → ${lang.english}`}
      </div>
      <div style={{
        fontSize: 14, fontWeight: 500, lineHeight: 1.5,
        color: 'rgba(255,255,255,0.62)',
        fontStyle: 'italic',
      }}>
        “{tx.source}”
      </div>
      <div style={{
        marginTop: 10,
        fontFamily: 'var(--font-display)',
        fontSize: 17, fontWeight: 600, lineHeight: 1.45,
        color: '#fff',
        letterSpacing: '-0.005em',
      }}>
        {tx.translated}
      </div>
    </div>
  );
}

Object.assign(window, { TranslationScreen });
