Accepted output, reconciled

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>Accepted output, reconciled</title><style>*{box-sizing:border-box}:root{--ink:#26353e;--muted:#526771;--accent:#285f77;--line:#d0dade;--soft:#edf3f5;color-scheme:light}body{margin:0;background:#f2f5f5;color:var(--ink);font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif}main{max-width:1120px;margin:auto;padding:28px 32px 64px}header{margin-bottom:20px}h1{font-size:clamp(1.5rem,3vw,2.1rem);line-height:1.2;letter-spacing:-.035em;margin:0 0 8px}header p{margin:0}h2{font-size:1.2rem;line-height:1.3;margin:0 0 16px}h3{font-size:1rem;margin:0 0 8px}p{margin:9px 0 16px}.panel{background:white;border:1px solid var(--line);border-radius:10px;padding:24px}.grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px}.fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.below{margin-top:24px}.muted,small{color:var(--muted)}.big{font-size:clamp(2rem,5vw,3.6rem);font-weight:750;line-height:1.14;letter-spacing:-.04em;margin:9px 0;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.subresult{font-size:1.2rem;font-weight:700}.formula{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;overflow-wrap:anywhere}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;padding:10px 12px;border:1px solid #879da8;border-radius:6px;background:white;color:var(--ink)}input,select{min-height:46px}textarea{line-height:1.6;resize:vertical}button{min-height:44px;padding:9px 15px;border:1px solid var(--accent);border-radius:6px;background:var(--accent);color:white;font-weight:650;cursor:pointer}button.secondary{background:white;color:var(--accent)}button:disabled{opacity:.5;cursor:not-allowed}:focus-visible{outline:3px solid #bf6a22;outline-offset:3px}.actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.check{display:flex;align-items:flex-start;gap:10px;font-weight:500}.check input{width:20px;height:20px;min-height:20px;margin:2px 0 0;flex:none;accent-color:var(--accent)}.badge{display:inline-block;background:var(--soft);color:var(--accent);font-size:.78rem;font-weight:700;padding:4px 9px;border-radius:24px}.error{min-height:24px;color:#a52f29;font-weight:650;margin:8px 0 0}.status{font-size:.88rem;color:var(--muted)}.note{background:#fff3de;border-left:3px solid #b47e3d;padding:12px 16px;color:#63491f}.rule{border-top:1px solid var(--line);margin:18px 0}table{border-collapse:collapse;width:100%;font-size:.92rem}th{font-size:.82rem;color:var(--muted);text-align:left}th,td{border-bottom:1px solid var(--line);padding:10px 8px;vertical-align:top}th:first-child,td:first-child{padding-left:0}details{border-top:1px solid var(--line);padding:16px 0}summary{font-weight:650;cursor:pointer}svg{display:block;width:100%;height:auto}figure{margin:0}figcaption{font-size:.84rem;color:var(--muted);margin-top:10px}pre{white-space:pre-wrap;overflow-wrap:anywhere;font:.86rem/1.6 ui-monospace,Consolas,monospace;background:#eaf0f3;border-radius:6px;padding:18px}ol{padding-left:24px}li{margin:7px 0}[hidden]{display:none!important}@media(max-width:720px){main{padding:22px 20px 44px}.grid{grid-template-columns:1fr;gap:18px}.panel{padding:20px}}@media(max-width:400px){main{padding:18px 16px 36px}.panel{padding:16px}.big{font-size:2.3rem}.fields{gap:12px}th,td{padding:8px 5px}}@media print{body{background:white}main{padding:0;max-width:none}.actions,button{display:none}.panel{break-inside:avoid}details>*{display:block}}.production-top{display:grid;grid-template-columns:1.25fr 1fr;background:#203e4b;color:white;border-radius:10px;padding:26px;gap:24px}.production-top p{margin-bottom:0;color:#d5e4ea}.finished{border-left:1px solid #64808d;padding-left:24px;align-self:center}.finished>b{display:block;font-size:2rem;margin:7px 0}.finished span:last-child{display:block;margin-top:16px;font-size:.9rem}.state-bar{display:flex;height:28px;border-radius:4px;overflow:hidden;background:#e8edef}.state-counts{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:15px}.state-counts b{display:block;font-size:1.6rem}.state-counts span{font-size:.85rem}.batch-ledger{display:grid;grid-template-columns:1fr 1fr;gap:24px}.batch-ledger article{border-top:3px solid #9bb1bd;padding-top:16px}@media(max-width:600px){.production-top{grid-template-columns:1fr;padding:22px;gap:18px}.finished{border-left:0;border-top:1px solid #64808d;padding:14px 0 0}.finished>b{font-size:1.6rem}.state-counts{grid-template-columns:1fr 1fr;gap:10px}.batch-ledger{grid-template-columns:1fr}}</style></head><body><main><header><h1>Accepted output, reconciled</h1><p>Fictional packet snapshot: compare accepted output with matching targets and reconcile every started unit.</p></header>
<section class="production-top" aria-live="polite"><div><span>Accepted-output attainment</span><div class="big" id="attainment">80%</div><b id="denominator">80 accepted / 100 target packets</b><p id="scope">Batches A + B · October 13, 2026</p></div><div class="finished"><span>Physically finished</span><b id="finished">95 packets</b><p>Finished includes accepted, held, and scrap.</p><span id="shortfall">20 packets below the accepted target</span></div></section>
<section class="panel below"><h2 id="started">120 started packets</h2><div id="stateBar" class="state-bar" aria-hidden="true"></div><div class="state-counts" id="stateCounts"></div><p id="coverage" class="status" role="status"></p><div class="actions"><label class="check" for="batchA"><input type="checkbox" id="batchA" checked>Batch A</label><label class="check" for="batchB"><input type="checkbox" id="batchB" checked>Batch B</label></div></section>
<section class="panel below"><h2>Fictional source ledger · packets</h2><div class="batch-ledger"><article><h3>Batch A</h3><p>Started 100 = accepted 60 + quality hold 10 + scrap 5 + unfinished 25</p><label for="targetA">Accepted target · local scenario<input id="targetA" value="80" inputmode="numeric"></label><p class="status">Supplied baseline: 80 accepted packets.</p></article><article><h3>Batch B</h3><p>Started 20 = accepted 20 + quality hold 0 + scrap 0 + unfinished 0</p><label for="targetB">Accepted target · local scenario<input id="targetB" value="20" inputmode="numeric"></label><p class="status">Supplied baseline: 20 accepted packets.</p></article></div><div class="actions"><button type="button" id="reset" class="secondary">Restore source targets</button></div><p id="error" role="status" class="error"></p></section>
<details class="below"><summary>Definitions and workbook calculation</summary><p>Each packet occupies exactly one state at the snapshot. Accepted is completed and accepted; hold is physically finished awaiting disposition; scrap is physically finished and rejected; unfinished is not physically finished. These are this fictional ledger’s definitions, not release authority.</p><p>Sum accepted quantities and their matching positive targets, then divide. The supplied batch ratios are 75% and 100%; their unweighted mean 87.5% is not the overall 80/100 ratio. A missing target is excluded with its ID disclosed. 0/0 is not applicable. Positive accepted output with a zero target requires a policy and blocks combined attainment. State reconciliation must pass first.</p><p>Target edits are unsaved local comparisons; source quantities remain fixed. No inspection release, OEE, runtime, machine control, forecast, import, or alerts.</p></details></main><script>const $=id=>document.getElementById(id),put=(id,s)=>{$(id).textContent=s};
function esc(s){return String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));}
function gcd(a,b){a=a<0n?-a:a;b=b<0n?-b:b;while(b){[a,b]=[b,a%b]}return a||1n;}
function R(n,d=1n){n=BigInt(n);d=BigInt(d);if(d===0n)throw Error('Undefined denominator.');if(d<0n){n=-n;d=-d}const g=gcd(n,d);return {n:n/g,d:d/g};}
function mul(a,b){return R(a.n*b.n,a.d*b.d)}function div(a,b){return R(a.n*b.d,a.d*b.n)}function add(a,b){return R(a.n*b.d+b.n*a.d,a.d*b.d)}function sub(a,b){return R(a.n*b.d-b.n*a.d,a.d*b.d)}function cmp(a,b){const x=a.n*b.d-b.n*a.d;return x<0n?-1:x>0n?1:0}
function parse(s,{max=1000000,positive=false,places=6}={}){const t=String(s).trim();if(!t)throw Error('Enter a value; blank is not zero.');const re=new RegExp('^[0-9]+(?:\.[0-9]{1,'+places+'})?$');if(!re.test(t))throw Error('Use digits and a US decimal point, up to '+places+' places; no signs, commas, or exponents.');const v=Number(t);if(!Number.isFinite(v)||v>max||(positive&&v===0))throw Error('Value must be '+(positive?'greater than zero':'nonnegative')+' and at most '+max+'.');const [a,b='']=t.split('.');return R(BigInt(a+b),10n**BigInt(b.length));}
function format(a,places=6){const neg=a.n<0n,n=neg?-a.n:a.n,scale=10n**BigInt(places),v=n*scale,q=v/a.d,rem=v%a.d,k=q+(rem*2n>=a.d?1n:0n);const f=(k%scale).toString().padStart(places,'0').replace(/0+$/,'');return {text:(neg&&k!==0n?'-':'')+(k/scale)+(f?'.'+f:''),approx:rem!==0n};}
function exact(a){let d=a.d;while(d%2n===0n)d/=2n;while(d%5n===0n)d/=5n;if(d!==1n)return a.n+'/'+a.d;let places=0,p=1n;while(p%a.d!==0n&&places<40){p*=10n;places++}return format(a,places).text;}
function display(a,places=6){if(a.n>0n&&cmp(a,R(1n,10n**BigInt(places)))<0)return '< '+format(R(1n,10n**BigInt(places)),places).text;const f=format(a,places);return (f.approx?'≈ ':'')+f.text;}
function listen(ids,fn){ids.forEach(id=>{ $(id).addEventListener('input',fn);$(id).addEventListener('change',fn); });}


