// scenes.jsx — BOS Month 2 Progress Report animated video (trustees)

const C = {
  bg:        '#f1ead7',
  bgWarmer:  '#ebe1c8',
  ink:       '#16203a',
  inkSoft:   '#2a3650',
  muted:     '#5a5448',     // darkened for AA on cream
  rule:      '#cdc1a4',
  ruleSoft:  '#ddd2b6',
  gold:      '#b8893d',     // display gold (large text on cream, all sizes on dark)
  goldDeep:  '#7d5a23',     // small-text gold on cream (passes AA at ≥4.5:1)
  positive:  '#3f6a4d',
  positiveSoft: '#dbe6dd',
  paper:     '#f8f3e4',
};

const SERIF = '"EB Garamond", "Cormorant Garamond", Georgia, serif';
const SANS  = '"Geist", "Inter", -apple-system, sans-serif';
const MONO  = '"JetBrains Mono", ui-monospace, SFMono-Regular, monospace';

const W = 1920;
const H = 1080;

// ── helpers ─────────────────────────────────────────────────────────────────
function CountUp({ to, from = 0, dur = 1.4, prefix='', suffix='', decimals = 0, style }) {
  const { localTime } = useSprite();
  const t = Easing.easeOutCubic(clamp(localTime / dur, 0, 1));
  const v = from + (to - from) * t;
  const formatted = decimals > 0
    ? v.toLocaleString('en-GB', { minimumFractionDigits: decimals, maximumFractionDigits: decimals })
    : Math.round(v).toLocaleString('en-GB');
  return <span style={style}>{prefix}{formatted}{suffix}</span>;
}

function Reveal({ at = 0, dur = 0.5, y = 20, children, style }) {
  const { localTime } = useSprite();
  const t = Easing.easeOutCubic(clamp((localTime - at) / dur, 0, 1));
  return (
    <div style={{
      opacity: t,
      transform: `translateY(${(1 - t) * y}px)`,
      willChange: 'transform, opacity',
      ...style,
    }}>{children}</div>
  );
}

// Eyebrow (small label above headline). Always single-line.
function Eyebrow({ x, y, children, color = C.goldDeep }) {
  return (
    <div style={{
      position:'absolute', left:x, top:y,
      fontFamily: SANS, fontSize: 17, fontWeight: 600,
      letterSpacing: '0.24em', textTransform: 'uppercase',
      color, whiteSpace: 'nowrap',
    }}>{children}</div>
  );
}

// Standard scene heading block (eyebrow + 2-line headline area + subtitle)
// Headline is given as already-formatted children with explicit line breaks.
function SceneHeader({ eyebrow, headline, subtitle, eyebrowAt = 0, headlineAt = 0.15, subtitleAt = 0.5 }) {
  return (
    <>
      <Reveal at={eyebrowAt} dur={0.7} y={18}>
        <Eyebrow x={96} y={148}>{eyebrow}</Eyebrow>
      </Reveal>
      <Reveal at={headlineAt} dur={0.9} y={26}>
        <div style={{
          position:'absolute', left: 96, top: 196, right: 96,
          fontFamily: SERIF, fontSize: 78, fontWeight: 500, color: C.ink,
          letterSpacing: '-0.005em', lineHeight: 1.08,
        }}>
          {headline}
        </div>
      </Reveal>
      <Reveal at={subtitleAt} dur={0.8} y={16}>
        <div style={{
          position:'absolute', left: 96, top: 396, maxWidth: 1500,
          fontFamily: SANS, fontSize: 24, color: C.muted, lineHeight: 1.45,
        }}>
          {subtitle}
        </div>
      </Reveal>
    </>
  );
}

// Shared chrome
function FrameChrome({ section, sceneLabel }) {
  return (
    <>
      <div style={{
        position:'absolute', left: 96, top: 56, whiteSpace:'nowrap',
        fontFamily: SANS, fontSize: 14, fontWeight: 600, letterSpacing: '0.22em',
        textTransform:'uppercase', color: C.ink,
      }}>
        British Omani Society
      </div>
      <div style={{
        position:'absolute', right: 96, top: 56, whiteSpace:'nowrap',
        fontFamily: SANS, fontSize: 14, fontWeight: 500, letterSpacing: '0.22em',
        textTransform:'uppercase', color: C.muted,
      }}>
        Trustee Briefing  ·  M2
      </div>
      <div style={{
        position:'absolute', left:96, top:88, right:96, height: 1, background: C.rule,
      }}/>

      <div style={{
        position:'absolute', left:96, bottom:88, right:96, height: 1, background: C.rule,
      }}/>
      <div style={{
        position:'absolute', left: 96, bottom: 40, whiteSpace:'nowrap',
        fontFamily: MONO, fontSize: 13, color: C.muted, letterSpacing: '0.1em',
      }}>
        {sceneLabel}
      </div>
      <div style={{
        position:'absolute', right: 96, bottom: 40, whiteSpace:'nowrap',
        fontFamily: MONO, fontSize: 13, color: C.muted, letterSpacing: '0.1em',
      }}>
        BOS001  ·  AD Strategy  ·  19 May 2026
      </div>
      <div style={{
        position:'absolute', left: 0, right: 0, bottom: 40, textAlign:'center', whiteSpace:'nowrap',
        fontFamily: SANS, fontSize: 13, fontWeight: 500, color: C.ink,
        letterSpacing: '0.28em', textTransform: 'uppercase',
      }}>
        {section}
      </div>
    </>
  );
}

