Jausing commited on
Commit
2477bbc
·
verified ·
1 Parent(s): 7033b1b

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +581 -188
  2. prompts.txt +2 -0
index.html CHANGED
@@ -3,9 +3,10 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Pensionsoptimering - Löneväxlingsverktyg</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
 
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
  <style>
11
  .slider-thumb::-webkit-slider-thumb {
@@ -71,41 +72,91 @@
71
  from { opacity: 0; }
72
  to { opacity: 1; }
73
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  </style>
75
  </head>
76
  <body class="bg-gray-50 min-h-screen">
77
  <div class="container mx-auto px-4 py-8">
78
  <header class="text-center mb-12">
79
- <h1 class="text-4xl font-bold text-blue-800 mb-4"> Pensionsoptimering, Löneväxling o annat tråk</h1>
80
  <p class="text-lg text-gray-600 max-w-3xl mx-auto">
81
- Är du som Thomander och inte kan greppa siffror i luften? Laborera fram hur löneväxling kan påverka din pensionssparande och totala inkomst. Justera parametrarna nedan för att se effekten i realtid. sedan till Rui och var riktigt mallig. 💗
 
82
  </p>
83
  </header>
84
 
85
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
86
  <!-- Input Controls -->
87
  <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-1">
88
- <h2 class="text-2xl font-semibold text-blue-700 mb-6">Inställningar</h2>
89
 
90
  <div class="space-y-6">
91
  <div>
92
  <label for="salary" class="block text-sm font-medium text-gray-700 mb-2">
93
- Månadslön (före skatt)
94
  <span class="tooltip ml-1">
95
  <i class="fas fa-info-circle text-blue-500"></i>
96
- <span class="tooltiptext">Din bruttolön innan skatt och andra avdrag</span>
97
  </span>
98
  </label>
99
  <div class="flex items-center">
100
  <span class="mr-2 text-gray-500">kr</span>
101
- <input type="range" id="salary" min="20000" max="100000" step="1000" value="45000" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
102
  <span id="salaryValue" class="ml-4 font-medium">45 000</span>
103
  </div>
104
  </div>
105
 
106
  <div>
107
  <label for="age" class="block text-sm font-medium text-gray-700 mb-2">
108
- Ålder
109
  <span class="tooltip ml-1">
110
  <i class="fas fa-info-circle text-blue-500"></i>
111
  <span class="tooltiptext">Din nuvarande ålder för att beräkna tills pension</span>
@@ -116,6 +167,24 @@
116
  <span id="ageValue" class="ml-4 font-medium">35</span>
117
  </div>
118
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
  <div>
121
  <label for="retirementAge" class="block text-sm font-medium text-gray-700 mb-2">
@@ -131,6 +200,76 @@
131
  </div>
132
  </div>
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  <div>
135
  <label for="pensionContribution" class="block text-sm font-medium text-gray-700 mb-2">
136
  Pensionsavsättning (% av lön)
@@ -175,7 +314,7 @@
175
 
176
  <div class="pt-4">
177
  <button id="calculateBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center">
178
- <i class="fas fa-calculator mr-2"></i> Beräkna pensionsoptimering
179
  </button>
180
  </div>
181
  </div>
@@ -183,33 +322,49 @@
183
 
184
  <!-- Results Visualization -->
185
  <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-2">
186
- <h2 class="text-2xl font-semibold text-blue-700 mb-6">Resultat</h2>
187
 
188
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
189
  <div class="bg-blue-50 rounded-lg p-4 border border-blue-100">
190
- <h3 class="text-lg font-medium text-blue-800 mb-2">Månadslön efter löneväxling</h3>
191
- <p class="text-3xl font-bold text-blue-600" id="netSalary">0 kr</p>
192
- <p class="text-sm text-gray-600 mt-1" id="salaryChange">Ingen förändring</p>
 
 
 
 
193
  </div>
194
 
195
  <div class="bg-green-50 rounded-lg p-4 border border-green-100">
196
- <h3 class="text-lg font-medium text-green-800 mb-2">Total pensionspot</h3>
197
- <p class="text-3xl font-bold text-green-600" id="totalPension">0 kr</p>
198
- <p class="text-sm text-gray-600 mt-1" id="pensionChange">Ingen förändring</p>
 
 
 
 
 
 
 
 
 
 
 
 
199
  </div>
200
  </div>
201
 
202
  <div class="mb-8">
203
- <h3 class="text-xl font-semibold text-gray-800 mb-4">Fördelning löneväxling</h3>
204
  <div class="h-64">
205
- <canvas id="contributionChart"></canvas>
206
  </div>
207
  </div>
208
 
209
  <div class="mb-8">
210
- <h3 class="text-xl font-semibold text-gray-800 mb-4">Pensionsutveckling över tid</h3>
211
  <div class="h-64">
212
- <canvas id="growthChart"></canvas>
213
  </div>
214
  </div>
215
 
@@ -219,19 +374,26 @@
219
  <i class="fas fa-lightbulb text-yellow-500 text-xl"></i>
220
  </div>
221
  <div class="ml-3">
222
- <h3 class="text-sm font-medium text-yellow-800">Tips för optimering</h3>
223
- <div class="mt-2 text-sm text-yellow-700" id="optimizationTips">
224
- <p>Justera löneväxlingsandelen för att se hur det påverkar din nettolön och pensionssparande.</p>
225
  </div>
226
  </div>
227
  </div>
228
  </div>
229
 
230
  <div class="bg-gray-50 rounded-lg p-4 border border-gray-200">
231
- <h3 class="text-lg font-medium text-gray-800 mb-3">Sammanfattning</h3>
232
- <div class="space-y-3 text-sm text-gray-700" id="summaryText">
233
- <p>Löneväxling innebär att du som anställd går med på att sänka din bruttolön mot att arbetsgivaren istället betalar in en motsvarande summa till din pension. Detta kan vara skattemässigt fördelaktigt eftersom pensionsavsättningar inte omfattas av arbetsgivaravgifter och vanlig inkomstskatt.</p>
234
- <p>Använd verktyget ovan för att se hur olika nivåer av löneväxling påverkar din nuvarande lön och framtida pension.</p>
 
 
 
 
 
 
 
235
  </div>
236
  </div>
237
  </div>
@@ -239,16 +401,39 @@
239
  </div>
240
 
241
  <script>
 
 
 
 
 
 
 
 
242
  // Format numbers with spaces as thousand separators
243
  function formatNumber(num) {
244
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
245
  }
246
 
247
- // Calculate tax based on salary (simplified Swedish tax model)
248
- function calculateTax(salary) {
249
- if (salary <= 20000) return salary * 0.30;
250
- if (salary <= 40000) return salary * 0.35;
251
- return salary * 0.45;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  }
253
 
254
  // Calculate employer contributions (simplified)
@@ -256,112 +441,239 @@
256
  return salary * 0.3142; // Approximate employer contributions in Sweden
257
  }
258
 
