175175 position : relative;
176176 }
177177
178+ .input-group .calculated .calculated-input : hover + .input-tooltip {
179+ visibility : visible;
180+ opacity : 1 ;
181+ }
182+
183+ .input-tooltip {
184+ visibility : hidden;
185+ background-color : # 333 ;
186+ color : # fff ;
187+ text-align : left;
188+ border-radius : 6px ;
189+ padding : 8px ;
190+ position : absolute;
191+ z-index : 1000 ;
192+ bottom : 125% ;
193+ left : 50% ;
194+ transform : translateX (-50% );
195+ opacity : 0 ;
196+ transition : opacity 0.3s ;
197+ max-width : 400px ;
198+ min-width : 250px ;
199+ font-size : 13px ;
200+ pointer-events : none;
201+ white-space : normal;
202+ word-wrap : break-word;
203+ line-height : 1.3 ;
204+ }
205+
178206 .input-group label .calculated-label {
179207 color : # 555 ;
180208 font-style : italic;
@@ -282,6 +310,7 @@ <h2>Fixed Variables</h2>
282310 < div class ="form-row "> < label for ="prepaymentPenalty "> Prepayment Penalty (% of remaining loan)</ label > < input type ="number " id ="prepaymentPenalty " step ="0.01 " value ="1.0 "> </ div >
283311 < div class ="form-row "> < label for ="registrationTax "> Registration Tax (% of house price)</ label > < input type ="number " id ="registrationTax " step ="0.01 " value ="6.0 "> </ div >
284312 < div class ="form-row "> < label for ="maintenanceCosts "> Maintenance Costs (% of house price/year)</ label > < input type ="number " id ="maintenanceCosts " step ="0.01 " value ="1.0 "> </ div >
313+ < div class ="form-row "> < label for ="simulationYears "> Simulation Years</ label > < input type ="number " id ="simulationYears " min ="1 " max ="50 " value ="30 "> </ div >
285314 </ form >
286315 </ aside >
287316 < main style ="flex: 1; ">
@@ -368,10 +397,6 @@ <h3>Stocks and Bonds</h3>
368397 </section>
369398 <section class="strategy-section simulation">
370399 <h3>Simulation Table</h3>
371- <div class="simulation-controls">
372- <label for="simulationYears${ idx } ">Years to simulate:</label>
373- <input type="number" id="simulationYears${ idx } " min="1" max="50" value="30" style="width: 60px; margin-left: 8px;">
374- </div>
375400 <div id="strategyTable${ idx } " class="section-content"></div>
376401 </section>
377402 </div>
@@ -409,16 +434,6 @@ <h3>Simulation Table</h3>
409434 renderVerticalTabContent ( idx , selectedTab ) ;
410435 updateStrategyInputs ( idx ) ;
411436 runStrategySimulation ( idx , true ) ; // Skip individual graph updates during init
412-
413- // Add event listener for simulation years input
414- const simulationYearsInput = document . getElementById ( `simulationYears${ idx } ` ) ;
415- if ( simulationYearsInput ) {
416- simulationYearsInput . addEventListener ( 'input' , ( ) => {
417- console . log ( '📝 Simulation years changed for idx:' , idx ) ;
418- runStrategySimulation ( idx ) ;
419- updateNetWorthGraph ( ) ;
420- } ) ;
421- }
422437}
423438
424439function renderStrategyTab ( idx ) {
@@ -482,13 +497,19 @@ <h3>Simulation Table</h3>
482497 </div>
483498 <div class="input-group calculated">
484499 <label class="calculated-label">Registration Costs (€)</label>
485- <input type="number" name="registrationCosts" value="24000" readonly class="calculated-input">
500+ <div style="position: relative;">
501+ <input type="number" name="registrationCosts" value="24000" readonly class="calculated-input">
502+ <span class="input-tooltip">Registration Costs = House Price × Registration Tax Rate</span>
503+ </div>
486504 <span class="calculated-note">(calculated)</span>
487505 <span class="tooltip">Registration Costs = House Price × Registration Tax Rate</span>
488506 </div>
489507 <div class="input-group calculated">
490508 <label class="calculated-label">Loan Balance at t=0 (€)</label>
491- <input type="number" name="loanBalance" value="324000" readonly class="calculated-input">
509+ <div style="position: relative;">
510+ <input type="number" name="loanBalance" value="324000" readonly class="calculated-input">
511+ <span class="input-tooltip">Loan Balance = House Price - Initial Deposit + Registration Costs</span>
512+ </div>
492513 <span class="calculated-note">(calculated)</span>
493514 <span class="tooltip">Loan Balance = House Price - Initial Deposit + Registration Costs</span>
494515 </div>
@@ -498,13 +519,19 @@ <h3>Simulation Table</h3>
498519 </div>
499520 <div class="input-group calculated">
500521 <label class="calculated-label">Monthly Loan Payment (€)</label>
501- <input type="number" name="monthlyRE" value="1200" readonly class="calculated-input">
522+ <div style="position: relative;">
523+ <input type="number" name="monthlyRE" value="1200" readonly class="calculated-input">
524+ <span class="input-tooltip">Monthly Payment = (Loan Balance × Monthly Interest Rate) / (1 - (1 + Monthly Interest Rate)^(-Loan Term × 12))</span>
525+ </div>
502526 <span class="calculated-note">(calculated)</span>
503527 <span class="tooltip">Monthly Payment = (Loan Balance × Monthly Interest Rate) / (1 - (1 + Monthly Interest Rate)^(-Loan Term × 12))</span>
504528 </div>
505529 <div class="input-group calculated">
506530 <label class="calculated-label">Monthly Maintenance (€)</label>
507- <input type="number" name="monthlyMaintenance" value="333" readonly class="calculated-input">
531+ <div style="position: relative;">
532+ <input type="number" name="monthlyMaintenance" value="333" readonly class="calculated-input">
533+ <span class="input-tooltip">Monthly Maintenance = House Price × Maintenance Rate / 12</span>
534+ </div>
508535 <span class="calculated-note">(calculated)</span>
509536 <span class="tooltip">Monthly Maintenance = House Price × Maintenance Rate / 12</span>
510537 </div>
@@ -582,24 +609,40 @@ <h3>Simulation Table</h3>
582609
583610 // Update tooltips with actual values
584611 const registrationTooltip = form . querySelector ( '[name="registrationCosts"]' ) . parentElement . querySelector ( '.tooltip' ) ;
612+ const registrationInputTooltip = form . querySelector ( '[name="registrationCosts"]' ) . nextElementSibling ;
585613 if ( registrationTooltip ) {
586614 registrationTooltip . textContent = `Registration Costs = House Price (€${ housePrice . toLocaleString ( ) } ) × Registration Tax Rate (${ registrationTaxRate } %)` ;
587615 }
616+ if ( registrationInputTooltip ) {
617+ registrationInputTooltip . textContent = `Registration Costs = House Price (€${ housePrice . toLocaleString ( ) } ) × Registration Tax Rate (${ registrationTaxRate } %)` ;
618+ }
588619
589- const loanBalanceTooltip = form . querySelector ( '[name="loanBalance"]' ) . parentElement . querySelector ( '.tooltip' ) ;
620+ const loanBalanceTooltip = form . querySelector ( '[name="loanBalance"]' ) . parentElement . parentElement . querySelector ( '.tooltip' ) ;
621+ const loanBalanceInputTooltip = form . querySelector ( '[name="loanBalance"]' ) . nextElementSibling ;
590622 if ( loanBalanceTooltip ) {
591623 loanBalanceTooltip . textContent = `Loan Balance = House Price (€${ housePrice . toLocaleString ( ) } ) - Initial Deposit (€${ initialDeposit . toLocaleString ( ) } ) + Registration Costs (€${ registrationCosts . toLocaleString ( ) } )` ;
592624 }
625+ if ( loanBalanceInputTooltip ) {
626+ loanBalanceInputTooltip . textContent = `Loan Balance = House Price (€${ housePrice . toLocaleString ( ) } ) - Initial Deposit (€${ initialDeposit . toLocaleString ( ) } ) + Registration Costs (€${ registrationCosts . toLocaleString ( ) } )` ;
627+ }
593628
594- const monthlyRETooltip = form . querySelector ( '[name="monthlyRE"]' ) . parentElement . querySelector ( '.tooltip' ) ;
629+ const monthlyRETooltip = form . querySelector ( '[name="monthlyRE"]' ) . parentElement . parentElement . querySelector ( '.tooltip' ) ;
630+ const monthlyREInputTooltip = form . querySelector ( '[name="monthlyRE"]' ) . nextElementSibling ;
595631 if ( monthlyRETooltip ) {
596632 monthlyRETooltip . textContent = `Monthly Payment = Loan Balance (€${ loanBalance . toLocaleString ( ) } ) × Monthly Interest Rate (${ ( monthlyLoanRate * 100 ) . toFixed ( 3 ) } %) / (1 - (1 + Monthly Interest Rate)^(-Loan Term (${ loanTerm } ) × 12))` ;
597633 }
634+ if ( monthlyREInputTooltip ) {
635+ monthlyREInputTooltip . textContent = `Monthly Payment = Loan Balance (€${ loanBalance . toLocaleString ( ) } ) × Monthly Interest Rate (${ ( monthlyLoanRate * 100 ) . toFixed ( 3 ) } %) / (1 - (1 + Monthly Interest Rate)^(-Loan Term (${ loanTerm } ) × 12))` ;
636+ }
598637
599- const maintenanceTooltip = form . querySelector ( '[name="monthlyMaintenance"]' ) . parentElement . querySelector ( '.tooltip' ) ;
638+ const maintenanceTooltip = form . querySelector ( '[name="monthlyMaintenance"]' ) . parentElement . parentElement . querySelector ( '.tooltip' ) ;
639+ const maintenanceInputTooltip = form . querySelector ( '[name="monthlyMaintenance"]' ) . nextElementSibling ;
600640 if ( maintenanceTooltip ) {
601641 maintenanceTooltip . textContent = `Monthly Maintenance = House Price (€${ housePrice . toLocaleString ( ) } ) × Maintenance Rate (${ maintenanceRate } %) / 12` ;
602642 }
643+ if ( maintenanceInputTooltip ) {
644+ maintenanceInputTooltip . textContent = `Monthly Maintenance = House Price (€${ housePrice . toLocaleString ( ) } ) × Maintenance Rate (${ maintenanceRate } %) / 12` ;
645+ }
603646
604647 // Validate initial deposit against cash at hand
605648 if ( initialDeposit > fixed . cashAtHand ) {
@@ -694,11 +737,19 @@ <h3>Simulation Table</h3>
694737 const fixedForm = document . getElementById ( 'fixedVarsForm' ) ;
695738 Array . from ( fixedForm . elements ) . forEach ( el => {
696739 el . addEventListener ( 'input' , ( ) => {
697- // Re-render current tab and update graph
698- const activeIdx = [ ...document . querySelectorAll ( '.tab-buttons button' ) ]
699- . findIndex ( btn => btn . classList . contains ( 'active' ) ) ;
700- renderStrategyTab ( activeIdx ) ;
701- updateNetWorthGraph ( ) ;
740+ if ( el . id === 'simulationYears' ) {
741+ // When simulation years change, update all strategies
742+ strategies . forEach ( ( _ , idx ) => {
743+ runStrategySimulation ( idx , true ) ;
744+ } ) ;
745+ updateNetWorthGraph ( ) ;
746+ } else {
747+ // Re-render current tab and update graph for other fixed variables
748+ const activeIdx = [ ...document . querySelectorAll ( '.tab-buttons button' ) ]
749+ . findIndex ( btn => btn . classList . contains ( 'active' ) ) ;
750+ renderStrategyTab ( activeIdx ) ;
751+ updateNetWorthGraph ( ) ;
752+ }
702753 } ) ;
703754 } ) ;
704755}
@@ -774,9 +825,8 @@ <h3>Simulation Table</h3>
774825}
775826
776827function simulateStrategy ( fixed , housePrice , initialDeposit , loanTerm , monthlyRE , monthlyRemainder , stocks , bonds , strategyIdx ) {
777- // Get simulation years from the input field, default to 30 if not found
778- const simulationYearsInput = document . getElementById ( `simulationYears${ strategyIdx } ` ) ;
779- const simulationYears = simulationYearsInput ? + simulationYearsInput . value : 30 ;
828+ // Get simulation years from the central input field
829+ const simulationYears = + document . getElementById ( 'simulationYears' ) . value ;
780830 let rows = [ ] ;
781831
782832 // Initial setup
0 commit comments