All Prompts
All Prompts

sectioncalculatorinteractiveformrevenueanalyticsdashboardresponsivemodern
Revenue Leak Calculator Section
Интерактивный калькулятор для клиник: выявляет утечки дохода на пути пациента. Аналитика, рекомендации.
Prompt
<div class="bg-white">
<style>@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap');
#calculator ::-webkit-scrollbar { width: 8px; }
#calculator ::-webkit-scrollbar-track { background: #f1f5f9; }
#calculator ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
.glass-card { backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); background: rgba(255,255,255,0.98); }
#calculator input[type=number]::-webkit-inner-spin-button,
#calculator input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
#calculator input[type=range] { -webkit-appearance: none; background: transparent; }
#calculator input[type=range]::-webkit-slider-thumb {
-webkit-appearance:none; height:20px; width:20px; border-radius:50%;
background:#0EA5E9; cursor:pointer; margin-top:-8px;
box-shadow:0 2px 6px rgba(14,165,233,0.3);
}
#calculator input[type=range]::-webkit-slider-runnable-track {
width:100%; height:6px; cursor:pointer; background:#E2E8F0; border-radius:4px;
}
#calculator input[type=checkbox] { accent-color:#0B1120; cursor:pointer; }
#calculator .quiz-option.is-selected {
background: #EFF6FF !important;
border-color: #0EA5E9 !important;
color: #0EA5E9 !important;
font-weight: 800 !important;
}</style>
<script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js"></script>
<section class="py-12 md:py-20 bg-slate-50" id="calculator" style="font-family: 'Inter', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;">
<div class="max-w-[1000px] mx-auto px-4 sm:px-6">
<div class="text-center mb-12">
<h2 class="text-[36px] md:text-[44px] font-extrabold text-slate-900 mb-3 tracking-tight">Calculate Your Exact Revenue Leak</h2>
<p class="text-[16px] md:text-[18px] text-slate-600 font-medium max-w-2xl mx-auto">
<span class="text-sky-500">\(Net Profit & Capacity Adjusted\)</span>
</p>
</div>
<div class="glass-card bg-white p-6 md:p-10 rounded-[24px] shadow-lg
border border-slate-200/60 relative overflow-hidden">
<div class="flex justify-center mb-10">
<div class="bg-slate-100 p-1.5 rounded-xl inline-flex shadow-inner border border-slate-200/50">
<button type="button" id="btn-aesthetics" class="px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-bold
text-slate-900 bg-white shadow-sm ring-1 ring-slate-200
transition-all">Aesthetics Clinic</button>
<button type="button" id="btn-dental" class="px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-medium
text-slate-600 hover:text-slate-900 hover:bg-slate-200/50
transition-all">Dental Practice</button>
</div>
</div>
<div class="grid md:grid-cols-2 gap-x-12 gap-y-10">
<div class="space-y-8">
<div class="flex items-center gap-2 mb-2 border-b border-slate-100 pb-3">
<iconify-icon icon="ph:funnel-bold" class="text-sky-500 text-lg"></iconify-icon>
<h3 class="text-[12px] font-bold uppercase text-slate-600 tracking-widest">Funnel Inputs</h3>
</div>
<div>
<label class="block text-[14px] font-semibold text-slate-900 mb-2">Monthly Enquiries \(New Leads\)</label>
<input type="number" id="input-enquiries" value="160" min="1" class="w-full bg-white border border-slate-200 rounded-xl px-4
py-3.5 text-slate-900 text-[16px] font-bold
focus:outline-none focus:border-sky-500 focus:ring-2
focus:ring-sky-500/20 transition-all" />
</div>
<div>
<div class="flex justify-between mb-3 items-end">
<label class="block text-[14px] font-semibold text-slate-900">Conversion Rate</label>
<span id="display-rate" class="text-[20px] font-bold text-sky-500">25%</span>
</div>
<input type="range" id="input-rate" min="1" max="99" value="25" class="w-full mb-3" />
<div class="flex items-start justify-between flex-wrap gap-2">
<div id="benchmark-badge" class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg
bg-emerald-50 text-emerald-700 border border-emerald-100
transition-colors duration-300">
<iconify-icon icon="ph:trophy-bold" class="text-sm"></iconify-icon>
<span class="text-[11px] font-bold">Industry Standard</span>
</div>
<span class="text-[11px] text-slate-400 font-medium mt-1.5">Based on segment data</span>
</div>
</div>
<div>
<label class="block text-[14px] font-semibold text-slate-900 mb-2">Avg. Treatment Value</label>
<div class="relative">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 font-bold">£</span>
<input type="number" id="input-value" value="1500" min="1" class="w-full bg-white border border-slate-200 rounded-xl pl-9 pr-4
py-3.5 text-slate-900 text-[16px] font-bold
focus:outline-none focus:border-sky-500 focus:ring-2
focus:ring-sky-500/20 transition-all" />
</div>
</div>
</div>
<div class="space-y-8">
<div class="flex items-center gap-2 mb-2 border-b border-slate-100 pb-3">
<iconify-icon icon="ph:scales-bold" class="text-sky-500 text-lg"></iconify-icon>
<h3 class="text-[12px] font-bold uppercase text-slate-600 tracking-widest">Economic Constraints</h3>
</div>
<div>
<label class="flex justify-between items-center mb-2">
<span class="text-[14px] font-semibold text-slate-900">Profit Margin \(Contribution\)</span>
<span class="text-[11px] font-medium text-slate-400 italic">Net after COGS/Ads</span>
</label>
<div class="relative">
<input type="number" id="input-margin" value="30" min="1" max="99" class="w-full bg-white border border-slate-200 rounded-xl px-4
py-3.5 text-slate-900 text-[16px] font-bold
focus:outline-none focus:border-sky-500 focus:ring-2
focus:ring-sky-500/20 transition-all" />
<span class="absolute right-4 top-1/2 -translate-y-1/2 text-slate-400 font-bold">%</span>
</div>
</div>
<div>
<label class="block text-[14px] font-semibold text-slate-900 mb-2">Spare Capacity \(Slots/Month\)</label>
<input type="number" id="input-capacity" value="25" min="0" class="w-full bg-white border border-slate-200 rounded-xl px-4
py-3.5 text-slate-900 text-[16px] font-bold
focus:outline-none focus:border-sky-500 focus:ring-2
focus:ring-sky-500/20 transition-all" />
<p class="text-[11px] text-slate-400 mt-2">Maximum additional patients you can handle.</p>
</div>
<div>
<label class="block text-[14px] font-semibold text-slate-900 mb-2">Recovery Potential</label>
<div class="flex bg-slate-100 rounded-lg p-1">
<button type="button" class="recovery-btn flex-1 py-2 rounded text-[12px] font-medium
text-slate-600 hover:bg-white hover:shadow-sm transition-all
border border-transparent" data-val="0.2">
<br />
<span class="text-[10px] opacity-70">20%</span>
</button>
<button type="button" class="recovery-btn flex-1 py-2 rounded text-[12px] font-bold
text-white bg-slate-900 shadow-sm transition-all transform
scale-105" data-val="0.35">
<br />
<span class="text-[10px] opacity-70">35%</span>
</button>
<button type="button" class="recovery-btn flex-1 py-2 rounded text-[12px] font-medium
text-slate-600 hover:bg-white hover:shadow-sm transition-all
border border-transparent" data-val="0.5">
<br />
<span class="text-[10px] opacity-70">50%</span>
</button>
</div>
</div>
<div class="pt-2">
<button type="button" id="btn-calculate" class="group relative w-full overflow-hidden rounded-xl
bg-slate-900 py-4 text-white shadow-lg shadow-slate-900/20
transition-all hover:bg-slate-800 hover:shadow-xl
hover:-translate-y-0.5">
<span class="relative flex items-center justify-center gap-2 text-[16px] font-bold">
<iconify-icon icon="ph:arrow-right-bold" class="group-hover:translate-x-1 transition-transform"></iconify-icon>
</span>
</button>
</div>
</div>
</div>
<div id="results-panel" class="mt-12 transition-all duration-700 ease-out opacity-0
translate-y-8 max-h-0 overflow-hidden pointer-events-none
border-t border-slate-100 pt-10">
<div class="flex justify-center mb-10">
<div class="bg-white p-1 rounded-full inline-flex items-center
cursor-pointer select-none border border-slate-200 shadow-sm" id="toggle-wrapper">
<span id="label-gross" class="px-5 py-2 rounded-full text-[13px] font-semibold text-slate-600 transition-all">Gross Revenue</span>
<div class="w-14 h-7 bg-slate-200 rounded-full mx-1 relative transition-colors duration-300" id="toggle-track">
<div class="absolute left-1 top-1 bg-white w-5 h-5 rounded-full shadow-md transition-all duration-300 transform" id="toggle-knob"></div>
</div>
<span id="label-net" class="px-5 py-2 rounded-full text-[13px] font-bold text-slate-900 bg-slate-50 shadow-inner transition-all">Net Profit \(Realizable\)</span>
</div>
</div>
<div id="quiz-section" class="mb-8">
<div id="quiz-prompt" class="bg-blue-50 border border-blue-100 rounded-xl p-5 flex
flex-col sm:flex-row sm:items-center sm:justify-between
gap-4">
<div>
<h4 class="text-[15px] font-bold text-slate-900">Refine your diagnosis?</h4>
<p class="text-[13px] text-slate-600">Answer 3 quick questions to personalise your Leak Map.</p>
</div>
<button type="button" id="btn-start-quiz" class="px-4 py-2 bg-white border border-blue-200 text-sky-500
font-bold text-[13px] rounded-lg hover:bg-blue-50
transition-colors shadow-sm">Start 30s Diagnostic</button>
</div>
<div id="quiz-panel" class="hidden bg-white border border-slate-200 rounded-xl p-6 relative">
<button type="button" id="btn-quiz-close" class="absolute top-4 right-4 text-slate-300 hover:text-slate-900 transition-colors">
<iconify-icon icon="ph:x-bold"></iconify-icon>
</button>
<div id="quiz-container"></div>
</div>
</div>
<div class="bg-white rounded-2xl border border-slate-200 p-6 md:p-8 shadow-sm mb-8">
<div class="mb-6">
<h3 class="text-[18px] font-bold text-slate-900">Your Leak Map</h3>
<p class="text-[14px] text-slate-600 mt-1 leading-relaxed">
<span id="leak-source" class="italic text-slate-400">Based on industry heuristics.</span>
</p>
</div>
<div class="flex h-3 rounded-full overflow-hidden bg-slate-100 mb-8">
<div id="bar-q" class="bg-emerald-500 h-full transition-all duration-1000 ease-out w-1/3"></div>
<div id="bar-e" class="bg-teal-500 h-full transition-all duration-1000 ease-out w-1/3"></div>
<div id="bar-n" class="bg-orange-500 h-full transition-all duration-1000 ease-out w-1/3"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-y-6 md:gap-x-8">
<div class="relative pl-5 border-l-[3px] border-emerald-100 hover:border-emerald-300 transition-colors group">
<div class="absolute -left-[7px] top-1 w-3 h-3 rounded-full bg-emerald-500 ring-4 ring-white"></div>
<div class="text-[14px] font-bold text-slate-900 mb-1 group-hover:text-emerald-700 transition-colors">Qualification & Fit</div>
<div id="val-q" class="text-[17px] font-bold text-emerald-600 mb-2 tracking-tight">£0 / month</div>
<p class="text-[13px] text-slate-600 leading-relaxed">Enquiries that never become viable opportunities.</p>
</div>
<div class="relative pl-5 border-l-[3px] border-teal-100 hover:border-teal-300 transition-colors group">
<div class="absolute -left-[7px] top-1 w-3 h-3 rounded-full bg-teal-500 ring-4 ring-white"></div>
<div class="text-[14px] font-bold text-slate-900 mb-1 group-hover:text-teal-700 transition-colors">Engagement & Follow-up</div>
<div id="val-e" class="text-[17px] font-bold text-teal-600 mb-2 tracking-tight">£0 / month</div>
<p class="text-[13px] text-slate-600 leading-relaxed">Leak caused by slow response and inconsistent follow-up.</p>
</div>
<div class="relative pl-5 border-l-[3px] border-orange-100 hover:border-orange-300 transition-colors group">
<div class="absolute -left-[7px] top-1 w-3 h-3 rounded-full bg-orange-500 ring-4 ring-white"></div>
<div class="text-[14px] font-bold text-slate-900 mb-1 group-hover:text-orange-700 transition-colors">No-shows & Drop-off</div>
<div id="val-n" class="text-[17px] font-bold text-orange-600 mb-2 tracking-tight">£0 / month</div>
<p class="text-[13px] text-slate-600 leading-relaxed">Leak caused by appointment drop-off and missed confirmations.</p>
</div>
</div>
<div class="mt-8 pt-6 border-t border-slate-100 text-center md:text-left
flex flex-col md:flex-row items-center gap-3">
<div class="text-[14px] text-slate-600">
<span id="result-recoverable-inline" class="text-[16px] font-bold text-slate-900">~£0/month</span>
</div>
<div id="capacity-warning" class="hidden inline-flex items-center gap-1.5 px-3 py-1 bg-red-50
text-red-600 text-[11px] font-bold rounded-full border
border-red-100">
<iconify-icon icon="ph:warning-bold"></iconify-icon>
</div>
</div>
</div>
<div class="bg-slate-50 rounded-2xl border border-slate-200 p-6 md:p-8 shadow-sm mb-8">
<div class="mb-6">
<h3 class="text-[18px] font-bold text-slate-900">Your Fastest Wins</h3>
<p class="text-[14px] text-slate-600 mt-1">
<span class="font-semibold text-slate-900">biggest leakage points</span>
</p>
</div>
<div id="wins-container" class="grid gap-4"></div>
</div>
<button type="button" id="btn-get-report" class="group relative w-full overflow-hidden rounded-xl
bg-emerald-600 py-4 text-white shadow-lg
shadow-emerald-600/20 transition-all hover:bg-emerald-700
hover:shadow-emerald-600/30 hover:-translate-y-0.5">
<span class="relative flex items-center justify-center gap-2 text-[16px] font-bold">
<iconify-icon icon="ph:arrow-right-bold" class="group-hover:translate-x-1 transition-transform"></iconify-icon>
</span>
</button>
</div>
</div>
</div>
</section>
<script>(function () {
const PRESETS = {
aesthetics: { enquiries: 160, rate: 25, value: 1500, margin: 30, capacity: 25 },
dental: { enquiries: 200, rate: 35, value: 2200, margin: 35, capacity: 20 }
};
const BENCHMARKS = {
dental: { p20: 30, avg: 45, top: 65 },
aesthetics: { p20: 20, avg: 35, top: 50 }
};
const WIN_STRATEGIES = {
e: { id:"engagement", color:"border-teal-500", title:"Speed-to-lead + follow-up sequence", desc:"Automate the first-touch + structured follow-up so enquiries don't go cold.", action:"Fixes Engagement Leak" },
q: { id:"qualification", color:"border-emerald-500", title:"Pre-qualification + message clarity", desc:"Filter and route enquiries to the right pathway to stop wasting time on low-fit leads.", action:"Fixes Qualification Leak" },
n: { id:"noshow", color:"border-orange-500", title:"Confirmation workflows + deposit systems", desc:"Reduce drop-off spikes using multi-channel reminders and frictionless deposits.", action:"Fixes No-Show Leak" }
};
const QUIZ_DATA = [
{ id:"responseTime", q:"How fast do you typically reply to new leads?", opts:[{ l:"< 15 mins", impact:{ e:0 } }, { l:"Same Day", impact:{ e:0.1 } }, { l:"Next Day+", impact:{ e:0.2 } }] },
{ id:"followUp", q:"How many times do you follow up if they don't answer?",opts:[{ l:"6+ times", impact:{ e:0 } }, { l:"2-5 times", impact:{ e:0.1 } }, { l:"0-1 times", impact:{ e:0.25 } }] },
{ id:"noShow", q:"What does your no-show rate feel like?", opts:[{ l:"Low (<5%)", impact:{ n:0 } }, { l:"Avg (10-15%)",impact:{ n:0.1 } }, { l:"High (20%+)",impact:{ n:0.2 } }] }
];
let activePreset = "aesthetics";
let isNetView = false;
let recoveryFactor = 0.35;
let quizWeights = null;
let quizAnswers = {};
let lastMetrics = null;
const $ = id => document.getElementById(id);
const fmtMoney = n => "£" + Math.round(n).toLocaleString("en-GB");
const els = {
btnAesth:$("btn-aesthetics"), btnDent:$("btn-dental"),
inEnq:$("input-enquiries"), inRate:$("input-rate"), inVal:$("input-value"),
inMarg:$("input-margin"), inCap:$("input-capacity"),
dispRate:$("display-rate"), badge:$("benchmark-badge"),
recBtns:document.querySelectorAll("#calculator .recovery-btn"),
btnCalc:$("btn-calculate"),
results:$("results-panel"),
toggleWrapper:$("toggle-wrapper"), toggleTrack:$("toggle-track"), toggleKnob:$("toggle-knob"),
labelGross:$("label-gross"), labelNet:$("label-net"),
barQ:$("bar-q"), barE:$("bar-e"), barN:$("bar-n"),
valQ:$("val-q"), valE:$("val-e"), valN:$("val-n"),
resInline:$("result-recoverable-inline"), capWarn:$("capacity-warning"),
winsContainer:$("wins-container"), leakSource:$("leak-source"),
quizPrompt:$("quiz-prompt"), quizPanel:$("quiz-panel"),
quizContainer:$("quiz-container"),
btnStartQuiz:$("btn-start-quiz"), btnQuizClose:$("btn-quiz-close"),
btnContinue:$("btn-get-report")
};
function calculate() {
const enq = parseFloat(els.inEnq.value) || 0;
const rate = parseFloat(els.inRate.value) || 0;
const val = parseFloat(els.inVal.value) || 0;
const margin = parseFloat(els.inMarg.value) || 0;
let capacity = parseFloat(els.inCap.value);
if (isNaN(capacity) || capacity < 0) capacity = 50;
const converted = enq * (rate / 100);
const lost = enq - converted;
let recoveredLeads = lost * recoveryFactor;
const isCapped = recoveredLeads > capacity;
if (isCapped) recoveredLeads = capacity;
const grossMonthly = recoveredLeads * val;
const netMonthly = grossMonthly * (margin / 100);
const displayMonthly = isNetView ? netMonthly : grossMonthly;
let w = { q:0.30, e:0.45, n:0.25 };
if (quizWeights) {
const total = quizWeights.q + quizWeights.e + quizWeights.n;
w = { q:quizWeights.q/total, e:quizWeights.e/total, n:quizWeights.n/total };
}
return { enq, rate, val, margin, capacity, displayMonthly, isCapped,
leakQ: displayMonthly * w.q,
leakE: displayMonthly * w.e,
leakN: displayMonthly * w.n,
weights: w };
}
function renderWins(m) {
const leaks = [
{ id:"q", val:m.leakQ, strategy:WIN_STRATEGIES.q },
{ id:"e", val:m.leakE, strategy:WIN_STRATEGIES.e },
{ id:"n", val:m.leakN, strategy:WIN_STRATEGIES.n }
].sort((a,b) => b.val - a.val);
els.winsContainer.innerHTML = leaks.slice(0,2).map((item, idx) => {
const s = item.strategy;
return `<div class="bg-white p-5 rounded-xl border-l-[4px] ${s.color} shadow-sm transition-all hover:shadow-md">
<div class="flex justify-between items-start mb-1">
<div class="text-[14px] font-bold text-slate-900">${s.title}
<span class="block text-[11px] font-normal text-slate-600 mt-0.5">Recover up to <span class="font-bold text-slate-900">${fmtMoney(item.val)}/mo</span></span>
</div>
${idx===0?'<span class="bg-slate-900 text-white text-[10px] px-2 py-0.5 rounded font-bold uppercase tracking-wide">High Impact</span>':''}
</div>
<div class="text-[13px] text-slate-600 mb-3 leading-relaxed mt-2">${s.desc}</div>
<div class="flex items-center gap-2">
<iconify-icon icon="ph:check-circle-fill" class="text-emerald-500 text-sm"></iconify-icon>
<span class="text-[12px] font-semibold text-slate-900">${s.action}</span>
</div>
</div>`;
}).join("");
}
function render(scroll=true) {
lastMetrics = calculate();
const m = lastMetrics;
els.valQ.textContent = fmtMoney(m.leakQ) + " / month";
els.valE.textContent = fmtMoney(m.leakE) + " / month";
els.valN.textContent = fmtMoney(m.leakN) + " / month";
els.resInline.textContent = "~" + fmtMoney(m.displayMonthly) + "/month";
els.barQ.style.width = (m.weights.q * 100) + "%";
els.barE.style.width = (m.weights.e * 100) + "%";
els.barN.style.width = (m.weights.n * 100) + "%";
els.capWarn.classList.toggle("hidden", !m.isCapped);
renderWins(m);
els.results.classList.remove("opacity-0","translate-y-8","max-h-0","pointer-events-none");
els.results.classList.add("opacity-100","translate-y-0","max-h-[2200px]","pointer-events-auto");
if (scroll) setTimeout(() => els.results.scrollIntoView({ behavior:"smooth", block:"start" }), 100);
}
function renderQuiz() {
els.quizContainer.innerHTML = QUIZ_DATA.map((q,i) => `
<div class="mb-5 last:mb-0" data-qid="${q.id}">
<p class="text-[14px] font-semibold text-slate-900 mb-2">${i+1}. ${q.q}</p>
<div class="grid grid-cols-3 gap-2">
${q.opts.map((opt,oi) => `<button type="button" class="quiz-option px-2 py-2 border border-slate-200 rounded text-[12px] text-slate-600 hover:border-sky-500 hover:text-sky-500 transition-all" data-qid="${q.id}" data-oid="${oi}">${opt.l}</button>`).join("")}
</div>
</div>`).join("");
}
function calculateQuizWeights() {
let base = { q:0.25, e:0.35, n:0.20 };
Object.values(quizAnswers).forEach(ans => {
if (ans.impact.e) base.e += ans.impact.e;
if (ans.impact.q) base.q += ans.impact.q;
if (ans.impact.n) base.n += ans.impact.n;
});
quizWeights = base;
els.leakSource.textContent = "Personalised based on your diagnosis.";
render(false);
}
function bindQuizClicks() {
els.quizContainer.addEventListener("click", e => {
const btn = e.target.closest(".quiz-option");
if (!btn) return;
const qId = btn.getAttribute("data-qid");
const oIdx = parseInt(btn.getAttribute("data-oid"), 10);
const grp = els.quizContainer.querySelector(`[data-qid="${qId}"]`);
if (grp) grp.querySelectorAll(".quiz-option").forEach(b => b.classList.remove("is-selected"));
btn.classList.add("is-selected");
quizAnswers[qId] = QUIZ_DATA.find(q => q.id === qId).opts[oIdx];
if (Object.keys(quizAnswers).length === QUIZ_DATA.length) {
calculateQuizWeights();
setTimeout(() => {
els.quizPanel.classList.add("hidden");
els.quizPrompt.classList.remove("hidden");
const h4 = els.quizPrompt.querySelector("h4");
h4.textContent = "Diagnosis Applied ✓";
h4.classList.add("text-emerald-600");
els.leakSource.scrollIntoView({ behavior:"smooth", block:"center" });
}, 450});
}
function updateBenchmark() {
const rate = parseFloat(els.inRate.value);
const b = BENCHMARKS[activePreset];
let text, bg, color, border;
if (rate < b.p20) { text="Needs Attention"; bg="bg-orange-50"; color="text-orange-700"; border="border-orange-100"; }
else if (rate < b.avg) { text="Below Average"; bg="bg-orange-50"; color="text-orange-600"; border="border-orange-100"; }
else if (rate < b.top) { text="Industry Standard"; bg="bg-blue-50"; color="text-blue-700"; border="border-blue-100"; }
else { text="Elite Performance"; bg="bg-emerald-50"; color="text-emerald-700";border="border-emerald-100";}
els.badge.className = `inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border transition-colors duration-300 ${bg} ${color} ${border}`;
els.badge.querySelector("span").textContent = text;
els.dispRate.textContent = rate + "%";
}
function toggleNetView() {
isNetView = !isNetView;
if (isNetView) {
els.toggleTrack.classList.replace("bg-slate-200","bg-emerald-500");
els.toggleKnob.style.transform = "translateX(28px)";
els.labelNet.classList.add("text-slate-900","bg-white","shadow-sm");
els.labelNet.classList.remove("text-slate-600","bg-slate-50","shadow-inner");
els.labelGross.classList.add("text-slate-600");
els.labelGross.classList.remove("text-slate-900","bg-white","shadow-sm","font-bold");
} else {
els.toggleTrack.classList.replace("bg-emerald-500","bg-slate-200");
els.toggleKnob.style.transform = "translateX(0px)";
els.labelGross.classList.add("text-slate-900","bg-white","shadow-sm","font-bold");
els.labelGross.classList.remove("text-slate-600");
els.labelNet.classList.add("text-slate-600","bg-slate-50","shadow-inner");
els.labelNet.classList.remove("text-slate-900","bg-white","shadow-sm");
}
if (lastMetrics) render(false);
}
function setRecovery(val, btn) {
recoveryFactor = parseFloat(val);
els.recBtns.forEach(b => b.className = "recovery-btn flex-1 py-2 rounded text-[12px] font-medium text-slate-600 hover:bg-white hover:shadow-sm transition-all border border-transparent");
btn.className = "recovery-btn flex-1 py-2 rounded text-[12px] font-bold text-white bg-slate-900 shadow-sm transition-all transform scale-105";
if (lastMetrics) render(false);
}
function applyPreset(type) {
activePreset = type;
const p = PRESETS[type];
els.inEnq.value = p.enquiries;
els.inRate.value = p.rate;
els.inVal.value = p.value;
els.inMarg.value = p.margin;
els.inCap.value = p.capacity;
if (type === "aesthetics") {
els.btnAesth.className = "px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-bold text-slate-900 bg-white shadow-sm ring-1 ring-slate-200 transition-all";
els.btnDent.className = "px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-medium text-slate-600 hover:text-slate-900 hover:bg-slate-200/50 transition-all";
} else {
els.btnDent.className = "px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-bold text-slate-900 bg-white shadow-sm ring-1 ring-slate-200 transition-all";
els.btnAesth.className = "px-6 md:px-8 py-2.5 rounded-lg text-[14px] font-medium text-slate-600 hover:text-slate-900 hover:bg-slate-200/50 transition-all";
}
quizWeights = null;
quizAnswers = {};
els.leakSource.textContent = "Based on industry heuristics.";
const h4 = els.quizPrompt.querySelector("h4");
h4.textContent = "Refine your diagnosis?";
h4.classList.remove("text-emerald-600");
els.quizPanel.classList.add("hidden");
els.quizPrompt.classList.remove("hidden");
updateBenchmark();
els.results.classList.add("opacity-0","pointer-events-none");
}
els.btnAesth.addEventListener("click", () => applyPreset("aesthetics"));
els.btnDent.addEventListener("click", () => applyPreset("dental"));
els.inRate.addEventListener("input", updateBenchmark);
els.btnCalc.addEventListener("click", () => render(true));
els.toggleWrapper.addEventListener("click", toggleNetView);
els.recBtns.forEach(btn => btn.addEventListener("click", () => setRecovery(btn.dataset.val, btn)));
els.btnStartQuiz.addEventListener("click", () => {
els.quizPrompt.classList.add("hidden");
els.quizPanel.classList.remove("hidden");
renderQuiz();
});
els.btnQuizClose.addEventListener("click", () => {
els.quizPanel.classList.add("hidden");
els.quizPrompt.classList.remove("hidden");
});
bindQuizClicks();
els.btnContinue.addEventListener("click", () => {
alert("Report button clicked! Integrate with your modal or form.");
});
applyPreset("aesthetics");
updateBenchmark();
})();</script>
</div>