259
- // Calculate compound interest
260
- function calculateCompoundInterest(principal, annualRate, years, monthlyContribution) {
261
  let amount = principal;
262
  const monthlyRate = annualRate / 12 / 100;
263
  const months = years * 12;
 
264
 
265
  for (let i = 0; i < months; i++) {
266
- amount = amount * (1 + monthlyRate) + monthlyContribution;
 
 
 
 
 
267
  }
268
 
269
  return amount;
270
  }
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  // Update all displayed values when inputs change
273
  function updateDisplayValues() {
274
  document.getElementById('salaryValue').textContent = formatNumber(document.getElementById('salary').value);
275
  document.getElementById('ageValue').textContent = document.getElementById('age').value;
 
276
  document.getElementById('retirementAgeValue').textContent = document.getElementById('retirementAge').value;
 
 
 
 
277
  document.getElementById('pensionContributionValue').textContent = document.getElementById('pensionContribution').value + '%';
278
  document.getElementById('salaryExchangeValue').textContent = document.getElementById('salaryExchange').value + '%';
279
  document.getElementById('expectedReturnValue').textContent = document.getElementById('expectedReturn').value + '%';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  }
281
 
282
  // Initialize charts
283
- let contributionChart;
284
- let growthChart;
285
 
286
  function initCharts() {
287
- const contributionCtx = document.getElementById('contributionChart').getContext('2d');
288
- contributionChart = new Chart(contributionCtx, {
289
- type: 'doughnut',
290
  data: {
291
- labels: ['Arbetsgivaravgifter sparade', 'Skatt sparad', 'Din nettolön'],
292
- datasets: [{
293
- data: [0, 0, 0],
294
- backgroundColor: [
295
- '#3b82f6',
296
- '#10b981',
297
- '#f59e0b'
298
- ],
299
- borderWidth: 1
300
- }]
 
 
301
  },
302
  options: {
303
  responsive: true,
304
  maintainAspectRatio: false,
305
  plugins: {
306
- legend: {
307
- position: 'right',
308
- },
309
  tooltip: {
310
  callbacks: {
311
  label: function(context) {
312
- let label = context.label || '';
313
- if (label) {
314
- label += ': ';
315
- }
316
- label += formatNumber(context.raw) + ' kr';
317
- return label;
318
  }
319
  }
320
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  }
322
  }
323
  });
324
 
325
- const growthCtx = document.getElementById('growthChart').getContext('2d');
326
- growthChart = new Chart(growthCtx, {
327
- type: 'line',
328
  data: {
329
- labels: [],
330
- datasets: [
331
- {
332
- label: 'Med löneväxling',
333
- data: [],
334
- borderColor: '#3b82f6',
335
- backgroundColor: 'rgba(59, 130, 246, 0.1)',
336
- borderWidth: 2,
337
- fill: true,
338
- tension: 0.4
339
- },
340
- {
341
- label: 'Utan löneväxling',
342
- data: [],
343
- borderColor: '#64748b',
344
- backgroundColor: 'rgba(100, 116, 139, 0.1)',
345
- borderWidth: 2,
346
- borderDash: [5, 5],
347
- fill: true,
348
- tension: 0.4
349
- }
350
- ]
351
  },
352
  options: {
353
  responsive: true,
354
  maintainAspectRatio: false,
355
  plugins: {
 
 
 
356
  tooltip: {
357
  callbacks: {
358
  label: function(context) {
359
- let label = context.dataset.label || '';
360
- if (label) {
361
- label += ': ';
362
- }
363
- label += formatNumber(context.raw) + ' kr';
364
- return label;
365
  }
366
  }
367
  }
@@ -380,130 +692,211 @@
380
  });
381
  }
382
 
383
- // Main calculation function
384
- function calculateResults() {
385
  // Get input values
386
  const salary = parseInt(document.getElementById('salary').value);
 
387
  const age = parseInt(document.getElementById('age').value);
388
  const retirementAge = parseInt(document.getElementById('retirementAge').value);
389
- const pensionContribution = parseFloat(document.getElementById('pensionContribution').value);
390
- const salaryExchange = parseInt(document.getElementById('salaryExchange').value);
 
 
 
391
  const expectedReturn = parseFloat(document.getElementById('expectedReturn').value);
392
 
393
- // Calculate years to retirement
394
  const yearsToRetirement = retirementAge - age;
 
395
 
396
- // Calculate pension contributions
397
- const totalPensionContribution = salary * (pensionContribution / 100);
398
- const exchangedAmount = totalPensionContribution * (salaryExchange / 100);
399
- const regularPensionContribution = totalPensionContribution - exchangedAmount;
400
-
401
- // Calculate tax savings from salary exchange
402
- const taxRate = calculateTax(salary) / salary;
403
- const employerContributionRate = 0.3142; // Approximate employer contributions in Sweden
404
 
405
- const taxSaved = exchangedAmount * taxRate;
406
- const employerContributionsSaved = exchangedAmount * employerContributionRate;
407
- const totalSavings = taxSaved + employerContributionsSaved;
408
-
409
- // Calculate net salary
410
- const taxWithoutExchange = calculateTax(salary);
411
- const taxWithExchange = calculateTax(salary - exchangedAmount);
412
- const netSalaryWithoutExchange = salary - taxWithoutExchange;
413
- const netSalaryWithExchange = (salary - exchangedAmount) - taxWithExchange;
414
-
415
- // Calculate pension growth
416
- const monthlyContributionWithExchange = (regularPensionContribution + exchangedAmount + totalSavings) / 12;
417
- const monthlyContributionWithoutExchange = (regularPensionContribution + (exchangedAmount * (1 - taxRate))) / 12;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
- const pensionWithExchange = calculateCompoundInterest(0, expectedReturn, yearsToRetirement, monthlyContributionWithExchange);
420
- const pensionWithoutExchange = calculateCompoundInterest(0, expectedReturn, yearsToRetirement, monthlyContributionWithoutExchange);
 
 
421
 
422
- // Update result displays
423
- document.getElementById('netSalary').textContent = formatNumber(Math.round(netSalaryWithExchange)) + ' kr';
 
 
 
 
424
 
425
- const salaryDifference = netSalaryWithExchange - netSalaryWithoutExchange;
426
- if (salaryDifference > 0) {
427
- document.getElementById('salaryChange').textContent = `+${formatNumber(Math.round(salaryDifference))} kr jämfört med utan löneväxling`;
428
- document.getElementById('salaryChange').className = 'text-sm text-green-600 mt-1';
429
- } else if (salaryDifference < 0) {
430
- document.getElementById('salaryChange').textContent = `${formatNumber(Math.round(salaryDifference))} kr jämfört med utan löneväxling`;
431
- document.getElementById('salaryChange').className = 'text-sm text-red-600 mt-1';
432
- } else {
433
- document.getElementById('salaryChange').textContent = 'Ingen förändring';
434
- document.getElementById('salaryChange').className = 'text-sm text-gray-600 mt-1';
435
- }
436
 
437
- document.getElementById('totalPension').textContent = formatNumber(Math.round(pensionWithExchange)) + ' kr';
 
 
 
 
 
438
 
439
- const pensionDifference = pensionWithExchange - pensionWithoutExchange;
440
- if (pensionDifference > 0) {
441
- document.getElementById('pensionChange').textContent = `+${formatNumber(Math.round(pensionDifference))} kr jämfört med utan löneväxling`;
442
- document.getElementById('pensionChange').className = 'text-sm text-green-600 mt-1';
443
- } else if (pensionDifference < 0) {
444
- document.getElementById('pensionChange').textContent = `${formatNumber(Math.round(pensionDifference))} kr jämfört med utan löneväxling`;
445
- document.getElementById('pensionChange').className = 'text-sm text-red-600 mt-1';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  } else {
447
- document.getElementById('pensionChange').textContent = 'Ingen förändring';
448
- document.getElementById('pensionChange').className = 'text-sm text-gray-600 mt-1';
 
 
 
 
449
  }
450
 
451
- // Update contribution chart
452
- contributionChart.data.datasets[0].data = [
453
- Math.round(employerContributionsSaved),
454
- Math.round(taxSaved),
455
- Math.round(netSalaryWithExchange)
456
- ];
457
- contributionChart.update();
458
-
459
- // Update growth chart
460
- const labels = [];
461
- const withExchangeData = [];
462
- const withoutExchangeData = [];
463
-
464
- for (let year = 0; year <= yearsToRetirement; year++) {
465
- labels.push(`År ${year}`);
466
-
467
- const withExchange = calculateCompoundInterest(0, expectedReturn, year, monthlyContributionWithExchange);
468
- const withoutExchange = calculateCompoundInterest(0, expectedReturn, year, monthlyContributionWithoutExchange);
469
-
470
- withExchangeData.push(Math.round(withExchange));
471
- withoutExchangeData.push(Math.round(withoutExchange));
472
  }
473
 
474
- growthChart.data.labels = labels;
475
- growthChart.data.datasets[0].data = withExchangeData;
476
- growthChart.data.datasets[1].data = withoutExchangeData;
477
- growthChart.update();
478
-
479
- // Update optimization tips
480
- let tips = '';
481
- if (salaryExchange === 0) {
482
- tips = 'Du använder inte löneväxling alls. Öka löneväxlingsandelen för att se potentiella skattebesparingar och högre pensionsavsättningar.';
483
- } else if (salaryExchange < 50) {
484
- tips = 'Du löneväxlar en del av din pensionsavsättning. Öka andelen för större skattebesparingar och högre pensionsavsättningar.';
485
- } else if (salaryExchange < 100) {
486
- tips = 'Du löneväxlar en stor del av din pensionsavsättning. Öka till 100% för maximala skattebesparingar.';
487
- } else {
488
- tips = 'Du löneväxlar hela din pensionsavsättning. Detta ger maximala skattebesparingar och pensionsavsättningar.';
489
  }
490
 
491
- if (yearsToRetirement < 10) {
492
- tips += ' Eftersom du har mindre än 10 år kvar till pension kan löneväxling vara särskilt fördelaktigt.';
493
- } else if (yearsToRetirement > 30) {
494
- tips += ' Med många år kvar till pension har ditt sparande lång tid att växa - löneväxling kan ge betydande fördelar över tid.';
495
  }
496
 
497
- document.getElementById('optimizationTips').innerHTML = `<p>${tips}</p>`;
498
 
499
  // Add animation classes
500
- document.getElementById('netSalary').classList.add('animate-grow');
 
501
  document.getElementById('totalPension').classList.add('animate-grow');
502
- document.querySelectorAll('.tooltip').forEach(el => el.classList.add('fade-in'));
503
 
504
  // Remove animation classes after animation completes
505
  setTimeout(() => {
506
- document.getElementById('netSalary').classList.remove('animate-grow');
 
507
  document.getElementById('totalPension').classList.remove('animate-grow');
508
  }, 1500);
509
  }
@@ -519,7 +912,7 @@
519
 
520
  // Set up calculate button
521
  document.getElementById('calculateBtn').addEventListener('click', function() {
522
- calculateResults();
523
  });
524
 
525
  // Initialize display values and charts
@@ -527,7 +920,7 @@
527
  initCharts();
528
 
529
  // Calculate initial results
530
- calculateResults();
531
  });
532
  </script>
533
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Jausing/misc-stuff" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Thomanders Pensionsoptimering</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/slider-ui/dist/slider-ui.min.js"></script>
10
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
  <style>
12
  .slider-thumb::-webkit-slider-thumb {
 
72
  from { opacity: 0; }
73
  to { opacity: 1; }
74
  }
75
+
76
+ .progress-bar {
77
+ height: 8px;
78
+ border-radius: 4px;
79
+ background-color: #e5e7eb;
80
+ overflow: hidden;
81
+ }
82
+
83
+ .progress-bar-fill {
84
+ height: 100%;
85
+ background-color: #3b82f6;
86
+ transition: width 0.3s ease;
87
+ }
88
+
89
+ .function-graph {
90
+ height: 200px;
91
+ width: 100%;
92
+ background-color: #f8fafc;
93
+ border-radius: 8px;
94
+ position: relative;
95
+ overflow: hidden;
96
+ }
97
+
98
+ .graph-line {
99
+ position: absolute;
100
+ bottom: 0;
101
+ left: 0;
102
+ width: 100%;
103
+ height: 2px;
104
+ background-color: #3b82f6;
105
+ }
106
+
107
+ .tax-bracket {
108
+ position: absolute;
109
+ bottom: 0;
110
+ height: 100%;
111
+ background-color: rgba(59, 130, 246, 0.1);
112
+ border-left: 1px dashed #3b82f6;
113
+ border-right: 1px dashed #3b82f6;
114
+ }
115
+
116
+ .tax-bracket-label {
117
+ position: absolute;
118
+ top: 5px;
119
+ transform: translateX(-50%);
120
+ font-size: 10px;
121
+ color: #3b82f6;
122
+ white-space: nowrap;
123
+ }
124
  </style>
125
  </head>
126
  <body class="bg-gray-50 min-h-screen">
127
  <div class="container mx-auto px-4 py-8">
128
  <header class="text-center mb-12">
129
+ <h1 class="text-4xl font-bold text-blue-800 mb-4">Thomanders Pensionsoptimering - Livscykelvärdering</h1>
130
  <p class="text-lg text-gray-600 max-w-3xl mx-auto">
131
+ Vad är en finansiell rådgivare från Max värd? Ungefär en prompt....En komplett modell för att maximera din upplevda livskvalitet genom optimal pensionsplanering.
132
+ Tar hänsyn till skiktgränser, subjektiv tidspreferens och osäkerhet i livslängd.
133
  </p>
134
  </header>
135
 
136
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
137
  <!-- Input Controls -->
138
  <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-1">
139
+ <h2 class="text-2xl font-semibold text-blue-700 mb-6">Hårda Parametrar</h2>
140
 
141
  <div class="space-y-6">
142
  <div>
143
  <label for="salary" class="block text-sm font-medium text-gray-700 mb-2">
144
+ Nuvarande månadslön (brutto)
145
  <span class="tooltip ml-1">
146
  <i class="fas fa-info-circle text-blue-500"></i>
147
+ <span class="tooltiptext">Din nuvarande bruttolön innan skatt och avdrag</span>
148
  </span>
149
  </label>
150
  <div class="flex items-center">
151
  <span class="mr-2 text-gray-500">kr</span>
152
+ <input type="range" id="salary" min="20000" max="150000" step="1000" value="45000" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
153
  <span id="salaryValue" class="ml-4 font-medium">45 000</span>
154
  </div>
155
  </div>
156
 
157
  <div>
158
  <label for="age" class="block text-sm font-medium text-gray-700 mb-2">
159
+ Nuvarande ålder
160
  <span class="tooltip ml-1">
161
  <i class="fas fa-info-circle text-blue-500"></i>
162
  <span class="tooltiptext">Din nuvarande ålder för att beräkna tills pension</span>
 
167
  <span id="ageValue" class="ml-4 font-medium">35</span>
168
  </div>
169
  </div>
170
+ </div>
171
+
172
+ <h2 class="text-2xl font-semibold text-blue-700 mt-8 mb-6">Semi-flexibla Parametrar</h2>
173
+
174
+ <div class="space-y-6">
175
+ <div>
176
+ <label for="salaryGrowth" class="block text-sm font-medium text-gray-700 mb-2">
177
+ Förväntad årlig löneutveckling (%)
178
+ <span class="tooltip ml-1">
179
+ <i class="fas fa-info-circle text-blue-500"></i>
180
+ <span class="tooltiptext">Genomsnittlig årlig ökning av din lön fram till pension</span>
181
+ </span>
182
+ </label>
183
+ <div class="flex items-center">
184
+ <input type="range" id="salaryGrowth" min="-2" max="10" step="0.5" value="2.5" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
185
+ <span id="salaryGrowthValue" class="ml-4 font-medium">2.5%</span>
186
+ </div>
187
+ </div>
188
 
189
  <div>
190
  <label for="retirementAge" class="block text-sm font-medium text-gray-700 mb-2">
 
200
  </div>
201
  </div>
202
 
203
+ <div>
204
+ <label for="lifeExpectancy" class="block text-sm font-medium text-gray-700 mb-2">
205
+ Förväntad dödsålder
206
+ <span class="tooltip ml-1">
207
+ <i class="fas fa-info-circle text-blue-500"></i>
208
+ <span class="tooltiptext">Ålder då du förväntar dig att dö (baserat på släkt och hälsa)</span>
209
+ </span>
210
+ </label>
211
+ <div class="flex items-center">
212
+ <input type="range" id="lifeExpectancy" min="65" max="100" step="1" value="85" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
213
+ <span id="lifeExpectancyValue" class="ml-4 font-medium">85</span>
214
+ </div>
215
+ </div>
216
+ </div>
217
+
218
+ <h2 class="text-2xl font-semibold text-blue-700 mt-8 mb-6">Subjektiva Värderingar</h2>
219
+
220
+ <div class="space-y-6">
221
+ <div>
222
+ <label for="currentValueMultiplier" class="block text-sm font-medium text-gray-700 mb-2">
223
+ Nuvarande värdefaktor (300% betyder 3x mer värde idag)
224
+ <span class="tooltip ml-1">
225
+ <i class="fas fa-info-circle text-blue-500"></i>
226
+ <span class="tooltiptext">Hur mycket mer värderar du pengar idag jämfört med efter pension?</span>
227
+ </span>
228
+ </label>
229
+ <div class="flex items-center">
230
+ <input type="range" id="currentValueMultiplier" min="100" max="500" step="10" value="300" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
231
+ <span id="currentValueMultiplierValue" class="ml-4 font-medium">300%</span>
232
+ </div>
233
+ <div class="function-graph mt-2" id="currentValueGraph">
234
+ <div class="graph-line"></div>
235
+ </div>
236
+ </div>
237
+
238
+ <div>
239
+ <label for="retirementValueMultiplier" class="block text-sm font-medium text-gray-700 mb-2">
240
+ Pensionsvärdefaktor (100% = neutral)
241
+ <span class="tooltip ml-1">
242
+ <i class="fas fa-info-circle text-blue-500"></i>
243
+ <span class="tooltiptext">Hur mycket värderar du pengar under pensionsåren jämfört med vid pensionsstart?</span>
244
+ </span>
245
+ </label>
246
+ <div class="flex items-center">
247
+ <input type="range" id="retirementValueMultiplier" min="0" max="200" step="5" value="100" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
248
+ <span id="retirementValueMultiplierValue" class="ml-4 font-medium">100%</span>
249
+ </div>
250
+ <div class="function-graph mt-2" id="retirementValueGraph">
251
+ <div class="graph-line"></div>
252
+ </div>
253
+ </div>
254
+
255
+ <div>
256
+ <label for="endOfLifeReserve" class="block text-sm font-medium text-gray-700 mb-2">
257
+ Reserv vid dödsålder (% av totalt sparande)
258
+ <span class="tooltip ml-1">
259
+ <i class="fas fa-info-circle text-blue-500"></i>
260
+ <span class="tooltiptext">Hur stor del av ditt sparande vill du ha kvar vid förväntad dödsålder?</span>
261
+ </span>
262
+ </label>
263
+ <div class="flex items-center">
264
+ <input type="range" id="endOfLifeReserve" min="0" max="100" step="5" value="20" class="w-full h-2 bg-gray-200 rounded-lg slider-thumb">
265
+ <span id="endOfLifeReserveValue" class="ml-4 font-medium">20%</span>
266
+ </div>
267
+ </div>
268
+ </div>
269
+
270
+ <h2 class="text-2xl font-semibold text-blue-700 mt-8 mb-6">Pensionsstrategi</h2>
271
+
272
+ <div class="space-y-6">
273
  <div>
274
  <label for="pensionContribution" class="block text-sm font-medium text-gray-700 mb-2">
275
  Pensionsavsättning (% av lön)
 
314
 
315
  <div class="pt-4">
316
  <button id="calculateBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center">
317
+ <i class="fas fa-calculator mr-2"></i> Beräkna Optimal Strategi
318
  </button>
319
  </div>
320
  </div>
 
322
 
323
  <!-- Results Visualization -->
324
  <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-2">
325
+ <h2 class="text-2xl font-semibold text-blue-700 mb-6">Optimeringsresultat</h2>
326
 
327
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
328
  <div class="bg-blue-50 rounded-lg p-4 border border-blue-100">
329
+ <h3 class="text-lg font-medium text-blue-800 mb-2">Optimal löneväxling</h3>
330
+ <p class="text-2xl font-bold text-blue-600" id="optimalExchange">0%</p>
331
+ </div>
332
+
333
+ <div class="bg-purple-50 rounded-lg p-4 border border-purple-100">
334
+ <h3 class="text-lg font-medium text-purple-800 mb-2">Maximerat livsvärde</h3>
335
+ <p class="text-2xl font-bold text-purple-600" id="maxValue">0</p>
336
  </div>
337
 
338
  <div class="bg-green-50 rounded-lg p-4 border border-green-100">
339
+ <h3 class="text-lg font-medium text-green-800 mb-2">Pensionspot vid pension</h3>
340
+ <p class="text-2xl font-bold text-green-600" id="totalPension">0 kr</p>
341
+ </div>
342
+ </div>
343
+
344
+ <div class="mb-6">
345
+ <h3 class="text-xl font-semibold text-gray-800 mb-3">Skatteskikt och Marginaleffekt</h3>
346
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
347
+ <div class="function-graph" id="taxBracketGraph">
348
+ <div class="graph-line"></div>
349
+ <!-- Tax brackets will be added dynamically -->
350
+ </div>
351
+ <div class="mt-2 text-sm text-gray-600" id="marginalTaxText">
352
+ Din marginaleffekt vid löneväxling beräknas baserat på dina parametrar.
353
+ </div>
354
  </div>
355
  </div>
356
 
357
  <div class="mb-8">
358
+ <h3 class="text-xl font-semibold text-gray-800 mb-4">Livscykelvärde över tid</h3>
359
  <div class="h-64">
360
+ <canvas id="lifecycleChart"></canvas>
361
  </div>
362
  </div>
363
 
364
  <div class="mb-8">
365
+ <h3 class="text-xl font-semibold text-gray-800 mb-4">Pensionsutveckling med optimal strategi</h3>
366
  <div class="h-64">
367
+ <canvas id="pensionChart"></canvas>
368
  </div>
369
  </div>
370
 
 
374
  <i class="fas fa-lightbulb text-yellow-500 text-xl"></i>
375
  </div>
376
  <div class="ml-3">
377
+ <h3 class="text-sm font-medium text-yellow-800">Optimeringsstrategi</h3>
378
+ <div class="mt-2 text-sm text-yellow-700" id="strategyTips">
379
+ <p>Systemet beräknar den optimala löneväxlingsnivån baserat dina parametrar och subjektiva värderingar.</p>
380
  </div>
381
  </div>
382
  </div>
383
  </div>
384
 
385
  <div class="bg-gray-50 rounded-lg p-4 border border-gray-200">
386
+ <h3 class="text-lg font-medium text-gray-800 mb-3">Livscykelanalys</h3>
387
+ <div class="space-y-3 text-sm text-gray-700" id="lifecycleAnalysis">
388
+ <p>Denna optimering tar hänsyn till:</p>
389
+ <ul class="list-disc pl-5 space-y-1">
390
+ <li>Skatteskikt och marginaleffekter av löneväxling</li>
391
+ <li>Din subjektiva värdering av pengar över tid</li>
392
+ <li>Förväntad löneutveckling och livslängd</li>
393
+ <li>Avkastning på pensionssparande</li>
394
+ <li>Önskad reserv vid förväntad dödsålder</li>
395
+ </ul>
396
+ <p>Resultatet visar den strategi som maximerar din upplevda livskvalitet över hela livscykeln.</p>
397
  </div>
398
  </div>
399
  </div>
 
401
  </div>
402
 
403
  <script>
404
+ // Swedish tax brackets for 2023 (simplified)
405
+ const TAX_BRACKETS = [
406
+ { min: 0, max: 509300, rate: 0.0, name: "Ingen skatt" },
407
+ { min: 509300, max: 673400, rate: 0.2, name: "Kommunal skatt" },
408
+ { min: 673400, max: 1018600, rate: 0.5, name: "Statlig skatt" },
409
+ { min: 1018600, max: Infinity, rate: 0.55, name: "Toppskatt" }
410
+ ];
411
+
412
  // Format numbers with spaces as thousand separators
413
  function formatNumber(num) {
414
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
415
  }
416
 
417
+ // Calculate marginal tax rate for a given salary
418
+ function calculateMarginalTax(salary) {
419
+ for (let i = TAX_BRACKETS.length - 1; i >= 0; i--) {
420
+ if (salary > TAX_BRACKETS[i].min) {
421
+ return TAX_BRACKETS[i].rate;
422
+ }
423
+ }
424
+ return 0;
425
+ }
426
+
427
+ // Calculate total tax for a given salary
428
+ function calculateTotalTax(salary) {
429
+ let tax = 0;
430
+ for (const bracket of TAX_BRACKETS) {
431
+ if (salary > bracket.min) {
432
+ const taxableAmount = Math.min(salary, bracket.max) - bracket.min;
433
+ tax += taxableAmount * bracket.rate;
434
+ }
435
+ }
436
+ return tax;
437
  }
438
 
439
  // Calculate employer contributions (simplified)
 
441
  return salary * 0.3142; // Approximate employer contributions in Sweden
442
  }
