// demo-phone.jsx — PocketPolyglot interactive landing demo
// Speech-free: learn the one missing word → the phrase unlocks.
// Target phrase: "Es dzeru kafiju." (I drink coffee) — Es ✓ · dzeru (new) · kafiju ✓
// Renders the real app vocabulary (kit.jsx) inside the real iOS frame (ios-frame.jsx).

// soft two-note unlock chime (UI sound — not speech)
function demoChime() {
  try {
    const Ctx = window.AudioContext || window.webkitAudioContext;
    if (!Ctx) return;
    const ctx = new Ctx();
    const t0 = ctx.currentTime;
    [[659.3, 0], [987.8, 0.14]].forEach(([f, d]) => {
      const o = ctx.createOscillator(), g = ctx.createGain();
      o.type = 'sine'; o.frequency.value = f;
      g.gain.setValueAtTime(0, t0 + d);
      g.gain.linearRampToValueAtTime(0.05, t0 + d + 0.02);
      g.gain.exponentialRampToValueAtTime(0.0001, t0 + d + 1.0);
      o.connect(g); g.connect(ctx.destination);
      o.start(t0 + d); o.stop(t0 + d + 1.1);
    });
  } catch (e) { /* audio may be blocked — silent is fine */ }
}

// real-audio playback with a live analyser. Plays an mp3 and exposes an
// AnalyserNode so a visualizer can read the actual amplitude as it sounds —
// no per-voice pre-rendering. `played` (0→1) is also tracked for progress.
// Everything degrades gracefully if Web Audio / playback is unavailable.
function useAudio(src, fallbackMs = 1300) {
  const [played, setPlayed] = React.useState(0);
  const [playing, setPlaying] = React.useState(false);
  const [analyser, setAnalyser] = React.useState(null);
  const aRef = React.useRef(null);
  const ctxRef = React.useRef(null);
  const anaRef = React.useRef(null);
  const raf = React.useRef(0);

  React.useEffect(() => {
    const a = new Audio();
    a.src = src;
    a.preload = 'auto';
    aRef.current = a;
    return () => { try { a.pause(); } catch (e) {} cancelAnimationFrame(raf.current); };
  }, [src]);

  // lazily build ctx → source → analyser → destination, once, on first play
  // (a user gesture, so the AudioContext is allowed to start).
  const ensureGraph = React.useCallback(() => {
    if (anaRef.current) return anaRef.current;
    try {
      const Ctx = window.AudioContext || window.webkitAudioContext;
      if (!Ctx || !aRef.current) return null;
      const ctx = new Ctx();
      const source = ctx.createMediaElementSource(aRef.current);
      const ana = ctx.createAnalyser();
      ana.fftSize = 256;
      ana.smoothingTimeConstant = 0.72;
      source.connect(ana);
      ana.connect(ctx.destination);
      ctxRef.current = ctx;
      anaRef.current = ana;
      setAnalyser(ana);
      return ana;
    } catch (e) { return null; }
  }, []);

  const finish = React.useCallback(() => {
    setPlaying(false);
    setPlayed(1);
    setTimeout(() => setPlayed(0), 650);
  }, []);

  // visual-only fallback (no audio) — keeps progress moving if playback fails
  const sweep = React.useCallback(() => {
    const start = performance.now();
    const tick = (now) => {
      const p = Math.min(1, (now - start) / fallbackMs);
      setPlayed(p);
      if (p < 1) raf.current = requestAnimationFrame(tick);
      else finish();
    };
    cancelAnimationFrame(raf.current);
    raf.current = requestAnimationFrame(tick);
  }, [fallbackMs, finish]);

  const play = React.useCallback(() => {
    const a = aRef.current;
    cancelAnimationFrame(raf.current);
    ensureGraph();
    if (ctxRef.current && ctxRef.current.state === 'suspended') { try { ctxRef.current.resume(); } catch (e) {} }
    setPlaying(true);
    setPlayed(0);
    if (!a) { sweep(); return; }
    try { a.pause(); a.currentTime = 0; } catch (e) {}
    const tick = () => {
      const d = a.duration && isFinite(a.duration) ? a.duration : fallbackMs / 1000;
      setPlayed(Math.min(1, a.currentTime / d));
      if (!a.paused && !a.ended) raf.current = requestAnimationFrame(tick);
    };
    a.onended = () => { cancelAnimationFrame(raf.current); finish(); };
    const pr = a.play();
    if (pr && pr.then) {
      pr.then(() => { raf.current = requestAnimationFrame(tick); }).catch(() => { sweep(); });
    } else {
      raf.current = requestAnimationFrame(tick);
    }
  }, [ensureGraph, sweep, fallbackMs, finish]);

  React.useEffect(() => () => cancelAnimationFrame(raf.current), []);
  return { played, playing, play, analyser };
}

