// Datapunt 4 — animated video, full detail (~4 min)
// Scene file 1 of 2 — palette, helpers, scenes 1-7

const PALETTE = {
  ink: "#0c1a14",
  paper: "#f5f1e8",
  paperWarm: "#ece5d2",
  cream: "#f9f6ef",
  moss: "#1b5e3a",
  mossDeep: "#0f3a23",
  mossLight: "#3d8a5c",
  orange: "#e6692a",
  orangeSoft: "#f29a64",
  sun: "#e8b341",
  sky: "#5a8aa3",
  bad: "#a8332a",
  inkSoft: "#3a4a40",
  line: "rgba(12,26,20,0.18)",
};

function fadeInOut(localTime, duration, entry = 0.6, exit = 0.6) {
  const exitStart = duration - exit;
  if (localTime < entry) return Easing.easeOutCubic(localTime / entry);
  if (localTime > exitStart)
    return 1 - Easing.easeInCubic((localTime - exitStart) / exit);
  return 1;
}
function nl(n) {
  return Math.round(n).toLocaleString("nl-NL");
}
function ramp(t, a, b, easeFn = Easing.easeOutCubic) {
  if (t <= a) return 0;
  if (t >= b) return 1;
  return easeFn((t - a) / (b - a));
}

function PaperBackground() {
  const time = useTime();
  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        background: `radial-gradient(ellipse at 30% 20%, ${PALETTE.cream} 0%, ${PALETTE.paper} 55%, ${PALETTE.paperWarm} 100%)`,
      }}
    >
      <div
        style={{
          position: "absolute",
          inset: 0,
          backgroundImage: `radial-gradient(rgba(12,26,20,0.04) 1px, transparent 1px)`,
          backgroundSize: "4px 4px",
          opacity: 0.5,
          transform: `translate(${Math.sin(time * 0.4) * 2}px, ${Math.cos(time * 0.3) * 2}px)`,
        }}
      />
    </div>
  );
}

const SCENE_LABELS = [
  [0, "PERSOONLIJKE NOOT"],
  [4, "INTRODUCTIE"],
  [9, "CENTRALE VRAAG"],
  [17, "DOELGROEP — CBS-MARKTVLOER"],
  [33, "DOELGROEP — PASSIEVE PORTEFEUILLE"],
  [44, "STRATEGIE MAP + BSC"],
  [64, "DE FUNNEL"],
  [79, "INVESTERING"],
  [93, "OPERATIONELE KOSTEN — 5 JAAR"],
  [109, "FTE-BURDEN RATE"],
  [122, "PRODUCTKANSENMATRIX"],
  [139, "WINSTGEVENDHEID PER KLANT"],
  [155, "CONTANTE WAARDE — NPV TABEL"],
  [173, "DRIE SCENARIO'S"],
  [190, "GEVOELIGHEIDSANALYSE"],
  [205, "FISCALE BEHANDELING"],
  [217, "RISICOMATRIX"],
  [232, "IMPLEMENTATIETIJDLIJN"],
  [248, "CONCLUSIE"],
];

function FilmChrome({ totalDuration }) {
  const time = useTime();
  const pct = (time / totalDuration) * 100;
  let label = SCENE_LABELS[0][1];
  let idx = 1;
  for (let i = 0; i < SCENE_LABELS.length; i++) {
    if (time >= SCENE_LABELS[i][0]) {
      label = SCENE_LABELS[i][1];
      idx = i + 1;
    }
  }
  const idxStr = String(idx).padStart(2, "0");

  return (
    <>
      <div
        style={{
          position: "absolute",
          top: 36,
          left: 48,
          display: "flex",
          alignItems: "center",
          gap: 12,
          fontFamily: "JetBrains Mono, monospace",
          fontSize: 12,
          letterSpacing: "0.18em",
          color: PALETTE.inkSoft,
          textTransform: "uppercase",
        }}
      >
        <svg width="18" height="18" viewBox="0 0 18 18">
          <path
            d="M9 1 L17 9 L9 17 L1 9 Z"
            fill="none"
            stroke={PALETTE.moss}
            strokeWidth="1.2"
          />
          <circle cx="9" cy="9" r="2.5" fill={PALETTE.orange} />
        </svg>
        <span>Datapunt 4 / Business Case</span>
      </div>

      <div
        style={{
          position: "absolute",
          top: 36,
          right: 48,
          fontFamily: "JetBrains Mono, monospace",
          fontSize: 12,
          letterSpacing: "0.18em",
          color: PALETTE.inkSoft,
          textTransform: "uppercase",
          display: "flex",
          alignItems: "center",
          gap: 10,
        }}
      >
        <span>
          {idxStr} — {label}
        </span>
        <span
          style={{
            width: 6,
            height: 6,
            borderRadius: 3,
            background: PALETTE.orange,
            opacity: 0.5 + Math.sin(time * 4) * 0.5,
          }}
        />
      </div>

      <div
        style={{
          position: "absolute",
          left: 48,
          right: 48,
          bottom: 36,
          height: 1,
          background: PALETTE.line,
        }}
      >
        <div
          style={{
            position: "absolute",
            left: 0,
            top: 0,
            height: 1,
            width: `${pct}%`,
            background: PALETTE.moss,
          }}
        />
        <div
          style={{
            position: "absolute",
            left: `${pct}%`,
            top: -3,
            width: 7,
            height: 7,
            marginLeft: -3,
            borderRadius: 4,
            background: PALETTE.orange,
          }}
        />
      </div>

      <div
        style={{
          position: "absolute",
          left: 48,
          bottom: 14,
          fontFamily: "JetBrains Mono, monospace",
          fontSize: 11,
          letterSpacing: "0.16em",
          color: PALETTE.inkSoft,
          textTransform: "uppercase",
        }}
      >
        Armand Swirc · 1110156 · GMS2E
      </div>
      <div
        style={{
          position: "absolute",
          right: 48,
          bottom: 14,
          fontFamily: "JetBrains Mono, monospace",
          fontSize: 11,
          letterSpacing: "0.16em",
          color: PALETTE.inkSoft,
          textTransform: "uppercase",
        }}
      >
        {Math.floor(time / 60)}:{String(Math.floor(time % 60)).padStart(2, "0")}{" "}
        / {Math.floor(totalDuration / 60)}:
        {String(Math.floor(totalDuration % 60)).padStart(2, "0")}
      </div>
    </>
  );
}

// Reusable headers
function SceneHeader({ eyebrow, title, accent = PALETTE.moss, sub, t }) {
  const eyebrowA = ramp(t, 0, 0.4);
  const subA = ramp(t, 0.4, 1.0);

  // Split title string into staggered words; keep JSX as-is
  const titleIsString = typeof title === 'string';
  const titleWords = titleIsString ? title.split(' ') : [];

  return (
    <div style={{ position: "absolute", left: 120, top: 120, right: 120 }}>
      <div
        style={{
          fontFamily: "JetBrains Mono, monospace",
          fontSize: 12,
          letterSpacing: "0.2em",
          color: PALETTE.orange,
          textTransform: "uppercase",
          opacity: eyebrowA,
          transform: `translateY(${(1 - eyebrowA) * -8}px)`,
        }}
      >
        {eyebrow}
      </div>

      <div
        style={{
          marginTop: 12,
          fontFamily: "Fraunces, serif",
          fontSize: 60,
          fontWeight: 500,
          letterSpacing: "-0.025em",
          lineHeight: 1.05,
          color: PALETTE.ink,
          maxWidth: 1500,
        }}
      >
        {titleIsString ? titleWords.map((word, i) => {
          const wa = ramp(t, 0.15 + i * 0.04, 0.5 + i * 0.04);
          return (
            <span key={i} style={{
              display: 'inline-block',
              opacity: wa,
              transform: `translateY(${(1 - wa) * 16}px)`,
              marginRight: '0.28em',
            }}>{word}</span>
          );
        }) : title}
      </div>

      {sub && (
        <div
          style={{
            marginTop: 14,
            fontFamily: "Fraunces, serif",
            fontStyle: "italic",
            fontSize: 22,
            color: PALETTE.inkSoft,
            maxWidth: 1100,
            opacity: subA,
            transform: `translateY(${(1 - subA) * -6}px)`,
          }}
        >
          {sub}
        </div>
      )}
    </div>
  );
}

