// Scenes file 2 of 2 — scenes 8-18 + composer

// ── 08: OPERATIONELE KOSTEN — 5 jaar (76-92s) ───────────────────────────
function SceneOpEx() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const yrs = [
    { y: 'Jaar 1 · 2026', opex: 109061, baat: 2000  },
    { y: 'Jaar 2 · 2027', opex: 105431, baat: 6000  },
    { y: 'Jaar 3 · 2028', opex: 70808,  baat: 27500 },
    { y: 'Jaar 4 · 2029', opex: 70808,  baat: 55000 },
    { y: 'Jaar 5 · 2030', opex: 70808,  baat: 79000 },
  ];
  const maxOp = 110000;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Operationele kosten & opbrengsten — Bijlage B · S2"
        title={<>Vijf jaar OpEx: <span style={{color: PALETTE.moss, fontStyle:'italic'}}>€427.192</span> · opbrengsten klimmen van €2.000 → €79.000.</>}
        sub="Marketing & Comm. + FTE-allocatie dalen vanaf jaar 3 (campagne vervalt). Opbrengsten groeien door productverdieping."
      />

      <div style={{ position: 'absolute', left: 120, right: 120, top: 380, height: 360 }}>
        {yrs.map((y, i) => {
          const a = ramp(t, 0.5 + i * 0.3, 1.2 + i * 0.3);
          const opH = (y.opex / maxOp) * 270 * a;
          const baatH = (y.baat / maxOp) * 270 * a;
          const xPct = (i / yrs.length) * 100;
          const wPct = (1 / yrs.length) * 0.9 * 100;
          return (
            <div key={i} style={{
              position: 'absolute', left: `${xPct}%`, width: `${wPct}%`,
              top: 0, bottom: 0,
            }}>
              {/* OpEx bar (down from top zero baseline at 280) */}
              <div style={{
                position: 'absolute', left: '14%', right: '52%',
                top: 280 - opH, height: opH,
                background: PALETTE.bad, border: `1px solid #7c241d`,
              }}>
                {a > 0.6 && (
                  <div style={{
                    position: 'absolute', top: -22, left: 0, right: 0, textAlign: 'center',
                    fontFamily: 'Fraunces', fontSize: 14, fontWeight: 500, color: PALETTE.bad,
                  }}>−€{nl(y.opex/1000)}k</div>
                )}
              </div>
              {/* baat bar */}
              <div style={{
                position: 'absolute', left: '52%', right: '14%',
                top: 280 - baatH, height: baatH,
                background: PALETTE.moss, border: `1px solid ${PALETTE.mossDeep}`,
              }}>
                {a > 0.6 && y.baat > 0 && (
                  <div style={{
                    position: 'absolute', top: -22, left: 0, right: 0, textAlign: 'center',
                    fontFamily: 'Fraunces', fontSize: 14, fontWeight: 500, color: PALETTE.moss,
                  }}>+€{nl(y.baat/1000)}k</div>
                )}
              </div>
              {/* baseline */}
              <div style={{
                position: 'absolute', left: 0, right: 0, top: 280, height: 1,
                background: PALETTE.ink,
              }}/>
              <div style={{
                position: 'absolute', left: 0, right: 0, top: 295, textAlign: 'center',
                fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.12em',
                color: PALETTE.inkSoft, textTransform: 'uppercase',
                opacity: a,
              }}>{y.y}</div>
            </div>
          );
        })}
      </div>

      {/* legend */}
      <div style={{
        position: 'absolute', left: 120, top: 320, display: 'flex', gap: 32,
        opacity: ramp(t, 0.3, 0.8),
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ width: 16, height: 16, background: PALETTE.bad }}/>
          <span style={{
            fontFamily: 'JetBrains Mono', fontSize: 14, letterSpacing: '0.14em',
            color: PALETTE.inkSoft, textTransform: 'uppercase',
          }}>OpEx</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ width: 16, height: 16, background: PALETTE.moss }}/>
          <span style={{
            fontFamily: 'JetBrains Mono', fontSize: 14, letterSpacing: '0.14em',
            color: PALETTE.inkSoft, textTransform: 'uppercase',
          }}>Bruto baten</span>
        </div>
      </div>

      {/* breakdown OpEx jaar 1 */}
      <div style={{
        position: 'absolute', left: 120, bottom: 110, right: 120,
        opacity: ramp(t, 4.2, 5.0),
        display: 'flex', gap: 16,
        fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.12em',
        color: PALETTE.inkSoft, textTransform: 'uppercase',
      }}>
        <div style={{ flex: 1, padding: '12px 16px', background: PALETTE.cream, border: `1px solid ${PALETTE.ink}` }}>
          <div>FTE-allocatie</div>
          <div style={{ fontFamily: 'Fraunces', fontSize: 24, color: PALETTE.ink, marginTop: 2, letterSpacing: 0 }}>€79.731</div>
          <div style={{ textTransform: 'none', letterSpacing: 0, fontFamily: 'Inter', fontSize: 13, marginTop: 2 }}>0,55 FTE jr 1-2 · 1,72× burden</div>
        </div>
        <div style={{ flex: 1, padding: '12px 16px', background: PALETTE.cream, border: `1px solid ${PALETTE.ink}` }}>
          <div>Studieboekenkorting</div>
          <div style={{ fontFamily: 'Fraunces', fontSize: 24, color: PALETTE.ink, marginTop: 2, letterSpacing: 0 }}>€12.000</div>
          <div style={{ textTransform: 'none', letterSpacing: 0, fontFamily: 'Inter', fontSize: 13, marginTop: 2 }}>€20 × 600 deelnemers</div>
        </div>
        <div style={{ flex: 1, padding: '12px 16px', background: PALETTE.cream, border: `1px solid ${PALETTE.ink}` }}>
          <div>Marketing & Comm.</div>
          <div style={{ fontFamily: 'Fraunces', fontSize: 24, color: PALETTE.ink, marginTop: 2, letterSpacing: 0 }}>€12.100</div>
          <div style={{ textTransform: 'none', letterSpacing: 0, fontFamily: 'Inter', fontSize: 13, marginTop: 2 }}>incl. btw · daalt naar €4.840</div>
        </div>
        <div style={{ flex: 1, padding: '12px 16px', background: PALETTE.cream, border: `1px solid ${PALETTE.ink}` }}>
          <div>Robin AI beheer</div>
          <div style={{ fontFamily: 'Fraunces', fontSize: 24, color: PALETTE.ink, marginTop: 2, letterSpacing: 0 }}>€3.630</div>
          <div style={{ textTransform: 'none', letterSpacing: 0, fontFamily: 'Inter', fontSize: 13, marginTop: 2 }}>incl. niet-aftr. btw</div>
        </div>
        <div style={{ flex: 1, padding: '12px 16px', background: PALETTE.cream, border: `1px solid ${PALETTE.ink}` }}>
          <div>Interpolis incentive</div>
          <div style={{ fontFamily: 'Fraunces', fontSize: 24, color: PALETTE.ink, marginTop: 2, letterSpacing: 0 }}>€1.600</div>
          <div style={{ textTransform: 'none', letterSpacing: 0, fontFamily: 'Inter', fontSize: 13, marginTop: 2 }}>200 klanten · €8/mnd</div>
        </div>
      </div>
    </div>
  );
}

