Profitability: Understand Your Numbers and Keep More of What You Earn
Most workshops are busy. Not all of them are profitable. This page covers the numbers, strategies, and mindset shifts that help you keep more of what you work so hard to earn.
Check Your Workshop Health ScoreWhy Most Workshops Struggle With Profitability
Here is a scenario that might sound familiar. You are flat out every day. The workshop is booked. Your technicians are busy. Customers keep coming in. But at the end of the month, when you look at what is left in the account, it does not match the effort you put in.
Most workshop owners price their labour based on what competitors charge rather than what it actually costs them to deliver the work. The result is a labour rate that covers wages but leaves nothing for profit, overheads, or growth.
Then there is the work you do not bill for. The extra half hour on a job that ran over. The courtesy check you did not charge for. The come-back you absorbed. These small leaks add up to thousands of dollars every month.
And most owners do not track parts margin separately from labour margin, which means they have no idea where the profit actually comes from or where it is disappearing to.
The good news is that profitability is not about working harder. It is about understanding your numbers and making better decisions with the information you already have.
What You Need to Know About Profitability
1 Labour Gross Profit
Labour Gross Profit is the profit remaining after paying technician wages, expressed as a percentage of your total labour revenue. It is the single most important indicator of whether your pricing is healthy.
If you bill $40,000 in labour and pay $16,000 in technician wages (including super), your Labour Gross Profit is 60%. That means 60 cents of every labour dollar stays in the business to cover overheads, rent, equipment, and your own income.
Benchmark: Aim for 60–70% or higher. Below 55% means your labour pricing almost certainly needs a review. Many workshops we work with have improved this number by 10–15 points simply by recalculating their true cost per productive hour and adjusting their rate.
2 Effective Labour Rate
Your posted labour rate is what you charge. Your Effective Labour Rate is what you actually earn per hour of technician time. The gap between the two represents all the revenue that leaks out through unbilled work, discounting, under-quoting, and downtime.
If your posted rate is $180/hour but your effective rate is $130/hour, you have a $50/hour gap. Across three technicians working 40 hours a week, that gap represents $6,000 per week in lost revenue potential.
Practical tip: Audit one week of completed jobs. Compare the time quoted against the time actually spent. How many hours were given away? Multiply those hours by your posted rate. That is the revenue you left on the table in a single week.
3 Average Repair Order
Your Average Repair Order (ARO) is the total revenue divided by the number of completed jobs. Small increases in ARO have a massive compound effect. If you complete 40 jobs a week and increase your ARO by just $50, that is an extra $2,000 per week — over $100,000 per year.
The most effective way to increase ARO is not upselling. It is performing a thorough digital vehicle inspection on every job and presenting the findings to the customer with photos. Customers approve work they can see and trust.
Practical tip: Track your ARO monthly. The absolute number matters less than the trend. Is it going up, down, or flat? If it is flat, look at how consistently your team is performing inspections and presenting findings.
4 Parts Margin
Many workshop owners focus on labour revenue but overlook parts as a profit centre. The margin you make on parts — the difference between what you pay and what you charge — can significantly impact your overall profitability.
Practical tip: Establish a standard parts markup policy and apply it consistently. A tiered approach works well — higher percentage markup on low-cost items, moderate markup on mid-range, and lower percentage (but higher dollar) markup on expensive parts. Review your parts margin monthly alongside your labour margin.
5 Common Profit Leaks
Profit leaks are the small, recurring losses that individually seem minor but collectively drain thousands from your business every month. The most common ones we see across workshops are unbilled time, courtesy work, come-backs, and poor job costing.
Practical tip: Pick one of these leaks and focus on it for a month. Track it, measure it, and put a process in place to reduce it. Once you have plugged one leak, move to the next. Small changes compound quickly.
Three Things You Can Do This Week
Calculate Your Labour Gross Profit
Pull up last month’s total labour revenue and total technician wages including super. Divide the difference by revenue and multiply by 100. If it is below 60%, your pricing needs a review.
Audit One Week of Jobs for Unbilled Time
Look at every completed job from last week. Compare time quoted against time actually spent. Multiply the difference by your posted rate. That number is what you gave away in a single week.
Review Your Labour Rate Against Your Costs
Calculate what it actually costs per hour to have a technician available — wages, super, leave loading, training, downtime, and overheads. Compare that to your posted rate. Is the gap big enough to cover profit?
Where Does Your Workshop Stand on Profitability?
Take the free Workshop Health Score and get a personalised snapshot of your business across profitability, productivity, management, customer experience, and quality of life. It takes 2 minutes.
Get Your Free Health ScoreFree Guide
The 5 Numbers Every Repairer Must Know
Download the Free Guide
A 14-page guide to the five KPIs that separate thriving workshops from struggling ones. Formulas, benchmarks, and practical tips you can act on this week.
Explore More Topics
.lgp-calc-wrap * { box-sizing: border-box; margin: 0; padding: 0; } .lgp-calc-wrap { font-family: ‘Inter’, ‘Segoe UI’, Arial, sans-serif; max-width: 680px; margin: 0 auto; color: #2c3e50; } .lgp-card { background: #fff; border-radius: 16px; box-shadow: 0 4px 32px rgba(13,138,138,0.10), 0 1px 4px rgba(0,0,0,0.06); overflow: hidden; } /* ── Header ── */ .lgp-header { background: linear-gradient(135deg, #1e5778 0%, #0d8a8a 100%); padding: 32px 36px 28px; color: #fff !important; } .lgp-header-tag { display: inline-block; background: rgba(255,255,255,0.18); font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 10px; border-radius: 20px; margin-bottom: 12px; } .lgp-header h2 { font-size: 22px; font-weight: 700; margin-bottom: 6px; line-height: 1.3; } .lgp-header p { font-size: 14px; opacity: 0.88; line-height: 1.5; } /* ── Body ── */ .lgp-body { padding: 32px 36px; } /* ── Inputs ── */ .lgp-section-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #0d8a8a; margin-bottom: 14px; } .lgp-input-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 6px; } .lgp-input-group { margin-bottom: 16px; } .lgp-label { display: block; font-size: 13px; font-weight: 600; color: #2c3e50; margin-bottom: 6px; line-height: 1.4; } .lgp-label-hint { font-size: 12px; font-weight: 400; color: #657574; margin-left: 4px; } .lgp-input-wrap { position: relative; } .lgp-input-prefix { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); font-size: 15px; font-weight: 600; color: #657574; pointer-events: none; } .lgp-input-suffix { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); font-size: 13px; font-weight: 600; color: #959f9d; pointer-events: none; } .lgp-input { width: 100%; padding: 13px 14px 13px 30px; border: 2px solid #e2e8ea; border-radius: 10px; font-size: 16px; font-weight: 600; color: #2c3e50; background: #f7f9f9; transition: border-color 0.2s, background 0.2s; outline: none; -moz-appearance: textfield; } .lgp-input.no-prefix { padding-left: 14px; } .lgp-input.has-suffix { padding-right: 52px; } .lgp-input::-webkit-outer-spin-button, .lgp-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .lgp-input:focus { border-color: #0d8a8a; background: #fff; } .lgp-input.error { border-color: #e05252; background: #fff5f5; } .lgp-error-msg { font-size: 12px; color: #e05252; margin-top: 5px; display: none; } /* ── Helper tip ── */ .lgp-tip { background: #f0fafa; border: 1px solid #c0e8e8; border-radius: 8px; padding: 10px 14px; font-size: 12px; color: #1a6060; line-height: 1.5; margin-bottom: 20px; } .lgp-tip strong { font-weight: 700; } /* ── Button ── */ .lgp-btn-calculate { width: 100%; padding: 16px; background: linear-gradient(135deg, #0d8a8a, #057883) !important; color: #fff !important; border: none; border-radius: 10px; font-size: 16px; font-weight: 700; cursor: pointer; transition: opacity 0.2s, transform 0.1s; letter-spacing: 0.01em; } .lgp-btn-calculate:hover { opacity: 0.92; transform: translateY(-1px); } .lgp-btn-calculate:active { transform: translateY(0); } /* ── Divider ── */ .lgp-divider { height: 1px; background: #e8eef0; margin: 28px 0; } /* ── Results ── */ .lgp-results { display: none; } .lgp-results.visible { display: block; animation: lgpFadeIn 0.4s ease; } @keyframes lgpFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* Score row */ .lgp-score-row { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; } .lgp-score-circle { flex-shrink: 0; width: 90px; height: 90px; border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 26px; font-weight: 800; color: #fff; line-height: 1; } .lgp-score-circle span { font-size: 12px; font-weight: 600; opacity: 0.85; margin-top: 1px; } .lgp-score-text h3 { font-size: 17px; font-weight: 700; margin-bottom: 4px; line-height: 1.3; } .lgp-score-text p { font-size: 13px; color: #657574; line-height: 1.5; } /* Gauge */ .lgp-gauge-wrap { margin-bottom: 24px; } .lgp-gauge-label { font-size: 12px; font-weight: 600; color: #657574; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 8px; } .lgp-gauge-track { height: 12px; border-radius: 6px; background: linear-gradient(to right, #e05252 0%, #e07b39 30%, #f4c430 50%, #8dc63f 65%, #0d8a8a 100%); position: relative; margin-bottom: 6px; } .lgp-gauge-needle { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 18px; height: 18px; background: #fff; border: 3px solid #2c3e50; border-radius: 50%; box-shadow: 0 1px 4px rgba(0,0,0,0.2); transition: left 0.7s cubic-bezier(.34,1.56,.64,1); } .lgp-gauge-bands { display: flex; justify-content: space-between; font-size: 10px; color: #959f9d; font-weight: 500; } /* ── Time breakdown panel ── */ .lgp-breakdown { background: #f7f9f9; border-radius: 12px; border: 1px solid #e2e8ea; overflow: hidden; margin-bottom: 24px; } .lgp-breakdown-header { background: #edf6f6; border-bottom: 1px solid #d0e8e8; padding: 12px 18px; display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: #0d8a8a; } .lgp-breakdown-grid { display: grid; grid-template-columns: repeat(3, 1fr); } .lgp-breakdown-col { padding: 16px 18px; border-right: 1px solid #e2e8ea; } .lgp-breakdown-col:last-child { border-right: none; } .lgp-breakdown-period { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: #959f9d; margin-bottom: 10px; } .lgp-breakdown-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; font-size: 12px; } .lgp-breakdown-row-label { color: #657574; } .lgp-breakdown-row-value { font-weight: 700; color: #2c3e50; } .lgp-breakdown-row-value.profit { color: #0d8a8a; } .lgp-breakdown-row-value.profit.warning { color: #c07000; } .lgp-breakdown-row-value.profit.danger { color: #c0392b; } .lgp-breakdown-divider { height: 1px; background: #e2e8ea; margin: 8px 0; } .lgp-breakdown-profit-label { font-size: 11px; color: #657574; margin-bottom: 2px; } .lgp-breakdown-profit-big { font-size: 20px; font-weight: 800; color: #0d8a8a; line-height: 1; } .lgp-breakdown-profit-big.warning { color: #c07000; } .lgp-breakdown-profit-big.danger { color: #c0392b; } /* Insight */ .lgp-insight { border-radius: 10px; padding: 16px 18px; margin-bottom: 24px; font-size: 14px; line-height: 1.6; border: 1px solid transparent; } .lgp-insight.status-excellent { background: #edfaf7; border-color: #b3e8de; color: #0a5e52; } .lgp-insight.status-good { background: #f0faf0; border-color: #b9e4b9; color: #2e6b2e; } .lgp-insight.status-ok { background: #fff8ec; border-color: #fddfa0; color: #7a4f00; } .lgp-insight.status-low { background: #fff3f0; border-color: #ffc9b8; color: #8a2010; } .lgp-insight strong { font-weight: 700; } /* Improvement */ .lgp-improvement { background: linear-gradient(135deg, #1e5778 0%, #0d8a8a 100%); border-radius: 10px; padding: 18px 20px; color: #fff; margin-bottom: 28px; } .lgp-improvement-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.75; margin-bottom: 8px; } .lgp-improvement p { font-size: 14px; line-height: 1.6; opacity: 0.95; } .lgp-improvement strong { font-weight: 800; } /* Rate increase scenario */ .lgp-scenario { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 12px; } .lgp-scenario-box { background: rgba(255,255,255,0.15); border-radius: 8px; padding: 10px 12px; text-align: center; } .lgp-scenario-label { font-size: 10px; opacity: 0.75; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; } .lgp-scenario-value { font-size: 16px; font-weight: 800; } .lgp-scenario-period { font-size: 10px; opacity: 0.7; margin-top: 1px; } /* Email */ .lgp-email-section { background: #f7f9f9; border-radius: 12px; padding: 24px; border: 1px solid #e2e8ea; } .lgp-email-section h4 { font-size: 16px; font-weight: 700; color: #2c3e50; margin-bottom: 4px; } .lgp-email-section > p { font-size: 13px; color: #657574; margin-bottom: 16px; line-height: 1.5; } .lgp-email-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 12px; } .lgp-email-input { width: 100%; padding: 12px 14px; border: 2px solid #e2e8ea; border-radius: 8px; font-size: 14px; color: #2c3e50; background: #fff; outline: none; transition: border-color 0.2s; } .lgp-email-input:focus { border-color: #0d8a8a; } .lgp-btn-email { width: 100%; padding: 13px; background: #1e5778; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 700; cursor: pointer; transition: background 0.2s, transform 0.1s; } .lgp-btn-email:hover { background: #174864; transform: translateY(-1px); } .lgp-privacy { text-align: center; font-size: 11px; color: #959f9d; margin-top: 10px; } .lgp-email-success { display: none; text-align: center; padding: 16px 0 4px; } .lgp-email-success .lgp-tick { font-size: 36px; margin-bottom: 8px; } .lgp-email-success h4 { font-size: 16px; font-weight: 700; color: #0d8a8a; margin-bottom: 4px; } .lgp-email-success p { font-size: 13px; color: #657574; margin-bottom: 0; } /* ── What If sliders ── */ .lgp-whatif { background: #fff; border: 2px solid #0d8a8a; border-radius: 12px; overflow: hidden; margin-bottom: 28px; } .lgp-whatif-header { background: linear-gradient(135deg, #0d8a8a, #057883) !important; padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; gap: 12px; } .lgp-whatif-title { font-size: 13px; font-weight: 700; color: #fff !important; text-transform: uppercase; letter-spacing: 0.07em; } .lgp-whatif-reset { background: rgba(255,255,255,0.2); border: none; color: #fff !important; font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 20px; cursor: pointer; transition: background 0.2s; letter-spacing: 0.04em; } .lgp-whatif-reset:hover { background: rgba(255,255,255,0.32); } .lgp-whatif-sliders { padding: 20px 20px 4px; } .lgp-slider-group { margin-bottom: 18px; } .lgp-slider-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; } .lgp-slider-name { font-size: 13px; font-weight: 600; color: #2c3e50; } .lgp-slider-value { font-size: 13px; font-weight: 700; color: #0d8a8a; min-width: 80px; text-align: right; } .lgp-slider-meta { font-size: 11px; color: #959f9d; margin-top: 4px; } input[type=range].lgp-range { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; border-radius: 3px; background: #e2e8ea; outline: none; cursor: pointer; } input[type=range].lgp-range::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%; background: #0d8a8a; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.2); cursor: pointer; transition: background 0.2s; } input[type=range].lgp-range::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: #0d8a8a; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.2); cursor: pointer; } input[type=range].lgp-range::-webkit-slider-runnable-track { border-radius: 3px; } /* What If impact panel */ .lgp-whatif-impact { margin: 0 20px 20px; background: #f7f9f9; border-radius: 10px; border: 1px solid #e2e8ea; overflow: hidden; } .lgp-impact-grid { display: grid; grid-template-columns: repeat(3, 1fr); } .lgp-impact-col { padding: 14px 16px; border-right: 1px solid #e2e8ea; } .lgp-impact-col:last-child { border-right: none; } .lgp-impact-period { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: #959f9d; margin-bottom: 10px; } .lgp-impact-row { margin-bottom: 6px; } .lgp-impact-label { font-size: 10px; color: #959f9d; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1px; } .lgp-impact-current { font-size: 13px; font-weight: 600; color: #657574; } .lgp-impact-new { font-size: 16px; font-weight: 800; color: #0d8a8a; } .lgp-impact-new.neutral { color: #657574; } .lgp-impact-arrow { font-size: 10px; color: #959f9d; margin: 2px 0; } .lgp-whatif-gain { background: linear-gradient(135deg, #1e5778, #0d8a8a); padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; gap: 12px; } .lgp-whatif-gain-label { font-size: 12px; color: rgba(255,255,255,0.8); font-weight: 600; } .lgp-whatif-gain-value { font-size: 22px; font-weight: 800; color: #fff; white-space: nowrap; } .lgp-whatif-gain-sub { font-size: 11px; color: rgba(255,255,255,0.65); margin-top: 1px; } .lgp-whatif-gain-zero { font-size: 13px; color: rgba(255,255,255,0.6); font-style: italic; } @media (max-width: 520px) { .lgp-body { padding: 24px 20px; } .lgp-header { padding: 24px 20px 20px; } .lgp-input-grid { grid-template-columns: 1fr; } .lgp-breakdown-grid { grid-template-columns: 1fr; } .lgp-breakdown-col { border-right: none; border-bottom: 1px solid #e2e8ea; } .lgp-breakdown-col:last-child { border-bottom: none; } .lgp-email-row { grid-template-columns: 1fr; } .lgp-scenario { grid-template-columns: 1fr; } .lgp-impact-grid { grid-template-columns: 1fr; } .lgp-impact-col { border-right: none; border-bottom: 1px solid #e2e8ea; } .lgp-impact-col:last-child { border-bottom: none; } }
Labour Gross Profit Calculator
Enter your labour rate and costs to instantly see your profit margin — and what it adds up to week by week, month by month, year by year.
—
—
📬 Get your full breakdown by email
We’ll send your results along with a practical guide to improving your Labour Gross Profit — including how to calculate your minimum viable labour rate.
(function() { var HUBSPOT_PORTAL_ID = ‘23910099’; var HUBSPOT_FORM_GUID = ‘096dbf78-6fd2-44c7-b9f0-6c8248bc33ac’; var lastLGP = 0, lastRate = 0, lastAnnualProfit = 0; window.lgpCalculate = function() { var rateEl = document.getElementById(‘lgp-rate’); var costEl = document.getElementById(‘lgp-cost’); var techsEl = document.getElementById(‘lgp-techs’); var hoursEl = document.getElementById(‘lgp-hours’); var rate = parseFloat(rateEl.value); var cost = parseFloat(costEl.value); var techs = parseFloat(techsEl.value); var hours = parseFloat(hoursEl.value); var valid = true; // Reset [‘lgp-rate’,’lgp-cost’,’lgp-techs’,’lgp-hours’].forEach(function(id) { document.getElementById(id).classList.remove(‘error’); }); [‘lgp-rate-err’,’lgp-cost-err’,’lgp-techs-err’,’lgp-hours-err’].forEach(function(id) { document.getElementById(id).style.display = ‘none’; }); if (!rateEl.value || isNaN(rate) || rate <= 0) { rateEl.classList.add('error'); document.getElementById('lgp-rate-err').style.display = 'block'; valid = false; } if (!costEl.value || isNaN(cost) || cost < 0) { costEl.classList.add('error'); document.getElementById('lgp-cost-err').style.display = 'block'; valid = false; } if (!techsEl.value || isNaN(techs) || techs <= 0) { techsEl.classList.add('error'); document.getElementById('lgp-techs-err').style.display = 'block'; valid = false; } if (!hoursEl.value || isNaN(hours) || hours = rate) { costEl.classList.add(‘error’); document.getElementById(‘lgp-cost-err’).textContent = ‘Tech cost can\’t exceed your labour rate. Check your numbers.’; document.getElementById(‘lgp-cost-err’).style.display = ‘block’; valid = false; } if (!valid) return; // Core figures var lgp = ((rate – cost) / rate) * 100; var profitPerHr = rate – cost; var wRevenue = rate * techs * hours; var wCost = cost * techs * hours; var wProfit = profitPerHr * techs * hours; var mRevenue = wRevenue * 4.333; var mCost = wCost * 4.333; var mProfit = wProfit * 4.333; var aRevenue = wRevenue * 52; var aCost = wCost * 52; var aProfit = wProfit * 52; // $10/hr rate increase scenario var rateIncrease = 10; var sWeek = rateIncrease * techs * hours; var sMonth = sWeek * 4.333; var sYear = sWeek * 52; lastLGP = lgp; lastRate = rate; lastAnnualProfit = aProfit; // Store base values for What If sliders baseWeekProfit = wProfit; baseRate = rate; baseCost = cost; baseTechs = techs; baseHours = hours; lgpResetSliders(); // LGP display document.getElementById(‘lgp-pct-display’).textContent = lgp.toFixed(1) + ‘%’; // Gauge setTimeout(function() { document.getElementById(‘lgp-needle’).style.left = Math.min(Math.max(lgp, 0), 100) + ‘%’; }, 100); // Banding var circle = document.getElementById(‘lgp-circle’); var title = document.getElementById(‘lgp-status-title’); var sub = document.getElementById(‘lgp-status-sub’); var insight = document.getElementById(‘lgp-insight’); var impText = document.getElementById(‘lgp-improvement-text’); var impLabel = document.getElementById(‘lgp-improvement-label’); var profitClass = ”; insight.className = ‘lgp-insight’; if (lgp >= 70) { circle.style.background = ‘linear-gradient(135deg, #0d8a8a, #057883)’; title.textContent = ‘Excellent — strong pricing margin’; sub.textContent = ‘You\’re keeping over 70 cents of every labour dollar billed.’; insight.classList.add(‘status-excellent’); insight.innerHTML = ‘Your LGP of ‘ + lgp.toFixed(1) + ‘% is excellent. At ‘ + fmt(aProfit) + ‘ annual labour profit, your pricing is working hard for you. The next frontier is parts margin and ARO — use digital inspections to present additional work on every job.’; impLabel.textContent = ‘💡 Even at this level — a $10/hr rate increase adds:’; profitClass = ”; } else if (lgp >= 60) { circle.style.background = ‘linear-gradient(135deg, #2e8b2e, #44b044)’; title.textContent = ‘Healthy — inside the benchmark range’; sub.textContent = ‘Your LGP is in the 60–70% zone. Small improvements compound fast.’; insight.classList.add(‘status-good’); insight.innerHTML = ‘An LGP of ‘ + lgp.toFixed(1) + ‘% is healthy. You\’re generating ‘ + fmt(wProfit) + ‘ labour profit per week. Closing the gap to 70% would add ‘ + fmt(sYear) + ‘ per year — usually achievable with a modest rate review or tightening unbilled time.’; impLabel.textContent = ‘💡 A $10/hr rate increase from here adds:’; profitClass = ”; } else if (lgp >= 55) { circle.style.background = ‘linear-gradient(135deg, #b37800, #e09900)’; title.textContent = ‘Below average — room to improve’; sub.textContent = ‘You\’re covering wages but margins are thin. Your rate needs a review.’; insight.classList.add(‘status-ok’); insight.innerHTML = ‘At ‘ + lgp.toFixed(1) + ‘%, your margin is below the healthy benchmark of 60%. You\’re generating ‘ + fmt(wProfit) + ‘/week in labour profit — but at 60% that would be ‘ + fmt((rate * 0.6 – cost) * techs * hours) + ‘/week. The most common fix is a labour rate that hasn\’t kept pace with wage increases. When did you last review your rate?’; impLabel.textContent = ‘💡 A $10/hr rate increase would add:’; profitClass = ‘warning’; } else { circle.style.background = ‘linear-gradient(135deg, #c0392b, #e05252)’; title.textContent = ‘Critical — pricing needs urgent review’; sub.textContent = ‘Below 55% means wages are consuming most of your labour revenue.’; insight.classList.add(‘status-low’); insight.innerHTML = ‘An LGP of ‘ + lgp.toFixed(1) + ‘% is below the minimum sustainable threshold. You\’re generating only ‘ + fmt(wProfit) + ‘/week in labour profit — not enough to cover overheads, equipment, and your own wage after wages are paid. A $10/hr rate increase alone would add ‘ + fmt(sYear) + ‘/year. This needs attention this week.’; impLabel.textContent = ‘⚠️ A $10/hr rate increase would immediately add:’; profitClass = ‘danger’; } // Populate breakdown var profitIds = [‘lgp-w-profit’,’lgp-m-profit’,’lgp-a-profit’]; profitIds.forEach(function(id) { var el = document.getElementById(id); el.className = ‘lgp-breakdown-profit-big’ + (profitClass ? ‘ ‘ + profitClass : ”); }); document.getElementById(‘lgp-w-rev’).textContent = fmt(wRevenue); document.getElementById(‘lgp-w-cost’).textContent = fmt(wCost); document.getElementById(‘lgp-w-profit’).textContent = fmt(wProfit); document.getElementById(‘lgp-m-rev’).textContent = fmt(mRevenue); document.getElementById(‘lgp-m-cost’).textContent = fmt(mCost); document.getElementById(‘lgp-m-profit’).textContent = fmt(mProfit); document.getElementById(‘lgp-a-rev’).textContent = fmt(aRevenue); document.getElementById(‘lgp-a-cost’).textContent = fmt(aCost); document.getElementById(‘lgp-a-profit’).textContent = fmt(aProfit); // Scenario impText.innerHTML = ‘If you raised your rate by just $10/hr — from ‘ + fmtRate(rate) + ‘ to ‘ + fmtRate(rate + 10) + ‘ — across ‘ + techs + ‘ tech’ + (techs > 1 ? ‘s’ : ”) + ‘ billing ‘ + hours + ‘ hours/week:’; document.getElementById(‘lgp-s-week’).textContent = fmt(sWeek); document.getElementById(‘lgp-s-month’).textContent = fmt(sMonth); document.getElementById(‘lgp-s-year’).textContent = fmt(sYear); // Show var results = document.getElementById(‘lgp-results’); results.classList.add(‘visible’); setTimeout(function() { results.scrollIntoView({ behavior: ‘smooth’, block: ‘nearest’ }); }, 100); }; // Store base figures for What If calculations var baseWeekProfit = 0, baseRate = 0, baseCost = 0, baseTechs = 0, baseHours = 0; window.lgpUpdateWhatIf = function() { if (!baseRate) return; // not yet calculated var ratePct = parseFloat(document.getElementById(‘lgp-si-rate’).value) || 0; var costPct = parseFloat(document.getElementById(‘lgp-si-cost’).value) || 0; var extraHrs = parseFloat(document.getElementById(‘lgp-si-hours’).value) || 0; var extraTechs = parseFloat(document.getElementById(‘lgp-si-techs’).value) || 0; var newRate = baseRate * (1 + ratePct / 100); var newCost = baseCost * (1 – costPct / 100); var newHours = baseHours + extraHrs; var newTechs = baseTechs + extraTechs; var newWeekProfit = (newRate – newCost) * newTechs * newHours; var newMonthProfit = newWeekProfit * 4.333; var newYearProfit = newWeekProfit * 52; var gainYear = newYearProfit – (baseWeekProfit * 52); // Slider labels document.getElementById(‘lgp-si-rate-label’).textContent = ratePct === 0 ? ‘+0% no change’ : ‘+’ + ratePct + ‘% ‘ + fmtRate(baseRate) + ‘ → ‘ + fmtRate(newRate); document.getElementById(‘lgp-si-cost-label’).textContent = costPct === 0 ? ‘-0% no change’ : ‘-‘ + costPct + ‘% ‘ + fmtRate(baseCost) + ‘ → ‘ + fmtRate(newCost); document.getElementById(‘lgp-si-hours-label’).textContent = extraHrs === 0 ? ‘+0 hrs no change’ : ‘+’ + extraHrs + ‘ hrs/wk ‘ + baseHours + ‘ → ‘ + newHours + ‘ hrs’; // Meta hints document.getElementById(‘lgp-si-rate-meta’).textContent = ratePct === 0 ? ‘Move the slider to see the impact of increasing your labour rate’ : ‘Your new rate would be ‘ + fmtRate(newRate) + ‘ (+’ + fmt(ratePct / 100 * baseRate) + ‘/hr)’; document.getElementById(‘lgp-si-cost-meta’).textContent = costPct === 0 ? ‘E.g. reducing overtime, improving scheduling, or renegotiating supplier costs’ : ‘Tech cost drops from ‘ + fmtRate(baseCost) + ‘ to ‘ + fmtRate(newCost) + ‘ per hour’; document.getElementById(‘lgp-si-hours-meta’).textContent = extraHrs === 0 ? ‘Even 1 extra billable hour per tech per day adds up significantly’ : baseTechs + ‘ tech’ + (baseTechs > 1 ? ‘s’ : ”) + ‘ × ‘ + extraHrs + ‘ extra hrs/wk = ‘ + fmt(extraHrs * baseTechs * 52) + ‘ extra billed hours per year’; document.getElementById(‘lgp-si-techs-label’).innerHTML = extraTechs === 0 ? ‘+0 no change’ : ‘+’ + extraTechs + ‘ tech’ + (extraTechs > 1 ? ‘s’ : ”) + ‘ ‘ + baseTechs + ‘ → ‘ + newTechs + ‘ total’; document.getElementById(‘lgp-si-techs-meta’).textContent = extraTechs === 0 ? ‘Assumes fully billable from week 1 — allow for a ramp-up period in reality’ : ‘Adding ‘ + extraTechs + ‘ tech’ + (extraTechs > 1 ? ‘s’ : ”) + ‘ at ‘ + newHours + ‘ hrs/wk each — remember to factor in ramp-up time’; // Impact panel document.getElementById(‘lgp-wi-cur-w’).textContent = fmt(baseWeekProfit); document.getElementById(‘lgp-wi-cur-m’).textContent = fmt(baseWeekProfit * 4.333); document.getElementById(‘lgp-wi-cur-a’).textContent = fmt(baseWeekProfit * 52); var noChange = gainYear === 0; document.getElementById(‘lgp-wi-new-w’).textContent = fmt(newWeekProfit); document.getElementById(‘lgp-wi-new-m’).textContent = fmt(newMonthProfit); document.getElementById(‘lgp-wi-new-a’).textContent = fmt(newYearProfit); [‘lgp-wi-new-w’,’lgp-wi-new-m’,’lgp-wi-new-a’].forEach(function(id) { document.getElementById(id).className = ‘lgp-impact-new’ + (noChange ? ‘ neutral’ : ”); }); // Gain callout document.getElementById(‘lgp-wi-gain’).textContent = gainYear === 0 ? ‘—’ : ‘+’ + fmt(gainYear); document.getElementById(‘lgp-wi-gain-sub’).textContent = gainYear === 0 ? ‘Adjust the sliders above to see your potential’ : ‘Compared to your current ‘ + fmt(baseWeekProfit * 52) + ‘ annual labour profit’; // Track slider fill colour [‘lgp-si-rate’,’lgp-si-cost’,’lgp-si-hours’,’lgp-si-techs’].forEach(function(id) { var el = document.getElementById(id); var max = parseFloat(el.max); var val = parseFloat(el.value); var pct = max === 0 ? 0 : (val / max) * 100; el.style.background = ‘linear-gradient(to right, #0d8a8a ‘ + pct + ‘%, #e2e8ea ‘ + pct + ‘%)’; }); }; window.lgpResetSliders = function() { [‘lgp-si-rate’,’lgp-si-cost’,’lgp-si-hours’,’lgp-si-techs’].forEach(function(id) { document.getElementById(id).value = 0; document.getElementById(id).style.background = ‘#e2e8ea’; }); lgpUpdateWhatIf(); }; window.lgpSubmitEmail = function() { var fname = document.getElementById(‘lgp-fname’).value.trim(); var email = document.getElementById(‘lgp-email’).value.trim(); if (!fname) { document.getElementById(‘lgp-fname’).style.borderColor = ‘#e05252’; document.getElementById(‘lgp-fname’).focus(); return; } if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { document.getElementById(‘lgp-email’).style.borderColor = ‘#e05252’; document.getElementById(‘lgp-email’).focus(); return; } var rate = parseFloat(document.getElementById(‘lgp-rate’).value) || 0; var techs = parseFloat(document.getElementById(‘lgp-techs’).value) || 0; var hours = parseFloat(document.getElementById(‘lgp-hours’).value) || 0; fetch(‘https://api.hsforms.com/submissions/v3/integration/submit/’ + HUBSPOT_PORTAL_ID + ‘/’ + HUBSPOT_FORM_GUID, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify({ fields: [ { name: ‘firstname’, value: fname }, { name: ’email’, value: email }, { name: ‘message’, value: ‘LGP Calculator | Rate: $’ + rate + ‘/hr | LGP: ‘ + lastLGP.toFixed(1) + ‘% | Techs: ‘ + techs + ‘ | Hrs/wk: ‘ + hours + ‘ | Annual labour profit: ‘ + fmt(lastAnnualProfit) }, { name: ‘lead_source’, value: ‘LGP Calculator — Workshop University’ } ], context: { pageUri: window.location.href, pageName: document.title } }) }).catch(function() {}); document.getElementById(‘lgp-email-form’).style.display = ‘none’; document.getElementById(‘lgp-email-success’).style.display = ‘block’; }; function fmt(n) { return ‘$’ + Math.round(n).toLocaleString(‘en-AU’); } function fmtRate(n) { return ‘$’ + Math.round(n) + ‘/hr’; } })();
Marketing > Forms > [form] > Embed ============================================================ –>.elr-calc-wrap * { box-sizing: border-box; margin: 0; padding: 0; } .elr-calc-wrap { font-family: ‘Inter’, ‘Segoe UI’, Arial, sans-serif; max-width: 680px; margin: 0 auto; color: #2c3e50; } .elr-card { background: #fff; border-radius: 16px; box-shadow: 0 4px 32px rgba(13,138,138,0.10), 0 1px 4px rgba(0,0,0,0.06); overflow: hidden; } /* Header */ .elr-header { background: linear-gradient(135deg, #0d8a8a 0%, #1e5778 100%); padding: 32px 36px 28px; color: #fff; } .elr-header-tag { display: inline-block; background: rgba(255,255,255,0.18); color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 10px; border-radius: 20px; margin-bottom: 12px; } .elr-header h2 { font-size: 22px; font-weight: 700; margin-bottom: 6px; line-height: 1.3; } .elr-header p { font-size: 14px; opacity: 0.88; line-height: 1.5; } /* Body */ .elr-body { padding: 32px 36px; } /* Input group */ .elr-input-group { margin-bottom: 20px; } .elr-label { display: block; font-size: 13px; font-weight: 600; color: #2c3e50; margin-bottom: 6px; } .elr-label-hint { font-size: 12px; font-weight: 400; color: #657574; margin-left: 4px; } .elr-input-wrap { position: relative; display: flex; align-items: center; } .elr-input-prefix { position: absolute; left: 14px; font-size: 15px; font-weight: 600; color: #657574; pointer-events: none; } .elr-input-suffix { position: absolute; right: 14px; font-size: 13px; font-weight: 600; color: #959f9d; pointer-events: none; } .elr-input { width: 100%; padding: 13px 14px 13px 28px; border: 2px solid #e2e8ea; border-radius: 10px; font-size: 16px; font-weight: 600; color: #2c3e50; background: #f7f9f9; transition: border-color 0.2s, background 0.2s; outline: none; appearance: none; -moz-appearance: textfield; } .elr-input.no-prefix { padding-left: 14px; } .elr-input.has-suffix { padding-right: 50px; } .elr-input::-webkit-outer-spin-button, .elr-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .elr-input:focus { border-color: #0d8a8a; background: #fff; } .elr-input.error { border-color: #e05252; background: #fff5f5; } .elr-error-msg { font-size: 12px; color: #e05252; margin-top: 5px; display: none; } .elr-input-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } @media (max-width: 520px) { .elr-input-row-2 { grid-template-columns: 1fr; } .elr-body { padding: 24px 20px; } .elr-header { padding: 24px 20px 20px; } } /* Section label */ .elr-section-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #0d8a8a; margin-bottom: 14px; margin-top: 4px; } /* Calculate button */ .elr-btn-calculate { width: 100%; padding: 16px; background: linear-gradient(135deg, #0d8a8a, #057883) !important; color: #fff !important; border: none; border-radius: 10px; font-size: 16px; font-weight: 700; cursor: pointer; transition: opacity 0.2s, transform 0.1s; margin-top: 8px; letter-spacing: 0.01em; } .elr-btn-calculate:hover { opacity: 0.92; transform: translateY(-1px); } .elr-btn-calculate:active { transform: translateY(0); } /* Divider */ .elr-divider { height: 1px; background: #e8eef0; margin: 28px 0; } /* Results */ .elr-results { display: none; } .elr-results.visible { display: block; animation: elrFadeIn 0.4s ease; } @keyframes elrFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* Rate comparison block */ .elr-rate-compare { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; margin-bottom: 24px; } .elr-rate-box { background: #f7f9f9; border-radius: 12px; padding: 18px 16px; text-align: center; } .elr-rate-box.posted { border: 2px solid #c2c5c4; } .elr-rate-box.actual { border: 2px solid #0d8a8a; } .elr-rate-box.actual.warning { border-color: #e07b39; } .elr-rate-box.actual.danger { border-color: #e05252; } .elr-rate-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #657574; margin-bottom: 6px; } .elr-rate-value { font-size: 28px; font-weight: 800; color: #2c3e50; line-height: 1; } .elr-rate-value.actual-value { color: #0d8a8a; } .elr-rate-value.actual-value.warning { color: #c07000; } .elr-rate-value.actual-value.danger { color: #c0392b; } .elr-rate-sub { font-size: 11px; color: #959f9d; margin-top: 4px; } .elr-vs { text-align: center; font-size: 12px; font-weight: 700; color: #c2c5c4; } .elr-gap-badge { display: inline-block; background: #e05252; color: #fff; font-size: 13px; font-weight: 700; padding: 3px 10px; border-radius: 20px; margin-top: 6px; } .elr-gap-badge.ok { background: #e07b39; } .elr-gap-badge.good { background: #2e8b2e; } .elr-gap-badge.excellent { background: #0d8a8a; } @media (max-width: 480px) { .elr-rate-compare { grid-template-columns: 1fr; } .elr-vs { display: none; } } /* Gauge */ .elr-gauge-wrap { margin-bottom: 24px; } .elr-gauge-label { font-size: 12px; font-weight: 600; color: #657574; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 8px; } .elr-gauge-track { height: 12px; border-radius: 6px; background: linear-gradient(to right, #e05252 0%, #e07b39 30%, #f4c430 55%, #8dc63f 75%, #0d8a8a 100%); position: relative; margin-bottom: 6px; } .elr-gauge-needle { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 18px; height: 18px; background: #fff; border: 3px solid #2c3e50; border-radius: 50%; box-shadow: 0 1px 4px rgba(0,0,0,0.2); transition: left 0.7s cubic-bezier(.34,1.56,.64,1); } .elr-gauge-bands { display: flex; justify-content: space-between; font-size: 10px; color: #959f9d; font-weight: 500; } /* Stats strip */ .elr-stats-strip { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin-bottom: 24px; } @media (max-width: 520px) { .elr-stats-strip { grid-template-columns: 1fr 1fr; } } .elr-stat-box { background: #f7f9f9; border-radius: 10px; padding: 14px 14px; border-left: 3px solid #0d8a8a; } .elr-stat-box.warning { border-left-color: #e07b39; } .elr-stat-box.danger { border-left-color: #e05252; } .elr-stat-label { font-size: 11px; font-weight: 600; color: #657574; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px; } .elr-stat-value { font-size: 19px; font-weight: 800; color: #2c3e50; line-height: 1.1; } .elr-stat-sub { font-size: 11px; color: #959f9d; margin-top: 2px; } /* Insight */ .elr-insight { border-radius: 10px; padding: 16px 18px; margin-bottom: 24px; font-size: 14px; line-height: 1.6; border: 1px solid transparent; } .elr-insight.status-excellent { background: #edfaf7; border-color: #b3e8de; color: #0a5e52; } .elr-insight.status-good { background: #f0faf0; border-color: #b9e4b9; color: #2e6b2e; } .elr-insight.status-ok { background: #fff8ec; border-color: #fddfa0; color: #7a4f00; } .elr-insight.status-low { background: #fff3f0; border-color: #ffc9b8; color: #8a2010; } .elr-insight strong { font-weight: 700; } /* Leak visualiser */ .elr-leak-visual { background: linear-gradient(135deg, #1e5778 0%, #0d8a8a 100%); border-radius: 10px; padding: 20px 22px; color: #fff; margin-bottom: 28px; } .elr-leak-visual-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.75; margin-bottom: 10px; } .elr-leak-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } @media (max-width: 480px) { .elr-leak-row { grid-template-columns: 1fr; } } .elr-leak-item {} .elr-leak-period { font-size: 11px; font-weight: 600; opacity: 0.7; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 2px; } .elr-leak-amount { font-size: 24px; font-weight: 800; line-height: 1.1; } .elr-leak-desc { font-size: 12px; opacity: 0.8; margin-top: 2px; } /* Email */ .elr-email-section { background: #f7f9f9; border-radius: 12px; padding: 24px; border: 1px solid #e2e8ea; } .elr-email-section h4 { font-size: 16px; font-weight: 700; color: #2c3e50; margin-bottom: 4px; } .elr-email-section p { font-size: 13px; color: #657574; margin-bottom: 16px; line-height: 1.5; } .elr-email-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 12px; } @media (max-width: 520px) { .elr-email-row { grid-template-columns: 1fr; } } .elr-email-input { width: 100%; padding: 12px 14px; border: 2px solid #e2e8ea; border-radius: 8px; font-size: 14px; color: #2c3e50; background: #fff; outline: none; transition: border-color 0.2s; } .elr-email-input:focus { border-color: #0d8a8a; } .elr-btn-email { width: 100%; padding: 13px; background: #1e5778; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 700; cursor: pointer; transition: background 0.2s, transform 0.1s; } .elr-btn-email:hover { background: #174864; transform: translateY(-1px); } .elr-privacy { text-align: center; font-size: 11px; color: #959f9d; margin-top: 10px; } .elr-email-success { display: none; text-align: center; padding: 16px 0 4px; } .elr-email-success .elr-tick { font-size: 36px; margin-bottom: 8px; } .elr-email-success h4 { font-size: 16px; font-weight: 700; color: #0d8a8a; margin-bottom: 4px; } .elr-email-success p { font-size: 13px; color: #657574; margin-bottom: 0; }
Effective Labour Rate Calculator
Discover the gap between what you charge and what you actually earn — and how much revenue is leaking out of your workshop every week.
📬 Get your personalised breakdown
We’ll email you a summary of your results and a step-by-step guide to closing your rate gap — the most common places revenue leaks and how to fix each one.
Results on the way!
Check your inbox shortly. In the meantime, explore the Profitability pillar to learn how to close the gap.
(function() { // ─── CONFIGURATION ─────────────────────────────────────────────────────────── var HUBSPOT_PORTAL_ID = ‘23910099’; var HUBSPOT_FORM_GUID = ‘096dbf78-6fd2-44c7-b9f0-6c8248bc33ac’; // ───────────────────────────────────────────────────────────────────────────── var lastELR = 0, lastPosted = 0, lastAnnualLeak = 0; window.elrCalculate = function() { var postedEl = document.getElementById(‘elr-posted’); var techsEl = document.getElementById(‘elr-techs’); var hoursEl = document.getElementById(‘elr-hours’); var revenueEl = document.getElementById(‘elr-revenue’); var posted = parseFloat(postedEl.value); var techs = parseFloat(techsEl.value); var hours = parseFloat(hoursEl.value); var revenue = parseFloat(revenueEl.value); var valid = true; // Reset errors [‘elr-posted’,’elr-techs’,’elr-hours’,’elr-revenue’].forEach(function(id) { document.getElementById(id).classList.remove(‘error’); }); [‘elr-posted-err’,’elr-techs-err’,’elr-hours-err’,’elr-revenue-err’].forEach(function(id) { document.getElementById(id).style.display = ‘none’; }); if (!postedEl.value || isNaN(posted) || posted <= 0) { postedEl.classList.add('error'); document.getElementById('elr-posted-err').style.display = 'block'; valid = false; } if (!techsEl.value || isNaN(techs) || techs <= 0) { techsEl.classList.add('error'); document.getElementById('elr-techs-err').style.display = 'block'; valid = false; } if (!hoursEl.value || isNaN(hours) || hours <= 0) { hoursEl.classList.add('error'); document.getElementById('elr-hours-err').style.display = 'block'; valid = false; } if (!revenueEl.value || isNaN(revenue) || revenue <= 0) { revenueEl.classList.add('error'); document.getElementById('elr-revenue-err').style.display = 'block'; valid = false; } if (!valid) return; // Core calculations var hoursPerMonth = techs * hours * 4.333; var elr = revenue / hoursPerMonth; var gap = posted – elr; var efficiency = (elr / posted) * 100; var weeklyPotential = posted * techs * hours; var monthlyPotential = weeklyPotential * 4.333; var weeklyLeak = gap * techs * hours; var annualLeak = weeklyLeak * 52; lastELR = elr; lastPosted = posted; lastAnnualLeak = annualLeak; // Posted rate display document.getElementById('elr-posted-display').textContent = formatRate(posted); // ELR display & colour document.getElementById('elr-actual-display').textContent = formatRate(elr); var actualBox = document.getElementById('elr-actual-box'); var actualValue = document.getElementById('elr-actual-display'); var gapBadge = document.getElementById('elr-gap-badge'); var insight = document.getElementById('elr-insight'); var gapBox = document.getElementById('elr-gap-box'); var weeklyBox = document.getElementById('elr-weekly-box'); var annualBox = document.getElementById('elr-annual-box'); // Reset classes actualBox.className = 'elr-rate-box actual'; actualValue.className = 'elr-rate-value actual-value'; gapBadge.className = 'elr-gap-badge'; insight.className = 'elr-insight'; gapBox.className = 'elr-stat-box'; weeklyBox.className = 'elr-stat-box'; annualBox.className = 'elr-stat-box'; if (gap = posted rate (unusual but possible) gapBadge.textContent = ‘No gap — excellent!’; gapBadge.classList.add(‘excellent’); insight.classList.add(‘status-excellent’); insight.innerHTML = ‘Impressive — your effective rate matches or exceeds your posted rate. This means virtually all technician hours are being billed at full rate with no discounting or unbilled time. Keep your job costing tight and review your rate annually to stay ahead of wage increases.’; } else if (efficiency >= 90) { gapBadge.textContent = ‘-‘ + formatRate(gap) + ‘/hr gap’; gapBadge.classList.add(‘good’); insight.classList.add(‘status-excellent’); insight.innerHTML = ‘Strong performance — you\’re capturing ‘ + efficiency.toFixed(0) + ‘% of your posted rate. The ‘ + formatRate(gap) + ‘/hr gap is small and likely unavoidable (some downtime, minor rounding). Focus on protecting this by keeping quoting consistent and flagging any jobs that regularly overrun.’; } else if (efficiency >= 75) { actualBox.classList.add(‘warning’); actualValue.classList.add(‘warning’); gapBadge.classList.add(‘ok’); gapBadge.textContent = ‘-‘ + formatRate(gap) + ‘/hr gap’; gapBox.classList.add(‘warning’); weeklyBox.classList.add(‘warning’); annualBox.classList.add(‘warning’); insight.classList.add(‘status-ok’); insight.innerHTML = ‘Your effective rate is ‘ + efficiency.toFixed(0) + ‘% of your posted rate — below the 90% benchmark. The ‘ + formatRate(gap) + ‘/hr gap across ‘ + techs + ‘ technician’ + (techs > 1 ? ‘s’ : ”) + ‘ is leaking ‘ + formatCurrency(annualLeak) + ‘ per year. The most common causes are unbilled overtime on jobs that ran over, free “courtesy” checks, and discounting without tracking. Pick one and fix it this month.’; } else if (efficiency >= 60) { actualBox.classList.add(‘warning’); actualValue.classList.add(‘warning’); gapBadge.textContent = ‘-‘ + formatRate(gap) + ‘/hr gap’; gapBox.classList.add(‘danger’); weeklyBox.classList.add(‘danger’); annualBox.classList.add(‘danger’); insight.classList.add(‘status-low’); insight.innerHTML = ‘Your effective rate is only ‘ + efficiency.toFixed(0) + ‘% of your posted rate — a significant gap. This means for every hour your technicians work, you\’re only collecting ‘ + formatRate(elr) + ‘ of the ‘ + formatRate(posted) + ‘ you charge. That\’s ‘ + formatCurrency(annualLeak) + ‘ leaking out per year. At this level, the issue is usually systemic — poor job costing, consistent underquoting, or a high volume of comeback work that doesn\’t get re-invoiced.’; } else { actualBox.classList.add(‘danger’); actualValue.classList.add(‘danger’); gapBadge.textContent = ‘-‘ + formatRate(gap) + ‘/hr gap’; gapBox.classList.add(‘danger’); weeklyBox.classList.add(‘danger’); annualBox.classList.add(‘danger’); insight.classList.add(‘status-low’); insight.innerHTML = ‘Critical: you\’re capturing less than 60% of your posted rate. A ‘ + formatRate(gap) + ‘/hr gap means you\’re effectively working at a heavily discounted rate whether you intended to or not. At ‘ + formatCurrency(annualLeak) + ‘ in annual leakage, this needs immediate attention. Start by auditing one full week of jobs — compare time quoted to time spent on every single job. The pattern will become obvious quickly.’; } // Gauge var needlePct = Math.min(Math.max(efficiency, 0), 100); setTimeout(function() { document.getElementById(‘elr-needle’).style.left = needlePct + ‘%’; }, 100); // Stats document.getElementById(‘elr-gap-value’).textContent = formatRate(gap > 0 ? gap : 0); document.getElementById(‘elr-weekly-leak’).textContent = formatCurrency(weeklyLeak > 0 ? weeklyLeak : 0); document.getElementById(‘elr-annual-leak’).textContent = formatCurrency(annualLeak > 0 ? annualLeak : 0); document.getElementById(‘elr-billed-display’).textContent = formatCurrency(revenue); document.getElementById(‘elr-potential-display’).textContent = formatCurrency(monthlyPotential); // Show results var results = document.getElementById(‘elr-results’); results.classList.add(‘visible’); setTimeout(function() { results.scrollIntoView({ behavior: ‘smooth’, block: ‘nearest’ }); }, 100); }; window.elrSubmitEmail = function() { var fname = document.getElementById(‘elr-fname’).value.trim(); var email = document.getElementById(‘elr-email’).value.trim(); if (!fname) { document.getElementById(‘elr-fname’).style.borderColor = ‘#e05252’; document.getElementById(‘elr-fname’).focus(); return; } if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { document.getElementById(‘elr-email’).style.borderColor = ‘#e05252’; document.getElementById(‘elr-email’).focus(); return; } if (HUBSPOT_PORTAL_ID !== ‘HUBSPOT_PORTAL_ID’ && HUBSPOT_FORM_GUID !== ‘HUBSPOT_FORM_GUID’) { var payload = { fields: [ { name: ‘firstname’, value: fname }, { name: ’email’, value: email }, { name: ‘posted_rate’, value: lastPosted.toFixed(0) }, { name: ‘elr’, value: lastELR.toFixed(0) }, { name: ‘annual_leak’, value: lastAnnualLeak.toFixed(0) }, { name: ‘lead_source’, value: ‘ELR Calculator — Workshop University’ } ], context: { pageUri: window.location.href, pageName: document.title } }; fetch(‘https://api.hsforms.com/submissions/v3/integration/submit/’ + HUBSPOT_PORTAL_ID + ‘/’ + HUBSPOT_FORM_GUID, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify(payload) }).catch(function() {}); } document.getElementById(‘elr-email-form’).style.display = ‘none’; document.getElementById(‘elr-email-success’).style.display = ‘block’; }; function formatRate(n) { return ‘$’ + Math.round(n); } function formatCurrency(n) { return ‘$’ + Math.round(n).toLocaleString(‘en-AU’); } })();