1/* ââââââââââââââââââââââââââââââââââââââ 2 Nimbus RM Impact Calculator â Modal 3 Shows revenue impact from higher win rates, 4 larger deals, and productivity improvement. 5 ââââââââââââââââââââââââââââââââââââââ */ 6 7(function () { 8 'use strict'; 9 10 var overlay = document.getElementById('rm-calc-modal-overlay'); 11 if (!overlay) return; 12 13 var calc = overlay.querySelector('.calc-modal'); 14 var openBtn = document.getElementById('open-rm-calc-modal'); 15 var closeBtn = document.getElementById('rm-calc-modal-close'); 16 var revenueInput = calc.querySelector('#rm-calc-revenue'); 17 var dealsInput = calc.querySelector('#rm-calc-deals'); 18 var winRateInput = calc.querySelector('#rm-calc-winrate'); 19 var winRateToggle = calc.querySelector('#rm-toggle-winrate'); 20 var dealSizeToggle = calc.querySelector('#rm-toggle-dealsize'); 21 var productivityToggle = calc.querySelector('#rm-toggle-productivity'); 22 var calculateBtn = calc.querySelector('#rm-calc-btn'); 23 var resultsPanel = calc.querySelector('.calc-results'); 24 var disclaimer = calc.querySelector('.calc-disclaimer'); 25 26 /* ââ Modal open / close ââ */ 27 function openModal() { 28 overlay.classList.add('open'); 29 overlay.setAttribute('aria-hidden', 'false'); 30 document.body.style.overflow = 'hidden'; 31 revenueInput.focus(); 32 } 33 34 function closeModal() { 35 overlay.classList.remove('open'); 36 overlay.setAttribute('aria-hidden', 'true'); 37 document.body.style.overflow = ''; 38 } 39 40 if (openBtn) openBtn.addEventListener('click', openModal); 41 closeBtn.addEventListener('click', closeModal); 42 43 overlay.addEventListener('click', function (e) { 44 if (e.target === overlay) closeModal(); 45 }); 46 47 document.addEventListener('keydown', function (e) { 48 if (e.key === 'Escape' && overlay.classList.contains('open')) closeModal(); 49 }); 50 51 /* ââ Calculator logic ââ */ 52 function formatCurrency(num) { 53 if (num >= 1e9) return '$' + (num / 1e9).toFixed(2) + 'B'; 54 if (num >= 1e6) return '$' + (num / 1e6).toFixed(2) + 'M'; 55 if (num >= 1e3) return '$' + (num / 1e3).toFixed(1) + 'K'; 56 return '$' + num.toLocaleString('en-US', { maximumFractionDigits: 0 }); 57 } 58 59 function calculate() { 60 var mrr = parseFloat(revenueInput.value.replace(/[^0-9.]/g, '')); 61 var dealsWon = parseInt(dealsInput.value.replace(/[^0-9]/g, ''), 10); 62 var winRate = parseFloat(winRateInput.value.replace(/[^0-9.]/g, '')); 63 64 if (!mrr || mrr <= 0 || !dealsWon || dealsWon <= 0 || !winRate || winRate <= 0 || winRate > 100) { 65 resultsPanel.innerHTML = '<p class="calc-error">Please enter valid values for all fields.</p>'; 66 resultsPanel.classList.add('visible'); 67 disclaimer.classList.remove('visible'); 68 return; 69 } 70 71 // Annualize MRR for calculations 72 var arr = mrr * 12; 73 var currentWinRate = winRate / 100; 74 var currentDealSize = arr / dealsWon; 75 var currentDealsWon = dealsWon; 76 77 var hasWinRate = winRateToggle.checked; 78 var hasDealSize = dealSizeToggle.checked; 79 var hasProductivity = productivityToggle.checked; 80 81 // Start with current values 82 var projectedWinRate = currentWinRate; 83 var projectedDealSize = currentDealSize; 84 var projectedDealsWon = currentDealsWon; 85 86 // 27% higher win rates â more deals won from same pipeline 87 if (hasWinRate) { 88 projectedWinRate = currentWinRate * 1.27; 89 if (projectedWinRate > 1) projectedWinRate = 1; 90 projectedDealsWon = Math.round(currentDealsWon * (projectedWinRate / currentWinRate)); 91 } 92 93 // 38% larger deal sizes 94 if (hasDealSize) { 95 projectedDealSize = currentDealSize * 1.38; 96 } 97 98 // 55% sales productivity â reps work more deals, so more deals won 99 if (hasProductivity) { 100 projectedDealsWon = Math.round(projectedDealsWon * 1.55); 101 } 102 103 var projectedARR = projectedDealsWon * projectedDealSize; 104 var projectedMRR = projectedARR / 12; 105 106 var html = ''; 107 html += '<div class="calc-scenario-grid">'; 108 109 // Today baseline 110 html += '<div class="calc-scenario today">'; 111 html += '<div class="calc-scenario-label">Today</div>'; 112 html += '<div class="calc-scenario-value">' + formatCurrency(mrr) + '<span style="font-size:.6em;font-weight:500;color:var(--n-text-mute);"> /mo</span></div>'; 113 html += '<div class="calc-scenario-detail">' + formatCurrency(arr) + '/yr · ' + currentDealsWon + ' deals · ' + formatCurrency(currentDealSize) + ' avg</div>'; 114 html += '</div>'; 115 116 // With NimbusRM 117 html += '<div class="calc-scenario base">'; 118 html += '<div class="calc-scenario-label">With Nimbus RM</div>'; 119 html += '<div class="calc-scenario-value">' + formatCurrency(projectedMRR) + '<span style="font-size:.6em;font-weight:500;color:var(--n-text-mute);"> /mo</span></div>'; 120 html += '<div class="calc-scenario-detail">' + formatCurrency(projectedARR) + '/yr · ' + projectedDealsWon + ' deals · ' + formatCurrency(projectedDealSize) + ' avg</div>'; 121 html += '</div>'; 122 123 // Breakdown cards for active toggles 124 if (hasWinRate) { 125 html += '<div class="calc-scenario competency">'; 126 html += '<div class="calc-scenario-label">Win Rate Impact</div>'; 127 html += '<div class="calc-scenario-value">' + (currentWinRate * 100).toFixed(0) + '% â ' + (projectedWinRate * 100).toFixed(0) + '%</div>'; 128 html += '<div class="calc-scenario-detail">27% higher win rates</div>'; 129 html += '</div>'; 130 } 131 132 if (hasDealSize) { 133 html += '<div class="calc-scenario cosell">'; 134 html += '<div class="calc-scenario-label">Deal Size Impact</div>'; 135 html += '<div class="calc-scenario-value">' + formatCurrency(currentDealSize) + ' â ' + formatCurrency(projectedDealSize) + '</div>'; 136 html += '<div class="calc-scenario-detail">38% larger deal sizes</div>'; 137 html += '</div>'; 138 } 139 140 if (hasProductivity) { 141 html += '<div class="calc-scenario competency">'; 142 html += '<div class="calc-scenario-label">Productivity Impact</div>'; 143 var preProductivityDeals = hasWinRate ? Math.round(currentDealsWon * (projectedWinRate / currentWinRate)) : currentDealsWon; 144 html += '<div class="calc-scenario-value">' + preProductivityDeals + ' â ' + projectedDealsWon + ' deals won</div>'; 145 html += '<div class="calc-scenario-detail">55% sales productivity improvement</div>'; 146 html += '</div>'; 147 } 148 149 html += '</div>'; 150 151 // Growth summary â show both monthly and annual 152 var growthMultiple = (projectedARR / arr).toFixed(1); 153 var growthMRR = projectedMRR - mrr; 154 var growthARR = projectedARR - arr; 155 html += '<div class="calc-summary">'; 156 html += '<span class="calc-summary-label">Potential Impact</span>'; 157 html += '<span class="calc-summary-value">' + formatCurrency(projectedMRR) + '/mo · ' + formatCurrency(projectedARR) + '/yr</span>'; 158 html += '<span class="calc-summary-multiple">' + growthMultiple + 'x your current revenue · +' + formatCurrency(growthMRR) + '/mo · +' + formatCurrency(growthARR) + '/yr</span>'; 159 html += '</div>'; 160 161 resultsPanel.innerHTML = html; 162 resultsPanel.classList.add('visible'); 163 disclaimer.classList.add('visible'); 164 } 165 166 calculateBtn.addEventListener('click', calculate); 167 168 [revenueInput, dealsInput, winRateInput].forEach(function (input) { 169 input.addEventListener('keydown', function (e) { 170 if (e.key === 'Enter') calculate(); 171 }); 172 }); 173})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.