// ── 09: FTE-burden rate (92-105s) ───────────────────────────────────────
function SceneFTE() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const cols = [
    { role: 'Jr. Accountmgr.', bruto: 40000, total: 68774, fte: 0.20, kost: 13755, factor: 1.72, delay: 0.6 },
    { role: 'Sr. Adviseur',    bruto: 55000, total: 98075, fte: 0.30, kost: 58845, factor: 1.78, delay: 1.2, twoFte: true },
    { role: 'Directeur (Karso)', bruto: 80000, total: 142628, fte: 0.05, kost: 7131, factor: 1.78, delay: 1.8 },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="FTE-burden rate — Bijlage E · integrale kostprijsfactor"
        title={<>Wat een medewerker écht kost — <span style={{color: PALETTE.moss, fontStyle:'italic'}}>×1,72</span> op het bruto salaris.</>}
        sub="Werkgeverslasten 33–34,5% (WW, WIA, ZVW, pensioen) + 28% overheadallocatie (IT, HR, compliance)."
      />

      <div style={{ position: 'absolute', left: 120, right: 120, top: 350, display: 'flex', gap: 20 }}>
        {cols.map((c, i) => {
          const a = ramp(t, c.delay, c.delay + 0.6);
          const stack = ramp(t, c.delay + 0.5, c.delay + 1.5);
          const brutoH = (c.bruto / 142628) * 240;
          const totalH = (c.total / 142628) * 240;
          return (
            <div key={i} style={{
              flex: 1, opacity: a,
              transform: `translateY(${(1 - a) * 16}px)`,
            }}>
              <div style={{
                fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
                color: PALETTE.inkSoft, textTransform: 'uppercase', textAlign: 'center',
              }}>{c.role}</div>

              <div style={{
                position: 'relative', height: 280, marginTop: 14,
                display: 'flex', alignItems: 'flex-end', justifyContent: 'center', gap: 16,
              }}>
                <div style={{ width: 70, textAlign: 'center' }}>
                  <div style={{
                    height: brutoH * stack, background: PALETTE.inkSoft,
                  }}/>
                  <div style={{
                    fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.1em',
                    marginTop: 6, color: PALETTE.inkSoft, textTransform: 'uppercase',
                  }}>Bruto</div>
                  <div style={{
                    fontFamily: 'Fraunces', fontSize: 14, color: PALETTE.ink,
                    fontVariantNumeric: 'tabular-nums',
                  }}>€{nl(c.bruto)}</div>
                </div>
                <div style={{ width: 70, textAlign: 'center' }}>
                  <div style={{
                    height: totalH * stack, background: PALETTE.moss, position: 'relative',
                  }}>
                    {/* segments */}
                    <div style={{
                      position: 'absolute', left: 0, right: 0, top: 0,
                      height: ((c.total - c.bruto) * 0.5) / c.total * (totalH * stack),
                      background: PALETTE.orange,
                    }}/>
                  </div>
                  <div style={{
                    fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.1em',
                    marginTop: 6, color: PALETTE.moss, textTransform: 'uppercase', fontWeight: 600,
                  }}>×{c.factor}</div>
                  <div style={{
                    fontFamily: 'Fraunces', fontSize: 14, color: PALETTE.moss,
                    fontVariantNumeric: 'tabular-nums', fontWeight: 500,
                  }}>€{nl(c.total)}</div>
                </div>
              </div>

              <div style={{
                marginTop: 16, padding: '10px 14px',
                background: PALETTE.cream, border: `1px solid ${PALETTE.ink}`,
                opacity: ramp(t, c.delay + 1.0, c.delay + 1.6),
              }}>
                <div style={{ fontSize: 14, color: PALETTE.inkSoft }}>Project-FTE</div>
                <div style={{
                  display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginTop: 2,
                }}>
                  <span style={{
                    fontFamily: 'Fraunces', fontSize: 20, fontWeight: 500,
                  }}>{c.twoFte ? '2 × ' : ''}{c.fte.toFixed(2)} FTE</span>
                  <span style={{
                    fontFamily: 'Fraunces', fontSize: 18, color: PALETTE.moss,
                    fontVariantNumeric: 'tabular-nums', fontWeight: 500,
                  }}>€{nl(c.kost)}</span>
                </div>
              </div>
            </div>
          );
        })}
      </div>

      <div style={{
        position: 'absolute', left: 120, right: 120, bottom: 110,
        opacity: ramp(t, 3.5, 4.3),
        padding: '16px 22px', background: PALETTE.mossDeep, color: PALETTE.cream,
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 24,
      }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.18em',
          textTransform: 'uppercase', opacity: 0.8,
        }}>Totale FTE-kosten S2 (jaar 1-2)</div>
        <div style={{
          fontFamily: 'Fraunces', fontSize: 36, fontWeight: 500,
          fontVariantNumeric: 'tabular-nums',
        }}>€13.755 + €58.845 + €7.131 = <span style={{ color: '#f5d28a' }}>€79.731 / jaar</span></div>
      </div>
    </div>
  );
}

// ── 10: PRODUCTKANSENMATRIX (105-122s) ──────────────────────────────────
function SceneProductMatrix() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const products = [
    { name: 'Spaarrekening',   f1: 2,  f2: 10, f3: 15,  kans: 20, delay: 0.5 },
    { name: 'Interpolis verz.', f1: 14, f2: 24, f3: 24,  kans: 15, delay: 0.9 },
    { name: 'Persoonlijk krediet', f1: 0, f2: 19, f3: 48, kans: 8, delay: 1.3 },
    { name: 'DUO herfin.',       f1: 0,  f2: 10, f3: 0,   kans: 5, delay: 1.7 },
    { name: 'Hypotheek',          f1: 0,  f2: 0,  f3: 701, kans: 25, delay: 2.1 },
    { name: 'Autolening',         f1: 0,  f2: 0,  f3: 45,  kans: 12, delay: 2.5 },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Productkansenmatrix — Bijlage F · tabel F1"
        title={<>Wat verdient Rabobank per klant — <span style={{color: PALETTE.moss, fontStyle:'italic'}}>gefaseerd</span> over 7 jaar.</>}
        sub="Gewogen gemiddelde opbrengst per actieve klant: ~€10 jr 1-2 · ~€85 jr 3-4 · ~€300 jr 5-7. Hypotheek levert het grootste bedrag — pas in fase 3."
      />

      {/* table */}
      <div style={{ position: 'absolute', left: 120, right: 120, top: 360 }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: '2.5fr 1fr 1fr 1fr 1fr',
          gap: 0,
          fontFamily: 'JetBrains Mono', fontSize: 14, letterSpacing: '0.14em',
          color: PALETTE.inkSoft, textTransform: 'uppercase',
          padding: '12px 16px',
          borderBottom: `2px solid ${PALETTE.ink}`,
          opacity: ramp(t, 0.2, 0.6),
        }}>
          <div>Product</div>
          <div style={{ textAlign: 'right' }}>Fase 1 · jr 1-2</div>
          <div style={{ textAlign: 'right' }}>Fase 2 · jr 3-4</div>
          <div style={{ textAlign: 'right' }}>Fase 3 · jr 5-7</div>
          <div style={{ textAlign: 'right' }}>Kans</div>
        </div>

        {products.map((p, i) => {
          const a = ramp(t, p.delay, p.delay + 0.5);
          return (
            <div key={i} style={{
              display: 'grid',
              gridTemplateColumns: '2.5fr 1fr 1fr 1fr 1fr',
              padding: '14px 16px',
              borderBottom: `1px solid ${PALETTE.line}`,
              opacity: a, transform: `translateX(${(1 - a) * -20}px)`,
              alignItems: 'baseline',
              fontVariantNumeric: 'tabular-nums',
            }}>
              <div style={{
                fontFamily: 'Fraunces', fontSize: 24, fontWeight: 500, color: PALETTE.ink,
                fontStyle: p.name === 'Hypotheek' ? 'italic' : 'normal',
              }}>{p.name}</div>
              <div style={{ textAlign: 'right', fontSize: 20, color: PALETTE.inkSoft, fontFamily: 'Fraunces' }}>{p.f1 ? `€${p.f1}` : '—'}</div>
              <div style={{ textAlign: 'right', fontSize: 20, color: p.f2 > 0 ? PALETTE.ink : PALETTE.inkSoft, fontFamily: 'Fraunces' }}>{p.f2 ? `€${p.f2}` : '—'}</div>
              <div style={{
                textAlign: 'right', fontSize: 24,
                color: p.name === 'Hypotheek' ? PALETTE.moss : PALETTE.ink,
                fontFamily: 'Fraunces', fontWeight: p.name === 'Hypotheek' ? 600 : 400,
              }}>{p.f3 ? `€${nl(p.f3)}` : '—'}</div>
              <div style={{ textAlign: 'right', fontSize: 16, color: PALETTE.orange, fontFamily: 'JetBrains Mono', letterSpacing: '0.06em' }}>{p.kans}%</div>
            </div>
          );
        })}

        <div style={{
          display: 'grid', gridTemplateColumns: '2.5fr 1fr 1fr 1fr 1fr',
          padding: '16px',
          background: PALETTE.mossDeep, color: PALETTE.cream, marginTop: 14,
          opacity: ramp(t, 3.5, 4.3),
          alignItems: 'baseline',
          fontVariantNumeric: 'tabular-nums',
        }}>
          <div style={{ fontFamily: 'Fraunces', fontStyle: 'italic', fontSize: 24, fontWeight: 500 }}>Gewogen gem. per klant / jaar</div>
          <div style={{ textAlign: 'right', fontFamily: 'Fraunces', fontSize: 28, fontWeight: 500 }}>~€10</div>
          <div style={{ textAlign: 'right', fontFamily: 'Fraunces', fontSize: 28, fontWeight: 500 }}>~€85</div>
          <div style={{ textAlign: 'right', fontFamily: 'Fraunces', fontSize: 34, fontWeight: 500, color: '#f5d28a' }}>~€300</div>
          <div style={{ textAlign: 'right', fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.14em', opacity: 0.7 }}>CLV → €3.500</div>
        </div>
      </div>
    </div>
  );
}

