// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // MortgageCard.swift — l'estimateur hypothécaire des fiches Immo·Ka : mise de // fonds ajustable, taux modifiable, paiement mensuel calculé LOCALEMENT et en // toute transparence (formule affichée en pied). Aucune donnée n'est envoyée. import SwiftUI struct MortgageCard: View { let price: Double let accent: Color @State private var downFraction: Double = 0.20 @State private var rate: Double = 4.5 @State private var years: Int = 25 @Environment(\.colorScheme) private var scheme private var payment: Double { MortgageMath.monthlyPayment(price: price, downFraction: downFraction, annualRate: rate, years: years) } private var down: Double { price * downFraction } var body: some View { VStack(alignment: .leading, spacing: 12) { UniverseSectionHeader(title: "Paiement hypothécaire estimé", accent: accent) HStack(alignment: .firstTextBaseline, spacing: 6) { Text(payment.money0) .font(KAFont.display(28)) .foregroundStyle(accent) .contentTransition(.numericText()) Text("/ mois") .font(KAFont.mono(10)) .foregroundStyle(.secondary) } .animation(.snappy, value: payment) VStack(alignment: .leading, spacing: 4) { HStack { Text("Mise de fonds") .font(.caption.weight(.semibold)) Spacer() Text("\(Int(downFraction * 100)) % · \(down.money0)") .font(KAFont.mono(10)) .foregroundStyle(accent) } Slider(value: $downFraction, in: 0.05...0.5, step: 0.05) .tint(accent) .accessibilityLabel("Mise de fonds") .accessibilityValue("\(Int(downFraction * 100)) pour cent") } HStack(spacing: 12) { Stepper(value: $rate, in: 1...10, step: 0.25) { VStack(alignment: .leading, spacing: 1) { Text("TAUX").font(KAFont.mono(8)).foregroundStyle(.secondary) Text(String(format: "%.2f %%", rate)) .font(.subheadline.weight(.bold)) } } .accessibilityLabel("Taux d'intérêt annuel") Stepper(value: $years, in: 5...30, step: 5) { VStack(alignment: .leading, spacing: 1) { Text("AMORTISSEMENT").font(KAFont.mono(8)).foregroundStyle(.secondary) Text("\(years) ans").font(.subheadline.weight(.bold)) } } .accessibilityLabel("Période d'amortissement") } Text("Estimation indicative calculée sur votre appareil — taxes, assurance SCHL et frais exclus.") .font(.caption2).foregroundStyle(.tertiary) } .padding(14) .frame(maxWidth: .infinity, alignment: .leading) .kaCard(accent: accent) } }