// grade_scenes.jsx — The three grade scenes + intro/outro
// All timing uses the OUTER Sprite's localTime. Nested Sprites would read
// root Stage time, causing scenes to render blank — so we gate children with
// inline localTime checks instead.

// Gated wrapper: shows children when parent sprite localTime ∈ [localStart, localEnd].
// Exposes {t, progress} where t = localTime - localStart.
function LocalGate({ parentLocalTime, start = 0, end = Infinity, children }) {
  if (parentLocalTime < start || parentLocalTime > end) return null;
  const dur = end - start;
  const t = parentLocalTime - start;
  const progress = dur > 0 && isFinite(dur) ? clamp(t / dur, 0, 1) : 0;
  return typeof children === 'function' ? children({ t, progress, duration: dur }) : children;
}

// A version of ScanLine that takes localT directly (no useSprite)
function ScanLineLocal({ x, y, width, height, t, duration = 1.4, color = TR.green }) {
  const p = clamp(t / duration, 0, 1);
  if (p <= 0 || p >= 1) return null;
  const eased = Easing.easeInOutCubic(p);
  const opacity = Math.sin(p * Math.PI);
  return (
    <div style={{
      position: 'absolute',
      left: x, top: y + eased * height - 2,
      width, height: 4,
      background: `linear-gradient(90deg, transparent, ${color}, transparent)`,
      boxShadow: `0 0 24px ${color}, 0 0 48px ${color}80`,
      opacity,
      pointerEvents: 'none',
      borderRadius: 2,
    }}/>
  );
}

// HotspotLocal — same as Hotspot but takes t
function HotspotLocal({ x, y, t, delay = 0, label, color = TR.amber }) {
  const progress = clamp((t - delay) / 0.5, 0, 1);
  if (progress <= 0) return null;
  const s = Easing.easeOutBack(progress);
  const pulse = 1 + Math.sin((t - delay) * 3) * 0.1;
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `translate(-50%, -50%) scale(${s})`,
      opacity: progress,
      pointerEvents: 'none',
    }}>
      <div style={{
        position: 'absolute', left: -22, top: -22,
        width: 44, height: 44,
        borderRadius: '50%',
        border: `1.5px solid ${color}`,
        transform: `scale(${pulse})`,
        opacity: 0.6,
      }}/>
      <div style={{
        width: 10, height: 10, borderRadius: '50%',
        background: color,
        boxShadow: `0 0 16px ${color}`,
      }}/>
      {label && (
        <div style={{
          position: 'absolute', left: 18, top: -9,
          whiteSpace: 'nowrap',
          fontFamily: TR.mono,
          fontSize: 12,
          color: color,
          letterSpacing: '0.08em',
          textTransform: 'uppercase',
        }}>
          {label}
        </div>
      )}
    </div>
  );
}

// HaloRingLocal — takes t
function HaloRingLocal({ x, y, size = 720, color = TR.green, color2 = TR.cyan, opacity = 0.35, t = 0 }) {
  const rot = t * 8;
  const breath = 1 + Math.sin(t * 1.2) * 0.015;
  const appear = Easing.easeOutCubic(clamp(t / 0.8, 0, 1));
  return (
    <div style={{
      position: 'absolute',
      left: x - size / 2, top: y - size / 2,
      width: size, height: size,
      opacity: appear * opacity,
      transform: `rotate(${rot}deg) scale(${breath})`,
      pointerEvents: 'none',
    }}>
      <div style={{
        position: 'absolute', inset: 0,
        borderRadius: '50%',
        background: `conic-gradient(from 0deg, ${color} 0deg, ${color2} 120deg, transparent 200deg, ${color} 360deg)`,
        filter: 'blur(60px)',
      }}/>
      <div style={{
        position: 'absolute', inset: '18%',
        borderRadius: '50%',
        border: `1px solid ${color}40`,
      }}/>
      <div style={{
        position: 'absolute', inset: '26%',
        borderRadius: '50%',
        border: `1px dashed ${color2}30`,
      }}/>
    </div>
  );
}

