mantenimento-app 2.4.1 → 2.4.2

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 CHANGED
@@ -295,6 +295,7 @@ const defaultExpenseItems = [
295
295
  calcBenefitFamilyAllowance: "Assegno familiare INPS percepito da {spouse}",
296
296
  calcBenefitPrimaryHomeMortgage: "Quota mutuo prima casa ceduta al collocatario ({payer} -> {receiver})",
297
297
  calcBenefitPrimaryHomeAssignment: "Assegnazione casa familiare - valore locativo ({receiver})",
298
+ calcBenefitExcludedFromTotal: "fuori totale",
298
299
  pdfCompBenefitsSection: "Benefici compensativi gia allocati",
299
300
  pdfCompBenefitsItem: "Beneficio",
300
301
  pdfCompBenefitsAmount: "Valore {currency}/mese",
@@ -654,6 +655,7 @@ const defaultExpenseItems = [
654
655
  calcBenefitFamilyAllowance: "INPS family allowance received by {spouse}",
655
656
  calcBenefitPrimaryHomeMortgage: "Primary-home mortgage share assigned to custodial parent ({payer} -> {receiver})",
656
657
  calcBenefitPrimaryHomeAssignment: "Primary home assignment - rental value ({receiver})",
658
+ calcBenefitExcludedFromTotal: "excluded from total",
657
659
  pdfCompBenefitsSection: "Compensative benefits already allocated",
658
660
  pdfCompBenefitsItem: "Benefit",
659
661
  pdfCompBenefitsAmount: "Value {currency}/month",
@@ -1496,6 +1498,14 @@ const defaultExpenseItems = [
1496
1498
  return { label, help };
1497
1499
  }
1498
1500
 
1501
+ function isLegacyLocativeExpenseLabel(label) {
1502
+ const normalized = String(label || "")
1503
+ .replace(/^[^A-Za-z\u00C0-\u024F]+/, "")
1504
+ .trim()
1505
+ .toLowerCase();
1506
+ return normalized === "casa (valore locativo)";
1507
+ }
1508
+
1499
1509
  function populateSuggestedExpenseOptions() {
1500
1510
  const select = document.getElementById("suggestedExpenseSelect");
1501
1511
  if (!select) return;
@@ -4638,14 +4648,14 @@ const defaultExpenseItems = [
4638
4648
  const rawBenefs = Array.isArray(m.compensativeBenefits)
4639
4649
  ? m.compensativeBenefits.filter((r) => r && Number(r.amount || 0) > 0.005)
4640
4650
  : [];
4641
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
4651
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
4642
4652
  const cardsHtml = benefitRows
4643
4653
  .map((row, i) => {
4644
4654
  const icon = (rawBenefs[i] && typeIcons[rawBenefs[i].type]) || "\u2726";
4645
4655
  return `<li class="spieg-benefit-card"><span class="spieg-benefit-icon">${icon}</span><span class="spieg-benefit-label">${escapeHtml(row.label)}</span><strong class="spieg-benefit-amount">${eur(row.amount)}</strong></li>`;
4646
4656
  })
4647
4657
  .join("");
4648
- const total = benefitRows.reduce((s, r) => s + r.amount, 0);
4658
+ const total = getCompensativeBenefitsTotal(benefitRows);
4649
4659
  const totalLabel = currentLang === "en" ? "Total allocated benefits" : "Totale benefici allocati";
4650
4660
  resultHtml = `
4651
4661
  <div class="spieg-no-transfer-badge">&#9878;&#65039;&ensp;${escapeHtml(tr("calcNoTransferSuggested"))}</div>
@@ -4730,21 +4740,32 @@ const defaultExpenseItems = [
4730
4740
  const amount = Number(row.amount || 0);
4731
4741
  if (row.type === "family") {
4732
4742
  const spouse = Number(row.to) === 2 ? name2 : name1;
4733
- return { label: msg("calcBenefitFamilyAllowance", { spouse }), amount };
4743
+ return { label: msg("calcBenefitFamilyAllowance", { spouse }), amount, includeInTotal: true };
4734
4744
  }
4735
4745
  if (row.type === "primary-home-mortgage") {
4736
4746
  const payer = Number(row.from) === 2 ? name2 : name1;
4737
4747
  const receiver = Number(row.to) === 2 ? name2 : name1;
4738
- return { label: msg("calcBenefitPrimaryHomeMortgage", { payer, receiver }), amount };
4748
+ return { label: msg("calcBenefitPrimaryHomeMortgage", { payer, receiver }), amount, includeInTotal: true };
4739
4749
  }
4740
4750
  if (row.type === "primary-home-assignment") {
4741
4751
  const receiver = Number(row.to) === 2 ? name2 : name1;
4742
- return { label: msg("calcBenefitPrimaryHomeAssignment", { receiver }), amount };
4752
+ return {
4753
+ label: `${msg("calcBenefitPrimaryHomeAssignment", { receiver })} (${tr("calcBenefitExcludedFromTotal")})`,
4754
+ amount,
4755
+ includeInTotal: false
4756
+ };
4743
4757
  }
4744
- return { label: tr("calcCompBenefitsLabel"), amount };
4758
+ return { label: tr("calcCompBenefitsLabel"), amount, includeInTotal: true };
4745
4759
  });
4746
4760
  }
4747
4761
 
4762
+ function getCompensativeBenefitsTotal(rows) {
4763
+ return (rows || []).reduce((sum, row) => {
4764
+ if (!row || row.includeInTotal === false) return sum;
4765
+ return sum + Number(row.amount || 0);
4766
+ }, 0);
4767
+ }
4768
+
4748
4769
  function formatCompensativeBenefitsInline(m, name1 = c1n(), name2 = c2n()) {
4749
4770
  return getCompensativeBenefitRows(m, name1, name2)
4750
4771
  .map((row) => `${row.label}: ${eur(row.amount)}`)
@@ -4851,14 +4872,14 @@ const defaultExpenseItems = [
4851
4872
  const rawBenefs = Array.isArray(m.compensativeBenefits)
4852
4873
  ? m.compensativeBenefits.filter((r) => r && Number(r.amount || 0) > 0.005)
4853
4874
  : [];
4854
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
4875
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
4855
4876
  const cardsHtml = benefitRows
4856
4877
  .map((row, i) => {
4857
4878
  const icon = (rawBenefs[i] && typeIcons[rawBenefs[i].type]) || "\u2726";
4858
4879
  return `<li class="spieg-benefit-card"><span class="spieg-benefit-icon">${icon}</span><span class="spieg-benefit-label">${escapeHtml(row.label)}</span><strong class="spieg-benefit-amount">${eur(row.amount)}</strong></li>`;
4859
4880
  })
4860
4881
  .join("");
4861
- const total = benefitRows.reduce((s, r) => s + r.amount, 0);
4882
+ const total = getCompensativeBenefitsTotal(benefitRows);
4862
4883
  const totalLabel = currentLang === "en" ? "Total allocated benefits" : "Totale benefici allocati";
4863
4884
  benefitCardsHtml = `
4864
4885
  <div class="result-benefits-box">
@@ -5122,12 +5143,12 @@ const defaultExpenseItems = [
5122
5143
  const rawBenefs = Array.isArray(m.compensativeBenefits)
5123
5144
  ? m.compensativeBenefits.filter((row) => row && Number(row.amount || 0) > 0.005)
5124
5145
  : [];
5125
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
5146
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
5126
5147
  const cardsHtml = compBenefits.map((row, idx) => {
5127
5148
  const icon = (rawBenefs[idx] && typeIcons[rawBenefs[idx].type]) || "\u2726";
5128
5149
  return `<li class="pdf-explain-benefit-card"><span class="pdf-explain-benefit-icon">${icon}</span><span class="pdf-explain-benefit-label">${escapeHtml(row.label)}</span><strong class="pdf-explain-benefit-amount">${eur(row.amount)}</strong></li>`;
5129
5150
  }).join("");
5130
- const benefitsTotal = compBenefits.reduce((sum, row) => sum + Number(row.amount || 0), 0);
5151
+ const benefitsTotal = getCompensativeBenefitsTotal(compBenefits);
5131
5152
  explainResultHtml = `
5132
5153
  <div class="pdf-explain-no-transfer-badge">&#9878;&#65039;&ensp;${escapeHtml(tr("calcNoTransferSuggested"))}</div>
5133
5154
  <div class="pdf-explain-benefits-section">
@@ -6050,6 +6071,7 @@ ${scenarioLab.length ? `
6050
6071
 
6051
6072
  function hydrateState(state) {
6052
6073
  if (!state || !state.base || !state.spese) return;
6074
+ let stateSpeseRows = Array.isArray(state.spese) ? state.spese : [];
6053
6075
  Object.entries(state.base).forEach(([k, v]) => {
6054
6076
  const el = document.getElementById(k);
6055
6077
  if (!el) return;
@@ -6065,11 +6087,15 @@ ${scenarioLab.length ? `
6065
6087
  speseConvivenzaAutoMode = Math.max(0, Number(state.base && state.base.speseConvivenza || 0)) <= 0.005;
6066
6088
  }
6067
6089
  if (Array.isArray(state.expenseItems) && state.expenseItems.length) {
6068
- expenseItems = state.expenseItems.map((item, idx) => normalizeExpenseItem(item, idx));
6090
+ const filteredPairs = state.expenseItems
6091
+ .map((item, idx) => ({ item, row: stateSpeseRows[idx] }))
6092
+ .filter((pair) => !isLegacyLocativeExpenseLabel(pair && pair.item && pair.item.label));
6093
+ expenseItems = filteredPairs.map((pair, idx) => normalizeExpenseItem(pair.item, idx));
6094
+ stateSpeseRows = filteredPairs.map((pair) => pair.row).filter((row) => row !== undefined);
6069
6095
  } else {
6070
6096
  expenseItems = defaultExpenseItems.map((item) => ({ ...item }));
6071
6097
  }
6072
- while (expenseItems.length < state.spese.length) {
6098
+ while (expenseItems.length < stateSpeseRows.length) {
6073
6099
  expenseItems.push(normalizeExpenseItem(null, expenseItems.length));
6074
6100
  }
6075
6101
  scenarioLab = normalizeScenarioLabState(state.scenarioLab);
@@ -6107,7 +6133,7 @@ ${scenarioLab.length ? `
6107
6133
  updateSpouseLabels();
6108
6134
  buildExpenseRows();
6109
6135
  syncPermanenza("calendar");
6110
- state.spese.forEach((row, i) => {
6136
+ stateSpeseRows.forEach((row, i) => {
6111
6137
  const c1 = document.getElementById(`c1_${i}`);
6112
6138
  const c2 = document.getElementById(`c2_${i}`);
6113
6139
  const d1 = document.getElementById(`c1d_${i}`);
@@ -295,6 +295,7 @@ const defaultExpenseItems = [
295
295
  calcBenefitFamilyAllowance: "Assegno familiare INPS percepito da {spouse}",
296
296
  calcBenefitPrimaryHomeMortgage: "Quota mutuo prima casa ceduta al collocatario ({payer} -> {receiver})",
297
297
  calcBenefitPrimaryHomeAssignment: "Assegnazione casa familiare - valore locativo ({receiver})",
298
+ calcBenefitExcludedFromTotal: "fuori totale",
298
299
  pdfCompBenefitsSection: "Benefici compensativi gia allocati",
299
300
  pdfCompBenefitsItem: "Beneficio",
300
301
  pdfCompBenefitsAmount: "Valore {currency}/mese",
@@ -654,6 +655,7 @@ const defaultExpenseItems = [
654
655
  calcBenefitFamilyAllowance: "INPS family allowance received by {spouse}",
655
656
  calcBenefitPrimaryHomeMortgage: "Primary-home mortgage share assigned to custodial parent ({payer} -> {receiver})",
656
657
  calcBenefitPrimaryHomeAssignment: "Primary home assignment - rental value ({receiver})",
658
+ calcBenefitExcludedFromTotal: "excluded from total",
657
659
  pdfCompBenefitsSection: "Compensative benefits already allocated",
658
660
  pdfCompBenefitsItem: "Benefit",
659
661
  pdfCompBenefitsAmount: "Value {currency}/month",
@@ -1496,6 +1498,14 @@ const defaultExpenseItems = [
1496
1498
  return { label, help };
1497
1499
  }
1498
1500
 
1501
+ function isLegacyLocativeExpenseLabel(label) {
1502
+ const normalized = String(label || "")
1503
+ .replace(/^[^A-Za-z\u00C0-\u024F]+/, "")
1504
+ .trim()
1505
+ .toLowerCase();
1506
+ return normalized === "casa (valore locativo)";
1507
+ }
1508
+
1499
1509
  function populateSuggestedExpenseOptions() {
1500
1510
  const select = document.getElementById("suggestedExpenseSelect");
1501
1511
  if (!select) return;
@@ -4638,14 +4648,14 @@ const defaultExpenseItems = [
4638
4648
  const rawBenefs = Array.isArray(m.compensativeBenefits)
4639
4649
  ? m.compensativeBenefits.filter((r) => r && Number(r.amount || 0) > 0.005)
4640
4650
  : [];
4641
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
4651
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
4642
4652
  const cardsHtml = benefitRows
4643
4653
  .map((row, i) => {
4644
4654
  const icon = (rawBenefs[i] && typeIcons[rawBenefs[i].type]) || "\u2726";
4645
4655
  return `<li class="spieg-benefit-card"><span class="spieg-benefit-icon">${icon}</span><span class="spieg-benefit-label">${escapeHtml(row.label)}</span><strong class="spieg-benefit-amount">${eur(row.amount)}</strong></li>`;
4646
4656
  })
4647
4657
  .join("");
4648
- const total = benefitRows.reduce((s, r) => s + r.amount, 0);
4658
+ const total = getCompensativeBenefitsTotal(benefitRows);
4649
4659
  const totalLabel = currentLang === "en" ? "Total allocated benefits" : "Totale benefici allocati";
4650
4660
  resultHtml = `
4651
4661
  <div class="spieg-no-transfer-badge">&#9878;&#65039;&ensp;${escapeHtml(tr("calcNoTransferSuggested"))}</div>
@@ -4730,21 +4740,32 @@ const defaultExpenseItems = [
4730
4740
  const amount = Number(row.amount || 0);
4731
4741
  if (row.type === "family") {
4732
4742
  const spouse = Number(row.to) === 2 ? name2 : name1;
4733
- return { label: msg("calcBenefitFamilyAllowance", { spouse }), amount };
4743
+ return { label: msg("calcBenefitFamilyAllowance", { spouse }), amount, includeInTotal: true };
4734
4744
  }
4735
4745
  if (row.type === "primary-home-mortgage") {
4736
4746
  const payer = Number(row.from) === 2 ? name2 : name1;
4737
4747
  const receiver = Number(row.to) === 2 ? name2 : name1;
4738
- return { label: msg("calcBenefitPrimaryHomeMortgage", { payer, receiver }), amount };
4748
+ return { label: msg("calcBenefitPrimaryHomeMortgage", { payer, receiver }), amount, includeInTotal: true };
4739
4749
  }
4740
4750
  if (row.type === "primary-home-assignment") {
4741
4751
  const receiver = Number(row.to) === 2 ? name2 : name1;
4742
- return { label: msg("calcBenefitPrimaryHomeAssignment", { receiver }), amount };
4752
+ return {
4753
+ label: `${msg("calcBenefitPrimaryHomeAssignment", { receiver })} (${tr("calcBenefitExcludedFromTotal")})`,
4754
+ amount,
4755
+ includeInTotal: false
4756
+ };
4743
4757
  }
4744
- return { label: tr("calcCompBenefitsLabel"), amount };
4758
+ return { label: tr("calcCompBenefitsLabel"), amount, includeInTotal: true };
4745
4759
  });
4746
4760
  }
4747
4761
 
4762
+ function getCompensativeBenefitsTotal(rows) {
4763
+ return (rows || []).reduce((sum, row) => {
4764
+ if (!row || row.includeInTotal === false) return sum;
4765
+ return sum + Number(row.amount || 0);
4766
+ }, 0);
4767
+ }
4768
+
4748
4769
  function formatCompensativeBenefitsInline(m, name1 = c1n(), name2 = c2n()) {
4749
4770
  return getCompensativeBenefitRows(m, name1, name2)
4750
4771
  .map((row) => `${row.label}: ${eur(row.amount)}`)
@@ -4851,14 +4872,14 @@ const defaultExpenseItems = [
4851
4872
  const rawBenefs = Array.isArray(m.compensativeBenefits)
4852
4873
  ? m.compensativeBenefits.filter((r) => r && Number(r.amount || 0) > 0.005)
4853
4874
  : [];
4854
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
4875
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
4855
4876
  const cardsHtml = benefitRows
4856
4877
  .map((row, i) => {
4857
4878
  const icon = (rawBenefs[i] && typeIcons[rawBenefs[i].type]) || "\u2726";
4858
4879
  return `<li class="spieg-benefit-card"><span class="spieg-benefit-icon">${icon}</span><span class="spieg-benefit-label">${escapeHtml(row.label)}</span><strong class="spieg-benefit-amount">${eur(row.amount)}</strong></li>`;
4859
4880
  })
4860
4881
  .join("");
4861
- const total = benefitRows.reduce((s, r) => s + r.amount, 0);
4882
+ const total = getCompensativeBenefitsTotal(benefitRows);
4862
4883
  const totalLabel = currentLang === "en" ? "Total allocated benefits" : "Totale benefici allocati";
4863
4884
  benefitCardsHtml = `
4864
4885
  <div class="result-benefits-box">
@@ -5122,12 +5143,12 @@ const defaultExpenseItems = [
5122
5143
  const rawBenefs = Array.isArray(m.compensativeBenefits)
5123
5144
  ? m.compensativeBenefits.filter((row) => row && Number(row.amount || 0) > 0.005)
5124
5145
  : [];
5125
- const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1" };
5146
+ const typeIcons = { family: "\uD83C\uDFDB", "primary-home-mortgage": "\uD83C\uDFE1", "primary-home-assignment": "\uD83C\uDFE0" };
5126
5147
  const cardsHtml = compBenefits.map((row, idx) => {
5127
5148
  const icon = (rawBenefs[idx] && typeIcons[rawBenefs[idx].type]) || "\u2726";
5128
5149
  return `<li class="pdf-explain-benefit-card"><span class="pdf-explain-benefit-icon">${icon}</span><span class="pdf-explain-benefit-label">${escapeHtml(row.label)}</span><strong class="pdf-explain-benefit-amount">${eur(row.amount)}</strong></li>`;
5129
5150
  }).join("");
5130
- const benefitsTotal = compBenefits.reduce((sum, row) => sum + Number(row.amount || 0), 0);
5151
+ const benefitsTotal = getCompensativeBenefitsTotal(compBenefits);
5131
5152
  explainResultHtml = `
5132
5153
  <div class="pdf-explain-no-transfer-badge">&#9878;&#65039;&ensp;${escapeHtml(tr("calcNoTransferSuggested"))}</div>
5133
5154
  <div class="pdf-explain-benefits-section">
@@ -6050,6 +6071,7 @@ ${scenarioLab.length ? `
6050
6071
 
6051
6072
  function hydrateState(state) {
6052
6073
  if (!state || !state.base || !state.spese) return;
6074
+ let stateSpeseRows = Array.isArray(state.spese) ? state.spese : [];
6053
6075
  Object.entries(state.base).forEach(([k, v]) => {
6054
6076
  const el = document.getElementById(k);
6055
6077
  if (!el) return;
@@ -6065,11 +6087,15 @@ ${scenarioLab.length ? `
6065
6087
  speseConvivenzaAutoMode = Math.max(0, Number(state.base && state.base.speseConvivenza || 0)) <= 0.005;
6066
6088
  }
6067
6089
  if (Array.isArray(state.expenseItems) && state.expenseItems.length) {
6068
- expenseItems = state.expenseItems.map((item, idx) => normalizeExpenseItem(item, idx));
6090
+ const filteredPairs = state.expenseItems
6091
+ .map((item, idx) => ({ item, row: stateSpeseRows[idx] }))
6092
+ .filter((pair) => !isLegacyLocativeExpenseLabel(pair && pair.item && pair.item.label));
6093
+ expenseItems = filteredPairs.map((pair, idx) => normalizeExpenseItem(pair.item, idx));
6094
+ stateSpeseRows = filteredPairs.map((pair) => pair.row).filter((row) => row !== undefined);
6069
6095
  } else {
6070
6096
  expenseItems = defaultExpenseItems.map((item) => ({ ...item }));
6071
6097
  }
6072
- while (expenseItems.length < state.spese.length) {
6098
+ while (expenseItems.length < stateSpeseRows.length) {
6073
6099
  expenseItems.push(normalizeExpenseItem(null, expenseItems.length));
6074
6100
  }
6075
6101
  scenarioLab = normalizeScenarioLabState(state.scenarioLab);
@@ -6107,7 +6133,7 @@ ${scenarioLab.length ? `
6107
6133
  updateSpouseLabels();
6108
6134
  buildExpenseRows();
6109
6135
  syncPermanenza("calendar");
6110
- state.spese.forEach((row, i) => {
6136
+ stateSpeseRows.forEach((row, i) => {
6111
6137
  const c1 = document.getElementById(`c1_${i}`);
6112
6138
  const c2 = document.getElementById(`c2_${i}`);
6113
6139
  const d1 = document.getElementById(`c1d_${i}`);
@@ -626,7 +626,7 @@
626
626
  <script src="supabase.min.js"></script>
627
627
  <script src="fabric.min.js"></script>
628
628
  <script src="html2pdf.bundle.min.js"></script>
629
- <script src="app.js?v=2.4.1"></script>
629
+ <script src="app.js?v=2.4.2"></script>
630
630
  </body>
631
631
  </html>
632
632
 
@@ -885,21 +885,60 @@
885
885
  }
886
886
 
887
887
  .extra-box-first-home {
888
+ position: relative;
889
+ overflow: hidden;
888
890
  background: linear-gradient(135deg, #ffffff 0%, #f0fffe 50%, #f5faff 100%);
889
891
  border: 1px solid rgba(27, 141, 127, 0.15);
890
892
  box-shadow: 0 2px 8px rgba(27, 141, 127, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.8);
891
893
  }
892
894
 
895
+ .extra-box-first-home::after {
896
+ content: "";
897
+ position: absolute;
898
+ inset: -40% -20% auto;
899
+ height: 180px;
900
+ background: radial-gradient(circle at 50% 50%, rgba(61, 181, 160, 0.16), rgba(216, 154, 53, 0.08) 45%, transparent 70%);
901
+ pointer-events: none;
902
+ animation: first-home-aurora 7s ease-in-out infinite alternate;
903
+ }
904
+
893
905
  .extra-box-first-home .extra-box-title::before {
894
906
  content: '🏠 ';
895
907
  margin-right: 4px;
896
908
  }
897
909
 
898
910
  .extra-box-first-home .extra-grid {
911
+ position: relative;
912
+ z-index: 1;
899
913
  gap: 8px 10px;
900
914
  }
901
915
 
916
+ .extra-box-first-home .field {
917
+ transition: transform 0.2s ease, filter 0.2s ease;
918
+ }
919
+
920
+ .extra-box-first-home .field:focus-within {
921
+ transform: translateY(-1px);
922
+ filter: saturate(1.04);
923
+ }
924
+
925
+ .extra-box-first-home .field input[type="number"],
926
+ .extra-box-first-home .field select {
927
+ border-width: 1.5px;
928
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset;
929
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
930
+ }
931
+
932
+ .extra-box-first-home .field input[type="number"]:focus,
933
+ .extra-box-first-home .field select:focus {
934
+ border-color: rgba(27, 141, 127, 0.4);
935
+ box-shadow: 0 0 0 3px rgba(27, 141, 127, 0.14), 0 1px 0 rgba(255, 255, 255, 0.85) inset;
936
+ background: linear-gradient(180deg, #ffffff, #f4fffd);
937
+ }
938
+
902
939
  .mortgage-split-slider {
940
+ position: relative;
941
+ overflow: hidden;
903
942
  margin-top: 12px;
904
943
  border: 1.5px solid rgba(27, 141, 127, 0.2);
905
944
  border-radius: 16px;
@@ -916,11 +955,25 @@
916
955
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
917
956
  }
918
957
 
958
+ .mortgage-split-slider::after {
959
+ content: "";
960
+ position: absolute;
961
+ inset: 0;
962
+ background: linear-gradient(112deg, transparent 30%, rgba(255, 255, 255, 0.55) 46%, transparent 58%);
963
+ transform: translateX(-120%);
964
+ transition: transform 0.5s ease;
965
+ pointer-events: none;
966
+ }
967
+
919
968
  .mortgage-split-slider:hover {
920
969
  box-shadow: 0 8px 20px rgba(27, 141, 127, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.8);
921
970
  border-color: rgba(27, 141, 127, 0.3);
922
971
  }
923
972
 
973
+ .mortgage-split-slider:hover::after {
974
+ transform: translateX(120%);
975
+ }
976
+
924
977
  .mortgage-split-slider.is-disabled {
925
978
  opacity: 0.55;
926
979
  filter: grayscale(0.4);
@@ -1098,6 +1151,17 @@
1098
1151
  box-shadow: 0 2px 6px rgba(27, 141, 127, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.6);
1099
1152
  transition: all 0.2s ease;
1100
1153
  letter-spacing: 0.2px;
1154
+ animation: split-center-breathe 2.6s ease-in-out infinite;
1155
+ }
1156
+
1157
+ @keyframes first-home-aurora {
1158
+ 0% { transform: translate3d(-5%, -12%, 0) scale(1); }
1159
+ 100% { transform: translate3d(6%, -6%, 0) scale(1.08); }
1160
+ }
1161
+
1162
+ @keyframes split-center-breathe {
1163
+ 0%, 100% { box-shadow: 0 2px 6px rgba(27, 141, 127, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.6); }
1164
+ 50% { box-shadow: 0 5px 14px rgba(27, 141, 127, 0.24), inset 0 1px 2px rgba(255, 255, 255, 0.75); }
1101
1165
  }
1102
1166
 
1103
1167
  #primaCasaMutuoSplitInfo {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mantenimento-app",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Frontend + backend architecture for the mantenimento calculator",
5
5
  "type": "commonjs",
6
6
  "main": "backend/calculate-model.js",