// Cascade Mode — causation diagram of failure modes converging on a single
// outcome. Pin a tallish section; as the user scrolls, the seven cards
// reveal one-by-one on an arc, each drawing a curved connector that meets
// at a convergence dot, with a short arrow finally firing into the
// outcome card on the right.
//
// Drop-in usage:
//   <script type="text/babel" src="cascade-mode.jsx"></script>
//   ...
//   <CascadeMode />                                       (uses defaults)
//   <CascadeMode items={[...]} accent="#1d4ed8"
//                outcomeLabel="Pilots stall"
//                outcomeBlurb="Each gap is fixable on its own. ..." />
//
// Self-contained: own scroll hook, own data, own keyframes. The component
// expects var(--ink) for the dark background; falls back to a deep navy.

const { useState: useCM_S, useEffect: useCM_E, useRef: useCM_R } = React;

const CASCADE_ITEMS_DEFAULT = [
  'Integration gaps',
  'Incomplete data',
  'Unclear ROI',
  'Misallocated budgets',
  'Cultural resistance',
  'Lack of orchestration',
  'Governance deficits',
];

// Inject keyframes once.
if (typeof document !== 'undefined' && !document.getElementById('cm-styles')) {
  const __cmStyle = document.createElement('style');
  __cmStyle.id = 'cm-styles';
  __cmStyle.textContent = `
    @keyframes cm-pulse {
      0%, 100% { opacity: 0.5; }
      50%      { opacity: 0; }
    }
  `;
  document.head.appendChild(__cmStyle);
}

const cmClamp = (v, a, b) => Math.max(a, Math.min(b, v));

// Hook: progress 0..1 as the pinned section scrolls past the viewport.
function useCM_PinProgress(ref) {
  const [p, setP] = useCM_S(0);
  useCM_E(() => {
    let raf = 0;
    const compute = () => {
      raf = 0;
      const el = ref.current;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const scrollable = rect.height - vh;
      const scrolled = Math.max(0, -rect.top);
      setP(cmClamp(scrolled / Math.max(scrollable, 1), 0, 1));
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(compute); };
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    compute();
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
      cancelAnimationFrame(raf);
    };
  }, [ref]);
  return p;
}