// ── 11: WINSTGEVENDHEID PER KLANT (122-138s) ────────────────────────────
function SceneProfitability() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const data = [-280, -485, -549, -613, -463, -288, -63, 212, 487, 762];
  const W = 1500, H = 380;
  const padL = 90, padR = 80, padT = 20, padB = 60;
  const plotW = W - padL - padR;
  const plotH = H - padT - padB;
  const yMin = -700, yMax = 800;
  const yScale = (v) => padT + ((yMax - v) / (yMax - yMin)) * plotH;
  const xScale = (i) => padL + (i / (data.length - 1)) * plotW;

  const drawT = ramp(t, 1.4, 8.0, Easing.easeInOutCubic);
  const segments = data.length - 1;
  const drawnSeg = drawT * segments;

  let pathD = `M ${xScale(0)} ${yScale(data[0])}`;
  for (let i = 1; i <= Math.floor(drawnSeg); i++) {
    pathD += ` L ${xScale(i)} ${yScale(data[i])}`;
  }
  if (drawnSeg < segments) {
    const fi = Math.floor(drawnSeg);
    const frac = drawnSeg - fi;
    if (fi + 1 < data.length) {
      const x = xScale(fi) + (xScale(fi + 1) - xScale(fi)) * frac;
      const y = yScale(data[fi]) + (yScale(data[fi + 1]) - yScale(data[fi])) * frac;
      pathD += ` L ${x} ${y}`;
    }
  }
  const headIdx = Math.min(segments, drawnSeg);
  const liveYear = Math.min(data.length, Math.floor(headIdx) + 1);
  const liveVal = data[Math.min(data.length - 1, Math.floor(headIdx))];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Winstgevendheid per klant — cumulatief saldo"
        title={<>Het kantelpunt: <span style={{color: PALETTE.moss, fontStyle:'italic'}}>jaar 5 positief</span>, jaar 8 terugverdiend.</>}
        sub="Jaar 1 kost €290 per klant (€222 OpEx + €68 CPA). Vanaf jaar 6 daalt de OpEx-allocatie naar €125/klant — campagne vervalt."
      />

      <div style={{
        position: 'absolute', right: 120, top: 290,
        opacity: ramp(t, 1.6, 2.2), textAlign: 'right',
      }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
          color: PALETTE.inkSoft, textTransform: 'uppercase',
        }}>jaar {liveYear} · cumulatief</div>
        <div style={{
          fontFamily: 'Fraunces', fontSize: 64, fontWeight: 500, lineHeight: 1, marginTop: 4,
          fontVariantNumeric: 'tabular-nums',
          color: liveVal >= 0 ? PALETTE.moss : PALETTE.bad,
        }}>{liveVal >= 0 ? '+' : '−'}€{nl(Math.abs(liveVal))}</div>
      </div>

      <div style={{ position: 'absolute', left: 120, right: 120, top: 380 }}>
        <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 460 }}>
          {[800, 400, 0, -400].map((v, k) => (
            <g key={k}>
              <line x1={padL} y1={yScale(v)} x2={W - padR} y2={yScale(v)}
                    stroke={v === 0 ? PALETTE.ink : 'rgba(12,26,20,0.08)'}
                    strokeWidth={v === 0 ? 1.5 : 1}/>
              <text x={padL - 12} y={yScale(v) + 4} textAnchor="end"
                    fontFamily="JetBrains Mono" fontSize="13" fill={PALETTE.inkSoft}>
                {v >= 0 ? `+€${v}` : `−€${Math.abs(v)}`}
              </text>
            </g>
          ))}

          {data.map((_, i) => (
            <text key={i} x={xScale(i)} y={H - padB + 24} textAnchor="middle"
                  fontFamily="JetBrains Mono" fontSize="13"
                  fill={i === 4 || i === 7 ? PALETTE.moss : PALETTE.inkSoft}
                  fontWeight={i === 4 || i === 7 ? 600 : 400}>
              jaar {i + 1}
            </text>
          ))}

          <path d={pathD} fill="none" stroke={PALETTE.orange} strokeWidth="3"
                strokeLinecap="round" strokeLinejoin="round"/>

          {drawT >= 4 / segments && (
            <g style={{
              opacity: ramp(t, 5.0, 5.5),
            }}>
              <circle cx={xScale(4)} cy={yScale(data[4])} r="9" fill="none" stroke={PALETTE.moss} strokeWidth="2"/>
              <circle cx={xScale(4)} cy={yScale(data[4])} r="4" fill={PALETTE.moss}/>
              <text x={xScale(4)} y={yScale(data[4]) - 28} textAnchor="middle"
                    fontFamily="JetBrains Mono" fontSize="13" fill={PALETTE.moss} fontWeight="600">
                JAAR 5 · +€151/JR
              </text>
            </g>
          )}

          {drawT >= 7 / segments && (
            <g style={{
              opacity: ramp(t, 6.5, 7.0),
            }}>
              <circle cx={xScale(7)} cy={yScale(data[7])} r="11" fill="none" stroke={PALETTE.mossDeep} strokeWidth="2"/>
              <circle cx={xScale(7)} cy={yScale(data[7])} r="5" fill={PALETTE.mossDeep}/>
              <text x={xScale(7)} y={yScale(data[7]) - 28} textAnchor="middle"
                    fontFamily="JetBrains Mono" fontSize="13" fill={PALETTE.mossDeep} fontWeight="600">
                JAAR 8 · TERUGVERDIEND
              </text>
            </g>
          )}
        </svg>
      </div>
    </div>
  );
}