// ── Scene 1: Cover ──────────────────────────────────────────────────────────
function SceneCover() {
  const { localTime, duration } = useSprite();
  const drift = interpolate([0, duration], [10, -10], Easing.linear)(localTime);

  return (
    <>
      <div style={{
        position:'absolute', left: 96, top: 56, whiteSpace:'nowrap',
        fontFamily: SANS, fontSize: 14, fontWeight: 600, letterSpacing: '0.22em',
        textTransform:'uppercase', color: C.ink,
      }}>BOS001</div>
      <div style={{
        position:'absolute', right: 96, top: 56, whiteSpace:'nowrap',
        fontFamily: SANS, fontSize: 14, fontWeight: 500, letterSpacing: '0.22em',
        textTransform:'uppercase', color: C.muted,
      }}>Prepared by AD Strategy Ltd</div>

      <div style={{
        position:'absolute', left:0, right:0, top: 0, bottom: 0,
        display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center',
        transform: `translateY(${drift}px)`,
        textAlign:'center',
      }}>
        <Reveal at={0.2} dur={0.8} y={20}>
          <div style={{
            fontFamily: SANS, fontSize: 15, fontWeight: 600,
            letterSpacing: '0.36em', textTransform: 'uppercase',
            color: C.goldDeep, marginBottom: 36, whiteSpace:'nowrap',
          }}>
            Confidential  ·  Board of Trustees
          </div>
        </Reveal>

        <Reveal at={0.5} dur={1.0} y={28}>
          <div style={{
            fontFamily: SERIF, fontSize: 54, fontWeight: 500,
            color: C.ink, letterSpacing: '0.02em',
            lineHeight: 1.1, whiteSpace:'nowrap',
          }}>
            The British Omani Society
          </div>
        </Reveal>

        <Reveal at={0.9} dur={0.9} y={20}>
          <div style={{
            width: 220, height: 1, background: C.gold, margin: '40px 0',
          }} />
        </Reveal>

        <Reveal at={1.1} dur={1.0} y={26}>
          <div style={{
            fontFamily: SERIF, fontSize: 112, fontWeight: 500,
            fontStyle: 'italic', color: C.ink, letterSpacing:'-0.005em',
            lineHeight: 1.05, whiteSpace:'nowrap',
          }}>
            The CRM Project
          </div>
        </Reveal>

        <Reveal at={1.7} dur={0.8} y={18}>
          <div style={{
            marginTop: 56, fontFamily: SANS, fontSize: 26, fontWeight: 400,
            color: C.inkSoft, letterSpacing:'0.04em', whiteSpace:'nowrap',
          }}>
            Month 2 Progress Report
          </div>
        </Reveal>

        <Reveal at={2.0} dur={0.8} y={14}>
          <div style={{
            marginTop: 18, fontFamily: MONO, fontSize: 15, color: C.muted,
            letterSpacing: '0.2em', textTransform: 'uppercase', whiteSpace:'nowrap',
          }}>
            1 March to 19 May 2026
          </div>
        </Reveal>
      </div>

      <Reveal at={2.4} dur={0.8}>
        <div style={{
          position:'absolute', left:0, right:0, bottom: 80, textAlign:'center', whiteSpace:'nowrap',
          fontFamily: SANS, fontSize: 13, color: C.muted, letterSpacing:'0.28em',
          textTransform: 'uppercase',
        }}>
          Anas Dayeh  ·  for the Board, Director and Staff
        </div>
      </Reveal>
    </>
  );
}

// ── Scene 2: Engagement at a glance ─────────────────────────────────────────
function SceneEngagement() {
  const stats = [
    { eyebrow: 'Contract envelope', big: '17', unit: 'days',  sub: '£5,100 maximum  ·  £300 per day', countTo: 17 },
    { eyebrow: 'Days used to date',  big: '13', unit: 'of 17', sub: 'four days reserved for UAT, import, and close-out', countTo: 13 },
    { eyebrow: 'Go-live target',     big: 'June', unit: '2026', sub: 'end of month, confirmed by the Director', countTo: null },
  ];

  return (
    <>
      <FrameChrome section="The Engagement" sceneLabel="01 / 09" />
      <SceneHeader
        eyebrow="Section 1  ·  Where we stand"
        headline={<>A 17-day engagement, on track<br/>for an end-of-June 2026 go-live.</>}
        subtitle="Phase 2 covers 1 March to 19 May. The platform is configured and ready for staff review."
      />

      <div style={{ position:'absolute', left:96, right:96, top:620, height:1, background: C.rule }}/>
      {stats.map((s, i) => (
        <Reveal key={i} at={1.0 + i * 0.18} dur={0.7} y={28}
          style={{
            position:'absolute',
            left: 96 + i * ((W - 192) / 3),
            top: 660, width: (W - 192) / 3 - 32,
          }}>
          <div style={{
            fontFamily: SANS, fontSize: 15, fontWeight: 600, letterSpacing:'0.24em',
            textTransform:'uppercase', color: C.goldDeep, marginBottom: 28, whiteSpace:'nowrap',
          }}>{s.eyebrow}</div>
          <div style={{
            display:'flex', alignItems:'baseline', gap: 18,
            fontFamily: SERIF, color: C.ink, lineHeight: 1, whiteSpace:'nowrap',
          }}>
            <Sprite start={0} end={999}>
              {s.countTo != null ? (
                <CountUp to={s.countTo} dur={1.4}
                  style={{ fontSize: 132, fontWeight: 500, letterSpacing:'-0.02em' }} />
              ) : (
                <span style={{ fontSize: 96, fontWeight: 500, fontStyle:'italic', letterSpacing:'-0.02em' }}>{s.big}</span>
              )}
            </Sprite>
            <span style={{ fontSize: 40, fontStyle:'italic', color: C.muted }}>{s.unit}</span>
          </div>
          <div style={{
            marginTop: 22, fontFamily: SANS, fontSize: 19, color: C.inkSoft,
            lineHeight: 1.4, maxWidth: 480,
          }}>{s.sub}</div>
        </Reveal>
      ))}
    </>
  );
}

