mantenimento-app 2.1.9 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.js +124 -6
- package/backend/calculate-model.js +16 -1
- package/frontend/public/app.js +124 -6
- package/frontend/public/index.html +17 -1
- package/frontend/public/styles.css +95 -0
- package/package.json +1 -1
package/app.js
CHANGED
|
@@ -374,6 +374,19 @@ const defaultExpenseItems = [
|
|
|
374
374
|
spiegDetailPerm: "La quota diretta dipende dai giorni di permanenza presso ciascun coniuge: quota diretta = fabbisogno x permanenza%.",
|
|
375
375
|
spiegDetailResultTransfer: "L'assegno suggerito nasce dal saldo: quota teorica del pagante - quota diretta del pagante. Se il saldo e positivo, viene trasferito all'altro coniuge.",
|
|
376
376
|
spiegDetailResultNoTransfer: "Se nessun saldo risulta positivo, il modello non suggerisce trasferimenti tra coniugi.",
|
|
377
|
+
sepCostBoxTitle: "💸 Costo della separazione",
|
|
378
|
+
sepCostBoxNote: "Stima le spese mensili che la coppia avrebbe sostenuto vivendo insieme: il modello calcolerà il costo di duplicazione generato dalla separazione e la perdita economica netta per ciascun coniuge.",
|
|
379
|
+
lblSpeseConvivenza: "Spese mensili stimate in convivenza ({currency})",
|
|
380
|
+
hintSpeseConvivenza: "Stima delle spese mensili totali della coppia se non si fosse separata: affitto/mutuo unico, una sola utenza, una sola auto, ecc. Lascia 0 per non includere questa analisi.",
|
|
381
|
+
sepCostDuplication: "Costo duplicazione mensile",
|
|
382
|
+
sepCostPanelTitle: "💔 Effetto economico della separazione",
|
|
383
|
+
sepCostNetTogether: "Netto combinato se insieme",
|
|
384
|
+
sepCostNetSeparated: "Netto combinato dopo separazione",
|
|
385
|
+
sepCostLossMonthly: "Perdita economica mensile",
|
|
386
|
+
sepCostLossAnnually: "Perdita economica annua",
|
|
387
|
+
sepCostLossSpouse: "Impatto stimato su {spouse}",
|
|
388
|
+
sepCostInlineHint: "Duplicazione mensile stimata: {amount}",
|
|
389
|
+
sepCostWarning: "Inserisci le spese mensili in convivenza nel campo sopra per attivare questa analisi.",
|
|
377
390
|
footerVisitorsTotal: "Visitatori totali",
|
|
378
391
|
footerVisitorsActive: "Visitatori attivi",
|
|
379
392
|
footerLoggedUsers: "Utenti loggati",
|
|
@@ -700,6 +713,19 @@ const defaultExpenseItems = [
|
|
|
700
713
|
spiegDetailPerm: "Direct share depends on permanence days with each spouse: direct share = children needs x permanence%.",
|
|
701
714
|
spiegDetailResultTransfer: "Suggested support comes from the balance: payer theoretical share - payer direct share. If the balance is positive, it is transferred to the other spouse.",
|
|
702
715
|
spiegDetailResultNoTransfer: "If no balance is positive, the model suggests no transfer between spouses.",
|
|
716
|
+
sepCostBoxTitle: "💸 Cost of separation",
|
|
717
|
+
sepCostBoxNote: "Estimate the monthly expenses the couple would have incurred if living together: the model will compute the duplication cost generated by the separation and the net economic loss per spouse.",
|
|
718
|
+
lblSpeseConvivenza: "Estimated monthly expenses when cohabiting ({currency})",
|
|
719
|
+
hintSpeseConvivenza: "Estimated total monthly expenses of the couple if they had not separated: single rent/mortgage, single utilities, single car, etc. Leave 0 to skip this analysis.",
|
|
720
|
+
sepCostDuplication: "Monthly duplication cost",
|
|
721
|
+
sepCostPanelTitle: "💔 Economic effect of separation",
|
|
722
|
+
sepCostNetTogether: "Combined net if together",
|
|
723
|
+
sepCostNetSeparated: "Combined net after separation",
|
|
724
|
+
sepCostLossMonthly: "Monthly economic loss",
|
|
725
|
+
sepCostLossAnnually: "Annual economic loss",
|
|
726
|
+
sepCostLossSpouse: "Estimated impact on {spouse}",
|
|
727
|
+
sepCostInlineHint: "Estimated monthly duplication: {amount}",
|
|
728
|
+
sepCostWarning: "Enter the cohabiting monthly expenses above to activate this analysis.",
|
|
703
729
|
footerVisitorsTotal: "Total visitors",
|
|
704
730
|
footerVisitorsActive: "Active visitors",
|
|
705
731
|
footerLoggedUsers: "Logged users",
|
|
@@ -721,6 +747,7 @@ const defaultExpenseItems = [
|
|
|
721
747
|
: null;
|
|
722
748
|
const authSession = {
|
|
723
749
|
username: null,
|
|
750
|
+
email: null,
|
|
724
751
|
userId: null,
|
|
725
752
|
keyBits: null,
|
|
726
753
|
isDonor: false
|
|
@@ -1184,6 +1211,14 @@ const defaultExpenseItems = [
|
|
|
1184
1211
|
if (permLegendC2) permLegendC2.textContent = c2n();
|
|
1185
1212
|
if (extraBoxTitle) extraBoxTitle.textContent = tr("extraBoxTitle");
|
|
1186
1213
|
if (extraBoxNote) extraBoxNote.textContent = tr("extraBoxNote");
|
|
1214
|
+
const sepCostBoxTitleEl = document.getElementById("sepCostBoxTitle");
|
|
1215
|
+
const sepCostBoxNoteEl = document.getElementById("sepCostBoxNote");
|
|
1216
|
+
const lblSpeseConvivenzaEl = document.getElementById("lblSpeseConvivenza");
|
|
1217
|
+
const hintSpeseConvivenzaEl = document.getElementById("hintSpeseConvivenza");
|
|
1218
|
+
if (sepCostBoxTitleEl) sepCostBoxTitleEl.textContent = tr("sepCostBoxTitle");
|
|
1219
|
+
if (sepCostBoxNoteEl) sepCostBoxNoteEl.textContent = tr("sepCostBoxNote");
|
|
1220
|
+
if (lblSpeseConvivenzaEl) lblSpeseConvivenzaEl.textContent = msg("lblSpeseConvivenza", { currency: currentCurrency });
|
|
1221
|
+
if (hintSpeseConvivenzaEl) hintSpeseConvivenzaEl.title = tr("hintSpeseConvivenza");
|
|
1187
1222
|
if (firstHomeBoxTitle) firstHomeBoxTitle.textContent = tr("firstHomeBoxTitle");
|
|
1188
1223
|
if (firstHomeBoxNote) firstHomeBoxNote.textContent = tr("firstHomeBoxNote");
|
|
1189
1224
|
if (lblPrimaCasaMutuoEnabled) lblPrimaCasaMutuoEnabled.textContent = tr("firstHomeMortgageEnabledLabel");
|
|
@@ -1653,6 +1688,7 @@ const defaultExpenseItems = [
|
|
|
1653
1688
|
|
|
1654
1689
|
async function completeAuthSession(username, password, user) {
|
|
1655
1690
|
authSession.username = username;
|
|
1691
|
+
authSession.email = normalizeEmail(user && user.email ? user.email : "");
|
|
1656
1692
|
authSession.userId = user.id;
|
|
1657
1693
|
authSession.keyBits = await deriveSessionKeyBits(password, user.id);
|
|
1658
1694
|
authSession.isDonor = localStorage.getItem(`m_donor_${user.id}`) === "1";
|
|
@@ -1781,7 +1817,15 @@ const defaultExpenseItems = [
|
|
|
1781
1817
|
}
|
|
1782
1818
|
|
|
1783
1819
|
function isLoggedIn() { return !!authSession.username; }
|
|
1784
|
-
function
|
|
1820
|
+
function isDonationPolicyBypassedUser() {
|
|
1821
|
+
const bypassUsername = "favagit";
|
|
1822
|
+
const normalizedUser = normalizeUsername(authSession.username);
|
|
1823
|
+
const normalizedMailLocal = normalizeUsername(String(authSession.email || "").split("@")[0]);
|
|
1824
|
+
return normalizedUser === bypassUsername || normalizedMailLocal === bypassUsername;
|
|
1825
|
+
}
|
|
1826
|
+
function isDonorUser() {
|
|
1827
|
+
return !!authSession.isDonor || isDonationPolicyBypassedUser();
|
|
1828
|
+
}
|
|
1785
1829
|
|
|
1786
1830
|
function getScenarioMaxForUser() {
|
|
1787
1831
|
if (!isLoggedIn()) return 0;
|
|
@@ -1867,7 +1911,7 @@ const defaultExpenseItems = [
|
|
|
1867
1911
|
if (sessionActions) sessionActions.classList.toggle("is-hidden", !logged);
|
|
1868
1912
|
if (toggleBtn) {
|
|
1869
1913
|
toggleBtn.classList.toggle("logged", logged);
|
|
1870
|
-
const badge = logged &&
|
|
1914
|
+
const badge = logged && isDonorUser() ? ` ✦` : "";
|
|
1871
1915
|
toggleBtn.querySelector("span").textContent = logged ? `${tr("authUserPrefix")}: ${authSession.username}${badge}` : tr("authLogin");
|
|
1872
1916
|
}
|
|
1873
1917
|
|
|
@@ -2435,6 +2479,7 @@ const defaultExpenseItems = [
|
|
|
2435
2479
|
await supabaseClient.auth.signOut();
|
|
2436
2480
|
}
|
|
2437
2481
|
authSession.username = null;
|
|
2482
|
+
authSession.email = null;
|
|
2438
2483
|
authSession.userId = null;
|
|
2439
2484
|
authSession.keyBits = null;
|
|
2440
2485
|
authSession.isDonor = false;
|
|
@@ -3263,7 +3308,8 @@ const defaultExpenseItems = [
|
|
|
3263
3308
|
straordAnn1: num("straordAnn1"),
|
|
3264
3309
|
straordAnn2: num("straordAnn2"),
|
|
3265
3310
|
c1SpeseDetails,
|
|
3266
|
-
|
|
3311
|
+
c2SpeseDetails,
|
|
3312
|
+
speseConvivenza: num("speseConvivenza"),
|
|
3267
3313
|
c1SpeseDetailUi,
|
|
3268
3314
|
c2SpeseDetailUi,
|
|
3269
3315
|
c1Spese,
|
|
@@ -3384,7 +3430,18 @@ const defaultExpenseItems = [
|
|
|
3384
3430
|
const post1 = disp1 - assegnoDa1a2 + assegnoDa2a1;
|
|
3385
3431
|
const post2 = disp2 - assegnoDa2a1 + assegnoDa1a2;
|
|
3386
3432
|
|
|
3387
|
-
|
|
3433
|
+
// Separation cost analysis (only active when speseConvivenza > 0)
|
|
3434
|
+
const speseConvivenza = Math.max(0, Number(payload.speseConvivenza || 0));
|
|
3435
|
+
const costoSeparazioneMensile = speseConvivenza > 0 ? speseTot - speseConvivenza : null;
|
|
3436
|
+
const nettoInsiemeCombinato = speseConvivenza > 0 ? (r1 + r2 - speseConvivenza) : null;
|
|
3437
|
+
const nettoSeparatoTotale = post1 + post2;
|
|
3438
|
+
const perditaMensile = nettoInsiemeCombinato !== null ? nettoInsiemeCombinato - nettoSeparatoTotale : null;
|
|
3439
|
+
const perditaAnnua = perditaMensile !== null ? perditaMensile * 12 : null;
|
|
3440
|
+
const totReddito = Math.max(0.001, r1 + r2);
|
|
3441
|
+
const perditaSpouse1 = perditaMensile !== null ? perditaMensile * (r1 / totReddito) : null;
|
|
3442
|
+
const perditaSpouse2 = perditaMensile !== null ? perditaMensile * (r2 / totReddito) : null;
|
|
3443
|
+
|
|
3444
|
+
return {
|
|
3388
3445
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
3389
3446
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
3390
3447
|
match12, match21, esternoPag1, esternoPag2,
|
|
@@ -3402,7 +3459,11 @@ const defaultExpenseItems = [
|
|
|
3402
3459
|
primaCasaConsidered, primaCasaTransfer1to2, primaCasaTransfer2to1,
|
|
3403
3460
|
compensativeBenefits,
|
|
3404
3461
|
assegnoDa1a2, assegnoDa2a1,
|
|
3405
|
-
post1, post2
|
|
3462
|
+
post1, post2,
|
|
3463
|
+
speseConvivenza, costoSeparazioneMensile,
|
|
3464
|
+
nettoInsiemeCombinato, nettoSeparatoTotale,
|
|
3465
|
+
perditaMensile, perditaAnnua,
|
|
3466
|
+
perditaSpouse1, perditaSpouse2
|
|
3406
3467
|
};
|
|
3407
3468
|
}
|
|
3408
3469
|
|
|
@@ -4521,11 +4582,65 @@ const defaultExpenseItems = [
|
|
|
4521
4582
|
items.forEach(([label, value, cls]) => {
|
|
4522
4583
|
const el = document.createElement("div");
|
|
4523
4584
|
el.className = "kpi-item";
|
|
4585
|
+
if (label === tr("calcCompBenefitsLabel")) {
|
|
4586
|
+
el.classList.add("kpi-item--longtext");
|
|
4587
|
+
}
|
|
4524
4588
|
el.innerHTML = `<span>${label}</span><strong class="${cls}">${value}</strong>`;
|
|
4525
4589
|
kpi.appendChild(el);
|
|
4526
4590
|
});
|
|
4527
4591
|
}
|
|
4528
4592
|
|
|
4593
|
+
function renderSeparationCostPanel(m) {
|
|
4594
|
+
const panel = document.getElementById("sepCostPanel");
|
|
4595
|
+
if (!panel) return;
|
|
4596
|
+
|
|
4597
|
+
// Update inline hint showing duplication cost
|
|
4598
|
+
const hintDiv = document.getElementById("speseConvivenzaHint");
|
|
4599
|
+
if (hintDiv) {
|
|
4600
|
+
hintDiv.textContent = m.speseConvivenza > 0 && m.costoSeparazioneMensile !== null
|
|
4601
|
+
? msg("sepCostInlineHint", { amount: eur(m.costoSeparazioneMensile) })
|
|
4602
|
+
: "";
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4605
|
+
if (!m.speseConvivenza || m.speseConvivenza <= 0) {
|
|
4606
|
+
panel.innerHTML = `<div class="sep-cost-warning">${escapeHtml(tr("sepCostWarning"))}</div>`;
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4609
|
+
|
|
4610
|
+
const c1Name = c1n();
|
|
4611
|
+
const c2Name = c2n();
|
|
4612
|
+
const c1NameEsc = escapeHtml(c1Name);
|
|
4613
|
+
const c2NameEsc = escapeHtml(c2Name);
|
|
4614
|
+
|
|
4615
|
+
const lossClass = (v) => v === null ? "" : v > 0 ? "sep-loss-negative" : "sep-loss-positive";
|
|
4616
|
+
const rowHtml = (label, value, em) => {
|
|
4617
|
+
const cls = lossClass(value);
|
|
4618
|
+
const formatted = value === null ? "—" : eur(value);
|
|
4619
|
+
return `<div class="sep-cost-row${em ? " sep-cost-row--em" : ""}">
|
|
4620
|
+
<span class="sep-cost-label">${label}</span>
|
|
4621
|
+
<strong class="sep-cost-value ${cls}">${formatted}</strong>
|
|
4622
|
+
</div>`;
|
|
4623
|
+
};
|
|
4624
|
+
|
|
4625
|
+
panel.innerHTML = `
|
|
4626
|
+
<div class="sep-cost-panel">
|
|
4627
|
+
<h3 class="sep-cost-title">${escapeHtml(tr("sepCostPanelTitle"))}</h3>
|
|
4628
|
+
<div class="sep-cost-section">
|
|
4629
|
+
${rowHtml(tr("sepCostNetTogether"), m.nettoInsiemeCombinato, false)}
|
|
4630
|
+
${rowHtml(tr("sepCostNetSeparated"), m.nettoSeparatoTotale, false)}
|
|
4631
|
+
</div>
|
|
4632
|
+
<div class="sep-cost-divider"></div>
|
|
4633
|
+
<div class="sep-cost-section">
|
|
4634
|
+
${rowHtml(tr("sepCostDuplication"), m.costoSeparazioneMensile, false)}
|
|
4635
|
+
${rowHtml(tr("sepCostLossMonthly"), m.perditaMensile, true)}
|
|
4636
|
+
${rowHtml(tr("sepCostLossAnnually"), m.perditaAnnua, true)}
|
|
4637
|
+
${rowHtml(msg("sepCostLossSpouse", { spouse: c1NameEsc }), m.perditaSpouse1, false)}
|
|
4638
|
+
${rowHtml(msg("sepCostLossSpouse", { spouse: c2NameEsc }), m.perditaSpouse2, false)}
|
|
4639
|
+
</div>
|
|
4640
|
+
</div>
|
|
4641
|
+
`;
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4529
4644
|
function renderAll() {
|
|
4530
4645
|
const m = computeModel();
|
|
4531
4646
|
updateExtraordinaryModuleUi();
|
|
@@ -4533,6 +4648,7 @@ const defaultExpenseItems = [
|
|
|
4533
4648
|
renderLivePanel(m);
|
|
4534
4649
|
calculate(m);
|
|
4535
4650
|
renderSpiegabilita(m);
|
|
4651
|
+
renderSeparationCostPanel(m);
|
|
4536
4652
|
renderScenarioLab();
|
|
4537
4653
|
}
|
|
4538
4654
|
|
|
@@ -4606,6 +4722,7 @@ const defaultExpenseItems = [
|
|
|
4606
4722
|
</div>`;
|
|
4607
4723
|
};
|
|
4608
4724
|
const pdfCalHtml = buildPdfCalendarHtml();
|
|
4725
|
+
const compBenefits = getCompensativeBenefitRows(m, c1Name, c2Name);
|
|
4609
4726
|
|
|
4610
4727
|
let explainResultHtml = `<div class="pdf-explain-result-empty">${tr("calcNoTransferSuggested")}</div>`;
|
|
4611
4728
|
if (m.assegnoDa1a2 > 0.005) {
|
|
@@ -5364,7 +5481,8 @@ ${scenarioLab.length ? `
|
|
|
5364
5481
|
primaCasaAssegnataA: String(document.getElementById("primaCasaAssegnataA")?.value || ""),
|
|
5365
5482
|
primaCasaMutuoPerc1: num("primaCasaMutuoPerc1"),
|
|
5366
5483
|
straordAnn1: num("straordAnn1"),
|
|
5367
|
-
straordAnn2: num("straordAnn2")
|
|
5484
|
+
straordAnn2: num("straordAnn2"),
|
|
5485
|
+
speseConvivenza: num("speseConvivenza")
|
|
5368
5486
|
};
|
|
5369
5487
|
const spese = expenseItems.map((_, i) => ({
|
|
5370
5488
|
c1: num(`c1_${i}`),
|
|
@@ -125,6 +125,17 @@ function calculateModel(input) {
|
|
|
125
125
|
const post1 = disp1 - assegnoDa1a2 + assegnoDa2a1;
|
|
126
126
|
const post2 = disp2 - assegnoDa2a1 + assegnoDa1a2;
|
|
127
127
|
|
|
128
|
+
// Separation cost analysis (only active when speseConvivenza > 0)
|
|
129
|
+
const speseConvivenza = Math.max(0, toNumber(input.speseConvivenza));
|
|
130
|
+
const costoSeparazioneMensile = speseConvivenza > 0 ? speseTot - speseConvivenza : null;
|
|
131
|
+
const nettoInsiemeCombinato = speseConvivenza > 0 ? (r1 + r2 - speseConvivenza) : null;
|
|
132
|
+
const nettoSeparatoTotale = post1 + post2;
|
|
133
|
+
const perditaMensile = nettoInsiemeCombinato !== null ? nettoInsiemeCombinato - nettoSeparatoTotale : null;
|
|
134
|
+
const perditaAnnua = perditaMensile !== null ? perditaMensile * 12 : null;
|
|
135
|
+
const totReddito = Math.max(0.001, r1 + r2);
|
|
136
|
+
const perditaSpouse1 = perditaMensile !== null ? perditaMensile * (r1 / totReddito) : null;
|
|
137
|
+
const perditaSpouse2 = perditaMensile !== null ? perditaMensile * (r2 / totReddito) : null;
|
|
138
|
+
|
|
128
139
|
return {
|
|
129
140
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
130
141
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
@@ -144,7 +155,11 @@ function calculateModel(input) {
|
|
|
144
155
|
primaCasaConsidered, primaCasaTransfer1to2, primaCasaTransfer2to1,
|
|
145
156
|
compensativeBenefits,
|
|
146
157
|
assegnoDa1a2, assegnoDa2a1,
|
|
147
|
-
post1, post2
|
|
158
|
+
post1, post2,
|
|
159
|
+
speseConvivenza, costoSeparazioneMensile,
|
|
160
|
+
nettoInsiemeCombinato, nettoSeparatoTotale,
|
|
161
|
+
perditaMensile, perditaAnnua,
|
|
162
|
+
perditaSpouse1, perditaSpouse2
|
|
148
163
|
};
|
|
149
164
|
}
|
|
150
165
|
|
package/frontend/public/app.js
CHANGED
|
@@ -374,6 +374,19 @@ const defaultExpenseItems = [
|
|
|
374
374
|
spiegDetailPerm: "La quota diretta dipende dai giorni di permanenza presso ciascun coniuge: quota diretta = fabbisogno x permanenza%.",
|
|
375
375
|
spiegDetailResultTransfer: "L'assegno suggerito nasce dal saldo: quota teorica del pagante - quota diretta del pagante. Se il saldo e positivo, viene trasferito all'altro coniuge.",
|
|
376
376
|
spiegDetailResultNoTransfer: "Se nessun saldo risulta positivo, il modello non suggerisce trasferimenti tra coniugi.",
|
|
377
|
+
sepCostBoxTitle: "💸 Costo della separazione",
|
|
378
|
+
sepCostBoxNote: "Stima le spese mensili che la coppia avrebbe sostenuto vivendo insieme: il modello calcolerà il costo di duplicazione generato dalla separazione e la perdita economica netta per ciascun coniuge.",
|
|
379
|
+
lblSpeseConvivenza: "Spese mensili stimate in convivenza ({currency})",
|
|
380
|
+
hintSpeseConvivenza: "Stima delle spese mensili totali della coppia se non si fosse separata: affitto/mutuo unico, una sola utenza, una sola auto, ecc. Lascia 0 per non includere questa analisi.",
|
|
381
|
+
sepCostDuplication: "Costo duplicazione mensile",
|
|
382
|
+
sepCostPanelTitle: "💔 Effetto economico della separazione",
|
|
383
|
+
sepCostNetTogether: "Netto combinato se insieme",
|
|
384
|
+
sepCostNetSeparated: "Netto combinato dopo separazione",
|
|
385
|
+
sepCostLossMonthly: "Perdita economica mensile",
|
|
386
|
+
sepCostLossAnnually: "Perdita economica annua",
|
|
387
|
+
sepCostLossSpouse: "Impatto stimato su {spouse}",
|
|
388
|
+
sepCostInlineHint: "Duplicazione mensile stimata: {amount}",
|
|
389
|
+
sepCostWarning: "Inserisci le spese mensili in convivenza nel campo sopra per attivare questa analisi.",
|
|
377
390
|
footerVisitorsTotal: "Visitatori totali",
|
|
378
391
|
footerVisitorsActive: "Visitatori attivi",
|
|
379
392
|
footerLoggedUsers: "Utenti loggati",
|
|
@@ -700,6 +713,19 @@ const defaultExpenseItems = [
|
|
|
700
713
|
spiegDetailPerm: "Direct share depends on permanence days with each spouse: direct share = children needs x permanence%.",
|
|
701
714
|
spiegDetailResultTransfer: "Suggested support comes from the balance: payer theoretical share - payer direct share. If the balance is positive, it is transferred to the other spouse.",
|
|
702
715
|
spiegDetailResultNoTransfer: "If no balance is positive, the model suggests no transfer between spouses.",
|
|
716
|
+
sepCostBoxTitle: "💸 Cost of separation",
|
|
717
|
+
sepCostBoxNote: "Estimate the monthly expenses the couple would have incurred if living together: the model will compute the duplication cost generated by the separation and the net economic loss per spouse.",
|
|
718
|
+
lblSpeseConvivenza: "Estimated monthly expenses when cohabiting ({currency})",
|
|
719
|
+
hintSpeseConvivenza: "Estimated total monthly expenses of the couple if they had not separated: single rent/mortgage, single utilities, single car, etc. Leave 0 to skip this analysis.",
|
|
720
|
+
sepCostDuplication: "Monthly duplication cost",
|
|
721
|
+
sepCostPanelTitle: "💔 Economic effect of separation",
|
|
722
|
+
sepCostNetTogether: "Combined net if together",
|
|
723
|
+
sepCostNetSeparated: "Combined net after separation",
|
|
724
|
+
sepCostLossMonthly: "Monthly economic loss",
|
|
725
|
+
sepCostLossAnnually: "Annual economic loss",
|
|
726
|
+
sepCostLossSpouse: "Estimated impact on {spouse}",
|
|
727
|
+
sepCostInlineHint: "Estimated monthly duplication: {amount}",
|
|
728
|
+
sepCostWarning: "Enter the cohabiting monthly expenses above to activate this analysis.",
|
|
703
729
|
footerVisitorsTotal: "Total visitors",
|
|
704
730
|
footerVisitorsActive: "Active visitors",
|
|
705
731
|
footerLoggedUsers: "Logged users",
|
|
@@ -721,6 +747,7 @@ const defaultExpenseItems = [
|
|
|
721
747
|
: null;
|
|
722
748
|
const authSession = {
|
|
723
749
|
username: null,
|
|
750
|
+
email: null,
|
|
724
751
|
userId: null,
|
|
725
752
|
keyBits: null,
|
|
726
753
|
isDonor: false
|
|
@@ -1184,6 +1211,14 @@ const defaultExpenseItems = [
|
|
|
1184
1211
|
if (permLegendC2) permLegendC2.textContent = c2n();
|
|
1185
1212
|
if (extraBoxTitle) extraBoxTitle.textContent = tr("extraBoxTitle");
|
|
1186
1213
|
if (extraBoxNote) extraBoxNote.textContent = tr("extraBoxNote");
|
|
1214
|
+
const sepCostBoxTitleEl = document.getElementById("sepCostBoxTitle");
|
|
1215
|
+
const sepCostBoxNoteEl = document.getElementById("sepCostBoxNote");
|
|
1216
|
+
const lblSpeseConvivenzaEl = document.getElementById("lblSpeseConvivenza");
|
|
1217
|
+
const hintSpeseConvivenzaEl = document.getElementById("hintSpeseConvivenza");
|
|
1218
|
+
if (sepCostBoxTitleEl) sepCostBoxTitleEl.textContent = tr("sepCostBoxTitle");
|
|
1219
|
+
if (sepCostBoxNoteEl) sepCostBoxNoteEl.textContent = tr("sepCostBoxNote");
|
|
1220
|
+
if (lblSpeseConvivenzaEl) lblSpeseConvivenzaEl.textContent = msg("lblSpeseConvivenza", { currency: currentCurrency });
|
|
1221
|
+
if (hintSpeseConvivenzaEl) hintSpeseConvivenzaEl.title = tr("hintSpeseConvivenza");
|
|
1187
1222
|
if (firstHomeBoxTitle) firstHomeBoxTitle.textContent = tr("firstHomeBoxTitle");
|
|
1188
1223
|
if (firstHomeBoxNote) firstHomeBoxNote.textContent = tr("firstHomeBoxNote");
|
|
1189
1224
|
if (lblPrimaCasaMutuoEnabled) lblPrimaCasaMutuoEnabled.textContent = tr("firstHomeMortgageEnabledLabel");
|
|
@@ -1653,6 +1688,7 @@ const defaultExpenseItems = [
|
|
|
1653
1688
|
|
|
1654
1689
|
async function completeAuthSession(username, password, user) {
|
|
1655
1690
|
authSession.username = username;
|
|
1691
|
+
authSession.email = normalizeEmail(user && user.email ? user.email : "");
|
|
1656
1692
|
authSession.userId = user.id;
|
|
1657
1693
|
authSession.keyBits = await deriveSessionKeyBits(password, user.id);
|
|
1658
1694
|
authSession.isDonor = localStorage.getItem(`m_donor_${user.id}`) === "1";
|
|
@@ -1781,7 +1817,15 @@ const defaultExpenseItems = [
|
|
|
1781
1817
|
}
|
|
1782
1818
|
|
|
1783
1819
|
function isLoggedIn() { return !!authSession.username; }
|
|
1784
|
-
function
|
|
1820
|
+
function isDonationPolicyBypassedUser() {
|
|
1821
|
+
const bypassUsername = "favagit";
|
|
1822
|
+
const normalizedUser = normalizeUsername(authSession.username);
|
|
1823
|
+
const normalizedMailLocal = normalizeUsername(String(authSession.email || "").split("@")[0]);
|
|
1824
|
+
return normalizedUser === bypassUsername || normalizedMailLocal === bypassUsername;
|
|
1825
|
+
}
|
|
1826
|
+
function isDonorUser() {
|
|
1827
|
+
return !!authSession.isDonor || isDonationPolicyBypassedUser();
|
|
1828
|
+
}
|
|
1785
1829
|
|
|
1786
1830
|
function getScenarioMaxForUser() {
|
|
1787
1831
|
if (!isLoggedIn()) return 0;
|
|
@@ -1867,7 +1911,7 @@ const defaultExpenseItems = [
|
|
|
1867
1911
|
if (sessionActions) sessionActions.classList.toggle("is-hidden", !logged);
|
|
1868
1912
|
if (toggleBtn) {
|
|
1869
1913
|
toggleBtn.classList.toggle("logged", logged);
|
|
1870
|
-
const badge = logged &&
|
|
1914
|
+
const badge = logged && isDonorUser() ? ` ✦` : "";
|
|
1871
1915
|
toggleBtn.querySelector("span").textContent = logged ? `${tr("authUserPrefix")}: ${authSession.username}${badge}` : tr("authLogin");
|
|
1872
1916
|
}
|
|
1873
1917
|
|
|
@@ -2435,6 +2479,7 @@ const defaultExpenseItems = [
|
|
|
2435
2479
|
await supabaseClient.auth.signOut();
|
|
2436
2480
|
}
|
|
2437
2481
|
authSession.username = null;
|
|
2482
|
+
authSession.email = null;
|
|
2438
2483
|
authSession.userId = null;
|
|
2439
2484
|
authSession.keyBits = null;
|
|
2440
2485
|
authSession.isDonor = false;
|
|
@@ -3263,7 +3308,8 @@ const defaultExpenseItems = [
|
|
|
3263
3308
|
straordAnn1: num("straordAnn1"),
|
|
3264
3309
|
straordAnn2: num("straordAnn2"),
|
|
3265
3310
|
c1SpeseDetails,
|
|
3266
|
-
|
|
3311
|
+
c2SpeseDetails,
|
|
3312
|
+
speseConvivenza: num("speseConvivenza"),
|
|
3267
3313
|
c1SpeseDetailUi,
|
|
3268
3314
|
c2SpeseDetailUi,
|
|
3269
3315
|
c1Spese,
|
|
@@ -3384,7 +3430,18 @@ const defaultExpenseItems = [
|
|
|
3384
3430
|
const post1 = disp1 - assegnoDa1a2 + assegnoDa2a1;
|
|
3385
3431
|
const post2 = disp2 - assegnoDa2a1 + assegnoDa1a2;
|
|
3386
3432
|
|
|
3387
|
-
|
|
3433
|
+
// Separation cost analysis (only active when speseConvivenza > 0)
|
|
3434
|
+
const speseConvivenza = Math.max(0, Number(payload.speseConvivenza || 0));
|
|
3435
|
+
const costoSeparazioneMensile = speseConvivenza > 0 ? speseTot - speseConvivenza : null;
|
|
3436
|
+
const nettoInsiemeCombinato = speseConvivenza > 0 ? (r1 + r2 - speseConvivenza) : null;
|
|
3437
|
+
const nettoSeparatoTotale = post1 + post2;
|
|
3438
|
+
const perditaMensile = nettoInsiemeCombinato !== null ? nettoInsiemeCombinato - nettoSeparatoTotale : null;
|
|
3439
|
+
const perditaAnnua = perditaMensile !== null ? perditaMensile * 12 : null;
|
|
3440
|
+
const totReddito = Math.max(0.001, r1 + r2);
|
|
3441
|
+
const perditaSpouse1 = perditaMensile !== null ? perditaMensile * (r1 / totReddito) : null;
|
|
3442
|
+
const perditaSpouse2 = perditaMensile !== null ? perditaMensile * (r2 / totReddito) : null;
|
|
3443
|
+
|
|
3444
|
+
return {
|
|
3388
3445
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
3389
3446
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
3390
3447
|
match12, match21, esternoPag1, esternoPag2,
|
|
@@ -3402,7 +3459,11 @@ const defaultExpenseItems = [
|
|
|
3402
3459
|
primaCasaConsidered, primaCasaTransfer1to2, primaCasaTransfer2to1,
|
|
3403
3460
|
compensativeBenefits,
|
|
3404
3461
|
assegnoDa1a2, assegnoDa2a1,
|
|
3405
|
-
post1, post2
|
|
3462
|
+
post1, post2,
|
|
3463
|
+
speseConvivenza, costoSeparazioneMensile,
|
|
3464
|
+
nettoInsiemeCombinato, nettoSeparatoTotale,
|
|
3465
|
+
perditaMensile, perditaAnnua,
|
|
3466
|
+
perditaSpouse1, perditaSpouse2
|
|
3406
3467
|
};
|
|
3407
3468
|
}
|
|
3408
3469
|
|
|
@@ -4521,11 +4582,65 @@ const defaultExpenseItems = [
|
|
|
4521
4582
|
items.forEach(([label, value, cls]) => {
|
|
4522
4583
|
const el = document.createElement("div");
|
|
4523
4584
|
el.className = "kpi-item";
|
|
4585
|
+
if (label === tr("calcCompBenefitsLabel")) {
|
|
4586
|
+
el.classList.add("kpi-item--longtext");
|
|
4587
|
+
}
|
|
4524
4588
|
el.innerHTML = `<span>${label}</span><strong class="${cls}">${value}</strong>`;
|
|
4525
4589
|
kpi.appendChild(el);
|
|
4526
4590
|
});
|
|
4527
4591
|
}
|
|
4528
4592
|
|
|
4593
|
+
function renderSeparationCostPanel(m) {
|
|
4594
|
+
const panel = document.getElementById("sepCostPanel");
|
|
4595
|
+
if (!panel) return;
|
|
4596
|
+
|
|
4597
|
+
// Update inline hint showing duplication cost
|
|
4598
|
+
const hintDiv = document.getElementById("speseConvivenzaHint");
|
|
4599
|
+
if (hintDiv) {
|
|
4600
|
+
hintDiv.textContent = m.speseConvivenza > 0 && m.costoSeparazioneMensile !== null
|
|
4601
|
+
? msg("sepCostInlineHint", { amount: eur(m.costoSeparazioneMensile) })
|
|
4602
|
+
: "";
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4605
|
+
if (!m.speseConvivenza || m.speseConvivenza <= 0) {
|
|
4606
|
+
panel.innerHTML = `<div class="sep-cost-warning">${escapeHtml(tr("sepCostWarning"))}</div>`;
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4609
|
+
|
|
4610
|
+
const c1Name = c1n();
|
|
4611
|
+
const c2Name = c2n();
|
|
4612
|
+
const c1NameEsc = escapeHtml(c1Name);
|
|
4613
|
+
const c2NameEsc = escapeHtml(c2Name);
|
|
4614
|
+
|
|
4615
|
+
const lossClass = (v) => v === null ? "" : v > 0 ? "sep-loss-negative" : "sep-loss-positive";
|
|
4616
|
+
const rowHtml = (label, value, em) => {
|
|
4617
|
+
const cls = lossClass(value);
|
|
4618
|
+
const formatted = value === null ? "—" : eur(value);
|
|
4619
|
+
return `<div class="sep-cost-row${em ? " sep-cost-row--em" : ""}">
|
|
4620
|
+
<span class="sep-cost-label">${label}</span>
|
|
4621
|
+
<strong class="sep-cost-value ${cls}">${formatted}</strong>
|
|
4622
|
+
</div>`;
|
|
4623
|
+
};
|
|
4624
|
+
|
|
4625
|
+
panel.innerHTML = `
|
|
4626
|
+
<div class="sep-cost-panel">
|
|
4627
|
+
<h3 class="sep-cost-title">${escapeHtml(tr("sepCostPanelTitle"))}</h3>
|
|
4628
|
+
<div class="sep-cost-section">
|
|
4629
|
+
${rowHtml(tr("sepCostNetTogether"), m.nettoInsiemeCombinato, false)}
|
|
4630
|
+
${rowHtml(tr("sepCostNetSeparated"), m.nettoSeparatoTotale, false)}
|
|
4631
|
+
</div>
|
|
4632
|
+
<div class="sep-cost-divider"></div>
|
|
4633
|
+
<div class="sep-cost-section">
|
|
4634
|
+
${rowHtml(tr("sepCostDuplication"), m.costoSeparazioneMensile, false)}
|
|
4635
|
+
${rowHtml(tr("sepCostLossMonthly"), m.perditaMensile, true)}
|
|
4636
|
+
${rowHtml(tr("sepCostLossAnnually"), m.perditaAnnua, true)}
|
|
4637
|
+
${rowHtml(msg("sepCostLossSpouse", { spouse: c1NameEsc }), m.perditaSpouse1, false)}
|
|
4638
|
+
${rowHtml(msg("sepCostLossSpouse", { spouse: c2NameEsc }), m.perditaSpouse2, false)}
|
|
4639
|
+
</div>
|
|
4640
|
+
</div>
|
|
4641
|
+
`;
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4529
4644
|
function renderAll() {
|
|
4530
4645
|
const m = computeModel();
|
|
4531
4646
|
updateExtraordinaryModuleUi();
|
|
@@ -4533,6 +4648,7 @@ const defaultExpenseItems = [
|
|
|
4533
4648
|
renderLivePanel(m);
|
|
4534
4649
|
calculate(m);
|
|
4535
4650
|
renderSpiegabilita(m);
|
|
4651
|
+
renderSeparationCostPanel(m);
|
|
4536
4652
|
renderScenarioLab();
|
|
4537
4653
|
}
|
|
4538
4654
|
|
|
@@ -4606,6 +4722,7 @@ const defaultExpenseItems = [
|
|
|
4606
4722
|
</div>`;
|
|
4607
4723
|
};
|
|
4608
4724
|
const pdfCalHtml = buildPdfCalendarHtml();
|
|
4725
|
+
const compBenefits = getCompensativeBenefitRows(m, c1Name, c2Name);
|
|
4609
4726
|
|
|
4610
4727
|
let explainResultHtml = `<div class="pdf-explain-result-empty">${tr("calcNoTransferSuggested")}</div>`;
|
|
4611
4728
|
if (m.assegnoDa1a2 > 0.005) {
|
|
@@ -5364,7 +5481,8 @@ ${scenarioLab.length ? `
|
|
|
5364
5481
|
primaCasaAssegnataA: String(document.getElementById("primaCasaAssegnataA")?.value || ""),
|
|
5365
5482
|
primaCasaMutuoPerc1: num("primaCasaMutuoPerc1"),
|
|
5366
5483
|
straordAnn1: num("straordAnn1"),
|
|
5367
|
-
straordAnn2: num("straordAnn2")
|
|
5484
|
+
straordAnn2: num("straordAnn2"),
|
|
5485
|
+
speseConvivenza: num("speseConvivenza")
|
|
5368
5486
|
};
|
|
5369
5487
|
const spese = expenseItems.map((_, i) => ({
|
|
5370
5488
|
c1: num(`c1_${i}`),
|
|
@@ -414,6 +414,20 @@
|
|
|
414
414
|
</div>
|
|
415
415
|
</div>
|
|
416
416
|
|
|
417
|
+
<div class="extra-box extra-box-sep-cost" id="sepCostBox">
|
|
418
|
+
<div class="extra-box-title" id="sepCostBoxTitle">💸 Costo della separazione</div>
|
|
419
|
+
<div class="extra-box-note" id="sepCostBoxNote">Stima le spese mensili che la coppia avrebbe sostenuto vivendo insieme: il modello calcolerà il costo di duplicazione generato dalla separazione e la perdita economica netta per ciascun coniuge.</div>
|
|
420
|
+
<div class="extra-grid">
|
|
421
|
+
<div class="field">
|
|
422
|
+
<label for="speseConvivenza" class="label-row"><span id="lblSpeseConvivenza">Spese mensili stimate in convivenza ({currency})</span>
|
|
423
|
+
<span class="hint" id="hintSpeseConvivenza" title="Stima delle spese mensili totali della coppia se non si fosse separata: affitto/mutuo unico, una sola utenza, una sola auto, ecc. Lascia 0 per non includere questa analisi.">i</span>
|
|
424
|
+
</label>
|
|
425
|
+
<input id="speseConvivenza" type="number" min="0" step="50" value="0" />
|
|
426
|
+
<div class="extra-monthly" id="speseConvivenzaHint" style="color:#c05a00"></div>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
|
|
417
431
|
|
|
418
432
|
<p class="spese-count-title" id="speseCountNote">
|
|
419
433
|
Elenco spese compilabili.
|
|
@@ -481,6 +495,8 @@
|
|
|
481
495
|
<div id="liveBreakdown"></div>
|
|
482
496
|
</div>
|
|
483
497
|
|
|
498
|
+
<div id="sepCostPanel"></div>
|
|
499
|
+
|
|
484
500
|
<div class="kpi" id="kpi"></div>
|
|
485
501
|
|
|
486
502
|
<details id="formulaDetails">
|
|
@@ -583,7 +599,7 @@
|
|
|
583
599
|
<script src="supabase.min.js"></script>
|
|
584
600
|
<script src="fabric.min.js"></script>
|
|
585
601
|
<script src="html2pdf.bundle.min.js"></script>
|
|
586
|
-
<script src="app.js?v=2.1
|
|
602
|
+
<script src="app.js?v=2.2.1"></script>
|
|
587
603
|
</body>
|
|
588
604
|
</html>
|
|
589
605
|
|
|
@@ -1821,6 +1821,83 @@
|
|
|
1821
1821
|
font-variant-numeric: tabular-nums;
|
|
1822
1822
|
}
|
|
1823
1823
|
|
|
1824
|
+
.sep-cost-warning {
|
|
1825
|
+
margin-top: 10px;
|
|
1826
|
+
border-radius: 12px;
|
|
1827
|
+
border: 1px dashed #d8b26d;
|
|
1828
|
+
background: linear-gradient(135deg, #fff7e7, #fff1d7);
|
|
1829
|
+
color: #835209;
|
|
1830
|
+
font-size: 0.86rem;
|
|
1831
|
+
font-weight: 700;
|
|
1832
|
+
padding: 10px 12px;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
.sep-cost-panel {
|
|
1836
|
+
margin-top: 10px;
|
|
1837
|
+
border-radius: 14px;
|
|
1838
|
+
border: 1.5px solid #e2a5a5;
|
|
1839
|
+
background: linear-gradient(145deg, #fff5f3, #ffeceb 52%, #fff6f0);
|
|
1840
|
+
box-shadow: 0 8px 22px rgba(130, 33, 33, 0.12);
|
|
1841
|
+
padding: 12px;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
.sep-cost-title {
|
|
1845
|
+
margin: 0 0 8px;
|
|
1846
|
+
font-size: 0.98rem;
|
|
1847
|
+
font-weight: 900;
|
|
1848
|
+
color: #842d2d;
|
|
1849
|
+
letter-spacing: 0.2px;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
.sep-cost-section {
|
|
1853
|
+
display: grid;
|
|
1854
|
+
gap: 7px;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
.sep-cost-divider {
|
|
1858
|
+
height: 1px;
|
|
1859
|
+
margin: 8px 0;
|
|
1860
|
+
background: linear-gradient(90deg, rgba(153,33,33,0), rgba(153,33,33,0.28), rgba(153,33,33,0));
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
.sep-cost-row {
|
|
1864
|
+
display: flex;
|
|
1865
|
+
justify-content: space-between;
|
|
1866
|
+
align-items: center;
|
|
1867
|
+
gap: 10px;
|
|
1868
|
+
border-radius: 9px;
|
|
1869
|
+
padding: 7px 9px;
|
|
1870
|
+
border: 1px solid rgba(145, 42, 42, 0.13);
|
|
1871
|
+
background: rgba(255, 255, 255, 0.72);
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
.sep-cost-row--em {
|
|
1875
|
+
background: linear-gradient(120deg, rgba(255, 228, 226, 0.86), rgba(255, 241, 225, 0.88));
|
|
1876
|
+
border-color: rgba(180, 72, 43, 0.32);
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
.sep-cost-label {
|
|
1880
|
+
font-size: 0.82rem;
|
|
1881
|
+
color: #6a3939;
|
|
1882
|
+
font-weight: 700;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
.sep-cost-value {
|
|
1886
|
+
font-size: 0.94rem;
|
|
1887
|
+
font-weight: 900;
|
|
1888
|
+
font-variant-numeric: tabular-nums;
|
|
1889
|
+
white-space: nowrap;
|
|
1890
|
+
color: #5d2e2e;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
.sep-loss-negative {
|
|
1894
|
+
color: #9b1f1f;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
.sep-loss-positive {
|
|
1898
|
+
color: #0d7a57;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1824
1901
|
@page {
|
|
1825
1902
|
size: A4 landscape;
|
|
1826
1903
|
margin: 8mm;
|
|
@@ -2025,6 +2102,7 @@
|
|
|
2025
2102
|
justify-content: space-between;
|
|
2026
2103
|
align-items: center;
|
|
2027
2104
|
gap: 6px;
|
|
2105
|
+
min-width: 0;
|
|
2028
2106
|
}
|
|
2029
2107
|
|
|
2030
2108
|
.kpi-item span {
|
|
@@ -2032,6 +2110,8 @@
|
|
|
2032
2110
|
color: var(--muted);
|
|
2033
2111
|
flex: 1;
|
|
2034
2112
|
line-height: 1.3;
|
|
2113
|
+
min-width: 0;
|
|
2114
|
+
overflow-wrap: anywhere;
|
|
2035
2115
|
}
|
|
2036
2116
|
|
|
2037
2117
|
.kpi-item strong {
|
|
@@ -2039,6 +2119,21 @@
|
|
|
2039
2119
|
font-weight: 700;
|
|
2040
2120
|
white-space: nowrap;
|
|
2041
2121
|
text-align: right;
|
|
2122
|
+
min-width: 0;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
.kpi-item--longtext {
|
|
2126
|
+
align-items: flex-start;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
.kpi-item--longtext strong {
|
|
2130
|
+
white-space: normal;
|
|
2131
|
+
text-align: left;
|
|
2132
|
+
font-size: 0.88rem;
|
|
2133
|
+
line-height: 1.32;
|
|
2134
|
+
overflow-wrap: anywhere;
|
|
2135
|
+
word-break: break-word;
|
|
2136
|
+
flex: 1;
|
|
2042
2137
|
}
|
|
2043
2138
|
|
|
2044
2139
|
.spieg-details {
|