// ── 00: JOKE SLIDE (0-4s) ────────────────────────────────────────────────
function SceneJoke() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.5, 0.7);
  const t = localTime;

  return (
    <div
      style={{
        position: "absolute",
        inset: 0,
        opacity: o,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      <div
        style={{
          maxWidth: 1100,
          textAlign: "center",
          padding: "0 80px",
          opacity: ramp(t, 0.2, 0.9),
          transform: `translateY(${(1 - ramp(t, 0.2, 0.9)) * 24}px)`,
        }}
      >
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.22em",
            color: PALETTE.orange,
            textTransform: "uppercase",
            marginBottom: 32,
          }}
        >
          Een persoonlijke noot vooraf
        </div>
        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontStyle: "italic",
            fontSize: 64,
            fontWeight: 500,
            lineHeight: 1.15,
            letterSpacing: "-0.02em",
            color: PALETTE.ink,
          }}
        >
          Sinds u bij Datapunt 3. 1,5 uur bezig bent geweest met het nakijken,
          is hier een kortere visuele versie.
        </div>
        <div
          style={{
            marginTop: 40,
            width: 64,
            height: 2,
            background: PALETTE.orange,
            margin: "40px auto 0",
          }}
        />
      </div>
    </div>
  );
}

// ── 01: INTRO (4-9s) ─────────────────────────────────────────────────────
function SceneIntro() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <svg
        style={{
          position: "absolute",
          right: "-200px",
          top: "50%",
          transform: "translateY(-50%)",
        }}
        width="1100"
        height="1100"
        viewBox="0 0 1100 1100"
      >
        <g
          style={{
            transform: `rotate(${t * 6}deg)`,
            transformOrigin: "550px 550px",
          }}
        >
          <path
            d="M550 60 L1040 550 L550 1040 L60 550 Z"
            fill="none"
            stroke={PALETTE.moss}
            strokeWidth="0.8"
            opacity={0.18}
          />
          <path
            d="M550 260 L840 550 L550 840 L260 550 Z"
            fill="none"
            stroke={PALETTE.orange}
            strokeWidth="1.2"
            opacity={0.4}
          />
        </g>
      </svg>

      <div
        style={{
          position: "absolute",
          left: 120,
          top: "50%",
          transform: "translateY(-50%)",
        }}
      >
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.24em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
            marginBottom: 28,
            opacity: ramp(t, 0.1, 0.5),
          }}
        >
          Business Case · Datapunt 4 · OP3 Creating Strategy
        </div>

        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontSize: 132,
            lineHeight: 0.92,
            letterSpacing: "-0.035em",
            fontWeight: 500,
            color: PALETTE.ink,
          }}
        >
          <div
            style={{
              opacity: ramp(t, 0.3, 1.0),
              transform: `translateY(${(1 - ramp(t, 0.3, 1.0)) * 30}px)`,
            }}
          >
            Rabobank
          </div>
          <div
            style={{
              opacity: ramp(t, 0.7, 1.4),
              transform: `translateY(${(1 - ramp(t, 0.7, 1.4)) * 30}px)`,
              color: PALETTE.moss,
              fontStyle: "italic",
            }}
          >
            Start.
          </div>
        </div>

        <div
          style={{
            marginTop: 32,
            fontFamily: "Fraunces, serif",
            fontStyle: "italic",
            fontSize: 26,
            lineHeight: 1.4,
            color: PALETTE.inkSoft,
            maxWidth: 720,
            opacity: ramp(t, 1.6, 2.4),
          }}
        >
          Onze bank, ook als jij de koers bepaalt — een financiële doorrekening.
        </div>
        <div
          style={{
            marginTop: 18,
            fontFamily: "Inter",
            fontSize: 16,
            lineHeight: 1.5,
            color: PALETTE.inkSoft,
            maxWidth: 640,
            opacity: ramp(t, 2.2, 3.0),
          }}
        >
          Armand Swirc · Rabobank Kring Zuid-Holland · 26 april 2026
        </div>
      </div>
    </div>
  );
}

// ── 02: CENTRALE VRAAG (5-13s) ───────────────────────────────────────────
function SceneVraag() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="De centrale vraag — uit Datapunt 1 t/m 3"
        title={
          <>
            Hoe vergroot Rabobank het marktaandeel onder{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              jongeren 18&ndash;25
            </span>{" "}
            in Zuid-Holland — zonder het vertrouwenskapitaal te ondermijnen?
          </>
        }
      />
      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          top: 460,
          display: "flex",
          gap: 28,
        }}
      >
        {[
          {
            l: "Primair onderzoek",
            v: "158",
            sub: "enquête-respondenten Gen Z",
            delay: 0.6,
          },
          {
            l: "Focusgroep",
            v: "6",
            sub: "kwalitatieve deelnemers",
            delay: 1.0,
          },
          {
            l: "Stakeholdergesprekken",
            v: "3",
            sub: "Karso · Tromp · Slager",
            delay: 1.4,
          },
          {
            l: "Methodes",
            v: "4",
            sub: "Strategy Map · BSC · NPV · Risico",
            delay: 1.8,
          },
        ].map((c, i) => {
          const a = ramp(t, c.delay, c.delay + 0.5);
          return (
            <div
              key={i}
              style={{
                flex: 1,
                padding: 24,
                background: PALETTE.cream,
                border: `1px solid ${PALETTE.ink}`,
                opacity: a,
                transform: `translateY(${(1 - a) * 18}px)`,
              }}
            >
              <div
                style={{
                  fontFamily: "JetBrains Mono, monospace",
                  fontSize: 13,
                  letterSpacing: "0.16em",
                  color: PALETTE.inkSoft,
                  textTransform: "uppercase",
                }}
              >
                {c.l}
              </div>
              <div
                style={{
                  fontFamily: "Fraunces, serif",
                  fontSize: 84,
                  fontWeight: 500,
                  color: PALETTE.moss,
                  lineHeight: 1,
                  marginTop: 8,
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {c.v}
              </div>
              <div
                style={{
                  marginTop: 8,
                  fontSize: 14,
                  color: PALETTE.inkSoft,
                  lineHeight: 1.4,
                }}
              >
                {c.sub}
              </div>
            </div>
          );
        })}
      </div>

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          bottom: 130,
          fontFamily: "Fraunces, serif",
          fontStyle: "italic",
          fontSize: 22,
          color: PALETTE.inkSoft,
          lineHeight: 1.5,
          opacity: ramp(t, 2.2, 3.0),
        }}
      >
        Strategische groeirichting: <b>marktpenetratie</b>. Waardestrategie:{" "}
        <b>customer intimacy</b> (Treacy &amp; Wiersema, 1993). Verdedigbaar
        voordeel: de <b>coöperatieve bundel</b> — campus, Robin AI, lokale
        adviseurs (Barney, 1991).
      </div>
    </div>
  );
}