// ── Scene 3: Accomplished ───────────────────────────────────────────────────
function SceneAccomplished() {
  const rows = [
    { num: '4',     label: 'CRM vendors evaluated through demo, trial and quote' },
    { num: '10',    label: 'online forms built, tested and verified in Beacon' },
    { num: '4',     label: 'scheme pipelines configured, 12 stages each' },
    { num: '12',    label: 'trustee records added, with biographical notes' },
    { num: '12',    label: 'configuration issues found in pre-UAT, all resolved' },
    { num: '1,807', label: 'member records cleaned and validated for import' },
  ];

  return (
    <>
      <FrameChrome section="What Has Been Accomplished" sceneLabel="02 / 09" />
      <SceneHeader
        eyebrow="Section 2  ·  Twelve weeks of work"
        headline={<>Selected.  Configured.  <span style={{fontStyle:'italic', color: C.gold}}>Stress-tested.</span></>}
        subtitle="From a four-vendor field to a platform built end-to-end inside a free trial; no subscription has been charged so far."
      />

      {rows.map((r, i) => {
        const col = i % 3, row = Math.floor(i / 3);
        const cellW = (W - 192) / 3;
        const x = 96 + col * cellW;
        const y = 540 + row * 220;
        return (
          <Reveal key={i} at={0.9 + i * 0.12} dur={0.6} y={24}
            style={{
              position:'absolute', left: x, top: y, width: cellW - 40,
              borderTop: `1px solid ${C.rule}`, paddingTop: 28,
            }}>
            <div style={{
              fontFamily: SERIF, fontSize: 92, fontWeight: 500, color: C.ink,
              letterSpacing:'-0.02em', lineHeight: 1, whiteSpace:'nowrap',
            }}>
              {r.num}
            </div>
            <div style={{
              marginTop: 22, fontFamily: SANS, fontSize: 19, color: C.inkSoft,
              lineHeight: 1.35, maxWidth: 500,
            }}>{r.label}</div>
          </Reveal>
        );
      })}
    </>
  );
}

// ── Scene 4: CRM funnel ─────────────────────────────────────────────────────
function SceneFunnel() {
  const vendors = [
    { name: 'Donorfy',    fate: 'eliminated at demonstration stage', detail: 'Fundraising-first; no native events or membership lifecycle.', killAt: 3.2 },
    { name: 'White Fuse', fate: 'eliminated after hands-on trial',   detail: 'No open API; no ISO 27001 or Cyber Essentials.', killAt: 4.6 },
    { name: 'GoodCRM',    fate: 'a close second',                    detail: 'Scored 4.22 / 5. Setup-fee waiver declined.', killAt: 6.2 },
    { name: 'Beacon',     fate: 'selected',                          detail: 'Scored 4.19 / 5. About £1,097 cheaper over 3 yrs.', isWinner: true },
  ];

  const { localTime } = useSprite();

  return (
    <>
      <FrameChrome section="The Selection Journey" sceneLabel="03 / 09" />
      <SceneHeader
        eyebrow="Section 3  ·  Four vendors, one platform"
        headline={<><span style={{fontStyle:'italic', color: C.gold}}>Beacon CRM</span> has been selected.</>}
        subtitle="Scored against Must, Should, and Nice-to-have criteria, then weighed on price."
      />

      <div style={{
        position:'absolute', left: 96, top: 530, right: 96, bottom: 160,
      }}>
        {vendors.map((v, i) => {
          const killed = v.killAt != null && localTime >= v.killAt;
          const winning = v.isWinner && localTime >= 6.8;
          const opacity = killed ? 0.32 : 1;

          return (
            <Reveal key={i} at={0.9 + i * 0.18} dur={0.6} y={24}
              style={{
                position:'absolute', left: 0, right: 0,
                top: i * 110, height: 100,
                display:'flex', alignItems:'center',
                borderTop: `1px solid ${C.rule}`,
                paddingTop: 28,
              }}>
              <div style={{
                width: 70, fontFamily: MONO, fontSize: 15, color: C.muted,
                letterSpacing:'0.1em',
              }}>0{i+1}</div>

              <div style={{
                flex: '0 0 460', position:'relative',
                opacity, transition: 'opacity 500ms ease',
              }}>
                <div style={{
                  fontFamily: SERIF, fontSize: 52, fontWeight: 500, color: C.ink,
                  letterSpacing:'-0.01em', lineHeight: 1,
                  fontStyle: winning ? 'italic' : 'normal',
                  whiteSpace: 'nowrap',
                }}>
                  {v.name}
                </div>
                {/* strikethrough */}
                <div style={{
                  position:'absolute', left: 0, top: 26,
                  height: 2, background: C.muted,
                  width: killed ? '90%' : '0%',
                  transition: 'width 600ms cubic-bezier(0.4, 0, 0.2, 1)',
                }}/>
              </div>

              <div style={{
                flex: 1, opacity, transition: 'opacity 500ms ease',
                paddingLeft: 24,
              }}>
                <div style={{
                  fontFamily: SANS, fontSize: 15, fontWeight: 600,
                  letterSpacing:'0.22em', textTransform:'uppercase',
                  color: winning ? C.goldDeep : C.muted, marginBottom: 8,
                  whiteSpace:'nowrap',
                }}>
                  {v.fate}
                </div>
                <div style={{
                  fontFamily: SANS, fontSize: 20, color: C.inkSoft, lineHeight: 1.35,
                }}>{v.detail}</div>
              </div>

              <div style={{
                width: 220, textAlign:'right', opacity,
                transition: 'opacity 500ms ease',
              }}>
                {v.name === 'Beacon' && (
                  <div style={{
                    display:'inline-block',
                    background: winning ? C.gold : C.bgWarmer,
                    color: winning ? C.bg : C.muted,
                    padding: '8px 18px',
                    fontFamily: MONO, fontSize: 16, fontWeight: 600,
                    letterSpacing:'0.06em',
                    transition: 'all 400ms ease',
                  }}>SELECTED</div>
                )}
                {v.name === 'GoodCRM' && (
                  <div style={{
                    display:'inline-block', background: C.bgWarmer,
                    padding: '8px 18px',
                    fontFamily: MONO, fontSize: 15, color: C.muted,
                    letterSpacing:'0.06em',
                  }}>4.22 / 5</div>
                )}
                {v.name === 'White Fuse' && (
                  <div style={{
                    display:'inline-block', background: 'transparent',
                    padding: '8px 18px',
                    fontFamily: MONO, fontSize: 15, color: C.muted,
                    letterSpacing:'0.06em',
                  }}>n/a</div>
                )}
              </div>
            </Reveal>
          );
        })}
      </div>
    </>
  );
}