// ── Live equalizer: centered bars driven by the real audio amplitude ─────
// Reads the AnalyserNode each frame and writes bar heights imperatively (no
// per-frame React renders). At rest the bars settle to a calm flat line.
function LiveWaveform({ analyser, playing, height = 50, count = 40, gap = 3, theme, color, radius = 3 }) {
  const T = theme;
  const c = color || (T ? T.wavePlayed : '#2C5E8C');
  const barsRef = React.useRef([]);
  const smooth = React.useRef(null);
  const raf = React.useRef(0);
  const REST = 0.08;

  if (!smooth.current || smooth.current.length !== count) {
    smooth.current = new Array(count).fill(REST);
  }

  React.useEffect(() => {
    const setBar = (i, v) => {
      const el = barsRef.current[i];
      if (el) el.style.transform = `scaleY(${Math.max(REST, Math.min(1, v)).toFixed(3)})`;
    };
    const reduce = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
    cancelAnimationFrame(raf.current);

    if (!playing || reduce) {
      // ease every bar back down to the resting line
      const start = smooth.current.slice();
      let t0 = null;
      const ease = (now) => {
        if (t0 == null) t0 = now;
        const k = Math.min(1, (now - t0) / 300);
        for (let i = 0; i < count; i++) {
          const v = start[i] + (REST - start[i]) * k;
          smooth.current[i] = v; setBar(i, v);
        }
        if (k < 1) raf.current = requestAnimationFrame(ease);
      };
      raf.current = requestAnimationFrame(ease);
      return () => cancelAnimationFrame(raf.current);
    }

    const freq = analyser ? new Uint8Array(analyser.frequencyBinCount) : null;
    const loop = () => {
      if (analyser && freq) {
        analyser.getByteFrequencyData(freq);
        const usable = Math.floor(freq.length * 0.72); // voice energy sits low-mid
        for (let i = 0; i < count; i++) {
          // perceptual mapping so low frequencies don't dominate every bar
          const lo = Math.min(usable - 1, Math.floor(Math.pow(i / count, 1.35) * usable));
          const hi = Math.max(lo, Math.min(usable - 1, Math.floor(Math.pow((i + 1) / count, 1.35) * usable)));
          let m = 0; for (let j = lo; j <= hi; j++) m = Math.max(m, freq[j]);
          let target = Math.min(1, Math.pow(m / 255, 0.82) * 1.18);
          const prev = smooth.current[i];
          // fast attack, slower release reads as natural speech
          const a = target > prev ? 0.6 : 0.16;
          const v = prev + (target - prev) * a;
          smooth.current[i] = v; setBar(i, v);
        }
      } else {
        // no analyser available: soft synthetic motion (better than a flat fill)
        const t = performance.now() / 1000;
        for (let i = 0; i < count; i++) {
          const v = 0.18 + 0.46 * (0.5 + 0.5 * Math.sin(t * 6.2 + i * 0.55)) * (0.55 + 0.45 * Math.sin(t * 2.1 + i * 0.3));
          smooth.current[i] = v; setBar(i, v);
        }
      }
      raf.current = requestAnimationFrame(loop);
    };
    raf.current = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf.current);
  }, [playing, analyser, count]);

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap, height, width: '100%' }}>
      {Array.from({ length: count }).map((_, i) => (
        <div key={i} ref={el => { barsRef.current[i] = el; }} style={{
          flex: 1, minWidth: 0, height, borderRadius: radius, background: c,
          transformOrigin: 'center', transform: `scaleY(${REST})`, willChange: 'transform',
        }} />
      ))}
    </div>
  );
}

