// Burn-up chart with Monte Carlo forecast cone — geometry, not decoration. function BurnUpCone({ width = 640, height = 220 }) { const pad = { l: 34, r: 96, t: 16, b: 26 }; const W = width - pad.l - pad.r; const H = height - pad.t - pad.b; const x = (f) => pad.l + f * W; const y = (f) => pad.t + (1 - f) * H; // scope line (total work), actual completed, cone from today const today = 0.58; const actual = [[0, 0], [0.08, 0.05], [0.18, 0.13], [0.26, 0.16], [0.36, 0.27], [0.46, 0.38], [0.58, 0.47]]; const coneHi = [[0.58, 0.47], [0.72, 0.66], [0.86, 0.88], [0.95, 1.0]]; const coneLo = [[0.58, 0.47], [0.74, 0.58], [0.9, 0.74], [1.0, 0.86]]; const mid = [[0.58, 0.47], [0.76, 0.63], [0.92, 0.83], [1.0, 0.93]]; const pts = (arr) => arr.map(([a, b]) => `${x(a)},${y(b)}`).join(' '); const cone = [...coneHi, ...[...coneLo].reverse()]; return ( ); } // Runway bar: milestone due date vs forecast range position function RunwayBar({ m }) { const toneColor = m.tone === 'warn' ? 'var(--warn)' : 'var(--ok)'; const left = Math.max(0, (m.pos - m.spread / 2) * 100); const w = Math.min(100 - left, m.spread * 100); return (