443
 
444
+ // Calculate compound interest with growing contributions
445
+ function calculateCompoundInterest(principal, annualRate, years, initialMonthlyContribution, contributionGrowthRate) {
446
  let amount = principal;
447
  const monthlyRate = annualRate / 12 / 100;
448
  const months = years * 12;
449
+ let currentContribution = initialMonthlyContribution;
450
 
451
  for (let i = 0; i < months; i++) {
452
+ // Apply annual contribution growth (every 12 months)
453
+ if (i > 0 && i % 12 === 0) {
454
+ currentContribution = currentContribution * (1 + contributionGrowthRate / 100);
455
+ }
456
+
457
+ amount = amount * (1 + monthlyRate) + currentContribution;
458
  }
459
 
460
  return amount;
461
  }
462
 
463
+ // Calculate projected salary with growth
464
+ function calculateProjectedSalary(currentSalary, growthRate, years) {
465
+ return currentSalary * Math.pow(1 + growthRate / 100, years);
466
+ }
467
+
468
+ // Calculate time value multiplier (current to retirement)
469
+ function calculateCurrentValueMultiplier(yearsToRetirement, currentMultiplier) {
470
+ // Linear interpolation from currentMultiplier to 100% at retirement
471
+ return 100 + (currentMultiplier - 100) * (1 - yearsToRetirement / (retirementAge - age));
472
+ }
473
+
474
+ // Calculate time value multiplier (retirement to death)
475
+ function calculateRetirementValueMultiplier(yearsFromRetirement, retirementMultiplier) {
476
+ // Linear interpolation from 100% to retirementMultiplier at death
477
+ return 100 + (retirementMultiplier - 100) * (yearsFromRetirement / (lifeExpectancy - retirementAge));
478
+ }
479
+
480
  // Update all displayed values when inputs change
