Skip to main content

Monthly payments are the dealer's preferred unit of deception. Here's the real math.

True APR, total interest over term, cost-per-month breakdown, and a 100-point Holdback Score.

Quick Check

The dealer quoted you a payment. Is it reasonable?

Enter the payment they quoted and we'll show you what's behind the number.

1
Vehicle & Deal
2
Financing
3
Add-ons

Tell us about the vehicle & deal

Enter what the dealer quoted. If you're missing a number, leave it blank. We'll work with what you have.

The negotiated price for the vehicle itself. Not including HST, licensing, or admin fees.
Where do I find this? ↓
The MSRP is on the window sticker of any new vehicle. For used vehicles, check the manufacturer’s website or AutoTrader for the original sticker price. If you can’t find it, leave this blank. Your score will still work.
Trade-in vs. private sale? ↓
Dealers typically offer 10–20% below private sale value. The advantage of a trade-in is HST savings: you only pay tax on the difference between your new vehicle price and trade-in value. Whether to trade or sell privately depends on your vehicle’s market value.
Amount you'll be financing
~$0

How are you paying?

Most buyers overpay here. A 1% rate difference on a $45,000 vehicle costs $900–$1,800 over the loan.

I don’t know my rate ↓
If the dealer only gave you a monthly payment, enter that below instead. We’ll calculate your implied interest rate, which is often higher than you’d expect. If you haven’t discussed rate yet, try checking with your bank or credit union for a pre-approval to use as a benchmark.
If you enter this AND a rate, we’ll cross-check for hidden fees rolled into your loan.
Most Ontario dealers charge $300–$900. Enter if known.

What add-ons were you offered?

Add-on markups range from 50% to 300%. Check everything you were presented with, and enter the quoted price if you have it.

Extended Warranty / Service Plan Dealer cost: $300–$800 · Typically sold for $1,500–$4,000+
High margin
GAP Insurance Covers write-off shortfall · Dealer cost ~$200, sold for $400–$1,200
High margin
Paint Protection / Ceramic Coating Dealer cost $150–$400 · Sold for $800–$2,500+
Very high margin
Fabric / Leather Protection Scotchgard equivalent · Dealer cost $50–$150, sold for $300–$800
Highest margin
Rust Proofing / Undercoat Modern vehicles have factory corrosion protection · Often unnecessary
Questionable value
Tire & Wheel Protection Road hazard coverage · Dealer cost $200–$400, sold for $700–$1,800
High margin
Credit / Life Insurance on Loan Almost always overpriced vs. term life insurance purchased independently
Very high margin
-- / 100

Price Position
0/35
Financing Terms
0/35
Finance Office
0/30
How we calculate your score ↓
$
Vehicle Price
--

%
Financing Terms
--

+
Finance Office Add-ons
--

Your Negotiation Playbook

Ready to use this?

A Holdback consultation goes deeper. We review your specific deal line by line, give you exact negotiation language, and tell you what to take and what to decline in the finance office.

Book My Consultation →
Flat fee · Remote via Zoom · Evening & weekend slots available

How We Calculate Your Score

Your score starts at a base of 30 and is adjusted across three categories, totalling up to 100 points.

Price (up to 35 points)

Compares your negotiated price to MSRP. New vehicles: we look for 2–5%+ below sticker. Used vehicles: we flag pricing relative to original MSRP but note that market comps are needed for a complete picture.

Financing (up to 35 points)

Compares your rate to the current Ontario market benchmark (). Penalizes terms of 72+ months due to interest cost and depreciation risk.

Add-ons (up to 30 points)

Scores based on total add-on cost, weighted by quoted prices when available. Dealer cost on these products is typically 15–25% of retail.

About this analysis: Holdback Scores are estimates based on Ontario market averages and publicly available pricing data. They are educational tools, not financial or legal advice. Actual dealer margins, regional conditions, manufacturer incentives, and individual credit profiles vary. For a deal-specific analysis using your exact numbers, book a Holdback consultation.

Straight Answers

The score benchmarks your deal against Ontario market averages for pricing, financing rates, and add-on costs. It flags where your deal has room to improve: pricing relative to MSRP, rate relative to market, and add-on margins. It does not replace a deal-specific consultation, but if the score is low, there is almost certainly money on the table.

No. You can enter estimated numbers to see how a potential deal stacks up. The analysis is most useful when you have actual figures from a dealer: a quoted price, interest rate, or list of offered add-ons. Not sure what the numbers on your quote mean? Learn how to read a dealer quote before entering your details.

We use your email to deliver your complete deal analysis and negotiation tips. We never share it with dealers, third parties, or use it for unrelated marketing. See the Privacy Policy for details.

A low score means the dealer likely has significant margin in one or more areas: price, financing rate, or add-on products. The detailed breakdown identifies which areas to push back on. A Deal Review ($147) or Buyer’s Brief ($297) gives you the specific language and strategy to address each one before you sign.

Want Expert Eyes on Your Deal?

The Deal Analyzer flags where you may be leaving money on the table. A Holdback consultation tells you exactly how much, and gives you the strategy to get it back.

One fee. No commissions. No dealer relationships. Same-day response.

Questions? Email hello@holdback.ca

You only buy a car every four to six years. They sell one every day.

