Denne hjemmeside er en Beta-version

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Campaign Exposure Calculator</title>
  <script src="/_sdk/element_sdk.js"></script>
  <script src="https://cdn.tailwindcss.com"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;600;700;800&amp;display=swap" rel="stylesheet">
  <style>
    body {
      box-sizing: border-box;
    }
    
    * {
      box-sizing: border-box;
    }
  </style>
  <style>@view-transition { navigation: auto; }</style>
  <script src="/_sdk/data_sdk.js" type="text/javascript"></script>
 </head>
 <body class="min-h-full flex items-center justify-center p-8">
  <div class="w-full max-w-4xl">
   <div id="calculator-card" class="rounded-2xl shadow-2xl p-8"><!-- Logo Section -->
    <div class="flex justify-center mb-6"><img src="https://usercontent.one/wp/syntesedigital.dk/wp-content/uploads/2025/01/Orange.png?media=1769522210" alt="Syntese Digital Logo" style="max-width: 200px; height: auto;">
    </div>
    <h1 id="calculator-title" class="text-3xl font-bold text-center mb-8"></h1>
    <div class="space-y-6"><!-- Customer Information Section -->
     <div id="customer-info-section" class="p-6 rounded-xl border-2">
      <h2 class="text-xl font-bold mb-4">Kundeoplysninger</h2>
      <div class="grid grid-cols-2 gap-4 mb-4">
       <div><label for="company-name" class="block text-sm font-semibold mb-2">Firmanavn</label> <input type="text" id="company-name" placeholder="Indtast firmanavn" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
       <div><label for="address" class="block text-sm font-semibold mb-2">Adresse</label> <input type="text" id="address" placeholder="Indtast adresse" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div>
      <div class="grid grid-cols-2 gap-4 mb-4">
       <div><label for="cvr" class="block text-sm font-semibold mb-2">CVR</label> <input type="text" id="cvr" placeholder="Indtast CVR" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
       <div><label for="contact-person" class="block text-sm font-semibold mb-2">Kontaktperson</label> <input type="text" id="contact-person" placeholder="Indtast kontaktperson" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div>
      <div class="grid grid-cols-2 gap-4 mb-4">
       <div><label for="email" class="block text-sm font-semibold mb-2">E-mail</label> <input type="email" id="email" placeholder="Indtast e-mail" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
       <div><label for="website" class="block text-sm font-semibold mb-2">Hjemmeside</label> <input type="text" id="website" placeholder="Indtast hjemmeside" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div>
      <div class="grid grid-cols-2 gap-4">
       <div><label for="phone" class="block text-sm font-semibold mb-2">Telefonnummer</label> <input type="tel" id="phone" placeholder="Indtast telefonnummer" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
       <div><label for="mobile" class="block text-sm font-semibold mb-2">Mobilnummer</label> <input type="tel" id="mobile" placeholder="Indtast mobilnummer" class="w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div>
     </div>
     <div id="products-container" class="space-y-4"><!-- Products will be added here dynamically -->
     </div><button id="add-product-button" class="w-full py-3 rounded-lg font-semibold transition-all hover:opacity-90 active:scale-95 flex items-center justify-center gap-2"> <span class="text-2xl">+</span> <span>Tilføj Produkt</span> </button>
     <div id="price-container" class="mt-6 p-6 rounded-xl">
      <h3 class="text-lg font-bold mb-4 text-center">Pris Oversigt</h3>
      <div id="products-summary" class="space-y-2 mb-4"><!-- Product summaries will be added here -->
      </div>
      <div class="border-t-2 pt-3 space-y-3">
       <div class="flex justify-between items-center"><span class="font-bold">Samlede Eksponeringer:</span> <span id="total-exposures" class="font-bold text-xl">0 visninger</span>
       </div>
       <div class="flex justify-between items-center text-sm opacity-60"><span>Normalpris (Listepris):</span> <span id="normal-price" class="line-through">kr 0</span>
       </div>
       <div class="flex justify-between items-center"><span class="text-sm font-semibold">Rabat:</span> <span id="discount-amount" class="font-bold text-lg text-green-600">kr 0</span>
       </div>
       <div class="border-t-2 pt-3 flex justify-between items-center"><span class="font-bold">Din pris (ekskl. Tech Fee):</span> <span id="total-price" class="font-bold text-xl">kr 0</span>
       </div>
       <div class="flex justify-between items-center text-sm opacity-80"><span>Tech Fee (13,5%):</span> <span id="vat-amount">kr 0</span>
       </div>
       <div class="border-t-2 pt-3 flex justify-between items-center"><span class="font-bold">Total pris (inkl. Tech Fee):</span> <span id="grand-total" class="font-bold text-xl">kr 0</span>
       </div>
      </div>
     </div><!-- Disclaimer Section -->
     <div id="disclaimer-section" class="p-4 rounded-lg text-xs">
      <p class="font-semibold mb-2">Forretnings- og betalingsbetingelser:</p>
      <p class="opacity-90 mb-2">For aftaler over 6 måneder, faktureres Tech fee og de første 3 måneder upfront. Efterfølgende faktureres man månedligt forud. For aftaler under 6 måneder, faktureres hele beløbet upfront. Banner produktion betales upfront.</p>
      <p class="opacity-90">Der henvises til vores forretningsbetingelser: <a href="https://syntesedigital.dk/forretningsbetingelser" target="_blank" rel="noopener noreferrer" class="underline hover:opacity-70">syntesedigital.dk/forretningsbetingelser</a></p>
     </div><!-- Comments Section -->
     <div><label for="comments" class="block text-sm font-semibold mb-2">Kommentarer / Særaftaler</label>
      <div id="payment-summary" class="mb-3 p-3 rounded-lg text-sm font-semibold" style="background: #374151; color: #ffffff;"><!-- Payment summary will be inserted here -->
      </div><textarea id="comments" rows="4" placeholder="Indtast eventuelle kommentarer eller særaftaler..." class="w-full px-4 py-3 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm resize-none">Kampagnen vises på Top 30 sites med mindre andet er aftalt.</textarea>
     </div><!-- Date Section -->
     <div><label for="contract-date" class="block text-sm font-semibold mb-2">Dato for aftale</label> <input type="date" id="contract-date" class="w-full px-4 py-3 rounded-lg border-2 focus:outline-none focus:ring-2 text-lg">
     </div><!-- Signature Section -->
     <div id="signature-section" class="p-6 rounded-xl border-2">
      <h2 class="text-xl font-bold mb-4">Underskrifter</h2>
      <p class="text-xs mb-6 opacity-75 leading-relaxed">Kunden bekræfter med sin underskrift at være berettiget til tegning af aftalen, og at informationerne i kontrakten er korrekte. Kunden bekræfter ligeledes at have modtaget og forstået forretningsbetingelser og accepterer hermed disse. Alle priser er angivet ekskl. moms.</p><!-- Seller Signature -->
      <div class="mb-6"><label class="block text-sm font-semibold mb-2">På vegne af Syntese Digital ApS</label>
       <canvas id="seller-signature" class="w-full border-2 rounded-lg cursor-crosshair" style="height: 120px; background: white;"></canvas><button id="clear-seller" class="mt-2 text-xs px-3 py-1 rounded hover:opacity-80">Ryd</button>
       <div class="mt-3"><label for="seller-name" class="block text-xs font-semibold mb-1">Navn</label> <input type="text" id="seller-name" placeholder="Indtast navn" class="w-full px-3 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div><!-- Customer Signature -->
      <div><label class="block text-sm font-semibold mb-2">Kunde Underskrift</label>
       <canvas id="customer-signature" class="w-full border-2 rounded-lg cursor-crosshair" style="height: 120px; background: white;"></canvas><button id="clear-customer" class="mt-2 text-xs px-3 py-1 rounded hover:opacity-80">Ryd</button>
       <div class="mt-3"><label for="customer-name-sig" class="block text-xs font-semibold mb-1">Kundens Navn</label> <input type="text" id="customer-name-sig" placeholder="Indtast navn" class="w-full px-3 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm">
       </div>
      </div>
     </div>
     <div class="grid grid-cols-2 gap-4"><button id="download-pdf-button" class="py-3 rounded-lg font-semibold transition-all hover:opacity-90 active:scale-95"> 📄 Download PDF </button> <button id="reset-button" class="py-3 rounded-lg font-semibold transition-all hover:opacity-90 active:scale-95"> 🔄 Nulstil </button>
     </div>
    </div>
   </div>
  </div>
  <script>
    const defaultConfig = {
      background_color: "#f0f4f8",
      card_color: "#ffffff",
      primary_color: "#3b82f6",
      text_color: "#1e293b",
      accent_color: "#f97316",
      font_family: "Raleway",
      font_size: 16,
      calculator_title: "Kampagne Aftale",
      budget_label: "Månedligt Budget",
      cmp_label: "CPM (Pris Per 1.000 Visninger)",
      result_label: "Samlede Eksponeringer"
    };

    let config = {};
    let products = [];
    let productIdCounter = 0;

    const campaignTypes = [
      { name: "Display Kampagne - DV360 - Standard Formater", cpm: 70, type: "campaign" },
      { name: "Display Kampagne - DV360 - Topscroll Formater", cpm: 100, type: "campaign" },
      { name: "Display Kampagne - DV360 - Midtscroll Formater", cpm: 100, type: "campaign" },
      { name: "Re-targeting Kampagne - DV360", cpm: 70, type: "campaign" },
      { name: "Youtube Kampagne - DV360", cpm: 100, type: "campaign" },
      { name: "Banner produktion - Standard formater", cpm: 0, listPrice: 3000, type: "production" },
      { name: "Banner produktion - High Impact formater", cpm: 0, listPrice: 5000, type: "production" }
    ];



    function createProduct() {
      const productId = productIdCounter++;
      const firstType = campaignTypes[0];
      const product = {
        id: productId,
        name: firstType.name,
        budget: firstType.type === 'production' ? (firstType.listPrice || 0) : 0,
        cpm: firstType.cpm,
        months: 1,
        quantity: 1,
        listPrice: firstType.listPrice || firstType.cpm,
        type: firstType.type
      };
      products.push(product);
      renderProducts();
      calculateTotals();
    }

    function removeProduct(productId) {
      products = products.filter(p => p.id !== productId);
      renderProducts();
      calculateTotals();
    }

    function updateProduct(productId, field, value) {
      const product = products.find(p => p.id === productId);
      if (product) {
        product[field] = value;
        calculateTotals();
      }
    }

    function renderProducts() {
      const container = document.getElementById('products-container');
      container.innerHTML = '';
      
      products.forEach(product => {
        const productDiv = document.createElement('div');
        productDiv.className = 'product-card p-6 rounded-xl border-2';
        productDiv.dataset.productId = product.id;
        
        const isProduction = product.type === 'production';
        
        productDiv.innerHTML = `
          <div class="flex justify-between items-center mb-4">
            <button class="remove-product-btn text-red-500 hover:text-red-700 font-bold text-xl" data-product-id="${product.id}">×</button>
          </div>
          
          <div class="space-y-4">
            <div>
              <label class="block text-sm font-semibold mb-2">Kampagnetype</label>
              <select 
                class="product-type-select w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2 text-sm font-semibold"
                data-product-id="${product.id}"
              >
                ${campaignTypes.map((type, index) => `
                  <option value="${index}" ${product.name === type.name ? 'selected' : ''}>
                    ${type.name}
                  </option>
                `).join('')}
              </select>
            </div>
            
            <div>
              <label class="block text-sm font-semibold mb-2">${isProduction ? 'Pris' : 'Månedligt Budget'}</label>
              <div class="relative">
                <span class="absolute left-4 top-1/2 transform -translate-y-1/2 text-lg font-semibold">kr</span>
                <input 
                  type="text" 
                  class="product-budget w-full pl-10 pr-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2"
                  value="${product.budget.toLocaleString('da-DK')}"
                  data-product-id="${product.id}"
                >
              </div>
            </div>
            
            ${isProduction ? `
            <div>
              <label class="block text-sm font-semibold mb-2">Antal</label>
              <input 
                type="number" 
                class="product-quantity w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2"
                min="1" 
                step="1"
                value="${product.quantity || 1}"
                data-product-id="${product.id}"
              >
              <div class="product-discount mt-2 p-2 rounded-lg text-center text-sm font-semibold" style="background: #10b981; color: white; display: none;">
                Rabat: 0%
              </div>
            </div>
            ` : ''}
            
            ${!isProduction ? `
            <div>
              <label class="block text-sm font-semibold mb-2">CPM (Pris Per 1.000 Visninger)</label>
              <div class="relative">
                <span class="absolute left-4 top-1/2 transform -translate-y-1/2 text-lg font-semibold">kr</span>
                <input 
                  type="text" 
                  class="product-cpm w-full pl-10 pr-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2"
                  value="${product.cpm.toLocaleString('da-DK')}"
                  data-product-id="${product.id}"
                >
              </div>
              <div class="product-discount mt-2 p-2 rounded-lg text-center text-sm font-semibold" style="background: #10b981; color: white; display: none;">
                Rabat: 0%
              </div>
            </div>
            
            <div>
              <label class="block text-sm font-semibold mb-2">Periode (måneder)</label>
              <input 
                type="number" 
                class="product-months w-full px-4 py-2 rounded-lg border-2 focus:outline-none focus:ring-2"
                min="1" 
                step="1"
                value="${product.months}"
                data-product-id="${product.id}"
              >
            </div>
            
            <div class="product-result p-4 rounded-lg text-center">
              <p class="text-sm font-semibold mb-1">Eksponeringer</p>
              <p class="text-2xl font-bold">0 visninger</p>
            </div>
            ` : ''}
          </div>
        `;
        
        container.appendChild(productDiv);
      });
      
      // Add event listeners
      document.querySelectorAll('.product-type-select').forEach(select => {
        select.addEventListener('change', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const selectedIndex = parseInt(e.target.value);
          const selectedType = campaignTypes[selectedIndex];
          const product = products.find(p => p.id === productId);
          if (product) {
            product.name = selectedType.name;
            product.cpm = selectedType.cpm;
            product.listPrice = selectedType.listPrice || selectedType.cpm;
            product.type = selectedType.type;
            
            // Set budget to list price for production items
            if (selectedType.type === 'production') {
              product.budget = selectedType.listPrice || 0;
            }
            
            // Re-render products to show/hide fields based on type
            renderProducts();
            calculateTotals();
          }
        });
      });
      
      document.querySelectorAll('.product-budget').forEach(input => {
        input.addEventListener('input', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const rawValue = e.target.value.replace(/\./g, '').replace(',', '.');
          const numValue = parseFloat(rawValue) || 0;
          updateProduct(productId, 'budget', numValue);
          e.target.value = numValue.toLocaleString('da-DK');
        });
        
        input.addEventListener('focus', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const product = products.find(p => p.id === productId);
          if (product && product.budget === 0) {
            e.target.value = '';
          }
        });
        
        input.addEventListener('blur', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const product = products.find(p => p.id === productId);
          if (product) {
            e.target.value = product.budget.toLocaleString('da-DK');
          }
        });
      });
      
      document.querySelectorAll('.product-cpm').forEach(input => {
        input.addEventListener('input', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const rawValue = e.target.value.replace(/\./g, '').replace(',', '.');
          const numValue = parseFloat(rawValue) || 0;
          updateProduct(productId, 'cpm', numValue);
          e.target.value = numValue.toLocaleString('da-DK');
        });
        
        input.addEventListener('focus', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const product = products.find(p => p.id === productId);
          if (product && product.cpm === 0) {
            e.target.value = '';
          }
        });
        
        input.addEventListener('blur', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          const product = products.find(p => p.id === productId);
          if (product) {
            e.target.value = product.cpm.toLocaleString('da-DK');
          }
        });
      });
      
      document.querySelectorAll('.product-months').forEach(input => {
        input.addEventListener('input', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          updateProduct(productId, 'months', parseInt(e.target.value) || 1);
        });
      });
      
      document.querySelectorAll('.product-quantity').forEach(input => {
        input.addEventListener('input', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          updateProduct(productId, 'quantity', parseInt(e.target.value) || 1);
        });
      });
      
      document.querySelectorAll('.remove-product-btn').forEach(btn => {
        btn.addEventListener('click', (e) => {
          const productId = parseInt(e.target.dataset.productId);
          removeProduct(productId);
        });
      });
      
      applyStylesToProducts();
    }

    function calculateTotals() {
      let totalExposures = 0;
      let totalPrice = 0;
      let totalNormalPrice = 0;
      let totalCampaignMonthlyPrice = 0;
      let totalProductionPrice = 0;
      let maxMonths = 0;
      
      const productsSummary = document.getElementById('products-summary');
      productsSummary.innerHTML = '';
      
      products.forEach(product => {
        const budget = product.budget;
        const cpm = product.cpm;
        const months = product.months;
        const quantity = product.quantity || 1;
        const listPrice = product.listPrice || 70;
        const isProduction = product.type === 'production';
        
        let exposures = 0;
        let productPrice = 0;
        let normalPriceForProduct = 0;
        
        if (isProduction) {
          // For production items, multiply by quantity
          productPrice = budget * quantity;
          normalPriceForProduct = listPrice * quantity;
          totalProductionPrice += productPrice;
        } else {
          // For campaign items, calculate based on CPM
          if (cpm > 0) {
            exposures = (budget / cpm) * 1000 * months;
          }
          totalExposures += exposures;
          productPrice = budget * months;
          normalPriceForProduct = (exposures / 1000) * listPrice;
          totalCampaignMonthlyPrice += budget;
          if (months > maxMonths) {
            maxMonths = months;
          }
        }
        
        totalPrice += productPrice;
        totalNormalPrice += normalPriceForProduct;
        
        // Update product result display
        const productCard = document.querySelector(`[data-product-id="${product.id}"]`);
        if (productCard) {
          const resultDiv = productCard.querySelector('.product-result p:last-child');
          if (resultDiv) {
            resultDiv.textContent = `${exposures.toLocaleString('en-US', { maximumFractionDigits: 0 })} visninger`;
          }
          
          // Update discount percentage - only show if there's a discount
          const discountDiv = productCard.querySelector('.product-discount');
          if (discountDiv) {
            const discountPercent = normalPriceForProduct > 0 ? ((normalPriceForProduct - productPrice) / normalPriceForProduct * 100) : 0;
            if (discountPercent > 0.01) {
              discountDiv.textContent = `Rabat: ${discountPercent.toFixed(0)}%`;
              discountDiv.style.display = 'block';
            } else {
              discountDiv.style.display = 'none';
            }
          }
        }
        
        // Add to summary
        if (!isProduction) {
          // Campaign items - show exposures
          if (exposures > 0) {
            const summaryItem = document.createElement('div');
            summaryItem.className = 'flex justify-between items-center text-sm';
            summaryItem.innerHTML = `
              <span>${product.name}:</span>
              <span>${exposures.toLocaleString('en-US', { maximumFractionDigits: 0 })} visninger</span>
            `;
            productsSummary.appendChild(summaryItem);
          }
        } else {
          // Production items - show price and discount
          const productDiscount = normalPriceForProduct - productPrice;
          const summaryItem = document.createElement('div');
          summaryItem.className = 'flex justify-between items-center text-sm';
          summaryItem.innerHTML = `
            <span>${product.name}:</span>
            <span>kr ${productPrice.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (Rabat: kr ${productDiscount.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })})</span>
          `;
          productsSummary.appendChild(summaryItem);
        }
      });
      
      const discountAmount = totalNormalPrice - totalPrice;
      const vatAmount = totalPrice * 0.135;
      const grandTotal = totalPrice + vatAmount;
      
      document.getElementById('total-exposures').textContent = `${totalExposures.toLocaleString('en-US', { maximumFractionDigits: 0 })} visninger`;
      
      const normalPriceElement = document.getElementById('normal-price').parentElement;
      const discountElement = document.getElementById('discount-amount').parentElement;
      
      // Only show discount lines if there's an actual discount (more than 1 kr)
      if (discountAmount > 1) {
        document.getElementById('normal-price').textContent = `kr ${totalNormalPrice.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
        document.getElementById('discount-amount').textContent = `kr ${discountAmount.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
        normalPriceElement.style.display = 'flex';
        discountElement.style.display = 'flex';
      } else {
        normalPriceElement.style.display = 'none';
        discountElement.style.display = 'none';
      }
      
      document.getElementById('total-price').textContent = `kr ${totalPrice.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
      document.getElementById('vat-amount').textContent = `kr ${vatAmount.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
      document.getElementById('grand-total').textContent = `kr ${grandTotal.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
      
      // Calculate payment summary
      const paymentSummary = document.getElementById('payment-summary');
      if (products.length > 0) {
        let upfrontPayment = 0;
        let monthlyPayment = 0;
        
        // Add production costs to upfront
        upfrontPayment += totalProductionPrice;
        
        // Calculate campaign payments
        if (maxMonths > 6) {
          // Over 6 months: Tech fee + first 3 months upfront, then monthly
          const techFee = totalPrice * 0.135;
          const first3Months = totalCampaignMonthlyPrice * 3;
          upfrontPayment += techFee + first3Months;
          monthlyPayment = totalCampaignMonthlyPrice;
        } else if (maxMonths > 0) {
          // Under 6 months: everything upfront
          upfrontPayment += totalCampaignMonthlyPrice * maxMonths + (totalCampaignMonthlyPrice * maxMonths * 0.135);
          monthlyPayment = 0;
        }
        
        let summaryText = '';
        if (upfrontPayment > 0) {
          summaryText += `Upfront betaling: kr ${upfrontPayment.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
        }
        if (monthlyPayment > 0) {
          if (summaryText) summaryText += '\n';
          summaryText += `Månedlig betaling: kr ${monthlyPayment.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
        }
        
        paymentSummary.textContent = summaryText || 'Tilføj produkter for at se betalingsoversigt';
        paymentSummary.style.whiteSpace = 'pre-line';
      } else {
        paymentSummary.textContent = 'Tilføj produkter for at se betalingsoversigt';
      }
    }

    function validateForm() {
      const requiredFields = [
        { id: 'company-name', label: 'Firmanavn' },
        { id: 'address', label: 'Adresse' },
        { id: 'cvr', label: 'CVR' },
        { id: 'contact-person', label: 'Kontaktperson' },
        { id: 'email', label: 'E-mail' },
        { id: 'phone', label: 'Telefonnummer' }
      ];
      
      const missingFields = [];
      const invalidFields = [];
      
      // Check required fields
      requiredFields.forEach(field => {
        const element = document.getElementById(field.id);
        const value = element.value.trim();
        
        // Remove any existing error styling
        element.style.borderColor = '#e5e7eb';
        element.style.boxShadow = 'none';
        
        if (!value) {
          missingFields.push(field.label);
          // Add error styling
          element.style.borderColor = '#ef4444';
          element.style.boxShadow = '0 0 0 3px rgba(239, 68, 68, 0.1)';
        }
      });
      
      // Check if at least one product exists
      if (products.length === 0) {
        missingFields.push('Mindst ét produkt');
      }
      
      return {
        isValid: missingFields.length === 0,
        missingFields: missingFields
      };
    }

    function showValidationError(missingFields) {
      // Create modal overlay
      const overlay = document.createElement('div');
      overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 10000;
      `;
      
      // Create modal content
      const modal = document.createElement('div');
      modal.style.cssText = `
        background: white;
        padding: 30px;
        border-radius: 12px;
        max-width: 500px;
        width: 90%;
        box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
        text-align: center;
      `;
      
      modal.innerHTML = `
        <div style="color: #ef4444; font-size: 48px; margin-bottom: 20px;">⚠️</div>
        <h3 style="color: #1e293b; margin: 0 0 15px 0; font-size: 24px;">Manglende oplysninger</h3>
        <p style="color: #64748b; margin: 0 0 20px 0; line-height: 1.6;">
          Du skal udfylde følgende felter før du kan downloade PDF'en:
        </p>
        <ul style="color: #ef4444; text-align: left; margin: 0 0 25px 0; padding-left: 20px;">
          ${missingFields.map(field => `<li style="margin-bottom: 5px;"><strong>${field}</strong></li>`).join('')}
        </ul>
        <button id="close-validation-modal" style="
          background: #3b82f6;
          color: white;
          border: none;
          padding: 12px 24px;
          border-radius: 8px;
          font-weight: bold;
          cursor: pointer;
          font-size: 16px;
          transition: all 0.2s;
        ">OK, jeg forstår</button>
      `;
      
      overlay.appendChild(modal);
      document.body.appendChild(overlay);
      
      // Add hover effect to button
      const closeBtn = modal.querySelector('#close-validation-modal');
      closeBtn.addEventListener('mouseenter', () => {
        closeBtn.style.background = '#2563eb';
      });
      closeBtn.addEventListener('mouseleave', () => {
        closeBtn.style.background = '#3b82f6';
      });
      
      // Close modal functionality
      function closeModal() {
        document.body.removeChild(overlay);
      }
      
      closeBtn.addEventListener('click', closeModal);
      overlay.addEventListener('click', (e) => {
        if (e.target === overlay) {
          closeModal();
        }
      });
      
      // Focus first missing field (if it's an input)
      setTimeout(() => {
        const firstMissingField = document.querySelector('input[style*="border-color: rgb(239, 68, 68)"]');
        if (firstMissingField) {
          firstMissingField.focus();
        }
      }, 100);
    }

    async function downloadPDF() {
      // Validate form before proceeding
      const validation = validateForm();
      if (!validation.isValid) {
        showValidationError(validation.missingFields);
        return;
      }
      
      // Show loading state
      const downloadButton = document.getElementById('download-pdf-button');
      const originalText = downloadButton.textContent;
      downloadButton.textContent = '⏳ Genererer PDF...';
      downloadButton.disabled = true;

      // Generate contract ID with company_cvr_date format
      const companyName = document.getElementById('company-name').value || 'FIRMA';
      const cvr = document.getElementById('cvr').value || 'CVR';
      const contractDate = document.getElementById('contract-date').value || new Date().toISOString().split('T')[0];
      
      // Clean company name and CVR for filename (remove spaces and special characters)
      const cleanCompanyName = companyName.replace(/[^a-zA-Z0-9æøåÆØÅ]/g, '').toUpperCase();
      const cleanCvr = cvr.replace(/[^0-9]/g, '');
      
      // Convert date from YYYY-MM-DD to DDMMYYYY format
      const dateParts = contractDate.split('-');
      const cleanDate = dateParts.length === 3 ? `${dateParts[2]}${dateParts[1]}${dateParts[0]}` : contractDate.replace(/-/g, '');
      
      const contractId = `${cleanCompanyName}_${cleanCvr}_${cleanDate}`;
      

      
      try {
        // Get all data
        const companyName = document.getElementById('company-name').value || 'N/A';
        const address = document.getElementById('address').value || 'N/A';
        const cvr = document.getElementById('cvr').value || 'N/A';
        const contactPerson = document.getElementById('contact-person').value || 'N/A';
        const email = document.getElementById('email').value || 'N/A';
        const website = document.getElementById('website').value || 'N/A';
        const phone = document.getElementById('phone').value || 'N/A';
        const mobile = document.getElementById('mobile').value || 'N/A';
        const totalExposures = document.getElementById('total-exposures').textContent;
        const normalPrice = document.getElementById('normal-price').textContent;
        const discountAmount = document.getElementById('discount-amount').textContent;
        const totalPrice = document.getElementById('total-price').textContent;
        const vatAmount = document.getElementById('vat-amount').textContent;
        const grandTotal = document.getElementById('grand-total').textContent;
        const comments = document.getElementById('comments').value || 'Ingen kommentarer';
        const sellerName = document.getElementById('seller-name').value || 'N/A';
        const customerNameSig = document.getElementById('customer-name-sig').value || 'N/A';
        const contractDate = document.getElementById('contract-date').value || new Date().toLocaleDateString('da-DK');
        const paymentSummary = document.getElementById('payment-summary').textContent;
        
        // Get signature images
        const sellerCanvas = document.getElementById('seller-signature');
        const customerCanvas = document.getElementById('customer-signature');
        const sellerSignature = sellerCanvas.toDataURL('image/png');
        const customerSignature = customerCanvas.toDataURL('image/png');
        
        // Check if there's a discount to show
        const totalDiscountAmount = parseFloat(discountAmount.replace('kr ', '').replace(/\./g, '').replace(',', '.'));
        const showDiscount = totalDiscountAmount > 1;
        
        // Build products HTML
        let productsHTML = '';
        products.forEach(product => {
          const isProduction = product.type === 'production';
          const quantity = product.quantity || 1;
          const exposures = !isProduction && product.cpm > 0 ? ((product.budget / product.cpm) * 1000 * product.months) : 0;
          const listPrice = product.listPrice || 70;
          const productPrice = isProduction ? product.budget * quantity : product.budget * product.months;
          const normalPrice = isProduction ? listPrice * quantity : (exposures / 1000) * listPrice;
          const discount = normalPrice - productPrice;
          const discountPercent = normalPrice > 0 ? ((discount / normalPrice) * 100) : 0;
          
          productsHTML += `
            <div style="margin-bottom: 20px; padding: 15px; border: 2px solid #e5e7eb; border-radius: 8px;">
              <h4 style="margin: 0 0 10px 0; color: #1e293b; font-size: 16px;">${product.name}</h4>
              ${isProduction ? `
                <p style="margin: 5px 0;"><strong>Pris:</strong> kr ${product.budget.toLocaleString('da-DK')}</p>
                <p style="margin: 5px 0;"><strong>Antal:</strong> ${quantity}</p>
                <p style="margin: 5px 0;"><strong>Listepris:</strong> kr ${listPrice.toLocaleString('da-DK')} pr. stk.</p>
                <p style="margin: 5px 0;"><strong>Total Listepris:</strong> kr ${normalPrice.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</p>
                ${discountPercent > 0.01 ? `<p style="margin: 5px 0; color: #10b981;"><strong>Rabat:</strong> ${discountPercent.toFixed(0)}% - Spar kr ${discount.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</p>` : ''}
              ` : `
                <p style="margin: 5px 0;"><strong>Månedligt Budget:</strong> kr ${product.budget.toLocaleString('da-DK')}</p>
                <p style="margin: 5px 0;"><strong>CPM:</strong> kr ${product.cpm.toLocaleString('da-DK')}</p>
                <p style="margin: 5px 0;"><strong>Listepris CPM:</strong> kr ${listPrice.toLocaleString('da-DK')}</p>
                <p style="margin: 5px 0;"><strong>Periode:</strong> ${product.months} måneder</p>
                ${discountPercent > 0.01 ? `<p style="margin: 5px 0; color: #10b981;"><strong>Rabat:</strong> ${discountPercent.toFixed(0)}% - Spar kr ${discount.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</p>` : ''}
                <p style="margin: 5px 0; color: #f97316;"><strong>Eksponeringer:</strong> ${exposures.toLocaleString('en-US', { maximumFractionDigits: 0 })} visninger</p>
              `}
            </div>
          `;
        });
        
        // Create HTML document
        const htmlContent = `<!DOCTYPE html>
<html lang="da">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kampagne Aftale - ${companyName}</title>
  <style>
    body {
      font-family: 'Raleway', Arial, sans-serif;
      max-width: 900px;
      margin: 0 auto;
      padding: 40px 20px;
      color: #1e293b;
      line-height: 1.6;
    }
    h1 {
      text-align: center;
      color: #1e293b;
      margin-bottom: 10px;
    }
    .subtitle {
      text-align: center;
      color: #64748b;
      margin-bottom: 10px;
    }
    .contract-id {
      text-align: center;
      color: #f97316;
      font-weight: bold;
      font-size: 14px;
      margin-bottom: 30px;
      padding: 8px 16px;
      background: #fef3e2;
      border-radius: 6px;
      display: inline-block;
      width: 100%;
      box-sizing: border-box;
    }
    .section {
      margin-bottom: 30px;
      padding: 20px;
      border: 2px solid #e5e7eb;
      border-radius: 8px;
    }
    .section h2 {
      margin-top: 0;
      color: #1e293b;
      border-bottom: 2px solid #f97316;
      padding-bottom: 10px;
    }
    .info-grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 15px;
    }
    .info-item {
      margin-bottom: 10px;
    }
    .info-item strong {
      display: block;
      color: #64748b;
      font-size: 14px;
      margin-bottom: 3px;
    }
    .price-summary {
      background: #f0f4f8;
      padding: 20px;
      border-radius: 8px;
      margin-top: 20px;
    }
    .price-row {
      display: flex;
      justify-content: space-between;
      margin: 10px 0;
      padding: 8px 0;
    }
    .price-row.total {
      border-top: 2px solid #1e293b;
      font-weight: bold;
      font-size: 18px;
      color: #3b82f6;
    }
    .signature-container {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 30px;
      margin-top: 20px;
    }
    .signature-box {
      text-align: center;
    }
    .signature-box img {
      width: 100%;
      max-width: 300px;
      height: 120px;
      border: none;
      margin: 10px 0;
    }
    .signature-line {
      border-top: 2px solid #1e293b;
      margin-top: 10px;
      padding-top: 5px;
    }
    .disclaimer {
      background: #64748b;
      color: white;
      padding: 15px;
      border-radius: 8px;
      font-size: 12px;
      margin-top: 20px;
    }
    .payment-info {
      background: #374151;
      color: white;
      padding: 15px;
      border-radius: 8px;
      margin: 15px 0;
      white-space: pre-line;
    }
    @media print {
      body {
        padding: 20px;
      }
      .no-print {
        display: none;
      }
    }
  </style>
</head>
<body>
  <h1>Kampagne Aftale</h1>
  <p class="subtitle">Syntese Digital ApS</p>
  <div class="contract-id">Kontrakt ID: ${contractId}</div>
  
  <div class="section">
    <h2>Kundeoplysninger</h2>
    <div class="info-grid">
      <div class="info-item">
        <strong>Firmanavn</strong>
        ${companyName}
      </div>
      <div class="info-item">
        <strong>Adresse</strong>
        ${address}
      </div>
      <div class="info-item">
        <strong>CVR</strong>
        ${cvr}
      </div>
      <div class="info-item">
        <strong>Kontaktperson</strong>
        ${contactPerson}
      </div>
      <div class="info-item">
        <strong>E-mail</strong>
        ${email}
      </div>
      <div class="info-item">
        <strong>Hjemmeside</strong>
        ${website}
      </div>
      <div class="info-item">
        <strong>Telefonnummer</strong>
        ${phone}
      </div>
      <div class="info-item">
        <strong>Mobilnummer</strong>
        ${mobile}
      </div>
    </div>
  </div>
  
  <div class="section">
    <h2>Produkter</h2>
    ${productsHTML}
  </div>
  
  <div class="section">
    <h2>Pris Oversigt</h2>
    <div class="price-summary">
      <div class="price-row">
        <span><strong>Samlede Eksponeringer:</strong></span>
        <span style="color: #f97316; font-weight: bold;">${totalExposures}</span>
      </div>
      ${showDiscount ? `
      <div class="price-row" style="font-size: 14px; opacity: 0.7;">
        <span>Normalpris (Listepris):</span>
        <span style="text-decoration: line-through;">${normalPrice}</span>
      </div>
      <div class="price-row">
        <span>Rabat:</span>
        <span style="color: #10b981; font-weight: bold;">${discountAmount}</span>
      </div>
      ` : ''}
      <div class="price-row">
        <span><strong>Din pris (ekskl. Tech Fee):</strong></span>
        <span><strong>${totalPrice}</strong></span>
      </div>
      <div class="price-row" style="font-size: 14px;">
        <span>Tech Fee (13,5%):</span>
        <span>${vatAmount}</span>
      </div>
      <div class="price-row total">
        <span style="color: #f97316;">Total pris (inkl. Tech Fee):</span>
        <span style="color: #f97316;">${grandTotal}</span>
      </div>
    </div>
    
    <div class="payment-info">
      ${paymentSummary}
    </div>
  </div>
  
  <div class="disclaimer">
    <p style="margin: 0 0 10px 0;"><strong>Forretnings- og betalingsbetingelser:</strong></p>
    <p style="margin: 0 0 10px 0;">For aftaler over 6 måneder, faktureres Tech fee og de første 3 måneder upfront. Efterfølgende faktureres man månedligt forud. For aftaler under 6 måneder, faktureres hele beløbet upfront. Banner produktion betales upfront.</p>
    <p style="margin: 0;">Der henvises til vores forretningsbetingelser: <a href="https://syntesedigital.dk/forretningsbetingelser" target="_blank" style="color: white; text-decoration: underline;">syntesedigital.dk/forretningsbetingelser</a></p>
  </div>
  
  <div class="section">
    <h2>Kommentarer / Særaftaler</h2>
    <p style="white-space: pre-wrap;">${comments}</p>
  </div>
  
  <div class="section">
    <h2>Dato for aftale</h2>
    <p><strong>${contractDate}</strong></p>
  </div>
  
  <div class="section">
    <h2>Underskrifter</h2>
    <p style="font-size: 12px; color: #64748b; margin-bottom: 20px;">
      Kunden bekræfter med sin underskrift at være berettiget til tegning af aftalen, og at informationerne i kontrakten er korrekte. Kunden bekræfter ligeledes at have modtaget og forstået forretningsbetingelser og accepterer hermed disse. Alle priser er angivet ekskl. moms.
    </p>
    
    <div class="signature-container">
      <div class="signature-box">
        <p><strong>På vegne af Syntese Digital ApS</strong></p>
        <img src="${sellerSignature}" alt="Sælger underskrift">
        <div class="signature-line">${sellerName}</div>
      </div>
      
      <div class="signature-box">
        <p><strong>Kunde Underskrift</strong></p>
        <img src="${customerSignature}" alt="Kunde underskrift">
        <div class="signature-line">${customerNameSig}</div>
      </div>
    </div>
  </div>
  
  <div class="no-print" style="text-align: center; margin-top: 40px; padding: 20px; background: #f0f4f8; border-radius: 8px;">
    <p style="margin-bottom: 0; font-weight: bold;">Tryk Ctrl+P (Windows) eller Cmd+P (Mac) for at gemme som PDF</p>
  </div>
  
  <p style="text-align: center; color: #94a3b8; font-size: 12px; margin-top: 40px;">
    Genereret af Syntese Digital Kampagne Aftale
  </p>
</body>
</html>
        `;
        
        // Open in new window
        const newWindow = window.open('', '_blank');
        if (newWindow) {
          newWindow.document.write(htmlContent);
          newWindow.document.close();
          
          // Show success message
          const successMsg = document.createElement('div');
          successMsg.style.cssText = 'position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #10b981; color: white; padding: 16px 24px; border-radius: 8px; z-index: 9999; font-weight: bold;';
          successMsg.textContent = '✅ PDF åbnet i nyt vindue - Tryk Ctrl+P for at gemme';
          document.body.appendChild(successMsg);
          setTimeout(() => successMsg.remove(), 4000);
        } else {
          // Show error if popup was blocked
          const errorMsg = document.createElement('div');
          errorMsg.style.cssText = 'position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #ef4444; color: white; padding: 16px 24px; border-radius: 8px; z-index: 9999; font-weight: bold;';
          errorMsg.textContent = '❌ Tillad pop-up vinduer i din browser';
          document.body.appendChild(errorMsg);
          setTimeout(() => errorMsg.remove(), 4000);
        }
      } catch (error) {
        console.error('Error generating PDF:', error);
        const errorMsg = document.createElement('div');
        errorMsg.style.cssText = 'position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #ef4444; color: white; padding: 16px 24px; border-radius: 8px; z-index: 9999; font-weight: bold;';
        errorMsg.textContent = '❌ Fejl ved generering af PDF';
        document.body.appendChild(errorMsg);
        setTimeout(() => errorMsg.remove(), 4000);
      } finally {
        // Reset button state
        downloadButton.textContent = originalText;
        downloadButton.disabled = false;
      }
    }



    function applyStylesToProducts() {
      const textColor = config.text_color || defaultConfig.text_color;
      const accentColor = config.accent_color || defaultConfig.accent_color;
      
      document.querySelectorAll('.product-card').forEach(card => {
        card.style.borderColor = '#e5e7eb';
        card.style.color = textColor;
      });
      
      document.querySelectorAll('.product-type-select').forEach(select => {
        select.style.borderColor = '#e5e7eb';
        select.style.color = textColor;
      });
      
      document.querySelectorAll('.product-budget, .product-cpm, .product-months').forEach(input => {
        input.style.borderColor = '#e5e7eb';
        input.style.color = textColor;
      });
      
      document.querySelectorAll('.product-result').forEach(result => {
        result.style.background = accentColor;
        result.style.color = '#ffffff';
      });
    }

    async function onConfigChange(newConfig) {
      const baseFont = newConfig.font_family || defaultConfig.font_family;
      const baseFontStack = 'Raleway, system-ui, -apple-system, sans-serif';
      const fontSize = newConfig.font_size || defaultConfig.font_size;
      
      document.body.style.background = newConfig.background_color || defaultConfig.background_color;
      document.body.style.fontFamily = `${baseFont}, ${baseFontStack}`;
      
      const card = document.getElementById('calculator-card');
      card.style.background = newConfig.card_color || defaultConfig.card_color;
      
      const title = document.getElementById('calculator-title');
      title.textContent = newConfig.calculator_title || defaultConfig.calculator_title;
      title.style.color = newConfig.text_color || defaultConfig.text_color;
      title.style.fontSize = `${fontSize * 1.875}px`;
      title.style.fontFamily = `${baseFont}, ${baseFontStack}`;
      
      const priceContainer = document.getElementById('price-container');
      priceContainer.style.background = newConfig.card_color || defaultConfig.card_color;
      priceContainer.style.borderColor = '#e5e7eb';
      priceContainer.style.borderWidth = '2px';
      priceContainer.style.borderStyle = 'solid';
      priceContainer.style.color = newConfig.text_color || defaultConfig.text_color;
      
      const resetButton = document.getElementById('reset-button');
      const accentColor = newConfig.accent_color || defaultConfig.accent_color;
      resetButton.style.background = accentColor + '33';
      resetButton.style.color = accentColor;
      resetButton.style.border = `2px solid ${accentColor}`;
      
      const downloadButton = document.getElementById('download-pdf-button');
      downloadButton.style.background = accentColor;
      downloadButton.style.color = '#ffffff';
      downloadButton.style.border = `2px solid ${accentColor}`;
      

      
      const addProductButton = document.getElementById('add-product-button');
      addProductButton.style.background = accentColor;
      addProductButton.style.color = '#ffffff';
      addProductButton.style.border = `2px solid ${accentColor}`;
      
      const customerInfoSection = document.getElementById('customer-info-section');
      customerInfoSection.style.borderColor = '#e5e7eb';
      customerInfoSection.style.color = newConfig.text_color || defaultConfig.text_color;
      
      const customerInputs = customerInfoSection.querySelectorAll('input');
      customerInputs.forEach(input => {
        input.style.borderColor = '#e5e7eb';
        input.style.color = newConfig.text_color || defaultConfig.text_color;
        input.style.background = '#ffffff';
      });
      
      const disclaimerSection = document.getElementById('disclaimer-section');
      disclaimerSection.style.background = '#64748b';
      disclaimerSection.style.color = '#ffffff';
      
      const commentsTextarea = document.getElementById('comments');
      commentsTextarea.style.borderColor = '#e5e7eb';
      commentsTextarea.style.color = newConfig.text_color || defaultConfig.text_color;
      
      const contractDateInput = document.getElementById('contract-date');
      contractDateInput.style.borderColor = '#e5e7eb';
      contractDateInput.style.color = newConfig.text_color || defaultConfig.text_color;
      
      const signatureSection = document.getElementById('signature-section');
      signatureSection.style.borderColor = '#e5e7eb';
      signatureSection.style.color = newConfig.text_color || defaultConfig.text_color;
      
      const signatureInputs = signatureSection.querySelectorAll('input');
      signatureInputs.forEach(input => {
        input.style.borderColor = '#e5e7eb';
        input.style.color = newConfig.text_color || defaultConfig.text_color;
      });
      
      const signatureCanvases = signatureSection.querySelectorAll('canvas');
      signatureCanvases.forEach(canvas => {
        canvas.style.borderColor = '#e5e7eb';
      });
      
      const clearButtons = signatureSection.querySelectorAll('button');
      clearButtons.forEach(btn => {
        btn.style.background = newConfig.accent_color || defaultConfig.accent_color;
        btn.style.color = '#ffffff';
      });
      
      applyStylesToProducts();
    }

    // Signature functionality
    function setupSignaturePad(canvasId, clearButtonId) {
      const canvas = document.getElementById(canvasId);
      const ctx = canvas.getContext('2d');
      const clearBtn = document.getElementById(clearButtonId);
      
      let isDrawing = false;
      let lastX = 0;
      let lastY = 0;
      
      function resizeCanvas() {
        const rect = canvas.getBoundingClientRect();
        const containerWidth = canvas.parentElement.offsetWidth;
        
        // Calculate responsive height based on screen size
        let canvasHeight = 120;
        if (window.innerWidth < 768) {
          canvasHeight = 180;
        }
        if (window.innerHeight > window.innerWidth) {
          canvasHeight = 220;
        }
        
        // Save current drawing
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        
        // Resize canvas
        canvas.width = containerWidth;
        canvas.height = canvasHeight;
        
        // Fill with white background
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        // Restore drawing if it existed
        if (imageData.width > 0) {
          ctx.putImageData(imageData, 0, 0);
        }
      }
      
      resizeCanvas();
      
      let resizeTimeout;
      window.addEventListener('resize', () => {
        clearTimeout(resizeTimeout);
        resizeTimeout = setTimeout(resizeCanvas, 100);
      });
      
      function getCoordinates(e) {
        const rect = canvas.getBoundingClientRect();
        let x, y;
        
        if (e.touches && e.touches.length > 0) {
          x = e.touches[0].clientX - rect.left;
          y = e.touches[0].clientY - rect.top;
        } else {
          x = e.clientX - rect.left;
          y = e.clientY - rect.top;
        }
        
        return { x, y };
      }
      
      function startDrawing(e) {
        e.preventDefault();
        isDrawing = true;
        const coords = getCoordinates(e);
        lastX = coords.x;
        lastY = coords.y;
      }
      
      function draw(e) {
        if (!isDrawing) return;
        e.preventDefault();
        
        const coords = getCoordinates(e);
        
        ctx.strokeStyle = '#000000';
        ctx.lineWidth = 2;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        
        ctx.beginPath();
        ctx.moveTo(lastX, lastY);
        ctx.lineTo(coords.x, coords.y);
        ctx.stroke();
        
        lastX = coords.x;
        lastY = coords.y;
      }
      
      function stopDrawing() {
        isDrawing = false;
      }
      
      // Mouse events
      canvas.addEventListener('mousedown', startDrawing);
      canvas.addEventListener('mousemove', draw);
      canvas.addEventListener('mouseup', stopDrawing);
      canvas.addEventListener('mouseleave', stopDrawing);
      
      // Touch events
      canvas.addEventListener('touchstart', startDrawing, { passive: false });
      canvas.addEventListener('touchmove', draw, { passive: false });
      canvas.addEventListener('touchend', stopDrawing);
      canvas.addEventListener('touchcancel', stopDrawing);
      
      clearBtn.addEventListener('click', () => {
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      });
    }

    function resetCalculator() {
      products = [];
      productIdCounter = 0;
      renderProducts();
      calculateTotals();
      
      document.getElementById('company-name').value = '';
      document.getElementById('cvr').value = '';
      document.getElementById('address').value = '';
      document.getElementById('contact-person').value = '';
      document.getElementById('email').value = '';
      document.getElementById('website').value = '';
      document.getElementById('phone').value = '';
      document.getElementById('mobile').value = '';
      
      // Sync contact person name to signature field
      document.getElementById('contact-person').addEventListener('input', (e) => {
        document.getElementById('customer-name-sig').value = e.target.value;
      });
      document.getElementById('comments').value = '';
      document.getElementById('seller-name').value = '';
      document.getElementById('customer-name-sig').value = '';
      
      const today = new Date().toISOString().split('T')[0];
      document.getElementById('contract-date').value = today;
      
      // Clear signatures
      const sellerCanvas = document.getElementById('seller-signature');
      const customerCanvas = document.getElementById('customer-signature');
      sellerCanvas.getContext('2d').clearRect(0, 0, sellerCanvas.width, sellerCanvas.height);
      customerCanvas.getContext('2d').clearRect(0, 0, customerCanvas.width, customerCanvas.height);
    }

    async function initializeApp() {
      // Initialize Element SDK
      if (window.elementSdk) {
        window.elementSdk.init({
          defaultConfig,
          onConfigChange,
          mapToCapabilities: (config) => ({
            recolorables: [
              {
                get: () => config.background_color || defaultConfig.background_color,
                set: (value) => {
                  config.background_color = value;
                  window.elementSdk.setConfig({ background_color: value });
                }
              },
              {
                get: () => config.card_color || defaultConfig.card_color,
                set: (value) => {
                  config.card_color = value;
                  window.elementSdk.setConfig({ card_color: value });
                }
              },
              {
                get: () => config.primary_color || defaultConfig.primary_color,
                set: (value) => {
                  config.primary_color = value;
                  window.elementSdk.setConfig({ primary_color: value });
                }
              },
              {
                get: () => config.text_color || defaultConfig.text_color,
                set: (value) => {
                  config.text_color = value;
                  window.elementSdk.setConfig({ text_color: value });
                }
              },
              {
                get: () => config.accent_color || defaultConfig.accent_color,
                set: (value) => {
                  config.accent_color = value;
                  window.elementSdk.setConfig({ accent_color: value });
                }
              }
            ],
            borderables: [],
            fontEditable: {
              get: () => config.font_family || defaultConfig.font_family,
              set: (value) => {
                config.font_family = value;
                window.elementSdk.setConfig({ font_family: value });
              }
            },
            fontSizeable: {
              get: () => config.font_size || defaultConfig.font_size,
              set: (value) => {
                config.font_size = value;
                window.elementSdk.setConfig({ font_size: value });
              }
            }
          }),
          mapToEditPanelValues: (config) => new Map([
            ["calculator_title", config.calculator_title || defaultConfig.calculator_title],
            ["budget_label", config.budget_label || defaultConfig.budget_label],
            ["cpm_label", config.cpm_label || defaultConfig.cpm_label],
            ["result_label", config.result_label || defaultConfig.result_label]
          ])
        });

        config = window.elementSdk.config;
        onConfigChange(config);
      } else {
        config = defaultConfig;
        onConfigChange(config);
      }
    }

    // Initialize the application
    initializeApp();

    // Set today's date as default
    const today = new Date().toISOString().split('T')[0];
    document.getElementById('contract-date').value = today;
    
    // Sync contact person name to customer signature name field
    document.getElementById('contact-person').addEventListener('input', (e) => {
      document.getElementById('customer-name-sig').value = e.target.value;
    });
    
    document.getElementById('add-product-button').addEventListener('click', createProduct);
    document.getElementById('reset-button').addEventListener('click', resetCalculator);
    document.getElementById('download-pdf-button').addEventListener('click', downloadPDF);
    
    // Initialize signature pads
    setupSignaturePad('seller-signature', 'clear-seller');
    setupSignaturePad('customer-signature', 'clear-customer');
  </script>
 <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'99df4b5126999302',t:'MTc2MzA0NzY1Ny4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>