// ── 12: NPV TABEL (138-156s) ────────────────────────────────────────────
function SceneNPVTable() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const rows = [
    { y: '0',  k: 200, rev: 10,   bruto: 2000,    opex: -119173, netto: -117173, cw: -117173 },
    { y: '1',  k: 408, rev: 10,   bruto: 4080,    opex: -103100, netto: -99020,  cw: -91685 },
    { y: '2',  k: 408, rev: 85,   bruto: 34680,   opex: -71670,  netto: -36990,  cw: -31713 },
    { y: '3',  k: 347, rev: 85,   bruto: 29495,   opex: -71670,  netto: -42175,  cw: -33480 },
    { y: '4',  k: 294, rev: 300,  bruto: 88200,   opex: -71670,  netto: 16530,   cw: 12150 },
    { y: '5',  k: 250, rev: 520,  bruto: 130000,  opex: -50000,  netto: 80000,   cw: 54447 },
    { y: '6',  k: 213, rev: 620,  bruto: 132060,  opex: -50000,  netto: 82060,   cw: 51712 },
    { y: '7',  k: 181, rev: 720,  bruto: 130320,  opex: -50000,  netto: 80320,   cw: 46866 },
    { y: '8',  k: 154, rev: 820,  bruto: 126280,  opex: -50000,  netto: 76280,   cw: 41212 },
    { y: '9',  k: 131, rev: 920,  bruto: 120520,  opex: -50000,  netto: 70520,   cw: 35278 },
    { y: '10', k: 111, rev: 1020, bruto: 113220,  opex: -50000,  netto: 63220,   cw: 29283 },
    { y: '11', k: 94,  rev: 1120, bruto: 105280,  opex: -50000,  netto: 55280,   cw: 23709 },
    { y: 'TV', k: 94,  rev: '—',  bruto: 188000,  opex: '—',     netto: 188000,  cw: 74663, term: true },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="NPV-tabel — Bijlage F · tabel F2 · disconto 8%"
        title={<>Contante waarde over <span style={{color: PALETTE.moss, fontStyle:'italic'}}>12 jaar</span> incl. restwaarde — €95.267.</>}
      />

      <div style={{ position: 'absolute', left: 120, right: 120, top: 320 }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: '0.6fr 0.8fr 0.8fr 1.1fr 1.1fr 1.1fr 1.1fr',
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.12em',
          color: PALETTE.inkSoft, textTransform: 'uppercase',
          padding: '10px 14px', borderBottom: `2px solid ${PALETTE.ink}`,
        }}>
          <div>Jaar</div>
          <div style={{ textAlign: 'right' }}>Klanten</div>
          <div style={{ textAlign: 'right' }}>Rev / klant</div>
          <div style={{ textAlign: 'right' }}>Bruto</div>
          <div style={{ textAlign: 'right' }}>OpEx</div>
          <div style={{ textAlign: 'right' }}>Netto kasstroom</div>
          <div style={{ textAlign: 'right' }}>CW (8%)</div>
        </div>

        {rows.map((r, i) => {
          const a = ramp(t, 0.3 + i * 0.18, 0.8 + i * 0.18);
          const fmt = (v) => typeof v === 'number'
            ? (v >= 0 ? '€' + nl(v) : '−€' + nl(Math.abs(v)))
            : v;
          return (
            <div key={i} style={{
              display: 'grid',
              gridTemplateColumns: '0.6fr 0.8fr 0.8fr 1.1fr 1.1fr 1.1fr 1.1fr',
              padding: '8px 14px',
              borderBottom: `1px solid ${PALETTE.line}`,
              opacity: a, transform: `translateX(${(1 - a) * -10}px)`,
              fontVariantNumeric: 'tabular-nums',
              fontFamily: 'Fraunces', fontSize: 18,
              background: r.term ? PALETTE.cream : 'transparent',
            }}>
              <div style={{ fontWeight: r.term ? 600 : 400 }}>{r.y}</div>
              <div style={{ textAlign: 'right', color: PALETTE.inkSoft }}>{r.k}</div>
              <div style={{ textAlign: 'right', color: PALETTE.inkSoft }}>{typeof r.rev === 'number' ? `€${r.rev}` : r.rev}</div>
              <div style={{ textAlign: 'right' }}>{fmt(r.bruto)}</div>
              <div style={{ textAlign: 'right', color: PALETTE.bad }}>{fmt(r.opex)}</div>
              <div style={{
                textAlign: 'right',
                color: r.netto >= 0 ? PALETTE.moss : PALETTE.bad,
              }}>{fmt(r.netto)}</div>
              <div style={{
                textAlign: 'right', fontWeight: 500,
                color: r.cw >= 0 ? PALETTE.moss : PALETTE.bad,
              }}>{fmt(r.cw)}</div>
            </div>
          );
        })}

        <div style={{
          marginTop: 18, padding: '14px 18px',
          background: PALETTE.mossDeep, color: PALETTE.cream,
          display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          opacity: ramp(t, 3.5, 4.3),
        }}>
          <span style={{
            fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.16em',
            textTransform: 'uppercase', opacity: 0.85,
          }}>Totale CW · 8% · 12 jaar incl. restwaarde €74.663</span>
          <span style={{
            fontFamily: 'Fraunces', fontSize: 50, fontWeight: 500,
            color: '#f5d28a', fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em',
          }}>€95.267</span>
        </div>
      </div>
    </div>
  );
}