// ── 03: DOELGROEP — markt (13-29s) ───────────────────────────────────────
function SceneDoelgroepMarkt() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const cities = [
    { name: "Rotterdam", val: 92116, w: 0.434, color: PALETTE.moss },
    { name: "Den Haag", val: 73577, w: 0.347, color: PALETTE.mossDeep },
    { name: "Leiden", val: 24102, w: 0.113, color: PALETTE.orange },
    { name: "Delft", val: 22571, w: 0.106, color: PALETTE.sun },
  ];

  const totalT = ramp(t, 0.5, 2.5);
  const totalVal = Math.round(212366 * totalT);
  const relT = ramp(t, 4.0, 5.5);
  const relVal = Math.round(31855 * relT);

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="De doelgroep — CBS Kerncijfers wijken & buurten 2025"
        title={
          <>
            De markt —{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              vier steden, één leeftijdscohort
            </span>
            .
          </>
        }
        sub="CBS publiceert leeftijdsband 15–25 op gemeenteniveau; gebruikt als controleerbare proxy voor 18–25 jaar in Rotterdam, Den Haag, Leiden, Delft."
      />

      <div style={{ position: "absolute", left: 120, top: 320 }}>
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.16em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
          }}
        >
          Totale markt — jongeren 15–25
        </div>
        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontSize: 200,
            fontWeight: 500,
            letterSpacing: "-0.04em",
            lineHeight: 0.9,
            color: PALETTE.ink,
            fontVariantNumeric: "tabular-nums",
            marginTop: 4,
          }}
        >
          {nl(totalVal)}
        </div>
      </div>

      <div
        style={{
          position: "absolute",
          right: 120,
          top: 320,
          opacity: ramp(t, 3.6, 4.4),
          textAlign: "right",
        }}
      >
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.18em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
          }}
        >
          Huidige Rabobank-penetratie
        </div>
        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontSize: 130,
            fontWeight: 500,
            color: PALETTE.moss,
            letterSpacing: "-0.03em",
            lineHeight: 1,
            marginTop: 6,
            fontVariantNumeric: "tabular-nums",
          }}
        >
          15,0<span style={{ fontSize: 80, color: PALETTE.inkSoft }}>%</span>
        </div>
        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontSize: 22,
            fontStyle: "italic",
            color: PALETTE.inkSoft,
            marginTop: 6,
          }}
        >
          ≈ {nl(relVal)} jonge relaties in pilotregio
        </div>
      </div>

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          top: 600,
          opacity: ramp(t, 5.5, 6.4),
        }}
      >
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.16em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
            marginBottom: 14,
          }}
        >
          Verdeling over vier steden
        </div>

        <div
          style={{
            display: "flex",
            height: 80,
            border: `1px solid ${PALETTE.ink}`,
            overflow: "hidden",
          }}
        >
          {cities.map((c, i) => {
            const fillT = ramp(t, 5.7 + i * 0.2, 6.5 + i * 0.2);
            return (
              <div
                key={c.name}
                style={{
                  flex: `0 0 ${c.w * 100}%`,
                  background: c.color,
                  position: "relative",
                  borderRight: i < 3 ? `1px solid ${PALETTE.paper}` : "none",
                }}
              >
                <div
                  style={{
                    position: "absolute",
                    inset: 0,
                    background: PALETTE.paperWarm,
                    transform: `scaleX(${1 - fillT})`,
                    transformOrigin: "right",
                  }}
                />
              </div>
            );
          })}
        </div>
        <div
          style={{
            display: "flex",
            marginTop: 14,
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.12em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
          }}
        >
          {cities.map((c, i) => (
            <div
              key={c.name}
              style={{
                flex: `0 0 ${c.w * 100}%`,
                opacity: ramp(t, 5.9 + i * 0.2, 6.5 + i * 0.2),
              }}
            >
              <div>{c.name}</div>
              <div
                style={{
                  color: PALETTE.ink,
                  fontFamily: "Fraunces",
                  fontSize: 22,
                  marginTop: 2,
                  letterSpacing: 0,
                }}
              >
                {nl(c.val)}
              </div>
            </div>
          ))}
        </div>

        {/* outlook: penetratie target */}
        <div
          style={{
            marginTop: 50,
            display: "flex",
            gap: 20,
            opacity: ramp(t, 8.5, 9.5),
          }}
        >
          {[
            {
              tag: "Vandaag",
              val: "15,00%",
              sub: "31.855 relaties",
              emph: false,
            },
            {
              tag: "S2 · 24 mnd",
              val: "15,23%",
              sub: "+480 actieve relaties",
              emph: true,
            },
            {
              tag: "S3 · 24 mnd",
              val: "15,33%",
              sub: "+700 actieve relaties",
              emph: false,
            },
          ].map((s, i) => (
            <div
              key={i}
              style={{
                flex: 1,
                padding: "18px 22px",
                background: s.emph ? PALETTE.mossDeep : PALETTE.cream,
                color: s.emph ? PALETTE.cream : PALETTE.ink,
                border: `1px solid ${PALETTE.ink}`,
              }}
            >
              <div
                style={{
                  fontFamily: "JetBrains Mono, monospace",
                  fontSize: 13,
                  letterSpacing: "0.16em",
                  opacity: 0.75,
                  textTransform: "uppercase",
                }}
              >
                {s.tag}
              </div>
              <div
                style={{
                  fontFamily: "Fraunces, serif",
                  fontSize: 50,
                  fontWeight: 500,
                  lineHeight: 1,
                  marginTop: 4,
                  fontVariantNumeric: "tabular-nums",
                  color: s.emph ? PALETTE.cream : PALETTE.moss,
                }}
              >
                {s.val}
              </div>
              <div
                style={{
                  fontFamily: "Fraunces",
                  fontStyle: "italic",
                  fontSize: 15,
                  marginTop: 4,
                  opacity: 0.9,
                }}
              >
                {s.sub}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── 04: PASSIEVE PORTEFEUILLE (29-40s) ───────────────────────────────────
function ScenePassief() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  // dot grid: 31855 jonge relaties, 80% passive = 25484
  const cols = 50,
    rows = 18;
  const total = cols * rows; // 900 dots
  const passiveCount = Math.round(total * 0.8);
  const targetCount = Math.round(total * (2640 / 31855)); // ~75 dots

  const passiveT = ramp(t, 1.0, 3.0);
  const targetT = ramp(t, 3.5, 5.0);
  const heractT = ramp(t, 5.5, 7.0);

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="Doelgroep · stroom 2 — passieve portefeuille"
        title={
          <>
            Onbenutte relaties —{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              ~80% van de jongeren is passief
            </span>
            .
          </>
        }
        sub="Eigen field research, 2026. 80% van Gen Z heeft een geërfde, passieve bankrelatie — nooit zelf gekozen."
      />

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 540,
          top: 360,
          display: "grid",
          gridTemplateColumns: `repeat(${cols}, 1fr)`,
          gridTemplateRows: `repeat(${rows}, 1fr)`,
          gap: 5,
          height: 380,
        }}
      >
        {Array.from({ length: total }).map((_, i) => {
          const isPassive = i < passiveCount;
          const isTarget = i < targetCount;
          let color = PALETTE.line;
          let opacity = 0.6;
          if (isPassive && passiveT > i / passiveCount) {
            color = PALETTE.inkSoft;
            opacity = 0.5;
          }
          if (isTarget && targetT > i / targetCount) {
            color = PALETTE.orange;
            opacity = 1;
          }
          if (
            isTarget &&
            heractT > i / targetCount &&
            (i % 8 === 0 || i % 8 === 3)
          ) {
            color = PALETTE.moss;
            opacity = 1;
          }
          return (
            <div
              key={i}
              style={{
                width: "100%",
                aspectRatio: "1",
                background: color,
                opacity,
                borderRadius: 1,
              }}
            />
          );
        })}
      </div>

      <div style={{ position: "absolute", right: 120, top: 360, width: 360 }}>
        {[
          {
            tag: "Jonge relaties NL pilotregio",
            val: "31.855",
            delay: 0.5,
            color: PALETTE.inkSoft,
          },
          {
            tag: "Passief / laagactief · 80%",
            val: "25.484",
            delay: 1.5,
            color: PALETTE.inkSoft,
          },
          {
            tag: "CRM-selectie pilot",
            val: "2.640",
            delay: 3.5,
            color: PALETTE.orange,
          },
          {
            tag: "Heractivaties · 12,7%",
            val: "+336",
            delay: 5.5,
            color: PALETTE.moss,
          },
        ].map((r, i) => {
          const a = ramp(t, r.delay, r.delay + 0.6);
          return (
            <div
              key={i}
              style={{
                padding: "14px 0",
                borderBottom: `1px dashed ${PALETTE.line}`,
                opacity: a,
                transform: `translateX(${(1 - a) * 16}px)`,
              }}
            >
              <div
                style={{
                  fontFamily: "JetBrains Mono, monospace",
                  fontSize: 13,
                  letterSpacing: "0.14em",
                  color: PALETTE.inkSoft,
                  textTransform: "uppercase",
                }}
              >
                {r.tag}
              </div>
              <div
                style={{
                  fontFamily: "Fraunces, serif",
                  fontSize: 56,
                  fontWeight: 500,
                  color: r.color,
                  lineHeight: 1.05,
                  marginTop: 4,
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {r.val}
              </div>
            </div>
          );
        })}
      </div>

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          bottom: 110,
          opacity: ramp(t, 6.5, 7.5),
          fontFamily: "Fraunces, serif",
          fontStyle: "italic",
          fontSize: 20,
          color: PALETTE.inkSoft,
          lineHeight: 1.5,
        }}
      >
        Robin benadert deze 2.640 met life-event berichten — DUO-aflossing,
        eerste salaris, huurcontract — geen massa-mailing.
      </div>
    </div>
  );
}

