(function(){ 'use strict'; const $ = id => document.getElementById(id); const form = $('paint-form'); if (!form || !window.SCT) return; function updateMode(){ const mode = $('project-type').value; const roomLabel = $('room-count-label'); roomLabel.textContent = mode === 'exterior' ? 'Number of identical wall sections' : 'Number of identical rooms'; $('ceiling-wrap').hidden = mode === 'exterior'; if (mode === 'exterior') $('include-ceiling').checked = false; } function calculate(event){ if (event) event.preventDefault(); SCT.showError($('paint-error'), ''); const length = SCT.positive($('length').value); const width = SCT.positive($('width').value); const height = SCT.positive($('height').value); const rooms = Math.max(1, SCT.integer($('rooms').value, 1)); const coats = Math.max(1, SCT.integer($('coats').value, 1)); const doors = SCT.integer($('doors').value); const windows = SCT.integer($('windows').value); const coverage = SCT.positive($('coverage').value, 350); const waste = SCT.positive($('waste').value); const price = SCT.positive($('price').value); const includeCeiling = $('include-ceiling').checked; const includePrimer = $('include-primer').checked; const primerCoverage = SCT.positive($('primer-coverage').value, 300); const primerPrice = SCT.positive($('primer-price').value); if (!length || !width || !height || !coverage){ SCT.showError($('paint-error'), 'Enter positive room dimensions and paint coverage.'); return; } const wallAreaSingle = 2 * (length + width) * height; const openingAreaSingle = (doors * 20) + (windows * 15); const wallPaintableSingle = Math.max(0, wallAreaSingle - openingAreaSingle); const ceilingAreaSingle = includeCeiling ? length * width : 0; const baseArea = (wallPaintableSingle + ceilingAreaSingle) * rooms; const coatedArea = baseArea * coats; const adjustedArea = coatedArea * (1 + waste / 100); const exactGallons = adjustedArea / coverage; const gallonsToBuy = Math.ceil(exactGallons); const primerArea = includePrimer ? baseArea * (1 + waste / 100) : 0; const exactPrimerGallons = includePrimer && primerCoverage ? primerArea / primerCoverage : 0; const primerGallonsToBuy = Math.ceil(exactPrimerGallons); const paintCost = gallonsToBuy * price; const primerCost = primerGallonsToBuy * primerPrice; const totalCost = paintCost + primerCost; const wholeGallons = Math.floor(exactGallons); const remainderQuarts = Math.ceil((exactGallons - wholeGallons) * 4); const shoppingPaint = gallonsToBuy <= 1 ? SCT.plural(gallonsToBuy, 'gallon') : `${SCT.plural(gallonsToBuy, 'gallon')} of finish paint`; SCT.setText('paint-main-result', SCT.plural(gallonsToBuy, 'gallon')); SCT.setText('exact-paint', `${SCT.format(exactGallons, 2)} gal`); SCT.setText('paint-area', `${SCT.format(adjustedArea, 0)} ft²`); SCT.setText('primer-result', includePrimer ? SCT.plural(primerGallonsToBuy, 'gallon') : 'Not included'); SCT.setText('paint-cost', price ? SCT.money(paintCost) : '—'); SCT.setText('primer-cost', includePrimer && primerPrice ? SCT.money(primerCost) : '—'); SCT.setText('total-cost', (price || primerPrice) ? SCT.money(totalCost) : '—'); SCT.setText('base-area', `${SCT.format(baseArea, 0)} ft²`); SCT.setText('coated-area', `${SCT.format(coatedArea, 0)} ft²`); SCT.setText('waste-result', `${SCT.format(waste, 0)}%`); SCT.setText('coverage-result', `${SCT.format(coverage, 0)} ft²/gal`); SCT.setText('shopping-list', includePrimer ? `Buy ${shoppingPaint} and ${SCT.plural(primerGallonsToBuy, 'gallon')} of primer.` : `Buy ${shoppingPaint}.`); SCT.setText('quart-option', exactGallons < 1 ? `Small project option: about ${Math.max(1, remainderQuarts)} quart${remainderQuarts === 1 ? '' : 's'} before rounding to full gallons.` : `Calculated use before purchase rounding: ${wholeGallons} gallon${wholeGallons === 1 ? '' : 's'}${remainderQuarts ? ` plus about ${remainderQuarts} quart${remainderQuarts === 1 ? '' : 's'}` : ''}.`); $('paint-results').removeAttribute('hidden'); } function loadExample(){ const values = { 'project-type':'interior','length':'14','width':'12','height':'8','rooms':'2','coats':'2', 'doors':'1','windows':'2','coverage':'350','waste':'10','price':'39.99', 'primer-coverage':'300','primer-price':'29.99' }; Object.entries(values).forEach(([id,value]) => { $(id).value = value; }); $('include-ceiling').checked = true; $('include-primer').checked = true; updateMode(); calculate(); } form.addEventListener('submit', calculate); $('project-type').addEventListener('change', updateMode); $('example-btn').addEventListener('click', loadExample); $('reset-btn').addEventListener('click', () => SCT.reset(form, () => { updateMode(); calculate(); })); $('print-btn').addEventListener('click', SCT.print); updateMode(); calculate(); })();