diff --git a/apps/web/app/[locale]/(public)/page.tsx b/apps/web/app/[locale]/(public)/page.tsx
index 6a4ea49..411e64b 100644
--- a/apps/web/app/[locale]/(public)/page.tsx
+++ b/apps/web/app/[locale]/(public)/page.tsx
@@ -25,9 +25,15 @@ import { listingsApi, type ListingDetail } from '@/lib/listings-api';
/* ------------------------------------------------------------------ */
+/**
+ * Heatmap + district stats are aggregated quarterly in MarketIndex
+ * (`YYYY-QN`). The previous `YYYY-MM` format never matched any row, so
+ * the heatmap and district table came back empty.
+ */
function currentPeriod(): string {
const now = new Date();
- return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
+ const quarter = Math.floor(now.getMonth() / 3) + 1;
+ return `${now.getFullYear()}-Q${quarter}`;
}
/* ------------------------------------------------------------------ */
diff --git a/apps/web/components/charts/__tests__/price-area-chart.spec.tsx b/apps/web/components/charts/__tests__/price-area-chart.spec.tsx
index 0e44121..20d03fc 100644
--- a/apps/web/components/charts/__tests__/price-area-chart.spec.tsx
+++ b/apps/web/components/charts/__tests__/price-area-chart.spec.tsx
@@ -58,7 +58,7 @@ describe('PriceAreaChart', () => {
);
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
'data-stroke',
- 'var(--color-signal-up)',
+ 'hsl(var(--signal-up))',
);
});
@@ -73,7 +73,7 @@ describe('PriceAreaChart', () => {
);
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
'data-stroke',
- 'var(--color-signal-down)',
+ 'hsl(var(--signal-down))',
);
});
@@ -81,7 +81,7 @@ describe('PriceAreaChart', () => {
render();
expect(screen.getByTestId('area-avgPriceM2')).toHaveAttribute(
'data-stroke',
- 'var(--color-signal-down)',
+ 'hsl(var(--signal-down))',
);
});
diff --git a/apps/web/components/charts/price-area-chart.tsx b/apps/web/components/charts/price-area-chart.tsx
index 74095d5..b09f95a 100644
--- a/apps/web/components/charts/price-area-chart.tsx
+++ b/apps/web/components/charts/price-area-chart.tsx
@@ -29,12 +29,12 @@ export function PriceAreaChart({ data, height = 280, className }: PriceAreaChart
const isUp =
data.length >= 2 && data[data.length - 1]!.avgPriceM2 >= data[0]!.avgPriceM2;
- const strokeColor = isUp
- ? 'var(--color-signal-up)'
- : 'var(--color-signal-down)';
- const fillColor = isUp
- ? 'var(--color-signal-up)'
- : 'var(--color-signal-down)';
+ // CSS tokens are stored as raw HSL components (`--signal-up: 142 72% 50%`),
+ // so they must be wrapped in `hsl(...)`. The previous `var(--color-signal-up)`
+ // form referenced a non-existent variable, leaving recharts with `undefined`
+ // and rendering an invisible line/area.
+ const strokeColor = isUp ? 'hsl(var(--signal-up))' : 'hsl(var(--signal-down))';
+ const fillColor = strokeColor;
return (
@@ -48,17 +48,17 @@ export function PriceAreaChart({ data, height = 280, className }: PriceAreaChart
diff --git a/apps/web/components/listings/sparkline.tsx b/apps/web/components/listings/sparkline.tsx
index 3ab8b5f..001ab4b 100644
--- a/apps/web/components/listings/sparkline.tsx
+++ b/apps/web/components/listings/sparkline.tsx
@@ -49,7 +49,7 @@ export function Sparkline({ listingId, width = 64, height = 20 }: SparklineProps
// Color based on trend direction
const trending = prices[prices.length - 1]! >= prices[0]!;
- const strokeColor = trending ? 'var(--color-signal-up)' : 'var(--color-signal-down)';
+ const strokeColor = trending ? 'hsl(var(--signal-up))' : 'hsl(var(--signal-down))';
return (