import {countries,provinces,personal,corporate,sources,reviewed} from './data.mjs'; import {amount,percentage,progressive,sales,company} from './engine.mjs'; const $=s=>document.querySelector(s); const form=$('#tax-form');let mode='income';let activeScope='',activePeriod=''; const escape=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const country=()=>countries.find(c=>c.code===$('#country').value); const money=n=>new Intl.NumberFormat('en',{style:'currency',currency:country().currency,maximumFractionDigits:2}).format(n); const select=(id,label,options)=>`
`; const rateField=()=>'

Confirm the rate with the authority. This is arithmetic using your rate, not an automatic tax determination.

'; $('#country').innerHTML=''+countries.filter(c=>!c.eu).map(c=>``).join('')+''+countries.filter(c=>c.eu).map(c=>``).join('')+''; $('#country').value='AU'; function clearResult(){ $('#result').innerHTML='

Your calculation

Make the numbers clear.

Confirm the scope and calculate to see a breakdown.

'; $('#error').textContent=''; } function configure(){ clearResult();$('#confirm').checked=false; const c=country(),data=(mode==='income'?personal:corporate)[c.code];let options='',links=[];let available=true; if(mode==='sales'){ activePeriod='Rate snapshot reviewed 21 September 2026 · current transactions only'; activeScope='Domestic transactions only. You must confirm the place of supply and product classification. Excludes imports, cross-border/reverse-charge transactions, special territories, excise duties, tax credits and registration rules.'; if(c.eu){ options+=select('rate-choice','VAT treatment',[['standard',`Standard VAT — ${c.vat}%`],['custom','Reduced / special rate — enter verified rate']]); options+=rateField();links.push(['European Commission VAT rates (source updated 13 July 2026)',sources.euVAT],['National tax rules and special territories',sources.euTax]); activeScope+=' Standard rate only is preset. Regional exceptions and reduced-rate eligibility are not determined. Do not use the national standard rate for special territories.'; }else if(c.code==='CA'){ options+=select('province','Place of supply — province / territory',provinces.map(p=>[p[0],p[1]])); options+=select('rate-choice','Treatment',[['standard','Ordinary supply subject to GST/HST and PST/QST'],['custom','Special / reduced treatment — enter verified combined rate']]);options+=rateField(); links.push(['CRA GST/HST and provincial rate table',sources.caSales]); activeScope+=' Provincial and federal amounts use the same pre-tax base. Product-specific PST/QST exemptions are not determined.'; }else if(c.code==='AU'){ options+=select('rate-choice','GST treatment',[['standard','Ordinary taxable supply — 10% GST'],['custom','Other treatment — enter verified rate']]);options+=rateField();links.push(['Australian Government GST guidance',sources.auSales]); }else if(c.code==='IN'){ options+=select('rate-choice','GST treatment',[['18','Standard rate — 18%'],['5','Merit rate — 5%'],['40','Special de-merit rate — 40%'],['custom','Other verified rate']]); options+=select('supply','Supply type',[['intra','Within the same state — CGST + SGST'],['inter','Between states — IGST']]);options+=rateField();links.push(['Government of India GST reform announcement',sources.inSales]); activeScope+=' These are rate presets, not an HSN/SAC classification service. Special goods, valuation rules and additional cesses are excluded.'; }else{ options+=rateField();links.push(['US state tax authority directory',sources.usSales]); activeScope='US sales tax has no single nationwide rate. This mode only performs arithmetic with the combined state/local rate YOU enter. It does not look up an address, establish nexus, determine exemptions or validate a rate. Check the destination jurisdiction and product before using it.'; } options+=select('price-mode','The entered amount is',[['exclusive','Before tax — add tax'],['inclusive','Including tax — extract tax']]); $('#amount-label').textContent=`Transaction amount (${c.currency})`;$('#amount-help').textContent='Use the transaction currency shown. This tool does not convert currencies.'; }else if(data){ activePeriod=data.period;activeScope=data.note;links.push(['Official rules for this calculation',data.source]); options=select('profile',mode==='income'?'Supported taxpayer profile':'Supported company profile',data.profiles.map(p=>[p.id,p.label])); $('#amount-label').textContent=mode==='income'?`Annual taxable income (${c.currency})`:`Eligible taxable profit (${c.currency})`; $('#amount-help').textContent=mode==='income'?'Use taxable income after deductions. Do not enter gross salary or subtract deductions twice.':'Use taxable profit after permitted deductions, not revenue or turnover. Eligibility must already be established.'; }else{ available=false;activePeriod='National rules not yet verified in this calculator'; activeScope=`${c.name} ${mode==='income'?'personal income':'company'} tax is not available yet. Regional rules, deductions and reliefs have not been implemented and verified. No numerical estimate will be shown. Use the official national tax database below.`; links.push(['European Commission — national tax rules',sources.euTax]); } $('#options').innerHTML=options; $('#period').textContent=activePeriod;$('#scope').textContent=activeScope; $('#amount').closest('.tax-field').hidden=!available;$('#amount').disabled=!available; $('.tax-confirm').hidden=!available;$('#confirm').disabled=!available;$('#calculate').disabled=!available; $('#sources').innerHTML=links.map(([label,url])=>`
  • ${escape(label)} ↗
  • `).join(''); const stale=Date.now()-Date.parse(reviewed)>90*86400000; $('#reviewed').textContent=`Source review: ${reviewed}. ${stale?'This snapshot is over 90 days old. Recheck the authority before relying on it.':'Each result uses the tax period shown above.'}`; if(!available)$('#result').innerHTML='

    Coverage

    Not available yet.

    No tax amount has been calculated. Follow the official source below for this country.

    '; updateCustom(); } function updateCustom(){const el=$('#custom-wrap');if(!el)return;const visible=!$('#rate-choice')||$('#rate-choice').value==='custom';el.hidden=!visible;$('#custom-rate').disabled=!visible;} function fieldRow(label,value){return `
    ${escape(label)}${escape(value)}
    `;} form.addEventListener('submit',e=>{ e.preventDefault();$('#error').textContent=''; try{ if(!form.reportValidity())return; if(!$('#confirm').checked)throw new Error('Confirm that your circumstances match the supported scope.'); const c=country(),value=amount($('#amount').value);let title='',total=0,body=''; if(mode==='sales'){ const custom=$('#custom-rate')&&!$('#custom-rate').disabled; let rates,labels; if(custom){rates=[percentage($('#custom-rate').value)];labels=['Tax using your supplied rate'];} else if(c.eu){rates=[c.vat];labels=['Standard VAT'];} else if(c.code==='CA'){const p=provinces.find(p=>p[0]===$('#province').value);rates=[p[2],p[3]];labels=['GST / HST',p[0]==='QC'?'QST':'PST'];} else if(c.code==='AU'){rates=[10];labels=['GST'];} else if(c.code==='IN'){const rate=percentage($('#rate-choice').value);rates=$('#supply').value==='intra'?[rate/2,rate/2]:[rate];labels=rates.length===2?['CGST','SGST / UTGST']:['IGST'];} else throw new Error('Enter your verified combined tax rate.'); const result=sales(value,rates,$('#price-mode').value==='inclusive');total=result.total;title=custom?'Tax at your supplied rate':'Estimated transaction tax'; body=fieldRow('Price before tax',money(result.base))+result.rows.map((r,i)=>fieldRow(`${labels[i]} (${r.rate}%)`,money(r.tax))).join('')+fieldRow('Price including tax',money(result.gross)); body+='

    Rounded to two decimal places. Invoice-level rounding or special valuation rules can differ.

    '; }else{ const data=(mode==='income'?personal:corporate)[c.code]; if(!data)throw new Error('This country and tax type are not supported yet.'); const p=data.profiles.find(p=>p.id===$('#profile').value);if(!p)throw new Error('Choose a supported profile.'); if(mode==='income'){ const r=progressive(value,p.bands);total=r.total;title='Basic bracket tax only'; body=fieldRow('Taxable income entered',money(value))+fieldRow('Bracket tax / taxable income',`${value?(total/value*100).toFixed(2):'0.00'}%`); body+='
    '+r.rows.filter(r=>r.base>0).map(r=>``).join('')+'
    Tax by income band
    Band starts atRateTax
    ${money(r.lower)}${r.rate}%${money(r.tax)}
    '; body+='

    Before the adjustments listed below. This is not total tax or take-home pay.

    '; }else{ const r=company(value,p);total=r.total;title='Estimated company tax component'; body=fieldRow('Eligible taxable profit',money(value))+fieldRow(`Basic tax (${p.rate}%)`,money(r.basic)); if(p.surcharge)body+=fieldRow(`Surcharge (${p.surcharge}% of basic tax)`,money(r.surcharge)); if(p.cess)body+=fieldRow(`Cess (${p.cess}% of tax + surcharge)`,money(r.cess)); } } $('#result').innerHTML=`

    ${escape(c.name)} · ${escape(activePeriod)}

    ${title}

    ${money(total)}${body}

    Included / excluded
    ${escape(activeScope)}

    `; }catch(err){clearResult();$('#error').textContent=err.message;} }); $('#country').addEventListener('change',()=>{$('#amount').value='';configure();}); form.addEventListener('input',e=>{if(e.target.id!=='country')clearResult();}); $('#options').addEventListener('change',()=>{updateCustom();clearResult();$('#confirm').checked=false;}); const tabs=[...document.querySelectorAll('[data-mode]')]; function activate(tab){mode=tab.dataset.mode;tabs.forEach(t=>{const on=t===tab;t.setAttribute('aria-selected',String(on));t.tabIndex=on?0:-1;});$('#tax-panel').setAttribute('aria-labelledby',tab.id);$('#amount').value='';configure();} tabs.forEach((tab,i)=>{tab.addEventListener('click',()=>activate(tab));tab.addEventListener('keydown',e=>{let n;if(e.key==='ArrowRight')n=(i+1)%tabs.length;else if(e.key==='ArrowLeft')n=(i+tabs.length-1)%tabs.length;else if(e.key==='Home')n=0;else if(e.key==='End')n=tabs.length-1;else return;e.preventDefault();tabs[n].focus();activate(tabs[n]);});}); configure();