// ── Scene 5: Commercial case ────────────────────────────────────────────────
function SceneCommercial() {
  const maxVal = 14831;
  const beacon3 = 7944.85;
  const good3   = 9042.00;
  const beacon5 = 13646.60;
  const good5   = 14830.80;

  const { localTime } = useSprite();
  const grow = Easing.easeOutCubic(clamp((localTime - 0.9) / 1.4, 0, 1));
  const BAR_AREA = 940;

  function Bar({ x, y, label, value, color, isWinner }) {
    const widthPx = (value / maxVal) * BAR_AREA * grow;
    return (
      <div style={{ position:'absolute', left: x, top: y, width: BAR_AREA + 200 }}>
        <div style={{
          display:'flex', alignItems:'baseline', justifyContent:'space-between',
          marginBottom: 10, width: BAR_AREA + 200,
        }}>
          <div style={{
            fontFamily: SERIF, fontSize: 30, fontWeight: 500, color: C.ink,
            fontStyle: isWinner ? 'italic' : 'normal', whiteSpace:'nowrap',
          }}>{label}</div>
          <div style={{
            fontFamily: MONO, fontSize: 24, fontWeight: 600,
            color: isWinner ? C.gold : C.inkSoft, opacity: grow, whiteSpace:'nowrap',
          }}>
            £<CountUp to={value} dur={1.4} decimals={0} />
          </div>
        </div>
        <div style={{
          height: 22, width: BAR_AREA, background: C.bgWarmer, borderRadius: 2, overflow:'hidden',
        }}>
          <div style={{
            width: widthPx, height: '100%', background: color,
          }}/>
        </div>
      </div>
    );
  }

  return (
    <>
      <FrameChrome section="The Commercial Case" sceneLabel="04 / 09" />
      <SceneHeader
        eyebrow="Section 4  ·  Beacon vs GoodCRM"
        headline={<>Cheaper at every horizon.</>}
        subtitle={"Three-year and five-year totals include VAT and Beacon’s 3% annual escalator. GoodCRM modelled flat at its Year 2 rate."}
      />

      <Reveal at={0.8} dur={0.6}>
        <div style={{
          position:'absolute', left: 96, top: 510, whiteSpace:'nowrap',
          fontFamily: SANS, fontSize: 14, fontWeight: 600,
          letterSpacing:'0.24em', textTransform:'uppercase', color: C.muted,
        }}>Three-year total  ·  incl. VAT</div>
      </Reveal>
      <Bar x={96} y={550} label="Beacon Standard" value={beacon3} color={C.gold} isWinner />
      <Bar x={96} y={650} label="GoodCRM Pro"     value={good3}   color={C.inkSoft} />

      <Reveal at={1.6} dur={0.6}>
        <div style={{
          position:'absolute', left: 96, top: 770, whiteSpace:'nowrap',
          fontFamily: SANS, fontSize: 14, fontWeight: 600,
          letterSpacing:'0.24em', textTransform:'uppercase', color: C.muted,
        }}>Five-year total  ·  incl. VAT</div>
      </Reveal>
      <Bar x={96} y={810} label="Beacon Standard" value={beacon5} color={C.gold} isWinner />
      <Bar x={96} y={910} label="GoodCRM Pro"     value={good5}   color={C.inkSoft} />

      {/* Saving callout */}
      <Reveal at={2.0} dur={0.8} y={28}>
        <div style={{
          position:'absolute', right: 96, top: 510,
          width: 460,
          background: C.positiveSoft,
          borderLeft: `3px solid ${C.positive}`,
          padding: '32px 36px',
        }}>
          <div style={{
            fontFamily: SANS, fontSize: 13, fontWeight: 600,
            letterSpacing:'0.24em', textTransform:'uppercase', color: C.positive,
            whiteSpace:'nowrap',
          }}>Beacon saving · 3 yrs</div>
          <div style={{
            marginTop: 14, fontFamily: SERIF, fontSize: 84, fontWeight: 500,
            color: C.positive, lineHeight: 1, letterSpacing:'-0.02em',
            whiteSpace:'nowrap',
          }}>
            ~£1,097
          </div>
          <div style={{
            marginTop: 16, fontFamily: SANS, fontSize: 18, color: C.inkSoft,
            lineHeight: 1.45,
          }}>
            …and approximately <strong>£1,184 saved over five years.</strong>
          </div>
          <div style={{
            marginTop: 18, paddingTop: 18, borderTop: `1px solid ${C.positive}33`,
            fontFamily: SANS, fontSize: 15, color: C.muted, lineHeight: 1.45,
          }}>
            {"Margins are after VAT, with Beacon’s published 3% escalator applied."}
          </div>
        </div>
      </Reveal>
    </>
  );
}

