<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Median Income Means Test Calculator</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
margin: 0;
padding: 1.5rem;
background: #f5f5f7;
color: #222;
}
h1, h2 {
margin-top: 0;
}
.card {
background: #fff;
border-radius: 8px;
padding: 1.25rem;
margin-bottom: 1.5rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
}
label {
display: block;
margin-bottom: 0.25rem;
font-weight: 600;
}
select, input {
width: 100%;
padding: 0.5rem;
margin-bottom: 0.75rem;
border-radius: 4px;
border: 1px solid #ccc;
font-size: 0.95rem;
}
button {
padding: 0.6rem 1.2rem;
border-radius: 4px;
border: none;
background: #0052cc;
color: #fff;
font-size: 0.95rem;
cursor: pointer;
}
button:hover {
background: #003f99;
}
.result {
margin-top: 0.75rem;
padding: 0.75rem;
border-radius: 4px;
background: #f0f4ff;
border: 1px solid #c3d4ff;
font-size: 0.95rem;
}
.result.pass {
background: #e6f7e9;
border-color: #9ad0a5;
}
.result.fail {
background: #ffecec;
border-color: #f5a3a3;
}
.row {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.col {
flex: 1 1 260px;
}
.lang-toggle {
margin-bottom: 1rem;
text-align: right;
}
.note {
font-size: 0.8rem;
color: #555;
margin-top: 0.5rem;
}
@media (max-width: 600px) {
body {
padding: 1rem;
}
.lang-toggle {
text-align: left;
margin-bottom: 0.75rem;
}
}
</style>
</head>
<body>
<div class="lang-toggle">
<label for="langSelect">Language / Idioma:</label>
<select id="langSelect">
<option value="en">English</option>
<option value="es">Español</option>
</select>
</div>
<h1 id="title-main">Median Income Means Test Calculator</h1>
<p id="subtitle-main">
Quick screening based on U.S. Trustee median income data (cases filed on or after November 1, 2025).
</p>
<div class="card">
<h2 id="section-lookup-title">1. Median Income Lookup</h2>
<div class="row">
<div class="col">
<label id="label-state" for="stateSelect">State</label>
<select id="stateSelect"></select>
</div>
<div class="col">
<label id="label-household" for="householdSize">Household size</label>
<input type="number" id="householdSize" min="1" value="1">
<div class="note" id="note-household">
For more than 4 people, the calculator adds $11,100 per additional person.
</div>
</div>
</div>
<button id="btnLookup">Lookup median income</button>
<div id="lookupResult" class="result" style="display:none;"></div>
</div>
<div class="card">
<h2 id="section-means-title">2. Means Test Style Check (Part 1)</h2>
<div class="row">
<div class="col">
<label id="label-income6" for="income6">
Total gross income for last 6 months
</label>
<input type="number" id="income6" min="0" step="0.01" placeholder="e.g. 25000">
</div>
<div class="col">
<label id="label-income-note">
This will be annualized and compared to the median.
</label>
</div>
</div>
<button id="btnMeans">Check against median</button>
<div id="meansResult" class="result" style="display:none;"></div>
</div>
<div class="card">
<h2 id="section-territory-title">3. Territories Median Income Lookup</h2>
<div class="row">
<div class="col">
<label id="label-territory" for="territorySelect">
Commonwealth / U.S. Territory
</label>
<select id="territorySelect"></select>
</div>
<div class="col">
<label id="label-territory-household" for="territoryHouseholdSize">
Household size
</label>
<input type="number" id="territoryHouseholdSize" min="1" value="1">
<div class="note" id="note-territory-household">
For more than 4 people, the calculator adds $11,100 per additional person.
</div>
</div>
</div>
<button id="btnTerritoryLookup">Lookup median income</button>
<div id="territoryResult" class="result" style="display:none;"></div>
</div>
<div class="note" id="disclaimer">
This tool is for educational and preliminary screening purposes only and does not constitute legal advice.
</div>
<script>
// ---------- DATA: STATES ----------
const medianIncomeData = {
"Alabama": [62672, 75465, 90321, 104003],
"Alaska": [83617, 109662, 109662, 138492],
"Arizona": [72039, 86745, 102274, 118067],
"Arkansas": [56923, 71742, 80218, 94566],
"California": [77221, 100161, 113553, 135505],
"Colorado": [85685, 106690, 127495, 149566],
"Connecticut": [82141, 103501, 131022, 155834],
"Delaware": [67733, 92445, 108420, 128854],
"District of Columbia": [83202, 157259, 157259, 162327],
"Florida": [68085, 84305, 95039, 111819],
"Georgia": [66722, 82787, 98877, 120315],
"Hawaii": [83068, 103479, 120289, 138536],
"Idaho": [71531, 83951, 95859, 116594],
"Illinois": [71304, 91526, 110712, 134366],
"Indiana": [62808, 79884, 93175, 112691],
"Iowa": [65883, 86523, 101463, 122826],
"Kansas": [67423, 85199, 101189, 122741],
"Kentucky": [60071, 71998, 83027, 106637],
"Louisiana": [57923, 70493, 82433, 100971],
"Maine": [73946, 88126, 104083, 128204],
"Maryland": [84699, 111673, 132464, 161913],
"Massachusetts": [85941, 109818, 135837, 173947],
"Michigan": [65625, 81293, 100797, 119856],
"Minnesota": [75704, 95807, 123244, 146039],
"Mississippi": [52594, 68525, 80722, 94965],
"Missouri": [63306, 79971, 97658, 115491],
"Montana": [69482, 89107, 100637, 118578],
"Nebraska": [65206, 88402, 100754, 121867],
"Nevada": [70370, 85660, 99032, 111184],
"New Hampshire": [85049, 106521, 137902, 151224],
"New Jersey": [84938, 104136, 133620, 163817],
"New Mexico": [64537, 77534, 85784, 96074],
"New York": [71393, 90520, 112616, 135475],
"North Carolina": [65396, 82221, 98932, 113744],
"North Dakota": [71663, 93882, 103951, 134284],
"Ohio": [64541, 81578, 99876, 120531],
"Oklahoma": [59611, 75229, 84618, 99188],
"Oregon": [77061, 91268, 113736, 136434],
"Pennsylvania": [70378, 85290, 107327, 132379],
"Rhode Island": [75662, 96205, 116357, 133954],
"South Carolina": [63146, 81614, 93219, 113332],
"South Dakota": [67416, 87506, 98297, 127386],
"Tennessee": [62339, 80722, 95011, 106775],
"Texas": [65123, 84491, 96728, 114938],
"Utah": [85644, 93302, 109860, 128363],
"Vermont": [70603, 94477, 111150, 134056],
"Virginia": [76479, 98577, 120001, 141113],
"Washington": [86314, 104354, 128360, 152553],
"West Virginia": [62270, 66833, 89690, 91270],
"Wisconsin": [69343, 87938, 105734, 129964],
"Wyoming": [69906, 89156, 95951, 107469]
};
// ---------- DATA: TERRITORIES ----------
const territoryMedianIncomeData = {
"Guam": [52478, 62748, 71504, 86528],
"Northern Mariana Islands": [35241, 35241, 41001, 60304],
"Puerto Rico": [29879, 29879, 39925, 49247],
"Virgin Islands": [41638, 50043, 53356, 58457]
};
const EXTRA_PER_PERSON = 11100;
// ---------- LANGUAGE STRINGS ----------
const strings = {
en: {
titleMain: "Median Income Means Test Calculator",
subtitleMain: "Quick screening based on U.S. Trustee median income data (cases filed on or after November 1, 2025).",
sectionLookupTitle: "1. Median Income Lookup",
sectionMeansTitle: "2. Means Test Style Check (Part 1)",
sectionTerritoryTitle: "3. Territories Median Income Lookup",
labelState: "State",
labelHousehold: "Household size",
noteHousehold: "For more than 4 people, the calculator adds $11,100 per additional person.",
btnLookup: "Lookup median income",
labelIncome6: "Total gross income for last 6 months",
labelIncomeNote: "This will be annualized and compared to the median.",
btnMeans: "Check against median",
labelTerritory: "Commonwealth / U.S. Territory",
labelTerritoryHousehold: "Household size",
noteTerritoryHousehold: "For more than 4 people, the calculator adds $11,100 per additional person.",
btnTerritoryLookup: "Lookup median income",
disclaimer: "This tool is for educational and preliminary screening purposes only and does not constitute legal advice.",
textMedianFor: (state, size, amount) =>
`Median income for ${state}, household size ${size}: $${amount.toLocaleString()}.`,
textAnnualizedIncome: (annual) =>
`Your annualized income (last 6 months × 2): $${annual.toLocaleString()}.`,
textBelowMedian: "Your annualized income is BELOW the median for your state and household size.",
textAboveMedian: "Your annualized income is ABOVE the median for your state and household size.",
textNoState: "Please select a state and enter a valid household size.",
textNoTerritory: "Please select a territory and enter a valid household size.",
textNeedIncome: "Please enter a valid 6‑month income amount."
},
es: {
titleMain: "Calculadora de Ingreso Mediano para la Prueba de Recursos",
subtitleMain: "Evaluación rápida basada en los datos de ingreso mediano del U.S. Trustee (casos presentados a partir del 1 de noviembre de 2025).",
sectionLookupTitle: "1. Consulta de Ingreso Mediano",
sectionMeansTitle: "2. Verificación Estilo Prueba de Recursos (Parte 1)",
sectionTerritoryTitle: "3. Consulta de Ingreso Mediano en Territorios",
labelState: "Estado",
labelHousehold: "Tamaño del hogar",
noteHousehold: "Para más de 4 personas, la calculadora suma $11,100 por cada persona adicional.",
btnLookup: "Consultar ingreso mediano",
labelIncome6: "Ingreso bruto total de los últimos 6 meses",
labelIncomeNote: "Se anualizará y se comparará con el ingreso mediano.",
btnMeans: "Comparar con el ingreso mediano",
labelTerritory: "Mancomunidad / Territorio de EE. UU.",
labelTerritoryHousehold: "Tamaño del hogar",
noteTerritoryHousehold: "Para más de 4 personas, la calculadora suma $11,100 por cada persona adicional.",
btnTerritoryLookup: "Consultar ingreso mediano",
disclaimer: "Esta herramienta es solo para fines educativos y de evaluación preliminar y no constituye asesoría legal.",
textMedianFor: (state, size, amount) =>
`Ingreso mediano para ${state}, hogar de ${size} persona(s): $${amount.toLocaleString()}.`,
textAnnualizedIncome: (annual) =>
`Su ingreso anualizado (últimos 6 meses × 2): $${annual.toLocaleString()}.`,
textBelowMedian: "Su ingreso anualizado está POR DEBAJO del ingreso mediano para su estado y tamaño de hogar.",
textAboveMedian: "Su ingreso anualizado está POR ENCIMA del ingreso mediano para su estado y tamaño de hogar.",
textNoState: "Seleccione un estado e ingrese un tamaño de hogar válido.",
textNoTerritory: "Seleccione un territorio e ingrese un tamaño de hogar válido.",
textNeedIncome: "Ingrese un monto válido de ingreso de 6 meses."
}
};
let currentLang = "en";
// ---------- HELPERS ----------
function getMedianFor(dataObj, key, householdSize) {
if (!dataObj[key]) return null;
const base = dataObj[key];
if (householdSize <= 0) return null;
if (householdSize <= 4) {
return base[householdSize - 1];
}
const extraPeople = householdSize - 4;
return base[3] + extraPeople * EXTRA_PER_PERSON;
}
function updateLanguage() {
const s = strings[currentLang];
document.getElementById("title-main").textContent = s.titleMain;
document.getElementById("subtitle-main").textContent = s.subtitleMain;
document.getElementById("section-lookup-title").textContent = s.sectionLookupTitle;
document.getElementById("section-means-title").textContent = s.sectionMeansTitle;
document.getElementById("section-territory-title").textContent = s.sectionTerritoryTitle;
document.getElementById("label-state").textContent = s.labelState;
document.getElementById("label-household").textContent = s.labelHousehold;
document.getElementById("note-household").textContent = s.noteHousehold;
document.getElementById("btnLookup").textContent = s.btnLookup;
document.getElementById("label-income6").textContent = s.labelIncome6;
document.getElementById("label-income-note").textContent = s.labelIncomeNote;
document.getElementById("btnMeans").textContent = s.btnMeans;
document.getElementById("label-territory").textContent = s.labelTerritory;
document.getElementById("label-territory-household").textContent = s.labelTerritoryHousehold;
document.getElementById("note-territory-household").textContent = s.noteTerritoryHousehold;
document.getElementById("btnTerritoryLookup").textContent = s.btnTerritoryLookup;
document.getElementById("disclaimer").textContent = s.disclaimer;
}
// ---------- INIT SELECTS ----------
function initSelects() {
const stateSelect = document.getElementById("stateSelect");
const territorySelect = document.getElementById("territorySelect");
stateSelect.innerHTML = '<option value="">--</option>';
territorySelect.innerHTML = '<option value="">--</option>';
Object.keys(medianIncomeData).sort().forEach(state => {
const opt = document.createElement("option");
opt.value = state;
opt.textContent = state;
stateSelect.appendChild(opt);
});
Object.keys(territoryMedianIncomeData).sort().forEach(t => {
const opt = document.createElement("option");
opt.value = t;
opt.textContent = t;
territorySelect.appendChild(opt);
});
}
// ---------- EVENT HANDLERS ----------
document.getElementById("langSelect").addEventListener("change", (e) => {
currentLang = e.target.value;
updateLanguage();
});
document.getElementById("btnLookup").addEventListener("click", () => {
const s = strings[currentLang];
const state = document.getElementById("stateSelect").value;
const size = parseInt(document.getElementById("householdSize").value, 10);
const resultDiv = document.getElementById("lookupResult");
if (!state || isNaN(size) || size < 1) {
resultDiv.textContent = s.textNoState;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
const median = getMedianFor(medianIncomeData, state, size);
if (median == null) {
resultDiv.textContent = s.textNoState;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
resultDiv.textContent = s.textMedianFor(state, size, median);
resultDiv.className = "result";
resultDiv.style.display = "block";
});
document.getElementById("btnMeans").addEventListener("click", () => {
const s = strings[currentLang];
const state = document.getElementById("stateSelect").value;
const size = parseInt(document.getElementById("householdSize").value, 10);
const income6 = parseFloat(document.getElementById("income6").value);
const resultDiv = document.getElementById("meansResult");
if (!state || isNaN(size) || size < 1) {
resultDiv.textContent = s.textNoState;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
if (isNaN(income6) || income6 < 0) {
resultDiv.textContent = s.textNeedIncome;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
const median = getMedianFor(medianIncomeData, state, size);
if (median == null) {
resultDiv.textContent = s.textNoState;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
const annualized = income6 * 2;
let msg = s.textMedianFor(state, size, median) + " ";
msg += s.textAnnualizedIncome(annualized) + " ";
if (annualized <= median) {
msg += s.textBelowMedian;
resultDiv.className = "result pass";
} else {
msg += s.textAboveMedian;
resultDiv.className = "result fail";
}
resultDiv.textContent = msg;
resultDiv.style.display = "block";
});
document.getElementById("btnTerritoryLookup").addEventListener("click", () => {
const s = strings[currentLang];
const territory = document.getElementById("territorySelect").value;
const size = parseInt(document.getElementById("territoryHouseholdSize").value, 10);
const resultDiv = document.getElementById("territoryResult");
if (!territory || isNaN(size) || size < 1) {
resultDiv.textContent = s.textNoTerritory;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
const median = getMedianFor(territoryMedianIncomeData, territory, size);
if (median == null) {
resultDiv.textContent = s.textNoTerritory;
resultDiv.className = "result";
resultDiv.style.display = "block";
return;
}
resultDiv.textContent = s.textMedianFor(territory, size, median);
resultDiv.className = "result";
resultDiv.style.display = "block";
});
// ---------- INIT ----------
initSelects();
updateLanguage();
</script>
</body>
</html>