How LLC Owners Save on Taxes in 2026

Therapist Find more write-offs — search your profession or a specific deduction
Try:
Others Also Use These Strategies
Therapist IRC §280A

Home Office Deduction for Therapists

Therapists who maintain a dedicated space in their home used exclusively and regularly for client sessions or administrative work qualify for the home office deduction. You can deduct a proportional share of rent or mortgage interest, utilities, internet, and homeowners insurance based on the square footage of the therapy space relative to total home square footage.

Eligibility Requirements
  • Dedicated room used exclusively for therapy sessions or administrative work
  • Space used regularly (not occasionally)
  • Can be a home office for telehealth sessions or in-person sessions
  • Works for both renters and homeowners
Example Savings Scenario

A therapist with a 200 sq ft home office in a 1,500 sq ft home (13.3%) paying $2,500/month rent deducts $3,990/year. A homeowner with $18,000 in mortgage interest and utilities deducts $2,394/year.

MERNA Strategy Notes

Use the simplified method ($5/sq ft, max 300 sq ft = $1,500/year) or the regular method (actual expenses × business %). The regular method almost always yields a larger deduction. Document the space with photos and floor plan measurements.

Common Mistake: The space must be used EXCLUSIVELY for business — a spare bedroom that doubles as a guest room does not qualify.
Therapist IRC §162

EHR Software and Telehealth Platform Deduction for Therapists

All software subscriptions used to run your therapy practice are 100% deductible as business expenses. This includes electronic health record (EHR) platforms (SimplePractice, TherapyNotes, TheraNest, Therapy Brands, Luminare Health), telehealth platforms (Zoom for Healthcare, Doxy.me, VSee), scheduling software (Calendly, Acuity), billing software, and any other practice management tools.

Eligibility Requirements
  • Licensed therapist, counselor, social worker, or psychologist
  • Software used exclusively or primarily for business
  • Monthly or annual subscription fees
  • One-time software purchases also qualify under Section 179
Example Savings Scenario

A therapist paying $99/month for SimplePractice ($1,188/year) plus $20/month for Zoom ($240/year) deducts $1,428/year, saving $400 at a 28% effective tax rate.

MERNA Strategy Notes

Pay annual subscriptions in December to accelerate the full year deduction into the current tax year. If you use software for both personal and business purposes, only the business-use percentage is deductible.

Common Mistake: Software used for both personal and business purposes must be allocated — only the business-use percentage is deductible.
Therapist IRC §162

Professional Liability Insurance Deduction for Therapists

Professional liability insurance (malpractice insurance) premiums are 100% deductible as an ordinary and necessary business expense for therapists, counselors, and social workers in private practice. This includes coverage from HPSO, CPH & Associates, APA Insurance Trust, NASW Assurance Services, and any other professional liability carrier. General business liability insurance and cyber liability insurance (for protecting client records) are also fully deductible.

Eligibility Requirements
  • Licensed therapist, counselor, social worker, or psychologist
  • Policy covers professional liability or malpractice
  • General business liability and cyber liability also qualify
  • Both individual and group practice policies are deductible
Example Savings Scenario

A therapist paying $800/year for HPSO liability coverage at a 28% effective tax rate saves $224/year. Adding cyber liability ($500/year) saves an additional $140 — total $364/year in tax savings.

MERNA Strategy Notes

Pay your annual premium in December to accelerate the deduction into the current tax year. If you work at multiple practices, each policy is separately deductible.

Common Mistake: Personal umbrella policies are NOT deductible — only policies that cover professional liability in your therapy practice qualify.
Education IRC §162 Uncle Kam Clients Only

Teacher Professional Development & Certification Deduction

Teachers can deduct professional development costs beyond the $300 educator expense cap if they are self-employed or if their employer requires the training. This includes graduate education courses, certification programs, teaching conferences, and curriculum development workshops. Costs must be directly related to maintaining or improving teaching skills.

Eligibility Requirements
  • Must be a teacher with unreimbursed professional development expenses
  • Education must maintain or improve teaching skills
  • Certification costs must be for your current teaching position
  • Must have documentation of expenses
Example Savings Scenario

A teacher spending $1,500 on NBCT certification prep, $600 on graduate courses, and $400 on teaching conferences deducts $2,500 (beyond the $300 educator expense limit).

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
Pharmacist IRC §162 Uncle Kam Clients Only

Pharmacist CE Credits, BCPS & Board Certification Fees

Continuing education credits required for pharmacist license renewal, BCPS/BCACP/BCOP board certification fees, ACPE-accredited courses, and state pharmacy board fees are fully deductible.

Eligibility Requirements
  • Licensed pharmacist
  • CE required for license renewal or specialty certification
  • Courses maintain or improve existing pharmacy skills
Example Savings Scenario

A clinical pharmacist paying $3,200 for BCPS exam prep, exam fee, and CE credits deducts the full amount — saving $1,056 at 33%.

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
Financial Advisor IRC §162 Uncle Kam Clients Only

