Spaces:
Paused
Paused
| <div id="ob-ip" role="group" aria-label="Interactive inverted-pair calculator. Adjust the model's probability of success and of failure; the Skew is the gap between them."> | |
| <div class="ip-grid"> | |
| <div> | |
| <div class="ip-q">"Probability of <b style="color:var(--opt,#e07a5f)">success</b>?"</div> | |
| <input id="ip-pos" class="ip-range" type="range" min="0" max="100" value="70"> | |
| <div class="ip-val" style="color:var(--opt,#e07a5f)">P⁺ = <span id="ip-posv">70</span></div> | |
| </div> | |
| <div> | |
| <div class="ip-q">"Probability of <b style="color:var(--pes,#3d5a80)">failure</b>?"</div> | |
| <input id="ip-neg" class="ip-range" type="range" min="0" max="100" value="15"> | |
| <div class="ip-val" style="color:var(--pes,#3d5a80)">P⁻ = <span id="ip-negv">15</span></div> | |
| </div> | |
| </div> | |
| <svg id="ip-svg" width="100%" height="84"></svg> | |
| <div id="ip-out" class="ip-out"></div> | |
| </div> | |
| <style> | |
| #ob-ip { font: 13px/1.45 system-ui, -apple-system, sans-serif; color: var(--text-color,#222); width:100%; max-width:560px; margin:0 auto; } | |
| #ob-ip .ip-grid { display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-bottom:6px; } | |
| #ob-ip .ip-q { font-size:12.5px; color:var(--muted-color,#666); margin-bottom:6px; } | |
| #ob-ip .ip-range { width:100%; } | |
| #ob-ip #ip-pos { accent-color: var(--opt,#e07a5f); } | |
| #ob-ip #ip-neg { accent-color: var(--pes,#3d5a80); } | |
| #ob-ip .ip-val { font-size:21px; font-weight:700; margin-top:2px; } | |
| #ob-ip .ip-out { text-align:center; font-size:14.5px; margin-top:4px; } | |
| </style> | |
| <script> | |
| (function () { | |
| var root = document.getElementById("ob-ip"); | |
| if (!root || !window.d3) { return; } | |
| var d3 = window.d3, svg = d3.select("#ip-svg"); | |
| var pos = document.getElementById("ip-pos"), neg = document.getElementById("ip-neg"); | |
| function cssVar(n, fb) { var v = getComputedStyle(document.documentElement).getPropertyValue(n); return (v && v.trim()) || fb; } | |
| function draw() { | |
| var p = +pos.value, n = +neg.value, comp = 100 - n, skew = p - comp; | |
| document.getElementById("ip-posv").textContent = p; | |
| document.getElementById("ip-negv").textContent = n; | |
| var OPT = cssVar("--opt", "#e07a5f"), PES = cssVar("--pes", "#3d5a80"), MUT = cssVar("--muted-color", "#666"), TXT = cssVar("--text-color", "#222"), BD = cssVar("--border-color", "#ccc"); | |
| var W = root.clientWidth || 520, m = 22, y = 40; | |
| var x = d3.scaleLinear().domain([0, 100]).range([m, W - m]); | |
| svg.attr("viewBox", "0 0 " + W + " 84").selectAll("*").remove(); | |
| svg.append("rect").attr("x", m).attr("y", y - 9).attr("width", W - 2 * m).attr("height", 18).attr("rx", 9).attr("fill", BD).attr("opacity", 0.35); | |
| svg.append("rect").attr("x", m).attr("y", y - 9).attr("width", x(p) - m).attr("height", 18).attr("rx", 9).attr("fill", OPT).attr("opacity", 0.85); | |
| svg.append("line").attr("x1", x(comp)).attr("x2", x(comp)).attr("y1", y - 17).attr("y2", y + 17).attr("stroke", PES).attr("stroke-width", 2).attr("stroke-dasharray", "3 3"); | |
| svg.append("text").attr("x", x(comp)).attr("y", y - 21).attr("text-anchor", "middle").attr("fill", PES).attr("font-size", 10).text("100 − P⁻ = " + comp); | |
| if (p !== comp) { | |
| var x1 = Math.min(x(p), x(comp)), x2 = Math.max(x(p), x(comp)); | |
| svg.append("rect").attr("x", x1).attr("y", y + 12).attr("width", x2 - x1).attr("height", 6).attr("rx", 2).attr("fill", skew > 0 ? OPT : PES); | |
| svg.append("text").attr("x", (x1 + x2) / 2).attr("y", y + 33).attr("text-anchor", "middle").attr("fill", TXT).attr("font-size", 11).attr("font-weight", 600).text((skew > 0 ? "+" : "") + skew + " pts unaccounted for"); | |
| } | |
| var verdict = skew > 1 ? "optimistic" : skew < -1 ? "pessimistic" : "coherent"; | |
| var vc = skew > 1 ? OPT : skew < -1 ? PES : MUT; | |
| document.getElementById("ip-out").innerHTML = "Skew = P⁺ − (100 − P⁻) = " + p + " − " + comp + " = <b style='color:" + vc + "'>" + (skew > 0 ? "+" : "") + skew + "</b> <span style='color:" + vc + "'>(" + verdict + ")</span>"; | |
| } | |
| pos.addEventListener("input", draw); neg.addEventListener("input", draw); | |
| if (window.ResizeObserver) { new ResizeObserver(draw).observe(root); } else { window.addEventListener("resize", draw); } | |
| new MutationObserver(draw).observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] }); | |
| draw(); | |
| })(); | |
| </script> | |