Initial Commit
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
function calculate() {
|
||||
const gross = parseFloat(document.getElementById('grossPay').value) || 0;
|
||||
const freq = parseInt(document.getElementById('payFreq').value);
|
||||
const status = document.getElementById('filingStatus').value;
|
||||
const stateCode = document.getElementById('state').value;
|
||||
const retPct = parseFloat(document.getElementById('retPct').value) / 100;
|
||||
const preTax = (parseFloat(document.getElementById('preTaxPay').value) || 0) * freq;
|
||||
const postTax = (parseFloat(document.getElementById('postTaxPay').value) || 0) * freq;
|
||||
const other = (parseFloat(document.getElementById('otherPay').value) || 0) * freq;
|
||||
const cityPct = (parseFloat(document.getElementById('cityTax').value) / 100) || 0;
|
||||
|
||||
const stdDed = STD_DEDUCTIONS[status];
|
||||
document.getElementById('stdDedLabel').textContent = '$' + stdDed.toLocaleString();
|
||||
|
||||
const retirement = gross * retPct;
|
||||
const preTaxTotal = retirement + preTax;
|
||||
const fedtaxable = Math.max(0, gross - stdDed - preTaxTotal);
|
||||
const taxable = Math.max(0, gross - preTaxTotal);
|
||||
|
||||
const fed = calcBracketTax(fedtaxable, FED_BRACKETS[status]);
|
||||
const ss = Math.min(gross, SS_BASE) * SS_RATE;
|
||||
const med = gross * MED_RATE;
|
||||
const addMed = gross > ADD_MED_THRESH[status] ? (gross - ADD_MED_THRESH[status]) * 0.009 : 0;
|
||||
const fica = ss + med + addMed;
|
||||
const stTax = calcStateTax(taxable, stateCode);
|
||||
const ctTax = Math.max(0,taxable * cityPct);
|
||||
const totalTax = fed + fica + stTax + ctTax;
|
||||
const totalDeductions = preTaxTotal + postTax + other + totalTax;
|
||||
const net = gross - totalDeductions;
|
||||
const netPer = net / freq;
|
||||
|
||||
currentData = { gross, retPct, retirement, preTax, preTaxTotal, postTax, other, fed, ss, med, addMed, fica, stTax, ctTax, totalTax, net, netPer, taxable, stdDed, freq, status, stateCode };
|
||||
renderResults(currentData);
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
function calcBracketTax(taxable, brackets) {
|
||||
let tax = 0, remaining = taxable;
|
||||
for (let b of brackets) {
|
||||
if (remaining <= 0) break;
|
||||
let inBracket = Math.min(remaining, Math.max(0, b.max - b.min));
|
||||
tax += inBracket * b.r;
|
||||
remaining -= inBracket;
|
||||
}
|
||||
return tax;
|
||||
}
|
||||
|
||||
function calcStateTax(taxable, stateCode) {
|
||||
const s = STATE_DATA[stateCode] || {t:'none'};
|
||||
if (s.t === 'none') return 0;
|
||||
if (s.t === 'flat') return Math.max(0, taxable * s.v);
|
||||
if (s.t === 'brackets') return calcBracketTax(taxable, s.v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function formatMoney(n) {
|
||||
//return '$' + Math.round(n).toLocaleString('en-US');
|
||||
return '$' + n.toFixed(2).toLocaleString('en-US');
|
||||
}
|
||||
|
||||
let currentData = {};
|
||||
|
||||
function renderResults(d) {
|
||||
const panel = document.getElementById('rightPanel');
|
||||
panel.innerHTML = `
|
||||
<div class="card fade-in">
|
||||
<h2><span class="icon">💵</span> Paycheck Breakdown</h2>
|
||||
<div class="results-grid">
|
||||
<div class="result-box primary">
|
||||
<div class="label">Net Take-Home</div>
|
||||
<div class="value positive">${formatMoney(d.net)}</div>
|
||||
<div class="sub">/year | ${formatMoney(d.netPer)} /${d.freq === 52 ? 'week' : d.freq === 26 ? '2 weeks' : d.freq === 24 ? '2 weeks' : d.freq === 12 ? 'month' : 'year'}</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">Federal Tax</div>
|
||||
<div class="value negative">${formatMoney(d.fed)}</div>
|
||||
<div class="sub effective-rate">${(d.fed/d.gross*100||0).toFixed(1)}% effective rate</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">FICA (SS + Medicare)</div>
|
||||
<div class="value negative">${formatMoney(d.fica)}</div>
|
||||
<div class="sub">SS: ${formatMoney(d.ss)} | Medicare: ${formatMoney(d.med + d.addMed)}</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">State Tax</div>
|
||||
<div class="value negative">${formatMoney(d.stTax)}</div>
|
||||
<div class="sub effective-rate">${(d.stTax/d.gross*100||0).toFixed(1)}% effective rate</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">City Tax</div>
|
||||
<div class="value negative">${formatMoney(d.ctTax)}</div>
|
||||
<div class="sub effective-rate">${(d.ctTax/d.gross*100||0).toFixed(1)}% effective rate</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">Retirement (401k)</div>
|
||||
<div class="value accent">${formatMoney(d.retirement)}</div>
|
||||
<div class="sub">${(d.retPct*100).toFixed(1)}% of gross</div>
|
||||
</div>
|
||||
<div class="result-box">
|
||||
<div class="label">Other Deductions</div>
|
||||
<div class="value">${formatMoney(d.preTax + d.postTax + d.other)}</div>
|
||||
<div class="sub">Pre/Post/Other combined</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card fade-in">
|
||||
<h2><span class="icon">📊</span> Allocation Breakdown</h2>
|
||||
<table class="breakdown-table">
|
||||
<thead><tr><th>Category</th><th>Annual</th><th>Per Pay</th><th>% of Gross</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Gross Pay</td><td class="amount">${formatMoney(d.gross)}</td><td class="amount">${formatMoney(d.gross/d.freq)}</td><td class="amount">100%</td></tr>
|
||||
<tr><td>Retirement (401k)</td><td class="amount negative">${formatMoney(d.retirement)}</td><td class="amount">${formatMoney(d.retirement/d.freq)}</td><td class="amount">${(d.retPct*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>Pre-Tax Deductions</td><td class="amount negative">${formatMoney(d.preTax)}</td><td class="amount">${formatMoney(d.preTax/d.freq)}</td><td class="amount">${(d.preTax/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>Federal Tax</td><td class="amount negative">${formatMoney(d.fed)}</td><td class="amount">${formatMoney(d.fed/d.freq)}</td><td class="amount">${(d.fed/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>FICA (SS + Med)</td><td class="amount negative">${formatMoney(d.fica)}</td><td class="amount">${formatMoney(d.fica/d.freq)}</td><td class="amount">${(d.fica/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>State Tax</td><td class="amount negative">${formatMoney(d.stTax)}</td><td class="amount">${formatMoney(d.stTax/d.freq)}</td><td class="amount">${(d.stTax/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>City Tax</td><td class="amount negative">${formatMoney(d.ctTax)}</td><td class="amount">${formatMoney(d.ctTax/d.freq)}</td><td class="amount">${(d.ctTax/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr><td>Post-Tax & Other</td><td class="amount negative">${formatMoney(d.postTax + d.other)}</td><td class="amount">${formatMoney((d.postTax + d.other)/d.freq)}</td><td class="amount">${((d.postTax + d.other)/d.gross*100).toFixed(1)}%</td></tr>
|
||||
<tr class="total-row"><td><strong>Net Take-Home</strong></td><td class="amount positive"><strong>${formatMoney(d.net)}</strong></td><td class="amount"><strong>${formatMoney(d.netPer)}</strong></td><td class="amount"><strong>${(d.net/d.gross*100).toFixed(1)}%</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card fade-in analysis-section">
|
||||
<h3><span class="icon">🔄</span> Retirement Contribution Analysis</h3>
|
||||
<div class="slider-container">
|
||||
<label>401(k) Contribution <span id="sliderVal">${(d.retPct*100).toFixed(1)}%</span></label>
|
||||
<input type="range" id="retSlider" min="0" max="25" step="0.5" value="${(d.retPct*100)}" oninput="updateAnalysis()">
|
||||
</div>
|
||||
<div class="comparison-table">
|
||||
<table>
|
||||
<thead><tr><th>Contribution %</th><th>Annual 401k</th><th>Net Pay / Period</th><th>Effective Tax Rate</th><th>Annual Take-Home</th></tr></thead>
|
||||
<tbody id="analysisBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="chart-container"><canvas id="analysisChart"></canvas></div>
|
||||
<div class="savings-summary">
|
||||
<div class="savings-box">
|
||||
<div class="sb-label">Annual Tax Shield</div>
|
||||
<div class="sb-value positive">-${formatMoney(d.fed * d.retPct)}</div>
|
||||
</div>
|
||||
<div class="savings-box">
|
||||
<div class="sb-label">Annual 401k Savings</div>
|
||||
<div class="sb-value accent">${formatMoney(d.retirement)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
updateAnalysis();
|
||||
}
|
||||
|
||||
function updateAnalysis() {
|
||||
if (!currentData.gross) return;
|
||||
const d = currentData;
|
||||
const currentPct = parseFloat(document.getElementById('retSlider').value);
|
||||
document.getElementById('sliderVal').textContent = currentPct.toFixed(1) + '%';
|
||||
|
||||
const rows = [];
|
||||
const step = 1;
|
||||
for (let p = 0; p <= 25; p += step) {
|
||||
const pct = p / 100;
|
||||
const retAmt = d.gross * pct;
|
||||
const stateCode = document.getElementById('state').value;
|
||||
const fedtaxable = Math.max(0, d.gross - d.stdDed - retAmt - d.preTax);
|
||||
const taxable = Math.max(0, d.gross - retAmt - d.preTax);
|
||||
const fed = calcBracketTax(fedtaxable, FED_BRACKETS[d.status]);
|
||||
const fica = d.fica; // SS/Medicare don't change with 401k
|
||||
//const stTax = d.stTax;
|
||||
const stTax = calcStateTax(taxable, stateCode);
|
||||
const cityPct = (parseFloat(document.getElementById('cityTax').value) / 100) || 0;
|
||||
const ctTax = Math.max(0,taxable * cityPct);
|
||||
const net = d.gross - retAmt - d.preTax - fed - fica - stTax - ctTax - d.postTax - d.other;
|
||||
const netPer = net / d.freq;
|
||||
const effRate = d.gross > 0 ? ((fed + fica + stTax + ctTax) / d.gross) * 100 : 0;
|
||||
rows.push({pct, retAmt, netPer, effRate, net});
|
||||
}
|
||||
|
||||
const tbody = document.getElementById('analysisBody');
|
||||
tbody.innerHTML = rows.map(r => `
|
||||
<tr class="${Math.abs(r.pct - currentPct) < 0.01 ? 'highlight-row' : ''}">
|
||||
<td>${(r.pct*100).toFixed(1)}%</td>
|
||||
<td>${formatMoney(r.retAmt)}</td>
|
||||
<td>${formatMoney(r.netPer)}</td>
|
||||
<td>${r.effRate.toFixed(1)}%</td>
|
||||
<td>${formatMoney(r.net)}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
drawChart(rows, currentPct);
|
||||
}
|
||||
|
||||
function drawChart(rows, currentPct) {
|
||||
const canvas = document.getElementById('analysisChart');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width * dpr;
|
||||
canvas.height = rect.height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
const w = rect.width, h = rect.height;
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
|
||||
const maxVal = Math.max(...rows.map(r => r.net));
|
||||
const barWidth = Math.min((w - 40) / rows.length * 0.6, 40);
|
||||
const gap = (w - 40) / rows.length * 0.4;
|
||||
|
||||
rows.forEach((r, i) => {
|
||||
const barH = (r.net / maxVal) * (h - 50);
|
||||
const x = 20 + i * (barWidth + gap);
|
||||
const y = h - 30 - barH;
|
||||
|
||||
ctx.fillStyle = Math.abs(r.pct - currentPct) < 0.005 ? '#6c5ce7' : '#2d3148';
|
||||
ctx.beginPath();
|
||||
ctx.roundRect(x, y, barWidth, barH, 4);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#8b8fa3';
|
||||
ctx.font = '11px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText((r.pct*100).toFixed(0) + '%', x + barWidth/2, h - 10);
|
||||
|
||||
if (Math.abs(r.pct - currentPct) < 0.005) {
|
||||
ctx.fillStyle = '#a29bfe';
|
||||
ctx.font = 'bold 12px sans-serif';
|
||||
ctx.fillText(formatMoney(r.net), x + barWidth/2, y - 8);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Wire up events
|
||||
document.getElementById('calcBtn').addEventListener('click', calculate);
|
||||
document.getElementById('retPct').addEventListener('input', (e) => {
|
||||
document.getElementById('retPctDisplay').textContent = e.target.value + '%';
|
||||
});
|
||||
document.getElementById('cityTax').addEventListener('input', (e) => {
|
||||
document.getElementById('cityTaxDisplay').textContent = e.target.value + '%';
|
||||
});
|
||||
|
||||
// Auto-calculate on load
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
// Attach listeners to all inputs for auto-update
|
||||
['grossPay','payCheck','payFreq','filingStatus','state','preTaxPay','postTaxPay','otherPay'].forEach(id => {
|
||||
document.getElementById(id).addEventListener('input', calculate);
|
||||
document.getElementById(id).addEventListener('change', calculate);
|
||||
});
|
||||
calculate();
|
||||
});
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Take-Home Pay Calculator & Retirement Analyzer</title>
|
||||
<link rel="stylesheet" href="retirement.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<a href="/">
|
||||
<h1>💰 Take-Home Pay Calculator</h1>
|
||||
</a>
|
||||
<p>2026 Federal & State Tax Calculator with Retirement Analysis</p>
|
||||
<a href="/annual">
|
||||
<button class="btn">Use Annual Salary</button>
|
||||
</a>
|
||||
<a href="/paycheck">
|
||||
<button class="btn">Use Last Paycheck</button>
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
:root {
|
||||
--bg: #0f1117; --card: #1a1d28; --card-alt: #222636;
|
||||
--accent: #6c5ce7; --accent-light: #a29bfe;
|
||||
--green: #00cec9; --red: #ff6b6b; --orange: #fdcb6e;
|
||||
--text: #e2e4f0; --text-dim: #8b8fa3; --border: #2d3148;
|
||||
--input-bg: #161825;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg); color: var(--text); min-height: 100vh; line-height: 1.5;
|
||||
}
|
||||
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
|
||||
header { text-align: center; padding: 30px 0 10px; }
|
||||
header h1 {
|
||||
font-size: 2.2rem;
|
||||
background: linear-gradient(135deg, var(--accent-light), var(--green));
|
||||
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
header a { text-decoration: none; }
|
||||
header p { color: var(--text-dim); font-size: 1rem; }
|
||||
.layout { display: grid; grid-template-columns: 380px 1fr; gap: 24px; margin-top: 24px; }
|
||||
.card { background: var(--card); border: 1px solid var(--border); border-radius: 16px; padding: 24px; }
|
||||
.card h2 { font-size: 1.15rem; margin-bottom: 18px; display: flex; align-items: center; gap: 8px; }
|
||||
.input-group { margin-bottom: 16px; }
|
||||
.input-group label {
|
||||
display: block; font-size: 0.82rem; color: var(--text-dim); margin-bottom: 5px;
|
||||
font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px;
|
||||
}
|
||||
.input-group input, .input-group select {
|
||||
width: 100%; padding: 10px 14px; background: var(--input-bg);
|
||||
border: 1px solid var(--border); border-radius: 10px; color: var(--text);
|
||||
font-size: 0.95rem; outline: none; transition: border-color 0.2s;
|
||||
}
|
||||
.input-group input:focus, .input-group select:focus { border-color: var(--accent); }
|
||||
.input-group select { cursor: pointer; appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%238b8fa3' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat; background-position: right 12px center; padding-right: 32px;
|
||||
}
|
||||
.input-group select option { background: var(--card); }
|
||||
.btn {
|
||||
width: 100%; padding: 12px; background: linear-gradient(135deg, var(--accent), #8b5cf6);
|
||||
color: #fff; border: none; border-radius: 10px; font-size: 1rem; font-weight: 600;
|
||||
cursor: pointer; transition: transform 0.15s, box-shadow 0.2s; margin-top: 8px;
|
||||
}
|
||||
.btn:hover { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(108,92,231,0.35); }
|
||||
.right-panel { display: flex; flex-direction: column; gap: 24px; }
|
||||
.results-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
|
||||
.result-box {
|
||||
background: var(--card-alt); border-radius: 12px; padding: 18px;
|
||||
text-align: center; border: 1px solid var(--border);
|
||||
}
|
||||
.result-box.primary {
|
||||
background: linear-gradient(135deg, rgba(108,92,231,0.15), rgba(0,206,201,0.1));
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.result-box .label { font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
|
||||
.result-box .value { font-size: 1.6rem; font-weight: 700; }
|
||||
.result-box .sub { font-size: 0.78rem; color: var(--text-dim); margin-top: 2px; }
|
||||
.result-box .value.positive { color: var(--green); }
|
||||
.result-box .value.negative { color: var(--red); }
|
||||
.result-box .value.accent { color: var(--accent-light); }
|
||||
.breakdown-table { width: 100%; border-collapse: collapse; }
|
||||
.breakdown-table th, .breakdown-table td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
|
||||
.breakdown-table th { color: var(--text-dim); font-weight: 600; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
.breakdown-table tr:last-child td { border-bottom: none; }
|
||||
.breakdown-table .amount { text-align: right; font-variant-numeric: tabular-nums; }
|
||||
.breakdown-table .total-row td { border-top: 2px solid var(--border); font-weight: 700; padding-top: 14px; }
|
||||
.slider-container { margin-bottom: 16px; }
|
||||
.slider-container label { display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem; color: var(--text-dim); margin-bottom: 10px; }
|
||||
.slider-container label span { font-weight: 700; color: var(--accent-light); font-size: 1rem; }
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none; width: 100%; height: 6px; background: var(--border);
|
||||
border-radius: 3px; outline: none;
|
||||
}
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none; width: 22px; height: 22px; border-radius: 50%;
|
||||
background: var(--accent); cursor: pointer; box-shadow: 0 0 10px rgba(108,92,231,0.4);
|
||||
}
|
||||
.chart-container { position: relative; height: 300px; margin-top: 10px; }
|
||||
canvas { width: 100% !important; height: 100% !important; }
|
||||
.empty-state { text-align: center; padding: 60px 20px; color: var(--text-dim); }
|
||||
.empty-state .icon { font-size: 3rem; margin-bottom: 12px; }
|
||||
.tax-brackets-info {
|
||||
font-size: 0.78rem; color: var(--text-dim); margin-top: 12px; padding: 12px;
|
||||
background: rgba(108,92,231,0.05); border-radius: 8px; border: 1px solid var(--border);
|
||||
}
|
||||
.tax-brackets-info strong { color: var(--accent-light); }
|
||||
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } .results-grid { grid-template-columns: 1fr 1fr; } }
|
||||
@media (max-width: 600px) { .results-grid { grid-template-columns: 1fr; } .two-col { grid-template-columns: 1fr; } }
|
||||
.fade-in { animation: fadeIn 0.3s ease-in; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
||||
.effective-rate { font-size: 0.8rem; color: var(--text-dim); margin-top: 2px; }
|
||||
.analysis-section h3 { font-size: 1rem; margin-bottom: 16px; }
|
||||
.comparison-table { margin-top: 16px; }
|
||||
.comparison-table table { width: 100%; border-collapse: collapse; }
|
||||
.comparison-table th, .comparison-table td { padding: 10px 12px; text-align: right; font-size: 0.85rem; border-bottom: 1px solid var(--border); }
|
||||
.comparison-table th { color: var(--text-dim); font-weight: 600; font-size: 0.75rem; text-transform: uppercase; }
|
||||
.comparison-table th:first-child, .comparison-table td:first-child { text-align: left; }
|
||||
.comparison-table .highlight-row { background: rgba(108,92,231,0.1); }
|
||||
.comparison-table .highlight-row td { color: var(--accent-light); font-weight: 600; }
|
||||
.savings-summary { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 16px; }
|
||||
.savings-box { background: var(--card-alt); border-radius: 10px; padding: 14px; text-align: center; }
|
||||
.savings-box .sb-label { font-size: 0.72rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.3px; }
|
||||
.savings-box .sb-value { font-size: 1.2rem; font-weight: 700; margin-top: 4px; }
|
||||
@@ -0,0 +1,106 @@
|
||||
// 2026 Tax Configuration
|
||||
const FED_BRACKETS = {
|
||||
single: [
|
||||
{min:0,max:12400,r:0.10},
|
||||
{min:12400,max:50400,r:0.12},
|
||||
{min:50400,max:105700,r:0.22},
|
||||
{min:105700,max:201775,r:0.24},
|
||||
{min:201775,max:256225,r:0.32},
|
||||
{min:256225,max:640600,r:0.35},
|
||||
{min:640600,max:Infinity,r:0.37}
|
||||
],
|
||||
married_joint: [
|
||||
{min:0,max:19300,r:0.00},
|
||||
{min:19300,max:44100,r:0.10},
|
||||
{min:44100,max:120100,r:0.12},
|
||||
{min:120100,max:230700,r:0.22},
|
||||
{min:230700,max:422850,r:0.24},
|
||||
{min:422850,max:531750,r:0.32},
|
||||
{min:531750,max:788000,r:0.35},
|
||||
{min:788000,max:Infinity,r:0.37}
|
||||
],
|
||||
head_household: [
|
||||
{min:0,max:15550,r:0.00},
|
||||
{min:15550,max:33250,r:0.10},
|
||||
{min:33250,max:83000,r:0.12},
|
||||
{min:83000,max:121250,r:0.22},
|
||||
{min:121250,max:217300,r:0.24},
|
||||
{min:217300,max:271750,r:0.32},
|
||||
{min:271750,max:656150,r:0.35},
|
||||
{min:656150,max:Infinity,r:0.37}
|
||||
],
|
||||
married_separate: [
|
||||
{min:0,max:12400,r:0.10},
|
||||
{min:12400,max:50400,r:0.12},
|
||||
{min:50400,max:105700,r:0.22},
|
||||
{min:105700,max:201775,r:0.24},
|
||||
{min:201775,max:256225,r:0.32},
|
||||
{min:256225,max:640600,r:0.35},
|
||||
{min:640600,max:Infinity,r:0.37}
|
||||
]
|
||||
};
|
||||
|
||||
const STD_DEDUCTIONS = { single: 16100, married_joint: 32200, head_household: 24150, married_separate: 16100 };
|
||||
const SS_BASE = 168600;
|
||||
const SS_RATE = 0.062;
|
||||
const MED_RATE = 0.0145;
|
||||
const ADD_MED_THRESH = { single: 200000, married_joint: 250000, head_household: 200000, married_separate: 125000 };
|
||||
|
||||
// State Tax Data (2026)
|
||||
const STATE_DATA = {
|
||||
//States with No Income Tax
|
||||
AK: {t:'none',n:'Alaska'},
|
||||
FL: {t:'none',n:'Florida'},
|
||||
NV: {t:'none',n:'Nevada'},
|
||||
NH: {t:'none',n:'New Hampshire'},
|
||||
SD: {t:'none',n:'South Dakota'},
|
||||
TN: {t:'none',n:'Tennessee'},
|
||||
TX: {t:'none',n:'Texas'},
|
||||
WA: {t:'none',n:'Washington'},
|
||||
WY: {t:'none',n:'Wyoming'},
|
||||
//States with Flat Income Tax
|
||||
AZ: {t:'flat',v:0.025,n:'Arizona'},
|
||||
CO: {t:'flat',v:0.044,n:'Colorado'},
|
||||
GA: {t:'flat',v:0.0539,n:'Georgia'},
|
||||
IL: {t:'flat',v:0.0495,n:'Illinois'},
|
||||
IN: {t:'flat',v:0.03,n:'Indiana'},
|
||||
IA: {t:'flat',v:0.038,n:'Iowa'},
|
||||
KY: {t:'flat',v:0.04,n:'Kentucky'},
|
||||
LA: {t:'flat',v:0.03,n:'Louisiana'},
|
||||
MI: {t:'flat',v:0.0425,n:'Michigan'},
|
||||
NC: {t:'flat',v:0.0399,n:'North Carolina'},
|
||||
PA: {t:'flat',v:0.0307,n:'Pennsylvania'},
|
||||
UT: {t:'flat',v:0.0455,n:'Utah'},
|
||||
//States with Flat Income Tax and Standard Deduction
|
||||
ID: {t:'brackets',v:[{min:0,max:4673,r:0},{min:4673,max:Infinity,r:0.05695}],n:'Idaho'},
|
||||
MS: {t:'brackets',v:[{min:0,max:10000,r:0},{min:10000,max:Infinity,r:0.044}],n:'Mississippi'},
|
||||
OH: {t:'brackets',v:[{min:0,max:26050,r:0},{min:26050,max:Infinity,r:0.0275}],n:'Ohio'},
|
||||
//States with Bracketed Income Tax
|
||||
AL: {t:'brackets',v:[{min:0,max:500,r:0.02},{min:500,max:3000,r:0.04},{min:3000,max:Infinity,r:0.05}],n:'Alabama'},
|
||||
AR: {t:'brackets',v:[{min:0,max:4500,r:0.02},{min:4500,max:Infinity,r:0.039}],n:'Arkansas'},
|
||||
CA: {t:'brackets',v:[{min:0,max:10756,r:0.01},{min:10756,max:25499,r:0.02},{min:25499,max:40245,r:0.04},{min:40245,max:55866,r:0.06},{min:55866,max:70606,r:0.08},{min:70606,max:360659,r:0.093},{min:360659,max:432787,r:0.103},{min:432787,max:721314,r:0.113},{min:721314,max:1000000,r:0.123},{min:1000000,max:Infinity,r:0.133}],n:'California'},
|
||||
CT: {t:'brackets',v:[{min:0,max:10000,r:0.02},{min:10000,max:50000,r:0.045},{min:50000,max:100000,r:0.055},{min:100000,max:200000,r:0.06},{min:200000,max:250000,r:0.065},{min:250000,max:500000,r:0.069},{min:500000,max:Infinity,r:0.0699}],n:'Connecticut'},
|
||||
DE: {t:'brackets',v:[{min:0,max:2000,r:0},{min:2000,max:5000,r:0.022},{min:5000,max:10000,r:0.039},{min:10000,max:20000,r:0.048},{min:20000,max:25000,r:0.052},{min:25000,max:60000,r:0.0555},{min:60000,max:Infinity,r:0.066}],n:'Delaware'},
|
||||
HI: {t:'brackets',v:[{min:0,max:9600,r:0.014},{min:9600,max:14400,r:0.032},{min:14400,max:19200,r:0.055},{min:19200,max:24000,r:0.064},{min:24000,max:36000,r:0.068},{min:36000,max:48000,r:0.072},{min:48000,max:125000,r:0.076},{min:125000,max:175000,r:0.079},{min:175000,max:225000,r:0.0825},{min:225000,max:275000,r:0.09},{min:275000,max:325000,r:0.1},{min:325000,max:Infinity,r:0.11}],n:'Hawaii'},
|
||||
KS: {t:'brackets',v:[{min:0,max:23000,r:0.052},{min:23000,max:Infinity,r:0.0558}],n:'Kansas'},
|
||||
ME: {t:'brackets',v:[{min:0,max:26800,r:0.058},{min:26800,max:63450,r:0.0675},{min:63450,max:Infinity,r:0.0715}],n:'Maine'},
|
||||
MD: {t:'brackets',v:[{min:0,max:1000,r:0.02},{min:1000,max:2000,r:0.03},{min:2000,max:3000,r:0.04},{min:3000,max:100000,r:0.0475},{min:100000,max:125000,r:0.05},{min:125000,max:150000,r:0.0525},{min:150000,max:250000,r:0.055},{min:250000,max:Infinity,r:0.0575}],n:'Maryland'},
|
||||
MA: {t:'brackets',v:[{min:0,max:1083150,r:0.05},{min:1083150,max:Infinity,r:0.09}],n:'Massachusetts'},
|
||||
MN: {t:'brackets',v:[{min:0,max:32570,r:0.0535},{min:32570,max:106990,r:0.068},{min:106990,max:198630,r:0.0785},{min:198630,max:Infinity,r:0.0985}],n:'Minnesota'},
|
||||
MO: {t:'brackets',v:[{min:0,max:1313,r:0},{min:1313,max:2626,r:0.02},{min:2626,max:3939,r:0.025},{min:3939,max:5252,r:0.03},{min:5252,max:6565,r:0.035},{min:6565,max:7878,r:0.04},{min:7878,max:9191,r:0.045},{min:9191,max:Infinity,r:0.047}],n:'Missouri'},
|
||||
MT: {t:'brackets',v:[{min:0,max:21100,r:0.047},{min:21100,max:Infinity,r:0.059}],n:'Montana'},
|
||||
NE: {t:'brackets',v:[{min:0,max:4030,r:0.0246},{min:4030,max:24120,r:0.0351},{min:24120,max:38870,r:0.0501},{min:38870,max:Infinity,r:0.052}],n:'Nebraska'},
|
||||
NJ: {t:'brackets',v:[{min:0,max:20000,r:0.014},{min:20000,max:35000,r:0.0175},{min:35000,max:40000,r:0.035},{min:40000,max:75000,r:0.05525},{min:75000,max:500000,r:0.0637},{min:500000,max:1000000,r:0.0897},{min:1000000,max:Infinity,r:0.1075}],n:'New Jersey'},
|
||||
NM: {t:'brackets',v:[{min:0,max:5500,r:0.015},{min:5500,max:16500,r:0.032},{min:16500,max:33500,r:0.043},{min:33500,max:66500,r:0.047},{min:66500,max:210000,r:0.049},{min:210000,max:Infinity,r:0.059}],n:'New Mexico'},
|
||||
NY: {t:'brackets',v:[{min:0,max:8500,r:0.04},{min:8500,max:11700,r:0.045},{min:11700,max:13900,r:0.0525},{min:13900,max:80650,r:0.055},{min:80650,max:215400,r:0.06},{min:215400,max:1077550,r:0.0685},{min:1077550,max:5000000,r:0.0965},{min:5000000,max:25000000,r:0.103},{min:25000000,max:Infinity,r:0.109}],n:'New York'},
|
||||
ND: {t:'brackets',v:[{min:0,max:48485,r:0},{min:48485,max:244825,r:0.0195},{min:244825,max:Infinity,r:0.025}],n:'North Dakota'},
|
||||
OK: {t:'brackets',v:[{min:0,max:1000,r:0.0025},{min:1000,max:2500,r:0.0075},{min:2500,max:3750,r:0.0175},{min:3750,max:4900,r:0.0275},{min:4900,max:7200,r:0.0375},{min:7200,max:Infinity,r:0.0475}],n:'Oklahoma'},
|
||||
OR: {t:'brackets',v:[{min:0,max:4400,r:0.0475},{min:4400,max:11050,r:0.0675},{min:11050,max:125000,r:0.0875},{min:125000,max:Infinity,r:0.099}],n:'Oregon'},
|
||||
RI: {t:'brackets',v:[{min:0,max:79900,r:0.0375},{min:79900,max:181650,r:0.0475},{min:181650,max:Infinity,r:0.0599}],n:'Rhode Island'},
|
||||
SC: {t:'brackets',v:[{min:0,max:3560,r:0},{min:3560,max:17830,r:0.03},{min:17830,max:Infinity,r:0.062}],n:'South Carolina'},
|
||||
VT: {t:'brackets',v:[{min:0,max:47900,r:0.0335},{min:47900,max:116000,r:0.066},{min:116000,max:242000,r:0.076},{min:242000,max:Infinity,r:0.0875}],n:'Vermont'},
|
||||
VA: {t:'brackets',v:[{min:0,max:3000,r:0.02},{min:3000,max:5000,r:0.03},{min:5000,max:17000,r:0.05},{min:17000,max:Infinity,r:0.0575}],n:'Virginia'},
|
||||
WV: {t:'brackets',v:[{min:0,max:10000,r:0.0222},{min:10000,max:25000,r:0.0296},{min:25000,max:40000,r:0.0333},{min:40000,max:60000,r:0.0444},{min:60000,max:Infinity,r:0.0482}],n:'West Virginia'},
|
||||
WI: {t:'brackets',v:[{min:0,max:14680,r:0.035},{min:14680,max:29370,r:0.044},{min:29370,max:323290,r:0.053},{min:323290,max:Infinity,r:0.0765}],n:'Wisconsin'},
|
||||
DC: {t:'brackets',v:[{min:0,max:10000,r:0.04},{min:10000,max:40000,r:0.06},{min:40000,max:60000,r:0.065},{min:60000,max:250000,r:0.085},{min:250000,max:500000,r:0.0925},{min:500000,max:1000000,r:0.0975},{min:1000000,max:Infinity,r:0.1075}],n:'Washington DC'}
|
||||
};
|
||||
Reference in New Issue
Block a user