481
  function updateDisplayValues() {
482
  document.getElementById('salaryValue').textContent = formatNumber(document.getElementById('salary').value);
483
  document.getElementById('ageValue').textContent = document.getElementById('age').value;
484
+ document.getElementById('salaryGrowthValue').textContent = document.getElementById('salaryGrowth').value + '%';
485
  document.getElementById('retirementAgeValue').textContent = document.getElementById('retirementAge').value;
486
+ document.getElementById('lifeExpectancyValue').textContent = document.getElementById('lifeExpectancy').value;
487
+ document.getElementById('currentValueMultiplierValue').textContent = document.getElementById('currentValueMultiplier').value + '%';
488
+ document.getElementById('retirementValueMultiplierValue').textContent = document.getElementById('retirementValueMultiplier').value + '%';
489
+ document.getElementById('endOfLifeReserveValue').textContent = document.getElementById('endOfLifeReserve').value + '%';
490
  document.getElementById('pensionContributionValue').textContent = document.getElementById('pensionContribution').value + '%';
491
  document.getElementById('salaryExchangeValue').textContent = document.getElementById('salaryExchange').value + '%';
492
  document.getElementById('expectedReturnValue').textContent = document.getElementById('expectedReturn').value + '%';
493
+
494
+ updateValueGraphs();
495
+ updateTaxBracketGraph();
496
+ }
497
+
498
+ // Update the value function graphs
499
+ function updateValueGraphs() {
500
+ const currentMultiplier = parseInt(document.getElementById('currentValueMultiplier').value);
501
+ const retirementMultiplier = parseInt(document.getElementById('retirementValueMultiplier').value);
502
+ const age = parseInt(document.getElementById('age').value);
503
+ const retirementAge = parseInt(document.getElementById('retirementAge').value);
504
+ const lifeExpectancy = parseInt(document.getElementById('lifeExpectancy').value);
505
+
506
+ // Current value graph (from now to retirement)
507
+ const currentGraph = document.getElementById('currentValueGraph');
508
+ currentGraph.innerHTML = '<div class="graph-line"></div>';
509
+
510
+ // Add points to show the value decay
511
+ for (let y = age; y <= retirementAge; y++) {
512
+ const yearsToRetirement = retirementAge - y;
513
+ const valuePercent = calculateCurrentValueMultiplier(yearsToRetirement, currentMultiplier);
514
+ const point = document.createElement('div');
515
+ point.style.position = 'absolute';
516
+ point.style.bottom = '0';
517
+ point.style.left = `${((y - age) / (retirementAge - age)) * 100}%`;
518
+ point.style.width = '2px';
519
+ point.style.height = `${Math.min(100, valuePercent)}%`;
520
+ point.style.backgroundColor = '#3b82f6';
521
+ currentGraph.appendChild(point);
522
+ }
523
+
524
+ // Retirement value graph (from retirement to death)
525
+ const retirementGraph = document.getElementById('retirementValueGraph');
526
+ retirementGraph.innerHTML = '<div class="graph-line"></div>';
527
+
528
+ // Add points to show the value decay
529
+ for (let y = retirementAge; y <= lifeExpectancy; y++) {
530
+ const yearsFromRetirement = y - retirementAge;
531
+ const valuePercent = calculateRetirementValueMultiplier(yearsFromRetirement, retirementMultiplier);
532
+ const point = document.createElement('div');
533
+ point.style.position = 'absolute';
534
+ point.style.bottom = '0';
535
+ point.style.left = `${((y - retirementAge) / (lifeExpectancy - retirementAge)) * 100}%`;
536
+ point.style.width = '2px';
537
+ point.style.height = `${Math.min(100, valuePercent)}%`;
538
+ point.style.backgroundColor = '#3b82f6';
539
+ retirementGraph.appendChild(point);
540
+ }
541
+ }
542
+
543
+ // Update the tax bracket graph
544
+ function updateTaxBracketGraph() {
545
+ const salary = parseInt(document.getElementById('salary').value) * 12; // Annual salary
546
+ const graph = document.getElementById('taxBracketGraph');
547
+ graph.innerHTML = '<div class="graph-line"></div>';
548
+
549
+ // Find the maximum bracket that applies to our salary
550
+ let maxBracket = 0;
551
+ for (const bracket of TAX_BRACKETS) {
552
+ if (salary > bracket.min) {
553
+ maxBracket = Math.max(maxBracket, bracket.max);
554
+ }
555
+ }
556
+
557
+ // Add tax brackets to the graph
558
+ for (const bracket of TAX_BRACKETS) {
559
+ if (bracket.max > maxBracket * 1.5) continue; // Don't show brackets far beyond our salary
560
+
561
+ const bracketDiv = document.createElement('div');
562
+ bracketDiv.className = 'tax-bracket';
563
+ bracketDiv.style.left = `${(bracket.min / (maxBracket * 1.5)) * 100}%`;
564
+ bracketDiv.style.width = `${((bracket.max - bracket.min) / (maxBracket * 1.5)) * 100}%`;
565
+ graph.appendChild(bracketDiv);
566
+
567
+ const label = document.createElement('div');
568
+ label.className = 'tax-bracket-label';
569
+ label.textContent = `${bracket.name} (${bracket.rate * 100}%)`;
570
+ label.style.left = `${(bracket.min / (maxBracket * 1.5)) * 100}%`;
571
+ graph.appendChild(label);
572
+ }
573
+
574
+ // Add current salary marker
575
+ const marker = document.createElement('div');
576
+ marker.style.position = 'absolute';
577
+ marker.style.bottom = '0';
578
+ marker.style.left = `${(salary / (maxBracket * 1.5)) * 100}%`;
579
+ marker.style.width = '2px';
580
+ marker.style.height = '100%';
581
+ marker.style.backgroundColor = '#ef4444';
582
+ graph.appendChild(marker);
583
+
584
+ const markerLabel = document.createElement('div');
585
+ markerLabel.className = 'tax-bracket-label';
586
+ markerLabel.textContent = `Din lön: ${formatNumber(salary)} kr`;
587
+ markerLabel.style.left = `${(salary / (maxBracket * 1.5)) * 100}%`;
588
+ markerLabel.style.color = '#ef4444';
589
+ graph.appendChild(markerLabel);
590
+
591
+ // Update marginal tax text
592
+ const marginalTax = calculateMarginalTax(salary) * 100;
593
+ document.getElementById('marginalTaxText').innerHTML = `
594
+ Din nuvarande årslön: <strong>${formatNumber(salary)} kr</strong><br>
595
+ Marginaltaxesats: <strong>${marginalTax}%</strong><br>
596
+ Löneväxling kan spara <strong>${marginalTax + 31.42}%</strong> (skatt + arbetsgivaravgifter)
597
+ `;
598
  }