// ImageSprite-local — takes t and duration directly
function PhoneImage({ src, x, y, width, height, t, duration, entryDur = 0.7, exitDur = 0.5, kenBurnsScale = 1.04 }) {
  const exitStart = Math.max(0, duration - exitDur);
  let opacity = 1;
  let scale = 1;
  if (t < entryDur) {
    const e = Easing.easeOutCubic(clamp(t / entryDur, 0, 1));
    opacity = e;
    scale = 0.96 + 0.04 * e;
  } else if (t > exitStart) {
    const e = Easing.easeInCubic(clamp((t - exitStart) / exitDur, 0, 1));
    opacity = 1 - e;
    scale = kenBurnsScale + 0.02 * e;
  } else {
    const holdSpan = exitStart - entryDur;
    const holdT = holdSpan > 0 ? (t - entryDur) / holdSpan : 0;
    scale = 1 + (kenBurnsScale - 1) * holdT;
  }
  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      width, height,
      opacity,
      transform: `scale(${scale})`,
      transformOrigin: 'center',
      willChange: 'transform, opacity',
    }}>
      <img src={src} alt="" style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
    </div>
  );
}

// WordReveal that takes t directly (no nested Sprite)
function WordRevealLocal({ text, x, y, size = 72, color = TR.ink, weight = 700, t = 0, delay = 0, stagger = 0.08, font = TR.sans, letterSpacing = '-0.03em', lineHeight = 1.02, maxWidth = 920 }) {
  const words = text.split(' ');
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      fontFamily: font,
      fontSize: size,
      fontWeight: weight,
      color,
      letterSpacing,
      lineHeight,
      display: 'flex', flexWrap: 'wrap', gap: '0.25em',
      maxWidth,
    }}>
      {words.map((w, i) => {
        const wt = clamp((t - delay - i * stagger) / 0.5, 0, 1);
        const e = Easing.easeOutCubic(wt);
        return (
          <span key={i} style={{
            display: 'inline-block',
            transform: `translateY(${(1 - e) * 30}px)`,
            opacity: e,
            willChange: 'transform, opacity',
          }}>
            {w}
          </span>
        );
      })}
    </div>
  );
}

// CheckItem local
function CheckItemLocal({ x, y, label, t, delay = 0, idx = 0, color = TR.green, neg = false }) {
  const pt = clamp((t - delay - idx * 0.15) / 0.5, 0, 1);
  const e = Easing.easeOutCubic(pt);
  const drawT = clamp((t - delay - idx * 0.15 - 0.15) / 0.35, 0, 1);
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      display: 'flex', alignItems: 'center', gap: 16,
      transform: `translateX(${(1 - e) * -16}px)`,
      opacity: e,
      fontFamily: TR.sans,
      fontSize: 22,
      fontWeight: 400,
      color: TR.ink,
      letterSpacing: '-0.01em',
    }}>
      <div style={{
        width: 28, height: 28, borderRadius: 8,
        border: `1.5px solid ${color}`,
        background: `${color}1a`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        <svg viewBox="0 0 24 24" width="20" height="20" fill="none">
          {neg ? (
            <path d="M6 6 L18 18 M18 6 L6 18" stroke={color} strokeWidth="2.5" strokeLinecap="round"
              strokeDasharray="30" strokeDashoffset={30 - 30 * drawT} />
          ) : (
            <path d="M5 12 L10 17 L19 7" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
              strokeDasharray="30" strokeDashoffset={30 - 30 * drawT} />
          )}
        </svg>
      </div>
      <span>{label}</span>
    </div>
  );
}

// Eyebrow local
function EyebrowLocal({ x, y, text, color = TR.inkDim, t, delay = 0 }) {
  const pt = clamp((t - delay) / 0.5, 0, 1);
  const e = Easing.easeOutCubic(pt);
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      transform: `translateY(${(1 - e) * 10}px)`,
      opacity: e,
      fontFamily: TR.mono,
      fontSize: 13,
      letterSpacing: '0.28em',
      color,
      textTransform: 'uppercase',
      fontWeight: 500,
      display: 'flex', alignItems: 'center', gap: 12,
    }}>
      <span style={{ width: 32, height: 1, background: color, display: 'inline-block' }}/>
      {text}
    </div>
  );
}

