// ====================================================================
// lw-studio-record.jsx — Champion: the recording STUDIO screen
// One beat at a time (Concept C) + centered recipient pill & revealable
// example script (Concept D). Record overlays fade out / review controls
// slide up when entering review, and the reverse on the next beat; the
// lemon filmstrip highlight slides to the active beat.
// ====================================================================
const { useState: useStateST, useEffect: useEffectST, useRef: useRefST, useLayoutEffect: useLayoutEffectST } = React;

// ── The studio ──────────────────────────────────────────────────────
function StudioScreen({ bene, theme, beats, segClips, setSegClips, rec,
                        onReviewAll, onExit, logActivity, startAt = 0 }) {
  const [active, setActive] = useStateST(Math.min(startAt, Math.max(0, beats.length - 1)));
  const [showEx, setShowEx] = useStateST(false);
  const [altIdx, setAltIdx] = useStateST(-1);          // -1 = the main example line
  const [phase, setPhase] = useStateST("live");        // live | preview | reviewBeat
  const [confirmOpen, setConfirmOpen] = useStateST(false);
  const pendingNavRef = useRefST(null);

  // review playback (lifted so the bar can live in a separate, sliding layer)
  const playRef = useRefST(null);
  const [playing, setPlaying] = useStateST(false);
  const [cur, setCur] = useStateST(0);
  const [dur, setDur] = useStateST(0);

  // filmstrip moving highlight
  const cardRefs = useRefST([]);
  const [hl, setHl] = useStateST(null);

  // live mic monitoring — proves audio is flowing, and catches a hijacked/silent
  // mic (e.g. a conferencing app holding the device) instead of shipping silence.
  const micBandsRef = useRefST([]);                // per-band magnitudes → equalizer
  const [micSilent, setMicSilent] = useStateST(false);
  const heardRef = useRefST(false);

  const beat = beats[active] || {};
  const recording = rec.status === "recording";
  const doneCount = segClips.filter(Boolean).length;
  const allDone = beats.length > 0 && doneCount === beats.length;

  const isReview = phase === "preview" || phase === "reviewBeat";
  const reviewClip = phase === "preview" ? { url: rec.recordedUrl, mock: rec.mode === "mock", dur: rec.elapsed }
                   : phase === "reviewBeat" ? segClips[active] : null;

  useEffectST(() => { setShowEx(false); setAltIdx(-1); }, [active]);

  // recorder finished → straight into review (the layers cross-fade/slide)
  useEffectST(() => { if (rec.status === "recorded") setPhase("preview"); }, [rec.status]);

  // reset playback whenever the clip under review changes
  useEffectST(() => {
    setPlaying(false); setCur(0);
    setDur((reviewClip && reviewClip.dur) || 0);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [phase, active]);

  // slide the lemon highlight to the active beat card
  useLayoutEffectST(() => {
    const el = cardRefs.current[active];
    if (el) setHl({ left: el.offsetLeft, top: el.offsetTop, width: el.offsetWidth, height: el.offsetHeight });
  }, [active, beats.length]);

  // tap the live mic so we can show a waveform and detect silent capture
  useEffectST(() => {
    if (rec.mode !== "live" || !rec.streamRef.current) { micBandsRef.current = []; return; }
    const stop = lwMonitorAudioLevel(rec.streamRef.current, (lvl, meta) => {
      micBandsRef.current = (meta && meta.bands) || [];
      if (lvl > 0.06) heardRef.current = true;
    });
    return stop;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [rec.mode, rec.streamRef.current, phase]);

  // while recording a live take, flag if we never hear anything for ~2.5s —
  // the tell-tale sign the mic was captured by other software.
  useEffectST(() => {
    if (!(recording && rec.mode === "live")) { setMicSilent(false); return; }
    heardRef.current = false;
    setMicSilent(false);
    const t = setTimeout(() => { if (!heardRef.current) setMicSilent(true); }, 2500);
    return () => clearTimeout(t);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [recording, rec.mode]);

  const exampleText = altIdx < 0 ? beat.ex : (beat.alts && beat.alts[altIdx]) || beat.ex;

  const startStop = async () => {
    if (recording) { await rec.stop(); /* → preview via effect */ }
    else { setPhase("live"); rec.start(); }
  };

  const commitTake = () => {
    // store the take; we deliberately do NOT revoke the previous blob url here —
    // a redone beat can still be referenced elsewhere, and revoking caused black frames
    setSegClips((s) => {
      const n = [...s];
      n[active] = { url: rec.recordedUrl, dur: rec.elapsed, mock: rec.mode === "mock" };
      return n;
    });
    logActivity && logActivity(`Recorded “${beat.t}”`, `${theme.label} · beat ${active + 1}`);
    rec.retake(false);               // clear current take, keep url alive in segClips
  };

  const keepTake = () => {
    commitTake();
    const nextEmpty = beats.findIndex((_, i) => i !== active && !segClips[i]);
    if (nextEmpty >= 0) { setActive(nextEmpty); setPhase("live"); }
    else onReviewAll();              // that was the last beat → stitched review
  };

  const runPending = () => { const fn = pendingNavRef.current; pendingNavRef.current = null; setConfirmOpen(false); if (fn) fn(); };
  const discardTake = () => { rec.retake(true); setPhase("live"); };
  const reRecordBeat = () => { setPhase("live"); };
  const looksGood = () => { const next = beats.findIndex((_, i) => !segClips[i]); if (next >= 0) setActive(next); setPhase("live"); };

  // Save & Exit — commit any take currently in preview, then jump straight to the
  // final review even if some beats are still empty. ReviewStage drops the empties.
  const saveAndExit = () => {
    if (recording) return;                 // can't save mid-recording
    if (phase === "preview") commitTake();  // persist the just-recorded take first
    onReviewAll();
  };

  const doJumpTo = (i) => {
    if (rec.status === "recorded") rec.retake(true);
    setActive(i);
    setPhase(segClips[i] ? "reviewBeat" : "live");
  };
  const jumpTo = (i) => {
    if (recording) return;
    if (phase === "preview") { pendingNavRef.current = () => doJumpTo(i); setConfirmOpen(true); return; }
    doJumpTo(i);
  };
  const requestExit = () => {
    if (phase === "preview") { pendingNavRef.current = () => onExit(); setConfirmOpen(true); return; }
    onExit();
  };

  // review-bar content depends on which review we're in
  const barTitle = phase === "reviewBeat" ? `Reviewing · beat ${active + 1}` : "How was that take?";
  const barMsg = phase === "reviewBeat" ? beat.t
    : (rec.mode === "mock" ? "Preview mode — imagine your take here." : "Watch it back, then keep it or try again.");
  const allRec = beats.every((b, i) => segClips[i]);
  const barReRecord = phase === "reviewBeat" ? reRecordBeat : discardTake;
  const barKeep = phase === "reviewBeat" ? (allRec ? onReviewAll : looksGood) : keepTake;
  const barKeepLabel = phase === "reviewBeat"
    ? (allRec ? "Review it all together" : "Looks good — next beat")
    : (beats.every((_, i) => i === active || segClips[i]) ? "Save & review all together" : "Keep & next beat");

  // playback helpers
  const togglePlay = () => { const v = playRef.current; if (!v) return; if (v.paused) { v.play(); setPlaying(true); } else { v.pause(); setPlaying(false); } };
  const onTime = () => { const v = playRef.current; if (!v) return; setCur(v.currentTime || 0); if (v.duration && isFinite(v.duration)) setDur(v.duration); };
  const seek = (e) => { const v = playRef.current; const d = dur || (v && v.duration) || 0; if (!d) return; const r = e.currentTarget.getBoundingClientRect();
    const p = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)); if (v) { v.currentTime = p * d; setCur(p * d); } };
  const pct = dur ? Math.min(100, (cur / dur) * 100) : 0;

  const recVisible = phase === "live";

  return (
    <div style={{ position: "relative", width: "100%", height: "100%", background: "#0c160c",
      display: "flex", flexDirection: "column", minHeight: 0 }}>
      {/* CAMERA AREA */}
      <div style={{ position: "relative", flex: 1, minHeight: 0, overflow: "hidden" }}>
        {/* base video layer */}
        {isReview ? (
          <div style={{ position: "absolute", inset: 0, background: "#0c160c" }}>
            {reviewClip && reviewClip.url
              ? <video key={phase + ":" + active} ref={playRef} src={reviewClip.url} playsInline
                  onTimeUpdate={onTime} onLoadedMetadata={onTime} onEnded={() => setPlaying(false)} onClick={togglePlay}
                  style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", cursor: "pointer" }} />
              : <img src={LW_PO.photo} alt="" style={{ position: "absolute", inset: 0, width: "100%", height: "100%",
                  objectFit: "cover", filter: "saturate(.9) brightness(.8)" }} />}
            {reviewClip && reviewClip.url && !playing && (
              <button onClick={togglePlay} aria-label="Play take" className="lw-press" style={{ position: "absolute", inset: 0,
                margin: "auto", width: 76, height: 76, borderRadius: "50%", border: "none", cursor: "pointer",
                background: "rgba(254,252,245,.92)", display: "flex", alignItems: "center", justifyContent: "center" }}>
                <svg width="28" height="28" viewBox="0 0 24 24" fill="#001D00"><path d="M7 4.5v15l13-7.5z"/></svg>
              </button>
            )}
          </div>
        ) : <LWCamera rec={rec} radius={0} poster={LW_PO.photo} mirror={true} />}

        {/* exit (always) */}
        <button onClick={requestExit} className="lw-press" style={{ position: "absolute", top: 18, left: 18, zIndex: 12,
          display: "flex", alignItems: "center", gap: 7, padding: "9px 15px 9px 11px", borderRadius: 999,
          background: "rgba(12,18,12,.5)", backdropFilter: "blur(8px)", border: "none", cursor: "pointer",
          color: "#fff", fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 600 }}>
          <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10 3L5 8l5 5"/></svg>
          Prep &amp; points
        </button>

        {recording && <div style={{ position: "absolute", top: 18, right: 18, zIndex: 12 }}><RecBadge elapsed={rec.elapsed} /></div>}
        {rec.mode === "mock" && phase === "live" && !recording && (
          <div style={{ position: "absolute", top: 20, right: 18, zIndex: 12, padding: "6px 13px", borderRadius: 999,
            background: "rgba(12,18,12,.5)", backdropFilter: "blur(8px)", color: "rgba(255,255,255,.85)",
            fontFamily: "var(--font-sans)", fontSize: 12 }}>Camera off · preview mode</div>
        )}

        {/* ── RECORD OVERLAYS (fade out → review; fade in ← review) ── */}
        <div style={{ position: "absolute", inset: 0, zIndex: 7,
          opacity: recVisible ? 1 : 0, transform: recVisible ? "translateY(0)" : "translateY(-8px)",
          pointerEvents: recVisible ? "auto" : "none",
          transition: recVisible ? "opacity .32s ease .16s, transform .32s ease .16s" : "opacity .22s ease, transform .22s ease" }}>
          {/* recipient pill — center, by the lens */}
          <div style={{ position: "absolute", top: 16, left: "50%", transform: "translateX(-50%)",
            display: "flex", alignItems: "center", gap: 10, padding: "7px 18px 7px 8px", borderRadius: 999,
            background: "rgba(12,18,12,.6)", backdropFilter: "blur(8px)", boxShadow: "0 2px 16px rgba(0,0,0,.3)" }}>
            <Avatar bene={bene} size={30} radius={999} />
            <span style={{ fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 600, color: "#fff" }}>
              Recording for {bene.firstName}</span>
          </div>

          {/* compact beat prompt — upper-left (fades out with the rest in review) */}
          <div key={active} className="lw-fade-plain" style={{ position: "absolute", top: 62, left: 18,
            width: 280, padding: "13px 15px", borderRadius: 14, background: "rgba(10,16,10,.52)", backdropFilter: "blur(8px)" }}>
            <div style={{ fontFamily: "var(--font-sans)", fontSize: 11, fontWeight: 700, letterSpacing: ".08em",
              textTransform: "uppercase", color: "rgba(254,252,245,.6)" }}>
              Beat {active + 1} of {beats.length}{segClips[active] ? " · recorded" : ""}</div>
            <div style={{ fontFamily: "var(--font-serif)", fontSize: 20, lineHeight: "25px", color: "#fff", marginTop: 5 }}>{beat.t}</div>
            <div style={{ fontFamily: "var(--font-sans)", fontSize: 13, color: "rgba(254,252,245,.72)", marginTop: 4 }}>{beat.h}</div>
            {beat.ex && (
              <button onClick={() => setShowEx((v) => !v)} className="lw-press" style={{ marginTop: 11, display: "inline-flex",
                alignItems: "center", gap: 7, padding: "6px 12px", borderRadius: 999, border: "1px solid rgba(254,252,245,.3)",
                background: showEx ? "rgba(247,247,117,.16)" : "rgba(254,252,245,.08)", cursor: "pointer",
                color: showEx ? "var(--helm-lemon)" : "#fff", fontFamily: "var(--font-sans)", fontSize: 12.5, fontWeight: 600 }}>
                <LWStar size={13} on="light" />
                {showEx ? "Hide example" : "Need words? See an example"}
              </button>
            )}
          </div>


          {/* example — small box, center-top near the lens */}
          {showEx && beat.ex && (
            <div className="lw-fade" style={{ position: "absolute", top: 66, left: "50%", transform: "translateX(-50%)",
              width: 440, maxWidth: "calc(100% - 360px)", padding: "13px 16px", borderRadius: 14, background: "rgba(8,12,8,.74)",
              backdropFilter: "blur(8px)", border: "1px solid rgba(254,252,245,.16)" }}>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
                <span style={{ fontFamily: "var(--font-sans)", fontSize: 10.5, fontWeight: 700, letterSpacing: ".07em",
                  textTransform: "uppercase", color: "rgba(254,252,245,.55)" }}>
                  {altIdx < 0 ? "You could say" : "Another way to say it"}</span>
                {beat.alts && beat.alts.length > 0 && (
                  <button onClick={() => setAltIdx((p) => (p + 2) % (beat.alts.length + 1) - 1)} className="lw-press"
                    style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "3px 9px", borderRadius: 999,
                      border: "none", cursor: "pointer", background: "rgba(254,252,245,.12)", color: "#fff",
                      fontFamily: "var(--font-sans)", fontSize: 11.5, fontWeight: 600 }}>
                    <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M3 8a5 5 0 1 0 1.5-3.5"/><path d="M3 2v3h3"/></svg>
                    Another phrasing</button>
                )}
              </div>
              <p key={altIdx} className="lw-fade-plain" style={{ margin: 0, fontFamily: "var(--font-serif)", fontSize: 17,
                lineHeight: "24px", color: "#fff", fontStyle: "italic" }}>“{exampleText}”</p>
            </div>
          )}

          {/* silent-mic warning — the conferencing-app capture symptom */}
          {micSilent && recording && (
            <div className="lw-fade-plain" style={{ position: "absolute", top: 62, left: "50%", transform: "translateX(-50%)",
              width: 470, maxWidth: "calc(100% - 80px)", display: "flex", alignItems: "flex-start", gap: 11,
              padding: "13px 16px", borderRadius: 14, background: "rgba(211,141,84,.96)",
              boxShadow: "0 6px 22px rgba(0,0,0,.35)", zIndex: 14 }}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#3a1c06" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, marginTop: 1 }}><path d="M12 2a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z"/><path d="M19 10v1a7 7 0 0 1-14 0v-1"/><path d="M12 19v3"/><path d="M3 3l18 18"/></svg>
              <div>
                <div style={{ fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 700, color: "#3a1c06" }}>
                  We can’t hear your microphone</div>
                <div style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, lineHeight: "17px", color: "#4a2509", marginTop: 2 }}>
                  Another app may be holding the mic. Your video is still recording — but the sound is silent.</div>
              </div>
            </div>
          )}

          {/* bottom record controls */}
          <div style={{ position: "absolute", bottom: 22, left: 0, right: 0, display: "flex",
            alignItems: "center", justifyContent: "center", gap: 30 }}>
            {rec.mode === "live"
              ? <WaveMeterControl bandsRef={micBandsRef} silent={micSilent} />
              : <div style={{ width: 64 }} />}
            <RecordButton recording={recording} onClick={startStop} size={84} />
            <ControlIcon label={showEx ? "Hide cue" : "Example"} active={showEx} disabled={!beat.ex}
              onClick={() => beat.ex && setShowEx((v) => !v)}>
              <LWStar size={20} on="light" />
            </ControlIcon>
          </div>
        </div>

        {/* ── REVIEW BAR (slides up from the bottom) ── */}
        <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 9, padding: "48px 200px 18px 22px",
          background: "linear-gradient(transparent, rgba(6,10,6,.94))",
          transform: isReview ? "translateY(0)" : "translateY(125%)", opacity: isReview ? 1 : 0,
          pointerEvents: isReview ? "auto" : "none",
          transition: isReview
            ? "transform .42s cubic-bezier(.2,.7,.2,1) .12s, opacity .3s ease .12s"
            : "transform .36s cubic-bezier(.4,0,.6,1), opacity .24s ease" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
            <div style={{ minWidth: 150 }}>
              <div style={{ fontFamily: "var(--font-serif)", fontSize: 19, lineHeight: "24px", color: "#fff" }}>{barTitle}</div>
              <div style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, color: "rgba(254,252,245,.7)", marginTop: 2,
                maxWidth: 260, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{barMsg}</div>
            </div>
            <button onClick={togglePlay} disabled={!(reviewClip && reviewClip.url)} aria-label={playing ? "Pause" : "Play"} className="lw-press"
              style={{ width: 44, height: 44, borderRadius: "50%", border: "none", flexShrink: 0,
                cursor: reviewClip && reviewClip.url ? "pointer" : "default", background: "rgba(254,252,245,.16)",
                color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", opacity: reviewClip && reviewClip.url ? 1 : .4 }}>
              {playing ? <svg width="15" height="15" viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="2" width="3.5" height="12" rx="1"/><rect x="9.5" y="2" width="3.5" height="12" rx="1"/></svg>
                : <svg width="15" height="15" viewBox="0 0 16 16" fill="currentColor"><path d="M4 3v10l9-5z"/></svg>}
            </button>
            <div onClick={seek} style={{ flex: 1, minWidth: 120, height: 8, borderRadius: 4, background: "rgba(254,252,245,.22)",
              cursor: reviewClip && reviewClip.url ? "pointer" : "default", position: "relative" }}>
              <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: pct + "%", borderRadius: 4, background: "var(--helm-lemon)" }} />
            </div>
            <div style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, color: "rgba(254,252,245,.8)", fontVariantNumeric: "tabular-nums", flexShrink: 0 }}>
              {lwFmt(cur)} / {lwFmt(dur)}</div>
            <div style={{ display: "flex", gap: 10, flexShrink: 0 }}>
              <Button variant="secondary" onClick={barReRecord} style={{ background: "rgba(254,252,245,.1)", color: "#fff", border: "1px solid rgba(254,252,245,.4)", padding: "11px 18px" }}>
                {phase === "reviewBeat" ? "Re-record" : "Re-record"}</Button>
              <Button variant="primary" onClick={barKeep} style={{ background: "var(--helm-lemon)", color: "var(--helm-dark-green)", padding: "11px 18px" }}>{barKeepLabel}</Button>
            </div>
          </div>
        </div>
      </div>

      {/* ── FILMSTRIP ── */}
      <div style={{ flexShrink: 0, height: 138, background: "#001400", borderTop: "1px solid rgba(254,252,245,.1)",
        display: "flex", alignItems: "center", gap: 14, padding: "0 22px" }}>
        <div style={{ position: "relative", display: "flex", gap: 11, flex: 1, overflowX: "auto", padding: "16px 0" }}>
          {/* sliding lemon highlight */}
          {hl && <div style={{ position: "absolute", left: hl.left, top: hl.top, width: hl.width, height: hl.height,
            borderRadius: 13, border: "2px solid var(--helm-lemon)", boxSizing: "border-box", pointerEvents: "none", zIndex: 2,
            transition: "left .42s cubic-bezier(.2,.7,.2,1), top .42s cubic-bezier(.2,.7,.2,1), width .42s, height .42s" }} />}
          {beats.map((b, i) => {
            const clip = segClips[i];
            return (
              <button key={i} ref={(el) => cardRefs.current[i] = el} onClick={() => jumpTo(i)} className="lw-press"
                style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", textAlign: "left",
                  width: 184, flexShrink: 0, padding: "11px 13px", borderRadius: 13, cursor: "pointer",
                  border: "2px solid transparent", boxSizing: "border-box",
                  background: clip ? "rgba(141,153,51,.28)" : "rgba(254,252,245,.06)" }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                  <span style={{ fontFamily: "var(--font-sans)", fontSize: 11, fontWeight: 700, letterSpacing: ".05em",
                    color: "rgba(254,252,245,.6)" }}>BEAT {i + 1}</span>
                  <span style={{ width: 19, height: 19, borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center",
                    background: clip ? "var(--helm-chartreuse-2)" : "rgba(254,252,245,.16)" }}>
                    {clip ? <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="#fff" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3.5 8.5l3 3 6-7"/></svg>
                      : <span style={{ fontSize: 10, color: "rgba(254,252,245,.7)" }}>{i + 1}</span>}
                  </span>
                </div>
                <span style={{ fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, color: "#fff", lineHeight: "17px",
                  margin: "7px 0 5px", overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }}>{b.t}</span>
                <span style={{ fontFamily: "var(--font-sans)", fontSize: 11.5, color: "rgba(254,252,245,.55)" }}>
                  {clip ? (clip.mock ? "Preview take" : lwFmt(clip.dur)) + " · tap to review" : "Not recorded"}</span>
              </button>
            );
          })}
        </div>
        <div style={{ width: 1, height: 82, background: "rgba(254,252,245,.12)", flexShrink: 0 }} />
        <div style={{ width: 210, flexShrink: 0, textAlign: "center" }}>
          <div style={{ fontFamily: "var(--font-sans)", fontSize: 13, color: "rgba(254,252,245,.62)", marginBottom: 9 }}>
            {doneCount} of {beats.length} beats recorded</div>
          <Button variant="secondary" disabled={recording || doneCount === 0} onClick={saveAndExit}
            style={{ background: "transparent", color: recording || doneCount === 0 ? "rgba(254,252,245,.45)" : "#fff",
              border: recording || doneCount === 0 ? "1px solid rgba(254,252,245,.2)" : "1px solid rgba(254,252,245,.5)", width: "100%" }}>
            Save &amp; exit</Button>
          {doneCount > 0 && !allDone && (
            <div style={{ fontFamily: "var(--font-sans)", fontSize: 11.5, color: "rgba(254,252,245,.45)", marginTop: 7, lineHeight: "15px" }}>
              Unrecorded beats are left out of the video.</div>
          )}
        </div>
      </div>

      {/* unsaved-take guard */}
      {confirmOpen && (
        <div onClick={() => { pendingNavRef.current = null; setConfirmOpen(false); }}
          style={{ position: "absolute", inset: 0, zIndex: 40, background: "rgba(6,10,6,.62)", backdropFilter: "blur(4px)",
            display: "flex", alignItems: "center", justifyContent: "center", padding: 30 }} className="lw-fade-plain">
          <div onClick={(e) => e.stopPropagation()} style={{ width: 440, maxWidth: "100%", background: "var(--helm-white)",
            borderRadius: 22, border: "1px solid var(--helm-dark-green)", boxShadow: "var(--shadow-card-lg)", padding: 28 }}>
            <h2 style={{ fontFamily: "var(--font-serif)", fontSize: 26, lineHeight: "30px", color: "var(--helm-dark-green)", margin: "0 0 8px" }}>
              Keep this take?</h2>
            <p style={{ fontFamily: "var(--font-sans)", fontSize: 15, lineHeight: "22px", color: "var(--helm-dark-green-2)", margin: "0 0 22px" }}>
              You just recorded “{beat.t}.” Save it to this beat, or discard it before moving on.</p>
            <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", flexWrap: "wrap" }}>
              <Button variant="ghost" onClick={() => { pendingNavRef.current = null; setConfirmOpen(false); }} style={{ color: "var(--helm-dark-grey)" }}>Cancel</Button>
              <Button variant="secondary" onClick={() => { discardTake(); runPending(); }}>Discard</Button>
              <Button variant="primary" onClick={() => { commitTake(); runPending(); }}>Save this take</Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// live mic equalizer — a fixed row of bars that grow & shrink IN PLACE with the
// voice (iOS "now playing" style), drawn from per-band frequency data. Loudest
// energy sits in the CENTER and tapers to the edges. Helm chartreuse; amber if silent.
function WaveMeter({ bandsRef, silent, w = 56, h = 30 }) {
  const ref = useRefST(null);
  const easeRef = useRefST([]);
  useEffectST(() => {
    const cv = ref.current; if (!cv) return;
    const dpr = window.devicePixelRatio || 1;
    cv.width = w * dpr; cv.height = h * dpr;
    const ctx = cv.getContext("2d");
    const NB = 7, center = (NB - 1) / 2;
    const color = silent ? "#D38D54" : "#8D9933";
    const slot = cv.width / NB, barW = slot * 0.56, r = Math.min(barW / 2, 3 * dpr);
    const mid = cv.height / 2, minH = barW;
    let raf;
    const draw = () => {
      ctx.clearRect(0, 0, cv.width, cv.height);
      ctx.fillStyle = color;
      const bands = bandsRef.current || [], ease = easeRef.current;
      for (let i = 0; i < NB; i++) {
        // mirror around the center: distance-from-center picks the band, so the
        // strongest (low-freq) energy lands in the middle and falls off outward.
        const band = bands[Math.abs(i - center)] || 0;
        const target = silent ? 0 : Math.min(1, band);
        ease[i] = (ease[i] == null ? 0 : ease[i]) * 0.68 + target * 0.32;   // settle in place
        const bh = Math.max(minH, ease[i] * cv.height * 0.92);
        const x = i * slot + (slot - barW) / 2, y = mid - bh / 2;
        ctx.beginPath();
        ctx.moveTo(x + r, y);
        ctx.arcTo(x + barW, y, x + barW, y + bh, r);
        ctx.arcTo(x + barW, y + bh, x, y + bh, r);
        ctx.arcTo(x, y + bh, x, y, r);
        ctx.arcTo(x, y, x + barW, y, r);
        ctx.fill();
      }
      raf = requestAnimationFrame(draw);
    };
    draw();
    return () => cancelAnimationFrame(raf);
  }, [silent, w, h]);
  return <canvas ref={ref} style={{ width: w, height: h, display: "block" }} aria-label="Microphone waveform" />;
}

// the equalizer dressed as a bottom-bar control (sits left of the record button,
// in the slot the unused Replay button used to occupy). Light, glass-like surface.
function WaveMeterControl({ bandsRef, silent }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 7 }}>
      <div style={{ width: 64, height: 44, borderRadius: 14, display: "flex", alignItems: "center", justifyContent: "center",
        background: silent ? "rgba(211,141,84,.18)" : "rgba(254,252,245,.13)", backdropFilter: "blur(6px)" }}>
        <WaveMeter bandsRef={bandsRef} silent={silent} />
      </div>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--font-sans)", fontSize: 11.5,
        fontWeight: 600, color: silent ? "var(--helm-orange-2, #D38D54)" : "rgba(254,252,245,.7)" }}>
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 2a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z"/><path d="M19 10v1a7 7 0 0 1-14 0v-1"/><path d="M12 19v3"/>
        </svg>
        {silent ? "No sound" : "Mic"}
      </span>
    </div>
  );
}

