How LLC Owners Save on Taxes in 2026

Crypto Trader Find more write-offs — search your profession or a specific deduction
Try:
Others Also Use These Strategies
Crypto IRC §162 / §179

Crypto Mining Equipment & Electricity

If you mine cryptocurrency, your mining hardware (ASICs, GPUs, mining rigs) and the electricity used to power them are fully deductible business expenses. Section 179 allows you to expense the full cost of equipment in the year of purchase rather than depreciating it over time.

Eligibility Requirements
  • Active cryptocurrency miner
  • Mining as a business (not hobby)
  • Hardware used exclusively for mining
Example Savings Scenario

A miner who spends $15,000 on ASICs and $8,000/year on electricity saves $5,750 in taxes at a 25% effective rate — plus Section 179 allows full first-year expensing of the hardware.

MERNA Strategy Notes

Document electricity usage with a dedicated circuit or smart meter. Keep all hardware receipts. If mining is a hobby, deductions are limited — structure as a business to maximize deductions.

Common Mistake: The IRS treats mining rewards as ordinary income at fair market value on the date received — failure to report is a major audit trigger.
IRC: Mining rewards are ordinary income (Rev. Rul. 2023-14). Equipment deductible under IRC §162 and §179.
Crypto IRC §170

Crypto Donation: Avoid Capital Gains Tax

When you donate appreciated cryptocurrency directly to a qualified 501(c)(3) charity, you avoid paying capital gains tax on the appreciation AND receive a charitable deduction for the full fair market value. This is one of the most powerful tax strategies available to crypto holders with large unrealized gains.

Eligibility Requirements
  • Hold appreciated cryptocurrency
  • Donate to a 501(c)(3) qualified charity
  • Held the crypto for more than one year (for long-term treatment)
Example Savings Scenario

A crypto holder donates $50,000 of Bitcoin with a $5,000 cost basis. They avoid $10,710 in capital gains tax (23.8% on $45,000 gain) AND get a $50,000 charitable deduction worth $12,500 at a 25% rate — total tax benefit of $23,210.

MERNA Strategy Notes

Use a Donor Advised Fund (DAF) to donate crypto and grant to charities over time. Requires qualified appraisal for donations over $5,000 of non-publicly traded crypto.

Common Mistake: Selling crypto first and then donating cash eliminates the capital gains avoidance benefit — always donate the crypto directly.
IRC: Charitable deduction under IRC §170. IRS Notice 2014-21 treats crypto as property — donation of appreciated property avoids capital gains.
Crypto IRC §165

Staking Rewards & DeFi Loss Deductions

Staking rewards are treated as ordinary income when received. However, losses from DeFi protocols, rug pulls, and worthless tokens may be deductible as casualty losses or worthless security losses under IRC §165. Proper documentation is critical.

Eligibility Requirements
  • Active DeFi participant or staker
  • Experienced rug pulls, protocol hacks, or worthless token losses
  • Staking rewards received during the tax year
Example Savings Scenario

A DeFi investor who lost $40,000 in a protocol hack and $20,000 in a rug pull may deduct those losses to offset $60,000 in other crypto gains — saving $14,280 at a 23.8% rate.

MERNA Strategy Notes

Document all DeFi losses with transaction records. Worthless token losses require proof the token has zero value. Consult a tax professional before claiming rug pull losses.

Common Mistake: The IRS has not issued clear guidance on all DeFi scenarios — aggressive deductions without documentation are a major audit risk.
IRC: Staking income: Rev. Rul. 2023-14. Worthless securities: IRC §165(g). Casualty losses: IRC §165(c).
Investments IRC §1001

Crypto Tax Loss Harvesting

Sell cryptocurrency at a loss to offset capital gains from other investments. Unlike stocks, crypto is NOT subject to the wash-sale rule, so you can immediately repurchase the same asset.