function CascadeMode({
  items = CASCADE_ITEMS_DEFAULT,
  accent = '#1d4ed8',
  dangerAccent = accent,
  eyebrow = 'Why pilots fail',
  heading = 'Seven failure modes — one outcome.',
  intro = 'Pilots rarely stall for a single reason. These seven recurring organizational gaps compound — we design every engagement to close them on day one.',
  outcomeLabel = 'Pilots stall',
  outcomeBlurb = 'Each gap is fixable on its own. Together they compound — turning promising pilots into stalled investments before they reach production.',
  ctaLabel = 'Read the methodology →',
  ctaHref = 'methodology.html',
  sectionId = 'failures',
}) {
  const sectionRef = useCM_R(null);
  const progress = useCM_PinProgress(sectionRef);
  const N = items.length;

  // Reveal schedule
  const HEAD_END = 0.06;
  const CARDS_END = 0.72;
  const cardWindow = (CARDS_END - HEAD_END) / N;
  const itemP = items.map((_, i) => {
    const start = HEAD_END + i * cardWindow;
    const end = start + cardWindow * 1.4;
    return cmClamp((progress - start) / (end - start), 0, 1);
  });
  const terminusP = cmClamp((progress - 0.78) / 0.14, 0, 1);

  // Diagram coords
  const DIAGRAM_W = 880;
  const DIAGRAM_H = 380;
  const CARD_W = 210;
  const CARD_H = 38;
  const ARC_BULGE = 110;
  const CONVERGE_X = 580;
  const CONVERGE_Y = DIAGRAM_H / 2;
  const ARROW_LEN = 80;
  const OUTCOME_W = 220;

  return (
    <section
      id={sectionId}
      ref={sectionRef}
      className="cm-section h-cascade-section"
      data-theme="dark"
      style={{
        position: 'relative',
        minHeight: '125vh',
        background: 'var(--ink, #0c1834)',
        color: '#fff',
      }}
    >
      <div
        className="h-cascade-pin"
        style={{
          position: 'sticky',
          top: 80,
          height: 'auto',
          maxHeight: 'calc(100vh - 80px)',
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'flex-start',
          alignItems: 'stretch',
          padding: '16px 64px 24px',
          boxSizing: 'border-box',
        }}
      >
        <div style={{ maxWidth: 1280, margin: '0 auto', width: '100%' }}>
          {/* Header */}
          <div
            className="h-cascade-header"
            style={{
              display: 'grid',
              gridTemplateColumns: '1fr auto',
              alignItems: 'flex-end',
              gap: 48,
              marginBottom: 14,
              marginTop: 14,
            }}
          >
            <div style={{ maxWidth: 760 }}>
              <div
                className="f-mono"
                style={{
                  fontFamily: '"JetBrains Mono", ui-monospace, Menlo, monospace',
                  fontSize: 11,
                  color: accent,
                  letterSpacing: '0.18em',
                  textTransform: 'uppercase',
                  marginBottom: 14,
                }}
              >{eyebrow}</div>
              <h3
                style={{
                  fontFamily: 'Inter, system-ui',
                  fontSize: 28,
                  lineHeight: 1.1,
                  margin: 0,
                  fontWeight: 700,
                  letterSpacing: '-0.025em',
                }}
              >{heading}</h3>
              <p
                style={{
                  fontSize: 13,
                  lineHeight: 1.55,
                  color: 'rgba(255,255,255,0.6)',
                  margin: '10px 0 0',
                  maxWidth: 540,
                }}
              >{intro}</p>
            </div>
            <a
              href={ctaHref}
              style={{
                display: 'inline-block',
                padding: '11px 20px',
                border: `1.4px solid ${accent}`,
                color: accent,
                textDecoration: 'none',
                fontFamily: '"JetBrains Mono", monospace',
                fontSize: 11,
                letterSpacing: '0.14em',
                textTransform: 'uppercase',
                borderRadius: 4,
                whiteSpace: 'nowrap',
              }}
            >{ctaLabel}</a>
          </div>

          {/* Diagram */}
          <div
            className="h-cascade-diagram"
            style={{
              position: 'relative',
              width: '100%',
              maxWidth: DIAGRAM_W,
              height: DIAGRAM_H,
              margin: '0 auto',
            }}
          >
            <svg
              width="100%"
              height="100%"
              viewBox={`0 0 ${DIAGRAM_W} ${DIAGRAM_H}`}
              preserveAspectRatio="xMidYMid meet"
              style={{
                position: 'absolute',
                inset: 0,
                pointerEvents: 'none',
                overflow: 'visible',
              }}
            >
              {items.map((_, i) => {
                const t = N === 1 ? 0.5 : i / (N - 1);
                const arc = 1 - Math.abs(2 * t - 1);
                const cardX = arc * ARC_BULGE;
                const cardY = 18 + t * (DIAGRAM_H - CARD_H - 36);
                const sx = cardX + CARD_W;
                const sy = cardY + CARD_H / 2;
                const ex = CONVERGE_X;
                const ey = CONVERGE_Y;
                const c1x = sx + 90;
                const c1y = sy;
                const c2x = ex - 100;
                const c2y = ey;
                const d = `M ${sx} ${sy} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${ex} ${ey}`;
                const p = itemP[i];
                const len = 620;
                return (
                  <path
                    key={`curve-${i}`}
                    d={d}
                    stroke={dangerAccent}
                    strokeWidth={1.4}
                    fill="none"
                    strokeLinecap="round"
                    strokeDasharray={len}
                    strokeDashoffset={len * (1 - p)}
                    opacity={0.22 + p * 0.7}
                    style={{
                      transition:
                        'stroke-dashoffset .55s cubic-bezier(.2,.7,.2,1), opacity .35s ease',
                      filter:
                        p > 0.6 ? `drop-shadow(0 0 6px ${dangerAccent}55)` : 'none',
                    }}
                  />
                );
              })}

              <circle
                cx={CONVERGE_X}
                cy={CONVERGE_Y}
                r={3 + terminusP * 4}
                fill={dangerAccent}
                opacity={cmClamp((progress - 0.18) / 0.10, 0, 1)}
                style={{ transition: 'r .35s ease, opacity .35s ease' }}
              />

              <line
                x1={CONVERGE_X}
                x2={CONVERGE_X + ARROW_LEN}
                y1={CONVERGE_Y}
                y2={CONVERGE_Y}
                stroke={dangerAccent}
                strokeWidth={3}
                strokeLinecap="round"
                strokeDasharray={ARROW_LEN}
                strokeDashoffset={ARROW_LEN * (1 - terminusP)}
                style={{
                  transition: 'stroke-dashoffset .5s cubic-bezier(.2,.7,.2,1)',
                  filter:
                    terminusP > 0.6
                      ? `drop-shadow(0 0 8px ${dangerAccent}aa)`
                      : 'none',
                }}
              />

              <polygon
                points={`${CONVERGE_X + ARROW_LEN - 2},${CONVERGE_Y - 8} ${CONVERGE_X + ARROW_LEN + 12},${CONVERGE_Y} ${CONVERGE_X + ARROW_LEN - 2},${CONVERGE_Y + 8}`}
                fill={dangerAccent}
                opacity={cmClamp((terminusP - 0.55) / 0.35, 0, 1)}
                style={{ transition: 'opacity .35s ease' }}
              />

              {terminusP > 0.6 && (
                <circle
                  cx={CONVERGE_X}
                  cy={CONVERGE_Y}
                  r="6"
                  fill="none"
                  stroke={dangerAccent}
                  strokeWidth="1"
                  opacity={cmClamp((terminusP - 0.6) / 0.4, 0, 1) * 0.55}
                >
                  <animate attributeName="r" values="6;20;6" dur="2.6s" repeatCount="indefinite" />
                  <animate attributeName="opacity" values="0.5;0;0.5" dur="2.6s" repeatCount="indefinite" />
                </circle>
              )}
            </svg>

            {/* Pills on the arc */}
            {items.map((title, i) => {
              const t = N === 1 ? 0.5 : i / (N - 1);
              const arc = 1 - Math.abs(2 * t - 1);
              const cardX = arc * ARC_BULGE;
              const cardY = 18 + t * (DIAGRAM_H - CARD_H - 36);
              const p = itemP[i];
              return (
                <div
                  key={title}
                  className="h-cascade-pill"
                  style={{
                    position: 'absolute',
                    left: `${(cardX / DIAGRAM_W) * 100}%`,
                    top: `${(cardY / DIAGRAM_H) * 100}%`,
                    width: `${(CARD_W / DIAGRAM_W) * 100}%`,
                    height: CARD_H,
                    display: 'flex',
                    alignItems: 'center',
                    gap: 12,
                    padding: '0 14px',
                    boxSizing: 'border-box',
                    borderRadius: 999,
                    border: `1px solid rgba(255,255,255,${(0.10 + p * 0.20).toFixed(3)})`,
                    background: `rgba(29,78,216,${(p * 0.12).toFixed(3)})`,
                    backdropFilter: 'blur(8px)',
                    WebkitBackdropFilter: 'blur(8px)',
                    opacity: 0.32 + p * 0.68,
                    transform: `translateX(${((1 - p) * -18).toFixed(2)}px)`,
                    transition:
                      'transform .4s cubic-bezier(.2,.7,.2,1), opacity .35s ease, border-color .35s ease, background .35s ease',
                  }}
                >
                  <span
                    style={{
                      fontFamily: '"JetBrains Mono", monospace',
                      fontSize: 10.5,
                      color: accent,
                      letterSpacing: '0.18em',
                      fontWeight: 600,
                    }}
                  >0{i + 1}</span>
                  <span
                    style={{
                      fontFamily: 'Inter, system-ui',
                      fontSize: 13.5,
                      fontWeight: 600,
                      letterSpacing: '-0.012em',
                      color: '#fff',
                      whiteSpace: 'nowrap',
                    }}
                  >{title}</span>
                </div>
              );
            })}

            {/* Outcome card */}
            <div
              className="h-cascade-outcome"
              style={{
                position: 'absolute',
                left: `${((CONVERGE_X + ARROW_LEN + 24) / DIAGRAM_W) * 100}%`,
                top: '50%',
                width: `${(OUTCOME_W / DIAGRAM_W) * 100}%`,
                transform: `translate(0, -50%) translateX(${((1 - terminusP) * 16).toFixed(2)}px) scale(${(0.94 + terminusP * 0.06).toFixed(3)})`,
                transformOrigin: 'left center',
                padding: '22px 22px 22px',
                border: `1.5px solid ${dangerAccent}`,
                background: terminusP > 0 ? `${dangerAccent}1a` : 'transparent',
                borderRadius: 6,
                opacity: 0.18 + terminusP * 0.82,
                transition:
                  'opacity .5s ease, transform .55s cubic-bezier(.2,.7,.2,1), background .35s ease',
              }}
            >
              <div
                style={{
                  fontFamily: '"JetBrains Mono", monospace',
                  fontSize: 10.5,
                  color: dangerAccent,
                  letterSpacing: '0.2em',
                  textTransform: 'uppercase',
                  marginBottom: 10,
                }}
              >Outcome</div>
              <div
                style={{
                  fontFamily: 'Inter, system-ui',
                  fontSize: 26,
                  lineHeight: 1.04,
                  fontWeight: 800,
                  letterSpacing: '-0.03em',
                  marginBottom: 10,
                }}
              >{outcomeLabel}</div>
              <div
                style={{
                  fontFamily: 'Inter, system-ui',
                  fontSize: 12.5,
                  lineHeight: 1.5,
                  color: 'rgba(255,255,255,0.72)',
                }}
              >{outcomeBlurb}</div>
            </div>
          </div>

          {/* Progress meter */}
          <div
            style={{
              marginTop: 32,
              display: 'flex',
              alignItems: 'center',
              gap: 14,
              color: 'rgba(255,255,255,0.55)',
            }}
          >
            <span
              style={{
                fontFamily: '"JetBrains Mono", monospace',
                fontSize: 10,
                letterSpacing: '0.22em',
                textTransform: 'uppercase',
              }}
            >Building the picture</span>
            <div
              style={{
                flex: 1,
                height: 1,
                background: 'rgba(255,255,255,0.18)',
                position: 'relative',
              }}
            >
              <div
                style={{
                  position: 'absolute',
                  left: 0, top: 0, bottom: 0,
                  width: `${(progress * 100).toFixed(1)}%`,
                  background: accent,
                  transition: 'width 60ms linear',
                }}
              />
            </div>
            <span
              style={{
                fontFamily: '"JetBrains Mono", monospace',
                fontSize: 10,
                letterSpacing: '0.14em',
                minWidth: 36,
                textAlign: 'right',
              }}
            >{Math.round(progress * 100)}%</span>
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { CascadeMode, CASCADE_ITEMS_DEFAULT });