// ── 13: DRIE SCENARIOS (156-173s) ────────────────────────────────────────
function SceneScenarios() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const sc = [
    { tag: 'S0', title: 'Worst case',  sub: 'Tegenvallend',  cw: -52000,  irr: 'neg.', be: 'nooit',  rel: 192, inv: 32419, opex: 422116, baat: 67800, delay: 0.6, bad: true },
    { tag: 'S2', title: 'Base case',   sub: 'Aanbevolen',     cw: 95000,   irr: '~12%', be: 'jaar 8', rel: 480, inv: 32419, opex: 427192, baat: 169500, delay: 1.4, good: true },
    { tag: 'S3', title: 'Best case',   sub: 'Opschaling 3 loc.', cw: 195000, irr: '~16%', be: 'jaar 7', rel: 700, inv: 40000, opex: 592885, baat: 247000, delay: 2.2, best: true },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Scenariovergelijking — Bijlage A · B · C"
        title={<>Drie uitvoeringsscenario's — alleen <span style={{color: PALETTE.moss, fontStyle:'italic'}}>S2 verdedigt zichzelf</span>.</>}
      />

      <div style={{
        position: 'absolute', left: 120, right: 120, top: 360,
        display: 'flex', gap: 20,
      }}>
        {sc.map((s, i) => {
          const a = ramp(t, s.delay, s.delay + 0.6);
          const color = s.bad ? PALETTE.bad : (s.good ? PALETTE.moss : PALETTE.mossLight);
          return (
            <div key={i} style={{
              flex: 1, opacity: a,
              transform: `translateY(${(1 - a) * 18}px)`,
              padding: 26,
              background: s.good ? PALETTE.mossDeep : PALETTE.cream,
              color: s.good ? PALETTE.cream : PALETTE.ink,
              border: `1px solid ${PALETTE.ink}`,
              borderTop: `4px solid ${color}`,
              boxShadow: s.good ? `8px 8px 0 ${PALETTE.orange}` : 'none',
              transform: s.good ? `translateY(${(1 - a) * 18}px) scale(${0.97 + 0.03 * a})` : `translateY(${(1 - a) * 18}px)`,
              transformOrigin: 'center',
            }}>
              <div style={{
                display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
              }}>
                <span style={{
                  fontFamily: 'Fraunces', fontSize: 56, fontWeight: 500, lineHeight: 1,
                  color: s.good ? '#f5d28a' : color,
                }}>{s.tag}</span>
                <span style={{
                  fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
                  textTransform: 'uppercase',
                  opacity: 0.7,
                }}>{s.sub}</span>
              </div>
              <div style={{
                fontFamily: 'Fraunces', fontStyle: 'italic',
                fontSize: 22, marginTop: 4,
              }}>{s.title}</div>

              <div style={{
                marginTop: 18, paddingTop: 18,
                borderTop: `1px solid ${s.good ? 'rgba(245,241,232,0.25)' : PALETTE.line}`,
                fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.12em',
                textTransform: 'uppercase', opacity: 0.85,
              }}>Contante waarde · 12 jr</div>
              <div style={{
                fontFamily: 'Fraunces', fontSize: 64, fontWeight: 500,
                color: s.bad ? PALETTE.bad : (s.good ? '#f5d28a' : PALETTE.moss),
                lineHeight: 1, marginTop: 4,
                fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em',
              }}>{s.cw < 0 ? '−' : '+'}€{nl(Math.abs(s.cw)/1000)}k</div>

              <div style={{ marginTop: 18 }}>
                {[
                  ['Actieve relaties', `+${s.rel}`],
                  ['IRR', s.irr],
                  ['Break-even', s.be],
                  ['Investering', `€${nl(s.inv)}`],
                  ['OpEx 5j', `€${nl(s.opex)}`],
                  ['Directe baten', `€${nl(s.baat)}`],
                ].map(([l, v], k) => (
                  <div key={k} style={{
                    display: 'flex', justifyContent: 'space-between',
                    padding: '6px 0',
                    fontSize: 13.5,
                    borderBottom: k < 5 ? `1px solid ${s.good ? 'rgba(245,241,232,0.12)' : PALETTE.line}` : 'none',
                  }}>
                    <span style={{ opacity: 0.75 }}>{l}</span>
                    <span style={{ fontFamily: 'Fraunces', fontWeight: 500, fontVariantNumeric: 'tabular-nums' }}>{v}</span>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── 14: GEVOELIGHEIDSANALYSE (173-188s) ──────────────────────────────────
function SceneSensitivity() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const matrix = [
    [218000, 167000, 125000, 91000],
    [134000, 95000, 64000, 39000],
    [76000, 20600, 8000, -16000],
    [18000, -12000, -36000, -55000],
    [-45000, -68000, -86000, -101000],
  ];
  const churnLabels = ['5%', '10%', '15% base', '25%', '35%'];
  const discLabels = ['6%', '8% base', '10%', '12%'];

  const valColor = (v) => {
    if (v < 0) return PALETTE.bad;
    if (v < 50000) return PALETTE.sun;
    if (v < 120000) return PALETTE.mossLight;
    return PALETTE.moss;
  };

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Gevoeligheidsanalyse — Bijlage H · NPV bij variabele aannames"
        title={<>NPV bij <span style={{color: PALETTE.moss, fontStyle:'italic'}}>churn × disconto</span> — robuust binnen redelijke bandbreedte.</>}
      />

      <div style={{
        position: 'absolute', left: 120, top: 360, width: 1100,
      }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: '160px repeat(4, 1fr)',
          gap: 4,
        }}>
          <div></div>
          {discLabels.map((l, i) => (
            <div key={i} style={{
              fontFamily: 'JetBrains Mono', fontSize: 14, letterSpacing: '0.14em',
              color: PALETTE.inkSoft, textTransform: 'uppercase', textAlign: 'center',
              padding: '8px 0',
              opacity: ramp(t, 0.2 + i * 0.08, 0.6 + i * 0.08),
            }}>{l}</div>
          ))}

          {matrix.map((row, ri) => (
            <React.Fragment key={ri}>
              <div style={{
                fontFamily: 'JetBrains Mono', fontSize: 14, letterSpacing: '0.14em',
                color: PALETTE.inkSoft, textTransform: 'uppercase',
                padding: '14px 12px', display: 'flex', alignItems: 'center',
                opacity: ramp(t, 0.4 + ri * 0.1, 0.8 + ri * 0.1),
              }}>Churn {churnLabels[ri]}</div>
              {row.map((v, ci) => {
                const a = ramp(t, 0.6 + ri * 0.12 + ci * 0.05, 1.0 + ri * 0.12 + ci * 0.05);
                const isBase = ri === 2 && ci === 1;
                return (
                  <div key={ci} style={{
                    padding: '14px 0',
                    background: valColor(v),
                    color: PALETTE.cream,
                    textAlign: 'center',
                    border: isBase ? `3px solid ${PALETTE.ink}` : 'none',
                    fontFamily: 'Fraunces', fontSize: isBase ? 24 : 20, fontWeight: 500,
                    fontVariantNumeric: 'tabular-nums',
                    opacity: a,
                    transform: `scale(${0.9 + 0.1 * a})`,
                  }}>
                    {v < 0 ? '−' : ''}€{nl(Math.abs(v)/1000)}k
                  </div>
                );
              })}
            </React.Fragment>
          ))}
        </div>
      </div>

      {/* legend right */}
      <div style={{
        position: 'absolute', right: 120, top: 360, width: 380,
        opacity: ramp(t, 4.0, 4.8),
      }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
          color: PALETTE.inkSoft, textTransform: 'uppercase', marginBottom: 12,
        }}>Conclusie</div>
        <div style={{
          fontFamily: 'Fraunces', fontStyle: 'italic',
          fontSize: 19, color: PALETTE.ink, lineHeight: 1.5,
        }}>
          Bij base (15% churn · 8% disconto) is CW <b style={{ color: PALETTE.moss }}>+€20.600</b> exclusief restwaarde, <b style={{ color: PALETTE.moss }}>+€95.000</b> inclusief.
        </div>
        <div style={{
          marginTop: 18,
          fontSize: 14, color: PALETTE.inkSoft, lineHeight: 1.5,
        }}>
          Project wordt riskant boven 20% churn én 10% disconto — onwaarschijnlijke combinatie. <b>Bij disconto 6%</b>: CW stijgt naar ~€114.000.
        </div>

        <div style={{
          marginTop: 28, padding: '14px 18px',
          background: PALETTE.cream, border: `1px solid ${PALETTE.ink}`,
        }}>
          <div style={{
            fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.14em',
            color: PALETTE.inkSoft, textTransform: 'uppercase',
          }}>Drempel · risicovrij 3% + opslag 5%</div>
          <div style={{
            fontFamily: 'Fraunces', fontSize: 32, fontWeight: 500, color: PALETTE.ink,
            marginTop: 2,
          }}>8% &gt; <span style={{ color: PALETTE.moss }}>IRR ~12%</span></div>
        </div>
      </div>
    </div>
  );
}

// ── 15: FISCALE BEHANDELING (188-200s) ──────────────────────────────────
function SceneFiscaal() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const rows = [
    { post: 'Robin AI software',           treat: 'Geactiveerd als IVA · 3 jr lin.', wet: 'art. 3.30 Wet IB',     bedrag: '€21.780',  shield: '€4.644 over 3 jr', delay: 0.5 },
    { post: 'Campusmaterialen',            treat: 'Direct aftrekbaar (≤€5.000)',     wet: 'art. 8 Wet Vpb',       bedrag: '€4.235',   shield: '€1.093',           delay: 0.9 },
    { post: 'FTE-allocatie',               treat: 'Direct aftrekbaar als personeelskost', wet: 'reguliere Vpb',   bedrag: 'jaarlijks',shield: '25,8% × loonkost', delay: 1.3 },
    { post: 'Studieboekenkorting',         treat: 'Verkoopkosten · zakelijke grondslag',  wet: 'art. 8 Wet Vpb',  bedrag: '€12.000/jr',shield: '€3.096/jr',        delay: 1.7 },
    { post: 'NIM & commissie-opbrengsten', treat: 'Belastbaar als reguliere Vpb-winst',   wet: '25,8% Vpb',       bedrag: '—',        shield: '—',                delay: 2.1 },
    { post: 'Btw op alle posten',          treat: 'NIET aftrekbaar · bancair vrijgesteld',wet: 'art. 11.1.i Wet OB',bedrag: 'incl. btw',shield: '—',                delay: 2.5 },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Fiscale & boekhoudkundige behandeling — Bijlage G"
        title={<>Vpb 25,8% · btw <span style={{color: PALETTE.bad, fontStyle:'italic'}}>niet aftrekbaar</span> (bancair vrijgesteld).</>}
        sub="Coöperatieve structuur verandert hier niets — alleen winstuitkering aan leden vrijgesteld (art. 9.1.g Wet Vpb), niet relevant hier."
      />

      <div style={{ position: 'absolute', left: 120, right: 120, top: 360 }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: '1.4fr 2fr 1.2fr 1fr 1fr',
          padding: '10px 14px',
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.12em',
          color: PALETTE.inkSoft, textTransform: 'uppercase',
          borderBottom: `2px solid ${PALETTE.ink}`,
        }}>
          <div>Post</div>
          <div>Behandeling</div>
          <div>Wettelijke basis</div>
          <div style={{ textAlign: 'right' }}>Bedrag</div>
          <div style={{ textAlign: 'right' }}>Tax shield</div>
        </div>
        {rows.map((r, i) => {
          const a = ramp(t, r.delay, r.delay + 0.5);
          return (
            <div key={i} style={{
              display: 'grid',
              gridTemplateColumns: '1.4fr 2fr 1.2fr 1fr 1fr',
              padding: '14px',
              borderBottom: `1px solid ${PALETTE.line}`,
              opacity: a, transform: `translateX(${(1 - a) * -14}px)`,
              alignItems: 'baseline',
              fontFamily: 'Fraunces', fontSize: 18,
              fontVariantNumeric: 'tabular-nums',
            }}>
              <div style={{ fontWeight: 500 }}>{r.post}</div>
              <div style={{ fontStyle: 'italic', color: PALETTE.inkSoft }}>{r.treat}</div>
              <div style={{ fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.06em', color: PALETTE.inkSoft, textTransform: 'uppercase' }}>{r.wet}</div>
              <div style={{ textAlign: 'right' }}>{r.bedrag}</div>
              <div style={{ textAlign: 'right', color: r.shield === '—' ? PALETTE.inkSoft : PALETTE.moss, fontWeight: 500 }}>{r.shield}</div>
            </div>
          );
        })}

        <div style={{
          marginTop: 22, padding: '14px 18px',
          background: PALETTE.cream, border: `1px solid ${PALETTE.ink}`,
          display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          opacity: ramp(t, 3.5, 4.3),
        }}>
          <span style={{
            fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.16em',
            color: PALETTE.inkSoft, textTransform: 'uppercase',
          }}>Totale Vpb-besparing op investering jaar 1</span>
          <span style={{
            fontFamily: 'Fraunces', fontSize: 32, fontWeight: 500, color: PALETTE.moss,
            fontVariantNumeric: 'tabular-nums',
          }}>€3.358 / jaar (yr 1-3)</span>
        </div>
      </div>
    </div>
  );
}

// ── 16: RISICOMATRIX (200-215s) ──────────────────────────────────────────
function SceneRisk() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const risks = [
    { naam: 'Marketing & Comm. geen go-besluit', kans: 4, impact: 5, rw: 20, type: 'L&G',       delay: 0.5 },
    { naam: 'ABN-exclusiviteit blokkeert HR',     kans: 3, impact: 4, rw: 12, type: 'Processen', delay: 0.8 },
    { naam: 'Churn > 25%',                        kans: 3, impact: 4, rw: 12, type: 'Financieel',delay: 1.1 },
    { naam: 'PSD3 dashboard-integratie fintech',  kans: 3, impact: 4, rw: 12, type: 'Financieel',delay: 1.4 },
    { naam: 'Robin-vertraging',                   kans: 3, impact: 4, rw: 12, type: 'Processen', delay: 1.7 },
    { naam: 'Privacy / GDPR (QR-flow)',           kans: 2, impact: 5, rw: 10, type: 'L&G',       delay: 2.0 },
    { naam: 'Adviseurscapaciteit',                kans: 3, impact: 3, rw: 9,  type: 'Processen', delay: 2.3 },
    { naam: 'Robin-completion < 25%',             kans: 2, impact: 4, rw: 8,  type: 'Klant',     delay: 2.6 },
    { naam: 'Renteomgeving daalt',                kans: 2, impact: 3, rw: 6,  type: 'Financieel',delay: 2.9 },
    { naam: 'Reputatierisico verkoperig',         kans: 2, impact: 3, rw: 6,  type: 'Klant',     delay: 3.2 },
  ];

  const cellSize = 60;

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Risico-impactmatrix — Bijlage I · 1-5 schaal"
        title={<>RW = kans × impact. <span style={{color: PALETTE.bad, fontStyle:'italic'}}>RW ≥ 12 = kritiek</span> — directe mitigatie vereist.</>}
      />

      {/* matrix grid 5x5 */}
      <div style={{
        position: 'absolute', left: 120, top: 360, width: 5 * cellSize + 50,
      }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
          color: PALETTE.inkSoft, textTransform: 'uppercase', marginBottom: 14,
        }}>Kans (x) × Impact (y)</div>

        <div style={{ display: 'flex' }}>
          {/* y axis */}
          <div style={{
            width: 50, display: 'flex', flexDirection: 'column-reverse', justifyContent: 'space-between',
          }}>
            {[1, 2, 3, 4, 5].map(v => (
              <div key={v} style={{
                height: cellSize, display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'JetBrains Mono', fontSize: 13,
                color: PALETTE.inkSoft,
              }}>{v}</div>
            ))}
          </div>
          <div style={{
            display: 'grid', gridTemplateColumns: `repeat(5, ${cellSize}px)`, gridAutoRows: `${cellSize}px`,
          }}>
            {Array.from({ length: 25 }).map((_, idx) => {
              const col = idx % 5;
              const row = 4 - Math.floor(idx / 5); // bottom-up
              const kans = col + 1;
              const impact = row + 1;
              const rw = kans * impact;
              const fill = rw >= 12 ? PALETTE.bad : rw >= 8 ? PALETTE.sun : PALETTE.mossLight;
              const opacity = rw >= 12 ? 0.85 : rw >= 8 ? 0.55 : 0.3;
              return (
                <div key={idx} style={{
                  background: fill, opacity,
                  border: `1px solid ${PALETTE.paper}`,
                  position: 'relative',
                }}/>
              );
            })}
          </div>
        </div>
        <div style={{
          marginLeft: 50, marginTop: 6,
          display: 'grid', gridTemplateColumns: `repeat(5, ${cellSize}px)`,
          fontFamily: 'JetBrains Mono', fontSize: 13, color: PALETTE.inkSoft,
          textAlign: 'center',
        }}>
          {[1, 2, 3, 4, 5].map(v => <div key={v}>{v}</div>)}
        </div>

        {/* dots for risks */}
        <svg style={{
          position: 'absolute', left: 50, top: 33, pointerEvents: 'none',
        }} width={5 * cellSize} height={5 * cellSize}>
          {risks.map((r, i) => {
            const a = ramp(t, r.delay, r.delay + 0.5);
            const cx = (r.kans - 0.5) * cellSize;
            const cy = (5 - r.impact + 0.5) * cellSize;
            return (
              <g key={i} style={{ opacity: a }}>
                <circle cx={cx} cy={cy} r="9" fill={PALETTE.ink} stroke={PALETTE.cream} strokeWidth="2"/>
                <text x={cx} y={cy + 3} textAnchor="middle" fontFamily="JetBrains Mono" fontSize="9" fill={PALETTE.cream} fontWeight="600">{i + 1}</text>
              </g>
            );
          })}
        </svg>
      </div>

      {/* risk list */}
      <div style={{ position: 'absolute', right: 120, top: 360, width: 760 }}>
        {risks.map((r, i) => {
          const a = ramp(t, r.delay, r.delay + 0.5);
          const critical = r.rw >= 12;
          return (
            <div key={i} style={{
              display: 'flex', alignItems: 'center', gap: 14,
              padding: '8px 12px',
              background: critical ? 'rgba(168,51,42,0.1)' : 'transparent',
              borderBottom: `1px solid ${PALETTE.line}`,
              opacity: a, transform: `translateX(${(1 - a) * 12}px)`,
            }}>
              <div style={{
                width: 28, height: 28, borderRadius: 14, background: PALETTE.ink, color: PALETTE.cream,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'JetBrains Mono', fontSize: 13, fontWeight: 600, flexShrink: 0,
              }}>{i + 1}</div>
              <div style={{ flex: 1, fontFamily: 'Fraunces', fontSize: 18, fontWeight: 500 }}>{r.naam}</div>
              <div style={{
                fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.14em',
                color: PALETTE.inkSoft, textTransform: 'uppercase', minWidth: 80, textAlign: 'right',
              }}>{r.type}</div>
              <div style={{
                fontFamily: 'Fraunces', fontSize: 24, fontWeight: 500,
                color: critical ? PALETTE.bad : (r.rw >= 8 ? PALETTE.sun : PALETTE.mossLight),
                minWidth: 50, textAlign: 'right', fontVariantNumeric: 'tabular-nums',
              }}>{r.rw}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── 17: IMPLEMENTATIETIJDLIJN (215-230s) ────────────────────────────────
function SceneTimeline() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const phases = [
    { q: 'Q2 2026', mile: 'Go-besluit M&C',         hard: true, sub: 'directiemandaat Karso',         delay: 0.5 },
    { q: 'Q3 2026', mile: 'Robin live',             hard: true, sub: 'life-event triggers actief',    delay: 1.0 },
    { q: 'Q3 2026', mile: '4 adviseurs Wft',        hard: true, sub: 'art. 4:23 Wft compliance',       delay: 1.5 },
    { q: 'Q3 2026', mile: 'Introductieweek HR',      hard: false, sub: '1e activatiespelletje · QR',   delay: 2.0 },
    { q: 'Q4 2026', mile: 'CPA-meting + check-in',   hard: false, sub: 'CPA-target ≤€120',             delay: 2.4 },
    { q: 'Q1 2027', mile: 'Week van het Geld',       hard: false, sub: 'penetratie ≥15,1%',             delay: 2.8 },
    { q: 'Q2 2027', mile: 'Go/no-go fase 2',          hard: false, sub: 'enquête-herhaling',             delay: 3.2 },
    { q: 'Q3 2027+', mile: 'Schaling ZH-breed',     hard: false, sub: 'naar S3 bij 2 kwartalen op KPI',  delay: 3.6 },
  ];

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <SceneHeader t={t}
        eyebrow="Implementatietijdlijn — Bijlage J"
        title={<>Drie <span style={{color: PALETTE.bad, fontStyle:'italic'}}>harde mijlpalen</span> Q3 2026 — ontbreekt één, dan stopt de keten.</>}
      />

      {/* horizontal timeline */}
      <div style={{
        position: 'absolute', left: 120, right: 120, top: 420,
      }}>
        {/* spine */}
        <div style={{
          position: 'absolute', left: 30, right: 30, top: 50, height: 2,
          background: PALETTE.ink,
        }}>
          <div style={{
            position: 'absolute', left: 0, top: 0, height: 2,
            background: PALETTE.moss,
            width: `${ramp(t, 0.3, 4.2) * 100}%`,
          }}/>
        </div>

        <div style={{
          display: 'grid',
          gridTemplateColumns: `repeat(${phases.length}, 1fr)`,
          gap: 0,
        }}>
          {phases.map((p, i) => {
            const a = ramp(t, p.delay, p.delay + 0.5);
            return (
              <div key={i} style={{
                opacity: a,
                transform: `translateY(${(1 - a) * 16}px)`,
                textAlign: 'center', position: 'relative',
              }}>
                <div style={{
                  fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
                  color: PALETTE.inkSoft, textTransform: 'uppercase',
                }}>{p.q}</div>
                <div style={{
                  width: p.hard ? 24 : 16, height: p.hard ? 24 : 16,
                  background: p.hard ? PALETTE.bad : PALETTE.moss,
                  border: p.hard ? `2px solid ${PALETTE.ink}` : 'none',
                  margin: '12px auto', borderRadius: p.hard ? 0 : 8,
                  transform: p.hard ? 'rotate(45deg)' : 'none',
                }}/>
                <div style={{
                  fontFamily: 'Fraunces', fontSize: 18, fontWeight: 500,
                  color: PALETTE.ink, lineHeight: 1.2,
                }}>{p.mile}</div>
                <div style={{
                  fontFamily: 'Inter', fontSize: 14, color: PALETTE.inkSoft,
                  marginTop: 4, lineHeight: 1.3,
                }}>{p.sub}</div>
              </div>
            );
          })}
        </div>
      </div>

      {/* legend */}
      <div style={{
        position: 'absolute', left: 120, bottom: 130, right: 120,
        display: 'flex', gap: 30, alignItems: 'center',
        opacity: ramp(t, 4.0, 4.6),
        fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.16em',
        color: PALETTE.inkSoft, textTransform: 'uppercase',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 14, height: 14, background: PALETTE.bad, transform: 'rotate(45deg)' }}/>
          Hard milestone
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 14, height: 14, background: PALETTE.moss, borderRadius: 7 }}/>
          Reguliere mijlpaal
        </div>
        <div style={{ marginLeft: 'auto', textTransform: 'none', fontFamily: 'Fraunces', fontStyle: 'italic', fontSize: 18, letterSpacing: 0 }}>
          Beslisregels Q2 2027: Robin-afronding ≥35% · app-activatie ≥40% · ≥4 events
        </div>
      </div>
    </div>
  );
}

// ── 18: CONCLUSIE (230-242s) ─────────────────────────────────────────────
function SceneConclusion() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.7, 1.0);
  const t = localTime;
  const stampScale = ramp(t, 1.4, 2.2, Easing.easeOutBack);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: o }}>
      <div style={{ position: 'absolute', left: 120, top: 200, maxWidth: 800 }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.2em',
          color: PALETTE.orange, textTransform: 'uppercase',
          opacity: ramp(t, 0, 0.4),
        }}>Financiële conclusie · Datapunt 4</div>

        <div style={{
          marginTop: 30,
          fontFamily: 'Fraunces, serif',
          fontSize: 84, lineHeight: 1.0,
          letterSpacing: '-0.025em', fontWeight: 500, color: PALETTE.ink,
        }}>
          <span style={{
            opacity: ramp(t, 0.3, 1.0),
            transform: `translateY(${(1 - ramp(t, 0.3, 1.0)) * 20}px)`,
            display: 'block',
          }}>S2 is de meest</span>
          <span style={{
            opacity: ramp(t, 0.7, 1.4),
            transform: `translateY(${(1 - ramp(t, 0.7, 1.4)) * 20}px)`,
            display: 'block',
            color: PALETTE.moss, fontStyle: 'italic',
          }}>verantwoorde keuze.</span>
        </div>

        <div style={{
          marginTop: 36,
          fontFamily: 'Fraunces', fontStyle: 'italic',
          fontSize: 22, lineHeight: 1.5,
          color: PALETTE.inkSoft, maxWidth: 720,
          opacity: ramp(t, 1.8, 2.6),
        }}>
          IRR boven drempel · positieve contante waarde · break-even op het moment dat klantwaarde concreet wordt via productverdieping (jaar 8). Dit verdedigt tegelijk de digitale positie tegen PSD3-fintechs.
        </div>

        <div style={{
          marginTop: 26,
          opacity: ramp(t, 3.0, 3.6),
          fontFamily: 'Inter', fontSize: 14,
          color: PALETTE.inkSoft, lineHeight: 1.5, maxWidth: 720,
        }}>
          Voortgang alleen verantwoord bij realisatie van drie harde mijlpalen voor Q3 2026 — go-besluit Marketing &amp; Comm., Robin-configuratie en Wft-certificering.
        </div>
      </div>

      <div style={{
        position: 'absolute', right: 120, top: 200, width: 440,
        transform: `rotate(-2deg) scale(${stampScale})`,
        transformOrigin: 'center',
      }}>
        <div style={{
          background: PALETTE.cream,
          border: `2px solid ${PALETTE.ink}`,
          padding: 30,
          boxShadow: `8px 8px 0 ${PALETTE.mossDeep}`,
        }}>
          <div style={{
            fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.2em',
            color: PALETTE.inkSoft, textTransform: 'uppercase',
          }}>Aanbeveling</div>

          <div style={{
            fontFamily: 'Fraunces, serif', fontSize: 60, fontWeight: 500,
            color: PALETTE.ink, lineHeight: 1, marginTop: 4,
          }}>Scenario S2</div>

          <div style={{ marginTop: 22 }}>
            {[
              ['Investering',     '€32.419'],
              ['OpEx 5 jaar',     '€427.192'],
              ['Directe baten 5j', '€169.500'],
              ['Contante waarde · 12 jr', '~€95.000'],
              ['Intern rendement', '~12%'],
              ['CPA',             '€68'],
              ['Break-even',      'jaar 8'],
            ].map(([l, v], i) => (
              <div key={i} style={{
                display: 'flex', justifyContent: 'space-between',
                padding: '8px 0',
                borderBottom: i < 6 ? `1px solid ${PALETTE.line}` : 'none',
                fontSize: 14,
              }}>
                <span style={{ color: PALETTE.inkSoft }}>{l}</span>
                <span style={{ fontFamily: 'Fraunces', fontWeight: 500 }}>{v}</span>
              </div>
            ))}
          </div>

          <div style={{
            marginTop: 22, padding: '14px 18px',
            background: PALETTE.moss, color: PALETTE.cream,
            textAlign: 'center',
            fontFamily: 'JetBrains Mono', fontSize: 13, letterSpacing: '0.18em',
            textTransform: 'uppercase',
          }}>✓ Go-besluit aanbevolen</div>
        </div>
      </div>

      <div style={{
        position: 'absolute', left: 120, bottom: 110,
        opacity: ramp(t, 5.5, 7.0),
        display: 'flex', alignItems: 'center', gap: 16,
        fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.2em',
        color: PALETTE.inkSoft, textTransform: 'uppercase',
      }}>
        <svg width="22" height="22" viewBox="0 0 22 22">
          <path d="M11 1 L21 11 L11 21 L1 11 Z" fill="none" stroke={PALETTE.moss} strokeWidth="1.5"/>
          <circle cx="11" cy="11" r="3" fill={PALETTE.orange}/>
        </svg>
        Datapunt 4 · Armand Swirc · 1110156 · Rabobank Kring Zuid-Holland · 26.04.2026
      </div>
    </div>
  );
}

