/* Practice figures, part two — connected and core-platform practices. Same rules as part one: instrument detail, CSS keyframes only, mobile drops panels rather than shrinking type. Shared helpers come from part one. */ /* Helpers are resolved at render time, not at load: with a dozen Babel scripts on one page the execution order of src modules is not guaranteed. */ const PFG = (props) => window.Fig(props); const GP = (props) => window.Panel(props); const GM = (...a) => window.MONO(...a); const cA = "var(--sx-accent)", cF = "var(--sx-field)", cS = "var(--sx-signal)", cAM = "var(--sx-amber)"; const cL = "var(--border-default)", cL2 = "var(--border-strong)"; const cQ = "var(--text-quiet)", cI = "var(--text-strong)", cB = "var(--text-body)"; /* ── Energy-tech ────────────────────────────────────────────────────────── The hierarchy a distribution utility actually has, reads climbing it, and the command coming back down with an acknowledgement that is checked. */ function FigEnergy({ mobile }) { const meters = mobile ? 5 : 9; const h = mobile ? 200 : 250; const sy = 24, fy = 84, my = mobile ? 140 : 148; const mx = (i) => 18 + i * ((mobile ? 330 : 250) / (meters - 1)); const feeders = [0, 1]; return ( circle · lahore east 3 IT centres kept in sync {feeders.map((f) => { const fx = f === 0 ? 84 : 232; return ( feeder F-{118 + f * 4} {f === 0 ? "12 transformers" : "9 transformers"} ); })} {Array.from({ length: meters }).map((_, i) => { const x = mx(i), tgt = x < 200 ? 84 : 232; return ( {!mobile && {4471 + i * 3}} ); })} {!mobile && ( <> {[["queued", "3", cQ], ["acknowledged", "3", cF], ["failed", "0", cF], ["window", "15 min", cQ]].map((r, i) => ( {r[0]} {r[1]} ))} validation before billing {[["spike", cF], ["zero", cF], ["rollover", cF], ["gap 07:45", cAM], ["clock drift", cF], ["phase", cF]].map((r, i) => ( {r[0]} ))} 1 of 96 intervals estimated, flagged on the record — never silently filled )} {mobile && 6 validation rules before a read reaches a bill} ); } /* ── Agri-tech ──────────────────────────────────────────────────────────── Three probe depths, the water balance that reads them, and the verification step that corrects the next cycle. */ function FigAgri({ mobile }) { const h = mobile ? 200 : 252, x0 = 30, x1 = 392, base = h - (mobile ? 44 : 74), top = 40; const N = 72; const X = (i) => x0 + (i / N) * (x1 - x0); const depths = [["20 cm", cF, 0.0], ["40 cm", cA, 0.14], ["60 cm", cQ, 0.26]]; const curve = (ph, amp) => { const d = []; for (let i = 0; i <= N; i++) { const c = i % 24; const v = (c < 17 ? 0.74 - c * 0.026 : 0.3 + (c - 17) * 0.066) * (1 - amp) + amp * 0.55 + ph * 0.1; d.push((i ? "L" : "M") + X(i).toFixed(1) + " " + (base - v * (base - top)).toFixed(1)); } return d.join(" "); }; const thr = base - 0.42 * (base - top); return ( {[0, 0.25, 0.5, 0.75, 1].map((t) => ( {Math.round(10 + t * 24)}% ))} refill point {depths.slice(0, mobile ? 2 : 3).map(([label, col, amp], i) => ( ))} {[0, 1, 2].slice(0, mobile ? 2 : 3).map((k) => { const x = X(k * 24 + 17); return ( valve · 9 mm ); })} {!mobile && ( <> verify 90 min {[["et₀", "5.6 mm/day"], ["crop kc", "1.05 mid"], ["rain 48h", "2 mm · low conf"], ["applied", "9.1 mm"], ["expected", "24.1% · got 24.7%"]].map((r, i) => ( {r[0]} {r[1]} ))} profile moved further than predicted, so next cycle drops the setpoint 0.4 mm )} {mobile && applied 9.1 mm · profile answered 24.7% vs 24.1% expected} ); } /* ── ERP & billing ──────────────────────────────────────────────────────── The cycle as a ledger: what came in, what was held, what was posted, and what is still owed. */ function FigLedger({ mobile }) { const rows = mobile ? [["reads_ingested", "6.52M", "", cF], ["exceptions_held", "20,510", "circle desk", cAM], ["bills_generated", "6.50M", "8 circles", cF], ["payments_posted", "5.91M", "bank files", cF]] : [["reads_ingested", "6.52M", "field · smart · manual", cF], ["exceptions_held", "20,510", "to circle desk, before billing", cAM], ["tariff_applied", "6.50M", "protected · unprotected · TOU", cF], ["bill_run", "6.50M", "batch, restartable checkpoints", cF], ["dispatch", "6.50M", "print · portal · sms", cF], ["payments_posted", "5.91M", "machine-readable bank returns", cF], ["rejected", "1,340", "re-presented next file", cAM]]; const rowH = 24, top = 26; const h = top + rows.length * rowH + (mobile ? 40 : 74); return ( stage count {rows.map((r, i) => { const y = top + i * rowH; return ( {r[0]} {!mobile && {r[2]}} {mobile && r[2] && {r[2]}} {r[1]} ); })} {!mobile && ( arrears ageing, by circle {[["0–30", 0.62, cF], ["31–60", 0.28, cF], ["61–90", 0.14, cAM], ["90+", 0.08, cS]].map((b, i) => ( {b[0]} ))} recovery reported per circle, division and tariff class 90.6% collected )} ); } /* ── Data platforms ─────────────────────────────────────────────────────── Four cadences, a late arrival that still lands in the right window, and the four keys everything is written against. */ function FigData({ mobile }) { const lanes = mobile ? [["telemetry", "40–80/day", 0.6, cA], ["meter reads", "15-min", 1.0, cF], ["documents", "on arrival", 1.7, cS]] : [["device telemetry", "40–80 msg / meter / day", 0.6, cA], ["meter reads", "15-minute interval", 1.0, cF], ["enterprise records", "nightly batch", 1.5, cQ], ["documents", "on arrival", 2.0, cS]]; const top = 30, gap = 30; const h = top + lanes.length * gap + (mobile ? 46 : 84); const lx = mobile ? 92 : 132, rx = 268; const outY = top + (lanes.length - 1) * gap / 2 + 8; return ( {lanes.map(([name, cadence, per, col], i) => { const y = top + i * gap; return ( {name} {cadence} {[0, 1, 2, 3].map((k) => ( ))} {i === 2 && !mobile && } ); })} window {["account", "site", "asset", "period"].map((k, i) => ( {k} ))} {!mobile && ( {[["rows / day", "41.2k"], ["reconciled", "nightly"], ["retention", "rolling"], ["late window", "72 h"]].map((r, i) => ( {r[0]} {r[1]} ))} master-file synchronisation keeps regional centres consistent )} ); } /* ── Cloud & DevOps ─────────────────────────────────────────────────────── The pipeline with its gate, the environments it promotes through, and the uptime that is a number rather than an opinion. */ function FigDevops({ mobile }) { const stages = mobile ? [["build", "2m10"], ["test", "4m02"], ["deploy", "1m18"]] : [["commit", "—"], ["build", "2m10"], ["test", "4m02"], ["canary 5%", "10m"], ["deploy", "1m18"]]; const h = mobile ? 196 : 240, y = mobile ? 74 : 86; const bw = mobile ? 108 : 70, gapx = (392 - bw) / (stages.length - 1); return ( uptime · trailing 90 days {Array.from({ length: mobile ? 30 : 45 }).map((_, i) => { const bad = i === (mobile ? 19 : 29); return ; })} 99.94% one incident · 34 min · postmortem published {stages.map(([s, dur], i) => { const x = 4 + i * gapx; return ( {i > 0 && } {s} {dur} ); })} gate failed, rolled back in 40s, no traffic served {!mobile && ( {[["dev", "ephemeral", cF], ["staging", "prod-shaped", cF], ["prod", "in-country", cA], ["dr", "tested quarterly", cQ]].map((e, i) => ( {e[0]} {e[1]} ))} )} ); } const PRACTICE_FIGURES = { "ai-agents": (m) => , "document-intelligence": (m) => , "applied-ml": (m) => window.PF_LONG.forecast(m), "computer-vision": (m) => , "industrial-iot": (m) => , "energy-tech": (m) => , "agri-tech": (m) => window.PF_LONG.agri(m), "erp-billing": (m) => window.PF_LONG.ledger(m), "data-platforms": (m) => , "cloud-devops": (m) => window.PF_LONG.devops(m), }; Object.assign(window, { PRACTICE_FIGURES, FigEnergy, FigAgri, FigLedger, FigData, FigDevops });