// ── Scene 6: Payments ───────────────────────────────────────────────────────
function ScenePayments() {
  const { localTime } = useSprite();

  const before = [
    { name: 'WorldPay  ·  Premium plan', value: 519, color: C.inkSoft },
    { name: 'Opayo  ·  UK card processor', value: 522, color: C.inkSoft },
    { name: 'GoCardless  ·  Advanced', value: 198, color: C.gold },
  ];
  const after = [
    { name: 'Stripe  ·  replaces card processors', value: 245, color: C.positive },
    { name: 'GoCardless  ·  Standard, –25%', value: 148, color: C.gold },
  ];

  const max = 600;
  const barW = 380;
  const grow = Easing.easeOutCubic(clamp((localTime - 0.8) / 1.2, 0, 1));

  function BarRow({ name, value, color, x, y }) {
    const w = (value / max) * barW * grow;
    return (
      <div style={{ position:'absolute', left: x, top: y, width: barW + 110 }}>
        <div style={{
          fontFamily: SANS, fontSize: 17, color: C.inkSoft, marginBottom: 10,
          whiteSpace:'nowrap',
        }}>{name}</div>
        <div style={{ display:'flex', alignItems:'center', gap: 14 }}>
          <div style={{
            width: barW, height: 20, background: C.bgWarmer, borderRadius: 2, overflow:'hidden',
          }}>
            <div style={{ width: w, height: '100%', background: color }}/>
          </div>
          <div style={{
            fontFamily: MONO, fontSize: 17, fontWeight: 600,
            color: C.ink, opacity: grow, whiteSpace:'nowrap',
          }}>
            £<CountUp to={value} dur={1.3} />
          </div>
        </div>
      </div>
    );
  }

  return (
    <>
      <FrameChrome section="Payment Infrastructure" sceneLabel="05 / 09" />
      <SceneHeader
        eyebrow="Section 5  ·  Three providers, then two"
        headline={<><span style={{fontStyle:'italic', color: C.positive}}>£820 to £870</span>&nbsp;a year of payment savings ahead.</>}
        subtitle="GoCardless has confirmed a 25% charity discount on Direct Debit fees. Stripe replaces WorldPay and Opayo through a phased migration that protects every paying member."
      />

      <Reveal at={0.55} dur={0.5}>
        <div style={{
          position:'absolute', left: 96, top: 478, whiteSpace:'nowrap',
          fontFamily: MONO, fontSize: 13, color: C.muted,
          letterSpacing:'0.16em', textTransform:'uppercase',
        }}>Annualised running costs, excl. transaction fees</div>
      </Reveal>
      <Reveal at={0.7} dur={0.6}>
        <div style={{
          position:'absolute', left: 96, top: 510, whiteSpace:'nowrap',
          fontFamily: SANS, fontSize: 14, fontWeight: 600,
          letterSpacing:'0.24em', textTransform:'uppercase', color: C.muted,
        }}>Today  ·  three providers</div>
      </Reveal>
      <Reveal at={0.75} dur={0.6}>
        <div style={{
          position:'absolute', left: 600, top: 510, whiteSpace:'nowrap',
          fontFamily: SANS, fontSize: 14, fontWeight: 600,
          letterSpacing:'0.24em', textTransform:'uppercase', color: C.muted,
        }}>After migration  ·  two providers</div>
      </Reveal>

      {before.map((b, i) => (
        <BarRow key={'b'+i} {...b} x={96} y={560 + i * 90} />
      ))}
      {after.map((a, i) => (
        <BarRow key={'a'+i} {...a} x={600} y={560 + i * 90} />
      ))}

      <Reveal at={1.4} dur={0.7} y={20}>
        <div style={{
          position:'absolute', left: 96, top: 840, width: 470,
          borderTop: `1px solid ${C.rule}`, paddingTop: 16,
          display:'flex', justifyContent:'space-between', alignItems:'baseline',
        }}>
          <div style={{ fontFamily: SANS, fontSize: 14, fontWeight: 600,
            letterSpacing:'0.22em', textTransform:'uppercase', color: C.muted,
            whiteSpace:'nowrap' }}>Today, total</div>
          <div style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, color: C.ink }}>
            ~£<CountUp to={1239} dur={1.4} />
          </div>
        </div>
      </Reveal>
      <Reveal at={1.55} dur={0.7} y={20}>
        <div style={{
          position:'absolute', left: 600, top: 840, width: 470,
          borderTop: `1px solid ${C.rule}`, paddingTop: 16,
          display:'flex', justifyContent:'space-between', alignItems:'baseline',
        }}>
          <div style={{ fontFamily: SANS, fontSize: 14, fontWeight: 600,
            letterSpacing:'0.22em', textTransform:'uppercase', color: C.muted,
            whiteSpace:'nowrap' }}>After, total</div>
          <div style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, color: C.positive }}>
            ~£<CountUp to={393} dur={1.4} />
          </div>
        </div>
      </Reveal>

      {/* Bonus upside */}
      <Reveal at={1.9} dur={0.7} y={20}>
        <div style={{
          position:'absolute', right: 96, top: 510,
          width: 480, padding: '28px 32px',
          background: C.paper, borderLeft: `3px solid ${C.gold}`,
        }}>
          <div style={{
            fontFamily: SANS, fontSize: 13, fontWeight: 600,
            letterSpacing:'0.24em', textTransform:'uppercase', color: C.goldDeep,
            whiteSpace:'nowrap',
          }}>A quieter upside</div>
          <div style={{
            marginTop: 18, fontFamily: SERIF, fontSize: 56, fontWeight: 500,
            color: C.ink, lineHeight: 1, whiteSpace:'nowrap',
          }}>
            <span style={{ color: C.positive }}>1.1%</span>
            <span style={{ fontSize: 28, color: C.muted, padding: '0 18px' }}>vs</span>
            48.3%
          </div>
          <div style={{
            marginTop: 18, fontFamily: SANS, fontSize: 17, color: C.inkSoft, lineHeight: 1.45,
          }}>
            Direct Debit failure rate against Opayo card renewals. Recovered
            revenue is not yet quantified here.
          </div>
        </div>
      </Reveal>
    </>
  );
}