Eligibility Requirements
  • Own cryptocurrency or digital assets
  • Have unrealized losses in any position
  • Have capital gains to offset (or use $3,000/year against ordinary income
Example Savings Scenario

An investor with $80,000 in crypto gains and $50,000 in crypto losses nets $30,000 in taxable gains — saving $11,900 at a 23.8% long-term rate vs. paying on the full $80,000.

MERNA Strategy Notes

Harvest losses before December 31. Immediately repurchase to maintain market exposure — no 30-day waiting period required for crypto. Track cost basis meticulously.

Common Mistake: Congress has proposed applying wash-sale rules to crypto — act while the loophole exists.
UNK Client Win Crypto Investor / High Net Worth

How a Crypto Investor Harvested $45,000 in Losses and Immediately Repurchased — No Wash-Sale Rule

A UNK client had $45,000 in unrealized losses across several altcoin positions during a market correction. He also had $60,000 in capital gains from selling Bitcoin earlier in the year. Uncle Kam identified the key advantage: unlike stocks, cryptocurrency is not subject to the wash-sale rule. The client sold the losing positions, harvested $45,000 in losses, and immediately repurchased the same coins — maintaining his full market exposure. The $45,000 in losses offset $45,000 of his gains, reducing his net capital gain to $15,000.

Result: $10,350 in capital gains tax saved (at 23% combined federal rate on $45,000). The client maintained his full crypto portfolio without any 31-day waiting period.

Hold crypto with unrealized losses? You can harvest them today and repurchase immediately. Book a call before year-end to capture your losses.

Be the Next Win — Book a Call
Common Questions About Crypto Tax Loss Harvesting
Web3 IRC §162 Uncle Kam Clients Only

DAO Contributor & Token Compensation Deductions

Web3 founders and DAO contributors can deduct token compensation paid to contributors (as ordinary business expenses), smart contract audit fees, legal fees for token structuring and regulatory compliance, protocol development costs, and governance participation expenses. Token compensation paid to contributors is deductible at fair market value on the date of transfer.

Eligibility Requirements
  • Web3 founder or DAO contributor
  • Paying contributors in tokens
  • Incurring smart contract, legal, or development costs
Example Savings Scenario

A Web3 founder who pays $80,000 in token compensation to contributors and $30,000 in smart contract audits deducts $110,000 — saving $27,500 at a 25% 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
Investments IRC §1001, §1031 Uncle Kam Clients Only

Crypto-to-Crypto Exchange Tax Treatment

Each cryptocurrency trade, swap, or exchange is a taxable event. Proper structuring — holding periods, loss harvesting, and entity selection — can dramatically reduce crypto tax liability.

Eligibility Requirements
  • Active crypto trader or long-term holder
  • Multiple transactions per year
  • Gains exceeding $10,000 annually
Example Savings Scenario

A trader with $200,000 in short-term crypto gains who restructures to maximize long-term holds and harvests $60,000 in losses saves $37,000 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
What Most Crypto Traders Don't Know

Unlike stocks, crypto is NOT subject to the wash-sale rule (IRC §1091) — you can sell at a loss, immediately rebuy, and still claim the full deduction. This is the #1 crypto tax strategy.

Donating appreciated crypto directly to charity lets you deduct the full fair market value AND avoid capital gains tax — worth 20–37% more than selling and donating cash.

Mining income is taxed as ordinary income at receipt — but mining equipment and electricity costs are fully deductible business expenses under IRC §162.

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 Crypto Traders

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

How are cryptocurrency gains taxed?
Crypto held less than 1 year is taxed as short-term capital gains (ordinary income rates, up to 37%). Crypto held 1+ year is taxed at long-term capital gains rates (0%, 15%, or 20% depending on income). Each trade is a taxable event.
What is tax loss harvesting for crypto traders?
Tax loss harvesting involves selling crypto at a loss to offset gains. Unlike stocks, crypto is not subject to wash sale rules \u2014 you can sell at a loss and immediately repurchase the same crypto. This strategy can eliminate $10,000\u2013$50,000+ in capital gains taxes.
Can crypto traders deduct trading losses?
Yes. Capital losses offset capital gains dollar-for-dollar. Excess losses can offset up to $3,000 of ordinary income per year, with remaining losses carried forward indefinitely. Worthless tokens can be claimed as ordinary losses under IRC \u00a7165.
How are staking rewards and DeFi income taxed?
Staking rewards are taxed as ordinary income at fair market value when received. DeFi yield, liquidity mining rewards, and airdrops are also taxed as ordinary income when received. Subsequent sale of these assets creates a separate capital gain/loss event.
Do crypto traders need to file Form 8949?
Yes. Every crypto sale, trade, or exchange must be reported on Form 8949 and Schedule D. This includes crypto-to-crypto trades, NFT purchases with crypto, and DeFi transactions. Crypto tax software (Koinly, TaxBit, CoinLedger) can automate this.
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 $20,000–$100,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); }); })();