// GradeMark local — FIXED with whiteSpace: nowrap and correct baseline
function GradeMarkLocal({ x, y, label, size = 220, t, delay = 0 }) {
  const pt = clamp((t - delay) / 0.7, 0, 1);
  const e = Easing.easeOutBack(pt);
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      fontFamily: TR.sans,
      fontSize: size,
      fontWeight: 900,
      lineHeight: 1,
      letterSpacing: '-0.06em',
      whiteSpace: 'nowrap',
      background: TR.gradient,
      WebkitBackgroundClip: 'text',
      WebkitTextFillColor: 'transparent',
      backgroundClip: 'text',
      transform: `scale(${0.6 + 0.4 * e})`,
      transformOrigin: 'left top',
      opacity: pt,
      filter: `drop-shadow(0 8px 40px ${TR.green}40)`,
      padding: '0.1em 0.05em 0.15em 0',
    }}>
      {label}
    </div>
  );
}

// Quality badge (replaces price block)
function QualityBadge({ x, y, t, delay = 0, accent = TR.green }) {
  const t1 = clamp((t - delay) / 0.6, 0, 1);
  const e1 = Easing.easeOutCubic(t1);
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      opacity: e1,
      transform: `translateY(${(1 - e1) * 16}px)`,
      display: 'flex', alignItems: 'center', gap: 18,
      padding: '14px 22px',
      border: `1px solid ${accent}`,
      borderRadius: 12,
      background: `${accent}10`,
    }}>
      <svg viewBox="0 0 24 24" width="24" height="24" fill="none">
        <path d="M12 2 L15 9 L22 10 L17 15 L18 22 L12 18 L6 22 L7 15 L2 10 L9 9 Z"
          stroke={accent} strokeWidth="1.6" strokeLinejoin="round" fill={`${accent}22`}/>
      </svg>
      <div>
        <div style={{
          fontFamily: TR.mono, fontSize: 11, letterSpacing: '0.22em',
          color: TR.inkDim, textTransform: 'uppercase', marginBottom: 2,
        }}>Geprüft &amp; zertifiziert</div>
        <div style={{
          fontFamily: TR.sans, fontSize: 20, fontWeight: 700, color: TR.ink,
          letterSpacing: '-0.01em',
        }}>30 Tage Garantie</div>
      </div>
    </div>
  );
}