// ── Scene 7: What's been built ──────────────────────────────────────────────
function SceneBuilt() {
  const cards = [
    { n: '14',     label: 'Custom data fields',   sub: 'capturing BOS-specific member info' },
    { n: '5',      label: 'Membership types',     sub: 'with correct annual fees · auto reference numbers' },
    { n: '10',     label: 'Online forms',         sub: 'applications, enquiries, events, schemes' },
    { n: '4',      label: 'Scheme pipelines',     sub: 'NGD · ALS · GYS · Internship  ·  12 stages each' },
    { n: '12',     label: 'Trustee records',      sub: 'with biographical notes · linked to BOS record' },
    { n: '7',      label: 'Operational views',    sub: 'plus a 3-card dashboard for daily login' },
    { n: '1,805',  label: 'Person records',       sub: 'validated and ready for controlled import' },
    { n: '12/12',  label: 'Issues resolved',      sub: 'pre-UAT stress test · all re-verified' },
  ];

  return (
    <>
      <FrameChrome section="The Beacon Platform, As Built" sceneLabel="06 / 09" />
      <SceneHeader
        eyebrow="Section 6  ·  Built inside a free trial"
        headline={<>A whole platform, <span style={{fontStyle:'italic', color: C.gold}}>already built.</span></>}
        subtitle="Trial account 32502 has been configured, stress-tested and verified. No subscription has been charged to date."
      />

      <div style={{
        position:'absolute', left: 96, top: 540, right: 96, bottom: 160,
        display:'grid', gridTemplateColumns:'repeat(4, 1fr)',
        gridTemplateRows:'repeat(2, 1fr)',
      }}>
        {cards.map((c, i) => (
          <Reveal key={i} at={0.7 + i * 0.1} dur={0.6} y={20}
            style={{
              padding: i % 4 === 0 ? '24px 24px 24px 0' : '24px 24px 24px 28px',
              borderTop: `1px solid ${C.rule}`,
              borderRight: i % 4 === 3 ? 'none' : `1px solid ${C.ruleSoft}`,
            }}>
            <div style={{
              fontFamily: SERIF, fontSize: 80, fontWeight: 500, color: C.ink,
              letterSpacing:'-0.02em', lineHeight: 1, whiteSpace:'nowrap',
            }}>
              {c.n}
            </div>
            <div style={{
              marginTop: 18, fontFamily: SANS, fontSize: 20, fontWeight: 600,
              color: C.ink, whiteSpace:'nowrap',
            }}>{c.label}</div>
            <div style={{
              marginTop: 8, fontFamily: SANS, fontSize: 15, color: C.muted, lineHeight: 1.4,
            }}>{c.sub}</div>
          </Reveal>
        ))}
      </div>
    </>
  );
}

