summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md455
-rw-r--r--app/README.md1012
-rw-r--r--app/i18n.akk-x-ob.js2
-rw-r--r--app/i18n.akk-x-ob.translit.js2
-rw-r--r--app/i18n.bar.js2
-rw-r--r--app/i18n.de-x-amt.js2
-rw-r--r--app/i18n.de-x-sales.js2
-rw-r--r--app/i18n.de.js2
-rw-r--r--app/i18n.en.js2
-rw-r--r--app/i18n.eo.js2
-rw-r--r--app/i18n.eu.js2
-rw-r--r--app/i18n.fr.js2
-rw-r--r--app/i18n.gmh.js2
-rw-r--r--app/i18n.goh.js2
-rw-r--r--app/i18n.got.js2
-rw-r--r--app/i18n.grc.js2
-rw-r--r--app/i18n.ine-x-proto.js2
-rw-r--r--app/i18n.ja.js2
-rw-r--r--app/i18n.jbo.js2
-rw-r--r--app/i18n.la.js2
-rw-r--r--app/i18n.nds.js2
-rw-r--r--app/i18n.nl.js2
-rw-r--r--app/i18n.sa.js2
-rw-r--r--app/i18n.tok.js2
-rw-r--r--app/i18n.tr.js2
-rw-r--r--app/i18n.uk.js2
-rw-r--r--app/index.html6
-rw-r--r--app/pruefe.js2
-rw-r--r--bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsxbin121001 -> 0 bytes
-rw-r--r--build_bav.py1592
-rw-r--r--recalc.log0
31 files changed, 776 insertions, 2339 deletions
diff --git a/README.md b/README.md
index 909befc..c4aa87d 100644
--- a/README.md
+++ b/README.md
@@ -1,309 +1,286 @@
-# bAV (DYNO) vs. Altersvorsorgedepot vs. privates ETF-Depot
+# Altersvorsorgerechner
-Vergleichsmodell für drei Wege der Altersvorsorge mit **demselben ETF**, Rechtsstand 2026.
-Vollständig formelbasierte Excel-Arbeitsmappe (6.359 Formeln), erzeugt aus einem Python-Skript.
+**Vergleichsrechner für drei Gestaltungsvarianten der Altersvorsorge bei gleichem Nettoaufwand.
+Rechtsstand 2026.**
-| Datei | Rolle |
-|---|---|
-| `bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx` | Das Modell. Nur die gelben Zellen im Blatt `Eingaben` ändern. |
-| `build_bav.py` | Generator. Erzeugt die Mappe vollständig neu. **Einzige Quelle der Wahrheit** — Änderungen gehören hierhin, nicht in die xlsx. |
-| `app/` | **Web-App zum Weitergeben.** Derselbe Rechenkern in JavaScript, mobilfreundlich, offlinefähig, mit Sensitivitätskurven. Siehe `app/README.md`. |
-| `tests/` (in den Sitzungsausgaben) | Regressionslauf gegen einen frischen LibreOffice-Recalc dieser Mappe. |
-| `README.md` | Diese Datei. |
-
-> **Zwei Quellen der Wahrheit.** Der Rechenkern liegt zweimal vor: als Formelgenerator in
-> `build_bav.py` und als JavaScript in Teil 1 von `app/index.html`. Sie stimmen auf 1,3·10⁻¹⁴
-> relativ überein — **sechs** Testfälle, jeweils rund 20 Aggregate, gegen einen frischen
-> LibreOffice-Recalc dieser Mappe. Bei jeder Rechtsänderung **beide** anfassen und danach den
-> Abgleich wiederholen; er ist der einzige Schutz davor, dass sie auseinanderlaufen.
+Bei dem vorliegenden Bestand handelt es sich um eine Webanwendung. Sie stellt gegenüber, was
+aus ein und demselben monatlichen Verzicht auf verfügbares Einkommen wird, je nachdem, ob
+dieser Betrag in eine betriebliche Altersversorgung, in ein Altersvorsorgedepot oder in ein
+privates ETF-Depot geleitet wird. Ein Server wird nicht betrieben; eine Übermittlung der
+eingegebenen Daten findet nicht statt.
---
-## 1. Das Vergleichsprinzip
-
-Ein Vergleich von Bruttobeiträgen wäre unfair: Entgeltumwandlung kommt aus dem Brutto,
-privates Sparen aus dem Netto. Deshalb wird der **Nettoaufwand** gleichgesetzt:
-
-```
-Nettoaufwand = Bruttobeitrag − Lohnsteuerersparnis − ersparter AN-Anteil zur Sozialversicherung
-```
-
-Genau dieser Betrag wird in allen drei Optionen investiert. Was übrig bleibt, ist ein
-Vergleich der Förderarchitekturen, nicht der Einzahlungshöhen.
+## § 1 Gegenstand und Zweck
-Über Zelle `C22` lässt sich die Richtung umkehren: Vorgabe des Nettoaufwands, Rückrechnung
-des Bruttobeitrags. Da N(B) wegen der Knicke bei 4 % und 8 % der BBG-RV, an den
-Beitragsbemessungsgrenzen und an den Tarifeckwerten nicht geschlossen invertierbar,
-aber stetig und streng monoton wachsend ist, geschieht das per Bisektion (34 Schritte,
-Blatt `Umrechnung`).
+(1) Verglichen werden drei Gestaltungsvarianten, und zwar durchgängig unter Zugrundelegung
+**desselben** Wertpapiers:
-### Die vier Werttreiber
-
-Steueraufschub ist für sich genommen wertlos: (1−t)·(1+r)ⁿ = (1+r)ⁿ·(1−t). Multiplikation
-kommutiert. Es bleiben nur:
+| | Gestaltungsvariante | Wesentliches Merkmal |
+|---|---|---|
+| 1. | **Betriebliche Altersversorgung** durch Entgeltumwandlung (§ 1a BetrAVG) | Beitrag aus dem Bruttoentgelt; Arbeitgeberzuschuss; im Ruhestand Beiträge zur Kranken- und Pflegeversicherung auf den Versorgungsbezug (§§ 229, 250 SGB V) |
+| 2. | **Altersvorsorgedepot** (Reform der geförderten privaten Altersvorsorge 2026) | Beitrag aus dem versteuerten Entgelt; Zulagen und Sonderausgabenabzug; keine Vorabpauschale; Verfügung vor Vollendung des 65. Lebensjahres förderschädlich |
+| 3. | **Privates ETF-Depot** | Beitrag aus dem versteuerten Entgelt; keinerlei Förderung; jederzeitige Verfügbarkeit; Abgeltungsteuer nebst Vorabpauschale |
-1. **Tarifarbitrage** t₀ − t₁ (Grenzsteuersatz beim Einzahlen minus beim Auszahlen)
-2. **Fremdgeld** — AG-Zuschuss bzw. Zulagen
-3. **Steuerfreie Thesaurierung** — bAV und Altersvorsorgedepot kennen keine Vorabpauschale
-4. **Neue Abgaben, die nur eine Option treffen** — KV/PV auf Versorgungsbezüge (§ 229 SGB V)
+(2) Die Auskunft richtet sich an Personen, welchen ein Angebot zur Entgeltumwandlung
+unterbreitet worden ist und welche die Vorteilhaftigkeit desselben zu beurteilen beabsichtigen.
+Vorkenntnisse werden nicht vorausgesetzt; sämtliche Eingabefelder sind mit sachgerechten
+Voreinstellungen versehen, und zu jedem Feld wird über die Schaltfläche `?` eine Erläuterung
+nebst Rechtsgrundlage bereitgehalten.
-Punkt 4 ist der dominante Nachteil der bAV; Punkt 2 ihr einziger struktureller Vorteil.
+(3) Es wird ausdrücklich darauf hingewiesen, dass es sich **nicht** um einen Produktvergleich,
+**nicht** um eine Anlageempfehlung und **nicht** um einen Haushaltsplaner handelt. Verglichen
+werden ausschließlich die Förderarchitekturen; die Anlageentscheidung ist in allen drei
+Varianten dieselbe und wird daher nicht mitverglichen (vgl. § 4).
---
-## 2. Blattstruktur
-
-| Blatt | Inhalt |
-|---|---|
-| `Anleitung` | Aufbau, Modellannahmen, Quellen |
-| `Begriffe` | 43 Fachbegriffe mit Fundstelle bzw. Kennzeichnung als Modellkonvention |
-| `Eingaben` | **Die einzigen Zellen, die man ändert.** Ergebnisblock am Fuß |
-| `Parameter` | Rechengrößen 2026 mit Fundstelle, abgeleitete Größen |
-| `Umrechnung` | Bisektion Nettoaufwand → Bruttobeitrag |
-| `Ansparphase` | 62 Spalten × 50 Jahre (Zeilen 8–57) |
-| `Auszahlung` | 58 Spalten × 34 Jahre (Zeilen 8–41) |
-| `Cashflow` | Zahlungsströme für IRR und Barwerte (Zeilen 5–69) |
-| `Vergleich` | Ergebnis, Diagnose, monatliche Leistung, Diagramm |
+## § 2 Inbetriebnahme
-### Feste Adressen im Blatt `Vergleich`
+(1) **Einfachster Weg.** Die Datei `app/index.html` ist mittels Doppelklicks zu öffnen. Ein
+Aufbau, eine Installation oder eine Verbindung zum Internet sind hierfür nicht erforderlich;
+sämtliche Berechnungen werden im Browser durchgeführt.
-Diese werden von anderen Blättern referenziert — beim Einfügen von Zeilen **mitziehen**:
+(2) **Mit Installierbarkeit und Offline-Betrieb.** Sofern zusätzlich das Symbol auf dem
+Startbildschirm sowie die Zwischenspeicherung durch den Dienstarbeiter (*service worker*)
+gewünscht wird, ist der Ordner `app/` über einen Webserver auszuliefern:
-| Zeile | Inhalt |
-|---|---|
-| 5–19 | Haupttabelle (13 = Barwert Netto-Auszahlungen, 15 = Barwert Netto-Ertrag, 17 = IRR) |
-| 22–37 | Diagnose (31–35 = Freibetragsanalyse, 36/37 = Memo-Zeilen für Rentenzahlungen nach dem Horizont) |
-| 40–48 | Monatliche Leistung (47 = äquivalente Monatsleistung real) |
-| 50–52 | Diagrammdaten |
-| 55 | Diagramm |
+```bash
+cd app && python3 -m http.server 8000 # sodann: http://localhost:8000
+```
-`Eingaben` verweist auf `Vergleich` **13, 15, 47**.
+Ein Betrieb über `http://localhost` ist zulässig; die Adresse gilt als sicherer Kontext im
+Sinne der einschlägigen Spezifikation und ist von dem Erfordernis einer
+Transportverschlüsselung ausdrücklich ausgenommen.
----
+(3) **Weitergabe an Dritte.** Hinsichtlich der drei hierfür vorgesehenen Wege — Versendung der
+Dateien, Bereitstellung auf einem Webspeicherplatz, Übermittlung eines Verweises einschließlich
+sämtlicher eingegebener Werte — wird auf [`app/README.md` § 1](app/README.md) verwiesen.
-## 3. Modellmechanik
+(4) **Verbleib der Daten.** Die eingegebenen Werte werden ausschließlich im Browser der
+nutzenden Person vorgehalten (`localStorage`, Schlüssel `altersvorsorge.v1`). Eine Übermittlung
+an einen Server, eine Erhebung von Nutzungsdaten zu Auswertungszwecken sowie ein Nachladen von
+Schriftarten oder Skripten von fremden Domänen finden nicht statt und sind auch nicht
+vorgesehen.
-### Ansparphase (jahresweise)
+---
-- Gehalt, BBG, Bezugsgröße, Durchschnittsentgelt und Rentenwert wachsen mit `C13`
-- Steuertarif: `ESt = s · λ · T(zvE / s / λ)` mit s = Splittingfaktor, λ = Tarifindex.
- Das ist exakt äquivalent zu einer proportionalen Verschiebung aller Eckwerte;
- λ = 1 zeigt volle kalte Progression
-- zvE-Näherung: Brutto − AN-Pauschbetrag − SA-Pauschbetrag − abziehbare Vorsorgeaufwendungen
- (RV voll, KV zu 96 %, PV voll). Genauigkeit ca. 1 %
-- Beiträge unterjährig: Verzinsung mit (1+r)^0,5 im Einzahlungsjahr
+## § 3 Verzeichnis der Bestandteile
-### Arbeitgeberzuschuss: zwei additive Komponenten
+| Datei bzw. Ordner | Zweckbestimmung |
+|---|---|
+| `app/index.html` | **Die vollständige Anwendung.** Rechenkern, Bedienoberfläche und Diagramme in einer einzigen Datei, gegliedert in nummerierte Teile 0 bis 14 |
+| `app/i18n.*.js` | Wörterbücher, je Sprachfassung eines. Deutsch ist Hauptsprache und Rückfallebene |
+| `app/manifest.json` | Angaben zur Installierbarkeit (Bezeichnung, Farben, Symbole) |
+| `app/service-worker.js` | Zwischenspeicherung für den Offline-Betrieb |
+| `app/pruefe.js` | Entwicklungswerkzeug zur Sprachprüfung; wird nicht ausgeliefert |
+| `app/akk-keilschrift*.js` | Erzeugung der Keilschriftfassung aus der Umschrift |
+| [`app/README.md`](app/README.md) | **Technische Dokumentation.** Aufbau, Modellmechanik im Einzelnen, Prüfung, Gestaltungsentscheidungen |
-Seit der Erweiterung zerfällt der Zuschuss in `agz = agz_var + agz_fx`:
+---
-| Komponente | Zelle | Rechtsgrund | Verhalten |
-|---|---|---|---|
-| `agz_var` — prozentual | `C26`, Modus `C30` | § 1a Abs. 1a BetrAVG bzw. Versorgungsordnung | proportional zum Beitrag, im Modus 2 auf die tatsächliche AG-Ersparnis gedeckelt |
-| `agz_fx` — Festbetrag | `C27`, `C28`, `C29` | Tarifvertrag / Betriebsvereinbarung (z. B. Deutsche Bahn) | betragsunabhängig, vom Zuschussmodus unberührt, oben drauf |
+## § 4 Das Vergleichsprinzip
-Der Festbetrag ist **arbeitgeberfinanzierte Zuwendung nach § 3 Nr. 63 EStG** und belegt
-deshalb den 8-%-Topf des § 3 Nr. 63 EStG *und* die 4-%-Beitragsfreiheit des
-§ 1 Abs. 1 S. 1 Nr. 9 SvEV **vorrangig** (Vertrauen ~80 %):
+(1) Ein Vergleich anhand der Bruttobeiträge wäre unsachgemäß: die Entgeltumwandlung wird aus
+dem Bruttoentgelt geleistet, das private Sparen hingegen aus dem versteuerten Entgelt.
+Gleichgesetzt wird daher der **Nettoaufwand**, mithin der Betrag, um welchen sich das
+verfügbare Einkommen tatsächlich mindert:
```
-agz_fx = aktiv · [beitrag_mtl ≥ agz_fix_min] · 12 · agz_fix · (dyn ? Lohnindex : 1)
-bav_svf = min(bav_br, max(0, 4 % · BBG_RV − agz_fx)) ← Verdrängung
-agz_var = f(bav_svf, sverp_ag, Modus)
-bav_stf = min(bav_br, max(0, 8 % · BBG_RV − agz_fx − agz_var))
+Nettoaufwand = Bruttobeitrag − Lohnsteuerersparnis − ersparter Arbeitnehmeranteil zur Sozialversicherung
```
-Die Reihenfolge ist zyklenfrei: `agz_fx` hängt nur am Beitrag, nicht an `sverp_ag`.
-Ökonomisch ist der Festbetrag ein **Sockel, kein Hebel** — er hebt den Durchschnittsertrag
-stark, die Grenzrendite des nächsten Beitragseuros senkt er sogar leicht
-(∂²Ertrag/∂agz_fix ∂beitrag ≤ 0), weil er dem Eigenbeitrag Freibetrag wegnimmt.
+(2) Ebendieser Betrag wird in sämtlichen drei Gestaltungsvarianten angelegt. Was verbleibt, ist
+mithin ein Vergleich der Förderarchitekturen und nicht ein Vergleich der Einzahlungshöhen.
-Die Mindestschwelle `agz_fix_min` macht N(B) **unstetig**: an der Schwelle springt der
-Nettoaufwand nach oben (Basisfall, 150 €/Monat fest ab 300 €/Monat Eigenbeitrag:
-164,54 € → 173,08 €). Monoton bleibt N, die Bisektion konvergiert also weiter, aber
-Zielwerte im Sprungintervall sind schlicht nicht erreichbar — `resid` zeigt das an.
+(3) Brutto- und Nettobetrag sind in der Anwendung wechselseitig gekoppelt; eine Vorgabe ist in
+beiden Richtungen zulässig. Da die Funktion N(B) wegen der Knickstellen bei 4 bzw. 8 vom
+Hundert der Beitragsbemessungsgrenze der Rentenversicherung, an den Beitragsbemessungsgrenzen
+sowie an den Tarifeckwerten nicht geschlossen umkehrbar, jedoch stetig und streng monoton
+wachsend ist, wird die Umkehrung durch ein Verfahren mit 34 Intervallhalbierungen bewirkt.
-**Nicht modelliert:** Übersteigt `agz_fx` allein 4 % der BBG-RV, wäre der Überhang beim
-Arbeitnehmer beitragspflichtiges Arbeitsentgelt. Diese Beitragslast wird nicht gegen-
-gerechnet; das Blatt `Kennzahlen` und die Diagnosetabelle der Web-App weisen den Überhang
-separat aus. Bei 2026er Werten greift das ab 338 €/Monat Festzuschuss.
+### Die vier Werttreiber
-### Schichtenmodell
+Der Steueraufschub ist für sich genommen ohne Wert, da (1−t)·(1+r)ⁿ = (1+r)ⁿ·(1−t) gilt; die
+Multiplikation ist kommutativ. Es verbleiben mithin ausschließlich:
-Beide geförderten Produkte werden in **zwei Schichten** geführt, weil sonst derselbe Euro
-zweimal besteuert würde:
+1. **Tarifarbitrage** t₀ − t₁ — Grenzsteuersatz im Zeitpunkt der Einzahlung abzüglich desjenigen
+ im Zeitpunkt der Auszahlung;
+2. **Fremdmittel** — Zuschuss des Arbeitgebers bzw. Zulagen;
+3. **Steuerfreie Thesaurierung** — betriebliche Altersversorgung und Altersvorsorgedepot kennen
+ die Vorabpauschale nicht;
+4. **Neu hinzutretende Abgaben, welche lediglich eine Variante betreffen** — Beiträge zur
+ Kranken- und Pflegeversicherung auf Versorgungsbezüge (§ 229 SGB V).
-| | gefördert | nicht gefördert |
-|---|---|---|
-| **bAV** | bis 8 % BBG-RV (§ 3 Nr. 63 EStG) → 100 % nachgelagert steuerpflichtig | Rest, aus versteuertem Entgelt → halber Unterschiedsbetrag (Kapital) bzw. Ertragsanteil (Rente) |
-| **AV-Depot** | Eigenbeitrag bis 1.800 € + Zulagen → 100 % nachgelagert | Beiträge darüber + reinvestierte Erstattung → halber Unterschiedsbetrag (Plan bzw. Einmalbetrag) oder Ertragsanteil (Rente) |
-
-Der Überschuss über den Jahreshöchstbetrag von 6.840 € läuft in eine eigene Schiene
-(„Sleeve"), die wie das Privatdepot besteuert wird — so bleibt der Nettoaufwand identisch.
-
-### Auszahlungsphase
-
-- **Auszahlungsform je Produkt getrennt**: `auszform` für die bAV (Kapital oder Rente),
- `av_auszform` für das Depot (Auszahlungsplan oder Rente), dazu `teilkap` für den Einmalbetrag
- von bis zu 30 % beim Depot, der in beiden Formen wirkt. Bei Verrentung geht das Restkapital an
- den Anbieter, ein Depotkonto gibt es danach nicht mehr
-- **KV/PV nur bei der bAV**: voller Satz allein vom Rentner (§ 250 SGB V), Freibetrag
- 1/20 Bezugsgröße für KV, Freigrenze für PV, Kapitalleistung auf 120 Monate verteilt,
- gemeinsame BBG mit der gesetzlichen Rente (§ 223 Abs. 3 SGB V)
-- **Verlust an Entgeltpunkten** wird der bAV netto gegengerechnet
-- Alle Kennzahlen auf **Äquivalenzbasis**: jeder Zahlungsstrom wird mit dem
- Wiederanlagezins nach Steuern auf den Rentenbeginn bezogen und dann als konstante
- Monatszahlung über denselben Zeitraum ausgedrückt. Weil Annuitisierung linear ist,
- addieren sich die Komponenten exakt (geprüft auf 10⁻¹²)
+Nummer 4 stellt den beherrschenden Nachteil der betrieblichen Altersversorgung dar; Nummer 2
+ist deren einziger struktureller Vorteil.
---
-## 4. Neu bauen
-
-```bash
-python3 build_bav.py
-python3 <skills>/xlsx/scripts/recalc.py bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx 32
-```
-
-`recalc.py` schreibt die von openpyxl erzeugten Formeln mit LibreOffice durch und legt die
-Werte im Cache ab — vorher liest jedes Werkzeug `None`.
-
-### Vier Fallstricke, die Zeit gekostet haben
-
-1. **`IRR()` ohne Startwert lässt LibreOffice hängen.** Immer `IRR(bereich; 0,05)` schreiben.
-2. **Recalc auf dem gemounteten Ordner hängt.** Nach `/tmp` kopieren, dort rechnen,
- zurückkopieren.
-3. **Notiztexte dürfen nicht mit `=` beginnen** — openpyxl schreibt sie sonst als Formel.
-4. **Hilfszellen kollidieren mit Datenspalten.** Die Auszahlung reicht inzwischen bis Spalte
- **BF** (58 Spalten), die Hilfszellen liegen bei CE/CG **unterhalb** von Zeile 8. Das
- funktioniert, ist aber fragil: beim Hinzufügen von Spalten jedes Mal nachrechnen. Die
- Erweiterung um die Depotverrentung hat drei Spalten gekostet.
+## § 5 Leistungsumfang
+
+- **Sensitivitätskurve** über denjenigen Regler, welcher zuletzt betätigt worden ist: 41
+ vollständige Modellläufe nebst Kennzeichnung der Schnittpunkte gegenüber dem privaten Depot.
+ Gewinnschwellen sind hierdurch ablesbar und müssen nicht errechnet werden.
+- **Wasserfalldarstellung der Werttreiber**, teleskopierend zerlegt und mithin exakt aufgehend.
+ Auf die Reihenfolgeabhängigkeit wird in der Anwendung ausdrücklich hingewiesen.
+- **Kapital- und Liquiditätsverlauf** über die gesamte Zeitachse, einschließlich der
+ Kennzeichnung des gebundenen gegenüber dem frei verfügbaren Kapital.
+- **Warnhinweis bei uneinheitlicher Rangfolge.** Barwert und äquivalente Monatsleistung ranken
+ unterschiedlich, sobald der Wiederanlagezins nach Steuern die Inflationsrate deutlich
+ übersteigt; hierauf wird hingewiesen.
+- **Sämtliche 45 Rechengrößen sind änderbar**, jeweils unter Angabe der Fundstelle. Wer eine
+ Modellannahme nicht teilt, hat sie zu ändern; ein Eingriff in den Quelltext ist hierfür nicht
+ erforderlich.
+- **Klartextfazit** in einem Satz nebst Belastbarkeitstest über ±1 Prozentpunkt Bruttorendite.
+ Die Formulierung ist beschreibend und nicht empfehlend gehalten.
+- **Weitergabe des Berechnungsstandes** als Verweis; die Werte werden im Fragmentbezeichner
+ geführt und mithin nicht an einen Server übermittelt (RFC 3986 § 3.5).
+- **23 Sprachfassungen**, darunter zwei Registervarianten des Deutschen (`de-x-amt` und
+ `de-x-sales`), welche denselben § 1a BetrAVG einmal als Verwaltungsschreiben und einmal als
+ Werbetext wiedergeben. Die Normzitate verbleiben in sämtlichen Sprachfassungen in deutscher
+ Sprache. Einzelheiten: [`app/README.md` § 3b](app/README.md).
+
+Hinsichtlich der Modellmechanik im Einzelnen — Schichtenmodell, Architektur des
+Arbeitgeberzuschusses, Auszahlungsphase, die beiden Zinssätze — wird auf
+[`app/README.md`](app/README.md) verwiesen; eine Wiedergabe an dieser Stelle unterbliebe nicht
+ohne die Gefahr des Auseinanderlaufens beider Darstellungen.
---
-## 5. Verifikation
-
-Vier Ebenen, alle bestanden:
+## § 6 Belastbarkeit der Rechtsannahmen
-1. **Recalc**: 0 Formelfehler
-2. **Strukturaudit**: alle blattinternen Hartbezüge gegen Ziel-Labels geprüft, keine toten
- Eingaben, alle Aggregatbereiche auf der korrekten Spannweite
-3. **Unabhängige Zweitimplementierung in Python**, aus der Spezifikation geschrieben, nicht
- aus den Excel-Formeln abgeleitet — 14 Aggregate, Abweichung **0,000000 %**
-4. **Zweiter Testfall**, der die im Basisfall unberührten Zweige aktiviert (Splitting,
- Kirchensteuer, Soli mit Milderungszone, Gehalt über BBG-RV, nicht geförderte Schicht,
- Sleeve) — Abweichung **0,00000000 %**
+Sämtliche nachstehend aufgeführten Annahmen sind in der Anwendung unter „Rechenweg →
+Belastbarkeit der Annahmen" einsehbar und änderbar.
-### Fehlerklassen, die der Recalc *nicht* findet
+| Annahme | Vertrauensgrad | Anmerkung |
+|---|---|---|
+| Rechengrößen der Sozialversicherung 2026, Tarif gemäß § 32a EStG 2026 | ~97 % | SVBezGrV 2026, Steuerfortentwicklungsgesetz |
+| Beitragspflicht in der Kranken- und Pflegeversicherung auf Versorgungsbezüge | ~95 % | §§ 229, 250 SGB V |
+| Freibetrag gemäß § 226 Abs. 2 S. 2 SGB V (KV), Freigrenze in der PV | ~95 % / ~85 % | Der die Pflegeversicherung betreffende Punkt stellt die häufigste Fehlerquelle in Ratgebertexten dar |
+| Beitragsfreiheit der Auszahlung aus dem Altersvorsorgedepot | ~85 % | Es handelt sich nicht um Versorgungsbezüge |
+| Halber Unterschiedsbetrag für nicht geförderte Schichten | ~80 % | § 22 Nr. 5 S. 2 Buchst. b i. V. m. § 20 Abs. 1 Nr. 6 S. 2 EStG |
+| Zuschuss lediglich bis zur Höhe der tatsächlichen Ersparnis des Arbeitgebers | ~75 % | Nach der Gegenauffassung sind die 15 vom Hundert als reine Pauschale zu verstehen |
+| Fester Arbeitgeberzuschuss belegt den 4-%- und den 8-%-Höchstbetrag vorrangig | ~80 % | Arbeitgeberfinanzierte Zuwendung im Sinne des § 3 Nr. 63 EStG; die eigene Entgeltumwandlung wird insoweit verdrängt |
+| **Sonderausgaben-Höchstbetrag 2.340 €** | **~70 %** | **Modellannahme.** Hiervon hängt ab, ob ein Kind den Wert des Altersvorsorgedepots hebt oder senkt |
+| Günstigerprüfung als Höchstwert, nicht als Summe | ~90 % | § 10a Abs. 2 EStG |
+| Unterstellt wird eine Pflichtversicherung in der KVdR im Ruhestand | ~70 % | Freiwillig Versicherte sind nicht geprüft worden |
+
+**Nicht abgebildet:** Abschläge bei vorzeitigem Rentenbezug; Auswirkungen der Entgeltumwandlung
+auf Kranken-, Arbeitslosen- und Elterngeld; Hinterbliebenenversorgung; Insolvenzsicherung
+(PSVaG); Portabilität bei einem Wechsel des Arbeitgebers; Kinderabschläge in der
+Pflegeversicherung; Günstigerprüfung gemäß § 32d Abs. 6 EStG; Pfändungs- und
+Grundsicherungsschutz. Ferner wird die Teilkapitalisierung der betrieblichen Altersversorgung
+nicht abgebildet; insoweit kennt das Modell ausschließlich die vollständige oder die
+unterbliebene Kapitalisierung.
-Beide in diesem Projekt tatsächlich aufgetreten:
+---
-- **Falsche Zeilenkonstanten** in handgeschriebenen Bezügen (`B26/B27` statt `B31/B32`).
- Fiel nur auf, weil die Größenordnung nicht stimmte — die Zahlenwerte lagen zufällig 1 %
- auseinander.
-- **Spaltenkollision**: eine neue Datenspalte landete auf einer Hilfszelle; deren Text
- wurde von SUMPRODUCT als 0 gewertet, wodurch ausgerechnet das erste Auszahlungsjahr
- entfiel. Fiel nur am Vorzeichen auf.
+## § 7 Ergebnisse des Regelfalls
-**Konsequenz für Weiterarbeit:** Nach jeder Änderung nicht nur den Recalc laufen lassen,
-sondern eine Größenordnung prüfen. Die Zweitimplementierung aus Abschnitt 5.3 ist das
-schärfste Werkzeug dafür.
+Zugrunde gelegt werden 40 Jahre Ansparphase, 75.000 € Jahresbruttoentgelt, 300 € Monatsbeitrag,
+gesetzliche Krankenversicherung, spitz berechneter Zuschuss von 15 vom Hundert sowie eine
+Bruttorendite von 7 vom Hundert:
----
-
-## 6. Rechtliche Annahmen und ihre Belastbarkeit
+| in heutiger Kaufkraft | bAV | AV-Depot | privat |
+|---|---|---|---|
+| Barwert des Nettoertrags | 27.737 € | 88.414 € | 73.740 € |
+| Äquivalente Monatsleistung | 587,67 € | 768,45 € | 689,48 € |
+| Interner Zinsfuß | 5,37 % | 6,61 % | 6,14 % |
-Alle im Blatt `Parameter` änderbar.
+Die betriebliche Altersversorgung obsiegt ausschließlich über zwei Hebel, welche beide
+außerhalb der Steuerarchitektur liegen:
+
+- **Private Krankenversicherung im Ruhestand** — bereits diese Einstellung allein bewirkt eine
+ Umkehr des Ergebnisses;
+- **Zuschuss ab etwa 30 vom Hundert** — die Gewinnschwelle folgt näherungsweise aus
+ (1+z)·(1−0,211) ≈ 1, mithin z ≈ 26,7 vom Hundert.
+
+> **Klarstellung.** Die vorstehenden Aussagen gelten für die *äquivalente Monatsleistung*, nicht
+> hingegen für den *Barwert des Nettoertrags*. Bei privater Krankenversicherung steigt die
+> betriebliche Altersversorgung auf 725,49 €/Monat gegenüber 689,48 € beim privaten Depot und
+> obsiegt mithin; im Barwert verbleibt sie mit 49.653 € gegenüber 73.740 € deutlich zurück. Die
+> Kennzahlen ranken deshalb unterschiedlich, weil der Barwert mit der Inflationsrate
+> (2,00 vom Hundert) abgezinst, die Monatsleistung hingegen mit dem Wiederanlagezins nach
+> Steuern (5,54 vom Hundert) verrentet wird; eine frühe Kapitalauszahlung wird hierdurch
+> systematisch günstiger bewertet. Welche Kennzahl maßgeblich ist, hängt davon ab, ob das
+> Kapital angelegt oder verbraucht wird.
+>
+> Die Gewinnschwelle von 26,7 vom Hundert ist überdies im spitz berechneten Zuschussmodus
+> **nicht erreichbar**: dort begrenzt § 1a Abs. 1a BetrAVG den Zuschuss auf die tatsächliche
+> Ersparnis des Arbeitgebers an Sozialversicherungsbeiträgen, im Regelfall rund 21 vom Hundert
+> des umgewandelten Betrags. Eine weitere Erhöhung des Reglers bleibt sodann wirkungslos.
-| Annahme | Vertrauen | Anmerkung |
-|---|---|---|
-| Rechengrößen SV 2026, § 32a-Tarif 2026 | ~97 % | SVBezGrV 2026, Steuerfortentwicklungsgesetz |
-| KV/PV-Pflicht auf Versorgungsbezüge | ~95 % | §§ 229, 250 SGB V |
-| Freibetrag § 226 Abs. 2 S. 2 SGB V (KV), Freigrenze in der PV | ~95 % / ~85 % | Der PV-Punkt ist die häufigste Fehlerquelle in Ratgebertexten |
-| Beitragsfreiheit der Altersvorsorgedepot-Auszahlung | ~85 % | Keine Versorgungsbezüge |
-| Halber Unterschiedsbetrag für nicht geförderte Schichten | ~80 % | § 22 Nr. 5 S. 2 Buchst. b i.V.m. § 20 Abs. 1 Nr. 6 S. 2 EStG |
-| Zuschuss nur bis zur tatsächlichen AG-Ersparnis (Modus 2) | ~75 % | Gegenauffassung liest 15 % als reine Pauschale = Modus 1 |
-| Fester AG-Zuschuss belegt 4-%- und 8-%-Topf vorrangig | ~80 % | Arbeitgeberfinanzierte Zuwendung nach § 3 Nr. 63 EStG; verdrängt eigene Umwandlung |
-| **Sonderausgaben-Höchstbetrag 2.340 €** | **~70 %** | **Modellannahme.** Bestimmt, ob ein Kind den Wert des AV-Depots hebt oder senkt |
-| Günstigerprüfung als Maximum, nicht Summe | ~90 % | § 10a Abs. 2 EStG |
-| Modell unterstellt KVdR-Pflichtversicherung im Ruhestand | ~70 % | Freiwillig Versicherte nicht geprüft |
-
-**Nicht modelliert:** Abschläge bei vorzeitigem Rentenbezug, Wirkung der Entgeltumwandlung
-auf Kranken-, Arbeitslosen- und Elterngeld, Hinterbliebenenversorgung, Insolvenzsicherung
-(PSVaG), Portabilität bei Arbeitgeberwechsel, Kinderabschläge in der PV, Günstigerprüfung
-nach § 32d Abs. 6 EStG, Pfändungs- und Grundsicherungsschutz.
+Die Rendite der betrieblichen Altersversorgung **fällt streng monoton** mit der Beitragshöhe,
+da der Freibetrag ein absoluter ist und seine Schutzwirkung mit 1/K abnimmt. Ein inneres Optimum
+besteht mithin nicht. Der einzige beitragsfreie Bereich (Kapital ≤ 120 × Freibetrag ≈ 46.000 €,
+entsprechend rund 42 €/Monat) ist zu gering bemessen, um als Vorsorgestrategie in Betracht zu
+kommen; er hängt überdies vollständig an einer politisch gesetzten Zahl.
---
-## 7. Wichtigste Befunde des Basisfalls
+## § 8 Prüfung
-40 Jahre, 75.000 € Brutto, 300 €/Monat, GKV, Zuschuss 15 % spitz, 7 % Bruttorendite:
+(1) Der Rechenkern ist gegen ein unabhängig geführtes Zweitmodell auf Maschinengenauigkeit
+abgeglichen worden: sechs unabhängige Testfälle zu je rund 20 Aggregaten, größte festgestellte
+relative Abweichung 1,3·10⁻¹⁴, nebst vier weiteren Fällen zum festen Arbeitgeberzuschuss, welche
+exakt übereinstimmen. Es handelt sich hierbei um wenige Dutzend Einheiten der letzten Stelle,
+mithin um akkumulierten Gleitkommafehler und nicht um eine systematische Abweichung.
-| in heutiger Kaufkraft | bAV | AV-Depot | privat |
-|---|---|---|---|
-| Barwert Netto-Ertrag | 27.737 € | 88.414 € | 73.740 € |
-| Äquivalente Monatsleistung | 587,67 € | 768,45 € | 689,48 € |
-| Interner Zinsfuß | 5,37 % | 6,61 % | 6,14 % |
+(2) Ferner bestehen ein Stilblatt-Test, ein Test der Bedienoberfläche mit 57 Zusicherungen sowie
+ein zweistufiger Test der Diagramme mit insgesamt 520 Kombinationen. Die Sprachprüfung
+`app/pruefe.js` schaltet sämtliche 23 Sprachfassungen durch und weist unter anderem nach, dass
+die Rechenergebnisse in allen Sprachfassungen identisch sind; sie umfasst 154 Prüfungen und
+setzt `jsdom` voraus.
-Die bAV gewinnt nur über zwei Hebel, beide außerhalb der Steuerarchitektur:
+(3) Einzelheiten nebst der Fehlerklassen, welche die vorgenannten Prüfungen nachweislich
+*nicht* auffinden, sind [`app/README.md` § 4](app/README.md) zu entnehmen.
-- **PKV im Ruhestand** (`C39` = 2) — allein das dreht das Ergebnis
-- **Zuschuss ≳ 30 %** — Break-even folgt näherungsweise aus (1+z)·(1−0,211) ≈ 1 ⟹ z ≈ 26,7 %
+---
-> **Präzisierung, beim Portieren aufgefallen.** Beide Aussagen gelten für die *äquivalente
-> Monatsleistung*, nicht für den *Barwert des Netto-Ertrags*. Mit PKV steigt die bAV auf
-> 725,49 €/Monat gegen 689,48 € beim Privatdepot — gewinnt also. Im Barwert bleibt sie mit
-> 49.653 € gegen 73.740 € klar hinten. Die Kennzahlen ranken unterschiedlich, weil der Barwert
-> mit der Inflation (2,00 %) abzinst, die Monatsleistung aber mit dem Wiederanlagezins nach
-> Steuern (5,54 %) verrentet: eine frühe Kapitalauszahlung wird dadurch systematisch besser
-> bewertet. Welche Zahl gilt, hängt daran, ob das Kapital angelegt oder verkonsumiert wird.
->
-> Der Break-even von 26,7 % ist außerdem **im Zuschussmodus 2 („spitz“) unerreichbar**: dort
-> deckelt § 1a Abs. 1a BetrAVG den Zuschuss auf die tatsächliche SV-Ersparnis des Arbeitgebers,
-> im Basisfall rund 21 % des umgewandelten Betrags. Ab da ändert der Zuschussregler nichts mehr.
-> In Modus 0 liegt der Break-even (Monatsleistung) bei knapp über 30 %.
+## § 9 Herkunft
-Die Rendite der bAV **fällt streng monoton** in der Beitragshöhe, weil der Freibetrag
-absolut ist und seine Schutzwirkung wie 1/K abnimmt. Es gibt kein inneres Optimum.
-Der einzige beitragsfreie Bereich (Kapital ≤ 120 × Freibetrag ≈ 46.000 €, entspricht
-~42 €/Monat) ist zu klein, um als Vorsorgestrategie zu taugen — und hängt vollständig
-an einer politisch gesetzten Zahl.
+Die vorliegende Anwendung ist aus einer vollständig formelbasierten Excel-Arbeitsmappe (6.359
+Formeln) hervorgegangen, welche ihrerseits durch ein Python-Skript erzeugt worden ist. Beide
+Bestandteile sind zwischenzeitlich entfallen, da die Webanwendung an ihre Stelle getreten ist;
+sie sind ausschließlich über die Versionsgeschichte zugänglich. Der Rechenkern in Teil 1 von
+`app/index.html` ist zeichengenau aus dem ursprünglichen Formelgenerator übertragen worden und
+stellt nunmehr **die einzige Stelle dar, an der gerechnet wird.**
---
-## 8. Offene Punkte
-
-- [ ] Anwendungsschreiben zur pAV-Reform abwarten → Sonderausgaben-Höchstbetrag und
- Besteuerung der nicht geförderten Schicht bestätigen
-- [ ] Tatsächliche DYNO-Vertragsdaten einsetzen: Durchführungsweg, Effektivkosten aus dem
- Produktinformationsblatt, zugesagter Zuschuss laut Versorgungsordnung
-- [ ] Klären, ob der Zuschuss auch oberhalb der Beitragsbemessungsgrenzen gezahlt wird
- (entscheidet 116 Basispunkte)
-- [ ] Prüfen, ob bereits andere Versorgungsbezüge bestehen — der Freibetrag gilt pro
- Person, nicht pro Vertrag
-- [x] ~~Verrentung des Altersvorsorgedepots~~ — eingebaut: eigene Eingabe `av_auszform`,
- unabhängig von der bAV-Auszahlungsform, mit eigenem Rentenfaktor und eigener Dynamik.
- Nicht geförderte Schicht dann mit dem Ertragsanteil statt dem halben Unterschiedsbetrag,
- zweite Memo-Zeile für Zahlungen nach dem Vergleichshorizont.
-- [ ] Teilkapitalisierung der **bAV** (0–30 % einmalig, Rest verrentet). Beim Depot ist das seit
- der Erweiterung möglich, bei der bAV noch nicht — das Modell kennt dort nur ganz oder gar
- nicht. Die einzige verbliebene Asymmetrie zwischen den beiden geförderten Produkten.
-- [ ] Optional: jahresweise Inversion des Nettoaufwands statt nur im ersten Jahr
-- [ ] Optional: Sensitivitätstabelle über Rendite × Option (Excel-Datentabellen werden von
- openpyxl nicht geschrieben; Alternative wäre eine vorgerechnete Matrix)
+## § 10 Offene Punkte
+
+- [ ] Das Anwendungsschreiben zur Reform der geförderten privaten Altersvorsorge ist abzuwarten;
+ sodann sind der Sonderausgaben-Höchstbetrag sowie die Besteuerung der nicht geförderten
+ Schicht zu bestätigen.
+- [ ] Es ist zu klären, ob der Zuschuss auch oberhalb der Beitragsbemessungsgrenzen geleistet
+ wird; hiervon hängen 116 Basispunkte ab.
+- [ ] Es ist zu prüfen, ob bereits weitere Versorgungsbezüge bestehen; der Freibetrag gilt je
+ Person und nicht je Vertrag.
+- [ ] Die Teilkapitalisierung der **betrieblichen Altersversorgung** (0 bis 30 vom Hundert
+ einmalig, im Übrigen verrentet) ist noch abzubilden. Beim Altersvorsorgedepot ist dies
+ bereits möglich; es handelt sich um die einzig verbliebene Asymmetrie zwischen den beiden
+ geförderten Produkten.
+- [ ] Fakultativ: jahresweise Umkehrung des Nettoaufwands anstelle der Umkehrung allein im
+ ersten Jahr.
+- [x] ~~Verrentung des Altersvorsorgedepots~~ — eingerichtet: eigene Eingabe `av_auszform`,
+ unabhängig von der Auszahlungsform der betrieblichen Altersversorgung, mit eigenem
+ Rentenfaktor und eigener Dynamik.
---
-## 9. Quellen
+## § 11 Quellen
- [SVBezGrV 2026](https://www.gesetze-im-internet.de/svbezgrv_2026/BJNR1160A0025.html)
- [§ 32a EStG](https://www.gesetze-im-internet.de/estg/__32a.html)
-- [BMF, FAQ Reform der geförderten privaten Altersvorsorge (05.05.2026)](https://www.bundesfinanzministerium.de/Content/DE/FAQ/reform-der-privaten-altersvorsorge.html)
+- [BMF, FAQ zur Reform der geförderten privaten Altersvorsorge (05.05.2026)](https://www.bundesfinanzministerium.de/Content/DE/FAQ/reform-der-privaten-altersvorsorge.html)
- [Bundesregierung, Private Altersvorsorge wird attraktiver (01.06.2026)](https://www.bundesregierung.de/breg-de/aktuelles/reform-private-altersvorsorge-2400072)
-- [BMF-Schreiben 13.01.2026, Basiszins Vorabpauschale § 18 Abs. 4 InvStG](https://www.bundesfinanzministerium.de/Content/DE/Downloads/BMF_Schreiben/Steuerarten/Investmentsteuer/2026-01-13-basiszins-berechnung-vorabpauschale.html)
+- [BMF-Schreiben vom 13.01.2026, Basiszins zur Vorabpauschale gemäß § 18 Abs. 4 InvStG](https://www.bundesfinanzministerium.de/Content/DE/Downloads/BMF_Schreiben/Steuerarten/Investmentsteuer/2026-01-13-basiszins-berechnung-vorabpauschale.html)
- [GKV-Spitzenverband, Rechengrößen 2026](https://www.gkv-spitzenverband.de/media/dokumente/presse/zahlen_und_grafiken/20260101_Faktenblatt_Rechengroessen_Beitragsrecht.pdf)
-- [DYNO](https://heydyno.de)
---
-*Keine Steuer- oder Anlageberatung. Das Modell ersetzt keine Prüfung des konkreten Vertrags.*
+*Es wird abschließend darauf hingewiesen, dass mit der vorliegenden Anwendung weder eine
+Steuer- noch eine Anlageberatung erbracht wird. Ein Modell ist kein Vertrag; die Prüfung des
+jeweils konkreten Vertragswerks wird hierdurch nicht ersetzt.*
diff --git a/app/README.md b/app/README.md
index 522018c..fab1593 100644
--- a/app/README.md
+++ b/app/README.md
@@ -1,244 +1,265 @@
-# Altersvorsorge-Vergleich — Web-App
+# Altersvorsorge-Vergleich — Webanwendung
-Progressive Web-App zum Excel-Modell im übergeordneten Ordner. Derselbe Rechenkern, dieselben
-Ergebnisse, aber bedienbar von Menschen, die keine Tabellenkalkulation aufmachen wollen.
+Progressive Webanwendung (PWA) zum Vergleich dreier Gestaltungsvarianten der Altersvorsorge.
+Es handelt sich um das eigentliche Erzeugnis dieses Bestandes; hinsichtlich einer allgemeinen
+Einführung wird auf das [Wurzel-README](../README.md) verwiesen. Der Rechenkern ist aus einer
+zwischenzeitlich entfallenen Excel-Arbeitsmappe übernommen worden, welche ausschließlich über
+die Versionsgeschichte zugänglich ist; die Ergebnisse sind dieselben, die Bedienung ist jedoch
+auch denjenigen Personen eröffnet, welche eine Tabellenkalkulation nicht zu öffnen beabsichtigen.
-| Datei | Rolle |
+| Datei | Zweckbestimmung |
|---|---|
-| `index.html` | **Die ganze App.** Rechenkern, Oberfläche, Diagramme — eine Datei, keine externen Abhängigkeiten außer den Wörterbüchern. Läuft per Doppelklick. |
+| `index.html` | **Die vollständige Anwendung.** Rechenkern, Bedienoberfläche und Diagramme in einer einzigen Datei, ohne externe Abhängigkeiten mit Ausnahme der Wörterbücher. Der Aufruf erfolgt mittels Doppelklicks. |
| `i18n.de.js` | Wörterbuch Deutsch. Hauptsprache und Rückfallebene. **Vollständig.** |
| `i18n.en.js` `i18n.nl.js` `i18n.fr.js` `i18n.la.js` `i18n.ja.js` | Englisch, Niederländisch, Französisch, Latein, Japanisch. **Vollständig** (459 Schlüssel). |
-| `i18n.nds.js` `i18n.bar.js` `i18n.eu.js` `i18n.eo.js` `i18n.tr.js` `i18n.uk.js` | Niederdeutsch, Bairisch, Baskisch, Esperanto, Türkisch, Ukrainisch. **Teilweise** (315 Schlüssel, siehe 3b). |
-| `i18n.got.js` `i18n.goh.js` `i18n.gmh.js` `i18n.grc.js` `i18n.sa.js` | Gotisch, Althochdeutsch, Mittelhochdeutsch, Altgriechisch, Sanskrit. **Teilweise**. |
-| `i18n.ine-x-proto.js` | Urindogermanisch, LIV²/Rix-Notation mit Laryngalen und Asterisk. Kein ISO-639-3-Code möglich (639-3 vergibt keine Codes an Rekonstruate), daher BCP-47-Privatuntertag `ine-x-proto`. **Vollständig**. |
-| `i18n.jbo.js` `i18n.tok.js` | Lojban, Toki Pona. Toki Pona speichert sitelen Lasina (ASCII); das Stilblatt setzt für `lang="tok"` ligaturfähige sitelen-pona-Zeichensätze, die die ASCII-Wörter zu Logographen binden — ohne installierten Zeichensatz bleibt lesbares Latein statt PUA-Kästchen. **Vollständig**. |
-| `i18n.akk-x-ob.js` | Altbabylonisch in Keilschrift (U+12000…). Erzeugt aus `i18n.akk-x-ob.translit.js` durch `node akk-keilschrift.js`; die Umschrift ist die Quelle, die Keilschrift das Erzeugnis. Codepunkte werden zur Bauzeit über die Unicode-Namenstabelle aufgelöst statt von Hand gesetzt. **Vollständig**. |
-| `manifest.json` | Macht die App installierbar (Name, Farben, Symbole). |
-| `service-worker.js` | Offline-Cache, `stale-while-revalidate`. |
-| `icon-*.png` | App-Symbole, 192 / 512 / 512-maskable. |
+| `i18n.nds.js` `i18n.bar.js` `i18n.eu.js` `i18n.eo.js` `i18n.tr.js` `i18n.uk.js` | Niederdeutsch, Bairisch, Baskisch, Esperanto, Türkisch, Ukrainisch. **Vollständig** (siehe § 3b). |
+| `i18n.got.js` `i18n.goh.js` `i18n.gmh.js` `i18n.grc.js` `i18n.sa.js` | Gotisch, Althochdeutsch, Mittelhochdeutsch, Altgriechisch, Sanskrit. **Vollständig.** |
+| `i18n.ine-x-proto.js` | Urindogermanisch in LIV²/Rix-Notation nebst Laryngalen und Asterisk. Ein Code nach ISO 639-3 ist nicht zu erlangen, da für Rekonstruate keine Codes vergeben werden; es wird daher der Privatuntertag `ine-x-proto` nach BCP 47 geführt. **Vollständig.** |
+| `i18n.jbo.js` `i18n.tok.js` | Lojban, Toki Pona. Toki Pona wird in sitelen Lasina (ASCII) vorgehalten; das Stilblatt setzt für `lang="tok"` ligaturfähige sitelen-pona-Zeichensätze, welche die ASCII-Wörter zu Logographen binden. Ist ein solcher Zeichensatz nicht installiert, verbleibt lesbares Latein anstelle leerer Kästchen. **Vollständig.** |
+| `i18n.akk-x-ob.js` | Altbabylonisch in Keilschrift (U+12000 ff.). Erzeugt aus `i18n.akk-x-ob.translit.js` mittels `node akk-keilschrift.js`; die Umschrift ist die Quelle, die Keilschrift das Erzeugnis. Die Codepunkte werden zur Bauzeit über die Unicode-Namenstabelle aufgelöst und nicht von Hand gesetzt. **Vollständig.** |
+| `manifest.json` | Bewirkt die Installierbarkeit (Bezeichnung, Farben, Symbole). |
+| `service-worker.js` | Offline-Zwischenspeicher, Verfahren `stale-while-revalidate`. |
+| `icon-*.png` | Symbole der Anwendung, 192 / 512 / 512-maskable. |
---
-## 1. Weitergeben — drei Wege
+## § 1 Weitergabe — drei Wege
-**a) Nur die Dateien.** `index.html` samt allen dreiundzwanzig `i18n.*.js` verschicken — sie gehören
-zusammen und müssen im selben Ordner liegen. Doppelklick genügt,
-alles rechnet, Eingaben werden im Browser gespeichert. Was fehlt, ist nur die PWA-Hülle —
-kein Symbol auf dem Startbildschirm, kein Offline-Cache. Beides braucht es hier auch nicht,
-die Datei liegt ja schon auf dem Gerät. Die App sagt das dem Nutzer auch selbst.
+**a) Ausschließlich die Dateien.** Es sind `index.html` nebst sämtlichen dreiundzwanzig
+`i18n.*.js` zu übersenden; sie gehören zusammen und haben in demselben Ordner zu liegen. Ein
+Doppelklick genügt, sämtliche Berechnungen werden durchgeführt, und die Eingaben werden im
+Browser vorgehalten. Es fehlt lediglich die PWA-Hülle — mithin das Symbol auf dem
+Startbildschirm sowie der Offline-Zwischenspeicher. Beides ist hier entbehrlich, da die Datei
+bereits auf dem Gerät vorliegt. Die Anwendung weist hierauf von sich aus hin.
-**b) Der ganze Ordner auf einem Webspace.** Irgendein HTTPS-Hosting genügt (GitHub Pages,
-Netlify, ein Unterverzeichnis auf der eigenen Domain). Dann ist sie installierbar und
-offlinefähig. Es gibt kein Backend, keine Datenbank, keine Build-Kette.
+**b) Der vollständige Ordner auf einem Webspeicherplatz.** Ein beliebiges HTTPS-Hosting genügt
+(GitHub Pages, Netlify, ein Unterverzeichnis der eigenen Domäne). Sodann ist die Anwendung
+installierbar und offlinefähig. Ein Hintergrundsystem, eine Datenbank sowie eine Baukette
+bestehen nicht.
```bash
-# lokal ausprobieren, mit Service Worker:
+# örtliche Erprobung einschließlich Dienstarbeiter:
cd app && python3 -m http.server 8000 # -> http://localhost:8000
```
-Service Worker laufen auch auf `http://localhost` — als „secure context“ ist localhost
-ausdrücklich ausgenommen.
+Dienstarbeiter (*service worker*) sind auch über `http://localhost` betriebsfähig; localhost ist
+als sicherer Kontext ausdrücklich ausgenommen.
-**c) Als Link.** Der Knopf *„Link mit meinen Zahlen kopieren“* kodiert den kompletten
-Eingabestand base64url in den Fragment-Bezeichner. Fragmente werden vom Browser **nicht** an
-den Server geschickt (RFC 3986 § 3.5) — der Link enthält also persönliche Zahlen, überträgt
-sie aber an niemanden außer den Empfänger.
+**c) Als Verweis.** Die Schaltfläche *„Link mit meinen Zahlen kopieren"* kodiert den
+vollständigen Eingabestand base64url in den Fragmentbezeichner. Fragmente werden vom Browser
+**nicht** an den Server übermittelt (RFC 3986 § 3.5); der Verweis enthält mithin persönliche
+Zahlen, überträgt diese jedoch an niemanden außer den Empfänger.
-## 2. Wo die Daten liegen
+## § 2 Verbleib der Daten
-Ausschließlich in `localStorage` unter dem Schlüssel `altersvorsorge.v1`, also im Browser des
-Nutzers. Kein Server, keine Analytik, keine Schriftarten von fremden Domains, keine externen
-Skripte. Die einzigen Netzwerkzugriffe der App sind die, die der Service Worker macht, um sich
-selbst zu aktualisieren.
+Ausschließlich in `localStorage` unter dem Schlüssel `altersvorsorge.v1`, mithin im Browser der
+nutzenden Person. Ein Server, eine Auswertung, Schriftarten von fremden Domänen sowie externe
+Skripte bestehen nicht. Die einzigen Netzwerkzugriffe der Anwendung sind diejenigen, welche der
+Dienstarbeiter zum Zwecke seiner eigenen Aktualisierung vornimmt.
-## 3. Aufbau der Datei
+## § 3 Aufbau der Datei
`index.html` ist in nummerierte Teile gegliedert:
| Teil | Inhalt |
|---|---|
| 0 | **Sprachen** — `t()`, Sprachwahl, Rückfall auf Deutsch |
-| 1 | **Rechenkern** — Portierung von `build_bav.py`. Reine Funktionen, kein DOM |
-| 2 | Felddefinitionen: 80 Eingaben mit Bereich, Einheit, Wörterbuchschlüssel |
-| 3 | Zustand, `localStorage`, Kodierung für den Teilen-Link |
+| 1 | **Rechenkern** — Portierung des ursprünglichen Formelgenerators. Reine Funktionen, kein DOM |
+| 2 | Felddefinitionen: 80 Eingaben nebst Bereich, Einheit und Wörterbuchschlüssel |
+| 3 | Zustand, `localStorage`, Kodierung für den Weitergabeverweis |
| 4 | Formatierung und Zahleneingabe, sprachabhängig |
| 5 | Kennzahlen |
-| 6 | Aufbau der Oberfläche |
-| 7 | Ergebniskarten mit Δ-Anzeige |
-| 7b | Klartext-Fazit, Beispielwert-Hinweis, mitlaufende Ergebnisleiste |
-| 8 | Diagramme, reines Canvas |
+| 6 | Aufbau der Bedienoberfläche |
+| 7 | Ergebniskarten nebst Δ-Anzeige |
+| 7b | Klartextfazit, Hinweis auf Beispielwerte, mitlaufende Ergebnisleiste |
+| 8 | Diagramme, ausschließlich Canvas |
| 9 | Rechenweg |
| 10 | Render-Schleife |
| 11 | Installation und Offline-Betrieb |
| 12 | Fensterrahmen: Titelleisten und Minimieren |
-| 13 | Kachelung: ein, zwei oder drei Fensterspalten |
-| 14 | Sprachumschaltung in der Oberfläche |
+| 13 | Kachelung: eine, zwei oder drei Fensterspalten |
+| 14 | Sprachumschaltung in der Bedienoberfläche |
Der Rechenkern in Teil 1 ist **die einzige Stelle, an der gerechnet wird.** Er ist zeichengenau
-aus `build_bav.py` übertragen; Änderungen an der Rechtslage gehören in beide Dateien.
+aus dem ursprünglichen Formelgenerator übertragen worden; Änderungen der Rechtslage sind mithin
+ausschließlich dort vorzunehmen.
-### Brutto und Netto sind gekoppelt
+### Brutto- und Nettobetrag sind gekoppelt
-Es gibt keinen Umschalter „ich gebe vor: Brutto / Netto“ mehr. Beide Felder zeigen dieselbe
-Größe, nur in verschiedener Währung:
+Ein Umschalter „Vorgabe: Brutto / Netto" besteht nicht mehr. Beide Felder weisen dieselbe Größe
+aus, lediglich in verschiedener Währung:
```
N(B) = B − SV-Ersparnis_AN(B) − Steuerersparnis(B)
```
`N` ist auf `[0, Bruttogehalt]` stetig und wegen `dN/dB = 1 − Grenz-SV-Satz − Grenzsteuersatz > 0`
-streng monoton wachsend, also eine Bijektion auf `[0, N(Bruttogehalt)]`. Ein Umschalter wäre
-eine Auswahl zwischen einer Funktion und ihrer Umkehrfunktion — also keine.
+streng monoton wachsend, mithin eine Bijektion auf `[0, N(Bruttogehalt)]`. Ein Umschalter wäre
+eine Auswahl zwischen einer Funktion und ihrer Umkehrfunktion, mithin keine Auswahl.
-`beitrag` bleibt die einzige Quelle der Wahrheit; `netto_ziel` ist ein **abgeleitetes Feld** mit
-`get` (Vorwärtsrechnung, Jahr 0 der Ansparphase) und `set` (Bisektion, `bruttoVonNetto`).
-Beide werten dasselbe erste Jahr aus — Lohn- und Tarifindex sind dort 1 —, weshalb die
-Richtungen exakt invers sind. Gemessen über 12 Parameterkombinationen × 5 Stützstellen:
+`beitrag` verbleibt die einzige maßgebliche Größe; `netto_ziel` ist ein **abgeleitetes Feld** mit
+`get` (Vorwärtsrechnung, Jahr 0 der Ansparphase) und `set` (Intervallhalbierung,
+`bruttoVonNetto`). Beide werten dasselbe erste Jahr aus — Lohn- und Tarifindex betragen dort 1 —,
+weshalb die Richtungen exakt invers sind. Gemessen über 12 Parameterkombinationen × 5
+Stützstellen:
| Richtung | größter relativer Fehler |
|---|---|
| B → N → B | 2,3 · 10⁻⁸ |
| N → B → N | 2,1 · 10⁻⁸ |
-Das ist genau die Auflösung der Bisektion: 34 Halbierungen auf `[0, 250.000 €]` sind
-1,5 · 10⁻⁵ €/Jahr, also gut ein Millionstel Cent im Monat. Die Monotonie ist zusätzlich auf
-`1 … 1.500 €/Monat` in Ein-Euro-Schritten geprüft; die kleinste beobachtete Steigung ist
-`dN/dB = 0,545`, d. h. Steuer und Sozialabgaben tragen zusammen nie mehr als 45,5 % des
-Bruttobeitrags.
+Dies entspricht genau der Auflösung des Halbierungsverfahrens: 34 Halbierungen auf
+`[0, 250.000 €]` ergeben 1,5 · 10⁻⁵ €/Jahr, mithin gut ein Millionstel Cent im Monat. Die
+Monotonie ist ergänzend auf `1 … 1.500 €/Monat` in Ein-Euro-Schritten geprüft worden; die
+geringste beobachtete Steigung beträgt `dN/dB = 0,545`, mithin tragen Steuer und Sozialabgaben
+zusammen niemals mehr als 45,5 vom Hundert des Bruttobeitrags.
-Fällt der Nettoaufwand für das erste Jahr auf null — weil man dann bereits ausgeschieden ist —,
-existiert die Umkehrung nicht. Die App sagt das statt still nichts zu tun.
+Fällt der Nettoaufwand für das erste Jahr auf null — weil zu diesem Zeitpunkt bereits ein
+Ausscheiden vorliegt —, so existiert die Umkehrung nicht. Die Anwendung weist hierauf hin,
+anstatt untätig zu verbleiben.
-## 3b. Neunzehn Sprachen
+## § 3b Dreiundzwanzig Sprachfassungen
-Deutsch ist die Hauptsprache; alle übrigen sind Übersetzungen derselben Rechtslage, kein
-zweiter Rechtsstand. **Die Normzitate bleiben in allen Sprachen deutsch**
-(`§ 1a BetrAVG`, `§ 226 Abs. 2 S. 2 SGB V`, …) — sie sind die Primärquellen und haben keine
-amtliche Übersetzung; eine eigene wäre hier keine Hilfe, sondern eine Fehlerquelle. Ebenso
-bleiben zwei Produktnamen stehen, weil sie Eigennamen sind: `Altersvorsorgedepot` und
-`Versorgungsbezüge`; im Japanischen mit Glosse (`Versorgungsbezüge(企業年金等の給付)`).
+Deutsch ist die Hauptsprache; sämtliche übrigen Fassungen sind Übersetzungen derselben
+Rechtslage und nicht etwa ein zweiter Rechtsstand. **Die Normzitate verbleiben in sämtlichen
+Sprachfassungen in deutscher Sprache** (`§ 1a BetrAVG`, `§ 226 Abs. 2 S. 2 SGB V`, …) — es
+handelt sich um die Primärquellen, für welche eine amtliche Übersetzung nicht vorliegt; eine
+eigene wäre insoweit keine Hilfe, sondern eine Fehlerquelle. Gleichermaßen verbleiben zwei
+Produktbezeichnungen unübersetzt, da es sich um Eigennamen handelt: `Altersvorsorgedepot` und
+`Versorgungsbezüge`; im Japanischen nebst Glosse
+(`Versorgungsbezüge(企業年金等の給付)`).
| | Sprachen | Schlüssel |
|---|---|---|
-| **vollständig** | `de` `de-x-amt` `de-x-sales` `en` `nl` `fr` `la` `ja` `nds` `bar` `eu` `eo` `tr` `uk` `got` `goh` `gmh` `grc` `sa` | 459 |
+| **vollständig** | `de` `de-x-amt` `de-x-sales` `en` `nl` `fr` `la` `ja` `nds` `bar` `eu` `eo` `tr` `uk` `got` `goh` `gmh` `grc` `sa` `ine-x-proto` `jbo` `tok` `akk-x-ob` | 459 |
| **teilweise** | — | — |
-Alle dreiundzwanzig Sprachen sind inzwischen vollständige Wörterbücher (459 von 459 Schlüsseln); die
-Tabellenzeile „teilweise“ bleibt stehen, weil `TEILWEISE` in `index.html` als Mechanismus
-weiterlebt — sie ist nur derzeit leer. Ursprünglich war die Auswahl strukturell, nicht nach
-Zeichenzahl: zuerst übersetzt wurde, was man anfasst oder als Überschrift liest —
-Feldbeschriftungen, Einheiten, Auswahlwerte, Fenstertitel, Kennzahlen, Tabellenköpfe,
-Diagrammlegenden, Meldungen; die langen juristischen Erläuterungen (die `?`-Texte an den
-Feldern, das Fazit, die Notizen unter den Feldern, der ganze Rechenweg) kamen erst in einer
-zweiten Fassung dazu. Für die drei historischen Sprachstufen und für Sanskrit und Altgriechisch
-ist der Vertrauensgrad in diesen Fließtext-Passagen entsprechend niedriger als in den
-Feldbeschriftungen selbst — siehe die Kopfkommentare der jeweiligen `i18n.*.js`-Datei für die
-genauen Prozentsätze und die dort neu geprägten Fachbegriffe.
+Sämtliche dreiundzwanzig Sprachfassungen sind zwischenzeitlich vollständige Wörterbücher (459 von
+459 Schlüsseln); die Tabellenzeile „teilweise" verbleibt, weil `TEILWEISE` in `index.html` als
+Mechanismus fortbesteht — sie ist lediglich derzeit unbesetzt. Ursprünglich erfolgte die Auswahl
+strukturell und nicht nach Zeichenzahl: zuerst übersetzt wurde dasjenige, was betätigt oder als
+Überschrift gelesen wird — Feldbeschriftungen, Einheiten, Auswahlwerte, Fenstertitel,
+Kennzahlen, Tabellenköpfe, Diagrammlegenden, Meldungen; die ausführlichen juristischen
+Erläuterungen (die `?`-Texte an den Feldern, das Fazit, die Notizen unter den Feldern, der
+gesamte Rechenweg) sind erst in einer zweiten Fassung hinzugetreten. Für die drei historischen
+Sprachstufen sowie für Sanskrit und Altgriechisch ist der Vertrauensgrad in diesen
+Fließtextpassagen entsprechend geringer als in den Feldbeschriftungen selbst; die genauen
+Prozentsätze sowie die dort neu geprägten Fachbegriffe sind den Kopfkommentaren der jeweiligen
+`i18n.*.js`-Datei zu entnehmen.
**Die drei alten germanischen Fassungen** (`got` Gotisch, `goh` Althochdeutsch,
-`gmh` Mittelhochdeutsch) sind kein Scherz, sondern eine Probe darauf, wie viel Fachsprache eine
-Sprachstufe trägt. Nur `goh` und `gmh` sind Vorstufen des Deutschen; **Gotisch ist ostgermanisch
-und damit eine Schwester, keine Ahnin** — es steht hier, weil es das älteste umfangreich
-überlieferte Germanisch überhaupt ist. Das Ergebnis ist ein klares Gefälle, und es folgt genau
-der Verstädterung:
-
-- **Gotisch** hat mit Wulfilas Bibel ein Korpus von rund 3.000 Lexemen, praktisch keines
- davon wirtschaftlich. Belegt sind immerhin `faihu` (Vermögen), `gild` (Abgabe), `wokrs` (Zins,
- Lk 19,23 *miþ wokra*), `mizdo` (Lohn), `asneis` (Lohnarbeiter). Alles Übrige — `haubidafaihu`
- für Kapital, `gagaleikeins` für Vergleich — ist geprägt. Vertrauensgrad ≈ 30 %.
+`gmh` Mittelhochdeutsch) sind nicht als Scherz zu verstehen, sondern als Probe darauf, wie viel
+Fachsprache eine Sprachstufe zu tragen vermag. Lediglich `goh` und `gmh` sind Vorstufen des
+Deutschen; **das Gotische ist ostgermanisch und mithin eine Schwester, keine Ahnin** — es steht
+hier, weil es das älteste umfangreich überlieferte Germanisch überhaupt darstellt. Das Ergebnis
+ist ein deutliches Gefälle, welches genau der Verstädterung folgt:
+
+- **Gotisch** verfügt mit der Wulfila-Bibel über ein Korpus von rund 3.000 Lexemen, von welchen
+ praktisch keines wirtschaftlicher Natur ist. Belegt sind immerhin `faihu` (Vermögen), `gild`
+ (Abgabe), `wokrs` (Zins, Lk 19,23 *miþ wokra*), `mizdo` (Lohn), `asneis` (Lohnarbeiter). Alles
+ Übrige — `haubidafaihu` für Kapital, `gagaleikeins` für Vergleich — ist geprägt.
+ Vertrauensgrad ≈ 30 vom Hundert.
- **Althochdeutsch** gewinnt durch Tatian und Notker: `gelt`, `zins`, `lon`, `wuohhar` sind
belegt, und **`widarmezzon` steht im Tatian genau für lateinisch *comparare*** — der
- Fenstertitel ist also kein Kunstwort. Vertrauensgrad ≈ 50 %.
-- **Mittelhochdeutsch** ist die tragfähigste Stufe, weil es bereits eine städtische Geld- und
- Rechtssprache gibt. Drei Treffer sind keine Prägung, sondern der jeweilige Terminus:
+ Fenstertitel ist mithin kein Kunstwort. Vertrauensgrad ≈ 50 vom Hundert.
+- **Mittelhochdeutsch** ist die tragfähigste Stufe, da bereits eine städtische Geld- und
+ Rechtssprache besteht. Drei Treffer sind keine Prägung, sondern der jeweilige Terminus:
**`houbetguot`** ist das Kapital, **`lîpgedinge`** die lebenslange Leibrente, **`tiurunge`**
- der Preisanstieg — also die Inflation. Dazu `gülte`, `stiure`, `wuocher`, `gewin`, `koste`.
- Vertrauensgrad ≈ 65 %.
-
-**Gotisch steht in lateinischer Umschrift** (Streitberg), nicht im Wulfila-Alphabet
-(U+10330–1034F). Der Grund ist der Grundsatz aus § 2: die App lädt keine Schriften von fremden
-Domains. Für gotische Schrift gibt es auf keinem verbreiteten System eine vorinstallierte Datei
-— 𐌰𐌻𐌻𐌰𐌹𐌼 wären leere Kästchen. Die Umschrift ist ohnehin die Form, in der das Gotische gelesen
-wird. Wer die Schrift will, braucht eine eingebettete Schriftart und damit eine andere
-Grundsatzentscheidung.
-
-### Registervarianten des Deutschen: gebaut
-
-**„Beamtendeutsch“ und „Vertrieb“** sind keine Sprachen, sondern Stilebenen derselben Sprache —
-sie stehen daher nach BCP 47 § 2.2.7 unter `de` mit privatem Untertag: `de-x-amt` und
-`de-x-sales`, in `i18n.de-x-amt.js` und `i18n.de-x-sales.js`. Anders als bei den übrigen
-Sprachen genügt hier keine Teilfassung: der Witz liegt gerade im Fließtext, den eine
-Teilübersetzung weglassen würde. Derselbe § 1a BetrAVG heißt im Amtsdeutsch „Ein Rechtsanspruch
+ der Preisanstieg, mithin die Inflation. Hinzu treten `gülte`, `stiure`, `wuocher`, `gewin`,
+ `koste`. Vertrauensgrad ≈ 65 vom Hundert.
+
+**Das Gotische steht in lateinischer Umschrift** (Streitberg) und nicht im Wulfila-Alphabet
+(U+10330–1034F). Maßgeblich hierfür ist der Grundsatz gemäß § 2: die Anwendung lädt keine
+Schriften von fremden Domänen. Für die gotische Schrift liegt auf keinem verbreiteten System
+eine vorinstallierte Datei vor — 𐌰𐌻𐌻𐌰𐌹𐌼 erschiene als leere Kästchen. Die Umschrift ist
+ohnehin diejenige Form, in welcher das Gotische gelesen wird. Wer die Schrift wünscht, bedarf
+einer eingebetteten Schriftart und mithin einer abweichenden Grundsatzentscheidung.
+
+### Registervarianten des Deutschen: eingerichtet
+
+**„Beamtendeutsch" und „Vertrieb"** sind keine Sprachen, sondern Stilebenen derselben Sprache;
+sie werden daher nach BCP 47 § 2.2.7 unter `de` mit privatem Untertag geführt: `de-x-amt` und
+`de-x-sales`, in `i18n.de-x-amt.js` und `i18n.de-x-sales.js`. Abweichend von den übrigen
+Sprachfassungen genügt hier keine Teilfassung: der Witz liegt gerade im Fließtext, welchen eine
+Teilübersetzung fortließe. Derselbe § 1a BetrAVG lautet im Amtsdeutsch „Ein Rechtsanspruch
besteht ausschließlich bis zur Höhe von 4 vom Hundert der Beitragsbemessungsgrenze der
-Rentenversicherung“ und im Vertriebsdeutsch „Bis zu 4 % on top — geschenkt vom Gesetzgeber!“ —
-beide beschreiben exakt dieselbe Rechtslage, und der Vergleich ist der Punkt. Die Zahlen ändern
-sich auch dort nicht; `pruefe.js` prüft das wie bei jeder anderen Sprache ohne Sonderfall.
-
-Technisch brauchte das drei Änderungen: `pickLang()` matcht seither zusätzlich zur
-Grundsprache beliebig viele `-x-[a-z0-9]{1,8}`-Untertags; `LANGS` und `DICT` bekamen
-Einträge mit Bindestrich; `LOCALES`/`GRUPPEN` brauchten dagegen **keine** neuen Einträge, weil
-ihre bestehenden `||`-Rückfälle (`'de-DE'` bzw. `'.'`) für beide Varianten schon das Richtige
-liefern. Der Sprachknopf zeigt nicht den vollen Code (`DE-X-AMT` wäre zu lang für die
-zweizeilige Schaltfläche), sondern nur den Teil nach dem letzten Bindestrich (`AMT`, `SALES`);
-`lang="…"` und das Autonym im `title` tragen weiterhin den vollen Code bzw. den vollen Namen.
-
-### Vorgemerkt, noch nicht gebaut
-
-**Rechtsläufige Sprachen (`he`, `fa`, `ar`).** Die Übersetzung ist der billige Teil. Teuer ist
-dreierlei: `applyStatic()` muss neben `lang` auch `dir` setzen; im Stilblatt müssen
-`margin-left`/`-right` durch die logischen Eigenschaften ersetzt werden, sonst kippt die
-Kachelung; und Teil 8 zeichnet auf Canvas, wo es **keinen Bidi-Algorithmus gibt** — Achsen,
-Legenden und der Wasserfall müssten von Hand gespiegelt werden. Dazu `fa-u-nu-latn` und
-`ar-u-nu-latn` in `LOCALES`, sonst liefert ICU ostarabische Ziffern (۱۲۳۴) neben einem `€`.
-Die Einzelheiten stehen als Kommentarblock in `index.html` direkt bei `TEILWEISE`.
-
-**Codes.** ISO 639-1, wo es einen gibt, sonst 639-3. Dreibuchstabig sind `grc`
-(**nicht** `el` — das wäre Neugriechisch), `nds` und `bar`; keine der drei hat einen
-zweibuchstabigen Code. Deshalb matcht `pickLang()` `[a-z]{2,3}` als Grundcode, optional gefolgt
-von den erwähnten `-x-…`-Untertags.
-
-**Wahl der Sprache**, in dieser Reihenfolge:
-
-1. `?lang=…` in der Adresse — teilbar, überschreibt alles,
-2. die gemerkte Wahl in `localStorage` unter `altersvorsorge.lang`,
+Rentenversicherung" und im Vertriebsdeutsch „Bis zu 4 % on top — geschenkt vom Gesetzgeber!" —
+beide Fassungen beschreiben exakt dieselbe Rechtslage, und der Vergleich ist der Punkt. Die
+Zahlen ändern sich auch dort nicht; `pruefe.js` prüft dies wie bei jeder anderen Sprache ohne
+Sonderfall.
+
+Technisch waren hierfür drei Änderungen erforderlich: `pickLang()` erkennt seither zusätzlich
+zur Grundsprache beliebig viele `-x-[a-z0-9]{1,8}`-Untertags; `LANGS` und `DICT` haben Einträge
+mit Bindestrich erhalten; `LOCALES` und `GRUPPEN` bedurften hingegen **keiner** neuen Einträge,
+da deren bestehende `||`-Rückfälle (`'de-DE'` bzw. `'.'`) für beide Varianten bereits das
+Zutreffende liefern. Die Sprachschaltfläche weist nicht den vollständigen Code aus (`DE-X-AMT`
+wäre für die zweizeilige Schaltfläche zu lang), sondern lediglich den Teil nach dem letzten
+Bindestrich (`AMT`, `SALES`); `lang="…"` sowie das Autonym im `title` tragen weiterhin den
+vollständigen Code bzw. die vollständige Bezeichnung.
+
+### Vorgemerkt, noch nicht eingerichtet
+
+**Rechtsläufige Sprachen (`he`, `fa`, `ar`).** Die Übersetzung stellt den geringeren Aufwand
+dar. Aufwendig ist Dreierlei: `applyStatic()` hat neben `lang` auch `dir` zu setzen; im Stilblatt
+sind `margin-left`/`-right` durch die logischen Eigenschaften zu ersetzen, da andernfalls die
+Kachelung kippt; und Teil 8 zeichnet auf Canvas, wo **ein Bidi-Algorithmus nicht besteht** —
+Achsen, Legenden und der Wasserfall wären mithin von Hand zu spiegeln. Hinzu treten
+`fa-u-nu-latn` und `ar-u-nu-latn` in `LOCALES`, da ICU andernfalls ostarabische Ziffern (۱۲۳۴)
+neben einem `€` liefert. Die Einzelheiten sind als Kommentarblock in `index.html` unmittelbar
+bei `TEILWEISE` niedergelegt.
+
+**Codes.** ISO 639-1, soweit ein solcher besteht, im Übrigen 639-3. Dreibuchstabig sind `grc`
+(**nicht** `el` — dies wäre Neugriechisch), `nds` und `bar`; für keine der drei Sprachen besteht
+ein zweibuchstabiger Code. `pickLang()` erkennt daher `[a-z]{2,3}` als Grundcode, fakultativ
+gefolgt von den vorgenannten `-x-…`-Untertags.
+
+**Wahl der Sprache**, in nachstehender Reihenfolge:
+
+1. `?lang=…` in der Adresse — weitergabefähig, überschreibt alles Übrige,
+2. die vorgehaltene Wahl in `localStorage` unter `altersvorsorge.lang`,
3. `navigator.language`, nach BCP-47-Teilkette (`xx` oder `xx-…`).
- **Latein, Altgriechisch, Sanskrit und Esperanto werden nie automatisch gewählt** — ein
- Browser, der `la` meldet, meint es fast sicher nicht als Anzeigesprache.
+ **Latein, Altgriechisch, Sanskrit und Esperanto werden niemals selbsttätig gewählt** — ein
+ Browser, welcher `la` meldet, meint dies mit an Sicherheit grenzender Wahrscheinlichkeit
+ nicht als Anzeigesprache.
-Die Knöpfe tragen das Kürzel, der `title` das **Autonym** (`Українська`, `Plattdüütsch`,
-`संस्कृतम्`) — nicht den übersetzten Namen. Wer Ukrainisch sucht, erkennt `Українська` auch dann,
-wenn die Oberfläche gerade auf Baskisch steht; nebenbei spart das 14 × 14 Wörterbucheinträge.
+Die Schaltflächen tragen das Kürzel, der `title` hingegen das **Autonym** (`Українська`,
+`Plattdüütsch`, `संस्कृतम्`) und nicht die übersetzte Bezeichnung. Wer Ukrainisch sucht, erkennt
+`Українська` auch dann, wenn die Oberfläche gegenwärtig auf Baskisch eingestellt ist; nebenbei
+werden hierdurch 14 × 14 Wörterbucheinträge eingespart.
**Zahlenformat.** `LOCALES` bildet jeden Code auf ein ICU-Tag ab, `GRUPPEN` auf das
-Tausenderzeichen, das `parseNum()` beim mehrdeutigen `1,234` heranzieht. Sprachen ohne eigene
-ICU-Daten (`nds`, `bar`, `eo`, `la`, `grc`, `sa`) bekommen `de-DE`: Devanāgarī-Ziffern neben
-einem `€` wären eine Schikane, keine Genauigkeit, und griechische Buchstabenzahlen erst recht.
-`fr` gruppiert mit U+202F, `uk` mit U+00A0 — beides so, wie ICU es tatsächlich setzt, nachgeprüft
-gegen `formatToParts`.
-
-**Zu Latein und Japanisch.** Das Latein ist pragmatisches Neulatein: klassische Syntax,
-aber gebildete Neuprägungen für Moderne (`pensio operativa`, `impensa pura`, `valor praesens`,
-`usura interna`). Römische Ziffern wären ein Witz auf Kosten der Lesbarkeit — und die
+Tausenderzeichen, welches `parseNum()` beim mehrdeutigen `1,234` heranzieht. Sprachen ohne
+eigene ICU-Daten (`nds`, `bar`, `eo`, `la`, `grc`, `sa`) erhalten `de-DE`: Devanāgarī-Ziffern
+neben einem `€` wären eine Schikane und keine Genauigkeit, griechische Buchstabenzahlen erst
+recht. `fr` gruppiert mit U+202F, `uk` mit U+00A0 — beides so, wie ICU es tatsächlich setzt,
+nachgeprüft gegen `formatToParts`.
+
+**Zu Latein und Japanisch.** Das Latein ist pragmatisches Neulatein: klassische Syntax, jedoch
+gebildete Neuprägungen für die Moderne (`pensio operativa`, `impensa pura`, `valor praesens`,
+`usura interna`). Römische Ziffern wären ein Witz zu Lasten der Lesbarkeit — und die
Trennzeichenkonvention ist ohnehin jünger als jede lateinische Quelle. Das Japanische folgt
-dem, was für Software dieser Art dort üblich ist: Erklärtexte in です・ます, Feldbeschriftungen
-als Nominalphrasen im 体言止め. Für die Schrift ist der `--ui`-Stapel um MS PGothic, Hiragino,
-Yu Gothic und Meiryo erweitert — eine Rasterschrift mit harten Kanten passt zum Thema.
+demjenigen, was für Software dieser Art dort üblich ist: Erläuterungstexte in です・ます,
+Feldbeschriftungen als Nominalphrasen im 体言止め. Für die Schrift ist der `--ui`-Stapel um
+MS PGothic, Hiragino, Yu Gothic und Meiryo erweitert worden — eine Rasterschrift mit harten
+Kanten ist dem Gegenstand angemessen.
-Der japanische Satzbau erzwingt, wofür die Funktionsform der Einträge da ist. Das Fazit lautet
-im Deutschen „X liegt vorn mit W — D mehr als Y“, im Japanischen dagegen
-`Xが首位です(W)。YをD上回ります。` — Verb am Ende, Vergleichsgröße mit を statt „als“. Als
-Verkettung fester Bausteine ließe sich das nicht bauen.
+Der japanische Satzbau erzwingt dasjenige, wozu die Funktionsform der Einträge bestimmt ist. Das
+Fazit lautet im Deutschen „X liegt vorn mit W — D mehr als Y", im Japanischen hingegen
+`Xが首位です(W)。YをD上回ります。` — das Verb am Ende, die Vergleichsgröße mit を anstelle von
+„als". Als Verkettung fester Bausteine ließe sich dies nicht herstellen.
-Der Umschalter oben im Kopffenster schreibt beides fort, Speicher und Adresse. Der Teilen-Link
-nimmt die Suchzeichenfolge mit, der Zustand steckt weiter im Fragment — beides stört sich nicht.
+Der Umschalter oben im Kopffenster schreibt beides fort, mithin Speicher und Adresse. Der
+Weitergabeverweis führt die Suchzeichenfolge mit, der Zustand verbleibt im Fragment; beides
+stört sich nicht.
**Aufbau der Wörterbücher.** Ein Eintrag ist entweder eine Zeichenkette oder eine Funktion
-`(p, f) → string`. Die Funktionsform ist keine Bequemlichkeit, sondern notwendig: ein Satz ist
-nicht die Verkettung seiner Teile. Stellung, Numerus und Rektion hängen an der Sprache, und
-`'mehr als ' + nom` funktioniert nur, solange beide Sprachen denselben Satzbau haben. Deshalb
-bekommen die Funktionen **Rohwerte** — Zahlen, keine fertigen Textstücke — und formatieren
-selbst über `f` (`f.eur`, `f.pct`, `f.nf2`, …). Sichtbar wird der Unterschied etwa im Fazit:
-das Deutsche braucht dort einen Genitiv (`der bAV`), das Englische eine Präposition.
+`(p, f) → string`. Die Funktionsform ist keine Bequemlichkeit, sondern zwingend erforderlich: ein
+Satz ist nicht die Verkettung seiner Teile. Stellung, Numerus und Rektion hängen an der Sprache,
+und `'mehr als ' + nom` ist lediglich so lange tragfähig, wie beide Sprachen denselben Satzbau
+aufweisen. Den Funktionen werden daher **Rohwerte** übergeben — Zahlen und keine fertigen
+Textstücke —, und die Formatierung erfolgt selbsttätig über `f` (`f.eur`, `f.pct`, `f.nf2`, …).
+Sichtbar wird der Unterschied etwa im Fazit: das Deutsche bedarf dort eines Genitivs (`der bAV`),
+das Englische einer Präposition.
```
t('n.beitrag.ueber8', { v8: v8 })
@@ -246,213 +267,228 @@ t('n.beitrag.ueber8', { v8: v8 })
en: 'Above 8 % of the pension-insurance contribution ceiling (' + f.eur(p.v8) + ' per year). …'
```
-**Schlüsselschema.** Eingabefelder liegen unter `f.<src>:<key>.label|hint|unit|o<wert>`,
-die Optionen also unter ihrem *Wert*, nicht unter ihrem Index — dann bleibt die Zuordnung
-richtig, wenn eine Option dazukommt. `FIELDS`, `OPTS` und `METRICS` tragen ihre Texte nicht
+**Schlüsselschema.** Eingabefelder liegen unter `f.<src>:<key>.label|hint|unit|o<wert>`, die
+Optionen mithin unter ihrem *Wert* und nicht unter ihrem Index; sodann verbleibt die Zuordnung
+zutreffend, wenn eine Option hinzutritt. `FIELDS`, `OPTS` und `METRICS` führen ihre Texte nicht
mehr als Feld, sondern als `Object.defineProperty`-Zugriffsfunktion: `f.label` steht unverändert
an jeder Aufrufstelle und liefert nach einem Sprachwechsel von selbst den neuen Wert.
-**Fehlt ein Eintrag**, greift Deutsch; fehlt auch der, erscheint der Schlüssel selbst im
-Klartext. Ein stiller Leerstring wäre die schlechtere Wahl — er verschwindet unbemerkt.
+**Fehlt ein Eintrag**, so greift Deutsch; fehlt auch dieser, so erscheint der Schlüssel selbst im
+Klartext. Ein stiller Leerstring wäre die schlechtere Wahl, da er unbemerkt verschwände.
-**Zahlen.** Umgeschaltet wird nur die Zifferngruppierung — `de` und `la` → `de-DE`,
-`en` → `en-GB`, `ja` → `ja-JP`; die Währung bleibt überall der nachgestellte Euro:
-`75.000,00 €` bzw. `75,000.00 €`. Die Eingabe nimmt **beide**
-Schreibweisen an, damit ein Sprachwechsel keine getippte Zahl entwertet. Die Regel in
-`parseNum`: stehen beide Zeichen im Text, ist das rechte das Dezimalzeichen; steht nur eines
-und folgen ihm genau drei Ziffern, ist es die Tausendergruppe der aktuellen Sprache
-(`GRUPPEN`: `.` für de und la, `,` für en und ja). Damit
-bleibt allein `1,234` mehrdeutig — und genau dort entscheidet die Sprache.
+**Zahlen.** Umgeschaltet wird ausschließlich die Zifferngruppierung — `de` und `la` → `de-DE`,
+`en` → `en-GB`, `ja` → `ja-JP`; die Währung verbleibt durchgängig der nachgestellte Euro:
+`75.000,00 €` bzw. `75,000.00 €`. Die Eingabe nimmt **beide** Schreibweisen an, damit ein
+Sprachwechsel eine eingegebene Zahl nicht entwertet. Die Regel in `parseNum` lautet: stehen beide
+Zeichen im Text, so ist das rechte das Dezimalzeichen; steht lediglich eines und folgen ihm genau
+drei Ziffern, so handelt es sich um die Tausendergruppe der gegenwärtigen Sprache (`GRUPPEN`:
+`.` für de und la, `,` für en und ja). Damit verbleibt allein `1,234` mehrdeutig — und genau dort
+entscheidet die Sprache.
**Was ein Sprachwechsel nicht anfasst:** die Eingaben, den Referenzstand und die Ergebnisse.
-`setLang` baut nur die Teile neu, deren Beschriftungen beim Aufbau festgeschrieben werden
-(Kennzahlenleiste, Registerkarten, Felder, Fenstertitel); alles Übrige zeichnet `refresh()`
-ohnehin bei jedem Durchgang. Der Referenzstand merkt sich deshalb den *Feldschlüssel* und
-nicht den fertigen Satz — sonst stünde nach dem Wechsel „vor der Änderung von …“ noch in der
-alten Sprache da.
-
-**Prüfung.** `pruefe.js` (Entwicklungswerkzeug, wird vom Service Worker nicht ausgeliefert) lädt die Seite kopflos in
-jsdom, schaltet alle dreiundzwanzig Sprachen durch, klappt jeden Abschnitt auf, erzwingt über fünf
-Szenarien die bedingten Texte und prüft: kein unaufgelöster Schlüssel, keine deutschen Reste im
-englischen Modus außer den erlaubten Fachbegriffen, kein sichtbar gebliebener Schlüssel, und
-— die eigentliche Invariante —
-**identische Rechenergebnisse in allen dreiundzwanzig Sprachen**.
-
-Die Liste der Wörterbücher liest das Skript aus `index.html` statt sie zu pflegen: eine neue
-Sprache soll den Test nicht stillschweigend an einem leeren Objekt vorbeilaufen lassen. Das
+`setLang` baut lediglich diejenigen Teile neu auf, deren Beschriftungen beim Aufbau
+festgeschrieben werden (Kennzahlenleiste, Registerkarten, Felder, Fenstertitel); alles Übrige
+zeichnet `refresh()` ohnehin bei jedem Durchgang. Der Referenzstand hält daher den
+*Feldschlüssel* vor und nicht den fertigen Satz; andernfalls stünde nach dem Wechsel „vor der
+Änderung von …" noch in der vormaligen Sprache da.
+
+**Prüfung.** `pruefe.js` (Entwicklungswerkzeug, wird vom Dienstarbeiter nicht ausgeliefert) lädt
+die Seite kopflos in jsdom, schaltet sämtliche dreiundzwanzig Sprachfassungen durch, klappt jeden
+Abschnitt auf, erzwingt über fünf Szenarien die bedingten Texte und prüft: kein unaufgelöster
+Schlüssel, keine deutschen Reste im englischen Modus außer den zugelassenen Fachbegriffen, kein
+sichtbar verbliebener Schlüssel, und — die eigentliche Invariante — **identische
+Rechenergebnisse in sämtlichen dreiundzwanzig Sprachfassungen**.
+
+Die Liste der Wörterbücher liest das Skript aus `index.html` aus, anstatt sie zu pflegen: eine
+neue Sprache soll den Test nicht stillschweigend an einem leeren Objekt vorbeilaufen lassen. Das
Regex für die `<script src="i18n….js">`-Tags lässt dabei auch Bindestriche im Dateinamen zu
-(`i18n.de-x-amt.js`), nicht nur zwei- bis dreibuchstabige Codes. Für Teilsprachen — sobald es
-wieder welche gibt — wird zusätzlich der Rückfall selbst nachgewiesen: jeder nicht übersetzte
-Schlüssel muss den *deutschen Text* liefern, nie einen Leerstring und nie den Schlüssel; kein
-eigener Eintrag darf den Typ wechseln (Zeichenkette ↔ Funktion); der Hinweis unter dem
-Umschalter steht genau bei den Teilsprachen und sonst nirgends. Umgekehrt wird für jede
-Vollsprache — das sind inzwischen alle dreiundzwanzig — nachgewiesen, dass ihr Wörterbuch tatsächlich
-459 von 459 Schlüsseln trägt und der Teilhinweis NICHT erscheint. Für die beiden
-Registervarianten des Deutschen wird zusätzlich geprüft, dass der Bindestrich-Untertag die
-Adresszeile und den Rückweg durch `pickLang()` übersteht. Bricht das Hauptskript beim Parsen —
-der wahrscheinlichste Fall ist ein Blockkommentar, den ein Regex-Literal vorzeitig schliesst —,
-steigt das Skript mit einer klaren Meldung aus, statt an einem `undefined` zu straucheln.
-154 Prüfungen.
-
-## 4. Prüfung
-
-Der Kern ist gegen die Excel-Mappe geprüft, sechs unabhängige Fälle, jeweils rund 20 Aggregate:
+(`i18n.de-x-amt.js`) und nicht nur zwei- bis dreibuchstabige Codes. Für Teilsprachen — sobald
+solche wieder bestehen — wird ergänzend der Rückfall selbst nachgewiesen: jeder nicht übersetzte
+Schlüssel hat den *deutschen Text* zu liefern, niemals einen Leerstring und niemals den
+Schlüssel; kein eigener Eintrag darf den Typ wechseln (Zeichenkette ↔ Funktion); der Hinweis
+unter dem Umschalter hat genau bei den Teilsprachen und sonst nirgends zu stehen. Umgekehrt wird
+für jede Vollsprache — mithin gegenwärtig für sämtliche dreiundzwanzig — nachgewiesen, dass ihr
+Wörterbuch tatsächlich 459 von 459 Schlüsseln trägt und der Teilhinweis NICHT erscheint. Für die
+beiden Registervarianten des Deutschen wird ergänzend geprüft, dass der Bindestrich-Untertag die
+Adresszeile sowie den Rückweg durch `pickLang()` übersteht. Bricht das Hauptskript beim Parsen —
+der wahrscheinlichste Fall ist ein Blockkommentar, welchen ein Regex-Literal vorzeitig schließt
+—, so bricht das Skript mit einer eindeutigen Meldung ab, anstatt an einem `undefined` zu
+straucheln. 154 Prüfungen.
+
+## § 4 Prüfung
+
+Der Kern ist gegen das ursprüngliche Excel-Modell geprüft worden, sechs unabhängige Fälle zu je
+rund 20 Aggregaten:
| Testfall | größte relative Abweichung |
|---|---|
-| Basisfall (40 J., 75.000 €, 300 €/Monat, GKV, Kapital, Ausscheiden mit 63) | 3,6 · 10⁻¹⁵ |
+| Regelfall (40 J., 75.000 €, 300 €/Monat, GKV, Kapital, Ausscheiden mit 63) | 3,6 · 10⁻¹⁵ |
| Splitting, KiSt 9 %, kinderlos, PKV, Rente, Fünftelregelung, Modus 2, Teilkapital | 1,3 · 10⁻¹⁴ |
-| GKV + lebenslange Rente, Zuschussmodus 0, KiSt 8 %, Teilkapital 30 % | 6,2 · 10⁻¹⁵ |
+| GKV nebst lebenslanger Rente, Zuschussmodus 0, KiSt 8 %, Teilkapital 30 % | 6,2 · 10⁻¹⁵ |
| **AVD verrentet** | 5,2 · 10⁻¹⁵ |
-| **AVD verrentet + 30 % Einmalbetrag** | 3,6 · 10⁻¹⁵ |
-| **beide Produkte verrentet, Splitting, PKV, andere Zeitachse, 2 Kinder** | 4,4 · 10⁻¹⁵ |
-| **fester AG-Zuschuss 100 €/Monat** | exakt (< 10⁻⁹ auf allen Jahreswerten) |
-| **fester Zuschuss 400 €/Monat, 4-%-Topf erschöpft** | exakt |
-| **fester Zuschuss mit Mindestschwelle, ober- und unterhalb** | exakt |
-| **Mindestschwelle + Modus 2 (Bisektion über die Sprungstelle)** | exakt |
-
-> Der Prüfanker ist **erhalten geblieben**: `build_bav.py` wurde für die Depotverrentung
-> mitgezogen (neue Eingaben, drei neue Spalten im Blatt `Auszahlung`, zweite Memo-Zeile im
-> Blatt `Vergleich`), die Mappe neu erzeugt und mit LibreOffice durchgerechnet — 0 Formelfehler,
-> und der Basisfall ist auf den Cent unverändert. Der JS-Kern wird gegen diesen Recalc geprüft,
-> nicht gegen sich selbst.
-
-Das sind wenige Dutzend ULP — akkumulierter Gleitkommafehler, nichts Systematisches.
-Die Referenzwerte stammen aus einem LibreOffice-Recalc der Mappe mit denselben Eingaben.
-
-> Die **Voreinstellungen** der App weichen bewusst vom Excel-Basisfall ab: „Ausscheiden aus dem
-> Job“ und „Teilzeit ab Alter“ stehen beide auf 67, also auf „durchgehend bis zur Rente“. Die
-> Testfälle setzen `ausscheid: 63, tzalter: 55` deshalb ausdrücklich — sonst prüfte man ein
-> anderes Szenario und merkte es nicht.
+| **AVD verrentet nebst 30 % Einmalbetrag** | 3,6 · 10⁻¹⁵ |
+| **beide Produkte verrentet, Splitting, PKV, abweichende Zeitachse, 2 Kinder** | 4,4 · 10⁻¹⁵ |
+| **fester AG-Zuschuss 100 €/Monat** | exakt (< 10⁻⁹ auf sämtlichen Jahreswerten) |
+| **fester Zuschuss 400 €/Monat, 4-%-Höchstbetrag erschöpft** | exakt |
+| **fester Zuschuss nebst Mindestschwelle, ober- und unterhalb derselben** | exakt |
+| **Mindestschwelle nebst Modus 2 (Halbierungsverfahren über die Sprungstelle)** | exakt |
+
+> Der Prüfanker ist **erhalten geblieben**: der ursprüngliche Formelgenerator ist für die
+> Depotverrentung mitgezogen worden (neue Eingaben, drei neue Spalten im Blatt `Auszahlung`,
+> zweite Memo-Zeile im Blatt `Vergleich`), die Mappe ist neu erzeugt und mit LibreOffice
+> durchgerechnet worden — 0 Formelfehler, und der Regelfall ist auf den Cent unverändert
+> geblieben. Der JavaScript-Kern wird gegen dieses Ergebnis geprüft und nicht gegen sich selbst.
+
+Es handelt sich um wenige Dutzend Einheiten der letzten Stelle, mithin um akkumulierten
+Gleitkommafehler und nicht um eine systematische Abweichung. Die Referenzwerte stammen aus einem
+LibreOffice-Durchlauf der Mappe unter denselben Eingaben.
+
+> Die **Voreinstellungen** der Anwendung weichen bewusst vom Excel-Regelfall ab: „Ausscheiden aus
+> dem Job" und „Teilzeit ab Alter" stehen beide auf 67, mithin auf „durchgehend bis zur Rente".
+> Die Testfälle setzen daher `ausscheid: 63, tzalter: 55` ausdrücklich; andernfalls würde ein
+> abweichendes Szenario geprüft, ohne dass dies bemerkt würde.
Damit die beiden Kopien des Kerns nicht auseinanderlaufen, schneidet `extract.js` Teil 1 aus
-`index.html` heraus und erzeugt daraus das `model.js`, gegen das getestet wird. Der Testkern
-*kann* also gar nicht vom ausgelieferten abweichen.
-
-Die Testskripte liegen unter `outputs/tests/`, `./tests/alle.sh` fährt alles durch:
-
-- **Stilblatt-Test:** vergleicht die im Dokument benutzten Klassen mit denen im Stilblatt,
- in beide Richtungen. Benutzt-ohne-Regel heißt: ein Element steht unformatiert da.
- Regel-ohne-Nutzung heißt: tote Zeilen, meist eine vergessene Umbenennung. Der Test hat
- nach dem Stilwechsel zwei echte Fehler gefunden — den unformatierten Wasserfall-Umschalter
- und sechs verwaiste Hilfsklassen. Zusätzlich: jede per `var()` referenzierte Farbvariable
- muss definiert sein.
+`index.html` heraus und erzeugt hieraus dasjenige `model.js`, gegen welches geprüft wird. Der
+Prüfkern *kann* mithin vom ausgelieferten Kern gar nicht abweichen.
+
+Die Prüfskripte werden als Sitzungsausgaben unter `outputs/tests/` geführt und liegen nicht im
+Arbeitsbaum vor; `./tests/alle.sh` fährt sämtliche Prüfungen durch:
+
+- **Stilblatt-Test:** vergleicht die im Dokument verwendeten Klassen mit denjenigen im Stilblatt,
+ und zwar in beiden Richtungen. Verwendet-ohne-Regel bedeutet: ein Element steht unformatiert
+ da. Regel-ohne-Verwendung bedeutet: tote Zeilen, im Regelfall eine unterbliebene Umbenennung.
+ Der Test hat nach dem Stilwechsel zwei tatsächliche Fehler aufgefunden — den unformatierten
+ Wasserfall-Umschalter sowie sechs verwaiste Hilfsklassen. Ergänzend gilt: jede per `var()`
+ referenzierte Farbvariable hat definiert zu sein.
- **Excel-Abgleich der Depotverrentung** (`7-avrente.js`): die drei neuen Fälle gegen einen
- frischen LibreOffice-Recalc, einschließlich der Memo-Zeile für Zahlungen nach dem Horizont.
-- **DOM-Test:** 57 Zusicherungen über jsdom — Karten, Sichtbarkeitsregeln, Regler, Segment-
- umschalter, Brutto-Netto-Kopplung in beide Richtungen, Fazittexte, mitlaufende Leiste,
- Rundung, Tabs, Kennzahlwechsel, Referenz merken, Zurücksetzen, `localStorage`.
- Die beiden seltenen Zweige des Fazits — „zulasten“ und „die Reihenfolge kehrt sich um“ —
- sind eigens durch Parametersuche im Modell aufgespürt und dann im DOM nachgestellt worden;
- ungetestete Textzweige sind sonst genau die, die beim Nutzer falsch dastehen.
+ frischen LibreOffice-Durchlauf, einschließlich der Memo-Zeile für Zahlungen nach dem Horizont.
+- **DOM-Test:** 57 Zusicherungen über jsdom — Karten, Sichtbarkeitsregeln, Regler,
+ Segmentumschalter, Brutto-Netto-Kopplung in beiden Richtungen, Fazittexte, mitlaufende Leiste,
+ Rundung, Registerkarten, Kennzahlwechsel, Referenz merken, Zurücksetzen, `localStorage`.
+ Die beiden seltenen Zweige des Fazits — „zulasten" und „die Reihenfolge kehrt sich um" — sind
+ eigens durch Parametersuche im Modell aufgespürt und sodann im DOM nachgestellt worden;
+ ungeprüfte Textzweige sind andernfalls genau diejenigen, welche beim Nutzer unzutreffend
+ dastehen.
- **Canvas-Test, Stufe 1** (Endlichkeit): 120 Kombinationen aus 2 Breiten × 15 Randfällen ×
- 4 Diagrammen. Jeder Zeichenaufruf wird auf endliche Koordinaten, gesetzte Farben und
- Beschriftungen ohne `NaN` geprüft. Fand drei echte Fehler: Division durch null bei
- Beitrag 0, entarteter Zeitraum bei Horizont = Rentenbeginn, und — der interessanteste —
- nicht ganzzahlige Zwischenwerte in der Sensitivitätskurve über das Feld *Alter*, wodurch
+ 4 Diagrammen. Jeder Zeichenaufruf wird auf endliche Koordinaten, gesetzte Farben sowie
+ Beschriftungen ohne `NaN` geprüft. Aufgefunden wurden drei tatsächliche Fehler: Division durch
+ null bei Beitrag 0, entarteter Zeitraum bei Horizont = Rentenbeginn, und — der bemerkenswerteste
+ — nicht ganzzahlige Zwischenwerte in der Sensitivitätskurve über das Feld *Alter*, wodurch
`Z[6,2]` indiziert wurde.
- **Canvas-Test, Stufe 2** (Sichtbarkeit): 400 Kombinationen aus 5 Breiten-/DPR-Paaren ×
- 20 Szenarien × 4 Diagrammen. Prüft zusätzlich, dass jede Koordinate **innerhalb der Bitmap**
- liegt. Diese Stufe entstand, nachdem Stufe 1 einen sichtbaren Fehler durchgelassen hatte:
- `prep()` skalierte die Zeichenmatrix mit `devicePixelRatio`, setzte `canvas.height` aber in
- logischen Pixeln — alles unterhalb von `h/dpr` wurde aus der Bitmap herausgezeichnet.
- Sämtliche Koordinaten waren dabei endlich, also fehlerfrei nach Stufe 1. Lehre: bei Canvas
- reicht „endlich“ nicht, es muss „im Bild“ geprüft werden.
-
-## 5. Was die App über das Excel hinaus kann
-
-- **Sensitivitätskurve** über den zuletzt bewegten Regler: 41 vollständige Modellläufe
- (~0,5 ms je Lauf), mit markierten Schnittpunkten gegen das Privatdepot. Damit sind
- Break-evens ablesbar statt ausgerechnet.
-- **Wasserfall der Werttreiber**, teleskopierend zerlegt, also exakt aufgehend. Reihenfolge-
- abhängig, weil die Effekte nicht additiv separierbar sind — die App sagt das dazu.
-- **Warnung bei uneiniger Rangfolge.** Barwert und äquivalente Monatsleistung ranken
- unterschiedlich, sobald der Wiederanlagezins nach Steuern deutlich über der Inflation liegt
- (im Basisfall 5,54 % gegen 2,00 %). Genau daran hängt die Aussage
- „PKV im Ruhestand dreht das Ergebnis“: nach Monatsleistung ja, nach Barwert nicht.
-- **Alle 45 Rechengrößen editierbar**, mit Fundstelle. Wer die Modellannahme
- „Sonderausgaben-Höchstbetrag 2.340 €“ (Vertrauensgrad ~70 %) nicht teilt, ändert sie.
-- **Live-Notizen an den Reglern.** Der Arbeitgeberzuschuss meldet, ab welchem Prozentsatz er
- sättigt; der Monatsbeitrag meldet das Überschreiten der 4-%- und der 8-%-Grenze der
- Beitragsbemessungsgrenze RV. Beides sind Schwellen, an denen der Regler seine Wirkung
- verliert oder die Rechtslage wechselt — ohne Hinweis dreht man ratlos weiter.
-- **Fester Arbeitgeberzuschuss** (Regler „Fester Zuschuss zusätzlich“, darunter der Schalter
- für die Dynamisierung, unter „Weitere Angaben“ die Mindest-Eigenleistung). Tarifvertragliche
- Festbeträge — Deutsche Bahn und viele andere — hängen nicht am Umwandlungsbetrag und stehen
- neben den 15 % des § 1a Abs. 1a BetrAVG. Der Regler meldet, wenn der Festbetrag den 4-%-Topf
- des § 1 Abs. 1 S. 1 Nr. 9 SvEV vorrangig belegt und dadurch die eigene Umwandlung verdrängt,
- und warnt oberhalb von 4 % der BBG-RV (2026: 338 €/Monat), wo das Modell die dann fällige
- Beitragspflicht des Überhangs bewusst nicht gegenrechnet.
-- **Klartext-Fazit** in einem Satz: wer vorn liegt, um wie viel, und welcher Posten des
- Wasserfalls den Abstand hauptsächlich trägt. Beschreibend formuliert, nicht empfehlend.
- Angehängt ein Belastbarkeitstest über ±1 Prozentpunkt Bruttorendite, der ausdrücklich sagt,
- wenn die Reihenfolge in dieser Spanne kippt — was sie überraschend oft tut.
-
-## 6. Bedienung auf dem Telefon
-
-Die Regler standen ursprünglich rund 1.000 px unter den Ergebniskarten. Wer auf einem 390-px-
-Gerät einen Regler schob, sah von der Wirkung **nichts** — genau das Gegenteil der Anforderung.
-Zwei Änderungen:
+ 20 Szenarien × 4 Diagrammen. Geprüft wird ergänzend, dass jede Koordinate **innerhalb der
+ Bitmap** liegt. Diese Stufe ist eingerichtet worden, nachdem Stufe 1 einen sichtbaren Fehler
+ durchgelassen hatte: `prep()` skalierte die Zeichenmatrix mit `devicePixelRatio`, setzte
+ `canvas.height` jedoch in logischen Pixeln — alles unterhalb von `h/dpr` wurde mithin aus der
+ Bitmap herausgezeichnet. Sämtliche Koordinaten waren dabei endlich und nach Stufe 1 mithin
+ fehlerfrei. Erkenntnis: bei Canvas genügt „endlich" nicht, es ist „im Bild" zu prüfen.
+
+## § 5 Was die Anwendung über die Tabellenkalkulation hinaus leistet
+
+- **Sensitivitätskurve** über denjenigen Regler, welcher zuletzt bewegt worden ist: 41
+ vollständige Modellläufe (~0,5 ms je Lauf) nebst gekennzeichneten Schnittpunkten gegenüber dem
+ privaten Depot. Gewinnschwellen sind hierdurch ablesbar und nicht zu errechnen.
+- **Wasserfall der Werttreiber**, teleskopierend zerlegt und mithin exakt aufgehend. Die
+ Darstellung ist reihenfolgeabhängig, da die Effekte nicht additiv separierbar sind; die
+ Anwendung weist hierauf hin.
+- **Warnhinweis bei uneinheitlicher Rangfolge.** Barwert und äquivalente Monatsleistung ranken
+ unterschiedlich, sobald der Wiederanlagezins nach Steuern die Inflationsrate deutlich
+ übersteigt (im Regelfall 5,54 gegenüber 2,00 vom Hundert). Hieran hängt genau die Aussage
+ „private Krankenversicherung im Ruhestand kehrt das Ergebnis um": nach Monatsleistung ja, nach
+ Barwert nicht.
+- **Sämtliche 45 Rechengrößen sind änderbar**, jeweils unter Angabe der Fundstelle. Wer die
+ Modellannahme „Sonderausgaben-Höchstbetrag 2.340 €" (Vertrauensgrad ~70 vom Hundert) nicht
+ teilt, hat sie zu ändern.
+- **Fortlaufende Notizen an den Reglern.** Der Arbeitgeberzuschuss meldet, ab welchem
+ Prozentsatz er sättigt; der Monatsbeitrag meldet das Überschreiten der 4-%- und der
+ 8-%-Grenze der Beitragsbemessungsgrenze der Rentenversicherung. Es handelt sich in beiden
+ Fällen um Schwellen, an welchen der Regler seine Wirkung verliert oder die Rechtslage wechselt;
+ ohne Hinweis würde ratlos weitergedreht.
+- **Fester Arbeitgeberzuschuss** (Regler „Fester Zuschuss zusätzlich", darunter der Schalter zur
+ Dynamisierung, unter „Weitere Angaben" die Mindest-Eigenleistung). Tarifvertragliche
+ Festbeträge — bei der Deutschen Bahn sowie in zahlreichen weiteren Tarifwerken vorgesehen —
+ hängen nicht am Umwandlungsbetrag und treten neben die 15 vom Hundert des § 1a Abs. 1a
+ BetrAVG. Der Regler meldet, wenn der Festbetrag den 4-%-Höchstbetrag des § 1 Abs. 1 S. 1 Nr. 9
+ SvEV vorrangig belegt und hierdurch die eigene Umwandlung verdrängt, und warnt oberhalb von
+ 4 vom Hundert der Beitragsbemessungsgrenze der Rentenversicherung (2026: 338 €/Monat), wo das
+ Modell die sodann anfallende Beitragspflicht des Überhangs bewusst nicht gegenrechnet.
+- **Klartextfazit** in einem Satz: wer vorn liegt, um welchen Betrag, und welcher Posten des
+ Wasserfalls den Abstand hauptsächlich trägt. Die Formulierung ist beschreibend und nicht
+ empfehlend gehalten. Angefügt ist ein Belastbarkeitstest über ±1 Prozentpunkt Bruttorendite,
+ welcher ausdrücklich mitteilt, wenn die Reihenfolge innerhalb dieser Spanne kippt — was
+ überraschend häufig der Fall ist.
+
+## § 6 Bedienung auf dem Telefon
+
+Die Regler standen ursprünglich rund 1.000 px unterhalb der Ergebniskarten. Wer auf einem
+390-px-Gerät einen Regler verschob, sah von der Wirkung **nichts** — mithin genau das Gegenteil
+der Anforderung. Zwei Änderungen wurden vorgenommen:
1. **Reihenfolge:** Ergebnis → *Ihre Angaben* → Diagramme → Weitere Angaben → Rechenweg.
- Die Diagramme sind Vertiefung, die Eingaben sind der Arbeitsplatz.
+ Die Diagramme dienen der Vertiefung, die Eingaben sind der Arbeitsplatz.
2. **Mitlaufende Ergebnisleiste**, eingeblendet per `IntersectionObserver`, sobald die
- Ergebniskarten den oberen Rand verlassen. Sie zeigt alle drei Werte, das Δ zum
- Referenzstand, die Bezeichnung der Kennzahl und einen Sprung zurück nach oben.
+ Ergebniskarten den oberen Rand verlassen. Sie weist sämtliche drei Werte, das Δ zum
+ Referenzstand, die Bezeichnung der Kennzahl sowie einen Rücksprung nach oben aus.
-Dazu: `:focus-visible` ist jetzt definiert (vorher gab es gar keine sichtbare Tastaturführung
-auf den Segment-Umschaltern), und `prefers-reduced-motion` schaltet Übergänge ab.
+Ergänzend gilt: `:focus-visible` ist nunmehr definiert (vormals bestand auf den
+Segmentumschaltern überhaupt keine sichtbare Tastaturführung), und `prefers-reduced-motion`
+schaltet Übergänge ab.
-> **Berichtigung.** Der `IntersectionObserver` beobachtete `#result`. Dieses Element gibt es
-> nicht; der Abschnitt heißt `#w-result`. `observe(null)` wirft nach WebIDL einen `TypeError`
-> (`observe(Element target)`), und die Ausnahme riss alles mit, was im Skript danach kam:
-> die Leiste selbst, die Registrierung des Service Workers und den Installationshinweis.
-> Behoben; die drei Dinge funktionieren erstmals.
+> **Berichtigung.** Der `IntersectionObserver` beobachtete `#result`. Ein solches Element besteht
+> nicht; der Abschnitt trägt die Bezeichnung `#w-result`. `observe(null)` wirft nach WebIDL einen
+> `TypeError` (`observe(Element target)`), und die Ausnahme riss alles mit sich, was im Skript
+> nachfolgte: die Leiste selbst, die Registrierung des Dienstarbeiters sowie den
+> Installationshinweis. Der Mangel ist behoben; die drei Vorgänge sind erstmals betriebsfähig.
-## 6b. Bedienung auf breiten Schirmen
+## § 6b Bedienung auf breiten Bildschirmen
Ein Fenster wird nicht breiter als rund 570 px. Darüber hinaus wird keine Zeile lesbarer — die
-Typografie mag 45 bis 75 Zeichen —, also wandert der gewonnene Platz in eine weitere Spalte
-statt in längere Zeilen:
+Typografie verträgt 45 bis 75 Zeichen —, weshalb der gewonnene Platz in eine weitere Spalte und
+nicht in längere Zeilen wandert:
| Breite | Spalten | Aufteilung |
|---|---|---|
| < 1080 px | 1 | Quelltextreihenfolge, unverändert |
| ≥ 1080 px | 2 | Eingaben ‖ Ausgaben |
-| ≥ 1560 px | 3 | Eingaben ‖ Ergebnis + Diagramm ‖ Herleitung |
-
-Die Aufteilung folgt der Wirkungsrichtung: was man anfasst, steht links; was daraus folgt,
-rechts daneben und damit **gleichzeitig im Bild**. Das ist der eigentliche Gewinn — Ursache und
-Wirkung ohne Scrollen, wofür auf dem Telefon die mitlaufende Leiste einspringt.
-
-Drei Entwurfsentscheidungen, jede mit ihrem Grund:
-
-1. **Die Fenster werden wirklich umgehängt** (`LAY.apply`), nicht bloß per CSS umsortiert.
- Der Quelltext bleibt einspaltig und damit in der für schmale Geräte richtigen Reihenfolge.
- `display:contents` auf vorgebauten Spalten hätte genau diese Reihenfolge zerstört, und eine
- reine Grid-Zuweisung (`grid-column`/`grid-row`) hätte in jeder Zeile eine Lücke in Höhe des
- jeweils höchsten Fensters gelassen. Echte Blockcontainer packen dicht.
-2. **`position:sticky` braucht einen Blockcontainer.** Der Grid-Bereich eines Elements ist genau
- eine Zeile hoch; ein darin klebendes Element hätte keinen Weg, sich irgendwohin zu kleben.
- Deshalb `.col` als Zwischenebene — und deshalb bleibt das Ergebnisfenster in seiner Spalte
- oben stehen, während links die Regler wandern. Die mitlaufende Leiste blendet sich dabei von
- selbst aus, ohne Sonderfall im Code: ihr Beobachter sieht das angeheftete Fenster ja
- unverwandt im Bild.
-3. **Die Enge hängt nicht mehr am Schirm, sondern am Fenster.** Ein 560 px breites Fenster auf
- einem 1600-px-Schirm braucht dieselben Regeln wie ein Telefon. Das ist der Fall, für den es
- `@container` gibt; die alten `@media (max-width:640px)`-Regeln bleiben als Rückfall stehen.
-
-Ein angeheftetes Fenster nimmt dauerhaft Platz weg. Über 60 % der Schirmhöhe wäre das ein
-schlechter Tausch, und ein Fenster höher als der Schirm ließe sein unteres Ende gar nicht mehr
-erreichen. In dem Fall (`body.nosticky`, gesetzt nach Messung in `LAY.fit`) scrollt es normal
-mit, und die mitlaufende Leiste übernimmt wieder — die dafür ja gebaut ist.
-
-Der Rechenweg baut 98 Tabellenzeilen. Solange kein Abschnitt aufgeklappt ist, wird der
-Neuaufbau jetzt bis 300 ms nach der letzten Eingabe verschoben und beim Aufklappen nachgeholt.
-
-## 7. Zwei Zinssätze und der Kapitalverlauf
-
-In der Auszahlungsphase arbeiten **zwei verschiedene Zinssätze**, und das ist kein Versehen:
+| ≥ 1560 px | 3 | Eingaben ‖ Ergebnis nebst Diagramm ‖ Herleitung |
+
+Die Aufteilung folgt der Wirkungsrichtung: was betätigt wird, steht links; was hieraus folgt,
+rechts daneben und mithin **gleichzeitig im Bild**. Hierin liegt der eigentliche Gewinn — Ursache
+und Wirkung ohne Scrollen, wofür auf dem Telefon die mitlaufende Leiste einspringt.
+
+Drei Entwurfsentscheidungen, jede nebst ihrer Begründung:
+
+1. **Die Fenster werden tatsächlich umgehängt** (`LAY.apply`) und nicht lediglich per CSS
+ umsortiert. Der Quelltext verbleibt einspaltig und mithin in der für schmale Geräte
+ zutreffenden Reihenfolge. `display:contents` auf vorgebauten Spalten hätte genau diese
+ Reihenfolge zerstört, und eine reine Grid-Zuweisung (`grid-column`/`grid-row`) hätte in jeder
+ Zeile eine Lücke in Höhe des jeweils höchsten Fensters hinterlassen. Echte Blockcontainer
+ packen dicht.
+2. **`position:sticky` bedarf eines Blockcontainers.** Der Grid-Bereich eines Elements ist genau
+ eine Zeile hoch; ein darin klebendes Element hätte keine Möglichkeit, sich irgendwohin zu
+ kleben. Hierfür besteht `.col` als Zwischenebene — und aus demselben Grund verbleibt das
+ Ergebnisfenster in seiner Spalte oben stehen, während links die Regler wandern. Die
+ mitlaufende Leiste blendet sich dabei von selbst aus, und zwar ohne Sonderfall im Code: ihr
+ Beobachter sieht das angeheftete Fenster unverwandt im Bild.
+3. **Die Enge hängt nicht mehr am Bildschirm, sondern am Fenster.** Ein 560 px breites Fenster
+ auf einem 1600-px-Bildschirm bedarf derselben Regeln wie ein Telefon. Es handelt sich um
+ denjenigen Fall, für welchen `@container` besteht; die vormaligen
+ `@media (max-width:640px)`-Regeln verbleiben als Rückfallebene.
+
+Ein angeheftetes Fenster nimmt dauerhaft Platz in Anspruch. Bei über 60 vom Hundert der
+Bildschirmhöhe wäre dies ein ungünstiger Tausch, und ein Fenster, welches höher als der Bildschirm
+ist, ließe sein unteres Ende überhaupt nicht mehr erreichen. In diesem Fall (`body.nosticky`,
+gesetzt nach Messung in `LAY.fit`) scrollt es regulär mit, und die mitlaufende Leiste übernimmt
+wieder — wofür sie eingerichtet worden ist.
+
+Der Rechenweg baut 98 Tabellenzeilen auf. Solange kein Abschnitt aufgeklappt ist, wird der
+Neuaufbau nunmehr bis 300 ms nach der letzten Eingabe verschoben und beim Aufklappen nachgeholt.
+
+## § 7 Zwei Zinssätze und der Kapitalverlauf
+
+In der Auszahlungsphase wirken **zwei verschiedene Zinssätze**; hierbei handelt es sich nicht um
+ein Versehen:
| Geld … | verzinst sich mit | versteuert |
|---|---|---|
@@ -460,9 +496,9 @@ In der Auszahlungsphase arbeiten **zwei verschiedene Zinssätze**, und das ist k
| … im Produkt (Privatdepot) | `rnet_priv` = 6,80 % | erst bei Entnahme |
| … ausgezahlt, noch nicht verbraucht | `wiederanl` = **5,54 %** | bereits versteuert |
-Wieviel davon betroffen ist, entscheidet die **Auszahlungsform**. Beide geförderten Produkte
-haben eine, und sie sind **unabhängig voneinander** einstellbar — wer die bAV als Kapital nimmt,
-kann das Depot trotzdem verrenten:
+In welchem Umfang dies zum Tragen kommt, entscheidet die **Auszahlungsform**. Beide geförderten
+Produkte verfügen über eine solche, und sie sind **unabhängig voneinander** einstellbar: wer die
+betriebliche Altersversorgung als Kapital nimmt, kann das Depot gleichwohl verrenten:
| | Einmalbetrag | Rest |
|---|---|---|
@@ -471,24 +507,28 @@ kann das Depot trotzdem verrenten:
### Die Verrentung des Altersvorsorgedepots
-Beim Depot hängen an der Auszahlungsform **drei** Wirkungen — nicht vier wie bei der bAV, weil
-KV/PV entfällt (keine Versorgungsbezüge):
-
-1. **Ertragsanteil statt halbem Unterschiedsbetrag** für die nicht geförderte Schicht, im
- Basisfall 30,7 % des Kapitals. Steuerpflichtig sind dann 17,0 % der Rente statt 26,2 % der
- Planentnahme (§ 22 Nr. 5 S. 2 Buchst. a EStG). Ein echter Vorteil der Verrentung.
-2. **Rentenfaktor statt Marktrendite** auf das Restkapital — eigenes Eingabefeld `rentfak_av`,
- weil ein Depotvertrag ohne Versicherungsmantel auskommt und günstiger sein kann.
-3. **Zahlungen nach dem Horizont**, die der Vergleich nicht mitzählt. Eigene Memo-Zeile in der
- Diagnose und eine Live-Notiz am Schalter; im Basisfall 145.618 €.
-
-Die geförderte Schicht ist in beiden Formen voll nachgelagert steuerpflichtig
-(§ 22 Nr. 5 S. 1 EStG) — daran ändert die Auszahlungsform nichts. Der Einmalbetrag wirkt in
-beiden Formen und wird als Kapital besteuert, auch wenn der Rest verrentet wird.
-
-Beim Altersvorsorgedepot kostet der Einmalbetrag aus denselben zwei Gründen wie bei der bAV:
-volle Progression im Zuflussjahr und danach nur noch der Satz nach Abgeltungsteuer. Im
-Basisfall:
+Beim Depot hängen an der Auszahlungsform **drei** Wirkungen — und nicht vier wie bei der
+betrieblichen Altersversorgung, da Beiträge zur Kranken- und Pflegeversicherung entfallen (keine
+Versorgungsbezüge):
+
+1. **Ertragsanteil anstelle des halben Unterschiedsbetrags** für die nicht geförderte Schicht, im
+ Regelfall 30,7 vom Hundert des Kapitals. Steuerpflichtig sind sodann 17,0 vom Hundert der
+ Rente anstelle von 26,2 vom Hundert der Planentnahme (§ 22 Nr. 5 S. 2 Buchst. a EStG). Es
+ handelt sich um einen tatsächlichen Vorteil der Verrentung.
+2. **Rentenfaktor anstelle der Marktrendite** auf das Restkapital — hierfür besteht ein eigenes
+ Eingabefeld `rentfak_av`, da ein Depotvertrag ohne Versicherungsmantel auskommt und mithin
+ günstiger sein kann.
+3. **Zahlungen nach dem Horizont**, welche der Vergleich nicht mitzählt. Hierfür bestehen eine
+ eigene Memo-Zeile in der Diagnose sowie eine fortlaufende Notiz am Schalter; im Regelfall
+ 145.618 €.
+
+Die geförderte Schicht ist in beiden Formen in vollem Umfang nachgelagert steuerpflichtig (§ 22
+Nr. 5 S. 1 EStG); hieran ändert die Auszahlungsform nichts. Der Einmalbetrag wirkt in beiden
+Formen und wird als Kapital besteuert, auch wenn der Rest verrentet wird.
+
+Beim Altersvorsorgedepot verursacht der Einmalbetrag aus denselben zwei Gründen Kosten wie bei
+der betrieblichen Altersversorgung: volle Progression im Zuflussjahr und sodann lediglich noch
+der Satz nach Abgeltungsteuer. Im Regelfall:
| Einmalbetrag | steuerpflichtig Jahr 0 | Grenzbelastung | Monatsleistung |
|---|---|---|---|
@@ -496,18 +536,20 @@ Basisfall:
| 15 % | 42.543 € | 29,7 % | 840,09 € |
| 30 % | 67.793 € | 32,3 % | 823,37 € |
-Zwei Kontrollen dazu: das Restkapital am Horizont ist über alle geprüften Renditen, Horizonte
-und Einmalbeträge **exakt 0,00 €** — der Annuitätenfaktor passt zur Rekursion, es wird nichts
-stillschweigend einbehalten. Und der Überschuss über den Jahreshöchstbetrag („Sleeve“) wird
-ohne Einmalbetrag verrentet; das ist eine Modellkonvention, kein Rechtssatz.
+Zwei Kontrollen sind hierzu vorgenommen worden: das Restkapital am Horizont beträgt über
+sämtliche geprüften Renditen, Horizonte und Einmalbeträge **exakt 0,00 €** — der
+Annuitätenfaktor passt mithin zur Rekursion, und es wird nichts stillschweigend einbehalten.
+Ferner wird der Überschuss über den Jahreshöchstbetrag („Sleeve") ohne Einmalbetrag verrentet;
+hierbei handelt es sich um eine Modellkonvention und nicht um einen Rechtssatz.
-**Verbleibende Modelllücke, ausdrücklich:** die bAV kennt weiterhin nur ganz oder gar nicht.
-Eine Teilkapitalisierung der Betriebsrente, die es in der Praxis gibt, ist nicht abgebildet —
-anders als beim Depot, wo Einmalbetrag und Verrentung seit dieser Fassung kombinierbar sind.
+**Verbleibende Modelllücke, ausdrücklich:** die betriebliche Altersversorgung kennt weiterhin
+lediglich die vollständige oder die unterbliebene Kapitalisierung. Eine Teilkapitalisierung der
+Betriebsrente, welche in der Praxis vorkommt, ist nicht abgebildet — abweichend vom Depot, wo
+Einmalbetrag und Verrentung seit dieser Fassung kombinierbar sind.
### Der Kapitalverlauf
-Eine Größe über die ganze Zeitachse, mit Verbrauch und mit Liquiditätszerlegung.
+Eine Größe über die gesamte Zeitachse, nebst Verbrauch und nebst Liquiditätszerlegung.
```
Wiederanlage(0) = 0
@@ -515,7 +557,7 @@ Wiederanlage(t+1) = (Wiederanlage(t) + netto(t))·(1+w) − M M = V(0)·ANN
Vermögen(t) = Produktkonto(t) + Wiederanlage(t)
```
-Die äquivalente Monatsleistung wird also **tatsächlich verbraucht**. Weil `ANNW` der
+Die äquivalente Monatsleistung wird mithin **tatsächlich verbraucht**. Da `ANNW` der
nachschüssige Annuitätenfaktor ist und der Konsum am Jahresende abgeht, gilt
`Wiederanlage(n) = 0` exakt.
@@ -523,40 +565,41 @@ Vier geprüfte Identitäten:
| | |
|---|---|
-| `Vermögen(0) = Produktkapital` | 0,00 € — die Wiederanlage ist am Rentenbeginn null, die Kurve läuft **knickfrei** durch |
-| `Vermögen(n) = 0` | 7,4 · 10⁻¹⁰ € — jede Option ist am Horizont punktgenau aufgebraucht |
-| `M = V(0)·ANNW`, `M/12` diskontiert `=` Monatsleistung | 0,00 € — der Verbrauch ist genau die Kennzahl oben |
+| `Vermögen(0) = Produktkapital` | 0,00 € — die Wiederanlage beträgt am Rentenbeginn null, die Kurve verläuft **knickfrei** |
+| `Vermögen(n) = 0` | 7,4 · 10⁻¹⁰ € — jede Variante ist am Horizont punktgenau aufgebraucht |
+| `M = V(0)·ANNW`, `M/12` diskontiert `=` Monatsleistung | 0,00 € — der Verbrauch entspricht genau der vorstehenden Kennzahl |
| Pfade **nicht** proportional | AV/privat wandert von 1,3152 auf 1,2497 |
-> **Warum das nicht proportional ist — und die naheliegende Variante schon.**
-> Setzt man *alles* auf den Wiederanlagezins und konsumiert daraus
-> (`G(t+1) = G(t)(1+w) − M`), kürzt sich der Unterschied heraus: `G_x/G_y = M_x/M_y` für alle t,
-> geprüft auf 4 · 10⁻¹⁴. Entscheidend ist, **wo** der Konsum abgeht. Nimmt man ihn nur aus der
-> Wiederanlage und lässt das Produktkapital im Produkt, wo es mit der Produktrendite **vor**
-> Steuern wächst, bleibt genau der Unterschied stehen, um den es geht.
+> **Weshalb dies nicht proportional ist — die naheliegende Variante hingegen schon.**
+> Wird *alles* auf den Wiederanlagezins gesetzt und hieraus konsumiert
+> (`G(t+1) = G(t)(1+w) − M`), so kürzt sich der Unterschied heraus: `G_x/G_y = M_x/M_y` für alle
+> t, geprüft auf 4 · 10⁻¹⁴. Maßgeblich ist mithin, **wo** der Konsum abgeht. Wird er
+> ausschließlich der Wiederanlage entnommen und verbleibt das Produktkapital im Produkt, wo es
+> mit der Produktrendite **vor** Steuern wächst, so verbleibt genau derjenige Unterschied, um
+> welchen es geht.
### Liquidität
-Durchgezogen das Vermögen insgesamt, gestrichelt in derselben Farbe der **frei verfügbare**
-Teil. Der Abstand ist gebundenes Kapital.
+Durchgezogen dargestellt ist das Vermögen insgesamt, gestrichelt in derselben Farbe der **frei
+verfügbare** Teil. Der Abstand ist gebundenes Kapital.
-| | Bindung | im Basisfall bei Rentenbeginn |
+| | Bindung | im Regelfall bei Rentenbeginn |
|---|---|---|
-| bAV | vollständig bis zum Rentenbeginn — § 1b BetrAVG kennt Unverfallbarkeit, nicht Verfügbarkeit; danach kein Konto mehr | **0 € von 357.076 € frei** |
-| Altersvorsorgedepot | Entnahme vor 65 ist förderschädlich; frei ist nur der „Sleeve“ über dem Jahreshöchstbetrag | 0 € von 240.001 € frei |
+| bAV | vollständig bis zum Rentenbeginn — § 1b BetrAVG kennt die Unverfallbarkeit, nicht die Verfügbarkeit; danach besteht kein Konto mehr | **0 € von 357.076 € frei** |
+| Altersvorsorgedepot | eine Entnahme vor Vollendung des 65. Lebensjahres ist förderschädlich; frei ist ausschließlich der „Sleeve" oberhalb des Jahreshöchstbetrags | 0 € von 240.001 € frei |
| privates ETF-Depot | jederzeit | **182.489 € von 182.489 € frei** |
-Das ist die einzige Achse, auf der eine bAV-Kapitalauszahlung gut aussieht: mit 68 springt sie
-von 0 % auf 100 % Verfügbarkeit. Und es ist die Achse, die in Beratungsgesprächen am häufigsten
-fehlt.
+Es handelt sich um die einzige Achse, auf welcher eine Kapitalauszahlung der betrieblichen
+Altersversorgung günstig erscheint: mit 68 springt sie von 0 auf 100 vom Hundert Verfügbarkeit.
+Und es ist diejenige Achse, welche in Beratungsgesprächen am häufigsten fehlt.
-### Warum kein Konsummodell
+### Weshalb kein Konsummodell
-Naheliegend wäre, Lebenshaltungskosten als eigene Eingabe zu führen. Das wurde geprüft und
-verworfen — es trägt **beweisbar keine vergleichende Information**. Weil der Nettoaufwand in
-allen drei Optionen identisch ist, unterscheiden sich die Zahlungsströme nur in der
-Auszahlungsphase; ein für alle drei gleicher Konsumstrom `C` ist damit eine gemeinsame additive
-Verschiebung:
+Naheliegend wäre, die Lebenshaltungskosten als eigene Eingabe zu führen. Dies ist geprüft und
+verworfen worden — es trägt **nachweislich keine vergleichende Information**. Da der
+Nettoaufwand in sämtlichen drei Varianten identisch ist, unterscheiden sich die Zahlungsströme
+ausschließlich in der Auszahlungsphase; ein für alle drei gleicher Konsumstrom `C` stellt mithin
+eine gemeinsame additive Verschiebung dar:
| Konsum | AV − privat bei t = 5 | bei t = 15 | bAV − privat bei t = 15 |
|---|---|---|---|
@@ -564,119 +607,128 @@ Verschiebung:
| 12.000 €/Jahr | 55.049,182535 € | 56.681,527808 € | −62.016,690135 € |
| 60.000 €/Jahr | 55.049,182535 € | 56.681,527808 € | −62.016,690135 € |
-Auf sechs Nachkommastellen identisch. Dazu käme: ein ehrliches Konsummodell bräuchte in der
-Ansparphase auch das Gehalt, sonst liefe die Kurve sofort ins Minus — das wäre ein
-Haushaltsplaner, kein Förderarchitektur-Vergleich. Und die Zahl „leer mit 87“ würde als Aussage
-über die Altersvorsorge insgesamt gelesen, obwohl das Modell nur diese eine Entscheidung kennt.
+Auf sechs Nachkommastellen identisch. Hinzu träte: ein sachgerechtes Konsummodell bedürfte in der
+Ansparphase auch des Gehalts, da die Kurve andernfalls unverzüglich ins Minus liefe — dies wäre
+ein Haushaltsplaner und kein Vergleich der Förderarchitekturen. Ferner würde die Angabe „leer mit
+87" als Aussage über die Altersvorsorge insgesamt gelesen, obgleich das Modell ausschließlich
+diese eine Entscheidung kennt.
-Der Verbrauch der **äquivalenten** Monatsleistung ist etwas anderes: er ist je Option
-verschieden, aus dem Modell abgeleitet und braucht keine Fremdannahme. Deshalb steht er drin.
+Der Verbrauch der **äquivalenten** Monatsleistung ist demgegenüber etwas anderes: er ist je
+Variante verschieden, aus dem Modell abgeleitet und bedarf keiner Fremdannahme. Er ist daher
+enthalten.
### Vier verworfene Fassungen
-Der Weg dorthin lohnt die Notiz, weil jede Zwischenstufe an einem anderen Denkfehler scheiterte:
+Der Weg dorthin verdient die Notiz, da jede Zwischenstufe an einem anderen Denkfehler scheiterte:
-1. **Nur das Produktkonto.** Die bAV fällt bei Kapitalwahl auf null und schweigt über den Rest.
- Verschweigt, dass die Kennzahl sehr wohl eine Wiederanlage unterstellt.
-2. **Die prospektive Reserve `V(t)`.** Mathematisch tadellos und exakt die Größe hinter der
- Monatsleistung — aber nach einer Kapitalauszahlung **negativ** (−54.555 € ab Alter 68), weil
- dann nur noch Lasten ausstehen. Wahr, wichtig, und als Kurve unlesbar.
-3. **Der reine Entsparpfad** `G(t+1) = G(t)(1+w) − M`. Läuft sauber auf null, aber die Pfade
- sind dann zwangsläufig proportional: wer den Verbrauch fixiert *und* alles zum selben Zins
+1. **Ausschließlich das Produktkonto.** Die betriebliche Altersversorgung fällt bei Kapitalwahl
+ auf null und schweigt über den Rest. Verschweigt mithin, dass die Kennzahl sehr wohl eine
+ Wiederanlage unterstellt.
+2. **Die prospektive Reserve `V(t)`.** Mathematisch tadellos und exakt diejenige Größe hinter der
+ Monatsleistung — nach einer Kapitalauszahlung jedoch **negativ** (−54.555 € ab Alter 68), da
+ sodann lediglich noch Lasten ausstehen. Zutreffend, bedeutsam, und als Kurve unlesbar.
+3. **Der reine Entsparpfad** `G(t+1) = G(t)(1+w) − M`. Läuft sauber auf null, doch sind die Pfade
+ sodann zwangsläufig proportional: wer den Verbrauch fixiert *und* alles zu demselben Zins
führt, hat das Vermögen determiniert.
4. **Der beitragsfreie Wert** in der Ansparphase, um den Einheitenwechsel am Rentenbeginn zu
- vermeiden. Stetig und sauber, aber es blieb bei einer Nettogröße, die für das Privatdepot
- eine Bewegung suggeriert, wo keine ist.
-
-## 8. Eine Lesefalle in der Sensitivitätskurve
-
-Reglern wie *Jahresbrutto* oder *Monatsbeitrag* verändern nicht nur die Förderarchitektur,
-sondern auch den **Nettoaufwand** — und damit den Betrag, der in allen drei Optionen investiert
-wird. Die drei Kurven sind deshalb bei jedem einzelnen x fair vergleichbar, das Niveau zwischen
-verschiedenen x aber nicht. Die auffälligen Sprünge sind echt und sitzen an den
-Beitragsbemessungsgrenzen: oberhalb von 69.750 € spart die Entgeltumwandlung keine
-KV/PV-Beiträge mehr, oberhalb von 101.400 € auch keine RV/AV-Beiträge. Der Nettoaufwand
-springt dort um bis zu 15 %, die investierte Summe mit ihm. Die App blendet einen Hinweis mit
-der tatsächlichen Spanne ein, sobald der Effekt 2 % übersteigt.
-
-## 9. Zwei Befunde, die beim Portieren aufgefallen sind
-
-**Die Vorabpauschale ist im Basisfall ein Vorteil für das Privatdepot.** Über 35 Jahre fallen
-121.774 € Vorabpauschale an, davon werden aber nur 11.942 € tatsächlich versteuert — der Rest
-läuft in den Sparer-Pauschbetrag. Die *volle* Summe erhöht dagegen die Kostenbasis und spart
-bei der Entnahme rund 22.000 € Abgeltungsteuer. Setzt man den Sparer-Pauschbetrag auf null,
-dreht das Vorzeichen. Der Balken „Wegfall der Vorabpauschale“ im Wasserfall ist deshalb
-negativ; das ist kein Vorzeichenfehler.
-
-**Der Arbeitgeberzuschuss sättigt — und zwar früher, als man denkt.** Im Zuschussmodus „spitz“
-(§ 1a Abs. 1a BetrAVG wörtlich) wächst der Zuschuss nur bis zur tatsächlichen SV-Ersparnis des
-Arbeitgebers. Bei 75.000 € Gehalt und 300 €/Monat liegt das Entgelt bereits **über** der
-KV-Beitragsbemessungsgrenze von 69.750 €: der Arbeitgeber spart dort überhaupt keine
-KV/PV-Beiträge, sondern nur RV/AV auf 3.600 €, also 381,60 € im Jahr — das sind 10,6 % des
-umgewandelten Betrags. Der gesetzliche Mindestzuschuss von 15 % ist damit schon der gedeckelte
-Wert; **jede Erhöhung des Reglers ist wirkungslos.** Die App zeigt das jetzt direkt am Regler an.
-
-Der im README des Modells genannte Break-even von ~26,7 % ist folglich im spitzen Modus gar
-nicht erreichbar, sondern nur in den Modi „voller Beitrag“ bzw. „sv-freier Anteil“.
-Die Sensitivitätskurve zeigt die Sättigung als waagerechten Ast.
+ vermeiden. Stetig und sauber, doch verblieb es bei einer Nettogröße, welche für das
+ Privatdepot eine Bewegung suggeriert, wo eine solche nicht besteht.
+
+## § 8 Eine Lesefalle in der Sensitivitätskurve
+
+Regler wie *Jahresbrutto* oder *Monatsbeitrag* verändern nicht allein die Förderarchitektur,
+sondern auch den **Nettoaufwand** — und mithin denjenigen Betrag, welcher in sämtlichen drei
+Varianten angelegt wird. Die drei Kurven sind daher bei jedem einzelnen x sachgerecht
+vergleichbar, das Niveau zwischen verschiedenen x hingegen nicht. Die auffälligen Sprünge sind
+zutreffend und sitzen an den Beitragsbemessungsgrenzen: oberhalb von 69.750 € erspart die
+Entgeltumwandlung keine Beiträge zur Kranken- und Pflegeversicherung mehr, oberhalb von
+101.400 € auch keine Beiträge zur Renten- und Arbeitslosenversicherung. Der Nettoaufwand springt
+dort um bis zu 15 vom Hundert, die angelegte Summe mit ihm. Die Anwendung blendet einen Hinweis
+nebst der tatsächlichen Spanne ein, sobald der Effekt 2 vom Hundert übersteigt.
+
+## § 9 Zwei Befunde, welche bei der Portierung aufgefallen sind
+
+**Die Vorabpauschale stellt im Regelfall einen Vorteil für das Privatdepot dar.** Über 35 Jahre
+fallen 121.774 € Vorabpauschale an, wovon jedoch lediglich 11.942 € tatsächlich versteuert werden
+— der Rest läuft in den Sparer-Pauschbetrag. Die *vollständige* Summe erhöht demgegenüber die
+Kostenbasis und erspart bei der Entnahme rund 22.000 € Abgeltungsteuer. Wird der
+Sparer-Pauschbetrag auf null gesetzt, so dreht das Vorzeichen. Der Balken „Wegfall der
+Vorabpauschale" im Wasserfall ist daher negativ; es handelt sich nicht um einen Vorzeichenfehler.
+
+**Der Arbeitgeberzuschuss sättigt — und zwar früher als angenommen.** Im spitz berechneten
+Zuschussmodus (§ 1a Abs. 1a BetrAVG dem Wortlaut nach) wächst der Zuschuss lediglich bis zur
+tatsächlichen Ersparnis des Arbeitgebers an Sozialversicherungsbeiträgen. Bei 75.000 € Gehalt
+und 300 €/Monat liegt das Entgelt bereits **oberhalb** der Beitragsbemessungsgrenze der
+Krankenversicherung von 69.750 €: der Arbeitgeber erspart dort überhaupt keine Beiträge zur
+Kranken- und Pflegeversicherung, sondern lediglich zur Renten- und Arbeitslosenversicherung auf
+3.600 €, mithin 381,60 € im Jahr — dies entspricht 10,6 vom Hundert des umgewandelten Betrags.
+Der gesetzliche Mindestzuschuss von 15 vom Hundert ist damit bereits der gedeckelte Wert; **jede
+Erhöhung des Reglers bleibt wirkungslos.** Die Anwendung weist dies nunmehr unmittelbar am
+Regler aus.
+
+Die im übergeordneten README genannte Gewinnschwelle von ~26,7 vom Hundert ist folglich im
+spitzen Modus nicht erreichbar, sondern ausschließlich in den Modi „voller Beitrag" bzw.
+„sv-freier Anteil". Die Sensitivitätskurve weist die Sättigung als waagerechten Ast aus.
---
-## 10. Das Aussehen: Windows 3.1 / NT 3.5
+## § 10 Das Erscheinungsbild: Windows 3.1 / NT 3.5
-Silber `#C0C0C0` auf Petrol `#008080`, Navy-Titelleisten, harte Ein-Pixel-Kanten, alles aus der
-16-Farben-VGA-Palette. **Es gibt nur ein Farbschema** — `prefers-color-scheme` ist entfernt,
-eine Dunkelvariante gäbe es hier nicht zu skinnen.
+Silber `#C0C0C0` auf Petrol `#008080`, Titelleisten in Navy, harte Ein-Pixel-Kanten, alles aus
+der 16-Farben-VGA-Palette. **Es besteht ausschließlich ein Farbschema** — `prefers-color-scheme`
+ist entfernt worden; eine Dunkelvariante wäre hier nicht zu gestalten.
-Drei Kantenformen tragen die ganze Oberfläche:
+Drei Kantenformen tragen die gesamte Bedienoberfläche:
-| Form | Aufbau | Wo |
+| Form | Aufbau | Verwendung |
|---|---|---|
| erhaben (3.1) | `1px solid #000` + `inset 1px 1px 0 #FFF` + `inset -1px -1px 0 #808080` | Schaltflächen |
| erhaben (95) | zusätzlich `border-color:#DFDFDF #000 #000 #DFDFDF` | Fenster, Kacheln |
| versenkt | `border-color:#808080 #FFF #FFF #808080` + `inset 1px 1px 0 #000` | Felder, Zeichenfläche |
-Gedrückte Umschalter bekommen zusätzlich das Rastermuster der eingerasteten Werkzeugleiste
+Gedrückte Umschalter erhalten ergänzend das Rastermuster der eingerasteten Werkzeugleiste
(`repeating-conic-gradient` mit 2 px Kachel). Das Fokusrechteck ist das originale gepunktete —
-zugleich das barrierefreiste, was Windows je hatte.
+zugleich dasjenige, welches Windows je an Barrierefreiheit aufzuweisen hatte.
-### Was bewusst aus Windows 95 / NT 4 kommt
+### Was bewusst aus Windows 95 / NT 4 übernommen worden ist
-Windows 3.1 kannte diese Steuerelemente schlicht nicht, und ohne sie wäre die App schlechter:
+Windows 3.1 kannte diese Steuerelemente schlicht nicht, und ohne sie wäre die Anwendung
+schlechter:
-- **Trackbar** — der Schieberegler ist ein Win95-Common-Control. Unter 3.1 hätte man Zahlen
- eintippen müssen; die unmittelbare Rückkopplung wäre dahin.
-- **Registerkarten** — 3.1 löste Mehrseitigkeit über eigene Dialoge. Vier Diagramme in vier
- Fenstern wären hier klar schlechter.
-- **Versenkter Rahmen** (`WS_EX_CLIENTEDGE`) statt 3.1s einfachem schwarzen Rahmen um
+- **Trackbar** — der Schieberegler ist ein Win95-Common-Control. Unter 3.1 wären Zahlen
+ einzutippen gewesen; die unmittelbare Rückkopplung wäre mithin entfallen.
+- **Registerkarten** — 3.1 löste die Mehrseitigkeit über eigene Dialoge. Vier Diagramme in vier
+ Fenstern wären hier eindeutig schlechter.
+- **Versenkter Rahmen** (`WS_EX_CLIENTEDGE`) anstelle des einfachen schwarzen Rahmens von 3.1 um
Eingabefelder — liest sich deutlich besser.
### Was 3.1 besser konnte
-Die Segmentschalter sind zu **echten Optionsfeldgruppen** geworden. Das ist die authentische
-Entsprechung für eine Auswahl unter wenigen Alternativen, es ist das semantisch richtige
-Element, und die Pfeiltastennavigation der Radiogruppe gibt es geschenkt.
+Die Segmentschalter sind zu **echten Optionsfeldgruppen** geworden. Dies ist die authentische
+Entsprechung für eine Auswahl unter wenigen Alternativen, es ist das semantisch zutreffende
+Element, und die Pfeiltastennavigation der Radiogruppe tritt ohne weiteres Zutun hinzu.
-### Fenster, die wirklich Fenster sind
+### Fenster, welche tatsächlich Fenster sind
-Jeder Abschnitt hat eine Titelleiste mit Systemmenü-Kasten und Minimieren-Knopf. Der Knopf ist
-kein Zierrat: er klappt den Inhalt tatsächlich ein, Doppelklick auf die Titelleiste ebenso, und
-der Zustand wird gespeichert. Auf dem Telefon ist das nützlich — man klappt „Ihre Angaben“ zu
-und hat das Diagramm ganzseitig.
+Jeder Abschnitt verfügt über eine Titelleiste nebst Systemmenü-Kasten und Minimieren-Schaltfläche.
+Die Schaltfläche ist kein Zierrat: sie klappt den Inhalt tatsächlich ein, ein Doppelklick auf die
+Titelleiste gleichermaßen, und der Zustand wird vorgehalten. Auf dem Telefon ist dies von Nutzen
+— „Ihre Angaben" wird zugeklappt, und das Diagramm steht ganzseitig zur Verfügung.
-Grau ist unter Windows die Farbe des *Deaktivierten*. Lesbarer Text bleibt deshalb durchgehend
-schwarz und wird über Größe und Kursivstellung abgestuft, nicht über Aufhellung. Das ist
-zugleich authentisch und der bessere Kontrast: Schwarz auf `#C0C0C0` sind 9,9 : 1.
+Grau ist unter Windows die Farbe des *Deaktivierten*. Lesbarer Text verbleibt daher durchgängig
+schwarz und wird über Größe und Kursivstellung abgestuft, nicht über Aufhellung. Dies ist
+zugleich authentisch und der bessere Kontrast: Schwarz auf `#C0C0C0` ergibt 9,9 : 1.
-## 11. Bewusst nicht gebaut
+## § 11 Bewusst nicht eingerichtet
-- **Onboarding-Assistent.** Elf Kernfelder tragen keinen Wizard; er verstellte nur den Blick
- auf die Kopplung der Größen.
-- **Animierte Zahlenübergänge.** Sie lenken von genau dem ab, was man vergleichen soll.
+- **Einführungsassistent.** Elf Kernfelder tragen keinen Assistenten; er verstellte lediglich den
+ Blick auf die Kopplung der Größen.
+- **Animierte Zahlenübergänge.** Sie lenken von genau demjenigen ab, was verglichen werden soll.
- **Aufgeräumte Rechengrößen.** Die 45 gesetzlichen Werte stehen bewusst hinten und bewusst
- vollständig. Wer die Modellannahme mit 70 % Vertrauensgrad nicht teilt, soll sie ändern
- können, ohne den Quelltext anzufassen.
+ vollständig. Wer die Modellannahme mit 70 vom Hundert Vertrauensgrad nicht teilt, soll sie
+ ändern können, ohne den Quelltext anfassen zu müssen.
---
-*Keine Steuer- oder Anlageberatung. Ein Modell ist kein Vertrag.*
+*Es wird abschließend darauf hingewiesen, dass weder eine Steuer- noch eine Anlageberatung
+erbracht wird. Ein Modell ist kein Vertrag.*
diff --git a/app/i18n.akk-x-ob.js b/app/i18n.akk-x-ob.js
index 512ed9b..be82919 100644
--- a/app/i18n.akk-x-ob.js
+++ b/app/i18n.akk-x-ob.js
@@ -289,7 +289,7 @@ window.I18N_AKK_X_OB = {
'ui.lang.partialNote': '𒇷𒊭𒉡𒌝 𒀭𒉡𒌝 <b>𒍣𒀉𒋫𒄠 𒅖𒋼𒂗</b> 𒈾𒁄𒆪𒌓: 𒋗𒈠𒌈 𒊭 𒁾𒁉𒅎, 𒋗𒈠𒌈 𒊭 𒈪𒈾𒋾𒅎, 𒊑𒊭𒌈 𒊭 𒁾𒉺𒋾𒅎 𒌋 𒋗𒈠𒌈 𒊭 𒉺𒀠𒄀𒅎 𒄿𒁀𒀸𒅆. 𒀀𒉿𒌈 𒊭 𒍣𒅎𒁕𒋾𒅎 𒊏𒀊𒊭𒌈 — 𒀀𒉿𒌈 𒊭 <span class="qm" style="cursor:default">?</span>, 𒀀𒉿𒌈 𒂵𒈪𒅕𒌈, 𒌋 𒉺𒁕𒀭 𒈪𒈾𒋾𒅎 — 𒄿𒈾 𒇷𒊭𒉏 𒊭 𒈠𒋾𒅎 𒅖𒋼𒂗 𒄿𒁀𒀸𒅆𒀀. 𒋗𒈠𒌈 𒊭 𒍣𒅎𒁕𒋾𒅎 (BetrAVG, EStG, SGB V) 𒄿𒈾 𒆗 𒇷𒊭𒉌 𒄿𒈾 𒇷𒊭𒉏 𒊭 𒈠𒋾𒅎 𒊭𒀜𒊏: 𒄿𒈾 𒍣𒅎𒁕𒋾𒅎 𒀭𒉌𒌈𒈠 𒄿𒁀𒀸𒅆.',
'sb.up': '𒀀𒈾 𒂊𒇷𒅖 𒀀𒈾 𒀀𒉿𒋾𒅎 𒂵𒈪𒅕𒋾𒅎',
'footer.1': '<b>𒆷 𒀀𒉿𒀜 𒈪𒅅𒋛𒅎, 𒆷 𒀀𒉿𒀜 𒊕𒁺.</b> 𒁾𒁍𒌝 𒆷 𒊑𒅅𒋧 𒅆. 𒍣𒅎𒁕𒌈 𒊭 2026 𒀀𒈾 𒊕𒁺 𒂠𒋆 𒊭 𒅆𒁍𒋾𒅎 𒄿𒈾 𒀸𒊑 𒈠𒁺𒋾𒅎 𒆷 𒃵𒊏𒀜; 𒁲𒈾𒌈 𒊭 𒌅𒆰𒋾𒅎 𒈠𒁲𒋾𒅎 𒄿𒈾 "𒉺𒁕𒀭 𒈪𒈾𒋾𒅎 → 𒁕𒀭𒉡𒌈 𒊭 𒁲𒈾𒋾𒅎" 𒊭𒀜𒊏 𒌋 𒄿𒈾 𒀭𒉏 𒅔𒈾𒀝𒆠𒊏.',
- 'footer.2': '𒇷𒅁𒁉 𒈪𒈾𒋾𒅎 𒅖𒋼𒂗 𒀀𒈾 𒅖𒋼𒂗 𒅖𒌅 𒁾 <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> 𒇷𒆪𒌝 𒌋 𒀀𒈾 𒊭𒆷𒀸 𒈪𒀉𒄩𒊏𒋾𒅎 𒀀𒁲 𒍠 𒊭 𒄿𒇷𒅎 𒈠𒍣 (𒈾𒅗𒊒𒌝 𒊏𒁍𒌝 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': '𒇷𒅁𒁉 𒈪𒈾𒋾𒅎 𒅖𒋼𒂗 𒀀𒈾 𒅖𒋼𒂗 𒅖𒌅 𒁾 𒉺𒉏 𒇷𒆪𒌝 𒌋 𒀀𒈾 𒊭𒆷𒀸 𒈪𒀉𒄩𒊏𒋾𒅎 𒀀𒁲 𒍠 𒊭 𒄿𒇷𒅎 𒈠𒍣 (𒈾𒅗𒊒𒌝 𒊏𒁍𒌝 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': '𒇽-𒈦 𒊭 𒂍 𒅆𒅁𒊑𒅎 (𒈾𒅗𒊒𒌝 𒊭 𒀉)',
diff --git a/app/i18n.akk-x-ob.translit.js b/app/i18n.akk-x-ob.translit.js
index 2e9f6aa..db9ed94 100644
--- a/app/i18n.akk-x-ob.translit.js
+++ b/app/i18n.akk-x-ob.translit.js
@@ -281,7 +281,7 @@ window.I18N_AKK_X_OB = {
'ui.lang.partialNote': 'lišānum annûm <b>zittam ištēn</b> nabalkut: šumātum ša ṭuppim, šumātum ša minâtim, rēšātum ša ṭuppātim u šumātum ša palgim ibaššī. awâtum ša ṣimdatim rapšātum — awâtum ša <span class="qm" style="cursor:default">?</span>, awâtum gamirtum, u padān minâtim — ina lišānim ša mātim ištēn ibaššiā. šumātum ša ṣimdatim ([[BetrAVG, EStG, SGB V]]) ina kal lišānī ina lišānim ša mātim šaṭrā: ina ṣimdatim annītumma ibašši.',
'sb.up': 'ana elīš ana awâtim gamirtim',
'footer.1': '<b>lā awât miksim, lā awât {SAG.DU}.</b> ṭuppum lā riksum šī. ṣimdatum ša 2026 ana {SAG.DU} eššim ša šībūtim ina ašrī mādûtim lā gamrat; dīnātum ša tukultim maṭītim ina "padān minâtim → dannūtum ša dīnātim" šaṭrā u ina annîm innakkirā.',
- 'footer.2': 'libbi minâtim ištēn ana ištēn ištu {DUB} <span class="pill">[[bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx]]</span> leqûm u ana šalāš mitharātim adi {ZAG} ša ilim maṣi (nakārum rabûm 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'libbi minâtim ištēn ana ištēn ištu {DUB} panîm leqûm u ana šalāš mitharātim adi {ZAG} ša ilim maṣi (nakārum rabûm 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': '{LU2}-{MASH} ša {E2} šiprim (nakārum ša {A2})',
diff --git a/app/i18n.bar.js b/app/i18n.bar.js
index ad40f50..10d86a6 100644
--- a/app/i18n.bar.js
+++ b/app/i18n.bar.js
@@ -434,7 +434,7 @@ window.I18N_BAR = {
'calc.sub': 'Fia oi, de’s nochvoizioang wuin.',
'share.sub': 'Eahnare Ogom liang ausschließlich in dem Browser (<kbd>localStorage</kbd>). Nix werd iwatrong, es gibt koan Server und koan Tracker.',
'footer.1': '<b>Koa Steia- oda Aunlogeberodung.</b> A Modej is koa Vatrog. D’Rechtslogn 2026 zua reformiatn privatn Oitersvuasorg is a mehrare Stelln no ned endgültig gklärt; de Aunahma mit’m niadrigstn Vatraunsgrad steng unta „Rechawég → Belastborkeit vo de Aunahma“ und san dert aa zum ändan.',
- 'footer.2': 'Rechnakern oans zu oans iwatrong aus’m Excel-Modej <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> und gengan drei Testfäj auf Maschinngenauigkeit prüaft (grössde relative Obweichung 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Rechnakern oans zu oans iwatrong aus’m ursprünglichn Excel-Modej und gengan drei Testfäj auf Maschinngenauigkeit prüaft (grössde relative Obweichung 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Konstante Monatszoihung iwa de ganze Auszoihungsphas mit demsejbm Weat, in heitiga Kaffkraft. De oazige Zoi, de si direkt mit Eahnam heitign Nettoeikomma vagleichn lasst.',
'metric.ertrag.desc': 'Wos de Mégglichkeit in heitiga Kaffkraft iwa an eignan Eisotz aussi obwirft: Barweat vo olle Netto-Leistunga minus Barweat vom Nettoaufwand.',
'metric.irr.desc': 'Renditn auf an tatsächlich eigsetztn Nettobetrog, nominal. Direkt vagleichboar mit da eigstejtn Bruttorenditn vom ETF — da Untaschied is gnau des, wos Fördarung und Obgom zsamm kostn oda bringan.',
diff --git a/app/i18n.de-x-amt.js b/app/i18n.de-x-amt.js
index 5fbf315..5f12dfe 100644
--- a/app/i18n.de-x-amt.js
+++ b/app/i18n.de-x-amt.js
@@ -243,7 +243,7 @@ window.I18N_DE_X_AMT = {
'ui.lang.partialNote': 'Diese Sprachfassung ist <b>teilweise übersetzt</b>: Oberfläche, Feldbezeichnungen, Tabellenüberschriften sowie Diagrammlegenden liegen in übersetzter Form vor. Die ausführlichen rechtlichen Erläuterungen — die Texte hinter dem Zeichen <span class="qm" style="cursor:default">?</span> an den Eingabefeldern, das abschließende Ergebnis sowie die Darstellung des Rechenwegs — erscheinen in deutscher Sprache. Die Rechtsgrundlagen (BetrAVG, EStG, SGB V) liegen unabhängig von der gewählten Sprachfassung ausschließlich in deutscher Sprache vor.',
'sb.up': 'Zurück zum Ergebnis (Seitenanfang)',
'footer.1': '<b>Es wird ausdrücklich darauf hingewiesen, dass mit der vorliegenden Anwendung weder eine steuerliche noch eine anlagebezogene Beratung im Sinne der einschlägigen berufsrechtlichen Vorschriften erbracht wird.</b> Ein Berechnungsmodell vermag eine auf den Einzelfall bezogene Beratung nicht zu ersetzen; ein Rechtsanspruch auf Richtigkeit der ausgewiesenen Beträge wird nicht begründet. Es wird ferner darauf hingewiesen, dass die Rechtslage 2026 betreffend die reformierte private Altersvorsorge in mehreren Punkten noch nicht abschließend geklärt ist. Diejenigen Annahmen, denen der geringste Vertrauensgrad beizumessen ist, sind unter „Rechenweg → Belastbarkeit der Annahmen" gesondert ausgewiesen und können dort im Einzelnen angepasst werden.',
- 'footer.2': 'Der Rechenkern ist unverändert und ohne inhaltliche Abweichung aus dem Berechnungsmodell <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> übernommen worden. Eine Überprüfung anhand dreier Testfälle hat ergeben, dass Übereinstimmung bis zur Maschinengenauigkeit besteht; die größte festgestellte relative Abweichung beträgt 1,3·10<sup>&minus;14</sup> und ist mithin als vernachlässigbar einzustufen.',
+ 'footer.2': 'Der Rechenkern ist unverändert und ohne inhaltliche Abweichung aus dem ursprünglichen, in Gestalt einer Tabellenkalkulation geführten Berechnungsmodell übernommen worden. Eine Überprüfung anhand dreier Testfälle hat ergeben, dass Übereinstimmung bis zur Maschinengenauigkeit besteht; die größte festgestellte relative Abweichung beträgt 1,3·10<sup>&minus;14</sup> und ist mithin als vernachlässigbar einzustufen.',
/* ---------------- Die drei Gestaltungsvarianten ---------------- */
'opt.bav.name': 'Betriebliche Altersversorgung im Wege der Entgeltumwandlung',
diff --git a/app/i18n.de-x-sales.js b/app/i18n.de-x-sales.js
index cee24fe..c64a1a3 100644
--- a/app/i18n.de-x-sales.js
+++ b/app/i18n.de-x-sales.js
@@ -247,7 +247,7 @@ window.I18N_DE_X_SALES = {
'ui.lang.partialNote': 'Diese Sprache ist <b>teilweise übersetzt</b>: Oberfläche, Feldnamen, Tabellenköpfe und Diagrammlegenden sind startklar. Die langen Erläuterungen — die <span class="qm" style="cursor:default">?</span>-Texte, das Fazit und der Rechenweg — zeigen wir noch auf Deutsch. Die Gesetzestexte (BetrAVG, EStG, SGB V) bleiben ohnehin überall deutsch, anders gibt es sie amtlich nicht.',
'sb.up': 'Rauf zu Ihrem Ergebnis',
'footer.1': '<b>Wichtig und ehrlich: keine Steuer- oder Anlageberatung.</b> So gut unser Rechner ist — das persönliche Gespräch ersetzt er nicht, und das wollen wir auch gar nicht behaupten. Die Rechtslage 2026 zur reformierten privaten Altersvorsorge ist an einigen Stellen noch offen; wir verstecken das nicht, sondern legen die unsichersten Annahmen unter „Rechenweg → Belastbarkeit der Annahmen" komplett offen — und Sie dürfen jede einzelne davon selbst nachjustieren. So viel Transparenz bekommen Sie sonst nirgends!',
- 'footer.2': 'Unser Rechenkern? Eins zu eins aus dem geprüften Excel-Modell <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> übernommen und an drei Testfällen bis auf Maschinengenauigkeit bestätigt — größte Abweichung 1,3·10<sup>&minus;14</sup>. Das ist die vierzehnte Nachkommastelle. Genauer geht es auf diesem Planeten schlicht nicht. Vergleichen Sie das ruhig mit dem, was Ihnen sonst so vorgerechnet wird!',
+ 'footer.2': 'Unser Rechenkern? Eins zu eins aus dem geprüften ursprünglichen Excel-Modell übernommen und an drei Testfällen bis auf Maschinengenauigkeit bestätigt — größte Abweichung 1,3·10<sup>&minus;14</sup>. Das ist die vierzehnte Nachkommastelle. Genauer geht es auf diesem Planeten schlicht nicht. Vergleichen Sie das ruhig mit dem, was Ihnen sonst so vorgerechnet wird!',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': 'Ihre bAV per Entgeltumwandlung',
diff --git a/app/i18n.de.js b/app/i18n.de.js
index 3377778..fd61603 100644
--- a/app/i18n.de.js
+++ b/app/i18n.de.js
@@ -229,7 +229,7 @@ window.I18N_DE = {
'ui.lang.partialNote': 'Diese Sprache ist <b>teilweise übersetzt</b>: Oberfläche, Feldnamen, Tabellenköpfe und Diagrammlegenden liegen vor. Die langen juristischen Erläuterungen — die <span class="qm" style="cursor:default">?</span>-Texte an den Feldern, das Fazit und der Rechenweg — erscheinen auf Deutsch. Die Fundstellen (BetrAVG, EStG, SGB V) sind ohnehin in jeder Sprache deutsch: amtlich gibt es sie nur so.',
'sb.up': 'Nach oben zum Ergebnis',
'footer.1': '<b>Keine Steuer- oder Anlageberatung.</b> Ein Modell ist kein Vertrag. Die Rechtslage 2026 zur reformierten privaten Altersvorsorge ist an mehreren Stellen noch nicht abschließend geklärt; die Annahmen mit dem geringsten Vertrauensgrad stehen unter „Rechenweg → Belastbarkeit der Annahmen“ und sind dort auch änderbar.',
- 'footer.2': 'Rechenkern eins zu eins portiert aus dem Excel-Modell <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> und gegen drei Testfälle auf Maschinengenauigkeit geprüft (größte relative Abweichung 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Rechenkern eins zu eins portiert aus dem ursprünglichen Excel-Modell und gegen drei Testfälle auf Maschinengenauigkeit geprüft (größte relative Abweichung 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': 'bAV (Entgeltumwandlung)',
diff --git a/app/i18n.en.js b/app/i18n.en.js
index 12eb412..9631e63 100644
--- a/app/i18n.en.js
+++ b/app/i18n.en.js
@@ -228,7 +228,7 @@ window.I18N_EN = {
'ui.lang.partialNote': 'This language is <b>partially translated</b>: interface, field names, table headers and chart legends are in place. The long legal explanations — the <span class="qm" style="cursor:default">?</span> texts on the fields, the verdict and the calculation — appear in German. The statutory citations (BetrAVG, EStG, SGB V) are German in every language anyway: officially they exist in no other form.',
'sb.up': 'Back up to the result',
'footer.1': '<b>Not tax or investment advice.</b> A model is not a contract. The 2026 legal position on reformed private retirement provision is not settled in several respects; the assumptions with the lowest confidence are listed under „How it is calculated → Robustness of the assumptions“ and can be changed there.',
- 'footer.2': 'Calculation core ported one-to-one from the Excel model <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> and checked against three test cases to machine precision (largest relative deviation 1.3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Calculation core ported one-to-one from the original Excel model and checked against three test cases to machine precision (largest relative deviation 1.3·10<sup>&minus;14</sup>).',
/* ---------------- The three options ---------------- */
'opt.bav.name': 'Occupational pension (bAV, salary sacrifice)',
diff --git a/app/i18n.eo.js b/app/i18n.eo.js
index 0ec390c..cb2a196 100644
--- a/app/i18n.eo.js
+++ b/app/i18n.eo.js
@@ -435,7 +435,7 @@ window.I18N_EO = {
'calc.sub': 'Por ĉiuj, kiuj volas sekvi la kalkulon.',
'share.sub': 'Viaj indikoj troviĝas ekskluzive en ĉi tiu retumilo (<kbd>localStorage</kbd>). Nenio estas transdonata, ne ekzistas servilo nek spurilo.',
'footer.1': '<b>Neniu imposta aŭ investa konsilo.</b> Modelo ne estas kontrakto. La laŭleĝa stato 2026 pri la reformita privata pensiprovizo ne estas ĉie fine klarigita; la supozoj kun la plej malalta fidindeco staras sub „Kalkulvojo → Fidindeco de la supozoj“ kaj estas tie ankaŭ ŝanĝeblaj.',
- 'footer.2': 'Kalkula kerno unu-al-unu portita el la Excel-modelo <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> kaj kontrolita kontraŭ tri testkazoj ĝis maŝina precizeco (plej granda relativa devio 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Kalkula kerno unu-al-unu portita el la origina Excel-modelo kaj kontrolita kontraŭ tri testkazoj ĝis maŝina precizeco (plej granda relativa devio 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Konstanta monata pago tra la tuta elpagofazo kun la sama valoro, en hodiaŭa aĉetpovo. La sola nombro, kiu rekte kompareblas kun via hodiaŭa neta enspezo.',
'metric.ertrag.desc': 'Kion la eblo en hodiaŭa aĉetpovo rezultigas preter la propra investo: nuna valoro de ĉiuj netaj elpagoj minus nuna valoro de la neta elspezo.',
'metric.irr.desc': 'Rendimento sur la efektive investita neta sumo, nominala. Rekte komparebla kun la agordita kruda rendimento de la ETF — la diferenco estas ĝuste tio, kion subvencio kaj kotizoj kune kostas aŭ alportas.',
diff --git a/app/i18n.eu.js b/app/i18n.eu.js
index ea43e3d..aa5b376 100644
--- a/app/i18n.eu.js
+++ b/app/i18n.eu.js
@@ -433,7 +433,7 @@ window.I18N_EU = {
'calc.sub': 'Kalkulua jarraitu nahi duten guztientzat.',
'share.sub': 'Zure datuak nabigatzaile honetan bakarrik daude (<kbd>localStorage</kbd>). Ez da ezer transmititzen, ez dago zerbitzaririk ez jarraipen-tresnarik.',
'footer.1': '<b>Ez da zerga- edo inbertsio-aholkularitza.</b> Eredu bat ez da kontratu bat. Diruz lagundutako pentsio pribatu erreformatuari buruzko 2026ko egoera juridikoa ez dago puntu batzuetan behin betiko argituta; konfiantza-maila baxuena duten hipotesiak «Kalkulu-bidea → Hipotesien sendotasuna» azpian daude, eta han alda daitezke.',
- 'footer.2': 'Kalkulu-nukleoa bat-batean <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> Excel ereduetik transferitu da, eta hiru test-kasuren aurrean egiaztatu da makina-zehaztasunarekin (desbideratze erlatibo handiena 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Kalkulu-nukleoa bat-batean jatorrizko Excel ereduetik transferitu da, eta hiru test-kasuren aurrean egiaztatu da makina-zehaztasunarekin (desbideratze erlatibo handiena 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Ordainketa-fase osoan zehar balio berarekin ordaintzen den hileko prestazio konstantea, gaurko erosteko ahalmenean. Zure gaurko diru-sarrera garbiarekin zuzenean konpara daitekeen zenbaki bakarra.',
'metric.ertrag.desc': 'Aukerak gaurko erosteko ahalmenean, ekarpen propiotik haratago, zer ematen duen: ordainketa garbi guztien gaurko balioa ken gastu garbiaren gaurko balioa.',
'metric.irr.desc': 'Benetan inbertitutako zenbateko garbiaren errendimendua, nominala. ETFaren ezarritako errendimendu gordinarekin zuzenean konparagarria — diferentzia laguntzek eta kenkariek batera zenbat kostatzen edo ematen duten da, hain zuzen.',
diff --git a/app/i18n.fr.js b/app/i18n.fr.js
index 3b042ff..989cefc 100644
--- a/app/i18n.fr.js
+++ b/app/i18n.fr.js
@@ -234,7 +234,7 @@ window.I18N_FR = {
'ui.lang.partialNote': 'Cette langue est <b>traduite en partie</b> : interface, noms de champs, en-têtes de tableaux et légendes de graphiques sont là. Les longues explications juridiques — les textes <span class="qm" style="cursor:default">?</span> des champs, la conclusion et le détail du calcul — s’affichent en allemand. Les références légales (BetrAVG, EStG, SGB V) restent allemandes dans toutes les langues : officiellement, elles n’existent pas autrement.',
'sb.up': 'Remonter au résultat',
'footer.1': '<b>Ni conseil fiscal ni conseil en placement.</b> Un modèle n’est pas un contrat. L’état du droit 2026 sur l’épargne retraite privée réformée n’est pas définitivement fixé sur plusieurs points ; les hypothèses les moins sûres figurent sous « Détail du calcul → Robustesse des hypothèses » et y sont modifiables.',
- 'footer.2': 'Moteur de calcul porté à l’identique depuis le modèle Excel <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> et vérifié à la précision machine sur trois cas de test (écart relatif maximal 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Moteur de calcul porté à l’identique depuis le modèle Excel d’origine et vérifié à la précision machine sur trois cas de test (écart relatif maximal 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Les trois options ---------------- */
'opt.bav.name': 'bAV (abandon de salaire)',
diff --git a/app/i18n.gmh.js b/app/i18n.gmh.js
index 5607a2d..a8cd51a 100644
--- a/app/i18n.gmh.js
+++ b/app/i18n.gmh.js
@@ -479,7 +479,7 @@ window.I18N_GMH = {
'calc.sub': 'Allen, die disem wege volgen wellen.',
'share.sub': 'Iuwer wort sint aleine in disem werke (<kbd>localStorage</kbd>). Niht wirt gesendet, enist deheiniu maht noch spehære.',
'footer.1': '<b>Enist niht rehtes noch schatzes rât.</b> Daz bilde enist niht triuwe. Rehtes stant 2026 nâch der niuwe der sînen sorge ist in manegen steten noch niht geendet; dise gesetzede mit minnestem getriuwe stânt under „Wec der rechenunge → Vestenunge der wænungen“ unde mügen dâ gewendet werden.',
- 'footer.2': 'Der rechenunge kerne ist aleine von dem Excel-bilde <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> abegeleitet unde wider drî fresen nâch des sumeres rihte gekoret (meiste gelîche underscheit 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Der rechenunge kerne ist aleine von dem êrsten Excel-bilde abegeleitet unde wider drî fresen nâch des sumeres rihte gekoret (meiste gelîche underscheit 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Gelîchiu mânôtlîchiu gâbe al gülte-zît mit dem selben werte, nâch hiutigem werde. Ein mâze, daz man widermezzen mac mit iuwerem lûteren schatze nû.',
'metric.ertrag.desc': 'Daz, sô diz nâch hiutigem werde über iuwer eigen werc tuot: der wert nû aller lûteren gâben âne den wert nû der lûteren nütze.',
'metric.irr.desc': 'Wuocher an dem wærlîche gelegeten lûteren schatze, nâch namen. Widermezzet mit dem gesetzeten allen wuochere des ETF — der underscheit ist der, daz gâbe unde gelt zesamene kosten oder gebent.',
diff --git a/app/i18n.goh.js b/app/i18n.goh.js
index 0125fd3..bd14f24 100644
--- a/app/i18n.goh.js
+++ b/app/i18n.goh.js
@@ -483,7 +483,7 @@ window.I18N_GOH = {
'calc.sub': 'Allen, die disemo wege folgen wellent.',
'share.sub': 'Iuweriu wort sint eino in disemo werke (<kbd>localStorage</kbd>). Niowiht wirdit gisant, ni ist iemer noh gisehan.',
'footer.1': '<b>Ni ist ewa- odo scazes rat.</b> Daz bilidi ist ni triuwa. Rehtes stant 2026 zi der niuwera sinera sorgu ist in manegen steten noh ni giendot; disiu gisezzida mit minnistero gitruwidu stant untar „Weg der rehhanungu → Fastnissi dero wanungo“ inti mugun dar gikeret werdan.',
- 'footer.2': 'Der rehhanungu kerno ist eino fona demo Excel-bilide <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> abageleitit inti wider dri fresa nah des sumeres rihti gikoron (meisto gilih untarscheit 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Der rehhanungu kerno ist eino fona demo êriston Excel-bilide abageleitit inti wider dri fresa nah des sumeres rihti gikoron (meisto gilih untarscheit 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Gilihiu manodlihiu gift al gelte-zit mit demo selben werde, nah hiutigemo werde. Ein mez, daz man widarmezzon mag mit iuweremo lutaren scazze nu.',
'metric.ertrag.desc': 'Daz, so disiu wisa nah hiutigemo werde ubar iuwer eigan werc tuot: der wert nu allero lutarero gifto ana den wert nu der lutaren nuzzida.',
'metric.irr.desc': 'Wuohhar an demo warlihho gilegiten lutaren scazze, nah namen. Widarmezzot mit demo gisezziten allen wuohhare des ETF — der untarscheit ist der, daz gift inti gelt saman koston odo geband.',
diff --git a/app/i18n.got.js b/app/i18n.got.js
index b2930b8..07052d1 100644
--- a/app/i18n.got.js
+++ b/app/i18n.got.js
@@ -489,7 +489,7 @@ window.I18N_GOT = {
'calc.sub': 'Allaim izei wiljand þamma wiga afargaggan.',
'share.sub': 'Þeina waurda sind ains in þamma waurstwa (<kbd>localStorage</kbd>). Ni waiht wairþiþ sandiþ, nist waldufni ni spaikulatjands.',
'footer.1': '<b>Ni ist gildis aiþþau faihu ragineins.</b> Frisahts nist triggwa. Witodis stojan 2026 bi niujein seina kararis in managam staþam ni ist andjis skeirjada; þo anahahona miþ minnistin trauainshugja standand undar „Wiga þizos rathjons → Swinþein þizo anahahano“ jah mahtjand jainar wandjan.',
- 'footer.2': 'Sa rathjons kern ains du ainamma ustauhans us Excel-frisahtja <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> jah wiþra þrins fraisteinins bi asanjis raihtein gakannids (maists galeiks missaleikeins 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Sa rathjons kern ains du ainamma ustauhans us þamma frumistin Excel-frisahtja jah wiþra þrins fraisteinins bi asanjis raihtein gakannids (maists galeiks missaleikeins 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Samaleiks menoþis giba all gibos mel miþ þamma samin waírþa, bi himma daga waírþa. Þata aina rathjo, þatei mag galeikan miþ þeinamma hrainjamma faihau nu.',
'metric.ertrag.desc': 'Þatei sa wilja bi himma daga waírþa ufar eiginana anafilh gataujiþ: waírþ nu allaizo hrainjaizo gibo inuh waírþ nu þis hrainis wilwis.',
'metric.irr.desc': 'Wokrs ana þamma sunjeino galagidin hrainjamma faihau, bi namin. Galeiks miþ þamma gasatidin allamma wokra þis ETF — so missaleikeins ist bi sunjai þatei giba jah gibandeis samana kostjand aiþþau giband.',
diff --git a/app/i18n.grc.js b/app/i18n.grc.js
index 275a51a..4dd9045 100644
--- a/app/i18n.grc.js
+++ b/app/i18n.grc.js
@@ -466,7 +466,7 @@ window.I18N_GRC = {
'calc.sub': 'Πᾶσι τοῖς τήνδε τὴν ὁδὸν βουλομένοις ἀκολουθεῖν.',
'share.sub': 'Τὰ σὰ δεδομένα μόνον ἐν τούτῳ τῷ προγράμματι κεῖται (<kbd>localStorage</kbd>). Οὐδὲν πέμπεται, οὐδεμία ἀρχὴ οὐδὲ κατάσκοπος.',
'footer.1': '<b>Οὔτε νόμιμος οὔτε χρηματιστικὴ συμβουλή ἐστιν.</b> Τὸ παράδειγμα οὐκ ἔστι πίστις. Ἡ νόμιμος κατάστασις τοῦ 2026 περὶ τῆς νεωστὶ ὡρισμένης θεραπείας ἐν πολλοῖς τόποις οὔπω τετέλεσται· αὗται αἱ ὑποθέσεις τῆς ἐλαχίστης πίστεως ὑπὸ τῇ «Ὁδῷ τοῦ λογισμοῦ → Βεβαιότητι τῶν ὑποθέσεων» κεῖνται καὶ ἐκεῖ μεταβάλλεσθαι δύνανται.',
- 'footer.2': 'Ὁ πυρὴν τοῦ λογισμοῦ μόνον ἐκ τοῦ Excel-παραδείγματος <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> εἴληπται καὶ πρὸς τρεῖς πείρας κατὰ τὴν ὀρθότητα τοῦ ἀθροίσματος ἐξητάσθη (μεγίστη διαφορὰ 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Ὁ πυρὴν τοῦ λογισμοῦ μόνον ἐκ τοῦ πρώτου Excel-παραδείγματος εἴληπται καὶ πρὸς τρεῖς πείρας κατὰ τὴν ὀρθότητα τοῦ ἀθροίσματος ἐξητάσθη (μεγίστη διαφορὰ 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Ἴση μηνιαία ἀπόδοσις πάντα τὸν χρόνον τῆς ἀποδόσεως τῇ αὐτῇ ἀξίᾳ, κατὰ τὴν νῦν ἀξίαν. Λόγος, ὃν τῷ καθαρῷ σου ἀργυρίῳ νῦν συγκρίνειν δύνασαι.',
'metric.ertrag.desc': 'Ὃ ἡ αἵρεσις κατὰ τὴν νῦν ἀξίαν ὑπὲρ τὴν ἰδίαν σου ἐργασίαν ποιεῖ· ἡ ἀξία νῦν πασῶν τῶν καθαρῶν ἀποδόσεων ἄνευ τῆς ἀξίας νῦν τῆς καθαρᾶς χρήσεως.',
'metric.irr.desc': 'Τόκος ἐπὶ τὸ ἀληθῶς τεθὲν καθαρὸν ἀργύριον, κατ᾽ ὄνομα. Συγκρίνεται σὺν τῷ ὡρισμένῳ τόκῳ τῷ ὅλῳ τοῦ ETF — ἡ διαφορὰ ἐστὶν ὅτι δόσις καὶ εἰσφορὰ ἅμα δαπανῶσιν ἢ δίδονται.',
diff --git a/app/i18n.ine-x-proto.js b/app/i18n.ine-x-proto.js
index 35ea823..cf043c7 100644
--- a/app/i18n.ine-x-proto.js
+++ b/app/i18n.ine-x-proto.js
@@ -279,7 +279,7 @@ window.I18N_INE_X_PROTO = {
'ui.lang.partialNote': '*h₁éh₂ dn̥ǵʰwéh₂s <b>déh₂mo-wr̥téh₂</b> h₁ésti: h₃ókʷ-wékʷā, réh₁ti-nómn̥h₂, plh₂téh₂s-stedʰmn̥h₂, ǵʰérbʰmn̥-wékʷā h₁sónti. *dʰéh₁mn̥-wékʷā dl̥h₃ǵʰā — <span class="qm" style="cursor:default">?</span>-wékʷā, lipóm, réh₁tyos pn̥tḗh₂s — dótskāi dn̥ǵʰwéh₂i h₁sónti. *dʰéh₁mn̥-nómn̥h₂ (BetrAVG, EStG, SGB V) h₂énti dn̥ǵʰwéh₂su dótskā h₁sónti: h₃rēǵs-dʰh₁tā tóri tāi h₁sónti.',
'sb.up': '*úperi h₁éy, lipóm h₂éd',
'footer.1': '*<b>né teutodéh₃ti-wékʷos, né pék̑u-wékʷos.</b> *nóh₃mn̥ né dʰh₁tóm h₁ésti. *2026-osyo dʰéh₁mn̥ néwoi swé-ǵr̥h₂tupék̑wei so’i-loi né sm̥ dʰh₁tóm h₁ésti; ménesa mính₂u-ménesa „réh₁tyos pn̥tḗh₂s → ménesōm tólh₂mn̥“ h₁sónti, h₂éltromn̥ā-kʷe.',
- 'footer.2': '*réh₁tyos k̑ērd h₁óynom h₁óynom lipóm <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> h₂epó bʰr̥tóm, tri-mn̥ mn̥dʰh₁tói dr̥k̑tóm (méǵh₂ h₂éltromn̥ 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': '*réh₁tyos k̑ērd h₁óynom h₁óynom lipóm h₂epó bʰr̥tóm, tri-mn̥ mn̥dʰh₁tói dr̥k̑tóm (méǵh₂ h₂éltromn̥ 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': '*wérǵoǵr̥h₂tupék̑u (pék̑u-h₂éltromn̥)',
diff --git a/app/i18n.ja.js b/app/i18n.ja.js
index 746ed0b..0bc2820 100644
--- a/app/i18n.ja.js
+++ b/app/i18n.ja.js
@@ -229,7 +229,7 @@ window.I18N_JA = {
'ui.lang.partialNote': 'この言語は<b>部分訳</b>です。画面表示・項目名・表の見出し・グラフの凡例は訳してあります。長い法律解説——各項目の <span class="qm" style="cursor:default">?</span> の文、判定、計算過程——はドイツ語で表示されます。条文の出典(BetrAVG、EStG、SGB V)はどの言語でもドイツ語のままです。公式にはドイツ語版しか存在しないためです。',
'sb.up': '結果に戻る',
'footer.1': '<b>税務・投資の助言ではありません。</b>モデルは契約ではありません。改革後の私的老後保障をめぐる2026年の法状況にはまだ確定していない点がいくつもあります。信頼度のもっとも低い仮定は「計算の内訳 → 仮定の頑健性」にまとめてあり、そこで変更もできます。',
- 'footer.2': '計算部分はExcelモデル <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> をそのまま移植し、3件のテストケースで機械精度まで一致を確認しています(相対誤差の最大は 1.3·10<sup>&minus;14</sup>)。',
+ 'footer.2': '計算部分は元のExcelモデルをそのまま移植し、3件のテストケースで機械精度まで一致を確認しています(相対誤差の最大は 1.3·10<sup>&minus;14</sup>)。',
/* ---------------- 三つの選択肢 ---------------- */
'opt.bav.name': '企業年金(賃金転換)',
diff --git a/app/i18n.jbo.js b/app/i18n.jbo.js
index 7f3b06a..b2e9543 100644
--- a/app/i18n.jbo.js
+++ b/app/i18n.jbo.js
@@ -262,7 +262,7 @@ window.I18N_JBO = {
'ui.lang.partialNote': 'ti bangu cu <b>po\'o pagbu se fanva</b>: lo samtci selfla .e lo se punji cmene .e lo tanbo stedu .e lo pixra ciksi cu zvati .i ku\'i lo clani flalu ciksi — lo <span class="qm" style="cursor:default">?</span> lisri, lo se jalge, lo lanli pluta — cu se cusku bau la .dotco. .i lo flalu judri (BetrAVG, EStG, SGB V) cu dotco bau ro bangu: lo se turni versio cu po\'o zvati bau la .dotco.',
'sb.up': 'ko klama ga\'u lo se jalge',
'footer.1': '<b>ti na flalu ja sorcu stidi.</b> lo ciste na se javni .i lo 2026 flalu be lo cnino sivni gunsisti sorcu cu na mulno se jdice vi so\'i da .i lo sruma poi mleca la\'u se xusra cu zvati lo "lanli pluta → lo tsali be lo sruma" gi\'e ka\'e se galfi vi ti',
- 'footer.2': 'lo lanli midju cu se fukpi lo tanbo ciste <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> gi\'e se cipra ci lo mupli co\'u lo minji preciso (lo zmadu parbi frica cu 1,3·10<sup>&minus;14</sup>)',
+ 'footer.2': 'lo lanli midju cu se fukpi lo tanbo ciste gi\'e se cipra ci lo mupli co\'u lo minji preciso (lo zmadu parbi frica cu 1,3·10<sup>&minus;14</sup>)',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': 'lo gunka gunsisti sorcu (galfi lo sumji jdini)',
diff --git a/app/i18n.la.js b/app/i18n.la.js
index d4b0f64..ffb1327 100644
--- a/app/i18n.la.js
+++ b/app/i18n.la.js
@@ -228,7 +228,7 @@ window.I18N_LA = {
'ui.lang.partialNote': 'Haec lingua <b>ex parte conversa</b> est: facies, nomina camporum, capita tabularum, indices diagrammatum adsunt. Longae explicationes iuridicae — textus <span class="qm" style="cursor:default">?</span> ad campos, iudicium, ratio computandi — Germanice apparent. Locorum citationes (BetrAVG, EStG, SGB V) in omni lingua Germanicae manent: publice aliter non exstant.',
'sb.up': 'Sursum ad exitum',
'footer.1': '<b>Non est consilium tributarium neque de collocando.</b> Exemplar non est contractus. Ius anni 2026 de provisione privata reformata pluribus locis nondum certum est; suppositiones minimae fidei sub „Ratio computandi → Firmitas suppositionum“ stant et ibi mutari possunt.',
- 'footer.2': 'Nucleus computandi ad litteram ex exemplari Excel <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> translatus et tribus casibus ad praecisionem machinae probatus (maxima discrepantia relativa 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Nucleus computandi ad litteram ex exemplari Excel pristino translatus et tribus casibus ad praecisionem machinae probatus (maxima discrepantia relativa 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Tres rationes ---------------- */
'opt.bav.name': 'Pensio operativa (conversio mercedis)',
diff --git a/app/i18n.nds.js b/app/i18n.nds.js
index ccc533f..1a803c0 100644
--- a/app/i18n.nds.js
+++ b/app/i18n.nds.js
@@ -433,7 +433,7 @@ window.I18N_NDS = {
'calc.sub': 'För all, de dat nakieken wüllt.',
'share.sub': 'Ehr Angaven liggt alleen in disse Browser (<kbd>localStorage</kbd>). Nix ward överdragen, dat gifft keen Server un keen Tracker.',
'footer.1': '<b>Keen Steuer- oder Anlaagberaden.</b> En Modell is keen Vertrag. De Rechtslaag 2026 to de reformeerte private Öllersvörsorg is an mehr Steden noch nich sluttich klaart; de Annahmen mit den lüttsten Vertroensgraad staht ünner „Reekweg → Belastborkeit vun de Annahmen“ un sünd dor ok to ännern.',
- 'footer.2': 'Reekkeern een to een överdragen ut dat Excel-Modell <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> un gegen dree Testfäll op Maschienngenauigkeit pröövt (grötte relative Afwieken 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Reekkeern een to een överdragen ut dat ursprüngliche Excel-Modell un gegen dree Testfäll op Maschienngenauigkeit pröövt (grötte relative Afwieken 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Kunstant Maandbetahlen över de hele Utbetahlensphaas mit den sülvigen Wart, in hüdige Koopkraft. De enkige Tall, de sik direkt mit Ehr hüdig Nettoinkamen verglieken lett.',
'metric.ertrag.desc': 'Wat de Mööglichkeit in hüdige Koopkraft över den egen Insatz erut afwirft: Barwart vun all Netto-Leisten minus Barwart vun de Nettoutgaav.',
'metric.irr.desc': 'Rendit op den wohrhaftig insetten Nettobetrag, nominaal. Direkt to verglieken mit de instellte Bruttorendit vun’n ETF — de Ünnerscheed is nau dat, wat Förderung un Afgaven tosamen kösten oder bringt.',
diff --git a/app/i18n.nl.js b/app/i18n.nl.js
index 2db754a..2ecfd93 100644
--- a/app/i18n.nl.js
+++ b/app/i18n.nl.js
@@ -231,7 +231,7 @@ window.I18N_NL = {
'ui.lang.partialNote': 'Deze taal is <b>gedeeltelijk vertaald</b>: interface, veldnamen, tabelkoppen en grafieklegenda’s zijn er. De lange juridische toelichtingen — de <span class="qm" style="cursor:default">?</span>-teksten bij de velden, de conclusie en de berekening — verschijnen in het Duits. De wetsverwijzingen (BetrAVG, EStG, SGB V) zijn in elke taal Duits: officieel bestaan ze niet anders.',
'sb.up': 'Omhoog naar de uitkomst',
'footer.1': '<b>Geen fiscaal of beleggingsadvies.</b> Een model is geen contract. De rechtstoestand 2026 rond het hervormde privépensioen is op meerdere punten nog niet definitief opgehelderd; de aannames met het laagste vertrouwen staan onder „Berekening → Houdbaarheid van de aannames“ en zijn daar ook aan te passen.',
- 'footer.2': 'Rekenkern één op één overgezet uit het Excel-model <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> en tegen drie testgevallen op machineprecisie getoetst (grootste relatieve afwijking 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Rekenkern één op één overgezet uit het oorspronkelijke Excel-model en tegen drie testgevallen op machineprecisie getoetst (grootste relatieve afwijking 1,3·10<sup>&minus;14</sup>).',
/* ---------------- De drie opties ---------------- */
'opt.bav.name': 'bAV (salarisuitruil)',
diff --git a/app/i18n.sa.js b/app/i18n.sa.js
index f02b9f8..43b986e 100644
--- a/app/i18n.sa.js
+++ b/app/i18n.sa.js
@@ -471,7 +471,7 @@ window.I18N_SA = {
'calc.sub': 'सर्वेभ्यः येषाम् इच्छा एतं मार्गम् अनुसर्तुम्।',
'share.sub': 'तव विवरणानि केवलम् अस्मिन् अनुप्रयोगे तिष्ठन्ति (<kbd>localStorage</kbd>). किमपि न प्रेष्यते, न कोऽपि सर्वरः न वा गुप्तचरः।',
'footer.1': '<b>न विधिपरामर्शः, न धनपरामर्शः।</b> प्रतिरूपं विश्वासयोग्यं न भवति। 2026-वर्षस्य नूतनस्वपरिचर्याविषये विधिस्थितिः बहुषु स्थानेषु अद्यापि अनिश्चिता; एताः न्यूनतमविश्वासयुक्ताः प्रकल्पनाः „गणनामार्गः → प्रकल्पनानां दृढता“ इत्यत्र तिष्ठन्ति, तत्र परिवर्तयितुं शक्यन्ते च।',
- 'footer.2': 'गणनाया मूलं केवलं Excel-प्रतिरूपात् <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> निष्कासितम्, त्रिभिः परीक्षाभिः योगस्य सत्यतायै परीक्षितं च (परमं भेदः 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'गणनाया मूलं केवलं मूल-Excel-प्रतिरूपात् निष्कासितम्, त्रिभिः परीक्षाभिः योगस्य सत्यतायै परीक्षितं च (परमं भेदः 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'सर्वं दानकालं तुल्यं मासिकं दानं तेनैव मूल्येन, अद्यतनक्रयशक्त्या। एकः अनुपातः, यं तव शुद्धधनेन इदानीं तुलयितुं शक्नोषि।',
'metric.ertrag.desc': 'यत् एतत् विकल्पः अद्यतनक्रयशक्त्या तव स्वकर्मणः उपरि करोति: सर्वेषां शुद्धदानानां वर्तमानमूल्यं शुद्धोपभोगशक्तेः वर्तमानमूल्यं विहाय।',
'metric.irr.desc': 'यथार्थतया स्थापितशुद्धधने वृद्धिः, नाममात्रेण। ETF-इत्यस्य निर्धारितया सम्पूर्णवृद्ध्या सह तुल्यते — भेदः तत्र यत् दानम् अंशदानं च सह व्ययन्ते वा दीयन्ते वा।',
diff --git a/app/i18n.tok.js b/app/i18n.tok.js
index 2f6395a..76896d0 100644
--- a/app/i18n.tok.js
+++ b/app/i18n.tok.js
@@ -269,7 +269,7 @@ window.I18N_TOK = {
'ui.lang.partialNote': 'toki ni li <b>kipisi taso</b>: nimi pi ilo, nimi pi ijo, lawa pi lipu nanpa, en nimi pi sitelen li lon. taso toki suli pi lipu lawa — sitelen <span class="qm" style="cursor:default">?</span>, toki pini, en nasin nanpa — li lon toki Tosi. nimi lipu (BetrAVG, EStG, SGB V) li awen lon toki Tosi lon toki ale: lipu lawa li lon nasin ni taso.',
'sb.up': 'o tawa sewi, tawa pini',
'footer.1': '<b>ni li sona ala pi mani lawa, li sona ala pi mani awen.</b> ilo nanpa li lipu ala. lipu lawa pi 2026 pi mani awen sin li ken ala pini lon ijo mute; nasin pi sona lili li lon "nasin nanpa → wawa pi nasin mi", li ken ante lon ni.',
- 'footer.2': 'nasin nanpa li kama tan lipu nanpa <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span>, li lukin lon nasin tu wan, li sama lon nasin pi ilo sona (ante suli li 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'nasin nanpa li kama tan lipu nanpa open, li lukin lon nasin tu wan, li sama lon nasin pi ilo sona (ante suli li 1,3·10<sup>&minus;14</sup>).',
/* ---------------- Die drei Optionen ---------------- */
'opt.bav.name': 'mani awen pali (pana tan mani ale)',
diff --git a/app/i18n.tr.js b/app/i18n.tr.js
index c04f77c..9f44096 100644
--- a/app/i18n.tr.js
+++ b/app/i18n.tr.js
@@ -433,7 +433,7 @@ window.I18N_TR = {
'calc.sub': 'Adım adım izlemek isteyenler için.',
'share.sub': 'Bilgileriniz yalnızca bu tarayıcıda tutulur (<kbd>localStorage</kbd>). Hiçbir şey aktarılmaz, ne sunucu ne de izleyici vardır.',
'footer.1': '<b>Vergi ya da yatırım danışmanlığı değildir.</b> Bir model, sözleşme değildir. Reforme edilmiş özel emeklilik birikimiyle ilgili 2026 hukuki durumu birçok noktada henüz kesin olarak açıklığa kavuşmamıştır; güven düzeyi en düşük varsayımlar „Hesap yolu → Varsayımların dayanıklılığı“ altında yer alır ve orada değiştirilebilir.',
- 'footer.2': 'Hesap çekirdeği birebir <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> Excel modelinden aktarılmış ve üç test durumuna karşı makine hassasiyetinde sınanmıştır (en büyük göreli sapma 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Hesap çekirdeği birebir özgün Excel modelinden aktarılmış ve üç test durumuna karşı makine hassasiyetinde sınanmıştır (en büyük göreli sapma 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Tüm ödeme evresi boyunca aynı değerle sabit aylık ödeme, bugünkü alım gücüyle. Bugünkü net gelirinizle doğrudan karşılaştırılabilen tek rakam.',
'metric.ertrag.desc': 'Seçeneğin bugünkü alım gücüyle kendi katkısının ötesinde ne getirdiği: tüm net ödemelerin bugünkü değeri eksi net yükün bugünkü değeri.',
'metric.irr.desc': 'Fiilen yatırılan net tutar üzerinden getiri, nominal. ETF’in ayarlanan brüt getirisiyle doğrudan karşılaştırılabilir — fark, teşvik ve kesintilerin birlikte ne kadar mal olduğu ya da kazandırdığıdır.',
diff --git a/app/i18n.uk.js b/app/i18n.uk.js
index acb6201..670476d 100644
--- a/app/i18n.uk.js
+++ b/app/i18n.uk.js
@@ -433,7 +433,7 @@ window.I18N_UK = {
'calc.sub': 'Для тих, хто хоче прослідкувати обчислення.',
'share.sub': 'Ваші дані зберігаються виключно в цьому браузері (<kbd>localStorage</kbd>). Нічого не передається, немає ні сервера, ні трекерів.',
'footer.1': '<b>Це не податкова чи інвестиційна консультація.</b> Модель — не договір. Правовий стан 2026 щодо реформованого приватного пенсійного забезпечення в кількох місцях ще не остаточно з’ясований; припущення з найнижчим рівнем довіри наведено під «Хід обчислення → Надійність припущень», і там їх можна змінити.',
- 'footer.2': 'Розрахункове ядро перенесено один в один з Excel-моделі <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> і перевірено на трьох тестових випадках з машинною точністю (найбільше відносне відхилення 1,3·10<sup>&minus;14</sup>).',
+ 'footer.2': 'Розрахункове ядро перенесено один в один з первісної Excel-моделі і перевірено на трьох тестових випадках з машинною точністю (найбільше відносне відхилення 1,3·10<sup>&minus;14</sup>).',
'metric.monat.desc': 'Стала місячна виплата протягом усієї фази виплат з однаковим значенням, у сьогоднішній купівельній спроможності. Єдине число, яке можна безпосередньо порівняти з вашим сьогоднішнім чистим доходом.',
'metric.ertrag.desc': 'Що варіант дає в сьогоднішній купівельній спроможності понад власний внесок: теперішня вартість усіх виплат нетто мінус теперішня вартість витрат нетто.',
'metric.irr.desc': 'Дохідність на фактично вкладену суму нетто, номінальна. Безпосередньо порівнянна з установленою валовою дохідністю ETF — різниця — це точно те, що разом коштують чи приносять пільги й відрахування.',
diff --git a/app/index.html b/app/index.html
index 3f72169..2157be6 100644
--- a/app/index.html
+++ b/app/index.html
@@ -537,8 +537,8 @@ a{color:var(--navy)}
<p data-i18n-html="footer.1"><b>Keine Steuer- oder Anlageberatung.</b> Ein Modell ist kein Vertrag. Die Rechtslage 2026 zur reformierten
privaten Altersvorsorge ist an mehreren Stellen noch nicht abschließend geklärt; die Annahmen mit dem
geringsten Vertrauensgrad stehen unter „Rechenweg → Belastbarkeit der Annahmen“ und sind dort auch änderbar.</p>
- <p data-i18n-html="footer.2">Rechenkern eins zu eins portiert aus dem Excel-Modell
- <span class="pill">bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx</span> und gegen drei Testfälle auf
+ <p data-i18n-html="footer.2">Rechenkern eins zu eins portiert aus dem ursprünglichen Excel-Modell
+ und gegen drei Testfälle auf
Maschinengenauigkeit geprüft (größte relative Abweichung 1,3·10<sup>&minus;14</sup>).</p>
</footer>
@@ -707,7 +707,7 @@ function tPlain(key, p){
/* =====================================================================
TEIL 1 — RECHENKERN
- Portierung von build_bav.py. Reine Funktionen, kein DOM.
+ Portierung des ursprünglichen Formelgenerators. Reine Funktionen, kein DOM.
===================================================================== */
(function (root) {
'use strict';
diff --git a/app/pruefe.js b/app/pruefe.js
index eefa941..f0326c4 100644
--- a/app/pruefe.js
+++ b/app/pruefe.js
@@ -138,7 +138,7 @@ setTimeout(() => {
// Deutsche Reste im englischen Modus: Umlaute und typisch deutsche Wörter.
// Fachbegriffe und Normzitate bleiben absichtlich deutsch.
- const erlaubt = /Altersvorsorgedepot|Versorgungsbez|BetrAVG|EStG|SGB|InvStG|SvEV|SolzG|BMF|BGBl|SVBezGrV|Steuerfortentwicklungsgesetz|Rentenwertbestimmungsverordnung|Altersvorsorgereformgesetz|Vorabpauschale|KVdR|PSVaG|Bezugsgr|bAV|Entgeltumwandlung|Baden-W|Deutsche Bahn|DYNO|Deutsch|Sprache/;
+ const erlaubt = /Altersvorsorgedepot|Versorgungsbez|BetrAVG|EStG|SGB|InvStG|SvEV|SolzG|BMF|BGBl|SVBezGrV|Steuerfortentwicklungsgesetz|Rentenwertbestimmungsverordnung|Altersvorsorgereformgesetz|Vorabpauschale|KVdR|PSVaG|Bezugsgr|bAV|Entgeltumwandlung|Baden-W|Deutsche Bahn|Deutsch|Sprache/;
const woerter = enText.split(/\s+/).filter(x => /[äöüßÄÖÜ]/.test(x) && !erlaubt.test(x));
check('keine deutschen Reste im EN-Modus', woerter.length === 0, [...new Set(woerter)].slice(0, 25).join(' '));
diff --git a/bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx b/bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx
deleted file mode 100644
index 28d65f5..0000000
--- a/bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx
+++ /dev/null
Binary files differ
diff --git a/build_bav.py b/build_bav.py
deleted file mode 100644
index 092fe0d..0000000
--- a/build_bav.py
+++ /dev/null
@@ -1,1592 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-bAV (DYNO) vs. Altersvorsorgedepot vs. privates ETF-Depot
-Vollstaendig formelbasiertes Excel-Modell, Rechtsstand 2026.
-"""
-import openpyxl
-from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
-from openpyxl.utils import get_column_letter as gcl
-from openpyxl.chart import BarChart, Reference
-
-import os
-OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- "bAV-DYNO_vs_Altersvorsorgedepot_vs_ETF.xlsx")
-
-FONT = "Arial"
-BLUE = Font(name=FONT, size=10, color="0000FF")
-BLACK = Font(name=FONT, size=10)
-GREEN = Font(name=FONT, size=10, color="008000")
-BOLD = Font(name=FONT, size=10, bold=True)
-H1 = Font(name=FONT, size=14, bold=True, color="1F3864")
-H2 = Font(name=FONT, size=11, bold=True, color="1F3864")
-YELLOW = PatternFill("solid", fgColor="FFFF00")
-GREYFILL = PatternFill("solid", fgColor="D9E1F2")
-HEADFILL = PatternFill("solid", fgColor="1F3864")
-HEADFONT = Font(name=FONT, size=9, bold=True, color="FFFFFF")
-THIN = Side(style="thin", color="BFBFBF")
-BOX = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
-
-EUR = '#,##0;(#,##0);"-"'
-EUR2 = '#,##0.00;(#,##0.00);"-"'
-PCT = '0.00%'
-PCT1 = '0.0%'
-NUM4 = '0.0000'
-
-wb = openpyxl.Workbook()
-
-# =====================================================================
-# 1) EINGABEN
-# =====================================================================
-ws = wb.active
-ws.title = "Eingaben"
-ws.sheet_view.showGridLines = False
-ws.column_dimensions['A'].width = 3
-ws.column_dimensions['B'].width = 52
-ws.column_dimensions['C'].width = 14
-ws.column_dimensions['D'].width = 10
-ws.column_dimensions['E'].width = 78
-
-ws['B1'] = "Eingaben - bAV (DYNO) vs. Altersvorsorgedepot vs. privates ETF-Depot"
-ws['B1'].font = H1
-ws['B2'] = "Nur die GELB hinterlegten Zellen (blaue Schrift) aendern. Alles andere ist Formel."
-ws['B2'].font = Font(name=FONT, size=10, italic=True)
-
-inp = [
- ("A", "PERSON UND ZEITACHSE", None, None, None),
- ("alter", "Alter heute (vollendete Jahre)", 40, "Jahre", "Startpunkt der Ansparphase; Kalenderjahr 0 = 2026."),
- ("rentbeg", "Auszahlungsbeginn (Alter)", 67, "Jahre", "Beginn Auszahlungsphase aller drei Optionen. Altersvorsorgedepot: fruehestens 65 (Reform 2026)."),
- ("planende", "Ende Auszahlungsplan / Vergleichshorizont (Alter)", 85, "Jahre", "Auszahlungsplaene laufen bis hierhin. Lebenslange Renten werden ueber denselben Horizont verglichen (Memo-Zeile fuer den Rest)."),
- ("ausscheid", "Ausscheiden aus dem Job / Vorruhestand (Alter)", 63, "Jahre", "Ab hier kein Gehalt, keine Beitraege mehr. Kapital verzinst sich weiter bis zum Auszahlungsbeginn."),
- ("tzalter", "Teilzeit ab Alter", 55, "Jahre", "Auf 999 setzen, wenn keine Teilzeit geplant ist."),
- ("tzfaktor", "Teilzeitfaktor (Anteil des Vollzeitgehalts)", 0.60, "", "0,60 = 60 %-Stelle."),
- ("A", "EINKOMMEN UND STEUER", None, None, None),
- ("gehalt", "Jahresbruttogehalt heute", 75000, "EUR", "Ohne Einmalzahlungen; ggf. inkl. anteiligem 13. Gehalt."),
- ("gsteig", "Gehalts- und Lohnsteigerung p.a.", 0.025, "", "Wird auch zur Fortschreibung von BBG, Bezugsgroesse, Durchschnittsentgelt und Rentenwert benutzt."),
- ("stkl", "Veranlagung: 1 = einzeln (Stkl. 1), 3 = zusammen (Stkl. 3)", 1, "1/3", "Massgeblich ist die VERANLAGUNGSART, nicht die Lohnsteuerklasse: die Klasse steuert nur den unterjaehrigen Abzug, der Jahresbescheid rechnet ohnehin mit Splitting. 3 = Splittingtarif nach 32a Abs. 5 EStG; dann unbedingt das zvE des Partners eintragen."),
- ("partner", "zu versteuerndes Einkommen des Partners (nur Stkl. 3)", 0, "EUR", "Bei Stkl. 3 wird der Splittingtarif nach 32a Abs. 5 EStG gerechnet: 2 x ESt((zvE + zvE_Partner)/2)."),
- ("kist", "Kirchensteuersatz (0 / 0,08 / 0,09)", 0.0, "", "8 % in BY und BW, sonst 9 %."),
- ("tarifanp", "Anpassung der Tarifeckwerte p.a. (kalte Progression)", 0.02, "", "Der ganze Tarif wird mit diesem Faktor gestreckt. 0 % = volle kalte Progression."),
- ("kinder", "Anzahl Kinder (fuer Kinderzulage)", 0, "", "Kinderzulage im Altersvorsorgedepot: 1 EUR je eingezahltem EUR bis 300 EUR je Kind."),
- ("kind_jahre", "Jahre, in denen noch Kinderzulage zusteht", 18, "Jahre", "Die Kinderzulage ist an den Kindergeldanspruch gekoppelt ( 85 EStG), laeuft also nicht ueber die gesamte Ansparphase. Auf 0 setzen, wenn kein Anspruch mehr besteht."),
- ("kinderlos", "Kinderlos (Zuschlag Pflegeversicherung)? 1 = ja", 0, "1/0", "0,6 Prozentpunkte Zuschlag, allein vom Arbeitnehmer zu tragen ( 55 Abs. 3 SGB XI)."),
- ("A", "BETRIEBLICHE ALTERSVORSORGE (DYNO)", None, None, None),
- ("modus", "Vorgabe: 1 = Bruttobeitrag, 2 = Nettoaufwand", 1, "1/2", "Bei 2 wird der Bruttobeitrag so bestimmt, dass der gewuenschte Nettoaufwand herauskommt (Bisektion im Blatt 'Umrechnung'). Der Nettoaufwand ist der tatsaechlich aufgegebene Konsum und damit die oekonomisch richtige Entscheidungsvariable."),
- ("beitrag", "Monatsbeitrag bAV brutto (nur bei Modus 1)", 300, "EUR", "Bruttoentgeltumwandlung nach 1a BetrAVG."),
- ("netto_ziel", "Monatlicher Nettoaufwand (nur bei Modus 2)", 165, "EUR", "Der Betrag, um den Ihr verfuegbares Einkommen im ersten Jahr sinkt. Danach wird der Bruttobeitrag nach der Dynamisierungsregel fortgeschrieben."),
- ("dyn", "Beitrag mit dem Gehalt dynamisieren? 1 = ja", 1, "1/0", "1 = Beitrag steigt mit der Gehaltssteigerung, 0 = nominal konstant."),
- ("agzus", "Arbeitgeberzuschuss (Anteil des Beitrags)", 0.15, "", "Gesetzliches Minimum 15 % ( 1a Abs. 1a BetrAVG). DYNO-Arbeitgeber zahlen oft mehr - hier eintragen, was im Vertrag steht."),
- ("agz_fix", "Fester AG-Zuschuss zusaetzlich (EUR je Monat)", 0, "EUR", "Betragsunabhaengiger Festzuschuss aus Tarifvertrag oder Betriebsvereinbarung - bei der Deutschen Bahn und in vielen Tarifwerken ueblich, dort ZUSAETZLICH zu den 15 % nach 1a Abs. 1a BetrAVG. Er ist arbeitgeberfinanzierte Zuwendung nach 3 Nr. 63 EStG und belegt den 8-%-Topf sowie die 4-%-Beitragsfreiheit ( 1 Abs. 1 S. 1 Nr. 9 SvEV) VORRANGIG; die eigene Entgeltumwandlung wird insoweit verdraengt und teurer."),
- ("agz_fix_dyn","Festen Zuschuss dynamisieren? 1 = ja", 0, "1/0", "0 = nominal konstant (Voreinstellung: Festbetraege stehen meist nominal im Tarifvertrag), 1 = steigt mit der Gehalts- bzw. Tarifsteigerung."),
- ("agz_fix_min","Mindest-Eigenbeitrag fuer den festen Zuschuss (EUR/Monat)", 0, "EUR", "Matching-Modelle knuepfen den Festbetrag an eine Mindest-Eigenleistung. 0 = bedingungslos; dann fliesst er in jedem aktiven Jahr, auch bei Beitrag null. Vorsicht: ein wirklich bedingungsloser Zuschuss ist kein Differenzeffekt der Umwandlungsentscheidung und verzerrt den Vergleich zugunsten der bAV."),
- ("agzus_sv", "Zuschussmodus: 0 = voller Beitrag, 1 = sv-freier Anteil, 2 = spitz", 2, "0/1/2", "Gilt nur fuer den prozentualen Zuschuss; der feste Zuschuss oben ist davon unberuehrt. 2 ist der Gesetzeswortlaut: 1a Abs. 1a BetrAVG schuldet den Zuschuss nur, SOWEIT der Arbeitgeber tatsaechlich Sozialversicherungsbeitraege spart. Liegt Ihr Entgelt ueber beiden Beitragsbemessungsgrenzen, spart er nichts - und schuldet nichts. 1 ist die verbreitete pauschale Praxis, 0 eine freiwillige oder tarifvertragliche Zusage."),
- ("auszform", "bAV-Auszahlung: 1 = Kapital, 2 = lebenslange Rente", 1, "1/2", "Kapital: voll steuerpflichtig im Zuflussjahr, KV/PV auf 120 Monate verteilt ( 229 Abs. 1 S. 3 SGB V)."),
- ("rentfak", "Rentenfaktor bAV (EUR Monatsrente je 10.000 EUR)", 26, "EUR", "Nur relevant bei Auszahlungsform 2. 26 EUR entspricht ca. 3,1 % Entnahmequote."),
- ("rentdyn", "Dynamik der bAV-Rente p.a.", 0.01, "", "Ueberschussbeteiligung / Fondsentwicklung in der Rentenphase."),
- ("fuenftel", "Fuenftelregelung auf bAV-Kapital pruefen? 1 = ja", 0, "1/0", "34 EStG ist bei planmaessiger Kapitalabfindung aus 3 Nr. 63-Vertraegen nach BFH X R 23/15 nur ausnahmsweise anwendbar. Konservativ: 0."),
- ("A", "KAPITALMARKT UND KOSTEN", None, None, None),
- ("rendite", "Bruttorendite des ETF p.a. (vor Kosten, vor Steuern)", 0.07, "", "Identischer ETF in allen drei Optionen - so war die Frage gestellt."),
- ("k_bav", "Kosten bAV-Produkt p.a. (Versicherungsmantel + TER)", 0.006, "", "DYNO wirbt mit provisionsfrei; realistisch bleiben Verwaltungs- und Mantelkosten. Effektivkosten aus dem Produktinformationsblatt eintragen."),
- ("k_av", "Kosten Altersvorsorgedepot p.a.", 0.005, "", "Standarddepot: Effektivkosten gesetzlich auf 1,0 % p.a. gedeckelt."),
- ("k_priv", "Kosten privates ETF-Depot p.a.", 0.002, "", "Reine TER eines breiten Welt-ETF."),
- ("infl", "Inflation p.a. (fuer die reale Darstellung)", 0.02, "", "Diskontierungssatz fuer die Barwerte in Kaufkraft von heute."),
- ("A", "RUHESTAND", None, None, None),
- ("kv_ruhe", "Krankenversicherung im Ruhestand: 1 = GKV, 2 = PKV", 1, "1/2", "Entscheidender Hebel: in der GKV sind Versorgungsbezuege mit dem vollen Beitragssatz belegt, private Altersvorsorge nicht."),
- ("sonst_zve", "sonstiges zu versteuerndes Einkommen im Ruhestand", 22000, "EUR", "Vor allem der steuerpflichtige Teil der gesetzlichen Rente, ohne die hier verglichenen Produkte. Bestimmt den Grenzsteuersatz in der Auszahlungsphase."),
- ("rente_br", "gesetzliche Bruttorente p.a. (heutige Werte)", 24000, "EUR", "Nur fuer den Beitragsbemessungsgrenzen-Deckel in der KV: Rente und Versorgungsbezuege teilen sich EINE Obergrenze ( 223 Abs. 3 SGB V)."),
- ("teilkap", "Altersvorsorgedepot: Teilkapital zu Beginn", 0.0, "", "Bis 30 % sind zu Beginn der Auszahlungsphase als Einmalbetrag moeglich. Gilt in beiden Auszahlungsformen."),
- ("av_auszform","Altersvorsorgedepot: 1 = Auszahlungsplan, 2 = lebenslange Rente", 1, "1/2", "Unabhaengig von der bAV-Auszahlungsform: wer die bAV als Kapital nimmt, kann das Depot trotzdem verrenten. Plan: Entnahme bleibt investiert, Besteuerung der nicht gefoerderten Schicht mit dem halben Unterschiedsbetrag. Rente: Kapital geht an den Versicherer, nicht gefoerderte Schicht nur mit dem Ertragsanteil ( 22 Nr. 5 S. 2 Buchst. a EStG)."),
- ("rentfak_av", "Rentenfaktor Altersvorsorgedepot (EUR je 10.000 EUR)", 26, "EUR", "Nur bei Auszahlungsform 2. Voreinstellung wie bei der bAV; ein Depotvertrag kann guenstiger sein als ein Versicherungsmantel - Wert aus dem Angebot eintragen."),
- ("rentdyn_av", "Dynamik der Altersvorsorgedepot-Rente p.a.", 0.01, "", "Ueberschussbeteiligung bzw. Fondsentwicklung in der Rentenphase des Depotvertrags."),
-]
-
-r = 4
-IN = {}
-for key, label, val, unit, note in inp:
- if key == "A":
- ws.cell(r, 2, label).font = H2
- ws.cell(r, 2).fill = GREYFILL
- ws.cell(r, 3).fill = GREYFILL
- ws.cell(r, 4).fill = GREYFILL
- r += 1
- continue
- ws.cell(r, 2, label).font = BLACK
- c = ws.cell(r, 3, val)
- c.font = BLUE
- c.fill = YELLOW
- c.border = BOX
- if isinstance(val, float) and val < 1.5 and key not in ("tzfaktor",):
- c.number_format = PCT
- elif key == "tzfaktor":
- c.number_format = PCT1
- elif isinstance(val, int) and abs(val) >= 1000:
- c.number_format = EUR
- ws.cell(r, 4, unit).font = Font(name=FONT, size=9, color="808080")
- ws.cell(r, 5, note).font = Font(name=FONT, size=9, color="595959")
- IN[key] = f"Eingaben!$C${r}"
- r += 1
-
-r += 1
-ws.cell(r, 2, "ERGEBNIS AUF EINEN BLICK (Details im Blatt 'Vergleich')").font = H2
-ws.cell(r, 2).fill = GREYFILL
-ws.cell(r, 3).fill = GREYFILL
-res_row = r + 1
-OPTS = ["bAV mit DYNO", "Altersvorsorgedepot", "privates ETF-Depot"]
-blocks = [
- ("Barwert der Netto-Auszahlungen",
- ["=Vergleich!$B$13", "=Vergleich!$C$13", "=Vergleich!$D$13"], EUR,
- "Summe aller Leistungen nach Steuern und Sozialabgaben, auf heute abgezinst - noch ohne Abzug des eigenen Einsatzes."),
- ("Barwert des Netto-Ertrags",
- ["=Vergleich!$B$15", "=Vergleich!$C$15", "=Vergleich!$D$15"], EUR,
- "Dasselbe abzueglich des Barwerts des Nettoaufwands: was die Option ueber den eigenen Einsatz hinaus abwirft."),
- ("Aequivalente Monatsleistung",
- ["=Vergleich!$B$47", "=Vergleich!$C$47", "=Vergleich!$D$47"], EUR2,
- "Konstante Monatszahlung ueber die Auszahlungsphase mit demselben Wert - vergleichbar mit Ihrem heutigen Nettoeinkommen."),
-]
-rr_ = res_row
-for title, fmls, fmt, note in blocks:
- ws.cell(rr_, 2, f"{title} (in heutiger Kaufkraft)").font = H2
- ws.cell(rr_, 5, note).font = Font(name=FONT, size=9, color="595959")
- rr_ += 1
- for i, lab in enumerate(OPTS):
- ws.cell(rr_, 2, f" {lab}").font = BLACK
- cc = ws.cell(rr_, 3, fmls[i])
- cc.font = Font(name=FONT, size=11, bold=True, color="008000")
- cc.number_format = fmt
- cc.border = BOX
- rr_ += 1
- rr_ += 1
-res_end = rr_
-
-# =====================================================================
-# 2) PARAMETER
-# =====================================================================
-pw = wb.create_sheet("Parameter")
-pw.sheet_view.showGridLines = False
-pw.column_dimensions['A'].width = 3
-pw.column_dimensions['B'].width = 56
-pw.column_dimensions['C'].width = 14
-pw.column_dimensions['D'].width = 92
-pw['B1'] = "Rechengroessen und Tarifkonstanten - Rechtsstand 2026"
-pw['B1'].font = H1
-
-par = [
- ("A", "SOZIALVERSICHERUNG 2026", None, None),
- ("bbg_rv", "Beitragsbemessungsgrenze RV/AV (jaehrlich)", 101400, "SVBezGrV 2026 (BGBl. 2025 I Nr. 116); bundeseinheitlich."),
- ("bbg_kv", "Beitragsbemessungsgrenze KV/PV (jaehrlich)", 69750, "SVBezGrV 2026; 5.812,50 EUR monatlich."),
- ("bezug", "Bezugsgroesse (monatlich)", 3955, "SVBezGrV 2026; 47.460 EUR jaehrlich."),
- ("frei_vb", "Freibetrag Versorgungsbezuege KV (monatlich)", None, "1/20 der Bezugsgroesse, 226 Abs. 2 S. 2 SGB V = 197,75 EUR/Monat in 2026. In der PV gilt statt des Freibetrags eine Freigrenze."),
- ("de_rv", "Vorlaeufiges Durchschnittsentgelt RV", 51944, "Anlage 1 zu SGB VI, Wert 2026 - Nenner fuer Entgeltpunkte."),
- ("rw", "Aktueller Rentenwert (ab 1.7.2026)", 42.52, "Rentenwertbestimmungsverordnung 2026; +4,24 % ggue. 40,79 EUR."),
- ("rv_an", "Rentenversicherung, Arbeitnehmeranteil", 0.093, "18,6 % haelftig."),
- ("av_an", "Arbeitslosenversicherung, Arbeitnehmeranteil", 0.013, "2,6 % haelftig."),
- ("kv_allg", "Krankenversicherung, allgemeiner Beitragssatz", 0.146, "241 SGB V."),
- ("kv_zus", "Durchschnittlicher Zusatzbeitrag 2026", 0.029, "Bekanntmachung des BMG; kassenindividuell abweichend."),
- ("pv_ges", "Pflegeversicherung, Gesamtbeitragssatz", 0.036, "55 SGB XI. Kinderabschlaege ab dem 2. Kind hier nicht modelliert."),
- ("pv_an", "Pflegeversicherung, Arbeitnehmeranteil", 0.018, "In Sachsen abweichend (2,3 %)."),
- ("pv_kl", "Zuschlag fuer Kinderlose (allein AN)", 0.006, "55 Abs. 3 SGB XI."),
- ("A", "EINKOMMENSTEUERTARIF 2026 ( 32a EStG)", None, None),
- ("gfb", "Grundfreibetrag / Ende Zone 1", 12348, "32a Abs. 1 EStG i.d.F. des Steuerfortentwicklungsgesetzes."),
- ("e2", "Ende Zone 2 (Progressionszone I)", 17799, "Grenzsteuersatz steigt von 14 % auf 23,97 %."),
- ("e3", "Ende Zone 3 (Progressionszone II)", 69878, "Grenzsteuersatz steigt von 23,97 % auf 42 %."),
- ("e4", "Beginn Zone 5 (Reichensteuer)", 277825, "Ab 277.826 EUR gilt 45 %."),
- ("a2", "Koeffizient a2 (Zone 2)", 914.51, "ESt = (a2*y + b2)*y mit y = (zvE - Grundfreibetrag)/10.000."),
- ("b2", "Koeffizient b2 (Zone 2)", 1400, ""),
- ("a3", "Koeffizient a3 (Zone 3)", 173.10, "ESt = (a3*z + b3)*z + c3 mit z = (zvE - 17.799)/10.000."),
- ("b3", "Koeffizient b3 (Zone 3)", 2397, ""),
- ("c3", "Konstante c3 (Zone 3)", 1034.87, ""),
- ("c4", "Konstante c4 (Zone 4)", 11135.63, "ESt = 0,42*zvE - c4."),
- ("c5", "Konstante c5 (Zone 5)", 19470.38, "ESt = 0,45*zvE - c5."),
- ("soli", "Solidaritaetszuschlag", 0.055, "SolzG 1995."),
- ("soli_fg", "Soli-Freigrenze (Grundtarif, festgesetzte ESt)", 20350, "2026; im Splitting doppelt. Milderungszone daneben."),
- ("soli_mz", "Milderungszone: Grenzbelastung", 0.119, "3 Abs. 2a SolzG."),
- ("an_pausch", "Arbeitnehmer-Pauschbetrag", 1230, "9a S. 1 Nr. 1a EStG."),
- ("sa_pausch", "Sonderausgaben-Pauschbetrag", 36, "10c EStG."),
- ("A", "KAPITALERTRAGSTEUER UND INVESTMENTSTEUER", None, None),
- ("kapst", "Abgeltungsteuersatz", 0.25, "32d Abs. 1 EStG."),
- ("kapst_eff","Effektive Belastung inkl. Soli und Kirchensteuer", None, "Formel: 0,25/(1+0,25*k) * (1+0,055+k) nach 32d Abs. 1 S. 3 EStG. Ohne KiSt 26,375 %, bei 9 % KiSt 27,99 %."),
- ("tfs", "Teilfreistellung Aktienfonds (Privatvermoegen)", 0.30, "20 Abs. 1 Nr. 3 i.V.m. 20 InvStG (Aktienfondsanteil > 50 %)."),
- ("sparerpb","Sparer-Pauschbetrag (Einzelveranlagung)", 1000, "20 Abs. 9 EStG; im Splitting 2.000 EUR."),
- ("basiszins","Basiszins Vorabpauschale 2026", 0.032, "BMF-Schreiben vom 13.01.2026, 18 Abs. 4 InvStG (2025: 2,53 %)."),
- ("vp_faktor","Faktor fuer den Basisertrag", 0.70, "18 Abs. 1 S. 1 InvStG."),
- ("A", "BETRIEBLICHE UND GEFOERDERTE PRIVATE ALTERSVORSORGE", None, None),
- ("st_frei_q","Steuerfrei nach 3 Nr. 63 EStG (Anteil der BBG-RV)", 0.08, "8 % der BBG-RV = 8.112 EUR in 2026."),
- ("sv_frei_q","Sozialversicherungsfrei (Anteil der BBG-RV)", 0.04, "1 Abs. 1 S. 1 Nr. 9 SvEV; 4 % = 4.056 EUR in 2026."),
- ("zul_g1", "Zulage Stufe 1 (je EUR Eigenbeitrag)", 0.50, "Altersvorsorgereformgesetz, in Kraft seit Mai 2026, Anwendung ab 1.1.2027."),
- ("zul_s1", "Grenze Stufe 1", 360, "Bis 360 EUR Eigenbeitrag: 50 Cent je EUR."),
- ("zul_g2", "Zulage Stufe 2 (je EUR Eigenbeitrag)", 0.25, "Von 361 bis 1.800 EUR: 25 Cent je EUR."),
- ("zul_s2", "Grenze Stufe 2 / Hoechstbetrag gefoerderter Eigenbeitrag", 1800, "Ergibt eine maximale Grundzulage von 540 EUR."),
- ("kind_zul","Kinderzulage je Kind (max.)", 300, "1 EUR je eingezahltem EUR bis 300 EUR je Kind."),
- ("av_max", "Hoechstbetrag Einzahlung Altersvorsorgevertrag p.a.", 6840, "BMF-FAQ zur Reform der geförderten privaten Altersvorsorge, Stand 05.05.2026."),
- ("av_sa_max","Hoechstbetrag Sonderausgabenabzug 10a EStG", 2340, "Eigenbeitrag bis 1.800 EUR zzgl. Zulagen. MODELLANNAHME, Vertrauensgrad ca. 70 %."),
- ("ertragsq","Ertragsanteil nicht gefoerderter Rententeile (Alter 67)", 0.17, "22 Nr. 1 S. 3 Buchst. a Doppelbuchst. bb EStG. Wird nur nachrichtlich gefuehrt."),
- ("halb", "Steuerpflichtiger Anteil des Unterschiedsbetrags", 0.50, "20 Abs. 1 Nr. 6 S. 2 EStG analog (Vertrag > 12 Jahre, Auszahlung nach 62): halber Unterschiedsbetrag."),
- ("kv_rentner","KV-Satz auf die gesetzliche Rente (Rentneranteil)", None, "Halber allgemeiner Satz zzgl. halbem Zusatzbeitrag, 249a SGB V."),
- ("kv_vb", "KV-Satz auf Versorgungsbezuege (voll)", None, "250 Abs. 1 Nr. 1 SGB V: der Rentner traegt den vollen Satz allein."),
-]
-
-r = 3
-P = {}
-for key, label, val, note in par:
- if key == "A":
- pw.cell(r, 2, label).font = H2
- pw.cell(r, 2).fill = GREYFILL
- pw.cell(r, 3).fill = GREYFILL
- r += 1
- continue
- pw.cell(r, 2, label).font = BLACK
- c = pw.cell(r, 3)
- c.border = BOX
- P[key] = f"Parameter!$C${r}"
- if val is None:
- c.font = BLACK
- else:
- c.value = val
- c.font = BLUE
- c.fill = YELLOW
- if isinstance(val, float) and val < 1.5:
- c.number_format = PCT
- elif isinstance(val, (int, float)) and abs(val) >= 1000:
- c.number_format = EUR2
- else:
- c.number_format = EUR2
- pw.cell(r, 4, note).font = Font(name=FONT, size=9, color="595959")
- r += 1
-
-# abgeleitete Parameter
-pw[P['frei_vb'].split('!')[1].replace('$', '')] = f"={P['bezug']}/20"
-pw[P['frei_vb'].split('!')[1].replace('$', '')].number_format = EUR2
-pw[P['kapst_eff'].split('!')[1].replace('$', '')] = f"={P['kapst']}/(1+{P['kapst']}*{IN['kist']})*(1+{P['soli']}+{IN['kist']})"
-pw[P['kapst_eff'].split('!')[1].replace('$', '')].number_format = PCT
-pw[P['kv_rentner'].split('!')[1].replace('$', '')] = f"=({P['kv_allg']}+{P['kv_zus']})/2"
-pw[P['kv_rentner'].split('!')[1].replace('$', '')].number_format = PCT
-pw[P['kv_vb'].split('!')[1].replace('$', '')] = f"={P['kv_allg']}+{P['kv_zus']}"
-pw[P['kv_vb'].split('!')[1].replace('$', '')].number_format = PCT
-
-# abgeleitete Hilfsgroessen
-r += 1
-pw.cell(r, 2, "ABGELEITETE GROESSEN").font = H2
-pw.cell(r, 2).fill = GREYFILL
-pw.cell(r, 3).fill = GREYFILL
-r += 1
-derived = [
- ("splitfak", "Splittingfaktor s (1 oder 2)", f"=IF({IN['stkl']}=3,2,1)", '0'),
- ("pv_an_eff", "PV-Anteil AN effektiv (inkl. Kinderlosenzuschlag)", f"={P['pv_an']}+IF({IN['kinderlos']}=1,{P['pv_kl']},0)", PCT),
- ("pv_ges_eff", "PV-Satz Rentner/Versorgungsbezuege effektiv", f"={P['pv_ges']}+IF({IN['kinderlos']}=1,{P['pv_kl']},0)", PCT),
- ("rnet_bav", "Nettorendite bAV-Depot p.a.", f"={IN['rendite']}-{IN['k_bav']}", PCT),
- ("rnet_av", "Nettorendite Altersvorsorgedepot p.a.", f"={IN['rendite']}-{IN['k_av']}", PCT),
- ("rnet_priv", "Nettorendite privates Depot p.a. (vor Steuern)", f"={IN['rendite']}-{IN['k_priv']}", PCT),
- ("n_jahre", "Jahre der Ansparphase", f"={IN['rentbeg']}-{IN['alter']}", '0'),
- ("n_ausz", "Jahre des Auszahlungsplans", f"={IN['planende']}-{IN['rentbeg']}+1", '0'),
- ("jahr_rb", "Kalenderjahr des Auszahlungsbeginns", f"=2026+{IN['rentbeg']}-{IN['alter']}", '0'),
- ("best_anteil", "Besteuerungsanteil der gesetzlichen Rente", None, PCT),
- ("sparerpb_eff", "Sparer-Pauschbetrag effektiv", f"={P['sparerpb']}*IF({IN['stkl']}=3,2,1)", EUR),
- ("wiederanl", "Wiederanlagezins nach Steuern p.a.", None, PCT),
-]
-for key, label, f, fmt in derived:
- pw.cell(r, 2, label).font = BLACK
- c = pw.cell(r, 3)
- c.border = BOX
- c.font = BLACK
- c.number_format = fmt
- if f:
- c.value = f
- P[key] = f"Parameter!$C${r}"
- r += 1
-pw[P['best_anteil'].split('!')[1].replace('$', '')] = f"=MIN(1,0.825+0.005*({P['jahr_rb']}-2023))"
-pw[P['wiederanl'].split('!')[1].replace('$', '')] = f"={P['rnet_priv']}*(1-{P['kapst_eff']}*(1-{P['tfs']}))"
-pw.cell(int(P['wiederanl'].split('$')[-1]), 4,
- "Rendite, zu der ein Einmalbetrag in einem normalen Depot wieder angelegt werden koennte, "
- "nach Abgeltungsteuer und Teilfreistellung. Massstab fuer das Verrentungsaequivalent.").font = \
- Font(name=FONT, size=9, color="595959")
-pw.cell(r - 2, 4, "22 Nr. 1 S. 3 Buchst. a Doppelbuchst. aa EStG: Kohorte 2023 = 82,5 %, +0,5 Prozentpunkte je Jahr bis 100 % ab 2058.").font = Font(name=FONT, size=9, color="595959")
-
-
-# =====================================================================
-# Hilfsfunktionen fuer Steuerformeln
-# =====================================================================
-def tarif(arg):
- """Grundtarif nach 32a EStG, angewandt auf die (bereits gesplittete und
- inflationsbereinigte) Bemessungsgrundlage in Zelle `arg`."""
- return (f"IF({arg}<={P['gfb']},0,"
- f"IF({arg}<={P['e2']},({P['a2']}*({arg}-{P['gfb']})/10000+{P['b2']})*({arg}-{P['gfb']})/10000,"
- f"IF({arg}<={P['e3']},({P['a3']}*({arg}-{P['e2']})/10000+{P['b3']})*({arg}-{P['e2']})/10000+{P['c3']},"
- f"IF({arg}<={P['e4']},0.42*{arg}-{P['c4']},0.45*{arg}-{P['c5']}))))")
-
-
-def arg_formula(zve_ref, lam_ref):
- """Tarifargument: Splitting und Streckung des Tarifs um den Faktor lambda."""
- return (f"=MAX(0,({zve_ref}+IF({IN['stkl']}=3,{IN['partner']},0))"
- f"/{P['splitfak']}/{lam_ref})")
-
-
-def est_formula(arg_ref, lam_ref):
- """Festgesetzte Einkommensteuer."""
- return f"={P['splitfak']}*{lam_ref}*({tarif(arg_ref)})"
-
-
-def steuer_ges(est_ref, lam_ref):
- """ESt + Solidaritaetszuschlag (mit Freigrenze und Milderungszone) + Kirchensteuer."""
- fg = f"({P['soli_fg']}*{P['splitfak']}*{lam_ref})"
- return (f"={est_ref}+IF({est_ref}<={fg},0,"
- f"MIN({P['soli']}*{est_ref},{P['soli_mz']}*({est_ref}-{fg})))"
- f"+{IN['kist']}*{est_ref}")
-
-
-# =====================================================================
-# 2b) UMRECHNUNG Nettoaufwand -> Bruttobeitrag (Bisektion)
-# =====================================================================
-# N(B) = B - SV-Ersparnis(B) - Steuerersparnis(B) ist stetig und streng monoton
-# wachsend in B (dN/dB = 1 - Grenz-SV-Satz - Grenzsteuersatz > 0), aber wegen der
-# Knicke bei 4 % und 8 % der BBG-RV, an den Beitragsbemessungsgrenzen und an den
-# Tarifeckwerten nicht geschlossen invertierbar. 34 Bisektionsschritte auf
-# [0; Bruttogehalt] liefern eine Genauigkeit von unter einem Zehntelcent.
-uw = wb.create_sheet("Umrechnung", 3)
-uw.sheet_view.showGridLines = False
-uw.column_dimensions['A'].width = 3
-uw.column_dimensions['B'].width = 46
-uw.column_dimensions['C'].width = 16
-uw.column_dimensions['D'].width = 76
-uw['B1'] = "Umrechnung Nettoaufwand -> Bruttobeitrag"
-uw['B1'].font = H1
-uw['B2'] = ("Nur aktiv bei Vorgabemodus 2. Gesucht ist die Nullstelle von N(B) - Zielwert; N ist streng monoton "
- "wachsend, also konvergiert die Bisektion garantiert.")
-uw['B2'].font = Font(name=FONT, size=10, italic=True, color="595959")
-
-U = {}
-ur = 4
-konst = [
- ("tz0", "Teilzeitfaktor im ersten Jahr", f"=IF({IN['alter']}>={IN['tzalter']},{IN['tzfaktor']},1)", PCT1),
- ("g0", "Bruttogehalt im ersten Jahr", None, EUR),
- ("bbgrv0", "BBG RV im ersten Jahr", f"={P['bbg_rv']}", EUR),
- ("bbgkv0", "BBG KV im ersten Jahr", f"={P['bbg_kv']}", EUR),
- ("lam0", "Tarifindex im ersten Jahr", "=1", NUM4),
- ("ziel", "Zielwert Nettoaufwand p.a.", f"=12*{IN['netto_ziel']}", EUR),
- ("vors_o", "abziehbare Vorsorgeaufwendungen ohne bAV", None, EUR),
- ("zve_o", "zvE ohne bAV", None, EUR),
- ("arg_o", "Tarifargument ohne bAV", None, EUR),
- ("est_o", "ESt ohne bAV", None, EUR),
- ("stg_o", "Steuer gesamt ohne bAV", None, EUR),
-]
-for key, label, fml, fmt in konst:
- uw.cell(ur, 2, label).font = BLACK
- c = uw.cell(ur, 3)
- c.font = GREEN
- c.number_format = fmt
- c.border = BOX
- if fml:
- c.value = fml
- U[key] = f"Umrechnung!$C${ur}"
- ur += 1
-uw[U['g0'].split('!')[1].replace('$', '')] = f"={IN['gehalt']}*{U['tz0']}"
-uw[U['vors_o'].split('!')[1].replace('$', '')] = (
- f"=MIN({U['g0']},{U['bbgrv0']})*{P['rv_an']}"
- f"+MIN({U['g0']},{U['bbgkv0']})*(0.96*({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
-uw[U['zve_o'].split('!')[1].replace('$', '')] = (
- f"=MAX(0,{U['g0']}-{P['an_pausch']}-{P['sa_pausch']}-{U['vors_o']})")
-uw[U['arg_o'].split('!')[1].replace('$', '')] = arg_formula(U['zve_o'], U['lam0'])
-uw[U['est_o'].split('!')[1].replace('$', '')] = est_formula(U['arg_o'], U['lam0'])
-uw[U['stg_o'].split('!')[1].replace('$', '')] = steuer_ges(U['est_o'], U['lam0'])
-
-UB_COLS = [("i", "Schritt", 8, '0'), ("lo", "lo", 14, EUR2), ("hi", "hi", 14, EUR2),
- ("mid", "B = (lo+hi)/2", 14, EUR2), ("svf", "sv-frei", 12, EUR2),
- ("drv", "D RV-Bem.", 12, EUR2), ("dkv", "D KV-Bem.", 12, EUR2),
- ("svan", "SV-Ersp. AN", 12, EUR2), ("svag", "SV-Ersp. AG", 12, EUR2),
- ("agfx", "AG fest", 12, EUR2),
- ("agz", "AG-Zuschuss", 12, EUR2), ("stf", "steuerfrei", 12, EUR2),
- ("vorsm", "Vorsorgeaufw.", 13, EUR2), ("zvem", "zvE mit bAV", 13, EUR2),
- ("argm", "Tarifarg.", 13, EUR2), ("estm", "ESt", 13, EUR2),
- ("stgm", "Steuer ges.", 13, EUR2), ("nb", "N(B)", 14, EUR2)]
-UC = {k: gcl(i + 2) for i, (k, _, _, _) in enumerate(UB_COLS)}
-UI = {k: i + 2 for i, (k, _, _, _) in enumerate(UB_COLS)}
-UFMT = {k: f for k, _, _, f in UB_COLS}
-
-UR0 = ur + 2
-uw.cell(UR0 - 1, 2, "Bisektion").font = H2
-for k, head, w, fmt in UB_COLS:
- uw.column_dimensions[UC[k]].width = w
- c = uw.cell(UR0, UI[k], head)
- c.font = HEADFONT
- c.fill = HEADFILL
- c.alignment = Alignment(horizontal="center", wrap_text=True)
-
-NIT = 34
-for t in range(NIT):
- r = UR0 + 1 + t
- p = r - 1
- C = {k: f"{UC[k]}{r}" for k in UC}
- Cp = {k: f"{UC[k]}{p}" for k in UC}
-
- def u(k, s):
- cell = uw.cell(r, UI[k], s)
- cell.number_format = UFMT[k]
- cell.font = BLACK
- return cell
-
- u("i", str(t + 1))
- if t == 0:
- u("lo", "=0")
- u("hi", f"={U['g0']}")
- else:
- u("lo", f"=IF({Cp['nb']}<{U['ziel']},{Cp['mid']},{Cp['lo']})")
- u("hi", f"=IF({Cp['nb']}<{U['ziel']},{Cp['hi']},{Cp['mid']})")
- u("mid", f"=({C['lo']}+{C['hi']})/2")
- u("agfx", f"=IF({C['mid']}/12+0.000000001<{IN['agz_fix_min']},0,12*{IN['agz_fix']})")
- u("svf", f"=MIN({C['mid']},MAX(0,{P['sv_frei_q']}*{U['bbgrv0']}-{C['agfx']}))")
- u("drv", f"=MIN({U['g0']},{U['bbgrv0']})-MIN({U['g0']}-{C['svf']},{U['bbgrv0']})")
- u("dkv", f"=MIN({U['g0']},{U['bbgkv0']})-MIN({U['g0']}-{C['svf']},{U['bbgkv0']})")
- u("svan", f"={C['drv']}*({P['rv_an']}+{P['av_an']})+{C['dkv']}*(({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
- u("svag", f"={C['drv']}*({P['rv_an']}+{P['av_an']})+{C['dkv']}*(({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an']})")
- u("agz", f"=IF({IN['agzus_sv']}=2,MIN({IN['agzus']}*{C['mid']},{C['svag']}),"
- f"{IN['agzus']}*IF({IN['agzus_sv']}=1,{C['svf']},{C['mid']}))+{C['agfx']}")
- u("stf", f"=MIN({C['mid']},MAX(0,{P['st_frei_q']}*{U['bbgrv0']}-{C['agz']}))")
- u("vorsm", f"=MIN({U['g0']}-{C['svf']},{U['bbgrv0']})*{P['rv_an']}"
- f"+MIN({U['g0']}-{C['svf']},{U['bbgkv0']})*(0.96*({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
- u("zvem", f"=MAX(0,{U['g0']}-{C['stf']}-{P['an_pausch']}-{P['sa_pausch']}-{C['vorsm']})")
- u("argm", arg_formula(C['zvem'], U['lam0']))
- u("estm", est_formula(C['argm'], U['lam0']))
- u("stgm", steuer_ges(C['estm'], U['lam0']))
- u("nb", f"={C['mid']}-{C['svan']}-({U['stg_o']}-{C['stgm']})")
- if t % 2 == 1:
- for k in UI:
- uw.cell(r, UI[k]).fill = PatternFill("solid", fgColor="F2F2F2")
-
-ULAST = UR0 + NIT
-rr = ULAST + 2
-erg = [
- ("b_jahr", "ERGEBNIS: Bruttobeitrag p.a.", f"=({UC['lo']}{ULAST}+{UC['hi']}{ULAST})/2", EUR2,
- "Loesung der Gleichung N(B) = Zielwert."),
- ("b_mtl", "ERGEBNIS: Bruttobeitrag pro Monat", None, EUR2, "Wird im Blatt 'Ansparphase' verwendet, sobald Modus 2 gewaehlt ist."),
- ("resid", "Residuum N(B) - Zielwert", f"={UC['nb']}{ULAST}-{U['ziel']}", '0.000000',
- "Muss praktisch null sein. Andernfalls ist der Zielwert nicht erreichbar - siehe naechste Zeile."),
- ("warn", "Pruefung", None, None, ""),
-]
-for key, label, fml, fmt, note in erg:
- uw.cell(rr, 2, label).font = BOLD
- c = uw.cell(rr, 3)
- c.font = Font(name=FONT, size=11, bold=True, color="008000")
- c.border = BOX
- if fmt:
- c.number_format = fmt
- if fml:
- c.value = fml
- uw.cell(rr, 4, note).font = Font(name=FONT, size=9, color="595959")
- U[key] = f"Umrechnung!$C${rr}"
- rr += 1
-uw[U['b_mtl'].split('!')[1].replace('$', '')] = f"={U['b_jahr']}/12"
-uw[U['warn'].split('!')[1].replace('$', '')] = (
- f'=IF({IN["modus"]}<>2,"nicht aktiv (Modus 1)",'
- f'IF(ABS({U["resid"]})>0.01,"ZIELWERT NICHT ERREICHBAR - Nettoaufwand uebersteigt das Gehalt","ok"))')
-uw[U['warn'].split('!')[1].replace('$', '')].font = Font(name=FONT, size=11, bold=True, color="C00000")
-
-# Der ab hier gueltige effektive Monatsbeitrag
-BEITRAG = f"IF({IN['modus']}=2,{U['b_mtl']},{IN['beitrag']})"
-
-# Rueckmeldung auf dem Eingabeblatt (unterhalb der drei Ergebniszeilen)
-ws.cell(res_end, 2, "Abgeleitet: Bruttobeitrag pro Monat").font = BOLD
-cc = ws.cell(res_end, 3, f"={BEITRAG}")
-cc.font = GREEN
-cc.number_format = EUR2
-ws.cell(res_end, 5, "Bei Modus 2 aus dem Nettoaufwand zurueckgerechnet, bei Modus 1 Ihre Eingabe.").font = Font(name=FONT, size=9, color="595959")
-ws.cell(res_end + 1, 2, "Abgeleitet: Nettoaufwand pro Monat (erstes Jahr)").font = BOLD
-cc = ws.cell(res_end + 1, 3)
-cc.font = GREEN
-cc.number_format = EUR2
-ws.cell(res_end + 1, 5, "Der tatsaechlich aufgegebene Konsum: Bruttobeitrag minus Steuer- und SV-Ersparnis.").font = Font(name=FONT, size=9, color="595959")
-NETTO_DISPLAY_CELL = ws.cell(res_end + 1, 3)
-
-# =====================================================================
-# 3) ANSPARPHASE
-# =====================================================================
-aw = wb.create_sheet("Ansparphase")
-aw.sheet_view.showGridLines = False
-aw.freeze_panes = "C8"
-
-A_COLS = [
- ("jahr", "Kalender-\njahr", 8, '0'),
- ("alter", "Alter", 7, '0'),
- ("aktiv", "erwerbs-\ntaetig", 7, '0'),
- ("anspar", "Anspar-\nphase", 7, '0'),
- ("lohnidx", "Lohn-\nindex", 8, NUM4),
- ("lam", "Tarif-\nindex L", 8, NUM4),
- ("tz", "Teilzeit-\nfaktor", 8, PCT1),
- ("brutto", "Brutto-\ngehalt", 11, EUR),
- ("bbgrv", "BBG RV", 11, EUR),
- ("bbgkv", "BBG KV", 11, EUR),
- ("bav_br", "bAV Brutto-\nbeitrag", 11, EUR),
- ("bav_stf", "davon st.-\nfrei 3/63", 11, EUR),
- ("bav_svf", "davon\nsv-frei", 11, EUR),
- ("agz_fx", "AG-Zuschuss\nfest", 11, EUR),
- ("agz_var", "AG-Zuschuss\nprozentual", 11, EUR),
- ("agz", "AG-\nZuschuss", 11, EUR),
- ("bav_ein", "Einzahlung\nbAV gesamt", 11, EUR),
- ("bav_gef", "davon ge-\nfoerdert 3/63", 12, EUR),
- ("bav_ngef", "davon NICHT\ngefoerdert", 12, EUR),
- ("drv", "D RV-Be-\nmessung", 11, EUR),
- ("dkv", "D KV-Be-\nmessung", 11, EUR),
- ("sverp", "SV-Ersparnis\nAN", 11, EUR),
- ("sverp_ag", "SV-Ersparnis\nAG", 11, EUR),
- ("vors_o", "Vorsorgeaufw.\nohne bAV", 12, EUR),
- ("vors_m", "Vorsorgeaufw.\nmit bAV", 12, EUR),
- ("zve_o", "zvE ohne\nbAV", 11, EUR),
- ("zve_m", "zvE mit\nbAV", 11, EUR),
- ("arg_o", "Tarifarg.\nohne", 11, EUR),
- ("est_o", "ESt ohne", 11, EUR),
- ("stg_o", "Steuer ges.\nohne", 11, EUR),
- ("arg_m", "Tarifarg.\nmit bAV", 11, EUR),
- ("est_m", "ESt mit\nbAV", 11, EUR),
- ("stg_m", "Steuer ges.\nmit bAV", 11, EUR),
- ("sterp", "Steuer-\nersparnis", 11, EUR),
- ("netto_a", "NETTO-\nAUFWAND", 12, EUR),
- ("av_eig", "AV-Depot\nEigenbeitrag", 12, EUR),
- ("av_zg", "Grund-\nzulage", 10, EUR),
- ("av_zk", "Kinder-\nzulage", 10, EUR),
- ("av_zul", "Zulage\ngesamt", 10, EUR),
- ("av_sa", "Sonderausg.\n10a", 11, EUR),
- ("zve_av", "zvE mit\nAV-SA", 11, EUR),
- ("arg_av", "Tarifarg.\nAV", 11, EUR),
- ("est_av", "ESt AV", 11, EUR),
- ("stg_av", "Steuer ges.\nAV", 11, EUR),
- ("av_vort", "Steuervorteil\ngesamt", 12, EUR),
- ("av_erst", "zusaetzl.\nErstattung", 11, EUR),
- ("av_gef", "Zufluss ge-\nfoerdert", 11, EUR),
- ("av_ngef", "Zufluss nicht\ngefoerdert", 12, EUR),
- ("av_ueber", "Ueberschuss\n> Hoechstbetr.", 12, EUR),
- ("priv_ein", "Einzahlung\nPrivatdepot", 12, EUR),
- ("k_bav_g", "KAPITAL bAV\ngefoerdert", 13, EUR),
- ("k_bav_n", "KAPITAL bAV\nnicht gefoerd.", 13, EUR),
- ("k_gef", "KAPITAL AV\ngefoerdert", 13, EUR),
- ("k_ngef", "KAPITAL AV\nnicht gef.", 13, EUR),
- ("sl_w", "Sleeve Wert", 12, EUR),
- ("sl_b", "Sleeve Basis", 12, EUR),
- ("sl_vp", "Sleeve VP", 11, EUR),
- ("sl_st", "Sleeve VP-\nSteuer", 11, EUR),
- ("pr_w", "KAPITAL\nPrivatdepot", 13, EUR),
- ("pr_b", "Kostenbasis\nPrivatdepot", 12, EUR),
- ("pr_vp", "Vorab-\npauschale", 11, EUR),
- ("pr_st", "Steuer auf\nVorabpausch.", 12, EUR),
- ("dep", "D Entgelt-\npunkte", 10, NUM4),
- ("dep_k", "kumulierte\nEP-Verluste", 11, NUM4),
-]
-AC = {k: gcl(i + 1) for i, (k, _, _, _) in enumerate(A_COLS)}
-AI = {k: i + 1 for i, (k, _, _, _) in enumerate(A_COLS)}
-AFMT = {k: ff for k, _, _, ff in A_COLS}
-
-aw['A1'] = "Ansparphase - Jahr fuer Jahr"
-aw['A1'].font = H1
-aw['A2'] = ("Vergleichsprinzip: gleicher NETTOAUFWAND. Der Nettoaufwand der Entgeltumwandlung (Spalte "
- + AC['netto_a'] + ") wird in den beiden anderen Optionen investiert. Der Arbeitgeberzuschuss ist "
- "das Zusatzgeld, das nur die bAV bekommt.")
-aw['A2'].font = Font(name=FONT, size=9, italic=True, color="595959")
-
-for k, head, w, fmt in A_COLS:
- col = AC[k]
- aw.column_dimensions[col].width = w
- c = aw.cell(7, AI[k], head)
- c.font = HEADFONT
- c.fill = HEADFILL
- c.alignment = Alignment(wrap_text=True, vertical="center", horizontal="center")
-aw.row_dimensions[7].height = 34
-
-N = 50
-R0 = 8
-for t in range(N):
- r = R0 + t
- p = r - 1
- first = (t == 0)
-
- def f(k, s):
- cell = aw.cell(r, AI[k], s)
- cell.number_format = AFMT[k]
- cell.font = BLACK
- return cell
-
- C = {k: f"{AC[k]}{r}" for k in AC}
- Cp = {k: f"{AC[k]}{p}" for k in AC}
-
- f("jahr", f"=2026+{t}")
- f("alter", f"={IN['alter']}+{t}")
- f("aktiv", f"=IF(AND({C['alter']}<{IN['ausscheid']},{C['alter']}<{IN['rentbeg']}),1,0)")
- f("anspar", f"=IF({C['alter']}<{IN['rentbeg']},1,0)")
- f("lohnidx", f"=(1+{IN['gsteig']})^{t}")
- f("lam", f"=(1+{IN['tarifanp']})^{t}")
- f("tz", f"=IF({C['alter']}>={IN['tzalter']},{IN['tzfaktor']},1)")
- f("brutto", f"={IN['gehalt']}*{C['lohnidx']}*{C['tz']}*{C['aktiv']}")
- f("bbgrv", f"={P['bbg_rv']}*{C['lohnidx']}")
- f("bbgkv", f"={P['bbg_kv']}*{C['lohnidx']}")
-
- # bAV
- f("bav_br", f"=MIN({C['brutto']},12*({BEITRAG})*IF({IN['dyn']}=1,{C['lohnidx']},1))*{C['aktiv']}")
- # Fester, betragsunabhaengiger Zuschuss. Faellt weg, wenn der eigene
- # Monatsbeitrag die vereinbarte Mindestschwelle nicht erreicht.
- f("agz_fx", f"={C['aktiv']}*IF({C['bav_br']}/12+0.000000001<{IN['agz_fix_min']},0,"
- f"12*{IN['agz_fix']}*IF({IN['agz_fix_dyn']}=1,{C['lohnidx']},1))")
- # Der 4-%-Topf des 1 Abs. 1 S. 1 Nr. 9 SvEV und der 8-%-Topf des 3 Nr. 63 EStG
- # werden zuerst vom Arbeitgeberbeitrag belegt, der Rest steht der Entgelt-
- # umwandlung des Arbeitnehmers zur Verfuegung.
- f("bav_svf", f"=MIN({C['bav_br']},MAX(0,{P['sv_frei_q']}*{C['bbgrv']}-{C['agz_fx']}))")
- # Modus 2 ( 1a Abs. 1a BetrAVG woertlich): Zuschuss nur bis zur tatsaechlichen
- # Ersparnis des Arbeitgebers. Oberhalb beider Beitragsbemessungsgrenzen ist sie null.
- # Der feste Zuschuss ist davon unberuehrt und kommt oben drauf.
- f("agz_var", f"=IF({IN['agzus_sv']}=2,MIN({IN['agzus']}*{C['bav_br']},{C['sverp_ag']}),"
- f"{IN['agzus']}*IF({IN['agzus_sv']}=1,{C['bav_svf']},{C['bav_br']}))")
- f("agz", f"={C['agz_var']}+{C['agz_fx']}")
- f("bav_stf", f"=MIN({C['bav_br']},MAX(0,{P['st_frei_q']}*{C['bbgrv']}-{C['agz']}))")
- f("bav_ein", f"={C['bav_br']}+{C['agz']}")
- f("bav_gef", f"=MIN({C['bav_ein']},{P['st_frei_q']}*{C['bbgrv']})")
- f("bav_ngef", f"={C['bav_ein']}-{C['bav_gef']}")
- f("drv", f"=MIN({C['brutto']},{C['bbgrv']})-MIN({C['brutto']}-{C['bav_svf']},{C['bbgrv']})")
- f("dkv", f"=MIN({C['brutto']},{C['bbgkv']})-MIN({C['brutto']}-{C['bav_svf']},{C['bbgkv']})")
- f("sverp", f"={C['drv']}*({P['rv_an']}+{P['av_an']})+{C['dkv']}*(({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
- # Arbeitgeberanteil: gleiche Haelften, aber ohne den Kinderlosenzuschlag zur Pflegeversicherung.
- f("sverp_ag", f"={C['drv']}*({P['rv_an']}+{P['av_an']})+{C['dkv']}*(({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an']})")
-
- # zvE
- f("vors_o", f"=MIN({C['brutto']},{C['bbgrv']})*{P['rv_an']}"
- f"+MIN({C['brutto']},{C['bbgkv']})*(0.96*({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
- f("vors_m", f"=MIN({C['brutto']}-{C['bav_svf']},{C['bbgrv']})*{P['rv_an']}"
- f"+MIN({C['brutto']}-{C['bav_svf']},{C['bbgkv']})*(0.96*({P['kv_allg']}+{P['kv_zus']})/2+{P['pv_an_eff']})")
- f("zve_o", f"=MAX(0,{C['brutto']}-{P['an_pausch']}*{C['lam']}-{P['sa_pausch']}-{C['vors_o']})")
- f("zve_m", f"=MAX(0,{C['brutto']}-{C['bav_stf']}-{P['an_pausch']}*{C['lam']}-{P['sa_pausch']}-{C['vors_m']})")
- f("arg_o", arg_formula(C['zve_o'], C['lam']))
- f("est_o", est_formula(C['arg_o'], C['lam']))
- f("stg_o", steuer_ges(C['est_o'], C['lam']))
- f("arg_m", arg_formula(C['zve_m'], C['lam']))
- f("est_m", est_formula(C['arg_m'], C['lam']))
- f("stg_m", steuer_ges(C['est_m'], C['lam']))
- f("sterp", f"={C['stg_o']}-{C['stg_m']}")
- f("netto_a", f"=MAX(0,{C['bav_br']}-{C['sverp']}-{C['sterp']})")
-
- # Altersvorsorgedepot
- f("av_eig", f"=MIN({C['netto_a']},{P['av_max']})")
- f("av_zg", f"={P['zul_g1']}*MIN({C['av_eig']},{P['zul_s1']})"
- f"+{P['zul_g2']}*MAX(0,MIN({C['av_eig']},{P['zul_s2']})-{P['zul_s1']})")
- f("av_zk", f"=MIN({C['av_eig']},{P['kind_zul']})*{IN['kinder']}*IF({t}<{IN['kind_jahre']},1,0)")
- f("av_zul", f"=MIN({C['av_zg']}+{C['av_zk']},MAX(0,{P['av_max']}-{C['av_eig']}))")
- f("av_sa", f"=MIN(MIN({C['av_eig']},{P['zul_s2']})+{C['av_zul']},{P['av_sa_max']})")
- f("zve_av", f"=MAX(0,{C['zve_o']}-{C['av_sa']})")
- f("arg_av", arg_formula(C['zve_av'], C['lam']))
- f("est_av", est_formula(C['arg_av'], C['lam']))
- f("stg_av", steuer_ges(C['est_av'], C['lam']))
- f("av_vort", f"={C['stg_o']}-{C['stg_av']}")
- f("av_erst", f"=MAX(0,{C['av_vort']}-{C['av_zul']})")
- f("av_gef", f"=MIN({C['av_eig']},{P['zul_s2']})+{C['av_zul']}")
- f("av_ngef", f"=MAX(0,{C['av_eig']}-{P['zul_s2']})+" + ("0" if first else f"{Cp['av_erst']}"))
- f("av_ueber", f"=MAX(0,{C['netto_a']}-{P['av_max']})")
- f("priv_ein", f"={C['netto_a']}")
-
- # Kapitalentwicklung
- gb = f"(1+{P['rnet_bav']})"
- ga = f"(1+{P['rnet_av']})"
- gp = f"(1+{P['rnet_priv']})"
- prev_kbg = "0" if first else Cp['k_bav_g']
- f("k_bav_g", f"=IF({C['anspar']}=0,{prev_kbg},{prev_kbg}*{gb}+{C['bav_gef']}*{gb}^0.5)")
- prev_kbn = "0" if first else Cp['k_bav_n']
- f("k_bav_n", f"=IF({C['anspar']}=0,{prev_kbn},{prev_kbn}*{gb}+{C['bav_ngef']}*{gb}^0.5)")
- prev_gef = "0" if first else Cp['k_gef']
- f("k_gef", f"=IF({C['anspar']}=0,{prev_gef},{prev_gef}*{ga}+{C['av_gef']}*{ga}^0.5)")
- prev_ngef = "0" if first else Cp['k_ngef']
- f("k_ngef", f"=IF({C['anspar']}=0,{prev_ngef},{prev_ngef}*{ga}+{C['av_ngef']}*{ga}^0.5)")
-
- # Sleeve (Ueberschuss ueber den Hoechstbetrag; Behandlung wie Privatdepot)
- prev_slw = "0" if first else Cp['sl_w']
- prev_slb = "0" if first else Cp['sl_b']
- f("sl_vp", f"=MAX(0,MIN({prev_slw}*{gp}+{C['av_ueber']}*{gp}^0.5-{prev_slw}-{C['av_ueber']},"
- f"{prev_slw}*{P['basiszins']}*{P['vp_faktor']}))")
- f("sl_st", f"=MAX(0,{C['sl_vp']}*(1-{P['tfs']})-{P['sparerpb_eff']})*{P['kapst_eff']}")
- f("sl_w", f"=IF({C['anspar']}=0,{prev_slw},{prev_slw}*{gp}+{C['av_ueber']}*{gp}^0.5-{C['sl_st']})")
- f("sl_b", f"=IF({C['anspar']}=0,{prev_slb},{prev_slb}+{C['av_ueber']}+{C['sl_vp']})")
-
- # Privatdepot
- prev_prw = "0" if first else Cp['pr_w']
- prev_prb = "0" if first else Cp['pr_b']
- f("pr_vp", f"=MAX(0,MIN({prev_prw}*{gp}+{C['priv_ein']}*{gp}^0.5-{prev_prw}-{C['priv_ein']},"
- f"{prev_prw}*{P['basiszins']}*{P['vp_faktor']}))")
- f("pr_st", f"=MAX(0,{C['pr_vp']}*(1-{P['tfs']})-{P['sparerpb_eff']})*{P['kapst_eff']}")
- f("pr_w", f"=IF({C['anspar']}=0,{prev_prw},{prev_prw}*{gp}+{C['priv_ein']}*{gp}^0.5-{C['pr_st']})")
- f("pr_b", f"=IF({C['anspar']}=0,{prev_prb},{prev_prb}+{C['priv_ein']}+{C['pr_vp']})")
-
- # Entgeltpunkte
- f("dep", f"={C['drv']}/({P['de_rv']}*{C['lohnidx']})")
- prev_dep = "0" if first else Cp['dep_k']
- f("dep_k", f"={prev_dep}+{C['dep']}")
-
- if t % 2 == 1:
- for k in AI:
- aw.cell(r, AI[k]).fill = PatternFill("solid", fgColor="F2F2F2")
-
-LAST = R0 + N - 1
-NETTO_DISPLAY_CELL.value = f"=Ansparphase!${AC['netto_a']}${R0}/12"
-
-# =====================================================================
-# 4) AUSZAHLUNG
-# =====================================================================
-zw = wb.create_sheet("Auszahlung")
-zw.sheet_view.showGridLines = False
-zw.freeze_panes = "C8"
-
-Z_COLS = [
- ("jahr", "Kalender-\njahr", 8, '0'),
- ("alter", "Alter", 7, '0'),
- ("t", "Jahr t seit\nheute", 8, '0'),
- ("lam", "Tarif-\nindex L", 8, NUM4),
- ("lohn", "Lohn-\nindex", 8, NUM4),
- ("plan", "Plan\naktiv", 6, '0'),
- ("sonst", "sonstiges\nzvE", 11, EUR),
- ("arg_b", "Tarifarg.\nBasis", 11, EUR),
- ("est_b", "ESt Basis", 11, EUR),
- ("stg_b", "Steuer ges.\nBasis", 11, EUR),
- ("bav_br_g", "bAV Zufluss\ngefoerdert", 12, EUR),
- ("bav_br_n", "bAV Zufluss\nnicht gefoerd.", 12, EUR),
- ("bav_br", "bAV Brutto-\nzufluss gesamt", 12, EUR),
- ("bav_stpfl", "davon steuer-\npflichtig", 12, EUR),
- ("bav_vb", "Versorgungs-\nbezug/Monat", 12, EUR),
- ("rente_m", "gesetzl. Rente\n/Monat", 12, EUR),
- ("vb_bpfl", "VB beitrags-\npflichtig (BBG)", 12, EUR),
- ("bav_kv", "KV auf bAV", 11, EUR),
- ("bav_pv", "PV auf bAV", 11, EUR),
- ("bav_kvpv", "KV+PV\nauf bAV", 11, EUR),
- ("mind_br", "Rentenminde-\nrung brutto", 12, EUR),
- ("mind_st", "Rentenminderung\nsteuerpflichtig", 13, EUR),
- ("mind_kv", "KV+PV-Erspar-\nnis Rente", 12, EUR),
- ("zve_bav", "zvE Option\nbAV", 11, EUR),
- ("arg_bav", "Tarifarg.\nbAV", 11, EUR),
- ("est_bav", "ESt bAV", 11, EUR),
- ("stg_bav", "Steuer ges.\nbAV", 11, EUR),
- ("zve_f", "zvE Fuenftel-\nregelung", 12, EUR),
- ("arg_f", "Tarifarg.\nFuenftel", 11, EUR),
- ("est_f", "ESt Fuenftel", 11, EUR),
- ("stg_f", "Steuer ges.\nFuenftel", 11, EUR),
- ("st_bav", "STEUER auf\nbAV (netto)", 12, EUR),
- ("bav_net", "NETTO bAV\n(nach Renten-\nminderung)", 13, EUR),
- ("gef_a", "AV gefoerdert\nStand", 12, EUR),
- ("gef_e", "Entnahme\ngefoerdert", 11, EUR),
- ("ngef_a", "AV nicht gef.\nStand", 12, EUR),
- ("ngef_e", "Entnahme\nnicht gef.", 11, EUR),
- ("sl_a", "Sleeve\nStand", 11, EUR),
- ("sl_e", "Sleeve\nEntnahme", 11, EUR),
- ("sl_st", "Sleeve\nSteuer", 11, EUR),
- ("ngef_ek", "davon Kapital\n(nicht gef.)", 12, EUR),
- ("ngef_er", "davon Rente\n(nicht gef.)", 12, EUR),
- ("av_rest", "MEMO AV-Rente\nnach dem Horizont", 14, EUR),
- ("av_stpfl", "steuerpfl.\nAV-Entnahme", 12, EUR),
- ("zve_av", "zvE Option\nAV-Depot", 11, EUR),
- ("arg_av", "Tarifarg.\nAV", 11, EUR),
- ("est_av", "ESt AV", 11, EUR),
- ("stg_av", "Steuer ges.\nAV", 11, EUR),
- ("av_net", "NETTO Alters-\nvorsorgedepot", 13, EUR),
- ("pr_a", "Privatdepot\nStand", 12, EUR),
- ("pr_ba", "Kostenbasis\nStand", 12, EUR),
- ("pr_e", "Entnahme\nPrivatdepot", 12, EUR),
- ("pr_g", "Gewinnanteil\nder Entnahme", 12, EUR),
- ("pr_st", "Abgeltung-\nsteuer", 11, EUR),
- ("pr_net", "NETTO privates\nETF-Depot", 13, EUR),
- ("df", "Diskont-\nfaktor", 9, NUM4),
- ("bav_rest", "MEMO bAV-Rente\nnach dem Horizont", 14, EUR),
- ("dfr", "Abzinsung auf\nRentenbeginn", 12, NUM4),
-]
-ZC = {k: gcl(i + 1) for i, (k, _, _, _) in enumerate(Z_COLS)}
-ZI = {k: i + 1 for i, (k, _, _, _) in enumerate(Z_COLS)}
-ZFMT = {k: ff for k, _, _, ff in Z_COLS}
-
-zw['A1'] = "Auszahlungsphase"
-zw['A1'].font = H1
-zw['A2'] = ("Alle drei Optionen sind Alternativen zueinander - die Spalten NETTO ... sind daher nebeneinander, "
- "nicht additiv zu lesen. Bei der bAV ist der Verlust an gesetzlicher Rente bereits abgezogen.")
-zw['A2'].font = Font(name=FONT, size=9, italic=True, color="595959")
-
-for k, head, w, fmt in Z_COLS:
- zw.column_dimensions[ZC[k]].width = w
- c = zw.cell(7, ZI[k], head)
- c.font = HEADFONT
- c.fill = HEADFILL
- c.alignment = Alignment(wrap_text=True, vertical="center", horizontal="center")
-zw.row_dimensions[7].height = 40
-
-# Startkapitalien (aus der Ansparphase, Zeile LAST)
-KBG = f"Ansparphase!${AC['k_bav_g']}${LAST}"
-KBN = f"Ansparphase!${AC['k_bav_n']}${LAST}"
-KB = f"({KBG}+{KBN})"
-KG = f"Ansparphase!${AC['k_gef']}${LAST}"
-KN = f"Ansparphase!${AC['k_ngef']}${LAST}"
-KS = f"Ansparphase!${AC['sl_w']}${LAST}"
-KSB = f"Ansparphase!${AC['sl_b']}${LAST}"
-KP = f"Ansparphase!${AC['pr_w']}${LAST}"
-KPB = f"Ansparphase!${AC['pr_b']}${LAST}"
-EPK = f"Ansparphase!${AC['dep_k']}${LAST}"
-
-NZ = 34
-Z0 = 8
-# Annuitaetenfaktoren
-zw['CE4'] = "Annuitaetenfaktor Altersvorsorgedepot"
-zw['CE4'].font = Font(name=FONT, size=9, color="595959")
-zw['CG4'] = f"=IF({P['rnet_av']}=0,1/{P['n_ausz']},{P['rnet_av']}/(1-(1+{P['rnet_av']})^(-{P['n_ausz']})))"
-zw['CG4'].number_format = PCT
-zw['CE5'] = "Annuitaetenfaktor privates Depot"
-zw['CE5'].font = Font(name=FONT, size=9, color="595959")
-zw['CG5'] = f"=IF({P['rnet_priv']}=0,1/{P['n_ausz']},{P['rnet_priv']}/(1-(1+{P['rnet_priv']})^(-{P['n_ausz']})))"
-zw['CG5'].number_format = PCT
-ANN_AV = "$CG$4"
-ANN_PR = "$CG$5"
-
-for t in range(NZ):
- r = Z0 + t
- p = r - 1
- first = (t == 0)
-
- def g(k, s):
- cell = zw.cell(r, ZI[k], s)
- cell.number_format = ZFMT[k]
- cell.font = BLACK
- return cell
-
- C = {k: f"{ZC[k]}{r}" for k in ZC}
- Cp = {k: f"{ZC[k]}{p}" for k in ZC}
-
- g("alter", f"={IN['rentbeg']}+{t}")
- g("t", f"={C['alter']}-{IN['alter']}")
- g("jahr", f"=2026+{C['t']}")
- g("lam", f"=(1+{IN['tarifanp']})^{C['t']}")
- g("lohn", f"=(1+{IN['gsteig']})^{C['t']}")
- g("plan", f"=IF({C['alter']}<={IN['planende']},1,0)")
- g("sonst", f"={IN['sonst_zve']}*(1+{IN['infl']})^{C['t']}")
- g("arg_b", arg_formula(C['sonst'], C['lam']))
- g("est_b", est_formula(C['arg_b'], C['lam']))
- g("stg_b", steuer_ges(C['est_b'], C['lam']))
-
- # --- bAV
- g("df", f"=1/(1+{IN['infl']})^{C['t']}")
- g("dfr", f"=1/(1+{P['wiederanl']})^{t}")
- g("bav_rest", f"=IF(AND({IN['auszform']}=2,{C['plan']}=0),"
- f"{KB}*{IN['rentfak']}/10000*12*(1+{IN['rentdyn']})^{t},0)")
- kap0 = "1" if first else "0"
- rente = f"{KB}*{IN['rentfak']}/10000*12*(1+{IN['rentdyn']})^{t}*{C['plan']}"
- g("bav_br_g", f"=IF({IN['auszform']}=1,IF({kap0}=1,{KBG},0),"
- f"{rente}*IF({KB}=0,0,{KBG}/{KB}))")
- g("bav_br_n", f"=IF({IN['auszform']}=1,IF({kap0}=1,{KBN},0),"
- f"{rente}*IF({KB}=0,0,{KBN}/{KB}))")
- g("bav_br", f"={C['bav_br_g']}+{C['bav_br_n']}")
- # Gefoerderte Schicht: voll nachgelagert ( 22 Nr. 5 S. 1 EStG).
- # Nicht gefoerderte Schicht: Kapital = halber Unterschiedsbetrag ( 22 Nr. 5 S. 2 Buchst. b
- # i.V.m. 20 Abs. 1 Nr. 6 S. 2 EStG), Rente = Ertragsanteil ( 22 Nr. 5 S. 2 Buchst. a).
- g("bav_stpfl", f"={C['bav_br_g']}+{C['bav_br_n']}*IF({IN['auszform']}=1,"
- f"(1-IF({KBN}=0,1,MIN(1,$CG$8/{KBN})))*{P['halb']},{P['ertragsq']})")
- # Versorgungsbezug pro Monat: Kapital 1/120 fuer 120 Monate, Rente laufend
- g("bav_vb", f"=IF({IN['auszform']}=1,IF({t}<10,{KB}/120,0),{C['bav_br']}/12)")
- g("rente_m", f"={IN['rente_br']}/12*(1+{IN['gsteig']})^{C['t']}")
- # 223 Abs. 3 SGB V: Rente und Versorgungsbezuege teilen sich EINE Beitragsbemessungsgrenze.
- g("vb_bpfl", f"=MAX(0,MIN({C['bav_vb']},{P['bbg_kv']}/12*{C['lohn']}-{C['rente_m']}))")
- g("bav_kv", f"=IF({IN['kv_ruhe']}=2,0,MAX(0,{C['vb_bpfl']}-{P['frei_vb']}*{C['lohn']})*{P['kv_vb']}*12)")
- g("bav_pv", f"=IF({IN['kv_ruhe']}=2,0,IF({C['bav_vb']}>{P['frei_vb']}*{C['lohn']},{C['vb_bpfl']}*{P['pv_ges_eff']}*12,0))")
- g("bav_kvpv", f"={C['bav_kv']}+{C['bav_pv']}")
-
- g("mind_br", f"={EPK}*{P['rw']}*12*(1+{IN['gsteig']})^({IN['rentbeg']}-{IN['alter']})*(1+{IN['gsteig']})^{t}*{C['plan']}")
- g("mind_st", f"={C['mind_br']}*{P['best_anteil']}")
- g("mind_kv", f"=IF({IN['kv_ruhe']}=2,0,{C['mind_br']}*({P['kv_rentner']}+{P['pv_ges_eff']}))")
-
- g("zve_bav", f"=MAX(0,{C['sonst']}-{C['mind_st']}+{C['bav_stpfl']}-{C['bav_kvpv']}+{C['mind_kv']})")
- g("arg_bav", arg_formula(C['zve_bav'], C['lam']))
- g("est_bav", est_formula(C['arg_bav'], C['lam']))
- g("stg_bav", steuer_ges(C['est_bav'], C['lam']))
- g("zve_f", f"=MAX(0,{C['sonst']}-{C['mind_st']}+{C['bav_stpfl']}/5-{C['bav_kvpv']}+{C['mind_kv']})")
- g("arg_f", arg_formula(C['zve_f'], C['lam']))
- g("est_f", est_formula(C['arg_f'], C['lam']))
- g("stg_f", steuer_ges(C['est_f'], C['lam']))
- g("st_bav", f"=IF(AND({IN['fuenftel']}=1,{IN['auszform']}=1,{C['bav_br']}>0),"
- f"MIN({C['stg_bav']}-{C['stg_b']},5*({C['stg_f']}-{C['stg_b']})),{C['stg_bav']}-{C['stg_b']})")
- g("bav_net", f"={C['bav_br']}-{C['bav_kvpv']}-{C['st_bav']}-{C['mind_br']}+{C['mind_kv']}")
-
- # --- Altersvorsorgedepot
- if first:
- g("gef_a", f"={KG}")
- g("ngef_a", f"={KN}")
- g("sl_a", f"={KS}")
- g("pr_a", f"={KP}")
- g("pr_ba", f"={KPB}")
- else:
- # Bei Verrentung geht das Restkapital an den Versicherer; ein Depotkonto
- # gibt es danach nicht mehr.
- g("gef_a", f"=IF({IN['av_auszform']}=2,0,MAX(0,({Cp['gef_a']}-{Cp['gef_e']})*(1+{P['rnet_av']})))")
- g("ngef_a", f"=IF({IN['av_auszform']}=2,0,MAX(0,({Cp['ngef_a']}-{Cp['ngef_e']})*(1+{P['rnet_av']})))")
- g("sl_a", f"=MAX(0,({Cp['sl_a']}-{Cp['sl_e']})*(1+{P['rnet_priv']}))")
- g("pr_a", f"=MAX(0,({Cp['pr_a']}-{Cp['pr_e']})*(1+{P['rnet_priv']}))")
- g("pr_ba", f"=MAX(0,{Cp['pr_ba']}-{Cp['pr_ba']}*IF({Cp['pr_a']}=0,0,{Cp['pr_e']}/{Cp['pr_a']}))")
-
- tk = f"IF({t}=0,{IN['teilkap']},0)"
- # Verrentetes Restkapital je Schicht und insgesamt
- KGR = f"({KG}*(1-{IN['teilkap']}))"
- KNR = f"({KN}*(1-{IN['teilkap']}))"
- KRR = f"({KGR}+{KNR})"
- # Laufende Depotrente; die Aufteilung auf die Schichten folgt ihrem Anteil
- # am verrenteten Kapital, genau wie bei der bAV.
- rente_av = f"{KRR}*{IN['rentfak_av']}/10000*12*(1+{IN['rentdyn_av']})^{t}*{C['plan']}"
- g("av_rest", f"=IF(AND({IN['av_auszform']}=2,{C['plan']}=0),"
- f"{KRR}*{IN['rentfak_av']}/10000*12*(1+{IN['rentdyn_av']})^{t},0)")
- g("gef_e", f"=IF({IN['av_auszform']}=1,"
- f"IF({C['plan']}=0,0,MIN({C['gef_a']},{KG}*{tk}+{KGR}*{ANN_AV})),"
- f"{KG}*{tk}+({rente_av})*IF({KRR}=0,0,{KGR}/{KRR}))")
- g("ngef_ek", f"=IF({IN['av_auszform']}=1,"
- f"IF({C['plan']}=0,0,MIN({C['ngef_a']},{KN}*{tk}+{KNR}*{ANN_AV})),"
- f"{KN}*{tk})")
- g("ngef_er", f"=IF({IN['av_auszform']}=1,0,({rente_av})*IF({KRR}=0,0,{KNR}/{KRR}))")
- g("ngef_e", f"={C['ngef_ek']}+{C['ngef_er']}")
- g("sl_e", f"=IF({C['plan']}=0,0,MIN({C['sl_a']},{KS}*{ANN_PR}))")
- g("sl_st", f"=MAX(0,{C['sl_e']}*(1-IF({KS}=0,1,MIN(1,{KSB}/{KS})))*(1-{P['tfs']}))*{P['kapst_eff']}")
- g("av_stpfl", f"={C['gef_e']}+{C['ngef_ek']}*(1-IF({KN}=0,1,MIN(1,"
- f"Ansparphase!SUMPRODUCT_PLACEHOLDER)))*{P['halb']}+{C['ngef_er']}*{P['ertragsq']}")
- g("zve_av", f"=MAX(0,{C['sonst']}+{C['av_stpfl']})")
- g("arg_av", arg_formula(C['zve_av'], C['lam']))
- g("est_av", est_formula(C['arg_av'], C['lam']))
- g("stg_av", steuer_ges(C['est_av'], C['lam']))
- g("av_net", f"={C['gef_e']}+{C['ngef_e']}-({C['stg_av']}-{C['stg_b']})+{C['sl_e']}-{C['sl_st']}")
-
- # --- Privatdepot
- g("pr_e", f"=IF({C['plan']}=0,0,MIN({C['pr_a']},{KP}*{ANN_PR}))")
- g("pr_g", f"={C['pr_e']}-IF({C['pr_a']}=0,0,{C['pr_ba']}*{C['pr_e']}/{C['pr_a']})")
- g("pr_st", f"=MAX(0,{C['pr_g']}*(1-{P['tfs']})-{P['sparerpb_eff']})*{P['kapst_eff']}")
- g("pr_net", f"={C['pr_e']}-{C['pr_st']}")
-
- if t % 2 == 1:
- for k in ZI:
- zw.cell(r, ZI[k]).fill = PatternFill("solid", fgColor="F2F2F2")
-
-ZLAST = Z0 + NZ - 1
-
-# Summe der nicht gefoerderten Eigenbeitraege (fuer die Ertragsquote)
-zw['CE7'] = "Summe nicht gefoerderter Eigenbeitraege (Anschaffungskosten)"
-zw['CE7'].font = Font(name=FONT, size=9, color="595959")
-zw['CG7'] = f"=SUM(Ansparphase!${AC['av_ngef']}${R0}:${AC['av_ngef']}${LAST})"
-zw['CG7'].number_format = EUR
-zw['CE8'] = "Summe nicht gefoerderter bAV-Beitraege (Anschaffungskosten)"
-zw['CE8'].font = Font(name=FONT, size=9, color="595959")
-zw['CG8'] = f"=SUM(Ansparphase!${AC['bav_ngef']}${R0}:${AC['bav_ngef']}${LAST})"
-zw['CG8'].number_format = EUR
-for t in range(NZ):
- r = Z0 + t
- zw.cell(r, ZI['av_stpfl']).value = (
- f"={ZC['gef_e']}{r}+{ZC['ngef_ek']}{r}*(1-IF({KN}=0,1,MIN(1,$CG$7/{KN})))*{P['halb']}"
- f"+{ZC['ngef_er']}{r}*{P['ertragsq']}")
-
-# =====================================================================
-# 5) CASHFLOW / IRR
-# =====================================================================
-cw = wb.create_sheet("Cashflow")
-cw.sheet_view.showGridLines = False
-cw['A1'] = "Zahlungsstroeme aus Sicht des Arbeitnehmers (fuer interne Zinsfuesse und Barwerte)"
-cw['A1'].font = H1
-cw['A2'] = "Negativ = Aufwand aus dem Netto, positiv = Netto-Zufluss. Alle drei Spalten haben in der Ansparphase denselben Aufwand."
-cw['A2'].font = Font(name=FONT, size=9, italic=True, color="595959")
-heads = ["Jahr", "Alter", "Nettoaufwand", "CF bAV (DYNO)", "CF Altersvorsorgedepot", "CF privates ETF-Depot",
- "Diskontfaktor", "BW bAV", "BW AV-Depot", "BW privat", "BW Aufwand"]
-for i, h in enumerate(heads):
- c = cw.cell(4, i + 1, h)
- c.font = HEADFONT
- c.fill = HEADFILL
- c.alignment = Alignment(wrap_text=True, horizontal="center")
- cw.column_dimensions[gcl(i + 1)].width = 15
-cw.row_dimensions[4].height = 30
-
-NCF = 65
-for t in range(NCF):
- r = 5 + t
- cw.cell(r, 1, f"=2026+{t}").number_format = '0'
- cw.cell(r, 2, f"={IN['alter']}+{t}").number_format = '0'
- aufw = (f"=IF({t}<{N},INDEX(Ansparphase!${AC['netto_a']}${R0}:${AC['netto_a']}${LAST},{t}+1),0)")
- cw.cell(r, 3, aufw).number_format = EUR
- for j, key in enumerate(['bav_net', 'av_net', 'pr_net']):
- col = ZC[key]
- cw.cell(r, 4 + j, f"=-$C{r}+IF(AND($B{r}>={IN['rentbeg']},$B{r}<={IN['rentbeg']}+{NZ}-1),"
- f"INDEX(Auszahlung!${col}${Z0}:${col}${ZLAST},$B{r}-{IN['rentbeg']}+1),0)").number_format = EUR
- cw.cell(r, 7, f"=1/(1+{IN['infl']})^{t}").number_format = NUM4
- cw.cell(r, 8, f"=$G{r}*(D{r}+$C{r})").number_format = EUR
- cw.cell(r, 9, f"=$G{r}*(E{r}+$C{r})").number_format = EUR
- cw.cell(r, 10, f"=$G{r}*(F{r}+$C{r})").number_format = EUR
- cw.cell(r, 11, f"=$G{r}*$C{r}").number_format = EUR
-CFLAST = 5 + NCF - 1
-
-# =====================================================================
-# 6) VERGLEICH
-# =====================================================================
-vw = wb.create_sheet("Vergleich")
-vw.sheet_view.showGridLines = False
-vw.column_dimensions['A'].width = 58
-for col in "BCD":
- vw.column_dimensions[col].width = 20
-vw.column_dimensions['E'].width = 86
-
-vw['A1'] = "Ergebnisvergleich"
-vw['A1'].font = H1
-vw['A2'] = "Alle drei Optionen kosten in der Ansparphase exakt denselben Betrag aus dem Netto."
-vw['A2'].font = Font(name=FONT, size=10, italic=True)
-
-for i, h in enumerate(["", "bAV mit DYNO", "Altersvorsorgedepot", "privates ETF-Depot", "Anmerkung"]):
- c = vw.cell(4, i + 1, h)
- c.font = HEADFONT
- c.fill = HEADFILL
- c.alignment = Alignment(horizontal="center", wrap_text=True)
-
-rows = [
- ("Summe eingezahlt aus dem Netto (nominal)",
- f"=SUM(Ansparphase!${AC['netto_a']}${R0}:${AC['netto_a']}${LAST})",
- "=B5", "=B5",
- "Identisch nach Konstruktion - das ist die Bedingung fuer einen fairen Vergleich."),
- ("Summe Fremdgeld (AG-Zuschuss bzw. Zulagen)",
- f"=SUM(Ansparphase!${AC['agz']}${R0}:${AC['agz']}${LAST})",
- f"=SUM(Ansparphase!${AC['av_zul']}${R0}:${AC['av_zul']}${LAST})",
- "=0",
- "Der Arbeitgeberzuschuss ist der eigentliche Grund, warum eine bAV attraktiv sein kann."),
- ("Kapital bei Auszahlungsbeginn (vor Steuern)",
- f"={KB}", f"={KG}+{KN}+{KS}", f"={KP}",
- "Beim Privatdepot ist die Vorabpauschale bereits jaehrlich abgezogen."),
- ("Summe Bruttoauszahlungen",
- f"=SUM(Auszahlung!${ZC['bav_br']}${Z0}:${ZC['bav_br']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['gef_e']}${Z0}:${ZC['gef_e']}${ZLAST})+SUM(Auszahlung!${ZC['ngef_e']}${Z0}:${ZC['ngef_e']}${ZLAST})+SUM(Auszahlung!${ZC['sl_e']}${Z0}:${ZC['sl_e']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['pr_e']}${Z0}:${ZC['pr_e']}${ZLAST})",
- "Nominal ueber den gesamten Auszahlungshorizont."),
- ("davon Einkommensteuer / Abgeltungsteuer",
- f"=SUM(Auszahlung!${ZC['st_bav']}${Z0}:${ZC['st_bav']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['stg_av']}${Z0}:${ZC['stg_av']}${ZLAST})-SUM(Auszahlung!${ZC['stg_b']}${Z0}:${ZC['stg_b']}${ZLAST})+SUM(Auszahlung!${ZC['sl_st']}${Z0}:${ZC['sl_st']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['pr_st']}${Z0}:${ZC['pr_st']}${ZLAST})",
- "bAV und Altersvorsorgedepot: nachgelagerte Besteuerung mit dem persoenlichen Grenzsteuersatz. Privatdepot: 25 % zzgl. Soli/KiSt auf 70 % des Gewinns. In der bAV-Spalte bereits saldiert mit der Steuerersparnis aus der geringeren gesetzlichen Rente."),
- ("davon Kranken- und Pflegeversicherung",
- f"=SUM(Auszahlung!${ZC['bav_kvpv']}${Z0}:${ZC['bav_kvpv']}${ZLAST})",
- "=0", "=0",
- "229 SGB V: Betriebsrenten sind Versorgungsbezuege, private Altersvorsorge nicht. In der PKV entfaellt das (Eingabe umstellen)."),
- ("Verlust an gesetzlicher Rente (brutto, kumuliert)",
- f"=SUM(Auszahlung!${ZC['mind_br']}${Z0}:${ZC['mind_br']}${ZLAST})",
- "=0", "=0",
- "Entgeltumwandlung mindert das rentenversicherungspflichtige Entgelt und damit die Entgeltpunkte."),
- ("Summe Netto-Auszahlungen (nominal)",
- f"=SUM(Auszahlung!${ZC['bav_net']}${Z0}:${ZC['bav_net']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['av_net']}${Z0}:${ZC['av_net']}${ZLAST})",
- f"=SUM(Auszahlung!${ZC['pr_net']}${Z0}:${ZC['pr_net']}${ZLAST})",
- "Nach Steuern, nach KV/PV, nach Abzug der gesetzlichen Rentenminderung."),
- ("Barwert der Netto-Auszahlungen (heutige Kaufkraft)",
- f"=SUMPRODUCT(Auszahlung!${ZC['bav_net']}${Z0}:${ZC['bav_net']}${ZLAST},Auszahlung!${ZC['df']}${Z0}:${ZC['df']}${ZLAST})",
- f"=SUMPRODUCT(Auszahlung!${ZC['av_net']}${Z0}:${ZC['av_net']}${ZLAST},Auszahlung!${ZC['df']}${Z0}:${ZC['df']}${ZLAST})",
- f"=SUMPRODUCT(Auszahlung!${ZC['pr_net']}${Z0}:${ZC['pr_net']}${ZLAST},Auszahlung!${ZC['df']}${Z0}:${ZC['df']}${ZLAST})",
- "Diskontiert mit der Inflationsrate - das ist die Groesse, die man vergleichen sollte."),
- ("Barwert des Nettoaufwands (heutige Kaufkraft)",
- f"=SUM(Cashflow!$K$5:$K${CFLAST})", "=B14", "=B14",
- "Ebenfalls identisch."),
- ("BARWERT DES NETTO-ERTRAGS (Ertrag minus Aufwand)",
- "=B13-B14", "=C13-C14", "=D13-D14",
- "Das Hauptergebnis: was jede Option in heutiger Kaufkraft ueber den eigenen Einsatz hinaus abwirft."),
- ("Verhaeltnis Ertrag zu Aufwand",
- "=IF(B14=0,0,B13/B14)", "=IF(C14=0,0,C13/C14)", "=IF(D14=0,0,D13/D14)",
- "Vielfaches des eingesetzten Nettokapitals, real."),
- ("Interner Zinsfuss (nominal, p.a.)",
- f"=IFERROR(IRR(Cashflow!$D$5:$D${CFLAST},0.05),\"n/a\")",
- f"=IFERROR(IRR(Cashflow!$E$5:$E${CFLAST},0.05),\"n/a\")",
- f"=IFERROR(IRR(Cashflow!$F$5:$F${CFLAST},0.05),\"n/a\")",
- "Rendite auf den tatsaechlichen Nettoeinsatz. Direkt mit der Bruttorendite des ETF vergleichbar."),
- ("Vorsprung gegenueber dem privaten ETF-Depot",
- "=B15-$D$15", "=C15-$D$15", "=0",
- "Positiv heisst: die gefoerderte Variante lohnt sich unter den eingestellten Annahmen."),
- ("Vorsprung in Prozent",
- "=IF($D$15=0,0,B15/$D$15-1)", "=IF($D$15=0,0,C15/$D$15-1)", "=0", ""),
-]
-r = 5
-for lab, b, c, d, note in rows:
- vw.cell(r, 1, lab).font = BOLD if lab.isupper() or lab.startswith("BARWERT") else BLACK
- for j, fml in enumerate([b, c, d]):
- cc = vw.cell(r, 2 + j, fml)
- cc.font = GREEN
- cc.number_format = EUR
- cc.border = BOX
- vw.cell(r, 5, note).font = Font(name=FONT, size=9, color="595959")
- vw.cell(r, 5).alignment = Alignment(wrap_text=True, vertical="top")
- r += 1
-for rr in (16,):
- for col in "BCD":
- vw[f"{col}{rr}"].number_format = '0.00"x"'
-for rr in (17, 19):
- for col in "BCD":
- vw[f"{col}{rr}"].number_format = PCT
-for col in "BCD":
- vw[f"{col}15"].font = Font(name=FONT, size=11, bold=True, color="008000")
- vw[f"{col}15"].fill = PatternFill("solid", fgColor="E2EFDA")
-
-vw.cell(21, 1, "DIAGNOSE").font = H2
-vw.cell(21, 1).fill = GREYFILL
-diag = [
- ("Grenzsteuersatz in der Ansparphase (erstes Jahr)",
- f"=IF(Ansparphase!${AC['bav_stf']}${R0}=0,0,Ansparphase!${AC['sterp']}${R0}/Ansparphase!${AC['bav_stf']}${R0})",
- PCT, "Ersparnis je umgewandeltem Euro, ohne die Sozialversicherung."),
- ("Ersparnisquote gesamt (Steuer + SV) im ersten Jahr",
- f"=IF(Ansparphase!${AC['bav_br']}${R0}=0,0,1-Ansparphase!${AC['netto_a']}${R0}/Ansparphase!${AC['bav_br']}${R0})",
- PCT, "So viel vom Bruttobeitrag zahlt der Staat. Genau dieser Vorteil wird spaeter nachgelagert zurueckgeholt."),
- ("Abgabenlast der bAV-Auszahlung (Steuer + KV/PV)",
- "=IF(B8=0,0,(B9+B10)/B8)", PCT,
- "Bei Kapitalauszahlung schlaegt die Progression in einem einzigen Jahr voll durch."),
- ("Abgabenlast der Altersvorsorgedepot-Auszahlung",
- "=IF(C8=0,0,(C9+C10)/C8)", PCT, ""),
- ("Abgabenlast der Privatdepot-Auszahlung",
- "=IF(D8=0,0,(D9+D10)/D8)", PCT, "25 % zzgl. Soli auf 70 % des Gewinns, also deutlich weniger als der Grenzsteuersatz."),
- ("Tatsaechliche SV-Ersparnis des ARBEITGEBERS (erstes Jahr)",
- f"=Ansparphase!${AC['sverp_ag']}${R0}", EUR,
- "Null, wenn Ihr Entgelt auch nach der Umwandlung noch ueber beiden Beitragsbemessungsgrenzen liegt. Dann schuldet der Arbeitgeber nach 1a Abs. 1a BetrAVG auch keinen Zuschuss - er kann ihn aber freiwillig zusagen (Modus 0 oder 1)."),
- ("Tatsaechliche SV-Ersparnis des ARBEITNEHMERS (erstes Jahr)",
- f"=Ansparphase!${AC['sverp']}${R0}", EUR,
- "Ebenfalls null oberhalb der Grenzen - dafuer gehen dann auch keine Entgeltpunkte verloren. Beides haengt an derselben Groesse."),
- ("Anteil der bAV-Beitraege OHNE Foerderung (erstes Jahr)",
- f"=IF(Ansparphase!${AC['bav_ein']}${R0}=0,0,Ansparphase!${AC['bav_ngef']}${R0}/Ansparphase!${AC['bav_ein']}${R0})",
- PCT, "Alles oberhalb von 8 % der BBG-RV ist weder steuer- noch sozialabgabenbeguenstigt. Diese Schicht wandert in einen Versicherungsmantel, ohne dafuer etwas zu bekommen - ausser der Beitragspflicht in der KV. Ist dieser Anteil gross, ist die bAV strukturell unterlegen."),
- ("Arbeitgeberzuschuss prozentual (erstes Jahr)",
- f"=Ansparphase!${AC['agz_var']}${R0}", EUR,
- "Der Teil nach 1a Abs. 1a BetrAVG bzw. der vertraglich zugesagte Prozentsatz, gerechnet nach dem eingestellten Zuschussmodus."),
- ("Fester Arbeitgeberzuschuss (erstes Jahr)",
- f"=Ansparphase!${AC['agz_fx']}${R0}", EUR,
- "Betragsunabhaengiger Festzuschuss aus Tarifvertrag oder Betriebsvereinbarung. Null, wenn der eigene Monatsbeitrag die eingestellte Mindestschwelle nicht erreicht."),
- ("Fester Zuschuss oberhalb des 4-%-Topfes (erstes Jahr)",
- f"=MAX(0,Ansparphase!${AC['agz_fx']}${R0}-{P['sv_frei_q']}*Ansparphase!${AC['bbgrv']}${R0})", EUR,
- "Dieser Teil waere beim Arbeitnehmer beitragspflichtiges Arbeitsentgelt. Das Modell rechnet die zusaetzliche Beitragslast NICHT gegen und ueberschaetzt die bAV insoweit. Sollte null sein."),
- ("Ausschoepfung des Rechtsanspruchs nach 1a BetrAVG (4 % BBG)",
- f"=IF(Ansparphase!${AC['bbgrv']}${R0}=0,0,Ansparphase!${AC['bav_br']}${R0}/({P['sv_frei_q']}*Ansparphase!${AC['bbgrv']}${R0}))",
- PCT, "Ueber 100 % besteht kein Rechtsanspruch mehr auf Entgeltumwandlung; darueber hinaus ist die Zustimmung des Arbeitgebers noetig."),
- ("Versorgungsbezug pro Monat zu Beginn der Auszahlung",
- f"=Auszahlung!${ZC['bav_vb']}${Z0}", EUR2,
- "Bei Kapitalauszahlung ein Hundertzwanzigstel der Leistung fuer 120 Monate ( 229 Abs. 1 S. 3 SGB V), bei Rente die laufende Monatsrente."),
- ("Freibetrag Versorgungsbezuege im Auszahlungsjahr",
- f"={P['frei_vb']}*Auszahlung!${ZC['lohn']}${Z0}", EUR2,
- "Ein Zwanzigstel der Bezugsgroesse, 226 Abs. 2 S. 2 SGB V. 2026: 197,75 EUR; waechst mit der Lohnentwicklung."),
- ("Verhaeltnis Versorgungsbezug zu Freibetrag",
- "=IF(B32=0,0,B31/B32)", '0.00"x"',
- "Bei einem Wert bis 1,00 faellt WEDER Kranken- NOCH Pflegeversicherung an. Darueber greift die KV nur auf den uebersteigenden Teil zu, die PV wegen ihrer Freigrenze dagegen auf den GESAMTEN Betrag. Weil der Freibetrag absolut ist, faellt seine Schutzwirkung wie 1/Kapital - deshalb sinkt die Rendite der bAV streng monoton in der Beitragshoehe."),
- ("Beitragsfrei moegliches Kapital bei Kapitalauszahlung",
- "=120*B32", EUR,
- "120 x Freibetrag. Vergleichen Sie mit Zeile 7. Liegt Ihr Kapital darueber, zahlen Sie auf den Ueberschuss den vollen Beitragssatz allein."),
- ("Beitragsfrei moegliches Kapital bei lebenslanger Rente",
- f"=IF({IN['rentfak']}=0,0,B32/{IN['rentfak']}*10000)", EUR,
- "Die Verrentung streckt den Bezug auf die Restlebenszeit statt auf 120 Monate und schirmt deshalb ein Vielfaches an Kapital unter demselben Freibetrag ab. Ein Vorteil, den der Barwertvergleich ueber einen festen Horizont nicht abbildet."),
- ("MEMO: bAV-Rentenzahlungen nach dem Vergleichshorizont",
- f"=SUM(Auszahlung!${ZC['bav_rest']}${Z0}:${ZC['bav_rest']}${ZLAST})", EUR,
- "Nur bei Auszahlungsform 2. Eine lebenslange Rente zahlt ueber den Horizont hinaus - diesen Betrag beruecksichtigt der Vergleich NICHT. Wer alt wird, gewinnt hier."),
- ("MEMO: Altersvorsorgedepot-Rente nach dem Vergleichshorizont",
- f"=SUM(Auszahlung!${ZC['av_rest']}${Z0}:${ZC['av_rest']}${ZLAST})", EUR,
- "Dasselbe fuer das Altersvorsorgedepot, wenn es verrentet wird. Beide Memo-Zeilen sind der Preis eines festen Vergleichshorizonts: eine lebenslange Rente wird darin systematisch unterschaetzt."),
-]
-r = 22
-for lab, fml, fmt, note in diag:
- vw.cell(r, 1, lab).font = BLACK
- c = vw.cell(r, 2, fml)
- c.font = GREEN
- c.number_format = fmt
- c.border = BOX
- vw.cell(r, 5, note).font = Font(name=FONT, size=9, color="595959")
- vw.cell(r, 5).alignment = Alignment(wrap_text=True, vertical="top")
- r += 1
-
-vw.cell(38, 1, "Hinweis: Ein Foerderungsanteil deutlich ueber 0 %, eine Ausschoepfung ueber 100 % oder ein Verhaeltnis "
- "Versorgungsbezug zu Freibetrag deutlich ueber 1,00 zeigen an, dass Sie ausserhalb des beguenstigten "
- "Korridors liegen.").font = Font(name=FONT, size=9, italic=True, color="C00000")
-
-RNG = lambda k: f"Auszahlung!${ZC[k]}${Z0}:${ZC[k]}${ZLAST}"
-DFR = f"Auszahlung!${ZC['dfr']}${Z0}:${ZC['dfr']}${ZLAST}"
-SP = lambda k: f"SUMPRODUCT({RNG(k)},{DFR})"
-ANNW = f"({P['wiederanl']}/(1-(1+{P['wiederanl']})^(-{P['n_ausz']})))"
-M = lambda expr: f"=({expr})*{ANNW}/12"
-
-vw.cell(40, 1, "MONATLICHE LEISTUNG - alle Optionen auf denselben Zeitraum verrentet").font = H2
-for cc_ in range(1, 5):
- vw.cell(40, cc_).fill = GREYFILL
-for i, h in enumerate(["bAV mit DYNO", "Altersvorsorgedepot", "privates ETF-Depot"]):
- vw.cell(40, 2 + i, h).font = Font(name=FONT, size=9, bold=True, color="1F3864")
- vw.cell(40, 2 + i).alignment = Alignment(horizontal="center")
-
-tabelle = [
- ("Wert aller Netto-Leistungen bei Rentenbeginn",
- f"={SP('bav_net')}", f"={SP('av_net')}", f"={SP('pr_net')}", EUR, False,
- "Alle Netto-Zahlungen mit dem Wiederanlagezins nach Steuern auf den Rentenbeginn bezogen. Ein Einmalbetrag und ein Zahlungsstrom werden damit vergleichbar - der Zeitpunkt wird bewertet statt ignoriert."),
- ("Bruttoleistung pro Monat",
- M(SP('bav_br')), M(f"{SP('gef_e')}+{SP('ngef_e')}+{SP('sl_e')}"), M(SP('pr_e')), EUR2, False,
- "Konstante nominale Monatszahlung ueber die Auszahlungsphase mit demselben Wert. Weil die Verrentung linear ist, addieren sich die folgenden Zeilen exakt."),
- ("abzueglich Einkommen-/Abgeltungsteuer",
- M(f"-{SP('st_bav')}"), M(f"-({SP('stg_av')}-{SP('stg_b')}+{SP('sl_st')})"), M(f"-{SP('pr_st')}"), EUR2, False,
- "bAV und Altersvorsorgedepot: persoenlicher Grenzsteuersatz. Privatdepot: nur der Gewinnanteil der Entnahme, mit 30 % Teilfreistellung."),
- ("abzueglich Kranken- und Pflegeversicherung",
- M(f"-{SP('bav_kvpv')}"), "=0", "=0", EUR2, False,
- "229, 250 SGB V. Nur die bAV ist betroffen."),
- ("abzueglich Verlust an gesetzlicher Rente",
- M(f"-({SP('mind_br')}-{SP('mind_kv')})"), "=0", "=0", EUR2, False,
- "Netto entgangene gesetzliche Rente aus der Entgeltumwandlung."),
- ("NETTO PRO MONAT (nominal)",
- M(SP('bav_net')), M(SP('av_net')), M(SP('pr_net')), EUR2, True,
- "Summe der vier Zeilen darueber. Gegenprobe fuer die Additivitaet."),
- ("NETTO PRO MONAT in heutiger Kaufkraft",
- f"=B46*Auszahlung!${ZC['df']}${Z0}", f"=C46*Auszahlung!${ZC['df']}${Z0}",
- f"=D46*Auszahlung!${ZC['df']}${Z0}", EUR2, True,
- "Die einzige Zahl, die man unmittelbar mit dem heutigen Nettoeinkommen vergleichen kann."),
-]
-r = 41
-for lab, b, c, d, fmt, hl, note in tabelle:
- vw.cell(r, 1, lab).font = BOLD if hl else BLACK
- for j, fml in enumerate([b, c, d]):
- cc = vw.cell(r, 2 + j, fml)
- cc.number_format = fmt
- cc.border = BOX
- if hl:
- cc.font = Font(name=FONT, size=11, bold=True, color="008000")
- cc.fill = PatternFill("solid", fgColor="E2EFDA")
- else:
- cc.font = GREEN
- vw.cell(r, 5, note).font = Font(name=FONT, size=9, color="595959")
- vw.cell(r, 5).alignment = Alignment(wrap_text=True, vertical="top")
- r += 1
-vw.cell(48, 1, "Der Bezugszeitraum ist fuer alle drei Optionen identisch (Rentenbeginn bis Vergleichshorizont). "
- "Bei Kapitalauszahlung wird der Einmalbetrag also nicht durch zwoelf geteilt, sondern mit dem "
- "Wiederanlagezins aus dem Blatt 'Parameter' auf denselben Zeitraum verrentet. Wer ihn verkonsumiert "
- "statt anzulegen, steht schlechter - dann den Wiederanlagezins auf 0 setzen.").font = \
- Font(name=FONT, size=9, italic=True, color="595959")
-vw.cell(48, 1).alignment = Alignment(wrap_text=True, vertical="top")
-vw.row_dimensions[48].height = 26
-
-vw['A50'] = "Barwert Netto-Ertrag bAV"
-vw['B50'] = "=B15"
-vw['A51'] = "Barwert Netto-Ertrag Altersvorsorgedepot"
-vw['B51'] = "=C15"
-vw['A52'] = "Barwert Netto-Ertrag privates Depot"
-vw['B52'] = "=D15"
-for rr in (50, 51, 52):
- vw[f"B{rr}"].number_format = EUR
- vw[f"A{rr}"].font = Font(name=FONT, size=9, color="808080")
- vw[f"B{rr}"].font = Font(name=FONT, size=9, color="808080")
-
-ch = BarChart()
-ch.type = "col"
-ch.title = "Barwert des Netto-Ertrags (heutige Kaufkraft)"
-ch.y_axis.title = "EUR"
-data = Reference(vw, min_col=2, min_row=50, max_row=52)
-cats = Reference(vw, min_col=1, min_row=50, max_row=52)
-ch.add_data(data, titles_from_data=False)
-ch.set_categories(cats)
-ch.legend = None
-ch.height = 8
-ch.width = 17
-vw.add_chart(ch, "A55")
-
-# =====================================================================
-# 7) ANLEITUNG
-# =====================================================================
-dw = wb.create_sheet("Anleitung", 0)
-dw.sheet_view.showGridLines = False
-dw.column_dimensions['A'].width = 4
-dw.column_dimensions['B'].width = 130
-txt = [
- ("H1", "bAV mit DYNO vs. Altersvorsorgedepot vs. privates ETF-Depot"),
- ("i", "Rechtsstand 2026. Alle Zahlen sind Formeln - aendern Sie die gelben Zellen im Blatt 'Eingaben' und alles rechnet neu."),
- ("", ""),
- ("H2", "Aufbau"),
- ("", "Begriffe - Legende aller Fachbegriffe und Spaltenueberschriften. Bei Unklarheiten zuerst dort nachsehen."),
- ("", "Eingaben - Ihre persoenlichen Groessen. Nur hier tippen."),
- ("", "Umrechnung - Bisektion, die aus einem vorgegebenen Nettoaufwand den noetigen Bruttobeitrag bestimmt."),
- ("", "Parameter - gesetzliche Rechengroessen 2026 mit Fundstelle. Anpassen, wenn sich das Recht aendert."),
- ("", "Ansparphase - Jahr fuer Jahr: Brutto, SV, Steuer, Nettoaufwand, Einzahlungen, Kapitalentwicklung, Entgeltpunkte."),
- ("", "Auszahlung - Jahr fuer Jahr: Bruttozufluss, KV/PV, Steuer, Netto je Option."),
- ("", "Cashflow - Zahlungsstroeme fuer interne Zinsfuesse und Barwerte."),
- ("", "Vergleich - das Ergebnis nebeneinander, mit Diagramm."),
- ("", ""),
- ("H2", "Das Vergleichsprinzip"),
- ("", "Ein Vergleich von Bruttobeitraegen waere unfair: die Entgeltumwandlung kommt aus dem Brutto, das private Sparen aus dem Netto."),
- ("", "Deshalb wird der NETTOAUFWAND gleichgesetzt. Aus dem eingegebenen Bruttobeitrag folgt, wieviel Netto tatsaechlich fehlt"),
- ("", "(Beitrag minus gesparte Lohnsteuer minus gesparter Arbeitnehmeranteil zur Sozialversicherung). Genau dieser Betrag wird in"),
- ("", "den beiden anderen Optionen investiert. Was uebrig bleibt, ist ein echter Vergleich der Foerderarchitekturen."),
- ("", "Ueber den Vorgabemodus koennen Sie die Richtung umkehren und direkt den Nettoaufwand festlegen - oekonomisch ist"),
- ("", "das die natuerlichere Groesse, denn sie misst den tatsaechlich aufgegebenen Konsum. Der Bruttobeitrag des ersten"),
- ("", "Jahres wird dann zurueckgerechnet und danach nach der eingestellten Dynamisierungsregel fortgeschrieben; in"),
- ("", "spaeteren Jahren kann der Nettoaufwand daher leicht abweichen (Teilzeit, Tarifprogression, Beitragsbemessungsgrenzen)."),
- ("", ""),
- ("H2", "Die drei Optionen im Kern"),
- ("", "1) bAV (Direktversicherung, ETF-basiert, z.B. DYNO)"),
- ("", " + Beitrag steuerfrei bis 8 % der BBG-RV ( 3 Nr. 63 EStG), sozialabgabenfrei bis 4 % ( 1 Abs. 1 S. 1 Nr. 9 SvEV)"),
- ("", " + Arbeitgeberzuschuss von mindestens 15 % ( 1a Abs. 1a BetrAVG) - das ist der eigentliche Renditetreiber"),
- ("", " + ggf. zusaetzlich ein tarifvertraglicher FESTBETRAG unabhaengig vom Monatsbeitrag (z.B. Deutsche Bahn)"),
- ("", " - Leistung voll steuerpflichtig ( 22 Nr. 5 S. 1 EStG); Kapitalabfindung trifft in einem Jahr den Spitzensteuersatz"),
- ("", " - Kranken- und Pflegeversicherung auf die volle Leistung, Beitragssatz allein vom Rentner ( 229, 250 SGB V)"),
- ("", " - Entgeltumwandlung mindert die Entgeltpunkte und damit die gesetzliche Rente"),
- ("", " - Produktkosten des Versicherungsmantels, gebundenes Kapital bis zum Rentenalter"),
- ("", "2) Altersvorsorgedepot (ab 1.1.2027, Altersvorsorgereformgesetz)"),
- ("", " + Zulage 50 Cent je Euro bis 360 EUR, 25 Cent je Euro bis 1.800 EUR (max. 540 EUR Grundzulage), 300 EUR je Kind"),
- ("", " + steuerfreie Thesaurierung in der Ansparphase - keine Vorabpauschale, kein Steuerabzug auf Ausschuettungen"),
- ("", " + KEINE Kranken- und Pflegeversicherungsbeitraege auf die Leistung"),
- ("", " - gefoerderte Teile voll nachgelagert steuerpflichtig; Beitraege ueber 1.800 EUR sind nicht gefoerdert"),
- ("", " - Auszahlung fruehestens ab 65, Kapital gebunden, Anlageuniversum durch Positivliste begrenzt"),
- ("", "3) Privates ETF-Depot"),
- ("", " + voellig flexibel, jederzeit verfuegbar, vererbbar, keine Produktbindung, niedrigste Kosten"),
- ("", " - Vorabpauschale nach 18 InvStG in jedem Jahr mit Wertzuwachs (Basiszins 2026: 3,20 %)"),
- ("", " - Abgeltungsteuer 25 % zzgl. Soli und ggf. Kirchensteuer auf 70 % des Gewinns (30 % Teilfreistellung)"),
- ("", " - keine Foerderung, kein Fremdgeld"),
- ("", ""),
- ("H2", "Wichtige Modellannahmen (bitte lesen, bevor Sie dem Ergebnis glauben)"),
- ("", "- Das zu versteuernde Einkommen wird aus dem Brutto naeherungsweise abgeleitet: abzueglich Arbeitnehmer-Pauschbetrag,"),
- ("", " Sonderausgaben-Pauschbetrag und der abziehbaren Vorsorgeaufwendungen (RV voll, KV zu 96 %, PV voll). Genauigkeit ca. 1 %."),
- ("", "- Der Einkommensteuertarif wird mit dem eingegebenen Satz gestreckt: ESt = s * L * T(zvE / s / L). Das ist exakt aequivalent"),
- ("", " zu einer proportionalen Verschiebung aller Tarifeckwerte. Auf 0 % setzen, um die kalte Progression zu sehen."),
- ("", "- BBG, Bezugsgroesse, Durchschnittsentgelt und Rentenwert werden mit der Lohnsteigerung fortgeschrieben."),
- ("", "- Oberhalb der Beitragsbemessungsgrenzen ist die Entgeltumwandlung sozialversicherungsrechtlich neutral: die"),
- ("", " Bemessungsgrundlage bleibt gedeckelt, also spart weder Arbeitnehmer noch Arbeitgeber Beitraege, und es gehen"),
- ("", " auch keine Entgeltpunkte verloren. Beides folgt aus derselben Differenz und ist im Modell zwingend gekoppelt."),
- ("", " Der Zuschussmodus 2 zieht daraus die Konsequenz und setzt den prozentualen Zuschuss dann auf null."),
- ("", "- Der FESTE Arbeitgeberzuschuss (z.B. Deutsche Bahn) ist betragsunabhaengig und vom Zuschussmodus unberuehrt: er"),
- ("", " beruht auf Tarifvertrag oder Betriebsvereinbarung, nicht auf 1a Abs. 1a BetrAVG, und kommt oben drauf."),
- ("", " Als arbeitgeberfinanzierte Zuwendung nach 3 Nr. 63 EStG belegt er den 8-%-Topf und die 4-%-Beitragsfreiheit"),
- ("", " VORRANGIG; die eigene Entgeltumwandlung wird insoweit verdraengt und teurer. Sein Barwert waechst nicht mit dem"),
- ("", " Beitrag - oekonomisch ist er ein Sockel, kein Hebel: er hebt den Durchschnittsertrag, nicht die Grenzrendite."),
- ("", " NICHT abgebildet: uebersteigt der feste Zuschuss allein 4 % der BBG-RV, waere der Ueberhang beim Arbeitnehmer"),
- ("", " beitragspflichtiges Arbeitsentgelt. Das Modell rechnet diese Beitragslast nicht gegen und ueberschaetzt die bAV"),
- ("", " insoweit; das Blatt 'Kennzahlen' weist den Ueberhang aus. Vertrauensgrad der Vorrang-Lesart ca. 80 %."),
- ("", "- Beitraege gelten als unterjaehrig geleistet (Verzinsung mit (1+r)^0,5 im Einzahlungsjahr)."),
- ("", "- In der Auszahlungsphase wird die Vorabpauschale nicht mehr fortgeschrieben; sie waere durch die Anrechnung auf den"),
- ("", " realisierten Gewinn ( 19 InvStG) barwertig weitgehend neutral."),
- ("", "- Der Sonderausgabenhoechstbetrag von 2.340 EUR fuer das Altersvorsorgedepot ist eine Modellannahme aus der BMF-FAQ"),
- ("", " (Eigenbeitrag bis 1.800 EUR zuzueglich Zulagen). Vertrauensgrad rund 70 % - im Blatt 'Parameter' aenderbar."),
- ("", "- Guenstigerpruefung nach 10a Abs. 2 EStG: die Gesamtfoerderung ist das MAXIMUM aus Zulagenanspruch und Steuervorteil"),
- ("", " aus dem Sonderausgabenabzug, nicht deren Summe. Solange der Steuervorteil groesser ist, erhoeht eine zusaetzliche"),
- ("", " Kinderzulage die Foerderung um exakt null - sie wird vollstaendig angerechnet. Erst wenn die Zulage den Steuervorteil"),
- ("", " uebersteigt, fliesst echtes zusaetzliches Geld. Das ist der Grund fuer scheinbar paradoxe Ergebnisse bei einem Kind."),
- ("", "- Die Steuererstattung aus der Guenstigerpruefung wird im Folgejahr als NICHT gefoerderter Beitrag in denselben Vertrag"),
- ("", " reinvestiert. Das ist eine Konvention, keine Rechtsfolge; sie haelt den Nettoaufwand aller drei Optionen exakt gleich."),
- ("", "- Die bAV wird in ZWEI Schichten gefuehrt: gefoerdert (bis 8 % der BBG-RV, 3 Nr. 63 EStG, voll nachgelagert"),
- ("", " steuerpflichtig) und NICHT gefoerdert (der Rest, aus versteuertem Entgelt; bei Kapitalauszahlung nur halber"),
- ("", " Unterschiedsbetrag nach 22 Nr. 5 S. 2 Buchst. b i.V.m. 20 Abs. 1 Nr. 6 S. 2 EStG, bei Rente Ertragsanteil)."),
- ("", " Ohne diese Trennung wuerde derselbe Euro zweimal besteuert - und der Barwert der bAV bei hohen Beitraegen negativ."),
- ("", "- Die Beitragsbemessungsgrenze der KV wird auf die Summe aus gesetzlicher Rente und Versorgungsbezuegen angewandt"),
- ("", " ( 223 Abs. 3 SGB V). Dafuer wird die gesetzliche Bruttorente als Eingabe benoetigt."),
- ("", "- Bei der lebenslangen bAV-Rente ist der Vergleich horizontabhaengig: das Modell zaehlt nur die Zahlungen bis zum"),
- ("", " eingestellten Vergleichshorizont. Die Zahlungen danach stehen als Memo-Zeile im Blatt 'Vergleich'. Eine Leibrente ist"),
- ("", " primaer eine Versicherung gegen Langlebigkeit, kein Renditeprodukt - sie kann deshalb im Barwertvergleich nur verlieren."),
- ("", "- Nicht modelliert: Abschlaege bei vorzeitigem Rentenbezug, Auswirkungen der Entgeltumwandlung auf Kranken-, Arbeitslosen-"),
- ("", " und Elterngeld, Hinterbliebenenversorgung, Insolvenzsicherung (PSVaG), Portabilitaet bei Arbeitgeberwechsel,"),
- ("", " Kinderabschlaege in der Pflegeversicherung, Guenstigerpruefung nach 32d Abs. 6 EStG."),
- ("", ""),
- ("H2", "Quellen"),
- ("", "SVBezGrV 2026 - https://www.gesetze-im-internet.de/svbezgrv_2026/BJNR1160A0025.html"),
- ("", "32a EStG - https://www.gesetze-im-internet.de/estg/__32a.html"),
- ("", "BMF, FAQ zur Reform der gefoerderten privaten Altersvorsorge, 05.05.2026 -"),
- ("", " https://www.bundesfinanzministerium.de/Content/DE/FAQ/reform-der-privaten-altersvorsorge.html"),
- ("", "Bundesregierung, Private Altersvorsorge wird attraktiver, 01.06.2026 -"),
- ("", " https://www.bundesregierung.de/breg-de/aktuelles/reform-private-altersvorsorge-2400072"),
- ("", "BMF-Schreiben vom 13.01.2026, Basiszins zur Vorabpauschale ( 18 Abs. 4 InvStG) -"),
- ("", " https://www.bundesfinanzministerium.de/Content/DE/Downloads/BMF_Schreiben/Steuerarten/Investmentsteuer/2026-01-13-basiszins-berechnung-vorabpauschale.pdf"),
- ("", "GKV-Spitzenverband, Rechengroessen 2026 - https://www.gkv-spitzenverband.de/media/dokumente/presse/zahlen_und_grafiken/20260101_Faktenblatt_Rechengroessen_Beitragsrecht.pdf"),
- ("", "DYNO - https://heydyno.de"),
- ("", ""),
- ("i", "Keine Steuer- oder Anlageberatung. Ich bin weder Steuerberater noch Anlageberater; das Modell ersetzt keine Pruefung des konkreten Vertrags."),
-]
-r = 2
-for style, line in txt:
- c = dw.cell(r, 2, line)
- if style == "H1":
- c.font = H1
- elif style == "H2":
- c.font = H2
- elif style == "i":
- c.font = Font(name=FONT, size=10, italic=True, color="595959")
- else:
- c.font = Font(name=FONT, size=10)
- r += 1
-
-# =====================================================================
-# 8) BEGRIFFE
-# =====================================================================
-bw = wb.create_sheet("Begriffe", 1)
-bw.sheet_view.showGridLines = False
-bw.column_dimensions['A'].width = 3
-bw.column_dimensions['B'].width = 34
-bw.column_dimensions['C'].width = 104
-bw.column_dimensions['D'].width = 44
-bw['B1'] = "Begriffslegende"
-bw['B1'].font = H1
-bw['B2'] = ("Die zentralen Groessen des Modells. Wo eine Rechtsnorm existiert, steht sie in der dritten Spalte; "
- "wo es eine Modellkonvention ist, steht das ausdruecklich dort.")
-bw['B2'].font = Font(name=FONT, size=10, italic=True, color="595959")
-
-GLOSS = [
- ("H", "Die Kerngroesse des Vergleichs", None, None),
- ("Nettoaufwand", (
- "Betrag, um den Ihr verfuegbares Einkommen im Beitragsjahr tatsaechlich sinkt:\n"
- " Nettoaufwand = Bruttobeitrag - Lohnsteuerersparnis - ersparter AN-Anteil zur Sozialversicherung\n"
- "Beispiel Basisfall: 3.600 - 1.237 - 382 = 1.981 EUR. Sie wandeln 3.600 EUR Brutto um, spueren aber nur 1.981 EUR.\n"
- "Genau dieser Betrag - nicht der Bruttobeitrag - wird in den beiden anderen Optionen investiert, denn privates "
- "Sparen erfolgt aus versteuertem Einkommen. Ohne diese Normierung wuerde man 3.600 EUR brutto gegen 3.600 EUR "
- "netto vergleichen und die bAV systematisch bevorzugen."),
- "Spalte AE im Blatt 'Ansparphase'"),
- ("Vorgabemodus", (
- "Modus 1: Sie geben den Bruttobeitrag vor, der Nettoaufwand ergibt sich.\n"
- "Modus 2: Sie geben den Nettoaufwand vor - also den aufgegebenen Konsum - und der noetige Bruttobeitrag wird "
- "zurueckgerechnet.\n"
- "Die Umkehrung ist nicht geschlossen darstellbar, weil N(B) Knicke bei 4 % und 8 % der BBG-RV, an den "
- "Beitragsbemessungsgrenzen und an den Tarifeckwerten hat. N ist aber stetig und streng monoton wachsend "
- "(dN/dB = 1 - Grenz-SV-Satz - Grenzsteuersatz, im Regelfall etwa 0,5 bis 0,6), also konvergiert eine Bisektion "
- "garantiert. Das Blatt 'Umrechnung' fuehrt 34 Schritte auf dem Intervall [0; Bruttogehalt] aus."),
- "Blatt 'Umrechnung'"),
- ("Fremdgeld", (
- "Geld, das nicht von Ihnen kommt: der Arbeitgeberzuschuss bei der bAV, die Zulagen beim Altersvorsorgedepot. "
- "Der einzige Posten, der eine gefoerderte Anlage strukturell besser machen kann als ein freies Depot - "
- "der Steueraufschub allein leistet das nicht."),
- "Zeile 6 im Blatt 'Vergleich'"),
-
- ("H", "Steuer", None, None),
- ("Grenzsteuersatz", (
- "Steuer auf den naechsten verdienten Euro, also die Ableitung des Tarifs. Entscheidend fuer den Wert eines "
- "Abzugs. 2026 zwischen 14 % und 45 %."),
- "32a EStG"),
- ("Durchschnittssteuersatz", (
- "Gesamte Steuer geteilt durch das gesamte zu versteuernde Einkommen. Immer kleiner als der Grenzsteuersatz. "
- "Relevant fuer die Auszahlungsphase, wenn eine grosse Summe auf einmal zufliesst."), None),
- ("zvE", (
- "Zu versteuerndes Einkommen: Bruttogehalt abzueglich Werbungskosten (mindestens Arbeitnehmer-Pauschbetrag), "
- "Sonderausgaben-Pauschbetrag und abziehbarer Vorsorgeaufwendungen. Bemessungsgrundlage des Tarifs."),
- "2 Abs. 5 EStG"),
- ("Splittingtarif", (
- "Bei Zusammenveranlagung: ESt = 2 x T((zvE1 + zvE2)/2). Senkt den Grenzsteuersatz stark, solange das halbierte "
- "Einkommen in der Progressionszone liegt, und wirkt gar nicht mehr im Spitzensteuersatz."),
- "32a Abs. 5 EStG"),
- ("Tarifindex L (lambda)", (
- "Streckungsfaktor des Steuertarifs fuer kuenftige Jahre. Das Modell rechnet ESt = s * L * T(zvE / s / L), was "
- "exakt einer proportionalen Verschiebung aller Tarifeckwerte entspricht. L = 1 bedeutet: keine Anpassung, also "
- "volle kalte Progression."), "Modellkonvention"),
- ("Nachgelagerte Besteuerung", (
- "Beitraege bleiben steuerfrei, dafuer ist die spaetere Leistung voll steuerpflichtig. Rechnerisch ist der Aufschub "
- "fuer sich genommen wertneutral, weil (1-t) * (1+r)^n = (1+r)^n * (1-t). Er lohnt nur, wenn der Steuersatz bei "
- "Auszahlung niedriger ist als bei Einzahlung."), "22 Nr. 5 S. 1 EStG"),
- ("Fuenftelregelung", (
- "Ermaessigte Besteuerung ausserordentlicher Einkuenfte: die Steuer wird auf ein Fuenftel berechnet und "
- "verfuenffacht. Bei planmaessigen Kapitalabfindungen aus 3 Nr. 63-Vertraegen nach der Rechtsprechung nur "
- "ausnahmsweise anwendbar - im Modell abschaltbar und per Default aus."), "34 EStG"),
-
- ("H", "Sozialversicherung", None, None),
- ("Beitragsbemessungsgrenze (BBG)", (
- "Obergrenze des beitragspflichtigen Entgelts. 2026: 101.400 EUR in RV und AV, 69.750 EUR in KV und PV. "
- "Oberhalb der Grenze ist eine Entgeltumwandlung sozialversicherungsrechtlich neutral - weder Sie noch Ihr "
- "Arbeitgeber sparen etwas, und es gehen auch keine Entgeltpunkte verloren."), "159 ff. SGB VI, 223 SGB V"),
- ("Bezugsgroesse", (
- "Rechengroesse des Sozialrechts, 2026: 3.955 EUR monatlich. Wichtig hier vor allem als Basis des Freibetrags "
- "auf Versorgungsbezuege (ein Zwanzigstel)."), "18 SGB IV"),
- ("Versorgungsbezug", (
- "Leistung aus betrieblicher Altersversorgung. In der GKV beitragspflichtig, und zwar mit dem VOLLEN Beitragssatz, "
- "den der Rentner allein traegt. Eine Kapitalabfindung wird dafuer auf 120 Monate verteilt. Leistungen aus "
- "PRIVATER Altersvorsorge sind keine Versorgungsbezuege und bleiben beitragsfrei - der groesste einzelne "
- "Unterschied zwischen den drei Optionen."), "229, 250 Abs. 1 Nr. 1 SGB V"),
- ("Freibetrag / Freigrenze", (
- "Beim Freibetrag bleibt nur der Betrag bis zur Grenze unbelastet, der Rest wird belastet (KV: 197,75 EUR/Monat "
- "in 2026). Bei der Freigrenze wird bei Ueberschreiten der GESAMTE Betrag belastet - so in der Pflegeversicherung. "
- "Mathematisch: stetige gegen unstetige Funktion."), "226 Abs. 2 SGB V"),
- ("Entgeltpunkt", (
- "Beitragspflichtiges Entgelt geteilt durch das Durchschnittsentgelt aller Versicherten (2026: 51.944 EUR). "
- "Ein Punkt ergibt seit Juli 2026 eine Monatsrente von 42,52 EUR. Entgeltumwandlung senkt das beitragspflichtige "
- "Entgelt und damit die Punkte - aber nur unterhalb der BBG."), "63, 70 SGB VI"),
- ("Besteuerungsanteil", (
- "Anteil der gesetzlichen Rente, der steuerpflichtig ist. Haengt vom Jahr des Rentenbeginns ab: 82,5 % fuer die "
- "Kohorte 2023, danach +0,5 Prozentpunkte pro Jahr bis 100 % ab 2058."),
- "22 Nr. 1 S. 3 Buchst. a Doppelbuchst. aa EStG"),
-
- ("H", "Betriebliche Altersvorsorge", None, None),
- ("Entgeltumwandlung", (
- "Umwandlung kuenftiger Gehaltsansprueche in eine Anwartschaft auf Betriebsrente. Ein Rechtsanspruch besteht nur "
- "bis 4 % der BBG-RV; darueber hinaus braucht es die Zustimmung des Arbeitgebers."), "1a BetrAVG"),
- ("Gefoerderte Schicht", (
- "Der Teil der Beitraege bis 8 % der BBG-RV (2026: 8.112 EUR). Steuerfrei beim Einzahlen, dafuer die Leistung "
- "spaeter zu 100 % steuerpflichtig."), "3 Nr. 63 EStG"),
- ("Nicht gefoerderte Schicht", (
- "Alles darueber. Fliesst aus versteuertem und verbeitragtem Entgelt in den Vertrag. Deshalb ist die Leistung "
- "spaeter NICHT voll steuerpflichtig, sondern nur mit dem halben Unterschiedsbetrag (Kapital) bzw. dem "
- "Ertragsanteil (Rente). Die KV-Pflicht trifft sie trotzdem in voller Hoehe."),
- "22 Nr. 5 S. 2 EStG"),
- ("Unterschiedsbetrag", (
- "Auszahlung minus eingezahlte Beitraege, also der reine Wertzuwachs. Bei Vertragsdauer ueber zwoelf Jahren und "
- "Auszahlung nach dem 62. Lebensjahr ist davon nur die Haelfte steuerpflichtig."), "20 Abs. 1 Nr. 6 S. 2 EStG"),
- ("Ertragsanteil", (
- "Pauschal unterstellter Zinsanteil einer Leibrente aus nicht gefoerdertem Kapital, abhaengig vom Alter bei "
- "Rentenbeginn (bei 67: 17 %). Nur dieser Anteil wird besteuert."),
- "22 Nr. 1 S. 3 Buchst. a Doppelbuchst. bb EStG"),
- ("Rentenfaktor", (
- "Monatliche Rente je 10.000 EUR Kapital. Ein Faktor von 26 entspricht etwa 3,1 % Entnahmequote pro Jahr - der "
- "Versicherer kalkuliert fuer ein sehr hohes Endalter. Eine Leibrente ist primaer eine Versicherung gegen "
- "Langlebigkeit, kein Renditeprodukt; im Barwertvergleich ueber einen festen Horizont kann sie deshalb nur "
- "verlieren."), "Vertragsbedingung"),
-
- ("H", "Gefoerderte private Altersvorsorge (Altersvorsorgedepot)", None, None),
- ("Zulage", (
- "Direkter staatlicher Zuschuss: 50 Cent je Euro bis 360 EUR Eigenbeitrag, 25 Cent je Euro bis 1.800 EUR, "
- "also hoechstens 540 EUR Grundzulage. Zusaetzlich 1 Euro je Euro bis 300 EUR je Kind, solange Kindergeld "
- "zusteht."), "Abschnitt XI EStG i.d.F. des Altersvorsorgereformgesetzes"),
- ("Sonderausgabenabzug", (
- "Alternative Foerderung: Eigenbeitraege bis 1.800 EUR zuzueglich Zulagen mindern das zvE."), "10a Abs. 1 EStG"),
- ("Guenstigerpruefung", (
- "Die Gesamtfoerderung ist das MAXIMUM aus Zulagenanspruch und Steuervorteil des Sonderausgabenabzugs, nicht "
- "deren Summe: F = max(Zulage, Steuervorteil). Solange der Steuervorteil groesser ist, erhoeht eine zusaetzliche "
- "Zulage die Foerderung um exakt null - sie wird vollstaendig angerechnet. Deshalb kann ein einzelnes Kind das "
- "Ergebnis sogar minimal verschlechtern, waehrend zwei Kinder es deutlich verbessern."), "10a Abs. 2 EStG"),
- ("Standarddepot", (
- "Kostenreguliertes Standardprodukt, das jeder Anbieter fuehren muss. Die Effektivkosten sind auf 1,0 % p.a. "
- "begrenzt."), "Altersvorsorgereformgesetz"),
-
- ("H", "Privates Depot", None, None),
- ("Vorabpauschale", (
- "Jaehrliche Vorwegbesteuerung thesaurierender Fonds. Bemessungsgrundlage ist der Basisertrag = Wert am "
- "Jahresanfang x Basiszins x 70 %, gedeckelt auf den tatsaechlichen Wertzuwachs. Basiszins 2026: 3,20 %. "
- "Bereits versteuerte Vorabpauschalen erhoehen die Anschaffungskosten und mindern spaeter den zu versteuernden "
- "Veraeusserungsgewinn - der Effekt ist also primaer ein Liquiditaets- und Zinseszinsnachteil."), "18 InvStG"),
- ("Teilfreistellung", (
- "Bei Aktienfonds mit einer Aktienquote ueber 50 % bleiben 30 % der Ertraege im Privatvermoegen steuerfrei. "
- "Effektive Belastung damit rund 18,5 % statt 26,375 %."), "20 InvStG"),
- ("Abgeltungsteuer", (
- "25 % zuzueglich Solidaritaetszuschlag und gegebenenfalls Kirchensteuer. Effektiv 26,375 % ohne bzw. rund "
- "27,8 bis 28,0 % mit Kirchensteuer. Anders als bei der nachgelagerten Besteuerung ist der Satz vom "
- "persoenlichen Grenzsteuersatz unabhaengig - der grosse Vorteil des freien Depots bei hohen Einkommen."),
- "32d, 43a EStG"),
- ("Sparer-Pauschbetrag", (
- "1.000 EUR je Person und Jahr steuerfreier Kapitalertrag, bei Zusammenveranlagung 2.000 EUR."), "20 Abs. 9 EStG"),
-
- ("H", "Auswertung", None, None),
- ("Barwert", (
- "Auf heute abgezinster Betrag, hier mit der Inflationsrate diskontiert. Damit sind alle Zahlen in Kaufkraft "
- "von heute vergleichbar - unerlaesslich, wenn Zahlungen 30 bis 50 Jahre auseinanderliegen."), None),
- ("Netto-Ertrag", (
- "Barwert aller Netto-Auszahlungen minus Barwert des gesamten Nettoaufwands. Die Hauptkennzahl: was eine Option "
- "ueber den eigenen Einsatz hinaus abwirft."), "Zeile 15 im Blatt 'Vergleich'"),
- ("Interner Zinsfuss (IRR)", (
- "Der Zinssatz, bei dem der Kapitalwert aller Zahlungsstroeme null wird, also die Nullstelle des Polynoms "
- "Summe CF_t / (1+i)^t. Direkt mit der angenommenen Bruttorendite des ETF vergleichbar: liegt der IRR darunter, "
- "frisst die Foerderarchitektur mehr als sie bringt."), "Blatt 'Cashflow'"),
- ("Annuitaetenfaktor", (
- "Faktor, der ein Kapital in eine konstante nominale Jahresentnahme ueber n Jahre umrechnet: "
- "a = r / (1 - (1+r)^-n). Wird fuer die Auszahlungsplaene von Altersvorsorgedepot und Privatdepot benutzt."),
- "Modellkonvention"),
- ("Sleeve", (
- "Hilfsbegriff des Modells: der Teil des Nettoaufwands, der den jaehrlichen Hoechstbetrag des "
- "Altersvorsorgevertrags von 6.840 EUR uebersteigt. Er wird in ein normales Depot geleitet und wie Option 3 "
- "besteuert, damit alle drei Optionen exakt denselben Nettoaufwand haben."), "Modellkonvention"),
- ("Vergleichshorizont", (
- "Alter, bis zu dem gerechnet wird (Default 85). Auszahlungsplaene enden hier. Eine lebenslange bAV-Rente zahlt "
- "darueber hinaus; dieser Betrag steht als Memo-Zeile im Blatt 'Vergleich' und geht NICHT in den Vergleich ein."),
- "Eingabe"),
-]
-
-r = 4
-for item in GLOSS:
- if item[0] == "H":
- bw.cell(r, 2, item[1]).font = H2
- for c in (2, 3, 4):
- bw.cell(r, c).fill = GREYFILL
- r += 1
- continue
- term, expl, ref = item
- tc = bw.cell(r, 2, term)
- tc.font = BOLD
- tc.alignment = Alignment(vertical="top")
- tc.border = BOX
- ec = bw.cell(r, 3, expl)
- ec.font = Font(name=FONT, size=10)
- ec.alignment = Alignment(wrap_text=True, vertical="top")
- ec.border = BOX
- rc = bw.cell(r, 4, ref if ref else "")
- rc.font = Font(name=FONT, size=9, italic=True, color="595959")
- rc.alignment = Alignment(wrap_text=True, vertical="top")
- rc.border = BOX
- lines = expl.count("\n") + 1 + len(expl) // 100
- bw.row_dimensions[r].height = max(28, 13 * lines)
- r += 1
-
-wb.save(OUT)
-print("saved", OUT)
diff --git a/recalc.log b/recalc.log
deleted file mode 100644
index e69de29..0000000
--- a/recalc.log
+++ /dev/null