How LLC Owners Save on Taxes in 2026

Real Estate Investor Find more write-offs — search your profession or a specific deduction
Try:
Why TurboTax/CPA May Be Blocking Your Rental Losses

The IRS classifies rental income as passive activity under IRC 469. Passive losses can only offset passive income - not your W-2 salary or business income. This is why TurboTax/CPA shows your rental losses as "suspended."

Three ways to unlock your rental losses:

  1. Real Estate Professional Status (REPS) - Spend 750+ hours/year and 50%+ of your working time in real estate. Losses become fully deductible against all income.
  2. Short-Term Rental (STR) Loophole - Average guest stay of 7 days or less classifies the rental as a business activity, making losses fully deductible without REPS.
  3. $25,000 Passive Loss Allowance - AGI below $100,000 allows up to $25,000 in rental losses against ordinary income. Phases out at $150,000 AGI.
Book A Free Strategy Call - We Will Show You Which Strategy Applies
Others Also Use These Strategies
Real Estate IRC §162 / IRC §212

Property Management Fees & Maintenance Deduction

All ordinary and necessary expenses for managing, conserving, and maintaining rental property are deductible. This includes property management fees (typically 8–12% of rent), repairs and maintenance, landscaping, snow removal, pest control, cleaning between tenants, locksmith fees, and any other costs directly related to keeping the property in rentable condition.

Eligibility Requirements
  • Rental property owner or real estate investor
  • Expenses directly related to managing rental property
  • Property must be held for rental income
Example Savings Scenario

A landlord paying $4,800/year in property management fees on a $4,000/month rental deducts the full amount, saving $1,440–$1,920 in taxes.

MERNA Strategy Notes

Repairs are immediately deductible; improvements must be depreciated. The line between repair and improvement matters — a new roof is an improvement, patching a roof is a repair.

Common Mistake: Capital improvements (new roof, new HVAC, additions) cannot be fully deducted in the year paid — they must be depreciated over their useful life unless you use Section 179 or bonus depreciation.
Real Estate IRC §168(c)

Rental Property Depreciation

Deduct the cost of residential rental property over 27.5 years and commercial property over 39 years, creating a non-cash deduction that reduces taxable income every year.

Eligibility Requirements
  • Own rental property placed in service
  • Property used for income-producing purposes
  • Land value excluded from depreciable basis
Example Savings Scenario

A $300,000 rental property (excluding land) generates $10,909/year in depreciation deductions, saving $3,818/year at a 35% tax rate.

MERNA Strategy Notes

Often overlooked by DIY filers. Depreciation recapture at 25% applies on sale — plan exit strategy with a 1031 exchange or installment sale.

Common Mistake: Failing to take depreciation does not eliminate recapture — the IRS taxes "allowed or allowable" depreciation.
UNK Client Win Residential Landlord

How a Nashville Landlord Discovered $42,000 in Missed Depreciation on Three Properties

A UNK client came in with three rental properties he had owned for 8 years. His previous CPA had been filing his returns but had never properly calculated depreciation on two of the properties — one had the land value excluded incorrectly, and another had never been depreciated at all. Through a Form 3115 catch-up, Uncle Kam recovered $42,000 in missed depreciation deductions in a single year, generating a $15,540 tax refund.

Result: $15,540 refund from missed deductions. The client also set up proper depreciation schedules going forward, saving $4,200/year in taxes he had been overpaying.

If you own rental property and have never had a depreciation review, you may be leaving thousands on the table every year. Book a call.

Be the Next Win — Book a Call
Common Questions About Rental Property Depreciation
Real Estate IRC §163(h)

Mortgage Interest Deduction

Deduct interest paid on mortgages for your primary residence and one second home, up to $750,000 of acquisition debt.

Eligibility Requirements
  • Mortgage on primary or second home
  • Loan used to buy, build, or improve the home
  • Itemize deductions on Schedule A
Example Savings Scenario

Paying $24,000 in mortgage interest annually saves $8,400 at a 35% tax rate when itemizing.

MERNA Strategy Notes

Compare itemized vs. standard deduction annually. For rental properties, mortgage interest is fully deductible on Schedule E with no dollar limit.

Common Mistake: Points paid on refinancing must be amortized over the loan life, not deducted all at once.
UNK Client Win Homeowner / W-2 Employee