// ── Scene 8: Decision ───────────────────────────────────────────────────────
function SceneDecision() {
  return (
    <>
      <FrameChrome section="Subscription Milestone" sceneLabel="07 / 09" />

      <Reveal at={0} dur={0.7} y={18}>
        <Eyebrow x={96} y={148} color={C.goldDeep}>Section 7  ·  From trial to live subscription</Eyebrow>
      </Reveal>

      <Reveal at={0.2} dur={1.0} y={26}>
        <div style={{
          position:'absolute', left: 96, top: 196, right: 96,
          fontFamily: SERIF, fontSize: 78, fontWeight: 500, color: C.ink,
          letterSpacing: '-0.005em', lineHeight: 1.08,
        }}>
          The trial converts to a live<br/>
          subscription on <span style={{fontStyle:'italic', color: C.gold}}>28 May 2026</span>.
        </div>
      </Reveal>

      {/* Price plate */}
      <Reveal at={0.9} dur={1.0} y={36}>
        <div style={{
          position:'absolute', left: 96, right: 96, top: 530,
          padding: '52px 64px',
          background: C.ink, color: C.bg,
          display:'flex', alignItems:'center', gap: 64,
        }}>
          <div style={{ flex: '0 0 auto' }}>
            <div style={{
              fontFamily: SANS, fontSize: 14, fontWeight: 600,
              letterSpacing:'0.26em', textTransform:'uppercase',
              color: C.gold, marginBottom: 18, whiteSpace:'nowrap',
            }}>
              Beacon Standard plan
            </div>
            <div style={{
              fontFamily: SERIF, fontSize: 128, fontWeight: 500,
              letterSpacing: '-0.03em', lineHeight: 1, whiteSpace:'nowrap',
            }}>
              £<Sprite start={0} end={999}>
                <CountUp to={2570.40} dur={1.6} decimals={2} />
              </Sprite>
            </div>
            <div style={{
              marginTop: 14, fontFamily: SANS, fontSize: 20,
              color: 'rgba(241,234,215,0.7)', whiteSpace:'nowrap',
            }}>
              per year, including VAT  ·  £2,142.00 excl. VAT
            </div>
          </div>

          <div style={{ width: 1, height: 200, background: 'rgba(241,234,215,0.18)', flexShrink:0 }} />

          <div style={{ flex: 1, maxWidth: 600 }}>
            <div style={{
              fontFamily: SANS, fontSize: 14, fontWeight: 600,
              letterSpacing:'0.26em', textTransform:'uppercase',
              color: C.gold, marginBottom: 18, whiteSpace:'nowrap',
            }}>
              What this unlocks
            </div>
            <div style={{
              fontFamily: SERIF, fontSize: 28, lineHeight: 1.4,
              color: C.bg, fontStyle:'italic',
            }}>
              First subscription month begins; the configured platform
              becomes live and ready for member data import.
            </div>
          </div>
        </div>
      </Reveal>

      <Reveal at={1.6} dur={0.7} y={14}>
        <div style={{
          position:'absolute', left: 96, top: 880, maxWidth: 1700,
          fontFamily: SANS, fontSize: 17, color: C.muted, lineHeight: 1.5,
        }}>
          Procurement sits with the Director. All other actions
          (GoCardless plan adjustment, Stripe verification, Opayo and WorldPay
          exit sequencing) are operational tasks managed by staff. The WebMetize
          website integration quote of £3,200 excl. VAT is out of project scope;
          a no-developer signpost approach is in place for Phase 1.
        </div>
      </Reveal>
    </>
  );
}

// ── Scene 9: Roadmap ────────────────────────────────────────────────────────
function SceneRoadmap() {
  const steps = [
    { date: 'w/c 26 May', who: 'BOS staff',    label: 'Staff UAT of Beacon forms' },
    { date: '28 May',     who: 'Director',     label: 'Trial converts to subscription', emphasis: true },
    { date: 'Early June', who: 'AD Strategy',  label: 'Controlled member-data import' },
    { date: 'June',       who: 'AD Strategy',  label: 'Payment provider connections' },
    { date: 'June',       who: 'BOS + AD',     label: 'Stripe verification, GoCardless plan move' },
    { date: 'June',       who: 'AD Strategy',  label: 'Staff training and handover' },
    { date: 'End June',   who: 'BOS + AD',     label: 'Go-live, final report, contract close', emphasis: true },
  ];

  return (
    <>
      <FrameChrome section="The Path To Go-Live" sceneLabel="08 / 09" />
      <SceneHeader
        eyebrow="Section 8  ·  Six weeks to live"
        headline={<>From staff review to <span style={{fontStyle:'italic', color: C.gold}}>end of June</span>.</>}
        subtitle="Each step is scoped to fit inside the four contract days remaining. Weekly check-ins with the Director will surface any slippage early; any overrun would be raised before incurring it."
      />

      <div style={{
        position:'absolute', left: 120, right: 120, top: 510, bottom: 160,
      }}>
        {/* vertical guide */}
        <div style={{
          position:'absolute', left: 240, top: 20, bottom: 20,
          width: 2, background: C.rule,
        }}/>

        {steps.map((s, i) => (
          <Reveal key={i} at={0.6 + i * 0.13} dur={0.6} y={18}
            style={{
              position:'absolute', left: 0, right: 0,
              top: i * 62, height: 56,
              display:'flex', alignItems:'center',
            }}>
            <div style={{
              width: 220, paddingRight: 28, textAlign:'right',
              fontFamily: MONO, fontSize: 18,
              color: s.emphasis ? C.goldDeep : C.muted,
              fontWeight: s.emphasis ? 700 : 500,
              letterSpacing: '0.08em', textTransform:'uppercase',
              whiteSpace:'nowrap',
            }}>{s.date}</div>

            <div style={{
              position:'relative', width: 40, display:'flex', justifyContent:'center',
            }}>
              <div style={{
                width: s.emphasis ? 16 : 10, height: s.emphasis ? 16 : 10,
                background: s.emphasis ? C.gold : C.ink,
                borderRadius: 9,
                boxShadow: s.emphasis ? `0 0 0 5px ${C.bg}, 0 0 0 6px ${C.gold}` : 'none',
              }}/>
            </div>

            <div style={{ flex: 1, paddingLeft: 28, display:'flex', alignItems:'center', justifyContent: 'space-between', paddingRight: 40 }}>
              <div style={{
                fontFamily: SERIF, fontSize: s.emphasis ? 32 : 28,
                color: C.ink, fontWeight: 500,
                fontStyle: s.emphasis ? 'italic' : 'normal',
                letterSpacing:'-0.005em', whiteSpace:'nowrap',
              }}>{s.label}</div>
              <div style={{
                fontFamily: SANS, fontSize: 12, fontWeight: 600,
                letterSpacing:'0.22em', textTransform:'uppercase', color: C.muted,
                padding: '5px 12px',
                border: `1px solid ${C.rule}`, borderRadius: 2,
                whiteSpace:'nowrap', marginLeft: 24, flexShrink: 0,
                background: C.bg,
              }}>{s.who}</div>
            </div>
          </Reveal>
        ))}
      </div>
    </>
  );
}

