diff --git a/app/src/data/posts/articles/ri-ctc-calculator-press-release.md b/app/src/data/posts/articles/ri-ctc-calculator-press-release.md
index 690655dab..e0b74d6c1 100644
--- a/app/src/data/posts/articles/ri-ctc-calculator-press-release.md
+++ b/app/src/data/posts/articles/ri-ctc-calculator-press-release.md
@@ -9,7 +9,7 @@ The Rhode Island CTC Calculator allows users to model how different Child Tax Cr
This tool exemplifies PolicyEngine's approach to policy analysis: providing transparent, accessible modeling that empowers policymakers, advocates, and the public to understand the trade-offs inherent in policy design. Use the calculator below:
+ height="800" frameborder="0">
The Niskanen Center tested the calculator and used it to evaluate how different CTC parameters would affect Rhode Island households across the income distribution. They then shared the tool with Governor Dan McKee's office, which used the calculator to evaluate reform options and design the Child Tax Credit proposal included in his fiscal year 2027 budget.
diff --git a/app/src/data/posts/articles/ri-governor-mckee-child-tax-credit.md b/app/src/data/posts/articles/ri-governor-mckee-child-tax-credit.md
index 1cb6ab061..e1b064f25 100644
--- a/app/src/data/posts/articles/ri-governor-mckee-child-tax-credit.md
+++ b/app/src/data/posts/articles/ri-governor-mckee-child-tax-credit.md
@@ -19,8 +19,8 @@ Governor McKee's proposal would replace this exemption with a $325 fully refunda
- **Credit amount:** $325 per qualifying child
- **Age eligibility:** Children under 19 years old
- **Refundability:** Fully refundable, meaning families can receive the credit with no earnings
-- **Phase-out:** Mirrors the personal exemption's phase-out structure. The credit amount is reduced by 20% for each $7,590 of AGI above $265,965 in 2027.
-- **Exemption integration:** Eliminates the personal exemption for CTC-qualifying children; the exemption remains for dependents 19 and older.
+- **Phase-out:** Mirrors the personal exemption's phase-out structure. The credit amount is reduced by 20% for each $7,590 of AGI above $265,965 in 2027.
+- **Exemption integration:** Eliminates the personal exemption for CTC-qualifying children; the exemption remains for dependents 19 and older.
Every household with a child would receive the same credit amount of $325 before the phase-out, rather than receiving tax savings determined by their income.
@@ -36,7 +36,7 @@ The reform primarily benefits lower-income families with children, as they see l
## Statewide impacts
-For tax year 2027, the proposal would reduce state revenues by $36.7 million, according to PolicyEngine's static modeling. The reform would also raise the net income of 29.2% of Rhode Island residents, with beneficiaries concentrated in lower income ranges (see Figure 2). We project that the proposal would reduce poverty and child poverty by 1.0 and 2.1%, respectively, as measured by the Supplemental Poverty Measure. Figure 3 displays the statewide impacts of Governor McKee's CTC proposal.
+For tax year 2027, the proposal would reduce state revenues by $36.7 million, according to PolicyEngine's static modeling. The reform would also raise the net income of 29.2% of Rhode Island residents, with beneficiaries concentrated in lower income ranges (see Figure 2). We project that the proposal would reduce poverty and child poverty by 1.0 and 2.1%, respectively, as measured by the Supplemental Poverty Measure. Figure 3 displays the statewide impacts of Governor McKee's CTC proposal.