// waveform sweep: animate played 0→1 once
function useSweep(durationMs = 1300) {
  const [played, setPlayed] = React.useState(0);
  const [playing, setPlaying] = React.useState(false);
  const raf = React.useRef(0);
  const play = React.useCallback(() => {
    setPlaying(true);
    const start = performance.now();
    const tick = (now) => {
      const p = Math.min(1, (now - start) / durationMs);
      setPlayed(p);
      if (p < 1) { raf.current = requestAnimationFrame(tick); }
      else { setPlaying(false); setTimeout(() => setPlayed(0), 650); }
    };
    cancelAnimationFrame(raf.current);
    raf.current = requestAnimationFrame(tick);
  }, [durationMs]);
  React.useEffect(() => () => cancelAnimationFrame(raf.current), []);
  return { played, playing, play };
}

const DEMO_WORDS = [
  { lv: 'Es', en: 'I', state: 'known' },
  { lv: 'dzeru', en: 'drink', state: 'new' },
  { lv: 'kafiju', en: 'coffee', state: 'known' },
];

// ── persistent strip showing the phrase being assembled ─────────────────
function WordStrip({ T, learned }) {
  return (
    <div style={{ display: 'flex', gap: 8, marginTop: 18 }}>
      {DEMO_WORDS.map((w, i) => {
        const isNew = w.state === 'new';
        const on = !isNew || learned;
        return (
          <div key={i} style={{
            flex: 1, borderRadius: 14, padding: '11px 8px 10px', textAlign: 'center',
            background: on ? (isNew ? T.primarySoft : T.surface) : (T.dark ? 'rgba(255,255,255,0.03)' : 'rgba(26,39,51,0.03)'),
            border: `1px solid ${on && isNew ? hexA(T.primary, 0.4) : T.hair}`,
            transition: 'background .4s, border-color .4s',
          }}>
            <div style={{
              fontFamily: ppHeadFont({}), fontSize: 18, fontWeight: 500, letterSpacing: -0.2,
              color: isNew ? (learned ? T.primary : T.faint) : T.ink,
            }}>{w.lv}</div>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4, marginTop: 5, height: 14 }}>
              {on ? (
                <>
                  <Icon name="check" size={11} color={isNew ? T.primary : T.good} sw={2.6} />
                  <span style={{ fontFamily: PP_UI, fontSize: 10.5, fontWeight: 600, color: isNew ? T.primary : T.faint }}>{isNew ? 'learned' : 'known'}</span>
                </>
              ) : (
                <>
                  <Icon name="lock" size={11} color={T.faint} sw={1.8} />
                  <span style={{ fontFamily: PP_UI, fontSize: 10.5, fontWeight: 600, color: T.faint }}>new</span>
                </>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function DemoScreen({ dark }) {
  const T = ppTheme(dark, {});
  const head = ppHeadFont({});
  const STAGES = ['start', 'learn', 'check', 'unlock', 'done'];
  const [stage, setStage] = React.useState('start');
  const [choice, setChoice] = React.useState(null);
  const wordPlay = useAudio('assets/ballad-dzeru.mp3', 1200);
  const phrasePlay = useAudio('assets/ballad-es-dzeru-kafiju.mp3', 1700);
  const learned = STAGES.indexOf(stage) >= STAGES.indexOf('unlock');
  const progress = STAGES.indexOf(stage) / (STAGES.length - 1);

  const options = [
    { en: 'to eat', ok: false },
    { en: 'to drink', ok: true },
    { en: 'to have', ok: false },
  ];
  const answered = choice !== null;
  const right = answered && options[choice].ok;

  // auto-flow from unlock → done
  React.useEffect(() => {
    if (stage === 'unlock') {
      demoChime();
      const id = setTimeout(() => setStage('done'), 2400);
      return () => clearTimeout(id);
    }
  }, [stage]);

  const reset = () => { setStage('start'); setChoice(null); };

  const labels = {
    start: 'Today · 1 phrase',
    learn: 'New word',
    check: 'Quick check',
    unlock: 'Phrase',
    done: 'New phrase',
  };

  // shared button
  const Cta = ({ onClick, children, tone = 'primary', icon }) => (
    <button onClick={onClick} style={{
      width: '100%', height: 56, borderRadius: 18, border: 'none', cursor: 'pointer',
      background: tone === 'good' ? T.good : tone === 'danger' ? '#C0485A' : tone === 'ghost' ? 'transparent' : T.primary,
      color: tone === 'ghost' ? T.sub : (tone === 'danger' ? '#fff' : (dark && tone !== 'good' ? '#0B1117' : '#fff')),
      outline: tone === 'ghost' ? `1.5px solid ${T.hair}` : 'none',
      fontFamily: PP_UI, fontSize: 17, fontWeight: 600,
      display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9,
      boxShadow: tone === 'ghost' ? 'none' : `0 8px 20px ${hexA(tone === 'danger' ? '#C0485A' : (tone === 'good' ? T.good : T.primary), dark ? 0.36 : 0.24)}`,
    }}>{icon}{children}</button>
  );

  return (
    <Screen theme={T}>
      {/* header: progress + label + word strip */}
      <div style={{ paddingTop: 64 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ flex: 1, height: 4, borderRadius: 99, background: dark ? 'rgba(255,255,255,0.09)' : 'rgba(26,39,51,0.08)', overflow: 'hidden' }}>
            <div style={{ width: `${Math.max(8, progress * 100)}%`, height: '100%', background: T.primary, borderRadius: 99, transition: 'width .5s cubic-bezier(.2,.6,.3,1)' }} />
          </div>
          <span style={{ fontFamily: PP_UI, fontSize: 12, fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase', color: T.faint, minWidth: 92, textAlign: 'right' }}>{labels[stage]}</span>
        </div>
        <WordStrip T={T} learned={learned} />
      </div>

      {/* stage body */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', paddingBottom: 6 }}>

        {stage === 'start' && (
          <>
            <div style={{ fontFamily: PP_UI, fontSize: 13.5, color: T.sub, textAlign: 'center', lineHeight: 1.5, maxWidth: 280 }}>
              You already know two of these words.<br />Learn one more and the phrase opens.
            </div>
            <div style={{ marginTop: 26 }}>
              <span style={{ fontFamily: head, fontSize: 32, fontWeight: 500, letterSpacing: -0.5, color: T.faint }}>
                Es <span style={{ color: T.faint }}>dzeru</span> kafiju<span>.</span>
              </span>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 22, padding: '9px 16px', borderRadius: 99, background: T.primarySoft, border: `1px solid ${hexA(T.primary, 0.35)}` }}>
              <Icon name="lock" size={14} color={T.primary} sw={1.9} />
              <span style={{ fontFamily: PP_UI, fontSize: 13.5, fontWeight: 600, color: T.primary }}>1 word to go — learn <i style={{ fontFamily: head, fontStyle: 'normal' }}>dzert</i></span>
            </div>
          </>
        )}

        {stage === 'learn' && (
          <>
            <div style={{ fontFamily: PP_UI, fontSize: 12, fontWeight: 600, letterSpacing: 1.4, textTransform: 'uppercase', color: T.faint }}>New word · verb</div>
            <div style={{ marginTop: 16 }}>
              <span style={{ fontFamily: head, fontSize: 54, fontWeight: 500, letterSpacing: -0.8, lineHeight: 1 }}>dzeru</span>
            </div>
            <div style={{ fontFamily: PP_UI, fontSize: 16, color: T.sub, marginTop: 10 }}>
              to drink <span style={{ color: T.faint }}>· DZEH-roo</span>
            </div>
            <div style={{ width: '78%', marginTop: 30 }}>
              <LiveWaveform analyser={wordPlay.analyser} playing={wordPlay.playing} height={48} count={38} theme={T} />
            </div>
            <div style={{ marginTop: 22 }}>
              <PlayOrb theme={T} size={68} playing={wordPlay.playing} onClick={wordPlay.play} />
            </div>
            <span style={{ fontFamily: PP_UI, fontSize: 13, color: T.faint, fontWeight: 500, marginTop: 14 }}>Tap to hear it</span>
          </>
        )}

        {stage === 'check' && (
          <>
            <div style={{ fontFamily: PP_UI, fontSize: 12, fontWeight: 600, letterSpacing: 1.4, textTransform: 'uppercase', color: T.faint }}>What does it mean?</div>
            <div style={{ marginTop: 14 }}>
              <span style={{ fontFamily: head, fontSize: 44, fontWeight: 500, letterSpacing: -0.6, lineHeight: 1 }}>dzeru</span>
            </div>
            <div style={{ width: '100%', marginTop: 24, display: 'flex', flexDirection: 'column', gap: 10 }}>
              {options.map((o, i) => {
                const picked = choice === i;
                let bg = T.surface, bd = T.hair, fg = T.ink;
                if (answered) {
                  if (right && o.ok) { bg = T.goodSoft; bd = hexA(T.good, 0.5); fg = T.good; }
                  else if (picked && !o.ok) { bg = dark ? 'rgba(224,116,138,0.12)' : 'rgba(158,43,58,0.07)'; bd = hexA('#C0485A', 0.45); fg = '#C0485A'; }
                  else { fg = T.faint; }
                }
                return (
                  <button key={i} disabled={answered} onClick={() => setChoice(i)} style={{
                    width: '100%', minHeight: 54, borderRadius: 16, cursor: answered ? 'default' : 'pointer',
                    background: bg, border: `1.5px solid ${bd}`, color: fg,
                    fontFamily: PP_UI, fontSize: 16.5, fontWeight: 600,
                    display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 18px',
                    boxShadow: answered ? 'none' : T.shadow,
                  }}>
                    {o.en}
                    {right && o.ok && <Icon name="check" size={18} color={T.good} sw={2.4} />}
                  </button>
                );
              })}
            </div>
            <div style={{ height: 22, marginTop: 14, fontFamily: PP_UI, fontSize: 13.5, fontWeight: 500, color: right ? T.good : '#C0485A', textAlign: 'center' }}>
              {answered && (right ? <>That&rsquo;s it — you know all three words now.</> : <>Not quite — give it another try.</>)}
            </div>
          </>
        )}

        {stage === 'unlock' && (
          <>
            <div className="pp-unlock-pop" style={{ position: 'relative', width: 132, height: 132, display: 'flex', alignItems: 'center', justifyContent: 'center', animation: 'ppUnlockPop .7s cubic-bezier(.34,1.4,.5,1) both' }}>
              <div className="pp-unlock-bloom" style={{ position: 'absolute', width: 104, height: 104, borderRadius: '50%', border: `1.5px solid ${hexA(T.primary, 0.4)}`, animation: 'ppUnlockBloom 1.4s cubic-bezier(.2,.6,.3,1) .2s forwards' }} />
              <div style={{ position: 'absolute', width: 92, height: 92, borderRadius: '50%', background: T.primarySoft }} />
              <div style={{ position: 'relative', width: 62, height: 62, borderRadius: '50%', background: T.primary, boxShadow: `0 8px 24px ${hexA(T.primary, dark ? 0.45 : 0.3)}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon name="unlock" size={25} color={dark ? '#0B1117' : '#fff'} sw={1.9} />
              </div>
            </div>
            <div className="pp-rise" style={{ fontFamily: PP_UI, fontSize: 12, fontWeight: 600, letterSpacing: 1.6, textTransform: 'uppercase', color: T.primary, marginTop: 26, animation: 'ppRise .6s ease .4s both' }}>Phrase unlocked</div>
            <div className="pp-rise" style={{ marginTop: 16, animation: 'ppRise .6s ease .55s both' }}>
              <span style={{ fontFamily: head, fontSize: 32, fontWeight: 500, letterSpacing: -0.5 }}>Es <span style={{ color: T.primary }}>dzeru</span> kafiju.</span>
            </div>
            <div className="pp-rise" style={{ fontFamily: PP_UI, fontSize: 14, color: T.sub, marginTop: 14, animation: 'ppRise .6s ease .7s both' }}>You know all its words now.</div>
          </>
        )}

        {stage === 'done' && (
          <>
            <div style={{ marginTop: 4, textAlign: 'center' }}>
              <span style={{ fontFamily: head, fontSize: 34, fontWeight: 500, letterSpacing: -0.5, lineHeight: 1.2 }}>Es <span style={{ color: T.primary }}>dzeru</span> kafiju.</span>
            </div>
            <div style={{ fontFamily: PP_UI, fontSize: 16, color: T.sub, marginTop: 12 }}>I drink coffee.</div>
            <div style={{ width: '80%', marginTop: 30 }}>
              <LiveWaveform analyser={phrasePlay.analyser} playing={phrasePlay.playing} height={54} count={46} theme={T} />
            </div>
            <div style={{ marginTop: 22 }}>
              <PlayOrb theme={T} size={74} playing={phrasePlay.playing} onClick={phrasePlay.play} />
            </div>
            <span style={{ fontFamily: PP_UI, fontSize: 13, color: T.faint, fontWeight: 500, marginTop: 14 }}>Tap to hear the whole phrase</span>
          </>
        )}
      </div>

      {/* bottom CTA */}
      <div style={{ paddingBottom: 30 }}>
        {stage === 'start' && <Cta onClick={() => setStage('learn')} icon={<svg width="17" height="17" viewBox="0 0 24 24" fill={dark ? '#0B1117' : '#fff'}><path d="M6 4.5v15a1 1 0 0 0 1.5.87l12-7.5a1 1 0 0 0 0-1.74l-12-7.5A1 1 0 0 0 6 4.5z" /></svg>}>Begin listening</Cta>}
        {stage === 'learn' && <Cta onClick={() => setStage('check')}>Continue</Cta>}
        {stage === 'check' && (!answered
          ? <div style={{ textAlign: 'center', fontFamily: PP_UI, fontSize: 13, color: T.faint, fontWeight: 500, padding: '18px 0' }}>Pick the meaning to continue.</div>
          : right
            ? <Cta onClick={() => setStage('unlock')}>See it unlock</Cta>
            : <Cta tone="danger" icon={<Icon name="replay" size={18} color="#fff" />} onClick={() => setChoice(null)}>Try again</Cta>)}
        {stage === 'unlock' && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 9, paddingBottom: 6 }}>
            <div style={{ width: 96, height: 3, borderRadius: 99, background: dark ? 'rgba(255,255,255,0.09)' : 'rgba(26,39,51,0.08)', overflow: 'hidden' }}>
              <div className="pp-fill-once" style={{ height: '100%', width: 0, borderRadius: 99, background: T.primary, animation: 'ppFillOnce 2.2s linear .2s forwards' }} />
            </div>
            <span style={{ fontFamily: PP_UI, fontSize: 12.5, color: T.faint }}>Hearing it…</span>
          </div>
        )}
        {stage === 'done' && <Cta tone="ghost" onClick={reset} icon={<Icon name="replay" size={17} color={T.sub} />}>Replay the demo</Cta>}
      </div>
    </Screen>
  );
}

// keyframes (mirrors screens-phrase.jsx so the demo stands alone)
if (typeof document !== 'undefined' && !document.getElementById('pp-demo-kf')) {
  const s = document.createElement('style');
  s.id = 'pp-demo-kf';
  s.textContent = `
    @keyframes ppUnlockBloom { 0% { transform: scale(0.7); opacity: 0.5; } 100% { transform: scale(1.6); opacity: 0; } }
    @keyframes ppUnlockPop { 0% { transform: scale(0.72); opacity: 0; } 60% { transform: scale(1.06); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
    @keyframes ppRise { 0% { transform: translateY(10px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
    @keyframes ppFillOnce { 0% { width: 0; } 100% { width: 100%; } }
    @media (prefers-reduced-motion: reduce) {
      .pp-unlock-bloom, .pp-unlock-pop, .pp-rise, .pp-fill-once { animation: none !important; opacity: 1 !important; transform: none !important; }
      .pp-fill-once { width: 100% !important; }
    }`;
  document.head.appendChild(s);
}

// ── scaled device wrapper ───────────────────────────────────────────────
function DemoPhone({ dark = false, scale = 0.74 }) {
  const W = 402, H = 874;
  return (
    <div style={{ width: W * scale, height: H * scale, position: 'relative' }}>
      <div style={{ position: 'absolute', top: 0, left: 0, width: W, height: H, transform: `scale(${scale})`, transformOrigin: 'top left' }}>
        <IOSDevice dark={dark}>
          <DemoScreen dark={dark} />
        </IOSDevice>
      </div>
    </div>
  );
}

Object.assign(window, { DemoPhone, DemoScreen });