How a Seattle Homeowner Recovered $9,200 by Itemizing Instead of Taking the Standard Deduction

A UNK client had been taking the standard deduction for three years while paying $28,000/year in mortgage interest on a $750,000 Seattle home. After a full deduction review, Uncle Kam found that stacking the mortgage interest deduction with state income taxes ($10,000 SALT cap), charitable contributions ($4,500), and property taxes pushed the itemized total to $42,500 — well above the $29,200 standard deduction for married filers. The client had been overpaying by $9,200/year.

Result: $9,200 in annual tax savings recovered — $27,600 over three years. The client amended two prior returns to claim the refund.

Are you sure you're taking every deduction available to you? A 30-minute strategy call could reveal thousands in missed write-offs.

Be the Next Win — Book a Call
Common Questions About Mortgage Interest Deduction
Real Estate IRC §1031 Uncle Kam Clients Only

1031 Like-Kind Exchange

Defer capital gains taxes indefinitely by reinvesting proceeds from the sale of investment property into a like-kind replacement property.

Eligibility Requirements
  • Property held for investment or business use
  • Replacement property identified within 45 days
  • Exchange completed within 180 days
  • Use a qualified intermediary
Example Savings Scenario

Selling a rental property with $500,000 in gains at a 20% capital gains rate saves $100,000 in immediate taxes. Deferred indefinitely with proper execution.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Business Expenses IRC §162 Uncle Kam Clients Only

MLS Fees, NAR Dues & Realtor Association Deduction

Real estate agents and brokers can deduct all professional membership fees and dues required to practice. This includes MLS access fees, National Association of Realtors (NAR) dues, state and local association dues, errors and omissions (E&O) insurance, and any other professional membership costs directly related to your real estate business.

Eligibility Requirements
  • Licensed real estate agent or broker
  • Self-employed (1099) real estate professional
  • Fees required to maintain MLS access or professional membership
Example Savings Scenario

A real estate agent paying $3,200/year in MLS fees, NAR dues, and E&O insurance deducts the full amount, saving $960–$1,280 in taxes.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §168 Uncle Kam Clients Only 2026 Law Update

Cost Segregation Study

Accelerates depreciation on commercial and residential rental property by reclassifying components into shorter recovery periods (5, 7, or 15 years) instead of 27.5 or 39 years.

Eligibility Requirements
  • Own commercial or rental property
  • Property cost basis over $500,000 for best ROI
  • Conducted by a qualified engineer or CPA firm
Example Savings Scenario

A $2M commercial building can generate $200,000–$400,000 in accelerated deductions in Year 1, saving $80,000–$160,000 in taxes at a 40% effective rate.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §469(c)(7) Uncle Kam Clients Only

Real Estate Professional Status (REPS) — 750 Hours

Qualify as a Real Estate Professional to treat all rental losses as non-passive, allowing unlimited deduction against any income including W-2 wages. Requires 750+ hours per year in real estate activities.

Eligibility Requirements
  • More than 750 hours per year in real estate activities
  • Real estate activities represent more than 50% of personal services
  • Material participation in each rental property (or group election)
Example Savings Scenario

A physician earning $400,000 W-2 whose spouse qualifies as a REPS can deduct $200,000 in rental losses, saving $74,000 in federal taxes.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §453 Uncle Kam Clients Only

Installment Sale

Spread the recognition of capital gains from a property sale over multiple years by receiving payments in installments, keeping annual income in lower tax brackets.

Eligibility Requirements
  • Selling real estate or business assets
  • Buyer agrees to pay over multiple years
  • Not dealer property or publicly traded securities
Example Savings Scenario

Selling a property with $600,000 in gains. Spreading over 6 years keeps you in the 15% capital gains bracket instead of 20%, saving $30,000+.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §280A(g) Uncle Kam Clients Only

Augusta Rule (Home Rental Exclusion)

Rent your personal home to your business for up to 14 days per year. The rental income is tax-free to you personally, and the business deducts the full rental expense.

Eligibility Requirements
  • Own a business (S-Corp, LLC, or sole prop)
  • Home rented for 14 days or fewer per year
  • Rental rate must be comparable to local market rates
  • Document with a rental agreement and business purpose
Example Savings Scenario

