⚠️ This is a guidance estimate only. Customs authorities, carriers and brokers decide the final classification, duty, tax, fees and admissibility.
`;
}
async function init(){
const selCountry = $('pp-country-select');
const selOrigin = $('pp-origin-select');
if(selCountry){
selCountry.innerHTML = '';
const sorted = countryList.slice().sort((a,b)=>a[1].localeCompare(b[1]));
sorted.forEach(([slug,name])=> selCountry.append(new Option(name, slug)));
selCountry.value = countryParam;
selCountry.addEventListener('change', e => renderCountry(e.target.value, true));
}
if(selOrigin){
selOrigin.innerHTML = '';
selOrigin.append(new Option('Any / MFN', ''));
countryList.slice().sort((a,b)=>a[1].localeCompare(b[1])).forEach(([slug,name])=> selOrigin.append(new Option(name, slug)));
selOrigin.value = originParam;
selOrigin.addEventListener('change', e => renderOrigin(e.target.value, true));
}
['hs_origin','hs_dest'].forEach(id=>{ const el = $(id); if(el) el.addEventListener('input',()=>{el.dataset.touched='1';}); });
try{ DEMINIMIS_MAP = await loadDeminimisSheet(); }catch(e){ DEMINIMIS_MAP = {}; }
try{ CUSTOMS_DATA = await loadCustomsFromSheet(); }catch(e){ CUSTOMS_DATA = {countries:{}}; }
try{ TARIFF_RULES = await loadTariffsFromSheet(); }catch(e){ TARIFF_RULES = []; }
await loadHS();
renderCountry(countryParam, false);
renderOrigin(originParam, false);
const hsInput = $('pp-hs-search');
if(hsInput) hsInput.addEventListener('input', computeHSRates);
}
const ddp = $('pp-ddp');
const ddu = $('pp-ddu');
const ddText = $('pp-dd-text');
function setMode(mode){
if(!ddp || !ddu || !ddText) return;
if(mode==='ddp'){
ddp.classList.add('pp-btn-blue'); ddu.classList.remove('pp-btn-blue');
ddText.innerHTML = '
DDP: sender prepays duties/taxes where supported. This can reduce delivery refusals and surprise charges for recipients.';
}else{
ddu.classList.add('pp-btn-blue'); ddp.classList.remove('pp-btn-blue');
ddText.innerHTML = '
DAP/DDU: receiver pays duties/taxes on delivery. Upfront cost is lower, but there is more risk of delays, refusals or extra contact from the carrier.';
}
}
if(ddp && ddu){ ddp.addEventListener('click',()=>setMode('ddp')); ddu.addEventListener('click',()=>setMode('ddu')); setMode('ddu'); }
const guessBtn = $('hs_guess_btn');
if(guessBtn){
guessBtn.addEventListener('click', async ()=>{
const box = $('hs_keyword');
const q = (box?.value||'').trim();
if(!q){ alert('Enter a commodity keyword first.'); return; }
try{
const r = await fetch('https://hts.usitc.gov/api/search?q=' + encodeURIComponent(q));
const j = await r.json();
const first = (j && j.response && j.response.docs && j.response.docs[0]) || null;
if(first && first.hscode) $('hs_code').value = String(first.hscode).replace(/\s+/g,'');
else alert('No suggestion found. Please enter HS6 manually.');
}catch(err){ alert('Keyword lookup is not available here. Please enter HS6 manually.'); }
});
}
const estimateBtn = $('hs_estimate_btn');
if(estimateBtn){
estimateBtn.addEventListener('click', async ()=>{
const origin = ($('hs_origin')?.value||'').toUpperCase().trim();
const dest = ($('hs_dest')?.value||'').toUpperCase().trim();
const hs6 = ($('hs_code')?.value||'').replace(/\D/g,'').slice(0,6);
const valStr = $('hs_value')?.value;
const wtStr = $('hs_weight')?.value;
const basis = $('hs_basis')?.value || 'CIF';
const payer = $('hs_payer')?.value || 'Recipient';
const result = $('hs_result');
if(!origin || !dest){ alert('Enter origin and destination ISO3.'); return; }
if(!hs6){ alert('Please enter a 6-digit HS code or use Suggest.'); return; }
if(result) result.innerHTML = '
Calculating estimate…
';
const data = await loadAllData();
const t = tariffFor(origin, dest, hs6, data.tariffs);
const adval = (t && t.adval!=null) ? Number(t.adval) : null;
const specPerKg = parseSpecificPerKg(t && t.specific);
const dm = deMinimis(dest, data.dm);
const vatPct = vatPercent(dest, data.vat);
const declared = Number(valStr||0);
const shipping = 0, insurance = 0;
const customsValue = (basis === 'CIF') ? (declared + shipping + insurance) : declared;
let duty = 0;
if(!(declared 0 ? specPerKg * Number(wtStr||0) : 0);
let vat = 0;
if(!(declared