地产

<body>

    <div class="calculator-card">
        <!-- Banner Image -->
        <img src="Banner - White.jpg" alt="Agent Banner" class="banner-img" onerror="this.style.display='none'" style="display: none;">

        <div class="card-content-wrapper">
            <header>
                <h1>Real Estate Investment Analyzer</h1>
                <p style="color:var(--text-sub); margin-top:0.5rem">Ontario, Canada</p>
            </header>

            <div class="layout-grid">
                
                <!-- 1. Mortgage Section -->
                <div class="section-box">
                    <div class="section-header">
                        <h2>1. Mortgage &amp; Investment</h2>
                    </div>
                    <div class="section-content">
                        <!-- Row 1: Price & Down Payment % -->
                        <div class="mortgage-grid-inner">
                            <div class="input-group">
                                <label>Property Price</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <!-- Changed to type="text" for formatting -->
                                    <input type="text" inputmode="decimal" id="price" value="800,000" style="padding-left: 1.8rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Down Payment</label>
                                <div class="input-wrapper">
                                    <input type="number" id="down-payment" value="20">
                                    <span class="suffix">%</span>
                                </div>
                            </div>
                        </div>

                        <!-- Row 2: Calculated Down Payment $ & Loan Amount (New) -->
                        <div class="mortgage-grid-inner">
                            <div class="input-group">
                                <label>Down Payment Amount</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" id="down-payment-amt" readonly="" style="padding-left: 1.8rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Loan Amount</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" id="loan-amount" readonly="" style="padding-left: 1.8rem;">
                                </div>
                            </div>
                        </div>

                        <!-- Row 3: Closing Costs & Appreciation -->
                        <div class="mortgage-grid-inner">
                            <div class="input-group">
                                <label>Closing Costs</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" inputmode="decimal" id="closing-costs" value="15,000" style="padding-left: 1.8rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Annual Appreciation</label>
                                <div class="input-wrapper">
                                    <input type="number" id="appreciation" value="3.0" step="0.1">
                                    <span class="suffix">%</span>
                                </div>
                            </div>
                        </div>

                        <!-- Row 4: Rate & Amortization -->
                        <div class="mortgage-grid-inner">
                            <div class="input-group">
                                <label>Interest Rate</label>
                                <div class="input-wrapper">
                                    <input type="number" id="rate" value="5.0" step="0.01">
                                    <span class="suffix">%</span>
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Amortization</label>
                                <select id="amortization">
                                    <option value="25" selected="">25 Years</option>
                                    <option value="30">30 Years</option>
                                </select>
                            </div>
                        </div>

                        <div class="result-highlight">
                            <label>Est. Monthly Payment</label>
                            <span id="monthly-mortgage-display" class="value-display">$3,722.27</span>
                        </div>
                    </div>
                </div>

                <!-- 2. Rental Income Section -->
                <div class="section-box">
                    <div class="section-header">
                        <h2>2. Rental Income</h2>
                    </div>
                    <div class="section-content">
                        <div class="input-group">
                            <label>Unit 1 Rent</label>
                            <div class="input-wrapper">
                                <span style="position:absolute; left:1rem; color:var(--text-sub);">$</span>
                                <input type="text" inputmode="decimal" id="rent-unit-1" value="2,500" style="padding-left: 2rem;">
                            </div>
                        </div>
                        <div class="input-group">
                            <label>Unit 2 Rent</label>
                            <div class="input-wrapper">
                                <span style="position:absolute; left:1rem; color:var(--text-sub);">$</span>
                                <input type="text" inputmode="decimal" id="rent-unit-2" value="1,800" style="padding-left: 2rem;">
                            </div>
                        </div>

                        <div class="result-highlight" style="background-color: #ecfdf5; border-color: #d1fae5;">
                            <label style="color: #047857;">Total Monthly Income</label>
                            <span id="total-rental-income" class="value-display" style="color: #047857;">$4,300.00</span>
                        </div>
                    </div>
                </div>

                <!-- 3. Operating Expenses Section -->
                <div class="section-box">
                    <div class="section-header">
                        <h2>3. Monthly Expenses</h2>
                    </div>
                    <div class="section-content">
                        <div class="expenses-grid">
                            <div class="input-group">
                                <label>Tax</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" inputmode="decimal" id="exp-tax" value="450" style="padding-left: 1.5rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Utilities</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" inputmode="decimal" id="exp-util" value="300" style="padding-left: 1.5rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Insurance</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" inputmode="decimal" id="exp-ins" value="120" style="padding-left: 1.5rem;">
                                </div>
                            </div>
                            <div class="input-group">
                                <label>Maint.</label>
                                <div class="input-wrapper">
                                    <span style="position:absolute; left:0.8rem; color:var(--text-sub);">$</span>
                                    <input type="text" inputmode="decimal" id="exp-maint" value="200" style="padding-left: 1.5rem;">
                                </div>
                            </div>
                        </div>
                        <div class="input-group">
                            <label>Property Management</label>
                            <div class="input-wrapper">
                                <span style="position:absolute; left:1rem; color:var(--text-sub);">$</span>
                                <input type="text" inputmode="decimal" id="exp-mgmt" value="0" style="padding-left: 2rem;">
                            </div>
                        </div>

                        <div class="result-highlight" style="background-color: #fff1f2; border-color: #ffe4e6;">
                            <label style="color: #be123c;">Total Monthly Expenses</label>
                            <span id="total-expenses" class="value-display" style="color: #be123c;">$1,070.00</span>
                        </div>
                    </div>
                </div>

                <!-- 4. Analysis Section -->
                <div class="section-box">
                    <div class="section-header">
                        <h2>4. Analysis</h2>
                    </div>
                    <div class="section-content">
                        <div class="analysis-grid">
                            <div class="analysis-card dark">
                                <h3 id="cash-flow-result" style="color: rgb(248, 113, 113);">-$492.27</h3>
                                <p>Monthly Cash Flow</p>
                                <span class="sub-text">(Net Income)</span>
                            </div>

                            <div class="analysis-card blue">
                                <h3 id="coc-result">-3.4%</h3>
                                <p>Cash on Cash</p>
                                <span class="sub-text">(Annual Cash Flow / Invested)</span>
                            </div>

                            <div class="analysis-card white">
                                <h3 id="total-return-result" style="color: var(--primary);">$615.60</h3>
                                <p>Monthly Total Return</p>
                                <span class="sub-text">(Cash Flow + Principal)</span>
                            </div>

                            <div class="analysis-card accent">
                                <h3 id="roi-result">89.4%</h3>
                                <p>5-Year Total ROI</p>
                                <span class="sub-text">(Total Gain / Invested)</span>
                            </div>
                        </div>
                    </div>
                </div>

            </div> <!-- End Grid -->

            <!-- Table Section -->
            <div class="table-container">
                <h4 style="margin-top:0; margin-bottom:1rem; color:var(--primary);">5-Year Projection</h4>
                <table>
                    <thead>
                        <tr>
                            <th>Year</th>
                            <th>Annual Interest</th>
                            <th>Total Principal Paid</th>
                            <th>Balance Remaining</th>
                        </tr>
                    </thead>
                    <tbody id="projection-body"><tr>
                        <td style="font-weight:600">Year 1</td>
                        <td style="color:#ef4444">$31,372.82</td>
                        <td style="color:var(--primary); font-weight:500">$13,294.44</td>
                        <td style="color:var(--text-sub)">$626,705.56</td>
                    </tr><tr>
                        <td style="font-weight:600">Year 2</td>
                        <td style="color:#ef4444">$30,699.79</td>
                        <td style="color:var(--primary); font-weight:500">$27,261.91</td>
                        <td style="color:var(--text-sub)">$612,738.09</td>
                    </tr><tr>
                        <td style="font-weight:600">Year 3</td>
                        <td style="color:#ef4444">$29,992.69</td>
                        <td style="color:var(--primary); font-weight:500">$41,936.49</td>
                        <td style="color:var(--text-sub)">$598,063.51</td>
                    </tr><tr>
                        <td style="font-weight:600">Year 4</td>
                        <td style="color:#ef4444">$29,249.79</td>
                        <td style="color:var(--primary); font-weight:500">$57,353.97</td>
                        <td style="color:var(--text-sub)">$582,646.03</td>
                    </tr><tr>
                        <td style="font-weight:600">Year 5</td>
                        <td style="color:#ef4444">$28,469.28</td>
                        <td style="color:var(--primary); font-weight:500">$73,551.95</td>
                        <td style="color:var(--text-sub)">$566,448.05</td>
                    </tr></tbody>
                </table>
            </div>
            <p class="note-canada">Mortgage calculated using semi-annual compounding (Canadian standard).</p>
        </div>
    </div>

    <script>
        // --- DOM Elements ---
        const inputs = {
            // Currency Fields (Managed as Text for Formatting)
            price: document.getElementById('price'),
            closingCosts: document.getElementById('closing-costs'),
            rent1: document.getElementById('rent-unit-1'),
            rent2: document.getElementById('rent-unit-2'),
            tax: document.getElementById('exp-tax'),
            util: document.getElementById('exp-util'),
            ins: document.getElementById('exp-ins'),
            maint: document.getElementById('exp-maint'),
            mgmt: document.getElementById('exp-mgmt'),

            // Percentage/Number Fields
            downPayment: document.getElementById('down-payment'),
            appreciation: document.getElementById('appreciation'),
            rate: document.getElementById('rate'),
            amortization: document.getElementById('amortization'),
        };

        const outputs = {
            // Readonly Inputs for Mortgage Section
            downPaymentAmt: document.getElementById('down-payment-amt'),
            loanAmount: document.getElementById('loan-amount'),
            
            monthlyMortgage: document.getElementById('monthly-mortgage-display'),
            totalRent: document.getElementById('total-rental-income'),
            totalExp: document.getElementById('total-expenses'),
            cashFlow: document.getElementById('cash-flow-result'),
            totalReturn: document.getElementById('total-return-result'),
            coc: document.getElementById('coc-result'),
            roi: document.getElementById('roi-result'),
            tableBody: document.getElementById('projection-body')
        };

        // --- Formatting Helpers ---

        function parseCurrency(valueStr) {
            if (!valueStr) return 0;
            // Remove commas and any non-numeric, non-dot characters
            const cleanStr = valueStr.replace(/,/g, '');
            return parseFloat(cleanStr) || 0;
        }

        function formatCurrencyDisplay(num) {
            if (isNaN(num)) return '';
            // Format with commas, no $ sign (handled by CSS/HTML labels)
            return num.toLocaleString('en-US', {
                minimumFractionDigits: 0,
                maximumFractionDigits: 2
            });
        }

        // --- Input Event Handling for Formatting ---
        
        // List of keys in 'inputs' that are currency fields requiring formatting
        const currencyKeys = ['price', 'closingCosts', 'rent1', 'rent2', 'tax', 'util', 'ins', 'maint', 'mgmt'];

        currencyKeys.forEach(key => {
            const el = inputs[key];
            
            // On Focus: Remove commas to allow editing
            el.addEventListener('focus', () => {
                const val = parseCurrency(el.value);
                el.value = val === 0 ? '' : val; 
            });

            // On Blur: Add commas back
            el.addEventListener('blur', () => {
                const val = parseCurrency(el.value);
                el.value = formatCurrencyDisplay(val);
            });
        });

        // --- URL State Management ---
        
        function loadStateFromURL() {
            try {
                const params = new URLSearchParams(window.location.search);
                let hasChanges = false;
                
                Object.keys(inputs).forEach(key => {
                    const val = params.get(key);
                    if (val !== null) {
                        // For currency fields, we need to ensure we format the loaded value
                        if (currencyKeys.includes(key)) {
                            const numVal = parseFloat(val);
                            inputs[key].value = formatCurrencyDisplay(numVal);
                        } else {
                            inputs[key].value = val;
                        }
                        hasChanges = true;
                    }
                });
                return hasChanges;
            } catch (e) {
                console.warn('Could not load state from URL:', e);
                return false;
            }
        }

        function updateURL() {
            try {
                const params = new URLSearchParams();
                Object.keys(inputs).forEach(key => {
                    // Store raw numbers in URL for currency fields
                    if (currencyKeys.includes(key)) {
                        params.set(key, parseCurrency(inputs[key].value));
                    } else {
                        params.set(key, inputs[key].value);
                    }
                });
                const newUrl = window.location.pathname + '?' + params.toString();
                window.history.replaceState(null, '', newUrl);
            } catch (e) {
                console.warn('URL state update failed (sandbox environment):', e);
            }
        }

        // Share function removed per user request

        // --- Formatter for Outputs ---
        const money = new Intl.NumberFormat('en-CA', {
            style: 'currency',
            currency: 'CAD',
            minimumFractionDigits: 2,
            maximumFractionDigits: 2
        });

        const percent = new Intl.NumberFormat('en-CA', {
            style: 'percent',
            minimumFractionDigits: 1,
            maximumFractionDigits: 1
        });

        // --- Main Logic ---
        function calculateAll() {
            updateURL();

            // 1. Parse Inputs (using helper for currency fields)
            const price = parseCurrency(inputs.price.value);
            const dpPercent = parseFloat(inputs.downPayment.value) || 0;
            const annualRatePercent = parseFloat(inputs.rate.value) || 0;
            const years = parseInt(inputs.amortization.value);
            const closingCosts = parseCurrency(inputs.closingCosts.value);
            const appreciationRate = parseFloat(inputs.appreciation.value) || 0;

            const downPaymentAmount = price * (dpPercent / 100);
            const principal = price - downPaymentAmount;
            const totalInitialInvestment = downPaymentAmount + closingCosts;

            // Update Readonly Fields for Down Payment Amount and Loan Amount
            outputs.downPaymentAmt.value = formatCurrencyDisplay(downPaymentAmount);
            outputs.loanAmount.value = formatCurrencyDisplay(principal);

            // Effective Monthly Rate from Semi-Annual
            let monthlyRate = 0;
            if (annualRatePercent > 0) {
                const semiAnnualRate = (annualRatePercent / 100) / 2;
                monthlyRate = Math.pow(1 + semiAnnualRate, 1 / 6) - 1;
            }

            const totalPayments = years * 12;
            let monthlyPayment = 0;

            if (monthlyRate === 0) {
                monthlyPayment = principal / totalPayments;
            } else {
                monthlyPayment = principal * (
                    (monthlyRate * Math.pow(1 + monthlyRate, totalPayments)) /
                    (Math.pow(1 + monthlyRate, totalPayments) - 1)
                );
            }

            outputs.monthlyMortgage.textContent = isFinite(monthlyPayment) ? money.format(monthlyPayment) : "$0.00";

            // 2. Rental Income
            const rent1 = parseCurrency(inputs.rent1.value);
            const rent2 = parseCurrency(inputs.rent2.value);
            const totalRent = rent1 + rent2;
            outputs.totalRent.textContent = money.format(totalRent);

            // 3. Operating Expenses
            const tax = parseCurrency(inputs.tax.value);
            const util = parseCurrency(inputs.util.value);
            const ins = parseCurrency(inputs.ins.value);
            const maint = parseCurrency(inputs.maint.value);
            const mgmt = parseCurrency(inputs.mgmt.value);
            
            const totalExp = tax + util + ins + maint + mgmt;
            outputs.totalExp.textContent = money.format(totalExp);

            // 4. Cash Flow
            const netMonthlyCashFlow = totalRent - totalExp - monthlyPayment;
            outputs.cashFlow.textContent = money.format(netMonthlyCashFlow);
            
            if (netMonthlyCashFlow >= 0) {
                outputs.cashFlow.style.color = '#4ade80'; 
            } else {
                outputs.cashFlow.style.color = '#f87171'; 
            }

            // 5. Cash on Cash Return
            const annualCashFlow = netMonthlyCashFlow * 12;
            let cocReturn = 0;
            if (totalInitialInvestment > 0) {
                cocReturn = annualCashFlow / totalInitialInvestment;
            }
            outputs.coc.textContent = percent.format(cocReturn);

            // 6. Total Monthly Return
            let firstYearPrincipal = 0;
            let tempBalance = principal;
            
            for (let m = 1; m <= 12; m++) {
                const interestPart = tempBalance * monthlyRate;
                const principalPart = monthlyPayment - interestPart;
                firstYearPrincipal += principalPart;
                tempBalance -= principalPart;
            }

            const avgMonthlyPrincipal = firstYearPrincipal / 12;
            const totalReturn = netMonthlyCashFlow + avgMonthlyPrincipal;

            outputs.totalReturn.textContent = money.format(totalReturn);
            outputs.totalReturn.style.color = totalReturn >= 0 ? 'var(--primary)' : '#dc2626';

            // 7. 5-Year ROI
            let balanceLoop = principal;
            let totalCashFlow5Years = netMonthlyCashFlow * 60; 

            for (let m = 1; m <= 60; m++) {
                const interestP = balanceLoop * monthlyRate;
                const principalP = monthlyPayment - interestP;
                balanceLoop -= principalP;
                if (balanceLoop < 0) balanceLoop = 0;
            }

            const futureValue = price * Math.pow(1 + appreciationRate/100, 5);
            const equityAtExit = futureValue - balanceLoop;
            const totalMoneyReturned = equityAtExit + totalCashFlow5Years;
            const totalProfit = totalMoneyReturned - totalInitialInvestment;

            let roi = 0;
            if (totalInitialInvestment > 0) {
                roi = totalProfit / totalInitialInvestment;
            }
            outputs.roi.textContent = percent.format(roi);

            // 8. Table
            generateTable(principal, monthlyRate, monthlyPayment);
        }

        function generateTable(startBalance, monthlyRate, monthlyPayment) {
            outputs.tableBody.innerHTML = ''; 
            
            let balance = startBalance;
            let cumulativePrincipal = 0;
            let yearlyInterest = 0;

            for (let month = 1; month <= 60; month++) {
                const interestPayment = balance * monthlyRate;
                const principalPayment = monthlyPayment - interestPayment;
                
                cumulativePrincipal += principalPayment;
                yearlyInterest += interestPayment;
                balance -= principalPayment;

                if (balance < 0) balance = 0;

                if (month % 12 === 0) {
                    const currentYear = month / 12;
                    const row = document.createElement('tr');
                    
                    row.innerHTML = `
                        <td style="font-weight:600">Year ${currentYear}</td>
                        <td style="color:#ef4444">${money.format(yearlyInterest)}</td>
                        <td style="color:var(--primary); font-weight:500">${money.format(cumulativePrincipal)}</td>
                        <td style="color:var(--text-sub)">${money.format(balance)}</td>
                    `;
                    outputs.tableBody.appendChild(row);
                    yearlyInterest = 0;
                }
            }
        }

        // --- Event Listeners ---
        Object.values(inputs).forEach(el => {
            el.addEventListener('input', calculateAll);
        });

        // Initial Run
        loadStateFromURL();
        calculateAll();

    </script>

</body>