feat: soft factor enrichment from Swiss location intelligence

When property has no soft factor data, estimate from location:
- 18 location rules covering CH cities/districts (Zürich quartiers,
  Zug tax haven, Bern, Basel, Genf, Lausanne, Luzern, Winterthur,
  logistics hubs) + generic CH fallback
- Estimated factors marked with 'estimated: true' on ScoreFactor
- ScoreBreakdownPanel shows purple 'Schätzung' badge on estimated rows
- Scoring engine: neutral 50 only if no location match found

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-22 11:04:51 +02:00
parent f82194ea7f
commit 98b4a1146b
4 changed files with 210 additions and 2 deletions
@@ -54,11 +54,16 @@ function CriterionRow({ factor, maxWeight }: { factor: ScoreFactor; maxWeight: n
return (
<Box sx={{ mb: 1.5 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', mb: 0.4 }}>
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.75 }}>
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.75, flexWrap: 'wrap' }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: '#1e293b', minWidth: 90 }}>{label}</Typography>
<Typography variant="caption" sx={{ color: imp.color, fontSize: '0.68rem', fontWeight: 500 }}>
{imp.label}
</Typography>
{factor.estimated && (
<Typography variant="caption" sx={{ fontSize: '0.62rem', color: '#7c3aed', bgcolor: '#f5f3ff', px: 0.5, borderRadius: 0.5, border: '1px solid #e9d5ff', lineHeight: 1.6 }}>
Schätzung
</Typography>
)}
<Typography variant="caption" sx={{ color: '#cbd5e1', fontSize: '0.65rem' }}>
{pct}%
</Typography>