// Stash showcase video — mobile-first scenes (540×960, 9:16)
// 0–3   Brand intro
// 3–10  Snap (camera → scan → save)
// 10–15 Dashboard (net worth, accounts)
// 15–19 Currency morph
// 19–24 Plans & goals
// 24–28 Sharing & workspaces
// 28–30 Outro

const STASH = {
  bg: '#0a0c0d', surface: '#121517', surfaceHi: '#191d20',
  line: 'rgba(255,255,255,0.08)', lineStrong: 'rgba(255,255,255,0.14)',
  text: '#f4f5f3', dim: 'rgba(244,245,243,0.62)', faint: 'rgba(244,245,243,0.38)',
  accent: '#9ef068', accentDim: 'rgba(158,240,104,0.18)',
  food: '#e88c72', transport: '#6aa6d6', home: '#b8924a', fun: '#b87fc8', health: '#6bb896',
  ui: `'Geist', -apple-system, system-ui, sans-serif`,
  num: `'JetBrains Mono', 'SF Mono', ui-monospace, monospace`,
};

// Real Stash mark — 3 stacked rounded bars
function Mark({ size = 56, animated = false, t = 1 }) {
  const bars = [
    { y: 14, c: STASH.accent },
    { y: 28, c: '#c8c8c8' },
    { y: 42, c: '#6a6a6a' },
  ];
  return (
    <svg width={size} height={size} viewBox="0 0 64 64" style={{ display: 'block' }}>
      {bars.map((b, i) => {
        const w = animated ? Math.max(0, Math.min(1, t * 3 - i * 0.7)) * 48 : 48;
        return (
          <rect key={i} x={32 - w / 2} y={b.y} width={w} height={8} rx={4} fill={b.c} />
        );
      })}
    </svg>
  );
}

// Status bar
function StatusBar() {
  return (
    <div style={{
      position: 'absolute', top: 0, left: 0, right: 0, height: 44,
      padding: '14px 24px 0',
      display: 'flex', justifyContent: 'space-between', alignItems: 'center',
      color: STASH.text, fontSize: 13, fontWeight: 600, fontFamily: '-apple-system, system-ui',
      zIndex: 30,
    }}>
      <span>9:41</span>
      <span style={{ display: 'flex', gap: 5, alignItems: 'center' }}>
        <svg width="14" height="9" viewBox="0 0 17 11" fill="currentColor">
          <rect x="0" y="7" width="3" height="4" rx="0.6"/>
          <rect x="4.5" y="5" width="3" height="6" rx="0.6"/>
          <rect x="9" y="2.5" width="3" height="8.5" rx="0.6"/>
          <rect x="13.5" y="0" width="3" height="11" rx="0.6"/>
        </svg>
        <svg width="18" height="9" viewBox="0 0 22 11" fill="none" stroke="currentColor" strokeWidth="1.2">
          <rect x="0.5" y="0.5" width="19" height="10" rx="2.5"/>
          <rect x="2" y="2" width="14" height="7" rx="1" fill="currentColor"/>
          <path d="M21 3.5v4" strokeLinecap="round"/>
        </svg>
      </span>
      <div style={{
        position: 'absolute', top: 6, left: '50%', transform: 'translateX(-50%)',
        width: 88, height: 24, borderRadius: 14, background: '#000',
      }}/>
    </div>
  );
}

// Backdrop with subtle gradient
function Backdrop() {
  return (
    <Sprite start={0} end={30}>
      {() => (
        <div style={{
          position: 'absolute', inset: 0,
          background: `radial-gradient(80% 60% at 50% 0%, rgba(158,240,104,0.07), transparent 60%), ${STASH.bg}`,
        }}/>
      )}
    </Sprite>
  );
}

