Add 2026 index investing cheat sheet
Β· 5 days ago
7f943d9e6d1c716e39601e14cabf16cf317efd63
Parent:
bf21cd3f7
Add a new interactive cheat-sheet page (index-investing-tax-advantaged.html) and its preview image. The page provides an interactive compound/FIRE calculator, age-based asset-allocation tool, account funding waterfall (401(k)/IRA/Roth/HSA/brokerage) with verified 2026 IRS limits, and tax-loss-harvesting / wash-sale guidance. Uses Bootstrap for layout and includes client-side JS for calculators and theme toggling. Includes accompanying image images/index-investing-tax-advantaged.png.
2 files changed +792 β0
Diff
Binary files /dev/null and b/images/index-investing-tax-advantaged.png differ --- /dev/null +++ b/index-investing-tax-advantaged.html @@ -0,0 +1,792 @@ +<!DOCTYPE html> +<html lang="en" data-theme="auto"> + +<head> + <meta charset="utf-8" /> + <meta content="width=device-width, initial-scale=1.0" name="viewport" /> + <title>Index Investing & Tax-Advantaged Accounts: 2026 Cheat Sheet</title> + <meta + content="Interactive guide to index investing and tax-advantaged accounts for 2026: compound-interest and FIRE calculator, asset allocation by age, an account funding waterfall (401k, IRA, Roth, HSA, brokerage) with verified 2026 IRS limits, and tax-loss-harvesting rules including the wash-sale window." + name="description" /> + <meta + content="index investing, index funds, ETF, tax-advantaged accounts, 401k 2026, Roth IRA, traditional IRA, HSA, FIRE calculator, compound interest, asset allocation by age, tax loss harvesting, wash sale rule, three-fund portfolio, Bogleheads, contribution limits 2026, backdoor Roth, asset location" + name="keywords" /> + <link href="https://cheatsheets.davidveksler.com/index-investing-tax-advantaged.html" rel="canonical" /> + + <!-- Open Graph / Facebook --> + <meta content="Index Investing & Tax-Advantaged Accounts: 2026 Cheat Sheet" property="og:title" /> + <meta + content="Compound/FIRE calculator, asset allocation by age, the account funding waterfall, and tax-loss-harvesting rules β with verified 2026 IRS contribution limits." + property="og:description" /> + <meta content="website" property="og:type" /> + <meta content="https://cheatsheets.davidveksler.com/index-investing-tax-advantaged.html" property="og:url" /> + <meta content="images/index-investing-tax-advantaged.png" property="og:image" /> + <meta content="Interactive index investing and tax-advantaged account cheat sheet with calculators" property="og:image:alt" /> + <meta content="1200" property="og:image:width" /> + <meta content="630" property="og:image:height" /> + + <!-- Twitter / X Card --> + <meta content="summary_large_image" name="twitter:card" /> + <meta content="Index Investing & Tax-Advantaged Accounts: 2026 Cheat Sheet" name="twitter:title" /> + <meta + content="Compound/FIRE calculator, asset allocation by age, account funding waterfall, and tax-loss-harvesting rules with verified 2026 IRS limits." + name="twitter:description" /> + <meta content="images/index-investing-tax-advantaged.png" name="twitter:image" /> + <meta content="@heroiclife" name="twitter:creator" /> + + <!-- JSON-LD Structured Data --> + <script type="application/ld+json"> + { + "@context": "https://schema.org", + "@type": "TechArticle", + "headline": "Index Investing & Tax-Advantaged Accounts: 2026 Cheat Sheet", + "description": "A comprehensive, interactive reference for index-fund investing and tax-advantaged accounts in 2026, including a compound-interest/FIRE calculator, asset allocation by age, the account funding waterfall across 401(k)/IRA/Roth/HSA/brokerage with verified IRS limits, and tax-loss-harvesting rules.", + "author": {"@type": "Person", "name": "David Veksler (AI Generated)"}, + "publisher": {"@type": "Organization", "name": "David Veksler Cheatsheets"}, + "datePublished": "2026-06-15", + "dateModified": "2026-06-15", + "keywords": "index investing, tax-advantaged accounts, 401k 2026 limits, Roth IRA, HSA, FIRE calculator, asset allocation, tax loss harvesting, wash sale rule, three-fund portfolio" + } + </script> + + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" + integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" /> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" + integrity="sha384-CK2SzKma4jA5H/MXDUU7i1TqZlCFaD4T01vtyDFvPlD97JQyS+IsSh1nI2EFbpyk" crossorigin="anonymous" /> + + <style> + /* Custom CSS is intentionally unlayered: this <style> follows the Bootstrap CDN + <link>, so plain rules win by source order. (Layering would demote us below + Bootstrap's own unlayered CDN sheet.) data-bs-theme is synced in JS so native + Bootstrap surfaces theme correctly too. */ + :root { + color-scheme: light dark; + --accent: light-dark(#0a6b4f, #2bd9a3); + --accent-2: light-dark(#1d4ed8, #6ea8ff); + --warn: light-dark(#9a6700, #ffcf6e); + --danger: light-dark(#b42318, #ff8a7a); + --page-bg: light-dark(#f4f6f8, #0f1419); + --card-bg: light-dark(#ffffff, #1a212b); + --card-bg-2: light-dark(#f0f3f6, #222c38); + --ink: light-dark(#1c2530, #e6edf3); + --ink-soft: light-dark(#54616e, #9fb0c0); + --line: light-dark(#dde3ea, #2c3744); + --stock: light-dark(#0a6b4f, #2bd9a3); + --bond: light-dark(#1d4ed8, #6ea8ff); + --shadow: light-dark(0 8px 28px rgba(20, 40, 60, .10), 0 8px 28px rgba(0, 0, 0, .45)); + --radius: .8rem; + } + + :root[data-theme="light"] { color-scheme: light; } + :root[data-theme="dark"] { color-scheme: dark; } + + * { scrollbar-width: thin; } + + body { + font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + background: var(--page-bg); + color: var(--ink); + line-height: 1.55; + } + + h1, h2, h3, h4 { text-wrap: balance; font-weight: 700; } + p, li { text-wrap: pretty; } + a { color: var(--accent-2); } + + main { max-width: 1100px; } + + code, kbd { + background: var(--card-bg-2); + color: var(--accent); + padding: .08em .4em; + border-radius: .3rem; + font-size: .9em; + } + + .masthead { + background: + radial-gradient(1200px 300px at 12% -10%, light-dark(#cdeede, #103b30) 0%, transparent 60%), + radial-gradient(1000px 300px at 100% 0%, light-dark(#d7e2ff, #16253f) 0%, transparent 55%), + var(--card-bg); + border-bottom: 1px solid var(--line); + } + + .card-panel { + background: var(--card-bg); + border: 1px solid var(--line); + border-radius: var(--radius); + box-shadow: var(--shadow); + } + + .tool { + background: var(--card-bg); + border: 1px solid var(--line); + border-left: 4px solid var(--accent); + border-radius: var(--radius); + } + + .metric { + background: var(--card-bg-2); + border-radius: .6rem; + padding: .65rem .85rem; + } + .metric .v { font-size: clamp(1.15rem, 1rem + 1.2vw, 1.7rem); font-weight: 700; color: var(--accent); line-height: 1.1; } + .metric .k { font-size: .76rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-soft); } + + input[type="range"] { accent-color: var(--accent); width: 100%; } + .form-control, .form-select { + background: var(--card-bg-2); + border-color: var(--line); + color: var(--ink); + } + .form-control:focus, .form-select:focus { + background: var(--card-bg-2); + color: var(--ink); + border-color: var(--accent); + box-shadow: 0 0 0 .2rem light-dark(rgba(10, 107, 79, .2), rgba(43, 217, 163, .25)); + } + + details.ref { + background: var(--card-bg); + border: 1px solid var(--line); + border-radius: var(--radius); + margin-bottom: .8rem; + overflow: hidden; + } + details.ref > summary { + cursor: pointer; + padding: .9rem 1.1rem; + font-weight: 600; + font-size: 1.05rem; + list-style: none; + display: flex; + align-items: center; + gap: .6rem; + } + details.ref > summary::-webkit-details-marker { display: none; } + details.ref > summary::after { + content: "\F282"; + font-family: "bootstrap-icons"; + margin-left: auto; + color: var(--ink-soft); + transition: transform .2s ease; + } + details.ref[open] > summary::after { transform: rotate(90deg); } + details.ref > summary:hover { color: var(--accent); } + details.ref .body { padding: 0 1.1rem 1.1rem; } + + .alloc-bar { display: flex; height: 2.4rem; border-radius: .5rem; overflow: hidden; font-weight: 700; } + .alloc-bar .seg { display: flex; align-items: center; justify-content: center; color: #fff; font-size: .9rem; transition: width .25s ease; } + .seg-stock { background: var(--stock); } + .seg-bond { background: var(--bond); } + + .waterfall-step { + background: var(--card-bg-2); + border-radius: .55rem; + padding: .7rem .85rem; + border: 1px solid var(--line); + display: flex; + gap: .8rem; + align-items: flex-start; + } + .waterfall-step .num { + flex: 0 0 1.9rem; height: 1.9rem; + display: grid; place-items: center; + background: var(--accent); color: #fff; + border-radius: 50%; font-weight: 700; + } + .waterfall-step.filled { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); } + .waterfall-step .fill-amt { color: var(--accent); font-weight: 700; } + + table { color: var(--ink); } + .table > :not(caption) > * > * { background: transparent; color: var(--ink); border-bottom-color: var(--line); } + .table thead th { border-bottom: 2px solid var(--line); color: var(--ink-soft); text-transform: uppercase; font-size: .76rem; letter-spacing: .03em; } + + .pill { display: inline-block; padding: .12rem .55rem; border-radius: 1rem; font-size: .76rem; font-weight: 600; } + .pill-pre { background: light-dark(#dcefe6, #0f3a2d); color: var(--accent); } + .pill-post { background: light-dark(#e2e9ff, #16284a); color: var(--accent-2); } + .pill-tri { background: light-dark(#fbe9c6, #3a2e10); color: var(--warn); } + + .theme-toggle { + background: var(--card-bg-2); + border: 1px solid var(--line); + color: var(--ink); + border-radius: 2rem; + padding: .35rem .8rem; + font-size: .85rem; + } + + :focus-visible { outline: 3px solid var(--accent-2); outline-offset: 2px; border-radius: 4px; } + + .canvas-wrap { position: relative; width: 100%; } + canvas { max-width: 100%; } + + .text-soft { color: var(--ink-soft); } + .text-accent { color: var(--accent); } + .bg-soft { background: var(--card-bg-2); } + .small-caps { text-transform: uppercase; letter-spacing: .05em; font-size: .76rem; } + + @media (prefers-reduced-motion: reduce) { + * { transition: none !important; animation: none !important; scroll-behavior: auto !important; } + } + + @media print { + .no-print { display: none !important; } + details.ref[open] .body, details.ref .body { display: block !important; } + details.ref > summary::after { display: none; } + body { background: #fff; color: #000; } + .tool, .card-panel, details.ref { box-shadow: none; border-color: #ccc; } + } + </style> +</head> + +<body> + <header class="masthead py-4 py-md-5 mb-4"> + <div class="container" style="max-width:1100px"> + <div class="d-flex justify-content-between align-items-start gap-3"> + <div> + <p class="small-caps text-soft mb-1"><i class="bi bi-graph-up-arrow"></i> Personal Finance Β· Reference</p> + <h1 class="display-6 mb-2">Index Investing & Tax-Advantaged Accounts</h1> + <p class="lead mb-0 text-soft" style="max-width:62ch"> + The whole game in one page: buy the haystack, hold it cheaply, shelter it from tax, and + let compounding do the work. Calculators, the 2026 limits, and the funding order that + beats stock-picking for almost everyone. + </p> + </div> + <button class="theme-toggle no-print flex-shrink-0" id="themeBtn" type="button" aria-label="Toggle color theme"> + <i class="bi bi-circle-half"></i> <span id="themeLbl">Auto</span> + </button> + </div> + <p class="small text-soft mt-3 mb-0"> + <i class="bi bi-patch-check"></i> <strong>Last verified: 2026-06-15.</strong> + 2026 figures from IRS Notice 2025-67 (retirement) and Rev. Proc. 2025-19 (HSA/HDHP). + Educational only β not individualized tax, legal, or investment advice. + </p> + </div> + </header> + + <main class="container pb-5"> + + <!-- ===================== QUICK REFERENCE ===================== --> + <section class="card-panel p-3 p-md-4 mb-4" aria-labelledby="qr"> + <h2 id="qr" class="h4 mb-3"><i class="bi bi-lightning-charge-fill text-accent"></i> Quick Reference β 2026 Contribution Limits</h2> + <div class="table-responsive"> + <table class="table table-sm align-middle mb-2"> + <thead> + <tr><th>Account</th><th>2026 limit</th><th>Catch-up (50+)</th><th>Tax treatment</th><th>Notes</th></tr> + </thead> + <tbody> + <tr> + <td><strong>401(k) / 403(b) / 457(b) / TSP</strong></td> + <td>$24,500</td> + <td>+$8,000 <span class="text-soft">(+$11,250 ages 60β63)</span></td> + <td><span class="pill pill-pre">Pre-tax</span> or <span class="pill pill-post">Roth</span></td> + <td>Employee deferral only; total additions cap $72,000</td> + </tr> + <tr> + <td><strong>Traditional / Roth IRA</strong></td> + <td>$7,500 <span class="text-soft">(combined)</span></td> + <td>+$1,100</td> + <td><span class="pill pill-pre">Pre-tax</span> / <span class="pill pill-post">Roth</span></td> + <td>Roth phases out $153kβ$168k single, $242kβ$252k MFJ</td> + </tr> + <tr> + <td><strong>HSA</strong> (with HDHP)</td> + <td>$4,400 self / $8,750 family</td> + <td>+$1,000 <span class="text-soft">(age 55+)</span></td> + <td><span class="pill pill-tri">Triple tax-free</span></td> + <td>Best deal in the code; needs an HSA-eligible HDHP</td> + </tr> + <tr> + <td><strong>SIMPLE IRA</strong></td> + <td>$17,000 <span class="text-soft">($18,100 some plans)</span></td> + <td>+$4,000 <span class="text-soft">(+$5,250 ages 60β63)</span></td> + <td><span class="pill pill-pre">Pre-tax</span></td> + <td>Small-employer plan</td> + </tr> + <tr> + <td><strong>Taxable brokerage</strong></td> + <td><span class="text-soft">Unlimited</span></td> + <td>β</td> + <td>Cap-gains</td> + <td>LTCG 0% up to $49,450 single / $98,900 MFJ taxable income</td> + </tr> + </tbody> + </table> + </div> + <p class="small text-soft mb-0">Catch-up reminder: starting in 2026, if your prior-year FICA wages exceeded <strong>$150,000</strong>, any 50+ catch-up to a workplace plan must go into the <strong>Roth</strong> (after-tax) source.</p> + </section> + + <!-- ===================== TOOL 1: COMPOUND / FIRE ===================== --> + <section class="tool p-3 p-md-4 mb-4" aria-labelledby="t1"> + <h2 id="t1" class="h4 mb-1"><i class="bi bi-fire text-accent"></i> Compound-Interest & FIRE Calculator</h2> + <p class="text-soft small mb-3">Returns are entered as <strong>real</strong> (after-inflation) so every figure is in today's dollars. FIRE target = annual spending Γ· withdrawal rate.</p> + <div class="row g-4"> + <div class="col-lg-5"> + <div class="row g-3"> + <div class="col-6"><label class="form-label small mb-1">Current age</label><input class="form-control" id="f_age" type="number" value="30" min="16" max="80"></div> + <div class="col-6"><label class="form-label small mb-1">Current balance ($)</label><input class="form-control" id="f_bal" type="number" value="25000" min="0" step="1000"></div> + <div class="col-6"><label class="form-label small mb-1">Monthly contribution ($)</label><input class="form-control" id="f_pmt" type="number" value="1500" min="0" step="50"></div> + <div class="col-6"><label class="form-label small mb-1">Annual spending ($)</label><input class="form-control" id="f_spend" type="number" value="60000" min="0" step="1000"></div> + <div class="col-6"> + <label class="form-label small mb-1">Real return: <span id="f_ret_l" class="text-accent fw-bold">5.0%</span></label> + <input class="form-range" id="f_ret" type="range" min="1" max="9" step="0.5" value="5"> + <div class="d-flex justify-content-between small text-soft"><span>1%</span><span>9%</span></div> + </div> + <div class="col-6"> + <label class="form-label small mb-1">Withdrawal rate: <span id="f_wr_l" class="text-accent fw-bold">4.0%</span></label> + <input class="form-range" id="f_wr" type="range" min="2.5" max="6" step="0.25" value="4"> + <div class="d-flex justify-content-between small text-soft"><span>2.5%</span><span>6%</span></div> + </div> + </div> + <div class="row g-2 mt-1"> + <div class="col-6"><div class="metric"><div class="v" id="o_fire">β</div><div class="k">FIRE number</div></div></div> + <div class="col-6"><div class="metric"><div class="v" id="o_age">β</div><div class="k">Financially independent at</div></div></div> + <div class="col-6"><div class="metric"><div class="v" id="o_yrs">β</div><div class="k">Years to FI</div></div></div> + <div class="col-6"><div class="metric"><div class="v" id="o_65">β</div><div class="k">Balance at 65</div></div></div> + </div> + <p class="small text-soft mt-2 mb-0" id="f_note"></p> + </div> + <div class="col-lg-7"> + <div class="canvas-wrap"><canvas id="f_chart" height="320" aria-label="Projected portfolio balance over time"></canvas></div> + <p class="small text-soft text-center mt-1 mb-0"><span class="text-accent">β </span> Portfolio <span style="color:var(--bond)">β¬</span> FIRE target line</p> + </div> + </div> + </section> + + <!-- ===================== TOOL 2: ASSET ALLOCATION ===================== --> + <section class="tool p-3 p-md-4 mb-4" aria-labelledby="t2"> + <h2 id="t2" class="h4 mb-1"><i class="bi bi-pie-chart-fill text-accent"></i> Asset Allocation by Age</h2> + <p class="text-soft small mb-3">Age-based heuristics for the stock/bond split. They're starting points, not laws β risk capacity, job stability, and sleep-at-night tolerance all shift the dial.</p> + <div class="row g-4 align-items-center"> + <div class="col-lg-5"> + <label class="form-label mb-1">Your age: <span id="a_age_l" class="text-accent fw-bold fs-5">35</span></label> + <input class="form-range" id="a_age" type="range" min="20" max="80" value="35"> + <label class="form-label small mt-2 mb-1">Glide-path rule</label> + <select class="form-select" id="a_rule"> + <option value="120">Aggressive β 120 β age in stocks</option> + <option value="110" selected>Moderate β 110 β age in stocks</option> + <option value="100">Conservative β 100 β age in stocks</option> + </select> + </div> + <div class="col-lg-7"> + <div class="alloc-bar mb-2" role="img" aria-label="Stock and bond allocation"> + <div class="seg seg-stock" id="a_seg_s" style="width:75%">75% Stocks</div> + <div class="seg seg-bond" id="a_seg_b" style="width:25%">25% Bonds</div> + </div> + <div class="row g-2 text-center"> + <div class="col-4"><div class="metric"><div class="v" id="a_stock">75%</div><div class="k">Stocks</div></div></div> + <div class="col-4"><div class="metric"><div class="v" id="a_bond">25%</div><div class="k">Bonds</div></div></div> + <div class="col-4"><div class="metric"><div class="v" id="a_intl">β</div><div class="k">Intl. of stocks</div></div></div> + </div> + <p class="small text-soft mt-2 mb-0" id="a_note"></p> + </div> + </div> + <div class="mt-3 p-3 bg-soft rounded"> + <strong class="small-caps text-soft">Canonical three-fund split (Bogleheads)</strong> + <p class="small mb-0 mt-1">Total US market + Total international + Total bond. A common stock split is ~60β70% US / 30β40% international (cap-weighted global is ~60/40). Hold bonds in tax-deferred space when you can.</p> + </div> + </section> + + <!-- ===================== TOOL 3: FUNDING WATERFALL ===================== --> + <section class="tool p-3 p-md-4 mb-4" aria-labelledby="t3"> + <h2 id="t3" class="h4 mb-1"><i class="bi bi-diagram-3-fill text-accent"></i> Account Funding Waterfall</h2> + <p class="text-soft small mb-3">Where should your next dollar go? Enter what you can invest this year and your situation β it fills the buckets in priority order (the Bogleheads "prioritizing investments" flow), using 2026 limits.</p> + <div class="row g-3 mb-3"> + <div class="col-md-4"><label class="form-label small mb-1">Annual amount to invest ($)</label><input class="form-control" id="w_amt" type="number" value="30000" min="0" step="500"></div> + <div class="col-md-3"><label class="form-label small mb-1">Age</label><input class="form-control" id="w_age" type="number" value="35" min="16" max="80"></div> + <div class="col-md-5 d-flex flex-column justify-content-end gap-1"> + <div class="form-check"><input class="form-check-input" type="checkbox" id="w_match" checked><label class="form-check-label small" for="w_match">Employer 401(k) match β up to <input type="number" id="w_matchamt" value="4500" min="0" step="500" style="width:90px" class="form-control form-control-sm d-inline-block">/yr</label></div> + <div class="form-check"><input class="form-check-input" type="checkbox" id="w_hsa" checked><label class="form-check-label small" for="w_hsa">HSA-eligible (have an HDHP) β <select id="w_hsatype" class="form-select form-select-sm d-inline-block" style="width:130px"><option value="self">self-only</option><option value="family">family</option></select></label></div> + <div class="form-check"><input class="form-check-input" type="checkbox" id="w_roth" checked><label class="form-check-label small" for="w_roth">Income allows direct Roth IRA (else use backdoor)</label></div> + </div> + </div> + <div id="w_steps" class="d-grid gap-2"></div> + <p class="small text-soft mt-2 mb-0" id="w_note"></p> + </section> + + <!-- ===================== TOOL 4: TLH / WASH SALE ===================== --> + <section class="tool p-3 p-md-4 mb-4" aria-labelledby="t4"> + <h2 id="t4" class="h4 mb-1"><i class="bi bi-scissors text-accent"></i> Tax-Loss Harvesting β Wash-Sale Window</h2> + <p class="text-soft small mb-3">The wash-sale rule (IRC Β§1091) disallows a loss if you buy a <em>substantially identical</em> security within <strong>30 days before or after</strong> the sale β a 61-day danger zone. Enter your sale date to see the window.</p> + <div class="row g-3 align-items-end"> + <div class="col-md-4"><label class="form-label small mb-1">Loss sale date</label><input class="form-control" id="ws_date" type="date" value="2026-06-15"></div> + <div class="col-md-8"> + <div class="p-3 bg-soft rounded"> + <div class="small text-soft small-caps mb-1">Do not buy a substantially identical security between</div> + <div class="fs-6"><i class="bi bi-calendar-x text-danger"></i> <strong id="ws_start">β</strong> and <strong id="ws_end">β</strong></div> + <div class="small text-soft mt-1" id="ws_note"></div> + </div> + </div> + </div> + <div class="row g-2 mt-2"> + <div class="col-md-4"><div class="metric"><div class="v">$3,000</div><div class="k">Max net loss vs. ordinary income / yr ($1,500 MFS)</div></div></div> + <div class="col-md-4"><div class="metric"><div class="v">β</div><div class="k">Carry-forward of excess losses (indefinite)</div></div></div> + <div class="col-md-4"><div class="metric"><div class="v">61 days</div><div class="k">Total wash-sale window (30 + sale + 30)</div></div></div> + </div> + <p class="small text-soft mt-2 mb-0"><i class="bi bi-exclamation-triangle"></i> A wash sale triggered by a purchase in your <strong>IRA</strong> permanently disallows the loss (Rev. Rul. 2008-5) β the basis is <em>not</em> added back. Avoid by holding a different-enough fund (e.g., S&P 500 β total-market) during the window.</p> + </section> + + <!-- ===================== REFERENCE SECTIONS ===================== --> + <h2 class="h4 mt-5 mb-3"><i class="bi bi-journal-text text-accent"></i> Reference</h2> + + <details class="ref" open> + <summary><i class="bi bi-1-circle"></i> Index investing fundamentals</summary> + <div class="body"> + <p><strong>The thesis.</strong> After costs, the average actively managed dollar must underperform the market average β it <em>is</em> the market minus fees (Sharpe's "arithmetic of active management"). SPIVA data consistently shows ~85β90% of US large-cap active funds trail the S&P 500 over 15 years. So: own the whole market at minimal cost and stop guessing.</p> + <ul> + <li><strong>Index fund:</strong> a fund that mechanically holds every security in an index (e.g., S&P 500, total US market). No manager picking winners β near-zero fees.</li> + <li><strong>Expense ratio:</strong> annual fee as % of assets. Realistic floor today: <code>0.03%</code> (VOO/VTI, FXAIX, SWPPX) β i.e. <strong>$3/yr per $10,000</strong>. Anything over ~0.20% for a broad index fund is overpriced. A 1% fee compounds to roughly a quarter of your ending balance over 40 years.</li> + <li><strong>ETF vs. mutual fund:</strong> ETFs trade intraday and are usually more tax-efficient in taxable accounts (in-kind creation/redemption avoids capital-gains distributions). Index <em>mutual</em> funds allow automatic fractional dollar investing. In a 401(k)/IRA the difference is cosmetic.</li> + <li><strong>Total return:</strong> S&P 500 long-run average β <strong>~10% nominal / ~6.5β7% real</strong> (1926βpresent). Wide dispersion: any given year is rarely "average." Don't extrapolate a single decade.</li> + </ul> + <div class="table-responsive"> + <table class="table table-sm"> + <thead><tr><th>Broad index fund</th><th>Ticker</th><th>Expense ratio</th><th>Covers</th></tr></thead> + <tbody> + <tr><td>Vanguard Total US Market</td><td>VTI / VTSAX</td><td>0.03% / 0.04%</td><td>~3,600 US stocks</td></tr> + <tr><td>Vanguard S&P 500</td><td>VOO / VFIAX</td><td>0.03% / 0.04%</td><td>500 US large-caps</td></tr> + <tr><td>Fidelity ZERO Total Market</td><td>FZROX</td><td>0.00%</td><td>US total (Fidelity-only)</td></tr> + <tr><td>Vanguard Total International</td><td>VXUS / VTIAX</td><td>0.05% / 0.09%</td><td>Developed + emerging ex-US</td></tr> + <tr><td>Vanguard Total Bond</td><td>BND / VBTLX</td><td>0.03% / 0.05%</td><td>US investment-grade bonds</td></tr> + </tbody> + </table> + </div> + <p class="small text-soft mb-0"><i class="bi bi-info-circle"></i> Expense ratios verified from issuer pages as of mid-2026; they change rarely but tag-check before quoting exact basis points.</p> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-2-circle"></i> Account types deep dive (401k Β· IRA Β· Roth Β· HSA Β· brokerage)</summary> + <div class="body"> + <div class="table-responsive"> + <table class="table table-sm align-middle"> + <thead><tr><th>Account</th><th>Contribution tax</th><th>Growth</th><th>Withdrawal tax</th><th>Key rules</th></tr></thead> + <tbody> + <tr><td><strong>Traditional 401(k)</strong></td><td>Pre-tax (deductible)</td><td>Tax-deferred</td><td>Ordinary income</td><td>RMDs at 73; 10% penalty before 59Β½ (some exceptions, Rule of 55)</td></tr> + <tr><td><strong>Roth 401(k)</strong></td><td>After-tax</td><td>Tax-free</td><td>Tax-free*</td><td>No income limit; no RMDs starting 2024 (SECURE 2.0)</td></tr> + <tr><td><strong>Traditional IRA</strong></td><td>Pre-tax (if eligible)</td><td>Tax-deferred</td><td>Ordinary income</td><td>Deduction phases out if covered by workplace plan</td></tr> + <tr><td><strong>Roth IRA</strong></td><td>After-tax</td><td>Tax-free</td><td>Tax-free*</td><td>Contributions withdrawable anytime; 5-year rule on earnings</td></tr> + <tr><td><strong>HSA</strong></td><td>Pre-tax</td><td>Tax-free</td><td>Tax-free (medical)</td><td>Triple tax-free; after 65 acts like a Traditional IRA for non-medical</td></tr> + <tr><td><strong>Taxable brokerage</strong></td><td>After-tax</td><td>Taxed (dividends/gains)</td><td>Cap-gains on growth</td><td>No limits, no penalties, full liquidity, step-up basis at death</td></tr> + </tbody> + </table> + </div> + <p class="small text-soft">*Roth tax-free on earnings requires the account be open 5 years <em>and</em> age 59Β½ (or death/disability/first-home $10k).</p> + <ul class="mb-0"> + <li><strong>HSA = the only triple-tax-advantaged account:</strong> deductible in, grows tax-free, tax-free out for qualified medical. Pay current medical out of pocket, save receipts, and let the HSA compound as a stealth retirement account β there's no deadline to reimburse yourself.</li> + <li><strong>Backdoor Roth IRA:</strong> over the income limit? Contribute non-deductible to a Traditional IRA, then convert to Roth. Watch the <em>pro-rata rule</em> β pre-tax IRA balances make the conversion partly taxable (Form 8606).</li> + <li><strong>Mega-backdoor Roth:</strong> if your plan allows after-tax (non-Roth) 401(k) contributions + in-plan Roth conversion, you can stuff up to the $72,000 total-additions cap minus deferrals and match into Roth. Plan-dependent.</li> + <li><strong>Roth conversion ladder (early retirement):</strong> convert Traditional β Roth in low-income years; each conversion is penalty-free to withdraw after 5 years β the classic FIRE bridge before 59Β½.</li> + <li><strong>Rule of 55:</strong> leave your employer in or after the year you turn 55 and you can tap <em>that</em> 401(k) penalty-free (not IRAs).</li> + <li><strong>72(t) / SEPP:</strong> substantially equal periodic payments let you tap an IRA early without the 10% penalty β rigid, locked for 5 years or to 59Β½.</li> + </ul> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-3-circle"></i> 2026 limits, phase-outs & thresholds (full tables)</summary> + <div class="body"> + <h3 class="h6 mt-1">Roth IRA β contribution phase-out (MAGI, 2026)</h3> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Filing status</th><th>Full contribution below</th><th>Phase-out range</th><th>No contribution above</th></tr></thead><tbody> + <tr><td>Single / Head of household</td><td>$153,000</td><td>$153,000 β $168,000</td><td>$168,000</td></tr> + <tr><td>Married filing jointly</td><td>$242,000</td><td>$242,000 β $252,000</td><td>$252,000</td></tr> + <tr><td>Married filing separately</td><td>β</td><td>$0 β $10,000</td><td>$10,000</td></tr> + </tbody></table></div> + + <h3 class="h6">Traditional IRA β deduction phase-out (MAGI, 2026, if covered by a workplace plan)</h3> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Situation</th><th>Phase-out range</th></tr></thead><tbody> + <tr><td>Single / HoH, covered by workplace plan</td><td>$81,000 β $91,000</td></tr> + <tr><td>MFJ, contributor covered by plan</td><td>$129,000 β $149,000</td></tr> + <tr><td>MFJ, you're not covered but spouse is</td><td>$242,000 β $252,000</td></tr> + <tr><td>Not covered by any workplace plan</td><td>Fully deductible (no limit)</td></tr> + </tbody></table></div> + + <h3 class="h6">HSA & HDHP (2026, Rev. Proc. 2025-19)</h3> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th></th><th>Self-only</th><th>Family</th></tr></thead><tbody> + <tr><td>HSA contribution limit</td><td>$4,400</td><td>$8,750</td></tr> + <tr><td>HSA catch-up (55+)</td><td colspan="2">+$1,000 (each spouse needs own HSA)</td></tr> + <tr><td>HDHP minimum deductible</td><td>$1,700</td><td>$3,400</td></tr> + <tr><td>HDHP max out-of-pocket</td><td>$8,500</td><td>$17,000</td></tr> + </tbody></table></div> + + <h3 class="h6">Long-term capital-gains brackets (2026 taxable income)</h3> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Rate</th><th>Single</th><th>Married filing jointly</th></tr></thead><tbody> + <tr><td>0%</td><td>up to $49,450</td><td>up to $98,900</td></tr> + <tr><td>15%</td><td>$49,451 β $545,500</td><td>$98,901 β $613,700</td></tr> + <tr><td>20%</td><td>over $545,500</td><td>over $613,700</td></tr> + </tbody></table></div> + <p class="small text-soft mb-0">Net investment income tax (NIIT) of 3.8% stacks on top above $200k single / $250k MFJ MAGI. Short-term gains (held β€1 year) are taxed as ordinary income β hold >1 year.</p> + + <h3 class="h6 mt-3">Year-by-year change (2025 β 2026)</h3> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Item</th><th>2025</th><th>2026</th></tr></thead><tbody> + <tr><td>401(k) deferral</td><td>$23,500</td><td>$24,500</td></tr> + <tr><td>401(k) catch-up (50+)</td><td>$7,500</td><td>$8,000</td></tr> + <tr><td>401(k) super catch-up (60β63)</td><td>$11,250</td><td>$11,250</td></tr> + <tr><td>Total additions (415(c))</td><td>$70,000</td><td>$72,000</td></tr> + <tr><td>IRA limit</td><td>$7,000</td><td>$7,500</td></tr> + <tr><td>IRA catch-up</td><td>$1,000</td><td>$1,100</td></tr> + <tr><td>HSA self / family</td><td>$4,300 / $8,550</td><td>$4,400 / $8,750</td></tr> + </tbody></table></div> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-4-circle"></i> Asset location β which fund goes in which account</summary> + <div class="body"> + <p>Same dollars, different tax drag depending on <em>where</em> you hold each asset. The principle: put tax-inefficient assets in shelters, tax-efficient assets in taxable.</p> + <div class="table-responsive"><table class="table table-sm"><thead><tr><th>Hold here</th><th>Put these assets</th><th>Why</th></tr></thead><tbody> + <tr><td><strong>Taxable brokerage</strong></td><td>Broad US/international stock index funds, municipal bonds</td><td>Qualified dividends + LTCG rates; ETFs shed gains; foreign tax credit on intl.</td></tr> + <tr><td><strong>Traditional (tax-deferred)</strong></td><td>Bonds, REITs, high-turnover funds</td><td>Interest/REIT distributions are ordinary income β shield them; you'll pay ordinary rates on withdrawal anyway</td></tr> + <tr><td><strong>Roth (tax-free)</strong></td><td>Highest expected-growth assets (small-cap, emerging, aggressive stocks)</td><td>All growth escapes tax forever β maximize the tax-free compounding base</td></tr> + </tbody></table></div> + <ul class="mb-0"> + <li><strong>One-fund simplicity beats perfect location.</strong> If juggling locations stops you from investing, a single target-date or total-world fund in every account is a fine choice β behavior > optimization.</li> + <li><strong>Hold international in taxable</strong> to claim the foreign tax credit (lost inside an IRA).</li> + <li><strong>Never hold bonds in a Roth</strong> if you have tax-deferred space β you're wasting your most valuable (tax-free) real estate on a low-growth asset.</li> + </ul> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-5-circle"></i> Withdrawal strategy, the 4% rule & RMDs</summary> + <div class="body"> + <ul> + <li><strong>The 4% rule (Bengen / Trinity study):</strong> withdraw 4% of the initial portfolio, adjust for inflation yearly; historically survived 30 years in ~95%+ of US scenarios. It's a planning heuristic, not a guarantee β sequence-of-returns risk early in retirement is the real danger. Longer horizons (FIRE at 40) lean toward 3.25β3.5%.</li> + <li><strong>Withdrawal order (typical tax-minimizing default):</strong> taxable first β tax-deferred (Traditional) next β Roth last. But blend: realize some Traditional income each year up to the top of a low bracket (and do Roth conversions) so you don't get RMD-bombed at 73.</li> + <li><strong>RMDs (Required Minimum Distributions):</strong> begin at <strong>age 73</strong> (rising to 75 for those born 1960+) on Traditional 401(k)/IRA. Roth IRAs never have RMDs; Roth 401(k)s no longer have them (SECURE 2.0, 2024+). Miss one and the penalty is 25% (10% if corrected promptly).</li> + <li><strong>QCD (Qualified Charitable Distribution):</strong> from 70Β½, send up to $108,000 (2025, inflation-indexed) of IRA money directly to charity β satisfies RMDs and stays off your AGI.</li> + <li><strong>Capital-gains harvesting:</strong> in low-income years, realize gains up to the top of the 0% LTCG bracket ($98,900 MFJ taxable income in 2026) to reset basis tax-free.</li> + </ul> + <p class="small text-soft mb-0">QCD figure is the 2025 indexed amount; the 2026 number tracks inflation β verify before quoting.</p> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-6-circle"></i> Tax-loss harvesting β the full rules</summary> + <div class="body"> + <ul> + <li><strong>What it is:</strong> sell a position at a loss to bank a capital loss, immediately buy a <em>similar-but-not-identical</em> fund to stay invested. The loss offsets gains and up to $3,000/yr of ordinary income; the rest carries forward forever.</li> + <li><strong>Wash-sale rule (IRC Β§1091):</strong> the loss is disallowed if you buy a substantially identical security within 30 days before or after the sale β across <em>all</em> your accounts, including your spouse's and your IRA. The 61-day window is the danger zone.</li> + <li><strong>"Substantially identical" is the art:</strong> selling VOO (S&P 500) and buying VTI (total market) is broadly considered safe; selling VOO and buying IVV (another S&P 500 fund) is risky. Use a different index or provider.</li> + <li><strong>IRA trap:</strong> a replacement buy inside your IRA permanently kills the loss (Rev. Rul. 2008-5) β basis is <em>not</em> restored. Turn off auto-reinvest/auto-buy in retirement accounts while harvesting.</li> + <li><strong>Tax-rate arbitrage:</strong> you harvest a short-or-long-term loss now but it offsets future gains. Best when you offset short-term gains (taxed at ordinary rates) or income. Watch out for resetting basis lower β larger gains later (deferral, not free money β unless you get a step-up at death).</li> + <li><strong>Don't let the tax tail wag the dog:</strong> a tiny loss isn't worth churning; harvesting matters most in volatile down markets and for large taxable balances. Useless inside tax-advantaged accounts (no taxable gains to offset).</li> + </ul> + <p class="mb-0"><strong>Worked example:</strong> You bought $50k of VTI; it drops to $42k. Sell (bank an $8k loss), buy $42k of VXUS-heavy total-world or VOO same day. Use $3k against this year's salary, carry $5k forward. You stayed ~100% invested and pocketed a tax asset.</p> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-exclamation-octagon-fill text-danger"></i> Common mistakes & anti-patterns</summary> + <div class="body"> + <ul class="mb-0"> + <li><strong>Leaving the match on the table.</strong> Not contributing enough to get the full employer match is a guaranteed 50β100% instant return refused. Always fund to the match first.</li> + <li><strong>Cash drag in the IRA.</strong> Contributing to an IRA but never buying funds β the money sits in a settlement account earning nothing. <em>Contributing β investing.</em></li> + <li><strong>Performance-chasing & stock-picking.</strong> Last year's winner is a coin flip next year. The index already owns it.</li> + <li><strong>Timing the market.</strong> Missing the 10 best days over 20 years roughly halves your return; those days cluster next to the worst ones. Time <em>in</em> > timing.</li> + <li><strong>High expense ratios & loads.</strong> A 1% advisor fee + 0.75% fund fee can consume ~40% of your lifetime gains. Insist on low-cost index funds; avoid front-loaded funds entirely.</li> + <li><strong>Selling in a crash.</strong> The single most expensive behavioral error. Write an Investment Policy Statement and automate contributions so you keep buying when it's cheap.</li> + <li><strong>Backdoor Roth pro-rata surprise.</strong> Doing a backdoor Roth while holding a big pre-tax IRA β the conversion is mostly taxable. Roll the pre-tax IRA into a 401(k) first.</li> + <li><strong>Ignoring the HSA.</strong> Treating the HSA as a spending account instead of the best retirement vehicle in the code. Invest it; pay current medical from cash flow.</li> + <li><strong>Over-diversifying into overlap.</strong> Owning five "different" funds that are all 80% the same megacaps. Two or three broad funds is plenty.</li> + <li><strong>Home-country / single-stock concentration.</strong> 100% one country or piling into your employer's stock concentrates risk exactly where your paycheck already is.</li> + </ul> + </div> + </details> + + <details class="ref"> + <summary><i class="bi bi-card-checklist"></i> The 60-second plan (decision guidance)</summary> + <div class="body"> + <ol class="mb-0"> + <li>Build a <strong>1-month emergency buffer</strong> + pay off any >8% debt before investing.</li> + <li>Contribute to the <strong>401(k) up to the full match</strong> (free money).</li> + <li>Max the <strong>HSA</strong> if you have an HDHP (triple tax-free; invest it).</li> + <li>Max a <strong>Roth or Traditional IRA</strong> ($7,500). Backdoor if over the income limit.</li> + <li>Finish maxing the <strong>401(k)</strong> ($24,500 total deferral).</li> + <li>Mega-backdoor Roth if available, then <strong>taxable brokerage</strong> β unlimited, flexible.</li> + <li>Buy <strong>broad, cheap index funds</strong> (US + international + bonds), set an age-appropriate split, automate, and ignore the noise for 30 years.</li> + </ol> + </div> + </details> + + <footer class="text-center text-soft small mt-5 pt-4" style="border-top:1px solid var(--line)"> + <p class="mb-1"><strong>Last verified: 2026-06-15.</strong> Limits per IRS Notice 2025-67 & Rev. Proc. 2025-19.</p> + <p class="mb-0">Educational reference, not tax/investment advice. Verify current-year figures at <a href="https://www.irs.gov/retirement-plans/cola-increases-for-dollar-limitations-on-benefits-and-contributions">irs.gov</a> before acting. Part of <a href="https://cheatsheets.davidveksler.com/">David Veksler's Cheatsheets</a> Β· AI generated.</p> + </footer> + </main> + + <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" + integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script> + <script> + (function () { + "use strict"; + const $ = id => document.getElementById(id); + const fmt = n => "$" + Math.round(n).toLocaleString("en-US"); + const fmtK = n => n >= 1e6 ? "$" + (n / 1e6).toFixed(n >= 1e7 ? 0 : 2).replace(/\.00$/, "") + "M" : "$" + Math.round(n / 1000) + "k"; + + /* ---------- Theme toggle ---------- */ + const modes = ["auto", "light", "dark"], icons = { auto: "bi-circle-half", light: "bi-sun", dark: "bi-moon-stars" }; + let tIdx = 0; + try { const s = localStorage.getItem("iitheme"); if (s) tIdx = Math.max(0, modes.indexOf(s)); } catch (e) {} + const prefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)"); + function applyTheme() { + const m = modes[tIdx]; + document.documentElement.setAttribute("data-theme", m); + const resolved = m === "auto" ? (prefersDark && prefersDark.matches ? "dark" : "light") : m; + document.documentElement.setAttribute("data-bs-theme", resolved); + $("themeLbl").textContent = m[0].toUpperCase() + m.slice(1); + $("themeBtn").querySelector("i").className = "bi " + icons[m]; + try { localStorage.setItem("iitheme", m); } catch (e) {} + drawFire(); + } + $("themeBtn").addEventListener("click", () => { tIdx = (tIdx + 1) % modes.length; applyTheme(); }); + if (prefersDark && prefersDark.addEventListener) prefersDark.addEventListener("change", () => { if (modes[tIdx] === "auto") applyTheme(); }); + + const cssVar = n => getComputedStyle(document.documentElement).getPropertyValue(n).trim(); + + /* ---------- Tool 1: Compound / FIRE ---------- */ + const fAge = $("f_age"), fBal = $("f_bal"), fPmt = $("f_pmt"), fSpend = $("f_spend"), fRet = $("f_ret"), fWr = $("f_wr"); + function computeFire() { + const age = +fAge.value, r = +fRet.value / 100, pmt = +fPmt.value * 12, wr = +fWr.value / 100; + const fire = (+fSpend.value) / wr; + let bal = +fBal.value, fiAge = null, series = [{ age, bal }]; + for (let a = age + 1; a <= 100; a++) { + bal = bal * (1 + r) + pmt; + series.push({ age: a, bal }); + if (fiAge === null && bal >= fire) fiAge = a; + if (a >= 95) break; + } + const at65 = (series.find(s => s.age === 65) || series[series.length - 1]).bal; + return { fire, fiAge, at65, series, age }; + } + let fireState; + function updateFire() { + $("f_ret_l").textContent = (+fRet.value).toFixed(1) + "%"; + $("f_wr_l").textContent = (+fWr.value).toFixed(1) + "%"; + fireState = computeFire(); + $("o_fire").textContent = fmtK(fireState.fire); + $("o_age").textContent = fireState.fiAge ? fireState.fiAge : ">95"; + $("o_yrs").textContent = fireState.fiAge ? (fireState.fiAge - fireState.age) : "β"; + $("o_65").textContent = fmtK(fireState.at65); + $("f_note").textContent = fireState.fiAge + ? "At a " + (+fWr.value).toFixed(1) + "% withdrawal rate you reach financial independence at " + fireState.fiAge + " β " + (fireState.fiAge - fireState.age) + " years of contributing " + fmt(+fPmt.value) + "/mo." + : "Not reaching the FIRE target by 95 at these inputs β raise contributions, return, or spending plan."; + drawFire(); + } + function drawFire() { + if (!fireState) return; + const cv = $("f_chart"), wrap = cv.parentElement; + const W = cv.width = wrap.clientWidth || 600, H = cv.height = 320, ctx = cv.getContext("2d"); + ctx.clearRect(0, 0, W, H); + const pad = { l: 52, r: 12, t: 14, b: 26 }; + const s = fireState.series, maxBal = Math.max(fireState.fire * 1.15, s[s.length - 1].bal); + const a0 = s[0].age, a1 = s[s.length - 1].age; + const x = a => pad.l + (a - a0) / (a1 - a0) * (W - pad.l - pad.r); + const y = v => H - pad.b - v / maxBal * (H - pad.t - pad.b); + const ink = cssVar("--ink-soft"), line = cssVar("--line"), acc = cssVar("--stock"), bond = cssVar("--bond"); + // grid + y labels + ctx.strokeStyle = line; ctx.fillStyle = ink; ctx.font = "11px system-ui"; ctx.lineWidth = 1; + for (let i = 0; i <= 4; i++) { + const v = maxBal * i / 4, yy = y(v); + ctx.beginPath(); ctx.moveTo(pad.l, yy); ctx.lineTo(W - pad.r, yy); ctx.stroke(); + ctx.fillText(fmtK(v), 4, yy + 4); + } + // x labels + ctx.textAlign = "center"; + for (let a = a0; a <= a1; a += Math.ceil((a1 - a0) / 6)) ctx.fillText(a, x(a), H - 8); + ctx.textAlign = "left"; + // FIRE target line + ctx.strokeStyle = bond; ctx.setLineDash([6, 4]); ctx.lineWidth = 2; + ctx.beginPath(); ctx.moveTo(pad.l, y(fireState.fire)); ctx.lineTo(W - pad.r, y(fireState.fire)); ctx.stroke(); + ctx.setLineDash([]); + // portfolio curve + ctx.strokeStyle = acc; ctx.lineWidth = 2.5; ctx.beginPath(); + s.forEach((p, i) => { const px = x(p.age), py = y(Math.min(p.bal, maxBal)); i ? ctx.lineTo(px, py) : ctx.moveTo(px, py); }); + ctx.stroke(); + // FI marker + if (fireState.fiAge) { + const p = s.find(q => q.age === fireState.fiAge); + ctx.fillStyle = acc; ctx.beginPath(); ctx.arc(x(p.age), y(Math.min(p.bal, maxBal)), 5, 0, 7); ctx.fill(); + } + } + [fAge, fBal, fPmt, fSpend, fRet, fWr].forEach(el => el.addEventListener("input", updateFire)); + window.addEventListener("resize", drawFire); + window.addEventListener("load", drawFire); + + /* ---------- Tool 2: Asset allocation ---------- */ + const aAge = $("a_age"), aRule = $("a_rule"); + function updateAlloc() { + const age = +aAge.value, rule = +aRule.value; + let stock = Math.max(20, Math.min(100, rule - age)); + const bond = 100 - stock; + $("a_age_l").textContent = age; + $("a_stock").textContent = stock + "%"; + $("a_bond").textContent = bond + "%"; + $("a_intl").textContent = Math.round(stock * 0.35) + "%"; + $("a_seg_s").style.width = stock + "%"; $("a_seg_s").textContent = stock + "% Stocks"; + $("a_seg_b").style.width = bond + "%"; $("a_seg_b").textContent = bond + "% Bonds"; + $("a_note").textContent = age < 40 + ? "Long runway: a big equity tilt rides out crashes β your biggest asset is future earnings." + : age < 60 + ? "Mid-career: start adding bonds to dampen sequence risk as the horizon shortens." + : "Near/in retirement: enough bonds to cover ~2β5 years of spending cushions a bad-timing sell-off."; + } + [aAge, aRule].forEach(el => el.addEventListener("input", updateAlloc)); + + /* ---------- Tool 3: Funding waterfall (2026 limits) ---------- */ + const L = { k401: 24500, k401catch: 8000, ira: 7500, iracatch: 1100, hsaSelf: 4400, hsaFam: 8750, total: 72000 }; + function updateWaterfall() { + let amt = Math.max(0, +$("w_amt").value), age = +$("w_age").value; + const hasMatch = $("w_match").checked, matchAmt = Math.max(0, +$("w_matchamt").value); + const hasHsa = $("w_hsa").checked, hsaCap = ($("w_hsatype").value === "family" ? L.hsaFam : L.hsaSelf) + (age >= 55 ? 1000 : 0); + const roth = $("w_roth").checked; + const k401cap = L.k401 + (age >= 50 ? L.k401catch : 0); + const iracap = L.ira + (age >= 50 ? L.iracatch : 0); + const steps = []; + steps.push({ t: "Emergency fund + high-interest debt", cap: Infinity, note: "Before the waterfall: 1β6 months expenses, kill >8% debt.", pre: true }); + if (hasMatch) steps.push({ t: "401(k) to the full employer match", cap: matchAmt, note: "Instant 50β100% return β never skip." }); + if (hasHsa) steps.push({ t: "Max the HSA", cap: hsaCap, note: "Triple tax-free; invest it, don't spend it." }); + steps.push({ t: roth ? "Max Roth IRA" : "Max IRA (backdoor Roth if over limit)", cap: iracap, note: "Broad, flexible, contributions withdrawable." }); + steps.push({ t: "Finish maxing the 401(k)", cap: k401cap - (hasMatch ? Math.min(matchAmt, k401cap) : 0), note: "Up to $" + k401cap.toLocaleString() + " total employee deferral." }); + steps.push({ t: "Taxable brokerage", cap: Infinity, note: "Unlimited, fully liquid, LTCG rates β the overflow bucket." }); + + let remaining = amt, html = "", n = 1, placed = 0; + for (const s of steps) { + if (s.pre) { html += stepHtml(n++, s.t, null, s.note, false); continue; } + const fill = Math.min(remaining, s.cap); + remaining -= fill; placed += fill; + html += stepHtml(n++, s.t, fill, s.note, fill > 0, s.cap); + } + $("w_steps").innerHTML = html; + $("w_note").textContent = "Allocated " + fmt(placed) + " of " + fmt(amt) + " across the buckets above" + + (remaining > 0 ? " β " + fmt(remaining) + " lands in taxable." : "."); + } + function stepHtml(n, title, fill, note, filled, cap) { + const amtTxt = fill === null ? "" : '<span class="fill-amt ms-2">' + fmt(fill) + (cap && cap !== Infinity ? ' <span class="text-soft fw-normal">/ ' + fmt(cap) + '</span>' : '') + '</span>'; + return '<div class="waterfall-step ' + (filled ? 'filled' : '') + '"><div class="num">' + n + '</div><div><div class="fw-semibold">' + title + amtTxt + '</div><div class="small text-soft">' + note + '</div></div></div>'; + } + ["w_amt", "w_age", "w_match", "w_matchamt", "w_hsa", "w_hsatype", "w_roth"].forEach(id => { + $(id).addEventListener("input", updateWaterfall); $(id).addEventListener("change", updateWaterfall); + }); + + /* ---------- Tool 4: Wash-sale window ---------- */ + function updateWash() { + const v = $("ws_date").value; if (!v) return; + const d = new Date(v + "T00:00:00"); + const start = new Date(d); start.setDate(start.getDate() - 30); + const end = new Date(d); end.setDate(end.getDate() + 30); + const opt = { year: "numeric", month: "short", day: "numeric" }; + $("ws_start").textContent = start.toLocaleDateString("en-US", opt); + $("ws_end").textContent = end.toLocaleDateString("en-US", opt); + $("ws_note").textContent = "61 calendar days total. Buying a substantially identical security anywhere in this window β including a spouse's account or an IRA auto-reinvest β disallows the loss."; + } + $("ws_date").addEventListener("input", updateWash); + + /* ---------- init ---------- */ + applyTheme(); updateFire(); updateAlloc(); updateWaterfall(); updateWash(); + })(); + </script> +</body> + +</html>