• info@usami-aeronautica.it
(() => { // — Parametri base — const K_2021_TODAY = 0.196; // +19,6% dal 2021 ad oggi const RAISE_STEP = 0.03; // +3% ogni 3 anni// — Utility — const fmtEUR = (n) => new Intl.NumberFormat(“it-IT”, { style: “currency”, currency: “EUR”, maximumFractionDigits: 0 }).format(n); const fmtPct = (r) => new Intl.NumberFormat(“it-IT”, { style: “percent”, minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(r);function parseMoney(raw) { if (raw == null) return 0; let s = String(raw).trim(); if (!s) return 0; s = s.replace(/[€\s]/g, “”); if (s.includes(“,”)) s = s.replace(/\./g, “”).replace(“,”, “.”); else s = s.replace(/,/g, “”); const n = Number.parseFloat(s); return Number.isFinite(n) ? n : 0; } function clampInt(n, min, max) { n = Math.trunc(Number(n)); if (!Number.isFinite(n)) n = min; return Math.max(min, Math.min(max, n)); } function pow(a, b) { return Math.pow(a, b); }function statusForMargin(v) { if (v < 1000) return { cls: "uwt-red uwt-blink", badge: { cls: "red", text: "Critico ❗" }, msg: "Con questo margine, le rinunce non sono una scelta: sono una conseguenza." }; if (v <= 1500) return { cls: "uwt-yellow", badge: { cls: "yellow", text: "Teso 😬" }, msg: "Regge finché non succede nulla: basta un imprevisto e salta tutto." }; return { cls: "uwt-blue", badge: { cls: "blue", text: "Sostenibile ✅" }, msg: "Hai un margine decente. La domanda è: quanto dura se i prezzi corrono?" }; }function buildTradeoffs(margin) { const items = []; const t1 = 1000, t2 = 1500; const need1 = Math.max(0, t1 - margin); const need2 = Math.max(0, t2 - margin);if (margin <= 0) { items.push(`Sei in negativo: per tornare a zero servono circa ${fmtEUR(Math.abs(margin))} al mese (tagli o entrate in più).`); items.push(`Per arrivare a ${fmtEUR(t1)} ti mancano circa ${fmtEUR(need1)} al mese.`); items.push(`Per essere “Sostenibile” (${fmtEUR(t2)}) ti mancano circa ${fmtEUR(need2)} al mese.`); items.push(`Traduzione: rinunci già oggi a risparmio, serenità e imprevisti.`); return items; } if (margin < t1) { items.push(`Margine sotto ${fmtEUR(t1)}: servono circa ${fmtEUR(need1)} al mese solo per “respirare”.`); items.push(`Per essere “Sostenibile” servono circa ${fmtEUR(need2)} in più ogni mese.`); items.push(`Rinunce tipiche: fondo emergenza rimandato, manutenzioni, cure, tempo libero “a singhiozzo”.`); return items; } if (margin <= t2) { items.push(`Se vuoi essere “Sostenibile”, mancano circa ${fmtEUR(need2)} al mese.`); items.push(`Rinunce tipiche: vacanze ridotte, spese per figli compressa, rinvio acquisti importanti.`); items.push(`Basta un aumento (auto/bollette) per tornare in rosso.`); return items; } items.push(`Sei sopra soglia: margine extra ≈ ${fmtEUR(margin - t2)} rispetto a ${fmtEUR(t2)}.`); items.push(`Se i prezzi salgono, proteggi questo margine: è la tua “armatura”.`); items.push(`Usalo per fondo emergenza / debiti / risparmio: così l’inflazione fa meno male.`); return items; }// Stima spese familiari (modello semplice e modificabile) function estimateFamilyExpenses(spouseYes, children, infants) { // base: // coniuge a carico: +240 // per figlio: +200 // extra neonato (oltre al figlio): +140 // extra gestione casa (se famiglia > 0): +90 const spouse = spouseYes ? 240 : 0; const child = 200 * children; const infantExtra = 140 * infants; const misc = (spouseYes || children > 0) ? 90 : 0; const est = spouse + child + infantExtra + misc; return Math.round(est / 10) * 10; }function initTool(root) { if (root.dataset.uwtInit === “1”) return; root.dataset.uwtInit = “1”;const $ = (sel) => root.querySelector(sel);const salaryEl = $(“.uwt-salary”); const fixedEl = $(“.uwt-fixed”); const familyEl = $(“.uwt-family”);const spouseEl = $(“.uwt-spouse”); const childrenEl = $(“.uwt-children”); const infantsEl = $(“.uwt-infants”);const yearsEl = $(“.uwt-years”); const inflEl = $(“.uwt-infl”);const btnCalc = $(“.uwt-calc”); const btnEstimate = $(“.uwt-estimate”); const btnGoToday = $(“.uwt-go-today”); const btnGoFuture = $(“.uwt-go-future”); const modeBtns = root.querySelectorAll(“.uwt-mode”);const errorBox = $(“.uwt-errorbox”);const panelToday = $(“.uwt-today”); const panelFuture = $(“.uwt-future”);// Outputs TODAY const outTodayMissing = $(“.uwt-out-today-missing”); const outTodayShould = $(“.uwt-out-today-should”); const outTodayLeft = $(“.uwt-out-today-left”); const outTodayLeftRow = $(“.uwt-out-today-left-row”); const outTodayBadge = $(“.uwt-out-today-badge”); const outTodayMsgSlot = root.querySelector(“.uwt-out-today-msg”) || null; const outTodayList = $(“.uwt-out-today-tradeoffs”);// Outputs FUTURE const outYears = $(“.uwt-out-years”); const outYears2 = $(“.uwt-out-years2”); const outYears3 = $(“.uwt-out-years3”);const outFuturePres = $(“.uwt-out-future-pres”); const outFutureShould = $(“.uwt-out-future-should”); const outFutureMissing= $(“.uwt-out-future-missing”); const outFutureMissingHero = $(“.uwt-out-future-missing-hero”); const outFutureLeft = $(“.uwt-out-future-left”); const outFutureLeftRow= $(“.uwt-out-future-left-row”); const outFutureList = $(“.uwt-out-future-tradeoffs”); const outFutureMessage= $(“.uwt-out-future-message”);// Share const shareWrap = $(“.uwt-share”); const btnCopy = $(“.uwt-copy”); const waLink = $(“.uwt-wa”); const btnNative = $(“.uwt-native”);// How-to values const vSalary = $(“.uwt-v-salary”); const vFixed = $(“.uwt-v-fixed”); const vFamily = $(“.uwt-v-family”); const vYears = $(“.uwt-v-years”); const vInfl = $(“.uwt-v-infl”); const vStep = $(“.uwt-v-step”); const vRaise = $(“.uwt-v-raise”); const vInflFac = $(“.uwt-v-inflfac”);let mode = “step”; // step | all let screen = “today”;// Evita Enter/submit root.addEventListener(“keydown”, (e) => { if (e.key === “Enter”) e.preventDefault(); }, true);const showError = (m) => { errorBox.style.display = “block”; errorBox.textContent = m; }; const clearError = () => { errorBox.style.display = “none”; errorBox.textContent = “”; };function setMode(next) { mode = next; modeBtns.forEach(b => b.setAttribute(“aria-pressed”, b.dataset.mode === mode ? “true” : “false”));if (mode === “all”) { btnGoToday.classList.add(“uwt-hidden”); btnGoFuture.classList.add(“uwt-hidden”); panelToday.classList.remove(“uwt-hidden”); panelFuture.classList.remove(“uwt-hidden”); } else { btnGoToday.classList.remove(“uwt-hidden”); btnGoFuture.classList.remove(“uwt-hidden”); setScreen(screen); } } function setScreen(next) { screen = next; if (mode === “all”) return; if (screen === “today”) { panelToday.classList.remove(“uwt-hidden”); panelFuture.classList.add(“uwt-hidden”); } else { panelToday.classList.add(“uwt-hidden”); panelFuture.classList.remove(“uwt-hidden”); } }function normalizeCounts() { const ch = (childrenEl.value === “5”) ? 5 : clampInt(childrenEl.value, 0, 5); let inf = (infantsEl.value === “3”) ? 3 : clampInt(infantsEl.value, 0, 3); if (inf > ch) { inf = Math.min(ch, 3); infantsEl.value = String(inf); } return { ch, inf }; }function renderList(ul, items) { ul.innerHTML = “”; items.forEach(t => { const li = document.createElement(“li”); li.textContent = t; ul.appendChild(li); }); }function applyRowClass(rowEl, cls) { rowEl.classList.remove(“uwt-red”,”uwt-yellow”,”uwt-blue”,”uwt-blink”); cls.split(” “).forEach(c => rowEl.classList.add(c)); }function setBadge(el, badge) { el.classList.remove(“red”,”yellow”,”blue”); el.classList.add(badge.cls); el.textContent = badge.text; }function buildShareText(obj) { return [ “Quanto valgono i tuoi soldi oggi e domani:”, “”, `💶 Stipendio: ${fmtEUR(obj.salary)}`, `🚨 OGGI MANCANO (dal 2021 +19,6%): ${fmtEUR(obj.todayMissing)}`, `✅ Dovrebbe essere oggi: ${fmtEUR(obj.shouldToday)}`, `🏚️ Ti resta oggi dopo spese: ${fmtEUR(obj.leftToday)}`, “”, `⏳ Tra ${obj.years} anni (scatti +3% ogni 3 anni):`, `📈 Stipendio presunto: ${fmtEUR(obj.presumed)}`, `📌 Dovrebbe essere: ${fmtEUR(obj.shouldFuture)}`, `🔥 DOMANI MANCANO: ${fmtEUR(obj.missingFuture)}`, `🧾 Ti resterebbe dopo spese: ${fmtEUR(obj.leftFuture)}` ].join(“\n”); }function doEstimate() { const spouseYes = spouseEl.value === “si”; const { ch, inf } = normalizeCounts(); familyEl.value = String(estimateFamilyExpenses(spouseYes, ch, inf)); }function doCalc() { clearError();const salary = parseMoney(salaryEl.value); const fixed = parseMoney(fixedEl.value); const family = parseMoney(familyEl.value); const years = clampInt(yearsEl.value, 0, 60); const infl = Number(inflEl.value);if (!(salary > 0)) return showError(“Inserisci uno stipendio valido (maggiore di 0).”); if (!Number.isFinite(infl) || infl < 0) return showError("Seleziona un tasso di inflazione valido.");const expNow = Math.max(0, fixed + family);// --- OGGI --- const todayMissing = salary * K_2021_TODAY; const shouldToday = salary * (1 + K_2021_TODAY); const leftToday = salary - expNow;outTodayMissing.textContent = fmtEUR(todayMissing); outTodayShould.textContent = fmtEUR(shouldToday); outTodayLeft.textContent = fmtEUR(leftToday);const stToday = statusForMargin(leftToday); applyRowClass(outTodayLeftRow, stToday.cls); setBadge(outTodayBadge, stToday.badge); if (outTodayMsgSlot) outTodayMsgSlot.textContent = stToday.msg; renderList(outTodayList, buildTradeoffs(leftToday));// --- DOMANI --- const step = Math.floor(years / 3); const raiseFactor = pow(1 + RAISE_STEP, step); const inflFactor = pow(1 + infl, years);const presumed = salary * raiseFactor; const shouldFuture= salary * (1 + K_2021_TODAY) * inflFactor; const missingFuture = shouldFuture - presumed;const expFuture = expNow * inflFactor; const leftFuture = presumed - expFuture;outYears.textContent = String(years); outYears2.textContent= String(years); outYears3.textContent= String(years);outFuturePres.textContent = fmtEUR(presumed); outFutureShould.textContent = fmtEUR(shouldFuture); outFutureMissing.textContent= fmtEUR(missingFuture); outFutureLeft.textContent = fmtEUR(leftFuture);// HERO "DOMANI MANCANO" (lampeggia se > 0) outFutureMissingHero.classList.remove(“uwt-red”,”uwt-blue”,”uwt-yellow”,”uwt-blink”); if (missingFuture > 0) outFutureMissingHero.classList.add(“uwt-red”,”uwt-blink”); else outFutureMissingHero.classList.add(“uwt-blue”);// Margine futuro (colori come oggi) const stF = statusForMargin(leftFuture); applyRowClass(outFutureLeftRow, stF.cls);const msg = missingFuture > 0 ? `Con scatti (+3% ogni 3 anni) e inflazione ${fmtPct(infl)} per ${years} anni, il divario cresce: ti mancano circa ${fmtEUR(missingFuture)} al mese rispetto a uno stipendio “in pari”.` : `In questo scenario sei sopra: margine ≈ ${fmtEUR(Math.abs(missingFuture))}. (Raro: significa che i prezzi crescono meno di quanto immagini o il netto è già alto).`;outFutureMessage.textContent = msg;renderList(outFutureList, [ `Scatti: step = floor(${years}/3) = ${step} → fattore scatti ≈ ${raiseFactor.toFixed(3)}.`, `Inflazione: fattore ≈ ${(inflFactor).toFixed(3)} (tasso ${fmtPct(infl)} per ${years} anni).`, …(missingFuture > 0 ? [`“DOMANI MANCANO” = ${fmtEUR(missingFuture)} → il 3% ogni 3 anni non basta.`] : [`“DOMANI MANCANO” ≤ 0 → sei sopra la curva in questo scenario.`]), …buildTradeoffs(leftFuture) ]);// How-to numeric values vSalary.textContent = fmtEUR(salary); vFixed.textContent = fmtEUR(fixed); vFamily.textContent = fmtEUR(family); vYears.textContent = String(years); vInfl.textContent = fmtPct(infl); vStep.textContent = String(step); vRaise.textContent = raiseFactor.toFixed(3); vInflFac.textContent = inflFactor.toFixed(3);// mostra pannelli panelToday.classList.remove(“uwt-hidden”); panelFuture.classList.remove(“uwt-hidden”);// share const shareText = buildShareText({ salary, todayMissing, shouldToday, leftToday, years, presumed, shouldFuture, missingFuture, leftFuture }); const waUrl = “https://wa.me/?text=” + encodeURIComponent(shareText);waLink.href = waUrl; shareWrap.classList.remove(“uwt-hidden”);btnCopy.onclick = async () => { try { await navigator.clipboard.writeText(shareText); btnCopy.textContent = “✅ Copiato”; setTimeout(()=>btnCopy.textContent=”📋 Copia testo”, 1400); } catch { alert(shareText); } };btnNative.onclick = async () => { try { if (navigator.share) await navigator.share({ title: “Oggi vs Domani”, text: shareText }); else btnCopy.click(); } catch { /* niente */ } };if (mode === “step”) setScreen(“today”); }// listeners btnEstimate.addEventListener(“click”, doEstimate); btnCalc.addEventListener(“click”, doCalc); btnGoToday.addEventListener(“click”, () => setScreen(“today”)); btnGoFuture.addEventListener(“click”, () => setScreen(“future”)); modeBtns.forEach(b => b.addEventListener(“click”, () => setMode(b.dataset.mode)));childrenEl.addEventListener(“change”, normalizeCounts); infantsEl.addEventListener(“change”, normalizeCounts);setMode(“step”); }// Boot robusto (Elementor può inserire HTML dopo il load) function initAll() { document.querySelectorAll(“[data-usami-wage-tool]”).forEach(initTool); }if (document.readyState === “loading”) { document.addEventListener(“DOMContentLoaded”, indicate); } else { indicate(); }function indicate() { initAll(); // MutationObserver: se Elementor carica il widget dopo, lo inizializziamo lo stesso const obs = new MutationObserver(() => initAll()); obs.observe(document.documentElement, { childList: true, subtree: true }); } })();