// Top chrome — small Stash mark in corner
function TopChrome() {
  return (
    <Sprite start={0} end={30}>
      {({ localTime }) => (
        <div style={{
          position: 'absolute', top: 0, left: 0, right: 0,
          padding: '20px 24px 0', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          color: STASH.dim, fontSize: 11, fontWeight: 500, letterSpacing: 1.4, textTransform: 'uppercase',
          fontFamily: STASH.ui, zIndex: 100, pointerEvents: 'none',
          opacity: localTime < 0.5 ? 0 : (localTime > 28 ? Math.max(0, 1 - (localTime - 28) / 1) : 0.7),
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Mark size={16}/>
            <span style={{ color: STASH.text, fontSize: 11, fontWeight: 600, letterSpacing: 0.4, textTransform: 'none' }}>Fynr</span>
          </div>
          <span style={{ fontFamily: STASH.num }}>{Math.min(30, localTime).toFixed(1)}s</span>
        </div>
      )}
    </Sprite>
  );
}

// Progress bar at bottom
function ProgressBar() {
  return (
    <Sprite start={0} end={30}>
      {({ localTime }) => (
        <div style={{
          position: 'absolute', bottom: 14, left: 24, right: 24, height: 2,
          background: 'rgba(255,255,255,0.08)', borderRadius: 1, overflow: 'hidden', zIndex: 100,
        }}>
          <div style={{
            position: 'absolute', inset: 0, width: `${(localTime / 30) * 100}%`,
            background: STASH.accent, borderRadius: 1,
            boxShadow: `0 0 8px ${STASH.accent}`,
          }}/>
        </div>
      )}
    </Sprite>
  );
}

// ── 1. Brand intro ─────────────────────────────────────────────────
function SceneBrand({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const exitT = duration - localTime;
        const exitOp = exitT < 0.5 ? exitT / 0.5 : 1;
        const exitS = exitT < 0.5 ? 1 + (1 - exitT / 0.5) * 0.2 : 1;

        const wordOp = animate({ from: 0, to: 1, start: 1.1, end: 1.6 })(t);
        const wordY = animate({ from: 16, to: 0, start: 1.1, end: 1.6, ease: Easing.easeOutCubic })(t);
        const tagOp = animate({ from: 0, to: 1, start: 1.6, end: 2.1 })(t);

        const ring = animate({ from: 0, to: 1, start: 0.2, end: 1.5 })(t);

        return (
          <div style={{
            position: 'absolute', inset: 0,
            display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
            opacity: exitOp, transform: `scale(${exitS})`, gap: 28,
          }}>
            <div style={{
              position: 'absolute', width: 380 * ring, height: 380 * ring,
              borderRadius: '50%', border: `1px solid ${STASH.accentDim}`,
              opacity: 1 - ring,
            }}/>
            <div style={{
              position: 'absolute', width: 560 * ring, height: 560 * ring,
              borderRadius: '50%', border: `1px solid ${STASH.accentDim}`,
              opacity: 0.5 - ring * 0.5,
            }}/>

            <div style={{
              padding: 28, borderRadius: 36,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              boxShadow: `0 0 80px ${STASH.accent}60`,
            }}>
              <Mark size={120} animated t={t} />
            </div>

            <div style={{ textAlign: 'center', opacity: wordOp, transform: `translateY(${wordY}px)` }}>
              <div style={{
                fontFamily: STASH.ui, fontWeight: 700, fontSize: 68,
                letterSpacing: -3.2, color: STASH.text, lineHeight: 1,
              }}>Fynr</div>
              <div style={{
                fontFamily: STASH.num, fontSize: 12, color: STASH.dim,
                letterSpacing: 2, textTransform: 'uppercase', marginTop: 16,
                opacity: tagOp,
              }}>Personal finance · in 5 seconds</div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 2. The Snap (camera → scan → save) ─────────────────────────────
function SceneSnap({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enterOp = animate({ from: 0, to: 1, start: 0, end: 0.5 })(t);
        const enterY = animate({ from: 30, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitT = duration - t;
        const exitOp = exitT < 0.4 ? exitT / 0.4 : 1;

        // Scan sweep 2.0 → 4.5
        const scanT = clamp((t - 2.0) / 2.5, 0, 1);
        const scanY = scanT * 360;
        const scanActive = t >= 2.0 && t <= 4.7;

        // Fields fly out 4.6 → 6.0
        const f = (i) => ({
          op: animate({ from: 0, to: 1, start: 4.5 + i * 0.25, end: 5.0 + i * 0.25 })(t),
          y: animate({ from: 18, to: 0, start: 4.5 + i * 0.25, end: 5.0 + i * 0.25, ease: Easing.easeOutCubic })(t),
        });

        // Receipt shrinks up after scan
        const rs = animate({ from: 1, to: 0.55, start: 4.3, end: 5.0, ease: Easing.easeInOutCubic })(t);
        const ry = animate({ from: 0, to: -90, start: 4.3, end: 5.0, ease: Easing.easeInOutCubic })(t);

        // "Saved" check after 6.2
        const savedOp = animate({ from: 0, to: 1, start: 6.0, end: 6.4 })(t);
        const savedScale = animate({ from: 0, to: 1, start: 6.0, end: 6.4, ease: Easing.easeOutBack })(t);

        const labelOp = animate({ from: 0, to: 1, start: 0.4, end: 0.9 })(t);

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            display: 'flex', flexDirection: 'column',
            opacity: enterOp * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
          }}>
            <div style={{ opacity: labelOp, marginBottom: 18 }}>
              <div style={{
                fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase',
                color: STASH.accent, fontWeight: 500,
              }}>The 5-second flow</div>
              <div style={{
                fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8,
                lineHeight: 1.05,
              }}>Snap. <span style={{ color: STASH.dim }}>Fynr does the rest.</span></div>
            </div>

            <div style={{
              flex: 1, position: 'relative',
              background: STASH.surface, borderRadius: 28,
              border: `1px solid ${STASH.line}`, overflow: 'hidden',
              padding: 20,
            }}>
              {/* Camera viewfinder header */}
              <div style={{
                display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                fontSize: 12, fontWeight: 600,
              }}>
                <span>New expense</span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 6, color: STASH.accent, fontSize: 11 }}>
                  <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor">
                    <path d="M12 2l1.8 6.2L20 10l-6.2 1.8L12 18l-1.8-6.2L4 10l6.2-1.8z"/>
                  </svg>
                  {scanActive ? 'Reading…' : (t > 5 ? 'Done' : 'Ready')}
                </span>
              </div>

              {/* Receipt */}
              <div style={{
                position: 'absolute', left: '50%', top: 70,
                transform: `translateX(-50%) translateY(${ry}px) scale(${rs})`,
                width: 220, aspectRatio: '0.7',
                background: '#f4f1e8', borderRadius: 16,
                color: '#1a1a1a', padding: '18px 18px 14px',
                boxShadow: scanActive
                  ? `0 16px 40px ${STASH.accent}30, 0 0 0 1px ${STASH.accent}90`
                  : '0 16px 40px rgba(0,0,0,0.5)',
                fontFamily: STASH.num, transformOrigin: 'top center',
                overflow: 'hidden',
              }}>
                <div style={{ fontSize: 16, fontWeight: 700, color: '#d3503a', letterSpacing: 0.6 }}>MIGROS</div>
                <div style={{ fontSize: 8, color: '#666' }}>Bahnhofstrasse 56, Zürich</div>
                <div style={{ fontSize: 8, color: '#666' }}>06.05.2026 · 18:42</div>
                <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column', gap: 5 }}>
                  {[60, 40, 90, 85, 70, 95, 50].map((w, i) => (
                    <div key={i} style={{ display: 'flex', justifyContent: 'space-between' }}>
                      <span style={{ background: i === 5 ? '#1a1a1a' : '#888', height: i === 5 ? 8 : 6, borderRadius: 1, opacity: i === 5 ? 1 : 0.5, width: w + '%' }}/>
                      <span style={{ background: i === 5 ? '#1a1a1a' : '#888', height: i === 5 ? 8 : 6, borderRadius: 1, opacity: i === 5 ? 1 : 0.5, width: 28 }}/>
                    </div>
                  ))}
                </div>

                {/* Scan line */}
                {scanActive && (
                  <>
                    <div style={{
                      position: 'absolute', left: 0, right: 0, top: 0,
                      height: scanY, background: `linear-gradient(180deg, transparent, ${STASH.accent}30 80%, ${STASH.accent}55)`,
                      pointerEvents: 'none',
                    }}/>
                    <div style={{
                      position: 'absolute', left: 0, right: 0, top: scanY, height: 2,
                      background: STASH.accent,
                      boxShadow: `0 0 14px 3px ${STASH.accent}, 0 0 32px ${STASH.accent}`,
                    }}/>
                  </>
                )}
              </div>

              {/* Extracted fields */}
              <div style={{
                position: 'absolute', left: 20, right: 20, bottom: 20,
                display: 'flex', flexDirection: 'column', gap: 8,
              }}>
                {[
                  { lbl: 'Amount', val: 'CHF 42.85', conf: '99%', big: true },
                  { lbl: 'Merchant', val: 'Migros', conf: '96%' },
                  { lbl: 'Category', val: 'Food', conf: '88%', cat: STASH.food },
                ].map((row, i) => (
                  <div key={i} style={{
                    opacity: f(i).op, transform: `translateY(${f(i).y}px)`,
                    padding: row.big ? '12px 14px' : '10px 14px',
                    borderRadius: 12, background: STASH.surfaceHi,
                    border: `0.5px solid ${STASH.line}`,
                    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  }}>
                    <div>
                      <div style={{ fontSize: 9, letterSpacing: 0.6, textTransform: 'uppercase', color: STASH.faint }}>{row.lbl}</div>
                      <div style={{
                        fontFamily: row.cat ? STASH.ui : STASH.num,
                        fontSize: row.big ? 22 : 13, fontWeight: 600, marginTop: 2,
                      }}>
                        {row.cat ? (
                          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '2px 9px', borderRadius: 999, background: 'rgba(232,140,114,0.16)', color: row.cat, fontSize: 11 }}>
                            <span style={{ width: 6, height: 6, borderRadius: 2, background: row.cat }}/> {row.val}
                          </span>
                        ) : row.val}
                      </div>
                    </div>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontFamily: STASH.num, fontSize: 9, color: STASH.faint }}>
                      <span style={{ width: 5, height: 5, borderRadius: '50%', background: STASH.accent, boxShadow: `0 0 5px ${STASH.accent}` }}/> {row.conf}
                    </span>
                  </div>
                ))}
              </div>

              {/* Saved checkmark overlay */}
              {savedOp > 0 && (
                <div style={{
                  position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                  background: `rgba(10,12,13,${savedOp * 0.7})`, opacity: savedOp,
                }}>
                  <div style={{
                    width: 110, height: 110, borderRadius: '50%', background: STASH.accent,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    transform: `scale(${savedScale})`,
                    boxShadow: `0 0 60px ${STASH.accent}80`,
                  }}>
                    <svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="#0a0c0d" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M4 12l5 5 11-12"/>
                    </svg>
                  </div>
                </div>
              )}
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 3. Dashboard (net worth + accounts) ─────────────────────────────
function SceneDashboard({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5 })(t);
        const enterY = animate({ from: 30, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitT = duration - t;
        const exitOp = exitT < 0.4 ? exitT / 0.4 : 1;

        const net = animate({ from: 0, to: 56283, start: 0.3, end: 1.6, ease: Easing.easeOutCubic })(t);
        const netStr = Math.round(net).toLocaleString('en-US').replace(/,/g, "'");

        // Sparkline draw
        const sparkP = animate({ from: 0, to: 1, start: 0.6, end: 1.8, ease: Easing.easeOutCubic })(t);

        // Account cards stagger
        const acc = (i) => ({
          op: animate({ from: 0, to: 1, start: 1.5 + i * 0.18, end: 2.0 + i * 0.18 })(t),
          y: animate({ from: 20, to: 0, start: 1.5 + i * 0.18, end: 2.0 + i * 0.18, ease: Easing.easeOutCubic })(t),
        });

        // New transaction lands at 2.8
        const txOp = animate({ from: 0, to: 1, start: 2.8, end: 3.2 })(t);
        const txY = animate({ from: 30, to: 0, start: 2.8, end: 3.2, ease: Easing.easeOutBack })(t);
        const flashOp = t > 2.8 && t < 3.6 ? Math.max(0, 1 - (t - 2.8) / 0.8) : 0;

        const labelOp = animate({ from: 0, to: 1, start: 0.1, end: 0.6 })(t);

        const data = [0.78, 0.81, 0.79, 0.84, 0.86, 0.91, 0.94, 0.92, 0.97, 0.99, 0.97, 1.0];
        const w = 460, h = 80, mn = Math.min(...data), mx = Math.max(...data);
        const pts = data.map((v, i) => [(i / (data.length - 1)) * w, h - ((v - mn) / (mx - mn)) * (h - 12) - 6]);
        const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ',' + p[1].toFixed(1)).join(' ');

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
          }}>
            <div style={{ opacity: labelOp, marginBottom: 22 }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Your money</div>
              <div style={{ fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8 }}>One number,<br/><span style={{ color: STASH.dim }}>every account.</span></div>
            </div>

            <div style={{
              padding: 22, borderRadius: 24,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
            }}>
              <div style={{ fontSize: 10, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>Net worth</div>
              <div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, marginTop: 6 }}>
                <span style={{ fontFamily: STASH.num, fontSize: 48, fontWeight: 500, letterSpacing: -2, lineHeight: 1 }}>{netStr}</span>
                <span style={{ fontFamily: STASH.num, fontSize: 14, color: STASH.dim, paddingBottom: 6 }}>CHF</span>
              </div>
              <div style={{
                display: 'inline-flex', alignItems: 'center', gap: 4, marginTop: 10,
                padding: '3px 9px', borderRadius: 999,
                background: STASH.accentDim, color: STASH.accent,
                fontFamily: STASH.num, fontSize: 11, fontWeight: 500,
              }}>
                <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>
                +2.4% · CHF 1'320
              </div>

              <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ marginTop: 14 }}>
                <defs>
                  <linearGradient id="dashSpark" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stopColor={STASH.accent} stopOpacity="0.32"/>
                    <stop offset="100%" stopColor={STASH.accent} stopOpacity="0"/>
                  </linearGradient>
                </defs>
                <path d={line + ` L${w},${h} L0,${h} Z`} fill="url(#dashSpark)" opacity={sparkP}/>
                <path d={line} fill="none" stroke={STASH.accent} strokeWidth="2"
                  strokeDasharray={`${1200 * sparkP} 1200`} strokeLinejoin="round"/>
                <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="4" fill={STASH.accent} opacity={sparkP}/>
              </svg>
            </div>

            <div style={{ display: 'flex', gap: 10, marginTop: 14 }}>
              {[
                { n: 'UBS', s: 'Bank · CHF', b: "4'820.55", c: STASH.accent, bg: 'rgba(158,240,104,0.13)' },
                { n: 'VIAC 3a', s: 'Savings', b: "18'420.00", c: STASH.transport, bg: 'rgba(126,184,228,0.13)' },
                { n: 'Revolut', s: 'EUR', b: '€842.10', c: STASH.fun, bg: 'rgba(184,127,200,0.13)' },
              ].map((a, i) => (
                <div key={i} style={{
                  flex: 1, padding: 12, borderRadius: 14,
                  background: STASH.surface, border: `1px solid ${STASH.line}`,
                  opacity: acc(i).op, transform: `translateY(${acc(i).y}px)`,
                }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
                    <div style={{ width: 22, height: 22, borderRadius: 7, background: a.bg, color: a.c, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 700 }}>{a.n[0]}</div>
                    <div style={{ fontSize: 9, color: STASH.faint }}>{a.s}</div>
                  </div>
                  <div style={{ fontFamily: STASH.num, fontSize: 14, fontWeight: 500, letterSpacing: -0.3 }}>{a.b}</div>
                </div>
              ))}
            </div>

            {/* New transaction landing */}
            <div style={{
              marginTop: 16, padding: '12px 14px', borderRadius: 14,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              display: 'flex', alignItems: 'center', gap: 12,
              opacity: txOp, transform: `translateY(${txY}px)`,
              boxShadow: `0 0 0 1px ${STASH.accent}${Math.round(flashOp * 99).toString(16).padStart(2, '0')}, 0 0 ${24 * flashOp}px ${STASH.accent}${Math.round(flashOp * 99).toString(16).padStart(2, '0')}`,
            }}>
              <div style={{ width: 32, height: 32, borderRadius: 10, background: 'rgba(232,140,114,0.16)', color: STASH.food, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700 }}>M</div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 12, fontWeight: 500 }}>Migros</div>
                <div style={{ fontSize: 10, color: STASH.faint, fontFamily: STASH.num }}>Food · just now</div>
              </div>
              <div style={{ fontFamily: STASH.num, fontSize: 13, fontWeight: 500 }}>−42.85</div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 4. Currency morph ──────────────────────────────────────────────
