mantenimento-app 2.1.3 → 2.1.5
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 +62 -16
- package/backend/calculate-model.js +9 -6
- package/frontend/public/app.js +62 -16
- package/frontend/public/index.html +27 -3
- package/frontend/public/styles.css +570 -7
- package/package.json +1 -1
package/app.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const defaultExpenseItems = [
|
|
2
2
|
{ label: "🏠 Affitto", help: "Canone mensile di locazione dell'abitazione." },
|
|
3
|
-
{ label: "🏦 Mutuo casa", help: "Rata mensile del mutuo abitazione." },
|
|
4
3
|
{ label: "🏡 Casa (valore locativo)", help: "Valore locativo teorico della casa in uso, se rilevante." },
|
|
5
4
|
{ label: "💡 Utenze", help: "Luce, gas, acqua, internet e altre utenze domestiche." },
|
|
6
5
|
{ label: "🛒 Cibo/Alimenti", help: "Spesa alimentare mensile imputabile al nucleo familiare." },
|
|
@@ -3244,14 +3243,18 @@ const defaultExpenseItems = [
|
|
|
3244
3243
|
const rawMutuoPerc1 = payload.primaCasaMutuoPerc1 === undefined ? 50 : payload.primaCasaMutuoPerc1;
|
|
3245
3244
|
const primaCasaMutuoPerc1 = Math.min(100, Math.max(0, Number(rawMutuoPerc1 || 0)));
|
|
3246
3245
|
const primaCasaMutuoPerc2 = 100 - primaCasaMutuoPerc1;
|
|
3246
|
+
const quotaMutuoSpese1 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100)) : 0;
|
|
3247
|
+
const quotaMutuoSpese2 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto - quotaMutuoSpese1) : 0;
|
|
3247
3248
|
|
|
3248
3249
|
const match12 = Math.min(aPag1, aPerc2);
|
|
3249
3250
|
const match21 = Math.min(aPag2, aPerc1);
|
|
3250
3251
|
const esternoPag1 = Math.max(0, aPag1 - match12);
|
|
3251
3252
|
const esternoPag2 = Math.max(0, aPag2 - match21);
|
|
3252
3253
|
|
|
3253
|
-
const
|
|
3254
|
-
const
|
|
3254
|
+
const speseBase1 = (payload.c1Spese || []).reduce((acc, v) => acc + Number(v || 0), 0);
|
|
3255
|
+
const speseBase2 = (payload.c2Spese || []).reduce((acc, v) => acc + Number(v || 0), 0);
|
|
3256
|
+
const spese1 = speseBase1 + quotaMutuoSpese1;
|
|
3257
|
+
const spese2 = speseBase2 + quotaMutuoSpese2;
|
|
3255
3258
|
const speseTot = spese1 + spese2;
|
|
3256
3259
|
|
|
3257
3260
|
const disp1 = r1 + aPerc1 + aFam1 - aPag1 - spese1;
|
|
@@ -3301,12 +3304,10 @@ const defaultExpenseItems = [
|
|
|
3301
3304
|
let primaCasaTransfer1to2 = 0;
|
|
3302
3305
|
let primaCasaTransfer2to1 = 0;
|
|
3303
3306
|
if (primaCasaConsidered) {
|
|
3304
|
-
const quotaMutuo1 = primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100);
|
|
3305
|
-
const quotaMutuo2 = primaCasaMutuoImporto - quotaMutuo1;
|
|
3306
3307
|
if (primaCasaAssegnataA === "1") {
|
|
3307
|
-
primaCasaTransfer2to1 = Math.max(0,
|
|
3308
|
+
primaCasaTransfer2to1 = Math.max(0, quotaMutuoSpese2);
|
|
3308
3309
|
} else if (primaCasaAssegnataA === "2") {
|
|
3309
|
-
primaCasaTransfer1to2 = Math.max(0,
|
|
3310
|
+
primaCasaTransfer1to2 = Math.max(0, quotaMutuoSpese1);
|
|
3310
3311
|
}
|
|
3311
3312
|
}
|
|
3312
3313
|
|
|
@@ -3326,6 +3327,7 @@ const defaultExpenseItems = [
|
|
|
3326
3327
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
3327
3328
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
3328
3329
|
match12, match21, esternoPag1, esternoPag2,
|
|
3330
|
+
speseBase1, speseBase2, quotaMutuoSpese1, quotaMutuoSpese2,
|
|
3329
3331
|
spese1, spese2, speseTot,
|
|
3330
3332
|
disp1, disp2, peso1, peso2,
|
|
3331
3333
|
mode, simplePerc,
|
|
@@ -3446,6 +3448,12 @@ const defaultExpenseItems = [
|
|
|
3446
3448
|
const assignedEl = document.getElementById("primaCasaAssegnataA");
|
|
3447
3449
|
const shareEl = document.getElementById("primaCasaMutuoPerc1");
|
|
3448
3450
|
const splitInfoEl = document.getElementById("primaCasaMutuoSplitInfo");
|
|
3451
|
+
const splitCenterEl = document.getElementById("primaCasaSplitCenter");
|
|
3452
|
+
const splitLeftNameEl = document.getElementById("primaCasaSplitLeftName");
|
|
3453
|
+
const splitRightNameEl = document.getElementById("primaCasaSplitRightName");
|
|
3454
|
+
const splitLeftAmountEl = document.getElementById("primaCasaSplitLeftAmount");
|
|
3455
|
+
const splitRightAmountEl = document.getElementById("primaCasaSplitRightAmount");
|
|
3456
|
+
const splitWrapEl = document.getElementById("primaCasaMutuoSliderWrap");
|
|
3449
3457
|
const splitLabelEl = document.getElementById("lblPrimaCasaMutuoPerc1");
|
|
3450
3458
|
const splitHintEl = document.getElementById("hintPrimaCasaMutuoPerc1");
|
|
3451
3459
|
if (!enabledEl || !amountEl || !assignedEl || !shareEl) return;
|
|
@@ -3454,6 +3462,7 @@ const defaultExpenseItems = [
|
|
|
3454
3462
|
amountEl.disabled = !isEnabled;
|
|
3455
3463
|
assignedEl.disabled = !isEnabled;
|
|
3456
3464
|
shareEl.disabled = !isEnabled;
|
|
3465
|
+
if (splitWrapEl) splitWrapEl.classList.toggle("is-disabled", !isEnabled);
|
|
3457
3466
|
|
|
3458
3467
|
const normalizedShare1 = Math.min(100, Math.max(0, num("primaCasaMutuoPerc1")));
|
|
3459
3468
|
if (Math.abs(normalizedShare1 - Number(shareEl.value || 0)) > 0.0001) {
|
|
@@ -3461,6 +3470,9 @@ const defaultExpenseItems = [
|
|
|
3461
3470
|
}
|
|
3462
3471
|
|
|
3463
3472
|
const share2 = 100 - normalizedShare1;
|
|
3473
|
+
const amount = Math.max(0, num("primaCasaMutuoImporto"));
|
|
3474
|
+
const quota1 = amount * (normalizedShare1 / 100);
|
|
3475
|
+
const quota2 = amount - quota1;
|
|
3464
3476
|
if (splitLabelEl) splitLabelEl.textContent = msg("firstHomeSplitLabel", { spouse: c1n() });
|
|
3465
3477
|
if (splitHintEl) splitHintEl.title = msg("firstHomeSplitHint", { spouse: c1n() });
|
|
3466
3478
|
if (splitInfoEl) {
|
|
@@ -3471,6 +3483,11 @@ const defaultExpenseItems = [
|
|
|
3471
3483
|
p2: share2.toFixed(0)
|
|
3472
3484
|
});
|
|
3473
3485
|
}
|
|
3486
|
+
if (splitCenterEl) splitCenterEl.textContent = `${normalizedShare1.toFixed(0)}% / ${share2.toFixed(0)}%`;
|
|
3487
|
+
if (splitLeftNameEl) splitLeftNameEl.textContent = c1n();
|
|
3488
|
+
if (splitRightNameEl) splitRightNameEl.textContent = c2n();
|
|
3489
|
+
if (splitLeftAmountEl) splitLeftAmountEl.textContent = eur(quota1);
|
|
3490
|
+
if (splitRightAmountEl) splitRightAmountEl.textContent = eur(quota2);
|
|
3474
3491
|
|
|
3475
3492
|
const noneOpt = assignedEl.querySelector("option[value='']");
|
|
3476
3493
|
const spouse1Opt = assignedEl.querySelector("option[value='1']");
|
|
@@ -4335,17 +4352,35 @@ const defaultExpenseItems = [
|
|
|
4335
4352
|
${m.incomeMode === "cu" ? `<br /><strong>${tr("calcIncomeBaseNote")}</strong> ${tr("cuNetNoteText")}` : ""}
|
|
4336
4353
|
`;
|
|
4337
4354
|
|
|
4338
|
-
let
|
|
4355
|
+
let mainHtml = `<span class="result-main-line">${escapeHtml(tr("calcNoTransferSuggested"))}</span>`;
|
|
4339
4356
|
if (m.assegnoDa1a2 > 0.005) {
|
|
4340
|
-
|
|
4357
|
+
mainHtml = `
|
|
4358
|
+
<span class="result-main-flow">${escapeHtml(c1n())} → ${escapeHtml(c2n())}</span>
|
|
4359
|
+
<span class="result-main-amount">${eur(m.assegnoDa1a2)} ${escapeHtml(tr("pdfPerMonth"))}</span>
|
|
4360
|
+
`;
|
|
4341
4361
|
} else if (m.assegnoDa2a1 > 0.005) {
|
|
4342
|
-
|
|
4362
|
+
mainHtml = `
|
|
4363
|
+
<span class="result-main-flow">${escapeHtml(c2n())} → ${escapeHtml(c1n())}</span>
|
|
4364
|
+
<span class="result-main-amount">${eur(m.assegnoDa2a1)} ${escapeHtml(tr("pdfPerMonth"))}</span>
|
|
4365
|
+
`;
|
|
4343
4366
|
} else {
|
|
4344
|
-
|
|
4345
|
-
|
|
4367
|
+
const benefitRows = getCompensativeBenefitRows(m, c1n(), c2n());
|
|
4368
|
+
if (benefitRows.length) {
|
|
4369
|
+
const benefitsHtml = benefitRows
|
|
4370
|
+
.map((row) => `<li><span>${escapeHtml(row.label)}</span><strong>${eur(row.amount)}</strong></li>`)
|
|
4371
|
+
.join("");
|
|
4372
|
+
mainHtml = `
|
|
4373
|
+
<span class="result-main-line">${escapeHtml(tr("calcNoTransferSuggested"))}</span>
|
|
4374
|
+
<div class="result-benefits-box">
|
|
4375
|
+
<span class="result-main-sub">${escapeHtml(tr("calcCompBenefitsLabel"))}</span>
|
|
4376
|
+
<ul class="result-benefits-list">${benefitsHtml}</ul>
|
|
4377
|
+
</div>
|
|
4378
|
+
`;
|
|
4379
|
+
} else if (benefitsInline) {
|
|
4380
|
+
mainHtml = `<span class="result-main-line">${escapeHtml(msg("calcNoTransferWithBenefits", { benefits: benefitsInline }))}</span>`;
|
|
4346
4381
|
}
|
|
4347
4382
|
}
|
|
4348
|
-
resultMain.
|
|
4383
|
+
resultMain.innerHTML = mainHtml;
|
|
4349
4384
|
|
|
4350
4385
|
kpi.innerHTML = "";
|
|
4351
4386
|
|
|
@@ -4520,7 +4555,16 @@ const defaultExpenseItems = [
|
|
|
4520
4555
|
<td class="expense-detail-cell">–</td>
|
|
4521
4556
|
</tr>`
|
|
4522
4557
|
: "";
|
|
4523
|
-
const
|
|
4558
|
+
const firstHomeExpenseRow = (m.quotaMutuoSpese1 > 0.005 || m.quotaMutuoSpese2 > 0.005)
|
|
4559
|
+
? `<tr>
|
|
4560
|
+
<td>${tr("pdfPrimaryHomeMortgage")}</td>
|
|
4561
|
+
<td class="num">${m.quotaMutuoSpese1 > 0.005 ? eur(m.quotaMutuoSpese1) : "–"}</td>
|
|
4562
|
+
<td class="num">${m.quotaMutuoSpese2 > 0.005 ? eur(m.quotaMutuoSpese2) : "–"}</td>
|
|
4563
|
+
<td class="num bold">${eur((m.quotaMutuoSpese1 || 0) + (m.quotaMutuoSpese2 || 0))}</td>
|
|
4564
|
+
<td class="expense-detail-cell">${tr("firstHomeAssignedToLabel")}: ${primaryHomeAssignedLabel}</td>
|
|
4565
|
+
</tr>`
|
|
4566
|
+
: "";
|
|
4567
|
+
const speseRows = speseRowsBase + firstHomeExpenseRow + extraSpeseRow;
|
|
4524
4568
|
|
|
4525
4569
|
const scenarioMetrics = [
|
|
4526
4570
|
{ label: tr("scenarioColMode"), val: (sm) => getModeName(sm.mode, sm.simplePerc), fmt: (v) => escapeHtml(v), numeric: false },
|
|
@@ -5319,7 +5363,7 @@ ${scenarioLab.length ? `
|
|
|
5319
5363
|
}
|
|
5320
5364
|
|
|
5321
5365
|
function resetAll() {
|
|
5322
|
-
document.querySelectorAll("input[type='number'], input[data-numeric='1']").forEach((el) => {
|
|
5366
|
+
document.querySelectorAll("input[type='number'], input[type='range'], input[data-numeric='1']").forEach((el) => {
|
|
5323
5367
|
if (el.id !== "perm2") {
|
|
5324
5368
|
el.value = el.defaultValue || 0;
|
|
5325
5369
|
}
|
|
@@ -5580,11 +5624,13 @@ ${scenarioLab.length ? `
|
|
|
5580
5624
|
}
|
|
5581
5625
|
|
|
5582
5626
|
document.addEventListener("input", (e) => {
|
|
5583
|
-
if (e.target && e.target.matches("input[type='number'], input[data-numeric='1']")) {
|
|
5627
|
+
if (e.target && e.target.matches("input[type='number'], input[type='range'], input[data-numeric='1']")) {
|
|
5584
5628
|
if (e.target.id === "perm1") {
|
|
5585
5629
|
syncPermanenza("perm1");
|
|
5586
5630
|
} else if (e.target.id === "perm2") {
|
|
5587
5631
|
syncPermanenza("perm2");
|
|
5632
|
+
} else if (e.target.id === "primaCasaMutuoPerc1" || e.target.id === "primaCasaMutuoImporto") {
|
|
5633
|
+
updateFirstHomeMortgageUi();
|
|
5588
5634
|
} else if (e.target.id === "reddito1" || e.target.id === "reddito2") {
|
|
5589
5635
|
const activeMode = document.getElementById("incomeMode")?.value || "monthly";
|
|
5590
5636
|
incomeValuesByMode[activeMode] = {
|
|
@@ -38,6 +38,8 @@ function calculateModel(input) {
|
|
|
38
38
|
const rawMutuoPerc1 = input.primaCasaMutuoPerc1 === undefined ? 50 : input.primaCasaMutuoPerc1;
|
|
39
39
|
const primaCasaMutuoPerc1 = clamp(toNumber(rawMutuoPerc1), 0, 100);
|
|
40
40
|
const primaCasaMutuoPerc2 = 100 - primaCasaMutuoPerc1;
|
|
41
|
+
const quotaMutuoSpese1 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100)) : 0;
|
|
42
|
+
const quotaMutuoSpese2 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto - quotaMutuoSpese1) : 0;
|
|
41
43
|
|
|
42
44
|
const match12 = Math.min(aPag1, aPerc2);
|
|
43
45
|
const match21 = Math.min(aPag2, aPerc1);
|
|
@@ -46,8 +48,10 @@ function calculateModel(input) {
|
|
|
46
48
|
|
|
47
49
|
const c1Spese = Array.isArray(input.c1Spese) ? input.c1Spese : [];
|
|
48
50
|
const c2Spese = Array.isArray(input.c2Spese) ? input.c2Spese : [];
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
+
const speseBase1 = c1Spese.reduce((acc, n) => acc + toNumber(n), 0);
|
|
52
|
+
const speseBase2 = c2Spese.reduce((acc, n) => acc + toNumber(n), 0);
|
|
53
|
+
const spese1 = speseBase1 + quotaMutuoSpese1;
|
|
54
|
+
const spese2 = speseBase2 + quotaMutuoSpese2;
|
|
51
55
|
const speseTot = spese1 + spese2;
|
|
52
56
|
|
|
53
57
|
const disp1 = r1 + aPerc1 + aFam1 - aPag1 - spese1;
|
|
@@ -102,12 +106,10 @@ function calculateModel(input) {
|
|
|
102
106
|
let primaCasaTransfer1to2 = 0;
|
|
103
107
|
let primaCasaTransfer2to1 = 0;
|
|
104
108
|
if (primaCasaConsidered) {
|
|
105
|
-
const quotaMutuo1 = primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100);
|
|
106
|
-
const quotaMutuo2 = primaCasaMutuoImporto - quotaMutuo1;
|
|
107
109
|
if (assigned === '1') {
|
|
108
|
-
primaCasaTransfer2to1 = Math.max(0,
|
|
110
|
+
primaCasaTransfer2to1 = Math.max(0, quotaMutuoSpese2);
|
|
109
111
|
} else if (assigned === '2') {
|
|
110
|
-
primaCasaTransfer1to2 = Math.max(0,
|
|
112
|
+
primaCasaTransfer1to2 = Math.max(0, quotaMutuoSpese1);
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
@@ -127,6 +129,7 @@ function calculateModel(input) {
|
|
|
127
129
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
128
130
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
129
131
|
match12, match21, esternoPag1, esternoPag2,
|
|
132
|
+
speseBase1, speseBase2, quotaMutuoSpese1, quotaMutuoSpese2,
|
|
130
133
|
spese1, spese2, speseTot,
|
|
131
134
|
disp1, disp2, peso1, peso2,
|
|
132
135
|
mode, simplePerc,
|
package/frontend/public/app.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const defaultExpenseItems = [
|
|
2
2
|
{ label: "🏠 Affitto", help: "Canone mensile di locazione dell'abitazione." },
|
|
3
|
-
{ label: "🏦 Mutuo casa", help: "Rata mensile del mutuo abitazione." },
|
|
4
3
|
{ label: "🏡 Casa (valore locativo)", help: "Valore locativo teorico della casa in uso, se rilevante." },
|
|
5
4
|
{ label: "💡 Utenze", help: "Luce, gas, acqua, internet e altre utenze domestiche." },
|
|
6
5
|
{ label: "🛒 Cibo/Alimenti", help: "Spesa alimentare mensile imputabile al nucleo familiare." },
|
|
@@ -3244,14 +3243,18 @@ const defaultExpenseItems = [
|
|
|
3244
3243
|
const rawMutuoPerc1 = payload.primaCasaMutuoPerc1 === undefined ? 50 : payload.primaCasaMutuoPerc1;
|
|
3245
3244
|
const primaCasaMutuoPerc1 = Math.min(100, Math.max(0, Number(rawMutuoPerc1 || 0)));
|
|
3246
3245
|
const primaCasaMutuoPerc2 = 100 - primaCasaMutuoPerc1;
|
|
3246
|
+
const quotaMutuoSpese1 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100)) : 0;
|
|
3247
|
+
const quotaMutuoSpese2 = primaCasaMutuoEnabled ? (primaCasaMutuoImporto - quotaMutuoSpese1) : 0;
|
|
3247
3248
|
|
|
3248
3249
|
const match12 = Math.min(aPag1, aPerc2);
|
|
3249
3250
|
const match21 = Math.min(aPag2, aPerc1);
|
|
3250
3251
|
const esternoPag1 = Math.max(0, aPag1 - match12);
|
|
3251
3252
|
const esternoPag2 = Math.max(0, aPag2 - match21);
|
|
3252
3253
|
|
|
3253
|
-
const
|
|
3254
|
-
const
|
|
3254
|
+
const speseBase1 = (payload.c1Spese || []).reduce((acc, v) => acc + Number(v || 0), 0);
|
|
3255
|
+
const speseBase2 = (payload.c2Spese || []).reduce((acc, v) => acc + Number(v || 0), 0);
|
|
3256
|
+
const spese1 = speseBase1 + quotaMutuoSpese1;
|
|
3257
|
+
const spese2 = speseBase2 + quotaMutuoSpese2;
|
|
3255
3258
|
const speseTot = spese1 + spese2;
|
|
3256
3259
|
|
|
3257
3260
|
const disp1 = r1 + aPerc1 + aFam1 - aPag1 - spese1;
|
|
@@ -3301,12 +3304,10 @@ const defaultExpenseItems = [
|
|
|
3301
3304
|
let primaCasaTransfer1to2 = 0;
|
|
3302
3305
|
let primaCasaTransfer2to1 = 0;
|
|
3303
3306
|
if (primaCasaConsidered) {
|
|
3304
|
-
const quotaMutuo1 = primaCasaMutuoImporto * (primaCasaMutuoPerc1 / 100);
|
|
3305
|
-
const quotaMutuo2 = primaCasaMutuoImporto - quotaMutuo1;
|
|
3306
3307
|
if (primaCasaAssegnataA === "1") {
|
|
3307
|
-
primaCasaTransfer2to1 = Math.max(0,
|
|
3308
|
+
primaCasaTransfer2to1 = Math.max(0, quotaMutuoSpese2);
|
|
3308
3309
|
} else if (primaCasaAssegnataA === "2") {
|
|
3309
|
-
primaCasaTransfer1to2 = Math.max(0,
|
|
3310
|
+
primaCasaTransfer1to2 = Math.max(0, quotaMutuoSpese1);
|
|
3310
3311
|
}
|
|
3311
3312
|
}
|
|
3312
3313
|
|
|
@@ -3326,6 +3327,7 @@ const defaultExpenseItems = [
|
|
|
3326
3327
|
r1, r2, r1Raw, r2Raw, incomeMode, figli, perm1, perm2,
|
|
3327
3328
|
aPerc1, aPag1, aPerc2, aPag2, aFam1, aFam2,
|
|
3328
3329
|
match12, match21, esternoPag1, esternoPag2,
|
|
3330
|
+
speseBase1, speseBase2, quotaMutuoSpese1, quotaMutuoSpese2,
|
|
3329
3331
|
spese1, spese2, speseTot,
|
|
3330
3332
|
disp1, disp2, peso1, peso2,
|
|
3331
3333
|
mode, simplePerc,
|
|
@@ -3446,6 +3448,12 @@ const defaultExpenseItems = [
|
|
|
3446
3448
|
const assignedEl = document.getElementById("primaCasaAssegnataA");
|
|
3447
3449
|
const shareEl = document.getElementById("primaCasaMutuoPerc1");
|
|
3448
3450
|
const splitInfoEl = document.getElementById("primaCasaMutuoSplitInfo");
|
|
3451
|
+
const splitCenterEl = document.getElementById("primaCasaSplitCenter");
|
|
3452
|
+
const splitLeftNameEl = document.getElementById("primaCasaSplitLeftName");
|
|
3453
|
+
const splitRightNameEl = document.getElementById("primaCasaSplitRightName");
|
|
3454
|
+
const splitLeftAmountEl = document.getElementById("primaCasaSplitLeftAmount");
|
|
3455
|
+
const splitRightAmountEl = document.getElementById("primaCasaSplitRightAmount");
|
|
3456
|
+
const splitWrapEl = document.getElementById("primaCasaMutuoSliderWrap");
|
|
3449
3457
|
const splitLabelEl = document.getElementById("lblPrimaCasaMutuoPerc1");
|
|
3450
3458
|
const splitHintEl = document.getElementById("hintPrimaCasaMutuoPerc1");
|
|
3451
3459
|
if (!enabledEl || !amountEl || !assignedEl || !shareEl) return;
|
|
@@ -3454,6 +3462,7 @@ const defaultExpenseItems = [
|
|
|
3454
3462
|
amountEl.disabled = !isEnabled;
|
|
3455
3463
|
assignedEl.disabled = !isEnabled;
|
|
3456
3464
|
shareEl.disabled = !isEnabled;
|
|
3465
|
+
if (splitWrapEl) splitWrapEl.classList.toggle("is-disabled", !isEnabled);
|
|
3457
3466
|
|
|
3458
3467
|
const normalizedShare1 = Math.min(100, Math.max(0, num("primaCasaMutuoPerc1")));
|
|
3459
3468
|
if (Math.abs(normalizedShare1 - Number(shareEl.value || 0)) > 0.0001) {
|
|
@@ -3461,6 +3470,9 @@ const defaultExpenseItems = [
|
|
|
3461
3470
|
}
|
|
3462
3471
|
|
|
3463
3472
|
const share2 = 100 - normalizedShare1;
|
|
3473
|
+
const amount = Math.max(0, num("primaCasaMutuoImporto"));
|
|
3474
|
+
const quota1 = amount * (normalizedShare1 / 100);
|
|
3475
|
+
const quota2 = amount - quota1;
|
|
3464
3476
|
if (splitLabelEl) splitLabelEl.textContent = msg("firstHomeSplitLabel", { spouse: c1n() });
|
|
3465
3477
|
if (splitHintEl) splitHintEl.title = msg("firstHomeSplitHint", { spouse: c1n() });
|
|
3466
3478
|
if (splitInfoEl) {
|
|
@@ -3471,6 +3483,11 @@ const defaultExpenseItems = [
|
|
|
3471
3483
|
p2: share2.toFixed(0)
|
|
3472
3484
|
});
|
|
3473
3485
|
}
|
|
3486
|
+
if (splitCenterEl) splitCenterEl.textContent = `${normalizedShare1.toFixed(0)}% / ${share2.toFixed(0)}%`;
|
|
3487
|
+
if (splitLeftNameEl) splitLeftNameEl.textContent = c1n();
|
|
3488
|
+
if (splitRightNameEl) splitRightNameEl.textContent = c2n();
|
|
3489
|
+
if (splitLeftAmountEl) splitLeftAmountEl.textContent = eur(quota1);
|
|
3490
|
+
if (splitRightAmountEl) splitRightAmountEl.textContent = eur(quota2);
|
|
3474
3491
|
|
|
3475
3492
|
const noneOpt = assignedEl.querySelector("option[value='']");
|
|
3476
3493
|
const spouse1Opt = assignedEl.querySelector("option[value='1']");
|
|
@@ -4335,17 +4352,35 @@ const defaultExpenseItems = [
|
|
|
4335
4352
|
${m.incomeMode === "cu" ? `<br /><strong>${tr("calcIncomeBaseNote")}</strong> ${tr("cuNetNoteText")}` : ""}
|
|
4336
4353
|
`;
|
|
4337
4354
|
|
|
4338
|
-
let
|
|
4355
|
+
let mainHtml = `<span class="result-main-line">${escapeHtml(tr("calcNoTransferSuggested"))}</span>`;
|
|
4339
4356
|
if (m.assegnoDa1a2 > 0.005) {
|
|
4340
|
-
|
|
4357
|
+
mainHtml = `
|
|
4358
|
+
<span class="result-main-flow">${escapeHtml(c1n())} → ${escapeHtml(c2n())}</span>
|
|
4359
|
+
<span class="result-main-amount">${eur(m.assegnoDa1a2)} ${escapeHtml(tr("pdfPerMonth"))}</span>
|
|
4360
|
+
`;
|
|
4341
4361
|
} else if (m.assegnoDa2a1 > 0.005) {
|
|
4342
|
-
|
|
4362
|
+
mainHtml = `
|
|
4363
|
+
<span class="result-main-flow">${escapeHtml(c2n())} → ${escapeHtml(c1n())}</span>
|
|
4364
|
+
<span class="result-main-amount">${eur(m.assegnoDa2a1)} ${escapeHtml(tr("pdfPerMonth"))}</span>
|
|
4365
|
+
`;
|
|
4343
4366
|
} else {
|
|
4344
|
-
|
|
4345
|
-
|
|
4367
|
+
const benefitRows = getCompensativeBenefitRows(m, c1n(), c2n());
|
|
4368
|
+
if (benefitRows.length) {
|
|
4369
|
+
const benefitsHtml = benefitRows
|
|
4370
|
+
.map((row) => `<li><span>${escapeHtml(row.label)}</span><strong>${eur(row.amount)}</strong></li>`)
|
|
4371
|
+
.join("");
|
|
4372
|
+
mainHtml = `
|
|
4373
|
+
<span class="result-main-line">${escapeHtml(tr("calcNoTransferSuggested"))}</span>
|
|
4374
|
+
<div class="result-benefits-box">
|
|
4375
|
+
<span class="result-main-sub">${escapeHtml(tr("calcCompBenefitsLabel"))}</span>
|
|
4376
|
+
<ul class="result-benefits-list">${benefitsHtml}</ul>
|
|
4377
|
+
</div>
|
|
4378
|
+
`;
|
|
4379
|
+
} else if (benefitsInline) {
|
|
4380
|
+
mainHtml = `<span class="result-main-line">${escapeHtml(msg("calcNoTransferWithBenefits", { benefits: benefitsInline }))}</span>`;
|
|
4346
4381
|
}
|
|
4347
4382
|
}
|
|
4348
|
-
resultMain.
|
|
4383
|
+
resultMain.innerHTML = mainHtml;
|
|
4349
4384
|
|
|
4350
4385
|
kpi.innerHTML = "";
|
|
4351
4386
|
|
|
@@ -4520,7 +4555,16 @@ const defaultExpenseItems = [
|
|
|
4520
4555
|
<td class="expense-detail-cell">–</td>
|
|
4521
4556
|
</tr>`
|
|
4522
4557
|
: "";
|
|
4523
|
-
const
|
|
4558
|
+
const firstHomeExpenseRow = (m.quotaMutuoSpese1 > 0.005 || m.quotaMutuoSpese2 > 0.005)
|
|
4559
|
+
? `<tr>
|
|
4560
|
+
<td>${tr("pdfPrimaryHomeMortgage")}</td>
|
|
4561
|
+
<td class="num">${m.quotaMutuoSpese1 > 0.005 ? eur(m.quotaMutuoSpese1) : "–"}</td>
|
|
4562
|
+
<td class="num">${m.quotaMutuoSpese2 > 0.005 ? eur(m.quotaMutuoSpese2) : "–"}</td>
|
|
4563
|
+
<td class="num bold">${eur((m.quotaMutuoSpese1 || 0) + (m.quotaMutuoSpese2 || 0))}</td>
|
|
4564
|
+
<td class="expense-detail-cell">${tr("firstHomeAssignedToLabel")}: ${primaryHomeAssignedLabel}</td>
|
|
4565
|
+
</tr>`
|
|
4566
|
+
: "";
|
|
4567
|
+
const speseRows = speseRowsBase + firstHomeExpenseRow + extraSpeseRow;
|
|
4524
4568
|
|
|
4525
4569
|
const scenarioMetrics = [
|
|
4526
4570
|
{ label: tr("scenarioColMode"), val: (sm) => getModeName(sm.mode, sm.simplePerc), fmt: (v) => escapeHtml(v), numeric: false },
|
|
@@ -5319,7 +5363,7 @@ ${scenarioLab.length ? `
|
|
|
5319
5363
|
}
|
|
5320
5364
|
|
|
5321
5365
|
function resetAll() {
|
|
5322
|
-
document.querySelectorAll("input[type='number'], input[data-numeric='1']").forEach((el) => {
|
|
5366
|
+
document.querySelectorAll("input[type='number'], input[type='range'], input[data-numeric='1']").forEach((el) => {
|
|
5323
5367
|
if (el.id !== "perm2") {
|
|
5324
5368
|
el.value = el.defaultValue || 0;
|
|
5325
5369
|
}
|
|
@@ -5580,11 +5624,13 @@ ${scenarioLab.length ? `
|
|
|
5580
5624
|
}
|
|
5581
5625
|
|
|
5582
5626
|
document.addEventListener("input", (e) => {
|
|
5583
|
-
if (e.target && e.target.matches("input[type='number'], input[data-numeric='1']")) {
|
|
5627
|
+
if (e.target && e.target.matches("input[type='number'], input[type='range'], input[data-numeric='1']")) {
|
|
5584
5628
|
if (e.target.id === "perm1") {
|
|
5585
5629
|
syncPermanenza("perm1");
|
|
5586
5630
|
} else if (e.target.id === "perm2") {
|
|
5587
5631
|
syncPermanenza("perm2");
|
|
5632
|
+
} else if (e.target.id === "primaCasaMutuoPerc1" || e.target.id === "primaCasaMutuoImporto") {
|
|
5633
|
+
updateFirstHomeMortgageUi();
|
|
5588
5634
|
} else if (e.target.id === "reddito1" || e.target.id === "reddito2") {
|
|
5589
5635
|
const activeMode = document.getElementById("incomeMode")?.value || "monthly";
|
|
5590
5636
|
incomeValuesByMode[activeMode] = {
|
|
@@ -377,7 +377,20 @@
|
|
|
377
377
|
<label for="primaCasaMutuoPerc1" class="label-row"><span id="lblPrimaCasaMutuoPerc1">Quota mutuo a carico Coniuge 1 (%)</span>
|
|
378
378
|
<span class="hint" id="hintPrimaCasaMutuoPerc1" title="Percentuale della rata mutuo pagata da Coniuge 1. La quota di Coniuge 2 e complementare a 100%.">i</span>
|
|
379
379
|
</label>
|
|
380
|
-
<
|
|
380
|
+
<div class="mortgage-split-slider" id="primaCasaMutuoSliderWrap">
|
|
381
|
+
<div class="mortgage-split-side mortgage-split-side-left" id="primaCasaSplitLeft">
|
|
382
|
+
<div class="mortgage-split-name" id="primaCasaSplitLeftName">Coniuge 1</div>
|
|
383
|
+
<div class="mortgage-split-amount" id="primaCasaSplitLeftAmount">0 EUR</div>
|
|
384
|
+
</div>
|
|
385
|
+
<div class="mortgage-split-range-wrap">
|
|
386
|
+
<input id="primaCasaMutuoPerc1" type="range" min="0" max="100" step="1" value="50" />
|
|
387
|
+
<div class="mortgage-split-center" id="primaCasaSplitCenter">50% / 50%</div>
|
|
388
|
+
</div>
|
|
389
|
+
<div class="mortgage-split-side mortgage-split-side-right" id="primaCasaSplitRight">
|
|
390
|
+
<div class="mortgage-split-name" id="primaCasaSplitRightName">Coniuge 2</div>
|
|
391
|
+
<div class="mortgage-split-amount" id="primaCasaSplitRightAmount">0 EUR</div>
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
381
394
|
<div class="extra-monthly" id="primaCasaMutuoSplitInfo">Ripartizione mutuo: Coniuge 1 50% · Coniuge 2 50%</div>
|
|
382
395
|
</div>
|
|
383
396
|
</div>
|
|
@@ -488,7 +501,17 @@
|
|
|
488
501
|
<p class="note">
|
|
489
502
|
Questo strumento e solo orientativo e non sostituisce una valutazione legale/professionale del caso concreto.
|
|
490
503
|
</p>
|
|
491
|
-
<div id="spiegPanel" class="spieg-panel"
|
|
504
|
+
<div id="spiegPanel" class="spieg-panel">
|
|
505
|
+
<details class="spieg-details" open>
|
|
506
|
+
<summary class="spieg-title">💡 Perche questo risultato?</summary>
|
|
507
|
+
<div class="spieg-grid">
|
|
508
|
+
<div class="spieg-item">
|
|
509
|
+
<div class="spieg-item-label">Stato calcolo</div>
|
|
510
|
+
<div class="spieg-item-body">Sezione in aggiornamento automatico: modifica i dati per vedere la spiegazione dettagliata del risultato.</div>
|
|
511
|
+
</div>
|
|
512
|
+
</div>
|
|
513
|
+
</details>
|
|
514
|
+
</div>
|
|
492
515
|
</div>
|
|
493
516
|
</section>
|
|
494
517
|
</div>
|
|
@@ -563,6 +586,7 @@
|
|
|
563
586
|
<script src="supabase.min.js"></script>
|
|
564
587
|
<script src="fabric.min.js"></script>
|
|
565
588
|
<script src="html2pdf.bundle.min.js"></script>
|
|
566
|
-
<script src="app.js?v=2.1.
|
|
589
|
+
<script src="app.js?v=2.1.5"></script>
|
|
567
590
|
</body>
|
|
568
591
|
</html>
|
|
592
|
+
|
|
@@ -80,6 +80,37 @@
|
|
|
80
80
|
gap: 10px;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
.runtime-badge {
|
|
84
|
+
display: inline-flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
gap: 6px;
|
|
87
|
+
margin-right: 2px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.runtime-badge-chip {
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
min-height: 30px;
|
|
94
|
+
padding: 5px 10px;
|
|
95
|
+
border-radius: 999px;
|
|
96
|
+
font-size: 0.72rem;
|
|
97
|
+
font-weight: 800;
|
|
98
|
+
letter-spacing: 0.05em;
|
|
99
|
+
text-transform: uppercase;
|
|
100
|
+
border: 1px solid rgba(255,255,255,0.28);
|
|
101
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.18);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.runtime-badge-chip--frontend {
|
|
105
|
+
color: #fff6da;
|
|
106
|
+
background: linear-gradient(135deg, rgba(145, 77, 7, 0.92), rgba(201, 118, 18, 0.92));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.runtime-badge-chip--api {
|
|
110
|
+
color: #f4fffb;
|
|
111
|
+
background: linear-gradient(135deg, rgba(17, 101, 92, 0.95), rgba(29, 146, 128, 0.95));
|
|
112
|
+
}
|
|
113
|
+
|
|
83
114
|
.top-actions {
|
|
84
115
|
position: relative;
|
|
85
116
|
display: inline-block;
|
|
@@ -819,6 +850,113 @@
|
|
|
819
850
|
font-weight: 700;
|
|
820
851
|
color: #184a44;
|
|
821
852
|
}
|
|
853
|
+
|
|
854
|
+
.mortgage-split-slider {
|
|
855
|
+
margin-top: 6px;
|
|
856
|
+
border: 1px solid #b9d6cf;
|
|
857
|
+
border-radius: 14px;
|
|
858
|
+
background:
|
|
859
|
+
radial-gradient(120% 160% at 0% 0%, rgba(229, 247, 242, 0.8), transparent 58%),
|
|
860
|
+
radial-gradient(120% 160% at 100% 0%, rgba(255, 241, 214, 0.8), transparent 58%),
|
|
861
|
+
linear-gradient(180deg, #fafdfc, #eef7f5);
|
|
862
|
+
padding: 10px;
|
|
863
|
+
display: grid;
|
|
864
|
+
grid-template-columns: minmax(0, 1fr) minmax(180px, 2fr) minmax(0, 1fr);
|
|
865
|
+
gap: 8px;
|
|
866
|
+
align-items: center;
|
|
867
|
+
transition: opacity 0.2s ease;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.mortgage-split-slider.is-disabled {
|
|
871
|
+
opacity: 0.58;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.mortgage-split-side {
|
|
875
|
+
border: 1px solid #c6ded8;
|
|
876
|
+
border-radius: 11px;
|
|
877
|
+
padding: 8px;
|
|
878
|
+
background: rgba(255, 255, 255, 0.84);
|
|
879
|
+
min-height: 66px;
|
|
880
|
+
display: grid;
|
|
881
|
+
align-content: center;
|
|
882
|
+
gap: 2px;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.mortgage-split-side-left {
|
|
886
|
+
box-shadow: inset 3px 0 0 #1b8d7f;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.mortgage-split-side-right {
|
|
890
|
+
box-shadow: inset -3px 0 0 #d89a35;
|
|
891
|
+
text-align: right;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.mortgage-split-name {
|
|
895
|
+
font-size: 0.76rem;
|
|
896
|
+
font-weight: 800;
|
|
897
|
+
color: #2a4a46;
|
|
898
|
+
overflow-wrap: anywhere;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.mortgage-split-amount {
|
|
902
|
+
font-size: 0.95rem;
|
|
903
|
+
font-weight: 900;
|
|
904
|
+
color: #124f48;
|
|
905
|
+
letter-spacing: 0.2px;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
.mortgage-split-range-wrap {
|
|
909
|
+
position: relative;
|
|
910
|
+
padding: 20px 0 10px;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
.mortgage-split-range-wrap input[type="range"] {
|
|
914
|
+
-webkit-appearance: none;
|
|
915
|
+
appearance: none;
|
|
916
|
+
width: 100%;
|
|
917
|
+
height: 8px;
|
|
918
|
+
border-radius: 999px;
|
|
919
|
+
background: linear-gradient(90deg, #2b9d8e 0%, #6cb9a9 46%, #dfb264 54%, #cb8a2d 100%);
|
|
920
|
+
outline: none;
|
|
921
|
+
margin: 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.mortgage-split-range-wrap input[type="range"]::-webkit-slider-thumb {
|
|
925
|
+
-webkit-appearance: none;
|
|
926
|
+
appearance: none;
|
|
927
|
+
width: 22px;
|
|
928
|
+
height: 22px;
|
|
929
|
+
border-radius: 50%;
|
|
930
|
+
border: 2px solid #ffffff;
|
|
931
|
+
background: radial-gradient(circle at 35% 30%, #ffffff 0%, #e8f8f5 42%, #177a6f 100%);
|
|
932
|
+
box-shadow: 0 3px 9px rgba(13, 70, 64, 0.35);
|
|
933
|
+
cursor: pointer;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.mortgage-split-range-wrap input[type="range"]::-moz-range-thumb {
|
|
937
|
+
width: 22px;
|
|
938
|
+
height: 22px;
|
|
939
|
+
border-radius: 50%;
|
|
940
|
+
border: 2px solid #ffffff;
|
|
941
|
+
background: radial-gradient(circle at 35% 30%, #ffffff 0%, #e8f8f5 42%, #177a6f 100%);
|
|
942
|
+
box-shadow: 0 3px 9px rgba(13, 70, 64, 0.35);
|
|
943
|
+
cursor: pointer;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.mortgage-split-center {
|
|
947
|
+
position: absolute;
|
|
948
|
+
top: -2px;
|
|
949
|
+
left: 50%;
|
|
950
|
+
transform: translateX(-50%);
|
|
951
|
+
font-size: 0.74rem;
|
|
952
|
+
font-weight: 900;
|
|
953
|
+
color: #114c45;
|
|
954
|
+
background: #ffffff;
|
|
955
|
+
border: 1px solid #b8d5ce;
|
|
956
|
+
border-radius: 999px;
|
|
957
|
+
padding: 2px 8px;
|
|
958
|
+
white-space: nowrap;
|
|
959
|
+
}
|
|
822
960
|
|
|
823
961
|
.label-row {
|
|
824
962
|
display: inline-flex;
|
|
@@ -1024,9 +1162,16 @@
|
|
|
1024
1162
|
max-width: 110px;
|
|
1025
1163
|
padding-right: 9px;
|
|
1026
1164
|
border-color: #0b6e66;
|
|
1027
|
-
color: #
|
|
1028
|
-
background: #
|
|
1165
|
+
color: #ffffff;
|
|
1166
|
+
background: linear-gradient(135deg, #0b6e66, #149a8f);
|
|
1029
1167
|
font-weight: 700;
|
|
1168
|
+
box-shadow: 0 0 0 1px rgba(11, 110, 102, 0.28), 0 3px 8px rgba(11, 110, 102, 0.18);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
.spese-detail-btn.has-note::before {
|
|
1172
|
+
content: "✓";
|
|
1173
|
+
font-size: 12px;
|
|
1174
|
+
font-weight: 900;
|
|
1030
1175
|
}
|
|
1031
1176
|
|
|
1032
1177
|
.spese-detail-btn.has-note .spese-detail-label {
|
|
@@ -1040,7 +1185,9 @@
|
|
|
1040
1185
|
.spese-detail-text {
|
|
1041
1186
|
width: 100%;
|
|
1042
1187
|
min-height: 52px;
|
|
1043
|
-
|
|
1188
|
+
max-height: 178px;
|
|
1189
|
+
resize: none;
|
|
1190
|
+
overflow-y: hidden;
|
|
1044
1191
|
border-radius: 8px;
|
|
1045
1192
|
border: 1px solid #c8dad4;
|
|
1046
1193
|
background: #f9fcfb;
|
|
@@ -1050,6 +1197,18 @@
|
|
|
1050
1197
|
color: #204644;
|
|
1051
1198
|
}
|
|
1052
1199
|
|
|
1200
|
+
.spese-detail-counter {
|
|
1201
|
+
margin-top: 3px;
|
|
1202
|
+
font-size: 0.66rem;
|
|
1203
|
+
color: #56716d;
|
|
1204
|
+
text-align: right;
|
|
1205
|
+
font-weight: 700;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.spese-detail-counter.is-limit {
|
|
1209
|
+
color: #9d3c2f;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1053
1212
|
.spese-partial {
|
|
1054
1213
|
font-size: 0.66rem;
|
|
1055
1214
|
color: #2f4745;
|
|
@@ -1220,6 +1379,299 @@
|
|
|
1220
1379
|
border: 1px solid #c6cdc3;
|
|
1221
1380
|
}
|
|
1222
1381
|
|
|
1382
|
+
/* ── Scenario Lab ─────────────────────────────────────────────── */
|
|
1383
|
+
.scenario-lab-card {
|
|
1384
|
+
margin-top: 14px;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
.scenario-lab-actions {
|
|
1388
|
+
display: flex;
|
|
1389
|
+
gap: 8px;
|
|
1390
|
+
flex-wrap: wrap;
|
|
1391
|
+
margin-bottom: 12px;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
.scenario-lab-empty {
|
|
1395
|
+
color: #6b7e78;
|
|
1396
|
+
font-style: italic;
|
|
1397
|
+
margin: 0;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.scenario-table-wrap {
|
|
1401
|
+
overflow-x: auto;
|
|
1402
|
+
-webkit-overflow-scrolling: touch;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
.scenario-table {
|
|
1406
|
+
border-collapse: collapse;
|
|
1407
|
+
width: 100%;
|
|
1408
|
+
font-size: 0.82rem;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
.scenario-table th,
|
|
1412
|
+
.scenario-table td {
|
|
1413
|
+
border: 1px solid var(--line);
|
|
1414
|
+
padding: 6px 10px;
|
|
1415
|
+
text-align: center;
|
|
1416
|
+
vertical-align: middle;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
.scenario-table thead th {
|
|
1420
|
+
background: linear-gradient(90deg, rgba(249,248,242,0.95), rgba(237,246,243,0.95));
|
|
1421
|
+
font-weight: 700;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
.scenario-table td.metric-label,
|
|
1425
|
+
.scenario-table th.metric-label {
|
|
1426
|
+
text-align: left;
|
|
1427
|
+
font-weight: 600;
|
|
1428
|
+
background: rgba(243,248,245,0.7);
|
|
1429
|
+
white-space: nowrap;
|
|
1430
|
+
min-width: 110px;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
.scenario-col-head { min-width: 120px; }
|
|
1434
|
+
|
|
1435
|
+
.scenario-badge {
|
|
1436
|
+
display: inline-block;
|
|
1437
|
+
background: var(--brand);
|
|
1438
|
+
color: #fff;
|
|
1439
|
+
border-radius: 4px;
|
|
1440
|
+
padding: 1px 7px;
|
|
1441
|
+
font-size: 0.74rem;
|
|
1442
|
+
font-weight: 700;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
.scenario-val { min-width: 90px; white-space: nowrap; }
|
|
1446
|
+
|
|
1447
|
+
.scenario-remove-btn {
|
|
1448
|
+
font-size: 0.72rem !important;
|
|
1449
|
+
padding: 2px 8px !important;
|
|
1450
|
+
margin-top: 4px;
|
|
1451
|
+
min-height: unset !important;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
.delta-col, .delta-col-head { min-width: 76px; font-weight: 600; white-space: nowrap; }
|
|
1455
|
+
.delta-pos { color: #18855e; }
|
|
1456
|
+
.delta-neg { color: #c0392b; }
|
|
1457
|
+
.delta-zero { color: #7a8b80; }
|
|
1458
|
+
|
|
1459
|
+
/* ── Spiegabilita ─────────────────────────────────────────────── */
|
|
1460
|
+
.spieg-panel { margin-top: 12px; }
|
|
1461
|
+
|
|
1462
|
+
.spieg-details {
|
|
1463
|
+
border: 1px solid #bfd7cf;
|
|
1464
|
+
border-radius: 14px;
|
|
1465
|
+
overflow: hidden;
|
|
1466
|
+
background: linear-gradient(180deg, #fbfdfc, #f4f9f7);
|
|
1467
|
+
box-shadow: 0 8px 24px rgba(8, 74, 67, 0.08);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.spieg-title {
|
|
1471
|
+
cursor: pointer;
|
|
1472
|
+
padding: 10px 14px;
|
|
1473
|
+
background: linear-gradient(90deg, rgba(248, 247, 240, 0.95), rgba(229, 243, 238, 0.95));
|
|
1474
|
+
font-weight: 700;
|
|
1475
|
+
font-size: 0.92rem;
|
|
1476
|
+
line-height: 1.3;
|
|
1477
|
+
user-select: none;
|
|
1478
|
+
list-style: none;
|
|
1479
|
+
color: #194f48;
|
|
1480
|
+
border-bottom: 1px solid #d3e4de;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
.spieg-title::-webkit-details-marker { display: none; }
|
|
1484
|
+
.spieg-title::before { content: "\25B8\0020"; font-size: 0.76rem; color: #1e6d63; }
|
|
1485
|
+
details[open] .spieg-title::before { content: "\25BE\0020"; }
|
|
1486
|
+
|
|
1487
|
+
.spieg-grid {
|
|
1488
|
+
display: grid;
|
|
1489
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1490
|
+
gap: 10px;
|
|
1491
|
+
padding: 12px;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
@media (max-width: 720px) {
|
|
1495
|
+
.spieg-grid { grid-template-columns: 1fr; }
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
.spieg-item {
|
|
1499
|
+
background: #f8fcfa;
|
|
1500
|
+
border: 1px solid #cfe3dc;
|
|
1501
|
+
border-radius: 10px;
|
|
1502
|
+
padding: 10px 12px;
|
|
1503
|
+
font-size: 0.82rem;
|
|
1504
|
+
min-width: 0;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.spieg-item--result {
|
|
1508
|
+
grid-column: 1 / -1;
|
|
1509
|
+
background: linear-gradient(120deg, #ebf8f2, #e3f4ed);
|
|
1510
|
+
border-color: #a5d2be;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
.spieg-item-label {
|
|
1514
|
+
display: inline-flex;
|
|
1515
|
+
align-items: center;
|
|
1516
|
+
gap: 6px;
|
|
1517
|
+
font-weight: 800;
|
|
1518
|
+
font-size: 0.73rem;
|
|
1519
|
+
color: #0f6a61;
|
|
1520
|
+
margin-bottom: 8px;
|
|
1521
|
+
text-transform: uppercase;
|
|
1522
|
+
letter-spacing: 0.04em;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.spieg-item-icon {
|
|
1526
|
+
display: inline-flex;
|
|
1527
|
+
align-items: center;
|
|
1528
|
+
justify-content: center;
|
|
1529
|
+
width: 18px;
|
|
1530
|
+
height: 18px;
|
|
1531
|
+
border-radius: 999px;
|
|
1532
|
+
background: #e0f1eb;
|
|
1533
|
+
color: #0f6a61;
|
|
1534
|
+
font-size: 0.73rem;
|
|
1535
|
+
line-height: 1;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.spieg-item-body {
|
|
1539
|
+
display: grid;
|
|
1540
|
+
gap: 8px;
|
|
1541
|
+
line-height: 1.5;
|
|
1542
|
+
min-width: 0;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
.spieg-people {
|
|
1546
|
+
display: grid;
|
|
1547
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1548
|
+
gap: 8px;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
@media (max-width: 560px) {
|
|
1552
|
+
.spieg-people { grid-template-columns: 1fr; }
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.spieg-person {
|
|
1556
|
+
border: 1px solid #d8e8e2;
|
|
1557
|
+
border-radius: 8px;
|
|
1558
|
+
background: #ffffff;
|
|
1559
|
+
padding: 8px;
|
|
1560
|
+
min-width: 0;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
.spieg-person--left { border-left: 4px solid #1d7d72; }
|
|
1564
|
+
.spieg-person--right { border-left: 4px solid #bf7a1f; }
|
|
1565
|
+
|
|
1566
|
+
.spieg-person-name {
|
|
1567
|
+
font-weight: 700;
|
|
1568
|
+
color: #204e48;
|
|
1569
|
+
margin-bottom: 2px;
|
|
1570
|
+
overflow-wrap: anywhere;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
.spieg-person-value {
|
|
1574
|
+
font-size: 1rem;
|
|
1575
|
+
font-weight: 800;
|
|
1576
|
+
color: #0f6259;
|
|
1577
|
+
font-variant-numeric: tabular-nums;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
.spieg-person-sub {
|
|
1581
|
+
margin-top: 2px;
|
|
1582
|
+
color: #5f7772;
|
|
1583
|
+
font-size: 0.74rem;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
.spieg-equation {
|
|
1587
|
+
display: flex;
|
|
1588
|
+
align-items: center;
|
|
1589
|
+
flex-wrap: wrap;
|
|
1590
|
+
gap: 6px;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
.spieg-pill {
|
|
1594
|
+
display: inline-flex;
|
|
1595
|
+
align-items: center;
|
|
1596
|
+
padding: 2px 8px;
|
|
1597
|
+
border-radius: 999px;
|
|
1598
|
+
background: #e8f3ef;
|
|
1599
|
+
border: 1px solid #cbe1d9;
|
|
1600
|
+
color: #184a44;
|
|
1601
|
+
font-weight: 700;
|
|
1602
|
+
font-variant-numeric: tabular-nums;
|
|
1603
|
+
max-width: 100%;
|
|
1604
|
+
overflow-wrap: anywhere;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
.spieg-pill--result {
|
|
1608
|
+
background: #dff3ea;
|
|
1609
|
+
border-color: #9dceb8;
|
|
1610
|
+
color: #0a6157;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
.spieg-op {
|
|
1614
|
+
color: #6d817c;
|
|
1615
|
+
font-weight: 700;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
.spieg-line--kv {
|
|
1619
|
+
display: grid;
|
|
1620
|
+
grid-template-columns: minmax(92px, 128px) minmax(0, 1fr);
|
|
1621
|
+
gap: 8px;
|
|
1622
|
+
align-items: baseline;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
@media (max-width: 560px) {
|
|
1626
|
+
.spieg-line--kv { grid-template-columns: 1fr; gap: 2px; }
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
.spieg-k {
|
|
1630
|
+
font-weight: 700;
|
|
1631
|
+
color: #295b54;
|
|
1632
|
+
overflow-wrap: anywhere;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
.spieg-v {
|
|
1636
|
+
color: #123f39;
|
|
1637
|
+
font-variant-numeric: tabular-nums;
|
|
1638
|
+
overflow-wrap: anywhere;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
.spieg-item-body--result {
|
|
1642
|
+
background: #ffffff;
|
|
1643
|
+
border: 1px dashed #9fceb9;
|
|
1644
|
+
border-radius: 10px;
|
|
1645
|
+
padding: 10px 12px;
|
|
1646
|
+
gap: 6px;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
.spieg-result-flow {
|
|
1650
|
+
font-weight: 800;
|
|
1651
|
+
color: #0f6a61;
|
|
1652
|
+
letter-spacing: 0.01em;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
.spieg-result-formula {
|
|
1656
|
+
color: #284e49;
|
|
1657
|
+
overflow-wrap: anywhere;
|
|
1658
|
+
font-variant-numeric: tabular-nums;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
.spieg-result-amount {
|
|
1662
|
+
font-size: 1.2rem;
|
|
1663
|
+
font-weight: 900;
|
|
1664
|
+
line-height: 1.2;
|
|
1665
|
+
color: #0e6b62;
|
|
1666
|
+
font-variant-numeric: tabular-nums;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
.spieg-result-empty {
|
|
1670
|
+
font-size: 0.95rem;
|
|
1671
|
+
font-weight: 800;
|
|
1672
|
+
color: #0f6a61;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1223
1675
|
@page {
|
|
1224
1676
|
size: A4 landscape;
|
|
1225
1677
|
margin: 8mm;
|
|
@@ -1633,15 +2085,114 @@
|
|
|
1633
2085
|
.result-pill {
|
|
1634
2086
|
border-radius: 14px;
|
|
1635
2087
|
padding: 14px;
|
|
1636
|
-
background:
|
|
1637
|
-
|
|
2088
|
+
background:
|
|
2089
|
+
radial-gradient(120% 180% at 0% -20%, rgba(215, 243, 236, 0.95), transparent 56%),
|
|
2090
|
+
radial-gradient(120% 180% at 100% -20%, rgba(255, 237, 201, 0.92), transparent 56%),
|
|
2091
|
+
linear-gradient(165deg, #f7fcfb, #ebf6f3);
|
|
2092
|
+
border: 1px solid #afcfc7;
|
|
2093
|
+
box-shadow: 0 12px 26px rgba(17, 70, 64, 0.16);
|
|
1638
2094
|
margin-bottom: 10px;
|
|
2095
|
+
position: relative;
|
|
2096
|
+
overflow: hidden;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
.result-pill::after {
|
|
2100
|
+
content: "";
|
|
2101
|
+
position: absolute;
|
|
2102
|
+
inset: -28px auto auto -28px;
|
|
2103
|
+
width: 120px;
|
|
2104
|
+
height: 120px;
|
|
2105
|
+
border-radius: 50%;
|
|
2106
|
+
background: radial-gradient(circle, rgba(59, 170, 154, 0.2) 0%, rgba(59, 170, 154, 0) 70%);
|
|
2107
|
+
pointer-events: none;
|
|
1639
2108
|
}
|
|
1640
2109
|
|
|
1641
2110
|
.result-pill .big {
|
|
1642
|
-
font-size: 1.
|
|
1643
|
-
font-weight:
|
|
2111
|
+
font-size: 1.3rem;
|
|
2112
|
+
font-weight: 900;
|
|
1644
2113
|
margin-top: 6px;
|
|
2114
|
+
line-height: 1.34;
|
|
2115
|
+
letter-spacing: 0.2px;
|
|
2116
|
+
color: #123b38;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
.result-main-flow {
|
|
2120
|
+
display: block;
|
|
2121
|
+
font-size: 1.02rem;
|
|
2122
|
+
font-weight: 800;
|
|
2123
|
+
color: #124741;
|
|
2124
|
+
text-transform: uppercase;
|
|
2125
|
+
letter-spacing: 0.3px;
|
|
2126
|
+
margin-bottom: 3px;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
.result-main-amount {
|
|
2130
|
+
display: block;
|
|
2131
|
+
font-size: 1.68rem;
|
|
2132
|
+
font-weight: 900;
|
|
2133
|
+
color: #0b625b;
|
|
2134
|
+
text-shadow: 0 1px 0 rgba(255,255,255,0.7);
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
.result-main-line {
|
|
2138
|
+
display: block;
|
|
2139
|
+
font-size: 1.25rem;
|
|
2140
|
+
font-weight: 800;
|
|
2141
|
+
color: #1c3f3b;
|
|
2142
|
+
margin-bottom: 6px;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
.result-main-sub {
|
|
2146
|
+
display: inline-flex;
|
|
2147
|
+
align-items: center;
|
|
2148
|
+
gap: 5px;
|
|
2149
|
+
font-size: 0.76rem;
|
|
2150
|
+
text-transform: uppercase;
|
|
2151
|
+
letter-spacing: 0.4px;
|
|
2152
|
+
font-weight: 900;
|
|
2153
|
+
color: #4e665f;
|
|
2154
|
+
background: rgba(255,255,255,0.78);
|
|
2155
|
+
border: 1px solid #bfd6d0;
|
|
2156
|
+
border-radius: 999px;
|
|
2157
|
+
padding: 3px 9px;
|
|
2158
|
+
margin-bottom: 0;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
.result-benefits-box {
|
|
2162
|
+
border: 1px solid #bdd6cf;
|
|
2163
|
+
border-radius: 12px;
|
|
2164
|
+
background: linear-gradient(180deg, rgba(249, 253, 252, 0.92), rgba(241, 249, 246, 0.92));
|
|
2165
|
+
padding: 8px;
|
|
2166
|
+
display: grid;
|
|
2167
|
+
gap: 8px;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
.result-benefits-list {
|
|
2171
|
+
margin: 0;
|
|
2172
|
+
padding: 0;
|
|
2173
|
+
list-style: none;
|
|
2174
|
+
display: grid;
|
|
2175
|
+
gap: 6px;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
.result-benefits-list li {
|
|
2179
|
+
display: flex;
|
|
2180
|
+
align-items: flex-start;
|
|
2181
|
+
justify-content: space-between;
|
|
2182
|
+
gap: 8px;
|
|
2183
|
+
padding: 7px 9px;
|
|
2184
|
+
border-radius: 10px;
|
|
2185
|
+
border: 1px solid #c5dbd5;
|
|
2186
|
+
background: rgba(255,255,255,0.86);
|
|
2187
|
+
font-size: 0.9rem;
|
|
2188
|
+
font-weight: 700;
|
|
2189
|
+
color: #284744;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
.result-benefits-list strong {
|
|
2193
|
+
white-space: nowrap;
|
|
2194
|
+
color: #0f5f57;
|
|
2195
|
+
font-size: 0.95rem;
|
|
1645
2196
|
}
|
|
1646
2197
|
|
|
1647
2198
|
.live-box {
|
|
@@ -2242,6 +2793,18 @@
|
|
|
2242
2793
|
.extra-grid {
|
|
2243
2794
|
grid-template-columns: 1fr;
|
|
2244
2795
|
}
|
|
2796
|
+
|
|
2797
|
+
.mortgage-split-slider {
|
|
2798
|
+
grid-template-columns: 1fr;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
.mortgage-split-side-right {
|
|
2802
|
+
text-align: left;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
.mortgage-split-range-wrap {
|
|
2806
|
+
order: -1;
|
|
2807
|
+
}
|
|
2245
2808
|
.spieg-grid {
|
|
2246
2809
|
grid-template-columns: 1fr;
|
|
2247
2810
|
}
|