599
 
600
  // Initialize charts
601
+ let lifecycleChart;
602
+ let pensionChart;
603
 
604
  function initCharts() {
605
+ const lifecycleCtx = document.getElementById('lifecycleChart').getContext('2d');
606
+ lifecycleChart = new Chart(lifecycleCtx, {
607
+ type: 'line',
608
  data: {
609
+ labels: [],
610
+ datasets: [
611
+ {
612
+ label: 'Upplevt värde över tid',
613
+ data: [],
614
+ borderColor: '#8b5cf6',
615
+ backgroundColor: 'rgba(139, 92, 246, 0.1)',
616
+ borderWidth: 3,
617
+ fill: true,
618
+ tension: 0.3
619
+ }
620
+ ]
621
  },
622
  options: {
623
  responsive: true,
624
  maintainAspectRatio: false,
625
  plugins: {
 
 
 
626
  tooltip: {
627
  callbacks: {
628
  label: function(context) {
629
+ return context.dataset.label + ': ' + context.raw.toFixed(2);
 
 
 
 
 
630
  }
631
  }
632
  }
633
+ },
634
+ scales: {
635
+ y: {
636
+ title: {
637
+ display: true,
638
+ text: 'Relativt värde'
639
+ }
640
+ },
641
+ x: {
642
+ title: {
643
+ display: true,
644
+ text: 'Ålder'
645
+ }
646
+ }
647
  }
648
  }
649
  });
650
 
651
+ const pensionCtx = document.getElementById('pensionChart').getContext('2d');
652
+ pensionChart = new Chart(pensionCtx, {
653
+ type: 'bar',
654
  data: {
655
+ labels: ['Arbetsgivaravgifter sparade', 'Skatt sparad', 'Pensionsavsättning'],
656
+ datasets: [{
657
+ data: [0, 0, 0],
658
+ backgroundColor: [
659
+ '#3b82f6',
660
+ '#10b981',
661
+ '#f59e0b'
662
+ ],
663
+ borderWidth: 1
664
+ }]
 
 
 
 
 
 
 
 
 
 
 
 
665
  },
666
  options: {
667
  responsive: true,
668
  maintainAspectRatio: false,
669
  plugins: {
670
+ legend: {
671
+ display: false
672
+ },
673
  tooltip: {
674
  callbacks: {
675
  label: function(context) {
676
+ return context.label + ': ' + formatNumber(context.raw) + ' kr';
 
 
 
 
 
677
  }
678
  }
679
  }
 
692
  });
693
  }
694
 
695
+ // Calculate the optimal salary exchange percentage
696
+ function calculateOptimalStrategy() {
697
  // Get input values
698
  const salary = parseInt(document.getElementById('salary').value);
699
+ const salaryGrowth = parseFloat(document.getElementById('salaryGrowth').value);
700
  const age = parseInt(document.getElementById('age').value);
701
  const retirementAge = parseInt(document.getElementById('retirementAge').value);
702
+ const lifeExpectancy = parseInt(document.getElementById('lifeExpectancy').value);
703
+ const currentMultiplier = parseInt(document.getElementById('currentValueMultiplier').value) / 100;
704
+ const retirementMultiplier = parseInt(document.getElementById('retirementValueMultiplier').value) / 100;
705
+ const endOfLifeReserve = parseInt(document.getElementById('endOfLifeReserve').value) / 100;
706
+ const pensionContribution = parseFloat(document.getElementById('pensionContribution').value) / 100;
707
  const expectedReturn = parseFloat(document.getElementById('expectedReturn').value);
708
 
709
+ // Calculate years to retirement and retirement duration
710
  const yearsToRetirement = retirementAge - age;
711
+ const retirementDuration = lifeExpectancy - retirementAge;
712
 
713
+ // Test different salary exchange percentages to find the optimal one
714
+ let maxValue = -Infinity;
715
+ let optimalExchange = 0;
716
+ let optimalPension = 0;
717
+ let optimalValues = [];
 
 
 
718
 
719
+ for (let exchange = 0; exchange <= 100; exchange += 5) {
720
+ // Calculate pension growth with this exchange percentage
721
+ const totalPensionContribution = salary * pensionContribution;
722
+ const exchangedAmount = totalPensionContribution * (exchange / 100);
723
+ const regularPensionContribution = totalPensionContribution - exchangedAmount;
724
+
725
+ // Calculate tax savings from salary exchange
726
+ const taxRate = calculateTotalTax(salary) / salary;
727
+ const marginalTaxRate = calculateMarginalTax(salary * 12) / 100;
728
+ const employerContributionRate = 0.3142;
729
+
730
+ const taxSaved = exchangedAmount * marginalTaxRate;
731
+ const employerContributionsSaved = exchangedAmount * employerContributionRate;
732
+ const totalSavings = taxSaved + employerContributionsSaved;
733
+
734
+ // Calculate net salary
735
+ const taxWithoutExchange = calculateTotalTax(salary);
736
+ const taxWithExchange = calculateTotalTax(salary - exchangedAmount);
737
+ const netSalaryWithoutExchange = salary - taxWithoutExchange;
738
+ const netSalaryWithExchange = (salary - exchangedAmount) - taxWithExchange;
739
+
740
+ // Calculate pension growth with salary growth
741
+ const monthlyContributionWithExchange = (regularPensionContribution + exchangedAmount + totalSavings) / 12;
742
+ const monthlyContributionWithoutExchange = (regularPensionContribution + (exchangedAmount * (1 - marginalTaxRate))) / 12;
743
+
744
+ const pensionWithExchange = calculateCompoundInterest(0, expectedReturn, yearsToRetirement, monthlyContributionWithExchange, salaryGrowth);
745
+ const pensionWithoutExchange = calculateCompoundInterest(0, expectedReturn, yearsToRetirement, monthlyContributionWithoutExchange, salaryGrowth);
746
+
747
+ // Calculate perceived value over lifecycle
748
+ let totalValue = 0;
749
+ const yearlyValues = [];
750
+
751
+ // Working years (current to retirement)
752
+ for (let year = 0; year < yearsToRetirement; year++) {
753
+ const currentAge = age + year;
754
+ const yearsRemaining = yearsToRetirement - year;
755
+
756
+ // Calculate salary at this year
757
+ const yearSalary = calculateProjectedSalary(salary, salaryGrowth, year);
758
+ const yearExchangedAmount = yearSalary * pensionContribution * (exchange / 100);
759
+ const yearTaxWithExchange = calculateTotalTax(yearSalary - yearExchangedAmount);
760
+ const yearNetSalary = (yearSalary - yearExchangedAmount) - yearTaxWithExchange;
761
+
762
+ // Calculate value multiplier for this year
763
+ const valueMultiplier = 1 + (currentMultiplier - 1) * (yearsRemaining / yearsToRetirement);
764
+
765
+ // Add to total value
766
+ const yearValue = yearNetSalary * valueMultiplier;
767
+ totalValue += yearValue;
768
+ yearlyValues.push({
769
+ age: currentAge,
770
+ value: yearValue,
771
+ type: 'working'
772
+ });
773
+ }
774
+
775
+ // Retirement years (retirement to death)
776
+ const annualPensionWithdrawal = (pensionWithExchange * (1 - endOfLifeReserve)) / retirementDuration;
777
+ let remainingPension = pensionWithExchange;
778
+
779
+ for (let year = 0; year < retirementDuration; year++) {
780
+ const currentAge = retirementAge + year;
781
+
782
+ // Calculate pension withdrawal for this year
783
+ const withdrawal = Math.min(annualPensionWithdrawal, remainingPension);
784
+ remainingPension -= withdrawal;
785
+
786
+ // Calculate value multiplier for this year
787
+ const valueMultiplier = 1 + (retirementMultiplier - 1) * (year / retirementDuration);
788
+
789
+ // Add to total value
790
+ const yearValue = withdrawal * valueMultiplier;
791
+ totalValue += yearValue;
792
+ yearlyValues.push({
793
+ age: currentAge,
794
+ value: yearValue,
795
+ type: 'retirement'
796
+ });
797
+ }
798
+
799
+ // Add remaining pension at death (if any)
800
+ if (remainingPension > 0) {
801
+ totalValue += remainingPension * retirementMultiplier;
802
+ yearlyValues.push({
803
+ age: lifeExpectancy,
804
+ value: remainingPension * retirementMultiplier,
805
+ type: 'reserve'
806
+ });
807
+ }
808
+
809
+ // Check if this is the best strategy so far
810
+ if (totalValue > maxValue) {
811
+ maxValue = totalValue;
812
+ optimalExchange = exchange;
813
+ optimalPension = pensionWithExchange;
814
+ optimalValues = yearlyValues;
815
+ }
816
+ }
817
 
818
+ // Update results display
819
+ document.getElementById('optimalExchange').textContent = optimalExchange + '%';
820
+ document.getElementById('maxValue').textContent = formatNumber(Math.round(maxValue / 1000)) + 'k';
821
+ document.getElementById('totalPension').textContent = formatNumber(Math.round(optimalPension)) + ' kr';
822
 
823
+ // Update lifecycle chart
824
+ const ages = optimalValues.map(v => v.age);
825
+ const values = optimalValues.map(v => v.value / 1000); // Scale down for chart
826
+ lifecycleChart.data.labels = ages;
827
+ lifecycleChart.data.datasets[0].data = values;
828
+ lifecycleChart.update();
829
 
830
+ // Update pension chart with optimal exchange details
831
+ const salaryInput = parseInt(document.getElementById('salary').value);
832
+ const pensionContributionInput = parseFloat(document.getElementById('pensionContribution').value) / 100;
833
+ const exchangedAmount = salaryInput * pensionContributionInput * (optimalExchange / 100);
834
+ const taxSaved = exchangedAmount * calculateMarginalTax(salaryInput * 12) / 100;
835
+ const employerContributionsSaved = exchangedAmount * 0.3142;
 
 
 
 
 
836
 
837
+ pensionChart.data.datasets[0].data = [
838
+ Math.round(employerContributionsSaved * 12),
839
+ Math.round(taxSaved * 12),
840
+ Math.round((salaryInput * pensionContributionInput - exchangedAmount + exchangedAmount + taxSaved + employerContributionsSaved) * 12)
841
+ ];
842
+ pensionChart.update();
843
 
844
+ // Update strategy tips
845
+ let tips = '';
846
+ if (optimalExchange === 0) {
847
+ tips = 'Baserat dina parametrar är ingen löneväxling optimal. Detta kan bero på:';
848
+ tips += '<ul class="list-disc pl-5 mt-1">';
849
+ tips += '<li>Låg marginaltaxesats</li>';
850
+ tips += '<li>Hög värdering av nuvarande inkomst</li>';
851
+ tips += '<li>Lång tid till pension</li>';
852
+ tips += '</ul>';
853
+ } else if (optimalExchange < 50) {
854
+ tips = 'En del löneväxling (' + optimalExchange + '%) är optimal. Detta balanserar:';
855
+ tips += '<ul class="list-disc pl-5 mt-1">';
856
+ tips += '<li>Skattesparande nu</li>';
857
+ tips += '<li>Framtida pensionsinkomst</li>';
858
+ tips += '<li>Din subjektiva värdering av pengar över tid</li>';
859
+ tips += '</ul>';
860
+ } else if (optimalExchange < 100) {
861
+ tips = 'Hög löneväxling (' + optimalExchange + '%) är optimal. Detta tyder på:';
862
+ tips += '<ul class="list-disc pl-5 mt-1">';
863
+ tips += '<li>Hög marginaltaxesats</li>';
864
+ tips += '<li>Relativt låg värdering av nuvarande inkomst</li>';
865
+ tips += '<li>Fördelaktig pensionsavkastning</li>';
866
+ tips += '</ul>';
867
  } else {
868
+ tips = 'Full löneväxling (100%) är optimal. Detta är typiskt när:';
869
+ tips += '<ul class="list-disc pl-5 mt-1">';
870
+ tips += '<li>Mycket hög marginaltaxesats</li>';
871
+ tips += '<li>Låg värdering av nuvarande inkomst</li>';
872
+ tips += '<li>Kort tid till pension</li>';
873
+ tips += '</ul>';
874
  }
875
 
876
+ // Add specific recommendations based on parameters
877
+ if (yearsToRetirement < 10) {
878
+ tips += '<p class="mt-2">Med mindre än 10 år till pension kan löneväxling vara särskilt fördelaktigt.</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
  }
880
 
881
+ if (calculateMarginalTax(salary * 12) > 0.5) {
882
+ tips += '<p class="mt-2">Din höga marginaltaxesats gör löneväxling extra attraktiv.</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
883
  }
884
 
885
+ if (currentMultiplier < 2) {
886
+ tips += '<p class="mt-2">Din relativt låga värdering av nuvarande inkomst gör pensionssparande mer attraktivt.</p>';
 
 
887
  }
888
 
889
+ document.getElementById('strategyTips').innerHTML = tips;
890
 
891
  // Add animation classes
892
+ document.getElementById('optimalExchange').classList.add('animate-grow');
893
+ document.getElementById('maxValue').classList.add('animate-grow');
894
  document.getElementById('totalPension').classList.add('animate-grow');
 
895
 
896
  // Remove animation classes after animation completes
897
  setTimeout(() => {
898
+ document.getElementById('optimalExchange').classList.remove('animate-grow');
899
+ document.getElementById('maxValue').classList.remove('animate-grow');
900
  document.getElementById('totalPension').classList.remove('animate-grow');
901
  }, 1500);
902
  }
 
912
 
913
  // Set up calculate button
914
  document.getElementById('calculateBtn').addEventListener('click', function() {
915
+ calculateOptimalStrategy();
916
  });
917
 
918
  // Initialize display values and charts
 
920
  initCharts();
921
 
922
  // Calculate initial results
923
+ calculateOptimalStrategy();
924
  });