// ── compose ──────────────────────────────────────────────────────────────
const TOTAL = 268;

const CHAPTERS = [
  { start: 0,   label: "Persoonlijke noot"      },
  { start: 4,   label: "Introductie"             },
  { start: 9,   label: "Centrale vraag"          },
  { start: 17,  label: "Doelgroep — markt"       },
  { start: 33,  label: "Passieve portefeuille"   },
  { start: 44,  label: "Strategie Map"           },
  { start: 60,  label: "Balanced Scorecard"      },
  { start: 70,  label: "De funnel"               },
  { start: 85,  label: "Investering"             },
  { start: 100, label: "Operationele kosten"     },
  { start: 116, label: "FTE-allocatie"           },
  { start: 130, label: "Productmatrix"           },
  { start: 147, label: "Winstgevendheid"         },
  { start: 164, label: "NPV-tabel"               },
  { start: 182, label: "Scenario's"              },
  { start: 200, label: "Sensitiviteit"           },
  { start: 215, label: "Fiscaal"                 },
  { start: 228, label: "Risico's"                },
  { start: 243, label: "Tijdlijn"                },
  { start: 258, label: "Conclusie"               },
];

function App() {
  return (
    <Stage width={1920} height={1080} duration={TOTAL} background={PALETTE.paper} fps={60} loop={true} chapters={CHAPTERS}>
      <PaperBackground />
      <Sprite start={0}    end={4.5}>{() => <SceneJoke />}</Sprite>
      <Sprite start={4}    end={9.5}>{() => <SceneIntro />}</Sprite>
      <Sprite start={9}    end={17.5}>{() => <SceneVraag />}</Sprite>
      <Sprite start={17}   end={33.5}>{() => <SceneDoelgroepMarkt />}</Sprite>
      <Sprite start={33}   end={44.5}>{() => <ScenePassief />}</Sprite>
      <Sprite start={44}   end={60}>{() => <SceneStrategyMap />}</Sprite>
      <Sprite start={60}   end={70}>{() => <SceneBSC />}</Sprite>
      <Sprite start={70}   end={85.5}>{() => <SceneFunnel />}</Sprite>
      <Sprite start={85}   end={100}>{() => <SceneInvestering />}</Sprite>
      <Sprite start={100}  end={116.5}>{() => <SceneOpEx />}</Sprite>
      <Sprite start={116}  end={130}>{() => <SceneFTE />}</Sprite>
      <Sprite start={130}  end={147.5}>{() => <SceneProductMatrix />}</Sprite>
      <Sprite start={147}  end={164}>{() => <SceneProfitability />}</Sprite>
      <Sprite start={164}  end={182.5}>{() => <SceneNPVTable />}</Sprite>
      <Sprite start={182}  end={200}>{() => <SceneScenarios />}</Sprite>
      <Sprite start={200}  end={215.5}>{() => <SceneSensitivity />}</Sprite>
      <Sprite start={215}  end={228}>{() => <SceneFiscaal />}</Sprite>
      <Sprite start={228}  end={243.5}>{() => <SceneRisk />}</Sprite>
      <Sprite start={243}  end={258.5}>{() => <SceneTimeline />}</Sprite>
      <Sprite start={258}  end={268}>{() => <SceneConclusion />}</Sprite>
      <FilmChrome totalDuration={TOTAL} />
    </Stage>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