$' + fmt(totalLeaseCost) + '
' + '
Monthly Payment
$' + fmt(state.leasePayment) + '
'; if (hasResidual) { statsHtml += '
Depreciation Cost
$' + fmt(depreciation) + '
' + '
Cost/Month of Depreciation
$' + fmt(depPerMonth) + '
'; if (state.impliedLeaseAPR > 0) { var lbm = getLeaseBenchmark(state.vehicleType); var rateColor = state.impliedLeaseAPR <= lbm ? 'var(--success)' : state.impliedLeaseAPR <= lbm + 2 ? 'var(--warn-ink)' : 'var(--danger)'; statsHtml += '
Implied APR
' + state.impliedLeaseAPR.toFixed(2) + '%
' + '
Money Factor
' + state.moneyFactor.toFixed(5) + '
'; } } document.getElementById('leaseStats').innerHTML = statsHtml; // Buyout analysis var insightBox = document.getElementById('leaseInsightBox'); var insight = document.getElementById('leaseInsight'); if (hasResidual) { var totalIfBuyout = totalLeaseCost + state.residualValue; var premium = totalIfBuyout - state.sellingPrice; insight.innerHTML = 'If you lease for ' + state.leaseTerm + ' months and then buy out at the residual of $' + fmt(state.residualValue) + ', your total cost to own would be $' + fmt(totalIfBuyout) + '. That is $' + fmt(premium) + ' more than buying outright at the current selling price. This premium covers the flexibility of the lease, but it\'s worth knowing.'; insightBox.style.display = 'block'; } else { insightBox.style.display = 'none'; } leaseCard.style.display = 'block'; } /* ── Render back-calculation insights ── */ function renderBackCalc() { var bcCard = document.getElementById('backCalcCard'); var bcText = document.getElementById('backCalcText'); var parts = []; if (state.paymentType === 'finance' && state.sellingPrice > 0 && state.loanTerm > 0) { var taxableAmt = Math.max(0, state.sellingPrice - state.tradeValue); var hstAmt = taxableAmt * 0.13; var totalCost = state.sellingPrice + hstAmt; var princ = totalCost - state.downPayment - state.tradeValue; if (princ > 0) { // Case A: monthly payment but no rate if (state.monthlyPayment > 0 && state.interestRate <= 0 && state.impliedRate > 0) { var benchmarkRate = getBenchmark(state.vehicleType); var benchLabel = state.vehicleType === 'new' ? 'new' : 'used'; var impliedCalc = calcAmort(princ, state.impliedRate, state.loanTerm); var benchCalc = calcAmort(princ, benchmarkRate, state.loanTerm); var extraInterest = impliedCalc.interest - benchCalc.interest; parts.push('Your quoted payment of $' + fmt(state.monthlyPayment) + '/month over ' + state.loanTerm + ' months implies a rate of approximately ' + state.impliedRate.toFixed(1) + '%. The Ontario market benchmark for ' + benchLabel + ' vehicle financing is ' + benchmarkRate + '%.' + (extraInterest > 100 ? ' At that implied rate, you would pay $' + fmt(extraInterest) + ' more in interest than at benchmark.' : '')); } // Case B: both monthly payment AND rate if (state.monthlyPayment > 0 && state.interestRate > 0) { var expectedCalc = calcAmort(princ, state.interestRate, state.loanTerm); var paymentDiff = state.monthlyPayment - expectedCalc.payment; if (paymentDiff > 20) { var overTerm = paymentDiff * state.loanTerm; parts.push('Based on your rate of ' + state.interestRate + '% and term of ' + state.loanTerm + ' months, your monthly payment should be approximately $' + fmt(expectedCalc.payment) + '. The dealer quoted $' + fmt(state.monthlyPayment) + '. That is $' + fmt(paymentDiff) + '/month higher, or $' + fmt(overTerm) + ' over the loan. The difference is likely add-ons or fees rolled into the financed amount.'); } } } } // Case C: trade-in HST insight if (state.tradeValue > 0 && state.sellingPrice > 0) { var hstSavings = state.tradeValue * 0.13; var netAmount = state.sellingPrice - state.tradeValue; parts.push('Your trade-in of $' + fmt(state.tradeValue) + ' saves you $' + fmt(hstSavings) + ' in Ontario HST versus selling privately. At a dealer, HST is charged on the net amount ($' + fmt(state.sellingPrice) + ' - $' + fmt(state.tradeValue) + ' = $' + fmt(netAmount) + '). If you sold privately, you\'d pay HST on the full $' + fmt(state.sellingPrice) + '.'); } if (parts.length > 0) { bcText.innerHTML = parts.join('

'); bcCard.style.display = 'block'; } else { bcCard.style.display = 'none'; } } /* ── Render breakdown cards (all ungated) ── */ function renderBreakdowns(sc) { // PRICE if (state.sellingPrice > 0 && state.msrp > 0) { var diff = state.msrp - state.sellingPrice; var pct = ((diff / state.msrp) * 100).toFixed(1); if (state.vehicleType === 'new') { if (diff > 0) { var priceMsg = 'You negotiated $' + esc(fmt(diff)) + ' (' + esc(pct) + '%) below MSRP. For a new vehicle in Ontario, anything above 3% is solid. '; if (parseFloat(pct) >= 5) { priceMsg += 'This is a strong price result.'; } else { priceMsg += 'There may still be room. A consultation can confirm using live incentive data.'; } setBreakdown('price', '#059669', 'badge-green', 'Below MSRP', priceMsg, Math.min(95, 40 + parseFloat(pct) * 8)); } else if (diff === 0) { setBreakdown('price', 'var(--warn-ink)', 'badge-yellow', 'Full MSRP', 'You\'re paying full MSRP with no discount. For most new vehicles in this market, there is room below sticker on price or through manufacturer incentives you may not be using.', 50); } else { setBreakdown('price', 'var(--danger-deep)', 'badge-red', 'Above MSRP', 'You\'re being asked to pay $' + esc(fmt(Math.abs(diff))) + ' above MSRP. Unless this vehicle has genuinely zero market alternatives, this is either negotiable or you should be comparing multiple dealers.', 20); } } else { if (diff > 0) { setBreakdown('price', '#059669', 'badge-green', 'Below Original MSRP', 'The selling price is $' + esc(fmt(diff)) + ' (' + esc(pct) + '%) below the original MSRP. For a used vehicle, the relationship to original MSRP is only one factor. Market value depends on age, mileage, condition, and local supply. Getting current market comps would give a more complete picture.', Math.min(85, 30 + parseFloat(pct) * 3)); } else { setBreakdown('price', 'var(--danger-deep)', 'badge-red', 'At or Above Original MSRP', 'The selling price is at or above the original MSRP for a used vehicle. Unless this is a rare or in-demand model with very low mileage, this warrants investigation. Getting current market comps would help confirm.', 20); } } } else if (state.sellingPrice > 0) { var noMsrpMsg = ''; if (state.vehicleType === 'used') { noMsrpMsg = 'No MSRP to compare against, so we can\'t assess pricing relative to original sticker. For used vehicles, market comps matter more than MSRP. Check AutoTrader, CarGurus, or a Holdback consultation for current market pricing on your specific vehicle.'; } else { noMsrpMsg = 'We didn\'t have an MSRP to compare against. Enter the MSRP for a full price analysis, or a Holdback consultation pulls current market pricing for your specific vehicle and trim.'; } setBreakdown('price', '#7c8a98', 'badge-grey', 'Needs Data', noMsrpMsg, 35); } else { setBreakdown('price', '#7c8a98', 'badge-grey', 'Needs Data', 'No pricing data was entered. Go back and enter at least a selling price for a price analysis.', 10); } // FINANCE var rateToUse = state.interestRate; if (rateToUse <= 0 && state.impliedRate > 0) rateToUse = state.impliedRate; if (state.paymentType === 'cash') { setBreakdown('finance', '#059669', 'badge-green', 'Cash Purchase', 'Cash purchases avoid financing markup entirely. Make sure you negotiated on the out-the-door price, not a "cash discount." Dealers sometimes add fees to cash deals to recoup lost finance profit.', 90); } else if (state.paymentType === 'lease') { if (state.impliedLeaseAPR > 0) { var leaseBench = getLeaseBenchmark(state.vehicleType); var leaseDiff = state.impliedLeaseAPR - leaseBench; if (leaseDiff <= 0) { setBreakdown('finance', '#059669', 'badge-green', 'Strong Lease Rate', 'Your lease implies an equivalent APR of ' + state.impliedLeaseAPR.toFixed(2) + '% (money factor: ' + state.moneyFactor.toFixed(5) + '). This is at or below the ' + leaseBench + '% benchmark. The rate side of your lease looks solid.', 80); } else if (leaseDiff <= 2) { setBreakdown('finance', 'var(--warn-ink)', 'badge-yellow', 'Lease Rate Above Benchmark', 'Your lease implies an equivalent APR of ' + state.impliedLeaseAPR.toFixed(2) + '% (money factor: ' + state.moneyFactor.toFixed(5) + '). The benchmark is ' + leaseBench + '%. Dealers can mark up the money factor, and that markup is not always disclosed. Ask the dealer for the base (buy) rate from the manufacturer.', 50); } else { setBreakdown('finance', 'var(--danger-deep)', 'badge-red', 'Lease Rate Well Above Benchmark', 'Your lease implies an equivalent APR of ' + state.impliedLeaseAPR.toFixed(2) + '% (money factor: ' + state.moneyFactor.toFixed(5) + '). The benchmark is ' + leaseBench + '%. This gap suggests significant money factor markup. Ask the dealer what the manufacturer base rate is and negotiate from there. Do not sign this lease without an independent review.', 20); } } else { setBreakdown('finance', '#7c8a98', 'badge-grey', 'Lease (Incomplete Data)', 'Enter your monthly payment, selling price, residual value, and lease term to get a full lease rate analysis. Without these numbers, we cannot calculate the implied money factor.', 50); } } else if (rateToUse > 0) { var benchmark = getBenchmark(state.vehicleType); var rateDiff = rateToUse - benchmark; var termForCalc = state.loanTerm || 60; var princForCalc = Math.max(0, state.sellingPrice + (Math.max(0, state.sellingPrice - state.tradeValue) * 0.13) - state.downPayment - state.tradeValue); var extraCost = Math.round(princForCalc * (rateDiff / 100) * (termForCalc / 12)); var rateLabel = (state.interestRate > 0) ? state.interestRate : state.impliedRate; var rateNote = (state.interestRate <= 0 && state.impliedRate > 0) ? ' (implied from your quoted payment)' : ''; var benchSource = ' Ontario market benchmark as of ' + BENCHMARKS.lastUpdated + '.'; // Include admin fee in analysis var adminNote = ''; if (state.adminFee > 0) { adminNote = ' The dealer admin fee of $' + esc(fmt(state.adminFee)) + ' is included in the financed amount.'; } if (rateDiff <= 0) { setBreakdown('finance', '#059669', 'badge-green', 'Competitive Rate', 'Your rate of ' + esc(rateLabel.toString()) + '%' + rateNote + ' is at or below the current Ontario market benchmark of ' + benchmark + '% for ' + (state.vehicleType === 'new' ? 'new' : 'used') + ' vehicles.' + benchSource + (state.loanTerm >= 84 ? ' Note: An 84+ month term significantly increases total interest cost and depreciation risk. Consider whether a shorter term is possible at a similar payment.' : ' The rate is solid.') + adminNote, 80); } else if (rateDiff <= 2) { setBreakdown('finance', 'var(--warn-ink)', 'badge-yellow', 'Rate Has Room', 'Your rate of ' + esc(rateLabel.toString()) + '%' + rateNote + ' is approximately ' + esc(rateDiff.toFixed(2)) + '% above the ' + (state.vehicleType === 'new' ? 'new' : 'used') + ' vehicle benchmark' + (extraCost > 0 ? ', an estimated $' + esc(fmt(extraCost)) + ' in additional interest over your term' : '') + '.' + benchSource + ' This gap is negotiable. Dealers mark up the bank\'s rate by 1 to 3%. A Holdback consultation shows you what rate you likely qualify for.' + adminNote, 50); } else { setBreakdown('finance', 'var(--danger-deep)', 'badge-red', 'Rate Is High', 'Your rate of ' + esc(rateLabel.toString()) + '%' + rateNote + ' is ' + esc(rateDiff.toFixed(2)) + '% above the ' + (state.vehicleType === 'new' ? 'new' : 'used') + ' vehicle benchmark' + (extraCost > 0 ? ', approximately $' + esc(fmt(Math.abs(extraCost))) + ' in extra interest over your term' : '') + '.' + benchSource + ' Unless your credit score is below 640, this rate has significant room to move. A consultation targets this directly.' + adminNote, 25); } } else { setBreakdown('finance', '#7c8a98', 'badge-grey', 'Rate Unknown', 'Enter your interest rate or monthly payment on Step 2 for a full financing analysis. If the dealer only gave you a monthly payment without a rate, that\'s worth investigating before signing.', 35); } // ADD-ONS var ac = state.addons.length; if (ac === 0) { setBreakdown('addon', '#059669', 'badge-green', 'No Add-ons Checked', 'You either weren\'t offered add-ons or haven\'t reached that stage yet. If you\'re buying new, the finance manager will present these products when you sit down to sign. A Holdback consultation prepares you for what to expect and what to decline.'); } else { var total = 0; var hasQuotedPrices = false; var dealerCostLowTotal = 0; var dealerCostHighTotal = 0; for (var i = 0; i < state.addons.length; i++) { var aid = state.addons[i]; var quotedPrice = state.addonPrices[aid]; if (quotedPrice > 0) { total += quotedPrice; hasQuotedPrices = true; } else { total += addonData[aid].defaultCost; } dealerCostLowTotal += addonData[aid].dealerCostLow; dealerCostHighTotal += addonData[aid].dealerCostHigh; } var badgeC = ac >= 3 ? 'badge-red' : 'badge-yellow'; var ic = ac >= 3 ? 'var(--danger-deep)' : 'var(--warn-ink)'; var addonMsg = 'You were offered ' + esc(ac.toString()) + ' add-on product' + (ac > 1 ? 's' : '') + ' with a combined ' + (hasQuotedPrices ? 'quoted' : 'estimated retail') + ' value of approximately $' + esc(fmt(total)) + '. The dealer\'s cost on these items is typically $' + esc(fmt(dealerCostLowTotal)) + '\u2013$' + esc(fmt(dealerCostHighTotal)) + '. Some may be worth keeping depending on your situation. A Holdback consultation reviews each one and gives you the language to decline the rest.'; setBreakdown('addon', ic, badgeC, ac + ' Add-on' + (ac > 1 ? 's' : '') + ' Offered', addonMsg); // Per-addon breakdown table var addonBreakdownWrap = document.getElementById('addonBreakdownWrap'); if (hasQuotedPrices) { var tableHtml = '
'; for (var j = 0; j < state.addons.length; j++) { var addonId = state.addons[j]; var price = state.addonPrices[addonId]; if (price > 0) { var dLow = addonData[addonId].dealerCostLow; var dHigh = addonData[addonId].dealerCostHigh; var markupLow = price > 0 && dHigh > 0 ? Math.round(price / dHigh) : 0; var markupHigh = price > 0 && dLow > 0 ? Math.round(price / dLow) : 0; tableHtml += ''; } } tableHtml += '
ProductQuotedEst. Dealer CostMarkup
' + esc(addonData[addonId].label) + '$' + fmt(price) + '$' + fmt(dLow) + '\u2013$' + fmt(dHigh) + '~' + markupLow + '-' + markupHigh + 'x
'; addonBreakdownWrap.innerHTML = tableHtml; } else { addonBreakdownWrap.innerHTML = ''; } } } /* ── Render negotiation playbook (gated) ── */ function renderNegotiationPlaybook(sc) { var talkingPoints = document.getElementById('talkingPoints'); var html = ''; // Price talking point if (sc.priceScore < sc.priceMax * 0.5) { html += '
What to say about the price
"I\'ve done my research and comparable ' + (state.vehicleDesc ? esc(state.vehicleDesc) + 's' : 'vehicles') + ' in the Canadian market are listing for less. I\'d like to discuss how we can get closer to a competitive range."
'; } // Rate talking point if (sc.financeScore < sc.financeMax * 0.5 && state.paymentType === 'finance') { html += '
What to say about the rate
"I\'d like to see the buy rate from the lender before any dealer markup. I\'m also getting quotes from my bank and credit union to compare."
'; } // Add-on talking point if (sc.addonScore < sc.addonMax * 0.5) { html += '
What to say at the finance desk
"I\'d like to see each product individually with the cost separated from the vehicle financing. I\'ll review them and let you know which ones I\'d like to include."
'; } // Always include general tip html += '
General tip
"I\'m not signing today. I\'d like to take the paperwork home to review it."
'; talkingPoints.innerHTML = html; // CTA card (dynamic based on weakest area) var ctaH, ctaB; var weakestArea = 'price'; var weakestPct = sc.priceMax > 0 ? sc.priceScore / sc.priceMax : 1; var financePct = sc.financeMax > 0 ? sc.financeScore / sc.financeMax : 1; var addonPct = sc.addonMax > 0 ? sc.addonScore / sc.addonMax : 1; if (financePct < weakestPct) { weakestArea = 'financing'; weakestPct = financePct; } if (addonPct < weakestPct) { weakestArea = 'addons'; } if (sc.total >= 80) { ctaH = 'Confirm before you commit.'; ctaB = 'A Deal Review ($147) validates your numbers and catches anything hidden in the fine print before you sign.'; } else if (sc.total >= 65) { if (weakestArea === 'financing') { ctaH = 'Your rate is the biggest opportunity here.'; } else if (weakestArea === 'addons') { ctaH = 'The finance office products are where you\'re leaving money.'; } else { ctaH = 'There\'s money left on the table.'; } ctaB = 'A Buyer\'s Brief ($297) identifies every dollar of avoidable cost and gives you the exact language to address each one with the dealer.'; } else if (sc.total >= 50) { ctaH = 'This deal has serious flags.'; ctaB = 'A Buyer\'s Brief ($297) covers the specific issues flagged above and gives you a game plan for the conversation with the dealer.'; } else { ctaH = 'Do not sign this deal yet.'; ctaB = 'A Buyer\'s Brief ($297) identifies where this deal is structured against you and gives you the language and strategy to fix it before you commit.'; } document.getElementById('ctaHeadline').textContent = ctaH; document.getElementById('ctaBody').textContent = ctaB; } /* ── Email gate submission ── */ function submitGate() { var email = document.getElementById('gateEmail').value.trim(); var name = document.getElementById('gateFirstName').value.trim(); if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email)) { var f = document.getElementById('gateEmail'); f.classList.add('error'); f.placeholder = 'Please enter a valid email'; return; } // Send lead data var sc = score(); var hbUtms = (window.Holdback && window.Holdback.getUTMs) ? window.Holdback.getUTMs() : {}; fetch('/api/lead', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(Object.assign({ email: email, name: name, source: 'Deal Analyzer', score: sc.total, vehicle: state.vehicleDesc, vehicleType: state.vehicleType, sellingPrice: state.sellingPrice, msrp: state.msrp, paymentType: state.paymentType, tradeValue: state.tradeValue, downPayment: state.downPayment, monthlyPayment: state.monthlyPayment, loanTerm: state.loanTerm, interestRate: state.interestRate, paymentFrequency: state.paymentFrequency, adminFee: state.adminFee, leasePayment: state.leasePayment, leaseTerm: state.leaseTerm, residualValue: state.residualValue, addons: state.addons, addonPrices: state.addonPrices, _hp: (document.getElementById('confirmAnalysis') || {}).value || '', _t0: window.__holdbackPageT0 || 0 }, hbUtms)) }).then(function(res) { if (!res || !res.ok) throw new Error(); }).catch(function() { var gate = document.getElementById('emailGate'); if (gate) { var notice = document.createElement('p'); notice.style.cssText = 'font-size: var(--fs-sm);color:var(--danger);margin-top:10px;'; notice.textContent = 'Your results are ready, but we couldn\u2019t save your email. Reach us at hello@holdback.ca'; gate.appendChild(notice); } }); trackEvent('da_email_submitted', {}); // Reveal all results revealResults(); } /* ── Change My Numbers ── */ function changeNumbers() { // Hide results and email gate document.getElementById('resultsSection').classList.remove('active'); document.getElementById('emailGateSection').classList.remove('active'); document.getElementById('emailGateSection').style.display = ''; // Show hero, progress, form document.getElementById('pageHero').style.display = ''; document.getElementById('progressContainer').style.display = ''; document.getElementById('formContainer').style.display = ''; // Navigate to step 1 goToStep(1, true); // Repopulate form populateFormFromState(); trackEvent('da_numbers_changed', {}); window.scrollTo({ top: 0, behavior: 'smooth' }); } /* ── Addon checkbox toggle ── */ function setupAddonToggles() { for (var i = 0; i < addonIds.length; i++) { (function(id) { var checkbox = document.getElementById('addon_' + id); var priceRow = document.getElementById('addonPriceRow_' + id); var item = checkbox.closest('.addon-item'); checkbox.addEventListener('change', function() { priceRow.style.display = this.checked ? 'block' : 'none'; if (this.checked) { item.classList.add('checked'); } else { item.classList.remove('checked'); } updateAddonTotal(); }); // Addon price input change var priceInput = document.getElementById('addonPrice_' + id); priceInput.addEventListener('input', function() { updateAddonTotal(); }); // Setup dollar formatting for addon price inputs setupDollarInput('addonPrice_' + id); })(addonIds[i]); } } /* ── FAQ accordion ── */ function setupFaq() { var faqItems = document.querySelectorAll('.faq-question'); for (var i = 0; i < faqItems.length; i++) { (function(item) { item.addEventListener('click', function() { var parent = this.parentElement; var isActive = parent.classList.contains('active'); var allItems = document.querySelectorAll('.faq-item'); for (var j = 0; j < allItems.length; j++) { allItems[j].classList.remove('active'); allItems[j].querySelector('.faq-icon').textContent = '+'; allItems[j].querySelector('.faq-question').setAttribute('aria-expanded', 'false'); } if (!isActive) { parent.classList.add('active'); this.querySelector('.faq-icon').textContent = '\u2212'; this.setAttribute('aria-expanded', 'true'); } }); item.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.click(); } }); })(faqItems[i]); } } /* ── Event listeners ── */ // Toggle buttons (vehicle type, payment type, payment frequency) var toggleBtns = document.querySelectorAll('.type-toggle [data-field][data-value]'); for (var i = 0; i < toggleBtns.length; i++) { (function(btn) { btn.addEventListener('click', function() { selectToggle(this.getAttribute('data-field'), this.getAttribute('data-value'), this); }); })(toggleBtns[i]); } // Term button group var termBtns = document.querySelectorAll('.term-btn'); for (var t = 0; t < termBtns.length; t++) { (function(btn) { btn.addEventListener('click', function() { for (var j = 0; j < termBtns.length; j++) { termBtns[j].classList.remove('selected'); } this.classList.add('selected'); document.getElementById('loanTerm').value = this.getAttribute('data-term'); state.loanTerm = parseInt(this.getAttribute('data-term'), 10); updateStep2Preview(); }); })(termBtns[t]); } // Info-tip toggle links var tipLinks = document.querySelectorAll('[data-tip]'); for (var k = 0; k < tipLinks.length; k++) { (function(link) { link.addEventListener('click', function() { toggleTip(this.getAttribute('data-tip')); }); })(tipLinks[k]); } // Step navigation document.getElementById('btnNextStep2').addEventListener('click', function() { goToStep(2); }); document.getElementById('btnNextStep3').addEventListener('click', function() { goToStep(3); }); document.getElementById('btnBackStep1').addEventListener('click', function() { goToStep(1); }); document.getElementById('btnBackStep2').addEventListener('click', function() { goToStep(2); }); // Clear selling price error on input document.getElementById('sellingPrice').addEventListener('input', function() { this.classList.remove('error'); document.getElementById('sellingPriceError').classList.remove('visible'); updateStep1Preview(); }); // Live preview updates for step 1 document.getElementById('tradeValue').addEventListener('input', updateStep1Preview); document.getElementById('downPayment').addEventListener('input', updateStep1Preview); // Live preview updates for step 2 document.getElementById('interestRate').addEventListener('input', updateStep2Preview); // Show results document.getElementById('btnShowScore').addEventListener('click', function() { showEmailGate(); }); // Email gate submit document.getElementById('btnSubmitGate').addEventListener('click', function() { submitGate(); }); // Allow Enter key in email field to submit document.getElementById('gateEmail').addEventListener('keydown', function(e) { if (e.key === 'Enter') { e.preventDefault(); submitGate(); } }); // Change my numbers document.getElementById('btnChangeNumbers').addEventListener('click', function() { changeNumbers(); }); document.getElementById('btnChangeTop').addEventListener('click', function() { changeNumbers(); }); document.getElementById('btnPrintDeal').addEventListener('click', function() { window.print(); }); // Share deal link document.getElementById('btnShareDeal').addEventListener('click', function() { var p = new URLSearchParams(); if (state.vehicleType) p.set('type', state.vehicleType); if (state.vehicleDesc) p.set('vehicle', state.vehicleDesc); if (state.sellingPrice > 0) p.set('sp', state.sellingPrice); if (state.msrp > 0) p.set('msrp', state.msrp); if (state.tradeValue > 0) p.set('tv', state.tradeValue); if (state.downPayment > 0) p.set('dp', state.downPayment); if (state.paymentType !== 'finance') p.set('pt', state.paymentType); if (state.interestRate > 0) p.set('rate', state.interestRate); if (state.loanTerm > 0) p.set('term', state.loanTerm); if (state.paymentFrequency !== 'monthly') p.set('freq', state.paymentFrequency); if (state.monthlyPayment > 0) p.set('pmt', state.monthlyPayment); if (state.adminFee > 0) p.set('af', state.adminFee); if (state.leasePayment > 0) p.set('lp', state.leasePayment); if (state.leaseTerm > 0) p.set('lt', state.leaseTerm); if (state.residualValue > 0) p.set('rv', state.residualValue); if (state.addons.length > 0) p.set('addons', state.addons.join(',')); var url = window.location.origin + window.location.pathname + '?' + p.toString(); navigator.clipboard.writeText(url).then(function() { var el = document.getElementById('shareDealCopied'); el.style.display = 'inline'; setTimeout(function() { el.style.display = 'none'; }, 2000); }); }); // CTA tracking document.getElementById('ctaButton').addEventListener('click', function() { trackEvent('da_cta_clicked', {}); }); // Methodology link smooth scroll document.getElementById('methodologyLink').addEventListener('click', function(e) { e.preventDefault(); var target = document.getElementById('methodology'); if (target) { target.scrollIntoView({ behavior: 'smooth' }); } }); // Save state on input blur for all fields var allInputs = document.querySelectorAll('input, select'); for (var b = 0; b < allInputs.length; b++) { allInputs[b].addEventListener('blur', function() { collectStep(currentStep); }); } // Setup dollar input formatting setupDollarInput('sellingPrice'); setupDollarInput('msrp'); setupDollarInput('tradeValue'); setupDollarInput('downPayment'); setupDollarInput('monthlyPayment'); setupDollarInput('adminFee'); setupDollarInput('leasePayment'); setupDollarInput('residualValue'); // Setup addon toggles and FAQ setupAddonToggles(); setupFaq(); // Populate benchmark rates in methodology section var methodRates = document.getElementById('methodologyRates'); if (methodRates) methodRates.textContent = BENCHMARKS.newRate + '% for new, ' + BENCHMARKS.usedRate + '% for used as of ' + BENCHMARKS.lastUpdated; // Restore state from session storage restoreState(); // Load from URL parameters (shared deal links) function loadDealFromURL() { var p = new URLSearchParams(window.location.search); if (!p.has('sp')) return; if (p.has('type')) state.vehicleType = p.get('type'); if (p.has('vehicle')) state.vehicleDesc = p.get('vehicle'); if (p.has('sp')) state.sellingPrice = parseInt(p.get('sp'), 10); if (p.has('msrp')) state.msrp = parseInt(p.get('msrp'), 10); if (p.has('tv')) state.tradeValue = parseInt(p.get('tv'), 10); if (p.has('dp')) state.downPayment = parseInt(p.get('dp'), 10); if (p.has('pt')) state.paymentType = p.get('pt'); if (p.has('rate')) state.interestRate = parseFloat(p.get('rate')); if (p.has('term')) state.loanTerm = parseInt(p.get('term'), 10); if (p.has('freq')) state.paymentFrequency = p.get('freq'); if (p.has('pmt')) state.monthlyPayment = parseInt(p.get('pmt'), 10); if (p.has('af')) state.adminFee = parseInt(p.get('af'), 10); if (p.has('lp')) state.leasePayment = parseInt(p.get('lp'), 10); if (p.has('lt')) state.leaseTerm = parseInt(p.get('lt'), 10); if (p.has('rv')) state.residualValue = parseInt(p.get('rv'), 10); if (p.has('addons')) state.addons = p.get('addons').split(','); // Populate form fields from state restoreState(); // Hide quick check, skip to full analysis document.getElementById('quickCheckContainer').style.display = 'none'; } loadDealFromURL(); // GA4: deal analyzer start // --- INCOME AFFORDABILITY --- setupDollarInput('incomeInput'); document.getElementById('incomeInput').addEventListener('input', function() { // Re-render payment reality to update affordability if (document.getElementById('resultsSection').classList.contains('active')) { renderPaymentReality(); } }); // --- DEAL COMPARISON --- setupDollarInput('cmpPrice'); setupDollarInput('cmpPayment'); document.getElementById('btnCompare').addEventListener('click', function() { var cmpPrice = getDollarValue('cmpPrice'); if (cmpPrice <= 0) { document.getElementById('cmpPrice').classList.add('error'); return; } document.getElementById('cmpPrice').classList.remove('error'); var cmpRate = parseFloat(document.getElementById('cmpRate').value) || 0; var cmpTerm = parseInt(document.getElementById('cmpTerm').value, 10) || state.loanTerm || 60; var cmpPmt = getDollarValue('cmpPayment'); // Calculate Deal B var cmpHst = Math.max(0, cmpPrice - state.tradeValue) * 0.13; var cmpPrincipal = (cmpPrice + cmpHst + state.adminFee) - state.tradeValue - state.downPayment; if (cmpPrincipal <= 0) cmpPrincipal = 1; var cmpImplied = 0; if (cmpPmt > 0 && cmpRate <= 0) { // Solve for implied rate var lo = 0, hi = 30; for (var i = 0; i < 50; i++) { var mid = (lo + hi) / 2; var mr = mid / 12 / 100; var calc = mr === 0 ? cmpPrincipal / cmpTerm : cmpPrincipal * (mr * Math.pow(1 + mr, cmpTerm)) / (Math.pow(1 + mr, cmpTerm) - 1); if (calc < cmpPmt) lo = mid; else hi = mid; } cmpImplied = Math.round((lo + hi) / 2 * 100) / 100; cmpRate = cmpImplied; } var cmpRes = cmpRate > 0 ? calcAmort(cmpPrincipal, cmpRate, cmpTerm) : { payment: cmpPrincipal / cmpTerm, totalPaid: cmpPrincipal, totalInterest: 0 }; var cmpMonthly = cmpPmt > 0 ? cmpPmt : cmpRes.payment; // Deal A values var aHst = Math.max(0, state.sellingPrice - state.tradeValue) * 0.13; var aPrincipal = (state.sellingPrice + aHst + state.adminFee) - state.tradeValue - state.downPayment; var aRate = state.interestRate > 0 ? state.interestRate : (state.impliedRate > 0 ? state.impliedRate : 0); var aTerm = state.loanTerm || 60; var aRes = aRate > 0 ? calcAmort(aPrincipal, aRate, aTerm) : { payment: aPrincipal / aTerm, totalPaid: aPrincipal, totalInterest: 0 }; var aMonthly = state.monthlyPayment > 0 ? state.monthlyPayment : aRes.payment; var benchmark = getBenchmark(state.vehicleType); // Render comparison function winner(a, b, lowerBetter) { if (a === b) return ['', '']; if (lowerBetter) return a < b ? ['color:var(--success);font-weight:700;', 'color: var(--danger-deep);'] : ['color: var(--danger-deep);', 'color:var(--success);font-weight:700;']; return a > b ? ['color:var(--success);font-weight:700;', 'color: var(--danger-deep);'] : ['color: var(--danger-deep);', 'color:var(--success);font-weight:700;']; } function row(label, aVal, bVal, fmt2, lowerBetter) { var w = winner(parseFloat(aVal) || 0, parseFloat(bVal) || 0, lowerBetter); var aStr = fmt2 ? fmt2(aVal) : aVal; var bStr = fmt2 ? fmt2(bVal) : bVal; return '' + label + '' + '' + aStr + '' + '' + bStr + ''; } function fmtD(v) { return '$' + Math.round(v).toLocaleString('en-CA'); } function fmtP(v) { return v.toFixed(2) + '%'; } var html = '
'; html += ''; html += ''; html += ''; html += ''; html += ''; html += row('Selling Price', state.sellingPrice, cmpPrice, fmtD, true); html += row('Interest Rate', aRate, cmpRate, fmtP, true); html += row('Term', aTerm, cmpTerm, function(v) { return v + ' mo'; }, true); html += row('Monthly Payment', aMonthly, cmpMonthly, fmtD, true); html += row('Total Interest', aRes.totalInterest, cmpRes.totalInterest, fmtD, true); html += row('Total Paid', aRes.totalPaid, cmpRes.totalPaid, fmtD, true); html += '
Deal A (yours)Deal B
'; // Summary var diff = cmpRes.totalPaid - aRes.totalPaid; if (diff > 0) { html += '
Deal A saves you ' + fmtD(Math.abs(diff)) + ' over the life of the loan compared to Deal B.
'; } else if (diff < 0) { html += '
Deal B saves you ' + fmtD(Math.abs(diff)) + ' over the life of the loan. Consider negotiating Deal A closer to these terms.
'; } else { html += '
Both deals have similar total cost. Look at the rate and term structure to decide which works better for your situation.
'; } document.getElementById('compareResults').innerHTML = html; document.getElementById('compareResults').style.display = 'block'; trackEvent('deal_comparison', { diff: Math.round(diff) }); }); trackEvent('deal_analyzer_start', {}); // =========================== // QUICK PAYMENT CHECK // =========================== var qcFreq = 'monthly'; var qcFreqBtns = document.querySelectorAll('.qc-freq-btn'); qcFreqBtns.forEach(function(btn) { btn.addEventListener('click', function() { qcFreqBtns.forEach(function(b) { b.classList.remove('selected'); }); btn.classList.add('selected'); qcFreq = btn.getAttribute('data-qcfreq'); }); }); setupDollarInput('qcPayment'); setupDollarInput('qcPrice'); // Skip to full analysis document.getElementById('qcSkip').addEventListener('click', function() { document.getElementById('quickCheckContainer').style.display = 'none'; }); // =========================== // DEAL CHAT TAB + LOGIC // =========================== // Tab switcher (ARIA tablist pattern: toggle aria-selected + hidden state) var qcTabBtns = document.querySelectorAll('.qc-tab-btn'); qcTabBtns.forEach(function(btn) { btn.addEventListener('click', function() { qcTabBtns.forEach(function(b) { b.classList.remove('active'); b.setAttribute('aria-selected', 'false'); }); btn.classList.add('active'); btn.setAttribute('aria-selected', 'true'); var tab = btn.getAttribute('data-tab'); var qcPanel = document.getElementById('panelQuickCheck'); var dcPanel = document.getElementById('panelDealChat'); qcPanel.classList.toggle('active', tab === 'quickcheck'); dcPanel.classList.toggle('active', tab === 'dealchat'); qcPanel.toggleAttribute('hidden', tab !== 'quickcheck'); dcPanel.toggleAttribute('hidden', tab !== 'dealchat'); if (tab === 'dealchat') { document.getElementById('dcInput').focus(); trackEvent('deal_chat_tab_opened'); } }); }); // Deal Chat skip to full analysis document.getElementById('dcSkip').addEventListener('click', function() { document.getElementById('quickCheckContainer').style.display = 'none'; }); // Vehicle Database (30 popular vehicles, Canadian MSRP ranges in CAD) var dcVehicles = { 'rav4': { name: 'Toyota RAV4', segment: 'Compact SUV', msrpLow: 35990, msrpHigh: 47490 }, 'cr-v': { name: 'Honda CR-V', segment: 'Compact SUV', msrpLow: 38980, msrpHigh: 51330 }, 'crv': { name: 'Honda CR-V', segment: 'Compact SUV', msrpLow: 38980, msrpHigh: 51330 }, 'civic': { name: 'Honda Civic', segment: 'Compact Sedan', msrpLow: 30650, msrpHigh: 42500 }, 'corolla': { name: 'Toyota Corolla', segment: 'Compact Sedan', msrpLow: 24490, msrpHigh: 35490 }, 'camry': { name: 'Toyota Camry', segment: 'Midsize Sedan', msrpLow: 33490, msrpHigh: 43990 }, 'accord': { name: 'Honda Accord', segment: 'Midsize Sedan', msrpLow: 37600, msrpHigh: 46600 }, 'cx-5': { name: 'Mazda CX-5', segment: 'Compact SUV', msrpLow: 33150, msrpHigh: 44850 }, 'cx5': { name: 'Mazda CX-5', segment: 'Compact SUV', msrpLow: 33150, msrpHigh: 44850 }, 'tucson': { name: 'Hyundai Tucson', segment: 'Compact SUV', msrpLow: 34599, msrpHigh: 47599 }, 'sportage': { name: 'Kia Sportage', segment: 'Compact SUV', msrpLow: 33995, msrpHigh: 46495 }, 'rogue': { name: 'Nissan Rogue', segment: 'Compact SUV', msrpLow: 34198, msrpHigh: 45998 }, 'forester': { name: 'Subaru Forester', segment: 'Compact SUV', msrpLow: 35995, msrpHigh: 43495 }, 'escape': { name: 'Ford Escape', segment: 'Compact SUV', msrpLow: 35499, msrpHigh: 48999 }, 'equinox': { name: 'Chevrolet Equinox', segment: 'Compact SUV', msrpLow: 35799, msrpHigh: 43399 }, 'tiguan': { name: 'Volkswagen Tiguan', segment: 'Compact SUV', msrpLow: 37495, msrpHigh: 47495 }, 'f-150': { name: 'Ford F-150', segment: 'Full-Size Truck', msrpLow: 43835, msrpHigh: 97510 }, 'f150': { name: 'Ford F-150', segment: 'Full-Size Truck', msrpLow: 43835, msrpHigh: 97510 }, 'ram 1500': { name: 'Ram 1500', segment: 'Full-Size Truck', msrpLow: 49645, msrpHigh: 98745 }, 'ram1500': { name: 'Ram 1500', segment: 'Full-Size Truck', msrpLow: 49645, msrpHigh: 98745 }, 'silverado': { name: 'Chevrolet Silverado', segment: 'Full-Size Truck', msrpLow: 46898, msrpHigh: 92698 }, 'sierra': { name: 'GMC Sierra', segment: 'Full-Size Truck', msrpLow: 49998, msrpHigh: 96998 }, 'tacoma': { name: 'Toyota Tacoma', segment: 'Midsize Truck', msrpLow: 43550, msrpHigh: 60590 }, 'highlander': { name: 'Toyota Highlander', segment: 'Midsize SUV', msrpLow: 46490, msrpHigh: 58190 }, '4runner': { name: 'Toyota 4Runner', segment: 'Midsize SUV', msrpLow: 52990, msrpHigh: 70990 }, 'wrangler': { name: 'Jeep Wrangler', segment: 'Off-Road SUV', msrpLow: 44495, msrpHigh: 68095 }, 'grand cherokee':{ name: 'Jeep Grand Cherokee', segment: 'Midsize SUV', msrpLow: 51995, msrpHigh: 78495 }, 'model 3': { name: 'Tesla Model 3', segment: 'Electric Sedan', msrpLow: 46990, msrpHigh: 62990 }, 'model3': { name: 'Tesla Model 3', segment: 'Electric Sedan', msrpLow: 46990, msrpHigh: 62990 }, 'model y': { name: 'Tesla Model Y', segment: 'Electric SUV', msrpLow: 54990, msrpHigh: 69990 }, 'modely': { name: 'Tesla Model Y', segment: 'Electric SUV', msrpLow: 54990, msrpHigh: 69990 }, 'ioniq 5': { name: 'Hyundai Ioniq 5', segment: 'Electric SUV', msrpLow: 47599, msrpHigh: 60599 }, 'ioniq5': { name: 'Hyundai Ioniq 5', segment: 'Electric SUV', msrpLow: 47599, msrpHigh: 60599 }, 'ev6': { name: 'Kia EV6', segment: 'Electric SUV', msrpLow: 48995, msrpHigh: 64495 }, 'niro ev': { name: 'Kia Niro EV', segment: 'Electric SUV', msrpLow: 44995, msrpHigh: 51995 }, 'niro': { name: 'Kia Niro EV', segment: 'Electric SUV', msrpLow: 44995, msrpHigh: 51995 }, 'prius': { name: 'Toyota Prius', segment: 'Hybrid Sedan', msrpLow: 34490, msrpHigh: 44790 }, 'mazda3': { name: 'Mazda3', segment: 'Compact Sedan', msrpLow: 26350, msrpHigh: 38050 }, 'mazda 3': { name: 'Mazda3', segment: 'Compact Sedan', msrpLow: 26350, msrpHigh: 38050 } }; var dcVehicleKeys = Object.keys(dcVehicles).sort(function(a, b) { return b.length - a.length; }); var dcMessages = document.getElementById('dcMessages'); var dcInput = document.getElementById('dcInput'); var dcSend = document.getElementById('dcSend'); var dcWelcome = document.getElementById('dcWelcome'); function dcFmt(n) { return '$' + Math.round(n).toLocaleString('en-CA'); } function dcAddMessage(type, html) { if (dcWelcome) { dcWelcome.style.display = 'none'; } var div = document.createElement('div'); div.className = 'dc-msg dc-msg-' + type; div.innerHTML = '
' + html + '
'; dcMessages.appendChild(div); dcMessages.scrollTop = dcMessages.scrollHeight; } function dcFindVehicle(text) { var lower = text.toLowerCase(); for (var i = 0; i < dcVehicleKeys.length; i++) { if (lower.indexOf(dcVehicleKeys[i]) !== -1) { return dcVehicles[dcVehicleKeys[i]]; } } return null; } function dcFindPrice(text) { var patterns = [ /\$\s?([\d,]+(?:\.\d{1,2})?)/, /(\d{2,3},?\d{3}(?:\.\d{1,2})?)\s*(?:dollars?|cad|cdn)?/i, /(?:for|at|price|quoted|paying|costs?)\s+\$?\s?([\d,]+)/i ]; for (var i = 0; i < patterns.length; i++) { var m = text.match(patterns[i]); if (m) { var val = parseFloat(m[1].replace(/,/g, '')); if (val >= 10000 && val <= 250000) return val; } } return null; } function dcFindYear(text) { var m = text.match(/\b(202[0-9]|203[0-9])\b/); return m ? parseInt(m[1], 10) : null; } function dcBuildResponse(input) { var vehicle = dcFindVehicle(input); var price = dcFindPrice(input); var year = dcFindYear(input); if (!vehicle && !price) { return '
I can help check a deal. Tell me the vehicle and the price you were quoted.
' + '
For example: "Is $42,000 for a 2026 RAV4 XLE a good deal?"
'; } if (vehicle && !price) { return '
The ' + vehicle.name + ' (' + vehicle.segment + ') has a Canadian MSRP range of ' + dcFmt(vehicle.msrpLow) + ' to ' + dcFmt(vehicle.msrpHigh) + ' depending on trim.
' + '
What price were you quoted? Include the dollar amount and I can check it against market data.
'; } if (!vehicle && price) { return '
You mentioned a price of ' + dcFmt(price) + ', but I could not identify the vehicle model.
' + '
We do not have pricing data for that model yet. Use the full Deal Analyzer below for a detailed analysis of any deal.
' + ''; } var msrpMid = (vehicle.msrpLow + vehicle.msrpHigh) / 2; var diffFromLow = ((price - vehicle.msrpLow) / vehicle.msrpLow * 100).toFixed(1); var diffFromHigh = ((price - vehicle.msrpHigh) / vehicle.msrpHigh * 100).toFixed(1); var verdict = ''; var detail = ''; var yearLabel = year ? year + ' ' : ''; if (price < vehicle.msrpLow) { var belowPct = Math.abs(parseFloat(diffFromLow)); verdict = 'Below MSRP Range'; detail = '
That price of ' + dcFmt(price) + ' for a ' + yearLabel + vehicle.name + ' is ' + belowPct + '% below the starting MSRP of ' + dcFmt(vehicle.msrpLow) + '. For a ' + vehicle.segment.toLowerCase() + ', that is a solid starting point.
'; detail += '
The MSRP range for this model is ' + dcFmt(vehicle.msrpLow) + ' to ' + dcFmt(vehicle.msrpHigh) + ' depending on trim level.
'; detail += '
Confirm this price includes all fees, not just the base vehicle. Verify that freight, PDI, A/C tax, and dealer documentation fees are accounted for.
'; } else if (price <= vehicle.msrpHigh) { if (price <= msrpMid) { verdict = 'Within MSRP Range (Lower Half)'; detail = '
That price of ' + dcFmt(price) + ' for a ' + yearLabel + vehicle.name + ' falls in the lower half of the MSRP range (' + dcFmt(vehicle.msrpLow) + ' to ' + dcFmt(vehicle.msrpHigh) + ').
'; detail += '
That is at sticker price. Most buyers negotiate 2-5% below MSRP on this model. On a ' + vehicle.segment.toLowerCase() + ', that could mean ' + dcFmt(price * 0.03) + ' to ' + dcFmt(price * 0.05) + ' in savings.
'; } else { verdict = 'Within MSRP Range (Upper Half)'; detail = '
That price of ' + dcFmt(price) + ' for a ' + yearLabel + vehicle.name + ' falls in the upper half of the MSRP range (' + dcFmt(vehicle.msrpLow) + ' to ' + dcFmt(vehicle.msrpHigh) + ').
'; detail += '
That is at sticker price for a higher trim. Most buyers negotiate 2-5% below MSRP. Make sure the trim and options justify the price point.
'; } detail += '
Run the numbers through the full Deal Analyzer below to see the complete picture including financing costs.
'; } else { var abovePct = Math.abs(parseFloat(diffFromHigh)); verdict = 'Above MSRP Range'; detail = '
That price of ' + dcFmt(price) + ' for a ' + yearLabel + vehicle.name + ' is ' + abovePct + '% above the top MSRP of ' + dcFmt(vehicle.msrpHigh) + '.
'; detail += '
Unless this is a high-demand model with limited inventory, there is room to negotiate. The full MSRP range for this ' + vehicle.segment.toLowerCase() + ' is ' + dcFmt(vehicle.msrpLow) + ' to ' + dcFmt(vehicle.msrpHigh) + '.
'; detail += '
Check for dealer markups, added accessories, or protection packages that may be inflating the price. A Holdback consultation can identify exactly where the overage is.
'; } return '
' + verdict + '
' + detail + ''; } function dcProcessInput() { var text = dcInput.value.trim(); if (!text) return; dcAddMessage('user', text.replace(//g, '>')); dcInput.value = ''; dcSend.disabled = true; setTimeout(function() { var response = dcBuildResponse(text); dcAddMessage('bot', response); dcSend.disabled = false; dcInput.focus(); if (typeof gtag === 'function') { var v = dcFindVehicle(text); var p = dcFindPrice(text); gtag('event', 'deal_chat_query', { vehicle: v ? v.name : 'unknown', price: p || 0, query: text.substring(0, 100) }); } }, 400); } dcSend.addEventListener('click', dcProcessInput); dcInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') { e.preventDefault(); dcProcessInput(); } }); document.getElementById('dcExampleList').addEventListener('click', function(e) { var li = e.target.closest('li'); if (li && li.dataset.q) { dcInput.value = li.dataset.q; dcProcessInput(); } }); // =========================== // END DEAL CHAT // =========================== // Quick-check uses the canonical solveForRate() defined above (line ~1777). // Both call sites here pass (payment, principal, months) to match that signature. document.getElementById('qcBtn').addEventListener('click', function() { var paymentRaw = getDollarValue('qcPayment'); if (paymentRaw <= 0) { document.getElementById('qcPayment').classList.add('error'); return; } document.getElementById('qcPayment').classList.remove('error'); // Convert to monthly var monthlyPmt = paymentRaw; if (qcFreq === 'biweekly') monthlyPmt = paymentRaw * 26 / 12; if (qcFreq === 'weekly') monthlyPmt = paymentRaw * 52 / 12; var price = getDollarValue('qcPrice'); var termVal = document.getElementById('qcTerm').value; var term = termVal ? parseInt(termVal, 10) : 0; var results = document.getElementById('qcResults'); var html = ''; // CASE 1: Price + Payment (+ optional term) if (price > 0) { var hst = Math.max(0, price) * 0.13; var principal = price + hst; var benchmarkRate = BENCHMARKS.newRate; if (term > 0) { // We have price + payment + term: solve for implied rate var implied = solveForRate(monthlyPmt, principal, term); // Canada Interest Act §4 — fixed-rate loans compound semi-annually, // not in advance. Effective monthly rate from a stated annual rate // is `(1 + r/2)^(1/6) - 1`, NOT `r/12`. The US-style monthly form // (formerly used here) under-stated the benchmark payment by ~$10/mo // on a 60-month $30k loan — making any quoted deal look closer to // benchmark than it actually was. var benchR = Math.pow(1 + benchmarkRate / 200, 1/6) - 1; var benchPmt = principal * (benchR * Math.pow(1 + benchR, term)) / (Math.pow(1 + benchR, term) - 1); var totalPaid = monthlyPmt * term; var benchTotal = benchPmt * term; var excess = totalPaid - benchTotal; html += '
'; html += '
' + (implied > 0 ? implied.toFixed(2) + '%' : 'N/A') + '
'; html += '
Implied interest rate
'; html += '
'; html += '
'; html += '
Total you\'ll pay
$' + Math.round(totalPaid).toLocaleString('en-CA') + '
'; html += '
Total interest
$' + Math.round(totalPaid - principal).toLocaleString('en-CA') + '
'; html += '
'; if (implied > 0 && implied > benchmarkRate + 0.5) { html += '
'; html += '
What this means
'; if (excess > 500) { html += '