@@ -44,7 +44,7 @@ For tax year 2027, the proposal would reduce state revenues by $36.7 million, ac
## Conclusion
-Governor McKee's proposed child tax credit would replace the personal exemption with a $325 fully refundable CTC for children under the age of 19. We project the reform would benefit 29.2% of Rhode Island residents, while lowering net income for no households.
+Governor McKee's proposed child tax credit would replace the personal exemption with a $325 fully refundable CTC for children under the age of 19. We project the reform would benefit 29.2% of Rhode Island residents, while lowering net income for no households.
As policymakers evaluate reforms such as these, analytical tools like PolicyEngine offer critical insights into the impacts on diverse household compositions and the broader economy.
diff --git a/app/src/data/posts/articles/validating-unemployment-insurance-estimates.md b/app/src/data/posts/articles/validating-unemployment-insurance-estimates.md
index 48b53c1be..e77a9c68b 100644
--- a/app/src/data/posts/articles/validating-unemployment-insurance-estimates.md
+++ b/app/src/data/posts/articles/validating-unemployment-insurance-estimates.md
@@ -66,12 +66,12 @@ TRIM3 does not document how it selects which non-reporters to assign UI or how i
## Summary
-| Model | Method | Distribution | Open source |
-| ------------------- | ------------------------------ | ----------------------- | -------------------------------------------------------------------- |
-| **PolicyEngine** | QRF + reweight to SOI | Nonparametric (learned) | [Yes](https://github.com/PolicyEngine/policyengine-us-data) |
-| **Fed/JCT** | Normal draw by percentile | Normal(μ, σ) | [Yes (Stata)](https://davidsplinter.com/CPS-UI-Imputation.txt) |
-| **CBO** | Probit → assign group averages | Point estimates | [Partial](https://github.com/US-CBO/means_tested_transfer_imputations) |
-| **TRIM3** | Adjust reported amounts | Deterministic | No |
+| Model | Method | Distribution | Open source |
+| ---------------- | ------------------------------ | ----------------------- | ---------------------------------------------------------------------- |
+| **PolicyEngine** | QRF + reweight to SOI | Nonparametric (learned) | [Yes](https://github.com/PolicyEngine/policyengine-us-data) |
+| **Fed/JCT** | Normal draw by percentile | Normal(μ, σ) | [Yes (Stata)](https://davidsplinter.com/CPS-UI-Imputation.txt) |
+| **CBO** | Probit → assign group averages | Point estimates | [Partial](https://github.com/US-CBO/means_tested_transfer_imputations) |
+| **TRIM3** | Adjust reported amounts | Deterministic | No |
## Why methodology matters
diff --git a/app/src/hooks/useUserReports.ts b/app/src/hooks/useUserReports.ts
index bddb1208e..cb77875a2 100644
--- a/app/src/hooks/useUserReports.ts
+++ b/app/src/hooks/useUserReports.ts
@@ -20,6 +20,7 @@ import {
} from '@/types/ingredients/UserPopulation';
import { UserReport } from '@/types/ingredients/UserReport';
import { UserSimulation } from '@/types/ingredients/UserSimulation';
+import { findPlaceFromRegionString, getPlaceDisplayName } from '@/utils/regionStrategies';
import { householdKeys, policyKeys, reportKeys, simulationKeys } from '../libs/queryKeys';
import { useGeographicAssociationsByUser } from './useUserGeographic';
import { useHouseholdAssociationsByUser } from './useUserHousehold';
@@ -470,6 +471,11 @@ export const useUserReportById = (userReportId: string, options?: { enabled?: bo
let name: string;
if (isNational) {
name = sim.countryId.toUpperCase();
+ } else if (sim.populationId.startsWith('place/')) {
+ // For US places (municipalities), use the place lookup function
+ // Import at top: import { findPlaceFromRegionString, getPlaceDisplayName } from '@/utils/regionStrategies';
+ const place = findPlaceFromRegionString(sim.populationId);
+ name = place ? getPlaceDisplayName(place.name) : sim.populationId;
} else {
// For subnational, extract the base geography ID and look up in metadata
// e.g., "us-fl" -> "fl", "uk-scotland" -> "scotland"
diff --git a/app/src/hooks/utils/useFetchReportIngredients.ts b/app/src/hooks/utils/useFetchReportIngredients.ts
index 50e8a3f65..4a968a1cd 100644
--- a/app/src/hooks/utils/useFetchReportIngredients.ts
+++ b/app/src/hooks/utils/useFetchReportIngredients.ts
@@ -32,6 +32,7 @@ import {
} from '@/types/ingredients/UserPopulation';
import { UserReport } from '@/types/ingredients/UserReport';
import { UserSimulation } from '@/types/ingredients/UserSimulation';
+import { findPlaceFromRegionString, getPlaceDisplayName } from '@/utils/regionStrategies';
import { combineLoadingStates, extractUniqueIds, useParallelQueries } from './normalizedUtils';
// Type for geography options from redux store
@@ -60,6 +61,10 @@ export function buildGeographiesFromSimulations(
let name: string;
if (isNational) {
name = sim.countryId.toUpperCase();
+ } else if (sim.populationId.startsWith('place/')) {
+ // For US places (municipalities), use the place lookup function
+ const place = findPlaceFromRegionString(sim.populationId);
+ name = place ? getPlaceDisplayName(place.name) : sim.populationId;
} else {
// For subnational, extract the base geography ID and look up in metadata
const parts = sim.populationId.split('-');
diff --git a/app/src/pathways/report/components/geographicOptions/USGeographicOptions.tsx b/app/src/pathways/report/components/geographicOptions/USGeographicOptions.tsx
index 8cf3fc196..23f523708 100644
--- a/app/src/pathways/report/components/geographicOptions/USGeographicOptions.tsx
+++ b/app/src/pathways/report/components/geographicOptions/USGeographicOptions.tsx
@@ -2,6 +2,7 @@ import { Box, Radio } from '@mantine/core';
import { USScopeType } from '@/types/regionTypes';
import { RegionOption, US_REGION_TYPES } from '@/utils/regionStrategies';
import USDistrictSelector from './USDistrictSelector';
+import USPlaceSelector from './USPlaceSelector';
import USStateSelector from './USStateSelector';
interface USGeographicOptionsProps {
@@ -75,6 +76,21 @@ export default function USGeographicOptions({
)}
+ {/* Place (city) option */}
+
+ handleScopeChange(US_REGION_TYPES.PLACE)}
+ />
+ {scope === US_REGION_TYPES.PLACE && (
+
+
+
+ )}
+
+
{/* Household option */}
void;
+}
+
+export default function USPlaceSelector({ selectedPlace, onPlaceChange }: USPlaceSelectorProps) {
+ const [selectedStateName, setSelectedStateName] = useState('');
+
+ // Get unique state names for the state dropdown
+ const stateNames = useMemo(() => getPlaceStateNames(), []);
+
+ // Initialize selectedStateName from selectedPlace if one is already selected
+ useEffect(() => {
+ if (selectedPlace) {
+ const place = findPlaceFromRegionString(selectedPlace);
+ if (place && place.stateName !== selectedStateName) {
+ setSelectedStateName(place.stateName);
+ }
+ }
+ }, [selectedPlace, selectedStateName]);
+
+ // Filter places based on selected state name
+ const filteredPlaces = useMemo(() => filterPlacesByState(selectedStateName), [selectedStateName]);
+
+ // Format places for the dropdown with clean display names, sorted alphabetically
+ const placeOptions = useMemo(
+ () =>
+ filteredPlaces
+ .map((p) => ({
+ value: placeToRegionString(p),
+ label: getPlaceDisplayName(p.name),
+ }))
+ .sort((a, b) => a.label.localeCompare(b.label)),
+ [filteredPlaces]
+ );
+
+ // Handle state change for place selection
+ const handleStateChange = (stateName: string | null) => {
+ setSelectedStateName(stateName || '');
+ // Auto-select the first place when a state is chosen
+ if (stateName) {
+ const statePlaces = filterPlacesByState(stateName);
+ if (statePlaces.length > 0) {
+ onPlaceChange(placeToRegionString(statePlaces[0]));
+ }
+ } else {
+ onPlaceChange('');
+ }
+ };
+
+ return (
+
+