// ── 05: STRATEGY MAP + BSC (44-64s) ─────────────────────────────────────
function SceneStrategyMap() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const monoLabel = {
    fontFamily: "JetBrains Mono, monospace",
    fontSize: 11,
    letterSpacing: "0.18em",
    textTransform: "uppercase",
  };

  // Canvas: 1920×1080. Content area x=220–1780.
  // Row y: fin=230 · kl=424 · proc=604 · learn=768. Gaps: ~90, ~86, ~80px.
  // H-gaps: fin/kl 44px, proc 28px, learn 26px.
  const goal = { x: 710, y: 124, w: 500, h: 54 };

  const rowLabels = [
    { title: "Financieel",           x: 40, y: 230 },
    { title: "Klant",                x: 40, y: 424 },
    { title: "Interne\nprocessen",   x: 40, y: 604 },
    { title: "Leren &\nontwikkelen", x: 40, y: 768 },
  ];

  // fin/kl: 3 × 490px, gap 44px  (220,754,1288 → right edge 1778)
  // proc:   5 × 284px, gap 28px  (220,532,844,1156,1468 → right edge 1752+28=1780... let's check: 1468+284=1752)
  // learn:  4 × 365px, gap 26px  (220,611,1002,1393 → right edge 1758)

  const nodes = [
    { id:"f1", x:220,  y:230, w:490, h:96, color:PALETTE.orange, title:"Penetratie 18–25 jaar",              sub:"15,0% → 15,23%" },
    { id:"f2", x:754,  y:230, w:490, h:96, color:PALETTE.moss,   title:"CLV-opbouw",                         sub:"winstgevend vanaf jaar 5" },
    { id:"f3", x:1288, y:230, w:490, h:96, color:PALETTE.sky,    title:"Positieve NPV ~€95k",                sub:"PSD3-risico gemitigeerd" },

    { id:"c1", x:220,  y:424, w:490, h:96, color:PALETTE.orange, title:"Meer actieve contacten bij life events", sub:"relevant op het eerste moment" },
    { id:"c2", x:754,  y:424, w:490, h:96, color:PALETTE.moss,   title:"Opt-in adviesgesprek ≥30%",          sub:"ervaren relevantie ≥4,0/5" },
    { id:"c3", x:1288, y:424, w:490, h:96, color:PALETTE.sky,    title:"Robin als voorkeursaanspreekpunt",    sub:"coöperatief eigenaarschap 41,1% → ≥55%" },

    { id:"p1", x:220,  y:604, w:284, h:96, color:PALETTE.orange, title:"Campusactiviteiten ≥8/jaar",          sub:"QR-instrook naar Robin" },
    { id:"p2", x:532,  y:604, w:284, h:96, color:PALETTE.orange, title:"Robin intake completion ≥40%",        sub:"campus → digitale intake" },
    { id:"p3", x:844,  y:604, w:284, h:96, color:PALETTE.moss,   title:"Eerste adviesgesprek ≤48 uur",        sub:"Startplan ≥90%" },
    { id:"p4", x:1156, y:604, w:284, h:96, color:PALETTE.moss,   title:"Financieel Startplan ≥90%",           sub:"van gesprekken · Wft-opvolging" },
    { id:"p5", x:1468, y:604, w:284, h:96, color:PALETTE.sky,    title:"App-activatie ≤14 dagen",             sub:"check-in na 3 maanden" },

    { id:"l1", x:220,  y:768, w:365, h:96, color:PALETTE.orange, title:"Go-besluit M&C + projectregie",       sub:"harde mijlpaal Q3" },
    { id:"l2", x:611,  y:768, w:365, h:96, color:PALETTE.orange, title:"Campuspilot & partnerships live",     sub:"locatie- en partnerinrichting" },
    { id:"l3", x:1002, y:768, w:365, h:96, color:PALETTE.sky,    title:"Robin live met life event-triggers",  sub:"DUO, huurcontract, eerste salaris" },
    { id:"l4", x:1393, y:768, w:365, h:96, color:PALETTE.moss,   title:"4 Wft-gecertificeerde adviseurs",     sub:"€800/adv/jaar · opleiding on-the-job" },
  ];

  // Phase bracket: centered in the gap between Klant-bottom(492) and Processen-top(548)
  const phaseY = 590;
  // Brackets span the process nodes of matching colour
  const phaseTags = [
    { label: "V1 Campusactivatie",  x: 518,  y: phaseY, color: PALETTE.orange, lineX1: 220,  lineX2: 816 },
    { label: "V2 Adviesvervolging", x: 1142, y: phaseY, color: PALETTE.moss,   lineX1: 844,  lineX2: 1440 },
    { label: "V3 Digitale intake",  x: 1610, y: phaseY, color: PALETTE.sky,    lineX1: 1468, lineX2: 1752 },
  ];

  const nodeById = Object.fromEntries(nodes.map((n) => [n.id, n]));
  const cx = (id) => nodeById[id].x + nodeById[id].w / 2;
  const cy = (id) => nodeById[id].y + nodeById[id].h / 2;
  const top    = (id) => ({ x: cx(id), y: nodeById[id].y });
  const bottom = (id) => ({ x: cx(id), y: nodeById[id].y + nodeById[id].h });
  const right  = (id) => ({ x: nodeById[id].x + nodeById[id].w, y: cy(id) });
  const pathFromPoints = (pts) => pts.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");

  // y routing: yLP between proc-top(604) and learn-bottom(864) → 734
  //            yPC between cust-bottom(492) and proc-top(548)  → 530 (below labels, above process)
  const yLP = 734;
  const yPC = 530;

  // ── Animation timing ──
  // Each arrow draws for 0.7s. Nodes appear when the arrow that hits them finishes.
  const ad = 0.7; // arrow draw duration

  const arrows = [
    // Horizontal: learning row (l nodes already visible)
    { id:"learn-1", delay:2.0, points:[right("l1"), { x:nodeById.l2.x, y:cy("l1") }] },
    { id:"learn-2", delay:2.4, points:[right("l2"), { x:nodeById.l3.x, y:cy("l2") }] },
    // Learn → Process (p nodes appear when arrow finishes)
    { id:"l1-p1", delay:3.0, points:[top("l1"), { x:cx("l1"), y:yLP },    { x:cx("p1"), y:yLP },    bottom("p1")] },
    { id:"l2-p2", delay:3.5, points:[top("l2"), { x:cx("l2"), y:yLP },    { x:cx("p2"), y:yLP },    bottom("p2")] },
    { id:"l3-p3", delay:4.0, points:[top("l3"), { x:cx("l3"), y:yLP-5 },  { x:cx("p3"), y:yLP-5 },  bottom("p3")] },
    { id:"l3-p4", delay:4.5, points:[top("l3"), { x:cx("l3"), y:yLP-12 }, { x:cx("p4"), y:yLP-12 }, bottom("p4")] },
    { id:"l4-p4", delay:5.0, points:[top("l4"), { x:cx("l4"), y:yLP-5 },  { x:cx("p4"), y:yLP-5 },  bottom("p4")] },
    { id:"l4-p5", delay:5.5, points:[top("l4"), { x:cx("l4"), y:yLP },    { x:cx("p5"), y:yLP },    bottom("p5")] },
    // Horizontal: process row (after p nodes are visible)
    { id:"proc-1",  delay:6.2, points:[right("p1"), { x:nodeById.p2.x, y:cy("p1") }] },
    { id:"proc-2",  delay:6.6, points:[right("p2"), { x:nodeById.p3.x, y:cy("p2") }] },
    { id:"proc-3",  delay:7.0, points:[right("p3"), { x:nodeById.p4.x, y:cy("p3") }] },
    { id:"proc-4",  delay:7.4, points:[right("p4"), { x:nodeById.p5.x, y:cy("p4") }] },
    // Process → Customer (c nodes appear when arrow finishes)
    { id:"p1-c1", delay:8.0, points:[top("p1"), { x:cx("p1"), y:yPC },   { x:cx("c1"), y:yPC },   bottom("c1")] },
    { id:"p2-c2", delay:8.5, points:[top("p2"), { x:cx("p2"), y:yPC-7 }, { x:cx("c2"), y:yPC-7 }, bottom("c2")] },
    { id:"p4-c2", delay:9.0, points:[top("p4"), { x:cx("p4"), y:yPC },   { x:cx("c2"), y:yPC },   bottom("c2")] },
    { id:"p5-c3", delay:9.5, points:[top("p5"), { x:cx("p5"), y:yPC-7 }, { x:cx("c3"), y:yPC-7 }, bottom("c3")] },
    // Customer → Financial (f nodes appear when arrow finishes)
    { id:"c1-f1", delay:10.2, points:[top("c1"), { x:cx("c1"), y:394 }, { x:cx("f1"), y:394 }, bottom("f1")] },
    { id:"c2-f2", delay:10.7, points:[top("c2"), { x:cx("c2"), y:394 }, { x:cx("f2"), y:394 }, bottom("f2")] },
    { id:"c3-f3", delay:11.2, points:[top("c3"), { x:cx("c3"), y:394 }, { x:cx("f3"), y:394 }, bottom("f3")] },
    // Financial → Goal (goal appears when last arrow finishes)
    { id:"f1-goal", delay:11.9, points:[top("f1"), { x:cx("f1"),          y:200 }, { x:goal.x+80,       y:200 }, { x:goal.x+80,       y:goal.y+goal.h }] },
    { id:"f2-goal", delay:12.4, points:[top("f2"), { x:cx("f2"),          y:192 }, { x:goal.x+goal.w/2, y:192 }, { x:goal.x+goal.w/2, y:goal.y+goal.h }] },
    { id:"f3-goal", delay:12.9, points:[top("f3"), { x:cx("f3"),          y:200 }, { x:goal.x+goal.w-80,y:200 }, { x:goal.x+goal.w-80,y:goal.y+goal.h }] },
  ];

  // Node appearance: each node fades in when the arrow that leads TO it finishes drawing
  const nodeAppear = {
    l1: 1.0, l2: 1.0, l3: 1.0, l4: 1.0, // base layer — no incoming arrows
    p1: 3.0 + ad, p2: 3.5 + ad, p3: 4.0 + ad, p4: 4.5 + ad, p5: 5.5 + ad,
    c1: 8.0 + ad, c2: 8.5 + ad, c3: 9.5 + ad,
    f1: 10.2 + ad, f2: 10.7 + ad, f3: 11.2 + ad,
  };
  const goalAppear = 12.9 + ad;

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      {/* Header — left column */}
      <div style={{ position: "absolute", left: 40, top: 52, width: 620 }}>
        <div style={{
          marginTop: 12,
          fontFamily: "Fraunces, serif",
          fontSize: 44,
          fontWeight: 500,
          letterSpacing: "-0.03em",
          lineHeight: 1.04,
          color: PALETTE.ink,
          opacity: ramp(t, 0.1, 0.7),
          transform: `translateY(${(1 - ramp(t, 0.1, 0.7)) * 16}px)`,
        }}>
          Van geërfde rekening naar{" "}
          <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>bewuste keuze</span>.
        </div>
        <div style={{
          marginTop: 10,
          fontFamily: "Fraunces, serif",
          fontStyle: "italic",
          fontSize: 16,
          color: PALETTE.inkSoft,
          opacity: ramp(t, 0.3, 0.95),
          transform: `translateY(${(1 - ramp(t, 0.3, 0.95)) * -8}px)`,
        }}>
          Horizontaal loopt de fase; verticaal ontstaat het resultaat.
        </div>
      </div>

      {/* Goal box */}
      <div style={{
        position: "absolute",
        left: goal.x, top: goal.y, width: goal.w, height: goal.h,
        opacity: ramp(t, goalAppear, goalAppear + 0.5),
        transform: `translateY(${(1 - ramp(t, 0.55, 1.05)) * -10}px)`,
        borderRadius: 4,
        background: PALETTE.mossDeep,
        borderTop: `4px solid ${PALETTE.mossLight}`,
        color: PALETTE.cream,
        display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "Inter", fontSize: 17, fontWeight: 600,
        boxShadow: "0 6px 18px rgba(15,58,35,0.14)",
        letterSpacing: "-0.01em",
      }}>
        Duurzame winstgroei jongerenportefeuille
      </div>

      {/* Row dividers + labels */}
      {rowLabels.map((row, index) => {
        const a = ramp(t, 0.8 + index * 0.1, 1.4 + index * 0.1);
        const accentColors = [PALETTE.orange, PALETTE.moss, PALETTE.sky, PALETTE.sun];
        return (
          <React.Fragment key={row.title}>
            <div style={{
              position: "absolute", left: 220, top: row.y, width: 1560, height: 1,
              opacity: a * 0.6,
              background: "rgba(12,26,20,0.12)",
            }} />
            <div style={{
              position: "absolute", left: 40, top: row.y + 10, width: 168,
              transform: `translateY(${(1 - a) * 10}px)`,
              color: PALETTE.ink, opacity: a,
            }}>
              <div style={{
                ...monoLabel,
                color: accentColors[index],
                fontSize: 9.5,
                marginBottom: 8,
              }}>
                Perspectief
              </div>
              <div style={{
                fontFamily: "Fraunces, serif",
                fontSize: index > 1 ? 17 : 19,
                fontWeight: 500,
                lineHeight: 1.1,
                whiteSpace: "pre-line",
              }}>
                {row.title}
              </div>
            </div>
          </React.Fragment>
        );
      })}

      {/* SVG: arrows + phase brackets */}
      <svg style={{ position:"absolute", inset:0, width:"100%", height:"100%", pointerEvents:"none" }}>
        <defs>
          <marker id="arrow-ink" viewBox="0 0 10 10" refX="9" refY="5"
            markerWidth="7" markerHeight="7" orient="auto-start-reverse">
            <path d="M 0 0 L 10 5 L 0 10 z" fill={PALETTE.ink} />
          </marker>
        </defs>

        {phaseTags.map((g, idx) => {
          const a = ramp(t, 2.2 + idx * 0.15, 2.8 + idx * 0.15);
          return (
            <g key={g.label} opacity={a}>
              <line x1={g.lineX1} y1={g.y} x2={g.lineX2} y2={g.y}
                stroke={g.color} strokeWidth={1.5} strokeDasharray="4 6" opacity={0.5} />
              <line x1={g.lineX1} y1={g.y-10} x2={g.lineX1} y2={g.y+10}
                stroke={g.color} strokeWidth={1.5} opacity={0.5} />
              <line x1={g.lineX2} y1={g.y-10} x2={g.lineX2} y2={g.y+10}
                stroke={g.color} strokeWidth={1.5} opacity={0.5} />
            </g>
          );
        })}

        {arrows.map((arrow) => {
          const draw = ramp(t, arrow.delay, arrow.delay + ad);
          const isHeavy = arrow.id.startsWith("proc") || arrow.id.startsWith("learn");
          return (
            <path
              key={arrow.id}
              d={pathFromPoints(arrow.points)}
              pathLength="1"
              stroke={PALETTE.ink}
              strokeWidth={isHeavy ? 3.2 : 2.2}
              strokeLinecap="round"
              strokeLinejoin="round"
              fill="none"
              strokeDasharray={`${Math.max(draw, 0.001)} 1`}
              markerEnd={draw > 0.98 ? "url(#arrow-ink)" : undefined}
              opacity={0.88}
            />
          );
        })}
      </svg>

      {/* Nodes */}
      {nodes.map((node, index) => {
        const appear = nodeAppear[node.id] || 1.0;
        const a = ramp(t, appear, appear + 0.5);
        const isSmall = index >= 6;
        return (
          <div key={node.id} style={{
            position: "absolute",
            left: node.x, top: node.y, width: node.w, minHeight: node.h,
            opacity: a,
            transform: `translateY(${(1 - a) * 14}px)`,
            borderRadius: 3,
            background: PALETTE.cream,
            border: `1px solid ${PALETTE.line}`,
            borderTop: `4px solid ${node.color}`,
            boxShadow: "0 2px 12px rgba(12,26,20,0.05)",
            padding: "16px 18px 14px",
            display: "flex", flexDirection: "column", justifyContent: "center",
          }}>
            <div style={{
              fontFamily: "Fraunces, serif",
              fontSize: isSmall ? 15 : 18,
              fontWeight: 500,
              color: PALETTE.ink,
              lineHeight: 1.12,
              letterSpacing: "-0.015em",
            }}>
              {node.title}
            </div>
            <div style={{
              marginTop: 7,
              fontFamily: "Inter",
              fontSize: isSmall ? 11.5 : 12.5,
              color: PALETTE.inkSoft,
              lineHeight: 1.35,
            }}>
              {node.sub}
            </div>
          </div>
        );
      })}

      {/* Phase tag labels */}
      {phaseTags.map((g, idx) => {
        const a = ramp(t, 2.3 + idx * 0.15, 2.9 + idx * 0.15);
        return (
          <div key={`${g.label}-tag`} style={{
            position: "absolute",
            left: g.x, top: g.y - 20,
            transform: `translateX(-50%) translateY(${(1 - a) * 8}px)`,
            padding: "3px 10px",
            borderRadius: 2,
            background: "rgba(245,241,232,0.97)",
            border: `1px solid ${g.color}44`,
            opacity: a,
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 10,
            letterSpacing: "0.14em",
            textTransform: "uppercase",
            color: g.color,
            whiteSpace: "nowrap",
          }}>
            {g.label}
          </div>
        );
      })}
    </div>
  );
}