Your quoted payment implies a rate of ' + implied.toFixed(2) + '%, which is above the ' + benchmarkRate + '% Ontario market benchmark. Over ' + term + ' months, that gap costs you roughly $' + Math.round(excess).toLocaleString('en-CA') + ' in extra interest. This could be a rate markup, or it could mean add-ons or fees have been rolled into the payment.

'; } else { html += '

Your rate is slightly above the ' + benchmarkRate + '% benchmark, but the difference is relatively small. Still worth confirming there are no add-ons rolled into the payment.

'; } html += '
'; } else if (implied > 0 && implied <= benchmarkRate) { html += '
'; html += '

Your implied rate of ' + implied.toFixed(2) + '% is at or below the market benchmark. The payment looks reasonable for this vehicle and term. Run the full analysis below to check the add-on and pricing details.

'; html += '
'; } } else { // Price + payment, no term: show across common terms html += '
Your $' + Math.round(paymentRaw).toLocaleString('en-CA') + '/' + (qcFreq === 'monthly' ? 'month' : qcFreq === 'biweekly' ? 'bi-week' : 'week') + ' payment implies these rates:
'; html += '
'; html += ''; [48, 60, 72, 84].forEach(function(t) { var imp = solveForRate(monthlyPmt, principal, t); var totalInt = (monthlyPmt * t) - principal; // Canadian semi-annual compounding (Interest Act §4), matching // calcMonthly() and the lower benchmark loop in CASE 2. var benchR2 = Math.pow(1 + benchmarkRate / 200, 1/6) - 1; var benchPmt2 = principal * (benchR2 * Math.pow(1 + benchR2, t)) / (Math.pow(1 + benchR2, t) - 1); var benchInt = (benchPmt2 * t) - principal; var diff2 = totalInt - benchInt; var rateStr = imp > 0 ? imp.toFixed(2) + '%' : 'N/A'; var color = imp > 0 && imp > benchmarkRate + 1 ? 'color: var(--danger-deep);font-weight:600;' : imp > 0 && imp > benchmarkRate ? 'color: var(--warn-ink);' : 'color:var(--success);'; html += ''; }); html += '
TermImplied RateTotal Interestvs. Benchmark
' + t + ' mo' + rateStr + '$' + Math.round(Math.max(0, totalInt)).toLocaleString('en-CA') + '' + (diff2 > 0 ? '+$' + Math.round(diff2).toLocaleString('en-CA') : '$0') + '
'; html += '