// ── Intro scene (0–3.2s) ─────────────────────────────────────────────────────
// Uses real homepage logo PNG. Large + centered, NOT on any phone.
function IntroScene() {
  return (
    <Sprite start={0} end={3.2}>
      {({ localTime }) => {
        const logoT = clamp(localTime / 1.0, 0, 1);
        const logoE = Easing.easeOutBack(logoT);
        const taglineOpacity = Easing.easeOutCubic(clamp((localTime - 1.5) / 0.6, 0, 1));
        const fadeOut = Easing.easeInCubic(clamp((localTime - 2.7) / 0.5, 0, 1));
        const alpha = 1 - fadeOut;
        return (
          <div style={{ position: 'absolute', inset: 0, opacity: alpha }}>
            {/* Scanline texture */}
            <div style={{
              position: 'absolute', inset: 0,
              backgroundImage: `repeating-linear-gradient(0deg, ${TR.green}0a 0px, ${TR.green}0a 1px, transparent 1px, transparent 3px)`,
              mixBlendMode: 'screen',
              pointerEvents: 'none',
            }}/>
            {/* Real PNG logo, centered top */}
            <div style={{
              position: 'absolute',
              left: '50%', top: 260,
              transform: `translateX(-50%) scale(${0.7 + 0.3 * logoE})`,
              opacity: logoT,
              filter: `drop-shadow(0 0 60px ${TR.green}55)`,
            }}>
              <img src="assets/logo.png" alt="TR"
                style={{ width: 220, height: 220, display: 'block' }}/>
            </div>
            {/* Tagline */}
            <div style={{
              position: 'absolute',
              left: '50%', top: 560,
              transform: 'translateX(-50%)',
              width: 1400,
              textAlign: 'center',
              fontFamily: TR.sans,
              fontSize: 96,
              fontWeight: 800,
              color: TR.ink,
              letterSpacing: '-0.03em',
              lineHeight: 1.05,
              opacity: Easing.easeOutCubic(clamp((localTime - 0.9) / 0.6, 0, 1)),
            }}>
              This is how we grade.
            </div>
            <div style={{
              position: 'absolute', left: 0, right: 0, top: 720,
              textAlign: 'center',
              fontFamily: TR.mono,
              fontSize: 20,
              letterSpacing: '0.26em',
              color: TR.inkDim,
              textTransform: 'uppercase',
              opacity: taglineOpacity,
            }}>
              Transparent · Honest · Tested
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── Tech HUD overlay ────────────────────────────────────────────────────────
// Scanlines, corner brackets, tick-marks, data readouts — all non-interactive
// decoration that sells the "diagnostic scan" feel across the grade scenes.
function TechHUD({ t, accent = TR.green, gradeLabel = 'A', gradeIndex = 1 }) {
  const scanY = ((t * 180) % 1200) - 100; // sweeps 0 → 1080 repeatedly
  const sweepOpacity = 0.55 * (1 - Math.abs((scanY - 540) / 640));
  const readoutOpacity = Easing.easeOutCubic(clamp((t - 0.3) / 0.6, 0, 1));
  const blink = (Math.floor(t * 2) % 2) === 0 ? 1 : 0.35;

  // Generate 24 random-ish tick values that change every 0.5s for "live data"
  const seed = Math.floor(t * 2);
  const rand = (i) => {
    const x = Math.sin((seed + 1) * 12.9898 + i * 78.233) * 43758.5453;
    return x - Math.floor(x);
  };

  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      opacity: readoutOpacity,
    }}>
      {/* Full-screen scanline texture (very subtle, always on) */}
      <div style={{
        position: 'absolute', inset: 0,
        backgroundImage: `repeating-linear-gradient(0deg, ${accent}08 0px, ${accent}08 1px, transparent 1px, transparent 3px)`,
        mixBlendMode: 'screen',
      }}/>

      {/* Moving horizontal scan sweep */}
      <div style={{
        position: 'absolute', left: 0, right: 0, top: scanY,
        height: 140,
        background: `linear-gradient(180deg, transparent, ${accent}22 45%, ${accent}55 50%, ${accent}22 55%, transparent)`,
        opacity: Math.max(0, sweepOpacity),
        pointerEvents: 'none',
      }}/>
      {/* Bright scan line */}
      <div style={{
        position: 'absolute', left: 0, right: 0, top: scanY + 68,
        height: 1,
        background: accent,
        opacity: 0.7,
        boxShadow: `0 0 12px ${accent}, 0 0 24px ${accent}aa`,
      }}/>

      {/* Corner brackets — top-left, top-right, bottom-left, bottom-right */}
      {[
        { top: 40, left: 40, rot: 0 },
        { top: 40, right: 40, rot: 90 },
        { bottom: 40, right: 40, rot: 180 },
        { bottom: 40, left: 40, rot: 270 },
      ].map((c, i) => (
        <div key={i} style={{
          position: 'absolute',
          top: c.top, left: c.left, right: c.right, bottom: c.bottom,
          width: 28, height: 28,
          transform: `rotate(${c.rot}deg)`,
        }}>
          <div style={{ position: 'absolute', top: 0, left: 0, width: 28, height: 2, background: accent, opacity: 0.9 }}/>
          <div style={{ position: 'absolute', top: 0, left: 0, width: 2, height: 28, background: accent, opacity: 0.9 }}/>
        </div>
      ))}

      {/* Left-edge vertical tick scale */}
      <div style={{
        position: 'absolute', left: 30, top: 120, bottom: 120,
        width: 10,
        display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
      }}>
        {Array.from({ length: 18 }).map((_, i) => (
          <div key={i} style={{
            width: i % 3 === 0 ? 10 : 5, height: 1,
            background: accent,
            opacity: i % 3 === 0 ? 0.6 : 0.3,
          }}/>
        ))}
      </div>

      {/* Right-edge data readout column */}
      <div style={{
        position: 'absolute', right: 40, top: 130,
        fontFamily: TR.mono, fontSize: 10,
        color: accent, letterSpacing: '0.14em',
        textAlign: 'right',
        lineHeight: 1.9,
        opacity: 0.7,
      }}>
        <div>SCAN.ACTIVE <span style={{ opacity: blink }}>●</span></div>
        <div>CH_01 · {(rand(0) * 0.08 + 0.94).toFixed(3)} V</div>
        <div>CH_02 · {(rand(1) * 0.4 + 4.7).toFixed(2)} A</div>
        <div>THRM · {(rand(2) * 2 + 34).toFixed(1)}°C</div>
        <div>Z · {Math.floor(rand(3) * 80 + 120)} Ω</div>
      </div>

      {/* Bottom-center timecode / sample counter */}
      <div style={{
        position: 'absolute', left: '50%', bottom: 96,
        transform: 'translateX(-50%)',
        fontFamily: TR.mono, fontSize: 11,
        color: TR.inkDim, letterSpacing: '0.28em',
        display: 'flex', gap: 24, alignItems: 'center',
      }}>
        <span>REF · TR-{gradeIndex.toString().padStart(3, '0')}</span>
        <span style={{ width: 40, height: 1, background: TR.line }}/>
        <span>{String(Math.floor(t * 10)).padStart(4, '0')} · SMPL</span>
        <span style={{ width: 40, height: 1, background: TR.line }}/>
        <span style={{ color: accent }}>G:{gradeLabel}</span>
      </div>

      {/* Small crosshair near grade mark */}
      <svg style={{
        position: 'absolute', left: 310, top: 340,
        pointerEvents: 'none',
        opacity: 0.45,
      }} width="60" height="60" viewBox="0 0 60 60" fill="none">
        <circle cx="30" cy="30" r="24" stroke={accent} strokeWidth="1" strokeDasharray="3 3"/>
        <line x1="30" y1="6" x2="30" y2="18" stroke={accent} strokeWidth="1"/>
        <line x1="30" y1="42" x2="30" y2="54" stroke={accent} strokeWidth="1"/>
        <line x1="6" y1="30" x2="18" y2="30" stroke={accent} strokeWidth="1"/>
        <line x1="42" y1="30" x2="54" y2="30" stroke={accent} strokeWidth="1"/>
      </svg>
    </div>
  );
}

// ── Generic grade scene ─────────────────────────────────────────────────────
function GradeScene({
  start, end,
  gradeLabel, gradeIndex,
  title, subtitle,
  bullets,
  imgSrc,
  imgX, imgY, imgW, imgH,
  hotspots = [],
  accent = TR.green,
}) {
  const dur = end - start;
  return (
    <Sprite start={start} end={end}>
      {({ localTime }) => {
        const fadeIn = Easing.easeOutCubic(clamp(localTime / 0.5, 0, 1));
        const fadeOut = Easing.easeInCubic(clamp((localTime - (dur - 0.5)) / 0.5, 0, 1));
        const alpha = fadeIn * (1 - fadeOut);
        return (
          <div style={{ position: 'absolute', inset: 0, opacity: alpha }}>
            {/* Tech HUD overlay — scanlines, crosshair, corner brackets, readout */}
            <TechHUD t={localTime} accent={accent} gradeLabel={gradeLabel} gradeIndex={gradeIndex} />

            {/* Step indicator top-right */}
            <div style={{
              position: 'absolute', top: 60, right: 80,
              display: 'flex', alignItems: 'center', gap: 20,
              fontFamily: TR.mono, fontSize: 14,
              color: TR.inkDim, letterSpacing: '0.24em',
            }}>
              <span>STAGE {gradeIndex} / 3</span>
              <div style={{ display: 'flex', gap: 6 }}>
                {[1,2,3].map(i => (
                  <span key={i} style={{
                    width: i === gradeIndex ? 28 : 14, height: 4,
                    background: i <= gradeIndex ? TR.gradient : TR.line,
                    borderRadius: 2,
                  }}/>
                ))}
              </div>
            </div>

            <EyebrowLocal x={80} y={200} text={subtitle} color={accent} t={localTime} delay={0.15}/>

            <GradeMarkLocal x={80} y={240} label={gradeLabel} size={220} t={localTime} delay={0.3}/>

            <WordRevealLocal
              text={title}
              x={80} y={500}
              size={58}
              weight={700}
              t={localTime}
              delay={0.6}
              stagger={0.06}
              letterSpacing="-0.03em"
              maxWidth={860}
            />

            <div style={{ position: 'absolute', left: 80, top: 680, width: 780 }}>
              {(() => {
                // Group consecutive bullets by `group` field
                const groups = [];
                bullets.forEach((b) => {
                  const last = groups[groups.length - 1];
                  if (last && last.group === b.group) last.items.push(b.label);
                  else groups.push({ group: b.group, items: [b.label] });
                });
                let itemCounter = 0;
                return groups.map((g, gi) => (
                  <div key={gi} style={{ marginBottom: gi < groups.length - 1 ? 14 : 0 }}>
                    {g.group && (
                      <div style={{
                        fontFamily: TR.mono, fontSize: 11,
                        color: accent, letterSpacing: '0.22em',
                        textTransform: 'uppercase', fontWeight: 500,
                        marginBottom: 6,
                        opacity: Easing.easeOutCubic(clamp((localTime - 1.0 - gi * 0.15) / 0.4, 0, 1)),
                      }}>
                        {g.group}
                      </div>
                    )}
                    {g.items.map((label, ii) => {
                      const idx = itemCounter++;
                      const pt = clamp((localTime - 1.1 - idx * 0.13) / 0.5, 0, 1);
                      const e = Easing.easeOutCubic(pt);
                      const drawT = clamp((localTime - 1.1 - idx * 0.13 - 0.15) / 0.35, 0, 1);
                      return (
                        <div key={ii} style={{
                          display: 'flex', alignItems: 'center', gap: 14,
                          marginBottom: 8,
                          transform: `translateX(${(1 - e) * -16}px)`,
                          opacity: e,
                          fontFamily: TR.sans, fontSize: 20, fontWeight: 400,
                          color: TR.ink, letterSpacing: '-0.01em',
                          lineHeight: 1.3,
                        }}>
                          <div style={{
                            width: 24, height: 24, borderRadius: 7,
                            border: `1.5px solid ${accent}`,
                            background: `${accent}1a`,
                            display: 'flex', alignItems: 'center', justifyContent: 'center',
                            flexShrink: 0,
                          }}>
                            <svg viewBox="0 0 24 24" width="16" height="16" fill="none">
                              <path d="M5 12 L10 17 L19 7" stroke={accent}
                                strokeWidth="2.8" strokeLinecap="round" strokeLinejoin="round"
                                strokeDasharray="30" strokeDashoffset={30 - 30 * drawT}/>
                            </svg>
                          </div>
                          <span>{label}</span>
                        </div>
                      );
                    })}
                  </div>
                ));
              })()}
            </div>

            {/* Bullets fill the bottom-left area (no separate badge — metrics live in Outro) */}

            {/* Right — phone photo */}
            <div style={{ position: 'absolute', right: 0, top: 0, width: 960, height: '100%', pointerEvents: 'none' }}>
              <HaloRingLocal
                x={480} y={540} size={780}
                color={accent} color2={TR.cyan}
                opacity={0.28}
                t={Math.max(0, localTime - 0.15)}
              />

              <LocalGate parentLocalTime={localTime} start={0.35} end={dur}>
                {({ t }) => (
                  <PhoneImage
                    src={imgSrc}
                    x={imgX} y={imgY}
                    width={imgW} height={imgH}
                    t={t}
                    duration={dur - 0.35}
                  />
                )}
              </LocalGate>

              {/* Scan line 0.9–2.5s local */}
              <LocalGate parentLocalTime={localTime} start={0.9} end={2.5}>
                {({ t }) => (
                  <ScanLineLocal
                    x={imgX} y={imgY}
                    width={imgW} height={imgH}
                    t={t}
                    duration={1.6}
                    color={accent}
                  />
                )}
              </LocalGate>

              {/* Hotspots 2.5s+ */}
              <LocalGate parentLocalTime={localTime} start={2.5} end={dur}>
                {({ t }) => (
                  <>
                    {hotspots.map((h, i) => (
                      <HotspotLocal
                        key={i}
                        x={h.x} y={h.y}
                        t={t}
                        delay={i * 0.2}
                        label={h.label}
                        color={h.color || accent}
                      />
                    ))}
                  </>
                )}
              </LocalGate>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

// ── Outro (summary) ────────────────────────────────────────────────────────
function OutroScene({ start, end }) {
  const dur = end - start;
  return (
    <Sprite start={start} end={end}>
      {({ localTime }) => {
        const fadeIn = Easing.easeOutCubic(clamp(localTime / 0.6, 0, 1));
        const fadeOut = Easing.easeInCubic(clamp((localTime - (dur - 0.5)) / 0.5, 0, 1));
        const alpha = fadeIn * (1 - fadeOut);

        const cards = [
          {
            label: 'A',   title: 'Like New',  sub: 'Pristine Condition',
            img: 'assets/gradeA.png',  color: TR.green,
            bullets: [
              'Passed all functional tests',
              'Flawless appearance',
              'Minor blemishes only on close inspection',
              'Battery > 80%',
            ],
          },
          {
            label: 'A/B', title: 'Excellent', sub: 'Premium · Best Seller',
            img: 'assets/gradeAB.png', color: TR.cyan,
            bullets: [
              'Passed all tests',
              'Minor signs of usage',
              'Wholesalers’ most sold mix',
              'Battery > 80%',
            ],
          },
          {
            label: 'B/C', title: 'Good',      sub: 'Economy Condition',
            img: 'assets/gradeBC.png', color: TR.amber,
            bullets: [
              'All functional tests passed',
              'Heavily used appearance',
              'Deeper scratches possible',
              'Battery > 80%',
            ],
          },
        ];

        const ctaT = clamp((localTime - 1.6) / 0.6, 0, 1);
        const ctaE = Easing.easeOutCubic(ctaT);

        return (
          <div style={{ position: 'absolute', inset: 0, opacity: alpha }}>
            {/* Subtle scanline texture on outro */}
            <div style={{
              position: 'absolute', inset: 0,
              backgroundImage: `repeating-linear-gradient(0deg, ${TR.green}06 0px, ${TR.green}06 1px, transparent 1px, transparent 3px)`,
              mixBlendMode: 'screen',
              pointerEvents: 'none',
            }}/>

            <EyebrowLocal x={80} y={100} text="All grades at a glance" t={localTime} delay={0.1}/>

            <WordRevealLocal
              text="Every grade. Fully functional."
              x={80} y={150}
              size={72}
              t={localTime}
              delay={0.2}
              stagger={0.05}
              maxWidth={1600}
            />

            {/* CTA top-right (not bottom, so doesn't collide with Apple chip) */}
            <div style={{
              position: 'absolute', right: 80, top: 130,
              opacity: ctaE,
              transform: `translateY(${(1 - ctaE) * 20}px)`,
              display: 'flex', alignItems: 'center', gap: 14,
              padding: '16px 26px',
              background: TR.gradient,
              borderRadius: 999,
              fontFamily: TR.sans,
              fontSize: 20, fontWeight: 700,
              color: '#031214', letterSpacing: '-0.01em',
            }}>
              tr-vertrieb.de
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                <path d="M5 12h14M13 6l6 6-6 6" stroke="#031214" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
            </div>

            <div style={{
              position: 'absolute', left: 80, top: 300,
              display: 'flex', gap: 28,
            }}>
              {cards.map((c, i) => {
                const cardT = clamp((localTime - 0.5 - i * 0.18) / 0.7, 0, 1);
                const e = Easing.easeOutBack(cardT);
                return (
                  <div key={i} style={{
                    width: 568, height: 560,
                    background: '#0f1419',
                    border: `1px solid ${TR.line}`,
                    borderRadius: 20,
                    padding: 28,
                    position: 'relative',
                    overflow: 'hidden',
                    opacity: cardT,
                    transform: `translateY(${(1 - e) * 40}px) scale(${0.94 + 0.06 * e})`,
                  }}>
                    <div style={{
                      position: 'absolute', top: 0, left: 0, right: 0, height: 3,
                      background: `linear-gradient(90deg, ${c.color}, transparent)`,
                    }}/>
                    <img src={c.img} alt="" style={{
                      position: 'absolute',
                      right: -60, bottom: -50,
                      height: 320,
                      objectFit: 'contain',
                      opacity: 0.45,
                      filter: `drop-shadow(0 20px 40px ${c.color}33)`,
                      pointerEvents: 'none',
                    }}/>
                    <div style={{
                      position: 'absolute', inset: 0,
                      background: 'linear-gradient(90deg, #0f1419 50%, rgba(15,20,25,0.3) 85%, transparent)',
                      pointerEvents: 'none',
                    }}/>
                    <div style={{ position: 'relative' }}>
                      <div style={{
                        fontFamily: TR.sans,
                        fontSize: c.label.length > 1 ? 92 : 128,
                        fontWeight: 900,
                        lineHeight: 1, letterSpacing: '-0.05em',
                        whiteSpace: 'nowrap',
                        background: `linear-gradient(135deg, ${c.color}, ${TR.cyan})`,
                        WebkitBackgroundClip: 'text',
                        WebkitTextFillColor: 'transparent',
                        backgroundClip: 'text',
                        padding: '0.05em 0 0.1em 0',
                      }}>{c.label}</div>
                      <div style={{
                        fontFamily: TR.sans, fontSize: 28, fontWeight: 700,
                        color: TR.ink, marginTop: 4, letterSpacing: '-0.02em',
                      }}>{c.title}</div>
                      <div style={{
                        fontFamily: TR.mono, fontSize: 12, color: c.color,
                        marginTop: 6, letterSpacing: '0.14em', textTransform: 'uppercase',
                      }}>{c.sub}</div>
                      <div style={{
                        width: 56, height: 1, background: TR.line, margin: '18px 0 14px',
                      }}/>
                      <ul style={{
                        listStyle: 'none', padding: 0, margin: 0,
                        display: 'flex', flexDirection: 'column', gap: 9,
                      }}>
                        {c.bullets.map((b, bi) => {
                          const bT = clamp((localTime - 1.2 - i * 0.12 - bi * 0.08) / 0.4, 0, 1);
                          const bE = Easing.easeOutCubic(bT);
                          return (
                            <li key={bi} style={{
                              display: 'flex', alignItems: 'center', gap: 10,
                              fontFamily: TR.sans, fontSize: 15, fontWeight: 500,
                              color: TR.ink, letterSpacing: '-0.005em',
                              opacity: bE,
                              transform: `translateX(${(1 - bE) * -8}px)`,
                            }}>
                              <svg viewBox="0 0 24 24" width="14" height="14" fill="none" style={{ flexShrink: 0 }}>
                                <path d="M5 12 L10 17 L19 7" stroke={c.color}
                                  strokeWidth="2.8" strokeLinecap="round" strokeLinejoin="round"/>
                              </svg>
                              {b}
                            </li>
                          );
                        })}
                      </ul>
                    </div>
                  </div>
                );
              })}
            </div>

            {/* Single metrics row — all four stats on ONE line, centered, clear of cards */}
            <div style={{
              position: 'absolute', left: 0, right: 0, top: 950,
              opacity: ctaE,
              transform: `translateY(${(1 - ctaE) * 16}px)`,
              display: 'flex', gap: 64, alignItems: 'center', justifyContent: 'center',
            }}>
              <div style={{ textAlign: 'center' }}>
                <div style={{ fontFamily: TR.mono, fontSize: 11, color: TR.inkDim, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Warranty</div>
                <div style={{ fontFamily: TR.sans, fontSize: 28, fontWeight: 700, color: TR.ink, marginTop: 4 }}>30 Days</div>
              </div>
              <div style={{ width: 1, height: 42, background: TR.line }}/>
              <div style={{ textAlign: 'center' }}>
                <div style={{ fontFamily: TR.mono, fontSize: 11, color: TR.inkDim, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Testing</div>
                <div style={{ fontFamily: TR.sans, fontSize: 28, fontWeight: 700, color: TR.ink, marginTop: 4 }}>52 Points</div>
              </div>
              <div style={{ width: 1, height: 42, background: TR.line }}/>
              <div style={{ textAlign: 'center' }}>
                <div style={{ fontFamily: TR.mono, fontSize: 11, color: TR.inkDim, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Battery</div>
                <div style={{ fontFamily: TR.sans, fontSize: 28, fontWeight: 700, color: TR.ink, marginTop: 4 }}>&gt; 80%</div>
              </div>
              <div style={{ width: 1, height: 42, background: TR.line }}/>
              <div style={{ textAlign: 'center' }}>
                <div style={{ fontFamily: TR.mono, fontSize: 11, color: TR.inkDim, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Data Wipe</div>
                <div style={{ fontFamily: TR.sans, fontSize: 28, fontWeight: 700, color: TR.ink, marginTop: 4 }}>Certified</div>
              </div>
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

Object.assign(window, { IntroScene, GradeScene, OutroScene });