function SceneCurrency({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5 })(t);
        const enterY = animate({ from: 30, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitT = duration - t;
        const exitOp = exitT < 0.4 ? exitT / 0.4 : 1;

        // CHF visible 0-2, swap to VND at 2, back at 3
        const flipPhase = t < 1.6 ? 0 : (t < 2.0 ? 1 : (t < 3.4 ? 2 : (t < 3.8 ? 3 : 0)));
        const showVND = t >= 1.8 && t <= 3.6;
        const flipScale = (t > 1.6 && t < 2.0) || (t > 3.4 && t < 3.8) ? 0.7 : 1;
        const flipOp = (t > 1.6 && t < 2.0) || (t > 3.4 && t < 3.8) ? 0.5 : 1;

        const valCHF = "56'283";
        const valVND = "1'595M";
        const labelOp = animate({ from: 0, to: 1, start: 0.1, end: 0.5 })(t);

        // Toggle indicator position
        const togglePos = showVND ? 1 : 0;

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
            display: 'flex', flexDirection: 'column',
          }}>
            <div style={{ opacity: labelOp }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Multi-currency</div>
              <div style={{ fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8 }}>CHF in Zürich.<br/><span style={{ color: STASH.accent }}>VND in Hà Nội.</span></div>
            </div>

            <div style={{
              flex: 1, display: 'flex', flexDirection: 'column',
              alignItems: 'center', justifyContent: 'center', gap: 32,
            }}>
              {/* Toggle */}
              <div style={{
                display: 'inline-flex', padding: 4, borderRadius: 999,
                background: STASH.surface, border: `1px solid ${STASH.line}`,
                fontFamily: STASH.num, fontSize: 13, fontWeight: 600,
                position: 'relative',
              }}>
                <div style={{
                  position: 'absolute', top: 4, bottom: 4, width: 'calc(50% - 4px)',
                  left: `calc(${togglePos * 50}% + 4px)`,
                  background: STASH.text, borderRadius: 999,
                  transition: 'left 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)',
                }}/>
                <div style={{ position: 'relative', padding: '8px 22px', color: showVND ? STASH.dim : STASH.bg }}>CHF</div>
                <div style={{ position: 'relative', padding: '8px 22px', color: showVND ? STASH.bg : STASH.dim }}>VND</div>
              </div>

              {/* Big amount */}
              <div style={{
                textAlign: 'center', fontFamily: STASH.num,
                transform: `scale(${flipScale})`, opacity: flipOp,
                transition: 'transform 0.25s, opacity 0.25s',
              }}>
                <div style={{
                  fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: STASH.faint, fontFamily: STASH.ui,
                }}>{showVND ? '🇻🇳 Vietnam' : '🇨🇭 Switzerland'}</div>
                <div style={{
                  marginTop: 14, fontSize: 76, fontWeight: 500, letterSpacing: -3, lineHeight: 1,
                  color: STASH.text,
                }}>
                  {showVND ? valVND : valCHF}
                </div>
                <div style={{ fontSize: 24, color: STASH.dim, marginTop: 8 }}>
                  {showVND ? '₫' : 'CHF'}
                </div>
              </div>

              <div style={{
                fontSize: 13, color: STASH.dim, textAlign: 'center', maxWidth: 360,
                lineHeight: 1.5,
              }}>
                Same money. Different number. Daily FX, cached at the edge.
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 5. Plans & Goals ───────────────────────────────────────────────
function ScenePlans({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5 })(t);
        const enterY = animate({ from: 30, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitT = duration - t;
        const exitOp = exitT < 0.4 ? exitT / 0.4 : 1;

        // Rate sweeps 0.6 → 2.4, settles at 7%
        const rateAnim = (() => {
          if (t < 0.6) return 0;
          if (t < 1.6) return ((t - 0.6) / 1.0) * 12;
          if (t < 2.4) return 12 - ((t - 1.6) / 0.8) * 5;
          return 7;
        })();
        const rate = rateAnim;

        // Goal ring fills 2.6 → 4.2
        const ringP = animate({ from: 0, to: 0.62, start: 2.4, end: 3.8, ease: Easing.easeOutCubic })(t);
        const goalEnter = animate({ from: 0, to: 1, start: 2.2, end: 2.7 })(t);

        // Projection chart
        const principal = 56283;
        const r = rate / 100 / 12;
        const months = 60;
        const data = [];
        for (let i = 0; i <= months; i++) data.push(principal * Math.pow(1 + r, i));
        const final = data[months];
        const w = 460, h = 100;
        const mn = data[0], mx = Math.max(data[months], data[0] * 1.05);
        const range = mx - mn || 1;
        const pts = data.map((v, i) => [(i / months) * w, h - ((v - mn) / range) * (h - 14) - 7]);
        const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ',' + p[1].toFixed(1)).join(' ');

        const labelOp = animate({ from: 0, to: 1, start: 0.1, end: 0.5 })(t);

        // Slider thumb position based on rate
        const thumbX = (rate / 12) * 100;

        // Goal ring SVG
        const ringR = 38, ringC = 2 * Math.PI * ringR;

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
            display: 'flex', flexDirection: 'column', gap: 16,
          }}>
            <div style={{ opacity: labelOp }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Plans & goals</div>
              <div style={{ fontSize: 30, fontWeight: 600, letterSpacing: -1.2, marginTop: 8, lineHeight: 1.05 }}>Project where<br/><span style={{ color: STASH.dim }}>you're heading.</span></div>
            </div>

            {/* Plan card */}
            <div style={{
              padding: 18, borderRadius: 22,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
                <div>
                  <div style={{ fontSize: 9, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>Retirement · in 5y</div>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 4 }}>
                    <span style={{ fontFamily: STASH.num, fontSize: 36, fontWeight: 500, color: STASH.accent, letterSpacing: -1.5, lineHeight: 1 }}>{rate.toFixed(1)}</span>
                    <span style={{ fontSize: 12, color: STASH.dim }}>% / year</span>
                  </div>
                </div>
                <div style={{
                  padding: '4px 10px', borderRadius: 999,
                  background: STASH.accentDim, color: STASH.accent,
                  fontSize: 10, fontWeight: 600,
                  display: 'inline-flex', alignItems: 'center', gap: 4,
                }}>
                  <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>
                  +CHF {Math.round(final - principal).toLocaleString('en-US').replace(/,/g, "'")}
                </div>
              </div>

              <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ marginTop: 10 }}>
                <defs>
                  <linearGradient id="planG" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stopColor={STASH.accent} stopOpacity="0.36"/>
                    <stop offset="100%" stopColor={STASH.accent} stopOpacity="0"/>
                  </linearGradient>
                </defs>
                <line x1="0" x2={w} y1={h * 0.5} y2={h * 0.5} stroke="rgba(255,255,255,0.05)" strokeDasharray="3,4"/>
                <path d={line + ` L${w},${h} L0,${h} Z`} fill="url(#planG)"/>
                <path d={line} fill="none" stroke={STASH.accent} strokeWidth="2.4" strokeLinejoin="round"/>
                <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="5" fill={STASH.accent} stroke={STASH.bg} strokeWidth="2"/>
              </svg>

              {/* Slider track */}
              <div style={{ marginTop: 10, position: 'relative', height: 18 }}>
                <div style={{ position: 'absolute', top: 8, left: 0, right: 0, height: 3, background: STASH.lineStrong, borderRadius: 2 }}/>
                <div style={{ position: 'absolute', top: 8, left: 0, width: `${thumbX}%`, height: 3, background: STASH.accent, borderRadius: 2 }}/>
                <div style={{
                  position: 'absolute', top: 0, left: `calc(${thumbX}% - 9px)`,
                  width: 18, height: 18, borderRadius: '50%',
                  background: STASH.accent,
                  boxShadow: `0 0 0 6px ${STASH.accent}28, 0 2px 8px ${STASH.accent}66`,
                }}/>
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between', fontFamily: STASH.num, fontSize: 9, color: STASH.faint, marginTop: 4 }}>
                <span>0%</span><span>6%</span><span>12%</span>
              </div>
            </div>

            {/* Goal card with ring */}
            <div style={{
              padding: 18, borderRadius: 22,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              display: 'flex', alignItems: 'center', gap: 16,
              opacity: goalEnter, transform: `translateY(${(1 - goalEnter) * 16}px)`,
            }}>
              <div style={{ position: 'relative', width: 90, height: 90, flexShrink: 0 }}>
                <svg width="90" height="90" viewBox="0 0 90 90">
                  <circle cx="45" cy="45" r={ringR} fill="none" stroke={STASH.lineStrong} strokeWidth="6"/>
                  <circle cx="45" cy="45" r={ringR} fill="none" stroke={STASH.accent} strokeWidth="6" strokeLinecap="round"
                    strokeDasharray={`${ringC * ringP} ${ringC}`}
                    transform="rotate(-90 45 45)"
                    style={{ filter: `drop-shadow(0 0 4px ${STASH.accent})` }}
                  />
                </svg>
                <div style={{
                  position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontFamily: STASH.num, fontSize: 16, fontWeight: 600, letterSpacing: -0.5,
                }}>{Math.round(ringP * 100)}%</div>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 9, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>Goal</div>
                <div style={{ fontSize: 16, fontWeight: 600, marginTop: 2 }}>Holiday in Bali</div>
                <div style={{ fontSize: 11, color: STASH.dim, marginTop: 4, fontFamily: STASH.num }}>
                  CHF 1'860 / 3'000 · 4 months left
                </div>
                <div style={{
                  display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 8,
                  padding: '3px 9px', borderRadius: 999,
                  background: STASH.accentDim, color: STASH.accent,
                  fontSize: 10, fontWeight: 600,
                }}>
                  <span style={{ width: 5, height: 5, borderRadius: '50%', background: STASH.accent, boxShadow: `0 0 5px ${STASH.accent}` }}/>
                  Auto-saving 285/mo
                </div>
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 6. Sharing & workspaces ────────────────────────────────────────
function SceneShare({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5 })(t);
        const enterY = animate({ from: 30, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitT = duration - t;
        const exitOp = exitT < 0.4 ? exitT / 0.4 : 1;

        // Workspace switch at 1.4
        const ws = t < 1.4 ? 0 : 1;
        const switchScale = (t > 1.2 && t < 1.6) ? 0.92 : 1;

        // Member avatars stagger in 1.8 → 3.0
        const mem = (i) => ({
          op: animate({ from: 0, to: 1, start: 1.8 + i * 0.18, end: 2.2 + i * 0.18 })(t),
          y: animate({ from: 14, to: 0, start: 1.8 + i * 0.18, end: 2.2 + i * 0.18, ease: Easing.easeOutBack })(t),
          s: animate({ from: 0.6, to: 1, start: 1.8 + i * 0.18, end: 2.2 + i * 0.18, ease: Easing.easeOutBack })(t),
        });

        // Invite link copies at 3.2
        const copied = t > 3.0 && t < 3.8;
        const copyScale = animate({ from: 0, to: 1, start: 3.0, end: 3.4, ease: Easing.easeOutBack })(t);
        const copyExit = t > 3.6 ? Math.max(0, 1 - (t - 3.6) / 0.4) : 1;

        const labelOp = animate({ from: 0, to: 1, start: 0.1, end: 0.5 })(t);

        const workspaces = ws === 0
          ? { name: 'Personal', dot: STASH.accent }
          : { name: 'Family', dot: STASH.fun };

        const members = [
          { i: 'M', n: 'Mai (you)', r: 'Owner', c: STASH.accent, bg: 'rgba(158,240,104,0.18)' },
          { i: 'L', n: 'Levi', r: 'Editor', c: STASH.transport, bg: 'rgba(106,166,214,0.18)' },
          { i: 'U', n: 'Uyen', r: 'Editor', c: STASH.fun, bg: 'rgba(184,127,200,0.18)' },
          { i: 'A', n: 'Anh', r: 'Viewer', c: STASH.health, bg: 'rgba(107,184,150,0.18)' },
        ];

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
            display: 'flex', flexDirection: 'column', gap: 18,
          }}>
            <div style={{ opacity: labelOp }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Built for shared lives</div>
              <div style={{ fontSize: 30, fontWeight: 600, letterSpacing: -1.2, marginTop: 8, lineHeight: 1.05 }}>One workspace<br/><span style={{ color: STASH.dim }}>per chapter.</span></div>
            </div>

            {/* Workspace switcher */}
            <div style={{
              alignSelf: 'flex-start',
              display: 'inline-flex', alignItems: 'center', gap: 8,
              padding: '8px 14px 8px 12px', borderRadius: 999,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              fontSize: 12, fontWeight: 600,
              transform: `scale(${switchScale})`,
              transition: 'transform 0.2s, background 0.3s',
              boxShadow: t > 1.2 && t < 1.6 ? `0 0 0 4px ${STASH.accent}30` : 'none',
            }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: workspaces.dot, transition: 'background 0.3s' }}/>
              <span>{workspaces.name}</span>
              <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"><path d="M6 9l6 6 6-6"/></svg>
            </div>

            {/* Members card */}
            <div style={{
              padding: 18, borderRadius: 22,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>Members</div>
                <div style={{ fontFamily: STASH.num, fontSize: 11, color: STASH.faint }}>{members.length}</div>
              </div>
              <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
                {members.map((m, i) => (
                  <div key={i} style={{
                    display: 'flex', alignItems: 'center', gap: 12,
                    opacity: mem(i).op, transform: `translateY(${mem(i).y}px) scale(${mem(i).s})`,
                  }}>
                    <div style={{
                      width: 32, height: 32, borderRadius: '50%',
                      background: m.bg, color: m.c,
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 13, fontWeight: 700,
                    }}>{m.i}</div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 13, fontWeight: 500 }}>{m.n}</div>
                    </div>
                    <div style={{
                      fontSize: 9, fontWeight: 700, letterSpacing: 0.6, textTransform: 'uppercase',
                      color: m.r === 'Owner' ? STASH.accent : STASH.faint,
                      padding: '3px 8px', borderRadius: 4,
                      background: m.r === 'Owner' ? STASH.accentDim : 'rgba(255,255,255,0.04)',
                    }}>{m.r}</div>
                  </div>
                ))}
              </div>

              {/* Invite link row */}
              <div style={{
                marginTop: 14, padding: '10px 12px', borderRadius: 12,
                background: STASH.surfaceHi, border: `0.5px dashed ${STASH.lineStrong}`,
                display: 'flex', alignItems: 'center', gap: 10,
              }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={STASH.accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
                  <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
                </svg>
                <div style={{ flex: 1, fontFamily: STASH.num, fontSize: 11, color: STASH.dim }}>fynr.app/i/3F8x…2k</div>
                <span style={{ fontSize: 10, color: STASH.faint, fontFamily: STASH.num }}>expires 7d</span>
              </div>
            </div>

            {/* "Link copied" toast */}
            {(copied || copyExit < 1) && (
              <div style={{
                position: 'absolute', left: '50%', bottom: 70,
                transform: `translateX(-50%) scale(${copyScale * copyExit})`,
                padding: '10px 18px', borderRadius: 999,
                background: STASH.accent, color: STASH.bg,
                fontSize: 12, fontWeight: 600,
                display: 'flex', alignItems: 'center', gap: 8,
                boxShadow: `0 12px 32px ${STASH.accent}66`,
                opacity: copyExit,
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M4 12l5 5 11-12"/>
                </svg>
                Invite link copied
              </div>
            )}
          </div>
        );
      }}
    </Sprite>
  );
}