If any rate looks higher than expected, add-ons or fees may be rolled into the payment. Enter your term above for a specific analysis, or run the full deal analyzer below.

'; } } else { // CASE 2: Payment only, no price html += '
What you\'re financing at $' + Math.round(paymentRaw).toLocaleString('en-CA') + '/' + (qcFreq === 'monthly' ? 'month' : qcFreq === 'biweekly' ? 'bi-week' : 'week') + ':
'; html += '
'; html += ''; [48, 60, 72, 84].forEach(function(t) { html += ''; [3, BENCHMARKS.newRate, 7, 9].forEach(function(rate) { var r = Math.pow(1 + rate / 200, 1/6) - 1; var princ = monthlyPmt * (Math.pow(1 + r, t) - 1) / (r * Math.pow(1 + r, t)); html += ''; }); html += ''; }); html += '
Termat 3%at ' + BENCHMARKS.newRate + '%at 7%at 9%
' + t + ' mo$' + Math.round(princ).toLocaleString('en-CA') + '
'; html += '

These figures represent the total amount financed (including HST). Enter the vehicle price above for a rate-specific analysis.

'; } // CTA html += '
'; html += '

Want the full picture? Run the complete deal analysis.

'; html += ''; html += '
'; results.innerHTML = html; results.style.display = 'block'; // Wire CTA document.getElementById('qcToFull').addEventListener('click', function() { // Pre-fill Step 1 with Quick Check data if available if (price > 0) { document.getElementById('sellingPrice').value = price.toLocaleString('en-CA'); state.sellingPrice = price; } document.getElementById('quickCheckContainer').style.display = 'none'; window.scrollTo({ top: document.getElementById('progressContainer').offsetTop - 80, behavior: 'smooth' }); }); // GA4 trackEvent('quick_check_complete', { has_price: price > 0, has_term: term > 0, frequency: qcFreq }); }); })();