// ── Scene 10: Close ─────────────────────────────────────────────────────────
function SceneClose() {
  return (
    <>
      <FrameChrome section="Ready For Sign-Off" sceneLabel="09 / 09" />

      <div style={{
        position:'absolute', left:0, right:0, top:0, bottom:0,
        display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center',
        textAlign:'center',
      }}>
        <Reveal at={0.0} dur={0.8} y={18}>
          <div style={{
            fontFamily: SANS, fontSize: 15, fontWeight: 600,
            letterSpacing:'0.36em', textTransform:'uppercase',
            color: C.goldDeep, marginBottom: 52, whiteSpace:'nowrap',
          }}>
            Thank You
          </div>
        </Reveal>

        <Reveal at={0.4} dur={1.0} y={26}>
          <div style={{
            fontFamily: SERIF, fontSize: 86, fontWeight: 500,
            color: C.ink, lineHeight: 1.12, letterSpacing:'-0.005em',
            whiteSpace:'nowrap',
          }}>
            The platform is built.
          </div>
        </Reveal>
        <Reveal at={0.7} dur={1.0} y={20}>
          <div style={{
            fontFamily: SERIF, fontSize: 86, fontWeight: 500,
            color: C.ink, lineHeight: 1.12, letterSpacing:'-0.005em',
            marginTop: 14, whiteSpace:'nowrap',
          }}>
            The savings are <span style={{fontStyle:'italic', color: C.gold}}>identified</span>.
          </div>
        </Reveal>

        <Reveal at={1.3} dur={0.9} y={18}>
          <div style={{
            marginTop: 56, fontFamily: SANS, fontSize: 24, color: C.inkSoft,
            lineHeight: 1.5, maxWidth: 1200,
          }}>
            The trial converts to a live subscription on 28 May,
            and go-live follows in June.
          </div>
        </Reveal>

        <Reveal at={1.9} dur={0.9} y={18}>
          <div style={{ marginTop: 64, width: 200, height: 1, background: C.gold }}/>
        </Reveal>

        <Reveal at={2.1} dur={0.9} y={12}>
          <div style={{
            marginTop: 28, fontFamily: MONO, fontSize: 14, color: C.muted,
            letterSpacing:'0.24em', textTransform:'uppercase', whiteSpace:'nowrap',
          }}>
            Anas Dayeh  ·  AD Strategy Ltd  ·  May 2026
          </div>
        </Reveal>
      </div>
    </>
  );
}

// ── Master video ────────────────────────────────────────────────────────────

const T = {
  cover:        [0,    6.0],
  engagement:   [6.0,  14.0],
  accomplished: [14.0, 24.0],
  funnel:       [24.0, 36.5],
  commercial:   [36.5, 49.0],
  payments:     [49.0, 62.0],
  built:        [62.0, 75.0],
  decision:     [75.0, 85.0],
  roadmap:      [85.0, 96.5],
  close:        [96.5, 107.0],
};

const DURATION = 107.0;

function BOSVideo() {
  const t = useTime();
  React.useEffect(() => {
    const el = document.querySelector('[data-video-root]');
    if (el) el.setAttribute('data-screen-label', `t=${Math.floor(t)}s`);
  }, [Math.floor(t)]);

  return (
    <div data-video-root style={{ position:'absolute', inset:0, background: C.bg, overflow:'hidden' }}>
      <Sprite start={T.cover[0]}        end={T.cover[1]}       ><SceneCover /></Sprite>
      <Sprite start={T.engagement[0]}   end={T.engagement[1]}  ><SceneEngagement /></Sprite>
      <Sprite start={T.accomplished[0]} end={T.accomplished[1]}><SceneAccomplished /></Sprite>
      <Sprite start={T.funnel[0]}       end={T.funnel[1]}      ><SceneFunnel /></Sprite>
      <Sprite start={T.commercial[0]}   end={T.commercial[1]}  ><SceneCommercial /></Sprite>
      <Sprite start={T.payments[0]}     end={T.payments[1]}    ><ScenePayments /></Sprite>
      <Sprite start={T.built[0]}        end={T.built[1]}       ><SceneBuilt /></Sprite>
      <Sprite start={T.decision[0]}     end={T.decision[1]}    ><SceneDecision /></Sprite>
      <Sprite start={T.roadmap[0]}      end={T.roadmap[1]}     ><SceneRoadmap /></Sprite>
      <Sprite start={T.close[0]}        end={T.close[1]}       ><SceneClose /></Sprite>

      <div style={{
        position:'absolute', inset:0, pointerEvents:'none',
        background: `radial-gradient(ellipse at center, transparent 60%, rgba(22,32,58,0.06) 100%)`,
      }}/>
    </div>
  );
}

Object.assign(window, { BOSVideo, DURATION_BOS: DURATION });