const source=[{id:'A',started:100,accepted:60,hold:10,scrap:5,unfinished:25,target:'80'},{id:'B',started:20,accepted:20,hold:0,scrap:0,unfinished:0,target:'20'}];
function summarize(rows){if(!rows.length)throw Error('Select at least one batch.');const totals={started:0,accepted:0,hold:0,scrap:0,unfinished:0},included=[],excluded=[],blocked=[];let accepted=0,target=0;for(const r of rows){for(const k of Object.keys(totals)){if(!Number.isInteger(r[k])||r[k]<0||r[k]>1000000)throw Error(r.id+': invalid '+k+' packet count.');totals[k]+=r[k];}if(r.accepted+r.hold+r.scrap+r.unfinished!==r.started)throw Error(r.id+': state counts do not reconcile with started.');if(r.target===null||String(r.target).trim()===''){excluded.push(r.id+' missing target');continue}if(!/^[0-9]+$/.test(String(r.target).trim())||Number(r.target)>1000000)throw Error(r.id+': target must be an integer from 0 to 1,000,000.');const t=Number(r.target);if(t===0){if(r.accepted===0)excluded.push(r.id+' 0/0 not applicable');else blocked.push(r.id+' positive output / zero target; policy required');continue}included.push(r.id);accepted+=r.accepted;target+=t;}return {totals,included,excluded,blocked,ratio:blocked.length||!target?null:accepted/target*100,accepted,target,finished:totals.accepted+totals.hold+totals.scrap};}
function update(){try{const rows=source.filter(r=>$(r.id==='A'?'batchA':'batchB').checked).map(r=>({...r,target:$(r.id==='A'?'targetA':'targetB').value})),s=summarize(rows);put('attainment',s.ratio===null?'Unavailable':s.ratio.toFixed(2).replace(/[.]?0+$/,'')+'%');put('denominator',s.ratio===null?'No approved matching-target ratio':s.accepted+' accepted / '+s.target+' target packets');put('scope',(s.ratio===null?'Attainment unavailable':'Attainment scope '+s.included.join(' + '))+' · State scope '+rows.map(r=>r.id).join(' + ')+' · October 13, 2026');put('finished',s.finished+' packets');put('shortfall',s.ratio===null?'Target comparison unavailable':s.target>=s.accepted?(s.target-s.accepted)+' packets below the included accepted target':(s.accepted-s.target)+' packets above the included accepted target');put('started',s.totals.started+' started packets');const parts=[['Accepted','accepted','#3e797c'],['Quality hold','hold','#ad813b'],['Scrap','scrap','#a65c52'],['Unfinished','unfinished','#aebfc7']];$('stateBar').innerHTML=parts.map(([label,k,color])=>'<span style="width:'+(s.totals.started?s.totals[k]/s.totals.started*100:0)+'%;background:'+color+'"></span>').join('');$('stateCounts').innerHTML=parts.map(([label,k,color])=>'<div><b>'+s.totals[k]+'</b><span>'+label+'</span></div>').join('');put('coverage',(s.included.length?'Attainment includes '+s.included.join(', ')+'. ':'No rows in attainment scope. ')+(s.excluded.length?'Excluded: '+s.excluded.join('; ')+'. ':'')+s.blocked.join('; '));put('error','');}catch(e){put('attainment','—');['denominator','scope','finished','shortfall','started','coverage'].forEach(id=>put(id,''));$('stateBar').innerHTML='';$('stateCounts').innerHTML='';put('error',e.message);}}
listen(['batchA','batchB','targetA','targetB'],update);$('reset').addEventListener('click',()=>{$('targetA').value='80';$('targetB').value='20';$('batchA').checked=true;$('batchB').checked=true;update()});globalThis.Tool={summarize,update};update();</script></body></html>