// Static location intelligence data per city — mock values based on Swiss market context export interface CityIntelligence { vacancyRatePct: number // Leerstandsquote % rentTrend12m: number // Mietpreisveränderung % (letztes Jahr) purchasingPowerIndex: number // Kaufkraft-Index (CH = 100) dominantIndustryClusters: string[] plannedInfrastructure: { project: string; timeline: string; impact: string }[] medianRentOffice: number // CHF/m²/Monat (Bürofläche) — getMarketRent rechnet auf Jahr um medianRentLogistics: number // CHF/m²/Monat medianRentRetail: number // CHF/m²/Monat avgDaysOnMarket: number // Durchschnittliche Tage bis Vermietung demandStrength: 'LOW' | 'MEDIUM' | 'HIGH' | 'VERY_HIGH' taxIndexCanton: number // Steuerindex 100 = CH-Mittel taxCalculatorUrl?: string // Kantonaler Steuerrechner } export const CITY_INTELLIGENCE: Record = { 'Zürich': { vacancyRatePct: 2.8, rentTrend12m: +4.2, purchasingPowerIndex: 128, dominantIndustryClusters: ['Finanz & Banking', 'Tech & Startups', 'Medien & Kreativ', 'Pharma & Life Science'], plannedInfrastructure: [ { project: 'Tram Hardbrücke-Verlängerung', timeline: '2027', impact: 'Bessere ÖV-Anbindung Industriequartier' }, { project: 'Rosengarten-Tunnel', timeline: '2030', impact: 'Entlastung Kreis 5/6, weniger Durchgangsverkehr' }, ], medianRentOffice: 42, medianRentLogistics: 14, medianRentRetail: 180, avgDaysOnMarket: 38, demandStrength: 'VERY_HIGH', taxIndexCanton: 100, taxCalculatorUrl: 'https://www.zh.ch/de/steuern-finanzen/steuerrechner.html', }, 'Basel': { vacancyRatePct: 4.1, rentTrend12m: +1.8, purchasingPowerIndex: 112, dominantIndustryClusters: ['Pharma & Chemie', 'Logistik & Handel', 'Medizintechnik', 'Finanzdienstleistungen'], plannedInfrastructure: [ { project: 'Basel SBB Südeingang Neubau', timeline: '2026', impact: 'Aufwertung Bahnhofumgebung' }, { project: 'Regio-S-Bahn Ausbau', timeline: '2028', impact: 'Bessere Grenzpendler-Anbindung' }, ], medianRentOffice: 32, medianRentLogistics: 11, medianRentRetail: 120, avgDaysOnMarket: 52, demandStrength: 'HIGH', taxIndexCanton: 98, taxCalculatorUrl: 'https://www.steuern.bs.ch/steuerrechner', }, 'Bern': { vacancyRatePct: 3.5, rentTrend12m: +2.1, purchasingPowerIndex: 108, dominantIndustryClusters: ['Bundesverwaltung & NPO', 'Gesundheit', 'Bildung & Forschung', 'Versicherungen'], plannedInfrastructure: [ { project: 'Bernmobil Netzausbau West', timeline: '2026', impact: 'Erschliessung Entwicklungsgebiet Ausserholligen' }, ], medianRentOffice: 28, medianRentLogistics: 10, medianRentRetail: 95, avgDaysOnMarket: 61, demandStrength: 'MEDIUM', taxIndexCanton: 112, taxCalculatorUrl: 'https://www.taxme.ch', }, 'Zug': { vacancyRatePct: 1.9, rentTrend12m: +5.1, purchasingPowerIndex: 148, dominantIndustryClusters: ['Rohstoffhandel', 'Crypto & Blockchain', 'Holding & Finanzen', 'Tech-Unternehmen'], plannedInfrastructure: [ { project: 'Metrobahn Zug-Luzern', timeline: '2029', impact: 'Direktverbindung Luzern in 18 Min.' }, ], medianRentOffice: 38, medianRentLogistics: 13, medianRentRetail: 140, avgDaysOnMarket: 24, demandStrength: 'VERY_HIGH', taxIndexCanton: 60, taxCalculatorUrl: 'https://www.zg.ch/behoerden/finanzdirektion/steuerverwaltung/steuerrechner', }, 'Winterthur': { vacancyRatePct: 5.8, rentTrend12m: +0.9, purchasingPowerIndex: 98, dominantIndustryClusters: ['Industrie & Maschinenbau', 'Logistik', 'Gesundheit & Soziales'], plannedInfrastructure: [ { project: 'Stadtraum HB Winterthur', timeline: '2027', impact: 'Aufwertung Bahnhofsumgebung, mehr Frequenz' }, ], medianRentOffice: 22, medianRentLogistics: 9, medianRentRetail: 75, avgDaysOnMarket: 74, demandStrength: 'MEDIUM', taxIndexCanton: 119, taxCalculatorUrl: 'https://www.zh.ch/de/steuern-finanzen/steuerrechner.html', }, 'Geneva': { vacancyRatePct: 2.2, rentTrend12m: +3.6, purchasingPowerIndex: 135, dominantIndustryClusters: ['Internationale Organisationen', 'Luxusgüter', 'Banking & Private Equity', 'Uhrenindustrie'], plannedInfrastructure: [ { project: 'CEVA Linie Verlängerung', timeline: '2026', impact: 'Bessere Verbindung Lancy-Pont-Rouge' }, ], medianRentOffice: 55, medianRentLogistics: 18, medianRentRetail: 220, avgDaysOnMarket: 31, demandStrength: 'HIGH', taxIndexCanton: 125, taxCalculatorUrl: 'https://www.ge.ch/calculer-impots', }, 'St.Gallen': { vacancyRatePct: 6.2, rentTrend12m: -0.5, purchasingPowerIndex: 95, dominantIndustryClusters: ['Textil & Mode', 'KMU', 'Logistik', 'Gesundheit'], plannedInfrastructure: [], medianRentOffice: 19, medianRentLogistics: 8, medianRentRetail: 65, avgDaysOnMarket: 88, demandStrength: 'LOW', taxIndexCanton: 107, taxCalculatorUrl: 'https://www.steuern.sg.ch/home/steuerrechner.html', }, } export function getCityIntelligence(city: string): CityIntelligence | null { // Try exact match first, then partial if (CITY_INTELLIGENCE[city]) return CITY_INTELLIGENCE[city] const key = Object.keys(CITY_INTELLIGENCE).find(k => city.toLowerCase().includes(k.toLowerCase())) return key ? CITY_INTELLIGENCE[key] : null } /** Median-Marktmiete in CHF/m²/**Jahr** (Daten sind monatlich gespeichert → ×12), passend zu property.rentPricePerSqm. */ export function getMarketRent(city: string, assetType: string): number | null { const intel = getCityIntelligence(city) if (!intel) return null const monthly = assetType === 'LOGISTICS' || assetType === 'LIGHT_INDUSTRIAL' ? intel.medianRentLogistics : assetType === 'RETAIL' ? intel.medianRentRetail : intel.medianRentOffice return monthly * 12 } // ── City coordinates (WGS84) ───────────────────────────────────────────────── const CITY_COORDS: Record = { 'Zürich': { lat: 47.3769, lng: 8.5417 }, 'Zürich-West': { lat: 47.3862, lng: 8.5195 }, 'Zürich-Nord': { lat: 47.4108, lng: 8.5450 }, 'Basel': { lat: 47.5596, lng: 7.5886 }, 'Bern': { lat: 46.9480, lng: 7.4474 }, 'Luzern': { lat: 47.0502, lng: 8.3093 }, 'Genf': { lat: 46.2044, lng: 6.1432 }, 'Lausanne': { lat: 46.5197, lng: 6.6323 }, 'Zug': { lat: 47.1661, lng: 8.5158 }, 'Winterthur': { lat: 47.5004, lng: 8.7256 }, 'St. Gallen': { lat: 47.4245, lng: 9.3767 }, 'Lugano': { lat: 46.0037, lng: 8.9511 }, 'Baar': { lat: 47.1965, lng: 8.5286 }, 'Muttenz': { lat: 47.5218, lng: 7.6468 }, 'Pratteln': { lat: 47.5163, lng: 7.6926 }, 'Reinach BL': { lat: 47.4948, lng: 7.5946 }, 'Allschwil': { lat: 47.5529, lng: 7.5368 }, 'Binningen': { lat: 47.5363, lng: 7.5687 }, } export function lookupCityCoords(location: string): { lat: number; lng: number } | null { if (CITY_COORDS[location]) return CITY_COORDS[location] // Prefix fallback: "Zürich Kreis 5" → "Zürich" const base = location.split(' ')[0] const key = Object.keys(CITY_COORDS).find(k => k.startsWith(base) || base === k) return key ? CITY_COORDS[key] : null }