<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EMI Calculator</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0d0f14;
--surface: #161922;
--surface2: #1e2330;
--border: #2a3045;
--gold: #c9a84c;
--gold-light: #e8c97a;
--gold-dim: rgba(201,168,76,0.12);
--text: #f0ede6;
--text-muted: #8891a8;
--green: #4caf82;
--red: #e05a5a;
--radius: 16px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
font-family: 'DM Sans', sans-serif;
color: var(--text);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 24px 16px;
}
.calculator {
width: 100%;
max-width: 860px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 24px;
overflow: hidden;
box-shadow: 0 40px 80px rgba(0,0,0,0.5), 0 0 0 1px rgba(201,168,76,0.08);
}
.header {
background: linear-gradient(135deg, #1a1d28 0%, #111420 100%);
padding: 36px 40px 28px;
border-bottom: 1px solid var(--border);
position: relative;
overflow: hidden;
}
.header::before {
content: '';
position: absolute;
top: -40px; right: -40px;
width: 200px; height: 200px;
background: radial-gradient(circle, rgba(201,168,76,0.15) 0%, transparent 70%);
pointer-events: none;
}
.header-label {
font-size: 11px;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--gold);
font-weight: 600;
margin-bottom: 8px;
}
.header h1 {
font-family: 'Playfair Display', serif;
font-size: 32px;
font-weight: 700;
color: var(--text);
line-height: 1.1;
}
.header p {
color: var(--text-muted);
font-size: 14px;
margin-top: 8px;
font-weight: 300;
}
.body {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
}
@media (max-width: 650px) {
.body { grid-template-columns: 1fr; }
.header { padding: 28px 24px 20px; }
.header h1 { font-size: 26px; }
.inputs { padding: 28px 24px; }
.results { padding: 28px 24px; }
}
.inputs {
padding: 36px 40px;
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 28px;
}
@media (max-width: 650px) {
.inputs { border-right: none; border-bottom: 1px solid var(--border); }
}
.field label {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--text-muted);
font-weight: 600;
margin-bottom: 10px;
}
.field label span {
font-family: 'Playfair Display', serif;
font-size: 18px;
letter-spacing: 0;
text-transform: none;
color: var(--gold);
font-weight: 400;
}
.input-row {
display: flex;
align-items: center;
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
transition: border-color 0.2s;
}
.input-row:focus-within {
border-color: var(--gold);
}
.input-prefix {
padding: 12px 14px;
background: var(--gold-dim);
color: var(--gold);
font-size: 14px;
font-weight: 600;
border-right: 1px solid var(--border);
white-space: nowrap;
}
.input-row input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: var(--text);
font-family: 'DM Sans', sans-serif;
font-size: 16px;
font-weight: 500;
padding: 12px 14px;
width: 100%;
}
input[type=range] {
-webkit-appearance: none;
width: 100%;
height: 4px;
background: var(--border);
border-radius: 2px;
outline: none;
margin-top: 12px;
cursor: pointer;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 18px;
height: 18px;
background: var(--gold);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 0 4px rgba(201,168,76,0.2);
transition: box-shadow 0.2s;
}
input[type=range]::-webkit-slider-thumb:hover {
box-shadow: 0 0 0 6px rgba(201,168,76,0.3);
}
.results {
padding: 36px 40px;
display: flex;
flex-direction: column;
gap: 0;
}
.emi-hero {
text-align: center;
padding-bottom: 28px;
border-bottom: 1px solid var(--border);
margin-bottom: 28px;
}
.emi-label {
font-size: 11px;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--text-muted);
font-weight: 600;
margin-bottom: 8px;
}
.emi-amount {
font-family: 'Playfair Display', serif;
font-size: 46px;
font-weight: 700;
color: var(--gold);
line-height: 1;
transition: all 0.3s ease;
}
.emi-sub {
font-size: 13px;
color: var(--text-muted);
margin-top: 6px;
}
.stat-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 28px;
}
.stat {
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 12px;
padding: 16px;
}
.stat-label {
font-size: 11px;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--text-muted);
font-weight: 600;
margin-bottom: 6px;
}
.stat-value {
font-family: 'Playfair Display', serif;
font-size: 22px;
font-weight: 700;
}
.stat-value.principal { color: var(--green); }
.stat-value.interest { color: var(--red); }
.stat-value.total { color: var(--text); }
.donut-section {
display: flex;
align-items: center;
gap: 20px;
}
.donut-wrap {
position: relative;
flex-shrink: 0;
}
.donut-wrap svg { display: block; }
.donut-center {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
pointer-events: none;
}
.donut-pct {
font-family: 'Playfair Display', serif;
font-size: 20px;
font-weight: 700;
color: var(--gold);
}
.donut-pct-label {
font-size: 9px;
letter-spacing: 1px;
text-transform: uppercase;
color: var(--text-muted);
}
.legend {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
}
.legend-dot {
width: 10px; height: 10px;
border-radius: 50%;
flex-shrink: 0;
}
.legend-text {
color: var(--text-muted);
flex: 1;
}
.legend-val {
font-weight: 600;
color: var(--text);
}
.amort-toggle {
margin-top: 24px;
background: none;
border: 1px solid var(--border);
color: var(--gold);
padding: 10px 20px;
border-radius: 8px;
font-family: 'DM Sans', sans-serif;
font-size: 13px;
font-weight: 500;
cursor: pointer;
width: 100%;
letter-spacing: 0.5px;
transition: background 0.2s, border-color 0.2s;
}
.amort-toggle:hover {
background: var(--gold-dim);
border-color: var(--gold);
}
.amort-table-wrap {
display: none;
margin-top: 0;
overflow: hidden;
}
.amort-table-wrap.open {
display: block;
}
.amort-table-inner {
max-height: 300px;
overflow-y: auto;
margin-top: 16px;
border: 1px solid var(--border);
border-radius: 12px;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
thead th {
background: var(--surface2);
padding: 10px 12px;
text-align: right;
font-size: 10px;
letter-spacing: 1px;
text-transform: uppercase;
color: var(--text-muted);
font-weight: 600;
position: sticky;
top: 0;
z-index: 1;
}
thead th:first-child { text-align: left; }
tbody tr { border-top: 1px solid var(--border); }
tbody tr:hover { background: var(--surface2); }
tbody td {
padding: 9px 12px;
text-align: right;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
}
tbody td:first-child { text-align: left; color: var(--text); font-weight: 500; }
</style>
</head>
<body>
<div class="calculator">
<div class="header">
<div class="header-label">Financial Tool</div>
<h1>EMI Calculator</h1>
<p>Calculate your Equated Monthly Installment instantly</p>
</div>
<div class="body">
<!-- INPUTS -->
<div class="inputs">
<div class="field">
<label>Loan Amount <span id="lbl-principal">₹10,00,000</span></label>
<div class="input-row">
<span class="input-prefix">₹</span>
<input type="number" id="principal" value="1000000" min="10000" max="100000000" step="10000">
</div>
<input type="range" id="principal-range" min="10000" max="10000000" step="10000" value="1000000">
</div>
<div class="field">
<label>Annual Interest Rate <span id="lbl-rate">8.5%</span></label>
<div class="input-row">
<span class="input-prefix">%</span>
<input type="number" id="rate" value="8.5" min="0.1" max="36" step="0.1">
</div>
<input type="range" id="rate-range" min="0.1" max="36" step="0.1" value="8.5">
</div>
<div class="field">
<label>Loan Tenure <span id="lbl-tenure">60 mo</span></label>
<div class="input-row">
<span class="input-prefix">Months</span>
<input type="number" id="tenure" value="60" min="1" max="360" step="1">
</div>
<input type="range" id="tenure-range" min="1" max="360" step="1" value="60">
</div>
</div>
<!-- RESULTS -->
<div class="results">
<div class="emi-hero">
<div class="emi-label">Monthly EMI</div>
<div class="emi-amount" id="emi-display">₹0</div>
<div class="emi-sub">per month</div>
</div>
<div class="stat-grid">
<div class="stat">
<div class="stat-label">Principal</div>
<div class="stat-value principal" id="stat-principal">₹0</div>
</div>
<div class="stat">
<div class="stat-label">Total Interest</div>
<div class="stat-value interest" id="stat-interest">₹0</div>
</div>
<div class="stat" style="grid-column: span 2;">
<div class="stat-label">Total Payment</div>
<div class="stat-value total" id="stat-total">₹0</div>
</div>
</div>
<div class="donut-section">
<div class="donut-wrap">
<svg width="100" height="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="38" fill="none" stroke="#2a3045" stroke-width="14"/>
<circle cx="50" cy="50" r="38" fill="none" stroke="#4caf82" stroke-width="14"
stroke-dasharray="0 239" stroke-linecap="round"
transform="rotate(-90 50 50)" id="donut-principal" style="transition: stroke-dasharray 0.5s ease;"/>
<circle cx="50" cy="50" r="38" fill="none" stroke="#e05a5a" stroke-width="14"
stroke-dasharray="0 239" stroke-linecap="round"
transform="rotate(-90 50 50)" id="donut-interest" style="transition: stroke-dasharray 0.5s ease, stroke-dashoffset 0.5s ease;"/>
</svg>
<div class="donut-center">
<div class="donut-pct" id="donut-pct">0%</div>
<div class="donut-pct-label">Interest</div>
</div>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-dot" style="background:#4caf82"></div>
<span class="legend-text">Principal</span>
<span class="legend-val" id="legend-principal">0%</span>
</div>
<div class="legend-item">
<div class="legend-dot" style="background:#e05a5a"></div>
<span class="legend-text">Interest</span>
<span class="legend-val" id="legend-interest">0%</span>
</div>
</div>
</div>
<button class="amort-toggle" id="amort-btn">▼ View Amortization Schedule</button>
<div class="amort-table-wrap" id="amort-wrap">
<div class="amort-table-inner">
<table>
<thead>
<tr>
<th>Month</th>
<th>Principal</th>
<th>Interest</th>
<th>Balance</th>
</tr>
</thead>
<tbody id="amort-body"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
const fmt = v => '₹' + Math.round(v).toLocaleString('en-IN');
const fmtShort = v => {
if (v >= 10000000) return '₹' + (v/10000000).toFixed(2) + ' Cr';
if (v >= 100000) return '₹' + (v/100000).toFixed(2) + ' L';
return fmt(v);
};
function sync(inputId, rangeId, lblId, fmtFn) {
const input = document.getElementById(inputId);
const range = document.getElementById(rangeId);
const lbl = document.getElementById(lblId);
input.addEventListener('input', () => {
range.value = input.value;
lbl.textContent = fmtFn(+input.value);
calculate();
});
range.addEventListener('input', () => {
input.value = range.value;
lbl.textContent = fmtFn(+range.value);
calculate();
});
}
sync('principal', 'principal-range', 'lbl-principal', v => '₹' + Number(v).toLocaleString('en-IN'));
sync('rate', 'rate-range', 'lbl-rate', v => v + '%');
sync('tenure', 'tenure-range', 'lbl-tenure', v => v + ' mo');
function calculate() {
const P = parseFloat(document.getElementById('principal').value) || 0;
const annualRate = parseFloat(document.getElementById('rate').value) || 0;
const N = parseInt(document.getElementById('tenure').value) || 0;
const r = annualRate / 12 / 100;
let emi = 0;
if (r === 0) {
emi = N > 0 ? P / N : 0;
} else {
emi = P * r * Math.pow(1+r, N) / (Math.pow(1+r, N) - 1);
}
const totalPayment = emi * N;
const totalInterest = totalPayment - P;
const interestPct = totalPayment > 0 ? (totalInterest / totalPayment * 100) : 0;
const principalPct = 100 - interestPct;
document.getElementById('emi-display').textContent = fmt(emi);
document.getElementById('stat-principal').textContent = fmtShort(P);
document.getElementById('stat-interest').textContent = fmtShort(totalInterest);
document.getElementById('stat-total').textContent = fmtShort(totalPayment);
document.getElementById('donut-pct').textContent = Math.round(interestPct) + '%';
document.getElementById('legend-principal').textContent = Math.round(principalPct) + '%';
document.getElementById('legend-interest').textContent = Math.round(interestPct) + '%';
// Donut chart (circumference ~238.76 for r=38)
const C = 2 * Math.PI * 38;
const pDash = (principalPct / 100) * C;
const iDash = (interestPct / 100) * C;
const pCircle = document.getElementById('donut-principal');
const iCircle = document.getElementById('donut-interest');
pCircle.setAttribute('stroke-dasharray', pDash + ' ' + C);
iCircle.setAttribute('stroke-dasharray', iDash + ' ' + C);
iCircle.setAttribute('stroke-dashoffset', -pDash);
// Amortization
buildAmort(P, r, N, emi);
}
function buildAmort(P, r, N, emi) {
const tbody = document.getElementById('amort-body');
tbody.innerHTML = '';
let balance = P;
for (let m = 1; m <= N; m++) {
const interest = balance * r;
const principal = emi - interest;
balance -= principal;
const tr = document.createElement('tr');
tr.innerHTML = `<td>${m}</td><td>${fmt(principal)}</td><td>${fmt(interest)}</td><td>${fmt(Math.max(0, balance))}</td>`;
tbody.appendChild(tr);
}
}
document.getElementById('amort-btn').addEventListener('click', () => {
const wrap = document.getElementById('amort-wrap');
const btn = document.getElementById('amort-btn');
const open = wrap.classList.toggle('open');
btn.textContent = open ? '▲ Hide Amortization Schedule' : '▼ View Amortization Schedule';
});
calculate();
</script>
</body>
</html>