Renting your home to your S-Corp for 14 days at $2,000/day = $28,000 tax-free income to you, $28,000 deduction for the business, saving $10,360 in combined taxes.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §469(c)(7) Uncle Kam Clients Only

Short-Term Rental (STR) Loophole

STR properties with average guest stays of 7 days or less are NOT subject to passive activity loss rules, allowing losses to offset active W-2 or business income.

Eligibility Requirements
  • Average rental period 7 days or less
  • Material participation in the rental activity (100+ hours, most of anyone)
  • Property rented on Airbnb, VRBO, or similar platforms
Example Savings Scenario

A $600,000 STR property with a cost seg study generates $150,000 in Year 1 deductions, offsetting $150,000 of W-2 income and saving $55,500 at a 37% rate.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
Real Estate IRC §1400Z-2 Uncle Kam Clients Only 2026 Law Update

Opportunity Zone Investment

Defer and potentially eliminate capital gains taxes by investing in Qualified Opportunity Zone Funds within 180 days of a capital gain event.

Eligibility Requirements
  • Capital gain from any asset sale within 180 days
  • Investment in a Qualified Opportunity Fund (QOF)
  • Hold for 10+ years to eliminate gain on appreciation
Example Savings Scenario

Investing $500,000 of capital gains into a QOF and holding 10 years eliminates all taxes on the new appreciation — potentially $300,000+ in tax-free gains.

Unlock the Full Strategy Breakdown — Free

Enter your email for instant access to MERNA strategy notes, IRS red flag warnings, action steps, and implementation guide.

No spam · No obligation · Instant access
What Most Real Estate Investors Don't Know

Cost Segregation generates more first-year deductions than any other strategy in the tax code.

REPS status can turn passive losses into unlimited active deductions — but requires 750+ hours documented.

The 1031 exchange can be chained indefinitely — some investors have deferred gains for 30+ years.

Who Uses This Strategy

This write-off is commonly used by the following taxpayer profiles. Click to see all strategies for your situation.

Common Questions for Real Estate Investors

Get answers to the most frequently asked tax questions for your profession.

What tax write-offs can a real estate investor claim?
Real estate investors can deduct mortgage interest, property taxes, depreciation (27.5 years for residential), repairs, property management fees, insurance, and travel to properties. Depreciation alone can shelter $10,000\u2013$30,000+ of rental income annually.
How does real estate depreciation work for taxes?
Residential rental properties depreciate over 27.5 years. A $300,000 property (excluding land) generates ~$10,909/year in depreciation deductions \u2014 a non-cash write-off that reduces taxable income without spending money.
What is the real estate professional tax status?
Real estate professional status (REPS) allows you to deduct unlimited rental losses against ordinary income. You must spend 750+ hours/year in real estate activities and more time in real estate than any other profession.
Can I use a cost segregation study to accelerate depreciation?
Yes. A cost segregation study reclassifies building components (flooring, fixtures, landscaping) from 27.5-year to 5\u201315 year depreciation. On a $500K property, this can front-load $50,000\u2013$100,000 in Year 1 deductions.
What is the QBI deduction for rental income?
Rental income may qualify for the 20% Qualified Business Income (QBI) deduction if it rises to the level of a trade or business. A safe harbor requires 250+ hours of rental services per year. This can save $5,000\u2013$20,000 annually.
0
0 write-offs saved
Tap to view your list

Your Biggest Missed Deduction Is Probably Locked Above

Uncle Kam clients save an average of $40,000–$250,000/year. The strategies that make that possible are unlocked on a free strategy call.