Series 7, Series 65, CFP & FINRA License Fees

FINRA exam fees (Series 7, 63, 65, 66), CFP certification and renewal fees, CFA exam fees, state investment advisor registration fees, and continuing education requirements are fully deductible.

Eligibility Requirements
  • Licensed financial advisor or investment professional
  • Fees for maintaining existing licenses
  • CE required for license renewal
Example Savings Scenario

An RIA paying $3,600 for CFP renewal, $1,200 in state registration fees, and $2,400 in CE courses deducts $7,200 — saving $2,376 at 33%.

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
Therapist IRC §401(k), §408(k) Uncle Kam Clients Only

Solo 401(k) and SEP-IRA for Therapists

Therapists in private practice can make tax-deductible retirement contributions that dramatically reduce taxable income. A Solo 401(k) allows contributions of up to $70,000/year ($77,500 if age 50+) in 2026 as both employee and employer. A SEP-IRA allows contributions of up to 20% of net self-employment income (max $70,000). Both reduce taxable income dollar-for-dollar and grow tax-deferred until retirement.

Eligibility Requirements
  • Self-employed therapist with net income from private practice
  • Solo 401(k): no full-time employees other than spouse
  • SEP-IRA: available even with part-time employees
  • Must open Solo 401(k) by December 31 to contribute for the current year
Example Savings Scenario

A therapist earning $100,000 net who contributes $30,000 to a Solo 401(k) reduces taxable income to $70,000, saving $8,400 in federal taxes at a 28% effective rate — plus the money grows tax-deferred.

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
Therapist IRC §1361, §3111 Uncle Kam Clients Only

S-Corp Election for Therapists in Private Practice

Therapists operating as sole proprietors or single-member LLCs pay self-employment tax (15.3%) on 100% of net profit. By electing S-Corp status, the therapist pays themselves a reasonable salary (subject to payroll taxes) and takes remaining profit as distributions — which are NOT subject to self-employment tax. For a therapist generating $120,000 in net profit, an S-Corp election typically saves $8,000–$15,000 per year in SE taxes alone.

Eligibility Requirements
  • Net self-employment income of $50,000+ per year
  • Therapist actively works in the practice
  • Willing to run payroll and pay a reasonable salary
  • Entity structured as LLC or corporation
Example Savings Scenario

A therapist with $120,000 net profit pays a $60,000 reasonable salary and takes $60,000 as distributions, saving approximately $9,180 in self-employment taxes annually.

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 Therapists Don't Know

A dedicated therapy office in your home qualifies for the home office deduction — therapists with a room used exclusively for client sessions can deduct a proportional share of rent, mortgage interest, utilities, and internet.

Continuing education (CEUs), licensure renewal fees, supervision hours, and professional association dues (NASW, APA, AAMFT) are all 100% deductible business expenses.

An S-Corp election can save therapists in private practice $8,000–$20,000/year in self-employment taxes once net income exceeds $50,000 — most solo practitioners never make this structural change.

Common Questions for Therapists

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

What tax deductions can a therapist claim?
Therapists in private practice can deduct their home office or office rent, continuing education (CEUs), licensure renewal fees, professional association dues (NASW, APA, AAMFT, NBCC), liability insurance, electronic health record (EHR) software, telehealth platform fees, phone and internet (business %), and retirement contributions. Most therapists miss $8,000\u2013$25,000 in deductions annually.
Can a therapist deduct a home office?
Yes \u2014 if you have a dedicated room used exclusively and regularly for client sessions or administrative work, you qualify for the home office deduction. You can deduct a proportional share of rent or mortgage interest, utilities, internet, and homeowners insurance. A 200 sq ft office in a 1,500 sq ft home = 13.3% of all home expenses deductible.
Should a therapist form an S-Corp?
Yes \u2014 therapists in private practice earning $50,000+ in net income typically save $8,000\u2013$20,000/year with an S-Corp election. You pay yourself a reasonable salary (e.g., $55,000) and take remaining profit as distributions, avoiding self-employment tax on the distribution portion. The S-Corp pays for itself in Year 1 for most solo practitioners.
Can a therapist deduct continuing education and CEUs?
Yes \u2014 all CEU courses, workshops, supervision hours, and professional conferences required to maintain your license are 100% deductible. This includes NASW, APA, AAMFT, and NBCC conference fees, online CEU platforms (CE4Less, Relias), and specialized training (EMDR, DBT, somatic therapy certifications).
What retirement account should a therapist use to reduce taxes?
A Solo 401(k) allows therapists to contribute up to $70,000/year ($77,500 if age 50+) in 2026, reducing taxable income dollar-for-dollar. A SEP-IRA allows contributions of up to 20% of net self-employment income (max $70,000). Both are far superior to a traditional IRA for high-income solo practitioners.
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 $8,000–$50,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); }); })();