(function () {
  'use strict';

  var root = document.getElementById('hppCalculator');
  if (!root) return;

  var STORAGE_KEY = 'putrigrafika_hpp_calculator_sheet_v2';
  var definitions = [
    {
      id: 'raw',
      title: 'Rincian Penggunaan Bahan Baku',
      color: '#326985',
      soft: '#d6ebf8',
      rows: [
        ['Duplex 250 gsm 90 x 120 cm', 1262, 3200],
        ['Pisau Pond', 1, 250000],
        ['Laminasi', 10000, 230],
        ['Spot UV', 10000, 250],
        ['Emboss', 0, 0],
        ['Lem Samping / Folding Glue', 10000, 100]
      ]
    },
    {
      id: 'operational',
      title: 'Biaya Operasional & Tenaga Kerja',
      color: '#587f03',
      soft: '#f0f8e6',
      rows: [
        ['Cetak SM52 1 set (2.000 Druck)', 1, 350000],
        ['Druck Berikutnya (SM52)', 8100, 95],
        ['Biaya Pond 1 set (2.000 Druck)', 1, 70000],
        ['Druck Berikutnya (Pond)', 8100, 40],
        ['Lain-Lain', 1, 200000]
      ]
    }
  ];

  var state = { sections: clone(definitions), paperMode: 'auto' };
  var saveTimer;
  var rupiah = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, maximumFractionDigits: 0 });
  var number = new Intl.NumberFormat('id-ID', { maximumFractionDigits: 2 });

  function clone(value) {
    return JSON.parse(JSON.stringify(value));
  }

  function numeric(value) {
    if (typeof value === 'number') {
      return Number.isFinite(value) && value > 0 ? value : 0;
    }
    var normalized = String(value || '')
      .replace(/\s/g, '')
      .replace(/\./g, '')
      .replace(',', '.')
      .replace(/[^\d.-]/g, '');
    var parsed = Number(normalized);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
  }

  function formatNumericValue(value) {
    var parsed = numeric(value);
    return parsed ? number.format(parsed) : '';
  }

  function formatNumericInput(input) {
    var raw = String(input.value || '').replace(/[^\d,]/g, '');
    var parts = raw.split(',');
    var integer = (parts.shift() || '').replace(/\D/g, '').replace(/^0+(?=\d)/, '');
    var decimal = parts.join('').replace(/\D/g, '').slice(0, 2);
    if (!integer && decimal) integer = '0';
    var grouped = integer.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
    input.value = grouped + (raw.indexOf(',') !== -1 ? ',' + decimal : '');
  }

  function formatAllNumericInputs() {
    root.querySelectorAll('[data-number-format]').forEach(function (input) {
      input.value = formatNumericValue(input.value);
    });
  }

  function escapeHtml(value) {
    return String(value || '').replace(/[&<>"']/g, function (character) {
      return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[character];
    });
  }

  function currency(value) {
    return rupiah.format(value);
  }

  function cleanDimension(value) {
    return parseFloat(Number(value).toFixed(2)).toString();
  }

  function parseDimensions(value) {
    var matches = String(value || '').replace(/,/g, '.').match(/\d+(?:\.\d+)?/g);
    if (!matches || matches.length < 2) return null;
    var width = parseFloat(matches[0]);
    var height = parseFloat(matches[1]);
    return width > 0 && height > 0 ? { width: width, height: height } : null;
  }

  function fitCount(areaSize, pieceSize) {
    return pieceSize > 0 && areaSize >= pieceSize ? Math.floor(areaSize / pieceSize) : 0;
  }

  function paperGrid(area, pieceWidth, pieceHeight, type, startNo, forcedCols, forcedRows) {
    var cols = typeof forcedCols === 'number' ? forcedCols : fitCount(area.width, pieceWidth);
    var rows = typeof forcedRows === 'number' ? forcedRows : fitCount(area.height, pieceHeight);
    var pieces = [];
    var no = startNo;
    for (var row = 0; row < rows; row++) {
      for (var col = 0; col < cols; col++) {
        pieces.push({
          x: area.x + col * pieceWidth,
          y: area.y + row * pieceHeight,
          width: pieceWidth,
          height: pieceHeight,
          type: type,
          no: no++
        });
      }
    }
    return { pieces: pieces, count: pieces.length };
  }

  function uniformPaperLayout(settings, orientation) {
    var landscape = orientation === 'landscape';
    var pieceWidth = landscape ? settings.cutHeight : settings.cutWidth;
    var pieceHeight = landscape ? settings.cutWidth : settings.cutHeight;
    var grid = paperGrid(
      { x: 0, y: 0, width: settings.planoWidth, height: settings.planoHeight },
      pieceWidth,
      pieceHeight,
      orientation,
      1
    );
    return {
      mode: orientation,
      label: landscape ? 'Lanskap Saja (Grid Mendatar)' : 'Potret Saja (Grid Tegak)',
      pieces: grid.pieces,
      count: grid.count
    };
  }

  function mixedPaperVertical(settings, firstType) {
    var area = { x: 0, y: 0, width: settings.planoWidth, height: settings.planoHeight };
    var first = firstType === 'landscape'
      ? { width: settings.cutHeight, height: settings.cutWidth, type: 'landscape' }
      : { width: settings.cutWidth, height: settings.cutHeight, type: 'portrait' };
    var second = firstType === 'landscape'
      ? { width: settings.cutWidth, height: settings.cutHeight, type: 'portrait' }
      : { width: settings.cutHeight, height: settings.cutWidth, type: 'landscape' };
    var maxCols = fitCount(area.width, first.width);
    var best = null;
    for (var cols = 1; cols <= maxCols; cols++) {
      var firstWidth = cols * first.width;
      var left = paperGrid(area, first.width, first.height, first.type, 1, cols);
      var remainingWidth = area.width - firstWidth;
      var right = remainingWidth > 0
        ? paperGrid({ x: firstWidth, y: 0, width: remainingWidth, height: area.height }, second.width, second.height, second.type, left.count + 1)
        : { pieces: [], count: 0 };
      var candidate = {
        mode: 'mixed',
        label: 'Auto Campur (Kombinasi Vertikal)',
        pieces: left.pieces.concat(right.pieces),
        count: left.count + right.count
      };
      if (!best || candidate.count > best.count) best = candidate;
    }
    return best;
  }

  function mixedPaperHorizontal(settings, firstType) {
    var area = { x: 0, y: 0, width: settings.planoWidth, height: settings.planoHeight };
    var first = firstType === 'landscape'
      ? { width: settings.cutHeight, height: settings.cutWidth, type: 'landscape' }
      : { width: settings.cutWidth, height: settings.cutHeight, type: 'portrait' };
    var second = firstType === 'landscape'
      ? { width: settings.cutWidth, height: settings.cutHeight, type: 'portrait' }
      : { width: settings.cutHeight, height: settings.cutWidth, type: 'landscape' };
    var maxRows = fitCount(area.height, first.height);
    var best = null;
    for (var rows = 1; rows <= maxRows; rows++) {
      var firstHeight = rows * first.height;
      var top = paperGrid(area, first.width, first.height, first.type, 1, null, rows);
      var remainingHeight = area.height - firstHeight;
      var bottom = remainingHeight > 0
        ? paperGrid({ x: 0, y: firstHeight, width: area.width, height: remainingHeight }, second.width, second.height, second.type, top.count + 1)
        : { pieces: [], count: 0 };
      var candidate = {
        mode: 'mixed',
        label: 'Auto Campur (Kombinasi Horizontal)',
        pieces: top.pieces.concat(bottom.pieces),
        count: top.count + bottom.count
      };
      if (!best || candidate.count > best.count) best = candidate;
    }
    return best;
  }

  function bestPaperLayout(settings, mode) {
    if (mode === 'portrait') return uniformPaperLayout(settings, 'portrait');
    if (mode === 'landscape') return uniformPaperLayout(settings, 'landscape');
    var candidates = [
      uniformPaperLayout(settings, 'portrait'),
      uniformPaperLayout(settings, 'landscape'),
      mixedPaperVertical(settings, 'portrait'),
      mixedPaperVertical(settings, 'landscape'),
      mixedPaperHorizontal(settings, 'portrait'),
      mixedPaperHorizontal(settings, 'landscape')
    ].filter(Boolean);
    return candidates.reduce(function (best, candidate) {
      return !best || candidate.count > best.count ? candidate : best;
    }, null);
  }

  function syncPaperModeUI() {
    var labels = { auto: 'Otomatis', portrait: 'Potret', landscape: 'Lanskap' };
    root.querySelectorAll('.hpp-paper-mode-btn').forEach(function (button) {
      button.classList.toggle('is-active', button.dataset.paperMode === state.paperMode);
    });
    document.getElementById('hppMapModeBadge').textContent = labels[state.paperMode] || labels.auto;
  }

  function drawPaperMap(settings, layout) {
    var svg = document.getElementById('hppPaperMap');
    if (!svg) return;
    var ns = 'http://www.w3.org/2000/svg';
    svg.setAttribute('viewBox', '0 0 ' + settings.planoWidth + ' ' + settings.planoHeight);
    svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
    svg.innerHTML = '';

    var defs = document.createElementNS(ns, 'defs');
    var pattern = document.createElementNS(ns, 'pattern');
    pattern.setAttribute('id', 'hppWastePattern');
    pattern.setAttribute('patternUnits', 'userSpaceOnUse');
    pattern.setAttribute('width', '6');
    pattern.setAttribute('height', '6');
    pattern.setAttribute('patternTransform', 'rotate(45)');
    var line = document.createElementNS(ns, 'line');
    line.setAttribute('x1', '0');
    line.setAttribute('y1', '0');
    line.setAttribute('x2', '0');
    line.setAttribute('y2', '6');
    line.setAttribute('stroke', '#f43f5e');
    line.setAttribute('stroke-width', '0.35');
    line.setAttribute('opacity', '0.34');
    pattern.appendChild(line);
    defs.appendChild(pattern);
    svg.appendChild(defs);

    var paper = document.createElementNS(ns, 'rect');
    paper.setAttribute('x', '0');
    paper.setAttribute('y', '0');
    paper.setAttribute('width', settings.planoWidth);
    paper.setAttribute('height', settings.planoHeight);
    paper.setAttribute('fill', 'url(#hppWastePattern)');
    paper.setAttribute('stroke', '#f43f5e');
    paper.setAttribute('stroke-width', '0.65');
    paper.setAttribute('stroke-dasharray', '2 1.5');
    svg.appendChild(paper);

    layout.pieces.forEach(function (piece) {
      var landscape = piece.type === 'landscape';
      var rect = document.createElementNS(ns, 'rect');
      rect.setAttribute('x', piece.x);
      rect.setAttribute('y', piece.y);
      rect.setAttribute('width', piece.width);
      rect.setAttribute('height', piece.height);
      rect.setAttribute('fill', landscape ? 'rgba(244,63,94,.09)' : 'rgba(79,70,229,.09)');
      rect.setAttribute('stroke', landscape ? '#f43f5e' : '#4f46e5');
      rect.setAttribute('stroke-width', '0.55');
      svg.appendChild(rect);

      var minSide = Math.min(piece.width, piece.height);
      if (layout.count <= 30 && minSide >= 7) {
        var label = document.createElementNS(ns, 'text');
        label.setAttribute('x', piece.x + piece.width / 2);
        label.setAttribute('y', piece.y + piece.height / 2);
        label.setAttribute('text-anchor', 'middle');
        label.setAttribute('dominant-baseline', 'middle');
        label.setAttribute('fill', landscape ? '#e11d48' : '#4f46e5');
        label.setAttribute('font-size', Math.max(2.5, Math.min(10, minSide * 0.28)));
        label.setAttribute('font-weight', '800');
        label.textContent = piece.no;
        svg.appendChild(label);
      }
    });
  }

  function updatePaperMap() {
    syncPaperModeUI();
    var cut = parseDimensions(document.getElementById('hppCutSize').value);
    var plano = parseDimensions(document.getElementById('hppPlanoSize').value);
    var yieldInput = document.getElementById('hppYield');
    var info = document.getElementById('hppMapInfo');
    if (!cut || !plano) {
      yieldInput.value = '';
      document.getElementById('hppMapPieces').textContent = '–';
      document.getElementById('hppMapUsed').textContent = '–';
      document.getElementById('hppMapWaste').textContent = '–';
      document.getElementById('hppMapWasteArea').textContent = 'periksa format ukuran';
      document.getElementById('hppMapTitle').textContent = 'Layout belum dapat dihitung';
      document.getElementById('hppPaperMap').innerHTML = '';
      info.textContent = 'Gunakan format lebar × tinggi, misalnya 41 × 28 untuk ukuran potong dan 90 × 120 untuk ukuran plano.';
      info.classList.add('is-error');
      return;
    }

    var settings = {
      cutWidth: cut.width,
      cutHeight: cut.height,
      planoWidth: plano.width,
      planoHeight: plano.height
    };
    var layout = bestPaperLayout(settings, state.paperMode);
    var planoArea = plano.width * plano.height;
    var usedArea = cut.width * cut.height * layout.count;
    var usedPercent = planoArea ? usedArea / planoArea * 100 : 0;
    var wasteArea = Math.max(0, planoArea - usedArea);
    var wastePercent = planoArea ? wasteArea / planoArea * 100 : 0;

    yieldInput.value = layout.count;
    document.getElementById('hppMapPieces').textContent = layout.count;
    document.getElementById('hppMapUsed').textContent = number.format(usedPercent) + '%';
    document.getElementById('hppMapWaste').textContent = number.format(wastePercent) + '%';
    document.getElementById('hppMapWasteArea').textContent = 'sisa ' + number.format(Math.round(wasteArea)) + ' cm²';
    document.getElementById('hppMapTitle').textContent = layout.count ? layout.label : 'Ukuran potong belum muat';
    document.getElementById('hppMapCutSize').textContent = 'Potong: ' + cleanDimension(cut.width) + ' x ' + cleanDimension(cut.height) + ' cm';
    document.getElementById('hppMapPlanoSize').textContent = 'Plano: ' + cleanDimension(plano.width) + ' x ' + cleanDimension(plano.height) + ' cm';
    var modeDescription = state.paperMode === 'auto'
      ? 'Layout memilih orientasi atau kombinasi dengan hasil terbanyak.'
      : (state.paperMode === 'portrait' ? 'Layout dipaksa menggunakan orientasi potret saja.' : 'Layout dipaksa menggunakan orientasi lanskap saja.');
    info.textContent = layout.count
      ? modeDescription + ' Satu lembar plano menghasilkan ' + layout.count + ' potongan dengan pemanfaatan area ' + number.format(usedPercent) + '%.'
      : 'Ukuran potong lebih besar daripada bidang plano dan belum dapat ditempatkan.';
    info.classList.toggle('is-error', layout.count === 0);
    drawPaperMap(settings, layout);
  }

  function updatePlanoSimulation() {
    var target = Math.max(0, numeric(document.getElementById('hppPrintRun').value));
    var piecesPerPlano = Math.max(0, numeric(document.getElementById('hppYield').value));
    var planoNeeded = target > 0 && piecesPerPlano > 0 ? Math.ceil(target / piecesPerPlano) : 0;
    var capacity = planoNeeded * piecesPerPlano;
    var excess = Math.max(0, capacity - target);

    document.getElementById('hppPlanoTarget').textContent = number.format(target) + ' pcs';
    document.getElementById('hppPlanoNeeded').textContent = planoNeeded
      ? 'BUTUH ' + number.format(planoNeeded) + ' PLANO'
      : 'BELUM DAPAT DIHITUNG';
    document.getElementById('hppPlanoSimulationInfo').textContent = planoNeeded
      ? '1 plano menghasilkan ' + number.format(piecesPerPlano) + ' pcs. ' +
        number.format(planoNeeded) + ' plano menyediakan ' + number.format(capacity) +
        ' pcs' + (excess ? ', lebih ' + number.format(excess) + ' pcs dari target.' : ', tepat sesuai target.')
      : 'Masukkan total oplah dan ukuran kertas yang valid.';
  }

  function renderSections() {
    document.getElementById('hppCostSections').innerHTML = state.sections.map(function (section) {
      var rows = section.rows.map(function (row) {
        var qtyValue = numeric(row[1]) ? numeric(row[1]) : '';
        var costValue = numeric(row[2]) ? numeric(row[2]) : '';
        return '<tr>' +
          '<td><input class="hpp-row-name" type="text" value="' + escapeHtml(row[0]) + '" aria-label="Nama produk"></td>' +
          '<td><input class="hpp-row-qty" type="text" inputmode="decimal" data-number-format="decimal" value="' + formatNumericValue(qtyValue) + '" aria-label="Kuantitas"></td>' +
          '<td><input class="hpp-row-cost" type="text" inputmode="decimal" data-number-format="decimal" value="' + formatNumericValue(costValue) + '" aria-label="Biaya per unit"></td>' +
          '<td class="hpp-row-total"></td>' +
          '<td><button type="button" class="hpp-remove-row no-print" title="Hapus baris" aria-label="Hapus baris"><i class="fa fa-times"></i></button></td>' +
          '</tr>';
      }).join('');
      var componentCount = section.rows.filter(function (row) { return String(row[0] || '').trim() !== ''; }).length;
      return '<section class="hpp-cost-section" data-section="' + section.id + '" style="--section-color:' + section.color + ';--section-soft:' + section.soft + '">' +
        '<header class="hpp-cost-header"><span class="hpp-cost-title"><i></i><span><strong>' + section.title + '</strong><small>' + componentCount + ' komponen biaya</small></span></span>' +
        '<button type="button" class="hpp-add-row no-print" title="Tambah komponen" aria-label="Tambah komponen ' + section.title + '"><i class="fa fa-plus"></i><span>Tambah</span></button></header>' +
        '<div class="hpp-cost-table-wrap"><table class="hpp-cost-table"><colgroup><col><col><col><col><col></colgroup>' +
        '<thead><tr><th>Nama Produk</th><th>Qty.</th><th>Cost<br>(per unit)</th><th>Total Cost</th><th></th></tr></thead>' +
        '<tbody>' + rows + '</tbody></table></div>' +
        '<footer class="hpp-cost-total"><span>TOTAL</span><strong>Rp 0</strong></footer></section>';
    }).join('');
    formatAllNumericInputs();
    calculate();
  }

  function syncRows() {
    root.querySelectorAll('.hpp-cost-section').forEach(function (element) {
      var section = state.sections.find(function (item) { return item.id === element.dataset.section; });
      section.rows = Array.prototype.map.call(element.querySelectorAll('tbody tr'), function (row) {
        return [
          row.querySelector('.hpp-row-name').value,
          numeric(row.querySelector('.hpp-row-qty').value),
          numeric(row.querySelector('.hpp-row-cost').value)
        ];
      });
    });
  }

  function calculate() {
    syncRows();
    var totals = { raw: 0, operational: 0 };
    root.querySelectorAll('.hpp-cost-section').forEach(function (sectionElement) {
      var id = sectionElement.dataset.section;
      var componentCount = 0;
      sectionElement.querySelectorAll('tbody tr').forEach(function (row) {
        var qty = numeric(row.querySelector('.hpp-row-qty').value);
        var cost = numeric(row.querySelector('.hpp-row-cost').value);
        var rowTotal = qty * cost;
        var hasName = row.querySelector('.hpp-row-name').value.trim() !== '';
        if (hasName) componentCount++;
        row.querySelector('.hpp-row-total').textContent = rowTotal ? currency(rowTotal) : (hasName ? '-' : '');
        totals[id] += rowTotal;
      });
      var componentLabel = sectionElement.querySelector('.hpp-cost-title small');
      if (componentLabel) componentLabel.textContent = componentCount + ' komponen biaya';
      sectionElement.querySelector('.hpp-cost-total strong').textContent = currency(totals[id]);
    });

    var production = numeric(document.getElementById('hppProductionQty').value);
    var margin = numeric(document.getElementById('hppMargin').value);
    var grand = totals.raw + totals.operational;
    var perPiece = production ? grand / production : 0;
    var profitPerPiece = perPiece * margin / 100;
    var selling = perPiece + profitPerPiece;
    var totalProfit = profitPerPiece * production;
    var rawPercent = grand ? totals.raw / grand * 100 : 0;
    var operationalPercent = grand ? totals.operational / grand * 100 : 0;

    document.getElementById('hppSellingPrice').textContent = currency(selling);
    document.getElementById('hppPerPiece').textContent = currency(perPiece);
    document.getElementById('hppProfitPerPiece').textContent = currency(profitPerPiece);
    document.getElementById('hppGrandTotal').textContent = currency(grand);
    document.getElementById('hppMarginSummary').textContent = number.format(margin) + '%';
    document.getElementById('hppTotalProfit').textContent = currency(totalProfit);
    document.getElementById('hppTotalSelling').textContent = currency(grand + totalProfit);
    document.getElementById('hppDonutTotal').textContent = currency(grand);
    document.getElementById('hppRawAmount').textContent = currency(totals.raw);
    document.getElementById('hppOperationalAmount').textContent = currency(totals.operational);
    document.getElementById('hppRawPercent').textContent = Math.round(rawPercent) + '%';
    document.getElementById('hppOperationalPercent').textContent = Math.round(operationalPercent) + '%';
    document.getElementById('hppPie').style.background = 'conic-gradient(from -90deg,#4f7f00 0 ' + operationalPercent.toFixed(3) + '%,#0878bd ' + operationalPercent.toFixed(3) + '% 100%)';
    updatePlanoSimulation();
    queueSave();
  }

  function collectState() {
    syncRows();
    var ids = ['hppProductName','hppFinishedSize','hppMaterial','hppFinishing','hppPrintSize','hppPrintYieldNote','hppCutSize','hppPlanoSize','hppYield','hppPrintRun','hppProductionQty','hppMargin'];
    var fields = {};
    ids.forEach(function (id) { fields[id] = document.getElementById(id).value; });
    return { fields: fields, sections: state.sections, paperMode: state.paperMode };
  }

  function queueSave() {
    window.clearTimeout(saveTimer);
    saveTimer = window.setTimeout(function () {
      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(collectState())); } catch (error) {}
    }, 250);
  }

  function loadSaved() {
    try {
      var saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
      if (!saved || !saved.fields || !Array.isArray(saved.sections) || saved.sections.length !== 2) return;
      state.sections = saved.sections;
      state.sections.forEach(function (section) {
        section.rows = section.rows.filter(function (row) {
          return String(row[0] || '').trim() !== '' || numeric(row[1]) || numeric(row[2]);
        });
      });
      if (['auto', 'portrait', 'landscape'].indexOf(saved.paperMode) !== -1) {
        state.paperMode = saved.paperMode;
      }
      Object.keys(saved.fields).forEach(function (id) {
        var input = document.getElementById(id);
        if (input) input.value = saved.fields[id];
      });
    } catch (error) {
      state.sections = clone(definitions);
    }
  }

  function setupImageInput(input) {
    input.addEventListener('change', function () {
      var file = input.files && input.files[0];
      if (!file) return;
      if (file.size > 4 * 1024 * 1024) {
        window.alert('Ukuran gambar maksimal 4 MB.');
        input.value = '';
        return;
      }
      var preview = input.closest('.hpp-image-panel').querySelector('img');
      var panel = input.closest('.hpp-image-panel');
      var reader = new FileReader();
      reader.onload = function (event) {
        preview.src = event.target.result;
        panel.classList.add('is-filled');
      };
      reader.readAsDataURL(file);
    });
  }

  root.addEventListener('input', function (event) {
    if (!event.target.matches('input')) return;
    if (event.target.matches('[data-number-format]')) {
      formatNumericInput(event.target);
    }
    if (event.target.id === 'hppCutSize' || event.target.id === 'hppPlanoSize') {
      updatePaperMap();
    }
    calculate();
  });

  root.addEventListener('click', function (event) {
    var paperMode = event.target.closest('.hpp-paper-mode-btn');
    if (paperMode) {
      state.paperMode = paperMode.dataset.paperMode;
      updatePaperMap();
      calculate();
      return;
    }
    var add = event.target.closest('.hpp-add-row');
    if (add) {
      syncRows();
      var sectionId = add.closest('.hpp-cost-section').dataset.section;
      var section = state.sections.find(function (item) { return item.id === sectionId; });
      section.rows.push(['', 0, 0]);
      renderSections();
      return;
    }
    var remove = event.target.closest('.hpp-remove-row');
    if (remove) {
      remove.closest('tr').remove();
      calculate();
      return;
    }
    var imageButton = event.target.closest('.hpp-image-button');
    if (imageButton) {
      document.getElementById(imageButton.dataset.input).click();
      return;
    }
    var imageReset = event.target.closest('.hpp-image-reset');
    if (imageReset) {
      var imagePanel = imageReset.closest('.hpp-image-panel');
      document.getElementById(imageReset.dataset.preview).src = imageReset.dataset.default;
      imagePanel.querySelector('input').value = '';
      imagePanel.classList.remove('is-filled');
    }
  });

  document.getElementById('hppReset').addEventListener('click', function () {
    if (!window.confirm('Reset seluruh isi HPP Calculator ke template awal?')) return;
    localStorage.removeItem(STORAGE_KEY);
    window.location.reload();
  });
  document.getElementById('hppPrint').addEventListener('click', function () { window.print(); });
  root.querySelectorAll('.hpp-image-input').forEach(setupImageInput);

  loadSaved();
  updatePaperMap();
  renderSections();
}());