Book A Free Strategy Call Free consultation. No obligation.
';// ── Open in a new window and print ─────────────────────────────── var win = window.open('', '_blank', 'width=850,height=700,scrollbars=yes,noopener=0'); if (!win) { // Fallback: inject an iframe for printing if popup is blocked var iframe = document.createElement('iframe'); iframe.style.cssText = 'position:fixed;top:-9999px;left:-9999px;width:850px;height:700px;border:0;'; document.body.appendChild(iframe); iframe.contentDocument.open(); iframe.contentDocument.write(html); iframe.contentDocument.close(); setTimeout(function() { iframe.contentWindow.focus(); iframe.contentWindow.print(); setTimeout(function() { document.body.removeChild(iframe); }, 2000); }, 600); return; } win.document.open(); win.document.write(html); win.document.close(); win.focus(); setTimeout(function() { win.print(); }, 600); }// ── Email Unlock: post to GHL silently, expand locked cards ────────────── function ukwfUnlockStrategies(e) { e.preventDefault(); // Support both the main wall form AND per-card gate forms var form = e ? e.target : null; var gateInput = form ? form.querySelector('.ukwf-gate-email-input') : null; var mainInput = document.getElementById('ukwf-unlock-email'); var emailInput = (gateInput && gateInput.value.trim()) ? gateInput : mainInput; var errorEl = document.getElementById('ukwf-unlock-error'); var email = emailInput ? emailInput.value.trim() : ''; // Also check the gate input if main is empty if (!email && gateInput) email = gateInput.value.trim(); // Basic email validation if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { if (errorEl) errorEl.style.display = 'block'; if (gateInput) { gateInput.style.borderColor = '#ff6b6b'; gateInput.focus(); } else if (emailInput) emailInput.focus(); return; } if (errorEl) errorEl.style.display = 'none'; if (gateInput) gateInput.style.borderColor = ''; // Disable all unlock buttons document.querySelectorAll('.ukwf-email-unlock-btn, .ukwf-gate-email-btn').forEach(function(b) { b.disabled = true; b.textContent = 'Unlocking...'; }); // Send lead to GHL via server-side PHP AJAX (bypasses webhook workflow) var professionEl = document.querySelector('.ukwf-profile-name'); var professionName = professionEl ? professionEl.textContent.trim().replace(/\s*Tax Write-Offs\s*&?\s*Deductions\s*$/i, '').trim() : ''; var nameParts = professionName.split('/'); var ghlFirstName = nameParts[0] ? nameParts[0].trim() : professionName; var ghlLastName = nameParts[1] ? nameParts[1].trim() : 'Tax Write-Off Finder'; var ajaxUrl = (typeof ukwfConfig !== 'undefined' && ukwfConfig.ajaxUrl) ? ukwfConfig.ajaxUrl : '/wp-admin/admin-ajax.php'; var nonce = (typeof ukwfConfig !== 'undefined' && ukwfConfig.leadNonce) ? ukwfConfig.leadNonce : ''; var formData = new FormData(); formData.append('action', 'ukwf_ghl_lead'); formData.append('nonce', nonce); formData.append('email', email); formData.append('firstName', ghlFirstName); formData.append('lastName', ghlLastName); formData.append('profession', professionName); formData.append('source', 'ukwf-unlock'); formData.append('page', window.location.pathname); fetch(ajaxUrl, { method: 'POST', body: formData }).catch(function() {}); // fire-and-forget // Expand all locked cards immediately ukwfDoUnlock(); } function ukwfDoUnlock() { // Hide the email wall var wall = document.getElementById('ukwf-email-unlock-wall'); if (wall) { wall.style.transition = 'opacity 0.3s ease'; wall.style.opacity = '0'; setTimeout(function() { wall.style.display = 'none'; }, 300); } // Unlock all locked cards instantly — no stagger (stagger caused 4+ second delay for 70+ cards) var lockedCards = document.querySelectorAll('.ukwf-result-card--locked'); lockedCards.forEach(function(card) { // Remove locked state — keep collapsed so user can open each card individually card.classList.remove('ukwf-result-card--locked'); card.classList.add('ukwf-result-card--open'); // Clear any inline styles that might block the toggle var body = card.querySelector('.ukwf-result-body'); if (body) { body.style.display = ''; body.style.maxHeight = ''; } // Remove lock badge var badge = card.querySelector('.ukwf-result-lock-badge'); if (badge) badge.style.display = 'none'; // Replace the locked gate with an unlocked badge var gate = card.querySelector('.ukwf-locked-strategy-gate'); if (gate) { gate.innerHTML = '
Unlocked — tap to expand
'; } }); // Show success banner var banner = document.getElementById('ukwf-unlock-banner'); if (banner) { banner.style.display = 'flex'; } // Persist unlock in localStorage so it survives refresh, tab close, and navigation // Uses the same ukwfSetUnlocked() that the book-call path uses, which sets // localStorage key 'ukwf_unlocked' = '1'. The main script block already checks // ukwfIsUnlocked() on page load and calls ukwfUnlockAll() automatically. if (typeof ukwfSetUnlocked === 'function') { ukwfSetUnlocked(); } else { try { localStorage.setItem('ukwf_unlocked', '1'); } catch(err) {} } // Also run the main unlock function to handle any card variants we might miss if (typeof ukwfUnlockAll === 'function') { ukwfUnlockAll(); } } // NOTE: Auto-unlock on page load is handled by the main script block which // checks ukwfIsUnlocked() and calls ukwfUnlockAll(). No DOMContentLoaded // listener needed here (it was broken anyway because LiteSpeed defers scripts // past DOMContentLoaded)./* ── Sticky Save Bar ───────────────────────────────────────────────── */ (function() { var SAVED_KEY = 'ukwf_saved_v2'; var bar = document.getElementById('ukwf-sticky-save-bar'); var countEl = document.getElementById('ukwf-sticky-save-count'); var badgeEl = document.getElementById('ukwf-sticky-cart-badge'); var savingsWrap = document.getElementById('ukwf-sticky-save-savings'); var savingsRange = document.getElementById('ukwf-sticky-savings-range'); if (!bar || !countEl) return;var _prevCount = 0;/* Parse a savings string like "$1,200–$4,500/year" -> {min, max} */ function parseSavings(str) { if (!str) return null; var nums = str.replace(/[^0-9]/g, ' ').trim().split(/\s+/).filter(Boolean); var vals = nums.map(function(n) { return parseInt(n, 10); }).filter(function(n) { return !isNaN(n) && n > 0; }); if (vals.length === 0) return null; if (vals.length === 1) return { min: vals[0], max: vals[0] }; return { min: Math.min.apply(null, vals), max: Math.max.apply(null, vals) }; }/* Format a number as $XK or $X.XM */ function fmtMoney(n) { if (n >= 1000000) return '$' + (n / 1000000).toFixed(1).replace(/\.0$/, '') + 'M'; if (n >= 1000) return '$' + Math.round(n / 1000) + 'K'; return '$' + n.toLocaleString(); }/* Animated count-up for a single element */ function animateCount(el, from, to, duration) { if (from === to) { el.textContent = to; return; } var start = null; function step(ts) { if (!start) start = ts; var progress = Math.min((ts - start) / duration, 1); var ease = 1 - Math.pow(1 - progress, 3); el.textContent = Math.round(from + (to - from) * ease); if (progress < 1) requestAnimationFrame(step); else el.textContent = to; } requestAnimationFrame(step); }function getSaved() { try { return JSON.parse(localStorage.getItem(SAVED_KEY) || '[]'); } catch(e) { return []; } }function updateBar() { var saved = getSaved(); var n = saved.length;/* Count-up animation when count changes */ if (n !== _prevCount) { animateCount(countEl, _prevCount, n, 600); if (badgeEl) animateCount(badgeEl, _prevCount, n, 600); /* Pop animation on bar when count increases */ if (n > _prevCount) { bar.classList.remove('ukwf-sticky-bar-pop'); void bar.offsetWidth; bar.classList.add('ukwf-sticky-bar-pop'); } _prevCount = n; }if (n > 0) { bar.classList.add('ukwf-sticky-save-bar--visible');/* Calculate total savings range */ var totalMin = 0, totalMax = 0, hasSavings = false; saved.forEach(function(item) { var p = parseSavings(item.savings || ''); if (p) { totalMin += p.min; totalMax += p.max; hasSavings = true; } });if (hasSavings && savingsWrap && savingsRange) { var rangeStr = totalMin === totalMax ? fmtMoney(totalMin) : fmtMoney(totalMin) + '–' + fmtMoney(totalMax); savingsRange.textContent = rangeStr; savingsWrap.style.display = ''; } else if (savingsWrap) { savingsWrap.style.display = 'none'; } } else { bar.classList.remove('ukwf-sticky-save-bar--visible'); if (savingsWrap) savingsWrap.style.display = 'none'; } }/* Update whenever a save/unsave happens */ window.addEventListener('ukwfSavedChanged', updateBar); /* Cross-tab sync */ window.addEventListener('storage', function(e) { if (e.key === SAVED_KEY) updateBar(); }); /* Expose globally */ window.ukwfStickyBarRefresh = updateBar; updateBar(); })();/* ── CART DRAWER ────────────────────────────────────────────────────── */ (function() { var SAVED_KEY = 'ukwf_saved_v2'; var drawer = document.getElementById('ukwf-cart-drawer'); var overlay = document.getElementById('ukwf-cart-overlay'); var itemsList = document.getElementById('ukwf-cart-items'); var emptyEl = document.getElementById('ukwf-cart-empty'); var footerEl = document.getElementById('ukwf-cart-footer'); var savingsStrip = document.getElementById('ukwf-cart-savings-strip'); var savingsAmount = document.getElementById('ukwf-cart-savings-amount'); var headerSub = document.getElementById('ukwf-cart-header-sub'); var footerCount = document.getElementById('ukwf-cart-footer-count'); if (!drawer) return;function getSaved() { try { return JSON.parse(localStorage.getItem(SAVED_KEY) || '[]'); } catch(e) { return []; } } function setSaved(arr) { localStorage.setItem(SAVED_KEY, JSON.stringify(arr)); window.dispatchEvent(new CustomEvent('ukwfSavedChanged')); if (typeof window.ukwfStickyBarRefresh === 'function') window.ukwfStickyBarRefresh(); if (typeof window.ukwfSavedBadgeRefresh === 'function') window.ukwfSavedBadgeRefresh(); } function parseSavings(str) { if (!str) return null; var nums = str.replace(/[^0-9]/g, ' ').trim().split(/\s+/).filter(Boolean); var vals = nums.map(function(n){ return parseInt(n,10); }).filter(function(n){ return !isNaN(n) && n > 0; }); if (!vals.length) return null; if (vals.length === 1) return { min: vals[0], max: vals[0] }; return { min: Math.min.apply(null,vals), max: Math.max.apply(null,vals) }; } function fmtMoney(n) { if (n >= 1000000) return '$' + (n/1000000).toFixed(1).replace(/\.0$/,'') + 'M'; if (n >= 1000) return '$' + Math.round(n/1000) + 'K'; return '$' + n.toLocaleString(); } function getCatIcon(cat) { var icons = { 'vehicle':'', 'home':'', 'travel':'', 'equipment':'', 'health':'', 'retirement':'', 'education':'', 'real estate':'' }; var k = (cat || '').toLowerCase(); for (var key in icons) { if (k.indexOf(key) !== -1) return icons[key]; } return ''; } function renderItems() { var saved = getSaved(); var n = saved.length; /* Update header sub */ if (headerSub) headerSub.textContent = n + ' deduction' + (n !== 1 ? 's' : '') + ' saved'; /* Show/hide empty state */ if (emptyEl) emptyEl.style.display = n === 0 ? '' : 'none'; if (footerEl) footerEl.style.display = n === 0 ? 'none' : ''; /* Savings strip */ var totalMin = 0, totalMax = 0, hasSavings = false; saved.forEach(function(item) { var p = parseSavings(item.savings || ''); if (p) { totalMin += p.min; totalMax += p.max; hasSavings = true; } }); if (hasSavings && savingsStrip) { savingsStrip.style.display = ''; var rangeStr = totalMin === totalMax ? fmtMoney(totalMin) : fmtMoney(totalMin) + ' – ' + fmtMoney(totalMax); if (savingsAmount) savingsAmount.textContent = rangeStr; } else if (savingsStrip) { savingsStrip.style.display = 'none'; } /* Footer count */ if (footerCount) footerCount.textContent = n > 0 ? n + ' write-off' + (n !== 1 ? 's' : '') + ' in your list' : ''; /* Remove existing items (keep empty state) */ var existing = itemsList ? itemsList.querySelectorAll('.ukwf-cart-item') : []; existing.forEach(function(el) { el.parentNode.removeChild(el); }); /* Render each item */ saved.forEach(function(item, idx) { var div = document.createElement('div'); div.className = 'ukwf-cart-item'; div.style.animationDelay = (idx * 0.04) + 's'; div.innerHTML = '
' + getCatIcon(item.category) + '
' + '
' + '
' + escHtml(item.name || item.slug) + '
' + (item.category ? '
' + escHtml(item.category) + '
' : '') + (item.savings ? '
' + escHtml(item.savings) + '/yr
' : '') + '
' + ''; /* Remove button handler */ div.querySelector('.ukwf-cart-item-remove').addEventListener('click', function() { var slug = this.getAttribute('data-slug'); var arr = getSaved().filter(function(i){ return i.slug !== slug; }); setSaved(arr); /* Animate out */ div.style.transition = 'opacity 0.18s, transform 0.18s'; div.style.opacity = '0'; div.style.transform = 'translateX(20px)'; setTimeout(function() { renderItems(); }, 180); /* Also update save buttons on page */ document.querySelectorAll('.ukwf-card-save-btn[data-slug="' + slug + '"]').forEach(function(btn) { btn.classList.remove('ukwf-card-save-btn--saved'); btn.setAttribute('aria-pressed','false'); var lbl = btn.querySelector('.ukwf-card-save-label'); if (lbl) lbl.textContent = 'Save'; }); }); if (itemsList) itemsList.appendChild(div); }); } function escHtml(s) { return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } function escAttr(s) { return String(s).replace(/"/g,'"').replace(/'/g,'''); } /* Open / close */ window.ukwfCartDrawerOpen = function() { renderItems(); if (drawer) drawer.classList.add('ukwf-cart-drawer--open'); if (overlay) overlay.classList.add('ukwf-cart-overlay--open'); document.body.style.overflow = 'hidden'; }; window.ukwfCartDrawerClose = function() { if (drawer) drawer.classList.remove('ukwf-cart-drawer--open'); if (overlay) overlay.classList.remove('ukwf-cart-overlay--open'); document.body.style.overflow = ''; }; window.ukwfCartClearAll = function() { if (!confirm('Remove all saved write-offs?')) return; setSaved([]); renderItems(); }; /* Keyboard close */ document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && drawer && drawer.classList.contains('ukwf-cart-drawer--open')) { window.ukwfCartDrawerClose(); } }); /* Re-render when saves change */ window.addEventListener('ukwfSavedChanged', function() { if (drawer && drawer.classList.contains('ukwf-cart-drawer--open')) { renderItems(); } }); window.addEventListener('storage', function(e) { if (e.key === SAVED_KEY && drawer && drawer.classList.contains('ukwf-cart-drawer--open')) { renderItems(); } }); })();/* ── CARD SAVE BUTTONS ──────────────────────────────────────────────── */ (function() { var SAVED_KEY = 'ukwf_saved_v2';function getSaved() { try { return JSON.parse(localStorage.getItem(SAVED_KEY) || '[]'); } catch(e) { return []; } } function setSaved(arr) { localStorage.setItem(SAVED_KEY, JSON.stringify(arr)); } function isSaved(slug) { return getSaved().some(function(i) { return i.slug === slug; }); } function updateBtn(btn) { var slug = btn.getAttribute('data-slug'); var saved = isSaved(slug); btn.classList.toggle('ukwf-card-save-btn--saved', saved); btn.setAttribute('aria-pressed', saved ? 'true' : 'false'); var label = btn.querySelector('.ukwf-card-save-label'); if (label) label.textContent = saved ? 'Saved' : 'Save'; } function initAllBtns() { document.querySelectorAll('.ukwf-card-save-btn').forEach(function(btn) { updateBtn(btn); btn.addEventListener('click', function(e) { e.stopPropagation(); var slug = btn.getAttribute('data-slug'); var name = btn.getAttribute('data-name'); var cat = btn.getAttribute('data-category') || ''; var savings = btn.getAttribute('data-savings') || ''; var saved = getSaved(); var idx = saved.findIndex(function(i) { return i.slug === slug; }); if (idx === -1) { saved.push({ slug: slug, name: name, category: cat, savings: savings, savedAt: Date.now() }); } else { saved.splice(idx, 1); } setSaved(saved); updateBtn(btn); /* Sync badge and sticky bar */ window.dispatchEvent(new CustomEvent('ukwfSavedChanged')); if (typeof window.ukwfSavedBadgeRefresh === 'function') window.ukwfSavedBadgeRefresh(); if (typeof window.ukwfStickyBarRefresh === 'function') window.ukwfStickyBarRefresh(); }); }); } /* Init on load and re-sync on saved changes from autocomplete */ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAllBtns); } else { initAllBtns(); } window.addEventListener('ukwfSavedChanged', function() { document.querySelectorAll('.ukwf-card-save-btn').forEach(updateBtn); }); })();