Percent of a percent
HTML for this example
Select the code and use your copy shortcut. Changes in this preview are temporary.
<!doctype html><html lang="en-US"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Percent of a percent</title><style>*{box-sizing:border-box} :root{color-scheme:light;--ink:#20303b;--muted:#536570;--line:#d3dce1;--accent:#245c76;--paper:#fff;--soft:#edf3f6}body{margin:0;background:#f3f5f5;color:var(--ink);font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{max-width:1080px;margin:auto;padding:30px 32px 64px}header{margin-bottom:20px}h1{font-size:clamp(1.5rem,3vw,2.15rem);line-height:1.18;letter-spacing:-.035em;margin:0 0 8px}h2{font-size:1.22rem;line-height:1.3;margin:0 0 16px}h3{font-size:1rem;margin:0 0 8px}p{margin:8px 0 16px}small,.muted{color:var(--muted)}.eyebrow{font-size:.76rem;letter-spacing:.13em;text-transform:uppercase;font-weight:750;color:var(--accent);margin-bottom:8px}.panel{background:var(--paper);border:1px solid var(--line);padding:24px;border-radius:16px}.grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px}.stack{display:grid;gap:18px}.fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}label{display:block;font-size:.9rem;font-weight:650}input,select,textarea,button{font:inherit}input,select,textarea{display:block;width:100%;min-width:0;margin-top:6px;border:1px solid #8b9ca6;border-radius:7px;padding:10px 12px;background:white;color:var(--ink)}input,select{min-height:46px}textarea{resize:vertical}button{border:1px solid var(--accent);border-radius:7px;padding:10px 16px;min-height:44px;background:var(--accent);color:white;cursor:pointer;font-weight:650}button.secondary{background:white;color:var(--accent)}button:hover{filter:brightness(.94)}:focus-visible{outline:3px solid #d06e1c;outline-offset:3px}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px}.answer{background:var(--ink);color:white;padding:26px;border-radius:14px}.answer .muted{color:#d9e5eb}.big{font-size:clamp(2.1rem,5vw,3.8rem);font-weight:750;line-height:1.16;letter-spacing:-.045em;margin:8px 0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.subresult{font-size:1.2rem;font-weight:650} .formula{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;overflow-wrap:anywhere}.note{border-left:3px solid #b47029;padding:10px 14px;background:#fff5e5;margin:14px 0;color:#66451b}.error{color:#a22621;font-weight:650;min-height:24px;margin:8px 0}.below{margin-top:28px}table{border-collapse:collapse;width:100%;font-size:.94rem}th{text-align:left;color:var(--muted);font-weight:650;font-size:.84rem}th,td{padding:11px 10px;border-bottom:1px solid var(--line);vertical-align:top}th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0}details{border-top:1px solid var(--line);padding:16px 0}summary{cursor:pointer;font-weight:650}svg{display:block;width:100%;height:auto}.tag{display:inline-block;font-size:.78rem;font-weight:650;padding:3px 8px;border-radius:30px;background:var(--soft);color:var(--accent)}.rule{height:1px;background:var(--line);margin:20px 0}.checklabel{display:flex;gap:10px;align-items:flex-start;font-weight:500}.checklabel input{width:20px;min-height:20px;flex:none;margin:2px 0}pre{white-space:pre-wrap;word-break:break-word;font: .86rem/1.6 ui-monospace,Consolas,monospace;background:#edf1f3;padding:20px;border-radius:8px}a{color:var(--accent)}[hidden]{display:none!important}@media(max-width:720px){main{padding:22px 20px 40px}.grid{grid-template-columns:1fr;gap:18px}.panel{padding:20px}.answer{padding:22px}.big{font-size:2.65rem}}@media(max-width:400px){main{padding:18px 16px 36px}.fields{gap:12px}th,td{padding:9px 6px}.panel{padding:16px}.big{font-size:2.25rem}}@media print{body{background:white}main{max-width:none;padding:0}.actions,button{display:none}.panel{break-inside:avoid}details>*{display:block}}.chain{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.chain div{border-top:5px solid #577d86;padding:12px;background:#edf4f3}.chain div:nth-child(2){border-color:#a18643}.chain div:nth-child(3){border-color:#2b6b65}.chain b{display:block;font-size:2rem}.chain span{font-size:.86rem}@media(max-width:450px){.chain{grid-template-columns:1fr;gap:8px}.chain div{display:flex;gap:16px;align-items:center;padding:8px 12px}.chain b{font-size:1.5rem}}</style></head><body><main><header><div class="eyebrow">Follow the denominator</div><h1>Percent of a percent</h1></header>
<p>Multiply a subset’s share by the completion rate within that subset.</p>
<div class="grid"><section class="answer" aria-live="polite"><div>Completed share of the original whole</div><div id="result" class="big">60%</div><div id="derive" class="formula">0.8 × 0.75 × 100 = 60%</div><div class="rule"></div><div id="modeled" class="subresult">7.2 modeled units from a base of 12</div><p id="zeroNote" class="muted">Rates describe a nested subset of the same whole.</p></section>
<section class="panel"><div class="fields"><label for="p">p · Eligible / whole (%)<input id="p" inputmode="decimal" value="80" ></label><label for="q">q · Complete / eligible (%)<input id="q" inputmode="decimal" value="75" ></label></div><div style="margin-top:16px"><label for="base">Hypothetical base (optional)<input id="base" inputmode="decimal" value="12" ></label></div><div class="actions"><button type="button" id="calculate">Calculate</button><button type="button" id="reset" class="secondary">Reset example</button></div><p class="error" id="error" role="status"></p></section></div>
<section class="below panel"><h2>The supplied count record</h2><div class="chain"><div><b>50</b><span>D01 · Whole set</span></div><div><b>40</b><span>E01 · Eligible within D01</span></div><div><b>30</b><span>C01 · Complete within E01</span></div></div><p>Fictional assignments · October 13, 2026 · Same assignment-ID basis</p><p class="formula">(40/50) × (30/40) = 30/50 = 60%</p><p id="recordNote" class="muted">Current rates match the supplied record. The optional base is a separate model, not counted assignments.</p></section>
<details class="below"><summary>Basis, limits, and calculation notes</summary><p>p and q each accept 0–100%, with up to six decimal places. A hypothetical base accepts 0–1,000,000. The displayed product is rounded to six places if needed. Inputs stay local to this page and are not saved.</p><p>Use linked denominators from one comparable group. Marginal rates from different groups do not establish an intersection. Swapping the rate values preserves multiplication but changes their meaning. Adding the rates does not answer this question.</p><p>Fractional modeled amounts are preserved. A rate within an empty group cannot be an observed conditional rate.</p></details></main><script>
const $=id=>document.getElementById(id);const put=(id,text)=>{$(id).textContent=text};const fmt=(x,n=6)=>{if(!Number.isFinite(x))throw Error('Result exceeds the numeric range.');let v=(Math.round(Math.abs(x)*10**n)/10**n)*(x<0?-1:1);return Object.is(v,-0)?'0':v.toFixed(n).replace(/\.?0+$/,'')||'0'};const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
function decimal(s,{max=1000000,signed=false,places=6}={}){s=String(s).trim();if(!s)throw Error('Enter a value; a blank field is not zero.');const r=new RegExp('^'+(signed?'[+-]?':'')+'(?:[0-9]+(?:\\.[0-9]{1,'+places+'})?|\\.[0-9]{1,'+places+'})$');if(!r.test(s))throw Error('Use a '+(signed?'signed':'nonnegative')+' US decimal with up to '+places+' decimal places; no commas or exponents.');const v=Number(s);if(!Number.isFinite(v)||Math.abs(v)>max)throw Error('Enter a value within '+(signed?'-':'0 to ')+max+'.');return v;}
function scaled(s){decimal(s);const [a,b='']=String(s).trim().split('.');return BigInt(a||'0')*1000000n+BigInt(b.padEnd(6,'0'));}
function rational(n,d,places=6){if(d===0n)throw Error('Zero denominator');let neg=(n<0n)!=(d<0n);n=n<0n?-n:n;d=d<0n?-d:d;const scale=10n**BigInt(places),v=n*scale,q=v/d,r=v%d;let rounded=q+(r*2n>=d?1n:0n);let s=(rounded/scale).toString();const f=(rounded%scale).toString().padStart(places,'0').replace(/0+$/,'');if(f)s+='.'+f;return {text:(neg&&rounded!==0n?'-':'')+s,approx:r!==0n};}
function bind(ids,fn){ids.forEach(id=>{ $(id).addEventListener('input',fn);$(id).addEventListener('change',fn); });}
function compound(p,q,base){const a=decimal(p,{max:100}),b=decimal(q,{max:100}),P=scaled(p),Q=scaled(q);const modeled=base.trim()===''?null:decimal(base)*a*b/10000;return {percent:a*b/100,share:rational(P*Q,100000000000000n,6),modeled,modelText:modeled===null?null:rational(scaled(base)*P*Q,10000000000000000000000n,22).text,empty:a===0};}
function update(){try{const r=compound($('p').value,$('q').value,$('base').value);put('result',(r.share.approx?'≈ ':'')+r.share.text+'%');put('derive',fmt(Number($('p').value)/100,8)+' × '+fmt(Number($('q').value)/100,8)+' × 100 '+(r.share.approx?'≈':'=')+' '+r.share.text+'%');put('modeled',r.modeled===null?'No hypothetical base supplied':r.modelText+' modeled units from a base of '+$('base').value);put('zeroNote',r.empty?'Numeric product only: the eligible subset is empty, so an observed conditional completion rate is undefined.':'Rates describe a nested subset of the same whole.');put('recordNote',Number($('p').value)===80&&Number($('q').value)===75?'Current rates match the supplied fictional count record. The optional base is a separate model.':'The edited rates are a separate calculation; the fixed 50/40/30 record above has not changed.');put('error','');}catch(e){put('result','—');put('derive','');put('modeled','');put('zeroNote','');put('recordNote','No current valid rate calculation. The supplied fictional count record remains separate.');put('error',e.message);}}
bind(['p','q','base'],update);$('calculate').addEventListener('click',update);$('reset').addEventListener('click',()=>{$('p').value='80';$('q').value='75';$('base').value='12';update()});globalThis.Tool={compound,update};update();
</script></body></html>