// circular control button used in the studio control bar
function ControlIcon({ children, label, onClick, disabled, active }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 7 }}>
      <button onClick={onClick} disabled={disabled} className="lw-press" aria-label={label} style={{
        width: 56, height: 56, borderRadius: "50%", border: "none", cursor: disabled ? "default" : "pointer",
        background: active ? "rgba(247,247,117,.2)" : "rgba(254,252,245,.13)", color: active ? "var(--helm-lemon)" : "#fff",
        opacity: disabled ? .35 : 1, display: "flex", alignItems: "center", justifyContent: "center",
        backdropFilter: "blur(6px)" }}>{children}</button>
      <span style={{ fontFamily: "var(--font-sans)", fontSize: 11.5, fontWeight: 600, color: "rgba(254,252,245,.7)" }}>{label}</span>
    </div>
  );
}

// ── StitchPlayer — plays the kept beats back-to-back as one video ────
function StitchPlayer({ segments, poster, accent = "var(--helm-lemon)" }) {
  const [idx, setIdx] = useStateST(0);
  const [playing, setPlaying] = useStateST(false);
  const vidRef = useRefST(null);
  const mockT = useRefST(null);
  // Only stitch beats that were actually recorded — empty beats are skipped
  // so a partial "Save & exit" video plays as one continuous piece.
  const segs = (segments || []).filter((s) => s && s.clip);
  const cur = segs[idx] || {};
  const clip = cur.clip;
  const isLive = clip && clip.url;

  const playFrom = (i) => { setIdx(i); setPlaying(true); };
  const next = () => { if (idx < segs.length - 1) playFrom(idx + 1); else { setPlaying(false); setIdx(0); } };

  useEffectST(() => {
    if (!playing) { if (mockT.current) clearTimeout(mockT.current); return; }
    if (isLive && vidRef.current) { vidRef.current.src = clip.url; vidRef.current.play().catch(() => {}); }
    else { mockT.current = setTimeout(next, Math.max(2200, (clip?.dur || 5) * 1000)); }
    return () => { if (mockT.current) clearTimeout(mockT.current); };
  }, [playing, idx]);

  return (
    <div style={{ position: "absolute", inset: 0, background: "#0c160c", borderRadius: "inherit", overflow: "hidden" }}>
      {isLive
        ? <video ref={vidRef} playsInline onEnded={next} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} />
        : <img src={poster} alt="" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", filter: "saturate(.9) brightness(.85)" }} />}
      <div style={{ position: "absolute", top: 18, left: 18, padding: "8px 15px", borderRadius: 999,
        background: "rgba(12,18,12,.6)", backdropFilter: "blur(6px)", display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ fontFamily: "var(--font-sans)", fontSize: 12, fontWeight: 700, color: accent }}>{String(idx + 1).padStart(2, "0")}</span>
        <span style={{ fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, color: "#fff", maxWidth: 320,
          overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{cur.label}</span>
      </div>
      {!playing && (
        <button onClick={() => playFrom(0)} className="lw-press" aria-label="Play stitched video" style={{ position: "absolute",
          inset: 0, margin: "auto", width: 84, height: 84, borderRadius: "50%", border: "none", cursor: "pointer",
          background: "rgba(254,252,245,.94)", display: "flex", alignItems: "center", justifyContent: "center" }}>
          <svg width="30" height="30" viewBox="0 0 24 24" fill="#001D00"><path d="M7 4.5v15l13-7.5z"/></svg>
        </button>
      )}
      <div style={{ position: "absolute", bottom: 16, left: 18, right: 18, display: "flex", gap: 6 }}>
        {segs.map((s, i) => (
          <div key={i} onClick={() => playFrom(i)} style={{ flex: 1, height: 5, borderRadius: 3, cursor: "pointer",
            background: i <= idx && playing ? accent : i < idx ? accent : "rgba(254,252,245,.28)" }} />
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { StudioScreen, StitchPlayer });