925
  </script>
926
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Jausing/misc-stuff" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
prompts.txt CHANGED
@@ -0,0 +1,2 @@
 
 
 
1
+ Addera förväntad löneutveckling, tack
2
+ Alltså det är ett lite komplicerat optimeringsproblem... Hårda parametrar är följande Nuvarande lön Nuvarande ålder Semi-flexibla parametrar är följande (parametrar du har en viss kontroll över, men kanske inte till 100%) Förväntad löneutveckling per år Pensionsålder Förväntad dödsålder Subjektivt avtagande funktion som sätter värdet på pengar idag kontra efter pensionsålder. Ponera exempelvis att du värderar samma inflationsjusterade summa pengar till 300% av hur du värderar pengarna efter pensionsålder idag, men dagen innan pensionen ska ju motsvarande tal vara typ 100.001% Subjektivt avtagande funktion som sätter värdet på pengar från pensionsålder till förväntad dödsålder. Notera att du troligtvis inte har värdet 0 vid din förväntade dödsålder, eftersom du vill ha lite pengar kvar om du skulle leva längre, men du kan ju också ha en "die with zero, aktiv dödshjälp om pengarna tar slut"-strategi Vi vill ju maximera perceived value för pengarna över tid. Målfunktionen måste också ha med de olika skatte-skikten osv för att det ska bli rätt