// ── 7. Outro ───────────────────────────────────────────────────────
function SceneOutro({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const markScale = animate({ from: 0.7, to: 1, start: 0, end: 0.5, ease: Easing.easeOutBack })(t);
        const markOp = animate({ from: 0, to: 1, start: 0, end: 0.4 })(t);
        const wordOp = animate({ from: 0, to: 1, start: 0.4, end: 0.9 })(t);
        const ctaOp = animate({ from: 0, to: 1, start: 0.9, end: 1.3 })(t);
        const ctaY = animate({ from: 14, to: 0, start: 0.9, end: 1.3, ease: Easing.easeOutCubic })(t);

        // Pulse halo
        const haloPhase = (Math.sin(t * 3) + 1) / 2;

        return (
          <div style={{
            position: 'absolute', inset: 0,
            display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
            color: STASH.text, fontFamily: STASH.ui, gap: 22,
          }}>
            <div style={{
              position: 'absolute', width: 360, height: 360, borderRadius: '50%',
              background: `radial-gradient(circle, ${STASH.accent}30, transparent 70%)`,
              opacity: 0.6 + haloPhase * 0.4,
              filter: 'blur(20px)',
            }}/>

            <div style={{
              padding: 24, borderRadius: 32,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              transform: `scale(${markScale})`, opacity: markOp,
              boxShadow: `0 0 80px ${STASH.accent}50`,
            }}>
              <Mark size={88} animated t={1} />
            </div>

            <div style={{ textAlign: 'center', opacity: wordOp }}>
              <div style={{ fontFamily: STASH.ui, fontWeight: 700, fontSize: 56, letterSpacing: -2.6, lineHeight: 1 }}>Fynr</div>
              <div style={{ fontFamily: STASH.num, fontSize: 11, color: STASH.accent, marginTop: 8, letterSpacing: 1.4, textTransform: 'uppercase' }}>fynr.app</div>
              <div style={{ fontSize: 14, color: STASH.dim, marginTop: 12, lineHeight: 1.4, maxWidth: 320 }}>
                Snap. Scan. Plan. Share.
              </div>
            </div>

            <div style={{
              padding: '14px 28px', borderRadius: 999,
              background: STASH.accent, color: STASH.bg,
              fontSize: 14, fontWeight: 600,
              opacity: ctaOp, transform: `translateY(${ctaY}px)`,
              boxShadow: `0 12px 32px ${STASH.accent}50`,
              display: 'inline-flex', alignItems: 'center', gap: 8,
            }}>
              Get Fynr
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ─────────────────────────────────────────────────────────────────
// SceneBudgets — budget bars stagger fill, upcoming list streams in
// ─────────────────────────────────────────────────────────────────
function SceneBudgets({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const enterY = animate({ from: 24, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitOp = t > duration - 0.5 ? Math.max(0, 1 - (t - (duration - 0.5)) / 0.5) : 1;

        const budgets = [
          { name: 'Groceries',     spent: 312, cap: 400, c: STASH.food,      icon: 'M3 7h18M5 7v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7M9 7V5a3 3 0 0 1 6 0v2' },
          { name: 'Transport',     spent: 78,  cap: 180, c: STASH.transport, icon: 'M5 17h14M7 17V7a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v10M7 13h10M9 17v3M15 17v3' },
          { name: 'Eating out',    spent: 220, cap: 240, c: STASH.fun,       icon: 'M3 8h18M5 8v8a4 4 0 0 0 4 4h6a4 4 0 0 0 4-4V8M9 4v4M15 4v4' },
          { name: 'Subscriptions', spent: 96,  cap: 160, c: STASH.health,    icon: 'M21 12a9 9 0 1 1-9-9 9 9 0 0 1 9 9zM12 7v5l3 2' },
        ];

        const upcoming = [
          { name: 'Spotify Family',   when: 'Tomorrow', amt: '−CHF 18.95',  cat: STASH.fun },
          { name: 'Rent',             when: 'May 28',   amt: "−CHF 1'650",  cat: STASH.home },
          { name: 'Salary · UBS',     when: 'May 31',   amt: "+CHF 6'420",  cat: STASH.accent, income: true },
        ];

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
          }}>
            <div style={{ marginBottom: 22 }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Budgets</div>
              <div style={{ fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8, lineHeight: 1.05 }}>
                Stay on plan,<br/><span style={{ color: STASH.dim }}>without thinking.</span>
              </div>
            </div>

            <div style={{
              padding: 18, borderRadius: 22,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
              display: 'flex', flexDirection: 'column', gap: 14,
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
                <span style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>May</span>
                <span style={{ fontFamily: STASH.num, fontSize: 11, color: STASH.dim }}>12 days left</span>
              </div>
              {budgets.map((b, i) => {
                const fillStart = 0.6 + i * 0.18;
                const fill = animate({ from: 0, to: 1, start: fillStart, end: fillStart + 0.7, ease: Easing.easeOutCubic })(t);
                const op = animate({ from: 0, to: 1, start: fillStart - 0.15, end: fillStart, ease: Easing.easeOutCubic })(t);
                const pct = Math.round((b.spent / b.cap) * 100);
                const over = b.spent / b.cap > 0.9;
                return (
                  <div key={i} style={{ opacity: op }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <div style={{
                          width: 22, height: 22, borderRadius: 7,
                          background: `${b.c}24`, color: b.c,
                          display: 'flex', alignItems: 'center', justifyContent: 'center',
                        }}>
                          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d={b.icon}/></svg>
                        </div>
                        <span style={{ fontSize: 13, fontWeight: 500 }}>{b.name}</span>
                      </div>
                      <span style={{ fontFamily: STASH.num, fontSize: 11, color: over ? '#ff8a6b' : STASH.dim }}>
                        <span style={{ color: STASH.text, fontWeight: 600 }}>{b.spent}</span> / {b.cap}
                      </span>
                    </div>
                    <div style={{
                      height: 6, borderRadius: 3, background: STASH.surfaceHi,
                      overflow: 'hidden', position: 'relative',
                    }}>
                      <div style={{
                        position: 'absolute', inset: 0,
                        width: `${(b.spent / b.cap) * 100 * fill}%`,
                        background: over
                          ? `linear-gradient(90deg, ${b.c}, #ff8a6b)`
                          : b.c,
                        borderRadius: 3,
                        boxShadow: over ? '0 0 8px #ff8a6b80' : 'none',
                      }}/>
                    </div>
                  </div>
                );
              })}
            </div>

            <div style={{ marginTop: 18 }}>
              <div style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint, marginBottom: 10 }}>Upcoming</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {upcoming.map((u, i) => {
                  const s = 2.4 + i * 0.18;
                  const op = animate({ from: 0, to: 1, start: s, end: s + 0.4, ease: Easing.easeOutCubic })(t);
                  const x = animate({ from: 16, to: 0, start: s, end: s + 0.4, ease: Easing.easeOutCubic })(t);
                  return (
                    <div key={i} style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: '10px 12px', borderRadius: 12,
                      background: STASH.surface, border: `1px solid ${STASH.line}`,
                      opacity: op, transform: `translateX(${x}px)`,
                    }}>
                      <div style={{ width: 6, height: 6, borderRadius: '50%', background: u.cat }}/>
                      <div style={{ flex: 1 }}>
                        <div style={{ fontSize: 12, fontWeight: 500 }}>{u.name}</div>
                        <div style={{ fontSize: 10, color: STASH.faint, fontFamily: STASH.num }}>{u.when}</div>
                      </div>
                      <div style={{ fontFamily: STASH.num, fontSize: 12, color: u.income ? STASH.accent : STASH.text, fontWeight: 600 }}>{u.amt}</div>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ─────────────────────────────────────────────────────────────────
// SceneImport — drag CSV/PDF, parse rows, auto-categorize, commit
// ─────────────────────────────────────────────────────────────────
function SceneImport({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const enterY = animate({ from: 24, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitOp = t > duration - 0.5 ? Math.max(0, 1 - (t - (duration - 0.5)) / 0.5) : 1;

        // 0–1.0   drop file  /  1.0–2.0 scan beam  / 2.0–4.0 rows + categorize / 4.0–6.0 commit
        const fileDropY = animate({ from: -120, to: 0, start: 0.4, end: 1.0, ease: Easing.easeOutCubic })(t);
        const fileOp = animate({ from: 0, to: 1, start: 0.4, end: 0.9 })(t);
        const scanActive = t > 1.1 && t < 2.4;
        const scanY = animate({ from: 0, to: 1, start: 1.1, end: 2.4, ease: Easing.linear })(t);
        const fileSettleOp = t > 2.4 ? Math.max(0, 1 - (t - 2.4) / 0.5) : 1;

        const rows = [
          { date: '04 May', m: 'Migros',          amt: '−CHF 42.85', cat: 'Groceries',     c: STASH.food },
          { date: '05 May', m: 'SBB Mobile',      amt: '−CHF 8.40',  cat: 'Transport',     c: STASH.transport },
          { date: '06 May', m: 'Spotify',         amt: '−CHF 18.95', cat: 'Subscriptions', c: STASH.fun },
          { date: '07 May', m: 'UBS · Salary',    amt: "+CHF 6'420", cat: 'Income',        c: STASH.accent, income: true },
          { date: '08 May', m: 'Coop Pronto',     amt: '−CHF 12.20', cat: 'Groceries',     c: STASH.food },
        ];

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
          }}>
            <div style={{ marginBottom: 18 }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>Import</div>
              <div style={{ fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8, lineHeight: 1.05 }}>
                Drop a statement.<br/><span style={{ color: STASH.dim }}>Done in seconds.</span>
              </div>
            </div>

            {/* Drop zone */}
            <div style={{
              position: 'relative', height: 130, borderRadius: 18,
              background: STASH.surface, border: `1.5px dashed ${scanActive ? STASH.accent : STASH.lineStrong}`,
              overflow: 'hidden',
              transition: 'border-color 0.2s',
              boxShadow: scanActive ? `inset 0 0 60px ${STASH.accent}18` : 'none',
            }}>
              {/* file card */}
              <div style={{
                position: 'absolute', left: '50%', top: '50%',
                transform: `translate(-50%, calc(-50% + ${fileDropY}px))`,
                opacity: fileOp * fileSettleOp,
                width: 220, padding: '12px 14px', borderRadius: 12,
                background: STASH.surfaceHi, border: `1px solid ${STASH.line}`,
                display: 'flex', alignItems: 'center', gap: 10,
                boxShadow: scanActive ? `0 0 24px ${STASH.accent}40` : '0 6px 16px rgba(0,0,0,0.4)',
              }}>
                <div style={{
                  width: 32, height: 38, borderRadius: 5, background: '#fff',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontFamily: STASH.num, fontSize: 9, color: '#1a1a1a', fontWeight: 700,
                  position: 'relative',
                }}>
                  <span>CSV</span>
                  <div style={{ position: 'absolute', top: 0, right: 0, width: 8, height: 8, background: STASH.surfaceHi, borderBottomLeftRadius: 3 }}/>
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>ubs-may-2026.csv</div>
                  <div style={{ fontSize: 10, color: STASH.faint, fontFamily: STASH.num }}>14 KB · 47 rows</div>
                </div>
                {scanActive && (
                  <div style={{ width: 14, height: 14, borderRadius: '50%', border: `2px solid ${STASH.accent}`, borderTopColor: 'transparent', animation: 'fynrSpin 0.8s linear infinite' }}/>
                )}
              </div>

              {/* scan beam */}
              {scanActive && (
                <div style={{
                  position: 'absolute', left: 0, right: 0, top: `${scanY * 100}%`,
                  height: 2, background: STASH.accent,
                  boxShadow: `0 0 12px ${STASH.accent}, 0 0 24px ${STASH.accent}80`,
                }}/>
              )}

              <style>{`@keyframes fynrSpin { to { transform: rotate(360deg); } }`}</style>
            </div>

            {/* rows table */}
            <div style={{
              marginTop: 14, padding: 14, borderRadius: 16,
              background: STASH.surface, border: `1px solid ${STASH.line}`,
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
                <span style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>Review</span>
                <span style={{ fontSize: 10, fontFamily: STASH.num, color: STASH.dim }}>auto-categorized</span>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
                {rows.map((r, i) => {
                  const s = 2.5 + i * 0.18;
                  const op = animate({ from: 0, to: 1, start: s, end: s + 0.35 })(t);
                  const x = animate({ from: -12, to: 0, start: s, end: s + 0.35, ease: Easing.easeOutCubic })(t);
                  return (
                    <div key={i} style={{
                      display: 'flex', alignItems: 'center', gap: 9,
                      opacity: op, transform: `translateX(${x}px)`,
                      fontFamily: STASH.num, fontSize: 11,
                    }}>
                      <span style={{ width: 38, color: STASH.faint }}>{r.date}</span>
                      <span style={{ flex: 1, fontFamily: STASH.ui, color: STASH.text }}>{r.m}</span>
                      <span style={{
                        padding: '2px 7px', borderRadius: 6,
                        background: `${r.c}1f`, color: r.c,
                        fontFamily: STASH.ui, fontSize: 9, fontWeight: 600,
                        letterSpacing: 0.3,
                      }}>{r.cat}</span>
                      <span style={{ width: 76, textAlign: 'right', color: r.income ? STASH.accent : STASH.text, fontWeight: 600 }}>{r.amt}</span>
                    </div>
                  );
                })}
              </div>
            </div>

            {/* commit toast */}
            {t > 4.4 && (() => {
              const op = animate({ from: 0, to: 1, start: 4.4, end: 4.8 })(t);
              const y = animate({ from: 16, to: 0, start: 4.4, end: 4.8, ease: Easing.easeOutCubic })(t);
              return (
                <div style={{
                  position: 'absolute', left: 24, right: 24, bottom: 60,
                  padding: '12px 16px', borderRadius: 14,
                  background: STASH.accent, color: STASH.bg,
                  display: 'flex', alignItems: 'center', gap: 10,
                  fontWeight: 600, fontSize: 13,
                  opacity: op, transform: `translateY(${y}px)`,
                  boxShadow: `0 12px 32px ${STASH.accent}50`,
                }}>
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M20 6L9 17l-5-5"/>
                  </svg>
                  <span>47 transactions imported</span>
                </div>
              );
            })()}
          </div>
        );
      }}
    </Sprite>
  );
}

// ─────────────────────────────────────────────────────────────────
// SceneLoans — people, loan card, repayment ticks balance down
// ─────────────────────────────────────────────────────────────────
function SceneLoans({ start, end }) {
  return (
    <Sprite start={start} end={end}>
      {({ localTime, duration }) => {
        const t = localTime;
        const enter = animate({ from: 0, to: 1, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const enterY = animate({ from: 24, to: 0, start: 0, end: 0.5, ease: Easing.easeOutCubic })(t);
        const exitOp = t > duration - 0.5 ? Math.max(0, 1 - (t - (duration - 0.5)) / 0.5) : 1;

        const people = [
          { initials: 'M', name: 'Mom',     bal: '+240',  c: STASH.accent, dim: 'rgba(158,240,104,0.18)' },
          { initials: 'L', name: 'Lukas',   bal: '−120',  c: '#e88c72',    dim: 'rgba(232,140,114,0.18)' },
          { initials: 'A', name: 'Anna',    bal: '+85',   c: STASH.accent, dim: 'rgba(158,240,104,0.18)' },
          { initials: 'T', name: 'Tom',     bal: '0',     c: STASH.faint,  dim: 'rgba(244,245,243,0.10)' },
        ];

        // Loan card balance ticks from 240 -> 180 between 3.0–4.4 (a 60 CHF repayment)
        const repayP = animate({ from: 0, to: 1, start: 3.0, end: 4.4, ease: Easing.easeOutCubic })(t);
        const balance = 240 - 60 * repayP;
        const balStr = balance.toFixed(0);
        const flashOp = t > 3.0 && t < 3.6 ? animate({ from: 0, to: 1, start: 3.0, end: 3.2 })(t) - animate({ from: 0, to: 1, start: 3.4, end: 3.6 })(t) : 0;

        const progressP = (240 - balance) / 240; // how much paid back
        const ringR = 28;
        const ringC = 2 * Math.PI * ringR;

        return (
          <div style={{
            position: 'absolute', inset: 0, padding: '60px 24px 40px',
            opacity: enter * exitOp, transform: `translateY(${enterY}px)`,
            color: STASH.text, fontFamily: STASH.ui,
          }}>
            <div style={{ marginBottom: 22 }}>
              <div style={{ fontSize: 11, letterSpacing: 1.8, textTransform: 'uppercase', color: STASH.accent, fontWeight: 500 }}>People & loans</div>
              <div style={{ fontSize: 32, fontWeight: 600, letterSpacing: -1.2, marginTop: 8, lineHeight: 1.05 }}>
                Who owes who,<br/><span style={{ color: STASH.dim }}>finally clear.</span>
              </div>
            </div>

            {/* People row */}
            <div style={{ display: 'flex', gap: 10, marginBottom: 16 }}>
              {people.map((p, i) => {
                const s = 0.6 + i * 0.12;
                const op = animate({ from: 0, to: 1, start: s, end: s + 0.4 })(t);
                const sc = animate({ from: 0.7, to: 1, start: s, end: s + 0.4, ease: Easing.easeOutBack })(t);
                return (
                  <div key={i} style={{
                    flex: 1, padding: 10, borderRadius: 14,
                    background: STASH.surface, border: `1px solid ${STASH.line}`,
                    display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6,
                    opacity: op, transform: `scale(${sc})`,
                  }}>
                    <div style={{
                      width: 32, height: 32, borderRadius: '50%',
                      background: p.dim, color: p.c,
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontWeight: 700, fontSize: 13,
                      border: `1.5px solid ${p.c}40`,
                    }}>{p.initials}</div>
                    <div style={{ fontSize: 10, color: STASH.dim }}>{p.name}</div>
                    <div style={{ fontFamily: STASH.num, fontSize: 11, fontWeight: 600, color: p.bal === '0' ? STASH.faint : p.c }}>
                      {p.bal === '0' ? '—' : `${p.bal}`}
                    </div>
                  </div>
                );
              })}
            </div>

            {/* Loan detail card */}
            {(() => {
              const cardOp = animate({ from: 0, to: 1, start: 1.2, end: 1.8, ease: Easing.easeOutCubic })(t);
              const cardY = animate({ from: 16, to: 0, start: 1.2, end: 1.8, ease: Easing.easeOutCubic })(t);
              return (
                <div style={{
                  padding: 20, borderRadius: 22,
                  background: STASH.surface, border: `1px solid ${STASH.line}`,
                  opacity: cardOp, transform: `translateY(${cardY}px)`,
                  position: 'relative', overflow: 'hidden',
                }}>
                  {/* flash on payment */}
                  <div style={{
                    position: 'absolute', inset: 0,
                    background: `radial-gradient(circle at 50% 50%, ${STASH.accent}30, transparent 70%)`,
                    opacity: flashOp, pointerEvents: 'none',
                  }}/>

                  <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                    <svg width="72" height="72" viewBox="0 0 72 72" style={{ flexShrink: 0 }}>
                      <circle cx="36" cy="36" r={ringR} fill="none" stroke={STASH.surfaceHi} strokeWidth="5"/>
                      <circle cx="36" cy="36" r={ringR} fill="none" stroke={STASH.accent} strokeWidth="5"
                        strokeLinecap="round" transform="rotate(-90 36 36)"
                        strokeDasharray={`${progressP * ringC} ${ringC}`}/>
                      <text x="36" y="34" textAnchor="middle" fill={STASH.text} fontFamily="Geist" fontSize="14" fontWeight="700">M</text>
                      <text x="36" y="48" textAnchor="middle" fill={STASH.dim} fontFamily="JetBrains Mono" fontSize="8">{Math.round(progressP * 100)}%</text>
                    </svg>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 11, letterSpacing: 1, textTransform: 'uppercase', color: STASH.faint }}>Mom owes you</div>
                      <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 2 }}>
                        <span style={{ fontFamily: STASH.num, fontSize: 36, fontWeight: 500, letterSpacing: -1.5, lineHeight: 1, color: STASH.accent }}>{balStr}</span>
                        <span style={{ fontFamily: STASH.num, fontSize: 12, color: STASH.dim }}>CHF</span>
                      </div>
                      <div style={{ fontSize: 10, color: STASH.faint, fontFamily: STASH.num, marginTop: 4 }}>
                        due May 31 · 1.5% p.a.
                      </div>
                    </div>
                  </div>

                  {/* Activity / repayment row */}
                  {t > 3.0 && (() => {
                    const op = animate({ from: 0, to: 1, start: 3.0, end: 3.4 })(t);
                    const y = animate({ from: 10, to: 0, start: 3.0, end: 3.4, ease: Easing.easeOutCubic })(t);
                    return (
                      <div style={{
                        marginTop: 14, padding: '10px 12px', borderRadius: 12,
                        background: STASH.accentDim, border: `1px solid ${STASH.accent}40`,
                        display: 'flex', alignItems: 'center', gap: 10,
                        opacity: op, transform: `translateY(${y}px)`,
                      }}>
                        <div style={{
                          width: 26, height: 26, borderRadius: '50%', background: STASH.accent,
                          display: 'flex', alignItems: 'center', justifyContent: 'center',
                        }}>
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={STASH.bg} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                            <path d="M12 5v14M5 12l7 7 7-7"/>
                          </svg>
                        </div>
                        <div style={{ flex: 1 }}>
                          <div style={{ fontSize: 12, fontWeight: 600, color: STASH.text }}>Repayment received</div>
                          <div style={{ fontSize: 10, color: STASH.dim, fontFamily: STASH.num }}>via TWINT · just now</div>
                        </div>
                        <div style={{ fontFamily: STASH.num, fontSize: 14, fontWeight: 700, color: STASH.accent }}>+60</div>
                      </div>
                    );
                  })()}
                </div>
              );
            })()}
          </div>
        );
      }}
    </Sprite>
  );
}

Object.assign(window, {
  STASH, Mark, StatusBar, Backdrop, TopChrome, ProgressBar,
  SceneBrand, SceneSnap, SceneDashboard, SceneCurrency, ScenePlans, SceneShare, SceneOutro,
  SceneBudgets, SceneImport, SceneLoans,
});
