Energy conversion record
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>Energy conversion record</title><style>*{box-sizing:border-box}html{color-scheme:light}body{margin:0;background:var(--bg,#eef1f4);color:var(--ink,#233449);font:16px/1.5 system-ui,-apple-system,Segoe UI,sans-serif}main{max-width:1040px;margin:auto;padding:26px 28px 44px}header{margin-bottom:20px}h1{font-size:clamp(26px,4vw,36px);letter-spacing:-.035em;line-height:1.15;margin:5px 0 10px}h2{font-size:21px;line-height:1.3;margin:0 0 15px}h3{font-size:17px;margin:0 0 9px}p{margin:8px 0 16px}.kicker{font-size:12px;text-transform:uppercase;letter-spacing:.12em;font-weight:750;color:var(--accent,#315b87)}.muted,small{color:#556473}.panel{margin:20px 0;padding:24px;border:1px solid var(--line,#ccd5df);border-radius:10px;background:#fff}.hero{padding:24px;background:var(--hero,#183b5c);color:#fff;border-radius:12px;margin:18px 0}.hero .kicker,.hero small{color:#d9e5ef}.big{font-size:clamp(32px,5vw,52px);line-height:1.15;font-weight:750;letter-spacing:-.035em;overflow-wrap:anywhere;margin:10px 0 15px}.row{display:flex;flex-wrap:wrap;gap:15px;align-items:end}.row>label{flex:1;min-width:140px}.grid{display:grid;grid-template-columns:1fr 1fr;gap:20px}.thirds{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:15px}label{display:block;font-size:14px;font-weight:650}input,select,textarea{font:inherit;font-size:16px;color:inherit;display:block;width:100%;margin-top:6px;padding:11px 12px;border:1px solid #a9b4c1;border-radius:6px;background:white;min-width:0}input[type=checkbox]{display:inline;width:auto;margin:0 8px 0 0;accent-color:var(--accent,#315b87)}textarea{min-height:100px;resize:vertical}button{font:inherit;font-weight:650;min-height:44px;border:1px solid var(--accent,#315b87);border-radius:6px;background:var(--accent,#315b87);color:white;padding:10px 16px;cursor:pointer}button.secondary{background:white;color:var(--accent,#315b87)}button:disabled{opacity:.5;cursor:default}button[aria-pressed=true]{box-shadow:0 0 0 3px #eab655}button:hover:not(:disabled){filter:brightness(.94)}:focus-visible{outline:3px solid #e5a72f;outline-offset:3px}.actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0 0}[hidden]{display:none!important}.error{color:#a3232a;font-weight:650}.error:not(:empty){padding:12px;background:#fff0ed;border-left:4px solid #ab3439;margin:14px 0}.note{padding:14px;background:#edf2f6;border-radius:6px;margin:14px 0}.mono,pre{font-family:ui-monospace,Consolas,monospace;font-variant-numeric:tabular-nums}pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:14px;line-height:1.7;margin:0}.mono{overflow-wrap:anywhere}table{width:100%;border-collapse:collapse;table-layout:fixed;font-size:14px}th,td{text-align:left;vertical-align:top;overflow-wrap:anywhere;padding:11px 8px;border-bottom:1px solid #d4dce4}th{font-size:12px;text-transform:uppercase;letter-spacing:.035em;color:#536372}th:first-child,td:first-child{padding-left:0}.tag{display:inline-block;padding:4px 8px;border:1px solid currentColor;border-radius:4px;font-size:12px;font-weight:750}.rule{border-top:1px solid #cbd4dd;padding-top:18px}.line{height:30px;border-bottom:1px solid #aab5bf}.stat{font-size:34px;line-height:1.15;font-weight:750}.stat small{font:14px system-ui;display:block;margin-top:8px}details{margin:20px 0;border-top:1px solid #cbd4dd;padding:18px 0}summary{font-weight:700;cursor:pointer}details p{margin-top:15px}a{color:var(--accent,#315b87)}footer{font-size:13px;color:#556473;margin-top:25px}fieldset{min-width:0;border:1px solid #c8d2db;border-radius:7px;padding:18px;margin:15px 0}legend{font-weight:750;padding:0 6px}@media(max-width:720px){main{padding:20px}.panel,.hero{padding:20px}.thirds{gap:10px}}@media(max-width:540px){main{padding:16px}.grid,.thirds{grid-template-columns:1fr}.panel,.hero{padding:18px}.row{gap:12px}.row>label{min-width:100px}h1{font-size:27px}th,td{padding:10px 5px;font-size:13px}.big{font-size:37px}}.surface{background:white;border:1px solid #ccd5df;border-radius:10px;padding:24px;margin:18px 0}.metrics{display:flex;gap:34px;flex-wrap:wrap}.metric b{font-size:clamp(32px,5vw,52px);line-height:1.1;display:block;letter-spacing:-.04em}.metric span{display:block;margin-top:8px;font-size:14px}.strip{display:grid;grid-template-columns:repeat(10,minmax(0,1fr));gap:7px;margin:22px 0}.unit{padding:10px 3px;text-align:center;background:#e5f0eb;border-bottom:4px solid #327660;font-size:13px;font-weight:700}.unit.rework{background:#fff0d5;border-color:#aa701d}.unit.fail{background:#f9e2e0;border-color:#ab3d35}.ledger-row{display:grid;grid-template-columns:100px 1fr 140px;gap:18px;padding:18px 0;border-bottom:1px solid #d2dbe3;align-items:start}.ledger-row p{margin:5px 0}.amount{text-align:right;font-size:22px;font-weight:750}.pill{display:inline-block;border-radius:20px;background:#e7edf2;padding:5px 10px;font-size:12px;font-weight:700}.timeline{border-left:3px solid #c7d4de;padding:0 0 0 22px;margin:16px 0}.timeline article{padding:10px 0 18px}.timeline h3{margin-bottom:5px}.timeline p{margin:5px 0}.artifact{font-family:Georgia,serif}.warning{background:#fff3db;border-left:4px solid #a66d18;padding:15px}.empty{color:#5d6771;font-style:italic}.check{color:#22694f}.bad{color:#9a332e}button.linklike{padding:8px 12px;min-height:40px;background:white;color:var(--accent,#315b87)}@media(max-width:540px){.surface{padding:18px}.ledger-row{grid-template-columns:65px 1fr;gap:12px}.ledger-row .amount{grid-column:2;text-align:left}.strip{gap:3px}.unit{font-size:11px;padding:8px 0}.metrics{gap:22px}.metric b{font-size:38px}}.hero{background:#284b55}.surface .grid>div{border-left:4px solid #739da6;padding-left:18px}#current{border-top:2px solid #b5d3d8;margin-top:22px;padding-top:20px}#current .big{font-size:clamp(28px,5vw,44px)}</style></head><body style="--bg:#eef4f5;--accent:#346c78"><main><header><div class="kicker">Supplied quantities · no measurement implied</div><h1>Energy conversion record</h1><p class="muted">Name the energy unit and calorie definition before converting through joules.</p></header><section class="hero"><div class="kicker">Worked record E01 · separate from your calculator</div><div class="big">250 Wh = 0.25 kWh</div><p>250 × 3,600 = 900,000 J = 0.9 MJ</p></section><section class="panel"><form id="form" novalidate><label for="quantity">Energy quantity · 0 to 1,000,000,000<input id="quantity" value="250" inputmode="decimal" autocomplete="off"></label><div class="grid" style="margin-top:18px"><label for="from">Source energy unit<select id="from"><option value="">Choose an energy unit</option><option value="J">J · joule</option><option value="kJ">kJ · kilojoule</option><option value="MJ">MJ · megajoule</option><option value="Wh">Wh · watt-hour</option><option value="kWh">kWh · kilowatt-hour</option><option value="cal_th">cal_th · thermochemical calorie</option><option value="cal_IT">cal_IT · International Table calorie</option></select></label><label for="to">Destination energy unit<select id="to"><option value="">Choose an energy unit</option><option value="J">J · joule</option><option value="kJ">kJ · kilojoule</option><option value="MJ">MJ · megajoule</option><option value="Wh">Wh · watt-hour</option><option value="kWh">kWh · kilowatt-hour</option><option value="cal_th">cal_th · thermochemical calorie</option><option value="cal_IT">cal_IT · International Table calorie</option></select></label></div><p id="origin" class="muted">Manual input · up to six fractional digits</p><div class="actions"><button>Calculate</button><button type="button" id="swap" class="secondary" disabled>Swap units</button><button type="button" id="reset" class="secondary">Reset</button></div></form><p id="error" class="error" role="alert"></p><div id="current" hidden aria-live="polite"><h2>Your conversion</h2><div id="answer" class="big"></div><p id="precision"></p></div><p id="swapReason" class="muted"></p></section><section class="surface"><h2>Definition comparison · one named calorie</h2><div class="grid"><div><b>Thermochemical calorie</b><p>1 cal_th = 4.184 J</p></div><div><b>International Table calorie</b><p>1 cal_IT = 4.1868 J</p></div></div><p>Difference: 0.0028 J per named unit.</p></section><section class="panel"><h2>Your factor and provenance record</h2><pre id="trace"></pre></section><details><summary>Accepted quantities and precision</summary><p>Only J, kJ, MJ, Wh, kWh, cal_th and cal_IT are accepted. Generic calorie needs its source definition. W and kW are power, so this converter cannot turn them into energy without a separate duration-based task. No duration is assumed.</p><p>Manual input accepts 0–1,000,000,000, up to six fractional digits, with outside whitespace trimmed and raw text retained. Numeric signs, commas and exponents are rejected. Outputs use at most six decimal places and identify rounding; tiny positives are shown below 0.000001 rather than exact zero. Internal rational values preserve the selected printed factors. Swap keeps that unrounded quantity separately from typed text, and is disabled outside the source range.</p><p>No meter import, nutrition interpretation, BTU/eV, tariff, cost, emissions, or savings. <a href="https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors/nist-guide-si-appendix-b9">NIST selected energy factors</a></p></details><footer>Local session only · No network or saved progress. Keep maintained source records authoritative.</footer></main><script>const $=id=>document.getElementById(id);const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
function gcd(a,b){return b?gcd(b,a%b):a}function rat(n,d=1n){if(d<=0n||n<0n)throw Error('Nonnegative finite quantity required.');const g=gcd(n,d);return {n:n/g,d:d/g}}function times(a,b){return rat(a.n*b.n,a.d*b.d)}function divide(a,b){if(!b.n)throw Error('Zero factor.');return rat(a.n*b.d,a.d*b.n)}function exactDecimal(s){const [a,b='']=s.split('.');return rat(BigInt(a+b),10n**BigInt(b.length))}function manual(raw,max){const s=raw.trim();if(!/^[0-9]+(?:[.][0-9]{1,6})?$/.test(s)||s.length>30)throw Error('Enter a nonnegative dot-decimal number with up to six places; blank, signs, commas and exponents are invalid.');const r=exactDecimal(s);if(r.n>BigInt(max)*r.d)throw Error('Manual quantity exceeds '+max+'.');return r}function format(r,p=6){const scale=10n**BigInt(p),q=(r.n*scale*2n+r.d)/(2n*r.d),s=q.toString().padStart(p+1,'0'),text=(p?s.slice(0,-p)+'.'+s.slice(-p):s).replace(/([.][0-9]*?)0+$/,'$1').replace(/[.]$/,'');return {text:r.n>0n&&!q?'<'+(1/Number(scale)).toFixed(p):text,approx:r.n*scale%r.d!==0n}}function within(r,max){return r.n<=BigInt(max)*r.d}
const factors={J:'1',kJ:'1000',MJ:'1000000',Wh:'3600',kWh:'3600000',cal_th:'4.184',cal_IT:'4.1868'},labels={J:'J',kJ:'kJ',MJ:'MJ',Wh:'Wh',kWh:'kWh',cal_th:'thermochemical calorie (cal_th)',cal_IT:'International Table calorie (cal_IT)'};let record=null,computed=null;
function factor(id){if(!(Object.hasOwn(factors,id))){if(['W','kW'].includes(id))throw Error('W and kW are power, not energy. Supply an energy quantity; no duration is assumed.');if(['cal','calorie','Calorie'].includes(id))throw Error('Calorie definition unresolved: choose thermochemical or International Table.');throw Error('Choose a supported energy unit.')}return exactDecimal(factors[id])}function convert(r,from,to){const a=factor(from),b=factor(to),joules=times(r,a);return {input:r,from,to,joules,result:divide(joules,b)}}
function clear(){record=null;$('current').hidden=true;$('trace').textContent='';$('error').textContent='';$('swap').disabled=true;$('swapReason').textContent='Calculate a valid record to enable Swap.'}function changed(){computed=null;$('origin').textContent='Manual input · up to six fractional digits';clear()}
function run(){try{const r=computed||manual($('quantity').value,1000000000);if(!within(r,1000000000))throw Error('Calculated quantity exceeds source range.');record=convert(r,$('from').value,$('to').value);const f=format(record.result);$('answer').textContent=f.text+' '+labels[record.to];$('precision').textContent=f.approx?'Approximate display · up to six places; internal value remains unrounded.':'Exact arithmetic using the selected printed factors; no measurement accuracy implied.';$('trace').textContent='Raw field text: '+$('quantity').value+'\nInput origin: '+(computed?'Calculated, unrounded internal quantity':'Manual supplied quantity')+'\nSource: '+labels[record.from]+'\nTarget: '+labels[record.to]+'\nSource factor: '+factors[record.from]+' J/unit\nTarget factor: '+factors[record.to]+' J/unit\nInput exact ratio: '+r.n+'/'+r.d+'\nJoule intermediate: '+record.joules.n+'/'+record.joules.d+' J\nResult exact ratio: '+record.result.n+'/'+record.result.d+'\nDerivation: input × source factor ÷ target factor\nFactor source: '+"https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors/nist-guide-si-appendix-b9";$('current').hidden=false;$('error').textContent='';$('swap').disabled=!within(record.result,1000000000);$('swapReason').textContent=$('swap').disabled?'Swap unavailable: calculated quantity exceeds 1,000,000,000 in the new source unit.':'Swap uses this record’s unrounded result, never the formatted text.'}catch(e){clear();$('error').textContent=e.message}}
$('form').addEventListener('submit',e=>{e.preventDefault();run()});$('quantity').addEventListener('input',changed);['from','to'].forEach(x=>$(x).addEventListener('change',changed));$('swap').onclick=()=>{if(!record||!within(record.result,1000000000))return;const old=record;computed=old.result;$('quantity').value=format(computed,12).text;$('from').value=old.to;$('to').value=old.from;$('origin').textContent='Calculated input · stored unrounded ratio '+computed.n+'/'+computed.d;run()};$('reset').onclick=()=>{computed=null;$('quantity').value='';$('from').value='';$('to').value='';clear();$('error').textContent='';$('swapReason').textContent='';$('origin').textContent='Manual input · up to six fractional digits'};clear();</script>
<script>
// Local calculation controls: no native form submission or sandbox permissions required.
(()=>{const form=document.getElementById('form');if(!form)throw Error('Calculation form missing');const dispatch=()=>form.dispatchEvent(new Event('submit',{bubbles:true,cancelable:true}));const buttons=[...form.querySelectorAll('button')].filter(button=>button.type==='submit');if(buttons.length!==1)throw Error('Expected one calculation control');for(const button of buttons){button.type='button';button.addEventListener('click',dispatch);}form.addEventListener('keydown',event=>{if(event.key==='Enter'&&!event.isComposing&&['INPUT','SELECT'].includes(event.target.tagName)){event.preventDefault();dispatch();}});})();
</script>
</body></html>