// ── 05b: BALANCED SCORECARD (58-64s) ────────────────────────────────────
function SceneBSC() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const bsc = [
    {
      p: "Financieel",
      d: "Marktpenetratie 18–25 verhogen zonder verlies van vertrouwenskapitaal",
      k: "15,0% → ≥15,23% · CPA ≤ €90 · contante waarde positief",
      a: "Projectinvestering €32.419 · CRM-kwartaalrapportage",
      f: "S2: OpEx 5j €427k · directe baten €169k · CW 12j ~€95k",
      ac: PALETTE.orange,
    },
    {
      p: "Klant",
      d: "Jongeren binden via relevant en tastbaar eerste contact",
      k: "Robin ≥40% · opt-in ≥30% · app-activatie ≥45%",
      a: "Life event-triggers · enquêteherhaling · Interpolis-incentive",
      f: "Directe opbrengsten €2k → €79k",
      ac: PALETTE.moss,
    },
    {
      p: "Processen",
      d: "Campus-funnel en adviesopvolging betrouwbaar laten draaien",
      k: "≥8 events · ≤48u · ≥90%",
      a: "Campusmateriaal · CRM-tijdstempel · advies",
      f: "Capex €4.235 · M&C €4.840–12k",
      ac: PALETTE.sky,
    },
    {
      p: "Leren & groeien",
      d: "Organisatorische randvoorwaarden voor de pilot zekerstellen",
      k: "Go-besluit · Robin live · Wft",
      a: "IT-projectplan · trainingsbureau · besluitvorming",
      f: "Opleiding €2.904 · kick-off €3.500",
      ac: PALETTE.sun,
    },
  ];

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="Balanced Scorecard — Bijlage D"
        title={
          <>
            Van randvoorwaarden naar{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              financieel resultaat
            </span>
            .
          </>
        }
        sub="De scorecard volgt dezelfde V1, V2 en V3-logica, maar vertaalt die naar meetbare KPI's, activiteiten en financiële gevolgen."
      />

      <div
        style={{
          position: "absolute",
          left: 118,
          right: 118,
          top: 320,
          display: "flex",
          flexDirection: "column",
          gap: 10,
        }}
      >
        {bsc.map((row, ri) => {
          const ra = ramp(t, 0.95 + ri * 0.36, 1.5 + ri * 0.36);
          return (
            <div
              key={ri}
              style={{
                opacity: ra,
                transform: `translateY(${(1 - ra) * 12}px)`,
                background: PALETTE.cream,
                border: `1px solid ${PALETTE.line}`,
                borderLeft: `6px solid ${row.ac}`,
                borderRadius: 0,
                overflow: "hidden",
                display: "grid",
                gridTemplateColumns: "190px 1.15fr 1fr 1.15fr 1.05fr",
                minHeight: 92,
              }}
            >
              {/* Perspective label */}
              <div
                style={{
                  padding: "16px 18px",
                  background: `${row.ac}10`,
                  display: "flex",
                  flexDirection: "column",
                  justifyContent: "center",
                }}
              >
                <div
                  style={{
                    fontFamily: "JetBrains Mono",
                    fontSize: 11,
                    letterSpacing: "0.16em",
                    color: row.ac,
                    textTransform: "uppercase",
                    marginBottom: 6,
                  }}
                >
                  Perspectief
                </div>
                <div
                  style={{
                    fontFamily: "Fraunces",
                    fontSize: 20,
                    fontWeight: 500,
                    color: PALETTE.ink,
                    lineHeight: 1.2,
                  }}
                  >
                  {row.p}
                </div>
              </div>

              {/* Data fields */}
              {[
                { label: "Doelstelling", value: row.d },
                { label: "KPI", value: row.k },
                { label: "Activiteiten", value: row.a },
                { label: "Financieel", value: row.f },
              ].map((field, fi) => (
                <div
                  key={fi}
                  style={{
                    padding: "16px 18px",
                    borderLeft: `1px solid ${PALETTE.line}`,
                    display: "flex",
                    flexDirection: "column",
                    justifyContent: "center",
                  }}
                >
                  <div
                    style={{
                      fontFamily: "JetBrains Mono",
                      fontSize: 10,
                      letterSpacing: "0.14em",
                      color: PALETTE.inkSoft,
                      textTransform: "uppercase",
                      marginBottom: 6,
                    }}
                  >
                    {field.label}
                  </div>
                  <div
                    style={{
                      fontFamily: "Inter",
                      fontSize: 14,
                      color: PALETTE.ink,
                      lineHeight: 1.3,
                    }}
                  >
                    {field.value}
                  </div>
                </div>
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── 06: FUNNEL (68-83.5s) ──────────────────────────────────────────────────
function SceneFunnel() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const rows = [
    {
      lbl: "Campuscontacten / jaar",
      val: 600,
      w: 1.0,
      delay: 1.2,
      color: PALETTE.moss,
    },
    {
      lbl: "Robin afronding · 40%",
      val: 240,
      w: 0.78,
      delay: 2.6,
      color: PALETTE.mossDeep,
    },
    {
      lbl: "Opt-in adviseur · 30%",
      val: 72,
      w: 0.54,
      delay: 4.0,
      color: PALETTE.orange,
    },
    {
      lbl: "× 2 jaar",
      val: 144,
      w: 0.34,
      delay: 5.4,
      color: PALETTE.mossLight,
    },
  ];

  const heractFrac = Easing.springOvershoot(ramp(t, 7.0, 8.4));
  const totalShow = ramp(t, 9.0, 10.2);
  const totalVal = Math.round(480 * Easing.springOvershoot(ramp(t, 9.2, 10.4)));

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="De funnel — pilotcapaciteit S2 · 24 maanden"
        title={
          <>
            Hoe komen we aan{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              +480 actieve relaties
            </span>
            ?
          </>
        }
        sub="Twee stromen, bewust apart gehouden in de berekening: nieuwe klanten via campus + heractivatie van passieve CRM."
      />

      <div style={{ position: "absolute", left: 120, top: 360, width: 760 }}>
        <div
          style={{
            fontFamily: "JetBrains Mono, monospace",
            fontSize: 13,
            letterSpacing: "0.16em",
            color: PALETTE.inkSoft,
            textTransform: "uppercase",
            marginBottom: 14,
            opacity: ramp(t, 0.3, 0.8),
          }}
        >
          Stroom 1 · nieuwe klanten
        </div>

        {rows.map((r, i) => {
          const a = ramp(t, r.delay, r.delay + 0.5);
          const fill = Easing.springOvershoot(ramp(t, r.delay + 0.2, r.delay + 0.9));
          return (
            <div
              key={i}
              style={{
                display: "flex",
                width: `${r.w * 100}%`,
                minWidth: 220,
                height: 56,
                marginBottom: 8,
                background: PALETTE.paperWarm,
                border: `1px solid ${PALETTE.ink}`,
                alignItems: "center",
                padding: "0 18px",
                justifyContent: "space-between",
                opacity: a,
                transform: `translateX(${(1 - a) * -20}px)`,
                position: "relative",
                overflow: "hidden",
              }}
            >
              <div
                style={{
                  position: "absolute",
                  inset: 0,
                  background: r.color,
                  transform: `scaleX(${fill})`,
                  transformOrigin: "left",
                }}
              />
              <div
                style={{
                  position: "relative",
                  fontFamily: "JetBrains Mono, monospace",
                  fontSize: 13,
                  letterSpacing: "0.14em",
                  color: fill > 0.5 ? PALETTE.cream : PALETTE.inkSoft,
                  textTransform: "uppercase",
                }}
              >
                {r.lbl}
              </div>
              <div
                style={{
                  position: "relative",
                  fontFamily: "Fraunces, serif",
                  fontSize: 28,
                  fontWeight: 500,
                  fontVariantNumeric: "tabular-nums",
                  color: fill > 0.5 ? PALETTE.cream : PALETTE.ink,
                }}
              >
                {nl(Math.round(r.val * fill))}
              </div>
            </div>
          );
        })}
      </div>

      <div style={{ position: "absolute", right: 120, top: 360, width: 540 }}>
        <div
          style={{
            opacity: ramp(t, 3.6, 4.4),
            transform: `translateY(${(1 - ramp(t, 3.6, 4.4)) * 18}px)`,
          }}
        >
          <div
            style={{
              fontFamily: "JetBrains Mono, monospace",
              fontSize: 13,
              letterSpacing: "0.16em",
              color: PALETTE.inkSoft,
              textTransform: "uppercase",
              marginBottom: 14,
            }}
          >
            Stroom 2 · heractivatie
          </div>

          <div
            style={{
              border: `1px solid ${PALETTE.ink}`,
              padding: 22,
              background: PALETTE.cream,
            }}
          >
            <div
              style={{
                fontFamily: "JetBrains Mono, monospace",
                fontSize: 13,
                letterSpacing: "0.14em",
                color: PALETTE.inkSoft,
                textTransform: "uppercase",
              }}
            >
              2.640 passieve relaties · 12,7% conversie
            </div>

            <div
              style={{
                fontFamily: "Fraunces, serif",
                fontSize: 80,
                fontWeight: 500,
                fontVariantNumeric: "tabular-nums",
                color: PALETTE.moss,
                lineHeight: 1,
                marginTop: 6,
              }}
            >
              +{Math.round(336 * heractFrac)}
            </div>

            <div
              style={{
                fontSize: 13,
                color: PALETTE.inkSoft,
                marginTop: 6,
                lineHeight: 1.4,
              }}
            >
              via Robin life-event berichten · 1,3% van totale passieve
              portefeuille.
            </div>
          </div>
        </div>

        <div
          style={{
            marginTop: 22,
            background: PALETTE.mossDeep,
            color: PALETTE.cream,
            padding: 24,
            position: "relative",
            overflow: "hidden",
            opacity: totalShow,
            transform: `scale(${0.95 + 0.05 * totalShow})`,
            transformOrigin: "left top",
          }}
        >
          <div
            style={{
              position: "absolute",
              inset: 0,
              background: `radial-gradient(circle at 80% 20%, rgba(230,105,42,0.25), transparent 50%)`,
            }}
          />
          <div style={{ position: "relative" }}>
            <div
              style={{
                fontFamily: "JetBrains Mono, monospace",
                fontSize: 13,
                letterSpacing: "0.18em",
                color: "rgba(245,241,232,0.7)",
                textTransform: "uppercase",
              }}
            >
              Totaal S2
            </div>
            <div
              style={{
                fontFamily: "Fraunces, serif",
                fontSize: 100,
                fontWeight: 500,
                lineHeight: 1,
                marginTop: 4,
                fontVariantNumeric: "tabular-nums",
                letterSpacing: "-0.03em",
              }}
            >
              +{nl(totalVal)}
            </div>
            <div
              style={{
                fontFamily: "Fraunces, serif",
                fontStyle: "italic",
                fontSize: 16,
                marginTop: 8,
                color: "rgba(245,241,232,0.85)",
              }}
            >
              actieve relaties · CPA €68 · onder norm ≤€90
            </div>
          </div>
        </div>
      </div>

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          bottom: 110,
          opacity: ramp(t, 7.5, 8.5),
          fontFamily: "Fraunces, serif",
          fontStyle: "italic",
          fontSize: 18,
          color: PALETTE.inkSoft,
          lineHeight: 1.4,
        }}
      >
        12,5% conversie over de 3.840 bereikbare jongeren — begrensd door
        pilotcapaciteit, niet door marktomvang.
      </div>
    </div>
  );
}

// ── 07: INVESTERING (62-76s) ─────────────────────────────────────────────
function SceneInvestering() {
  const { localTime, duration } = useSprite();
  const o = fadeInOut(localTime, duration, 0.8, 0.8);
  const t = localTime;

  const breakdown = [
    {
      l: "Robin AI · software & config",
      v: 21780,
      c: PALETTE.moss,
      delay: 0.6,
    },
    { l: "Campusactivatiemateriaal", v: 4235, c: PALETTE.orange, delay: 1.0 },
    {
      l: "Adviseursopleiding (Wft)",
      v: 2904,
      c: PALETTE.mossLight,
      delay: 1.4,
    },
    { l: "Stakeholder kick-off", v: 3500, c: PALETTE.sun, delay: 1.8 },
  ];
  const totalT = ramp(t, 0.6, 2.6);
  const totalVal = Math.round(32419 * totalT);

  return (
    <div style={{ position: "absolute", inset: 0, opacity: o }}>
      <SceneHeader
        t={t}
        eyebrow="Eenmalige projectinvestering — Bijlage B"
        title={
          <>
            De pilotinvestering:{" "}
            <span style={{ color: PALETTE.moss, fontStyle: "italic" }}>
              €32.419
            </span>{" "}
            in jaar 1.
          </>
        }
      />

      <div style={{ position: "absolute", left: 120, top: 320 }}>
        <div
          style={{
            fontFamily: "Fraunces, serif",
            fontSize: 200,
            fontWeight: 500,
            color: PALETTE.ink,
            letterSpacing: "-0.04em",
            lineHeight: 0.9,
            fontVariantNumeric: "tabular-nums",
          }}
        >
          €{nl(totalVal)}
        </div>
        <div
          style={{
            fontFamily: "Fraunces",
            fontStyle: "italic",
            fontSize: 22,
            color: PALETTE.inkSoft,
            marginTop: 12,
            opacity: ramp(t, 2.4, 3.0),
          }}
        >
          kapitaal &nbsp;·&nbsp; €26.015 &nbsp; + &nbsp; projectkosten €6.404
        </div>
      </div>

      <div
        style={{
          position: "absolute",
          right: 120,
          top: 320,
          width: 560,
        }}
      >
        {breakdown.map((b, i) => {
          const a = ramp(t, b.delay, b.delay + 0.5);
          const fill = ramp(t, b.delay + 0.2, b.delay + 0.9);
          const w = (b.v / 21780) * 100; // scaled vs largest
          return (
            <div
              key={i}
              style={{
                marginBottom: 18,
                opacity: a,
                transform: `translateY(${(1 - a) * 12}px)`,
              }}
            >
              <div
                style={{
                  display: "flex",
                  justifyContent: "space-between",
                  alignItems: "baseline",
                  marginBottom: 6,
                }}
              >
                <span
                  style={{
                    fontFamily: "JetBrains Mono, monospace",
                    fontSize: 13,
                    letterSpacing: "0.14em",
                    color: PALETTE.inkSoft,
                    textTransform: "uppercase",
                  }}
                >
                  {b.l}
                </span>
                <span
                  style={{
                    fontFamily: "Fraunces, serif",
                    fontSize: 22,
                    fontWeight: 500,
                    color: PALETTE.ink,
                    fontVariantNumeric: "tabular-nums",
                  }}
                >
                  €{nl(b.v)}
                </span>
              </div>
              <div
                style={{
                  height: 14,
                  background: PALETTE.paperWarm,
                  border: `1px solid ${PALETTE.ink}`,
                  position: "relative",
                  overflow: "hidden",
                }}
              >
                <div
                  style={{
                    position: "absolute",
                    inset: 0,
                    background: b.c,
                    transform: `scaleX(${fill * (w / 100)})`,
                    transformOrigin: "left",
                  }}
                />
              </div>
            </div>
          );
        })}
      </div>

      <div
        style={{
          position: "absolute",
          left: 120,
          right: 120,
          bottom: 130,
          display: "flex",
          gap: 24,
          opacity: ramp(t, 4.2, 5.0),
        }}
      >
        {[
          {
            l: "Vpb-aftrek · IVA Robin",
            v: "€4.644",
            sub: "€6.000/jr × 3 jr × 25,8%",
          },
          {
            l: "Btw-behandeling",
            v: "niet-aftr.",
            sub: "art. 11.1.i Wet OB · fin. dienst vrijgesteld",
          },
          {
            l: "Activering Robin AI",
            v: "3 jr lin.",
            sub: "art. 3.30 Wet IB · IVA",
          },
        ].map((c, i) => (
          <div
            key={i}
            style={{
              flex: 1,
              padding: "14px 18px",
              background: PALETTE.cream,
              border: `1px solid ${PALETTE.ink}`,
            }}
          >
            <div
              style={{
                fontFamily: "JetBrains Mono, monospace",
                fontSize: 12,
                letterSpacing: "0.14em",
                color: PALETTE.inkSoft,
                textTransform: "uppercase",
              }}
            >
              {c.l}
            </div>
            <div
              style={{
                fontFamily: "Fraunces, serif",
                fontSize: 30,
                fontWeight: 500,
                color: PALETTE.moss,
                marginTop: 2,
                fontVariantNumeric: "tabular-nums",
              }}
            >
              {c.v}
            </div>
            <div style={{ fontSize: 12, color: PALETTE.inkSoft, marginTop: 2 }}>
              {c.sub}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// Export to window so file 2 can use them
Object.assign(window, {
  PALETTE,
  fadeInOut,
  nl,
  ramp,
  PaperBackground,
  FilmChrome,
  SceneHeader,
  SceneJoke,
  SceneIntro,
  SceneVraag,
  SceneDoelgroepMarkt,
  ScenePassief,
  SceneStrategyMap,
  SceneFunnel,
  SceneInvestering,
});
