// MyFoodCraving — homepage product video (1:1, 30s, autoplay loop).
// Ported from the Claude Design "Product video for MyFoodCraving" project.
// Self-contained: trimmed timeline engine + five scene "acts".
//
// Homepage embed differences vs. the design source:
//   - No scrubber/playback bar — it auto-plays, loops silently, and pauses
//     when scrolled off-screen (IntersectionObserver) for perf.
//   - Honours prefers-reduced-motion by freezing on a representative frame.
//   - Scales the 1080×1080 canvas to fill a responsive square via transform.
//   - Image paths point at /assets/img/hero-dishes/*.
//
// Usage: <ProductVideo /> after aliasing `const ProductVideo = window.MfcProductVideo;`
(function () {
  const { useState, useEffect, useRef, useMemo, createContext, useContext } = React;

  /* ───────────────────────── engine ───────────────────────── */
  const Easing = {
    linear: (t) => t,
    easeInQuad: (t) => t * t,
    easeOutQuad: (t) => t * (2 - t),
    easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
    easeInCubic: (t) => t * t * t,
    easeOutCubic: (t) => (--t) * t * t + 1,
    easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
    easeOutQuart: (t) => 1 - (--t) * t * t * t,
    easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
    easeOutExpo: (t) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)),
    easeOutBack: (t) => { const c1 = 1.70158, c3 = c1 + 1; return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2); },
  };
  const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
  function interpolate(input, output, ease = Easing.linear) {
    return (t) => {
      if (t <= input[0]) return output[0];
      if (t >= input[input.length - 1]) return output[output.length - 1];
      for (let i = 0; i < input.length - 1; i++) {
        if (t >= input[i] && t <= input[i + 1]) {
          const span = input[i + 1] - input[i];
          const local = span === 0 ? 0 : (t - input[i]) / span;
          const ef = Array.isArray(ease) ? (ease[i] || Easing.linear) : ease;
          return output[i] + (output[i + 1] - output[i]) * ef(local);
        }
      }
      return output[output.length - 1];
    };
  }

  const TimelineContext = createContext({ time: 0, duration: 30, playing: false });
  const useTimeline = () => useContext(TimelineContext);
  const SpriteContext = createContext({ localTime: 0, progress: 0, duration: 0 });
  const useSprite = () => useContext(SpriteContext);

  function Sprite({ start = 0, end = Infinity, children }) {
    const { time } = useTimeline();
    const visible = time >= start && time <= end;
    if (!visible) return null;
    const duration = end - start;
    const localTime = Math.max(0, time - start);
    const progress = duration > 0 && isFinite(duration) ? clamp(localTime / duration, 0, 1) : 0;
    const value = { localTime, progress, duration, visible };
    return React.createElement(SpriteContext.Provider, { value }, typeof children === 'function' ? children(value) : children);
  }

  // Representative still shown when prefers-reduced-motion is set: mid "picks
  // tuned to your data" beat, with the first pick selected.
  const FROZEN_FRAME = 11.2;

  /* ── stage: autoplay loop, pause off-screen, scale-to-fit, no controls ── */
  function MfcVideoStage({ duration = 30, background = '#F7F1E3', children }) {
    const W = 1080, H = 1080;
    const wrapRef = useRef(null);
    const [scale, setScale] = useState(0.4);
    const reduce = useMemo(
      () => typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches,
      []
    );
    const [time, setTime] = useState(reduce ? FROZEN_FRAME : 0);
    const rafRef = useRef(null);
    const lastRef = useRef(null);
    const runningRef = useRef(true);

    // scale the fixed 1080×1080 canvas to the responsive square's width
    useEffect(() => {
      const el = wrapRef.current;
      if (!el) return;
      const measure = () => { if (el.clientWidth) setScale(el.clientWidth / W); };
      measure();
      const ro = new ResizeObserver(measure);
      ro.observe(el);
      window.addEventListener('resize', measure);
      return () => { ro.disconnect(); window.removeEventListener('resize', measure); };
    }, []);

    // pause when scrolled off-screen / tab hidden
    useEffect(() => {
      if (reduce) return;
      const el = wrapRef.current;
      if (!el) return;
      const io = new IntersectionObserver(
        ([e]) => { runningRef.current = e.isIntersecting; if (!e.isIntersecting) lastRef.current = null; },
        { threshold: 0.15 }
      );
      io.observe(el);
      const onVis = () => { if (document.hidden) { runningRef.current = false; lastRef.current = null; } };
      document.addEventListener('visibilitychange', onVis);
      return () => { io.disconnect(); document.removeEventListener('visibilitychange', onVis); };
    }, [reduce]);

    // timeline loop
    useEffect(() => {
      if (reduce) return;
      const step = (ts) => {
        if (runningRef.current) {
          if (lastRef.current == null) lastRef.current = ts;
          const dt = (ts - lastRef.current) / 1000;
          lastRef.current = ts;
          setTime((t) => { let n = t + dt; if (n >= duration) n = n % duration; return n; });
        } else {
          lastRef.current = null;
        }
        rafRef.current = requestAnimationFrame(step);
      };
      rafRef.current = requestAnimationFrame(step);
      return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); lastRef.current = null; };
    }, [duration, reduce]);

    const ctx = useMemo(() => ({ time, duration, playing: !reduce }), [time, duration, reduce]);

    return (
      <div
        ref={wrapRef}
        role="img"
        aria-label="MyFoodCraving demo: low iron and vitamin D flagged from your data, then meals, guided cooking, and weekly tracking tuned to close the gap."
        style={{
          position: 'relative', width: '100%', aspectRatio: '1 / 1',
          borderRadius: 24, overflow: 'hidden', background,
          border: '1.5px solid var(--ink, #1F1A14)', boxShadow: '10px 10px 0 var(--ink, #1F1A14)',
        }}
      >
        <div style={{ position: 'absolute', top: 0, left: 0, width: W, height: H, transform: `scale(${scale})`, transformOrigin: 'top left', background }}>
          <TimelineContext.Provider value={ctx}>{children}</TimelineContext.Provider>
        </div>
      </div>
    );
  }

  /* ───────────────────────── brand tokens ───────────────────────── */
  const C = {
    cream: '#F7F1E3', creamDeep: '#EFE6CF', creamSoft: '#FBF7EC', paper: '#FFFCF3', kraft: '#E8DCC0',
    ink: '#1F1A14', inkSoft: '#3A332A', inkMuted: '#6B6253', inkFaint: '#9A8F7C',
    rule: 'rgba(31,26,20,0.14)', ruleStrong: 'rgba(31,26,20,0.28)',
    orange: '#FF6D2E', orangeDeep: '#E2531A', orangeSoft: 'rgba(255,109,46,0.14)',
    matcha: '#7A9C5A', matchaDeep: '#5E7E40', matchaSoft: 'rgba(122,156,90,0.18)',
    berry: '#C84B5A', butter: '#F4D67A',
  };
  const SANS = 'Geist, ui-sans-serif, system-ui, sans-serif';
  const SERIF = '"Instrument Serif", Georgia, serif';
  const MONO = '"JetBrains Mono", ui-monospace, monospace';
  const HAND = '"Caveat", cursive';
  const GRAIN = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")";
  const IMG = '/assets/img/hero-dishes';

  /* ───────────────────────── shared bits ───────────────────────── */
  function fade(localTime, duration, entry = 0.5, exit = 0.4) {
    if (localTime < entry) return Easing.easeOutCubic(clamp(localTime / entry, 0, 1));
    if (localTime > duration - exit) return 1 - Easing.easeInCubic(clamp((localTime - (duration - exit)) / exit, 0, 1));
    return 1;
  }
  function Eyebrow({ children, color = C.inkMuted, dot = true, size = 16, style }) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, fontFamily: MONO, fontSize: size, fontWeight: 500, letterSpacing: '0.16em', textTransform: 'uppercase', color, ...style }}>
        {dot && <span style={{ width: 9, height: 9, borderRadius: '50%', background: C.orange, flexShrink: 0 }} />}
        {children}
      </div>
    );
  }
  function Pill({ children, color = C.ink, bg = 'transparent', border = C.ruleStrong }) {
    return <span style={{ fontFamily: MONO, fontSize: 15, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color, background: bg, border: `1.5px solid ${border}`, borderRadius: 999, padding: '7px 15px', whiteSpace: 'nowrap' }}>{children}</span>;
  }
  function fmtClock(sec) { const m = Math.floor(sec / 60), s = Math.floor(sec % 60); return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; }

  /* ───────────────────────── ACT 1 — the insight ───────────────────────── */
  function ActHook() {
    const { localTime, duration } = useSprite();
    const o = fade(localTime, duration, 0.6, 0.5);
    const camScale = interpolate([0, duration], [1.0, 1.05], Easing.linear)(localTime);
    const camY = interpolate([0, duration], [10, -14], Easing.linear)(localTime);
    const lines = ['Eat what your', 'body’s actually', 'craving.'];
    return (
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '0 92px', opacity: o, transform: `translateY(${camY}px) scale(${camScale})`, transformOrigin: '50% 46%' }}>
        <div style={{ opacity: clamp((localTime - 0.3) / 0.6, 0, 1), transform: `translateY(${(1 - clamp((localTime - 0.3) / 0.6, 0, 1)) * 10}px)`, marginBottom: 30 }}>
          <Eyebrow>Cook well, live well</Eyebrow>
        </div>
        <h1 style={{ margin: 0, fontFamily: SANS, fontWeight: 500, fontSize: 104, lineHeight: 0.96, letterSpacing: '-0.04em', color: C.ink }}>
          {lines.map((ln, i) => {
            const start = 0.5 + i * 0.28;
            const p = Easing.easeOutCubic(clamp((localTime - start) / 0.6, 0, 1));
            const isMid = i === 1;
            return (
              <div key={i} style={{ overflow: 'hidden' }}>
                <span style={{ display: 'inline-block', opacity: p, transform: `translateY(${(1 - p) * 64}px)`, fontFamily: isMid ? SERIF : SANS, fontStyle: isMid ? 'italic' : 'normal', fontWeight: isMid ? 400 : 500, color: isMid ? C.orange : C.ink, fontSize: isMid ? 116 : 104, lineHeight: 0.96 }}>{ln}</span>
              </div>
            );
          })}
        </h1>
        <div style={{ marginTop: 44, display: 'flex', alignItems: 'center', gap: 12, opacity: clamp((localTime - 1.9) / 0.6, 0, 1), transform: `translateY(${(1 - clamp((localTime - 1.9) / 0.6, 0, 1)) * 10}px)` }}>
          <span style={{ position: 'relative', width: 11, height: 11 }}>
            <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', background: C.matcha }} />
            <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', background: C.matcha, opacity: 0.4 * (0.5 + 0.5 * Math.sin(localTime * 4)), transform: `scale(${1.6 + 0.5 * Math.sin(localTime * 4)})` }} />
          </span>
          <span style={{ fontFamily: MONO, fontSize: 18, letterSpacing: '0.1em', color: C.inkMuted, textTransform: 'uppercase' }}>Synced from your wearable &amp; labs</span>
        </div>
      </div>
    );
  }

  /* ───────────────────────── ACT 2 — picks tuned to your data ───────────────────────── */
  function MetricRow({ name, pct, fillColor, status, statusColor, delay = 0, localTime }) {
    const a = Easing.easeOutCubic(clamp((localTime - delay) / 0.7, 0, 1));
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 18, opacity: clamp((localTime - delay) / 0.4, 0, 1) }}>
        <span style={{ fontFamily: MONO, fontSize: 16, letterSpacing: '0.04em', color: C.inkSoft, width: 130, flexShrink: 0 }}>{name}</span>
        <div style={{ flex: 1, height: 14, background: C.creamDeep, borderRadius: 999, overflow: 'hidden', border: `1px solid ${C.rule}` }}>
          <div style={{ height: '100%', width: `${pct * a}%`, background: fillColor, borderRadius: 999 }} />
        </div>
        <span style={{ fontFamily: MONO, fontSize: 14, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: statusColor, width: 116, textAlign: 'right', flexShrink: 0 }}>{status}</span>
      </div>
    );
  }
  function RecipePick({ img, name, tag, tagColor, delay, selected, selT, localTime }) {
    const a = Easing.easeOutBack(clamp((localTime - delay) / 0.6, 0, 1));
    const lift = selected ? Easing.easeOutCubic(clamp(selT, 0, 1)) : 0;
    const pop = selected ? `8px 8px 0 ${C.orange}` : `5px 5px 0 ${C.ink}`;
    return (
      <div style={{ width: 252, opacity: clamp((localTime - delay) / 0.4, 0, 1), transform: `translateY(${(1 - a) * 30 - lift * 10}px) translateX(${-lift * 6}px)` }}>
        <div style={{ width: '100%', height: 222, borderRadius: 18, overflow: 'hidden', border: `1.5px solid ${selected ? C.orange : C.ink}`, boxShadow: pop, position: 'relative' }}>
          <img src={img} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
          <span style={{ position: 'absolute', left: 12, bottom: 12, fontFamily: MONO, fontSize: 13, fontWeight: 600, letterSpacing: '0.05em', color: C.ink, background: 'rgba(255,252,243,0.92)', border: `1.5px solid ${tagColor}`, borderRadius: 999, padding: '5px 11px' }}>+ {tag}</span>
        </div>
        <div style={{ fontFamily: SERIF, fontStyle: 'italic', fontSize: 28, color: C.ink, marginTop: 14, lineHeight: 1.05 }}>{name}</div>
      </div>
    );
  }
  function ActRecommend() {
    const { localTime, duration } = useSprite();
    const o = fade(localTime, duration, 0.5, 0.45);
    const selT = (localTime - 4.6) / 0.6;
    const selected = localTime > 4.5;
    return (
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '0 76px', opacity: o }}>
        <div style={{ opacity: clamp(localTime / 0.5, 0, 1), transform: `translateY(${(1 - clamp(localTime / 0.5, 0, 1)) * 10}px)`, marginBottom: 26 }}>
          <Eyebrow>// Picks tuned to your data</Eyebrow>
        </div>

        {/* snapshot card */}
        <div style={{ background: C.paper, border: `1.5px solid ${C.ink}`, borderRadius: 22, boxShadow: `6px 6px 0 ${C.ink}`, padding: '26px 30px', opacity: clamp((localTime - 0.2) / 0.5, 0, 1), transform: `translateY(${(1 - clamp((localTime - 0.2) / 0.5, 0, 1)) * 16}px)` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
            <span style={{ fontFamily: MONO, fontSize: 14, fontWeight: 600, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.inkMuted }}>Your snapshot · today</span>
            <span style={{ fontFamily: MONO, fontSize: 13, letterSpacing: '0.08em', color: C.matchaDeep, textTransform: 'uppercase' }}>● live</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            <MetricRow name="Iron" pct={31} fillColor={C.orange} status="running low" statusColor={C.orange} delay={0.5} localTime={localTime} />
            <MetricRow name="Vitamin D" pct={24} fillColor={C.orange} status="running low" statusColor={C.orange} delay={0.7} localTime={localTime} />
            <MetricRow name="Protein" pct={86} fillColor={C.matcha} status="on track" statusColor={C.matchaDeep} delay={0.9} localTime={localTime} />
          </div>
        </div>

        {/* connector */}
        <div style={{ display: 'flex', justifyContent: 'center', margin: '20px 0 18px', opacity: clamp((localTime - 1.7) / 0.5, 0, 1) }}>
          <span style={{ fontFamily: MONO, fontSize: 15, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.inkMuted, display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ color: C.orange, fontSize: 20 }}>↓</span> so we cook around it
          </span>
        </div>

        {/* picks */}
        <div style={{ display: 'flex', gap: 26, justifyContent: 'center' }}>
          <RecipePick img={`${IMG}/mediterranean-quinoa-bowl.jpg`} name="Mediterranean quinoa bowl" tag="iron · fiber" tagColor={C.orange} delay={2.0} selected={selected} selT={selT} localTime={localTime} />
          <RecipePick img={`${IMG}/miso-mushroom-soup.jpg`} name="Miso mushroom soup" tag="vitamin d" tagColor={C.orange} delay={2.2} localTime={localTime} />
          <RecipePick img={`${IMG}/gochujang-salmon-rice.jpg`} name="Gochujang salmon rice" tag="protein 29g" tagColor={C.matcha} delay={2.4} localTime={localTime} />
        </div>
      </div>
    );
  }

  /* ───────────────────────── ACT 3 — guided cooking ───────────────────────── */
  const STEPS = [
    { title: 'Rinse and toast the quinoa.', detail: 'Rinse 1 cup quinoa, then toast it in the dry pan for two minutes until it smells nutty.', tip: 'Toasting deepens the flavor — don’t skip it.' },
    { title: 'Simmer until fluffy.', detail: 'Add 2 cups water, bring to a boil, then cover and simmer for 15 minutes.', tip: 'Rest it off the heat 5 minutes before fluffing.' },
    { title: 'Prep the fresh add-ins.', detail: 'Halve the cherry tomatoes, dice the cucumber, and crumble the feta.', tip: '' },
    { title: 'Whisk the lemon dressing.', detail: 'Lemon juice, olive oil, a little garlic, oregano and salt — whisk until it emulsifies.', tip: 'Taste and balance: more lemon if it needs lift.' },
    { title: 'Fold everything together.', detail: 'Toss the add-ins through the warm quinoa, top with herbs, and serve.', tip: '' },
  ];
  const INGREDIENTS = ['Quinoa — 1 cup', 'Cherry tomatoes — 1 cup', 'Cucumber — 1', 'Feta — ½ cup', 'Lemon — 1', 'Olive oil — 3 tbsp', 'Parsley + mint — handful'];

  function ActCook() {
    const { localTime, duration } = useSprite();
    const o = fade(localTime, duration, 0.5, 0.45);
    const stepIdx = clamp(Math.floor((localTime - 0.8) / 1.9), 0, STEPS.length - 1);
    const stepLocal = (localTime - 0.8) - stepIdx * 1.9; // time since this step began
    const stepEnter = Easing.easeOutCubic(clamp(stepLocal / 0.45, 0, 1));
    const progress = clamp((stepIdx + clamp(stepLocal / 1.9, 0, 1)) / STEPS.length, 0, 1);
    const checked = clamp(Math.floor((localTime - 0.9) / 1.25), 0, INGREDIENTS.length);
    const timerSec = clamp(900 - Math.floor(Math.max(0, localTime - 1)), 0, 900);
    const step = STEPS[stepIdx];
    const camScale = interpolate([0, duration], [1.0, 1.03], Easing.linear)(localTime);

    return (
      <div style={{ position: 'absolute', inset: 0, padding: '64px 70px', opacity: o, transform: `scale(${camScale})`, transformOrigin: '50% 44%', display: 'flex', flexDirection: 'column' }}>
        {/* header */}
        <div style={{ opacity: clamp(localTime / 0.5, 0, 1), transform: `translateY(${(1 - clamp(localTime / 0.5, 0, 1)) * 12}px)` }}>
          <div style={{ fontFamily: MONO, fontSize: 14, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.inkMuted, marginBottom: 12 }}>← Recipes / Mediterranean</div>
          <h2 style={{ margin: 0, fontFamily: SERIF, fontStyle: 'italic', fontSize: 62, lineHeight: 1.0, color: C.ink, letterSpacing: '-0.01em' }}>Mediterranean <span style={{ color: C.orange }}>quinoa</span> bowl</h2>
          <div style={{ display: 'flex', gap: 12, marginTop: 18, flexWrap: 'wrap' }}>
            <Pill><span style={{ color: C.orange }}>●</span>&nbsp; 30 min</Pill><Pill>Easy</Pill><Pill>2 servings</Pill><Pill>5 steps</Pill>
          </div>
          {/* progress */}
          <div style={{ marginTop: 20, height: 12, background: C.creamDeep, borderRadius: 999, overflow: 'hidden', border: `1.5px solid ${C.ink}` }}>
            <div style={{ height: '100%', width: `${progress * 100}%`, background: `linear-gradient(90deg, ${C.orange}, ${C.orangeDeep})`, borderRadius: 999 }} />
          </div>
        </div>

        {/* two-column stage */}
        <div style={{ display: 'flex', gap: 28, marginTop: 30, flex: 1, minHeight: 0 }}>
          {/* step card */}
          <div style={{ flex: '1 1 0', background: C.paper, border: `1.5px solid ${C.ink}`, borderRadius: 24, boxShadow: `8px 8px 0 ${C.matcha}`, padding: '30px 32px', display: 'flex', flexDirection: 'column' }}>
            {/* pips */}
            <div style={{ display: 'flex', gap: 10, marginBottom: 26 }}>
              {STEPS.map((_, i) => (
                <div key={i} style={{ flex: 1, height: 8, borderRadius: 999, background: i < stepIdx ? C.matcha : i === stepIdx ? C.orange : C.creamDeep, border: `1.5px solid ${i <= stepIdx ? 'transparent' : C.rule}` }} />
              ))}
            </div>
            <div style={{ fontFamily: MONO, fontSize: 15, fontWeight: 600, letterSpacing: '0.14em', color: C.orange, textTransform: 'uppercase' }}>Step {String(stepIdx + 1).padStart(2, '0')} / 05</div>
            <div key={stepIdx} style={{ opacity: stepEnter, transform: `translateY(${(1 - stepEnter) * 14}px)`, flex: 1, display: 'flex', flexDirection: 'column' }}>
              <div style={{ fontFamily: SERIF, fontStyle: 'italic', fontSize: 46, lineHeight: 1.04, color: C.ink, margin: '14px 0 16px' }}>{step.title}</div>
              <div style={{ fontFamily: SANS, fontSize: 22, lineHeight: 1.45, color: C.inkSoft, fontWeight: 400 }}>{step.detail}</div>
              {step.tip ? (
                <div style={{ marginTop: 'auto', paddingTop: 18, display: 'flex', alignItems: 'flex-start', gap: 8 }}>
                  <span style={{ fontFamily: HAND, fontSize: 30, color: C.matchaDeep, lineHeight: 1 }}>✎ tip:</span>
                  <span style={{ fontFamily: HAND, fontSize: 28, color: C.matchaDeep, lineHeight: 1.1 }}>{step.tip}</span>
                </div>
              ) : null}
            </div>
            {/* nav */}
            <div style={{ display: 'flex', gap: 12, marginTop: 22 }}>
              <div style={{ fontFamily: MONO, fontSize: 16, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: C.inkMuted, border: `1.5px solid ${C.ruleStrong}`, borderRadius: 999, padding: '11px 22px' }}>← Back</div>
              <div style={{ fontFamily: MONO, fontSize: 16, fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase', color: C.paper, background: C.ink, borderRadius: 999, padding: '12px 26px', boxShadow: stepLocal > 1.4 ? `3px 3px 0 ${C.orange}` : 'none' }}>
                {stepIdx === STEPS.length - 1 ? 'Finish ✓' : 'Next step →'}
              </div>
            </div>
          </div>

          {/* sidebar: ingredients + timer */}
          <div style={{ width: 332, flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 22 }}>
            <div style={{ background: C.paper, border: `1.5px solid ${C.ink}`, borderRadius: 22, boxShadow: `5px 5px 0 ${C.ink}`, padding: '22px 24px', flex: 1 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 16 }}>
                <span style={{ fontFamily: SANS, fontSize: 22, fontWeight: 600, color: C.ink }}>Ingredients</span>
                <span style={{ fontFamily: MONO, fontSize: 13, letterSpacing: '0.06em', color: C.inkMuted }}>{checked}/{INGREDIENTS.length}</span>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 13 }}>
                {INGREDIENTS.map((ing, i) => {
                  const on = i < checked;
                  const justOn = i === checked - 1;
                  const pop = justOn ? Easing.easeOutBack(clamp((localTime - 0.9 - i * 1.25) / 0.4, 0, 1)) : 1;
                  return (
                    <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                      <span style={{ width: 22, height: 22, borderRadius: 6, border: `1.5px solid ${on ? C.matcha : C.ruleStrong}`, background: on ? C.matcha : 'transparent', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.paper, fontSize: 14, fontWeight: 700, flexShrink: 0, transform: `scale(${pop})` }}>{on ? '✓' : ''}</span>
                      <span style={{ fontFamily: SANS, fontSize: 17, color: on ? C.inkFaint : C.inkSoft, textDecoration: on ? 'line-through' : 'none' }}>{ing}</span>
                    </div>
                  );
                })}
              </div>
            </div>
            {/* timer */}
            <div style={{ background: C.ink, borderRadius: 22, padding: '20px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div>
                <div style={{ fontFamily: MONO, fontSize: 13, letterSpacing: '0.14em', textTransform: 'uppercase', color: C.inkFaint, marginBottom: 4 }}>⏱ Simmer timer</div>
                <div style={{ fontFamily: MONO, fontWeight: 600, fontSize: 44, color: C.orange, fontVariantNumeric: 'tabular-nums', letterSpacing: '0.02em' }}>{fmtClock(timerSec)}</div>
              </div>
              <div style={{ width: 14, height: 14, borderRadius: '50%', background: C.matcha, opacity: 0.5 + 0.5 * Math.sin(localTime * 5) }} />
            </div>
          </div>
        </div>
      </div>
    );
  }

  /* ───────────────────────── ACT 4 — track / logged ───────────────────────── */
  function ActTrack() {
    const { localTime, duration } = useSprite();
    const o = fade(localTime, duration, 0.45, 0.4);
    const stamp = Easing.easeOutBack(clamp(localTime / 0.5, 0, 1));
    const days = [0.4, 0.55, 0.5, 0.7, 0.62, 0.8, 0.96]; // week → today tallest
    const targetPct = 0.9;
    return (
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', padding: '0 92px', opacity: o }}>
        {/* logged stamp */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 16, transform: `scale(${stamp})`, marginBottom: 14 }}>
          <span style={{ width: 60, height: 60, borderRadius: '50%', background: C.matcha, color: C.paper, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 32, fontWeight: 700, boxShadow: `4px 4px 0 ${C.ink}` }}>✓</span>
          <span style={{ fontFamily: SANS, fontWeight: 500, fontSize: 56, letterSpacing: '-0.03em', color: C.ink }}>Meal logged.</span>
        </div>
        <div style={{ fontFamily: MONO, fontSize: 16, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.inkMuted, marginBottom: 40, opacity: clamp((localTime - 0.5) / 0.4, 0, 1) }}>// it counts toward your week</div>

        {/* weekly chart card */}
        <div style={{ width: '100%', maxWidth: 720, background: C.paper, border: `1.5px solid ${C.ink}`, borderRadius: 24, boxShadow: `8px 8px 0 ${C.matcha}`, padding: '30px 34px', opacity: clamp((localTime - 0.6) / 0.5, 0, 1), transform: `translateY(${(1 - clamp((localTime - 0.6) / 0.5, 0, 1)) * 16}px)` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 24 }}>
            <span style={{ fontFamily: SANS, fontSize: 24, fontWeight: 600, color: C.ink }}>Iron intake <span style={{ fontFamily: SERIF, fontStyle: 'italic', color: C.inkMuted, fontWeight: 400 }}>· last 7 days</span></span>
            <span style={{ fontFamily: MONO, fontSize: 15, letterSpacing: '0.06em', color: C.matchaDeep, textTransform: 'uppercase' }}>trending up</span>
          </div>
          <div style={{ position: 'relative', height: 200, display: 'flex', alignItems: 'flex-end', gap: 16 }}>
            {/* target line */}
            <div style={{ position: 'absolute', left: 0, right: 0, bottom: `${targetPct * 100}%`, borderTop: `2px dashed ${C.ruleStrong}` }}>
              <span style={{ position: 'absolute', right: 0, top: -22, fontFamily: MONO, fontSize: 12, letterSpacing: '0.08em', color: C.inkMuted, textTransform: 'uppercase' }}>goal</span>
            </div>
            {days.map((d, i) => {
              const a = Easing.easeOutCubic(clamp((localTime - 0.8 - i * 0.09) / 0.6, 0, 1));
              const today = i === days.length - 1;
              return (
                <div key={i} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', height: '100%' }}>
                  <div style={{ width: '100%', height: `${d * a * 100}%`, background: today ? C.matcha : C.kraft, border: `1.5px solid ${today ? C.matchaDeep : C.ruleStrong}`, borderRadius: '8px 8px 0 0' }} />
                  <span style={{ fontFamily: MONO, fontSize: 12, color: today ? C.matchaDeep : C.inkFaint, marginTop: 8, letterSpacing: '0.04em' }}>{['M', 'T', 'W', 'T', 'F', 'S', 'S'][i]}</span>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    );
  }

  /* ───────────────────────── ACT 5 — logo ───────────────────────── */
  function ActLogo() {
    const { localTime } = useSprite();
    const mark = Easing.easeOutBack(clamp((localTime - 0.1) / 0.6, 0, 1));
    const word = clamp((localTime - 0.5) / 0.5, 0, 1);
    const tag = clamp((localTime - 0.95) / 0.5, 0, 1);
    return (
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
        <div style={{ width: 132, height: 132, borderRadius: '50%', background: C.orange, display: 'flex', alignItems: 'center', justifyContent: 'center', transform: `scale(${mark}) rotate(-6deg)`, boxShadow: `6px 6px 0 ${C.ink}` }}>
          <span style={{ fontFamily: SERIF, fontStyle: 'italic', fontSize: 92, color: C.paper, lineHeight: 1, marginTop: 6 }}>m</span>
        </div>
        <div style={{ marginTop: 34, fontFamily: SANS, fontWeight: 500, fontSize: 58, letterSpacing: '-0.03em', color: C.ink, opacity: word, transform: `translateY(${(1 - word) * 12}px)` }}>
          MyFood<span style={{ fontFamily: SERIF, fontStyle: 'italic', fontWeight: 400, color: C.orange }}>Craving</span>
        </div>
        <div style={{ marginTop: 16, fontFamily: MONO, fontSize: 17, letterSpacing: '0.18em', textTransform: 'uppercase', color: C.inkMuted, opacity: tag }}>cook well, live well</div>
      </div>
    );
  }

  /* ───────────────────────── grain overlay ───────────────────────── */
  function Grain() {
    return <div style={{ position: 'absolute', inset: 0, backgroundImage: GRAIN, backgroundSize: '200px 200px', mixBlendMode: 'multiply', opacity: 0.18, pointerEvents: 'none', zIndex: 50 }} />;
  }

  /* ───────────────────────── root ───────────────────────── */
  function ProductVideo() {
    return (
      <MfcVideoStage duration={30} background={C.cream}>
        <Sprite start={0} end={6.5}><ActHook /></Sprite>
        <Sprite start={6.4} end={13.7}><ActRecommend /></Sprite>
        <Sprite start={13.6} end={24.4}><ActCook /></Sprite>
        <Sprite start={24.3} end={28.5}><ActTrack /></Sprite>
        <Sprite start={28.4} end={30}><ActLogo /></Sprite>
        <Grain />
      </MfcVideoStage>
    );
  }

  window.MfcProductVideo = ProductVideo;
})();
