// Scroll-driven hand-off transitions between sections.
// Rule: NO chapter numbers, NO headline text. Each transition is a single
// continuous element-morph that uses the visual vocabulary of the surrounding
// sections — so the hero element of one section literally becomes the hero
// element of the next.
//
//   02 → 03   16 spark bars (section 02 chart)  ➜  3 pillars (section 03)
//   03 → 04   3 pillars                          ➜  ladder rails + 6 rungs
//   04 → 05   ladder rungs                        ➜  8-point capability wheel

function useScrollProgress(ref) {
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    function onScroll() {
      const el = ref.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const viewH = window.innerHeight;
      const total = r.height + viewH;
      const passed = viewH - r.top;
      setT(Math.max(0, Math.min(1, passed / total)));
    }
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
    };
  }, [ref]);
  return t;
}

const clamp01 = v => Math.max(0, Math.min(1, v));
const lerp = (a, b, t) => a + (b - a) * t;
const easeOut = t => 1 - Math.pow(1 - t, 3);
const easeInOut = t => t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t + 2, 2) / 2;

/* ============================================================
   02 → 03 — Spark bars consolidate into 3 pillars
   ============================================================ */
function Trans02to03() {
  const ref = React.useRef(null);
  const t = useScrollProgress(ref);

  // 16 bars, exact heights from the section-02 sparkline.
  const SPARK = [14, 22, 18, 28, 24, 38, 32, 46, 42, 58, 52, 68, 62, 76, 72, 86];
  // 3 destination centers (% of canvas width) — match 03 pillar order.
  const TARGETS = [
    { x: 16, color1: '#0D903A', color2: '#074c2a', label: 'PERFORMANCE LADDER' },
    { x: 50, color1: '#246BB2', color2: '#164A97', label: 'STANDARD OF EXCELLENCE' },
    { x: 84, color1: '#FFBA00', color2: '#8C6100', label: 'SCALE & CONTROL' },
  ];
  // Which target each bar gravitates to.
  const targetIdx = SPARK.map((_, i) => i < 5 ? 0 : i < 11 ? 1 : 2);
  // Pick 3 "winner" bars whose colour swaps to the slab gradient.
  const WINNERS = [2, 8, 13];

  // Three phases.
  const rise   = clamp01(t / 0.22);           // 0 → 0.22  bars grow up
  const tall   = clamp01((t - 0.20) / 0.30);  // 0.20 → 0.50  bars climb tall
  const merge  = clamp01((t - 0.45) / 0.40);  // 0.45 → 0.85  migrate + consolidate
  const finish = clamp01((t - 0.80) / 0.20);  // 0.80 → 1.00 settle into pillars

  return (
    <section ref={ref} className="trans trans--02to03" data-screen-label="Transition 02→03">
      <div className="trans-bg"></div>
      <div className="trans-stage">
        <div className="trans-canvas">
          {SPARK.map((h, i) => {
            const tgt = TARGETS[targetIdx[i]];
            const isWinner = WINNERS.includes(i);
            // Original X (0..1 within the 16-bar strip, centered ~ 10–90%)
            const baseX = 10 + (i / (SPARK.length - 1)) * 80;
            // Position lerp: origin → cluster center
            const x = lerp(baseX, tgt.x, easeInOut(merge));
            // Height grows in phases:
            //   1) rise to its spark height
            //   2) climb to tall
            //   3) for winners, expand to full slab; for losers, collapse
            const sparkH    = h / 100;                                   // 0.14 → 0.86
            const tallH     = lerp(sparkH, 0.85, easeOut(tall));         // → 85% of canvas
            const winnerH   = lerp(tallH, 1.0, easeOut(finish));         // → 100%
            const loserH    = lerp(tallH, 0.0, easeInOut(merge));        // collapses to 0
            const h01       = isWinner ? winnerH : loserH;
            // Width: winners fatten into slabs, losers stay narrow
            const baseW = 28;
            const slabW = 240;
            const w     = isWinner
              ? lerp(baseW, slabW, easeOut(merge))
              : baseW * (1 - easeInOut(merge));
            // Tilt — winners pick up the diagonal slab clip near the end
            const tilt = isWinner ? lerp(0, -6, easeOut(finish)) : 0;
            // Colour blend — winners shift from spark gradient to slab gradient
            const blend = isWinner ? easeOut(merge) : 0;
            const grad = `linear-gradient(180deg,
              color-mix(in oklab, #0FE872 ${(1-blend)*100}%, ${tgt.color1}) 0%,
              color-mix(in oklab, rgba(255,186,0,0.4) ${(1-blend)*100}%, ${tgt.color2}) 100%)`;
            // Opacity — losers fade as they collapse
            const op = isWinner ? 1 : (1 - easeInOut(merge));
            // Vertical rise from below
            const baseRise = clamp01(rise * 2 - i * 0.02);

            return (
              <div
                key={i}
                className={'t23-bar' + (isWinner ? ' t23-bar--winner' : '')}
                style={{
                  left: `calc(${x}% - ${w/2}px)`,
                  bottom: 0,
                  width: w,
                  height: `${h01 * 92}%`,
                  background: grad,
                  opacity: op * (0.2 + baseRise * 0.8),
                  transform: `translateY(${(1 - baseRise) * 40}px) rotate(${tilt}deg)`,
                  transformOrigin: 'bottom center',
                  boxShadow: isWinner
                    ? `0 0 ${40 * easeOut(merge)}px rgba(255,186,0,${0.25 * easeOut(merge)})`
                    : `0 0 12px rgba(15,232,114,${0.18 * (1 - easeInOut(merge))})`,
                }}
              />
            );
          })}

          {/* Pillar labels — fade in only after winners have consolidated */}
          {TARGETS.map((tg, i) => (
            <div
              key={'lbl'+i}
              className="t23-pillar-label"
              style={{
                left: `${tg.x}%`,
                opacity: finish,
                color: tg.color1 === '#FFBA00' ? '#FFBA00' : tg.color1,
              }}
            >
              <span className="t23-pillar-num">0{i+1}</span>
              <span className="t23-pillar-name">{tg.label}</span>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   03 → 04 — 3 pillars un-tilt into ladder rails + rungs draw
   ============================================================ */
function Trans03to04() {
  const ref = React.useRef(null);
  const t = useScrollProgress(ref);

  // Phase A: 3 tilted pillars (matching 03 hero) un-tilt + slide
  const straighten = clamp01(t / 0.35);
  // Phase B: middle pillar fades, outer 2 become the ladder rails
  const fade       = clamp01((t - 0.30) / 0.20);
  // Phase C: 6 rungs draw across, one by one
  const rungs      = clamp01((t - 0.40) / 0.50);
  // Phase D: climbing dot ascends
  const climb      = clamp01((t - 0.45) / 0.50);

  // Source pillars (tilted, like section 03 slabs)
  const PILLARS = [
    { from: { x: 200, w: 200, tilt: -8, color: '#0D903A', color2: '#074c2a' },
      to:   { x: 200, w: 6,   tilt:  0, color: '#FFBA00', color2: '#FFBA00' } },
    { from: { x: 400, w: 200, tilt: -8, color: '#246BB2', color2: '#164A97' },
      to:   { x: 400, w: 4,   tilt:  0, color: '#246BB2', color2: '#164A97' } },
    { from: { x: 600, w: 200, tilt: -8, color: '#FFBA00', color2: '#8C6100' },
      to:   { x: 600, w: 6,   tilt:  0, color: '#FFBA00', color2: '#FFBA00' } },
  ];

  const RUNGS = ['Case', 'Sim', 'Mimic', 'Shadow', 'Supervise', 'Independent'];

  return (
    <section ref={ref} className="trans trans--03to04" data-screen-label="Transition 03→04">
      <div className="trans-bg trans-bg--deep"></div>
      <div className="trans-stage">
        <div className="trans-canvas">
          <svg viewBox="0 0 800 420" preserveAspectRatio="xMidYMid meet" className="t34-svg">
            <defs>
              <linearGradient id="t34-rail" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%"   stopColor="#FFBA00" stopOpacity="0.25"/>
                <stop offset="50%"  stopColor="#FFBA00" stopOpacity="1"/>
                <stop offset="100%" stopColor="#0FE872" stopOpacity="0.45"/>
              </linearGradient>
              <filter id="t34-glow" x="-30%" y="-30%" width="160%" height="160%">
                <feGaussianBlur stdDeviation="3" result="b"/>
                <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
              </filter>
            </defs>

            {/* Pillars → rails (interpolated) */}
            {PILLARS.map((p, i) => {
              const x  = lerp(p.from.x,    p.to.x,    easeInOut(straighten));
              const w  = lerp(p.from.w,    p.to.w,    easeOut(straighten));
              const tlt= lerp(p.from.tilt, p.to.tilt, easeInOut(straighten));
              const isMiddle = i === 1;
              const op = isMiddle ? (1 - fade) : 1;
              const fill = `url(#${i === 1 ? 't34-rail' : 't34-rail'})`;
              // Render as a tilted rect via path
              const half = w / 2;
              const top = 40, bot = 380;
              const xt = x + Math.tan(tlt * Math.PI / 180) * (bot - top) / 2;
              const xb = x - Math.tan(tlt * Math.PI / 180) * (bot - top) / 2;
              const d = `M ${xt - half} ${top}
                         L ${xt + half} ${top}
                         L ${xb + half} ${bot}
                         L ${xb - half} ${bot} Z`;
              // Color blends with straighten
              const c1 = straighten < 0.8 ? p.from.color  : '#FFBA00';
              return (
                <g key={i} opacity={op}>
                  <path
                    d={d}
                    fill={`url(#pillar-${i})`}
                    filter="url(#t34-glow)"
                  />
                  <defs>
                    <linearGradient id={`pillar-${i}`} x1="0" y1="0" x2="0" y2="1">
                      <stop offset="0%"   stopColor={p.from.color}  stopOpacity={1 - easeOut(straighten) * 0.6}/>
                      <stop offset="100%" stopColor={p.from.color2} stopOpacity={1 - easeOut(straighten) * 0.6}/>
                    </linearGradient>
                  </defs>
                  {/* Rail overlay strengthens as we straighten */}
                  <line
                    x1={x} y1={top - 20} x2={x} y2={bot + 20}
                    stroke="url(#t34-rail)"
                    strokeWidth={2.5}
                    strokeLinecap="round"
                    opacity={easeOut(straighten) * (isMiddle ? (1 - fade) : 1)}
                    filter="url(#t34-glow)"
                  />
                </g>
              );
            })}

            {/* Rungs draw across the outer two rails */}
            {RUNGS.map((label, i) => {
              // bottom-up draw order
              const order = RUNGS.length - 1 - i;
              const localT = clamp01(rungs * RUNGS.length - order);
              const y = 360 - i * 52;
              const x1 = 200, x2 = 600;
              const cx = (x1 + x2) / 2;
              const half = (x2 - x1) / 2;
              const draw1 = cx - half * easeOut(localT);
              const draw2 = cx + half * easeOut(localT);

              return (
                <g key={i} opacity={localT}>
                  <line
                    x1={draw1} y1={y} x2={draw2} y2={y}
                    stroke="#FFBA00" strokeWidth="3.5" strokeLinecap="round"
                    filter="url(#t34-glow)"
                  />
                  {/* Rung tick numbers */}
                  <text
                    x={x1 - 16} y={y + 4} textAnchor="end"
                    fontFamily="var(--font-condensed, monospace)"
                    fontSize="11" fontWeight="700"
                    fill="#FFBA00" fillOpacity={localT * 0.7}
                    style={{letterSpacing:'0.14em'}}
                  >{String(i+1).padStart(2,'0')}</text>
                  {/* Rung labels — appear after rung is drawn */}
                  <text
                    x={x2 + 16} y={y + 4}
                    fontFamily="var(--font-sans, sans-serif)"
                    fontSize="13" fontWeight="600"
                    fill="#fff" fillOpacity={Math.max(0, localT - 0.4) * 1.6}
                    style={{letterSpacing:'-0.005em'}}
                  >{label}</text>
                </g>
              );
            })}

            {/* Climbing dot */}
            {climb > 0.02 && (
              <g filter="url(#t34-glow)">
                <circle
                  cx={400}
                  cy={lerp(360, 360 - 5 * 52, easeOut(climb))}
                  r={9}
                  fill="#FFBA00"
                />
                <circle
                  cx={400}
                  cy={lerp(360, 360 - 5 * 52, easeOut(climb))}
                  r={18}
                  fill="none"
                  stroke="#FFBA00"
                  strokeOpacity="0.35"
                  strokeWidth="1.5"
                />
              </g>
            )}
          </svg>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   04 → 05 — Ladder rungs detach and curl into the capability wheel
   ============================================================ */
function Trans04to05() {
  const ref = React.useRef(null);
  const t = useScrollProgress(ref);

  // Phase A: ladder visible
  const settle = clamp01(t / 0.20);
  // Phase B: rungs detach + curl outward into circle
  const curl   = clamp01((t - 0.18) / 0.55);
  // Phase C: wheel hub + ring appears
  const hub    = clamp01((t - 0.65) / 0.30);

  // 8 capability target angles + colors (from section 05).
  // Angles match window.CAPABILITIES.angle (every 45°, starting at 0 = top).
  const CAPS = [
    { angle:   0, color: '#0D903A', short: 'Finance' },
    { angle:  45, color: '#0F8E42', short: 'Business' },
    { angle:  90, color: '#246BB2', short: 'Macro' },
    { angle: 135, color: '#1A549F', short: 'Products' },
    { angle: 180, color: '#164A97', short: 'Value' },
    { angle: 225, color: '#19519C', short: 'Acquisition' },
    { angle: 270, color: '#077934', short: 'Reactivation' },
    { angle: 315, color: '#057430', short: 'Execution' },
  ];

  const cx = 400, cy = 210, R = 150;

  // Source ladder rung Y positions (matching Trans03to04: 360 - i*52, 6 rungs)
  // We have 8 capability targets. The 6 original rungs map to 6 capabilities;
  // the remaining 2 emerge from rail tips.
  const RUNG_Y = [360, 308, 256, 204, 152, 100];
  const SOURCE = [
    { x: 400, y: RUNG_Y[0], spawn: 0   }, // rung 1
    { x: 400, y: RUNG_Y[1], spawn: 0   }, // rung 2
    { x: 400, y: RUNG_Y[2], spawn: 0   }, // rung 3
    { x: 400, y: RUNG_Y[3], spawn: 0   }, // rung 4
    { x: 400, y: RUNG_Y[4], spawn: 0   }, // rung 5
    { x: 400, y: RUNG_Y[5], spawn: 0   }, // rung 6
    { x: 200, y:  60,       spawn: 0.1 }, // emerges from left rail top
    { x: 600, y:  60,       spawn: 0.1 }, // emerges from right rail top
  ];

  return (
    <section ref={ref} className="trans trans--04to05" data-screen-label="Transition 04→05">
      <div className="trans-bg trans-bg--cosmos"></div>
      <div className="trans-stage">
        <div className="trans-canvas">
          <svg viewBox="0 0 800 420" preserveAspectRatio="xMidYMid meet" className="t45-svg">
            <defs>
              <radialGradient id="t45-hub" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#fff" stopOpacity="1"/>
                <stop offset="100%" stopColor="#FFBA00" stopOpacity="1"/>
              </radialGradient>
              <filter id="t45-glow" x="-30%" y="-30%" width="160%" height="160%">
                <feGaussianBlur stdDeviation="3" result="b"/>
                <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
              </filter>
            </defs>

            {/* Fading ladder rails */}
            <g opacity={(1 - curl) * settle} filter="url(#t45-glow)">
              <line x1={200} y1={40} x2={200} y2={380} stroke="#FFBA00" strokeWidth="2.5" strokeLinecap="round" opacity="0.75"/>
              <line x1={600} y1={40} x2={600} y2={380} stroke="#FFBA00" strokeWidth="2.5" strokeLinecap="round" opacity="0.75"/>
              {/* 6 rungs visible at start */}
              {RUNG_Y.map((y, i) => (
                <line key={i} x1={210} y1={y} x2={590} y2={y}
                      stroke="#FFBA00" strokeWidth={3.5} strokeLinecap="round"
                      opacity={0.85}/>
              ))}
            </g>

            {/* Faint guide circle for the wheel — appears with hub */}
            {hub > 0.05 && (
              <g opacity={hub * 0.5}>
                <circle cx={cx} cy={cy} r={R} fill="none"
                        stroke="rgba(255,186,0,0.45)" strokeWidth="1"
                        strokeDasharray="2 5"/>
                {/* 8 light spokes */}
                {CAPS.map((c, i) => {
                  const a = (c.angle - 90) * Math.PI / 180;
                  return (
                    <line
                      key={i}
                      x1={cx + Math.cos(a) * 40}
                      y1={cy + Math.sin(a) * 40}
                      x2={cx + Math.cos(a) * (R - 20)}
                      y2={cy + Math.sin(a) * (R - 20)}
                      stroke="rgba(255,186,0,0.15)"
                      strokeWidth="1"
                    />
                  );
                })}
              </g>
            )}

            {/* 8 morphing nodes — ladder rungs ➜ capability wedges */}
            {CAPS.map((c, i) => {
              const src = SOURCE[i];
              const localT = clamp01((curl - src.spawn) / Math.max(0.001, 1 - src.spawn));
              const a = (c.angle - 90) * Math.PI / 180;
              const tgtX = cx + Math.cos(a) * R;
              const tgtY = cy + Math.sin(a) * R;
              // Bezier curl: anchor pulls toward center first, so it arcs.
              const midX = lerp(src.x, tgtX, 0.5);
              const midY = lerp(src.y, tgtY, 0.5);
              // Bend toward center as t goes 0 → 1 (smooth arc, not straight)
              const bendX = lerp(midX, cx, 0.4) * (1 - Math.abs(localT - 0.5) * 2);
              const bendY = lerp(midY, cy, 0.4) * (1 - Math.abs(localT - 0.5) * 2);
              // Bezier point
              const u = easeInOut(localT);
              const px = (1 - u) * ((1 - u) * src.x + u * midX) + u * ((1 - u) * midX + u * tgtX);
              const py = (1 - u) * ((1 - u) * src.y + u * midY) + u * ((1 - u) * midY + u * tgtY);
              // Append arc curvature
              const _ = bendX + bendY; // silence unused
              const dotR = lerp(5, 11, localT);
              // Trailing arc — short segment from previous step
              const u0 = Math.max(0, u - 0.06);
              const sx = (1 - u0) * ((1 - u0) * src.x + u0 * midX) + u0 * ((1 - u0) * midX + u0 * tgtX);
              const sy = (1 - u0) * ((1 - u0) * src.y + u0 * midY) + u0 * ((1 - u0) * midY + u0 * tgtY);

              // At very end, draw a short capability wedge marker
              const wedgeOp = clamp01((localT - 0.85) / 0.15);
              const wa1 = a - (Math.PI / 8) * 0.7;
              const wa2 = a + (Math.PI / 8) * 0.7;
              const Rin = R - 10, Rou = R + 18;
              const wedgeD = `
                M ${cx + Math.cos(wa1) * Rin} ${cy + Math.sin(wa1) * Rin}
                L ${cx + Math.cos(wa1) * Rou} ${cy + Math.sin(wa1) * Rou}
                A ${Rou} ${Rou} 0 0 1 ${cx + Math.cos(wa2) * Rou} ${cy + Math.sin(wa2) * Rou}
                L ${cx + Math.cos(wa2) * Rin} ${cy + Math.sin(wa2) * Rin}
                A ${Rin} ${Rin} 0 0 0 ${cx + Math.cos(wa1) * Rin} ${cy + Math.sin(wa1) * Rin}
                Z`;

              return (
                <g key={i} filter="url(#t45-glow)">
                  {/* Trailing dotted arc */}
                  {localT > 0.1 && localT < 0.95 && (
                    <line x1={sx} y1={sy} x2={px} y2={py}
                          stroke={c.color} strokeOpacity="0.7"
                          strokeWidth="2" strokeLinecap="round"/>
                  )}
                  {/* Moving node */}
                  <circle
                    cx={px} cy={py} r={dotR}
                    fill={c.color}
                    fillOpacity={0.85 + 0.15 * localT}
                  />
                  {/* Final wedge bloom at endpoint */}
                  {wedgeOp > 0 && (
                    <path d={wedgeD} fill={c.color}
                          fillOpacity={wedgeOp * 0.55}
                          stroke={c.color} strokeOpacity={wedgeOp}
                          strokeWidth="1"/>
                  )}
                </g>
              );
            })}

            {/* Center hub */}
            {hub > 0.02 && (
              <g filter="url(#t45-glow)" opacity={hub}>
                <circle cx={cx} cy={cy} r={32} fill="url(#t45-hub)"/>
                <text x={cx} y={cy + 3} textAnchor="middle"
                      fontFamily="var(--font-condensed, monospace)"
                      fontSize="9" fontWeight="800"
                      fill="#0f172a"
                      style={{letterSpacing:'0.16em'}}>STANDARD</text>
              </g>
            )}
          </svg>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Trans02to03, Trans03to04, Trans04to05 });
