const { useState, useEffect, useRef, useCallback } = React; /* ============================================================ ARTIFACT — what each rung produces (right-side panel) ============================================================ */ function Artifact({ rung }){ const a = rung.artifact; if(a.type === "case"){ return (
{a.title}
); } if(a.type === "sim"){ const rounds = [{m:"Quarter capacity",p:72},{m:"Promo conflict",p:88},{m:"Stockout cascade",p:54},{m:"Demand spike",p:81}]; return (
{a.title}
Round 3 · turn 2/4 · 00:48 remaining
Constraint: +CS volume, −1 truck
{rounds.map((r,i)=>(
{r.m}
{r.p}
))}
); } if(a.type === "roleplay"){ return (
{a.title}
Persona · BoD member · Hard Mode
"You have 60 seconds. Why are we behind?"
Interrupts at 0:18. Pivots to capex at 0:34. Refuses your first scope cut at 0:52.
{["Structure","Clarity","Client-fit","Next step"].map((k,i)=>(
{k}
{["A","A","B+","A−"][i]}
))}
); } if(a.type === "shadow"){ return (
{a.title}
Incident timeline.svg
Handoff log.csv
What went wrong: Inventory write-down trigger missed at hand-off T-72h.
What to say: "We need a single owner per SKU class. Here's the rule."
Next step: Propose rule to ops lead by Wed. Re-baseline write-down threshold.
); } if(a.type === "debrief"){ return (
{a.title}
{[ ["Brief was clear before delivery","pass"], ["Decision was made on time","pass"], ["Stakeholders signed off","pass"], ["Quality bar met on outputs","pass"], ["Lessons captured for next cycle","watch"] ].map((r,i)=>(
{r[1]==="pass"?"✓":"!"}
{r[0]}
{r[1]}
))}
); } if(a.type === "review"){ return (
{a.title}
{[{l:"Cases reviewed",v:"12 / 12"},{l:"Passed quality bar",v:"11"},{l:"Pass rate",v:"92%"}].map((c,i)=>(
{c.l}
{c.v}
))}
Placement signal: Ready for permanent role — Customer Success lead, Region East.
); } return null; } /* ============================================================ MOUNTAIN — six camps on a hand-drawn summit path ============================================================ */ // Camp positions: x,y on a 1200x720 viewBox, ascending left→right. const CAMPS = [ { x:120, y:610, lblX:120, lblY:660, polaroidX:30, polaroidY:480, rotate:-6, noteX:130, noteY:680, note:"Base camp · build judgment" }, { x:300, y:520, lblX:300, lblY:570, polaroidX:230, polaroidY:380, rotate:4, noteX:310, noteY:590, note:"Decide under pressure" }, { x:480, y:430, lblX:480, lblY:480, polaroidX:400, polaroidY:300, rotate:-3, noteX:490, noteY:500, note:"Practice the conversation" }, { x:660, y:350, lblX:660, lblY:400, polaroidX:590, polaroidY:240, rotate:5, noteX:670, noteY:420, note:"Read the real artifacts" }, { x:850, y:255, lblX:850, lblY:305, polaroidX:790, polaroidY:150, rotate:-4, noteX:860, noteY:325, note:"Drive real work, supervised" }, { x:1060, y:140, lblX:1050,lblY:195, polaroidX:980, polaroidY:50, rotate:6, noteX:1000,noteY:215, note:"Own it · summit reached" }, ]; const POLAROID_GRAD = [ "linear-gradient(135deg,#94A3B8,#64748B)", // grey · case "linear-gradient(135deg,#1A549F,#246BB2)", // blue · sim "linear-gradient(135deg,#6B46C1,#4338CA)", // indigo · roleplay "linear-gradient(135deg,#475569,#1F2937)", // slate · shadow "linear-gradient(135deg,#0EA34A,#057430)", // green · supervised "linear-gradient(135deg,#0D903A,#1A549F)", // brand gradient · independent ]; function Polaroid({ camp, idx, active, onClick }){ return (
{window.RUNGS[idx].name}
); } function Mountain({ active, setActive }){ const wrapRef = useRef(null); return (
{/* Sun + clouds (abstract) */} {/* Far range */} {/* Mid range */} {/* Main summit ridge (the path the camps sit on) */} {/* Hand-drawn trail (dashed) */} {/* Distance labels */} START SUMMIT {/* Birds */} {/* CAMP BUTTONS (the SVG-anchored interactive points) */} {CAMPS.map((c,i)=>{ const isActive = i===active; return ( setActive(i)} tabIndex="0" role="button" aria-label={`Rung ${i+1}`} style={{opacity: 1, transition:`opacity 0.5s ease`}}> {/* flag pole */} {/* flag */} {/* ring + dot */} {i+1} {/* label */} {window.RUNGS[i].name} ); })} {/* Polaroid layer (HTML overlay) — animates as rungs are selected */} {CAMPS.map((c,i)=>( setActive(i)} /> ))} {/* Hand-drawn arrow note pointing at active camp */}
click any camp →
); } /* ============================================================ ROOT ============================================================ */ function Ladder(){ const [active, setActive] = useState(0); const [isOpen, setIsOpen] = useState(false); const [autoPlay, setAutoPlay] = useState(false); const r = window.RUNGS[active]; useEffect(() => { const el = document.getElementById("ladder-root"); if(!el) return; const observer = new IntersectionObserver((entries) => { if(entries[0].isIntersecting){ setAutoPlay(true); observer.disconnect(); } }, { threshold: 0.5 }); observer.observe(el); return () => observer.disconnect(); }, []); useEffect(() => { if (!autoPlay) return; const timer = setInterval(() => { setActive((prev) => { if(prev >= 5) { setAutoPlay(false); return prev; } return prev + 1; }); }, 1200); return () => clearInterval(timer); }, [autoPlay]); const handleSelect = (i) => { setAutoPlay(false); setActive(i); setIsOpen(true); }; // Prevent background scroll when modal is open useEffect(() => { if(isOpen) document.body.style.overflow = "hidden"; else document.body.style.overflow = ""; return () => { document.body.style.overflow = ""; }; }, [isOpen]); return (
{isOpen && (
setIsOpen(false)}>
e.stopPropagation()} style={{ width: "100%", maxWidth: 540, display: "flex", flexDirection: "column", position: "relative" }} >
{r.n}
Rung {String(r.n).padStart(2,"0")} · {r.label}
{r.fullName || r.name}

{r.tagline}

{r.what}
{r.criteria.map((c,i)=>(
{c.lbl}: {c.val}
{c.desc}
))}
)}
); } const el = document.getElementById("ladder-root"); if(el){ ReactDOM.createRoot(el).render(); }